@dotenvx/dotenvx 1.59.1 → 1.60.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 +12 -1
- package/README.md +14 -4
- package/package.json +7 -6
- package/src/cli/actions/decrypt.js +15 -8
- package/src/cli/actions/encrypt.js +15 -8
- package/src/cli/actions/ext/genexample.js +2 -2
- package/src/cli/actions/ext/gitignore.js +3 -3
- package/src/cli/actions/get.js +12 -7
- package/src/cli/actions/keypair.js +13 -5
- package/src/cli/actions/rotate.js +16 -9
- package/src/cli/actions/run.js +13 -6
- package/src/cli/actions/set.js +19 -12
- package/src/cli/dotenvx.js +19 -21
- package/src/cli/examples.js +1 -1
- package/src/db/session.js +10 -6
- package/src/lib/extensions/ops.js +112 -63
- package/src/lib/helpers/catchAndLog.js +1 -1
- package/src/lib/helpers/createSpinner.js +24 -0
- package/src/lib/helpers/cryptography/index.js +4 -0
- package/src/lib/helpers/cryptography/mutateKeysSrc.js +4 -4
- package/src/lib/helpers/cryptography/mutateKeysSrcSync.js +38 -0
- package/src/lib/helpers/cryptography/opsKeypair.js +2 -2
- package/src/lib/helpers/cryptography/opsKeypairSync.js +14 -0
- package/src/lib/helpers/cryptography/provision.js +7 -7
- package/src/lib/helpers/cryptography/provisionSync.js +47 -0
- package/src/lib/helpers/cryptography/provisionWithPrivateKey.js +1 -1
- package/src/lib/helpers/detectEncoding.js +2 -2
- package/src/lib/helpers/detectEncodingSync.js +22 -0
- package/src/lib/helpers/errors.js +15 -0
- package/src/lib/helpers/fsx.js +27 -3
- package/src/lib/helpers/installPrecommitHook.js +2 -2
- package/src/lib/helpers/isIgnoringDotenvKeys.js +1 -1
- package/src/lib/helpers/keyResolution/index.js +3 -1
- package/src/lib/helpers/keyResolution/keyValues.js +12 -12
- package/src/lib/helpers/keyResolution/keyValuesSync.js +85 -0
- package/src/lib/helpers/keyResolution/readFileKey.js +10 -8
- package/src/lib/helpers/keyResolution/readFileKeySync.js +15 -0
- package/src/lib/helpers/kits/sample.js +9 -21
- package/src/lib/main.d.ts +18 -3
- package/src/lib/main.js +18 -18
- package/src/lib/services/decrypt.js +8 -8
- package/src/lib/services/encrypt.js +17 -11
- package/src/lib/services/genexample.js +2 -2
- package/src/lib/services/get.js +30 -21
- package/src/lib/services/keypair.js +21 -5
- package/src/lib/services/prebuild.js +7 -12
- package/src/lib/services/precommit.js +7 -11
- package/src/lib/services/rotate.js +22 -18
- package/src/lib/services/run.js +82 -9
- package/src/lib/services/sets.js +139 -12
- package/src/shared/logger.js +3 -3
- package/src/lib/helpers/sleep.js +0 -5
package/src/cli/dotenvx.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
/* c8 ignore start */
|
|
4
|
-
const { Command } = require('commander')
|
|
4
|
+
const { Command, Option } = require('commander')
|
|
5
5
|
const program = new Command()
|
|
6
6
|
|
|
7
7
|
const { setLogLevel, logger } = require('../shared/logger')
|
|
@@ -13,9 +13,6 @@ 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
|
-
|
|
19
16
|
// for use with run
|
|
20
17
|
const envs = []
|
|
21
18
|
function collectEnvs (type) {
|
|
@@ -74,10 +71,11 @@ program.command('run')
|
|
|
74
71
|
.option('--strict', 'process.exit(1) on any errors', false)
|
|
75
72
|
.option('--convention <name>', 'load a .env convention (available conventions: [\'nextjs\', \'flow\'])')
|
|
76
73
|
.option('--ignore <errorCodes...>', 'error code(s) to ignore (example: --ignore=MISSING_ENV_FILE)')
|
|
77
|
-
.option('--ops
|
|
74
|
+
.option('--no-ops', 'disable dotenvx-ops features')
|
|
75
|
+
.addOption(new Option('--ops-off', 'DEPRECATED: use --no-ops').hideHelp())
|
|
78
76
|
.action(function (...args) {
|
|
79
77
|
this.envs = envs
|
|
80
|
-
runAction.apply(this, args)
|
|
78
|
+
return runAction.apply(this, args)
|
|
81
79
|
})
|
|
82
80
|
|
|
83
81
|
// dotenvx get
|
|
@@ -97,10 +95,10 @@ program.command('get')
|
|
|
97
95
|
.option('-pp, --pretty-print', 'pretty print output')
|
|
98
96
|
.option('--pp', 'pretty print output (alias)')
|
|
99
97
|
.option('--format <type>', 'format of the output (json, shell, eval)', 'json')
|
|
100
|
-
.option('--ops
|
|
98
|
+
.option('--no-ops', 'disable dotenvx-ops features')
|
|
101
99
|
.action(function (...args) {
|
|
102
100
|
this.envs = envs
|
|
103
|
-
getAction.apply(this, args)
|
|
101
|
+
return getAction.apply(this, args)
|
|
104
102
|
})
|
|
105
103
|
|
|
106
104
|
// dotenvx set
|
|
@@ -117,10 +115,10 @@ program.command('set')
|
|
|
117
115
|
.option('-c, --encrypt', 'encrypt value', true)
|
|
118
116
|
.option('-p, --plain', 'store value as plain text', false)
|
|
119
117
|
.option('--no-create', 'do not create .env file(s) when missing')
|
|
120
|
-
.option('--ops
|
|
118
|
+
.option('--no-ops', 'disable dotenvx-ops features')
|
|
121
119
|
.action(function (...args) {
|
|
122
120
|
this.envs = envs
|
|
123
|
-
setAction.apply(this, args)
|
|
121
|
+
return setAction.apply(this, args)
|
|
124
122
|
})
|
|
125
123
|
|
|
126
124
|
// dotenvx encrypt
|
|
@@ -131,12 +129,12 @@ program.command('encrypt')
|
|
|
131
129
|
.option('-fk, --env-keys-file <path>', 'path to your .env.keys file (default: same path as your env file)')
|
|
132
130
|
.option('-k, --key <keys...>', 'keys(s) to encrypt (default: all keys in file)')
|
|
133
131
|
.option('-ek, --exclude-key <excludeKeys...>', 'keys(s) to exclude from encryption (default: none)')
|
|
134
|
-
.option('--no-create', 'do not create .env file(s) when missing')
|
|
135
|
-
.option('--ops-off', 'disable dotenvx-ops features', sesh.opsOff())
|
|
136
132
|
.option('--stdout', 'send to stdout')
|
|
133
|
+
.option('--no-create', 'do not create .env file(s) when missing')
|
|
134
|
+
.option('--no-ops', 'disable dotenvx-ops features')
|
|
137
135
|
.action(function (...args) {
|
|
138
136
|
this.envs = envs
|
|
139
|
-
encryptAction.apply(this, args)
|
|
137
|
+
return encryptAction.apply(this, args)
|
|
140
138
|
})
|
|
141
139
|
|
|
142
140
|
// dotenvx decrypt
|
|
@@ -147,11 +145,11 @@ program.command('decrypt')
|
|
|
147
145
|
.option('-fk, --env-keys-file <path>', 'path to your .env.keys file (default: same path as your env file)')
|
|
148
146
|
.option('-k, --key <keys...>', 'keys(s) to decrypt (default: all keys in file)')
|
|
149
147
|
.option('-ek, --exclude-key <excludeKeys...>', 'keys(s) to exclude from decryption (default: none)')
|
|
150
|
-
.option('--ops
|
|
148
|
+
.option('--no-ops', 'disable dotenvx-ops features')
|
|
151
149
|
.option('--stdout', 'send to stdout')
|
|
152
150
|
.action(function (...args) {
|
|
153
151
|
this.envs = envs
|
|
154
|
-
decryptAction.apply(this, args)
|
|
152
|
+
return decryptAction.apply(this, args)
|
|
155
153
|
})
|
|
156
154
|
|
|
157
155
|
// dotenvx rotate
|
|
@@ -162,11 +160,11 @@ program.command('rotate')
|
|
|
162
160
|
.option('-fk, --env-keys-file <path>', 'path to your .env.keys file (default: same path as your env file)')
|
|
163
161
|
.option('-k, --key <keys...>', 'keys(s) to encrypt (default: all keys in file)')
|
|
164
162
|
.option('-ek, --exclude-key <excludeKeys...>', 'keys(s) to exclude from encryption (default: none)')
|
|
165
|
-
.option('--ops
|
|
163
|
+
.option('--no-ops', 'disable dotenvx-ops features')
|
|
166
164
|
.option('--stdout', 'send to stdout')
|
|
167
165
|
.action(function (...args) {
|
|
168
166
|
this.envs = envs
|
|
169
|
-
rotateAction.apply(this, args)
|
|
167
|
+
return rotateAction.apply(this, args)
|
|
170
168
|
})
|
|
171
169
|
|
|
172
170
|
// dotenvx keypair
|
|
@@ -177,7 +175,7 @@ program.command('keypair')
|
|
|
177
175
|
.argument('[KEY]', 'environment variable key name')
|
|
178
176
|
.option('-f, --env-file <paths...>', 'path(s) to your env file(s)')
|
|
179
177
|
.option('-fk, --env-keys-file <path>', 'path to your .env.keys file (default: same path as your env file)')
|
|
180
|
-
.option('--ops
|
|
178
|
+
.option('--no-ops', 'disable dotenvx-ops features')
|
|
181
179
|
.option('-pp, --pretty-print', 'pretty print output')
|
|
182
180
|
.option('--pp', 'pretty print output (alias)')
|
|
183
181
|
.option('--format <type>', 'format of the output (json, shell)', 'json')
|
|
@@ -208,11 +206,11 @@ program.command('help [command]')
|
|
|
208
206
|
}
|
|
209
207
|
})
|
|
210
208
|
|
|
211
|
-
// dotenvx
|
|
209
|
+
// dotenvx ops
|
|
212
210
|
program.addHelpText('after', ' ')
|
|
213
211
|
program.addHelpText('after', 'Advanced: ')
|
|
214
|
-
program.addHelpText('after', ' ops
|
|
215
|
-
program.addHelpText('after', ' ext
|
|
212
|
+
program.addHelpText('after', ' ops ⛨ Ops [www.dotenvx.com/ops]')
|
|
213
|
+
program.addHelpText('after', ' ext 🔌 extensions')
|
|
216
214
|
|
|
217
215
|
// dotenvx ext
|
|
218
216
|
program.addCommand(require('./commands/ext'))
|
package/src/cli/examples.js
CHANGED
package/src/db/session.js
CHANGED
|
@@ -1,20 +1,24 @@
|
|
|
1
1
|
const Ops = require('./../lib/extensions/ops')
|
|
2
|
+
const { logger } = require('./../shared/logger')
|
|
2
3
|
|
|
3
4
|
class Session {
|
|
4
5
|
constructor () {
|
|
5
6
|
this.ops = new Ops()
|
|
6
|
-
this.opsStatus = this.ops.status()
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
//
|
|
10
|
-
//
|
|
10
|
+
// ops status helpers
|
|
11
11
|
//
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
async noOps () {
|
|
13
|
+
const status = await this.ops.status()
|
|
14
|
+
logger.debug(`ops: ${status}`)
|
|
15
|
+
return status === 'off'
|
|
14
16
|
}
|
|
15
17
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
+
noOpsSync () {
|
|
19
|
+
const status = this.ops.statusSync()
|
|
20
|
+
logger.debug(`ops: ${status}`)
|
|
21
|
+
return status === 'off'
|
|
18
22
|
}
|
|
19
23
|
}
|
|
20
24
|
|
|
@@ -1,97 +1,146 @@
|
|
|
1
1
|
const path = require('path')
|
|
2
2
|
const childProcess = require('child_process')
|
|
3
|
+
const util = require('util')
|
|
3
4
|
|
|
4
|
-
|
|
5
|
+
const execFile = util.promisify(childProcess.execFile)
|
|
5
6
|
|
|
6
7
|
class Ops {
|
|
7
|
-
|
|
8
|
-
this.
|
|
8
|
+
async status () {
|
|
9
|
+
if (this._isForcedOff()) return 'off'
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
const binary = await this._resolveBinary()
|
|
12
|
+
if (!binary) return 'off'
|
|
13
|
+
|
|
14
|
+
try {
|
|
15
|
+
return await this._exec(binary, ['status'])
|
|
16
|
+
} catch (_e) {
|
|
17
|
+
return 'off'
|
|
12
18
|
}
|
|
19
|
+
}
|
|
13
20
|
|
|
14
|
-
|
|
15
|
-
|
|
21
|
+
statusSync () {
|
|
22
|
+
if (this._isForcedOff()) return 'off'
|
|
16
23
|
|
|
17
|
-
|
|
18
|
-
if (!
|
|
19
|
-
try { this.opsLib = this._opsCli() } catch (_e) {}
|
|
20
|
-
}
|
|
24
|
+
const binary = this._resolveBinarySync()
|
|
25
|
+
if (!binary) return 'off'
|
|
21
26
|
|
|
22
|
-
|
|
23
|
-
|
|
27
|
+
try {
|
|
28
|
+
return this._execSync(binary, ['status'])
|
|
29
|
+
} catch (_e) {
|
|
30
|
+
return 'off'
|
|
24
31
|
}
|
|
25
32
|
}
|
|
26
33
|
|
|
27
|
-
|
|
28
|
-
if (this._isForcedOff()
|
|
29
|
-
return 'off'
|
|
30
|
-
}
|
|
34
|
+
async keypair (publicKey) {
|
|
35
|
+
if (this._isForcedOff()) return {}
|
|
31
36
|
|
|
32
|
-
|
|
33
|
-
|
|
37
|
+
const binary = await this._resolveBinary()
|
|
38
|
+
if (!binary) return {}
|
|
39
|
+
|
|
40
|
+
const args = ['keypair']
|
|
41
|
+
if (publicKey) args.push(publicKey)
|
|
34
42
|
|
|
35
|
-
|
|
36
|
-
|
|
43
|
+
try {
|
|
44
|
+
return JSON.parse(await this._exec(binary, args))
|
|
45
|
+
} catch (_e) {
|
|
37
46
|
return {}
|
|
38
47
|
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
keypairSync (publicKey) {
|
|
51
|
+
if (this._isForcedOff()) return {}
|
|
39
52
|
|
|
40
|
-
|
|
53
|
+
const binary = this._resolveBinarySync()
|
|
54
|
+
if (!binary) return {}
|
|
55
|
+
|
|
56
|
+
const args = ['keypair']
|
|
57
|
+
if (publicKey) args.push(publicKey)
|
|
58
|
+
|
|
59
|
+
try {
|
|
60
|
+
return JSON.parse(this._execSync(binary, args))
|
|
61
|
+
} catch (_e) {
|
|
62
|
+
return {}
|
|
63
|
+
}
|
|
41
64
|
}
|
|
42
65
|
|
|
43
66
|
observe (payload) {
|
|
44
|
-
if (
|
|
45
|
-
|
|
46
|
-
|
|
67
|
+
if (this._isForcedOff()) return
|
|
68
|
+
|
|
69
|
+
const binary = this._resolveBinarySync()
|
|
70
|
+
if (!binary) return
|
|
71
|
+
|
|
72
|
+
let status = 'off'
|
|
73
|
+
try {
|
|
74
|
+
status = this._execSync(binary, ['status'])
|
|
75
|
+
} catch (_e) {
|
|
76
|
+
return
|
|
77
|
+
}
|
|
78
|
+
if (status === 'off') return
|
|
79
|
+
|
|
80
|
+
const encoded = Buffer.from(JSON.stringify(payload)).toString('base64')
|
|
81
|
+
try {
|
|
82
|
+
const subprocess = childProcess.spawn(binary, ['observe', encoded], {
|
|
83
|
+
stdio: 'ignore',
|
|
84
|
+
detached: true
|
|
85
|
+
})
|
|
86
|
+
subprocess.unref()
|
|
87
|
+
} catch (_e) {
|
|
88
|
+
// noop
|
|
47
89
|
}
|
|
48
90
|
}
|
|
49
91
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
_opsNpm () {
|
|
54
|
-
const npmBin = path.resolve(process.cwd(), 'node_modules/.bin/dotenvx-ops')
|
|
55
|
-
return this._opsLib(npmBin)
|
|
92
|
+
async _exec (binary, args) {
|
|
93
|
+
const { stdout } = await execFile(binary, args)
|
|
94
|
+
return stdout.toString().trim()
|
|
56
95
|
}
|
|
57
96
|
|
|
58
|
-
|
|
59
|
-
return
|
|
97
|
+
_execSync (binary, args) {
|
|
98
|
+
return childProcess.execFileSync(binary, args).toString().trim()
|
|
60
99
|
}
|
|
61
100
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
101
|
+
async _resolveBinary () {
|
|
102
|
+
if (this._binaryPromise) return this._binaryPromise
|
|
103
|
+
|
|
104
|
+
this._binaryPromise = (async () => {
|
|
105
|
+
const npmBin = path.resolve(process.cwd(), 'node_modules/.bin/dotenvx-ops')
|
|
106
|
+
try {
|
|
107
|
+
await this._exec(npmBin, ['--version'])
|
|
108
|
+
return npmBin
|
|
109
|
+
} catch (_e) {}
|
|
110
|
+
|
|
111
|
+
try {
|
|
112
|
+
await this._exec('dotenvx-ops', ['--version'])
|
|
113
|
+
return 'dotenvx-ops'
|
|
114
|
+
} catch (_e) {}
|
|
115
|
+
|
|
116
|
+
return null
|
|
117
|
+
})()
|
|
118
|
+
|
|
119
|
+
return this._binaryPromise
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
_resolveBinarySync () {
|
|
123
|
+
if (this._binarySync !== undefined) return this._binarySync
|
|
124
|
+
|
|
125
|
+
const npmBin = path.resolve(process.cwd(), 'node_modules/.bin/dotenvx-ops')
|
|
126
|
+
try {
|
|
127
|
+
this._execSync(npmBin, ['--version'])
|
|
128
|
+
this._binarySync = npmBin
|
|
129
|
+
return this._binarySync
|
|
130
|
+
} catch (_e) {}
|
|
131
|
+
|
|
132
|
+
try {
|
|
133
|
+
this._execSync('dotenvx-ops', ['--version'])
|
|
134
|
+
this._binarySync = 'dotenvx-ops'
|
|
135
|
+
return this._binarySync
|
|
136
|
+
} catch (_e) {}
|
|
137
|
+
|
|
138
|
+
this._binarySync = null
|
|
139
|
+
return null
|
|
91
140
|
}
|
|
92
141
|
|
|
93
142
|
_isForcedOff () {
|
|
94
|
-
return process.env.
|
|
143
|
+
return process.env.DOTENVX_NO_OPS === 'true'
|
|
95
144
|
}
|
|
96
145
|
}
|
|
97
146
|
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
const FRAMES = ['◇', '⬖', '◆', '⬗']
|
|
2
|
+
const FRAME_INTERVAL_MS = 80
|
|
3
|
+
|
|
4
|
+
async function createSpinner (options = {}) {
|
|
5
|
+
const stream = process.stderr
|
|
6
|
+
const hasCursorControls = typeof stream.cursorTo === 'function' && typeof stream.clearLine === 'function'
|
|
7
|
+
const enabled = Boolean(stream.isTTY && hasCursorControls && !options.quiet && !options.verbose && !options.debug)
|
|
8
|
+
if (!enabled) return null
|
|
9
|
+
|
|
10
|
+
const text = options.text || 'thinking'
|
|
11
|
+
const frames = options.frames || FRAMES
|
|
12
|
+
|
|
13
|
+
const { default: yoctoSpinner } = await import('yocto-spinner')
|
|
14
|
+
return yoctoSpinner({
|
|
15
|
+
text,
|
|
16
|
+
spinner: {
|
|
17
|
+
frames,
|
|
18
|
+
interval: FRAME_INTERVAL_MS
|
|
19
|
+
},
|
|
20
|
+
stream
|
|
21
|
+
}).start()
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
module.exports = createSpinner
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
module.exports = {
|
|
2
2
|
opsKeypair: require('./opsKeypair'),
|
|
3
|
+
opsKeypairSync: require('./opsKeypairSync'),
|
|
3
4
|
localKeypair: require('./localKeypair'),
|
|
4
5
|
encryptValue: require('./encryptValue'),
|
|
5
6
|
decryptKeyValue: require('./decryptKeyValue'),
|
|
6
7
|
isEncrypted: require('./isEncrypted'),
|
|
7
8
|
isPublicKey: require('./isPublicKey'),
|
|
9
|
+
mutateKeysSrc: require('./mutateKeysSrc'),
|
|
10
|
+
mutateKeysSrcSync: require('./mutateKeysSrcSync'),
|
|
8
11
|
provision: require('./provision'),
|
|
12
|
+
provisionSync: require('./provisionSync'),
|
|
9
13
|
provisionWithPrivateKey: require('./provisionWithPrivateKey'),
|
|
10
14
|
mutateSrc: require('./mutateSrc'),
|
|
11
15
|
|
|
@@ -9,7 +9,7 @@ const FIRST_TIME_KEYS_SRC = [
|
|
|
9
9
|
const path = require('path')
|
|
10
10
|
const fsx = require('./../fsx')
|
|
11
11
|
|
|
12
|
-
function mutateKeysSrc ({ envFilepath, keysFilepath, privateKeyName, privateKeyValue }) {
|
|
12
|
+
async function mutateKeysSrc ({ envFilepath, keysFilepath, privateKeyName, privateKeyValue }) {
|
|
13
13
|
const filename = path.basename(envFilepath)
|
|
14
14
|
const filepath = path.resolve(envFilepath)
|
|
15
15
|
let resolvedKeysFilepath = path.join(path.dirname(filepath), '.env.keys')
|
|
@@ -19,13 +19,13 @@ function mutateKeysSrc ({ envFilepath, keysFilepath, privateKeyName, privateKeyV
|
|
|
19
19
|
const appendPrivateKey = [`# ${filename}`, `${privateKeyName}=${privateKeyValue}`, ''].join('\n')
|
|
20
20
|
|
|
21
21
|
let keysSrc = ''
|
|
22
|
-
if (fsx.
|
|
23
|
-
keysSrc = fsx.readFileX(resolvedKeysFilepath)
|
|
22
|
+
if (await fsx.exists(resolvedKeysFilepath)) {
|
|
23
|
+
keysSrc = await fsx.readFileX(resolvedKeysFilepath)
|
|
24
24
|
}
|
|
25
25
|
keysSrc = keysSrc.length > 1 ? keysSrc : `${FIRST_TIME_KEYS_SRC}\n`
|
|
26
26
|
keysSrc = `${keysSrc}\n${appendPrivateKey}`
|
|
27
27
|
|
|
28
|
-
fsx.writeFileX(resolvedKeysFilepath, keysSrc) // TODO: don't write if ops
|
|
28
|
+
await fsx.writeFileX(resolvedKeysFilepath, keysSrc) // TODO: don't write if ops
|
|
29
29
|
|
|
30
30
|
const envKeysFilepath = keysFilepath || path.join(path.dirname(envFilepath), path.basename(resolvedKeysFilepath))
|
|
31
31
|
|
|
@@ -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 mutateKeysSrcSync ({ 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.readFileXSync(resolvedKeysFilepath)
|
|
24
|
+
}
|
|
25
|
+
keysSrc = keysSrc.length > 1 ? keysSrc : `${FIRST_TIME_KEYS_SRC}\n`
|
|
26
|
+
keysSrc = `${keysSrc}\n${appendPrivateKey}`
|
|
27
|
+
|
|
28
|
+
fsx.writeFileXSync(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 = mutateKeysSrcSync
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const Ops = require('../../extensions/ops')
|
|
2
2
|
|
|
3
|
-
function opsKeypair (existingPublicKey) {
|
|
4
|
-
const kp = new Ops().keypair(existingPublicKey)
|
|
3
|
+
async function opsKeypair (existingPublicKey) {
|
|
4
|
+
const kp = await new Ops().keypair(existingPublicKey)
|
|
5
5
|
const publicKey = kp.public_key
|
|
6
6
|
const privateKey = kp.private_key
|
|
7
7
|
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const Ops = require('../../extensions/ops')
|
|
2
|
+
|
|
3
|
+
function opsKeypairSync (existingPublicKey) {
|
|
4
|
+
const kp = new Ops().keypairSync(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 = opsKeypairSync
|
|
@@ -4,8 +4,8 @@ const opsKeypair = require('./opsKeypair')
|
|
|
4
4
|
const localKeypair = require('./localKeypair')
|
|
5
5
|
const { keyNames } = require('../keyResolution')
|
|
6
6
|
|
|
7
|
-
function provision ({ envSrc, envFilepath, keysFilepath,
|
|
8
|
-
|
|
7
|
+
async function provision ({ envSrc, envFilepath, keysFilepath, noOps }) {
|
|
8
|
+
noOps = noOps !== false
|
|
9
9
|
const { publicKeyName, privateKeyName } = keyNames(envFilepath)
|
|
10
10
|
|
|
11
11
|
let publicKey
|
|
@@ -14,12 +14,12 @@ function provision ({ envSrc, envFilepath, keysFilepath, opsOn }) {
|
|
|
14
14
|
let envKeysFilepath
|
|
15
15
|
let privateKeyAdded = false
|
|
16
16
|
|
|
17
|
-
if (
|
|
18
|
-
const kp =
|
|
17
|
+
if (noOps) {
|
|
18
|
+
const kp = localKeypair()
|
|
19
19
|
publicKey = kp.publicKey
|
|
20
20
|
privateKey = kp.privateKey
|
|
21
21
|
} else {
|
|
22
|
-
const kp =
|
|
22
|
+
const kp = await opsKeypair()
|
|
23
23
|
publicKey = kp.publicKey
|
|
24
24
|
privateKey = kp.privateKey
|
|
25
25
|
}
|
|
@@ -27,8 +27,8 @@ function provision ({ envSrc, envFilepath, keysFilepath, opsOn }) {
|
|
|
27
27
|
const mutated = mutateSrc({ envSrc, envFilepath, keysFilepath, publicKeyName, publicKeyValue: publicKey })
|
|
28
28
|
envSrc = mutated.envSrc
|
|
29
29
|
|
|
30
|
-
if (
|
|
31
|
-
const mutated = mutateKeysSrc({ envFilepath, keysFilepath, privateKeyName, privateKeyValue: privateKey })
|
|
30
|
+
if (noOps) {
|
|
31
|
+
const mutated = await mutateKeysSrc({ envFilepath, keysFilepath, privateKeyName, privateKeyValue: privateKey })
|
|
32
32
|
keysSrc = mutated.keysSrc
|
|
33
33
|
envKeysFilepath = mutated.envKeysFilepath
|
|
34
34
|
privateKeyAdded = true
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
const mutateSrc = require('./mutateSrc')
|
|
2
|
+
const mutateKeysSrcSync = require('./mutateKeysSrcSync')
|
|
3
|
+
const opsKeypairSync = require('./opsKeypairSync')
|
|
4
|
+
const localKeypair = require('./localKeypair')
|
|
5
|
+
const { keyNames } = require('../keyResolution')
|
|
6
|
+
|
|
7
|
+
function provisionSync ({ envSrc, envFilepath, keysFilepath, noOps }) {
|
|
8
|
+
noOps = noOps !== false
|
|
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 (noOps) {
|
|
18
|
+
const kp = localKeypair()
|
|
19
|
+
publicKey = kp.publicKey
|
|
20
|
+
privateKey = kp.privateKey
|
|
21
|
+
} else {
|
|
22
|
+
const kp = opsKeypairSync()
|
|
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 (noOps) {
|
|
31
|
+
const mutated = mutateKeysSrcSync({ 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 = provisionSync
|
|
@@ -3,7 +3,7 @@ const mutateSrc = require('./mutateSrc')
|
|
|
3
3
|
const localKeypair = require('./localKeypair')
|
|
4
4
|
|
|
5
5
|
function provisionWithPrivateKey ({ envSrc, envFilepath, keysFilepath, privateKeyValue, publicKeyValue, publicKeyName }) {
|
|
6
|
-
const { publicKey, privateKey } = localKeypair(privateKeyValue) //
|
|
6
|
+
const { publicKey, privateKey } = localKeypair(privateKeyValue) // noOps doesn't matter here since privateKeyValue was already discovered prior (via ops and local) and passed as privateKeyValue
|
|
7
7
|
|
|
8
8
|
// if derivation doesn't match what's in the file (or preset in env)
|
|
9
9
|
if (publicKeyValue && publicKeyValue !== publicKey) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const fs = require('fs')
|
|
2
2
|
|
|
3
|
-
function detectEncoding (filepath) {
|
|
4
|
-
const buffer = fs.
|
|
3
|
+
async function detectEncoding (filepath) {
|
|
4
|
+
const buffer = await fs.promises.readFile(filepath)
|
|
5
5
|
|
|
6
6
|
// check for UTF-16LE BOM (Byte Order Mark)
|
|
7
7
|
if (buffer.length >= 2 && buffer[0] === 0xFF && buffer[1] === 0xFE) {
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
const fs = require('fs')
|
|
2
|
+
|
|
3
|
+
function detectEncodingSync (filepath) {
|
|
4
|
+
const buffer = fs.readFileSync(filepath)
|
|
5
|
+
|
|
6
|
+
// check for UTF-16LE BOM (Byte Order Mark)
|
|
7
|
+
if (buffer.length >= 2 && buffer[0] === 0xFF && buffer[1] === 0xFE) {
|
|
8
|
+
return 'utf16le'
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/* c8 ignore start */
|
|
12
|
+
// check for UTF-8 BOM
|
|
13
|
+
if (buffer.length >= 3 && buffer[0] === 0xEF && buffer[1] === 0xBB && buffer[2] === 0xBF) {
|
|
14
|
+
return 'utf8'
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/* c8 ignore stop */
|
|
18
|
+
|
|
19
|
+
return 'utf8'
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
module.exports = detectEncodingSync
|