Repository navigation
Add the rekey command; fix clone encryption of nested fields and custom collection names - #112
Merged
travist merged 4 commits intoOct 28, 2026
Conversation
- Re-encrypt encrypted fields within the rows of a datagrid or editgrid. The encrypted paths were looked up as flat paths (data.grid.field) against array data, so those values silently kept the source secret. The form is now walked against the submission data itself. - Name custom submission collections the way the server does, with everything but letters and digits stripped from the project and collection names. Projects with a dash in their name had their submissions cloned where the server never reads them. - Clone the revisions of a custom collection from and to its <collection>_revisions collection instead of submissionrevisions. - Warn when the destination still holds submissions in a collection an earlier clone misnamed. - Move the crypto helpers to src/encryption.js and the connection helpers to src/db.js. decrypt() no longer logs every failed attempt. - Remove src/eachComponentAsync.js, which is no longer used. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Re-encrypt the project settings and encrypted submission data of a
database with a new DB_SECRET, for example after a clone was run with
the wrong --dst-db-secret.
formio rekey <mongo_url> --new-db-secret NEW \
--old-db-secret OLD1 [--old-db-secret OLD2] [--dry-run]
- Settings are re-encrypted with the new DB_SECRET. Field values are
re-encrypted with the project's own secret when it has one, otherwise
with the new DB_SECRET, the same way the server picks the key.
- Each value is first tried with its target secret and left alone when
it already opens, so the command can be re-run until nothing is left.
Otherwise every old secret is tried, and the re-encrypted value is
read back before it is written.
- Covers fields within datagrid and editgrid rows and containers,
custom submission collections, and submission revisions (unless
--no-submission-revisions).
- Writes only apply when the stored ciphertext is unchanged since it
was read, so a value edited mid-run is never overwritten.
- Values no secret can open, and projects whose settings cannot be
decrypted, are reported and left as they are, and the command exits
with an error.
The server's own DB_SECRET_OLD rotation is not a substitute: it misses
nested values, skips falsy values and revisions, and runs its field
updates without awaiting them.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
travist
force-pushed
the
feat/rekey-command
branch
from
October 24, 2026 19:29
ce6f561 to
2447000
Compare
…y-command Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- rekey kept the projects and forms cursors open while it re-keyed the submissions of each form. On a large database the server closes an idle cursor, and the rekey stopped part way. It now lists the ids first and reads each project and form on its own. - rekey never re-keyed the revisions of a custom collection that earlier clones wrote to the default submissionrevisions collection. It now re-keys them where they are and says so. - Encrypted values an API returns as JSON serialized Buffers were skipped with no message when cloning from an API source. They are now read and re-encrypted like any other encrypted value. - An absolute --ca or --cert path was prefixed with the working directory. - idList (which now ignores repeated ids) and the legacy collection name live in src/db.js, shared by Cloner and Rekeyer. - Removed the encrypt/decrypt/legacyKey wrappers and defaultSaltLength from Cloner, which call src/encryption.js directly. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
travist
merged commit Oct 28, 2026
5c1d92e
into
improve-clone-performance-and-bug-fixes
1 check failed
travist
added a commit
that referenced
this pull request
Oct 28, 2026
…-fixes Bring the rekey command (#112) into master
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #111. Retarget to
masteronce #111 merges.Why
A customer database was cloned with the wrong
--dst-db-secret, leaving project settings (and possibly encrypted fields) under a key the destination server does not use. There was no safe way to re-encrypt a database in place. Looking into it turned up two clone bugs.Changes
formio rekey(new command)projects.settings_encryptedwith the new DB_SECRET. Encrypted field values are re-encrypted with the project's ownsettings.secretwhen it has one, otherwise with the new DB_SECRET, which is how the server picks the key.--old-db-secretis tried in turn, and the re-encrypted value is read back before writing.--no-submission-revisions). Deleted documents are included.The server's built-in
DB_SECRET_OLDrotation (src/util/updateSecret.jsin formio-server) isn't a substitute. It readsproject.settings.secretfrom the raw document, where it is always undefined. It also misses nested values, skips falsy values and revisions, and fires its field updates without awaiting them.Clone fixes
data.grid.fieldwere looked up against array data, found nothing, and those values silently kept the source secret. The form is now walked against the submission data itself.myproject_records). The clone used the raw names (my-project_records), so for projects with symbols in their name, submissions landed where the server never reads them. The clone now uses the server's naming and warns when the destination still holds submissions in a misnamed collection.submissionrevisionsinstead of<collection>_revisions.Refactoring
src/encryption.jsand the connection helpers tosrc/db.js.decrypt()no longer logs every failed attempt, whichrekeywould trigger once per wrong key.src/eachComponentAsync.js, which is now unused.Testing
test/cloner/rekey.js(19 tests): value walking, dry run, full re-key including nested, revision and custom-collection values, re-run idempotency, project-secret targeting,--projectfiltering, undecryptable settings and values,--no-submission-revisions, and the concurrent-change guard.rekey.mocha test/cloner/index.js: 269 passing.yarn test:cli: 16 passing. Each commit passes on its own.🤖 Generated with Claude Code