@dotenvx/dotenvx 1.55.1 → 1.57.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.
- package/CHANGELOG.md +18 -1
- package/README.md +43 -45
- package/package.json +3 -3
- package/src/cli/actions/decrypt.js +2 -2
- package/src/cli/actions/encrypt.js +10 -14
- package/src/cli/actions/ext/genexample.js +3 -2
- package/src/cli/actions/ext/gitignore.js +2 -2
- package/src/cli/actions/get.js +4 -2
- package/src/cli/actions/keypair.js +3 -2
- package/src/cli/actions/rotate.js +19 -21
- package/src/cli/actions/run.js +1 -14
- package/src/cli/actions/set.js +16 -16
- package/src/cli/commands/ext.js +0 -3
- package/src/cli/dotenvx.js +29 -25
- package/src/cli/examples.js +2 -2
- package/src/db/session.js +21 -0
- package/src/lib/extensions/ops.js +98 -0
- package/src/lib/helpers/buildEnvs.js +2 -15
- package/src/lib/helpers/{decryptKeyValue.js → cryptography/decryptKeyValue.js} +1 -1
- package/src/lib/helpers/cryptography/index.js +14 -0
- package/src/lib/helpers/{isPublicKey.js → cryptography/isPublicKey.js} +1 -1
- package/src/lib/helpers/{keypair.js → cryptography/localKeypair.js} +2 -2
- package/src/lib/helpers/cryptography/mutateKeysSrc.js +38 -0
- package/src/lib/helpers/cryptography/mutateSrc.js +24 -0
- package/src/lib/helpers/cryptography/opsKeypair.js +14 -0
- package/src/lib/helpers/cryptography/provision.js +47 -0
- package/src/lib/helpers/cryptography/provisionWithPrivateKey.js +26 -0
- package/src/lib/helpers/envResolution/determine.js +46 -0
- package/src/lib/helpers/{guessEnvironment.js → envResolution/environment.js} +4 -6
- package/src/lib/helpers/envResolution/index.js +8 -0
- package/src/lib/helpers/errors.js +13 -0
- package/src/lib/helpers/executeDynamic.js +11 -14
- package/src/lib/helpers/findEnvFiles.js +1 -1
- package/src/lib/helpers/isFullyEncrypted.js +3 -3
- package/src/lib/helpers/keyResolution/index.js +13 -0
- package/src/lib/helpers/keyResolution/keyNames.js +24 -0
- package/src/lib/helpers/keyResolution/keyValues.js +85 -0
- package/src/lib/helpers/keyResolution/readFileKey.js +15 -0
- package/src/lib/helpers/keyResolution/readProcessKey.js +7 -0
- package/src/lib/helpers/localDisplayPath.js +11 -0
- package/src/lib/helpers/parse.js +1 -1
- package/src/lib/helpers/prependPublicKey.js +17 -0
- package/src/lib/helpers/preserveShebang.js +16 -0
- package/src/lib/main.d.ts +19 -3
- package/src/lib/main.js +23 -32
- package/src/lib/services/decrypt.js +23 -19
- package/src/lib/services/encrypt.js +41 -136
- package/src/lib/services/get.js +3 -3
- package/src/lib/services/keypair.js +12 -16
- package/src/lib/services/prebuild.js +2 -2
- package/src/lib/services/precommit.js +2 -2
- package/src/lib/services/rotate.js +59 -42
- package/src/lib/services/run.js +29 -112
- package/src/lib/services/sets.js +40 -124
- package/src/shared/colors.js +10 -0
- package/src/shared/logger.js +4 -3
- package/src/lib/helpers/decrypt.js +0 -31
- package/src/lib/helpers/deprecationNotice.js +0 -17
- package/src/lib/helpers/determineEnvs.js +0 -65
- package/src/lib/helpers/encrypt.js +0 -29
- package/src/lib/helpers/findPrivateKey.js +0 -25
- package/src/lib/helpers/findPublicKey.js +0 -15
- package/src/lib/helpers/guessPrivateKeyName.js +0 -18
- package/src/lib/helpers/guessPublicKeyName.js +0 -18
- package/src/lib/helpers/parseEncryptionKeyFromDotenvKey.js +0 -19
- package/src/lib/helpers/parseEnvironmentFromDotenvKey.js +0 -19
- package/src/lib/helpers/smartDotenvPrivateKey.js +0 -89
- package/src/lib/helpers/smartDotenvPublicKey.js +0 -42
- package/src/lib/services/ops.js +0 -136
- /package/src/lib/helpers/{encryptValue.js → cryptography/encryptValue.js} +0 -0
- /package/src/lib/helpers/{isEncrypted.js → cryptography/isEncrypted.js} +0 -0
package/src/cli/dotenvx.js
CHANGED
|
@@ -13,6 +13,9 @@ const executeDynamic = require('./../lib/helpers/executeDynamic')
|
|
|
13
13
|
const removeDynamicHelpSection = require('./../lib/helpers/removeDynamicHelpSection')
|
|
14
14
|
const removeOptionsHelpParts = require('./../lib/helpers/removeOptionsHelpParts')
|
|
15
15
|
|
|
16
|
+
const Session = require('./../db/session')
|
|
17
|
+
const sesh = new Session()
|
|
18
|
+
|
|
16
19
|
// for use with run
|
|
17
20
|
const envs = []
|
|
18
21
|
function collectEnvs (type) {
|
|
@@ -68,12 +71,11 @@ program.command('run')
|
|
|
68
71
|
.option('-e, --env <strings...>', 'environment variable(s) set as string (example: "HELLO=World")', collectEnvs('env'), [])
|
|
69
72
|
.option('-f, --env-file <paths...>', 'path(s) to your env file(s)', collectEnvs('envFile'), [])
|
|
70
73
|
.option('-fk, --env-keys-file <path>', 'path to your .env.keys file (default: same path as your env file)')
|
|
71
|
-
.option('-fv, --env-vault-file <paths...>', 'path(s) to your .env.vault file(s)', collectEnvs('envVaultFile'), [])
|
|
72
74
|
.option('-o, --overload', 'override existing env variables (by default, existing env vars take precedence over .env files)')
|
|
73
75
|
.option('--strict', 'process.exit(1) on any errors', false)
|
|
74
76
|
.option('--convention <name>', 'load a .env convention (available conventions: [\'nextjs\', \'flow\'])')
|
|
75
77
|
.option('--ignore <errorCodes...>', 'error code(s) to ignore (example: --ignore=MISSING_ENV_FILE)')
|
|
76
|
-
.option('--ops-off', 'disable dotenvx-ops features',
|
|
78
|
+
.option('--ops-off', 'disable dotenvx-ops features', sesh.opsOff())
|
|
77
79
|
.action(function (...args) {
|
|
78
80
|
this.envs = envs
|
|
79
81
|
runAction.apply(this, args)
|
|
@@ -88,15 +90,15 @@ program.command('get')
|
|
|
88
90
|
.option('-e, --env <strings...>', 'environment variable(s) set as string (example: "HELLO=World")', collectEnvs('env'), [])
|
|
89
91
|
.option('-f, --env-file <paths...>', 'path(s) to your env file(s)', collectEnvs('envFile'), [])
|
|
90
92
|
.option('-fk, --env-keys-file <path>', 'path to your .env.keys file (default: same path as your env file)')
|
|
91
|
-
.option('-fv, --env-vault-file <paths...>', 'path(s) to your .env.vault file(s)', collectEnvs('envVaultFile'), [])
|
|
92
93
|
.option('-o, --overload', 'override existing env variables (by default, existing env vars take precedence over .env files)')
|
|
93
94
|
.option('--strict', 'process.exit(1) on any errors', false)
|
|
94
95
|
.option('--convention <name>', 'load a .env convention (available conventions: [\'nextjs\', \'flow\'])')
|
|
95
96
|
.option('--ignore <errorCodes...>', 'error code(s) to ignore (example: --ignore=MISSING_ENV_FILE)')
|
|
96
97
|
.option('-a, --all', 'include all machine envs as well')
|
|
97
98
|
.option('-pp, --pretty-print', 'pretty print output')
|
|
99
|
+
.option('--pp', 'pretty print output (alias)')
|
|
98
100
|
.option('--format <type>', 'format of the output (json, shell, eval)', 'json')
|
|
99
|
-
.option('--ops-off', 'disable dotenvx-ops features',
|
|
101
|
+
.option('--ops-off', 'disable dotenvx-ops features', sesh.opsOff())
|
|
100
102
|
.action(function (...args) {
|
|
101
103
|
this.envs = envs
|
|
102
104
|
getAction.apply(this, args)
|
|
@@ -106,7 +108,7 @@ program.command('get')
|
|
|
106
108
|
const setAction = require('./actions/set')
|
|
107
109
|
program.command('set')
|
|
108
110
|
.usage('<KEY> <value> [options]')
|
|
109
|
-
.description('
|
|
111
|
+
.description('encrypt a single environment variable')
|
|
110
112
|
.addHelpText('after', examples.set)
|
|
111
113
|
.allowUnknownOption()
|
|
112
114
|
.argument('KEY', 'KEY')
|
|
@@ -115,7 +117,7 @@ program.command('set')
|
|
|
115
117
|
.option('-fk, --env-keys-file <path>', 'path to your .env.keys file (default: same path as your env file)')
|
|
116
118
|
.option('-c, --encrypt', 'encrypt value', true)
|
|
117
119
|
.option('-p, --plain', 'store value as plain text', false)
|
|
118
|
-
.option('--ops-off', 'disable dotenvx-ops features',
|
|
120
|
+
.option('--ops-off', 'disable dotenvx-ops features', sesh.opsOff())
|
|
119
121
|
.action(function (...args) {
|
|
120
122
|
this.envs = envs
|
|
121
123
|
setAction.apply(this, args)
|
|
@@ -129,7 +131,7 @@ program.command('encrypt')
|
|
|
129
131
|
.option('-fk, --env-keys-file <path>', 'path to your .env.keys file (default: same path as your env file)')
|
|
130
132
|
.option('-k, --key <keys...>', 'keys(s) to encrypt (default: all keys in file)')
|
|
131
133
|
.option('-ek, --exclude-key <excludeKeys...>', 'keys(s) to exclude from encryption (default: none)')
|
|
132
|
-
.option('--ops-off', 'disable dotenvx-ops features',
|
|
134
|
+
.option('--ops-off', 'disable dotenvx-ops features', sesh.opsOff())
|
|
133
135
|
.option('--stdout', 'send to stdout')
|
|
134
136
|
.action(function (...args) {
|
|
135
137
|
this.envs = envs
|
|
@@ -144,13 +146,28 @@ program.command('decrypt')
|
|
|
144
146
|
.option('-fk, --env-keys-file <path>', 'path to your .env.keys file (default: same path as your env file)')
|
|
145
147
|
.option('-k, --key <keys...>', 'keys(s) to decrypt (default: all keys in file)')
|
|
146
148
|
.option('-ek, --exclude-key <excludeKeys...>', 'keys(s) to exclude from decryption (default: none)')
|
|
147
|
-
.option('--ops-off', 'disable dotenvx-ops features',
|
|
149
|
+
.option('--ops-off', 'disable dotenvx-ops features', sesh.opsOff())
|
|
148
150
|
.option('--stdout', 'send to stdout')
|
|
149
151
|
.action(function (...args) {
|
|
150
152
|
this.envs = envs
|
|
151
153
|
decryptAction.apply(this, args)
|
|
152
154
|
})
|
|
153
155
|
|
|
156
|
+
// dotenvx rotate
|
|
157
|
+
const rotateAction = require('./actions/rotate')
|
|
158
|
+
program.command('rotate')
|
|
159
|
+
.description('rotate keypair(s) and re-encrypt .env file(s)')
|
|
160
|
+
.option('-f, --env-file <paths...>', 'path(s) to your env file(s)', collectEnvs('envFile'), [])
|
|
161
|
+
.option('-fk, --env-keys-file <path>', 'path to your .env.keys file (default: same path as your env file)')
|
|
162
|
+
.option('-k, --key <keys...>', 'keys(s) to encrypt (default: all keys in file)')
|
|
163
|
+
.option('-ek, --exclude-key <excludeKeys...>', 'keys(s) to exclude from encryption (default: none)')
|
|
164
|
+
.option('--ops-off', 'disable dotenvx-ops features', sesh.opsOff())
|
|
165
|
+
.option('--stdout', 'send to stdout')
|
|
166
|
+
.action(function (...args) {
|
|
167
|
+
this.envs = envs
|
|
168
|
+
rotateAction.apply(this, args)
|
|
169
|
+
})
|
|
170
|
+
|
|
154
171
|
// dotenvx keypair
|
|
155
172
|
const keypairAction = require('./actions/keypair')
|
|
156
173
|
program.command('keypair')
|
|
@@ -159,8 +176,9 @@ program.command('keypair')
|
|
|
159
176
|
.argument('[KEY]', 'environment variable key name')
|
|
160
177
|
.option('-f, --env-file <paths...>', 'path(s) to your env file(s)')
|
|
161
178
|
.option('-fk, --env-keys-file <path>', 'path to your .env.keys file (default: same path as your env file)')
|
|
162
|
-
.option('--ops-off', 'disable dotenvx-ops features',
|
|
179
|
+
.option('--ops-off', 'disable dotenvx-ops features', sesh.opsOff())
|
|
163
180
|
.option('-pp, --pretty-print', 'pretty print output')
|
|
181
|
+
.option('--pp', 'pretty print output (alias)')
|
|
164
182
|
.option('--format <type>', 'format of the output (json, shell)', 'json')
|
|
165
183
|
.action(keypairAction)
|
|
166
184
|
|
|
@@ -173,21 +191,6 @@ program.command('ls')
|
|
|
173
191
|
.option('-ef, --exclude-env-file <excludeFilenames...>', 'path(s) to exclude from your env file(s) (default: none)')
|
|
174
192
|
.action(lsAction)
|
|
175
193
|
|
|
176
|
-
// dotenvx rotate
|
|
177
|
-
const rotateAction = require('./actions/rotate')
|
|
178
|
-
program.command('rotate')
|
|
179
|
-
.description('rotate keypair(s) and re-encrypt .env file(s)')
|
|
180
|
-
.option('-f, --env-file <paths...>', 'path(s) to your env file(s)', collectEnvs('envFile'), [])
|
|
181
|
-
.option('-fk, --env-keys-file <path>', 'path to your .env.keys file (default: same path as your env file)')
|
|
182
|
-
.option('-k, --key <keys...>', 'keys(s) to encrypt (default: all keys in file)')
|
|
183
|
-
.option('-ek, --exclude-key <excludeKeys...>', 'keys(s) to exclude from encryption (default: none)')
|
|
184
|
-
.option('--ops-off', 'disable dotenvx-ops features', false)
|
|
185
|
-
.option('--stdout', 'send to stdout')
|
|
186
|
-
.action(function (...args) {
|
|
187
|
-
this.envs = envs
|
|
188
|
-
rotateAction.apply(this, args)
|
|
189
|
-
})
|
|
190
|
-
|
|
191
194
|
// dotenvx help
|
|
192
195
|
program.command('help [command]')
|
|
193
196
|
.description('display help for command')
|
|
@@ -249,7 +252,8 @@ program.helpInformation = function () {
|
|
|
249
252
|
const filteredLines = lines.filter(line =>
|
|
250
253
|
!line.includes('DEPRECATED') &&
|
|
251
254
|
!line.includes('help [command]') &&
|
|
252
|
-
!line.includes('🔌 extensions')
|
|
255
|
+
!line.includes('🔌 extensions') &&
|
|
256
|
+
!/^\s*ls\b/.test(line)
|
|
253
257
|
)
|
|
254
258
|
|
|
255
259
|
return filteredLines.join('\n')
|
package/src/cli/examples.js
CHANGED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
const Ops = require('./../lib/extensions/ops')
|
|
2
|
+
|
|
3
|
+
class Session {
|
|
4
|
+
constructor () {
|
|
5
|
+
this.ops = new Ops()
|
|
6
|
+
this.opsStatus = this.ops.status()
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
//
|
|
10
|
+
// opsOff/On
|
|
11
|
+
//
|
|
12
|
+
opsOn () {
|
|
13
|
+
return this.opsStatus === 'on'
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
opsOff () {
|
|
17
|
+
return !this.opsOn()
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
module.exports = Session
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
const path = require('path')
|
|
2
|
+
const childProcess = require('child_process')
|
|
3
|
+
|
|
4
|
+
// const { logger } = require('./../../shared/logger')
|
|
5
|
+
|
|
6
|
+
class Ops {
|
|
7
|
+
constructor () {
|
|
8
|
+
this.opsLib = null
|
|
9
|
+
|
|
10
|
+
if (this._isForcedOff()) {
|
|
11
|
+
return
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// check npm lib
|
|
15
|
+
try { this.opsLib = this._opsNpm() } catch (_e) {}
|
|
16
|
+
|
|
17
|
+
// check binary cli
|
|
18
|
+
if (!this.opsLib) {
|
|
19
|
+
try { this.opsLib = this._opsCli() } catch (_e) {}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (this.opsLib) {
|
|
23
|
+
// logger.successv(`🛡️ ops: ${this.opsLib.status()}`)
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
status () {
|
|
28
|
+
if (this._isForcedOff() || !this.opsLib) {
|
|
29
|
+
return 'off'
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return this.opsLib.status()
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
keypair (publicKey) {
|
|
36
|
+
if (this._isForcedOff() || !this.opsLib) {
|
|
37
|
+
return {}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return this.opsLib.keypair(publicKey)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
observe (payload) {
|
|
44
|
+
if (!this._isForcedOff() && this.opsLib && this.opsLib.status() !== 'off') {
|
|
45
|
+
const encoded = Buffer.from(JSON.stringify(payload)).toString('base64')
|
|
46
|
+
this.opsLib.observe(encoded)
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
//
|
|
51
|
+
// private
|
|
52
|
+
//
|
|
53
|
+
_opsNpm () {
|
|
54
|
+
const npmBin = path.resolve(process.cwd(), 'node_modules/.bin/dotenvx-ops')
|
|
55
|
+
return this._opsLib(npmBin)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
_opsCli () {
|
|
59
|
+
return this._opsLib('dotenvx-ops')
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
_opsLib (binary) {
|
|
63
|
+
childProcess.execFileSync(binary, ['--version'], { stdio: ['pipe', 'pipe', 'ignore'] })
|
|
64
|
+
|
|
65
|
+
return {
|
|
66
|
+
status: () => {
|
|
67
|
+
return childProcess.execFileSync(binary, ['status'], { stdio: ['pipe', 'pipe', 'ignore'] }).toString().trim()
|
|
68
|
+
},
|
|
69
|
+
keypair: (publicKey) => {
|
|
70
|
+
const args = ['keypair']
|
|
71
|
+
if (publicKey) {
|
|
72
|
+
args.push(publicKey)
|
|
73
|
+
}
|
|
74
|
+
const output = childProcess.execFileSync(binary, args, { stdio: ['pipe', 'pipe', 'ignore'] }).toString().trim()
|
|
75
|
+
const parsed = JSON.parse(output.toString())
|
|
76
|
+
return parsed
|
|
77
|
+
},
|
|
78
|
+
observe: (encoded) => {
|
|
79
|
+
try {
|
|
80
|
+
const subprocess = childProcess.spawn(binary, ['observe', encoded], {
|
|
81
|
+
stdio: 'ignore',
|
|
82
|
+
detached: true
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
subprocess.unref() // let it run independently
|
|
86
|
+
} catch (e) {
|
|
87
|
+
// noop
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
_isForcedOff () {
|
|
94
|
+
return process.env.DOTENVX_OPS_OFF === 'true'
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
module.exports = Ops
|
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
const path = require('path')
|
|
2
|
-
|
|
3
1
|
const conventions = require('./conventions')
|
|
4
2
|
const dotenvOptionPaths = require('./dotenvOptionPaths')
|
|
5
|
-
const DeprecationNotice = require('./deprecationNotice')
|
|
6
3
|
|
|
7
|
-
function buildEnvs (options
|
|
4
|
+
function buildEnvs (options) {
|
|
8
5
|
// build envs using user set option.path
|
|
9
6
|
const optionPaths = dotenvOptionPaths(options) // [ '.env' ]
|
|
10
7
|
|
|
@@ -13,18 +10,8 @@ function buildEnvs (options, DOTENV_KEY = undefined) {
|
|
|
13
10
|
envs = conventions(options.convention).concat(envs)
|
|
14
11
|
}
|
|
15
12
|
|
|
16
|
-
new DeprecationNotice({ DOTENV_KEY }).dotenvKey() // DEPRECATION NOTICE
|
|
17
|
-
|
|
18
13
|
for (const optionPath of optionPaths) {
|
|
19
|
-
|
|
20
|
-
if (DOTENV_KEY) {
|
|
21
|
-
envs.push({
|
|
22
|
-
type: 'envVaultFile',
|
|
23
|
-
value: path.join(path.dirname(optionPath), '.env.vault')
|
|
24
|
-
})
|
|
25
|
-
} else {
|
|
26
|
-
envs.push({ type: 'envFile', value: optionPath })
|
|
27
|
-
}
|
|
14
|
+
envs.push({ type: 'envFile', value: optionPath })
|
|
28
15
|
}
|
|
29
16
|
|
|
30
17
|
return envs
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
opsKeypair: require('./opsKeypair'),
|
|
3
|
+
localKeypair: require('./localKeypair'),
|
|
4
|
+
encryptValue: require('./encryptValue'),
|
|
5
|
+
decryptKeyValue: require('./decryptKeyValue'),
|
|
6
|
+
isEncrypted: require('./isEncrypted'),
|
|
7
|
+
isPublicKey: require('./isPublicKey'),
|
|
8
|
+
provision: require('./provision'),
|
|
9
|
+
provisionWithPrivateKey: require('./provisionWithPrivateKey'),
|
|
10
|
+
mutateSrc: require('./mutateSrc'),
|
|
11
|
+
|
|
12
|
+
// other
|
|
13
|
+
isFullyEncrypted: require('./../isFullyEncrypted')
|
|
14
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const { PrivateKey } = require('eciesjs')
|
|
2
2
|
|
|
3
|
-
function
|
|
3
|
+
function localKeypair (existingPrivateKey) {
|
|
4
4
|
let kp
|
|
5
5
|
|
|
6
6
|
if (existingPrivateKey) {
|
|
@@ -18,4 +18,4 @@ function keypair (existingPrivateKey) {
|
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
module.exports =
|
|
21
|
+
module.exports = localKeypair
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
const FIRST_TIME_KEYS_SRC = [
|
|
2
|
+
'#/------------------!DOTENV_PRIVATE_KEYS!-------------------/',
|
|
3
|
+
'#/ private decryption keys. DO NOT commit to source control /',
|
|
4
|
+
'#/ [how it works](https://dotenvx.com/encryption) /',
|
|
5
|
+
// '#/ backup with: `dotenvx ops backup` /',
|
|
6
|
+
'#/----------------------------------------------------------/'
|
|
7
|
+
].join('\n')
|
|
8
|
+
|
|
9
|
+
const path = require('path')
|
|
10
|
+
const fsx = require('./../fsx')
|
|
11
|
+
|
|
12
|
+
function mutateKeysSrc ({ envFilepath, keysFilepath, privateKeyName, privateKeyValue }) {
|
|
13
|
+
const filename = path.basename(envFilepath)
|
|
14
|
+
const filepath = path.resolve(envFilepath)
|
|
15
|
+
let resolvedKeysFilepath = path.join(path.dirname(filepath), '.env.keys')
|
|
16
|
+
if (keysFilepath) {
|
|
17
|
+
resolvedKeysFilepath = path.resolve(keysFilepath)
|
|
18
|
+
}
|
|
19
|
+
const appendPrivateKey = [`# ${filename}`, `${privateKeyName}=${privateKeyValue}`, ''].join('\n')
|
|
20
|
+
|
|
21
|
+
let keysSrc = ''
|
|
22
|
+
if (fsx.existsSync(resolvedKeysFilepath)) {
|
|
23
|
+
keysSrc = fsx.readFileX(resolvedKeysFilepath)
|
|
24
|
+
}
|
|
25
|
+
keysSrc = keysSrc.length > 1 ? keysSrc : `${FIRST_TIME_KEYS_SRC}\n`
|
|
26
|
+
keysSrc = `${keysSrc}\n${appendPrivateKey}`
|
|
27
|
+
|
|
28
|
+
fsx.writeFileX(resolvedKeysFilepath, keysSrc) // TODO: don't write if ops
|
|
29
|
+
|
|
30
|
+
const envKeysFilepath = keysFilepath || path.join(path.dirname(envFilepath), path.basename(resolvedKeysFilepath))
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
keysSrc,
|
|
34
|
+
envKeysFilepath
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
module.exports = mutateKeysSrc
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
const path = require('path')
|
|
2
|
+
const preserveShebang = require('./../preserveShebang')
|
|
3
|
+
const prependPublicKey = require('./../prependPublicKey')
|
|
4
|
+
|
|
5
|
+
function mutateSrc ({ envSrc, envFilepath, keysFilepath, publicKeyName, publicKeyValue }) {
|
|
6
|
+
const filename = path.basename(envFilepath)
|
|
7
|
+
const filepath = path.resolve(envFilepath)
|
|
8
|
+
let resolvedKeysFilepath = path.join(path.dirname(filepath), '.env.keys')
|
|
9
|
+
if (keysFilepath) {
|
|
10
|
+
resolvedKeysFilepath = path.resolve(keysFilepath)
|
|
11
|
+
}
|
|
12
|
+
const relativeFilepath = path.relative(path.dirname(filepath), resolvedKeysFilepath)
|
|
13
|
+
|
|
14
|
+
const ps = preserveShebang(envSrc)
|
|
15
|
+
const prependedPublicKey = prependPublicKey(publicKeyName, publicKeyValue, filename, relativeFilepath)
|
|
16
|
+
|
|
17
|
+
envSrc = `${ps.firstLinePreserved}${prependedPublicKey}\n${ps.envSrc}`
|
|
18
|
+
|
|
19
|
+
return {
|
|
20
|
+
envSrc
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
module.exports = mutateSrc
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const Ops = require('../../extensions/ops')
|
|
2
|
+
|
|
3
|
+
function opsKeypair (existingPublicKey) {
|
|
4
|
+
const kp = new Ops().keypair(existingPublicKey)
|
|
5
|
+
const publicKey = kp.public_key
|
|
6
|
+
const privateKey = kp.private_key
|
|
7
|
+
|
|
8
|
+
return {
|
|
9
|
+
publicKey,
|
|
10
|
+
privateKey
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
module.exports = opsKeypair
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
const mutateSrc = require('./mutateSrc')
|
|
2
|
+
const mutateKeysSrc = require('./mutateKeysSrc')
|
|
3
|
+
const opsKeypair = require('./opsKeypair')
|
|
4
|
+
const localKeypair = require('./localKeypair')
|
|
5
|
+
const { keyNames } = require('../keyResolution')
|
|
6
|
+
|
|
7
|
+
function provision ({ envSrc, envFilepath, keysFilepath, opsOn }) {
|
|
8
|
+
opsOn = opsOn === true
|
|
9
|
+
const { publicKeyName, privateKeyName } = keyNames(envFilepath)
|
|
10
|
+
|
|
11
|
+
let publicKey
|
|
12
|
+
let privateKey
|
|
13
|
+
let keysSrc
|
|
14
|
+
let envKeysFilepath
|
|
15
|
+
let privateKeyAdded = false
|
|
16
|
+
|
|
17
|
+
if (opsOn) {
|
|
18
|
+
const kp = opsKeypair()
|
|
19
|
+
publicKey = kp.publicKey
|
|
20
|
+
privateKey = kp.privateKey
|
|
21
|
+
} else {
|
|
22
|
+
const kp = localKeypair()
|
|
23
|
+
publicKey = kp.publicKey
|
|
24
|
+
privateKey = kp.privateKey
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const mutated = mutateSrc({ envSrc, envFilepath, keysFilepath, publicKeyName, publicKeyValue: publicKey })
|
|
28
|
+
envSrc = mutated.envSrc
|
|
29
|
+
|
|
30
|
+
if (!opsOn) {
|
|
31
|
+
const mutated = mutateKeysSrc({ envFilepath, keysFilepath, privateKeyName, privateKeyValue: privateKey })
|
|
32
|
+
keysSrc = mutated.keysSrc
|
|
33
|
+
envKeysFilepath = mutated.envKeysFilepath
|
|
34
|
+
privateKeyAdded = true
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return {
|
|
38
|
+
envSrc,
|
|
39
|
+
keysSrc,
|
|
40
|
+
publicKey,
|
|
41
|
+
privateKey,
|
|
42
|
+
privateKeyAdded,
|
|
43
|
+
envKeysFilepath
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
module.exports = provision
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
const Errors = require('./../errors')
|
|
2
|
+
const mutateSrc = require('./mutateSrc')
|
|
3
|
+
const localKeypair = require('./localKeypair')
|
|
4
|
+
|
|
5
|
+
function provisionWithPrivateKey ({ envSrc, envFilepath, keysFilepath, privateKeyValue, publicKeyValue, publicKeyName }) {
|
|
6
|
+
const { publicKey, privateKey } = localKeypair(privateKeyValue) // opsOn doesn't matter here since privateKeyValue was already discovered prior (via ops and local) and passed as privateKeyValue
|
|
7
|
+
|
|
8
|
+
// if derivation doesn't match what's in the file (or preset in env)
|
|
9
|
+
if (publicKeyValue && publicKeyValue !== publicKey) {
|
|
10
|
+
throw new Errors({ publicKey, publicKeyExisting: publicKeyValue }).mispairedPrivateKey()
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// scenario when encrypting a monorepo second .env file from a prior generated -fk .env.keys file
|
|
14
|
+
if (!publicKeyValue) {
|
|
15
|
+
const mutated = mutateSrc({ envSrc, envFilepath, keysFilepath, publicKeyName, publicKeyValue: publicKey })
|
|
16
|
+
envSrc = mutated.envSrc
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return {
|
|
20
|
+
envSrc,
|
|
21
|
+
publicKey,
|
|
22
|
+
privateKey
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
module.exports = provisionWithPrivateKey
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
const dotenvPrivateKeyNames = require('./../dotenvPrivateKeyNames')
|
|
2
|
+
const guessPrivateKeyFilename = require('./../guessPrivateKeyFilename')
|
|
3
|
+
|
|
4
|
+
const TYPE_ENV_FILE = 'envFile'
|
|
5
|
+
const DEFAULT_ENVS = [{ type: TYPE_ENV_FILE, value: '.env' }]
|
|
6
|
+
|
|
7
|
+
function envsFromDotenvPrivateKey (privateKeyNames) {
|
|
8
|
+
const envs = []
|
|
9
|
+
|
|
10
|
+
for (const privateKeyName of privateKeyNames) {
|
|
11
|
+
const filename = guessPrivateKeyFilename(privateKeyName)
|
|
12
|
+
envs.push({ type: TYPE_ENV_FILE, value: filename })
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return envs
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function determine (envs = [], processEnv) {
|
|
19
|
+
const privateKeyNames = dotenvPrivateKeyNames(processEnv)
|
|
20
|
+
if (!envs || envs.length <= 0) {
|
|
21
|
+
// if process.env.DOTENV_PRIVATE_KEY or process.env.DOTENV_PRIVATE_KEY_${environment} is set, assume inline encryption methodology
|
|
22
|
+
if (privateKeyNames.length > 0) {
|
|
23
|
+
return envsFromDotenvPrivateKey(privateKeyNames)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return DEFAULT_ENVS // default to .env file expectation
|
|
27
|
+
} else {
|
|
28
|
+
let fileAlreadySpecified = false
|
|
29
|
+
|
|
30
|
+
for (const env of envs) {
|
|
31
|
+
if (env.type === TYPE_ENV_FILE) {
|
|
32
|
+
fileAlreadySpecified = true
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// return early since envs array objects already contain 1 .env file
|
|
37
|
+
if (fileAlreadySpecified) {
|
|
38
|
+
return envs
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// no .env file specified as a flag so default to .env
|
|
42
|
+
return [...DEFAULT_ENVS, ...envs]
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
module.exports = determine
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const path = require('path')
|
|
2
2
|
|
|
3
|
-
function
|
|
4
|
-
const filename = path.basename(filepath)
|
|
3
|
+
function environment (filepath) {
|
|
4
|
+
const filename = path.basename(filepath).toLowerCase()
|
|
5
5
|
|
|
6
6
|
const parts = filename.split('.')
|
|
7
7
|
const possibleEnvironmentList = [...parts.slice(2)]
|
|
@@ -17,13 +17,11 @@ function guessEnvironment (filepath) {
|
|
|
17
17
|
return possibleEnvironmentList[0]
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
if (
|
|
21
|
-
possibleEnvironmentList.length === 2
|
|
22
|
-
) {
|
|
20
|
+
if (possibleEnvironmentList.length === 2) {
|
|
23
21
|
return possibleEnvironmentList.join('_')
|
|
24
22
|
}
|
|
25
23
|
|
|
26
24
|
return possibleEnvironmentList.slice(0, 2).join('_')
|
|
27
25
|
}
|
|
28
26
|
|
|
29
|
-
module.exports =
|
|
27
|
+
module.exports = environment
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
buildEnvs: require('./../buildEnvs'),
|
|
3
|
+
determine: require('./determine'),
|
|
4
|
+
findEnvFiles: require('./../findEnvFiles'),
|
|
5
|
+
dotenvOptionPaths: require('./../dotenvOptionPaths'),
|
|
6
|
+
environment: require('./environment'),
|
|
7
|
+
conventions: require('./../conventions')
|
|
8
|
+
}
|
|
@@ -8,6 +8,8 @@ class Errors {
|
|
|
8
8
|
this.key = options.key
|
|
9
9
|
this.privateKey = options.privateKey
|
|
10
10
|
this.privateKeyName = options.privateKeyName
|
|
11
|
+
this.publicKey = options.publicKey
|
|
12
|
+
this.publicKeyExisting = options.publicKeyExisting
|
|
11
13
|
this.command = options.command
|
|
12
14
|
|
|
13
15
|
this.message = options.message
|
|
@@ -55,6 +57,17 @@ class Errors {
|
|
|
55
57
|
return e
|
|
56
58
|
}
|
|
57
59
|
|
|
60
|
+
mispairedPrivateKey () {
|
|
61
|
+
const code = 'MISPAIRED_PRIVATE_KEY'
|
|
62
|
+
const message = `[${code}] private key's derived public key (${truncate(this.publicKey)}) does not match the existing public key (${truncate(this.publicKeyExisting)})`
|
|
63
|
+
const help = `[${code}] https://github.com/dotenvx/dotenvx/issues/752`
|
|
64
|
+
|
|
65
|
+
const e = new Error(message)
|
|
66
|
+
e.code = code
|
|
67
|
+
e.help = help
|
|
68
|
+
return e
|
|
69
|
+
}
|
|
70
|
+
|
|
58
71
|
looksWrongPrivateKey () {
|
|
59
72
|
const code = 'WRONG_PRIVATE_KEY'
|
|
60
73
|
const message = `[${code}] could not decrypt ${this.key} using private key '${this.privateKeyName}=${truncate(this.privateKey)}'`
|
|
@@ -23,20 +23,17 @@ function executeDynamic (program, command, rawArgs) {
|
|
|
23
23
|
const result = childProcess.spawnSync(`dotenvx-${command}`, forwardedArgs, { stdio: 'inherit', env })
|
|
24
24
|
if (result.error) {
|
|
25
25
|
if (command === 'ops') {
|
|
26
|
-
const ops = `
|
|
27
|
-
|
|
|
28
|
-
|
|
|
29
|
-
|
|
|
30
|
-
|
|
|
31
|
-
|
|
|
32
|
-
|
|
|
33
|
-
|
|
|
34
|
-
|
|
|
35
|
-
|
|
|
36
|
-
|
|
|
37
|
-
| |
|
|
38
|
-
| Learn more at https://dotenvx.com/ops |
|
|
39
|
-
|_______________________________________________________________________|`
|
|
26
|
+
const ops = ` ___________________________________________________________________
|
|
27
|
+
| |
|
|
28
|
+
| ██████╗ ██████╗ ███████╗ |
|
|
29
|
+
| ██╔═══██╗██╔══██╗██╔════╝ |
|
|
30
|
+
| ██║ ██║██████╔╝███████╗ |
|
|
31
|
+
| ██║ ██║██╔═══╝ ╚════██║ |
|
|
32
|
+
| ╚██████╔╝██║ ███████║ |
|
|
33
|
+
| ╚═════╝ ╚═╝ ╚══════╝ |
|
|
34
|
+
| |
|
|
35
|
+
| Learn more at [https://dotenvx.com/ops] |
|
|
36
|
+
|___________________________________________________________________|`
|
|
40
37
|
|
|
41
38
|
console.log(ops)
|
|
42
39
|
console.log('')
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const fsx = require('./fsx')
|
|
2
2
|
|
|
3
|
-
const RESERVED_ENV_FILES = ['.env.
|
|
3
|
+
const RESERVED_ENV_FILES = ['.env.project', '.env.keys', '.env.me', '.env.x', '.env.example']
|
|
4
4
|
|
|
5
5
|
function findEnvFiles (directory) {
|
|
6
6
|
try {
|