@dotenvx/dotenvx 1.5.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 +18 -1
- package/README.md +88 -2
- package/package.json +9 -9
- 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 +2 -32
- package/src/cli/dotenvx.js +12 -14
- 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/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/confirm.js +0 -12
- package/src/shared/createSpinner.js +0 -97
package/src/lib/main.js
CHANGED
|
@@ -10,6 +10,7 @@ const Run = require('./services/run')
|
|
|
10
10
|
const Sets = require('./services/sets')
|
|
11
11
|
const Status = require('./services/status')
|
|
12
12
|
const Encrypt = require('./services/encrypt')
|
|
13
|
+
const Decrypt = require('./services/decrypt')
|
|
13
14
|
const Genexample = require('./services/genexample')
|
|
14
15
|
const Settings = require('./services/settings')
|
|
15
16
|
const VaultEncrypt = require('./services/vaultEncrypt')
|
|
@@ -162,11 +163,6 @@ const parse = function (src) {
|
|
|
162
163
|
return dotenv.parse(src)
|
|
163
164
|
}
|
|
164
165
|
|
|
165
|
-
/** @type {import('./main').vaultEncrypt} */
|
|
166
|
-
const vaultEncrypt = function (directory, envFile) {
|
|
167
|
-
return new VaultEncrypt(directory, envFile).run()
|
|
168
|
-
}
|
|
169
|
-
|
|
170
166
|
/** @type {import('./main').ls} */
|
|
171
167
|
const ls = function (directory, envFile) {
|
|
172
168
|
return new Ls(directory, envFile).run()
|
|
@@ -198,6 +194,11 @@ const encrypt = function (envFile, key) {
|
|
|
198
194
|
return new Encrypt(envFile, key).run()
|
|
199
195
|
}
|
|
200
196
|
|
|
197
|
+
/** @type {import('./main').encrypt} */
|
|
198
|
+
const decrypt = function (envFile, key) {
|
|
199
|
+
return new Decrypt(envFile, key).run()
|
|
200
|
+
}
|
|
201
|
+
|
|
201
202
|
/** @type {import('./main').status} */
|
|
202
203
|
const status = function (directory) {
|
|
203
204
|
return new Status(directory).run()
|
|
@@ -211,8 +212,8 @@ const settings = function (key = null) {
|
|
|
211
212
|
|
|
212
213
|
// misc/cleanup
|
|
213
214
|
|
|
214
|
-
/** @type {import('./main').
|
|
215
|
-
const
|
|
215
|
+
/** @type {import('./main').vaultDecrypt} */
|
|
216
|
+
const vaultDecrypt = function (encrypted, keyStr) {
|
|
216
217
|
try {
|
|
217
218
|
return dotenv.decrypt(encrypted, keyStr)
|
|
218
219
|
} catch (e) {
|
|
@@ -236,6 +237,11 @@ const decrypt = function (encrypted, keyStr) {
|
|
|
236
237
|
}
|
|
237
238
|
}
|
|
238
239
|
|
|
240
|
+
/** @type {import('./main').vaultEncrypt} */
|
|
241
|
+
const vaultEncrypt = function (directory, envFile) {
|
|
242
|
+
return new VaultEncrypt(directory, envFile).run()
|
|
243
|
+
}
|
|
244
|
+
|
|
239
245
|
module.exports = {
|
|
240
246
|
// dotenv proxies
|
|
241
247
|
config,
|
|
@@ -243,7 +249,7 @@ module.exports = {
|
|
|
243
249
|
parse,
|
|
244
250
|
// actions related
|
|
245
251
|
encrypt,
|
|
246
|
-
|
|
252
|
+
decrypt,
|
|
247
253
|
ls,
|
|
248
254
|
get,
|
|
249
255
|
set,
|
|
@@ -252,5 +258,6 @@ module.exports = {
|
|
|
252
258
|
// settings
|
|
253
259
|
settings,
|
|
254
260
|
// misc/cleanup
|
|
255
|
-
|
|
261
|
+
vaultEncrypt,
|
|
262
|
+
vaultDecrypt
|
|
256
263
|
}
|
|
@@ -2,124 +2,105 @@ const fs = require('fs')
|
|
|
2
2
|
const path = require('path')
|
|
3
3
|
const dotenv = require('dotenv')
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
const smartDotenvPrivateKey = require('./../helpers/smartDotenvPrivateKey')
|
|
6
|
+
const guessPrivateKeyName = require('./../helpers/guessPrivateKeyName')
|
|
7
|
+
const decryptValue = require('./../helpers/decryptValue')
|
|
8
|
+
const isEncrypted = require('./../helpers/isEncrypted')
|
|
9
|
+
const replace = require('./../helpers/replace')
|
|
6
10
|
|
|
7
|
-
const
|
|
11
|
+
const ENCODING = 'utf8'
|
|
8
12
|
|
|
9
13
|
class Decrypt {
|
|
10
|
-
constructor (
|
|
11
|
-
this.
|
|
12
|
-
this.
|
|
13
|
-
|
|
14
|
-
this.
|
|
15
|
-
this.
|
|
16
|
-
|
|
17
|
-
this.processedEnvs = []
|
|
18
|
-
this.changedFilenames = new Set()
|
|
19
|
-
this.unchangedFilenames = new Set()
|
|
14
|
+
constructor (envFile = '.env', key = []) {
|
|
15
|
+
this.envFile = envFile
|
|
16
|
+
this.key = key
|
|
17
|
+
this.processedEnvFiles = []
|
|
18
|
+
this.changedFilepaths = new Set()
|
|
19
|
+
this.unchangedFilepaths = new Set()
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
run () {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
23
|
+
const envFilepaths = this._envFilepaths()
|
|
24
|
+
const keys = this._keys()
|
|
25
|
+
for (const envFilepath of envFilepaths) {
|
|
26
|
+
const filepath = path.resolve(envFilepath)
|
|
27
|
+
|
|
28
|
+
const row = {}
|
|
29
|
+
row.keys = []
|
|
30
|
+
row.filepath = filepath
|
|
31
|
+
row.envFilepath = envFilepath
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
// get the src
|
|
35
|
+
let src = fs.readFileSync(filepath, { encoding: ENCODING })
|
|
36
|
+
|
|
37
|
+
// if DOTENV_PRIVATE_KEY_* already set in process.env then use it
|
|
38
|
+
const privateKey = smartDotenvPrivateKey(envFilepath)
|
|
39
|
+
row.privateKey = privateKey
|
|
40
|
+
row.privateKeyName = guessPrivateKeyName(filepath)
|
|
41
|
+
|
|
42
|
+
// track possible changes
|
|
43
|
+
row.changed = false
|
|
44
|
+
|
|
45
|
+
// iterate over all non-encrypted values and encrypt them
|
|
46
|
+
const parsed = dotenv.parse(src)
|
|
47
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
48
|
+
if (keys.length < 1 || keys.includes(key)) { // optionally control which key to decrypt
|
|
49
|
+
const encrypted = isEncrypted(key, value)
|
|
50
|
+
if (encrypted) {
|
|
51
|
+
row.keys.push(key) // track key(s)
|
|
52
|
+
|
|
53
|
+
const plainValue = decryptValue(value, privateKey)
|
|
54
|
+
// once newSrc is built write it out
|
|
55
|
+
src = replace(src, key, plainValue)
|
|
56
|
+
|
|
57
|
+
row.changed = true // track change
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (row.changed) {
|
|
63
|
+
row.envSrc = src
|
|
64
|
+
this.changedFilepaths.add(envFilepath)
|
|
65
|
+
} else {
|
|
66
|
+
row.envSrc = src
|
|
67
|
+
this.unchangedFilepaths.add(envFilepath)
|
|
68
|
+
}
|
|
69
|
+
} catch (e) {
|
|
70
|
+
if (e.code === 'ENOENT') {
|
|
71
|
+
const error = new Error(`missing ${envFilepath} file (${filepath})`)
|
|
72
|
+
error.code = 'MISSING_ENV_FILE'
|
|
73
|
+
|
|
74
|
+
row.error = error
|
|
75
|
+
} else {
|
|
76
|
+
row.error = e
|
|
77
|
+
}
|
|
56
78
|
}
|
|
57
|
-
} else {
|
|
58
|
-
for (const [dotenvKey, value] of Object.entries(dotenvKeys)) {
|
|
59
|
-
const environment = dotenvKey.replace('DOTENV_KEY_', '').toLowerCase()
|
|
60
|
-
const row = this._processRow(value, dotenvVault, environment)
|
|
61
79
|
|
|
62
|
-
|
|
63
|
-
}
|
|
80
|
+
this.processedEnvFiles.push(row)
|
|
64
81
|
}
|
|
65
82
|
|
|
66
83
|
return {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
84
|
+
processedEnvFiles: this.processedEnvFiles,
|
|
85
|
+
changedFilepaths: [...this.changedFilepaths],
|
|
86
|
+
unchangedFilepaths: [...this.unchangedFilepaths]
|
|
70
87
|
}
|
|
71
88
|
}
|
|
72
89
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
const ciphertext = dotenvVault[vaultKey] // attempt to find ciphertext
|
|
77
|
-
|
|
78
|
-
const row = {}
|
|
79
|
-
row.environment = environment
|
|
80
|
-
row.dotenvKey = value ? value.trim() : value
|
|
81
|
-
row.ciphertext = ciphertext
|
|
82
|
-
|
|
83
|
-
if (ciphertext && ciphertext.length >= 1) {
|
|
84
|
-
// Decrypt
|
|
85
|
-
const decrypted = libDecrypt(ciphertext, value.trim())
|
|
86
|
-
row.decrypted = decrypted
|
|
87
|
-
|
|
88
|
-
// envFilename
|
|
89
|
-
// replace _ with . to support filenames like .env.development.local
|
|
90
|
-
let envFilename = `.env.${environment.replace('_', '.')}`
|
|
91
|
-
if (environment === 'development') {
|
|
92
|
-
envFilename = '.env'
|
|
93
|
-
}
|
|
94
|
-
row.filename = envFilename
|
|
95
|
-
row.filepath = path.resolve(this.directory, envFilename)
|
|
96
|
-
|
|
97
|
-
// check if exists and is changing
|
|
98
|
-
if (fs.existsSync(row.filepath) && (fs.readFileSync(row.filepath, { encoding: ENCODING }).toString() === decrypted)) {
|
|
99
|
-
this.unchangedFilenames.add(envFilename)
|
|
100
|
-
} else {
|
|
101
|
-
row.shouldWrite = true
|
|
102
|
-
this.changedFilenames.add(envFilename)
|
|
103
|
-
}
|
|
104
|
-
} else {
|
|
105
|
-
const message = `${vaultKey} missing in .env.vault: ${this.envVaultFilepath}`
|
|
106
|
-
const warning = new Error(message)
|
|
107
|
-
row.warning = warning
|
|
90
|
+
_envFilepaths () {
|
|
91
|
+
if (!Array.isArray(this.envFile)) {
|
|
92
|
+
return [this.envFile]
|
|
108
93
|
}
|
|
109
94
|
|
|
110
|
-
return
|
|
95
|
+
return this.envFile
|
|
111
96
|
}
|
|
112
97
|
|
|
113
|
-
|
|
114
|
-
if (this.
|
|
115
|
-
return []
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
if (!Array.isArray(this.environment)) {
|
|
119
|
-
return [this.environment]
|
|
98
|
+
_keys () {
|
|
99
|
+
if (!Array.isArray(this.key)) {
|
|
100
|
+
return [this.key]
|
|
120
101
|
}
|
|
121
102
|
|
|
122
|
-
return this.
|
|
103
|
+
return this.key
|
|
123
104
|
}
|
|
124
105
|
}
|
|
125
106
|
|
|
@@ -6,6 +6,7 @@ const findOrCreatePublicKey = require('./../helpers/findOrCreatePublicKey')
|
|
|
6
6
|
const guessPrivateKeyName = require('./../helpers/guessPrivateKeyName')
|
|
7
7
|
const encryptValue = require('./../helpers/encryptValue')
|
|
8
8
|
const isEncrypted = require('./../helpers/isEncrypted')
|
|
9
|
+
const isPublicKey = require('./../helpers/isPublicKey')
|
|
9
10
|
const replace = require('./../helpers/replace')
|
|
10
11
|
|
|
11
12
|
const ENCODING = 'utf8'
|
|
@@ -37,25 +38,29 @@ class Encrypt {
|
|
|
37
38
|
const envKeysFilepath = path.join(path.dirname(filepath), '.env.keys')
|
|
38
39
|
const {
|
|
39
40
|
envSrc,
|
|
41
|
+
keysSrc,
|
|
40
42
|
publicKey,
|
|
41
43
|
privateKey,
|
|
44
|
+
publicKeyAdded,
|
|
42
45
|
privateKeyAdded
|
|
43
46
|
} = findOrCreatePublicKey(filepath, envKeysFilepath)
|
|
47
|
+
|
|
48
|
+
// handle .env.keys write
|
|
49
|
+
fs.writeFileSync(envKeysFilepath, keysSrc)
|
|
50
|
+
|
|
51
|
+
src = envSrc // src was potentially modified by findOrCreatePublicKey so we set it again here
|
|
52
|
+
|
|
53
|
+
row.changed = publicKeyAdded // track change
|
|
44
54
|
row.publicKey = publicKey
|
|
45
55
|
row.privateKey = privateKey
|
|
46
|
-
row.privateKeyName = guessPrivateKeyName(filepath)
|
|
47
56
|
row.privateKeyAdded = privateKeyAdded
|
|
48
|
-
|
|
49
|
-
src = envSrc // src was potentially changed by findOrCreatePublicKey so we set it again here
|
|
50
|
-
|
|
51
|
-
// track possible changes
|
|
52
|
-
row.changed = false
|
|
57
|
+
row.privateKeyName = guessPrivateKeyName(filepath)
|
|
53
58
|
|
|
54
59
|
// iterate over all non-encrypted values and encrypt them
|
|
55
60
|
const parsed = dotenv.parse(src)
|
|
56
61
|
for (const [key, value] of Object.entries(parsed)) {
|
|
57
62
|
if (keys.length < 1 || keys.includes(key)) { // optionally control which key to encrypt
|
|
58
|
-
const encrypted = isEncrypted(key, value)
|
|
63
|
+
const encrypted = isEncrypted(key, value) || isPublicKey(key, value)
|
|
59
64
|
if (!encrypted) {
|
|
60
65
|
row.keys.push(key) // track key(s)
|
|
61
66
|
|
package/src/lib/services/sets.js
CHANGED
|
@@ -43,14 +43,21 @@ class Sets {
|
|
|
43
43
|
const envKeysFilepath = path.join(path.dirname(filepath), '.env.keys')
|
|
44
44
|
const {
|
|
45
45
|
envSrc,
|
|
46
|
+
keysSrc,
|
|
46
47
|
publicKey,
|
|
47
48
|
privateKey,
|
|
49
|
+
publicKeyAdded,
|
|
48
50
|
privateKeyAdded
|
|
49
51
|
} = findOrCreatePublicKey(filepath, envKeysFilepath)
|
|
50
|
-
|
|
52
|
+
|
|
53
|
+
// handle .env.keys write
|
|
54
|
+
fs.writeFileSync(envKeysFilepath, keysSrc)
|
|
55
|
+
|
|
56
|
+
src = envSrc // src was potentially modified by findOrCreatePublicKey so we set it again here
|
|
57
|
+
|
|
51
58
|
value = encryptValue(value, publicKey)
|
|
52
59
|
|
|
53
|
-
row.changed =
|
|
60
|
+
row.changed = publicKeyAdded // track change
|
|
54
61
|
row.encryptedValue = value
|
|
55
62
|
row.publicKey = publicKey
|
|
56
63
|
row.privateKey = privateKey
|
|
@@ -4,7 +4,7 @@ const diff = require('diff')
|
|
|
4
4
|
const chalk = require('chalk')
|
|
5
5
|
|
|
6
6
|
const Ls = require('./ls')
|
|
7
|
-
const
|
|
7
|
+
const VaultDecrypt = require('./vaultDecrypt')
|
|
8
8
|
|
|
9
9
|
const containsDirectory = require('./../helpers/containsDirectory')
|
|
10
10
|
const guessEnvironment = require('./../helpers/guessEnvironment')
|
|
@@ -60,7 +60,7 @@ class Status {
|
|
|
60
60
|
row.raw = fs.readFileSync(filepath, { encoding: ENCODING })
|
|
61
61
|
|
|
62
62
|
// grab decrypted
|
|
63
|
-
const { processedEnvs } = new
|
|
63
|
+
const { processedEnvs } = new VaultDecrypt(this.directory, row.environment).run()
|
|
64
64
|
const result = processedEnvs[0]
|
|
65
65
|
|
|
66
66
|
// handle warnings
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
const fs = require('fs')
|
|
2
|
+
const path = require('path')
|
|
3
|
+
const dotenv = require('dotenv')
|
|
4
|
+
|
|
5
|
+
const ENCODING = 'utf8'
|
|
6
|
+
|
|
7
|
+
const libDecrypt = require('./../../lib/helpers/decrypt')
|
|
8
|
+
|
|
9
|
+
class VaultDecrypt {
|
|
10
|
+
constructor (directory = '.', environment) {
|
|
11
|
+
this.directory = directory
|
|
12
|
+
this.environment = environment
|
|
13
|
+
|
|
14
|
+
this.envKeysFilepath = path.resolve(this.directory, '.env.keys')
|
|
15
|
+
this.envVaultFilepath = path.resolve(this.directory, '.env.vault')
|
|
16
|
+
|
|
17
|
+
this.processedEnvs = []
|
|
18
|
+
this.changedFilenames = new Set()
|
|
19
|
+
this.unchangedFilenames = new Set()
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
run () {
|
|
23
|
+
if (!fs.existsSync(this.envVaultFilepath)) {
|
|
24
|
+
const code = 'MISSING_ENV_VAULT_FILE'
|
|
25
|
+
const message = `missing .env.vault (${this.envVaultFilepath})`
|
|
26
|
+
const help = `? generate one with [dotenvx encrypt ${this.directory}]`
|
|
27
|
+
|
|
28
|
+
const error = new Error(message)
|
|
29
|
+
error.code = code
|
|
30
|
+
error.help = help
|
|
31
|
+
throw error
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (!fs.existsSync(this.envKeysFilepath)) {
|
|
35
|
+
const code = 'MISSING_ENV_KEYS_FILE'
|
|
36
|
+
const message = `missing .env.keys (${this.envKeysFilepath})`
|
|
37
|
+
const help = '? a .env.keys file must be present in order to decrypt your .env.vault contents to .env file(s)'
|
|
38
|
+
|
|
39
|
+
const error = new Error(message)
|
|
40
|
+
error.code = code
|
|
41
|
+
error.help = help
|
|
42
|
+
throw error
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const dotenvKeys = dotenv.configDotenv({ path: this.envKeysFilepath }).parsed
|
|
46
|
+
const dotenvVault = dotenv.configDotenv({ path: this.envVaultFilepath }).parsed
|
|
47
|
+
const environments = this._environments()
|
|
48
|
+
|
|
49
|
+
if (environments.length > 0) {
|
|
50
|
+
// iterate over the environments
|
|
51
|
+
for (const environment of environments) {
|
|
52
|
+
const value = dotenvKeys[`DOTENV_KEY_${environment.toUpperCase()}`]
|
|
53
|
+
const row = this._processRow(value, dotenvVault, environment)
|
|
54
|
+
|
|
55
|
+
this.processedEnvs.push(row)
|
|
56
|
+
}
|
|
57
|
+
} else {
|
|
58
|
+
for (const [dotenvKey, value] of Object.entries(dotenvKeys)) {
|
|
59
|
+
const environment = dotenvKey.replace('DOTENV_KEY_', '').toLowerCase()
|
|
60
|
+
const row = this._processRow(value, dotenvVault, environment)
|
|
61
|
+
|
|
62
|
+
this.processedEnvs.push(row)
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
processedEnvs: this.processedEnvs,
|
|
68
|
+
changedFilenames: [...this.changedFilenames],
|
|
69
|
+
unchangedFilenames: [...this.unchangedFilenames]
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
_processRow (value, dotenvVault, environment) {
|
|
74
|
+
environment = environment.toLowerCase() // important so we don't later write .env.DEVELOPMENT for example
|
|
75
|
+
const vaultKey = `DOTENV_VAULT_${environment.toUpperCase()}`
|
|
76
|
+
const ciphertext = dotenvVault[vaultKey] // attempt to find ciphertext
|
|
77
|
+
|
|
78
|
+
const row = {}
|
|
79
|
+
row.environment = environment
|
|
80
|
+
row.dotenvKey = value ? value.trim() : value
|
|
81
|
+
row.ciphertext = ciphertext
|
|
82
|
+
|
|
83
|
+
if (ciphertext && ciphertext.length >= 1) {
|
|
84
|
+
// Decrypt
|
|
85
|
+
const decrypted = libDecrypt(ciphertext, value.trim())
|
|
86
|
+
row.decrypted = decrypted
|
|
87
|
+
|
|
88
|
+
// envFilename
|
|
89
|
+
// replace _ with . to support filenames like .env.development.local
|
|
90
|
+
let envFilename = `.env.${environment.replace('_', '.')}`
|
|
91
|
+
if (environment === 'development') {
|
|
92
|
+
envFilename = '.env'
|
|
93
|
+
}
|
|
94
|
+
row.filename = envFilename
|
|
95
|
+
row.filepath = path.resolve(this.directory, envFilename)
|
|
96
|
+
|
|
97
|
+
// check if exists and is changing
|
|
98
|
+
if (fs.existsSync(row.filepath) && (fs.readFileSync(row.filepath, { encoding: ENCODING }).toString() === decrypted)) {
|
|
99
|
+
this.unchangedFilenames.add(envFilename)
|
|
100
|
+
} else {
|
|
101
|
+
row.shouldWrite = true
|
|
102
|
+
this.changedFilenames.add(envFilename)
|
|
103
|
+
}
|
|
104
|
+
} else {
|
|
105
|
+
const message = `${vaultKey} missing in .env.vault: ${this.envVaultFilepath}`
|
|
106
|
+
const warning = new Error(message)
|
|
107
|
+
row.warning = warning
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return row
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
_environments () {
|
|
114
|
+
if (this.environment === undefined) {
|
|
115
|
+
return []
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (!Array.isArray(this.environment)) {
|
|
119
|
+
return [this.environment]
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return this.environment
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
module.exports = VaultDecrypt
|
package/src/shared/logger.js
CHANGED
|
@@ -9,7 +9,6 @@ const transports = winston.transports
|
|
|
9
9
|
const packageJson = require('./../lib/helpers/packageJson')
|
|
10
10
|
|
|
11
11
|
const levels = {
|
|
12
|
-
blank0: 0,
|
|
13
12
|
error: 0,
|
|
14
13
|
errorv: 0,
|
|
15
14
|
errorvp: 0,
|
|
@@ -47,8 +46,6 @@ const dotenvxFormat = printf(({ level, message, label, timestamp }) => {
|
|
|
47
46
|
const formattedMessage = typeof message === 'object' ? JSON.stringify(message) : message
|
|
48
47
|
|
|
49
48
|
switch (level.toLowerCase()) {
|
|
50
|
-
case 'blank0': // special blank that always displays - even with quiet flag (for use with get action)
|
|
51
|
-
return formattedMessage
|
|
52
49
|
case 'error':
|
|
53
50
|
return error(formattedMessage)
|
|
54
51
|
case 'errorv':
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
const { Command } = require('commander')
|
|
2
|
-
|
|
3
|
-
const examples = require('./../examples')
|
|
4
|
-
const { logger } = require('./../../shared/logger')
|
|
5
|
-
|
|
6
|
-
const vault = new Command('vault')
|
|
7
|
-
|
|
8
|
-
vault
|
|
9
|
-
.description('DEPRECATED: moved to [dotenvx ext vault]')
|
|
10
|
-
|
|
11
|
-
// dotenvx vault migrate
|
|
12
|
-
const migrateAction = require('./../actions/ext/vault/migrate')
|
|
13
|
-
vault.command('migrate')
|
|
14
|
-
.description('DEPRECATED: moved to [dotenvx ext vault migrate]')
|
|
15
|
-
.action(function (...args) {
|
|
16
|
-
logger.warn('DEPRECATION NOTICE: [dotenvx vault migrate] moved to [dotenvx ext vault migrate]')
|
|
17
|
-
|
|
18
|
-
migrateAction.apply(this, args)
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
// dotenvx vault encrypt
|
|
22
|
-
const encryptAction = require('./../actions/ext/vault/encrypt')
|
|
23
|
-
vault.command('encrypt')
|
|
24
|
-
.description('DEPRECATED: moved to [dotenvx ext vault encrypt]')
|
|
25
|
-
.addHelpText('after', examples.vaultEncrypt)
|
|
26
|
-
.argument('[directory]', 'directory to encrypt', '.')
|
|
27
|
-
.option('-f, --env-file <paths...>', 'path(s) to your env file(s)')
|
|
28
|
-
.action(function (...args) {
|
|
29
|
-
logger.warn('DEPRECATION NOTICE: [dotenvx vault encrypt] moved to [dotenvx ext vault encrypt]')
|
|
30
|
-
|
|
31
|
-
encryptAction.apply(this, args)
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
// dotenvx vault decrypt
|
|
35
|
-
const decryptAction = require('./../actions/ext/vault/decrypt')
|
|
36
|
-
vault.command('decrypt')
|
|
37
|
-
.description('DEPRECATED: moved to [dotenvx ext vault decrypt]')
|
|
38
|
-
.argument('[directory]', 'directory to decrypt', '.')
|
|
39
|
-
.option('-e, --environment <environments...>', 'environment(s) to decrypt')
|
|
40
|
-
.action(function (...args) {
|
|
41
|
-
logger.warn('DEPRECATION NOTICE: [dotenvx vault decrypt] moved to [dotenvx ext vault decrypt]')
|
|
42
|
-
|
|
43
|
-
decryptAction.apply(this, args)
|
|
44
|
-
})
|
|
45
|
-
|
|
46
|
-
// dotenvx vault status
|
|
47
|
-
const statusAction = require('./../actions/ext/vault/status')
|
|
48
|
-
vault.command('status')
|
|
49
|
-
.description('DEPRECATED: moved to [dotenvx ext vault status]')
|
|
50
|
-
.argument('[directory]', 'directory to check status against', '.')
|
|
51
|
-
.action(function (...args) {
|
|
52
|
-
logger.warn('DEPRECATION NOTICE: [dotenvx vault status] moved to [dotenvx ext vault status]')
|
|
53
|
-
|
|
54
|
-
statusAction.apply(this, args)
|
|
55
|
-
})
|
|
56
|
-
|
|
57
|
-
module.exports = vault
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
const path = require('path')
|
|
3
|
-
const execa = require('execa')
|
|
4
|
-
|
|
5
|
-
const xsel = 'xsel'
|
|
6
|
-
const xselFallback = path.join(__dirname, './fallbacks/linux/xsel')
|
|
7
|
-
|
|
8
|
-
const copyArguments = ['--clipboard', '--input']
|
|
9
|
-
const pasteArguments = ['--clipboard', '--output']
|
|
10
|
-
|
|
11
|
-
const makeError = (xselError, fallbackError) => {
|
|
12
|
-
let error
|
|
13
|
-
if (xselError.code === 'ENOENT') {
|
|
14
|
-
error = new Error('Couldn\'t find the `xsel` binary and fallback didn\'t work. On Debian/Ubuntu you can install xsel with: sudo apt install xsel')
|
|
15
|
-
} else {
|
|
16
|
-
error = new Error('Both xsel and fallback failed')
|
|
17
|
-
error.xselError = xselError
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
error.fallbackError = fallbackError
|
|
21
|
-
return error
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const xselWithFallback = async (argumentList, options) => {
|
|
25
|
-
try {
|
|
26
|
-
return await execa.stdout(xsel, argumentList, options)
|
|
27
|
-
} catch (xselError) {
|
|
28
|
-
try {
|
|
29
|
-
return await execa.stdout(xselFallback, argumentList, options)
|
|
30
|
-
} catch (fallbackError) {
|
|
31
|
-
throw makeError(xselError, fallbackError)
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const xselWithFallbackSync = (argumentList, options) => {
|
|
37
|
-
try {
|
|
38
|
-
return execa.sync(xsel, argumentList, options)
|
|
39
|
-
} catch (xselError) {
|
|
40
|
-
try {
|
|
41
|
-
return execa.sync(xselFallback, argumentList, options)
|
|
42
|
-
} catch (fallbackError) {
|
|
43
|
-
throw makeError(xselError, fallbackError)
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
module.exports = {
|
|
49
|
-
copy: async options => {
|
|
50
|
-
await xselWithFallback(copyArguments, options)
|
|
51
|
-
},
|
|
52
|
-
copySync: options => {
|
|
53
|
-
xselWithFallbackSync(copyArguments, options)
|
|
54
|
-
},
|
|
55
|
-
paste: options => xselWithFallback(pasteArguments, options),
|
|
56
|
-
pasteSync: options => xselWithFallbackSync(pasteArguments, options)
|
|
57
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
const execa = require('execa')
|
|
3
|
-
|
|
4
|
-
const env = {
|
|
5
|
-
...process.env,
|
|
6
|
-
LC_CTYPE: 'UTF-8'
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
module.exports = {
|
|
10
|
-
copy: async options => execa('pbcopy', { ...options, env }),
|
|
11
|
-
paste: async options => execa.stdout('pbpaste', { ...options, env }),
|
|
12
|
-
copySync: options => execa.sync('pbcopy', { ...options, env }),
|
|
13
|
-
pasteSync: options => execa.sync('pbpaste', { ...options, env })
|
|
14
|
-
}
|