@dotenvx/dotenvx 1.75.1 → 2.1.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 +39 -1
- package/README.md +4 -114
- package/package.json +8 -7
- package/src/cli/actions/decrypt.js +35 -17
- package/src/cli/actions/doctor.js +2 -2
- package/src/cli/actions/encrypt.js +64 -85
- package/src/cli/actions/ext/genexample.js +2 -2
- package/src/cli/actions/get.js +22 -7
- package/src/cli/actions/keypair.js +55 -42
- package/src/cli/actions/login.js +4 -3
- package/src/cli/actions/normalizeArmorAliases.js +9 -0
- package/src/cli/actions/run.js +65 -22
- package/src/cli/actions/set.js +87 -37
- package/src/cli/dotenvx.js +8 -23
- package/src/lib/api/{postKeypair.js → postArmorKeyring.js} +4 -14
- package/src/lib/{helpers/envResolution → conventions}/environment.js +1 -1
- package/src/lib/conventions/filepaths.js +9 -0
- package/src/lib/conventions/keynames.js +38 -0
- package/src/lib/helpers/catchAndLog.js +4 -1
- package/src/lib/helpers/cryptography/index.js +2 -9
- package/src/lib/helpers/cryptography/{isPublicKey.js → isDotenvPublicKey.js} +2 -2
- package/src/lib/helpers/cryptography/isPlainKey.js +7 -0
- package/src/lib/helpers/cryptography/mutateKeysSrc.js +5 -21
- package/src/lib/helpers/envResolution/index.js +1 -1
- package/src/lib/helpers/errors.js +26 -0
- package/src/lib/helpers/keypairMetadata.js +1 -1
- package/src/lib/helpers/prompts.js +46 -0
- package/src/lib/main.d.ts +2 -39
- package/src/lib/main.js +83 -46
- package/src/lib/providers/armor/index.js +29 -0
- package/src/lib/providers/index.js +46 -0
- package/src/lib/providers/worker.js +6 -0
- package/src/lib/resolvers/envs.js +302 -0
- package/src/lib/resolvers/get.js +69 -0
- package/src/lib/resolvers/keypair.js +81 -0
- package/src/lib/resolvers/ls.js +41 -0
- package/src/lib/services/armorDown.js +2 -2
- package/src/lib/services/{armorKeypair.js → armorKeyring.js} +14 -51
- package/src/lib/services/armorMove.js +2 -2
- package/src/lib/services/armorPull.js +2 -2
- package/src/lib/services/armorPush.js +2 -2
- package/src/lib/services/armorUp.js +2 -2
- package/src/lib/services/genexample.js +5 -6
- package/src/lib/services/login.js +25 -0
- package/src/lib/services/prebuild.js +9 -3
- package/src/lib/services/precommit.js +9 -3
- package/src/lib/transforms/decrypt.js +83 -0
- package/src/lib/transforms/encrypt.js +178 -0
- package/src/lib/transforms/set.js +179 -0
- package/src/shared/logger.js +5 -0
- package/src/cli/actions/normalizeArmorOptions.js +0 -10
- package/src/cli/actions/rotate.js +0 -87
- package/src/lib/helpers/append.js +0 -62
- package/src/lib/helpers/cryptography/armorKeypair.js +0 -42
- package/src/lib/helpers/cryptography/armorKeypairSync.js +0 -55
- package/src/lib/helpers/cryptography/encryptValue.js +0 -7
- package/src/lib/helpers/cryptography/localKeypair.js +0 -14
- package/src/lib/helpers/cryptography/mutateKeysSrcSync.js +0 -38
- package/src/lib/helpers/cryptography/provision.js +0 -56
- package/src/lib/helpers/cryptography/provisionSync.js +0 -51
- package/src/lib/helpers/cryptography/provisionWithPrivateKey.js +0 -26
- package/src/lib/helpers/escapeDollarSigns.js +0 -5
- package/src/lib/helpers/escapeForRegex.js +0 -5
- package/src/lib/helpers/evalKeyValue.js +0 -23
- package/src/lib/helpers/isIgnoringDotenvKeys.js +0 -19
- package/src/lib/helpers/keyResolution/index.js +0 -16
- package/src/lib/helpers/keyResolution/keyNamesForEnvFile.js +0 -24
- package/src/lib/helpers/keyResolution/keyValues.js +0 -99
- package/src/lib/helpers/keyResolution/keyValuesFromEnvSrc.js +0 -85
- package/src/lib/helpers/keyResolution/keyValuesSync.js +0 -103
- package/src/lib/helpers/keyResolution/readFileKey.js +0 -19
- package/src/lib/helpers/keyResolution/readFileKeySync.js +0 -17
- package/src/lib/helpers/keyResolution/readProcessKey.js +0 -7
- package/src/lib/helpers/localDisplayPath.js +0 -11
- package/src/lib/helpers/parse.js +0 -214
- package/src/lib/helpers/pluralize.js +0 -10
- package/src/lib/helpers/quotes.js +0 -36
- package/src/lib/helpers/replace.js +0 -82
- package/src/lib/helpers/resolveEscapeSequences.js +0 -5
- package/src/lib/services/decrypt.js +0 -156
- package/src/lib/services/encrypt.js +0 -213
- package/src/lib/services/get.js +0 -76
- package/src/lib/services/keypair.js +0 -60
- package/src/lib/services/loginPoll.js +0 -36
- package/src/lib/services/ls.js +0 -57
- package/src/lib/services/rotate.js +0 -197
- package/src/lib/services/run.js +0 -255
- package/src/lib/services/sets.js +0 -328
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
const fsx = require('./../helpers/fsx')
|
|
2
|
+
const path = require('path')
|
|
3
|
+
const { encrypted, parse, parseSync } = require('@dotenvx/primitives')
|
|
4
|
+
|
|
5
|
+
const TYPE_ENV = 'env'
|
|
6
|
+
const TYPE_ENV_FILE = 'envFile'
|
|
7
|
+
|
|
8
|
+
const Errors = require('./../helpers/errors')
|
|
9
|
+
const detectEncoding = require('./../helpers/detectEncoding')
|
|
10
|
+
const detectEncodingSync = require('./../helpers/detectEncodingSync')
|
|
11
|
+
const keynames = require('./../conventions/keynames')
|
|
12
|
+
const providers = require('./../providers')
|
|
13
|
+
|
|
14
|
+
function unresolvedEncryptedErrors (parsed) {
|
|
15
|
+
const keys = []
|
|
16
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
17
|
+
if (encrypted(value)) {
|
|
18
|
+
keys.push(key)
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (keys.length < 1) {
|
|
23
|
+
return []
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return [new Errors({ message: `could not decrypt ${keys.join(', ')}` }).decryptionFailed()]
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function decryptErrors (parsed, errors) {
|
|
30
|
+
const mappedErrors = (errors || []).map(error => {
|
|
31
|
+
return new Errors({
|
|
32
|
+
code: error.code,
|
|
33
|
+
message: error.message,
|
|
34
|
+
help: error.help
|
|
35
|
+
}).custom()
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
if (mappedErrors.length > 0) {
|
|
39
|
+
return mappedErrors
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return unresolvedEncryptedErrors(parsed)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function inject (processEnv, parsed) {
|
|
46
|
+
for (const key of Object.keys(parsed)) {
|
|
47
|
+
processEnv[key] = parsed[key]
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function buildParseOptions ({ processEnv, overload, envKeysFilepath, provider }) {
|
|
52
|
+
const options = {
|
|
53
|
+
processEnv,
|
|
54
|
+
overload,
|
|
55
|
+
fk: envKeysFilepath
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (provider) {
|
|
59
|
+
options.provider = provider
|
|
60
|
+
} else {
|
|
61
|
+
options.provider = null
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return options
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async function injectEnv ({ env, overload, processEnv, envKeysFilepath, provider }) {
|
|
68
|
+
const row = {}
|
|
69
|
+
row.type = TYPE_ENV
|
|
70
|
+
row.string = env.value
|
|
71
|
+
|
|
72
|
+
try {
|
|
73
|
+
const parseProcessEnv = { ...processEnv }
|
|
74
|
+
if (env.privateKeyName && Object.prototype.hasOwnProperty.call(processEnv, env.privateKeyName)) {
|
|
75
|
+
parseProcessEnv[env.privateKeyName] = processEnv[env.privateKeyName]
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const parseOptions = buildParseOptions({
|
|
79
|
+
processEnv: parseProcessEnv,
|
|
80
|
+
overload,
|
|
81
|
+
envKeysFilepath,
|
|
82
|
+
provider
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
const {
|
|
86
|
+
parsed,
|
|
87
|
+
errors,
|
|
88
|
+
injected,
|
|
89
|
+
existed
|
|
90
|
+
} = await parse(env.value, parseOptions)
|
|
91
|
+
|
|
92
|
+
row.parsed = parsed
|
|
93
|
+
row.errors = decryptErrors(parsed, errors)
|
|
94
|
+
row.injected = injected || {}
|
|
95
|
+
row.existed = existed || {}
|
|
96
|
+
|
|
97
|
+
inject(processEnv, row.parsed)
|
|
98
|
+
} catch (e) {
|
|
99
|
+
row.errors = [e]
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return row
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function injectEnvSync ({ env, overload, processEnv, envKeysFilepath, provider }) {
|
|
106
|
+
const row = {}
|
|
107
|
+
row.type = TYPE_ENV
|
|
108
|
+
row.string = env.value
|
|
109
|
+
|
|
110
|
+
try {
|
|
111
|
+
const parseProcessEnv = { ...processEnv }
|
|
112
|
+
if (env.privateKeyName && Object.prototype.hasOwnProperty.call(processEnv, env.privateKeyName)) {
|
|
113
|
+
parseProcessEnv[env.privateKeyName] = processEnv[env.privateKeyName]
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const parseOptions = buildParseOptions({
|
|
117
|
+
processEnv: parseProcessEnv,
|
|
118
|
+
overload,
|
|
119
|
+
envKeysFilepath,
|
|
120
|
+
provider
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
const {
|
|
124
|
+
parsed,
|
|
125
|
+
errors,
|
|
126
|
+
injected,
|
|
127
|
+
existed
|
|
128
|
+
} = parseSync(env.value, parseOptions)
|
|
129
|
+
|
|
130
|
+
row.parsed = parsed
|
|
131
|
+
row.errors = decryptErrors(parsed, errors)
|
|
132
|
+
row.injected = injected || {}
|
|
133
|
+
row.existed = existed || {}
|
|
134
|
+
|
|
135
|
+
inject(processEnv, row.parsed)
|
|
136
|
+
} catch (e) {
|
|
137
|
+
row.errors = [e]
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return row
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
async function injectEnvFile ({ env, overload, processEnv, envKeysFilepath, provider, readableFilepaths }) {
|
|
144
|
+
const row = {}
|
|
145
|
+
row.type = TYPE_ENV_FILE
|
|
146
|
+
row.filepath = env.value
|
|
147
|
+
|
|
148
|
+
const filepath = path.resolve(env.value)
|
|
149
|
+
try {
|
|
150
|
+
const encoding = await detectEncoding(filepath)
|
|
151
|
+
const src = await fsx.readFileX(filepath, { encoding })
|
|
152
|
+
readableFilepaths.add(env.value)
|
|
153
|
+
|
|
154
|
+
const { privateKeyName } = keynames(filepath)
|
|
155
|
+
const fk = envKeysFilepath || (processEnv[privateKeyName] ? null : path.resolve(path.dirname(filepath), '.env.keys'))
|
|
156
|
+
const parseOptions = buildParseOptions({
|
|
157
|
+
processEnv,
|
|
158
|
+
overload,
|
|
159
|
+
envKeysFilepath: fk,
|
|
160
|
+
provider
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
const {
|
|
164
|
+
parsed,
|
|
165
|
+
errors,
|
|
166
|
+
injected,
|
|
167
|
+
existed
|
|
168
|
+
} = await parse(src, parseOptions)
|
|
169
|
+
|
|
170
|
+
row.src = src
|
|
171
|
+
row.parsed = parsed
|
|
172
|
+
row.injected = injected || {}
|
|
173
|
+
row.errors = decryptErrors(parsed, errors)
|
|
174
|
+
row.existed = existed || {}
|
|
175
|
+
|
|
176
|
+
inject(processEnv, parsed)
|
|
177
|
+
} catch (e) {
|
|
178
|
+
if (e.code === 'ENOENT' || e.code === 'EISDIR') {
|
|
179
|
+
row.errors = [new Errors({ envFilepath: env.value, filepath }).missingEnvFile()]
|
|
180
|
+
} else {
|
|
181
|
+
row.errors = [e]
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return row
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function injectEnvFileSync ({ env, overload, processEnv, envKeysFilepath, provider, readableFilepaths }) {
|
|
189
|
+
const row = {}
|
|
190
|
+
row.type = TYPE_ENV_FILE
|
|
191
|
+
row.filepath = env.value
|
|
192
|
+
|
|
193
|
+
const filepath = path.resolve(env.value)
|
|
194
|
+
try {
|
|
195
|
+
const encoding = detectEncodingSync(filepath)
|
|
196
|
+
const src = fsx.readFileXSync(filepath, { encoding })
|
|
197
|
+
readableFilepaths.add(env.value)
|
|
198
|
+
|
|
199
|
+
const { privateKeyName } = keynames(filepath)
|
|
200
|
+
const fk = envKeysFilepath || (processEnv[privateKeyName] ? null : path.resolve(path.dirname(filepath), '.env.keys'))
|
|
201
|
+
const parseOptions = buildParseOptions({
|
|
202
|
+
processEnv,
|
|
203
|
+
overload,
|
|
204
|
+
envKeysFilepath: fk,
|
|
205
|
+
provider
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
const {
|
|
209
|
+
parsed,
|
|
210
|
+
errors,
|
|
211
|
+
injected,
|
|
212
|
+
existed
|
|
213
|
+
} = parseSync(src, parseOptions)
|
|
214
|
+
|
|
215
|
+
row.src = src
|
|
216
|
+
row.parsed = parsed
|
|
217
|
+
row.injected = injected || {}
|
|
218
|
+
row.errors = decryptErrors(parsed, errors)
|
|
219
|
+
row.existed = existed || {}
|
|
220
|
+
|
|
221
|
+
inject(processEnv, parsed)
|
|
222
|
+
} catch (e) {
|
|
223
|
+
if (e.code === 'ENOENT' || e.code === 'EISDIR') {
|
|
224
|
+
row.errors = [new Errors({ envFilepath: env.value, filepath }).missingEnvFile()]
|
|
225
|
+
} else {
|
|
226
|
+
row.errors = [e]
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
return row
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
async function envs (options = {}) {
|
|
234
|
+
const processedEnvs = []
|
|
235
|
+
const readableFilepaths = new Set()
|
|
236
|
+
const processEnv = options.processEnv || process.env
|
|
237
|
+
const envKeysFilepath = options.envKeysFilepath || options.envKeysFile || null
|
|
238
|
+
const provider = options.noArmor ? null : await providers(options)
|
|
239
|
+
|
|
240
|
+
for (const env of options.envs || []) {
|
|
241
|
+
if (env.type === TYPE_ENV_FILE) {
|
|
242
|
+
processedEnvs.push(await injectEnvFile({
|
|
243
|
+
env,
|
|
244
|
+
overload: options.overload,
|
|
245
|
+
processEnv,
|
|
246
|
+
envKeysFilepath,
|
|
247
|
+
provider,
|
|
248
|
+
readableFilepaths
|
|
249
|
+
}))
|
|
250
|
+
} else if (env.type === TYPE_ENV) {
|
|
251
|
+
processedEnvs.push(await injectEnv({
|
|
252
|
+
env,
|
|
253
|
+
overload: options.overload,
|
|
254
|
+
processEnv,
|
|
255
|
+
envKeysFilepath,
|
|
256
|
+
provider
|
|
257
|
+
}))
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return {
|
|
262
|
+
processedEnvs,
|
|
263
|
+
readableFilepaths: [...readableFilepaths]
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
function envsSync (options = {}) {
|
|
268
|
+
const processedEnvs = []
|
|
269
|
+
const readableFilepaths = new Set()
|
|
270
|
+
const processEnv = options.processEnv || process.env
|
|
271
|
+
const envKeysFilepath = options.envKeysFilepath || options.envKeysFile || null
|
|
272
|
+
const provider = options.noArmor ? null : providers.sync(options)
|
|
273
|
+
|
|
274
|
+
for (const env of options.envs || []) {
|
|
275
|
+
if (env.type === TYPE_ENV_FILE) {
|
|
276
|
+
processedEnvs.push(injectEnvFileSync({
|
|
277
|
+
env,
|
|
278
|
+
overload: options.overload,
|
|
279
|
+
processEnv,
|
|
280
|
+
envKeysFilepath,
|
|
281
|
+
provider,
|
|
282
|
+
readableFilepaths
|
|
283
|
+
}))
|
|
284
|
+
} else if (env.type === TYPE_ENV) {
|
|
285
|
+
processedEnvs.push(injectEnvSync({
|
|
286
|
+
env,
|
|
287
|
+
overload: options.overload,
|
|
288
|
+
processEnv,
|
|
289
|
+
envKeysFilepath,
|
|
290
|
+
provider
|
|
291
|
+
}))
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
return {
|
|
296
|
+
processedEnvs,
|
|
297
|
+
readableFilepaths: [...readableFilepaths]
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
module.exports = envs
|
|
302
|
+
module.exports.sync = envsSync
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
const envsResolver = require('./envs')
|
|
2
|
+
const Errors = require('./../helpers/errors')
|
|
3
|
+
const { determine } = require('./../helpers/envResolution')
|
|
4
|
+
|
|
5
|
+
function collectErrors (processedEnvs) {
|
|
6
|
+
const errors = []
|
|
7
|
+
for (const processedEnv of processedEnvs) {
|
|
8
|
+
for (const error of processedEnv.errors || []) {
|
|
9
|
+
errors.push(error)
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
return errors
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function result ({ key, all, processedEnvs, processEnv }) {
|
|
16
|
+
const errors = collectErrors(processedEnvs)
|
|
17
|
+
|
|
18
|
+
if (key) {
|
|
19
|
+
const parsed = {}
|
|
20
|
+
const value = processEnv[key]
|
|
21
|
+
parsed[key] = value
|
|
22
|
+
|
|
23
|
+
if (value === undefined) {
|
|
24
|
+
errors.push(new Errors({ key }).missingKey())
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return { parsed, errors }
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (all) {
|
|
31
|
+
return { parsed: processEnv, errors }
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const parsed = {}
|
|
35
|
+
for (const processedEnv of processedEnvs) {
|
|
36
|
+
if (processedEnv.parsed) {
|
|
37
|
+
for (const key of Object.keys(processedEnv.parsed)) {
|
|
38
|
+
parsed[key] = processEnv[key]
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return { parsed, errors }
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function buildOptions (options, processEnv) {
|
|
47
|
+
return {
|
|
48
|
+
envs: determine(options.envs || [], processEnv),
|
|
49
|
+
overload: options.overload,
|
|
50
|
+
processEnv,
|
|
51
|
+
envKeysFilepath: options.envKeysFilepath || options.envKeysFile || null,
|
|
52
|
+
noArmor: options.noArmor,
|
|
53
|
+
onStatus: options.onStatus
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function get (options = {}) {
|
|
58
|
+
const processEnv = { ...(options.processEnv || process.env) }
|
|
59
|
+
const { processedEnvs } = await envsResolver(buildOptions(options, processEnv))
|
|
60
|
+
|
|
61
|
+
return result({
|
|
62
|
+
key: options.key,
|
|
63
|
+
all: options.all,
|
|
64
|
+
processedEnvs,
|
|
65
|
+
processEnv
|
|
66
|
+
})
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
module.exports = get
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
const fsx = require('./../helpers/fsx')
|
|
2
|
+
const path = require('path')
|
|
3
|
+
const keynames = require('./../conventions/keynames')
|
|
4
|
+
const filepaths = require('./../conventions/filepaths')
|
|
5
|
+
|
|
6
|
+
const { keyring, keyringSync, publickeys } = require('@dotenvx/primitives')
|
|
7
|
+
const providers = require('./../providers')
|
|
8
|
+
|
|
9
|
+
function buildOptions ({ publicKey, processEnv, fk }) {
|
|
10
|
+
const ring = {}
|
|
11
|
+
if (publicKey) {
|
|
12
|
+
ring[publicKey] = ''
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const options = {
|
|
16
|
+
processEnv,
|
|
17
|
+
fk,
|
|
18
|
+
ring
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return options
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function outputKeypair ({ out, filepath, publicKey, ring }) {
|
|
25
|
+
const { publicKeyName, privateKeyName } = keynames(filepath)
|
|
26
|
+
|
|
27
|
+
out[publicKeyName] = publicKey || null
|
|
28
|
+
out[privateKeyName] = publicKey ? ring[publicKey] || null : null
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async function keypair (options = {}) {
|
|
32
|
+
const out = {}
|
|
33
|
+
const processEnv = options.processEnv || process.env
|
|
34
|
+
|
|
35
|
+
for (const filepath of filepaths(options.envFile)) {
|
|
36
|
+
const src = await fsx.readFileX(filepath)
|
|
37
|
+
const publicKey = publickeys(src)[0]
|
|
38
|
+
|
|
39
|
+
const keyringOptions = buildOptions({
|
|
40
|
+
publicKey,
|
|
41
|
+
processEnv,
|
|
42
|
+
fk: options.envKeysFilepath || options.envKeysFile || path.resolve(path.dirname(filepath), '.env.keys')
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
const provider = await providers(options)
|
|
46
|
+
keyringOptions.provider = provider
|
|
47
|
+
|
|
48
|
+
const ring = await keyring(keyringOptions)
|
|
49
|
+
|
|
50
|
+
outputKeypair({ out, filepath, publicKey, ring })
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return out
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function keypairSync (options = {}) {
|
|
57
|
+
const out = {}
|
|
58
|
+
const processEnv = options.processEnv || process.env
|
|
59
|
+
|
|
60
|
+
for (const filepath of filepaths(options.envFile)) {
|
|
61
|
+
const src = fsx.readFileXSync(filepath)
|
|
62
|
+
const publicKey = publickeys(src)[0]
|
|
63
|
+
|
|
64
|
+
const keyringOptions = buildOptions({
|
|
65
|
+
publicKey,
|
|
66
|
+
processEnv,
|
|
67
|
+
fk: options.envKeysFilepath || options.envKeysFile || path.resolve(path.dirname(filepath), '.env.keys')
|
|
68
|
+
})
|
|
69
|
+
const provider = providers.sync(options)
|
|
70
|
+
keyringOptions.provider = provider
|
|
71
|
+
|
|
72
|
+
const ring = keyringSync(keyringOptions)
|
|
73
|
+
|
|
74
|
+
outputKeypair({ out, filepath, publicKey, ring })
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return out
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
module.exports = keypair
|
|
81
|
+
module.exports.sync = keypairSync
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
const { fdir: Fdir } = require('fdir')
|
|
2
|
+
const path = require('path')
|
|
3
|
+
const picomatch = require('picomatch')
|
|
4
|
+
|
|
5
|
+
function patternsFor (value) {
|
|
6
|
+
if (!Array.isArray(value)) {
|
|
7
|
+
return [`**/${value}`]
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
return value.map(part => `**/${part}`)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function excludePatternsFor (value) {
|
|
14
|
+
if (!Array.isArray(value)) {
|
|
15
|
+
return [`**/${value}`]
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return value.map(part => `**/${part}`)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function ls (options = {}) {
|
|
22
|
+
const ignore = ['node_modules/**', '**/node_modules/**', '.git/**', '**/.git/**']
|
|
23
|
+
const cwd = path.resolve(options.directory || './')
|
|
24
|
+
const envFile = options.envFile || ['.env*']
|
|
25
|
+
const excludeEnvFile = options.excludeEnvFile || []
|
|
26
|
+
const excludePatterns = excludePatternsFor(excludeEnvFile)
|
|
27
|
+
const excludes = excludePatterns.length > 0 ? ignore.concat(excludePatterns) : ignore
|
|
28
|
+
const exclude = picomatch(excludes, { dot: true })
|
|
29
|
+
const include = picomatch(patternsFor(envFile), {
|
|
30
|
+
dot: true,
|
|
31
|
+
ignore: excludes
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
return new Fdir()
|
|
35
|
+
.withRelativePaths()
|
|
36
|
+
.filter((filepath) => !exclude(filepath) && include(filepath))
|
|
37
|
+
.crawl(cwd)
|
|
38
|
+
.sync()
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
module.exports = ls
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const prompts = require('../helpers/prompts')
|
|
2
2
|
const PostArmorDown = require('../api/postArmorDown')
|
|
3
|
-
const
|
|
3
|
+
const keynames = require('../conventions/keynames')
|
|
4
4
|
const upsertEnvKey = require('../helpers/upsertEnvKey')
|
|
5
5
|
const readEnvKey = require('../helpers/readEnvKey')
|
|
6
6
|
const teamChoicesFromMeta = require('../helpers/teamChoicesFromMeta')
|
|
@@ -24,7 +24,7 @@ class ArmorDown {
|
|
|
24
24
|
const {
|
|
25
25
|
publicKeyName,
|
|
26
26
|
privateKeyName
|
|
27
|
-
} =
|
|
27
|
+
} = keynames(envFile)
|
|
28
28
|
|
|
29
29
|
const publicKey = readEnvKey(publicKeyName, envFile, { strict: true, ignore: ['MISSING_PRIVATE_KEY'] })
|
|
30
30
|
let json
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
const
|
|
2
|
-
const PostKeypair = require('../api/postKeypair')
|
|
3
|
-
const keypairMetadata = require('../helpers/keypairMetadata')
|
|
4
|
-
const teamChoicesFromMeta = require('../helpers/teamChoicesFromMeta')
|
|
1
|
+
const PostArmorKeyring = require('../api/postArmorKeyring')
|
|
5
2
|
|
|
6
3
|
const ACCESS_APPROVAL_REQUIRED = 'ACCESS_APPROVAL_REQUIRED'
|
|
7
4
|
const ACCESS_APPROVAL_PENDING = 'ACCESS_APPROVAL_PENDING'
|
|
@@ -40,44 +37,37 @@ function approvalTimeoutError () {
|
|
|
40
37
|
return error
|
|
41
38
|
}
|
|
42
39
|
|
|
43
|
-
class
|
|
44
|
-
constructor (hostname, token, devicePublicKey, publicKey
|
|
40
|
+
class ArmorKeyring {
|
|
41
|
+
constructor (hostname, token, devicePublicKey, publicKey) {
|
|
45
42
|
this.hostname = hostname
|
|
46
43
|
this.token = token
|
|
47
44
|
this.devicePublicKey = devicePublicKey
|
|
48
45
|
this.publicKey = publicKey
|
|
49
|
-
this.team = options.team
|
|
50
|
-
this.envFile = options.envFile || '.env'
|
|
51
|
-
this.metadata = options.metadata
|
|
52
46
|
this.onApprovalRequired = null
|
|
53
47
|
}
|
|
54
48
|
|
|
55
|
-
async request (
|
|
49
|
+
async request (grantToken) {
|
|
56
50
|
if (grantToken !== undefined) {
|
|
57
|
-
return await new
|
|
51
|
+
return await new PostArmorKeyring(
|
|
58
52
|
this.hostname,
|
|
59
53
|
this.token,
|
|
60
54
|
this.devicePublicKey,
|
|
61
55
|
this.publicKey,
|
|
62
|
-
team,
|
|
63
|
-
metadata,
|
|
64
56
|
grantToken
|
|
65
57
|
).run()
|
|
66
58
|
}
|
|
67
59
|
|
|
68
|
-
return await new
|
|
60
|
+
return await new PostArmorKeyring(
|
|
69
61
|
this.hostname,
|
|
70
62
|
this.token,
|
|
71
63
|
this.devicePublicKey,
|
|
72
|
-
this.publicKey
|
|
73
|
-
team,
|
|
74
|
-
metadata
|
|
64
|
+
this.publicKey
|
|
75
65
|
).run()
|
|
76
66
|
}
|
|
77
67
|
|
|
78
|
-
async requestWithApprovalPolling (
|
|
68
|
+
async requestWithApprovalPolling () {
|
|
79
69
|
try {
|
|
80
|
-
return await this.request(
|
|
70
|
+
return await this.request()
|
|
81
71
|
} catch (error) {
|
|
82
72
|
if (!isAccessApprovalRequired(error)) {
|
|
83
73
|
throw error
|
|
@@ -97,16 +87,16 @@ class ArmorKeypair {
|
|
|
97
87
|
this.onApprovalRequired({ approvalUri, code: error.code })
|
|
98
88
|
}
|
|
99
89
|
|
|
100
|
-
return await this.poll(
|
|
90
|
+
return await this.poll(grantToken)
|
|
101
91
|
}
|
|
102
92
|
}
|
|
103
93
|
|
|
104
|
-
async poll (
|
|
94
|
+
async poll (grantToken) {
|
|
105
95
|
const startedAt = Date.now()
|
|
106
96
|
|
|
107
97
|
while (true) {
|
|
108
98
|
try {
|
|
109
|
-
return await this.request(
|
|
99
|
+
return await this.request(grantToken)
|
|
110
100
|
} catch (error) {
|
|
111
101
|
if (!isAccessPending(error)) {
|
|
112
102
|
throw error
|
|
@@ -122,35 +112,8 @@ class ArmorKeypair {
|
|
|
122
112
|
}
|
|
123
113
|
|
|
124
114
|
async run () {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
if (this.team) {
|
|
128
|
-
return await this.requestWithApprovalPolling(this.team, metadata)
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
try {
|
|
132
|
-
return await this.requestWithApprovalPolling(undefined, metadata)
|
|
133
|
-
} catch (error) {
|
|
134
|
-
if (error.code !== 'DOTENVX_TEAM_REQUIRED') {
|
|
135
|
-
throw error
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
const choices = teamChoicesFromMeta(error.meta)
|
|
139
|
-
|
|
140
|
-
let team = choices[0].value
|
|
141
|
-
if (choices.length > 1) {
|
|
142
|
-
team = await prompts.select({
|
|
143
|
-
message: 'Select team',
|
|
144
|
-
choices
|
|
145
|
-
}, {
|
|
146
|
-
input: process.stdin,
|
|
147
|
-
output: process.stderr
|
|
148
|
-
})
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
return await this.requestWithApprovalPolling(team, metadata)
|
|
152
|
-
}
|
|
115
|
+
return await this.requestWithApprovalPolling()
|
|
153
116
|
}
|
|
154
117
|
}
|
|
155
118
|
|
|
156
|
-
module.exports =
|
|
119
|
+
module.exports = ArmorKeyring
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const prompts = require('../helpers/prompts')
|
|
2
2
|
const PostArmorMove = require('../api/postArmorMove')
|
|
3
3
|
const GetAccount = require('../api/getAccount')
|
|
4
|
-
const
|
|
4
|
+
const keynames = require('../conventions/keynames')
|
|
5
5
|
const readEnvKey = require('../helpers/readEnvKey')
|
|
6
6
|
|
|
7
7
|
class ArmorMove {
|
|
@@ -24,7 +24,7 @@ class ArmorMove {
|
|
|
24
24
|
const {
|
|
25
25
|
publicKeyName,
|
|
26
26
|
privateKeyName
|
|
27
|
-
} =
|
|
27
|
+
} = keynames(envFile)
|
|
28
28
|
const publicKey = readEnvKey(publicKeyName, envFile, { strict: true, ignore: ['MISSING_PRIVATE_KEY'] })
|
|
29
29
|
|
|
30
30
|
const accountJson = await new GetAccount(hostname, token).run()
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const prompts = require('../helpers/prompts')
|
|
2
2
|
const PostArmorPull = require('../api/postArmorPull')
|
|
3
3
|
const upsertEnvKey = require('../helpers/upsertEnvKey')
|
|
4
|
-
const
|
|
4
|
+
const keynames = require('../conventions/keynames')
|
|
5
5
|
const readEnvKey = require('../helpers/readEnvKey')
|
|
6
6
|
const teamChoicesFromMeta = require('../helpers/teamChoicesFromMeta')
|
|
7
7
|
|
|
@@ -24,7 +24,7 @@ class ArmorPull {
|
|
|
24
24
|
const {
|
|
25
25
|
publicKeyName,
|
|
26
26
|
privateKeyName
|
|
27
|
-
} =
|
|
27
|
+
} = keynames(envFile)
|
|
28
28
|
|
|
29
29
|
const publicKey = readEnvKey(publicKeyName, envFile, { strict: true, ignore: ['MISSING_PRIVATE_KEY'] })
|
|
30
30
|
let json
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const { derive } = require('@dotenvx/primitives')
|
|
2
2
|
const prompts = require('../helpers/prompts')
|
|
3
3
|
const PostArmorPush = require('../api/postArmorPush')
|
|
4
|
-
const
|
|
4
|
+
const keynames = require('../conventions/keynames')
|
|
5
5
|
const readEnvKey = require('../helpers/readEnvKey')
|
|
6
6
|
const teamChoicesFromMeta = require('../helpers/teamChoicesFromMeta')
|
|
7
7
|
|
|
@@ -29,7 +29,7 @@ class ArmorPush {
|
|
|
29
29
|
const envFile = this.envFile
|
|
30
30
|
const team = this.team
|
|
31
31
|
|
|
32
|
-
const { privateKeyName } =
|
|
32
|
+
const { privateKeyName } = keynames(envFile)
|
|
33
33
|
|
|
34
34
|
const privateKey = readEnvKey(privateKeyName, '.env.keys', { strict: true })
|
|
35
35
|
const publicKey = publicKeyFromPrivateKey(privateKey)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const prompts = require('../helpers/prompts')
|
|
2
2
|
const PostArmorUp = require('../api/postArmorUp')
|
|
3
|
-
const
|
|
3
|
+
const keynames = require('../conventions/keynames')
|
|
4
4
|
const removeEnvKey = require('../helpers/removeEnvKey')
|
|
5
5
|
const readEnvKey = require('../helpers/readEnvKey')
|
|
6
6
|
const teamChoicesFromMeta = require('../helpers/teamChoicesFromMeta')
|
|
@@ -24,7 +24,7 @@ class ArmorUp {
|
|
|
24
24
|
const {
|
|
25
25
|
publicKeyName,
|
|
26
26
|
privateKeyName
|
|
27
|
-
} =
|
|
27
|
+
} = keynames(envFile)
|
|
28
28
|
|
|
29
29
|
const publicKey = readEnvKey(publicKeyName, envFile, { strict: true, ignore: ['MISSING_PRIVATE_KEY'] })
|
|
30
30
|
const privateKey = readEnvKey(privateKeyName, '.env.keys', { strict: true, ignore: ['MISSING_KEY'] })
|