@attest-it/core 0.6.0 → 0.7.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.
@@ -62,6 +62,14 @@ function getDefaultPrivateKeyPath() {
62
62
  function getDefaultPublicKeyPath() {
63
63
  return path.join(process.cwd(), "attest-it-public.pem");
64
64
  }
65
+ function getDefaultYubiKeyEncryptedKeyPath() {
66
+ const homeDir = os.homedir();
67
+ if (process.platform === "win32") {
68
+ const appData = process.env.APPDATA ?? path.join(homeDir, "AppData", "Roaming");
69
+ return path.join(appData, "attest-it", "yubikey-private.enc");
70
+ }
71
+ return path.join(homeDir, ".config", "attest-it", "yubikey-private.enc");
72
+ }
65
73
  async function ensureDir(dirPath) {
66
74
  try {
67
75
  await fs.mkdir(dirPath, { recursive: true });
@@ -221,6 +229,6 @@ async function setKeyPermissions(keyPath) {
221
229
  }
222
230
  }
223
231
 
224
- export { checkOpenSSL, generateKeyPair, getDefaultPrivateKeyPath, getDefaultPublicKeyPath, setKeyPermissions, sign, verify };
225
- //# sourceMappingURL=chunk-VC3BBBBO.js.map
226
- //# sourceMappingURL=chunk-VC3BBBBO.js.map
232
+ export { checkOpenSSL, generateKeyPair, getDefaultPrivateKeyPath, getDefaultPublicKeyPath, getDefaultYubiKeyEncryptedKeyPath, setKeyPermissions, sign, verify };
233
+ //# sourceMappingURL=chunk-T3NLSO5B.js.map
234
+ //# sourceMappingURL=chunk-T3NLSO5B.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/crypto.ts"],"names":[],"mappings":"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","file":"chunk-T3NLSO5B.js","sourcesContent":["/**\n * Cryptographic utilities for key generation, signing, and verification.\n *\n * @remarks\n * This module provides cryptographic operations using OpenSSL for key management\n * and signature verification. It uses RSA-2048 with SHA-256 for signatures,\n * which is universally supported across all OpenSSL and LibreSSL versions.\n *\n * @packageDocumentation\n */\n\nimport { spawn } from 'node:child_process'\nimport * as fs from 'node:fs/promises'\nimport * as path from 'node:path'\nimport * as os from 'node:os'\n\n/**\n * Paths to a generated keypair.\n * @public\n */\nexport interface KeyPaths {\n /** Path to the private key file */\n privatePath: string\n /** Path to the public key file */\n publicPath: string\n}\n\n/**\n * Options for key generation.\n * @public\n */\nexport interface KeygenOptions {\n /** Path for private key (default: OS-specific config dir) */\n privatePath?: string\n /** Path for public key (default: repo root) */\n publicPath?: string\n /** Overwrite existing keys (default: false) */\n force?: boolean\n}\n\n/**\n * Options for signing data.\n * @public\n */\nexport interface SignOptions {\n /** Path to the private key file (legacy) */\n privateKeyPath?: string\n /** Key provider to use for retrieving the private key */\n keyProvider?: import('./key-provider/types.js').KeyProvider\n /** Key reference for the provider */\n keyRef?: string\n /** Data to sign (string or Buffer) */\n data: string | Buffer\n}\n\n/**\n * Options for verifying signatures.\n * @public\n */\nexport interface VerifyOptions {\n /** Path to the public key file */\n publicKeyPath: string\n /** Original data that was signed */\n data: string | Buffer\n /** Base64-encoded signature to verify */\n signature: string\n}\n\n/**\n * Result from spawning an OpenSSL process.\n * @internal\n */\ninterface SpawnResult {\n /** Process exit code */\n exitCode: number\n /** Standard output as Buffer */\n stdout: Buffer\n /** Standard error as string */\n stderr: string\n}\n\n/**\n * Run OpenSSL with the given arguments.\n * @param args - Command-line arguments for OpenSSL\n * @param stdin - Optional data to write to stdin\n * @returns Process result with exit code and outputs\n * @internal\n */\nasync function runOpenSSL(args: string[], stdin?: Buffer): Promise<SpawnResult> {\n return new Promise((resolve, reject) => {\n const child = spawn('openssl', args, {\n stdio: ['pipe', 'pipe', 'pipe'],\n })\n\n const stdoutChunks: Buffer[] = []\n let stderr = ''\n\n child.stdout.on('data', (chunk: Buffer) => {\n stdoutChunks.push(chunk)\n })\n\n child.stderr.on('data', (chunk: Buffer) => {\n stderr += chunk.toString()\n })\n\n child.on('error', (err) => {\n reject(new Error(`Failed to spawn OpenSSL: ${err.message}`))\n })\n\n child.on('close', (code) => {\n resolve({\n exitCode: code ?? 1,\n stdout: Buffer.concat(stdoutChunks),\n stderr,\n })\n })\n\n if (stdin) {\n child.stdin.write(stdin)\n }\n child.stdin.end()\n })\n}\n\n/**\n * Check if OpenSSL is available and get version info.\n * @returns OpenSSL version string\n * @throws Error if OpenSSL is not available\n * @public\n */\nexport async function checkOpenSSL(): Promise<string> {\n const result = await runOpenSSL(['version'])\n\n if (result.exitCode !== 0) {\n throw new Error(`OpenSSL check failed: ${result.stderr}`)\n }\n\n return result.stdout.toString().trim()\n}\n\n/**\n * Cached result of OpenSSL availability check.\n * @internal\n */\nlet openSSLChecked = false\n\n/**\n * Ensure OpenSSL is available before performing cryptographic operations.\n * @throws Error with installation instructions if OpenSSL is not available\n * @internal\n */\nasync function ensureOpenSSLAvailable(): Promise<void> {\n if (openSSLChecked) {\n return\n }\n\n try {\n await checkOpenSSL()\n openSSLChecked = true\n } catch {\n throw new Error(\n 'OpenSSL is not installed or not in PATH. ' +\n 'Please install OpenSSL to use attest-it. ' +\n 'On macOS: brew install openssl. ' +\n 'On Ubuntu: apt-get install openssl',\n )\n }\n}\n\n/**\n * Get the default private key path based on OS.\n * - macOS/Linux: ~/.config/attest-it/private.pem\n * - Windows: %APPDATA%\\attest-it\\private.pem\n * @public\n */\nexport function getDefaultPrivateKeyPath(): string {\n const homeDir = os.homedir()\n\n if (process.platform === 'win32') {\n const appData = process.env.APPDATA ?? path.join(homeDir, 'AppData', 'Roaming')\n return path.join(appData, 'attest-it', 'private.pem')\n }\n\n return path.join(homeDir, '.config', 'attest-it', 'private.pem')\n}\n\n/**\n * Get the default public key path (in repo).\n * @public\n */\nexport function getDefaultPublicKeyPath(): string {\n return path.join(process.cwd(), 'attest-it-public.pem')\n}\n\n/**\n * Get the default YubiKey encrypted key path based on OS.\n * - macOS/Linux: ~/.config/attest-it/yubikey-private.enc\n * - Windows: %APPDATA%\\attest-it\\yubikey-private.enc\n * @public\n */\nexport function getDefaultYubiKeyEncryptedKeyPath(): string {\n const homeDir = os.homedir()\n\n if (process.platform === 'win32') {\n const appData = process.env.APPDATA ?? path.join(homeDir, 'AppData', 'Roaming')\n return path.join(appData, 'attest-it', 'yubikey-private.enc')\n }\n\n return path.join(homeDir, '.config', 'attest-it', 'yubikey-private.enc')\n}\n\n/**\n * Ensure a directory exists, creating it and parent directories if needed.\n * @param dirPath - Directory path to create\n * @internal\n */\nasync function ensureDir(dirPath: string): Promise<void> {\n try {\n await fs.mkdir(dirPath, { recursive: true })\n } catch (err) {\n if (err instanceof Error && 'code' in err && err.code !== 'EEXIST') {\n throw err\n }\n }\n}\n\n/**\n * Check if a file exists.\n * @param filePath - File path to check\n * @returns true if file exists\n * @internal\n */\nasync function fileExists(filePath: string): Promise<boolean> {\n try {\n await fs.access(filePath)\n return true\n } catch {\n return false\n }\n}\n\n/**\n * Clean up one or more files, ignoring errors if files don't exist.\n * @param paths - File paths to delete\n * @internal\n */\nasync function cleanupFiles(...paths: string[]): Promise<void> {\n for (const filePath of paths) {\n try {\n await fs.unlink(filePath)\n } catch {\n // Ignore cleanup errors - file may not exist\n }\n }\n}\n\n/**\n * Generate a new RSA-2048 keypair using OpenSSL.\n *\n * RSA-2048 with SHA-256 is used because it's universally supported across\n * all OpenSSL and LibreSSL versions, including older macOS systems.\n *\n * @param options - Generation options\n * @returns Paths to generated keys\n * @throws Error if OpenSSL fails or keys exist without force\n * @public\n */\nexport async function generateKeyPair(options: KeygenOptions = {}): Promise<KeyPaths> {\n // Ensure OpenSSL is available before proceeding\n await ensureOpenSSLAvailable()\n\n const {\n privatePath = getDefaultPrivateKeyPath(),\n publicPath = getDefaultPublicKeyPath(),\n force = false,\n } = options\n\n // Check if keys already exist\n const privateExists = await fileExists(privatePath)\n const publicExists = await fileExists(publicPath)\n\n if ((privateExists || publicExists) && !force) {\n const existing = [privateExists ? privatePath : null, publicExists ? publicPath : null].filter(\n Boolean,\n )\n throw new Error(\n `Key files already exist: ${existing.join(', ')}. Use force: true to overwrite.`,\n )\n }\n\n // Ensure parent directories exist\n await ensureDir(path.dirname(privatePath))\n await ensureDir(path.dirname(publicPath))\n\n try {\n // Generate RSA-2048 private key\n const genArgs = [\n 'genpkey',\n '-algorithm',\n 'RSA',\n '-pkeyopt',\n 'rsa_keygen_bits:2048',\n '-out',\n privatePath,\n ]\n\n const genResult = await runOpenSSL(genArgs)\n if (genResult.exitCode !== 0) {\n throw new Error(`Failed to generate private key: ${genResult.stderr}`)\n }\n\n // Set restrictive permissions on private key\n await setKeyPermissions(privatePath)\n\n // Extract public key\n const pubResult = await runOpenSSL(['pkey', '-in', privatePath, '-pubout', '-out', publicPath])\n\n if (pubResult.exitCode !== 0) {\n throw new Error(`Failed to extract public key: ${pubResult.stderr}`)\n }\n\n return {\n privatePath,\n publicPath,\n }\n } catch (err) {\n // Clean up both key files on any failure\n await cleanupFiles(privatePath, publicPath)\n throw err\n }\n}\n\n/**\n * Sign data using an RSA private key with SHA-256.\n *\n * Uses `openssl dgst -sha256 -sign` which is universally supported across\n * all OpenSSL and LibreSSL versions.\n *\n * @param options - Signing options\n * @returns Base64-encoded signature\n * @throws Error if signing fails\n * @public\n */\nexport async function sign(options: SignOptions): Promise<string> {\n // Ensure OpenSSL is available before proceeding\n await ensureOpenSSLAvailable()\n\n const { privateKeyPath, keyProvider, keyRef, data } = options\n\n // Determine which key path to use\n let effectiveKeyPath: string\n let cleanup: (() => Promise<void>) | undefined\n\n if (keyProvider && keyRef) {\n // Use key provider to retrieve the key\n const result = await keyProvider.getPrivateKey(keyRef)\n effectiveKeyPath = result.keyPath\n cleanup = result.cleanup\n } else if (privateKeyPath) {\n // Legacy path: use privateKeyPath directly\n effectiveKeyPath = privateKeyPath\n } else {\n throw new Error(\n 'Either privateKeyPath or both keyProvider and keyRef must be provided for signing',\n )\n }\n\n try {\n // Check if private key exists\n if (!(await fileExists(effectiveKeyPath))) {\n throw new Error(`Private key not found: ${effectiveKeyPath}`)\n }\n\n // Convert data to Buffer\n const dataBuffer = typeof data === 'string' ? Buffer.from(data, 'utf8') : data\n\n // OpenSSL dgst cannot handle empty files, so we need to add a single byte\n // for empty data and document this limitation\n const processBuffer = dataBuffer.length === 0 ? Buffer.from([0x00]) : dataBuffer\n\n // Create temporary directory with OS-level uniqueness guarantees\n // This prevents TOCTOU race conditions that Math.random() would allow\n const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'attest-it-'))\n const dataFile = path.join(tmpDir, 'data.bin')\n const sigFile = path.join(tmpDir, 'sig.bin')\n\n try {\n // Write data to temp file\n await fs.writeFile(dataFile, processBuffer)\n\n // Sign using openssl dgst -sha256 (cross-platform compatible)\n const signArgs = ['dgst', '-sha256', '-sign', effectiveKeyPath, '-out', sigFile, dataFile]\n const result = await runOpenSSL(signArgs)\n\n if (result.exitCode !== 0) {\n throw new Error(`Failed to sign data: ${result.stderr}`)\n }\n\n // Read the signature\n const sigBuffer = await fs.readFile(sigFile)\n return sigBuffer.toString('base64')\n } finally {\n // Clean up temp directory and all files within it\n try {\n await fs.rm(tmpDir, { recursive: true, force: true })\n } catch {\n // Ignore cleanup errors - OS will eventually clean tmpdir\n }\n }\n } finally {\n // Always call cleanup function if provided\n if (cleanup) {\n await cleanup()\n }\n }\n}\n\n/**\n * Verify a signature using an RSA public key with SHA-256.\n *\n * Uses `openssl dgst -sha256 -verify` which is universally supported across\n * all OpenSSL and LibreSSL versions.\n *\n * @param options - Verification options\n * @returns true if signature is valid\n * @throws Error if verification fails (not just invalid signature)\n * @public\n */\nexport async function verify(options: VerifyOptions): Promise<boolean> {\n // Ensure OpenSSL is available before proceeding\n await ensureOpenSSLAvailable()\n\n const { publicKeyPath, data, signature } = options\n\n // Check if public key exists\n if (!(await fileExists(publicKeyPath))) {\n throw new Error(`Public key not found: ${publicKeyPath}`)\n }\n\n // Convert data to Buffer\n const dataBuffer = typeof data === 'string' ? Buffer.from(data, 'utf8') : data\n\n // OpenSSL dgst cannot handle empty files, so we use the same workaround\n // as in sign() - add a single byte for empty data\n const processBuffer = dataBuffer.length === 0 ? Buffer.from([0x00]) : dataBuffer\n\n // Decode signature from base64\n const sigBuffer = Buffer.from(signature, 'base64')\n\n // Create temporary directory with OS-level uniqueness guarantees\n // This prevents TOCTOU race conditions that Math.random() would allow\n const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'attest-it-'))\n const dataFile = path.join(tmpDir, 'data.bin')\n const sigFile = path.join(tmpDir, 'sig.bin')\n\n try {\n // Write data and signature to temp files\n await fs.writeFile(dataFile, processBuffer)\n await fs.writeFile(sigFile, sigBuffer)\n\n // Verify using openssl dgst -sha256 (cross-platform compatible)\n const verifyArgs = [\n 'dgst',\n '-sha256',\n '-verify',\n publicKeyPath,\n '-signature',\n sigFile,\n dataFile,\n ]\n const result = await runOpenSSL(verifyArgs)\n\n // dgst -verify: Exit code 0 means valid, non-0 means invalid\n // Output contains \"Verified OK\" on success\n return result.exitCode === 0 && result.stdout.toString().includes('Verified OK')\n } finally {\n // Clean up temp directory and all files within it\n try {\n await fs.rm(tmpDir, { recursive: true, force: true })\n } catch {\n // Ignore cleanup errors - OS will eventually clean tmpdir\n }\n }\n}\n\n/**\n * Set restrictive permissions on a private key file.\n * @param keyPath - Path to the private key\n * @public\n */\nexport async function setKeyPermissions(keyPath: string): Promise<void> {\n // On Windows, use fs.chmod which has limited effect\n // On Unix, set to 0o600 (read/write for owner only)\n if (process.platform === 'win32') {\n // Windows doesn't support Unix-style permissions in the same way\n // But we still call chmod for consistency\n await fs.chmod(keyPath, 0o600)\n } else {\n await fs.chmod(keyPath, 0o600)\n }\n}\n"]}
@@ -817,6 +817,14 @@ export declare function getDefaultPrivateKeyPath(): string;
817
817
  */
818
818
  export declare function getDefaultPublicKeyPath(): string;
819
819
 
820
+ /**
821
+ * Get the default YubiKey encrypted key path based on OS.
822
+ * - macOS/Linux: ~/.config/attest-it/yubikey-private.enc
823
+ * - Windows: %APPDATA%\attest-it\yubikey-private.enc
824
+ * @public
825
+ */
826
+ export declare function getDefaultYubiKeyEncryptedKeyPath(): string;
827
+
820
828
  /**
821
829
  * Get the gate configuration for a given gate ID.
822
830
  *
@@ -827,6 +835,18 @@ export declare function getDefaultPublicKeyPath(): string;
827
835
  */
828
836
  export declare function getGate(config: AttestItConfig, gateId: string): GateConfig | undefined;
829
837
 
838
+ /**
839
+ * Get the user's home public keys directory.
840
+ *
841
+ * This returns ~/.attest-it/public-keys, which is different from the
842
+ * config directory (~/.config/attest-it). The public keys directory
843
+ * is designed to be easily shareable and discoverable.
844
+ *
845
+ * @returns Path to the user's home public keys directory
846
+ * @public
847
+ */
848
+ export declare function getHomePublicKeysDir(): string;
849
+
830
850
  /**
831
851
  * Get the path to the local config file.
832
852
  *
@@ -855,6 +875,19 @@ export declare function getPreference<K extends keyof UserPreferences>(key: K):
855
875
  */
856
876
  export declare function getPreferencesPath(): string;
857
877
 
878
+ /**
879
+ * Get the project public keys directory.
880
+ *
881
+ * This returns .attest-it/public-keys relative to the given project root.
882
+ * The project public keys directory is used for CI/GitHub Actions to
883
+ * verify attestation seals.
884
+ *
885
+ * @param projectRoot - The project root directory (defaults to cwd)
886
+ * @returns Path to the project public keys directory
887
+ * @public
888
+ */
889
+ export declare function getProjectPublicKeysDir(projectRoot?: string): string;
890
+
858
891
  /**
859
892
  * Extract the public key from an Ed25519 private key.
860
893
  *
@@ -865,6 +898,15 @@ export declare function getPreferencesPath(): string;
865
898
  */
866
899
  export declare function getPublicKeyFromPrivate(privateKeyPem: string): string;
867
900
 
901
+ /**
902
+ * Check if a project has attest-it configuration.
903
+ *
904
+ * @param projectRoot - The project root directory (defaults to cwd)
905
+ * @returns True if the project has .attest-it/config.yaml or similar
906
+ * @public
907
+ */
908
+ export declare function hasProjectConfig(projectRoot?: string): boolean;
909
+
868
910
  /**
869
911
  * A single identity configuration.
870
912
  * @public
@@ -1262,6 +1304,8 @@ export declare function listPackageFiles(packages: string[], ignore?: string[],
1262
1304
  url: string;
1263
1305
  /** User UUID */
1264
1306
  user_uuid: string;
1307
+ /** Human-readable account name (e.g., "North Family") */
1308
+ name?: string;
1265
1309
  }
1266
1310
 
1267
1311
  /**
@@ -1292,7 +1336,7 @@ export declare function listPackageFiles(packages: string[], ignore?: string[],
1292
1336
  static isInstalled(): Promise<boolean>;
1293
1337
  /**
1294
1338
  * List all 1Password accounts.
1295
- * @returns Array of account information
1339
+ * @returns Array of account information including human-readable names
1296
1340
  */
1297
1341
  static listAccounts(): Promise<OnePasswordAccount[]>;
1298
1342
  /**
@@ -1891,6 +1935,49 @@ export declare function listPackageFiles(packages: string[], ignore?: string[],
1891
1935
  */
1892
1936
  export declare function savePreferences(preferences: UserPreferences): Promise<void>;
1893
1937
 
1938
+ /**
1939
+ * Save a public key to the user's home directory and optionally to the project directory.
1940
+ *
1941
+ * This saves the public key as a base64-encoded string (matching the format in config.yaml)
1942
+ * to:
1943
+ * 1. ~/.attest-it/public-keys/<slug>.pem (always)
1944
+ * 2. ./.attest-it/public-keys/<slug>.pem (if project has attest-it config)
1945
+ *
1946
+ * @param slug - The identity slug (used for the filename)
1947
+ * @param publicKey - The base64-encoded public key
1948
+ * @param projectRoot - The project root directory (defaults to cwd)
1949
+ * @returns Paths where the key was saved
1950
+ * @public
1951
+ */
1952
+ export declare function savePublicKey(slug: string, publicKey: string, projectRoot?: string): Promise<SavePublicKeyResult>;
1953
+
1954
+ /**
1955
+ * Result from saving public keys.
1956
+ * @public
1957
+ */
1958
+ export declare interface SavePublicKeyResult {
1959
+ /** Path where the key was saved in the user's home directory */
1960
+ homePath: string;
1961
+ /** Path where the key was saved in the project directory, if applicable */
1962
+ projectPath?: string;
1963
+ }
1964
+
1965
+ /**
1966
+ * Save a public key to the user's home directory and optionally to the project directory (sync).
1967
+ *
1968
+ * This saves the public key as a base64-encoded string (matching the format in config.yaml)
1969
+ * to:
1970
+ * 1. ~/.attest-it/public-keys/<slug>.pem (always)
1971
+ * 2. ./.attest-it/public-keys/<slug>.pem (if project has attest-it config)
1972
+ *
1973
+ * @param slug - The identity slug (used for the filename)
1974
+ * @param publicKey - The base64-encoded public key
1975
+ * @param projectRoot - The project root directory (defaults to cwd)
1976
+ * @returns Paths where the key was saved
1977
+ * @public
1978
+ */
1979
+ export declare function savePublicKeySync(slug: string, publicKey: string, projectRoot?: string): SavePublicKeyResult;
1980
+
1894
1981
  /**
1895
1982
  * A seal represents a cryptographic attestation that a gate's fingerprint
1896
1983
  * was signed by an authorized team member.
@@ -817,6 +817,14 @@ export declare function getDefaultPrivateKeyPath(): string;
817
817
  */
818
818
  export declare function getDefaultPublicKeyPath(): string;
819
819
 
820
+ /**
821
+ * Get the default YubiKey encrypted key path based on OS.
822
+ * - macOS/Linux: ~/.config/attest-it/yubikey-private.enc
823
+ * - Windows: %APPDATA%\attest-it\yubikey-private.enc
824
+ * @public
825
+ */
826
+ export declare function getDefaultYubiKeyEncryptedKeyPath(): string;
827
+
820
828
  /**
821
829
  * Get the gate configuration for a given gate ID.
822
830
  *
@@ -827,6 +835,18 @@ export declare function getDefaultPublicKeyPath(): string;
827
835
  */
828
836
  export declare function getGate(config: AttestItConfig, gateId: string): GateConfig | undefined;
829
837
 
838
+ /**
839
+ * Get the user's home public keys directory.
840
+ *
841
+ * This returns ~/.attest-it/public-keys, which is different from the
842
+ * config directory (~/.config/attest-it). The public keys directory
843
+ * is designed to be easily shareable and discoverable.
844
+ *
845
+ * @returns Path to the user's home public keys directory
846
+ * @public
847
+ */
848
+ export declare function getHomePublicKeysDir(): string;
849
+
830
850
  /**
831
851
  * Get the path to the local config file.
832
852
  *
@@ -855,6 +875,19 @@ export declare function getPreference<K extends keyof UserPreferences>(key: K):
855
875
  */
856
876
  export declare function getPreferencesPath(): string;
857
877
 
878
+ /**
879
+ * Get the project public keys directory.
880
+ *
881
+ * This returns .attest-it/public-keys relative to the given project root.
882
+ * The project public keys directory is used for CI/GitHub Actions to
883
+ * verify attestation seals.
884
+ *
885
+ * @param projectRoot - The project root directory (defaults to cwd)
886
+ * @returns Path to the project public keys directory
887
+ * @public
888
+ */
889
+ export declare function getProjectPublicKeysDir(projectRoot?: string): string;
890
+
858
891
  /**
859
892
  * Extract the public key from an Ed25519 private key.
860
893
  *
@@ -865,6 +898,15 @@ export declare function getPreferencesPath(): string;
865
898
  */
866
899
  export declare function getPublicKeyFromPrivate(privateKeyPem: string): string;
867
900
 
901
+ /**
902
+ * Check if a project has attest-it configuration.
903
+ *
904
+ * @param projectRoot - The project root directory (defaults to cwd)
905
+ * @returns True if the project has .attest-it/config.yaml or similar
906
+ * @public
907
+ */
908
+ export declare function hasProjectConfig(projectRoot?: string): boolean;
909
+
868
910
  /**
869
911
  * A single identity configuration.
870
912
  * @public
@@ -1262,6 +1304,8 @@ export declare function listPackageFiles(packages: string[], ignore?: string[],
1262
1304
  url: string;
1263
1305
  /** User UUID */
1264
1306
  user_uuid: string;
1307
+ /** Human-readable account name (e.g., "North Family") */
1308
+ name?: string;
1265
1309
  }
1266
1310
 
1267
1311
  /**
@@ -1292,7 +1336,7 @@ export declare function listPackageFiles(packages: string[], ignore?: string[],
1292
1336
  static isInstalled(): Promise<boolean>;
1293
1337
  /**
1294
1338
  * List all 1Password accounts.
1295
- * @returns Array of account information
1339
+ * @returns Array of account information including human-readable names
1296
1340
  */
1297
1341
  static listAccounts(): Promise<OnePasswordAccount[]>;
1298
1342
  /**
@@ -1891,6 +1935,49 @@ export declare function listPackageFiles(packages: string[], ignore?: string[],
1891
1935
  */
1892
1936
  export declare function savePreferences(preferences: UserPreferences): Promise<void>;
1893
1937
 
1938
+ /**
1939
+ * Save a public key to the user's home directory and optionally to the project directory.
1940
+ *
1941
+ * This saves the public key as a base64-encoded string (matching the format in config.yaml)
1942
+ * to:
1943
+ * 1. ~/.attest-it/public-keys/<slug>.pem (always)
1944
+ * 2. ./.attest-it/public-keys/<slug>.pem (if project has attest-it config)
1945
+ *
1946
+ * @param slug - The identity slug (used for the filename)
1947
+ * @param publicKey - The base64-encoded public key
1948
+ * @param projectRoot - The project root directory (defaults to cwd)
1949
+ * @returns Paths where the key was saved
1950
+ * @public
1951
+ */
1952
+ export declare function savePublicKey(slug: string, publicKey: string, projectRoot?: string): Promise<SavePublicKeyResult>;
1953
+
1954
+ /**
1955
+ * Result from saving public keys.
1956
+ * @public
1957
+ */
1958
+ export declare interface SavePublicKeyResult {
1959
+ /** Path where the key was saved in the user's home directory */
1960
+ homePath: string;
1961
+ /** Path where the key was saved in the project directory, if applicable */
1962
+ projectPath?: string;
1963
+ }
1964
+
1965
+ /**
1966
+ * Save a public key to the user's home directory and optionally to the project directory (sync).
1967
+ *
1968
+ * This saves the public key as a base64-encoded string (matching the format in config.yaml)
1969
+ * to:
1970
+ * 1. ~/.attest-it/public-keys/<slug>.pem (always)
1971
+ * 2. ./.attest-it/public-keys/<slug>.pem (if project has attest-it config)
1972
+ *
1973
+ * @param slug - The identity slug (used for the filename)
1974
+ * @param publicKey - The base64-encoded public key
1975
+ * @param projectRoot - The project root directory (defaults to cwd)
1976
+ * @returns Paths where the key was saved
1977
+ * @public
1978
+ */
1979
+ export declare function savePublicKeySync(slug: string, publicKey: string, projectRoot?: string): SavePublicKeyResult;
1980
+
1894
1981
  /**
1895
1982
  * A seal represents a cryptographic attestation that a gate's fingerprint
1896
1983
  * was signed by an authorized team member.
@@ -817,6 +817,14 @@ export declare function getDefaultPrivateKeyPath(): string;
817
817
  */
818
818
  export declare function getDefaultPublicKeyPath(): string;
819
819
 
820
+ /**
821
+ * Get the default YubiKey encrypted key path based on OS.
822
+ * - macOS/Linux: ~/.config/attest-it/yubikey-private.enc
823
+ * - Windows: %APPDATA%\attest-it\yubikey-private.enc
824
+ * @public
825
+ */
826
+ export declare function getDefaultYubiKeyEncryptedKeyPath(): string;
827
+
820
828
  /**
821
829
  * Get the gate configuration for a given gate ID.
822
830
  *
@@ -827,6 +835,18 @@ export declare function getDefaultPublicKeyPath(): string;
827
835
  */
828
836
  export declare function getGate(config: AttestItConfig, gateId: string): GateConfig | undefined;
829
837
 
838
+ /**
839
+ * Get the user's home public keys directory.
840
+ *
841
+ * This returns ~/.attest-it/public-keys, which is different from the
842
+ * config directory (~/.config/attest-it). The public keys directory
843
+ * is designed to be easily shareable and discoverable.
844
+ *
845
+ * @returns Path to the user's home public keys directory
846
+ * @public
847
+ */
848
+ export declare function getHomePublicKeysDir(): string;
849
+
830
850
  /**
831
851
  * Get the path to the local config file.
832
852
  *
@@ -855,6 +875,19 @@ export declare function getPreference<K extends keyof UserPreferences>(key: K):
855
875
  */
856
876
  export declare function getPreferencesPath(): string;
857
877
 
878
+ /**
879
+ * Get the project public keys directory.
880
+ *
881
+ * This returns .attest-it/public-keys relative to the given project root.
882
+ * The project public keys directory is used for CI/GitHub Actions to
883
+ * verify attestation seals.
884
+ *
885
+ * @param projectRoot - The project root directory (defaults to cwd)
886
+ * @returns Path to the project public keys directory
887
+ * @public
888
+ */
889
+ export declare function getProjectPublicKeysDir(projectRoot?: string): string;
890
+
858
891
  /**
859
892
  * Extract the public key from an Ed25519 private key.
860
893
  *
@@ -865,6 +898,15 @@ export declare function getPreferencesPath(): string;
865
898
  */
866
899
  export declare function getPublicKeyFromPrivate(privateKeyPem: string): string;
867
900
 
901
+ /**
902
+ * Check if a project has attest-it configuration.
903
+ *
904
+ * @param projectRoot - The project root directory (defaults to cwd)
905
+ * @returns True if the project has .attest-it/config.yaml or similar
906
+ * @public
907
+ */
908
+ export declare function hasProjectConfig(projectRoot?: string): boolean;
909
+
868
910
  /**
869
911
  * A single identity configuration.
870
912
  * @public
@@ -1262,6 +1304,8 @@ export declare function listPackageFiles(packages: string[], ignore?: string[],
1262
1304
  url: string;
1263
1305
  /** User UUID */
1264
1306
  user_uuid: string;
1307
+ /** Human-readable account name (e.g., "North Family") */
1308
+ name?: string;
1265
1309
  }
1266
1310
 
1267
1311
  /**
@@ -1292,7 +1336,7 @@ export declare function listPackageFiles(packages: string[], ignore?: string[],
1292
1336
  static isInstalled(): Promise<boolean>;
1293
1337
  /**
1294
1338
  * List all 1Password accounts.
1295
- * @returns Array of account information
1339
+ * @returns Array of account information including human-readable names
1296
1340
  */
1297
1341
  static listAccounts(): Promise<OnePasswordAccount[]>;
1298
1342
  /**
@@ -1891,6 +1935,49 @@ export declare function listPackageFiles(packages: string[], ignore?: string[],
1891
1935
  */
1892
1936
  export declare function savePreferences(preferences: UserPreferences): Promise<void>;
1893
1937
 
1938
+ /**
1939
+ * Save a public key to the user's home directory and optionally to the project directory.
1940
+ *
1941
+ * This saves the public key as a base64-encoded string (matching the format in config.yaml)
1942
+ * to:
1943
+ * 1. ~/.attest-it/public-keys/<slug>.pem (always)
1944
+ * 2. ./.attest-it/public-keys/<slug>.pem (if project has attest-it config)
1945
+ *
1946
+ * @param slug - The identity slug (used for the filename)
1947
+ * @param publicKey - The base64-encoded public key
1948
+ * @param projectRoot - The project root directory (defaults to cwd)
1949
+ * @returns Paths where the key was saved
1950
+ * @public
1951
+ */
1952
+ export declare function savePublicKey(slug: string, publicKey: string, projectRoot?: string): Promise<SavePublicKeyResult>;
1953
+
1954
+ /**
1955
+ * Result from saving public keys.
1956
+ * @public
1957
+ */
1958
+ export declare interface SavePublicKeyResult {
1959
+ /** Path where the key was saved in the user's home directory */
1960
+ homePath: string;
1961
+ /** Path where the key was saved in the project directory, if applicable */
1962
+ projectPath?: string;
1963
+ }
1964
+
1965
+ /**
1966
+ * Save a public key to the user's home directory and optionally to the project directory (sync).
1967
+ *
1968
+ * This saves the public key as a base64-encoded string (matching the format in config.yaml)
1969
+ * to:
1970
+ * 1. ~/.attest-it/public-keys/<slug>.pem (always)
1971
+ * 2. ./.attest-it/public-keys/<slug>.pem (if project has attest-it config)
1972
+ *
1973
+ * @param slug - The identity slug (used for the filename)
1974
+ * @param publicKey - The base64-encoded public key
1975
+ * @param projectRoot - The project root directory (defaults to cwd)
1976
+ * @returns Paths where the key was saved
1977
+ * @public
1978
+ */
1979
+ export declare function savePublicKeySync(slug: string, publicKey: string, projectRoot?: string): SavePublicKeyResult;
1980
+
1894
1981
  /**
1895
1982
  * A seal represents a cryptographic attestation that a gate's fingerprint
1896
1983
  * was signed by an authorized team member.
@@ -817,6 +817,14 @@ export declare function getDefaultPrivateKeyPath(): string;
817
817
  */
818
818
  export declare function getDefaultPublicKeyPath(): string;
819
819
 
820
+ /**
821
+ * Get the default YubiKey encrypted key path based on OS.
822
+ * - macOS/Linux: ~/.config/attest-it/yubikey-private.enc
823
+ * - Windows: %APPDATA%\attest-it\yubikey-private.enc
824
+ * @public
825
+ */
826
+ export declare function getDefaultYubiKeyEncryptedKeyPath(): string;
827
+
820
828
  /**
821
829
  * Get the gate configuration for a given gate ID.
822
830
  *
@@ -827,6 +835,18 @@ export declare function getDefaultPublicKeyPath(): string;
827
835
  */
828
836
  export declare function getGate(config: AttestItConfig, gateId: string): GateConfig | undefined;
829
837
 
838
+ /**
839
+ * Get the user's home public keys directory.
840
+ *
841
+ * This returns ~/.attest-it/public-keys, which is different from the
842
+ * config directory (~/.config/attest-it). The public keys directory
843
+ * is designed to be easily shareable and discoverable.
844
+ *
845
+ * @returns Path to the user's home public keys directory
846
+ * @public
847
+ */
848
+ export declare function getHomePublicKeysDir(): string;
849
+
830
850
  /**
831
851
  * Get the path to the local config file.
832
852
  *
@@ -855,6 +875,19 @@ export declare function getPreference<K extends keyof UserPreferences>(key: K):
855
875
  */
856
876
  export declare function getPreferencesPath(): string;
857
877
 
878
+ /**
879
+ * Get the project public keys directory.
880
+ *
881
+ * This returns .attest-it/public-keys relative to the given project root.
882
+ * The project public keys directory is used for CI/GitHub Actions to
883
+ * verify attestation seals.
884
+ *
885
+ * @param projectRoot - The project root directory (defaults to cwd)
886
+ * @returns Path to the project public keys directory
887
+ * @public
888
+ */
889
+ export declare function getProjectPublicKeysDir(projectRoot?: string): string;
890
+
858
891
  /**
859
892
  * Extract the public key from an Ed25519 private key.
860
893
  *
@@ -865,6 +898,15 @@ export declare function getPreferencesPath(): string;
865
898
  */
866
899
  export declare function getPublicKeyFromPrivate(privateKeyPem: string): string;
867
900
 
901
+ /**
902
+ * Check if a project has attest-it configuration.
903
+ *
904
+ * @param projectRoot - The project root directory (defaults to cwd)
905
+ * @returns True if the project has .attest-it/config.yaml or similar
906
+ * @public
907
+ */
908
+ export declare function hasProjectConfig(projectRoot?: string): boolean;
909
+
868
910
  /**
869
911
  * A single identity configuration.
870
912
  * @public
@@ -1262,6 +1304,8 @@ export declare function listPackageFiles(packages: string[], ignore?: string[],
1262
1304
  url: string;
1263
1305
  /** User UUID */
1264
1306
  user_uuid: string;
1307
+ /** Human-readable account name (e.g., "North Family") */
1308
+ name?: string;
1265
1309
  }
1266
1310
 
1267
1311
  /**
@@ -1292,7 +1336,7 @@ export declare function listPackageFiles(packages: string[], ignore?: string[],
1292
1336
  static isInstalled(): Promise<boolean>;
1293
1337
  /**
1294
1338
  * List all 1Password accounts.
1295
- * @returns Array of account information
1339
+ * @returns Array of account information including human-readable names
1296
1340
  */
1297
1341
  static listAccounts(): Promise<OnePasswordAccount[]>;
1298
1342
  /**
@@ -1891,6 +1935,49 @@ export declare function listPackageFiles(packages: string[], ignore?: string[],
1891
1935
  */
1892
1936
  export declare function savePreferences(preferences: UserPreferences): Promise<void>;
1893
1937
 
1938
+ /**
1939
+ * Save a public key to the user's home directory and optionally to the project directory.
1940
+ *
1941
+ * This saves the public key as a base64-encoded string (matching the format in config.yaml)
1942
+ * to:
1943
+ * 1. ~/.attest-it/public-keys/<slug>.pem (always)
1944
+ * 2. ./.attest-it/public-keys/<slug>.pem (if project has attest-it config)
1945
+ *
1946
+ * @param slug - The identity slug (used for the filename)
1947
+ * @param publicKey - The base64-encoded public key
1948
+ * @param projectRoot - The project root directory (defaults to cwd)
1949
+ * @returns Paths where the key was saved
1950
+ * @public
1951
+ */
1952
+ export declare function savePublicKey(slug: string, publicKey: string, projectRoot?: string): Promise<SavePublicKeyResult>;
1953
+
1954
+ /**
1955
+ * Result from saving public keys.
1956
+ * @public
1957
+ */
1958
+ export declare interface SavePublicKeyResult {
1959
+ /** Path where the key was saved in the user's home directory */
1960
+ homePath: string;
1961
+ /** Path where the key was saved in the project directory, if applicable */
1962
+ projectPath?: string;
1963
+ }
1964
+
1965
+ /**
1966
+ * Save a public key to the user's home directory and optionally to the project directory (sync).
1967
+ *
1968
+ * This saves the public key as a base64-encoded string (matching the format in config.yaml)
1969
+ * to:
1970
+ * 1. ~/.attest-it/public-keys/<slug>.pem (always)
1971
+ * 2. ./.attest-it/public-keys/<slug>.pem (if project has attest-it config)
1972
+ *
1973
+ * @param slug - The identity slug (used for the filename)
1974
+ * @param publicKey - The base64-encoded public key
1975
+ * @param projectRoot - The project root directory (defaults to cwd)
1976
+ * @returns Paths where the key was saved
1977
+ * @public
1978
+ */
1979
+ export declare function savePublicKeySync(slug: string, publicKey: string, projectRoot?: string): SavePublicKeyResult;
1980
+
1894
1981
  /**
1895
1982
  * A seal represents a cryptographic attestation that a gate's fingerprint
1896
1983
  * was signed by an authorized team member.
@@ -0,0 +1,3 @@
1
+ export { checkOpenSSL, generateKeyPair, getDefaultPrivateKeyPath, getDefaultPublicKeyPath, getDefaultYubiKeyEncryptedKeyPath, setKeyPermissions, sign, verify } from './chunk-T3NLSO5B.js';
2
+ //# sourceMappingURL=crypto-VT6YNHUE.js.map
3
+ //# sourceMappingURL=crypto-VT6YNHUE.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"crypto-CE2YISRD.js"}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"crypto-VT6YNHUE.js"}