@dotenvx/dotenvx
Advanced tools
Comparing version 1.29.0 to 1.30.0
@@ -5,4 +5,27 @@ # Changelog | ||
[Unreleased](https://github.com/dotenvx/dotenvx/compare/v1.29.0...main) | ||
[Unreleased](https://github.com/dotenvx/dotenvx/compare/v1.30.0...main) | ||
## [1.30.0](https://github.com/dotenvx/dotenvx/compare/v1.29.0...v1.30.0) | ||
### Added | ||
* add `-fk` (`--env-keys-file`) flag to customize the path to your `.env.keys` file with `run, get, set, encrypt, decrypt, and keypair` 🎉 ([#486](https://github.com/dotenvx/dotenvx/pull/486)) | ||
This is great for monorepos. Maintain one `.env.keys` file across multiple monorepos `.env*` files. | ||
```sh | ||
$ dotenvx encrypt -fk .env.keys -f apps/backend/.env | ||
$ dotenvx encrypt -fk .env.keys -f apps/frontend/.env | ||
$ tree -a . | ||
├── .env.keys | ||
└── apps | ||
├── backend | ||
│ └── .env | ||
└── frontend | ||
└── .env | ||
$ dotenvx get -fk .env.keys -f apps/backend/.env | ||
``` | ||
## [1.29.0](https://github.com/dotenvx/dotenvx/compare/v1.28.0...v1.29.0) | ||
@@ -9,0 +32,0 @@ |
{ | ||
"version": "1.29.0", | ||
"version": "1.30.0", | ||
"name": "@dotenvx/dotenvx", | ||
@@ -4,0 +4,0 @@ "description": "a better dotenv–from the creator of `dotenv`", |
129
README.md
@@ -586,3 +586,3 @@ [![dotenvx](https://dotenvx.com/better-banner.png)](https://dotenvx.com) | ||
Set `--log-level` to whatever you wish. For example, to supress warnings (risky), set log level to `error`: | ||
Set `--log-level` to whatever you wish. For example, to suppress warnings (risky), set log level to `error`: | ||
@@ -960,3 +960,3 @@ ```sh | ||
Set `--log-level` to whatever you wish. For example, to supress warnings (risky), set log level to `error`: | ||
Set `--log-level` to whatever you wish. For example, to suppress warnings (risky), set log level to `error`: | ||
@@ -1020,2 +1020,15 @@ ```sh | ||
</details> | ||
* <details><summary>`run -fk`</summary><br> | ||
Specify path to `.env.keys`. This is useful with monorepos. | ||
```sh | ||
$ mkdir -p apps/app1 | ||
$ touch apps/app1/.env | ||
$ dotenvx set HELLO world -fk .env.keys -f apps/app1/.env | ||
$ dotenvx run -fk .env.keys -f apps/app1/.env -- yourcommand | ||
``` | ||
</details> | ||
* <details><summary>`get KEY`</summary><br> | ||
@@ -1046,2 +1059,16 @@ | ||
</details> | ||
* <details><summary>`get KEY -fk`</summary><br> | ||
Specify path to `.env.keys`. This is useful with monorepos. | ||
```sh | ||
$ mkdir -p apps/app1 | ||
$ touch apps/app1/.env | ||
$ dotenvx set HELLO world -fk .env.keys -f apps/app1/.env | ||
$ dotenvx get HELLO -fk .env.keys -f apps/app1/.env | ||
world | ||
``` | ||
</details> | ||
* <details><summary>`get KEY --env`</summary><br> | ||
@@ -1220,2 +1247,28 @@ | ||
</details> | ||
* <details><summary>`set KEY value -fk`</summary><br> | ||
Specify path to `.env.keys`. This is useful with monorepos. | ||
```sh | ||
$ mkdir -p apps/app1 | ||
$ touch apps/app1/.env | ||
$ dotenvx set HELLO world -fk .env.keys -f apps/app1/.env | ||
set HELLO with encryption (.env) | ||
``` | ||
Put it to use. | ||
```sh | ||
$ dotenvx get -fk .env.keys -f apps/app1/.env | ||
``` | ||
Use it with a relative path. | ||
```sh | ||
$ cd apps/app1 | ||
$ dotenvx get -fk ../../.env.keys -f .env | ||
``` | ||
</details> | ||
* <details><summary>`set KEY "value with spaces"`</summary><br> | ||
@@ -1288,2 +1341,28 @@ | ||
</details> | ||
* <details><summary>`encrypt -fk`</summary><br> | ||
Specify path to `.env.keys`. This is useful with monorepos. | ||
```sh | ||
$ mkdir -p apps/app1 | ||
$ echo "HELLO=World" > apps/app1/.env | ||
$ dotenvx encrypt -fk .env.keys -f apps/app1/.env | ||
✔ encrypted (apps/app1/.env) | ||
``` | ||
Put it to use. | ||
```sh | ||
$ dotenvx run -fk .env.keys -f apps/app1/.env | ||
``` | ||
Use with a relative path. | ||
```sh | ||
$ cd apps/app1 | ||
$ dotenvx run -fk ../../.env.keys -f .env | ||
``` | ||
</details> | ||
* <details><summary>`encrypt -k`</summary><br> | ||
@@ -1383,2 +1462,17 @@ | ||
</details> | ||
* <details><summary>`decrypt -fk`</summary><br> | ||
Specify path to `.env.keys`. This is useful with monorepos. | ||
```sh | ||
$ mkdir -p apps/app1 | ||
$ echo "HELLO=World" > apps/app1/.env | ||
$ dotenvx encrypt -fk .env.keys -f apps/app1/.env | ||
✔ encrypted (apps/app1/.env) | ||
$ dotenvx decrypt -fk .env.keys -f apps/app1/.env | ||
✔ decrypted (apps/app1/.env) | ||
``` | ||
</details> | ||
* <details><summary>`decrypt -k`</summary><br> | ||
@@ -1465,3 +1559,3 @@ | ||
</details> | ||
* <details><summary>`keypair -f .env.production`</summary><br> | ||
* <details><summary>`keypair -f`</summary><br> | ||
@@ -1479,2 +1573,16 @@ Print public/private keys for `.env.production` file. | ||
</details> | ||
* <details><summary>`keypair -fk`</summary><br> | ||
Specify path to `.env.keys`. This is useful for printing public/private keys for monorepos. | ||
```sh | ||
$ mkdir -p apps/app1 | ||
$ echo "HELLO=World" > apps/app1/.env | ||
$ dotenvx encrypt -fk .env.keys -f apps/app1/.env | ||
$ dotenvx keypair -fk .env.keys -f apps/app1/.env | ||
{"DOTENV_PUBLIC_KEY":"<publicKey>","DOTENV_PRIVATE_KEY":"<privateKey>"} | ||
``` | ||
</details> | ||
* <details><summary>`keypair DOTENV_PRIVATE_KEY`</summary><br> | ||
@@ -1917,2 +2025,17 @@ | ||
</details> | ||
* <details><summary>`config(envKeysFile:)` - envKeysFile</summary><br> | ||
Use `envKeysFile` to customize the path to your `.env.keys` file. This is useful with monorepos. | ||
```ini | ||
# .env | ||
HELLO="World" | ||
``` | ||
```js | ||
// index.js | ||
require('@dotenvx/dotenvx').config({envKeysFile: '../../.env.keys'}) | ||
``` | ||
</details> | ||
* <details><summary>`parse(src)`</summary><br> | ||
@@ -1919,0 +2042,0 @@ |
@@ -20,3 +20,3 @@ const fsx = require('./../../lib/helpers/fsx') | ||
processedEnvs | ||
} = new Decrypt(envs, options.key, options.excludeKey).run() | ||
} = new Decrypt(envs, options.key, options.excludeKey, options.envKeysFile).run() | ||
@@ -27,2 +27,5 @@ for (const processedEnv of processedEnvs) { | ||
console.error(processedEnv.error.message) | ||
if (processedEnv.error.help) { | ||
console.error(processedEnv.error.help) | ||
} | ||
} else { | ||
@@ -44,3 +47,3 @@ console.log(processedEnv.envSrc) | ||
unchangedFilepaths | ||
} = new Decrypt(envs, options.key, options.excludeKey).run() | ||
} = new Decrypt(envs, options.key, options.excludeKey, options.envKeysFile).run() | ||
@@ -58,2 +61,5 @@ for (const processedEnv of processedEnvs) { | ||
console.error(processedEnv.error.message) | ||
if (processedEnv.error.help) { | ||
console.error(processedEnv.error.help) | ||
} | ||
} | ||
@@ -60,0 +66,0 @@ } else if (processedEnv.changed) { |
@@ -19,3 +19,3 @@ const fsx = require('./../../lib/helpers/fsx') | ||
processedEnvs | ||
} = new Encrypt(envs, options.key, options.excludeKey).run() | ||
} = new Encrypt(envs, options.key, options.excludeKey, options.envKeysFile).run() | ||
@@ -32,3 +32,3 @@ for (const processedEnv of processedEnvs) { | ||
unchangedFilepaths | ||
} = new Encrypt(envs, options.key, options.excludeKey).run() | ||
} = new Encrypt(envs, options.key, options.excludeKey, options.envKeysFile).run() | ||
@@ -35,0 +35,0 @@ for (const processedEnv of processedEnvs) { |
@@ -27,3 +27,3 @@ const { logger } = require('./../../shared/logger') | ||
try { | ||
const { parsed, errors } = new Get(key, envs, options.overload, process.env.DOTENV_KEY, options.all).run() | ||
const { parsed, errors } = new Get(key, envs, options.overload, process.env.DOTENV_KEY, options.all, options.envKeysFile).run() | ||
@@ -30,0 +30,0 @@ for (const error of errors || []) { |
@@ -13,3 +13,3 @@ const { logger } = require('./../../shared/logger') | ||
const results = main.keypair(options.envFile, key) | ||
const results = main.keypair(options.envFile, key, options.envKeysFile) | ||
@@ -16,0 +16,0 @@ if (typeof results === 'object' && results !== null) { |
@@ -48,3 +48,3 @@ const path = require('path') | ||
uniqueInjectedKeys | ||
} = new Run(envs, options.overload, process.env.DOTENV_KEY).run() | ||
} = new Run(envs, options.overload, process.env.DOTENV_KEY, process.env, options.envKeysFile).run() | ||
@@ -51,0 +51,0 @@ for (const processedEnv of processedEnvs) { |
@@ -24,2 +24,3 @@ const fsx = require('./../../lib/helpers/fsx') | ||
const envs = this.envs | ||
const envKeysFilepath = options.envKeysFile | ||
@@ -30,3 +31,3 @@ const { | ||
unchangedFilepaths | ||
} = new Sets(key, value, envs, encrypt).run() | ||
} = new Sets(key, value, envs, encrypt, envKeysFilepath).run() | ||
@@ -70,3 +71,3 @@ let withEncryption = '' | ||
if (processedEnv.privateKeyAdded) { | ||
logger.success(`✔ key added to .env.keys (${processedEnv.privateKeyName})`) | ||
logger.success(`✔ key added to ${processedEnv.envKeysFilepath} (${processedEnv.privateKeyName})`) | ||
@@ -73,0 +74,0 @@ if (!isIgnoringDotenvKeys()) { |
@@ -59,2 +59,3 @@ #!/usr/bin/env node | ||
.option('-f, --env-file <paths...>', 'path(s) to your env file(s)', collectEnvs('envFile'), []) | ||
.option('-fk, --env-keys-file <path>', 'path to your .env.keys file (default: same path as your env file)') | ||
.option('-fv, --env-vault-file <paths...>', 'path(s) to your .env.vault file(s)', collectEnvs('envVaultFile'), []) | ||
@@ -78,2 +79,3 @@ .option('-o, --overload', 'override existing env variables') | ||
.option('-f, --env-file <paths...>', 'path(s) to your env file(s)', collectEnvs('envFile'), []) | ||
.option('-fk, --env-keys-file <path>', 'path to your .env.keys file (default: same path as your env file)') | ||
.option('-fv, --env-vault-file <paths...>', 'path(s) to your .env.vault file(s)', collectEnvs('envVaultFile'), []) | ||
@@ -102,2 +104,3 @@ .option('-o, --overload', 'override existing env variables') | ||
.option('-f, --env-file <paths...>', 'path(s) to your env file(s)', collectEnvs('envFile'), []) | ||
.option('-fk, --env-keys-file <path>', 'path to your .env.keys file (default: same path as your env file)') | ||
.option('-c, --encrypt', 'encrypt value (default: true)', true) | ||
@@ -115,2 +118,3 @@ .option('-p, --plain', 'store value as plain text', false) | ||
.option('-f, --env-file <paths...>', 'path(s) to your env file(s)', collectEnvs('envFile'), []) | ||
.option('-fk, --env-keys-file <path>', 'path to your .env.keys file (default: same path as your env file)') | ||
.option('-k, --key <keys...>', 'keys(s) to encrypt (default: all keys in file)') | ||
@@ -129,2 +133,3 @@ .option('-ek, --exclude-key <excludeKeys...>', 'keys(s) to exclude from encryption (default: none)') | ||
.option('-f, --env-file <paths...>', 'path(s) to your env file(s)', collectEnvs('envFile'), []) | ||
.option('-fk, --env-keys-file <path>', 'path to your .env.keys file (default: same path as your env file)') | ||
.option('-k, --key <keys...>', 'keys(s) to decrypt (default: all keys in file)') | ||
@@ -145,2 +150,3 @@ .option('-ek, --exclude-key <excludeKeys...>', 'keys(s) to exclude from decryption (default: none)') | ||
.option('-f, --env-file <paths...>', 'path(s) to your env file(s)') | ||
.option('-fk, --env-keys-file <path>', 'path to your .env.keys file (default: same path as your env file)') | ||
.option('-pp, --pretty-print', 'pretty print output') | ||
@@ -147,0 +153,0 @@ .option('--format <type>', 'format of the output (json, shell)', 'json') |
@@ -1,6 +0,4 @@ | ||
const path = require('path') | ||
const childProcess = require('child_process') | ||
// helpers | ||
const guessPrivateKeyName = require('./guessPrivateKeyName') | ||
const ProKeypair = require('./proKeypair') | ||
@@ -10,25 +8,12 @@ // services | ||
function findPrivateKey (envFilepath) { | ||
function findPrivateKey (envFilepath, envKeysFilepath = null) { | ||
// use path/to/.env.${environment} to generate privateKeyName | ||
const privateKeyName = guessPrivateKeyName(envFilepath) | ||
let privateKey | ||
try { | ||
// if installed as sibling module | ||
const projectRoot = path.resolve(process.cwd()) | ||
const dotenvxProPath = require.resolve('@dotenvx/dotenvx-pro', { paths: [projectRoot] }) | ||
const { keypair } = require(dotenvxProPath) | ||
privateKey = keypair(envFilepath, privateKeyName) | ||
} catch (_e) { | ||
try { | ||
// if installed as binary cli | ||
privateKey = childProcess.execSync(`dotenvx-pro keypair ${privateKeyName} -f ${envFilepath}`, { stdio: ['pipe', 'pipe', 'ignore'] }).toString().trim() | ||
} catch (_e) { | ||
// fallback to local KeyPair - smart enough to handle process.env, .env.keys, etc | ||
privateKey = new Keypair(envFilepath, privateKeyName).run() | ||
} | ||
} | ||
const proKeypairs = new ProKeypair(envFilepath).run() // TODO: implement custom envKeysFilepath | ||
const keypairs = new Keypair(envFilepath, envKeysFilepath).run() | ||
return privateKey | ||
return proKeypairs[privateKeyName] || keypairs[privateKeyName] | ||
} | ||
module.exports = findPrivateKey |
@@ -1,6 +0,4 @@ | ||
const path = require('path') | ||
const childProcess = require('child_process') | ||
// helpers | ||
const guessPublicKeyName = require('./guessPublicKeyName') | ||
const ProKeypair = require('./proKeypair') | ||
@@ -13,22 +11,8 @@ // services | ||
let publicKey | ||
try { | ||
// if installed as sibling module | ||
const projectRoot = path.resolve(process.cwd()) | ||
const dotenvxProPath = require.resolve('@dotenvx/dotenvx-pro', { paths: [projectRoot] }) | ||
const { keypair } = require(dotenvxProPath) | ||
publicKey = keypair(envFilepath, publicKeyName) | ||
} catch (_e) { | ||
try { | ||
// if installed as binary cli | ||
publicKey = childProcess.execSync(`dotenvx-pro keypair ${publicKeyName} -f ${envFilepath}`, { stdio: ['pipe', 'pipe', 'ignore'] }).toString().trim() | ||
} catch (_e) { | ||
// fallback to local KeyPair - smart enough to handle process.env, .env.keys, etc | ||
publicKey = new Keypair(envFilepath, publicKeyName).run() | ||
} | ||
} | ||
const proKeypairs = new ProKeypair(envFilepath).run() | ||
const keypairs = new Keypair(envFilepath).run() | ||
return publicKey | ||
return proKeypairs[publicKeyName] || keypairs[publicKeyName] | ||
} | ||
module.exports = findPublicKey |
@@ -16,8 +16,10 @@ const fsx = require('./fsx') | ||
function searchKeysFile (privateKeyName, envFilepath) { | ||
const directory = path.dirname(envFilepath) | ||
const envKeysFilepath = path.resolve(directory, '.env.keys') | ||
function searchKeysFile (privateKeyName, envFilepath, envKeysFilepath = null) { | ||
let keysFilepath = path.resolve(path.dirname(envFilepath), '.env.keys') // typical scenario | ||
if (envKeysFilepath) { // user specified -fk flag | ||
keysFilepath = path.resolve(envKeysFilepath) | ||
} | ||
if (fsx.existsSync(envKeysFilepath)) { | ||
const keysSrc = fsx.readFileX(envKeysFilepath) | ||
if (fsx.existsSync(keysFilepath)) { | ||
const keysSrc = fsx.readFileX(keysFilepath) | ||
const keysParsed = dotenv.parse(keysSrc) | ||
@@ -53,3 +55,3 @@ | ||
function smartDotenvPrivateKey (envFilepath) { | ||
function smartDotenvPrivateKey (envFilepath, envKeysFilepath = null) { | ||
let privateKey = null | ||
@@ -65,3 +67,3 @@ let privateKeyName = guessPrivateKeyName(envFilepath) // DOTENV_PRIVATE_KEY_${ENVIRONMENT} | ||
// 2. attempt .env.keys second (path/to/.env.keys) | ||
privateKey = searchKeysFile(privateKeyName, envFilepath) | ||
privateKey = searchKeysFile(privateKeyName, envFilepath, envKeysFilepath) | ||
if (privateKey) { | ||
@@ -81,3 +83,3 @@ return privateKey | ||
// 3.2. attempt .env.keys second (path/to/.env.keys) | ||
privateKey = searchKeysFile(privateKeyName, envFilepath) | ||
privateKey = searchKeysFile(privateKeyName, envFilepath, envKeysFilepath) | ||
if (privateKey) { | ||
@@ -84,0 +86,0 @@ return privateKey |
@@ -37,2 +37,5 @@ // @ts-check | ||
// envKeysFile | ||
const envKeysFile = options.envKeysFile | ||
// DOTENV_KEY (DEPRECATED) | ||
@@ -74,3 +77,3 @@ let DOTENV_KEY = process.env.DOTENV_KEY | ||
uniqueInjectedKeys | ||
} = new Run(envs, overload, DOTENV_KEY, processEnv).run() | ||
} = new Run(envs, overload, DOTENV_KEY, processEnv, envKeysFile).run() | ||
@@ -195,4 +198,9 @@ let lastError | ||
/** @type {import('./main').keypair} */ | ||
const keypair = function (envFile, key) { | ||
return new Keypair(envFile, key).run() | ||
const keypair = function (envFile, key, envKeysFile = null) { | ||
const keypairs = new Keypair(envFile, envKeysFile).run() | ||
if (key) { | ||
return keypairs[key] | ||
} else { | ||
return keypairs | ||
} | ||
} | ||
@@ -199,0 +207,0 @@ |
@@ -18,6 +18,7 @@ const fsx = require('./../helpers/fsx') | ||
class Decrypt { | ||
constructor (envs = [], key = [], excludeKey = []) { | ||
constructor (envs = [], key = [], excludeKey = [], envKeysFilepath = null) { | ||
this.envs = determineEnvs(envs, process.env) | ||
this.key = key | ||
this.excludeKey = excludeKey | ||
this.envKeysFilepath = envKeysFilepath | ||
@@ -68,3 +69,3 @@ this.processedEnvs = [] | ||
const privateKey = findPrivateKey(envFilepath) | ||
const privateKey = findPrivateKey(envFilepath, this.envKeysFilepath) | ||
const privateKeyName = guessPrivateKeyName(envFilepath) | ||
@@ -71,0 +72,0 @@ |
@@ -18,3 +18,3 @@ const fsx = require('./../helpers/fsx') | ||
const findPublicKey = require('./../helpers/findPublicKey') | ||
const keyPair = require('./../helpers/keyPair') | ||
const keypair = require('./../helpers/keypair') | ||
const truncate = require('./../helpers/truncate') | ||
@@ -24,6 +24,7 @@ const isPublicKey = require('./../helpers/isPublicKey') | ||
class Encrypt { | ||
constructor (envs = [], key = [], excludeKey = []) { | ||
constructor (envs = [], key = [], excludeKey = [], envKeysFilepath = null) { | ||
this.envs = determineEnvs(envs, process.env) | ||
this.key = key | ||
this.excludeKey = excludeKey | ||
this.envKeysFilepath = envKeysFilepath | ||
@@ -80,7 +81,13 @@ this.processedEnvs = [] | ||
const privateKeyName = guessPrivateKeyName(envFilepath) | ||
const existingPrivateKey = findPrivateKey(envFilepath) | ||
const existingPrivateKey = findPrivateKey(envFilepath, this.envKeysFilepath) | ||
const existingPublicKey = findPublicKey(envFilepath) | ||
let envKeysFilepath = path.join(path.dirname(filepath), '.env.keys') | ||
if (this.envKeysFilepath) { | ||
envKeysFilepath = path.resolve(this.envKeysFilepath) | ||
} | ||
const relativeFilepath = path.relative(path.dirname(filepath), envKeysFilepath) | ||
if (existingPrivateKey) { | ||
const kp = keyPair(existingPrivateKey) | ||
const kp = keypair(existingPrivateKey) | ||
publicKey = kp.publicKey | ||
@@ -96,2 +103,13 @@ privateKey = kp.privateKey | ||
} | ||
// typical scenario when encrypting a monorepo second .env file from a prior generated -fk .env.keys file | ||
if (!existingPublicKey) { | ||
const ps = this._preserveShebang(envSrc) | ||
const firstLinePreserved = ps.firstLinePreserved | ||
envSrc = ps.envSrc | ||
const prependPublicKey = this._prependPublicKey(publicKeyName, publicKey, filename, relativeFilepath) | ||
envSrc = `${firstLinePreserved}${prependPublicKey}\n${envSrc}` | ||
} | ||
} else if (existingPublicKey) { | ||
@@ -102,3 +120,3 @@ publicKey = existingPublicKey | ||
let keysSrc = '' | ||
const envKeysFilepath = path.join(path.dirname(filepath), '.env.keys') | ||
if (fsx.existsSync(envKeysFilepath)) { | ||
@@ -108,24 +126,11 @@ keysSrc = fsx.readFileX(envKeysFilepath) | ||
// preserve shebang | ||
const [firstLine, ...remainingLines] = envSrc.split('\n') | ||
let firstLinePreserved = '' | ||
if (firstLine.startsWith('#!')) { | ||
firstLinePreserved = firstLine + '\n' | ||
envSrc = remainingLines.join('\n') | ||
} | ||
const ps = this._preserveShebang(envSrc) | ||
const firstLinePreserved = ps.firstLinePreserved | ||
envSrc = ps.envSrc | ||
const kp = keyPair() // generates a fresh keypair in memory | ||
const kp = keypair() // generates a fresh keypair in memory | ||
publicKey = kp.publicKey | ||
privateKey = kp.privateKey | ||
// publicKey | ||
const prependPublicKey = [ | ||
'#/-------------------[DOTENV_PUBLIC_KEY]--------------------/', | ||
'#/ public-key encryption for .env files /', | ||
'#/ [how it works](https://dotenvx.com/encryption) /', | ||
'#/----------------------------------------------------------/', | ||
`${publicKeyName}="${publicKey}"`, | ||
'', | ||
`# ${filename}` | ||
].join('\n') | ||
const prependPublicKey = this._prependPublicKey(publicKeyName, publicKey, filename, relativeFilepath) | ||
@@ -153,2 +158,3 @@ // privateKey | ||
row.privateKeyAdded = true | ||
row.envKeysFilepath = this.envKeysFilepath || path.join(path.dirname(envFilepath), path.basename(envKeysFilepath)) | ||
} | ||
@@ -220,4 +226,34 @@ | ||
} | ||
_prependPublicKey (publicKeyName, publicKey, filename, relativeFilepath = '') { | ||
const comment = relativeFilepath === '.env.keys' ? '' : ` # ${relativeFilepath}` | ||
return [ | ||
'#/-------------------[DOTENV_PUBLIC_KEY]--------------------/', | ||
'#/ public-key encryption for .env files /', | ||
'#/ [how it works](https://dotenvx.com/encryption) /', | ||
'#/----------------------------------------------------------/', | ||
`${publicKeyName}="${publicKey}"${comment}`, | ||
'', | ||
`# ${filename}` | ||
].join('\n') | ||
} | ||
_preserveShebang (envSrc) { | ||
// preserve shebang | ||
const [firstLine, ...remainingLines] = envSrc.split('\n') | ||
let firstLinePreserved = '' | ||
if (firstLine.startsWith('#!')) { | ||
firstLinePreserved = firstLine + '\n' | ||
envSrc = remainingLines.join('\n') | ||
} | ||
return { | ||
firstLinePreserved, | ||
envSrc | ||
} | ||
} | ||
} | ||
module.exports = Encrypt |
@@ -5,3 +5,3 @@ const Run = require('./run') | ||
class Get { | ||
constructor (key, envs = [], overload = false, DOTENV_KEY = '', all = false, strict = false) { | ||
constructor (key, envs = [], overload = false, DOTENV_KEY = '', all = false, envKeysFilepath = null) { | ||
this.key = key | ||
@@ -12,3 +12,3 @@ this.envs = envs | ||
this.all = all | ||
this.strict = strict | ||
this.envKeysFilepath = envKeysFilepath | ||
} | ||
@@ -18,3 +18,3 @@ | ||
const processEnv = { ...process.env } | ||
const { processedEnvs } = new Run(this.envs, this.overload, this.DOTENV_KEY, processEnv).run() | ||
const { processedEnvs } = new Run(this.envs, this.overload, this.DOTENV_KEY, processEnv, this.envKeysFilepath).run() | ||
@@ -21,0 +21,0 @@ const errors = [] |
@@ -7,5 +7,5 @@ const guessPublicKeyName = require('./../helpers/guessPublicKeyName') | ||
class Keypair { | ||
constructor (envFile = '.env', key = undefined) { | ||
constructor (envFile = '.env', envKeysFilepath = null) { | ||
this.envFile = envFile | ||
this.key = key | ||
this.envKeysFilepath = envKeysFilepath | ||
} | ||
@@ -25,3 +25,3 @@ | ||
const privateKeyName = guessPrivateKeyName(envFilepath) | ||
const privateKeyValue = smartDotenvPrivateKey(envFilepath) | ||
const privateKeyValue = smartDotenvPrivateKey(envFilepath, this.envKeysFilepath) | ||
@@ -31,7 +31,3 @@ out[privateKeyName] = privateKeyValue | ||
if (this.key) { | ||
return out[this.key] | ||
} else { | ||
return out | ||
} | ||
return out | ||
} | ||
@@ -38,0 +34,0 @@ |
@@ -19,3 +19,3 @@ const fsx = require('./../helpers/fsx') | ||
class Run { | ||
constructor (envs = [], overload = false, DOTENV_KEY = '', processEnv = process.env) { | ||
constructor (envs = [], overload = false, DOTENV_KEY = '', processEnv = process.env, envKeysFilepath = null) { | ||
this.envs = determineEnvs(envs, processEnv, DOTENV_KEY) | ||
@@ -25,2 +25,3 @@ this.overload = overload | ||
this.processEnv = processEnv | ||
this.envKeysFilepath = envKeysFilepath | ||
@@ -97,3 +98,3 @@ this.processedEnvs = [] | ||
const privateKey = findPrivateKey(envFilepath) | ||
const privateKey = findPrivateKey(envFilepath, this.envKeysFilepath) | ||
const privateKeyName = guessPrivateKeyName(envFilepath) | ||
@@ -100,0 +101,0 @@ const { parsed, errors, injected, preExisted } = new Parse(src, privateKey, this.processEnv, this.overload, privateKeyName).run() |
@@ -17,3 +17,3 @@ const fsx = require('./../helpers/fsx') | ||
const findPublicKey = require('./../helpers/findPublicKey') | ||
const keyPair = require('./../helpers/keyPair') | ||
const keypair = require('./../helpers/keypair') | ||
const truncate = require('./../helpers/truncate') | ||
@@ -23,3 +23,3 @@ const isEncrypted = require('./../helpers/isEncrypted') | ||
class Sets { | ||
constructor (key, value, envs = [], encrypt = true) { | ||
constructor (key, value, envs = [], encrypt = true, envKeysFilepath = null) { | ||
this.envs = determineEnvs(envs, process.env) | ||
@@ -29,2 +29,3 @@ this.key = key | ||
this.encrypt = encrypt | ||
this.envKeysFilepath = envKeysFilepath | ||
@@ -82,7 +83,13 @@ this.processedEnvs = [] | ||
const privateKeyName = guessPrivateKeyName(envFilepath) | ||
const existingPrivateKey = findPrivateKey(envFilepath) | ||
const existingPrivateKey = findPrivateKey(envFilepath, this.envKeysFilepath) | ||
const existingPublicKey = findPublicKey(envFilepath) | ||
let envKeysFilepath = path.join(path.dirname(filepath), '.env.keys') | ||
if (this.envKeysFilepath) { | ||
envKeysFilepath = path.resolve(this.envKeysFilepath) | ||
} | ||
const relativeFilepath = path.relative(path.dirname(filepath), envKeysFilepath) | ||
if (existingPrivateKey) { | ||
const kp = keyPair(existingPrivateKey) | ||
const kp = keypair(existingPrivateKey) | ||
publicKey = kp.publicKey | ||
@@ -102,2 +109,13 @@ privateKey = kp.privateKey | ||
} | ||
// typical scenario when encrypting a monorepo second .env file from a prior generated -fk .env.keys file | ||
if (!existingPublicKey) { | ||
const ps = this._preserveShebang(envSrc) | ||
const firstLinePreserved = ps.firstLinePreserved | ||
envSrc = ps.envSrc | ||
const prependPublicKey = this._prependPublicKey(publicKeyName, publicKey, filename, relativeFilepath) | ||
envSrc = `${firstLinePreserved}${prependPublicKey}\n${envSrc}` | ||
} | ||
} else if (existingPublicKey) { | ||
@@ -108,3 +126,2 @@ publicKey = existingPublicKey | ||
let keysSrc = '' | ||
const envKeysFilepath = path.join(path.dirname(filepath), '.env.keys') | ||
if (fsx.existsSync(envKeysFilepath)) { | ||
@@ -114,24 +131,11 @@ keysSrc = fsx.readFileX(envKeysFilepath) | ||
// preserve shebang | ||
const [firstLine, ...remainingLines] = envSrc.split('\n') | ||
let firstLinePreserved = '' | ||
if (firstLine.startsWith('#!')) { | ||
firstLinePreserved = firstLine + '\n' | ||
envSrc = remainingLines.join('\n') | ||
} | ||
const ps = this._preserveShebang(envSrc) | ||
const firstLinePreserved = ps.firstLinePreserved | ||
envSrc = ps.envSrc | ||
const kp = keyPair() // generates a fresh keypair in memory | ||
const kp = keypair() // generates a fresh keypair in memory | ||
publicKey = kp.publicKey | ||
privateKey = kp.privateKey | ||
// publicKey | ||
const prependPublicKey = [ | ||
'#/-------------------[DOTENV_PUBLIC_KEY]--------------------/', | ||
'#/ public-key encryption for .env files /', | ||
'#/ [how it works](https://dotenvx.com/encryption) /', | ||
'#/----------------------------------------------------------/', | ||
`${publicKeyName}="${publicKey}"`, | ||
'', | ||
`# ${filename}` | ||
].join('\n') | ||
const prependPublicKey = this._prependPublicKey(publicKeyName, publicKey, filename, relativeFilepath) | ||
@@ -159,2 +163,3 @@ // privateKey | ||
row.privateKeyAdded = true | ||
row.envKeysFilepath = this.envKeysFilepath || path.join(path.dirname(envFilepath), path.basename(envKeysFilepath)) | ||
} | ||
@@ -193,4 +198,34 @@ | ||
} | ||
_prependPublicKey (publicKeyName, publicKey, filename, relativeFilepath = '.env.keys') { | ||
const comment = relativeFilepath === '.env.keys' ? '' : ` # -fk ${relativeFilepath}` | ||
return [ | ||
'#/-------------------[DOTENV_PUBLIC_KEY]--------------------/', | ||
'#/ public-key encryption for .env files /', | ||
'#/ [how it works](https://dotenvx.com/encryption) /', | ||
'#/----------------------------------------------------------/', | ||
`${publicKeyName}="${publicKey}"${comment}`, | ||
'', | ||
`# ${filename}` | ||
].join('\n') | ||
} | ||
_preserveShebang (envSrc) { | ||
// preserve shebang | ||
const [firstLine, ...remainingLines] = envSrc.split('\n') | ||
let firstLinePreserved = '' | ||
if (firstLine.startsWith('#!')) { | ||
firstLinePreserved = firstLine + '\n' | ||
envSrc = remainingLines.join('\n') | ||
} | ||
return { | ||
firstLinePreserved, | ||
envSrc | ||
} | ||
} | ||
} | ||
module.exports = Sets |
237050
85
3772
2155
6