UNPKG

@capgo/cli

Version:
235 lines (234 loc) 9.36 kB
/** * Generate a JWT for App Store Connect API authentication. * Uses ES256 algorithm with the .p8 private key. */ export declare function generateJwt(keyId: string, issuerId: string, p8Content: string): string; export declare class AppleApiHttpError extends Error { readonly status: number; constructor(status: number, message: string); } /** * Verify the API key works and try to detect the team ID from existing certificates. * Throws on 401/403 with a user-friendly message. */ export declare function verifyApiKey(token: string): Promise<{ valid: true; teamId: string; }>; export interface AscDistributionCert { id: string; name: string; serialNumber: string; expirationDate: string; /** * Base64-encoded DER of the certificate. Populated when {@link listDistributionCerts} * is called with `includeContent: true` — kept optional so existing callers don't pay * the larger payload when they don't need it. */ certificateContent?: string; } /** * Why a local Keychain cert can't be used to ship builds. * * Concrete enumeration so the import-pick-identity UI can render a stable * Reason column and so we can add specific guidance per reason (e.g. * "managed" certs get a "can't sign locally" note, "not-visible" certs get * a "Open Developer Portal to verify" note). */ export type CertAvailabilityReason = 'expired' | 'managed' | 'not-visible' | 'check-failed' | 'no-private-key'; export interface CertAvailability { available: boolean; reason?: CertAvailabilityReason; /** Short human-readable reason for display in the picker. */ reasonText?: string; /** When available — Apple-side cert resource id for downstream API calls. */ appleCertId?: string; } /** * Pure classifier: given a local cert + the result of an Apple-side lookup, * decide whether it's usable for shipping builds and surface a short * reasonText for the picker UI. * * Exported separately from the lookup function so we can unit-test the * decision logic without mocking network calls. Callers compose: * * const certId = await findCertIdBySha1(token, identity.sha1) * .catch(err => { lookupError = err; return null }) * const availability = classifyCertAvailability({ * localExpirationDate: identity.expirationDate, * appleCertId: certId, * lookupError, * }) * * The `expired` and `managed` branches don't need a lookup — they're checked * up-front from local metadata. Callers can pass null `appleCertId` without * having run the lookup at all when those local-side conditions already * disqualify the identity. */ export declare function classifyCertAvailability(args: { localExpirationDate?: string; isManaged?: boolean; appleCertId: string | null; lookupError?: unknown; }): CertAvailability; /** * List all iOS distribution certificates. * * Set `includeContent: true` when you need to compute the cert's SHA1 for * matching against a local Keychain identity ({@link findCertIdBySha1}). */ export declare function listDistributionCerts(token: string, options?: { includeContent?: boolean; }): Promise<AscDistributionCert[]>; /** * Compute the SHA1 hash of an ASC certificate's base64-DER content. Returns * the lowercase 40-char hex string used elsewhere as the canonical identity * key — matches the SHA1 reported by `security find-identity` on macOS. * * SECURITY NOTE on SHA1: this is NOT a security primitive. macOS itself * reports code-signing identities as cert-DER SHA1 (via `security * find-identity`), and we have to use the same hash to look up an Apple-side * cert by its on-Mac counterpart. SHA1 here is a non-secret identifier, not * a message digest protecting any data. CodeQL's "weak cryptographic * algorithm" rule is suppressed for this reason. */ export declare function computeCertSha1(certificateContentBase64: string): string; /** * Match a local Keychain identity (by its SHA1) against an Apple-side * certificate and return the Apple certificate ID needed for profile * creation. Returns null if no Apple-side cert matches the SHA1. */ export declare function findCertIdBySha1(token: string, sha1: string): Promise<string | null>; /** * Like {@link findCertIdBySha1} but returns the full Apple-side cert * record (id + name + expirationDate + serialNumber) when matched. Used * by the eager batch validation so the picker / manual-portal-walkthrough * step can surface concrete disambiguators (expiration date, last few * chars of serial number — both visible in the Apple Developer Portal * when the user clicks into a cert) that help the user pick the right * row when multiple distribution certs are listed for the same team. * * Apple's API does NOT expose a "created by" field on certs (the portal * UI shows it, but `/v1/certificates` doesn't return that column). The * disambiguators we can give are expirationDate + serialNumber. */ export declare function findCertBySha1(token: string, sha1: string): Promise<AscDistributionCert | null>; /** * List all provisioning profiles linked to a specific Apple-side certificate. * Used by the import-flow no-match-recovery menu to surface profiles that * exist on Apple but haven't been downloaded to the user's Mac. */ export interface AscProfileSummary { id: string; name: string; profileType: string; profileContent: string; expirationDate: string; bundleIdentifier: string; } export declare function listProfilesForCert(token: string, certificateId: string): Promise<AscProfileSummary[]>; /** * Revoke (delete) a certificate by ID. */ export declare function revokeCertificate(token: string, certId: string): Promise<void>; /** * Error thrown when certificate limit is reached. * Contains the existing certificates so the UI can ask the user which to revoke. */ export declare class CertificateLimitError extends Error { readonly certificates: AscDistributionCert[]; constructor(certificates: AscDistributionCert[]); } /** * Create a distribution certificate using a CSR. * Returns the certificate ID, base64 DER content, expiration date, and team ID. * * Throws CertificateLimitError if the limit is reached, so the UI can ask * the user which certificate to revoke. */ export declare function createCertificate(token: string, csrPem: string): Promise<{ certificateId: string; certificateContent: string; expirationDate: string; teamId: string; }>; /** * Find an existing bundle ID or register a new one. * Returns the Apple resource ID needed for profile creation. */ export declare function ensureBundleId(token: string, identifier: string): Promise<{ bundleIdResourceId: string; }>; /** * An App Store Connect app record. Used by the iOS app-verification step to * check whether an app exists whose `bundleId` matches the project's Release * `PRODUCT_BUNDLE_IDENTIFIER`. */ export interface AscApp { id: string; bundleId: string; name: string; } /** * Parse a `GET /v1/apps` response into {@link AscApp} records. Tolerant of * missing `data`, missing `attributes`, and missing individual fields — Apple * omits attributes the API key isn't entitled to see rather than nulling them. */ export declare function parseAppsResponse(json: any): AscApp[]; /** * Parse a `GET /v1/bundleIds` response into the list of registered identifier * strings, dropping any falsy entries (missing `attributes`/`identifier`). */ export declare function parseBundleIdsResponse(json: any): string[]; /** * List every App Store Connect app visible to the API key, following * pagination. Uses the existing {@link ascFetch} — no separate fetch path. */ export declare function listApps(token: string): Promise<AscApp[]>; /** * List every registered bundle ID identifier visible to the API key, following * pagination. Uses the existing {@link ascFetch} — no separate fetch path. */ export declare function listBundleIds(token: string): Promise<string[]>; /** * Get the profile name we use for a given appId. */ export declare function getCapgoProfileName(appId: string): string; /** * Find existing provisioning profiles matching our naming convention. * Only returns profiles we created (named "Capgo <appId> AppStore"). */ export declare function findCapgoProfiles(token: string, appId: string): Promise<Array<{ id: string; name: string; profileType: string; }>>; /** * Delete a provisioning profile by ID. */ export declare function deleteProfile(token: string, profileId: string): Promise<void>; /** * Create an App Store provisioning profile linking a certificate and bundle ID. * Returns the base64 mobileprovision content. * * Throws a DuplicateProfileError if duplicate profiles exist, so the caller * can ask the user whether to delete them and retry. */ export declare class DuplicateProfileError extends Error { readonly profiles: Array<{ id: string; name: string; profileType: string; }>; constructor(profiles: Array<{ id: string; name: string; profileType: string; }>); } export declare function createProfile(token: string, bundleIdResourceId: string, certificateId: string, appId: string): Promise<{ profileId: string; profileName: string; profileContent: string; expirationDate: string; }>;