In version 24.0.0, we introduced a registration validation system to improve the already existing registration system. This validation system is able to track the number of devices a customer has registered EmEditor on.
This page aims to be transparent about our motivations and to document how the validation system works. If we update the validation system in the future, we will also update this page.
Motivation
In the past, there was no way for us to detect users who were sharing their licenses with multiple people or using their licenses on more devices than allowed by the EULA (End-User License Agreement). We would like customers to purchase enough licenses to follow the terms of the license. This would ensure fairness among customers who have purchased multiple licenses and help us keep delivering a quality product.
Terminology
- Registration: The one-time process of activating EmEditor Professional with a registration key or Emurasoft Customer Center credentials.
- Validation: The periodic check that runs each time EmEditor starts to verify that the current installation is associated with a valid license.
- Registration key: A string used to register EmEditor.
- Offline registration: A type of registration that lets users register and validate EmEditor without connecting to the EmEditor server.
- Device: A single counted unit under the license, representing one EmEditor installation. Multiple per-user installations of EmEditor on the same machine are treated as one device.
- Device limit: The maximum number of devices that may be registered to a user, based on the number of licenses the user owns, as defined in the EULA.
- Machine: A Windows environment where EmEditor is installed and can run. A machine is uniquely identified by its machine ID. A machine is not necessarily equivalent to a physical computer, because multiple virtual machines can be installed on one computer.
- Machine ID: A combination of several Windows attributes (MachineGuid, OS install date, volume serial number, processor name, and motherboard name) that is used to distinguish one machine from another.
- MachineGuid: An identifier for a Windows installation, used as one of the inputs to the machine ID.
- Virtual machine (VM): A Windows machine running inside a virtualization environment.
- Local device token: A signed token stored on the user’s machine that verifies that the device was registered.
- History record: A database record associated with a 2Checkout or reseller purchase.
- Stripe subscription ID: The identifier of a user’s Stripe subscription, used to associate registered devices with the Stripe subscription.
- Reseller: A third-party vendor that sells EmEditor licenses (other than 2Checkout or Stripe). Customers who purchase through resellers must register the product and create a Customer Center account to view and manage devices online.
- Registered Devices page: A page in the Emurasoft Customer Center that lists all devices currently registered for a customer’s licenses and subscriptions.
- Go: A programming language used for server-side logic.
Requirements
This section lists the requirements for the validation system.
Functional
- The validation system should loosely enforce the device limit clause of the license. It must not sacrifice customer satisfaction, and the limit should never come as a surprise to users.
- Registration runs once when the user submits the Register Product dialog box or completes any other registration flow. Validation runs each time EmEditor is opened.
- Registration requires EmEditor to be able to connect to
support.emeditor.com via HTTPS, while validation does not require an internet connection.
- Users should be able to use an offline license that allows the app to register and validate without connecting to our server. If a user encounters errors during normal registration, an offline license should provide an alternative way to register.
- Users’ privacy rights must be maintained. The collection of personal information will be opt-in.
- The system should fit into the existing registration flow and must not introduce an entirely new way to register. Current users should be able to register without having to learn new steps.
- Uninstalling the app should unregister the device.
- Users can log in to the Emurasoft Customer Center to view devices so that devices can be unregistered outside of the app.
- Customers who purchase from resellers other than 2Checkout must register the product and create a Customer Center account, since otherwise there is no way for them to view and manage their devices online.
- The system should be tested in the background in version 23, and should be fully enforced starting with version 24.
- We will start selling subscriptions via Stripe, so the system must be able to integrate with Stripe.
- We will offer registration keys for Stripe subscriptions.
- Users should be able to use EmEditor in a VM environment without having to re-register frequently.
Technical
- The system should be simple so that it is easy to maintain.
- A machine can be identified by its machine ID.
- The machine ID is a combination of several Windows constants used to identify a machine.
- Because these values can uniquely identify a machine, they should be hashed to avoid storing the raw values in plaintext.
- EmEditor Portable can be installed on a USB drive, with its settings stored on that drive. The USB drive can be used on many machines, and the validation system would detect different machine IDs. Therefore, if the app detects that it is a portable version running from a USB drive, registration does not occur.
- EmEditor can be installed per-user on a multi-user machine. All per-user installations of EmEditor on the same machine must be counted as a single device.
- There should be a way for us to override the device limit for a given registration key if necessary.
- A signed token containing the device information should be stored on the user’s device. This associates the current device with the device record stored in the database.
- The system should be designed so that a floating license mechanism can be integrated in the future, if needed.
Output
- You can view a list of all devices on the Registered Devices page of Customer Center.
- If the device limit is reached, a notification will appear. The app will not prevent its use when the device limit is exceeded.

- If the user bought the app from a reseller (not 2Checkout or Stripe) and has not registered the product, a notification will ask the user to register the product.
Device table
The device table is stored in our database and records all devices that were registered. Note that a History record is associated with a purchase and it is where a legacy registration key is stored. A Device record is defined in Go as follows.
type Device struct {
DeviceID string
UserID int
HistoryID sql.NullInt64
StripeSubscriptionID sql.NullString
MachineID MachineID
RegistrationDate time.Time
ValidationDate time.Time
InstallationType InstallationType
Label string
Unregistered bool
}
The fields are explained in the documentation for Registered Devices. The MachineID field is explained below.
Privacy measures for label
The Label field may contain personal information. The Label device field in the Register Product dialog box defaults to {computer name} {user name}. The personal information inside the label field is not necessary for the basic functionality of the app. Therefore, we made the label field opt-in to stick to our policy of privacy by default.
Machine ID
The machine ID is used to identify a machine and is stored in the following structure.
type MachineID struct {
// Identifies a Windows installation
// HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\MachineGuid
MachineGuid string
// Time of Windows installation
// SOFTWARE\Microsoft\Windows NT\CurrentVersion\InstallTime
OSInstallDate string
// Filesystem identifier created when a storage drive is formatted
// Volume serial number from GetVolumeInformationW()
VolumeSerialNumber string
// Name of processor
// HARDWARE\DESCRIPTION\System\CentralProcessor\0\ProcessorNameString
ProcessorName string
// Name of motherboard
// HARDWARE\DESCRIPTION\System\BIOS\BaseBoardManufacturer and HARDWARE\DESCRIPTION\System\BIOS\BaseBoardProduct
MotherboardName string
}
Each field is securely hashed on the client’s machine before the registration request is sent. The hashed machine ID is stored securely in our database with end-to-end encryption. The plaintext identifier values are never transmitted and are not stored on our servers.
Comparing Machine IDs
We use multiple Windows constants to determine whether two machines are the same. Previously, we assumed that the MachineGuid would remain constant for a given machine, but this turned out to be false. A common case where the MachineGuid changes for a single EmEditor installation is when the customer installs the app on a VM drive that is then booted into different Windows installations.
To improve robustness, we use multiple values from the OS that are mostly constant and together help identify a machine. Using the following algorithm, we decide whether two machines are considered the same.
// Returns true if machine a and b are considered to be equal.
// Machines are considered equal if it scores at least 3 points from the following points.
// 3 points: MachineGuid matches
// 2 points: OS install date matches
// 2 points: Volume serial number matches
// 1 point: Processor name matches
// 1 point: Motherboard name matches
func IsMachineIDSame(a, b MachineID) bool {
// Quick check: MachineGuid matches (3 points)
if a.MachineGuid == b.MachineGuid {
return true
}
score := 0
// 2 points: OS install date matches
if a.OSInstallDate == b.OSInstallDate {
score += 2
}
// 2 points: Volume serial number matches
if a.VolumeSerialNumber == b.VolumeSerialNumber {
score += 2
}
// 1 point: Processor name matches
if a.ProcessorName == b.ProcessorName {
score += 1
}
// 1 point: Motherboard name matches
if a.MotherboardName == b.MotherboardName {
score += 1
}
return score >= 3
}
If the MachineGuid is the same, we immediately consider the machines to be the same. Otherwise, we look for a total score of 3 or more points, which corresponds to at least two other matching values. The device count, explained below, uses this logic to determine the number of unique machines.
Before version 24.5, we considered only the MachineGuid when determining whether machines were the same. Some customers using VMs then had a negative experience, quickly reaching the device limit even though they believed they had not registered that often. By considering other constants in addition to the MachineGuid, we help ensure that EmEditor can be used in VM environments without unexpectedly hitting the device limit.
Device count
This section describes how we determine how many devices you can register.
First, we query all devices associated with a given registration key or Stripe subscription ID and filter them to those that are currently registered.
Next, we count the number of unique machines using the logic described above. If two devices have the same machine ID according to IsMachineIDSame, then device count is 1. If two devices have different machine IDs, the device count is 2. If there are multiple devices that are considered to be on the same machine, they may represent per-user installations on the same machine or VM.
The EULA allows the licensee to install EmEditor on up to two devices per license. If EmEditor is for personal use and is not installed on corporate computers, the licensee may install EmEditor on up to five devices per license.
The algorithm to get the maximum device limit for a user will not be publically documented.
Local Device token
A LocalDevice token is stored locally on the user’s device in the form of a JWT (JSON Web Token). It associates the current device with the database Device record. It also allows EmEditor to do some validation even if it is offline. The token payload is defined as follows.
type LocalDevice struct {
DeviceID string
MachineID MachineID
// StripeSubscriptionID is empty if this device is not associated with a subscription.
StripeSubscriptionID string
}
For per-user installations, the token is stored in the registry as LocalDeviceToken in Computer\HKEY_CURRENT_USER\Software\EmSoft\EmEditor v3\Common.
Offline registration
An offline license allows a user to register without an internet connection. Registration only requires a license file.
A customer can request an offline license file. The customer must include their legacy registration key or Stripe order ID in the request. We will reply to the customer’s email address within a few business days with the license file. The license file is a text file that contains a JWT token with the following payload.
type LicenseFile struct {
LicenseID string
UserID int
FullName string
Email string
// Is nil if not a Stripe subscription
StripeSubscriptionID *string
// Is nil if not a registration key
HistoryID *int
}
The offline license token is saved to the registry entry OfflineLicense.
There are three ways that the device limit is enforced and illegal sharing of the license file is prevented. 1) When EmEditor can access the internet, validation is performed. 2) We will only send the license file via email instead of downloading from our website. 3) The Registration Information dialog will display the license owner’s full name and email.
OfflineLicense table
Usage of offline licenses is tracked using the OfflineLicense table. It includes the machine ID to track how many machines used the license and the Revoked flag to allow us to revoke a license.
type OfflineLicense struct {
LicenseID string
UserID int
MachineID MachineID
StripeSubscriptionID sql.NullString
HistoryID sql.NullInt64
// Revoked indicates that this license cannot be used
Revoked bool
}
Registration Information dialog box
Registration Information displays information about the user’s registration. This is useful for knowing what your registration status is and for diagnosing any issues with validation. It also allows the user to edit the device information and to unregister.
The dialog runs validation and shows whether or not it was successful.
Stripe registration keys
We have introduced a new registration key format specifically for Stripe subscriptions, referred to as the “Stripe registration key” in this article. The older format is called the “legacy registration key,” while the term “registration key” is used to encompass both formats.
The Stripe registration key format is as follows:
r-xxxx-xxxx-xxxx-xxxx-xxxx
where x is a base58 character. Each character is generated randomly, which means that one Stripe registration key has 117 bits of entropy.
Registration process
There are four scenarios where the registration process may happen.
- Most users will register through the Register Product dialog box.
- Register using the MSI installer.
- Offline registration using the command line.
- If you unregister a device, then open EmEditor on that device, the device is registered automatically.
There are three online registration flows, depending on whether a legacy registration key is used (RegisterDeviceLegacyRegkey()), a Stripe registration key is used (RegisterDeviceStripeRegkey) or a Stripe subscription is used (RegisterDeviceSubscription()). There is an additional registration flow for offline registration (StoreOfflineLicenseAndValidate()).
In this section, “Client” refers to the local EmEditor app on the user’s machine. “Server” is our backend server and database.
Finding a subscription to use
- If the user signs in, the server tries to find a valid Stripe subscription that has 0 associated devices.
- If no subscription has 0 associated devices, then it tries to find a subscription that has not exceeded the device limit.
- If there is a usable Stripe subscription,
RegisterDeviceSubscription() is called.
- If such Stripe subscription does not exist, it will find a valid legacy registration key that has not exceeded the device limit.
RegisterDeviceLegacyRegkey() is used for legacy registration keys.
Registration with legacy registration key (RegisterDeviceLegacyRegkey())
- If a device token already exists, the client sends an unregister request to the server. The token and registration key are deleted from the registry.
- The client sends a registration request to the server, which includes the legacy registration key, email, machine ID, label, and installation type.
- The server compares the input email with the actual email of the user to make sure they are similar.
- The server gets the device count (defined in the previous section) to determine if the legacy registration key can be used to register the device
- A
Device record is created.
- The client receives the device ID. Using the device ID, the client requests a local device token.
- The server creates and responds with the local device token. The expiration date of the token is set to the legacy registration key expiration date. The client writes the token to local storage.
Registration with Stripe registration key (RegisterDeviceStripeRegkey())
- If a device token already exists, the client sends an unregister request to the server. The token and registration key is deleted from the registry.
- The client sends a registration request to the server, which includes the Stripe registration key, email, machine ID, label, and installation type.
- The server compares the input email with the actual email of the user to make sure they are similar.
- The server verifies that the Stripe subscription is valid.
- The server gets the device count (defined in previous section) to determine if the Stripe registration key can be used to register the device
- A
Device record is created.
- The client receives the device ID. Using the device ID, the client requests a local device token.
- The server creates and responds with the local device token. The expiration of the token is set to one month in the future if the subscription status is active. If the subscription status is canceled, the expiration date is set to the end date of the current billing period. The client writes the token to local storage.
Registration with Stripe subscription (RegisterDeviceSubscription())
- If a device token already exists, the client sends an unregister request to the server. The token and registration key is deleted from the registry.
- The client sends a registration request to the server, which includes the Stripe subscription, machine ID, label, and installation type.
- The server verifies that the Stripe subscription is valid.
- The server queries
deviceCount (defined in previous section) to determine if the Stripe subscription can be used to register the device.
- A
Device record is created.
- The client receives the device ID. Using the device ID, the client requests a local device token.
- The server creates and responds with the local device token. The expiration is set to one month in the future if the subscription status is active. If the subscription status is canceled, the expiration date is set to the end date of the current billing period. The client writes the token to local storage.
Registration with offline license (StoreOfflineLicenseAndValidate())
The user registers an offline license by saving the license file to the filesystem, then running the command line option
/ol "licenseFilePath"
This list outlines the offline registration process.
- Delete the registration key, local device token, and offline license token from the registry.
- Read the license file and save it to the registry.
- Run
ValidateDevice().
Validation process (ValidateDevice())
Validation occurs every time the app is opened.
- If local device token does not exist in the registry, call
ValidateOfflineLicense().
- The token’s signature is validated. The actual machine ID is compared with the machine ID in the token. The result is ignored if the app is running on a removable drive.
- If validation fails due to expected reasons such as a mismatched machine ID, the reason is output as status text.
- For other unexpected errors such as network error, validation succeeds.
- A random number generator determines if validation should stop here. This is to reduce the load of requests to our server.
- The validation function sleeps the thread for a certain duration. This is again to reduce the request load, as we assume that macros and other automated use cases that rapidly start and close the app would only run it for a short duration.
- The client requests the
Device data for the stored device ID.
- If the device is associated with a Stripe subscription, the server verifies that the Stripe subscription is valid.
- If
device.Unregistered == true, the client attempts to register the device.
- The
device.ValidationDate is updated.
- If the token was issued before
current time - 7 days, a new token is created to renew the old token. The new token has an expiration date of one month.
Offline license validation process (ValidateOfflineLicense())
Offline license validation occurs if the registry does not contain the local device token. If an unexpected error occurs, validation succeeds. This means that if the user is offline, validation will still succeed.
- If the offline license token does not exist, validation succeeds. One case where this may happen is if registration previously failed due to a network error but the registration key was valid. This allows EmEditor to be used in this case.
- Read and validate the token.
- Request the server to validate the offline license with the token and machine ID.
- The server validates the token.
- For Stripe subscriptions, the server checks that the subscription has the status
active.
- If an
OfflineLicense entry for the license ID does not exist, it is created with the token data.
- If the entry exists and
license.Revoked == true, it returns StatusLicenseRevoked. Otherwise validation succeeds.
Uninstallation
When you uninstall the desktop version of EmEditor, your device will automatically be unregistered. This makes it easy to install to another machine without having to unregister the previous device manually.
Because the portable and Store App versions do not have an uninstallation process, they will not unregister automatically when you remove those apps. Therefore, if you have a portable or Store App and you are no longer using it on your device, you must manually unregister it from the Registered Devices page in Customer Center.
Security
We are using secure-by-design practices to ensure privacy and to protect against exploits in the validation system. The following lists some of the guiding principles that we used when implementing the system.
-
End-to-end encryption
-
All client-to-server and server-to-server communication uses HTTPS with CA-validated TLS encryption with no insecure fallback.
-
Server-side database records are secured with Azure-managed encryption and secure settings.
-
Token security
-
The local device token and offline license token follow the JWT standard and are signed with ECDSA. This allows client-side authentication without sharing the private key.
-
PII privacy
-
The label option during registration is optional.
-
MachineID fields are securely hashed on the client side before being encrypted and transmitted. The plaintext contents of these fields are never transmitted or stored on our servers.
-
Client-side logs are not persisted. Server-side logs contain minimal data about requests and do not include request body content such as the registration fields.
Support
If you have any questions or feedback about the validation system, feel free to send us a message.
Avoid Illegitimate License Sellers
/in General/by Yutaka EmuraDear EmEditor Users,
As the developer of EmEditor, I urgently need to address a growing concern in our community: the sale of pirated or invalid licenses. It has been noted that such licenses are being offered at significantly discounted prices on various online platforms, including auction sites. Please be aware that if you encounter an EmEditor license at a price that seems too good to be true, it is almost certainly from an illegal source. These offers are not only illegal but also pose significant risks to users. I strongly urge you to refrain from purchasing these licenses.
Why Avoid Illegitimate Licenses:
The Benefits of Genuine Licenses:
How to Ensure Your License is Genuine:
Purchase your EmEditor license directly from our official website or through authorized resellers. If you have any doubts about the authenticity of a license, please contact us for verification before completing your purchase.
Your Action Matters:
By choosing genuine licenses, you’re not only ensuring a seamless and secure experience but also supporting the ongoing development and improvement of EmEditor.
We take this issue very seriously and are actively working to combat the sale of these illegal licenses. Your awareness and cooperation are vital in this effort.
Thank you for being a vital part of the EmEditor community.
Sincerely,
Yutaka Emura
Developer of EmEditor
See also: Warning Against Unauthorized Usage – Crack, Keygen, Serial, etc.
EmEditor v24.1.0 Released (Including Technical Review)
/in EmEditor Core/by Yutaka EmuraToday, we are releasing EmEditor v24.1.0.
In version 24.1, we have added support for the new context menu in Windows 11 Explorer. With Windows 11, the design of the context menu has been revamped compared to Windows 10 and earlier versions, necessitating special handling for apps to support this change. EmEditor is now compatible with the Windows 11 context menu, enabling you to directly select the Edit in EmEditor command. Additionally, when right-clicking on a folder or the background, the Find in Files with EmEditor command becomes available. To use this feature, the EmEditor tray icon must be displayed in the notification area of the taskbar, and it is supported only when running the desktop installer version on Windows 11. This feature is accessible in both the EmEditor Professional and EmEditor Free versions.
Another significant feature added in the new Professional version is the enhancement of AI capabilities. Version 24.0 introduced AI macros using the OpenAI API (hereafter abbreviated as “API”). Version 24.1 introduces an AI assisted writing feature that predicts and autocompletes what you are typing next while composing text. AI autocomplete can reduce typing effort and improve writing speed. I am writing this text using EmEditor and am personally experiencing the convenience of the AI assisted writing feature.
By default, the AI functionality is disabled. To enable this feature, you need to check the Enable AI option on the AI page of the Customize dialog box in EmEditor, and agree to allow OpenAI to process the text data within documents opened in EmEditor. Please read OpenAI’s Privacy Policy, and if you agree, click the Continue button. According to this privacy policy, data sent to the API will not be used for training OpenAI’s models.
Next, enter your API key in the OpenAI API Key text box. If you are logged into OpenAI, you can obtain your API key here. It is recommended to store the API key in the ‘OPENAI_API_KEY‘ environment variable, but if you use the portable version of EmEditor or do not wish to share the key with other apps because you are sharing the computer, you can disable the Use “OPENAI_API_KEY” environment variable option and save the API key exclusively for EmEditor. By default, gpt-4-turbo-preview is the preferred model. It offers more accurate suggestions than gpt-3.5-turbo. For writing in foreign languages, selecting gpt-4-turbo-preview is advisable. Also, to enable this feature, you must activate the AI assisted writing option on the General page of each configuration properties. It is enabled by default for Text, Markdown, and HTML configurations.
When this feature is enabled, as you type, AI will automatically predict and suggest the next text. The suggested text appears in gray by default, and you can accept the suggestion by pressing the Tab or End key. If you want to accept only part of the suggested text, press the Right arrow key for the number of characters to accept, or Ctrl+Right to accept one word. Pressing the Delete key will remove the first character of the suggested text. Pressing the Esc key or another key cancels the suggestion. Moreover, if you want to force a prediction by AI when no suggested text is displayed, or request a different suggestion, press Ctrl+Space.
Simply opening a file in EmEditor does not call the API. It only starts calling the API when you begin typing characters. Moreover, the following conditions must all be met to utilize this functionality:
As described above, we aim to minimize the frequency of API usage. However, using the API still incurs a fee payable to OpenAI, calculated in tokens. Each suggestion consumes about 100 tokens for input and about 10 tokens for output. According to current pricing, using the default gpt-4-turbo-preview model consumes approx. US$0.0013 per instance. Opting for gpt-3.5-turbo significantly reduces the cost to approx. US$0.000065 per instance. For reference, using ChatGPT Plus provided by the same company incurs a monthly fee of US$20 or more, but if you only use the API with EmEditor, you don’t need to pay for ChatGPT Plus. Using AI with EmEditor is unlikely to amount to US$20 a month, making it an economically viable option. Using the AI macro introduced in v24.0, you can ask EmEditor any free-form questions just like with ChatGPT Plus, making it possible to completely replace ChatGPT Plus with EmEditor.
Furthermore, this version responds to customer requests.
1. The hexadecimal characters used for IPv6 addresses in highlight and sorting commands were only recognized in lowercase in previous versions. This was because RFC 5952 recommends writing IPv6 addresses in lowercase. However, based on feedback from a customer indicating that both uppercase and lowercase letters may be mixed, we now support uppercase letters as well.
2. The CommitList plugin has been improved with the addition of the Delete Remote Branch command.
I hope you like EmEditor, whether you use the Professional or Free version. Please contact us or write in forums if you have any questions, feature requests, or any ideas in the future.
Thank you for using EmEditor!
— Yutaka Emura
Please see EmEditor v24.1 New Features for details and screenshots.
If you use the Desktop Installer version, you can select Check for Updates on the Help menu to download the newest version. If this method fails, please download the newest version, and run the downloaded installer. If you use the Desktop portable version, you can go to the Download page to download the newest version. The Store App versions can be updated through Microsoft Store (64-bit or 32-bit) after a few days.
EmEditor was reviewed in Mado-no-mori
/in Reviews/by Yutaka EmuraA Revolutionary Text Editor Assisted by Generative AI is Here! Achieved with EmEditor Macros
– An In-depth Explanation of Macro Processing! Achieve a Kansai Dialect Conversion Feature with Extreme Modification!
EmEditor v24.0.1 released
/in EmEditor Core/by Yutaka EmuraToday, we are releasing EmEditor v24.0.1.
v24.0.1 includes the following bug fixes.
If you use the Desktop Installer version, you can select Check for Updates on the Help to download the newest version. If this method fails, please download the newest version, and run the downloaded installer. If you use the Desktop portable version, you can go to the Download page to download the newest version. The Store App versions can be updated through Microsoft Store (64-bit or 32-bit) after a few days.
EmEditor v24.0.0 released (including technical review)
/in EmEditor Core/by Yutaka EmuraToday, we are releasing EmEditor v24.0.0.
In the previous version, v23.1, we introduced how to use generative AI by calling OpenAI‘s API from macros. Typically, text is used as an argument for invoking generative AI, which suggests a high affinity between text editors and generative AI. When writing documents in a text editor, one of the purposes of using generative AI is to proofread the document. In this use case, you would want to easily compare the document before and after proofreading to easily decide which parts of the changed text to keep or discard. In this version, we added a “Copy to Other” command to the context menu that appears when right-clicking on the changed text while comparing documents in a split window. Selecting this will copy the changed part to the other document being compared. If you want to copy all changes in the document at once, click the “Copy All to Other” button newly added at the title part of the split window.
After the comparison is done, you may want to close unnecessary documents and keep only the needed ones. In such cases, you can now close only the document in the currently active pane by clicking the newly added [X (Close)] button or pressing Ctrl+W or Ctrl+F4.
We further developed the library’s
ChatOpenAI.jseemacro example and added it to EmEditor by default under the name AI.jsee. By using the AI macro, you can perform proofreading, summarization, translation, generate images, or ask questions to AI for selected text or the entire document. When you run this macro for the first time, you will be prompted to enter your OpenAI API key. If you are logged into OpenAI, you can get your secrect OpenAI API key by visiting here. To skip entering this key in the future, please set the environment variableOPENAI_API_KEY.In this version, we have also responded to many requests from our customers.
1. Onigmo regular expressions now support the
\Q...\Esyntax. This syntax allows you to disable regular expression metacharacters without needing to escape them. For example, to search for the string[a.c], the conventional regular expression would require you to escape the metacharacters"[", ".", "]"with backslashes,\[a\.c\]. In the new version, you can simply write\Q[a.c]\E, eliminating the need to escape metacharacters. Note that Boost‘s Regex has supported the\Q...\Esyntax for some time.2. We added an option to the Find Next and Find Previous commands that only matches non-overlapping strings. For example, if you search for “AA” in the string “AAAAA”, initially only the first four characters, “AAAA”, are highlighted. When you execute the Find Next (F3) command, the search position shifts one character at a time, allowing you to search through all the “AA” pairs. With this version, setting the Find only non-overlapping strings in Find Next/Previous checkbox in the Advanced dialog box makes the command operate in a way that only non-overlapping strings match, ending the search leaving the last “A” unsearched, thus aligning the highlight with the search position.
3. In EmEditor, URI and email addresses are highlighted, and we frequently receive requests to extract just those parts. In previous versions, this could be done by specifying an appropriate regular expression in the Find dialog and selecting Extract, but many of our customers are not familiar with regular expressions. In this version, you can easily extract just the URIs or email addresses by specifying options in the Extract Frequent Strings command.
4. When opening a CSV in EmEditor, the delimiter positions are automatically adjusted by default. However, very long cells can cause the column width to become very wide, making the entire CSV hard to view. In this version, we added a Maximum column width textbox to the CSV Options page of the Customize dialog, allowing you to specify the maximum column width.
5. In the previous version, EmEditor started displaying a warning message when a file opened in it was deleted by another application. In this version, you can choose whether or not to display the warning message. It can be specified on the File page of the Configuration Properties via the Prompt if file deleted checkbox.
6. Some customers have reported slow startup times for EmEditor on recent versions of Windows 11. This is primarily due to the retrieval of the Windows Clipboard History during startup. The new version has this option disabled by default, but it can be enabled on the Clipboard page of the Customize dialog.
7. The new version disables the Switch to no wrap option in the Compare Files wizard by default.
Furthermore, in this version, we have significantly optimized commands like Split a File, Combine Files, Increase Line Indent, Decrease Line Indent, achieving a speed increase of 27 to 124 times compared to v23.1, according to our tests.
As announced by Makoto Emura on his blog, starting from this version, a warning message may appear if you use EmEditor Professional on more devices than allowed by the EULA (end-user license agreement). To maintain our lower license fees and ensure fairness among customers who have purchased multiple licenses, please purchase enough licenses to follow the terms of the license.
Uninstalling EmEditor unregisters the device, allowing you to install it on a different device. You can view your registered devices here. We have unregistered all devices when v24.0.0 was released so that old devices will be unregistered. When you use EmEditor, the device will automatically be registered.
I hope you like EmEditor, whether you use the Professional or Free version. Please contact us or write in forums if you have any questions, feature requests, or any ideas in the future.
Thank you for using EmEditor!
— Yutaka Emura
Please see EmEditor v24.0 New Features for details and screenshots.
If you use the Desktop Installer version, you can select Check for Updates on the Help menu to download the newest version. If this method fails, please download the newest version, and run the downloaded installer. If you use the Desktop portable version, you can go to the Download page to download the newest version. The Store App versions can be updated through Microsoft Store (64-bit or 32-bit) after a few days.
EmEditor v23.1.3 released
/in EmEditor Core/by Yutaka EmuraToday, we are releasing EmEditor v23.1.3.
v23.1.3 includes the following bug fixes.
Please see EmEditor v23.1 New Features for details and screenshots.
If you use the Desktop Installer version, you can select Check for Updates on the Help to download the newest version. If this method fails, please download the newest version, and run the downloaded installer. If you use the Desktop portable version, you can go to the Download page to download the newest version. The Store App versions can be updated through Microsoft Store (64-bit or 32-bit) after a few days.
New Validation System Explained
/in General/by Makoto EmuraIn version 24.0.0, we introduced a registration validation system to improve the already existing registration system. This validation system is able to track the number of devices a customer has registered EmEditor on.
This page aims to be transparent about our motivations and to document how the validation system works. If we update the validation system in the future, we will also update this page.
Motivation
In the past, there was no way for us to detect users who were sharing their licenses with multiple people or using their licenses on more devices than allowed by the EULA (End-User License Agreement). We would like customers to purchase enough licenses to follow the terms of the license. This would ensure fairness among customers who have purchased multiple licenses and help us keep delivering a quality product.
Terminology
Requirements
This section lists the requirements for the validation system.
Functional
support.emeditor.comvia HTTPS, while validation does not require an internet connection.Technical
Output
Device table
The device table is stored in our database and records all devices that were registered. Note that a
Historyrecord is associated with a purchase and it is where a legacy registration key is stored. ADevicerecord is defined in Go as follows.type Device struct { DeviceID string UserID int HistoryID sql.NullInt64 StripeSubscriptionID sql.NullString MachineID MachineID RegistrationDate time.Time ValidationDate time.Time InstallationType InstallationType Label string Unregistered bool }The fields are explained in the documentation for Registered Devices. The
MachineIDfield is explained below.Privacy measures for label
The
Labelfield may contain personal information. The Label device field in the Register Product dialog box defaults to{computer name} {user name}. The personal information inside the label field is not necessary for the basic functionality of the app. Therefore, we made the label field opt-in to stick to our policy of privacy by default.Machine ID
The machine ID is used to identify a machine and is stored in the following structure.
type MachineID struct { // Identifies a Windows installation // HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\MachineGuid MachineGuid string // Time of Windows installation // SOFTWARE\Microsoft\Windows NT\CurrentVersion\InstallTime OSInstallDate string // Filesystem identifier created when a storage drive is formatted // Volume serial number from GetVolumeInformationW() VolumeSerialNumber string // Name of processor // HARDWARE\DESCRIPTION\System\CentralProcessor\0\ProcessorNameString ProcessorName string // Name of motherboard // HARDWARE\DESCRIPTION\System\BIOS\BaseBoardManufacturer and HARDWARE\DESCRIPTION\System\BIOS\BaseBoardProduct MotherboardName string }Each field is securely hashed on the client’s machine before the registration request is sent. The hashed machine ID is stored securely in our database with end-to-end encryption. The plaintext identifier values are never transmitted and are not stored on our servers.
Comparing Machine IDs
We use multiple Windows constants to determine whether two machines are the same. Previously, we assumed that the MachineGuid would remain constant for a given machine, but this turned out to be false. A common case where the MachineGuid changes for a single EmEditor installation is when the customer installs the app on a VM drive that is then booted into different Windows installations.
To improve robustness, we use multiple values from the OS that are mostly constant and together help identify a machine. Using the following algorithm, we decide whether two machines are considered the same.
// Returns true if machine a and b are considered to be equal. // Machines are considered equal if it scores at least 3 points from the following points. // 3 points: MachineGuid matches // 2 points: OS install date matches // 2 points: Volume serial number matches // 1 point: Processor name matches // 1 point: Motherboard name matches func IsMachineIDSame(a, b MachineID) bool { // Quick check: MachineGuid matches (3 points) if a.MachineGuid == b.MachineGuid { return true } score := 0 // 2 points: OS install date matches if a.OSInstallDate == b.OSInstallDate { score += 2 } // 2 points: Volume serial number matches if a.VolumeSerialNumber == b.VolumeSerialNumber { score += 2 } // 1 point: Processor name matches if a.ProcessorName == b.ProcessorName { score += 1 } // 1 point: Motherboard name matches if a.MotherboardName == b.MotherboardName { score += 1 } return score >= 3 }If the MachineGuid is the same, we immediately consider the machines to be the same. Otherwise, we look for a total score of 3 or more points, which corresponds to at least two other matching values. The device count, explained below, uses this logic to determine the number of unique machines.
Before version 24.5, we considered only the MachineGuid when determining whether machines were the same. Some customers using VMs then had a negative experience, quickly reaching the device limit even though they believed they had not registered that often. By considering other constants in addition to the MachineGuid, we help ensure that EmEditor can be used in VM environments without unexpectedly hitting the device limit.
Device count
This section describes how we determine how many devices you can register.
First, we query all devices associated with a given registration key or Stripe subscription ID and filter them to those that are currently registered.
Next, we count the number of unique machines using the logic described above. If two devices have the same machine ID according to
IsMachineIDSame, then device count is 1. If two devices have different machine IDs, the device count is 2. If there are multiple devices that are considered to be on the same machine, they may represent per-user installations on the same machine or VM.The EULA allows the licensee to install EmEditor on up to two devices per license. If EmEditor is for personal use and is not installed on corporate computers, the licensee may install EmEditor on up to five devices per license.
The algorithm to get the maximum device limit for a user will not be publically documented.
Local Device token
A
LocalDevicetoken is stored locally on the user’s device in the form of a JWT (JSON Web Token). It associates the current device with the databaseDevicerecord. It also allows EmEditor to do some validation even if it is offline. The token payload is defined as follows.type LocalDevice struct { DeviceID string MachineID MachineID // StripeSubscriptionID is empty if this device is not associated with a subscription. StripeSubscriptionID string }For per-user installations, the token is stored in the registry as
LocalDeviceTokeninComputer\HKEY_CURRENT_USER\Software\EmSoft\EmEditor v3\Common.Offline registration
An offline license allows a user to register without an internet connection. Registration only requires a license file.
A customer can request an offline license file. The customer must include their legacy registration key or Stripe order ID in the request. We will reply to the customer’s email address within a few business days with the license file. The license file is a text file that contains a JWT token with the following payload.
type LicenseFile struct { LicenseID string UserID int FullName string Email string // Is nil if not a Stripe subscription StripeSubscriptionID *string // Is nil if not a registration key HistoryID *int }The offline license token is saved to the registry entry
OfflineLicense.There are three ways that the device limit is enforced and illegal sharing of the license file is prevented. 1) When EmEditor can access the internet, validation is performed. 2) We will only send the license file via email instead of downloading from our website. 3) The Registration Information dialog will display the license owner’s full name and email.
OfflineLicense table
Usage of offline licenses is tracked using the
OfflineLicensetable. It includes the machine ID to track how many machines used the license and theRevokedflag to allow us to revoke a license.type OfflineLicense struct { LicenseID string UserID int MachineID MachineID StripeSubscriptionID sql.NullString HistoryID sql.NullInt64 // Revoked indicates that this license cannot be used Revoked bool }Registration Information dialog box
Registration Information displays information about the user’s registration. This is useful for knowing what your registration status is and for diagnosing any issues with validation. It also allows the user to edit the device information and to unregister.
The dialog runs validation and shows whether or not it was successful.
Stripe registration keys
We have introduced a new registration key format specifically for Stripe subscriptions, referred to as the “Stripe registration key” in this article. The older format is called the “legacy registration key,” while the term “registration key” is used to encompass both formats.
The Stripe registration key format is as follows:
where
xis a base58 character. Each character is generated randomly, which means that one Stripe registration key has 117 bits of entropy.Registration process
There are four scenarios where the registration process may happen.
There are three online registration flows, depending on whether a legacy registration key is used (
RegisterDeviceLegacyRegkey()), a Stripe registration key is used (RegisterDeviceStripeRegkey) or a Stripe subscription is used (RegisterDeviceSubscription()). There is an additional registration flow for offline registration (StoreOfflineLicenseAndValidate()).In this section, “Client” refers to the local EmEditor app on the user’s machine. “Server” is our backend server and database.
Finding a subscription to use
RegisterDeviceSubscription()is called.RegisterDeviceLegacyRegkey()is used for legacy registration keys.Registration with legacy registration key (RegisterDeviceLegacyRegkey())
Devicerecord is created.Registration with Stripe registration key (RegisterDeviceStripeRegkey())
Devicerecord is created.Registration with Stripe subscription (RegisterDeviceSubscription())
deviceCount(defined in previous section) to determine if the Stripe subscription can be used to register the device.Devicerecord is created.Registration with offline license (StoreOfflineLicenseAndValidate())
The user registers an offline license by saving the license file to the filesystem, then running the command line option
This list outlines the offline registration process.
ValidateDevice().Validation process (ValidateDevice())
Validation occurs every time the app is opened.
ValidateOfflineLicense().Devicedata for the stored device ID.device.Unregistered == true, the client attempts to register the device.device.ValidationDateis updated.current time - 7 days, a new token is created to renew the old token. The new token has an expiration date of one month.Offline license validation process (ValidateOfflineLicense())
Offline license validation occurs if the registry does not contain the local device token. If an unexpected error occurs, validation succeeds. This means that if the user is offline, validation will still succeed.
active.OfflineLicenseentry for the license ID does not exist, it is created with the token data.license.Revoked == true, it returnsStatusLicenseRevoked. Otherwise validation succeeds.Uninstallation
When you uninstall the desktop version of EmEditor, your device will automatically be unregistered. This makes it easy to install to another machine without having to unregister the previous device manually.
Because the portable and Store App versions do not have an uninstallation process, they will not unregister automatically when you remove those apps. Therefore, if you have a portable or Store App and you are no longer using it on your device, you must manually unregister it from the Registered Devices page in Customer Center.
Security
We are using secure-by-design practices to ensure privacy and to protect against exploits in the validation system. The following lists some of the guiding principles that we used when implementing the system.
Support
If you have any questions or feedback about the validation system, feel free to send us a message.
EmEditor v23.1.2 released
/in EmEditor Core/by Yutaka EmuraToday, we are releasing EmEditor v23.1.2.
v23.1.2 includes the following bug fixes.
Please see EmEditor v23.1 New Features for details and screenshots.
If you use the Desktop Installer version, you can select Check for Updates on the Help to download the newest version. If this method fails, please download the newest version, and run the downloaded installer. If you use the Desktop portable version, you can go to the Download page to download the newest version. The Store App versions can be updated through Microsoft Store (64-bit or 32-bit) after a few days.
EmEditor v23.1.1 released
/in EmEditor Core/by Yutaka EmuraToday, we are releasing EmEditor v23.1.1.
v23.1.1 includes the following bug fixes.
If you use the Desktop Installer version, you can select Check for Updates on the Help to download the newest version. If this method fails, please download the newest version, and run the downloaded installer. If you use the Desktop portable version, you can go to the Download page to download the newest version. The Store App versions can be updated through Microsoft Store (64-bit or 32-bit) after a few days.
EmEditor v23.1.0 released (including technical review)
/in EmEditor Core/by Yutaka EmuraToday, we are releasing EmEditor v23.1.0.
In the previous version (v23.0), we introduced how to access the web page of the generated AI using macros and the built-in Web Browser in EmEditor and obtain various information and services. However, customers who have a paid API key for the generated AI site can obtain faster, higher-quality services with more stable operation by directly calling the API. To do this, the fetch function in JavaScript is used, but since this function operates asynchronously, the return value of the function may not be obtained before the macro ends. Actually, even in v23.0, it was possible to use this method if the built-in Web Browser in EmEditor was displayed, but there was a problem that async functions could not be used if the Web Browser was not displayed. In this new version (v23.1), by using the KeepRunning property, it is now possible to wait for the completion of the async function without ending the macro (EmEditor Professional only). Before calling the async function, specify the KeepRunning property as follows.
This keeps the macro running, allowing you to obtain the return value of the async function. To end the macro after obtaining the return value of the async function, you can specify it as follows:
This is almost equivalent to Quit() when waiting for the completion of async functions, and the macro ends immediately.
Below is a sample macro using the fetch function to utilize the OpenAI API. To run this sample macro, you need to replace {your-API-key} with your API key. When you run the following macro, it sends the question “How are you?” to the OpenAI API and displays the answer in the output bar.
The CharOpenAI.jsee macro example further extends this sample by displaying a popup menu of commonly used questions (“Proofread”, “Summarize”, “Look up”, “Translate”…) for the currently selected text or entire document. When a question is selected, it sends the question to the OpenAI API and displays the answer in the output bar.
Actually, I am using the CharOpenAI.jsee macro to translate and proofread while writing this blog. By combining the generated AI with a text editor, I have been able to significantly improve my work efficiency.
Another major change in v23.1 is the speed improvement when handling large files. In v23.0, changes to lines were stored in memory instead of temporary files for faster operation. However, in systems with limited memory, this could result in slowness or errors due to insufficient system memory. In v23.1, the memory-related algorithms have been revised to operate more efficiently. Additionally, when virtual memory becomes insufficient, it now uses temporary files to store data. As a result, users no longer need to worry about the size of virtual memory, and the frequency of crashes due to memory shortage has been significantly reduced. The improvements in code related to memory, as well as the use of multi-threading and the SIMD instruction set, have resulted in a speed increase of 1.51 to 41.2 times faster than v23.0 for many commands when editing huge files, including CSV files.
The Help feature now defaults to using an external browser instead of EmEditor’s built-in Web Browser, similar to v22.5 and earlier versions. Furthermore, the Help page has been added to the Customize dialog box, allowing users to change settings related to Help.
Lastly, Makoto Emura added the Completion List feature using the Language Server Protocol (LSP). To utilize this feature, the Language Server Protocol must be enabled in the Language Server page of configuration properties, and the Show completion list option is also enabled (EmEditor Professional only). Currently, only JavaScript supports this feature.
I hope you like EmEditor, whether you use the Professional or Free version. Please contact us or write in forums if you have any questions, feature requests, or any ideas in the future.
Thank you for using EmEditor!
— Yutaka Emura
Please see EmEditor v23.1 New Features for details and screenshots.
This release also includes all bug fixes while developing v23.1.
If you use the Desktop Installer version, you can select Check for Updates on the Help to download the newest version. If this method fails, please download the newest version, and run the downloaded installer. If you use the Desktop portable version, you can go to the Download page to download the newest version. The Store App versions can be updated through Microsoft Store (64-bit or 32-bit) after a few days.