@dotenvx/dotenvx 1.71.3 → 1.73.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 +17 -1
- package/README.md +3 -3
- package/package.json +8 -4
- package/src/cli/actions/armor/down.js +37 -0
- package/src/cli/actions/armor/move.js +42 -0
- package/src/cli/actions/armor/pull.js +37 -0
- package/src/cli/actions/armor/push.js +37 -0
- package/src/cli/actions/armor/up.js +37 -0
- package/src/cli/actions/decrypt.js +1 -1
- package/src/cli/actions/encrypt.js +1 -1
- package/src/cli/actions/login.js +63 -0
- package/src/cli/actions/logout.js +36 -0
- package/src/cli/actions/normalizeArmorOptions.js +1 -2
- package/src/cli/actions/set.js +1 -1
- package/src/cli/commands/armor.js +72 -0
- package/src/cli/dotenvx.js +17 -19
- package/src/db/device.js +73 -0
- package/src/db/session.js +187 -4
- package/src/lib/api/getAccount.js +32 -0
- package/src/lib/api/postArmorDown.js +48 -0
- package/src/lib/api/postArmorMove.js +48 -0
- package/src/lib/api/postArmorPull.js +48 -0
- package/src/lib/api/postArmorPush.js +48 -0
- package/src/lib/api/postArmorUp.js +51 -0
- package/src/lib/api/postKeypair.js +60 -0
- package/src/lib/api/postLogout.js +34 -0
- package/src/lib/api/postOauthDeviceCode.js +38 -0
- package/src/lib/api/postOauthToken.js +35 -0
- package/src/lib/helpers/armoredKeyDisplay.js +10 -0
- package/src/lib/helpers/buildApiError.js +16 -0
- package/src/lib/helpers/buildOauthError.js +14 -0
- package/src/lib/helpers/createSpinner.js +1 -1
- package/src/lib/helpers/cryptography/armorKeypair.js +32 -11
- package/src/lib/helpers/cryptography/armorKeypairSync.js +48 -7
- package/src/lib/helpers/cryptography/provision.js +2 -2
- package/src/lib/helpers/cryptography/provisionSync.js +2 -2
- package/src/lib/helpers/decryptDeviceValue.js +10 -0
- package/src/lib/helpers/encryptDeviceValue.js +9 -0
- package/src/lib/helpers/formatCode.js +11 -0
- package/src/lib/helpers/http.js +7 -0
- package/src/lib/helpers/jsonToEnv.js +7 -0
- package/src/lib/helpers/keyResolution/index.js +1 -1
- package/src/lib/helpers/keyResolution/{keyNames.js → keyNamesForEnvFile.js} +2 -2
- package/src/lib/helpers/keyResolution/keyValues.js +2 -2
- package/src/lib/helpers/keyResolution/keyValuesSync.js +2 -2
- package/src/lib/helpers/keypairMetadata.js +77 -0
- package/src/lib/helpers/listenForOpenKey.js +46 -0
- package/src/lib/helpers/normalizeToken.js +5 -0
- package/src/lib/helpers/openUrl.js +7 -0
- package/src/lib/helpers/readEnvKey.js +31 -0
- package/src/lib/helpers/removeEnvKey.js +50 -0
- package/src/lib/helpers/sanitizeCommandForMetadata.js +64 -0
- package/src/lib/helpers/teamChoicesFromMeta.js +8 -0
- package/src/lib/helpers/upsertEnvKey.js +61 -0
- package/src/lib/main.d.ts +0 -24
- package/src/lib/main.js +1 -1
- package/src/lib/services/armorDown.js +71 -0
- package/src/lib/services/armorKeypair.js +156 -0
- package/src/lib/services/armorMove.js +54 -0
- package/src/lib/services/armorPull.js +71 -0
- package/src/lib/services/armorPush.js +76 -0
- package/src/lib/services/armorUp.js +73 -0
- package/src/lib/services/decrypt.js +2 -2
- package/src/lib/services/encrypt.js +2 -2
- package/src/lib/services/keypair.js +5 -7
- package/src/lib/services/login.js +26 -0
- package/src/lib/services/loginPoll.js +35 -0
- package/src/lib/services/logout.js +26 -0
- package/src/lib/services/rotate.js +2 -2
- package/src/lib/services/run.js +3 -3
- package/src/lib/services/sets.js +3 -3
- package/src/lib/extensions/armor.js +0 -204
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
const fs = require('fs')
|
|
2
|
+
const path = require('path')
|
|
3
|
+
|
|
4
|
+
function escapeForRegex (value) {
|
|
5
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
function upsertEnvKey (key, value, keysFilepath = '.env.keys') {
|
|
9
|
+
const resolvedKeysFilepath = path.resolve(keysFilepath)
|
|
10
|
+
const keyValueLine = `${key}=${value}`
|
|
11
|
+
const created = !fs.existsSync(resolvedKeysFilepath)
|
|
12
|
+
|
|
13
|
+
let src = ''
|
|
14
|
+
if (!created) {
|
|
15
|
+
src = fs.readFileSync(resolvedKeysFilepath, 'utf8')
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const eol = src.includes('\r\n') ? '\r\n' : '\n'
|
|
19
|
+
const keyPattern = new RegExp(`^\\s*(?:export\\s+)?${escapeForRegex(key)}\\s*=`)
|
|
20
|
+
const lines = src.length > 0 ? src.split(/\r?\n/) : []
|
|
21
|
+
|
|
22
|
+
while (lines.length > 0 && lines[lines.length - 1] === '') {
|
|
23
|
+
lines.pop()
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
let replaced = false
|
|
27
|
+
const nextLines = []
|
|
28
|
+
|
|
29
|
+
for (const line of lines) {
|
|
30
|
+
if (keyPattern.test(line)) {
|
|
31
|
+
if (!replaced) {
|
|
32
|
+
nextLines.push(keyValueLine)
|
|
33
|
+
replaced = true
|
|
34
|
+
}
|
|
35
|
+
continue
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
nextLines.push(line)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (!replaced) {
|
|
42
|
+
nextLines.push(keyValueLine)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const nextSrc = `${nextLines.join(eol)}${eol}`
|
|
46
|
+
const changed = created || nextSrc !== src
|
|
47
|
+
|
|
48
|
+
if (changed) {
|
|
49
|
+
fs.writeFileSync(resolvedKeysFilepath, nextSrc, 'utf8')
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
changed,
|
|
54
|
+
key,
|
|
55
|
+
value,
|
|
56
|
+
created,
|
|
57
|
+
filepath: keysFilepath
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
module.exports = upsertEnvKey
|
package/src/lib/main.d.ts
CHANGED
|
@@ -179,14 +179,6 @@ export interface DotenvConfigOptions {
|
|
|
179
179
|
*/
|
|
180
180
|
noArmor?: boolean;
|
|
181
181
|
|
|
182
|
-
/**
|
|
183
|
-
* Turn off Dotenvx Armor features. Alias for `noArmor`.
|
|
184
|
-
*
|
|
185
|
-
* @default false
|
|
186
|
-
* @example require('@dotenvx/dotenvx').config({ noVlt: true })
|
|
187
|
-
*/
|
|
188
|
-
noVlt?: boolean;
|
|
189
|
-
|
|
190
182
|
/**
|
|
191
183
|
* Turn off Dotenvx Armor features. Alias for `noArmor`.
|
|
192
184
|
*
|
|
@@ -270,14 +262,6 @@ export interface SetOptions {
|
|
|
270
262
|
*/
|
|
271
263
|
noArmor?: boolean;
|
|
272
264
|
|
|
273
|
-
/**
|
|
274
|
-
* Turn off Dotenvx Armor features. Alias for `noArmor`.
|
|
275
|
-
*
|
|
276
|
-
* @default false
|
|
277
|
-
* @example require('@dotenvx/dotenvx').set(key, value, { noVlt: true })
|
|
278
|
-
*/
|
|
279
|
-
noVlt?: boolean;
|
|
280
|
-
|
|
281
265
|
/**
|
|
282
266
|
* Turn off Dotenvx Armor features. Alias for `noArmor`.
|
|
283
267
|
*
|
|
@@ -363,14 +347,6 @@ export interface GetOptions {
|
|
|
363
347
|
*/
|
|
364
348
|
noArmor?: boolean;
|
|
365
349
|
|
|
366
|
-
/**
|
|
367
|
-
* Turn off Dotenvx Armor features. Alias for `noArmor`.
|
|
368
|
-
*
|
|
369
|
-
* @default false
|
|
370
|
-
* @example require('@dotenvx/dotenvx').get('KEY', { noVlt: true })
|
|
371
|
-
*/
|
|
372
|
-
noVlt?: boolean;
|
|
373
|
-
|
|
374
350
|
/**
|
|
375
351
|
* Turn off Dotenvx Armor features. Alias for `noArmor`.
|
|
376
352
|
*
|
package/src/lib/main.js
CHANGED
|
@@ -325,7 +325,7 @@ const keypair = function (envFile, key, envKeysFile = null, noArmor = false) {
|
|
|
325
325
|
|
|
326
326
|
function resolveNoArmor (options = {}) {
|
|
327
327
|
const sesh = new Session()
|
|
328
|
-
return options.noArmor === true || options.
|
|
328
|
+
return options.noArmor === true || options.noOps === true || (!options.token && sesh.noArmorSync())
|
|
329
329
|
}
|
|
330
330
|
|
|
331
331
|
module.exports = {
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
const prompts = require('../helpers/prompts')
|
|
2
|
+
const PostArmorDown = require('../api/postArmorDown')
|
|
3
|
+
const keyNamesForEnvFile = require('../helpers/keyResolution/keyNamesForEnvFile')
|
|
4
|
+
const upsertEnvKey = require('../helpers/upsertEnvKey')
|
|
5
|
+
const readEnvKey = require('../helpers/readEnvKey')
|
|
6
|
+
const teamChoicesFromMeta = require('../helpers/teamChoicesFromMeta')
|
|
7
|
+
|
|
8
|
+
class ArmorDown {
|
|
9
|
+
constructor (hostname, token, devicePublicKey, envFile = '.env', team = undefined) {
|
|
10
|
+
this.hostname = hostname
|
|
11
|
+
this.token = token
|
|
12
|
+
this.devicePublicKey = devicePublicKey
|
|
13
|
+
this.envFile = envFile
|
|
14
|
+
this.team = team
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async run () {
|
|
18
|
+
const hostname = this.hostname
|
|
19
|
+
const token = this.token
|
|
20
|
+
const devicePublicKey = this.devicePublicKey
|
|
21
|
+
const envFile = this.envFile
|
|
22
|
+
const team = this.team
|
|
23
|
+
|
|
24
|
+
const {
|
|
25
|
+
publicKeyName,
|
|
26
|
+
privateKeyName
|
|
27
|
+
} = keyNamesForEnvFile(envFile)
|
|
28
|
+
|
|
29
|
+
const publicKey = readEnvKey(publicKeyName, envFile, { strict: true, ignore: ['MISSING_PRIVATE_KEY'] })
|
|
30
|
+
let json
|
|
31
|
+
|
|
32
|
+
if (team) {
|
|
33
|
+
json = await new PostArmorDown(hostname, token, devicePublicKey, publicKey, team).run()
|
|
34
|
+
} else {
|
|
35
|
+
try {
|
|
36
|
+
json = await new PostArmorDown(hostname, token, devicePublicKey, publicKey, undefined).run()
|
|
37
|
+
} catch (error) {
|
|
38
|
+
if (error.code !== 'DOTENVX_TEAM_REQUIRED') {
|
|
39
|
+
throw error
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const choices = teamChoicesFromMeta(error.meta)
|
|
43
|
+
|
|
44
|
+
let team = choices[0].value
|
|
45
|
+
if (choices.length > 1) {
|
|
46
|
+
team = await prompts.select({
|
|
47
|
+
message: 'Select team',
|
|
48
|
+
choices
|
|
49
|
+
}, {
|
|
50
|
+
input: process.stdin,
|
|
51
|
+
output: process.stderr
|
|
52
|
+
})
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
json = await new PostArmorDown(hostname, token, devicePublicKey, publicKey, team).run()
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
upsertEnvKey(privateKeyName, json.private_key)
|
|
60
|
+
|
|
61
|
+
return {
|
|
62
|
+
...json,
|
|
63
|
+
changed: json.changed,
|
|
64
|
+
privateKeyName,
|
|
65
|
+
privateKeyValue: json.private_key,
|
|
66
|
+
publicKeyValue: publicKey
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
module.exports = ArmorDown
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
const prompts = require('../helpers/prompts')
|
|
2
|
+
const PostKeypair = require('../api/postKeypair')
|
|
3
|
+
const keypairMetadata = require('../helpers/keypairMetadata')
|
|
4
|
+
const teamChoicesFromMeta = require('../helpers/teamChoicesFromMeta')
|
|
5
|
+
|
|
6
|
+
const ACCESS_APPROVAL_REQUIRED = 'ACCESS_APPROVAL_REQUIRED'
|
|
7
|
+
const ACCESS_APPROVAL_PENDING = 'ACCESS_APPROVAL_PENDING'
|
|
8
|
+
const ACCESS_PENDING = 'ACCESS_PENDING'
|
|
9
|
+
const POLL_INTERVAL = 1000
|
|
10
|
+
const POLL_TIMEOUT = 5 * 60 * 1000
|
|
11
|
+
|
|
12
|
+
function grantTokenFromError (error) {
|
|
13
|
+
return error.meta && error.meta.grant_token
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function isAccessApprovalRequired (error) {
|
|
17
|
+
return error.code === ACCESS_APPROVAL_REQUIRED
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function isAccessPending (error) {
|
|
21
|
+
return error.code === ACCESS_PENDING || error.code === ACCESS_APPROVAL_PENDING
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function approvalUriFromError (error) {
|
|
25
|
+
if (error.meta) {
|
|
26
|
+
return error.meta.approval_uri
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return error.json && error.json.error && error.json.error.approval_uri
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async function sleep (ms) {
|
|
33
|
+
await new Promise(resolve => setTimeout(resolve, ms))
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function approvalTimeoutError () {
|
|
37
|
+
const code = 'ACCESS_APPROVAL_TIMEOUT'
|
|
38
|
+
const error = new Error(`[${code}] approval timed out after 5 minutes`)
|
|
39
|
+
error.code = code
|
|
40
|
+
return error
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
class ArmorKeypair {
|
|
44
|
+
constructor (hostname, token, devicePublicKey, publicKey, options = {}) {
|
|
45
|
+
this.hostname = hostname
|
|
46
|
+
this.token = token
|
|
47
|
+
this.devicePublicKey = devicePublicKey
|
|
48
|
+
this.publicKey = publicKey
|
|
49
|
+
this.team = options.team
|
|
50
|
+
this.envFile = options.envFile || '.env'
|
|
51
|
+
this.metadata = options.metadata
|
|
52
|
+
this.onApprovalRequired = null
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async request (team, metadata, grantToken) {
|
|
56
|
+
if (grantToken !== undefined) {
|
|
57
|
+
return await new PostKeypair(
|
|
58
|
+
this.hostname,
|
|
59
|
+
this.token,
|
|
60
|
+
this.devicePublicKey,
|
|
61
|
+
this.publicKey,
|
|
62
|
+
team,
|
|
63
|
+
metadata,
|
|
64
|
+
grantToken
|
|
65
|
+
).run()
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return await new PostKeypair(
|
|
69
|
+
this.hostname,
|
|
70
|
+
this.token,
|
|
71
|
+
this.devicePublicKey,
|
|
72
|
+
this.publicKey,
|
|
73
|
+
team,
|
|
74
|
+
metadata
|
|
75
|
+
).run()
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async requestWithApprovalPolling (team, metadata) {
|
|
79
|
+
try {
|
|
80
|
+
return await this.request(team, metadata)
|
|
81
|
+
} catch (error) {
|
|
82
|
+
if (!isAccessApprovalRequired(error)) {
|
|
83
|
+
throw error
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const grantToken = grantTokenFromError(error)
|
|
87
|
+
if (!grantToken) {
|
|
88
|
+
throw error
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const approvalUri = approvalUriFromError(error)
|
|
92
|
+
if (!approvalUri) {
|
|
93
|
+
throw error
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (this.onApprovalRequired) {
|
|
97
|
+
this.onApprovalRequired({ approvalUri, code: error.code })
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return await this.poll(team, metadata, grantToken)
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async poll (team, metadata, grantToken) {
|
|
105
|
+
const startedAt = Date.now()
|
|
106
|
+
|
|
107
|
+
while (true) {
|
|
108
|
+
try {
|
|
109
|
+
return await this.request(team, metadata, grantToken)
|
|
110
|
+
} catch (error) {
|
|
111
|
+
if (!isAccessPending(error)) {
|
|
112
|
+
throw error
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (Date.now() - startedAt >= POLL_TIMEOUT) {
|
|
116
|
+
throw approvalTimeoutError()
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
await sleep(POLL_INTERVAL)
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async run () {
|
|
125
|
+
const metadata = keypairMetadata(this.envFile, this.metadata)
|
|
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
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
module.exports = ArmorKeypair
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
const prompts = require('../helpers/prompts')
|
|
2
|
+
const PostArmorMove = require('../api/postArmorMove')
|
|
3
|
+
const GetAccount = require('../api/getAccount')
|
|
4
|
+
const keyNamesForEnvFile = require('../helpers/keyResolution/keyNamesForEnvFile')
|
|
5
|
+
const readEnvKey = require('../helpers/readEnvKey')
|
|
6
|
+
|
|
7
|
+
class ArmorMove {
|
|
8
|
+
constructor (hostname, token, devicePublicKey, envFile = '.env') {
|
|
9
|
+
this.hostname = hostname
|
|
10
|
+
this.token = token
|
|
11
|
+
this.devicePublicKey = devicePublicKey
|
|
12
|
+
this.envFile = envFile
|
|
13
|
+
|
|
14
|
+
this.team = null
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async run () {
|
|
18
|
+
const hostname = this.hostname
|
|
19
|
+
const token = this.token
|
|
20
|
+
const devicePublicKey = this.devicePublicKey
|
|
21
|
+
const envFile = this.envFile
|
|
22
|
+
let team = this.team
|
|
23
|
+
|
|
24
|
+
const {
|
|
25
|
+
publicKeyName,
|
|
26
|
+
privateKeyName
|
|
27
|
+
} = keyNamesForEnvFile(envFile)
|
|
28
|
+
const publicKey = readEnvKey(publicKeyName, envFile, { strict: true, ignore: ['MISSING_PRIVATE_KEY'] })
|
|
29
|
+
|
|
30
|
+
const accountJson = await new GetAccount(hostname, token).run()
|
|
31
|
+
const choices = accountJson.organizations.map(o => ({
|
|
32
|
+
name: o.provider_slug,
|
|
33
|
+
value: o.provider_slug
|
|
34
|
+
}))
|
|
35
|
+
team = await prompts.select({
|
|
36
|
+
message: 'Select team',
|
|
37
|
+
choices
|
|
38
|
+
}, {
|
|
39
|
+
input: process.stdin,
|
|
40
|
+
output: process.stderr
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
const json = await new PostArmorMove(hostname, token, devicePublicKey, publicKey, team).run()
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
...json,
|
|
47
|
+
privateKeyName,
|
|
48
|
+
privateKeyValue: json.private_key,
|
|
49
|
+
publicKeyValue: publicKey
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
module.exports = ArmorMove
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
const prompts = require('../helpers/prompts')
|
|
2
|
+
const PostArmorPull = require('../api/postArmorPull')
|
|
3
|
+
const upsertEnvKey = require('../helpers/upsertEnvKey')
|
|
4
|
+
const keyNamesForEnvFile = require('../helpers/keyResolution/keyNamesForEnvFile')
|
|
5
|
+
const readEnvKey = require('../helpers/readEnvKey')
|
|
6
|
+
const teamChoicesFromMeta = require('../helpers/teamChoicesFromMeta')
|
|
7
|
+
|
|
8
|
+
class ArmorPull {
|
|
9
|
+
constructor (hostname, token, devicePublicKey, envFile = '.env', team = undefined) {
|
|
10
|
+
this.hostname = hostname
|
|
11
|
+
this.token = token
|
|
12
|
+
this.devicePublicKey = devicePublicKey
|
|
13
|
+
this.envFile = envFile
|
|
14
|
+
this.team = team
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async run () {
|
|
18
|
+
const hostname = this.hostname
|
|
19
|
+
const token = this.token
|
|
20
|
+
const devicePublicKey = this.devicePublicKey
|
|
21
|
+
const envFile = this.envFile
|
|
22
|
+
const team = this.team
|
|
23
|
+
|
|
24
|
+
const {
|
|
25
|
+
publicKeyName,
|
|
26
|
+
privateKeyName
|
|
27
|
+
} = keyNamesForEnvFile(envFile)
|
|
28
|
+
|
|
29
|
+
const publicKey = readEnvKey(publicKeyName, envFile, { strict: true, ignore: ['MISSING_PRIVATE_KEY'] })
|
|
30
|
+
let json
|
|
31
|
+
|
|
32
|
+
if (team) {
|
|
33
|
+
json = await new PostArmorPull(hostname, token, devicePublicKey, publicKey, team).run()
|
|
34
|
+
} else {
|
|
35
|
+
try {
|
|
36
|
+
json = await new PostArmorPull(hostname, token, devicePublicKey, publicKey, undefined).run()
|
|
37
|
+
} catch (error) {
|
|
38
|
+
if (error.code !== 'DOTENVX_TEAM_REQUIRED') {
|
|
39
|
+
throw error
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const choices = teamChoicesFromMeta(error.meta)
|
|
43
|
+
|
|
44
|
+
let team = choices[0].value
|
|
45
|
+
if (choices.length > 1) {
|
|
46
|
+
team = await prompts.select({
|
|
47
|
+
message: 'Select team',
|
|
48
|
+
choices
|
|
49
|
+
}, {
|
|
50
|
+
input: process.stdin,
|
|
51
|
+
output: process.stderr
|
|
52
|
+
})
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
json = await new PostArmorPull(hostname, token, devicePublicKey, publicKey, team).run()
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const result = upsertEnvKey(privateKeyName, json.private_key)
|
|
60
|
+
|
|
61
|
+
return {
|
|
62
|
+
...json,
|
|
63
|
+
changed: result.changed,
|
|
64
|
+
privateKeyName,
|
|
65
|
+
privateKeyValue: json.private_key,
|
|
66
|
+
publicKeyValue: publicKey
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
module.exports = ArmorPull
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
const { PrivateKey } = require('eciesjs')
|
|
2
|
+
const prompts = require('../helpers/prompts')
|
|
3
|
+
const PostArmorPush = require('../api/postArmorPush')
|
|
4
|
+
const keyNamesForEnvFile = require('../helpers/keyResolution/keyNamesForEnvFile')
|
|
5
|
+
const readEnvKey = require('../helpers/readEnvKey')
|
|
6
|
+
const teamChoicesFromMeta = require('../helpers/teamChoicesFromMeta')
|
|
7
|
+
|
|
8
|
+
function publicKeyFromPrivateKey (privateKey) {
|
|
9
|
+
try {
|
|
10
|
+
return new PrivateKey(Buffer.from(privateKey, 'hex')).publicKey.toHex()
|
|
11
|
+
} catch {
|
|
12
|
+
return ''
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
class ArmorPush {
|
|
17
|
+
constructor (hostname, token, devicePublicKey, envFile = '.env', team = undefined) {
|
|
18
|
+
this.hostname = hostname
|
|
19
|
+
this.token = token
|
|
20
|
+
this.devicePublicKey = devicePublicKey
|
|
21
|
+
this.envFile = envFile
|
|
22
|
+
this.team = team
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async run () {
|
|
26
|
+
const hostname = this.hostname
|
|
27
|
+
const token = this.token
|
|
28
|
+
const devicePublicKey = this.devicePublicKey
|
|
29
|
+
const envFile = this.envFile
|
|
30
|
+
const team = this.team
|
|
31
|
+
|
|
32
|
+
const { privateKeyName } = keyNamesForEnvFile(envFile)
|
|
33
|
+
|
|
34
|
+
const privateKey = readEnvKey(privateKeyName, '.env.keys', { strict: true })
|
|
35
|
+
const publicKey = publicKeyFromPrivateKey(privateKey)
|
|
36
|
+
|
|
37
|
+
let json
|
|
38
|
+
|
|
39
|
+
if (team) {
|
|
40
|
+
json = await new PostArmorPush(hostname, token, devicePublicKey, privateKey, team).run()
|
|
41
|
+
} else {
|
|
42
|
+
try {
|
|
43
|
+
json = await new PostArmorPush(hostname, token, devicePublicKey, privateKey, undefined).run()
|
|
44
|
+
} catch (error) {
|
|
45
|
+
if (error.code !== 'DOTENVX_TEAM_REQUIRED') {
|
|
46
|
+
throw error
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const choices = teamChoicesFromMeta(error.meta)
|
|
50
|
+
|
|
51
|
+
let team = choices[0].value
|
|
52
|
+
if (choices.length > 1) {
|
|
53
|
+
team = await prompts.select({
|
|
54
|
+
message: 'Select team',
|
|
55
|
+
choices
|
|
56
|
+
}, {
|
|
57
|
+
input: process.stdin,
|
|
58
|
+
output: process.stderr
|
|
59
|
+
})
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
json = await new PostArmorPush(hostname, token, devicePublicKey, privateKey, team).run()
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
...json,
|
|
68
|
+
changed: json.changed,
|
|
69
|
+
privateKeyName,
|
|
70
|
+
privateKeyValue: json.private_key,
|
|
71
|
+
publicKeyValue: publicKey
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
module.exports = ArmorPush
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
const prompts = require('../helpers/prompts')
|
|
2
|
+
const PostArmorUp = require('../api/postArmorUp')
|
|
3
|
+
const keyNamesForEnvFile = require('../helpers/keyResolution/keyNamesForEnvFile')
|
|
4
|
+
const removeEnvKey = require('../helpers/removeEnvKey')
|
|
5
|
+
const readEnvKey = require('../helpers/readEnvKey')
|
|
6
|
+
const teamChoicesFromMeta = require('../helpers/teamChoicesFromMeta')
|
|
7
|
+
|
|
8
|
+
class ArmorUp {
|
|
9
|
+
constructor (hostname, token, devicePublicKey, envFile = '.env', team = undefined) {
|
|
10
|
+
this.hostname = hostname
|
|
11
|
+
this.token = token
|
|
12
|
+
this.devicePublicKey = devicePublicKey
|
|
13
|
+
this.envFile = envFile
|
|
14
|
+
this.team = team
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async run () {
|
|
18
|
+
const hostname = this.hostname
|
|
19
|
+
const token = this.token
|
|
20
|
+
const devicePublicKey = this.devicePublicKey
|
|
21
|
+
const envFile = this.envFile
|
|
22
|
+
const team = this.team
|
|
23
|
+
|
|
24
|
+
const {
|
|
25
|
+
publicKeyName,
|
|
26
|
+
privateKeyName
|
|
27
|
+
} = keyNamesForEnvFile(envFile)
|
|
28
|
+
|
|
29
|
+
const publicKey = readEnvKey(publicKeyName, envFile, { strict: true, ignore: ['MISSING_PRIVATE_KEY'] })
|
|
30
|
+
const privateKey = readEnvKey(privateKeyName, '.env.keys', { strict: true, ignore: ['MISSING_KEY'] })
|
|
31
|
+
|
|
32
|
+
let json
|
|
33
|
+
|
|
34
|
+
if (team) {
|
|
35
|
+
json = await new PostArmorUp(hostname, token, devicePublicKey, publicKey, privateKey, team).run()
|
|
36
|
+
} else {
|
|
37
|
+
try {
|
|
38
|
+
json = await new PostArmorUp(hostname, token, devicePublicKey, publicKey, privateKey, undefined).run()
|
|
39
|
+
} catch (error) {
|
|
40
|
+
if (error.code !== 'DOTENVX_TEAM_REQUIRED') {
|
|
41
|
+
throw error
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const choices = teamChoicesFromMeta(error.meta)
|
|
45
|
+
|
|
46
|
+
let team = choices[0].value
|
|
47
|
+
if (choices.length > 1) {
|
|
48
|
+
team = await prompts.select({
|
|
49
|
+
message: 'Select team',
|
|
50
|
+
choices
|
|
51
|
+
}, {
|
|
52
|
+
input: process.stdin,
|
|
53
|
+
output: process.stderr
|
|
54
|
+
})
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
json = await new PostArmorUp(hostname, token, devicePublicKey, publicKey, privateKey, team).run()
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
removeEnvKey(privateKeyName)
|
|
62
|
+
|
|
63
|
+
return {
|
|
64
|
+
...json,
|
|
65
|
+
changed: json.changed,
|
|
66
|
+
privateKeyName,
|
|
67
|
+
privateKeyValue: json.private_key,
|
|
68
|
+
publicKeyValue: publicKey
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
module.exports = ArmorUp
|
|
@@ -11,7 +11,7 @@ const {
|
|
|
11
11
|
} = require('./../helpers/envResolution')
|
|
12
12
|
|
|
13
13
|
const {
|
|
14
|
-
|
|
14
|
+
keyNamesForEnvFile,
|
|
15
15
|
keyValues
|
|
16
16
|
} = require('./../helpers/keyResolution')
|
|
17
17
|
|
|
@@ -77,7 +77,7 @@ class Decrypt {
|
|
|
77
77
|
let envSrc = await fsx.readFileX(filepath, { encoding })
|
|
78
78
|
const envParsed = dotenvParse(envSrc, false, false, true)
|
|
79
79
|
|
|
80
|
-
const { privateKeyName } =
|
|
80
|
+
const { privateKeyName } = keyNamesForEnvFile(envFilepath)
|
|
81
81
|
const { privateKeyValue, privateKeySource } = await keyValues(envFilepath, {
|
|
82
82
|
keysFilepath: this.envKeysFilepath,
|
|
83
83
|
noArmor: this.noArmor,
|
|
@@ -11,7 +11,7 @@ const {
|
|
|
11
11
|
} = require('./../helpers/envResolution')
|
|
12
12
|
|
|
13
13
|
const {
|
|
14
|
-
|
|
14
|
+
keyNamesForEnvFile,
|
|
15
15
|
keyValues
|
|
16
16
|
} = require('./../helpers/keyResolution')
|
|
17
17
|
|
|
@@ -102,7 +102,7 @@ class Encrypt {
|
|
|
102
102
|
let publicKey
|
|
103
103
|
let privateKey
|
|
104
104
|
|
|
105
|
-
const { publicKeyName, privateKeyName } =
|
|
105
|
+
const { publicKeyName, privateKeyName } = keyNamesForEnvFile(envFilepath)
|
|
106
106
|
const { publicKeyValue, privateKeyValue } = await keyValues(envFilepath, {
|
|
107
107
|
keysFilepath: this.envKeysFilepath,
|
|
108
108
|
noArmor: this.noArmor,
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
const
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
keyValuesSync
|
|
5
|
-
} = require('./../helpers/keyResolution')
|
|
1
|
+
const keyNamesForEnvFile = require('./../helpers/keyResolution/keyNamesForEnvFile')
|
|
2
|
+
const keyValues = require('./../helpers/keyResolution/keyValues')
|
|
3
|
+
const keyValuesSync = require('./../helpers/keyResolution/keyValuesSync')
|
|
6
4
|
|
|
7
5
|
class Keypair {
|
|
8
6
|
constructor (envFile = '.env', envKeysFilepath = null, noArmor = false, options = {}) {
|
|
@@ -17,7 +15,7 @@ class Keypair {
|
|
|
17
15
|
|
|
18
16
|
const filepaths = this._filepaths()
|
|
19
17
|
for (const filepath of filepaths) {
|
|
20
|
-
const { publicKeyName, privateKeyName } =
|
|
18
|
+
const { publicKeyName, privateKeyName } = keyNamesForEnvFile(filepath)
|
|
21
19
|
const { publicKeyValue, privateKeyValue } = keyValuesSync(filepath, {
|
|
22
20
|
keysFilepath: this.envKeysFilepath,
|
|
23
21
|
noArmor: this.noArmor,
|
|
@@ -36,7 +34,7 @@ class Keypair {
|
|
|
36
34
|
|
|
37
35
|
const filepaths = this._filepaths()
|
|
38
36
|
for (const filepath of filepaths) {
|
|
39
|
-
const { publicKeyName, privateKeyName } =
|
|
37
|
+
const { publicKeyName, privateKeyName } = keyNamesForEnvFile(filepath)
|
|
40
38
|
const { publicKeyValue, privateKeyValue } = await keyValues(filepath, {
|
|
41
39
|
keysFilepath: this.envKeysFilepath,
|
|
42
40
|
noArmor: this.noArmor,
|