@dotenvx/dotenvx 1.4.0 → 1.6.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 +32 -1
- package/README.md +100 -2
- package/package.json +9 -10
- package/src/cli/actions/decrypt.js +71 -0
- package/src/cli/actions/encrypt.js +54 -42
- package/src/cli/actions/ext/genexample.js +4 -12
- package/src/cli/actions/ext/gitignore.js +5 -0
- package/src/cli/actions/ext/prebuild.js +1 -0
- package/src/cli/actions/ext/scan.js +9 -6
- package/src/cli/actions/ext/settings.js +5 -4
- package/src/cli/actions/ext/vault/decrypt.js +6 -13
- package/src/cli/actions/ext/vault/encrypt.js +5 -12
- package/src/cli/actions/ext/vault/migrate.js +22 -39
- package/src/cli/actions/get.js +6 -5
- package/src/cli/actions/run.js +3 -110
- package/src/cli/actions/set.js +2 -2
- package/src/cli/commands/ext.js +12 -1
- package/src/cli/dotenvx.js +16 -15
- package/src/cli/examples.js +17 -1
- package/src/lib/helpers/execute.js +9 -0
- package/src/lib/helpers/executeCommand.js +117 -0
- package/src/lib/helpers/executeExtension.js +38 -0
- package/src/lib/helpers/findOrCreatePublicKey.js +14 -8
- package/src/lib/helpers/isEncrypted.js +1 -2
- package/src/lib/helpers/isFullyEncrypted.js +2 -1
- package/src/lib/helpers/isIgnoringDotenvKeys.js +1 -1
- package/src/lib/helpers/isPublicKey.js +7 -0
- package/src/lib/helpers/keyPair.js +8 -2
- package/src/lib/helpers/smartDotenvPrivateKey.js +64 -6
- package/src/lib/main.js +16 -9
- package/src/lib/services/decrypt.js +79 -98
- package/src/lib/services/encrypt.js +12 -7
- package/src/lib/services/sets.js +9 -2
- package/src/lib/services/status.js +2 -2
- package/src/lib/services/vaultDecrypt.js +126 -0
- package/src/shared/logger.js +0 -3
- package/src/cli/actions/ext/hub/login.js +0 -126
- package/src/cli/actions/ext/hub/logout.js +0 -43
- package/src/cli/actions/ext/hub/open.js +0 -63
- package/src/cli/actions/ext/hub/pull.js +0 -105
- package/src/cli/actions/ext/hub/push.js +0 -112
- package/src/cli/actions/ext/hub/status.js +0 -8
- package/src/cli/actions/ext/hub/token.js +0 -9
- package/src/cli/commands/ext/hub.js +0 -89
- package/src/cli/commands/vault.js +0 -57
- package/src/lib/helpers/clipboardy/fallbacks/linux/xsel +0 -0
- package/src/lib/helpers/clipboardy/fallbacks/windows/clipboard_i686.exe +0 -0
- package/src/lib/helpers/clipboardy/fallbacks/windows/clipboard_x86_64.exe +0 -0
- package/src/lib/helpers/clipboardy/linux.js +0 -57
- package/src/lib/helpers/clipboardy/macos.js +0 -14
- package/src/lib/helpers/clipboardy/termux.js +0 -41
- package/src/lib/helpers/clipboardy/windows.js +0 -16
- package/src/lib/helpers/clipboardy.js +0 -51
- package/src/lib/helpers/extractUsernameName.js +0 -10
- package/src/lib/helpers/forgivingDirectory.js +0 -11
- package/src/lib/helpers/gitRoot.js +0 -14
- package/src/lib/helpers/gitUrl.js +0 -13
- package/src/lib/helpers/isGitRepo.js +0 -13
- package/src/lib/helpers/isGithub.js +0 -5
- package/src/lib/helpers/resolvePath.js +0 -8
- package/src/shared/createSpinner.js +0 -17
|
@@ -1,47 +1,30 @@
|
|
|
1
1
|
const { logger } = require('./../../../../shared/logger')
|
|
2
2
|
|
|
3
|
-
function migrate (
|
|
4
|
-
// debug args
|
|
5
|
-
logger.debug(`directory: ${directory}`)
|
|
6
|
-
|
|
3
|
+
function migrate () {
|
|
7
4
|
const options = this.opts()
|
|
8
5
|
logger.debug(`options: ${JSON.stringify(options)}`)
|
|
9
6
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
logger.help2('')
|
|
32
|
-
} catch (error) {
|
|
33
|
-
logger.error(error.message)
|
|
34
|
-
if (error.help) {
|
|
35
|
-
logger.help(error.help)
|
|
36
|
-
}
|
|
37
|
-
if (error.debug) {
|
|
38
|
-
logger.debug(error.debug)
|
|
39
|
-
}
|
|
40
|
-
if (error.code) {
|
|
41
|
-
logger.debug(`ERROR_CODE: ${error.code}`)
|
|
42
|
-
}
|
|
43
|
-
process.exit(1)
|
|
44
|
-
}
|
|
7
|
+
logger.help2('To migrate your .env.vault file to encrypted .env file(s):')
|
|
8
|
+
logger.help('')
|
|
9
|
+
logger.help(' 1. Run [dotenvx ext vault decrypt]')
|
|
10
|
+
logger.help(' 2. Run [ls -a .env*]')
|
|
11
|
+
logger.help('')
|
|
12
|
+
logger.help2('Lastly, encrypt each .env(.environment) file:')
|
|
13
|
+
logger.help('')
|
|
14
|
+
logger.help(' 3. Run [dotenvx encrypt -f .env.production]')
|
|
15
|
+
logger.help2('')
|
|
16
|
+
logger.help2('For example:')
|
|
17
|
+
logger.help2('')
|
|
18
|
+
logger.help2(' $ dotenvx encrypt -f .env')
|
|
19
|
+
logger.help2(' $ dotenvx encrypt -f .env.ci')
|
|
20
|
+
logger.help2(' $ dotenvx encrypt -f .env.production')
|
|
21
|
+
logger.help2('')
|
|
22
|
+
logger.help2('Afterward:')
|
|
23
|
+
logger.help2('')
|
|
24
|
+
logger.help2('Update production with your new DOTENV_PRIVATE_KEY_PRODUCTION located in .env.keys')
|
|
25
|
+
logger.help2('')
|
|
26
|
+
logger.success('Learn more at [https://dotenvx.com/docs/quickstart#add-encryption]')
|
|
27
|
+
logger.help2('')
|
|
45
28
|
}
|
|
46
29
|
|
|
47
30
|
module.exports = migrate
|
package/src/cli/actions/get.js
CHANGED
|
@@ -21,17 +21,18 @@ function get (key) {
|
|
|
21
21
|
const value = main.get(key, envs, options.overload, process.env.DOTENV_KEY, options.all)
|
|
22
22
|
|
|
23
23
|
if (typeof value === 'object' && value !== null) {
|
|
24
|
+
let space = 0
|
|
24
25
|
if (options.prettyPrint) {
|
|
25
|
-
|
|
26
|
-
} else {
|
|
27
|
-
logger.blank0(value)
|
|
26
|
+
space = 2
|
|
28
27
|
}
|
|
28
|
+
|
|
29
|
+
process.stdout.write(JSON.stringify(value, null, space))
|
|
29
30
|
} else {
|
|
30
31
|
if (value === undefined) {
|
|
31
|
-
|
|
32
|
+
process.stdout.write('')
|
|
32
33
|
process.exit(1)
|
|
33
34
|
} else {
|
|
34
|
-
|
|
35
|
+
process.stdout.write(value)
|
|
35
36
|
}
|
|
36
37
|
}
|
|
37
38
|
}
|
package/src/cli/actions/run.js
CHANGED
|
@@ -1,118 +1,11 @@
|
|
|
1
1
|
const path = require('path')
|
|
2
|
-
const execa = require('execa')
|
|
3
|
-
const which = require('which')
|
|
4
2
|
const { logger } = require('./../../shared/logger')
|
|
5
3
|
|
|
4
|
+
const executeCommand = require('./../../lib/helpers/executeCommand')
|
|
6
5
|
const Run = require('./../../lib/services/run')
|
|
7
6
|
|
|
8
7
|
const conventions = require('./../../lib/helpers/conventions')
|
|
9
8
|
|
|
10
|
-
const executeCommand = async function (commandArgs, env) {
|
|
11
|
-
const signals = [
|
|
12
|
-
'SIGHUP', 'SIGQUIT', 'SIGILL', 'SIGTRAP', 'SIGABRT',
|
|
13
|
-
'SIGBUS', 'SIGFPE', 'SIGUSR1', 'SIGSEGV', 'SIGUSR2'
|
|
14
|
-
]
|
|
15
|
-
|
|
16
|
-
logger.debug(`executing process command [${commandArgs.join(' ')}]`)
|
|
17
|
-
|
|
18
|
-
// handler for SIGINT
|
|
19
|
-
let commandProcess
|
|
20
|
-
const sigintHandler = () => {
|
|
21
|
-
logger.debug('received SIGINT')
|
|
22
|
-
logger.debug('checking command process')
|
|
23
|
-
logger.debug(commandProcess)
|
|
24
|
-
|
|
25
|
-
if (commandProcess) {
|
|
26
|
-
logger.debug('sending SIGINT to command process')
|
|
27
|
-
commandProcess.kill('SIGINT') // Send SIGINT to the command process
|
|
28
|
-
} else {
|
|
29
|
-
logger.debug('no command process to send SIGINT to')
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
// handler for SIGTERM
|
|
33
|
-
const sigtermHandler = () => {
|
|
34
|
-
logger.debug('received SIGTERM')
|
|
35
|
-
logger.debug('checking command process')
|
|
36
|
-
logger.debug(commandProcess)
|
|
37
|
-
|
|
38
|
-
if (commandProcess) {
|
|
39
|
-
logger.debug('sending SIGTERM to command process')
|
|
40
|
-
commandProcess.kill('SIGTERM') // Send SIGTEM to the command process
|
|
41
|
-
} else {
|
|
42
|
-
logger.debug('no command process to send SIGTERM to')
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const handleOtherSignal = (signal) => {
|
|
47
|
-
logger.debug(`received ${signal}`)
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
try {
|
|
51
|
-
// ensure the first command is expanded
|
|
52
|
-
try {
|
|
53
|
-
commandArgs[0] = path.resolve(which.sync(`${commandArgs[0]}`))
|
|
54
|
-
logger.debug(`expanding process command to [${commandArgs.join(' ')}]`)
|
|
55
|
-
} catch (e) {
|
|
56
|
-
logger.debug(`could not expand process command. using [${commandArgs.join(' ')}]`)
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// expand any other commands that follow a --
|
|
60
|
-
let expandNext = false
|
|
61
|
-
for (let i = 0; i < commandArgs.length; i++) {
|
|
62
|
-
if (commandArgs[i] === '--') {
|
|
63
|
-
expandNext = true
|
|
64
|
-
} else if (expandNext) {
|
|
65
|
-
try {
|
|
66
|
-
commandArgs[i] = path.resolve(which.sync(`${commandArgs[i]}`))
|
|
67
|
-
logger.debug(`expanding process command to [${commandArgs.join(' ')}]`)
|
|
68
|
-
} catch (e) {
|
|
69
|
-
logger.debug(`could not expand process command. using [${commandArgs.join(' ')}]`)
|
|
70
|
-
}
|
|
71
|
-
expandNext = false
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
commandProcess = execa(commandArgs[0], commandArgs.slice(1), {
|
|
76
|
-
stdio: 'inherit',
|
|
77
|
-
env: { ...process.env, ...env }
|
|
78
|
-
})
|
|
79
|
-
|
|
80
|
-
process.on('SIGINT', sigintHandler)
|
|
81
|
-
process.on('SIGTERM', sigtermHandler)
|
|
82
|
-
|
|
83
|
-
signals.forEach(signal => {
|
|
84
|
-
process.on(signal, () => handleOtherSignal(signal))
|
|
85
|
-
})
|
|
86
|
-
|
|
87
|
-
// Wait for the command process to finish
|
|
88
|
-
const { exitCode } = await commandProcess
|
|
89
|
-
|
|
90
|
-
if (exitCode !== 0) {
|
|
91
|
-
logger.debug(`received exitCode ${exitCode}`)
|
|
92
|
-
throw new Error(`Command exited with exit code ${exitCode}`)
|
|
93
|
-
}
|
|
94
|
-
} catch (error) {
|
|
95
|
-
// no color on these errors as they can be standard errors for things like jest exiting with exitCode 1 for a single failed test.
|
|
96
|
-
if (error.signal !== 'SIGINT' && error.signal !== 'SIGTERM') {
|
|
97
|
-
if (error.code === 'ENOENT') {
|
|
98
|
-
logger.errornocolor(`Unknown command: ${error.command}`)
|
|
99
|
-
} else if (error.message.includes('Command failed with exit code 1')) {
|
|
100
|
-
logger.errornocolor(`Command exited with exit code 1: ${error.command}`)
|
|
101
|
-
} else {
|
|
102
|
-
logger.errornocolor(error.message)
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// Exit with the error code from the command process, or 1 if unavailable
|
|
107
|
-
process.exit(error.exitCode || 1)
|
|
108
|
-
} finally {
|
|
109
|
-
// Clean up: Remove the SIGINT handler
|
|
110
|
-
process.removeListener('SIGINT', sigintHandler)
|
|
111
|
-
// Clean up: Remove the SIGTERM handler
|
|
112
|
-
process.removeListener('SIGTERM', sigtermHandler)
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
9
|
async function run () {
|
|
117
10
|
const commandArgs = this.args
|
|
118
11
|
logger.debug(`process command [${commandArgs.join(' ')}]`)
|
|
@@ -160,11 +53,11 @@ async function run () {
|
|
|
160
53
|
if (processedEnv.error.code === 'MISSING_ENV_FILE') {
|
|
161
54
|
// do not warn for conventions (too noisy)
|
|
162
55
|
if (!options.convention) {
|
|
163
|
-
logger.warnv(processedEnv.error)
|
|
56
|
+
logger.warnv(processedEnv.error.message)
|
|
164
57
|
logger.help(`? add one with [echo "HELLO=World" > ${processedEnv.filepath}] and re-run [dotenvx run -- ${commandArgs.join(' ')}]`)
|
|
165
58
|
}
|
|
166
59
|
} else {
|
|
167
|
-
logger.warnv(processedEnv.error)
|
|
60
|
+
logger.warnv(processedEnv.error.message)
|
|
168
61
|
}
|
|
169
62
|
} else {
|
|
170
63
|
// debug parsed
|
package/src/cli/actions/set.js
CHANGED
|
@@ -38,10 +38,10 @@ function set (key, value) {
|
|
|
38
38
|
|
|
39
39
|
if (processedEnvFile.error) {
|
|
40
40
|
if (processedEnvFile.error.code === 'MISSING_ENV_FILE') {
|
|
41
|
-
logger.warn(processedEnvFile.error)
|
|
41
|
+
logger.warn(processedEnvFile.error.message)
|
|
42
42
|
logger.help(`? add one with [echo "HELLO=World" > ${processedEnvFile.envFilepath}] and re-run [dotenvx set]`)
|
|
43
43
|
} else {
|
|
44
|
-
logger.warn(processedEnvFile.error)
|
|
44
|
+
logger.warn(processedEnvFile.error.message)
|
|
45
45
|
}
|
|
46
46
|
} else {
|
|
47
47
|
fs.writeFileSync(processedEnvFile.filepath, processedEnvFile.envSrc, ENCODING)
|
package/src/cli/commands/ext.js
CHANGED
|
@@ -1,11 +1,23 @@
|
|
|
1
1
|
const { Command } = require('commander')
|
|
2
2
|
|
|
3
3
|
const examples = require('./../examples')
|
|
4
|
+
const executeExtension = require('../../lib/helpers/executeExtension')
|
|
4
5
|
|
|
5
6
|
const ext = new Command('ext')
|
|
6
7
|
|
|
7
8
|
ext
|
|
8
9
|
.description('🔌 extensions')
|
|
10
|
+
.allowUnknownOption()
|
|
11
|
+
|
|
12
|
+
ext.addHelpText('after', ' hub 🚫 DEPRECATED: to be replaced by [dotenvx pro]')
|
|
13
|
+
|
|
14
|
+
ext
|
|
15
|
+
.argument('[command]', 'dynamic ext command')
|
|
16
|
+
.argument('[args...]', 'dynamic ext command arguments')
|
|
17
|
+
.action((command, args, cmdObj) => {
|
|
18
|
+
const rawArgs = process.argv.slice(3) // adjust the index based on where actual args start
|
|
19
|
+
executeExtension(ext, command, rawArgs)
|
|
20
|
+
})
|
|
9
21
|
|
|
10
22
|
// dotenvx ext ls
|
|
11
23
|
ext.command('ls')
|
|
@@ -53,6 +65,5 @@ ext.command('settings')
|
|
|
53
65
|
.action(require('./../actions/ext/settings'))
|
|
54
66
|
|
|
55
67
|
ext.addCommand(require('./../commands/ext/vault'))
|
|
56
|
-
ext.addCommand(require('./../commands/ext/hub'))
|
|
57
68
|
|
|
58
69
|
module.exports = ext
|
package/src/cli/dotenvx.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
/* c8 ignore start */
|
|
3
4
|
const fs = require('fs')
|
|
4
5
|
const path = require('path')
|
|
5
6
|
const { execSync } = require('child_process')
|
|
@@ -72,14 +73,17 @@ program.command('get')
|
|
|
72
73
|
})
|
|
73
74
|
|
|
74
75
|
// dotenvx set
|
|
76
|
+
const setAction = require('./actions/set')
|
|
75
77
|
program.command('set')
|
|
76
78
|
.description('set a single environment variable')
|
|
79
|
+
.addHelpText('after', examples.set)
|
|
80
|
+
.allowUnknownOption()
|
|
77
81
|
.argument('KEY', 'KEY')
|
|
78
82
|
.argument('value', 'value')
|
|
79
83
|
.option('-f, --env-file <paths...>', 'path(s) to your env file(s)', '.env')
|
|
80
84
|
.option('-c, --encrypt', 'encrypt value (default: true)', true)
|
|
81
85
|
.option('-p, --plain', 'store value as plain text', false)
|
|
82
|
-
.action(
|
|
86
|
+
.action(setAction)
|
|
83
87
|
|
|
84
88
|
// dotenvx encrypt
|
|
85
89
|
const encryptAction = require('./actions/encrypt')
|
|
@@ -87,8 +91,18 @@ program.command('encrypt')
|
|
|
87
91
|
.description('convert .env file(s) to encrypted .env file(s)')
|
|
88
92
|
.option('-f, --env-file <paths...>', 'path(s) to your env file(s)')
|
|
89
93
|
.option('-k, --key <keys...>', 'keys(s) to encrypt (default: all keys in file)')
|
|
94
|
+
.option('--stdout', 'send to stdout')
|
|
90
95
|
.action(encryptAction)
|
|
91
96
|
|
|
97
|
+
// dotenvx decrypt
|
|
98
|
+
const decryptAction = require('./actions/decrypt')
|
|
99
|
+
program.command('decrypt')
|
|
100
|
+
.description('convert encrypted .env file(s) to plain .env file(s)')
|
|
101
|
+
.option('-f, --env-file <paths...>', 'path(s) to your env file(s)')
|
|
102
|
+
.option('-k, --key <keys...>', 'keys(s) to encrypt (default: all keys in file)')
|
|
103
|
+
.option('--stdout', 'send to stdout')
|
|
104
|
+
.action(decryptAction)
|
|
105
|
+
|
|
92
106
|
// dotenvx pro
|
|
93
107
|
program.command('pro')
|
|
94
108
|
.description('🏆 pro')
|
|
@@ -113,20 +127,6 @@ program.command('pro')
|
|
|
113
127
|
// dotenvx ext
|
|
114
128
|
program.addCommand(require('./commands/ext'))
|
|
115
129
|
|
|
116
|
-
//
|
|
117
|
-
// DEPRECATED AND hidden
|
|
118
|
-
//
|
|
119
|
-
program.addCommand(require('./commands/vault'))
|
|
120
|
-
|
|
121
|
-
program.command('convert')
|
|
122
|
-
.description('DEPRECATED: moved to [dotenvx encrypt]')
|
|
123
|
-
.option('-f, --env-file <paths...>', 'path(s) to your env file(s)')
|
|
124
|
-
.action(function (...args) {
|
|
125
|
-
logger.warn('DEPRECATION NOTICE: [dotenvx convert] has moved to [dotenvx encrypt]')
|
|
126
|
-
|
|
127
|
-
encryptAction.apply(this, args)
|
|
128
|
-
})
|
|
129
|
-
|
|
130
130
|
const lsAction = require('./actions/ext/ls')
|
|
131
131
|
program.command('ls')
|
|
132
132
|
.description('DEPRECATED: moved to [dotenvx ext ls]')
|
|
@@ -203,5 +203,6 @@ program.helpInformation = function () {
|
|
|
203
203
|
|
|
204
204
|
return filteredLines.join('\n')
|
|
205
205
|
}
|
|
206
|
+
/* c8 ignore stop */
|
|
206
207
|
|
|
207
208
|
program.parse(process.argv)
|
package/src/cli/examples.js
CHANGED
|
@@ -100,10 +100,26 @@ Try it:
|
|
|
100
100
|
`
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
+
const set = function () {
|
|
104
|
+
return `
|
|
105
|
+
Examples:
|
|
106
|
+
|
|
107
|
+
\`\`\`
|
|
108
|
+
$ dotenvx set KEY value
|
|
109
|
+
$ dotenvx set KEY "value with spaces"
|
|
110
|
+
$ dotenvx set KEY -- "---value with a dash---"
|
|
111
|
+
$ dotenvx set KEY -- "-----BEGIN OPENSSH PRIVATE KEY-----
|
|
112
|
+
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
|
|
113
|
+
-----END OPENSSH PRIVATE KEY-----"
|
|
114
|
+
\`\`\`
|
|
115
|
+
`
|
|
116
|
+
}
|
|
117
|
+
|
|
103
118
|
module.exports = {
|
|
104
119
|
run,
|
|
105
120
|
vaultEncrypt,
|
|
106
121
|
precommit,
|
|
107
122
|
prebuild,
|
|
108
|
-
gitignore
|
|
123
|
+
gitignore,
|
|
124
|
+
set
|
|
109
125
|
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
const path = require('path')
|
|
2
|
+
const which = require('which')
|
|
3
|
+
const execute = require('./../../lib/helpers/execute')
|
|
4
|
+
const { logger } = require('./../../shared/logger')
|
|
5
|
+
|
|
6
|
+
async function executeCommand (commandArgs, env) {
|
|
7
|
+
const signals = [
|
|
8
|
+
'SIGHUP', 'SIGQUIT', 'SIGILL', 'SIGTRAP', 'SIGABRT',
|
|
9
|
+
'SIGBUS', 'SIGFPE', 'SIGUSR1', 'SIGSEGV', 'SIGUSR2'
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
logger.debug(`executing process command [${commandArgs.join(' ')}]`)
|
|
13
|
+
|
|
14
|
+
// handler for SIGINT
|
|
15
|
+
let commandProcess
|
|
16
|
+
const sigintHandler = () => {
|
|
17
|
+
logger.debug('received SIGINT')
|
|
18
|
+
logger.debug('checking command process')
|
|
19
|
+
logger.debug(commandProcess)
|
|
20
|
+
|
|
21
|
+
if (commandProcess) {
|
|
22
|
+
logger.debug('sending SIGINT to command process')
|
|
23
|
+
commandProcess.kill('SIGINT') // Send SIGINT to the command process
|
|
24
|
+
/* c8 ignore start */
|
|
25
|
+
} else {
|
|
26
|
+
logger.debug('no command process to send SIGINT to')
|
|
27
|
+
}
|
|
28
|
+
/* c8 ignore stop */
|
|
29
|
+
}
|
|
30
|
+
// handler for SIGTERM
|
|
31
|
+
|
|
32
|
+
/* c8 ignore start */
|
|
33
|
+
const sigtermHandler = () => {
|
|
34
|
+
logger.debug('received SIGTERM')
|
|
35
|
+
logger.debug('checking command process')
|
|
36
|
+
logger.debug(commandProcess)
|
|
37
|
+
|
|
38
|
+
if (commandProcess) {
|
|
39
|
+
logger.debug('sending SIGTERM to command process')
|
|
40
|
+
commandProcess.kill('SIGTERM') // Send SIGTEM to the command process
|
|
41
|
+
} else {
|
|
42
|
+
logger.debug('no command process to send SIGTERM to')
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const handleOtherSignal = (signal) => {
|
|
47
|
+
logger.debug(`received ${signal}`)
|
|
48
|
+
}
|
|
49
|
+
/* c8 ignore stop */
|
|
50
|
+
|
|
51
|
+
try {
|
|
52
|
+
// ensure the first command is expanded
|
|
53
|
+
try {
|
|
54
|
+
commandArgs[0] = path.resolve(which.sync(`${commandArgs[0]}`))
|
|
55
|
+
logger.debug(`expanding process command to [${commandArgs.join(' ')}]`)
|
|
56
|
+
} catch (e) {
|
|
57
|
+
logger.debug(`could not expand process command. using [${commandArgs.join(' ')}]`)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// expand any other commands that follow a --
|
|
61
|
+
let expandNext = false
|
|
62
|
+
for (let i = 0; i < commandArgs.length; i++) {
|
|
63
|
+
if (commandArgs[i] === '--') {
|
|
64
|
+
expandNext = true
|
|
65
|
+
} else if (expandNext) {
|
|
66
|
+
try {
|
|
67
|
+
commandArgs[i] = path.resolve(which.sync(`${commandArgs[i]}`))
|
|
68
|
+
logger.debug(`expanding process command to [${commandArgs.join(' ')}]`)
|
|
69
|
+
} catch (e) {
|
|
70
|
+
logger.debug(`could not expand process command. using [${commandArgs.join(' ')}]`)
|
|
71
|
+
}
|
|
72
|
+
expandNext = false
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
commandProcess = execute.execa(commandArgs[0], commandArgs.slice(1), {
|
|
77
|
+
stdio: 'inherit',
|
|
78
|
+
env: { ...process.env, ...env }
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
process.on('SIGINT', sigintHandler)
|
|
82
|
+
process.on('SIGTERM', sigtermHandler)
|
|
83
|
+
|
|
84
|
+
signals.forEach(signal => {
|
|
85
|
+
process.on(signal, () => handleOtherSignal(signal))
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
// Wait for the command process to finish
|
|
89
|
+
const { exitCode } = await commandProcess
|
|
90
|
+
|
|
91
|
+
if (exitCode !== 0) {
|
|
92
|
+
logger.debug(`received exitCode ${exitCode}`)
|
|
93
|
+
throw new Error(`Command exited with exit code ${exitCode}`)
|
|
94
|
+
}
|
|
95
|
+
} catch (error) {
|
|
96
|
+
// no color on these errors as they can be standard errors for things like jest exiting with exitCode 1 for a single failed test.
|
|
97
|
+
if (error.signal !== 'SIGINT' && error.signal !== 'SIGTERM') {
|
|
98
|
+
if (error.code === 'ENOENT') {
|
|
99
|
+
logger.errornocolor(`Unknown command: ${error.command}`)
|
|
100
|
+
} else if (error.message.includes('Command failed with exit code 1')) {
|
|
101
|
+
logger.errornocolor(`Command exited with exit code 1: ${error.command}`)
|
|
102
|
+
} else {
|
|
103
|
+
logger.errornocolor(error.message)
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Exit with the error code from the command process, or 1 if unavailable
|
|
108
|
+
process.exit(error.exitCode || 1)
|
|
109
|
+
} finally {
|
|
110
|
+
// Clean up: Remove the SIGINT handler
|
|
111
|
+
process.removeListener('SIGINT', sigintHandler)
|
|
112
|
+
// Clean up: Remove the SIGTERM handler
|
|
113
|
+
process.removeListener('SIGTERM', sigtermHandler)
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
module.exports = executeCommand
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
const path = require('path')
|
|
2
|
+
const childProcess = require('child_process')
|
|
3
|
+
const { logger } = require('../../shared/logger')
|
|
4
|
+
|
|
5
|
+
function executeExtension (ext, command, rawArgs) {
|
|
6
|
+
if (!command) {
|
|
7
|
+
ext.outputHelp()
|
|
8
|
+
process.exit(1)
|
|
9
|
+
return
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// construct the full command line manually including flags
|
|
13
|
+
const commandIndex = rawArgs.indexOf(command)
|
|
14
|
+
const forwardedArgs = rawArgs.slice(commandIndex + 1)
|
|
15
|
+
|
|
16
|
+
logger.debug(`command: ${command}`)
|
|
17
|
+
logger.debug(`args: ${JSON.stringify(forwardedArgs)}`)
|
|
18
|
+
|
|
19
|
+
const binPath = path.join(process.cwd(), 'node_modules', '.bin')
|
|
20
|
+
const newPath = `${binPath}:${process.env.PATH}`
|
|
21
|
+
const env = { ...process.env, PATH: newPath }
|
|
22
|
+
|
|
23
|
+
const result = childProcess.spawnSync(`dotenvx-ext-${command}`, forwardedArgs, { stdio: 'inherit', env })
|
|
24
|
+
if (result.error) {
|
|
25
|
+
if (command === 'hub') {
|
|
26
|
+
logger.warn(`[INSTALLATION_NEEDED] install dotenvx-ext-${command} to use [dotenvx ext ${command}] commands`)
|
|
27
|
+
logger.help('? see installation instructions [https://github.com/dotenvx/dotenvx-ext-hub]')
|
|
28
|
+
} else {
|
|
29
|
+
logger.info(`error: unknown command '${command}'`)
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (result.status !== 0) {
|
|
34
|
+
process.exit(result.status)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
module.exports = executeExtension
|
|
@@ -24,20 +24,23 @@ function findOrCreatePublicKey (envFilepath, envKeysFilepath) {
|
|
|
24
24
|
// parsed
|
|
25
25
|
const envParsed = dotenv.parse(envSrc)
|
|
26
26
|
const keysParsed = dotenv.parse(keysSrc)
|
|
27
|
+
const existingPublicKey = envParsed[publicKeyName]
|
|
28
|
+
const existingPrivateKey = keysParsed[privateKeyName]
|
|
27
29
|
|
|
28
30
|
// if DOTENV_PUBLIC_KEY_${environment} already present then go no further
|
|
29
|
-
if (
|
|
31
|
+
if (existingPublicKey && existingPublicKey.length > 0) {
|
|
30
32
|
return {
|
|
31
33
|
envSrc,
|
|
32
34
|
keysSrc,
|
|
33
|
-
publicKey:
|
|
34
|
-
privateKey:
|
|
35
|
+
publicKey: existingPublicKey,
|
|
36
|
+
privateKey: existingPrivateKey,
|
|
37
|
+
publicKeyAdded: false,
|
|
35
38
|
privateKeyAdded: false
|
|
36
39
|
}
|
|
37
40
|
}
|
|
38
41
|
|
|
39
42
|
// generate key pair
|
|
40
|
-
const { publicKey, privateKey } = keyPair()
|
|
43
|
+
const { publicKey, privateKey } = keyPair(existingPrivateKey)
|
|
41
44
|
|
|
42
45
|
// publicKey
|
|
43
46
|
const prependPublicKey = [
|
|
@@ -65,17 +68,20 @@ function findOrCreatePublicKey (envFilepath, envKeysFilepath) {
|
|
|
65
68
|
|
|
66
69
|
envSrc = `${prependPublicKey}\n${envSrc}`
|
|
67
70
|
keysSrc = keysSrc.length > 1 ? keysSrc : `${firstTimeKeysSrc}\n`
|
|
68
|
-
keysSrc = `${keysSrc}\n${appendPrivateKey}`
|
|
69
71
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
+
let privateKeyAdded = false
|
|
73
|
+
if (!existingPrivateKey) {
|
|
74
|
+
keysSrc = `${keysSrc}\n${appendPrivateKey}`
|
|
75
|
+
privateKeyAdded = true
|
|
76
|
+
}
|
|
72
77
|
|
|
73
78
|
return {
|
|
74
79
|
envSrc,
|
|
75
80
|
keysSrc,
|
|
76
81
|
publicKey,
|
|
77
82
|
privateKey,
|
|
78
|
-
|
|
83
|
+
publicKeyAdded: true,
|
|
84
|
+
privateKeyAdded
|
|
79
85
|
}
|
|
80
86
|
}
|
|
81
87
|
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
const ENCRYPTION_PATTERN = /^encrypted:.+/
|
|
2
|
-
const PUBLIC_KEY_PATTERN = /^DOTENV_PUBLIC_KEY/
|
|
3
2
|
|
|
4
3
|
function isEncrypted (key, value) {
|
|
5
|
-
return
|
|
4
|
+
return ENCRYPTION_PATTERN.test(value)
|
|
6
5
|
}
|
|
7
6
|
|
|
8
7
|
module.exports = isEncrypted
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
const dotenv = require('dotenv')
|
|
2
2
|
|
|
3
3
|
const isEncrypted = require('./isEncrypted')
|
|
4
|
+
const isPublicKey = require('./isPublicKey')
|
|
4
5
|
|
|
5
6
|
function isFullyEncrypted (src) {
|
|
6
7
|
const parsed = dotenv.parse(src)
|
|
7
8
|
|
|
8
9
|
for (const [key, value] of Object.entries(parsed)) {
|
|
9
|
-
const result = isEncrypted(key, value)
|
|
10
|
+
const result = isEncrypted(key, value) || isPublicKey(key, value)
|
|
10
11
|
if (!result) {
|
|
11
12
|
return false
|
|
12
13
|
}
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
const { PrivateKey } = require('eciesjs')
|
|
2
2
|
|
|
3
|
-
function keyPair () {
|
|
4
|
-
|
|
3
|
+
function keyPair (existingPrivateKey) {
|
|
4
|
+
let kp
|
|
5
|
+
|
|
6
|
+
if (existingPrivateKey) {
|
|
7
|
+
kp = new PrivateKey(Buffer.from(existingPrivateKey, 'hex'))
|
|
8
|
+
} else {
|
|
9
|
+
kp = new PrivateKey()
|
|
10
|
+
}
|
|
5
11
|
|
|
6
12
|
const publicKey = kp.publicKey.toHex()
|
|
7
13
|
const privateKey = kp.secret.toString('hex')
|