UNPKG

@capgo/cli

Version:
96 lines (95 loc) 3.68 kB
import { Buffer } from 'node:buffer'; export interface KeystoreDname { commonName: string; organizationName?: string; countryCode?: string; } export interface KeystoreOptions { alias: string; storePassword: string; keyPassword: string; dname: KeystoreDname; /** Default: 27 years (~10000 days, Android Play standard) */ validityYears?: number; /** Default: 2048-bit RSA */ keySize?: number; } export interface KeystoreResult { p12Base64: string; p12Bytes: Buffer; alias: string; notAfter: Date; } /** * Sanitize a keystore alias for use as an on-disk filename component. * * The alias originates from user input (e.g. `keystoreNewAlias`). It is used * verbatim for the keystore crypto and the saved `KEYSTORE_KEY_ALIAS`, but the * value used to build the `<alias>.p12` filename must be sanitized so a value * like `../../evil` or `/etc/x` cannot escape the target directory. * * Rules: * - strip any directory components (keep only the basename), * - allow only `[A-Za-z0-9._-]`, replacing any other char with `_`, * - normalize empty or dot-only results (``, `.`, `..`) to a safe default, * - the return value never contains `/`, `\`, or `..`. * * IMPORTANT: this is ONLY for the filename. Do NOT use it for the crypto alias * or the saved key alias — those must stay exactly what the user chose. */ export declare function sanitizeKeystoreAlias(alias: string): string; /** * Generate a URL-safe random password suitable for Android keystore use. * 24 bytes → 32-char base64url string. Collision-resistant, never written in logs. */ export declare function generateRandomPassword(): string; /** * Generate a PKCS#12 (.p12) keystore with a self-signed certificate. * * Key decisions: * - 3DES encryption for Gradle/keytool compatibility (same as iOS csr.ts). * - 27-year validity — Google Play requires keys to outlive all future app updates. * - 2048-bit RSA — standard for Android app signing. * - Subject/issuer identical (self-signed). * * Throws if alias or passwords are empty. */ export declare function generateKeystore(options: KeystoreOptions): KeystoreResult; export type ProbeKeyPasswordResult = { ok: true; } | { ok: false; reason: 'wrong-password' | 'unsupported-format' | 'parse-error' | 'no-private-key'; message: string; }; /** * Check whether the given password can both unlock a PKCS#12 keystore AND * decrypt the private key inside it. * * Useful for the "skip the key-password prompt if it's the same as the store * password" UX path: in practice most PKCS#12 keystores use a single password * for both the integrity MAC and the encrypted private-key bag. If this * returns `ok: true`, the CLI can use the store password as the key password * without asking the user. * * Returns `unsupported-format` for JKS (node-forge can't parse it) — caller * should fall back to prompting. */ export declare function tryUnlockPrivateKey(bytes: Uint8Array, password: string): ProbeKeyPasswordResult; export type ListAliasesResult = { ok: true; aliases: string[]; } | { ok: false; reason: 'wrong-password' | 'unsupported-format' | 'parse-error'; message: string; }; /** * Extract key aliases (PKCS#12 `friendlyName` attributes) from a keystore file. * * Works for PKCS#12 (.p12, .pfx) keystores. JKS (Java KeyStore — common for * .jks / .keystore files created by `keytool`) is NOT PKCS#12 and cannot be * parsed by node-forge; callers should treat `unsupported-format` as "ask the * user for the alias manually". */ export declare function listKeystoreAliases(bytes: Uint8Array, password: string): ListAliasesResult;