@capgo/cli
Version:
A CLI to upload to capgo servers
160 lines (159 loc) • 6.89 kB
TypeScript
import type { MobileprovisionDetail } from '../mobileprovision-parser.js';
/** Standard locations Xcode writes provisioning profiles into. */
export declare const PROVISIONING_PROFILE_DIRS: readonly ["Library/Developer/Xcode/UserData/Provisioning Profiles", "Library/MobileDevice/Provisioning Profiles"];
export type IdentityType = 'distribution' | 'development' | 'unknown';
export interface SigningIdentity {
/** SHA1 hash of the certificate, lowercase 40-char hex */
sha1: string;
/** Full identity string from `security find-identity` (e.g. "Apple Distribution: Acme Corp (XYZ123ABCD)") */
name: string;
/** Best-effort classification from the name prefix */
type: IdentityType;
/** Human-readable team name extracted from the identity string */
teamName: string;
/** Apple Team ID (10-char alphanumeric) extracted from the identity string */
teamId: string;
}
export interface DiscoveredProfile extends MobileprovisionDetail {
/** Absolute path to the .mobileprovision file */
path: string;
}
export interface IdentityProfileMatch {
identity: SigningIdentity;
/** Profiles whose embedded developer certs include this identity's SHA1 */
profiles: DiscoveredProfile[];
}
export interface ExportedP12 {
/** Base64-encoded PKCS#12 blob containing the chosen identity's cert + private key */
base64: string;
/** Auto-generated passphrase used to wrap the export */
passphrase: string;
}
export declare class MacOSSigningError extends Error {
readonly cause?: unknown | undefined;
constructor(message: string, cause?: unknown | undefined);
}
export declare class NotMacOSError extends MacOSSigningError {
constructor();
}
/** Returns `true` when running on macOS (Darwin). */
export declare function isMacOS(): boolean;
/**
* Run a subprocess and capture stdout/stderr/exit-code.
*
* Public so tests can inject a fake runner via the optional argument on
* higher-level functions. Not intended for downstream callers.
*/
export interface SecurityRunResult {
stdout: string;
stderr: string;
code: number | null;
}
export type SecurityRunner = (args: readonly string[]) => Promise<SecurityRunResult>;
/**
* Parse the human-readable output of `security find-identity -v -p codesigning`.
* Each line looks like:
* ` 1) <SHA1> "Apple Distribution: Acme Corp (XYZ123ABCD)"`
*
* Exported so unit tests can verify parsing without spawning a subprocess.
*/
export declare function parseFindIdentityOutput(stdout: string): SigningIdentity[];
/**
* List all code-signing identities visible in the user's default Keychain.
* Read-only — does NOT trigger any Keychain access prompt.
*
* @param runner Optional injection point for testing. Pass a fake to avoid
* spawning the real `/usr/bin/security` binary.
*/
export declare function listSigningIdentities(runner?: SecurityRunner): Promise<SigningIdentity[]>;
/**
* Scan all standard Xcode provisioning-profile directories under the user's
* home and return parsed metadata for every readable `.mobileprovision`.
*
* Read-only — pure filesystem reads, no Keychain interaction.
*
* Files that fail to parse are silently skipped (a teammate's malformed
* profile shouldn't break the whole listing).
*
* @param homeDirOverride Optional override for HOME, used in tests.
*/
export declare function scanProvisioningProfiles(homeDirOverride?: string): Promise<DiscoveredProfile[]>;
/**
* Given a list of identities and profiles, return one match entry per
* identity, populated with profiles whose embedded developer certs include
* that identity's SHA1.
*
* Pure function — no I/O.
*/
export declare function matchIdentitiesToProfiles(identities: readonly SigningIdentity[], profiles: readonly DiscoveredProfile[]): IdentityProfileMatch[];
/**
* Generate a cryptographically random passphrase suitable for wrapping the
* exported PKCS#12. 32 bytes of entropy → 64-char hex string.
*/
export declare function generateP12Passphrase(): string;
/**
* Output shape from the Swift helper's stdout — always emitted as one line of
* JSON regardless of success or failure. See keychain-export.swift for the
* source of truth.
*/
interface SwiftHelperResult {
ok: boolean;
p12Path?: string;
p12SizeBytes?: number;
identityName?: string;
errorCode?: 'INVALID_ARGS' | 'NO_IDENTITY' | 'USER_DENIED' | 'EXPORT_FAILED' | 'WRITE_FAILED' | 'INTERNAL';
message?: string;
osStatus?: number;
}
/**
* Returns true if the Swift helper is already cached at the version-keyed
* tmp path. Lets the UI decide whether to show a "compiling…" step or skip
* straight to the export step (the cached case is effectively instant).
*
* Sync + cheap (single existsSync). Safe to call from a React onChange
* handler.
*/
export declare function isHelperCached(): boolean;
/**
* Pre-compile the Swift helper without doing anything else. Used by the UI
* to show an explicit "compiling helper" step before the export, so the user
* isn't left staring at a spinner that says "look for the macOS dialog"
* while we silently build a binary.
*
* Returns the path to the compiled binary (same as `ensureSwiftHelper`).
*/
export declare function precompileSwiftHelper(): Promise<string>;
export interface ExportP12Options {
/**
* Pre-resolved Swift helper binary path. Used in tests to inject a fake
* binary; in production this is computed automatically.
*/
helperPathOverride?: string;
}
/**
* Export the chosen identity from the user's Keychain as a base64'd PKCS#12.
*
* Triggers exactly TWO macOS Keychain prompts on the user's first run for
* a given identity (one for "access" ACL, one for "export" ACL). Both
* decisions are cached when the user clicks "Always Allow", so subsequent
* runs against the same identity from the same binary are silent.
*
* Internally calls the bundled Swift helper (compiled on first use to the
* OS temp folder via `swiftc`). The helper uses Security framework's
* `SecItemExport(.formatPKCS12)` — the only Apple-supported path that works
* on Xcode-imported (non-extractable) signing keys.
*
* @param targetSha1 SHA1 of the identity to export (from {@link listSigningIdentities})
* @param options See {@link ExportP12Options}
*/
export declare function exportP12FromKeychain(targetSha1: string, options?: ExportP12Options): Promise<ExportedP12>;
/**
* Parse the helper's JSON output. Tolerates: extra whitespace, trailing
* newline, BOM. Throws a clear error if the output is unparsable — that
* indicates the helper crashed without emitting JSON, which our Swift code
* tries hard to never do (see keychain-export.swift's top-level catch).
*
* Exported for tests.
*/
export declare function parseHelperJson(stdout: string, stderr: string, exitCode: number | null): SwiftHelperResult;
export {};