@dotenvx/dotenvx 1.71.2 → 1.72.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 +15 -1
- package/README.md +2 -2
- package/package.json +8 -3
- package/src/cli/actions/decrypt.js +7 -3
- package/src/cli/actions/encrypt.js +9 -3
- package/src/cli/actions/get.js +3 -1
- package/src/cli/actions/keypair.js +3 -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/rotate.js +6 -2
- package/src/cli/actions/run.js +2 -1
- package/src/cli/actions/set.js +4 -2
- package/src/cli/dotenvx.js +14 -19
- package/src/db/device.js +73 -0
- package/src/db/session.js +186 -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/extensions/armor.js +13 -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 +2 -1
- 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/keyValues.js +3 -0
- package/src/lib/helpers/keyResolution/keyValuesFromEnvSrc.js +3 -0
- package/src/lib/helpers/keyResolution/keyValuesSync.js +3 -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/main.d.ts +0 -24
- package/src/lib/main.js +1 -1
- package/src/lib/services/decrypt.js +7 -2
- package/src/lib/services/encrypt.js +5 -2
- package/src/lib/services/get.js +8 -3
- package/src/lib/services/keypair.js +12 -3
- 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 +10 -3
- package/src/lib/services/run.js +12 -3
- package/src/lib/services/sets.js +26 -5
package/src/db/session.js
CHANGED
|
@@ -1,9 +1,139 @@
|
|
|
1
|
+
const fs = require('fs')
|
|
2
|
+
const path = require('path')
|
|
3
|
+
const Conf = require('conf')
|
|
4
|
+
const dotenv = require('dotenv')
|
|
5
|
+
const envPaths = require('env-paths')
|
|
6
|
+
|
|
1
7
|
const Armor = require('./../lib/extensions/armor')
|
|
8
|
+
const jsonToEnv = require('./../lib/helpers/jsonToEnv')
|
|
2
9
|
const { logger } = require('./../shared/logger')
|
|
3
10
|
|
|
11
|
+
const ARMOR = {
|
|
12
|
+
HOSTNAME: 'DOTENVX_ARMOR_HOSTNAME',
|
|
13
|
+
USER: 'DOTENVX_ARMOR_USER',
|
|
14
|
+
USERNAME: 'DOTENVX_ARMOR_USERNAME',
|
|
15
|
+
TOKEN: 'DOTENVX_ARMOR_TOKEN',
|
|
16
|
+
ON: 'DOTENVX_ARMOR_ON',
|
|
17
|
+
VERSION: 'DOTENVX_ARMOR_VERSION',
|
|
18
|
+
VERSION_LAST_CHECK: 'DOTENVX_ARMOR_VERSION_LAST_CHECK'
|
|
19
|
+
}
|
|
20
|
+
|
|
4
21
|
class Session {
|
|
5
22
|
constructor () {
|
|
6
23
|
this.armor = new Armor()
|
|
24
|
+
this._store = null
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
_configPath () {
|
|
28
|
+
const cwd = process.env.DOTENVX_CONFIG || this._defaultConfigCwd()
|
|
29
|
+
return path.resolve(cwd, '.env')
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
_defaultConfigCwd () {
|
|
33
|
+
return envPaths('dotenvx', { suffix: '' }).config
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
_configExists () {
|
|
37
|
+
return fs.existsSync(this._configPath())
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
_newStore () {
|
|
41
|
+
return new Conf({
|
|
42
|
+
cwd: process.env.DOTENVX_CONFIG || undefined,
|
|
43
|
+
projectName: 'dotenvx',
|
|
44
|
+
configName: '.env',
|
|
45
|
+
projectSuffix: '',
|
|
46
|
+
fileExtension: '',
|
|
47
|
+
serialize: function (json) {
|
|
48
|
+
return jsonToEnv(json)
|
|
49
|
+
},
|
|
50
|
+
// Convert .env format to an object
|
|
51
|
+
deserialize: function (env) {
|
|
52
|
+
return dotenv.parse(env)
|
|
53
|
+
}
|
|
54
|
+
})
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
createStore () {
|
|
58
|
+
if (!this._store) this._store = this._newStore()
|
|
59
|
+
return this._store
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
openStore () {
|
|
63
|
+
if (!this._store && !this._configExists()) {
|
|
64
|
+
return null
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (!this._store) this._store = this._newStore()
|
|
68
|
+
return this._store
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
get store () {
|
|
72
|
+
return this.openStore()
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
status () {
|
|
76
|
+
// if logged in
|
|
77
|
+
if (this.username() && this.token() && this.on()) {
|
|
78
|
+
return 'on'
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return 'off'
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
//
|
|
85
|
+
// Get
|
|
86
|
+
//
|
|
87
|
+
readSetting (key) {
|
|
88
|
+
const store = this.openStore()
|
|
89
|
+
if (!store) return undefined
|
|
90
|
+
|
|
91
|
+
return store.get(ARMOR[key])
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
hostname () {
|
|
95
|
+
return this.readSetting('HOSTNAME') || 'https://armor.dotenvx.com'
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
username () {
|
|
99
|
+
return this.readSetting('USERNAME') || undefined
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
token () {
|
|
103
|
+
return this.readSetting('TOKEN') || undefined
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
devicePublicKey () {
|
|
107
|
+
const Device = require('./device')
|
|
108
|
+
return new Device().publicKey()
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
path () {
|
|
112
|
+
return this._store ? this._store.path : this._configPath()
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
on () {
|
|
116
|
+
return (this.readSetting('ON') || 'true') === 'true'
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
off () {
|
|
120
|
+
return (this.readSetting('ON') || 'true') === 'false'
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async systemInformation () {
|
|
124
|
+
const si = require('systeminformation')
|
|
125
|
+
const system = await si.system()
|
|
126
|
+
const osInfo = await si.osInfo()
|
|
127
|
+
|
|
128
|
+
return {
|
|
129
|
+
system_uuid: system.uuid,
|
|
130
|
+
os_platform: osInfo.platform,
|
|
131
|
+
os_arch: osInfo.arch
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
async notifyUpdate () {
|
|
136
|
+
// native login keeps this lightweight; sidecar commands still handle full update messaging
|
|
7
137
|
}
|
|
8
138
|
|
|
9
139
|
//
|
|
@@ -20,6 +150,62 @@ class Session {
|
|
|
20
150
|
logger.debug(`armor: ${status}`)
|
|
21
151
|
return status === 'off'
|
|
22
152
|
}
|
|
153
|
+
|
|
154
|
+
//
|
|
155
|
+
// Set/Delete
|
|
156
|
+
//
|
|
157
|
+
login (hostname, id, username, accessToken) {
|
|
158
|
+
if (!hostname) {
|
|
159
|
+
throw new Error('DOTENVX_ARMOR_HOSTNAME not set. Run [dotenvx login]')
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (!id) {
|
|
163
|
+
throw new Error('DOTENVX_ARMOR_USER not set. Run [dotenvx login]')
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (!username) {
|
|
167
|
+
throw new Error('DOTENVX_ARMOR_USERNAME not set. Run [dotenvx login]')
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (!accessToken) {
|
|
171
|
+
throw new Error('DOTENVX_ARMOR_TOKEN not set. Run [dotenvx login]')
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const store = this.createStore()
|
|
175
|
+
store.set(ARMOR.USER, id)
|
|
176
|
+
store.set(ARMOR.USERNAME, username)
|
|
177
|
+
store.set(ARMOR.TOKEN, accessToken)
|
|
178
|
+
store.set(ARMOR.HOSTNAME, hostname)
|
|
179
|
+
store.set(ARMOR.ON, 'true')
|
|
180
|
+
|
|
181
|
+
return accessToken
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
logout (hostname, id, accessToken) {
|
|
185
|
+
if (!hostname) {
|
|
186
|
+
throw new Error('DOTENVX_ARMOR_HOSTNAME not set. Run [dotenvx login]')
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (!id) {
|
|
190
|
+
throw new Error('DOTENVX_ARMOR_USER not set. Run [dotenvx login]')
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (!accessToken) {
|
|
194
|
+
throw new Error('DOTENVX_ARMOR_TOKEN not set. Run [dotenvx login]')
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const store = this.openStore()
|
|
198
|
+
if (!store) return true
|
|
199
|
+
|
|
200
|
+
store.delete(ARMOR.USER)
|
|
201
|
+
store.delete(ARMOR.USERNAME)
|
|
202
|
+
store.delete(ARMOR.TOKEN)
|
|
203
|
+
store.delete(ARMOR.HOSTNAME)
|
|
204
|
+
store.delete(ARMOR.ON)
|
|
205
|
+
store.delete(ARMOR.VERSION)
|
|
206
|
+
store.delete(ARMOR.VERSION_LAST_CHECK)
|
|
207
|
+
return true
|
|
208
|
+
}
|
|
23
209
|
}
|
|
24
210
|
|
|
25
211
|
module.exports = Session
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
const { http } = require('../helpers/http')
|
|
2
|
+
const buildApiError = require('../helpers/buildApiError')
|
|
3
|
+
const normalizeToken = require('../helpers/normalizeToken')
|
|
4
|
+
|
|
5
|
+
class PostLogout {
|
|
6
|
+
constructor (hostname, token) {
|
|
7
|
+
this.hostname = hostname
|
|
8
|
+
this.token = token
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
async run () {
|
|
12
|
+
const token = normalizeToken(this.token)
|
|
13
|
+
const url = `${this.hostname}/api/logout`
|
|
14
|
+
|
|
15
|
+
const resp = await http(url, {
|
|
16
|
+
method: 'POST',
|
|
17
|
+
headers: {
|
|
18
|
+
Authorization: `Bearer ${token}`,
|
|
19
|
+
'Content-Type': 'application/json'
|
|
20
|
+
},
|
|
21
|
+
body: JSON.stringify({})
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
const json = await resp.body.json()
|
|
25
|
+
|
|
26
|
+
if (resp.statusCode >= 400) {
|
|
27
|
+
throw buildApiError(resp.statusCode, json)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return json
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
module.exports = PostLogout
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
const { http } = require('../helpers/http')
|
|
2
|
+
const buildOauthError = require('../helpers/buildOauthError')
|
|
3
|
+
|
|
4
|
+
const OAUTH_CLIENT_ID = 'oac_dotenvxcli'
|
|
5
|
+
|
|
6
|
+
class PostOauthDeviceCode {
|
|
7
|
+
constructor (hostname, devicePublicKey, systemInformation, dotenvxProjectId = null) {
|
|
8
|
+
this.hostname = hostname
|
|
9
|
+
this.devicePublicKey = devicePublicKey
|
|
10
|
+
this.systemInformation = systemInformation
|
|
11
|
+
this.dotenvxProjectId = dotenvxProjectId
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
async run () {
|
|
15
|
+
const resp = await http(`${this.hostname}/oauth/device/code`, {
|
|
16
|
+
method: 'POST',
|
|
17
|
+
headers: {
|
|
18
|
+
'Content-Type': 'application/json'
|
|
19
|
+
},
|
|
20
|
+
body: JSON.stringify({
|
|
21
|
+
client_id: OAUTH_CLIENT_ID,
|
|
22
|
+
device_public_key: this.devicePublicKey,
|
|
23
|
+
system_information: this.systemInformation,
|
|
24
|
+
dotenvx_project_id: this.dotenvxProjectId
|
|
25
|
+
})
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
const json = await resp.body.json()
|
|
29
|
+
|
|
30
|
+
if (resp.statusCode >= 400) {
|
|
31
|
+
throw buildOauthError(resp.statusCode, json)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return json
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
module.exports = PostOauthDeviceCode
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
const { http } = require('../helpers/http')
|
|
2
|
+
const buildOauthError = require('../helpers/buildOauthError')
|
|
3
|
+
|
|
4
|
+
const OAUTH_CLIENT_ID = 'oac_dotenvxcli'
|
|
5
|
+
|
|
6
|
+
class PostOauthToken {
|
|
7
|
+
constructor (hostname, deviceCode) {
|
|
8
|
+
this.hostname = hostname
|
|
9
|
+
this.deviceCode = deviceCode
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
async run () {
|
|
13
|
+
const resp = await http(`${this.hostname}/oauth/token`, {
|
|
14
|
+
method: 'POST',
|
|
15
|
+
headers: {
|
|
16
|
+
'Content-Type': 'application/json'
|
|
17
|
+
},
|
|
18
|
+
body: JSON.stringify({
|
|
19
|
+
client_id: OAUTH_CLIENT_ID,
|
|
20
|
+
device_code: this.deviceCode,
|
|
21
|
+
grant_type: 'urn:ietf:params:oauth:grant-type:device_code'
|
|
22
|
+
})
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
const json = await resp.body.json()
|
|
26
|
+
|
|
27
|
+
if (resp.statusCode >= 400) {
|
|
28
|
+
throw buildOauthError(resp.statusCode, json)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return json
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
module.exports = PostOauthToken
|
|
@@ -43,6 +43,7 @@ class Armor {
|
|
|
43
43
|
if (options.noSpinner) args.push('--no-spinner')
|
|
44
44
|
if (options.token) args.push('--token', options.token)
|
|
45
45
|
if (options.envFilepath) args.push('-f', options.envFilepath)
|
|
46
|
+
if (options.command) args.push('--metadata', this._serializeMetadata(options))
|
|
46
47
|
if (publicKey) args.push(publicKey)
|
|
47
48
|
|
|
48
49
|
try {
|
|
@@ -62,6 +63,7 @@ class Armor {
|
|
|
62
63
|
if (options.noSpinner) args.push('--no-spinner')
|
|
63
64
|
if (options.token) args.push('--token', options.token)
|
|
64
65
|
if (options.envFilepath) args.push('-f', options.envFilepath)
|
|
66
|
+
if (options.command) args.push('--metadata', this._serializeMetadata(options))
|
|
65
67
|
if (publicKey) args.push(publicKey)
|
|
66
68
|
|
|
67
69
|
try {
|
|
@@ -97,6 +99,17 @@ class Armor {
|
|
|
97
99
|
}
|
|
98
100
|
}
|
|
99
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
|
+
|
|
100
113
|
async _exec (binary, args) {
|
|
101
114
|
const { stdout, stderr } = await execFile(binary, args)
|
|
102
115
|
if (stderr && stderr.length > 0) {
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
function buildApiError (statusCode, json) {
|
|
2
|
+
const code = json.error.code || statusCode.toString()
|
|
3
|
+
const message = `[${code}] ${json.error.message}`
|
|
4
|
+
const help = `[${code}] ${json.error.help || JSON.stringify(json)}`
|
|
5
|
+
const meta = json.error.meta
|
|
6
|
+
|
|
7
|
+
const error = new Error(message)
|
|
8
|
+
error.code = code
|
|
9
|
+
error.help = help
|
|
10
|
+
error.meta = meta
|
|
11
|
+
error.json = json
|
|
12
|
+
|
|
13
|
+
return error
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
module.exports = buildApiError
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
function buildOauthError (statusCode, json) {
|
|
2
|
+
const code = json.error
|
|
3
|
+
const message = `[${code}] ${json.error_description}`
|
|
4
|
+
const help = `[${code}] ${JSON.stringify(json)}`
|
|
5
|
+
|
|
6
|
+
const error = new Error(message)
|
|
7
|
+
error.code = code
|
|
8
|
+
error.help = help
|
|
9
|
+
error.statusCode = statusCode
|
|
10
|
+
|
|
11
|
+
return error
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
module.exports = buildOauthError
|
|
@@ -4,7 +4,7 @@ const FRAME_INTERVAL_MS = 80
|
|
|
4
4
|
async function createSpinner (options = {}) {
|
|
5
5
|
const stream = process.stderr
|
|
6
6
|
const hasCursorControls = typeof stream.cursorTo === 'function' && typeof stream.clearLine === 'function'
|
|
7
|
-
const enabled = Boolean(stream.isTTY && hasCursorControls && !options.quiet && !options.verbose && !options.debug)
|
|
7
|
+
const enabled = Boolean(stream.isTTY && hasCursorControls && options.spinner !== false && !options.quiet && !options.verbose && !options.debug)
|
|
8
8
|
if (!enabled) return null
|
|
9
9
|
|
|
10
10
|
const text = options.text || 'thinking'
|
|
@@ -3,7 +3,8 @@ const Armor = require('../../extensions/armor')
|
|
|
3
3
|
async function armorKeypair (existingPublicKey, options = {}) {
|
|
4
4
|
const keypairOptions = {
|
|
5
5
|
token: options.token,
|
|
6
|
-
envFilepath: options.envFilepath
|
|
6
|
+
envFilepath: options.envFilepath,
|
|
7
|
+
command: options.command
|
|
7
8
|
}
|
|
8
9
|
|
|
9
10
|
const kp = await new Armor().keypair(existingPublicKey, keypairOptions)
|
|
@@ -4,7 +4,7 @@ const armorKeypair = require('./armorKeypair')
|
|
|
4
4
|
const localKeypair = require('./localKeypair')
|
|
5
5
|
const { keyNames } = require('../keyResolution')
|
|
6
6
|
|
|
7
|
-
async function provision ({ envSrc, envFilepath, keysFilepath, noArmor, token, selectKeyStorage }) {
|
|
7
|
+
async function provision ({ envSrc, envFilepath, keysFilepath, noArmor, token, selectKeyStorage, command }) {
|
|
8
8
|
noArmor = noArmor !== false
|
|
9
9
|
if (!noArmor && selectKeyStorage) {
|
|
10
10
|
noArmor = await selectKeyStorage() !== 'armored'
|
|
@@ -24,7 +24,7 @@ async function provision ({ envSrc, envFilepath, keysFilepath, noArmor, token, s
|
|
|
24
24
|
publicKey = kp.publicKey
|
|
25
25
|
privateKey = kp.privateKey
|
|
26
26
|
} else {
|
|
27
|
-
const armorOptions = { token, envFilepath }
|
|
27
|
+
const armorOptions = { token, envFilepath, command }
|
|
28
28
|
const kp = await armorKeypair(undefined, armorOptions)
|
|
29
29
|
publicKey = kp.publicKey
|
|
30
30
|
privateKey = kp.privateKey
|
|
@@ -4,7 +4,7 @@ const armorKeypairSync = require('./armorKeypairSync')
|
|
|
4
4
|
const localKeypair = require('./localKeypair')
|
|
5
5
|
const { keyNames } = require('../keyResolution')
|
|
6
6
|
|
|
7
|
-
function provisionSync ({ envSrc, envFilepath, keysFilepath, noArmor }) {
|
|
7
|
+
function provisionSync ({ envSrc, envFilepath, keysFilepath, noArmor, command }) {
|
|
8
8
|
noArmor = noArmor !== false
|
|
9
9
|
const { publicKeyName, privateKeyName } = keyNames(envFilepath)
|
|
10
10
|
|
|
@@ -20,7 +20,7 @@ function provisionSync ({ envSrc, envFilepath, keysFilepath, noArmor }) {
|
|
|
20
20
|
publicKey = kp.publicKey
|
|
21
21
|
privateKey = kp.privateKey
|
|
22
22
|
} else {
|
|
23
|
-
const kp = armorKeypairSync(undefined, { envFilepath })
|
|
23
|
+
const kp = armorKeypairSync(undefined, { envFilepath, command })
|
|
24
24
|
publicKey = kp.publicKey
|
|
25
25
|
privateKey = kp.privateKey
|
|
26
26
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
const { decrypt } = require('eciesjs')
|
|
2
|
+
|
|
3
|
+
function decryptDeviceValue (value, privateKey) {
|
|
4
|
+
const secret = Buffer.from(privateKey, 'hex')
|
|
5
|
+
const ciphertext = Buffer.from(value, 'base64')
|
|
6
|
+
|
|
7
|
+
return decrypt(secret, ciphertext).toString()
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
module.exports = decryptDeviceValue
|
|
@@ -77,6 +77,9 @@ async function keyValues (filepath, opts = {}) {
|
|
|
77
77
|
if (opts.token) {
|
|
78
78
|
armorOptions.token = opts.token
|
|
79
79
|
}
|
|
80
|
+
if (opts.command) {
|
|
81
|
+
armorOptions.command = opts.command
|
|
82
|
+
}
|
|
80
83
|
const kp = await armorKeypair(publicKey, armorOptions)
|
|
81
84
|
privateKey = kp.privateKey
|
|
82
85
|
privateKeySource = 'armor'
|
|
@@ -57,6 +57,9 @@ function keyValuesFromEnvSrc (src, privateKeyName = null, opts = {}) {
|
|
|
57
57
|
if (opts.token) {
|
|
58
58
|
armorOptions.token = opts.token
|
|
59
59
|
}
|
|
60
|
+
if (opts.command) {
|
|
61
|
+
armorOptions.command = opts.command
|
|
62
|
+
}
|
|
60
63
|
const kp = armorKeypairSync(publicKeyValue, armorOptions)
|
|
61
64
|
privateKeyValue = kp.privateKey
|
|
62
65
|
privateKeySource = 'armor'
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
function listenForOpenKey (onOpen) {
|
|
2
|
+
const stdin = process.stdin
|
|
3
|
+
if (!stdin.isTTY) return () => {}
|
|
4
|
+
|
|
5
|
+
const canSetRawMode = typeof stdin.setRawMode === 'function'
|
|
6
|
+
const wasRawMode = Boolean(stdin.isRaw)
|
|
7
|
+
let didHandleOpenChoice = false
|
|
8
|
+
|
|
9
|
+
const cleanup = () => {
|
|
10
|
+
stdin.off('data', onData)
|
|
11
|
+
if (canSetRawMode) stdin.setRawMode(wasRawMode)
|
|
12
|
+
stdin.pause()
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const onData = (chunk) => {
|
|
16
|
+
const key = String(chunk)
|
|
17
|
+
const lower = key.toLowerCase()
|
|
18
|
+
|
|
19
|
+
if (key === '\u0003') {
|
|
20
|
+
cleanup()
|
|
21
|
+
process.kill(process.pid, 'SIGINT')
|
|
22
|
+
return
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (key === '\r' || key === '\n' || lower === 'y') {
|
|
26
|
+
if (!didHandleOpenChoice) {
|
|
27
|
+
didHandleOpenChoice = true
|
|
28
|
+
Promise.resolve(onOpen()).catch(() => {})
|
|
29
|
+
}
|
|
30
|
+
return
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (lower === 'n') {
|
|
34
|
+
cleanup()
|
|
35
|
+
process.kill(process.pid, 'SIGINT')
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (canSetRawMode) stdin.setRawMode(true)
|
|
40
|
+
stdin.resume()
|
|
41
|
+
stdin.on('data', onData)
|
|
42
|
+
|
|
43
|
+
return cleanup
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
module.exports = listenForOpenKey
|
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 = {
|
|
@@ -25,12 +25,13 @@ const dotenvParse = require('./../helpers/dotenvParse')
|
|
|
25
25
|
const detectEncoding = require('./../helpers/detectEncoding')
|
|
26
26
|
|
|
27
27
|
class Decrypt {
|
|
28
|
-
constructor (envs = [], key = [], excludeKey = [], envKeysFilepath = null, noArmor = false) {
|
|
28
|
+
constructor (envs = [], key = [], excludeKey = [], envKeysFilepath = null, noArmor = false, options = {}) {
|
|
29
29
|
this.envs = determine(envs, process.env)
|
|
30
30
|
this.key = key
|
|
31
31
|
this.excludeKey = excludeKey
|
|
32
32
|
this.envKeysFilepath = envKeysFilepath
|
|
33
33
|
this.noArmor = noArmor
|
|
34
|
+
this.command = options.command
|
|
34
35
|
|
|
35
36
|
this.processedEnvs = []
|
|
36
37
|
this.changedFilepaths = new Set()
|
|
@@ -77,7 +78,11 @@ class Decrypt {
|
|
|
77
78
|
const envParsed = dotenvParse(envSrc, false, false, true)
|
|
78
79
|
|
|
79
80
|
const { privateKeyName } = keyNames(envFilepath)
|
|
80
|
-
const { privateKeyValue, privateKeySource } = await keyValues(envFilepath, {
|
|
81
|
+
const { privateKeyValue, privateKeySource } = await keyValues(envFilepath, {
|
|
82
|
+
keysFilepath: this.envKeysFilepath,
|
|
83
|
+
noArmor: this.noArmor,
|
|
84
|
+
command: this.command
|
|
85
|
+
})
|
|
81
86
|
|
|
82
87
|
row.privateKey = privateKeyValue
|
|
83
88
|
row.privateKeySource = privateKeySource
|