@better-update/cli 0.29.0 → 0.29.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.mjs +121 -54
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -34,7 +34,7 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
|
34
34
|
|
|
35
35
|
//#endregion
|
|
36
36
|
//#region package.json
|
|
37
|
-
var version = "0.29.
|
|
37
|
+
var version = "0.29.2";
|
|
38
38
|
|
|
39
39
|
//#endregion
|
|
40
40
|
//#region src/lib/interactive-mode.ts
|
|
@@ -18926,15 +18926,6 @@ const grantRecipient = (args) => Effect.gen(function* () {
|
|
|
18926
18926
|
} });
|
|
18927
18927
|
});
|
|
18928
18928
|
/**
|
|
18929
|
-
* Resolve the passphrase needed to unlock the active identity before a crypto
|
|
18930
|
-
* operation: prompt for it when the identity is the on-disk file, or return
|
|
18931
|
-
* `undefined` when the raw `BETTER_UPDATE_IDENTITY` env key is in use (CI). The
|
|
18932
|
-
* resolved value is threaded into {@link unlockVaultKey} by the cipher helpers.
|
|
18933
|
-
*/
|
|
18934
|
-
const resolveVaultPassphrase = Effect.gen(function* () {
|
|
18935
|
-
return (yield* activeRecipient).source === "file" ? yield* promptPassword("Passphrase to unlock this device's identity:") : void 0;
|
|
18936
|
-
});
|
|
18937
|
-
/**
|
|
18938
18929
|
* Unlock the org vault key for an interactive command, reusing a cached vault key
|
|
18939
18930
|
* from the OS keychain when one is present and unexpired — so the device
|
|
18940
18931
|
* passphrase is prompted at most once per cache TTL rather than on every command
|
|
@@ -18942,6 +18933,12 @@ const resolveVaultPassphrase = Effect.gen(function* () {
|
|
|
18942
18933
|
* The CI `BETTER_UPDATE_IDENTITY` key carries no passphrase and is never cached:
|
|
18943
18934
|
* it skips straight to the raw unwrap. On a cache miss the full unlock runs —
|
|
18944
18935
|
* prompt, Argon2id, fetch + unwrap — and the result is cached for next time.
|
|
18936
|
+
*
|
|
18937
|
+
* The cached key is the unwrapped vault key, which both unwraps (decrypt/read)
|
|
18938
|
+
* and wraps (encrypt/write) DEKs — so this single entry point backs every vault
|
|
18939
|
+
* operation: download/build-resolve reads, seal-for-upload + generate writes, and
|
|
18940
|
+
* rotation. There is no read-only cache: an unlock makes the next write seamless
|
|
18941
|
+
* too.
|
|
18945
18942
|
*/
|
|
18946
18943
|
const unlockVaultKeyInteractive = (api) => Effect.gen(function* () {
|
|
18947
18944
|
const recipient = yield* activeRecipient;
|
|
@@ -18953,6 +18950,17 @@ const unlockVaultKeyInteractive = (api) => Effect.gen(function* () {
|
|
|
18953
18950
|
yield* cache.set(recipient.publicKey, vault);
|
|
18954
18951
|
return vault;
|
|
18955
18952
|
}).pipe(Effect.provide(VaultCacheLive));
|
|
18953
|
+
/**
|
|
18954
|
+
* Forget the active recipient's cached vault key. Called after a rotation re-keys
|
|
18955
|
+
* the vault: the cached key + version are now stale, so leaving them would make
|
|
18956
|
+
* the next seal upload a key/version the server CAS-rejects (and the next decrypt
|
|
18957
|
+
* fail integrity). Clearing forces a fresh unlock at the new version next time —
|
|
18958
|
+
* which also correctly locks out a device that just revoked its own access.
|
|
18959
|
+
*/
|
|
18960
|
+
const forgetCachedVaultKey = Effect.gen(function* () {
|
|
18961
|
+
const recipient = yield* activeRecipient;
|
|
18962
|
+
yield* (yield* VaultCache).clear(recipient.publicKey);
|
|
18963
|
+
}).pipe(Effect.provide(VaultCacheLive));
|
|
18956
18964
|
/** Look up a registered recipient by its key id or full `SHA256:` fingerprint. */
|
|
18957
18965
|
const findRecipient = (api, selector) => Effect.gen(function* () {
|
|
18958
18966
|
const { items } = yield* api.userEncryptionKeys.list();
|
|
@@ -18992,13 +19000,6 @@ const getActiveOrgId = (api) => Effect.gen(function* () {
|
|
|
18992
19000
|
if (me.activeOrganization === null) return yield* new IdentityError({ message: "No active organization for this token." });
|
|
18993
19001
|
return me.activeOrganization.id;
|
|
18994
19002
|
});
|
|
18995
|
-
/** Resolve the active org id and unlock this device's vault key — the once-per-command I/O. */
|
|
18996
|
-
const openVaultSession = (api, passphrase) => Effect.gen(function* () {
|
|
18997
|
-
return {
|
|
18998
|
-
orgId: yield* getActiveOrgId(api),
|
|
18999
|
-
vault: yield* unlockVaultKey(api, passphrase)
|
|
19000
|
-
};
|
|
19001
|
-
});
|
|
19002
19003
|
/**
|
|
19003
19004
|
* {@link openVaultSession} that unlocks the vault key interactively — reusing the
|
|
19004
19005
|
* OS-keychain-cached key when one is live (no prompt), prompting for the device
|
|
@@ -19129,6 +19130,43 @@ const openFromDownload = (args) => {
|
|
|
19129
19130
|
//#region src/lib/android-keystore.ts
|
|
19130
19131
|
const DEFAULT_KEYSTORE_VALIDITY_DAYS = 1e4;
|
|
19131
19132
|
const renderDistinguishedName = (params) => `CN=${params.commonName}, O=${params.organization}`;
|
|
19133
|
+
const FINGERPRINT_PATTERNS = {
|
|
19134
|
+
md5: /MD5:\s*(?<value>[0-9A-F:]+)/iu,
|
|
19135
|
+
sha1: /SHA-?1:\s*(?<value>[0-9A-F:]+)/iu,
|
|
19136
|
+
sha256: /SHA-?256:\s*(?<value>[0-9A-F:]+)/iu
|
|
19137
|
+
};
|
|
19138
|
+
/**
|
|
19139
|
+
* Parse certificate fingerprints out of `keytool -list -v` output. The fingerprint
|
|
19140
|
+
* labels (`MD5:`, `SHA1:`, `SHA256:`) are stable across keytool locales — only the
|
|
19141
|
+
* surrounding prose is translated — so label-anchored regexes are robust. MD5 is
|
|
19142
|
+
* absent on modern JDKs (dropped from `-v` output); that field stays `undefined`.
|
|
19143
|
+
* keytool already emits the canonical uppercase, colon-separated form the dashboard
|
|
19144
|
+
* displays verbatim, so no normalization is needed.
|
|
19145
|
+
*/
|
|
19146
|
+
const parseKeystoreFingerprints = (output) => ({
|
|
19147
|
+
md5: output.match(FINGERPRINT_PATTERNS.md5)?.groups?.["value"],
|
|
19148
|
+
sha1: output.match(FINGERPRINT_PATTERNS.sha1)?.groups?.["value"],
|
|
19149
|
+
sha256: output.match(FINGERPRINT_PATTERNS.sha256)?.groups?.["value"]
|
|
19150
|
+
});
|
|
19151
|
+
/**
|
|
19152
|
+
* Run `keytool -list -v` against an on-disk keystore and extract its certificate
|
|
19153
|
+
* fingerprints. Only the store password is required to read a certificate. Used at
|
|
19154
|
+
* upload/generate time to populate the public, server-visible fingerprint metadata
|
|
19155
|
+
* the dashboard renders.
|
|
19156
|
+
*/
|
|
19157
|
+
const extractKeystoreFingerprints = (params) => Command.string(Command.make("keytool", "-list", "-v", "-keystore", params.keystorePath, "-alias", params.keyAlias, "-storepass", params.storePassword).pipe(Command.env({ LC_ALL: "C" }))).pipe(Effect.mapError((cause) => new BuildFailedError({
|
|
19158
|
+
step: "extract keystore fingerprints",
|
|
19159
|
+
exitCode: 1,
|
|
19160
|
+
message: `keytool -list failed to run (is the JDK installed?): ${String(cause)}`
|
|
19161
|
+
})), Effect.flatMap((output) => {
|
|
19162
|
+
const fingerprints = parseKeystoreFingerprints(output);
|
|
19163
|
+
if (fingerprints.sha1 === void 0 && fingerprints.sha256 === void 0) return Effect.fail(new BuildFailedError({
|
|
19164
|
+
step: "extract keystore fingerprints",
|
|
19165
|
+
exitCode: 1,
|
|
19166
|
+
message: "keytool produced no SHA-1/SHA-256 fingerprints — verify the key alias and keystore password"
|
|
19167
|
+
}));
|
|
19168
|
+
return Effect.succeed(fingerprints);
|
|
19169
|
+
}));
|
|
19132
19170
|
const generateAndroidKeystore = (input) => Command.exitCode(Command.make("keytool", "-genkeypair", "-v", "-storetype", "JKS", "-keystore", input.outputPath, "-alias", input.keyAlias, "-keyalg", "RSA", "-keysize", "2048", "-validity", String(input.validityDays ?? DEFAULT_KEYSTORE_VALIDITY_DAYS), "-storepass", input.storePassword, "-keypass", input.keyPassword, "-dname", renderDistinguishedName({
|
|
19133
19171
|
commonName: input.commonName,
|
|
19134
19172
|
organization: input.organization
|
|
@@ -19610,8 +19648,18 @@ const generateAndUploadKeystore = (api, input) => Effect.scoped(Effect.gen(funct
|
|
|
19610
19648
|
...compact({ validityDays: input.validityDays })
|
|
19611
19649
|
});
|
|
19612
19650
|
const bytes = yield* fs.readFile(keystorePath);
|
|
19613
|
-
const
|
|
19614
|
-
|
|
19651
|
+
const fingerprints = yield* extractKeystoreFingerprints({
|
|
19652
|
+
keystorePath,
|
|
19653
|
+
keyAlias: input.keyAlias,
|
|
19654
|
+
storePassword: input.storePassword
|
|
19655
|
+
});
|
|
19656
|
+
const session = yield* openVaultSessionInteractive(api);
|
|
19657
|
+
const metadata = compact({
|
|
19658
|
+
keyAlias: input.keyAlias,
|
|
19659
|
+
md5Fingerprint: fingerprints.md5,
|
|
19660
|
+
sha1Fingerprint: fingerprints.sha1,
|
|
19661
|
+
sha256Fingerprint: fingerprints.sha256
|
|
19662
|
+
});
|
|
19615
19663
|
const envelope = yield* sealForUpload({
|
|
19616
19664
|
session,
|
|
19617
19665
|
credentialType: "keystore",
|
|
@@ -19661,7 +19709,7 @@ const generateAndUploadDistributionCertificate = (api, input) => Effect.gen(func
|
|
|
19661
19709
|
step: "p12-build",
|
|
19662
19710
|
message: cause.message
|
|
19663
19711
|
})));
|
|
19664
|
-
const session = yield*
|
|
19712
|
+
const session = yield* openVaultSessionInteractive(api);
|
|
19665
19713
|
const metadata = {
|
|
19666
19714
|
serialNumber: bundle.metadata.serialNumber,
|
|
19667
19715
|
appleTeamIdentifier: bundle.metadata.appleTeamId,
|
|
@@ -20667,7 +20715,7 @@ const generateAndUploadDistributionCertificateViaAppleId = (api, input) => Effec
|
|
|
20667
20715
|
step: "parse-p12",
|
|
20668
20716
|
message: cause.message
|
|
20669
20717
|
})));
|
|
20670
|
-
const session = yield*
|
|
20718
|
+
const session = yield* openVaultSessionInteractive(api);
|
|
20671
20719
|
const envelopeMetadata = {
|
|
20672
20720
|
serialNumber: metadata.serialNumber,
|
|
20673
20721
|
appleTeamIdentifier: metadata.appleTeamId,
|
|
@@ -21065,14 +21113,12 @@ const isMissingResolveError = (cause) => hasTag(cause) && (cause._tag === "NotFo
|
|
|
21065
21113
|
const randomKeystoreSecret = () => randomBytes(24).toString("base64url");
|
|
21066
21114
|
const generateKeystoreAuto = (api, applicationIdentifier) => Effect.gen(function* () {
|
|
21067
21115
|
yield* Console.log("Generating a new Android Keystore...");
|
|
21068
|
-
const passphrase = yield* resolveVaultPassphrase;
|
|
21069
21116
|
return (yield* generateAndUploadKeystore(api, {
|
|
21070
21117
|
keyAlias: "upload",
|
|
21071
21118
|
storePassword: randomKeystoreSecret(),
|
|
21072
21119
|
keyPassword: randomKeystoreSecret(),
|
|
21073
21120
|
commonName: applicationIdentifier,
|
|
21074
|
-
organization: "better-update"
|
|
21075
|
-
...compact({ passphrase })
|
|
21121
|
+
organization: "better-update"
|
|
21076
21122
|
})).id;
|
|
21077
21123
|
});
|
|
21078
21124
|
const generateKeystoreInteractive = (api) => Effect.gen(function* () {
|
|
@@ -21081,15 +21127,13 @@ const generateKeystoreInteractive = (api) => Effect.gen(function* () {
|
|
|
21081
21127
|
const keyPassword = yield* promptPassword("Key password");
|
|
21082
21128
|
const commonName = yield* promptText("Common name (CN)", { placeholder: "Your App" });
|
|
21083
21129
|
const organization = yield* promptText("Organization (O)", { placeholder: "Your Company" });
|
|
21084
|
-
const passphrase = yield* resolveVaultPassphrase;
|
|
21085
21130
|
yield* Console.log("Generating keystore with keytool...");
|
|
21086
21131
|
return (yield* generateAndUploadKeystore(api, {
|
|
21087
21132
|
keyAlias: alias,
|
|
21088
21133
|
storePassword,
|
|
21089
21134
|
keyPassword,
|
|
21090
21135
|
commonName,
|
|
21091
|
-
organization
|
|
21092
|
-
...compact({ passphrase })
|
|
21136
|
+
organization
|
|
21093
21137
|
})).id;
|
|
21094
21138
|
});
|
|
21095
21139
|
const pickExistingKeystore = (api) => Effect.gen(function* () {
|
|
@@ -21112,6 +21156,25 @@ const resolveAndroidAppId = (api, input) => Effect.gen(function* () {
|
|
|
21112
21156
|
})).id;
|
|
21113
21157
|
});
|
|
21114
21158
|
const resolveAndroidKeystoreId = (api, choice) => choice === "generate" ? generateKeystoreInteractive(api) : pickExistingKeystore(api);
|
|
21159
|
+
const bindAndroidKeystore = (api, appId, keystoreId) => Effect.gen(function* () {
|
|
21160
|
+
const existing = yield* api.androidBuildCredentials.list({ path: { applicationIdentifierId: appId } });
|
|
21161
|
+
const target = existing.items.find((group) => group.isDefault) ?? existing.items.at(0);
|
|
21162
|
+
if (target === void 0) {
|
|
21163
|
+
yield* api.androidBuildCredentials.create({
|
|
21164
|
+
path: { applicationIdentifierId: appId },
|
|
21165
|
+
payload: {
|
|
21166
|
+
name: "Default",
|
|
21167
|
+
isDefault: true,
|
|
21168
|
+
androidUploadKeystoreId: keystoreId
|
|
21169
|
+
}
|
|
21170
|
+
});
|
|
21171
|
+
return;
|
|
21172
|
+
}
|
|
21173
|
+
yield* api.androidBuildCredentials.update({
|
|
21174
|
+
path: { id: target.id },
|
|
21175
|
+
payload: { androidUploadKeystoreId: keystoreId }
|
|
21176
|
+
});
|
|
21177
|
+
});
|
|
21115
21178
|
const setupAndroidInteractive = (api, input) => Effect.gen(function* () {
|
|
21116
21179
|
yield* Console.log("");
|
|
21117
21180
|
yield* Console.log(`No Android build credentials configured for ${input.applicationIdentifier}.`);
|
|
@@ -21134,15 +21197,7 @@ const setupAndroidInteractive = (api, input) => Effect.gen(function* () {
|
|
|
21134
21197
|
message: `Build aborted — no keystore bound to ${input.applicationIdentifier}.`,
|
|
21135
21198
|
hint: "Run `better-update credentials generate keystore` or upload via the dashboard."
|
|
21136
21199
|
});
|
|
21137
|
-
|
|
21138
|
-
yield* api.androidBuildCredentials.create({
|
|
21139
|
-
path: { applicationIdentifierId: appId },
|
|
21140
|
-
payload: {
|
|
21141
|
-
name: "Default",
|
|
21142
|
-
isDefault: true,
|
|
21143
|
-
androidUploadKeystoreId: keystoreId
|
|
21144
|
-
}
|
|
21145
|
-
});
|
|
21200
|
+
yield* bindAndroidKeystore(api, appId, yield* choice === "generate" ? generateKeystoreAuto(api, input.applicationIdentifier) : pickExistingKeystore(api));
|
|
21146
21201
|
yield* Console.log("Android build credentials configured.");
|
|
21147
21202
|
});
|
|
21148
21203
|
const ensureAndroidCredentialsAvailable = (api, input) => api.buildCredentials.resolve({
|
|
@@ -25896,8 +25951,9 @@ const detectFormat = (bytes) => {
|
|
|
25896
25951
|
/**
|
|
25897
25952
|
* Validate keystore bytes + alias/passwords locally before sealing. Mirrors the
|
|
25898
25953
|
* old server check: magic-byte format detection + required-field validation.
|
|
25899
|
-
* Fingerprints
|
|
25900
|
-
*
|
|
25954
|
+
* Fingerprints cannot be derived from the raw bytes; they are extracted separately
|
|
25955
|
+
* via keytool (`extractKeystoreFingerprints` in ./android-keystore) at upload/generate
|
|
25956
|
+
* time and attached to the public metadata.
|
|
25901
25957
|
*/
|
|
25902
25958
|
const validateAndroidKeystore = (params) => Effect.gen(function* () {
|
|
25903
25959
|
if (params.bytes.byteLength < 16) return yield* new CredentialValidationError({ message: "Keystore file too small" });
|
|
@@ -26049,7 +26105,7 @@ const uploadIosDistributionCertificate = (api, input, bytes) => Effect.gen(funct
|
|
|
26049
26105
|
validUntil: info.expiresAt.toISOString()
|
|
26050
26106
|
};
|
|
26051
26107
|
const envelope = yield* sealForUpload({
|
|
26052
|
-
session: yield*
|
|
26108
|
+
session: yield* openVaultSessionInteractive(api),
|
|
26053
26109
|
credentialType: "distribution-certificate",
|
|
26054
26110
|
metadata,
|
|
26055
26111
|
secret: {
|
|
@@ -26075,7 +26131,7 @@ const uploadIosPushKey = (api, input, bytes) => Effect.gen(function* () {
|
|
|
26075
26131
|
appleTeamIdentifier: input.appleTeamIdentifier
|
|
26076
26132
|
};
|
|
26077
26133
|
const envelope = yield* sealForUpload({
|
|
26078
|
-
session: yield*
|
|
26134
|
+
session: yield* openVaultSessionInteractive(api),
|
|
26079
26135
|
credentialType: "push-key",
|
|
26080
26136
|
metadata,
|
|
26081
26137
|
secret: { p8Pem: toUtf8(bytes) }
|
|
@@ -26100,7 +26156,7 @@ const uploadIosAscApiKey = (api, input, bytes) => Effect.gen(function* () {
|
|
|
26100
26156
|
appleTeamIdentifier: input.appleTeamIdentifier
|
|
26101
26157
|
});
|
|
26102
26158
|
const envelope = yield* sealForUpload({
|
|
26103
|
-
session: yield*
|
|
26159
|
+
session: yield* openVaultSessionInteractive(api),
|
|
26104
26160
|
credentialType: "asc-api-key",
|
|
26105
26161
|
metadata,
|
|
26106
26162
|
secret: { p8Pem: toUtf8(bytes) }
|
|
@@ -26127,14 +26183,25 @@ const uploadAndroidKeystore = (api, input, bytes) => Effect.gen(function* () {
|
|
|
26127
26183
|
if (input.password === void 0) return yield* missing("password");
|
|
26128
26184
|
if (!input.keyAlias) return yield* missing("key-alias");
|
|
26129
26185
|
if (!input.keyPassword) return yield* missing("key-password");
|
|
26130
|
-
const
|
|
26186
|
+
const parsed = yield* validateAndroidKeystore({
|
|
26131
26187
|
bytes,
|
|
26132
26188
|
keyAlias: input.keyAlias,
|
|
26133
26189
|
keystorePassword: input.password,
|
|
26134
26190
|
keyPassword: input.keyPassword
|
|
26135
|
-
})
|
|
26191
|
+
});
|
|
26192
|
+
const fingerprints = yield* extractKeystoreFingerprints({
|
|
26193
|
+
keystorePath: input.filePath,
|
|
26194
|
+
keyAlias: parsed.keyAlias,
|
|
26195
|
+
storePassword: input.password
|
|
26196
|
+
});
|
|
26197
|
+
const metadata = compact({
|
|
26198
|
+
keyAlias: parsed.keyAlias,
|
|
26199
|
+
md5Fingerprint: fingerprints.md5,
|
|
26200
|
+
sha1Fingerprint: fingerprints.sha1,
|
|
26201
|
+
sha256Fingerprint: fingerprints.sha256
|
|
26202
|
+
});
|
|
26136
26203
|
const envelope = yield* sealForUpload({
|
|
26137
|
-
session: yield*
|
|
26204
|
+
session: yield* openVaultSessionInteractive(api),
|
|
26138
26205
|
credentialType: "keystore",
|
|
26139
26206
|
metadata,
|
|
26140
26207
|
secret: {
|
|
@@ -26162,7 +26229,7 @@ const uploadAndroidGoogleServiceAccountKey = (api, input, bytes) => Effect.gen(f
|
|
|
26162
26229
|
googleProjectId: parsed.googleProjectId
|
|
26163
26230
|
};
|
|
26164
26231
|
const envelope = yield* sealForUpload({
|
|
26165
|
-
session: yield*
|
|
26232
|
+
session: yield* openVaultSessionInteractive(api),
|
|
26166
26233
|
credentialType: "google-service-account-key",
|
|
26167
26234
|
metadata,
|
|
26168
26235
|
secret: { json }
|
|
@@ -26191,10 +26258,7 @@ const uploadCredential = (api, input) => Effect.gen(function* () {
|
|
|
26191
26258
|
const hasKey = (candidate) => Object.hasOwn(uploadHandlers, candidate);
|
|
26192
26259
|
const handler = hasKey(key) ? uploadHandlers[key] : void 0;
|
|
26193
26260
|
if (!handler) return yield* new CredentialValidationError({ message: `Unsupported credential combination: platform=${input.platform} type=${input.type}` });
|
|
26194
|
-
return yield* handler(api, input
|
|
26195
|
-
...input,
|
|
26196
|
-
...compact({ passphrase: yield* resolveVaultPassphrase })
|
|
26197
|
-
}, bytes);
|
|
26261
|
+
return yield* handler(api, input, bytes);
|
|
26198
26262
|
});
|
|
26199
26263
|
const deleteCredential = (api, input) => {
|
|
26200
26264
|
const path = { id: input.id };
|
|
@@ -27185,10 +27249,14 @@ const runCredentialsManager = Effect.gen(function* () {
|
|
|
27185
27249
|
* one, re-wrap the new vault key to each recipient, then submit the rotation
|
|
27186
27250
|
* atomically (the server CAS-guards on the current version and requires a
|
|
27187
27251
|
* recovery recipient in the set). Drops every recipient not in `recipients`.
|
|
27252
|
+
*
|
|
27253
|
+
* Unlocks via the cache-aware path (reusing a live `credentials unlock` session),
|
|
27254
|
+
* then drops that cached key once the re-key lands — it is now stale, so the next
|
|
27255
|
+
* operation must re-unlock at the new version.
|
|
27188
27256
|
*/
|
|
27189
27257
|
const rotateVaultTo = (args) => Effect.gen(function* () {
|
|
27190
27258
|
const orgId = yield* getActiveOrgId(args.api);
|
|
27191
|
-
const current = yield*
|
|
27259
|
+
const current = yield* unlockVaultKeyInteractive(args.api);
|
|
27192
27260
|
const newVaultKey = generateVaultKey();
|
|
27193
27261
|
const newVersion = current.vaultVersion + 1;
|
|
27194
27262
|
const { deks } = yield* args.api.orgVault.listCredentialDeks();
|
|
@@ -27226,11 +27294,13 @@ const rotateVaultTo = (args) => Effect.gen(function* () {
|
|
|
27226
27294
|
recipient: recipient.publicKey
|
|
27227
27295
|
}))
|
|
27228
27296
|
})), { concurrency: "unbounded" });
|
|
27229
|
-
|
|
27297
|
+
const rotated = yield* args.api.orgVault.rotate({ payload: {
|
|
27230
27298
|
fromVersion: current.vaultVersion,
|
|
27231
27299
|
recipientWraps,
|
|
27232
27300
|
credentialDeks
|
|
27233
27301
|
} });
|
|
27302
|
+
yield* forgetCachedVaultKey;
|
|
27303
|
+
return rotated;
|
|
27234
27304
|
});
|
|
27235
27305
|
/** The encryption keys currently holding the vault key, joined with their public keys. */
|
|
27236
27306
|
const currentRecipients = (api) => Effect.gen(function* () {
|
|
@@ -27365,7 +27435,6 @@ const rotateCommand = defineCommand({
|
|
|
27365
27435
|
yield* confirmRecipients(recipients, args.yes === true);
|
|
27366
27436
|
const rotated = yield* rotateVaultTo({
|
|
27367
27437
|
api,
|
|
27368
|
-
passphrase: yield* resolveVaultPassphrase,
|
|
27369
27438
|
recipients: recipients.map(toRotationRecipient)
|
|
27370
27439
|
});
|
|
27371
27440
|
yield* printHuman(`Rotated the vault to version ${String(rotated.vaultVersion)} (${String(recipients.length)} recipients).`);
|
|
@@ -27401,7 +27470,6 @@ const revokeCommand$1 = defineCommand({
|
|
|
27401
27470
|
yield* confirmRecipients(surviving, args.yes === true);
|
|
27402
27471
|
const rotated = yield* rotateVaultTo({
|
|
27403
27472
|
api,
|
|
27404
|
-
passphrase: yield* resolveVaultPassphrase,
|
|
27405
27473
|
recipients: surviving.map(toRotationRecipient)
|
|
27406
27474
|
});
|
|
27407
27475
|
yield* printHuman(`Revoked ${target.label} and rotated the vault to version ${String(rotated.vaultVersion)}.`);
|
|
@@ -27487,7 +27555,6 @@ const recoveryCommand = defineCommand({
|
|
|
27487
27555
|
yield* confirmRecipients(surviving, args.yes === true);
|
|
27488
27556
|
const rotated = yield* rotateVaultTo({
|
|
27489
27557
|
api,
|
|
27490
|
-
passphrase: yield* resolveVaultPassphrase,
|
|
27491
27558
|
recipients: [...surviving.map(toRotationRecipient), {
|
|
27492
27559
|
userEncryptionKeyId: registered.id,
|
|
27493
27560
|
publicKey: newRecovery.publicKey
|