@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,26 @@
|
|
|
1
|
+
const Session = require('../../db/session')
|
|
2
|
+
const PostOauthDeviceCode = require('../api/postOauthDeviceCode')
|
|
3
|
+
|
|
4
|
+
class Login {
|
|
5
|
+
constructor (hostname) {
|
|
6
|
+
this.hostname = hostname
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
async run () {
|
|
10
|
+
const sesh = new Session()
|
|
11
|
+
const devicePublicKey = sesh.devicePublicKey()
|
|
12
|
+
const systemInformation = await sesh.systemInformation()
|
|
13
|
+
|
|
14
|
+
const data = await new PostOauthDeviceCode(this.hostname, devicePublicKey, systemInformation).run()
|
|
15
|
+
|
|
16
|
+
return {
|
|
17
|
+
deviceCode: data.device_code,
|
|
18
|
+
userCode: data.user_code,
|
|
19
|
+
verificationUri: data.verification_uri,
|
|
20
|
+
verificationUriComplete: data.verification_uri_complete,
|
|
21
|
+
interval: data.interval
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
module.exports = Login
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
const Session = require('../../db/session')
|
|
2
|
+
const PostOauthToken = require('../api/postOauthToken')
|
|
3
|
+
|
|
4
|
+
class LoginPoll {
|
|
5
|
+
constructor (hostname, deviceCode, interval) {
|
|
6
|
+
this.hostname = hostname
|
|
7
|
+
this.deviceCode = deviceCode
|
|
8
|
+
this.interval = interval
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
async run () {
|
|
12
|
+
const sesh = new Session()
|
|
13
|
+
|
|
14
|
+
while (true) {
|
|
15
|
+
try {
|
|
16
|
+
const data = await new PostOauthToken(this.hostname, this.deviceCode).run()
|
|
17
|
+
|
|
18
|
+
if (data.access_token) {
|
|
19
|
+
sesh.login(this.hostname, data.id, data.username, data.access_token)
|
|
20
|
+
return data
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
await new Promise(resolve => setTimeout(resolve, this.interval * 1000))
|
|
24
|
+
} catch (error) {
|
|
25
|
+
if (error.code === 'authorization_pending') {
|
|
26
|
+
await new Promise(resolve => setTimeout(resolve, (this.interval + 1) * 1000))
|
|
27
|
+
} else {
|
|
28
|
+
throw error
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
module.exports = LoginPoll
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
const Session = require('../../db/session')
|
|
2
|
+
const PostLogout = require('../api/postLogout')
|
|
3
|
+
|
|
4
|
+
class Logout {
|
|
5
|
+
constructor (hostname) {
|
|
6
|
+
this.hostname = hostname
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
async run () {
|
|
10
|
+
const sesh = new Session()
|
|
11
|
+
const token = sesh.token()
|
|
12
|
+
|
|
13
|
+
const data = await new PostLogout(this.hostname, token).run()
|
|
14
|
+
|
|
15
|
+
const id = data.id
|
|
16
|
+
const username = data.username
|
|
17
|
+
const accessToken = data.access_token
|
|
18
|
+
const settingsDevicesUrl = `${this.hostname}/settings/devices`
|
|
19
|
+
|
|
20
|
+
sesh.logout(this.hostname, id, accessToken)
|
|
21
|
+
|
|
22
|
+
return { username, accessToken, settingsDevicesUrl }
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
module.exports = Logout
|
|
@@ -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
|
|
|
@@ -83,7 +83,7 @@ class Rotate {
|
|
|
83
83
|
let envSrc = await fsx.readFileX(filepath, { encoding })
|
|
84
84
|
const envParsed = dotenvParse(envSrc, false, false, true)
|
|
85
85
|
|
|
86
|
-
const { publicKeyName, privateKeyName } =
|
|
86
|
+
const { publicKeyName, privateKeyName } = keyNamesForEnvFile(envFilepath)
|
|
87
87
|
const { privateKeyValue } = await keyValues(envFilepath, {
|
|
88
88
|
keysFilepath: this.envKeysFilepath,
|
|
89
89
|
noArmor: this.noArmor,
|
package/src/lib/services/run.js
CHANGED
|
@@ -10,7 +10,7 @@ const detectEncoding = require('./../helpers/detectEncoding')
|
|
|
10
10
|
const detectEncodingSync = require('./../helpers/detectEncodingSync')
|
|
11
11
|
|
|
12
12
|
const {
|
|
13
|
-
|
|
13
|
+
keyNamesForEnvFile,
|
|
14
14
|
keyValues,
|
|
15
15
|
keyValuesSync,
|
|
16
16
|
keyValuesFromEnvSrc
|
|
@@ -147,7 +147,7 @@ class Run {
|
|
|
147
147
|
const src = fsx.readFileXSync(filepath, { encoding })
|
|
148
148
|
this.readableFilepaths.add(envFilepath)
|
|
149
149
|
|
|
150
|
-
const { privateKeyName } =
|
|
150
|
+
const { privateKeyName } = keyNamesForEnvFile(filepath)
|
|
151
151
|
const { privateKeyValue, privateKeySource } = keyValuesSync(filepath, {
|
|
152
152
|
keysFilepath: this.envKeysFilepath,
|
|
153
153
|
noArmor: this.noArmor,
|
|
@@ -202,7 +202,7 @@ class Run {
|
|
|
202
202
|
const src = await fsx.readFileX(filepath, { encoding })
|
|
203
203
|
this.readableFilepaths.add(envFilepath)
|
|
204
204
|
|
|
205
|
-
const { privateKeyName } =
|
|
205
|
+
const { privateKeyName } = keyNamesForEnvFile(filepath)
|
|
206
206
|
const { privateKeyValue, privateKeySource } = await keyValues(filepath, {
|
|
207
207
|
keysFilepath: this.envKeysFilepath,
|
|
208
208
|
noArmor: this.noArmor,
|
package/src/lib/services/sets.js
CHANGED
|
@@ -10,7 +10,7 @@ const {
|
|
|
10
10
|
} = require('./../helpers/envResolution')
|
|
11
11
|
|
|
12
12
|
const {
|
|
13
|
-
|
|
13
|
+
keyNamesForEnvFile,
|
|
14
14
|
keyValues,
|
|
15
15
|
keyValuesSync
|
|
16
16
|
} = require('./../helpers/keyResolution')
|
|
@@ -131,7 +131,7 @@ class Sets {
|
|
|
131
131
|
let publicKey
|
|
132
132
|
let privateKey
|
|
133
133
|
|
|
134
|
-
const { publicKeyName, privateKeyName } =
|
|
134
|
+
const { publicKeyName, privateKeyName } = keyNamesForEnvFile(filepath)
|
|
135
135
|
const { publicKeyValue, privateKeyValue } = keyValuesSync(filepath, {
|
|
136
136
|
keysFilepath: this.envKeysFilepath,
|
|
137
137
|
noArmor: this.noArmor,
|
|
@@ -248,7 +248,7 @@ class Sets {
|
|
|
248
248
|
let publicKey
|
|
249
249
|
let privateKey
|
|
250
250
|
|
|
251
|
-
const { publicKeyName, privateKeyName } =
|
|
251
|
+
const { publicKeyName, privateKeyName } = keyNamesForEnvFile(filepath)
|
|
252
252
|
const { publicKeyValue, privateKeyValue } = await keyValues(filepath, {
|
|
253
253
|
keysFilepath: this.envKeysFilepath,
|
|
254
254
|
noArmor: this.noArmor,
|
|
@@ -1,204 +0,0 @@
|
|
|
1
|
-
const path = require('path')
|
|
2
|
-
const childProcess = require('child_process')
|
|
3
|
-
const util = require('util')
|
|
4
|
-
const { logger } = require('../../shared/logger')
|
|
5
|
-
|
|
6
|
-
const execFile = util.promisify(childProcess.execFile)
|
|
7
|
-
const BINARY_NAMES = ['dotenvx-armor', 'dotenvx-vlt', 'dotenvx-ops']
|
|
8
|
-
|
|
9
|
-
class Armor {
|
|
10
|
-
async status () {
|
|
11
|
-
if (this._isForcedOff()) return 'off'
|
|
12
|
-
|
|
13
|
-
const binary = await this._resolveBinary()
|
|
14
|
-
if (!binary) return 'off'
|
|
15
|
-
|
|
16
|
-
try {
|
|
17
|
-
return await this._exec(binary, ['status'])
|
|
18
|
-
} catch (_e) {
|
|
19
|
-
return 'off'
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
statusSync () {
|
|
24
|
-
if (this._isForcedOff()) return 'off'
|
|
25
|
-
|
|
26
|
-
const binary = this._resolveBinarySync()
|
|
27
|
-
if (!binary) return 'off'
|
|
28
|
-
|
|
29
|
-
try {
|
|
30
|
-
return this._execSync(binary, ['status'])
|
|
31
|
-
} catch (_e) {
|
|
32
|
-
return 'off'
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
async keypair (publicKey, options = {}) {
|
|
37
|
-
if (this._isForcedOff()) return {}
|
|
38
|
-
|
|
39
|
-
const binary = await this._resolveBinary()
|
|
40
|
-
if (!binary) return {}
|
|
41
|
-
|
|
42
|
-
const args = ['keypair']
|
|
43
|
-
if (options.noSpinner) args.push('--no-spinner')
|
|
44
|
-
if (options.token) args.push('--token', options.token)
|
|
45
|
-
if (options.envFilepath) args.push('-f', options.envFilepath)
|
|
46
|
-
if (options.command) args.push('--metadata', this._serializeMetadata(options))
|
|
47
|
-
if (publicKey) args.push(publicKey)
|
|
48
|
-
|
|
49
|
-
try {
|
|
50
|
-
return JSON.parse(await this._execInteractive(binary, args))
|
|
51
|
-
} catch (_e) {
|
|
52
|
-
return {}
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
keypairSync (publicKey, options = {}) {
|
|
57
|
-
if (this._isForcedOff()) return {}
|
|
58
|
-
|
|
59
|
-
const binary = this._resolveBinarySync()
|
|
60
|
-
if (!binary) return {}
|
|
61
|
-
|
|
62
|
-
const args = ['keypair']
|
|
63
|
-
if (options.noSpinner) args.push('--no-spinner')
|
|
64
|
-
if (options.token) args.push('--token', options.token)
|
|
65
|
-
if (options.envFilepath) args.push('-f', options.envFilepath)
|
|
66
|
-
if (options.command) args.push('--metadata', this._serializeMetadata(options))
|
|
67
|
-
if (publicKey) args.push(publicKey)
|
|
68
|
-
|
|
69
|
-
try {
|
|
70
|
-
return JSON.parse(this._execInteractiveSync(binary, args))
|
|
71
|
-
} catch (_e) {
|
|
72
|
-
return {}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
observe (payload) {
|
|
77
|
-
if (this._isForcedOff()) return
|
|
78
|
-
|
|
79
|
-
const binary = this._resolveBinarySync()
|
|
80
|
-
if (!binary) return
|
|
81
|
-
|
|
82
|
-
let status = 'off'
|
|
83
|
-
try {
|
|
84
|
-
status = this._execSync(binary, ['status'])
|
|
85
|
-
} catch (_e) {
|
|
86
|
-
return
|
|
87
|
-
}
|
|
88
|
-
if (status === 'off') return
|
|
89
|
-
|
|
90
|
-
const encoded = Buffer.from(JSON.stringify(payload)).toString('base64')
|
|
91
|
-
try {
|
|
92
|
-
const subprocess = childProcess.spawn(binary, ['observe', encoded], {
|
|
93
|
-
stdio: 'ignore',
|
|
94
|
-
detached: true
|
|
95
|
-
})
|
|
96
|
-
subprocess.unref()
|
|
97
|
-
} catch (_e) {
|
|
98
|
-
// noop
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
_serializeMetadata (options) {
|
|
103
|
-
return JSON.stringify({
|
|
104
|
-
command: this._serializeCommand(options.command)
|
|
105
|
-
})
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
_serializeCommand (command) {
|
|
109
|
-
if (Array.isArray(command)) return command.map((arg) => `${arg}`).join(' ')
|
|
110
|
-
return `${command}`
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
async _exec (binary, args) {
|
|
114
|
-
const { stdout, stderr } = await execFile(binary, args)
|
|
115
|
-
if (stderr && stderr.length > 0) {
|
|
116
|
-
process.stderr.write(stderr.toString())
|
|
117
|
-
}
|
|
118
|
-
return stdout.toString().trim()
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
_execSync (binary, args) {
|
|
122
|
-
logger.debug(binary)
|
|
123
|
-
logger.debug(args)
|
|
124
|
-
return childProcess.execFileSync(binary, args).toString().trim()
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
_execInteractive (binary, args) {
|
|
128
|
-
return new Promise((resolve, reject) => {
|
|
129
|
-
const spawnOptions = {
|
|
130
|
-
stdio: ['inherit', 'pipe', 'inherit']
|
|
131
|
-
}
|
|
132
|
-
const subprocess = childProcess.spawn(binary, args, spawnOptions)
|
|
133
|
-
let stdout = ''
|
|
134
|
-
|
|
135
|
-
subprocess.stdout.on('data', (data) => {
|
|
136
|
-
stdout += data.toString()
|
|
137
|
-
})
|
|
138
|
-
subprocess.on('error', reject)
|
|
139
|
-
subprocess.on('close', (code) => {
|
|
140
|
-
if (code !== 0) {
|
|
141
|
-
reject(new Error(`${binary} ${args.join(' ')} exited with code ${code}`))
|
|
142
|
-
return
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
resolve(stdout.trim())
|
|
146
|
-
})
|
|
147
|
-
})
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
_execInteractiveSync (binary, args) {
|
|
151
|
-
logger.debug(binary)
|
|
152
|
-
logger.debug(args)
|
|
153
|
-
return childProcess.execFileSync(binary, args, {
|
|
154
|
-
stdio: ['inherit', 'pipe', 'inherit']
|
|
155
|
-
}).toString().trim()
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
async _resolveBinary () {
|
|
159
|
-
if (this._binaryPromise) return this._binaryPromise
|
|
160
|
-
|
|
161
|
-
this._binaryPromise = (async () => {
|
|
162
|
-
for (const binary of this._binaryCandidates()) {
|
|
163
|
-
try {
|
|
164
|
-
await this._exec(binary, ['--version'])
|
|
165
|
-
return binary
|
|
166
|
-
} catch (_e) {}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
return null
|
|
170
|
-
})()
|
|
171
|
-
|
|
172
|
-
return this._binaryPromise
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
_resolveBinarySync () {
|
|
176
|
-
if (this._binarySync !== undefined) return this._binarySync
|
|
177
|
-
|
|
178
|
-
for (const binary of this._binaryCandidates()) {
|
|
179
|
-
try {
|
|
180
|
-
this._execSync(binary, ['--version'])
|
|
181
|
-
this._binarySync = binary
|
|
182
|
-
return this._binarySync
|
|
183
|
-
} catch (err) {
|
|
184
|
-
logger.debug(err.message)
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
this._binarySync = null
|
|
189
|
-
return null
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
_binaryCandidates () {
|
|
193
|
-
return BINARY_NAMES.flatMap((binary) => [
|
|
194
|
-
path.resolve(process.cwd(), `node_modules/.bin/${binary}`),
|
|
195
|
-
binary
|
|
196
|
-
])
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
_isForcedOff () {
|
|
200
|
-
return process.env.DOTENVX_NO_ARMOR === 'true' || process.env.DOTENVX_NO_VLT === 'true' || process.env.DOTENVX_NO_OPS === 'true'
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
module.exports = Armor
|