{"id":18030097,"url":"https://github.com/humphd/sops-age","last_synced_at":"2025-09-03T02:17:43.364Z","repository":{"id":229929850,"uuid":"776929539","full_name":"humphd/sops-age","owner":"humphd","description":"JavaScript library to decrypt files encrypted with SOPS and age","archived":false,"fork":false,"pushed_at":"2025-06-03T15:47:34.000Z","size":413,"stargazers_count":5,"open_issues_count":3,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-08-02T02:53:13.303Z","etag":null,"topics":["age","bun","decryption","deno","sops"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/sops-age","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/humphd.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-03-24T20:33:53.000Z","updated_at":"2025-07-24T16:21:40.000Z","dependencies_parsed_at":null,"dependency_job_id":"927047f3-d726-4dd2-b70d-691422f13c2d","html_url":"https://github.com/humphd/sops-age","commit_stats":null,"previous_names":["humphd/sops-age"],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/humphd/sops-age","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/humphd%2Fsops-age","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/humphd%2Fsops-age/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/humphd%2Fsops-age/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/humphd%2Fsops-age/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/humphd","download_url":"https://codeload.github.com/humphd/sops-age/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/humphd%2Fsops-age/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273377237,"owners_count":25094547,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-03T02:00:09.631Z","response_time":76,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["age","bun","decryption","deno","sops"],"created_at":"2024-10-30T09:13:16.525Z","updated_at":"2025-09-03T02:17:43.318Z","avatar_url":"https://github.com/humphd.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# sops-age\n\n`sops-age` is a TypeScript library designed to decrypt files encrypted with [SOPS](https://github.com/getsops/sops) (Secrets OPerationS) and the [age](https://github.com/FiloSottile/age) encryption tool. This library provides an easy way to decrypt environment variables, configuration files, and other sensitive data encrypted with SOPS and age in your applications. It works in most JavaScript runtimes (node.js, the browser, Deno, Bun, etc).\n\n## Features\n\n- Supports decryption of SOPS files encrypted with `age`\n- Automatic age key discovery, following SOPS conventions\n- SSH key support, automatically converting Ed25519 and RSA SSH keys to age format\n- Compatible with various file formats including `.env`, `.json`, and `.yaml`\n- Supports multiple input types (`string`, `Buffer`, `File`, `Blob`, streams, etc.)\n- Works across different JavaScript runtimes (Node.js, Deno, Bun, browser)\n- Simple, unified API for decrypting SOPS data from files, URLs, or raw content\n- Automatic file type detection with optional manual override\n\n## Installation\n\nInstall `sops-age` using your preferred package manager:\n\n```sh\n# npm\nnpm install sops-age\n\n# pnpm\npnpm add sops-age\n\n# yarn\nyarn add sops-age\n```\n\n## Usage\n\nThe library can be used in various JavaScript environments and supports multiple module formats:\n\n### ESM (recommended)\n\n```js\nimport { decryptSops } from \"sops-age\";\n\n// Decrypt from a local file (keys auto-discovered from env and file system)\nconst config = await decryptSops({\n  path: \"./config.enc.json\",\n});\n\n// Or with explicit age key\nconst config = await decryptSops({\n  path: \"./config.enc.json\",\n  secretKey: \"AGE-SECRET-KEY-1qgdy...\",\n});\n```\n\n### CommonJS\n\n```js\nconst { decryptSops } = require(\"sops-age\");\n\n// Decrypt from a URL\nconst config = await decryptSops({\n  url: \"https://example.com/config.enc.yaml\",\n  secretKey: \"AGE-SECRET-KEY-1qgdy...\",\n});\n```\n\n### Browser (CDN)\n\n```html\n\u003c!-- Add to your HTML --\u003e\n\u003cscript src=\"https://unpkg.com/sops-age/dist/index.global.js\"\u003e\u003c/script\u003e\n\n\u003cscript\u003e\n  // The library is available as window.decryptSops\n  async function loadConfig() {\n    const config = await decryptSops({\n      url: \"https://example.com/config.enc.json\",\n      secretKey: \"AGE-SECRET-KEY-1qgdy...\",\n    });\n    console.log(config);\n  }\n\u003c/script\u003e\n```\n\n### TypeScript\n\nThe library includes TypeScript type definitions:\n\n```ts\nimport { decryptSops, type DecryptSopsOptions } from \"sops-age\";\n\nconst options: DecryptSopsOptions = {\n  secretKey: \"AGE-SECRET-KEY-1qgdy...\",\n  fileType: \"json\",\n};\n\nconst config = await decryptSops(jsonString, options);\n```\n\n### Basic Usage\n\nThe library provides a unified `decryptSops` function that can handle various input types:\n\n```js\nimport { decryptSops } from \"sops-age\";\n\n// Decrypt from a local file, auto-discovering age keys\nconst config = await decryptSops({\n  path: \"./config.enc.json\",\n});\n\n// Decrypt from a URL with explicit age key\nconst remoteConfig = await decryptSops({\n  url: \"https://example.com/config.enc.yaml\",\n  secretKey: \"AGE-SECRET-KEY-1qgdy...\",\n});\n\n// Decrypt from string content\nconst content = '{\"sops\": {...}}';\nconst data = await decryptSops(content, {\n  secretKey: \"AGE-SECRET-KEY-1qgdy...\",\n  fileType: \"json\",\n});\n```\n\n### Supported File Types\n\n`sops-age` supports the following file types:\n\n- `.env`\n- `.json`\n- `.yaml` / `.yml`\n\nThe library automatically detects the file type based on file extension or content. You can also manually specify the file type using the `fileType` option.\n\n## Input Types\n\n`sops-age` supports various input types for the SOPS-encrypted content:\n\n- `string`: Raw string content of a SOPS file\n- `File`: File object (in browser environments)\n- `Blob`: Binary data\n- `ArrayBuffer`: Raw binary data\n- `Uint8Array`: Typed array of bytes\n- `Buffer`: Node.js Buffer (in Node.js environment)\n- `ReadableStream\u003cUint8Array\u003e`: Stream of binary data\n\n## Age Key Discovery\n\n`sops-age` automatically discovers age keys using the same logic as SOPS itself. When no `secretKey` is explicitly provided, the library will search for keys in the following order:\n\n### 1. SSH Keys (Converted to Age Format)\n\nThe library can automatically convert SSH private keys to age format:\n\n- **Environment variable**: `SOPS_AGE_SSH_PRIVATE_KEY_FILE` - path to SSH private key\n- **Default locations**: `~/.ssh/id_ed25519` and `~/.ssh/id_rsa` (in that order)\n- **Supported types**: Ed25519 and RSA keys\n\n```js\n// Set environment variable to use specific SSH key\nprocess.env.SOPS_AGE_SSH_PRIVATE_KEY_FILE = \"/path/to/my/ssh/key\";\n\n// Keys will be auto-discovered and converted\nconst config = await decryptSops({ path: \"./config.enc.json\" });\n```\n\n### 2. Age Keys from Environment Variables\n\n- **`SOPS_AGE_KEY`**: Direct age private key\n- **`SOPS_AGE_KEY_FILE`**: Path to file containing age keys\n- **`SOPS_AGE_KEY_CMD`**: Command that outputs age keys\n\n```js\n// Direct key\nprocess.env.SOPS_AGE_KEY = \"AGE-SECRET-KEY-1qgdy...\";\n\n// Key file\nprocess.env.SOPS_AGE_KEY_FILE = \"/path/to/keys.txt\";\n\n// Command that outputs keys\nprocess.env.SOPS_AGE_KEY_CMD = \"my-key-manager get-age-key\";\n```\n\n### 3. Default Config File\n\nThe library checks for age keys in the default SOPS config directory:\n\n- **Linux/Unix**: `~/.config/sops/age/keys.txt` (or `$XDG_CONFIG_HOME/sops/age/keys.txt`)\n- **macOS**: `~/Library/Application Support/sops/age/keys.txt` (or `$XDG_CONFIG_HOME/sops/age/keys.txt` if set)\n- **Windows**: `%APPDATA%\\sops\\age\\keys.txt`\n\nExample `keys.txt` file:\n\n```text\n# Created: 2024-01-15T10:30:00Z\n# Public key: age1je6kjhzuhdjy3fqptpttxjh5k8q46vygzlgtpuq3030c947pc5tqz9dqvr\nAGE-SECRET-KEY-1QGDY7NWZDM5HG2QMSKQHQZPQF2QJLTQHQZPQF2QJLTQHQZPQF2QJLTQHQZ\n\n# Another key\nAGE-SECRET-KEY-1ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ABCDEFGHIJKLMNOP\n```\n\n## Key Discovery Priority\n\nWhen no explicit `secretKey` is provided, keys are discovered in this order:\n\n1. **SSH Keys**: `SOPS_AGE_SSH_PRIVATE_KEY_FILE` → `~/.ssh/id_ed25519` → `~/.ssh/id_rsa`\n2. **Age Keys**: `SOPS_AGE_KEY` → `SOPS_AGE_KEY_FILE` → `SOPS_AGE_KEY_CMD`\n3. **Default Config**: Platform-specific `sops/age/keys.txt` file\n\nThe library will try all discovered keys until one successfully decrypts the file.\n\n## Age Key Utilities\n\nThe library includes utilities for discovering age keys and converting SSH keys to age format:\n\n```js\nimport { sshKeyToAge, sshKeyFileToAge, findAllAgeKeys } from \"sops-age\";\n\n// Convert SSH key content to age format\nconst sshKeyContent = \"-----BEGIN OPENSSH PRIVATE KEY-----\\n...\";\nconst ageKey = sshKeyToAge(sshKeyContent);\n\n// Convert SSH key file to age format\nconst ageKey = await sshKeyFileToAge(\"/path/to/ssh/key\");\n\n// Discover all available age keys\nconst allKeys = await findAllAgeKeys();\nconsole.log(\"Found keys:\", allKeys);\n```\n\n## API Reference\n\n### `decryptSops(input, options?)`\n\nDecrypts SOPS-encrypted content directly from a string, Buffer, or other supported input types.\n\n```js\n// With auto-discovered keys\nconst decrypted = await decryptSops(jsonString, {\n  fileType: \"json\",\n});\n\n// With explicit key\nconst decrypted = await decryptSops(jsonString, {\n  secretKey: \"AGE-SECRET-KEY-1qgdy...\",\n  fileType: \"json\",\n});\n```\n\n### `decryptSops({ path: \"...\", ... })`\n\nDecrypts a SOPS-encrypted file from the local filesystem.\n\n```js\nconst decrypted = await decryptSops({\n  path: \"/path/to/config.enc.json\",\n  // secretKey optional - will auto-discover\n});\n```\n\n### `decryptSops({ url: \"https://...\", ... })`\n\nDecrypts a SOPS-encrypted file from a URL.\n\n```js\nconst decrypted = await decryptSops({\n  url: \"https://example.com/config.enc.json\",\n  secretKey: \"AGE-SECRET-KEY-1qgdy...\", // or auto-discover\n});\n```\n\n### `decryptSops(sopsObject, options?)`\n\nDecrypts SOPS-encrypted content directly from a pre-parsed SOPS object.\n\n```js\nconst sopsObject = {\n  secret:\n    \"ENC[AES256_GCM,data:trrpgezXug4Dq9T/inwkMA==,iv:glPwxoY2UuHO91vlJRaqYtFkPY1VsWvkJtfkEKZJdns=,tag:v7DbOYl7C5gdQRdW6BVoLw==,type:str]\",\n  sops: {\n    // ... SOPS metadata\n  },\n};\n\n// Auto-discovers keys from environment/config\nconst decrypted = await decryptSops(sopsObject);\n```\n\n### `DecryptSopsOptions`\n\nThe `decryptSops` function accepts the following options:\n\n- `secretKey`: The age secret key for decryption (optional - will auto-discover if not provided)\n- `fileType`: Optional file type ('env', 'json', or 'yaml'). Auto-detected if not specified\n- `keyPath`: Optional path to decrypt only a specific value\n- `path`: Path to local SOPS file (when using file-based decryption)\n- `url`: URL of SOPS file (when using URL-based decryption)\n\n### Utility Functions\n\n#### `findAllAgeKeys()`\n\nDiscovers all available age keys (including converted SSH keys) using SOPS logic:\n\n```js\nimport { findAllAgeKeys } from \"sops-age\";\n\nconst keys = await findAllAgeKeys();\nconsole.log(\"Available age keys:\", keys);\n```\n\n#### `sshKeyToAge(keyContent, filePath)`\n\nConverts SSH private key content to age format:\n\n```js\nimport { sshKeyToAge } from \"sops-age\";\n\nconst sshKey = \"-----BEGIN OPENSSH PRIVATE KEY-----\\n...\";\nconst ageKey = sshKeyToAge(sshKey, \"id_ed25519\");\n// Returns: \"AGE-SECRET-KEY-1...\" or null for unsupported keys\n```\n\n#### `sshKeyFileToAge(filePath)`\n\nConverts SSH private key file to age format:\n\n```js\nimport { sshKeyFileToAge } from \"sops-age\";\n\nconst ageKey = await sshKeyFileToAge(\"~/.ssh/id_ed25519\");\n// Returns: \"AGE-SECRET-KEY-1...\" or null\n```\n\n## License\n\n`sops-age` is released under the MIT License. See the [LICENSE](./LICENSE.md) file for more details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhumphd%2Fsops-age","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhumphd%2Fsops-age","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhumphd%2Fsops-age/lists"}