@dotenvx/dotenvx 1.59.1 → 1.60.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 (52) hide show
  1. package/CHANGELOG.md +18 -1
  2. package/README.md +14 -4
  3. package/package.json +7 -6
  4. package/src/cli/actions/decrypt.js +15 -8
  5. package/src/cli/actions/encrypt.js +22 -17
  6. package/src/cli/actions/ext/genexample.js +2 -2
  7. package/src/cli/actions/ext/gitignore.js +3 -3
  8. package/src/cli/actions/get.js +12 -7
  9. package/src/cli/actions/keypair.js +13 -5
  10. package/src/cli/actions/rotate.js +26 -14
  11. package/src/cli/actions/run.js +13 -6
  12. package/src/cli/actions/set.js +31 -17
  13. package/src/cli/dotenvx.js +19 -21
  14. package/src/cli/examples.js +1 -1
  15. package/src/db/session.js +10 -6
  16. package/src/lib/extensions/ops.js +112 -63
  17. package/src/lib/helpers/catchAndLog.js +1 -1
  18. package/src/lib/helpers/createSpinner.js +24 -0
  19. package/src/lib/helpers/cryptography/index.js +4 -0
  20. package/src/lib/helpers/cryptography/mutateKeysSrc.js +4 -4
  21. package/src/lib/helpers/cryptography/mutateKeysSrcSync.js +38 -0
  22. package/src/lib/helpers/cryptography/opsKeypair.js +2 -2
  23. package/src/lib/helpers/cryptography/opsKeypairSync.js +14 -0
  24. package/src/lib/helpers/cryptography/provision.js +15 -11
  25. package/src/lib/helpers/cryptography/provisionSync.js +51 -0
  26. package/src/lib/helpers/cryptography/provisionWithPrivateKey.js +1 -1
  27. package/src/lib/helpers/detectEncoding.js +2 -2
  28. package/src/lib/helpers/detectEncodingSync.js +22 -0
  29. package/src/lib/helpers/errors.js +15 -0
  30. package/src/lib/helpers/fsx.js +27 -3
  31. package/src/lib/helpers/installPrecommitHook.js +2 -2
  32. package/src/lib/helpers/isIgnoringDotenvKeys.js +1 -1
  33. package/src/lib/helpers/keyResolution/index.js +3 -1
  34. package/src/lib/helpers/keyResolution/keyValues.js +12 -12
  35. package/src/lib/helpers/keyResolution/keyValuesSync.js +85 -0
  36. package/src/lib/helpers/keyResolution/readFileKey.js +10 -8
  37. package/src/lib/helpers/keyResolution/readFileKeySync.js +15 -0
  38. package/src/lib/helpers/kits/sample.js +9 -21
  39. package/src/lib/main.d.ts +20 -4
  40. package/src/lib/main.js +30 -22
  41. package/src/lib/services/decrypt.js +8 -8
  42. package/src/lib/services/encrypt.js +19 -12
  43. package/src/lib/services/genexample.js +2 -2
  44. package/src/lib/services/get.js +30 -21
  45. package/src/lib/services/keypair.js +21 -5
  46. package/src/lib/services/prebuild.js +7 -12
  47. package/src/lib/services/precommit.js +7 -11
  48. package/src/lib/services/rotate.js +26 -20
  49. package/src/lib/services/run.js +82 -9
  50. package/src/lib/services/sets.js +142 -13
  51. package/src/shared/logger.js +3 -3
  52. package/src/lib/helpers/sleep.js +0 -5
@@ -11,7 +11,8 @@ const {
11
11
 
12
12
  const {
13
13
  keyNames,
14
- keyValues
14
+ keyValues,
15
+ keyValuesSync
15
16
  } = require('./../helpers/keyResolution')
16
17
 
17
18
  const {
@@ -19,21 +20,23 @@ const {
19
20
  decryptKeyValue,
20
21
  isEncrypted,
21
22
  provision,
23
+ provisionSync,
22
24
  provisionWithPrivateKey
23
25
  } = require('./../helpers/cryptography')
24
26
 
25
27
  const replace = require('./../helpers/replace')
26
28
  const dotenvParse = require('./../helpers/dotenvParse')
27
29
  const detectEncoding = require('./../helpers/detectEncoding')
30
+ const detectEncodingSync = require('./../helpers/detectEncodingSync')
28
31
 
29
32
  class Sets {
30
- constructor (key, value, envs = [], encrypt = true, envKeysFilepath = null, opsOn = false, noCreate = false) {
33
+ constructor (key, value, envs = [], encrypt = true, envKeysFilepath = null, noOps = false, noCreate = false) {
31
34
  this.envs = determine(envs, process.env)
32
35
  this.key = key
33
36
  this.value = value
34
37
  this.encrypt = encrypt
35
38
  this.envKeysFilepath = envKeysFilepath
36
- this.opsOn = opsOn
39
+ this.noOps = noOps
37
40
  this.noCreate = noCreate
38
41
 
39
42
  this.processedEnvs = []
@@ -42,7 +45,7 @@ class Sets {
42
45
  this.readableFilepaths = new Set()
43
46
  }
44
47
 
45
- run () {
48
+ runSync () {
46
49
  // example
47
50
  // envs [
48
51
  // { type: 'envFile', value: '.env' }
@@ -50,7 +53,7 @@ class Sets {
50
53
 
51
54
  for (const env of this.envs) {
52
55
  if (env.type === TYPE_ENV_FILE) {
53
- this._setEnvFile(env.value)
56
+ this._setEnvFileSync(env.value)
54
57
  }
55
58
  }
56
59
 
@@ -61,7 +64,26 @@ class Sets {
61
64
  }
62
65
  }
63
66
 
64
- _setEnvFile (envFilepath) {
67
+ async run () {
68
+ // example
69
+ // envs [
70
+ // { type: 'envFile', value: '.env' }
71
+ // ]
72
+
73
+ for (const env of this.envs) {
74
+ if (env.type === TYPE_ENV_FILE) {
75
+ await this._setEnvFile(env.value)
76
+ }
77
+ }
78
+
79
+ return {
80
+ processedEnvs: this.processedEnvs,
81
+ changedFilepaths: [...this.changedFilepaths],
82
+ unchangedFilepaths: [...this.unchangedFilepaths]
83
+ }
84
+ }
85
+
86
+ _setEnvFileSync (envFilepath) {
65
87
  const row = {}
66
88
  row.key = this.key || null
67
89
  row.value = this.value || null
@@ -77,14 +99,120 @@ class Sets {
77
99
 
78
100
  if (!fsx.existsSync(filepath)) {
79
101
  if (this.noCreate) {
80
- detectEncoding(filepath) // throws ENOENT
102
+ detectEncodingSync(filepath) // throws ENOENT
103
+ } else {
104
+ fsx.writeFileXSync(filepath, '')
105
+ }
106
+ }
107
+
108
+ const encoding = detectEncodingSync(filepath)
109
+ let envSrc = fsx.readFileXSync(filepath, { encoding })
110
+
111
+ // blank files seeded by `set` should contain only the key being set
112
+ if (row.key && envSrc.trim().length === 0) {
113
+ envSrc = `${row.key}="${this.value}"\n`
114
+ seededWithInitialKey = true
115
+ }
116
+
117
+ const envParsed = dotenvParse(envSrc)
118
+ row.originalValue = envParsed[row.key] || null
119
+ if (seededWithInitialKey) {
120
+ row.originalValue = null
121
+ }
122
+ const wasPlainText = !isEncrypted(row.originalValue)
123
+ this.readableFilepaths.add(envFilepath)
124
+
125
+ if (this.encrypt) {
126
+ let publicKey
127
+ let privateKey
128
+
129
+ const { publicKeyName, privateKeyName } = keyNames(filepath)
130
+ const { publicKeyValue, privateKeyValue } = keyValuesSync(filepath, { keysFilepath: this.envKeysFilepath, noOps: this.noOps })
131
+
132
+ // first pass - provisionSync
133
+ if (!privateKeyValue && !publicKeyValue) {
134
+ const prov = provisionSync({ envSrc, envFilepath, keysFilepath: this.envKeysFilepath, noOps: this.noOps })
135
+ envSrc = prov.envSrc
136
+ publicKey = prov.publicKey
137
+ privateKey = prov.privateKey
138
+ row.envKeysFilepath = prov.envKeysFilepath
139
+ row.localPrivateKeyAdded = prov.localPrivateKeyAdded
140
+ row.remotePrivateKeyAdded = prov.remotePrivateKeyAdded
141
+ } else if (privateKeyValue) {
142
+ const prov = provisionWithPrivateKey({ envSrc, envFilepath, keysFilepath: this.envKeysFilepath, privateKeyValue, publicKeyValue, publicKeyName })
143
+ publicKey = prov.publicKey
144
+ privateKey = prov.privateKey
145
+ envSrc = prov.envSrc
146
+
147
+ if (row.originalValue) {
148
+ row.originalValue = decryptKeyValue(row.key, row.originalValue, privateKeyName, privateKey)
149
+ }
150
+ } else if (publicKeyValue) {
151
+ publicKey = publicKeyValue
152
+ }
153
+
154
+ row.publicKey = publicKey
155
+ row.privateKey = privateKey
156
+ try {
157
+ row.encryptedValue = encryptValue(this.value, publicKey)
158
+ } catch {
159
+ throw new Errors({ publicKeyName, publicKey }).invalidPublicKey()
160
+ }
161
+ row.privateKeyName = privateKeyName
162
+ }
163
+
164
+ const goingFromPlainTextToEncrypted = wasPlainText && this.encrypt
165
+ const valueChanged = this.value !== row.originalValue
166
+ const shouldPersistSeededPlainValue = seededWithInitialKey && !this.encrypt
167
+
168
+ if (shouldPersistSeededPlainValue) {
169
+ row.envSrc = envSrc
170
+ this.changedFilepaths.add(envFilepath)
171
+ row.changed = true
172
+ } else if (goingFromPlainTextToEncrypted || valueChanged) {
173
+ row.envSrc = replace(envSrc, this.key, row.encryptedValue || this.value)
174
+ this.changedFilepaths.add(envFilepath)
175
+ row.changed = true
176
+ } else {
177
+ row.envSrc = envSrc
178
+ this.unchangedFilepaths.add(envFilepath)
179
+ row.changed = false
180
+ }
181
+ } catch (e) {
182
+ if (e.code === 'ENOENT') {
183
+ row.error = new Errors({ envFilepath, filepath }).missingEnvFile()
184
+ } else {
185
+ row.error = e
186
+ }
187
+ }
188
+
189
+ this.processedEnvs.push(row)
190
+ }
191
+
192
+ async _setEnvFile (envFilepath) {
193
+ const row = {}
194
+ row.key = this.key || null
195
+ row.value = this.value || null
196
+ row.type = TYPE_ENV_FILE
197
+
198
+ const filepath = path.resolve(envFilepath)
199
+ row.filepath = filepath
200
+ row.envFilepath = envFilepath
201
+ row.changed = false
202
+
203
+ try {
204
+ let seededWithInitialKey = false
205
+
206
+ if (!(await fsx.exists(filepath))) {
207
+ if (this.noCreate) {
208
+ await detectEncoding(filepath) // throws ENOENT
81
209
  } else {
82
- fsx.writeFileX(filepath, '')
210
+ await fsx.writeFileX(filepath, '')
83
211
  }
84
212
  }
85
213
 
86
- const encoding = detectEncoding(filepath)
87
- let envSrc = fsx.readFileX(filepath, { encoding })
214
+ const encoding = await detectEncoding(filepath)
215
+ let envSrc = await fsx.readFileX(filepath, { encoding })
88
216
 
89
217
  // blank files seeded by `set` should contain only the key being set
90
218
  if (row.key && envSrc.trim().length === 0) {
@@ -105,16 +233,17 @@ class Sets {
105
233
  let privateKey
106
234
 
107
235
  const { publicKeyName, privateKeyName } = keyNames(filepath)
108
- const { publicKeyValue, privateKeyValue } = keyValues(filepath, { keysFilepath: this.envKeysFilepath, opsOn: this.opsOn })
236
+ const { publicKeyValue, privateKeyValue } = await keyValues(filepath, { keysFilepath: this.envKeysFilepath, noOps: this.noOps })
109
237
 
110
238
  // first pass - provision
111
239
  if (!privateKeyValue && !publicKeyValue) {
112
- const prov = provision({ envSrc, envFilepath, keysFilepath: this.envKeysFilepath, opsOn: this.opsOn })
240
+ const prov = await provision({ envSrc, envFilepath, keysFilepath: this.envKeysFilepath, noOps: this.noOps })
113
241
  envSrc = prov.envSrc
114
242
  publicKey = prov.publicKey
115
243
  privateKey = prov.privateKey
116
- row.privateKeyAdded = prov.privateKeyAdded
117
244
  row.envKeysFilepath = prov.envKeysFilepath
245
+ row.localPrivateKeyAdded = prov.localPrivateKeyAdded
246
+ row.remotePrivateKeyAdded = prov.remotePrivateKeyAdded
118
247
  } else if (privateKeyValue) {
119
248
  const prov = provisionWithPrivateKey({ envSrc, envFilepath, keysFilepath: this.envKeysFilepath, privateKeyValue, publicKeyValue, publicKeyName })
120
249
  publicKey = prov.publicKey
@@ -20,8 +20,8 @@ const success = getColor('amber')
20
20
  const successv = (m) => getColor('amber')(`⟐ ${m}`)
21
21
  const info = getColor('gray')
22
22
  const help = getColor('dodgerblue')
23
- const verbose = getColor('plum')
24
- const debug = getColor('plum')
23
+ const verbose = (m) => getColor('plum')(`┆ ${m}`)
24
+ const debug = (m) => getColor('plum')(`┆ ${m}`)
25
25
 
26
26
  let currentLevel = levels.info // default log level
27
27
  let currentName = 'dotenvx' // default logger name
@@ -121,7 +121,7 @@ function setLogLevel (options) {
121
121
  logger.setLevel(logLevel)
122
122
  // Only log which level it's setting if it's not set to quiet mode
123
123
  if (!options.quiet || (options.quiet && logLevel !== 'error')) {
124
- logger.debug(`Setting log level to ${logLevel}`)
124
+ logger.debug(`setting log level to: ${logLevel}`)
125
125
  }
126
126
  }
127
127
 
@@ -1,5 +0,0 @@
1
- function sleep (ms) {
2
- return new Promise(resolve => setTimeout(resolve, ms))
3
- }
4
-
5
- module.exports = sleep