@orion-js/env
Advanced tools
| #!/usr/bin/env node | ||
| var __create = Object.create; | ||
| var __defProp = Object.defineProperty; | ||
| var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | ||
| var __getOwnPropNames = Object.getOwnPropertyNames; | ||
| var __getProtoOf = Object.getPrototypeOf; | ||
| var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
| var __copyProps = (to, from, except, desc) => { | ||
| if (from && typeof from === "object" || typeof from === "function") { | ||
| for (let key of __getOwnPropNames(from)) | ||
| if (!__hasOwnProp.call(to, key) && key !== except) | ||
| __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); | ||
| } | ||
| return to; | ||
| }; | ||
| var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( | ||
| // If the importer is in node compatibility mode or this is not an ESM | ||
| // file that has been converted to a CommonJS file using a Babel- | ||
| // compatible transform (i.e. "__esModule" has not been set), then set | ||
| // "default" to the CommonJS "module.exports" for node compatibility. | ||
| isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, | ||
| mod | ||
| )); | ||
| // src/cli/index.ts | ||
| var import_commander = require("commander"); | ||
| var import_chalk = __toESM(require("chalk"), 1); | ||
| // src/cli/init/index.ts | ||
| var import_yaml = __toESM(require("yaml"), 1); | ||
| // src/crypto/tweetnacl.ts | ||
| var import_tweetnacl_es6 = __toESM(require("tweetnacl-es6"), 1); | ||
| // src/crypto/util.ts | ||
| function validateBase64(s) { | ||
| if (!/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(s)) { | ||
| throw new TypeError("invalid encoding"); | ||
| } | ||
| } | ||
| var decodeUTF8 = (s) => { | ||
| if (typeof s !== "string") throw new TypeError("expected string"); | ||
| let i; | ||
| const d = unescape(encodeURIComponent(s)); | ||
| const b = new Uint8Array(d.length); | ||
| for (i = 0; i < d.length; i++) b[i] = d.charCodeAt(i); | ||
| return b; | ||
| }; | ||
| var encodeUTF8 = (arr) => { | ||
| let i; | ||
| const s = []; | ||
| for (i = 0; i < arr.length; i++) s.push(String.fromCharCode(arr[i])); | ||
| return decodeURIComponent(escape(s.join(""))); | ||
| }; | ||
| var encodeBase64 = (arr) => Buffer.from(arr).toString("base64"); | ||
| var decodeBase64 = (s) => { | ||
| validateBase64(s); | ||
| return new Uint8Array(Array.prototype.slice.call(Buffer.from(s, "base64"), 0)); | ||
| }; | ||
| // src/crypto/tweetnacl.ts | ||
| var newNonce = () => import_tweetnacl_es6.default.randomBytes(import_tweetnacl_es6.default.box.nonceLength); | ||
| var generateKeyPair = () => import_tweetnacl_es6.default.box.keyPair(); | ||
| var encrypt = (bSecretKey, aPublicKey, message) => { | ||
| const nonce = newNonce(); | ||
| const messageUint8 = decodeUTF8(message); | ||
| const encrypted = import_tweetnacl_es6.default.box(messageUint8, nonce, aPublicKey, bSecretKey); | ||
| const fullMessage = new Uint8Array(nonce.length + encrypted.length); | ||
| fullMessage.set(nonce); | ||
| fullMessage.set(encrypted, nonce.length); | ||
| const base64FullMessage = encodeBase64(fullMessage); | ||
| return base64FullMessage; | ||
| }; | ||
| var decrypt = (aSecretKey, bPublicKey, messageWithNonce) => { | ||
| const messageWithNonceAsUint8Array = decodeBase64(messageWithNonce); | ||
| const nonce = messageWithNonceAsUint8Array.slice(0, import_tweetnacl_es6.default.box.nonceLength); | ||
| const message = messageWithNonceAsUint8Array.slice(import_tweetnacl_es6.default.box.nonceLength, messageWithNonce.length); | ||
| const decrypted = import_tweetnacl_es6.default.box.open(message, nonce, bPublicKey, aSecretKey); | ||
| if (!decrypted) { | ||
| throw new Error("Could not decrypt message"); | ||
| } | ||
| const base64DecryptedMessage = encodeUTF8(decrypted); | ||
| return base64DecryptedMessage; | ||
| }; | ||
| // src/crypto/index.ts | ||
| function generateKeys() { | ||
| const { publicKey, secretKey } = generateKeyPair(); | ||
| const encryptKeyHex = encodeBase64(publicKey); | ||
| const decryptKeyHex = encodeBase64(secretKey); | ||
| return { | ||
| encryptKey: encryptKeyHex, | ||
| decryptKey: decryptKeyHex | ||
| }; | ||
| } | ||
| function encrypt2(encryptKey, message) { | ||
| const encryptPublicKey = decodeBase64(encryptKey); | ||
| const tempPair = generateKeyPair(); | ||
| const encrypted = encrypt(tempPair.secretKey, encryptPublicKey, message); | ||
| const hexTempPublic = encodeBase64(tempPair.publicKey); | ||
| return `${hexTempPublic}:${encrypted}`; | ||
| } | ||
| function decrypt2(decryptKey, encrypted) { | ||
| const decryptSecretKey = decodeBase64(decryptKey); | ||
| const [messagePubKeyHex, encryptedMessage] = encrypted.split(":"); | ||
| const messagePubKey = decodeBase64(messagePubKeyHex); | ||
| return decrypt(decryptSecretKey, messagePubKey, encryptedMessage); | ||
| } | ||
| // src/files/index.ts | ||
| var import_node_fs = __toESM(require("fs"), 1); | ||
| var import_node_path = __toESM(require("path"), 1); | ||
| function readFile(filePath) { | ||
| if (!import_node_fs.default.existsSync(filePath)) return null; | ||
| return import_node_fs.default.readFileSync(filePath).toString(); | ||
| } | ||
| function writeFile(path2, content) { | ||
| ensureDirectory(path2); | ||
| import_node_fs.default.writeFileSync(path2, content); | ||
| } | ||
| function ensureDirectory(filePath) { | ||
| const dirname = import_node_path.default.dirname(filePath); | ||
| if (import_node_fs.default.existsSync(dirname)) return true; | ||
| ensureDirectory(dirname); | ||
| import_node_fs.default.mkdirSync(dirname); | ||
| } | ||
| // src/cli/init/index.ts | ||
| async function envInit({ path: path2 }) { | ||
| if (!path2) { | ||
| path2 = ".env.local.yml"; | ||
| } | ||
| const keypair = generateKeys(); | ||
| const envFile = { | ||
| version: "1.0", | ||
| publicKey: keypair.encryptKey, | ||
| cleanKeys: {}, | ||
| encryptedKeys: {}, | ||
| readFromSecret: {} | ||
| }; | ||
| const text = import_yaml.default.stringify(envFile); | ||
| writeFile(path2, text); | ||
| console.log(""); | ||
| console.log( | ||
| `Environment file created. You need to use the following key to decrypt the environment variables:` | ||
| ); | ||
| console.log(""); | ||
| console.log(keypair.decryptKey); | ||
| console.log(""); | ||
| } | ||
| // src/cli/add/encryptValue.ts | ||
| var encryptValue = (key, value, config) => { | ||
| config.encryptedKeys[key] = encrypt2(config.publicKey, value); | ||
| }; | ||
| // src/cli/add/getConfig.ts | ||
| var import_yaml2 = __toESM(require("yaml"), 1); | ||
| var getConfig = (envPath) => { | ||
| const configFile = readFile(envPath); | ||
| if (!configFile) { | ||
| throw new Error("No config file found at path " + envPath); | ||
| } | ||
| return import_yaml2.default.parse(configFile); | ||
| }; | ||
| // src/cli/add/getParams.ts | ||
| var import_prompts = __toESM(require("prompts"), 1); | ||
| var getParams = async (config) => { | ||
| const response = await (0, import_prompts.default)([ | ||
| { | ||
| type: "text", | ||
| name: "key", | ||
| message: "Key" | ||
| }, | ||
| { | ||
| type: "text", | ||
| name: "value", | ||
| message: "Value" | ||
| } | ||
| ]); | ||
| return { | ||
| key: response.key, | ||
| value: response.value | ||
| }; | ||
| }; | ||
| // src/cli/add/index.ts | ||
| var import_yaml3 = __toESM(require("yaml"), 1); | ||
| var sortObjectByKeys = (object) => { | ||
| if (!object) return {}; | ||
| const sorted = {}; | ||
| Object.keys(object).sort().forEach((key) => { | ||
| sorted[key] = object[key]; | ||
| }); | ||
| return sorted; | ||
| }; | ||
| async function envAdd({ path: path2 }) { | ||
| if (!path2) { | ||
| path2 = ".env.local.yml"; | ||
| } | ||
| const config = getConfig(path2); | ||
| const { key, value } = await getParams(config); | ||
| if (!value) return; | ||
| encryptValue(key, value, config); | ||
| config.cleanKeys = sortObjectByKeys(config.cleanKeys); | ||
| config.encryptedKeys = sortObjectByKeys(config.encryptedKeys); | ||
| config.readFromSecret = sortObjectByKeys(config.readFromSecret); | ||
| const text = import_yaml3.default.stringify(config); | ||
| writeFile(path2, text); | ||
| } | ||
| // src/environment/getVariables.ts | ||
| function readSecrets(readFromSecret) { | ||
| const variables = {}; | ||
| let secretKey = null; | ||
| if (!readFromSecret) return { variables, secretKey }; | ||
| for (const secretName in readFromSecret) { | ||
| const keys = readFromSecret[secretName]; | ||
| if (!process.env[secretName]) { | ||
| console.warn( | ||
| `@orion/env could not find the secret "${secretName}" in the environment. Related variables will be undefined.` | ||
| ); | ||
| continue; | ||
| } | ||
| try { | ||
| const values = JSON.parse(process.env[secretName]); | ||
| if (values.ORION_ENV_SECRET_KEY) { | ||
| secretKey = values.ORION_ENV_SECRET_KEY; | ||
| } | ||
| for (const key of keys) { | ||
| if (values[key]) { | ||
| variables[key] = values[key]; | ||
| } else { | ||
| console.warn( | ||
| `@orion/env could not find the variable "${key}" in the secret "${secretName}". Related variables will be undefined.` | ||
| ); | ||
| } | ||
| } | ||
| } catch (error) { | ||
| console.warn( | ||
| `'@orion/env found a the secret "${secretName}" variable in the environment but it is not a valid JSON. Related variables will be undefined.'` | ||
| ); | ||
| } | ||
| } | ||
| return { variables, secretKey }; | ||
| } | ||
| function getVariables(config, secretKey) { | ||
| const { cleanKeys, encryptedKeys, readFromSecret } = config; | ||
| const { variables, secretKey: foundSecretKey } = readSecrets(readFromSecret); | ||
| let decryptKey = foundSecretKey || secretKey; | ||
| if (!decryptKey) { | ||
| throw new Error( | ||
| "Orion encrypted env was passed but process.env.ORION_ENV_SECRET_KEY is not defined" | ||
| ); | ||
| } | ||
| for (const key in cleanKeys) { | ||
| const value = cleanKeys[key]; | ||
| variables[key] = value; | ||
| } | ||
| for (const key in encryptedKeys) { | ||
| const encrypted = encryptedKeys[key]; | ||
| try { | ||
| variables[key] = decrypt2(decryptKey, encrypted); | ||
| } catch (error) { | ||
| throw new Error( | ||
| `Orion encrypted env was passed but process.env.ORION_ENV_SECRET_KEY is not the right key for "${key}"` | ||
| ); | ||
| } | ||
| } | ||
| return variables; | ||
| } | ||
| // src/cli/read/index.ts | ||
| async function envRead({ path: path2, key, secret }) { | ||
| if (!path2) { | ||
| path2 = ".env.local.yml"; | ||
| } | ||
| if (!secret) { | ||
| throw new Error("Secret is required"); | ||
| } | ||
| const config = getConfig(path2); | ||
| const variables = getVariables(config, secret); | ||
| if (key) { | ||
| console.log(variables[key]); | ||
| } else { | ||
| console.log(JSON.stringify(variables, null, 2)); | ||
| } | ||
| } | ||
| // src/cli/migrate/index.ts | ||
| var import_yaml4 = __toESM(require("yaml"), 1); | ||
| var import_prompts2 = __toESM(require("prompts"), 1); | ||
| async function envMigrate({ path: path2, secret }) { | ||
| if (!path2) { | ||
| path2 = ".env.local.yml"; | ||
| } | ||
| const config = getConfig(path2); | ||
| const currentSecret = secret ?? await promptForSecret(); | ||
| const decryptedKeys = decryptAllKeys(config.encryptedKeys, currentSecret); | ||
| const newKeypair = generateKeys(); | ||
| const newEncryptedKeys = reEncryptAllKeys(decryptedKeys, newKeypair.encryptKey); | ||
| const updatedConfig = { | ||
| ...config, | ||
| publicKey: newKeypair.encryptKey, | ||
| encryptedKeys: newEncryptedKeys | ||
| }; | ||
| const text = import_yaml4.default.stringify(updatedConfig); | ||
| writeFile(path2, text); | ||
| console.log(""); | ||
| console.log("Config file migrated successfully."); | ||
| console.log(""); | ||
| console.log("New secret key (save this securely):"); | ||
| console.log(""); | ||
| console.log(newKeypair.decryptKey); | ||
| console.log(""); | ||
| } | ||
| async function promptForSecret() { | ||
| const response = await (0, import_prompts2.default)({ | ||
| type: "password", | ||
| name: "secret", | ||
| message: "Current secret key" | ||
| }); | ||
| if (!response.secret) { | ||
| throw new Error("Secret is required"); | ||
| } | ||
| return response.secret; | ||
| } | ||
| function decryptAllKeys(encryptedKeys, secretKey) { | ||
| const decrypted = {}; | ||
| for (const key in encryptedKeys) { | ||
| try { | ||
| decrypted[key] = decrypt2(secretKey, encryptedKeys[key]); | ||
| } catch (error) { | ||
| throw new Error(`Failed to decrypt key "${key}". Is the secret key correct?`); | ||
| } | ||
| } | ||
| return decrypted; | ||
| } | ||
| function reEncryptAllKeys(decryptedKeys, newPublicKey) { | ||
| const encrypted = {}; | ||
| for (const key in decryptedKeys) { | ||
| encrypted[key] = encrypt2(newPublicKey, decryptedKeys[key]); | ||
| } | ||
| return encrypted; | ||
| } | ||
| // src/cli/index.ts | ||
| var program = new import_commander.Command(); | ||
| var run = (action) => async (...args) => { | ||
| try { | ||
| await action(...args); | ||
| } catch (e) { | ||
| console.error(import_chalk.default.red(`Error: ${e.message}`)); | ||
| } | ||
| }; | ||
| program.command("init").description("Creates a new encrypted env file").option("--path <path>", "Specify the env file name").action(run(envInit)); | ||
| program.command("add").description("Adds a new environment to the encrypted env file").option("--path <path>", "Specify the env file name").action(run(envAdd)); | ||
| program.command("read").description("Prints the value of the env file in JSON or a specific variable in plain text").option("--path <path>", "Specify the env file name").option("--key <key>", "Prints the value of a specific variable in plain text").option("--secret <secret>", "The password to decrypt the keys").action(run(envRead)); | ||
| program.command("migrate").description("Migrates the config file to a new keypair, re-encrypting all keys").option("--path <path>", "Specify the env file name").option("--secret <secret>", "The current secret key to decrypt existing keys").action(run(envMigrate)); | ||
| program.parse(process.argv); | ||
| if (!process.argv.slice(2).length) { | ||
| program.outputHelp(); | ||
| } | ||
| //# sourceMappingURL=index.cjs.map |
| {"version":3,"sources":["../src/cli/index.ts","../src/cli/init/index.ts","../src/crypto/tweetnacl.ts","../src/crypto/util.ts","../src/crypto/index.ts","../src/files/index.ts","../src/cli/add/encryptValue.ts","../src/cli/add/getConfig.ts","../src/cli/add/getParams.ts","../src/cli/add/index.ts","../src/environment/getVariables.ts","../src/cli/read/index.ts","../src/cli/migrate/index.ts"],"sourcesContent":["#!/usr/bin/env node\nimport {Command} from 'commander'\nimport chalk from 'chalk'\nimport envInit from './init'\nimport envAdd from './add'\nimport envRead from './read'\nimport envMigrate from './migrate'\n\nconst program = new Command()\n\nconst run =\n action =>\n async (...args) => {\n try {\n await action(...args)\n } catch (e) {\n console.error(chalk.red(`Error: ${e.message}`))\n }\n }\n\nprogram\n .command('init')\n .description('Creates a new encrypted env file')\n .option('--path <path>', 'Specify the env file name')\n .action(run(envInit))\n\nprogram\n .command('add')\n .description('Adds a new environment to the encrypted env file')\n .option('--path <path>', 'Specify the env file name')\n .action(run(envAdd))\n\nprogram\n .command('read')\n .description('Prints the value of the env file in JSON or a specific variable in plain text')\n .option('--path <path>', 'Specify the env file name')\n .option('--key <key>', 'Prints the value of a specific variable in plain text')\n .option('--secret <secret>', 'The password to decrypt the keys')\n .action(run(envRead))\n\nprogram\n .command('migrate')\n .description('Migrates the config file to a new keypair, re-encrypting all keys')\n .option('--path <path>', 'Specify the env file name')\n .option('--secret <secret>', 'The current secret key to decrypt existing keys')\n .action(run(envMigrate))\n\nprogram.parse(process.argv)\n\nif (!process.argv.slice(2).length) {\n program.outputHelp()\n}\n","import YAML from 'yaml'\nimport {generateKeys} from '../../crypto'\nimport {Config} from '../../environment/getVariables'\nimport {writeFile} from '../../files'\n\nexport default async function envInit({path}) {\n if (!path) {\n path = '.env.local.yml'\n }\n\n const keypair = generateKeys()\n\n const envFile: Config = {\n version: '1.0',\n publicKey: keypair.encryptKey,\n cleanKeys: {},\n encryptedKeys: {},\n readFromSecret: {},\n }\n\n const text = YAML.stringify(envFile)\n\n writeFile(path, text)\n\n console.log('')\n\n console.log(\n `Environment file created. You need to use the following key to decrypt the environment variables:`,\n )\n\n console.log('')\n\n console.log(keypair.decryptKey)\n\n console.log('')\n}\n","import nacl from 'tweetnacl-es6'\nimport {decodeUTF8, encodeUTF8, encodeBase64, decodeBase64} from './util'\n\nconst newNonce = () => nacl.randomBytes(nacl.box.nonceLength)\nexport const generateKeyPair = () => nacl.box.keyPair()\n\nexport const encrypt = (bSecretKey: Uint8Array, aPublicKey: Uint8Array, message: string) => {\n const nonce = newNonce()\n const messageUint8 = decodeUTF8(message)\n const encrypted = nacl.box(messageUint8, nonce, aPublicKey, bSecretKey)\n\n const fullMessage = new Uint8Array(nonce.length + encrypted.length)\n fullMessage.set(nonce)\n fullMessage.set(encrypted, nonce.length)\n\n const base64FullMessage = encodeBase64(fullMessage)\n return base64FullMessage\n}\n\nexport const decrypt = (\n aSecretKey: Uint8Array,\n bPublicKey: Uint8Array,\n messageWithNonce: string,\n) => {\n const messageWithNonceAsUint8Array = decodeBase64(messageWithNonce)\n const nonce = messageWithNonceAsUint8Array.slice(0, nacl.box.nonceLength)\n const message = messageWithNonceAsUint8Array.slice(nacl.box.nonceLength, messageWithNonce.length)\n\n const decrypted = nacl.box.open(message, nonce, bPublicKey, aSecretKey)\n\n if (!decrypted) {\n throw new Error('Could not decrypt message')\n }\n\n const base64DecryptedMessage = encodeUTF8(decrypted)\n return base64DecryptedMessage\n}\n","// Written in 2014-2016 by Dmitry Chestnykh and Devi Mandiri.\n// Public domain.\n\nimport {WithImplicitCoercion} from 'node:buffer'\n\nfunction validateBase64(s: string) {\n if (!/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(s)) {\n throw new TypeError('invalid encoding')\n }\n}\n\nexport const decodeUTF8 = (s: string | number | boolean) => {\n if (typeof s !== 'string') throw new TypeError('expected string')\n let i: number\n const d = unescape(encodeURIComponent(s))\n const b = new Uint8Array(d.length)\n for (i = 0; i < d.length; i++) b[i] = d.charCodeAt(i)\n return b\n}\n\nexport const encodeUTF8 = (arr: string | any[]) => {\n let i: number\n const s = []\n for (i = 0; i < arr.length; i++) s.push(String.fromCharCode(arr[i]))\n return decodeURIComponent(escape(s.join('')))\n}\n\nexport const encodeBase64 = (arr: Uint8Array<any>) => Buffer.from(arr).toString('base64')\n\nexport const decodeBase64 = (s: WithImplicitCoercion<string>) => {\n validateBase64(s as any)\n return new Uint8Array(Array.prototype.slice.call(Buffer.from(s, 'base64'), 0))\n}\n","import {generateKeyPair, encrypt as tweetEncrypt, decrypt as tweetDecrypt} from './tweetnacl'\nimport {encodeBase64, decodeBase64} from './util'\n\nexport function generateKeys() {\n const {publicKey, secretKey} = generateKeyPair()\n\n const encryptKeyHex = encodeBase64(publicKey)\n const decryptKeyHex = encodeBase64(secretKey)\n\n return {\n encryptKey: encryptKeyHex,\n decryptKey: decryptKeyHex,\n }\n}\n\n/**\n * Creates a temporal keypair just to encrypt one message.\n * Saves the public key in the result so that the message can be decrypted.\n */\nexport function encrypt(encryptKey: string, message: string) {\n const encryptPublicKey = decodeBase64(encryptKey)\n const tempPair = generateKeyPair()\n const encrypted = tweetEncrypt(tempPair.secretKey, encryptPublicKey, message)\n const hexTempPublic = encodeBase64(tempPair.publicKey)\n return `${hexTempPublic}:${encrypted}`\n}\n\n/**\n * Ecrypts a message using the decrypt key\n */\nexport function decrypt(decryptKey: string, encrypted: string) {\n const decryptSecretKey = decodeBase64(decryptKey)\n const [messagePubKeyHex, encryptedMessage] = encrypted.split(':')\n const messagePubKey = decodeBase64(messagePubKeyHex)\n\n return tweetDecrypt(decryptSecretKey, messagePubKey, encryptedMessage)\n}\n","import fs from 'node:fs'\nimport path from 'node:path'\n\nexport function readFile(filePath: string) {\n if (!fs.existsSync(filePath)) return null\n\n return fs.readFileSync(filePath).toString()\n}\n\nexport function writeFile(path: string, content: string) {\n ensureDirectory(path)\n fs.writeFileSync(path, content)\n}\n\nexport function ensureDirectory(filePath) {\n const dirname = path.dirname(filePath)\n if (fs.existsSync(dirname)) return true\n ensureDirectory(dirname)\n fs.mkdirSync(dirname)\n}\n","import {encrypt} from '../../crypto'\nimport {Config} from '../../environment/getVariables'\n\nexport const encryptValue = (key: string, value: string, config: Config) => {\n config.encryptedKeys[key] = encrypt(config.publicKey, value)\n}\n","import YAML from 'yaml'\nimport {Config} from '../../environment/getVariables'\nimport {readFile} from '../../files'\n\nexport const getConfig = (envPath: string): Config => {\n const configFile = readFile(envPath)\n\n if (!configFile) {\n throw new Error('No config file found at path ' + envPath)\n }\n\n return YAML.parse(configFile)\n}\n","import prompts from 'prompts'\nimport {Config} from '../../environment/getVariables'\n\nexport const getParams = async (config: Config) => {\n const response = await prompts([\n {\n type: 'text',\n name: 'key',\n message: 'Key',\n },\n {\n type: 'text',\n name: 'value',\n message: 'Value',\n },\n ])\n\n return {\n key: response.key as string,\n value: response.value as string,\n }\n}\n","import {encryptValue} from './encryptValue'\nimport {getConfig} from './getConfig'\nimport {getParams} from './getParams'\nimport YAML from 'yaml'\nimport {writeFile} from '../../files'\n\nconst sortObjectByKeys = (object: any) => {\n if (!object) return {}\n const sorted = {}\n Object.keys(object)\n .sort()\n .forEach(key => {\n sorted[key] = object[key]\n })\n return sorted\n}\n\nexport default async function envAdd({path}) {\n if (!path) {\n path = '.env.local.yml'\n }\n\n const config = getConfig(path)\n const {key, value} = await getParams(config)\n if (!value) return\n\n encryptValue(key, value, config)\n\n // sort keys alphabetically\n config.cleanKeys = sortObjectByKeys(config.cleanKeys)\n config.encryptedKeys = sortObjectByKeys(config.encryptedKeys)\n config.readFromSecret = sortObjectByKeys(config.readFromSecret)\n\n const text = YAML.stringify(config)\n writeFile(path, text)\n}\n","import {decrypt} from '../crypto'\n\nexport interface Config {\n version: string\n publicKey: string\n cleanKeys: {\n [key: string]: string\n }\n encryptedKeys: {\n [key: string]: string\n }\n readFromSecret?: {\n [key: string]: string[]\n }\n}\n\nexport interface Variables {\n [key: string]: string\n}\n\nfunction readSecrets(readFromSecret): {variables: Variables; secretKey: string} {\n const variables: Variables = {}\n let secretKey = null\n if (!readFromSecret) return {variables, secretKey}\n for (const secretName in readFromSecret) {\n const keys = readFromSecret[secretName]\n if (!process.env[secretName]) {\n console.warn(\n `@orion/env could not find the secret \"${secretName}\" in the environment. Related variables will be undefined.`,\n )\n continue\n }\n\n try {\n const values = JSON.parse(process.env[secretName])\n if (values.ORION_ENV_SECRET_KEY) {\n secretKey = values.ORION_ENV_SECRET_KEY\n }\n for (const key of keys) {\n if (values[key]) {\n variables[key] = values[key]\n } else {\n console.warn(\n `@orion/env could not find the variable \"${key}\" in the secret \"${secretName}\". Related variables will be undefined.`,\n )\n }\n }\n } catch (error) {\n console.warn(\n `'@orion/env found a the secret \"${secretName}\" variable in the environment but it is not a valid JSON. Related variables will be undefined.'`,\n )\n }\n }\n return {variables, secretKey: secretKey}\n}\n\nexport function getVariables(config: Config, secretKey?: string): Variables {\n const {cleanKeys, encryptedKeys, readFromSecret} = config\n const {variables, secretKey: foundSecretKey} = readSecrets(readFromSecret)\n let decryptKey = foundSecretKey || secretKey\n if (!decryptKey) {\n throw new Error(\n 'Orion encrypted env was passed but process.env.ORION_ENV_SECRET_KEY is not defined',\n )\n }\n\n for (const key in cleanKeys) {\n const value = cleanKeys[key]\n variables[key] = value\n }\n\n for (const key in encryptedKeys) {\n const encrypted = encryptedKeys[key]\n try {\n variables[key] = decrypt(decryptKey, encrypted)\n } catch (error) {\n throw new Error(\n `Orion encrypted env was passed but process.env.ORION_ENV_SECRET_KEY is not the right key for \"${key}\"`,\n )\n }\n }\n return variables\n}\n","import {getVariables} from '../../environment/getVariables'\nimport {getConfig} from '../add/getConfig'\n\nexport default async function envRead({path, key, secret}) {\n if (!path) {\n path = '.env.local.yml'\n }\n if (!secret) {\n throw new Error('Secret is required')\n }\n\n const config = getConfig(path)\n const variables = getVariables(config, secret)\n\n if (key) {\n console.log(variables[key])\n } else {\n console.log(JSON.stringify(variables, null, 2))\n }\n}\n","import YAML from 'yaml'\nimport {decrypt, encrypt, generateKeys} from '../../crypto'\nimport {Config} from '../../environment/getVariables'\nimport {writeFile} from '../../files'\nimport {getConfig} from '../add/getConfig'\nimport prompts from 'prompts'\n\ninterface MigrateOptions {\n path?: string\n secret?: string\n}\n\n/**\n * Migrates an env config file to a new keypair.\n * Re-encrypts all encrypted keys with the new public key.\n */\nexport default async function envMigrate({path, secret}: MigrateOptions) {\n if (!path) {\n path = '.env.local.yml'\n }\n\n const config = getConfig(path)\n\n // Get the current secret key if not provided\n const currentSecret = secret ?? (await promptForSecret())\n\n // Decrypt all encrypted keys using the old secret\n const decryptedKeys = decryptAllKeys(config.encryptedKeys, currentSecret)\n\n // Generate a new keypair\n const newKeypair = generateKeys()\n\n // Re-encrypt all keys with the new public key\n const newEncryptedKeys = reEncryptAllKeys(decryptedKeys, newKeypair.encryptKey)\n\n // Create the updated config\n const updatedConfig: Config = {\n ...config,\n publicKey: newKeypair.encryptKey,\n encryptedKeys: newEncryptedKeys,\n }\n\n // Write the updated config file\n const text = YAML.stringify(updatedConfig)\n writeFile(path, text)\n\n console.log('')\n console.log('Config file migrated successfully.')\n console.log('')\n console.log('New secret key (save this securely):')\n console.log('')\n console.log(newKeypair.decryptKey)\n console.log('')\n}\n\nasync function promptForSecret(): Promise<string> {\n const response = await prompts({\n type: 'password',\n name: 'secret',\n message: 'Current secret key',\n })\n\n if (!response.secret) {\n throw new Error('Secret is required')\n }\n\n return response.secret as string\n}\n\nfunction decryptAllKeys(\n encryptedKeys: Record<string, string>,\n secretKey: string,\n): Record<string, string> {\n const decrypted: Record<string, string> = {}\n\n for (const key in encryptedKeys) {\n try {\n decrypted[key] = decrypt(secretKey, encryptedKeys[key])\n } catch (error) {\n throw new Error(`Failed to decrypt key \"${key}\". Is the secret key correct?`)\n }\n }\n\n return decrypted\n}\n\nfunction reEncryptAllKeys(\n decryptedKeys: Record<string, string>,\n newPublicKey: string,\n): Record<string, string> {\n const encrypted: Record<string, string> = {}\n\n for (const key in decryptedKeys) {\n encrypted[key] = encrypt(newPublicKey, decryptedKeys[key])\n }\n\n return encrypted\n}\n\n"],"mappings":"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","names":["nacl","encrypt","decrypt","fs","path","path","YAML","encrypt","import_yaml","YAML","prompts","import_yaml","path","YAML","decrypt","path","import_yaml","import_prompts","path","YAML","prompts","decrypt","encrypt","chalk"]} |
| #!/usr/bin/env node |
| #!/usr/bin/env node |
| {"version":3,"sources":["../src/cli/index.ts","../src/cli/init/index.ts","../src/crypto/tweetnacl.ts","../src/crypto/util.ts","../src/crypto/index.ts","../src/files/index.ts","../src/cli/add/encryptValue.ts","../src/cli/add/getConfig.ts","../src/cli/add/getParams.ts","../src/cli/add/index.ts","../src/environment/getVariables.ts","../src/cli/read/index.ts","../src/cli/migrate/index.ts"],"sourcesContent":["#!/usr/bin/env node\nimport {Command} from 'commander'\nimport chalk from 'chalk'\nimport envInit from './init'\nimport envAdd from './add'\nimport envRead from './read'\nimport envMigrate from './migrate'\n\nconst program = new Command()\n\nconst run =\n action =>\n async (...args) => {\n try {\n await action(...args)\n } catch (e) {\n console.error(chalk.red(`Error: ${e.message}`))\n }\n }\n\nprogram\n .command('init')\n .description('Creates a new encrypted env file')\n .option('--path <path>', 'Specify the env file name')\n .action(run(envInit))\n\nprogram\n .command('add')\n .description('Adds a new environment to the encrypted env file')\n .option('--path <path>', 'Specify the env file name')\n .action(run(envAdd))\n\nprogram\n .command('read')\n .description('Prints the value of the env file in JSON or a specific variable in plain text')\n .option('--path <path>', 'Specify the env file name')\n .option('--key <key>', 'Prints the value of a specific variable in plain text')\n .option('--secret <secret>', 'The password to decrypt the keys')\n .action(run(envRead))\n\nprogram\n .command('migrate')\n .description('Migrates the config file to a new keypair, re-encrypting all keys')\n .option('--path <path>', 'Specify the env file name')\n .option('--secret <secret>', 'The current secret key to decrypt existing keys')\n .action(run(envMigrate))\n\nprogram.parse(process.argv)\n\nif (!process.argv.slice(2).length) {\n program.outputHelp()\n}\n","import YAML from 'yaml'\nimport {generateKeys} from '../../crypto'\nimport {Config} from '../../environment/getVariables'\nimport {writeFile} from '../../files'\n\nexport default async function envInit({path}) {\n if (!path) {\n path = '.env.local.yml'\n }\n\n const keypair = generateKeys()\n\n const envFile: Config = {\n version: '1.0',\n publicKey: keypair.encryptKey,\n cleanKeys: {},\n encryptedKeys: {},\n readFromSecret: {},\n }\n\n const text = YAML.stringify(envFile)\n\n writeFile(path, text)\n\n console.log('')\n\n console.log(\n `Environment file created. You need to use the following key to decrypt the environment variables:`,\n )\n\n console.log('')\n\n console.log(keypair.decryptKey)\n\n console.log('')\n}\n","import nacl from 'tweetnacl-es6'\nimport {decodeUTF8, encodeUTF8, encodeBase64, decodeBase64} from './util'\n\nconst newNonce = () => nacl.randomBytes(nacl.box.nonceLength)\nexport const generateKeyPair = () => nacl.box.keyPair()\n\nexport const encrypt = (bSecretKey: Uint8Array, aPublicKey: Uint8Array, message: string) => {\n const nonce = newNonce()\n const messageUint8 = decodeUTF8(message)\n const encrypted = nacl.box(messageUint8, nonce, aPublicKey, bSecretKey)\n\n const fullMessage = new Uint8Array(nonce.length + encrypted.length)\n fullMessage.set(nonce)\n fullMessage.set(encrypted, nonce.length)\n\n const base64FullMessage = encodeBase64(fullMessage)\n return base64FullMessage\n}\n\nexport const decrypt = (\n aSecretKey: Uint8Array,\n bPublicKey: Uint8Array,\n messageWithNonce: string,\n) => {\n const messageWithNonceAsUint8Array = decodeBase64(messageWithNonce)\n const nonce = messageWithNonceAsUint8Array.slice(0, nacl.box.nonceLength)\n const message = messageWithNonceAsUint8Array.slice(nacl.box.nonceLength, messageWithNonce.length)\n\n const decrypted = nacl.box.open(message, nonce, bPublicKey, aSecretKey)\n\n if (!decrypted) {\n throw new Error('Could not decrypt message')\n }\n\n const base64DecryptedMessage = encodeUTF8(decrypted)\n return base64DecryptedMessage\n}\n","// Written in 2014-2016 by Dmitry Chestnykh and Devi Mandiri.\n// Public domain.\n\nimport {WithImplicitCoercion} from 'node:buffer'\n\nfunction validateBase64(s: string) {\n if (!/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(s)) {\n throw new TypeError('invalid encoding')\n }\n}\n\nexport const decodeUTF8 = (s: string | number | boolean) => {\n if (typeof s !== 'string') throw new TypeError('expected string')\n let i: number\n const d = unescape(encodeURIComponent(s))\n const b = new Uint8Array(d.length)\n for (i = 0; i < d.length; i++) b[i] = d.charCodeAt(i)\n return b\n}\n\nexport const encodeUTF8 = (arr: string | any[]) => {\n let i: number\n const s = []\n for (i = 0; i < arr.length; i++) s.push(String.fromCharCode(arr[i]))\n return decodeURIComponent(escape(s.join('')))\n}\n\nexport const encodeBase64 = (arr: Uint8Array<any>) => Buffer.from(arr).toString('base64')\n\nexport const decodeBase64 = (s: WithImplicitCoercion<string>) => {\n validateBase64(s as any)\n return new Uint8Array(Array.prototype.slice.call(Buffer.from(s, 'base64'), 0))\n}\n","import {generateKeyPair, encrypt as tweetEncrypt, decrypt as tweetDecrypt} from './tweetnacl'\nimport {encodeBase64, decodeBase64} from './util'\n\nexport function generateKeys() {\n const {publicKey, secretKey} = generateKeyPair()\n\n const encryptKeyHex = encodeBase64(publicKey)\n const decryptKeyHex = encodeBase64(secretKey)\n\n return {\n encryptKey: encryptKeyHex,\n decryptKey: decryptKeyHex,\n }\n}\n\n/**\n * Creates a temporal keypair just to encrypt one message.\n * Saves the public key in the result so that the message can be decrypted.\n */\nexport function encrypt(encryptKey: string, message: string) {\n const encryptPublicKey = decodeBase64(encryptKey)\n const tempPair = generateKeyPair()\n const encrypted = tweetEncrypt(tempPair.secretKey, encryptPublicKey, message)\n const hexTempPublic = encodeBase64(tempPair.publicKey)\n return `${hexTempPublic}:${encrypted}`\n}\n\n/**\n * Ecrypts a message using the decrypt key\n */\nexport function decrypt(decryptKey: string, encrypted: string) {\n const decryptSecretKey = decodeBase64(decryptKey)\n const [messagePubKeyHex, encryptedMessage] = encrypted.split(':')\n const messagePubKey = decodeBase64(messagePubKeyHex)\n\n return tweetDecrypt(decryptSecretKey, messagePubKey, encryptedMessage)\n}\n","import fs from 'node:fs'\nimport path from 'node:path'\n\nexport function readFile(filePath: string) {\n if (!fs.existsSync(filePath)) return null\n\n return fs.readFileSync(filePath).toString()\n}\n\nexport function writeFile(path: string, content: string) {\n ensureDirectory(path)\n fs.writeFileSync(path, content)\n}\n\nexport function ensureDirectory(filePath) {\n const dirname = path.dirname(filePath)\n if (fs.existsSync(dirname)) return true\n ensureDirectory(dirname)\n fs.mkdirSync(dirname)\n}\n","import {encrypt} from '../../crypto'\nimport {Config} from '../../environment/getVariables'\n\nexport const encryptValue = (key: string, value: string, config: Config) => {\n config.encryptedKeys[key] = encrypt(config.publicKey, value)\n}\n","import YAML from 'yaml'\nimport {Config} from '../../environment/getVariables'\nimport {readFile} from '../../files'\n\nexport const getConfig = (envPath: string): Config => {\n const configFile = readFile(envPath)\n\n if (!configFile) {\n throw new Error('No config file found at path ' + envPath)\n }\n\n return YAML.parse(configFile)\n}\n","import prompts from 'prompts'\nimport {Config} from '../../environment/getVariables'\n\nexport const getParams = async (config: Config) => {\n const response = await prompts([\n {\n type: 'text',\n name: 'key',\n message: 'Key',\n },\n {\n type: 'text',\n name: 'value',\n message: 'Value',\n },\n ])\n\n return {\n key: response.key as string,\n value: response.value as string,\n }\n}\n","import {encryptValue} from './encryptValue'\nimport {getConfig} from './getConfig'\nimport {getParams} from './getParams'\nimport YAML from 'yaml'\nimport {writeFile} from '../../files'\n\nconst sortObjectByKeys = (object: any) => {\n if (!object) return {}\n const sorted = {}\n Object.keys(object)\n .sort()\n .forEach(key => {\n sorted[key] = object[key]\n })\n return sorted\n}\n\nexport default async function envAdd({path}) {\n if (!path) {\n path = '.env.local.yml'\n }\n\n const config = getConfig(path)\n const {key, value} = await getParams(config)\n if (!value) return\n\n encryptValue(key, value, config)\n\n // sort keys alphabetically\n config.cleanKeys = sortObjectByKeys(config.cleanKeys)\n config.encryptedKeys = sortObjectByKeys(config.encryptedKeys)\n config.readFromSecret = sortObjectByKeys(config.readFromSecret)\n\n const text = YAML.stringify(config)\n writeFile(path, text)\n}\n","import {decrypt} from '../crypto'\n\nexport interface Config {\n version: string\n publicKey: string\n cleanKeys: {\n [key: string]: string\n }\n encryptedKeys: {\n [key: string]: string\n }\n readFromSecret?: {\n [key: string]: string[]\n }\n}\n\nexport interface Variables {\n [key: string]: string\n}\n\nfunction readSecrets(readFromSecret): {variables: Variables; secretKey: string} {\n const variables: Variables = {}\n let secretKey = null\n if (!readFromSecret) return {variables, secretKey}\n for (const secretName in readFromSecret) {\n const keys = readFromSecret[secretName]\n if (!process.env[secretName]) {\n console.warn(\n `@orion/env could not find the secret \"${secretName}\" in the environment. Related variables will be undefined.`,\n )\n continue\n }\n\n try {\n const values = JSON.parse(process.env[secretName])\n if (values.ORION_ENV_SECRET_KEY) {\n secretKey = values.ORION_ENV_SECRET_KEY\n }\n for (const key of keys) {\n if (values[key]) {\n variables[key] = values[key]\n } else {\n console.warn(\n `@orion/env could not find the variable \"${key}\" in the secret \"${secretName}\". Related variables will be undefined.`,\n )\n }\n }\n } catch (error) {\n console.warn(\n `'@orion/env found a the secret \"${secretName}\" variable in the environment but it is not a valid JSON. Related variables will be undefined.'`,\n )\n }\n }\n return {variables, secretKey: secretKey}\n}\n\nexport function getVariables(config: Config, secretKey?: string): Variables {\n const {cleanKeys, encryptedKeys, readFromSecret} = config\n const {variables, secretKey: foundSecretKey} = readSecrets(readFromSecret)\n let decryptKey = foundSecretKey || secretKey\n if (!decryptKey) {\n throw new Error(\n 'Orion encrypted env was passed but process.env.ORION_ENV_SECRET_KEY is not defined',\n )\n }\n\n for (const key in cleanKeys) {\n const value = cleanKeys[key]\n variables[key] = value\n }\n\n for (const key in encryptedKeys) {\n const encrypted = encryptedKeys[key]\n try {\n variables[key] = decrypt(decryptKey, encrypted)\n } catch (error) {\n throw new Error(\n `Orion encrypted env was passed but process.env.ORION_ENV_SECRET_KEY is not the right key for \"${key}\"`,\n )\n }\n }\n return variables\n}\n","import {getVariables} from '../../environment/getVariables'\nimport {getConfig} from '../add/getConfig'\n\nexport default async function envRead({path, key, secret}) {\n if (!path) {\n path = '.env.local.yml'\n }\n if (!secret) {\n throw new Error('Secret is required')\n }\n\n const config = getConfig(path)\n const variables = getVariables(config, secret)\n\n if (key) {\n console.log(variables[key])\n } else {\n console.log(JSON.stringify(variables, null, 2))\n }\n}\n","import YAML from 'yaml'\nimport {decrypt, encrypt, generateKeys} from '../../crypto'\nimport {Config} from '../../environment/getVariables'\nimport {writeFile} from '../../files'\nimport {getConfig} from '../add/getConfig'\nimport prompts from 'prompts'\n\ninterface MigrateOptions {\n path?: string\n secret?: string\n}\n\n/**\n * Migrates an env config file to a new keypair.\n * Re-encrypts all encrypted keys with the new public key.\n */\nexport default async function envMigrate({path, secret}: MigrateOptions) {\n if (!path) {\n path = '.env.local.yml'\n }\n\n const config = getConfig(path)\n\n // Get the current secret key if not provided\n const currentSecret = secret ?? (await promptForSecret())\n\n // Decrypt all encrypted keys using the old secret\n const decryptedKeys = decryptAllKeys(config.encryptedKeys, currentSecret)\n\n // Generate a new keypair\n const newKeypair = generateKeys()\n\n // Re-encrypt all keys with the new public key\n const newEncryptedKeys = reEncryptAllKeys(decryptedKeys, newKeypair.encryptKey)\n\n // Create the updated config\n const updatedConfig: Config = {\n ...config,\n publicKey: newKeypair.encryptKey,\n encryptedKeys: newEncryptedKeys,\n }\n\n // Write the updated config file\n const text = YAML.stringify(updatedConfig)\n writeFile(path, text)\n\n console.log('')\n console.log('Config file migrated successfully.')\n console.log('')\n console.log('New secret key (save this securely):')\n console.log('')\n console.log(newKeypair.decryptKey)\n console.log('')\n}\n\nasync function promptForSecret(): Promise<string> {\n const response = await prompts({\n type: 'password',\n name: 'secret',\n message: 'Current secret key',\n })\n\n if (!response.secret) {\n throw new Error('Secret is required')\n }\n\n return response.secret as string\n}\n\nfunction decryptAllKeys(\n encryptedKeys: Record<string, string>,\n secretKey: string,\n): Record<string, string> {\n const decrypted: Record<string, string> = {}\n\n for (const key in encryptedKeys) {\n try {\n decrypted[key] = decrypt(secretKey, encryptedKeys[key])\n } catch (error) {\n throw new Error(`Failed to decrypt key \"${key}\". Is the secret key correct?`)\n }\n }\n\n return decrypted\n}\n\nfunction reEncryptAllKeys(\n decryptedKeys: Record<string, string>,\n newPublicKey: string,\n): Record<string, string> {\n const encrypted: Record<string, string> = {}\n\n for (const key in decryptedKeys) {\n encrypted[key] = encrypt(newPublicKey, decryptedKeys[key])\n }\n\n return encrypted\n}\n\n"],"mappings":"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","names":["encrypt","decrypt","path","path","encrypt","YAML","YAML","YAML","path","YAML","decrypt","path","YAML","prompts","path","YAML","decrypt","encrypt"]} |
+58
-0
@@ -269,2 +269,59 @@ #!/usr/bin/env node | ||
| // src/cli/migrate/index.ts | ||
| import YAML4 from "yaml"; | ||
| import prompts2 from "prompts"; | ||
| async function envMigrate({ path: path2, secret }) { | ||
| if (!path2) { | ||
| path2 = ".env.local.yml"; | ||
| } | ||
| const config = getConfig(path2); | ||
| const currentSecret = secret ?? await promptForSecret(); | ||
| const decryptedKeys = decryptAllKeys(config.encryptedKeys, currentSecret); | ||
| const newKeypair = generateKeys(); | ||
| const newEncryptedKeys = reEncryptAllKeys(decryptedKeys, newKeypair.encryptKey); | ||
| const updatedConfig = { | ||
| ...config, | ||
| publicKey: newKeypair.encryptKey, | ||
| encryptedKeys: newEncryptedKeys | ||
| }; | ||
| const text = YAML4.stringify(updatedConfig); | ||
| writeFile(path2, text); | ||
| console.log(""); | ||
| console.log("Config file migrated successfully."); | ||
| console.log(""); | ||
| console.log("New secret key (save this securely):"); | ||
| console.log(""); | ||
| console.log(newKeypair.decryptKey); | ||
| console.log(""); | ||
| } | ||
| async function promptForSecret() { | ||
| const response = await prompts2({ | ||
| type: "password", | ||
| name: "secret", | ||
| message: "Current secret key" | ||
| }); | ||
| if (!response.secret) { | ||
| throw new Error("Secret is required"); | ||
| } | ||
| return response.secret; | ||
| } | ||
| function decryptAllKeys(encryptedKeys, secretKey) { | ||
| const decrypted = {}; | ||
| for (const key in encryptedKeys) { | ||
| try { | ||
| decrypted[key] = decrypt2(secretKey, encryptedKeys[key]); | ||
| } catch (error) { | ||
| throw new Error(`Failed to decrypt key "${key}". Is the secret key correct?`); | ||
| } | ||
| } | ||
| return decrypted; | ||
| } | ||
| function reEncryptAllKeys(decryptedKeys, newPublicKey) { | ||
| const encrypted = {}; | ||
| for (const key in decryptedKeys) { | ||
| encrypted[key] = encrypt2(newPublicKey, decryptedKeys[key]); | ||
| } | ||
| return encrypted; | ||
| } | ||
| // src/cli/index.ts | ||
@@ -282,2 +339,3 @@ var program = new Command(); | ||
| program.command("read").description("Prints the value of the env file in JSON or a specific variable in plain text").option("--path <path>", "Specify the env file name").option("--key <key>", "Prints the value of a specific variable in plain text").option("--secret <secret>", "The password to decrypt the keys").action(run(envRead)); | ||
| program.command("migrate").description("Migrates the config file to a new keypair, re-encrypting all keys").option("--path <path>", "Specify the env file name").option("--secret <secret>", "The current secret key to decrypt existing keys").action(run(envMigrate)); | ||
| program.parse(process.argv); | ||
@@ -284,0 +342,0 @@ if (!process.argv.slice(2).length) { |
+12
-11
| { | ||
| "name": "@orion-js/env", | ||
| "version": "4.1.5", | ||
| "version": "4.1.6", | ||
| "main": "./dist/index.cjs", | ||
@@ -10,2 +10,8 @@ "author": "nicolaslopezj", | ||
| }, | ||
| "scripts": { | ||
| "test": "vitest run", | ||
| "clean": "rm -rf ./dist", | ||
| "build": "tsup --config tsup.config.ts && tsup --config cli.tsup.config.ts", | ||
| "dev": "tsup --watch" | ||
| }, | ||
| "dependencies": { | ||
@@ -20,3 +26,3 @@ "chalk": "^4.1.2", | ||
| "peerDependencies": { | ||
| "@orion-js/logger": "4.1.4" | ||
| "@orion-js/logger": "workspace:*" | ||
| }, | ||
@@ -42,10 +48,5 @@ "devDependencies": { | ||
| "files": [ | ||
| "dist" | ||
| ], | ||
| "scripts": { | ||
| "test": "vitest run", | ||
| "clean": "rm -rf ./dist", | ||
| "build": "tsup --config tsup.config.ts && tsup --config cli.tsup.config.ts", | ||
| "dev": "tsup --watch" | ||
| } | ||
| } | ||
| "dist", | ||
| "dist-cli" | ||
| ] | ||
| } |
-21
| MIT License | ||
| Copyright (c) 2022 Orionjs Team | ||
| Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| of this software and associated documentation files (the "Software"), to deal | ||
| in the Software without restriction, including without limitation the rights | ||
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| copies of the Software, and to permit persons to whom the Software is | ||
| furnished to do so, subject to the following conditions: | ||
| The above copyright notice and this permission notice shall be included in all | ||
| copies or substantial portions of the Software. | ||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| SOFTWARE. |
117982
95.03%14
40%1169
53.41%31
10.71%