@better-update/cli 0.29.1 → 0.30.0
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 +70 -7
- 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.
|
|
37
|
+
var version = "0.30.0";
|
|
38
38
|
|
|
39
39
|
//#endregion
|
|
40
40
|
//#region src/lib/interactive-mode.ts
|
|
@@ -484,6 +484,7 @@ var AndroidUploadKeystore = class extends Schema.Class("AndroidUploadKeystore")(
|
|
|
484
484
|
md5Fingerprint: Schema.NullOr(Schema.String),
|
|
485
485
|
sha1Fingerprint: Schema.NullOr(Schema.String),
|
|
486
486
|
sha256Fingerprint: Schema.NullOr(Schema.String),
|
|
487
|
+
keystoreType: Schema.NullOr(Schema.Literal("JKS", "PKCS12")),
|
|
487
488
|
createdAt: DateTimeString,
|
|
488
489
|
updatedAt: DateTimeString
|
|
489
490
|
}) {};
|
|
@@ -498,7 +499,8 @@ const UploadAndroidUploadKeystoreBody = Schema.Struct({
|
|
|
498
499
|
keyAlias: Schema.String.pipe(Schema.minLength(1), Schema.maxLength(200)),
|
|
499
500
|
md5Fingerprint: Schema.optional(Schema.String.pipe(Schema.maxLength(200))),
|
|
500
501
|
sha1Fingerprint: Schema.optional(Schema.String.pipe(Schema.maxLength(200))),
|
|
501
|
-
sha256Fingerprint: Schema.optional(Schema.String.pipe(Schema.maxLength(200)))
|
|
502
|
+
sha256Fingerprint: Schema.optional(Schema.String.pipe(Schema.maxLength(200))),
|
|
503
|
+
keystoreType: Schema.optional(Schema.Literal("JKS", "PKCS12"))
|
|
502
504
|
});
|
|
503
505
|
const DeleteAndroidUploadKeystoreResult = DeletedResult;
|
|
504
506
|
/** Encrypted envelope plus metadata; the CLI decrypts `ciphertext` to recover `{ keystoreBase64, keystorePassword, keyPassword }`. */
|
|
@@ -19130,6 +19132,43 @@ const openFromDownload = (args) => {
|
|
|
19130
19132
|
//#region src/lib/android-keystore.ts
|
|
19131
19133
|
const DEFAULT_KEYSTORE_VALIDITY_DAYS = 1e4;
|
|
19132
19134
|
const renderDistinguishedName = (params) => `CN=${params.commonName}, O=${params.organization}`;
|
|
19135
|
+
const FINGERPRINT_PATTERNS = {
|
|
19136
|
+
md5: /MD5:\s*(?<value>[0-9A-F:]+)/iu,
|
|
19137
|
+
sha1: /SHA-?1:\s*(?<value>[0-9A-F:]+)/iu,
|
|
19138
|
+
sha256: /SHA-?256:\s*(?<value>[0-9A-F:]+)/iu
|
|
19139
|
+
};
|
|
19140
|
+
/**
|
|
19141
|
+
* Parse certificate fingerprints out of `keytool -list -v` output. The fingerprint
|
|
19142
|
+
* labels (`MD5:`, `SHA1:`, `SHA256:`) are stable across keytool locales — only the
|
|
19143
|
+
* surrounding prose is translated — so label-anchored regexes are robust. MD5 is
|
|
19144
|
+
* absent on modern JDKs (dropped from `-v` output); that field stays `undefined`.
|
|
19145
|
+
* keytool already emits the canonical uppercase, colon-separated form the dashboard
|
|
19146
|
+
* displays verbatim, so no normalization is needed.
|
|
19147
|
+
*/
|
|
19148
|
+
const parseKeystoreFingerprints = (output) => ({
|
|
19149
|
+
md5: output.match(FINGERPRINT_PATTERNS.md5)?.groups?.["value"],
|
|
19150
|
+
sha1: output.match(FINGERPRINT_PATTERNS.sha1)?.groups?.["value"],
|
|
19151
|
+
sha256: output.match(FINGERPRINT_PATTERNS.sha256)?.groups?.["value"]
|
|
19152
|
+
});
|
|
19153
|
+
/**
|
|
19154
|
+
* Run `keytool -list -v` against an on-disk keystore and extract its certificate
|
|
19155
|
+
* fingerprints. Only the store password is required to read a certificate. Used at
|
|
19156
|
+
* upload/generate time to populate the public, server-visible fingerprint metadata
|
|
19157
|
+
* the dashboard renders.
|
|
19158
|
+
*/
|
|
19159
|
+
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({
|
|
19160
|
+
step: "extract keystore fingerprints",
|
|
19161
|
+
exitCode: 1,
|
|
19162
|
+
message: `keytool -list failed to run (is the JDK installed?): ${String(cause)}`
|
|
19163
|
+
})), Effect.flatMap((output) => {
|
|
19164
|
+
const fingerprints = parseKeystoreFingerprints(output);
|
|
19165
|
+
if (fingerprints.sha1 === void 0 && fingerprints.sha256 === void 0) return Effect.fail(new BuildFailedError({
|
|
19166
|
+
step: "extract keystore fingerprints",
|
|
19167
|
+
exitCode: 1,
|
|
19168
|
+
message: "keytool produced no SHA-1/SHA-256 fingerprints — verify the key alias and keystore password"
|
|
19169
|
+
}));
|
|
19170
|
+
return Effect.succeed(fingerprints);
|
|
19171
|
+
}));
|
|
19133
19172
|
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({
|
|
19134
19173
|
commonName: input.commonName,
|
|
19135
19174
|
organization: input.organization
|
|
@@ -19611,8 +19650,19 @@ const generateAndUploadKeystore = (api, input) => Effect.scoped(Effect.gen(funct
|
|
|
19611
19650
|
...compact({ validityDays: input.validityDays })
|
|
19612
19651
|
});
|
|
19613
19652
|
const bytes = yield* fs.readFile(keystorePath);
|
|
19653
|
+
const fingerprints = yield* extractKeystoreFingerprints({
|
|
19654
|
+
keystorePath,
|
|
19655
|
+
keyAlias: input.keyAlias,
|
|
19656
|
+
storePassword: input.storePassword
|
|
19657
|
+
});
|
|
19614
19658
|
const session = yield* openVaultSessionInteractive(api);
|
|
19615
|
-
const metadata = {
|
|
19659
|
+
const metadata = compact({
|
|
19660
|
+
keyAlias: input.keyAlias,
|
|
19661
|
+
md5Fingerprint: fingerprints.md5,
|
|
19662
|
+
sha1Fingerprint: fingerprints.sha1,
|
|
19663
|
+
sha256Fingerprint: fingerprints.sha256,
|
|
19664
|
+
keystoreType: "JKS"
|
|
19665
|
+
});
|
|
19616
19666
|
const envelope = yield* sealForUpload({
|
|
19617
19667
|
session,
|
|
19618
19668
|
credentialType: "keystore",
|
|
@@ -25904,8 +25954,9 @@ const detectFormat = (bytes) => {
|
|
|
25904
25954
|
/**
|
|
25905
25955
|
* Validate keystore bytes + alias/passwords locally before sealing. Mirrors the
|
|
25906
25956
|
* old server check: magic-byte format detection + required-field validation.
|
|
25907
|
-
* Fingerprints
|
|
25908
|
-
*
|
|
25957
|
+
* Fingerprints cannot be derived from the raw bytes; they are extracted separately
|
|
25958
|
+
* via keytool (`extractKeystoreFingerprints` in ./android-keystore) at upload/generate
|
|
25959
|
+
* time and attached to the public metadata.
|
|
25909
25960
|
*/
|
|
25910
25961
|
const validateAndroidKeystore = (params) => Effect.gen(function* () {
|
|
25911
25962
|
if (params.bytes.byteLength < 16) return yield* new CredentialValidationError({ message: "Keystore file too small" });
|
|
@@ -26135,12 +26186,24 @@ const uploadAndroidKeystore = (api, input, bytes) => Effect.gen(function* () {
|
|
|
26135
26186
|
if (input.password === void 0) return yield* missing("password");
|
|
26136
26187
|
if (!input.keyAlias) return yield* missing("key-alias");
|
|
26137
26188
|
if (!input.keyPassword) return yield* missing("key-password");
|
|
26138
|
-
const
|
|
26189
|
+
const parsed = yield* validateAndroidKeystore({
|
|
26139
26190
|
bytes,
|
|
26140
26191
|
keyAlias: input.keyAlias,
|
|
26141
26192
|
keystorePassword: input.password,
|
|
26142
26193
|
keyPassword: input.keyPassword
|
|
26143
|
-
})
|
|
26194
|
+
});
|
|
26195
|
+
const fingerprints = yield* extractKeystoreFingerprints({
|
|
26196
|
+
keystorePath: input.filePath,
|
|
26197
|
+
keyAlias: parsed.keyAlias,
|
|
26198
|
+
storePassword: input.password
|
|
26199
|
+
});
|
|
26200
|
+
const metadata = compact({
|
|
26201
|
+
keyAlias: parsed.keyAlias,
|
|
26202
|
+
md5Fingerprint: fingerprints.md5,
|
|
26203
|
+
sha1Fingerprint: fingerprints.sha1,
|
|
26204
|
+
sha256Fingerprint: fingerprints.sha256,
|
|
26205
|
+
keystoreType: parsed.format
|
|
26206
|
+
});
|
|
26144
26207
|
const envelope = yield* sealForUpload({
|
|
26145
26208
|
session: yield* openVaultSessionInteractive(api),
|
|
26146
26209
|
credentialType: "keystore",
|