@dotenvx/dotenvx 1.5.0 → 1.6.1

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.
Files changed (54) hide show
  1. package/CHANGELOG.md +24 -1
  2. package/README.md +88 -2
  3. package/package.json +9 -9
  4. package/src/cli/actions/decrypt.js +71 -0
  5. package/src/cli/actions/encrypt.js +54 -42
  6. package/src/cli/actions/ext/genexample.js +4 -12
  7. package/src/cli/actions/ext/gitignore.js +5 -0
  8. package/src/cli/actions/ext/prebuild.js +1 -0
  9. package/src/cli/actions/ext/scan.js +9 -6
  10. package/src/cli/actions/ext/settings.js +5 -4
  11. package/src/cli/actions/ext/vault/decrypt.js +6 -13
  12. package/src/cli/actions/ext/vault/encrypt.js +5 -12
  13. package/src/cli/actions/ext/vault/migrate.js +22 -39
  14. package/src/cli/actions/get.js +6 -5
  15. package/src/cli/actions/run.js +3 -110
  16. package/src/cli/actions/set.js +2 -2
  17. package/src/cli/commands/ext.js +2 -32
  18. package/src/cli/dotenvx.js +12 -14
  19. package/src/lib/helpers/execute.js +9 -0
  20. package/src/lib/helpers/executeCommand.js +117 -0
  21. package/src/lib/helpers/executeExtension.js +38 -0
  22. package/src/lib/helpers/findOrCreatePublicKey.js +14 -8
  23. package/src/lib/helpers/guessEnvironment.js +4 -1
  24. package/src/lib/helpers/isEncrypted.js +1 -2
  25. package/src/lib/helpers/isFullyEncrypted.js +2 -1
  26. package/src/lib/helpers/isIgnoringDotenvKeys.js +1 -1
  27. package/src/lib/helpers/isPublicKey.js +7 -0
  28. package/src/lib/helpers/keyPair.js +8 -2
  29. package/src/lib/helpers/smartDotenvPrivateKey.js +64 -6
  30. package/src/lib/main.js +16 -9
  31. package/src/lib/services/decrypt.js +79 -98
  32. package/src/lib/services/encrypt.js +12 -7
  33. package/src/lib/services/sets.js +9 -2
  34. package/src/lib/services/status.js +2 -2
  35. package/src/lib/services/vaultDecrypt.js +126 -0
  36. package/src/shared/logger.js +0 -3
  37. package/src/cli/commands/vault.js +0 -57
  38. package/src/lib/helpers/clipboardy/fallbacks/linux/xsel +0 -0
  39. package/src/lib/helpers/clipboardy/fallbacks/windows/clipboard_i686.exe +0 -0
  40. package/src/lib/helpers/clipboardy/fallbacks/windows/clipboard_x86_64.exe +0 -0
  41. package/src/lib/helpers/clipboardy/linux.js +0 -57
  42. package/src/lib/helpers/clipboardy/macos.js +0 -14
  43. package/src/lib/helpers/clipboardy/termux.js +0 -41
  44. package/src/lib/helpers/clipboardy/windows.js +0 -16
  45. package/src/lib/helpers/clipboardy.js +0 -51
  46. package/src/lib/helpers/extractUsernameName.js +0 -10
  47. package/src/lib/helpers/forgivingDirectory.js +0 -11
  48. package/src/lib/helpers/gitRoot.js +0 -14
  49. package/src/lib/helpers/gitUrl.js +0 -13
  50. package/src/lib/helpers/isGitRepo.js +0 -13
  51. package/src/lib/helpers/isGithub.js +0 -5
  52. package/src/lib/helpers/resolvePath.js +0 -8
  53. package/src/shared/confirm.js +0 -12
  54. package/src/shared/createSpinner.js +0 -97
@@ -1,47 +1,30 @@
1
1
  const { logger } = require('./../../../../shared/logger')
2
2
 
3
- function migrate (directory) {
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
- try {
11
- logger.help2('To migrate your .env.vault file to encrypted .env file(s):')
12
- logger.help('')
13
- logger.help(' 1. Run [dotenvx ext vault decrypt]')
14
- logger.help(' 2. Run [ls -a .env*]')
15
- logger.help('')
16
- logger.help2('Lastly, encrypt each .env(.environment) file:')
17
- logger.help('')
18
- logger.help(' 3. Run [dotenvx encrypt -f .env.production]')
19
- logger.help2('')
20
- logger.help2('For example:')
21
- logger.help2('')
22
- logger.help2(' $ dotenvx encrypt -f .env')
23
- logger.help2(' $ dotenvx encrypt -f .env.ci')
24
- logger.help2(' $ dotenvx encrypt -f .env.production')
25
- logger.help2('')
26
- logger.help2('Afterward:')
27
- logger.help2('')
28
- logger.help2('Update production with your new DOTENV_PRIVATE_KEY_PRODUCTION located in .env.keys')
29
- logger.help2('')
30
- logger.success('Learn more at [https://dotenvx.com/docs/quickstart#add-encryption]')
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
@@ -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
- logger.blank0(JSON.stringify(value, null, 2))
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
- logger.blank0('')
32
+ process.stdout.write('')
32
33
  process.exit(1)
33
34
  } else {
34
- logger.blank0(value)
35
+ process.stdout.write(value)
35
36
  }
36
37
  }
37
38
  }
@@ -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
@@ -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)
@@ -1,9 +1,7 @@
1
- const path = require('path')
2
- const { spawnSync } = require('child_process')
3
1
  const { Command } = require('commander')
4
- const { logger } = require('../../shared/logger')
5
2
 
6
3
  const examples = require('./../examples')
4
+ const executeExtension = require('../../lib/helpers/executeExtension')
7
5
 
8
6
  const ext = new Command('ext')
9
7
 
@@ -17,36 +15,8 @@ ext
17
15
  .argument('[command]', 'dynamic ext command')
18
16
  .argument('[args...]', 'dynamic ext command arguments')
19
17
  .action((command, args, cmdObj) => {
20
- if (!command) {
21
- ext.outputHelp()
22
- process.exit(1)
23
- }
24
-
25
- // construct the full command line manually including flags
26
18
  const rawArgs = process.argv.slice(3) // adjust the index based on where actual args start
27
- const commandIndex = rawArgs.indexOf(command)
28
- const forwardedArgs = rawArgs.slice(commandIndex + 1)
29
-
30
- logger.debug(`command: ${command}`)
31
- logger.debug(`args: ${JSON.stringify(forwardedArgs)}`)
32
-
33
- const binPath = path.join(process.cwd(), 'node_modules', '.bin')
34
- const newPath = `${binPath}:${process.env.PATH}`
35
- const env = { ...process.env, PATH: newPath }
36
-
37
- const result = spawnSync(`dotenvx-ext-${command}`, forwardedArgs, { stdio: 'inherit', env })
38
- if (result.error) {
39
- if (command === 'hub') {
40
- logger.warn(`[INSTALLATION_NEEDED] install dotenvx-ext-${command} to use [dotenvx ext ${command}] commands`)
41
- logger.help('? see installation instructions [https://github.com/dotenvx/dotenvx-ext-hub]')
42
- } else {
43
- logger.info(`error: unknown command '${command}'`)
44
- }
45
- }
46
-
47
- if (result.status !== 0) {
48
- process.exit(result.status)
49
- }
19
+ executeExtension(ext, command, rawArgs)
50
20
  })
51
21
 
52
22
  // dotenvx ext ls
@@ -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')
@@ -90,8 +91,18 @@ program.command('encrypt')
90
91
  .description('convert .env file(s) to encrypted .env file(s)')
91
92
  .option('-f, --env-file <paths...>', 'path(s) to your env file(s)')
92
93
  .option('-k, --key <keys...>', 'keys(s) to encrypt (default: all keys in file)')
94
+ .option('--stdout', 'send to stdout')
93
95
  .action(encryptAction)
94
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
+
95
106
  // dotenvx pro
96
107
  program.command('pro')
97
108
  .description('🏆 pro')
@@ -116,20 +127,6 @@ program.command('pro')
116
127
  // dotenvx ext
117
128
  program.addCommand(require('./commands/ext'))
118
129
 
119
- //
120
- // DEPRECATED AND hidden
121
- //
122
- program.addCommand(require('./commands/vault'))
123
-
124
- program.command('convert')
125
- .description('DEPRECATED: moved to [dotenvx encrypt]')
126
- .option('-f, --env-file <paths...>', 'path(s) to your env file(s)')
127
- .action(function (...args) {
128
- logger.warn('DEPRECATION NOTICE: [dotenvx convert] has moved to [dotenvx encrypt]')
129
-
130
- encryptAction.apply(this, args)
131
- })
132
-
133
130
  const lsAction = require('./actions/ext/ls')
134
131
  program.command('ls')
135
132
  .description('DEPRECATED: moved to [dotenvx ext ls]')
@@ -206,5 +203,6 @@ program.helpInformation = function () {
206
203
 
207
204
  return filteredLines.join('\n')
208
205
  }
206
+ /* c8 ignore stop */
209
207
 
210
208
  program.parse(process.argv)
@@ -0,0 +1,9 @@
1
+ const execa = require('execa')
2
+
3
+ const execute = {
4
+ execa (command, args, options) {
5
+ return execa(command, args, options)
6
+ }
7
+ }
8
+
9
+ module.exports = execute
@@ -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 (envParsed[publicKeyName] && envParsed[publicKeyName].length > 0) {
31
+ if (existingPublicKey && existingPublicKey.length > 0) {
30
32
  return {
31
33
  envSrc,
32
34
  keysSrc,
33
- publicKey: envParsed[publicKeyName],
34
- privateKey: keysParsed[privateKeyName],
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
- fs.writeFileSync(envFilepath, envSrc)
71
- fs.writeFileSync(envKeysFilepath, keysSrc)
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
- privateKeyAdded: true
83
+ publicKeyAdded: true,
84
+ privateKeyAdded
79
85
  }
80
86
  }
81
87
 
@@ -7,7 +7,10 @@ function guessEnvironment (filepath) {
7
7
  const possibleEnvironmentList = [...parts.slice(2)]
8
8
 
9
9
  if (possibleEnvironmentList.length === 0) {
10
- return 'development'
10
+ // handle .env1 -> development1
11
+ const environment = filename.replace('.env', 'development')
12
+
13
+ return environment
11
14
  }
12
15
 
13
16
  if (possibleEnvironmentList.length === 1) {
@@ -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 PUBLIC_KEY_PATTERN.test(key) || ENCRYPTION_PATTERN.test(value)
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
  }
@@ -13,7 +13,7 @@ function isIgnoringDotenvKeys () {
13
13
  return false
14
14
  }
15
15
 
16
- return false
16
+ return true
17
17
  }
18
18
 
19
19
  module.exports = isIgnoringDotenvKeys
@@ -0,0 +1,7 @@
1
+ const PUBLIC_KEY_PATTERN = /^DOTENV_PUBLIC_KEY/
2
+
3
+ function isPublicKey (key, value) {
4
+ return PUBLIC_KEY_PATTERN.test(key)
5
+ }
6
+
7
+ module.exports = isPublicKey
@@ -1,7 +1,13 @@
1
1
  const { PrivateKey } = require('eciesjs')
2
2
 
3
- function keyPair () {
4
- const kp = new PrivateKey()
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')