@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
package/CHANGELOG.md
CHANGED
|
@@ -2,7 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
-
[Unreleased](https://github.com/dotenvx/dotenvx/compare/v1.
|
|
5
|
+
[Unreleased](https://github.com/dotenvx/dotenvx/compare/v1.73.0...main)
|
|
6
|
+
|
|
7
|
+
## [1.73.0](https://github.com/dotenvx/dotenvx/compare/v1.72.0...v1.73.0) (2026-06-16)
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
* Add `dotenvx armor` commands directly inside dotenvx ([#839](https://github.com/dotenvx/dotenvx/pull/839))
|
|
12
|
+
|
|
13
|
+
> `dotenvx` remains local-first: `armor` commands are optional under professional security section
|
|
14
|
+
|
|
15
|
+
## [1.72.0](https://github.com/dotenvx/dotenvx/compare/v1.71.3...v1.72.0) (2026-06-15)
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
|
|
19
|
+
* Move `armor login` command to first class `dotenvx login` command. ([#836](https://github.com/dotenvx/dotenvx/pull/836))
|
|
20
|
+
* `dotenvx` remains local-first: login is optional and only needed when you want Armor features like moving keys off-device, team sharing, and audit access.
|
|
21
|
+
* Patch 2 high severity dependencies ([#837](https://github.com/dotenvx/dotenvx/pull/837))
|
|
6
22
|
|
|
7
23
|
## [1.71.3](https://github.com/dotenvx/dotenvx/compare/v1.71.2...v1.71.3) (2026-06-11)
|
|
8
24
|
|
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
|
|
14
|
-
### Quickstart [](https://www.npmjs.com/package/@dotenvx/dotenvx) [](https://www.npmjs.com/package/@dotenvx/dotenvx)
|
|
14
|
+
### Quickstart [](https://www.npmjs.com/package/@dotenvx/dotenvx) [](https://www.npmjs.com/package/@dotenvx/dotenvx)
|
|
15
15
|
|
|
16
16
|
Install and use it in code just like `dotenv`.
|
|
17
17
|
|
|
@@ -2119,8 +2119,8 @@ Commands:
|
|
|
2119
2119
|
run inject env at runtime [dotenvx run -- yourcommand]
|
|
2120
2120
|
get [KEY] return a single environment variable
|
|
2121
2121
|
set <KEY> <value> set a single environment variable
|
|
2122
|
-
encrypt
|
|
2123
|
-
decrypt
|
|
2122
|
+
encrypt encrypt .env file(s)
|
|
2123
|
+
decrypt decrypt .env file(s)
|
|
2124
2124
|
keypair [KEY] print public/private keys for .env file(s)
|
|
2125
2125
|
ls [directory] print all .env files in a tree structure
|
|
2126
2126
|
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.
|
|
2
|
+
"version": "1.73.0",
|
|
3
3
|
"name": "@dotenvx/dotenvx",
|
|
4
4
|
"description": "a secure dotenv–from the creator of `dotenv`",
|
|
5
5
|
"author": "@motdotla",
|
|
@@ -36,7 +36,6 @@
|
|
|
36
36
|
"standard": "standard",
|
|
37
37
|
"standard:fix": "standard --fix",
|
|
38
38
|
"test": "tap run --test-env=DOTENVX_NO_ARMOR=true --allow-empty-coverage --disable-coverage --timeout=60000",
|
|
39
|
-
"test-coverage": "tap run --test-env=DOTENVX_NO_ARMOR=true --show-full-coverage --timeout=60000",
|
|
40
39
|
"testshell": "bash shellspec",
|
|
41
40
|
"release:check": "npm test && npm run testshell",
|
|
42
41
|
"prerelease": "npm run release:check",
|
|
@@ -45,21 +44,26 @@
|
|
|
45
44
|
"funding": "https://dotenvx.com",
|
|
46
45
|
"dependencies": {
|
|
47
46
|
"commander": "^11.1.0",
|
|
47
|
+
"conf": "^10.2.0",
|
|
48
48
|
"dotenv": "^17.2.1",
|
|
49
49
|
"eciesjs": "^0.4.10",
|
|
50
50
|
"enquirer": "^2.4.1",
|
|
51
|
+
"env-paths": "^2.2.1",
|
|
51
52
|
"execa": "^5.1.1",
|
|
52
53
|
"fdir": "^6.2.0",
|
|
53
54
|
"ignore": "^5.3.0",
|
|
54
55
|
"object-treeify": "1.1.33",
|
|
56
|
+
"open": "^8.4.2",
|
|
55
57
|
"picomatch": "^4.0.4",
|
|
58
|
+
"systeminformation": "^5.22.11",
|
|
59
|
+
"undici": "^7.11.0",
|
|
56
60
|
"which": "^4.0.0",
|
|
57
61
|
"yocto-spinner": "^1.1.0"
|
|
58
62
|
},
|
|
59
63
|
"devDependencies": {
|
|
60
|
-
"@yao-pkg/pkg": "^6.
|
|
64
|
+
"@yao-pkg/pkg": "^6.12.0",
|
|
61
65
|
"capture-console": "^1.0.2",
|
|
62
|
-
"esbuild": "^0.
|
|
66
|
+
"esbuild": "^0.28.1",
|
|
63
67
|
"proxyquire": "^2.1.3",
|
|
64
68
|
"sinon": "^14.0.1",
|
|
65
69
|
"standard": "^17.1.0",
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
const { logger } = require('../../../shared/logger')
|
|
2
|
+
const Session = require('./../../../db/session')
|
|
3
|
+
const ArmorDown = require('./../../../lib/services/armorDown')
|
|
4
|
+
const createSpinner = require('../../../lib/helpers/createSpinner')
|
|
5
|
+
const armoredKeyDisplay = require('../../../lib/helpers/armoredKeyDisplay')
|
|
6
|
+
|
|
7
|
+
async function down () {
|
|
8
|
+
const options = this.opts()
|
|
9
|
+
const spinner = await createSpinner({ ...options, text: 'dearmoring' })
|
|
10
|
+
|
|
11
|
+
logger.debug(`options: ${JSON.stringify(options)}`)
|
|
12
|
+
|
|
13
|
+
const sesh = new Session()
|
|
14
|
+
await sesh.notifyUpdate()
|
|
15
|
+
const hostname = options.hostname || sesh.hostname()
|
|
16
|
+
const token = options.token || sesh.token()
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
const devicePublicKey = sesh.devicePublicKey()
|
|
20
|
+
|
|
21
|
+
const { changed, privateKeyName, publicKeyValue } = await new ArmorDown(hostname, token, devicePublicKey, options.envFile, options.team).run()
|
|
22
|
+
const keyDisplay = armoredKeyDisplay(publicKeyValue) || privateKeyName
|
|
23
|
+
|
|
24
|
+
if (spinner) spinner.stop()
|
|
25
|
+
if (changed) {
|
|
26
|
+
logger.success(`◇ dearmored to .env.keys (${keyDisplay})`)
|
|
27
|
+
} else {
|
|
28
|
+
logger.info(`○ no change (${keyDisplay})`)
|
|
29
|
+
}
|
|
30
|
+
} catch (error) {
|
|
31
|
+
if (spinner) spinner.stop()
|
|
32
|
+
logger.error(error.message)
|
|
33
|
+
process.exit(1)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
module.exports = down
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
const { logger } = require('../../../shared/logger')
|
|
2
|
+
const Session = require('./../../../db/session')
|
|
3
|
+
const ArmorMove = require('./../../../lib/services/armorMove')
|
|
4
|
+
const createSpinner = require('../../../lib/helpers/createSpinner')
|
|
5
|
+
const armoredKeyDisplay = require('../../../lib/helpers/armoredKeyDisplay')
|
|
6
|
+
|
|
7
|
+
async function move () {
|
|
8
|
+
const options = this.opts()
|
|
9
|
+
const spinner = await createSpinner({ ...options, text: 'moving' })
|
|
10
|
+
|
|
11
|
+
logger.debug(`options: ${JSON.stringify(options)}`)
|
|
12
|
+
|
|
13
|
+
const sesh = new Session()
|
|
14
|
+
await sesh.notifyUpdate()
|
|
15
|
+
const hostname = options.hostname || sesh.hostname()
|
|
16
|
+
const token = options.token || sesh.token()
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
const devicePublicKey = sesh.devicePublicKey()
|
|
20
|
+
|
|
21
|
+
const {
|
|
22
|
+
changed,
|
|
23
|
+
privateKeyName,
|
|
24
|
+
publicKeyValue,
|
|
25
|
+
team
|
|
26
|
+
} = await new ArmorMove(hostname, token, devicePublicKey, options.envFile).run()
|
|
27
|
+
const keyDisplay = armoredKeyDisplay(publicKeyValue) || privateKeyName
|
|
28
|
+
|
|
29
|
+
if (spinner) spinner.stop()
|
|
30
|
+
if (changed) {
|
|
31
|
+
logger.success(`⛨ moved to ${team} (${keyDisplay})`)
|
|
32
|
+
} else {
|
|
33
|
+
logger.info(`○ no change (${keyDisplay})`)
|
|
34
|
+
}
|
|
35
|
+
} catch (error) {
|
|
36
|
+
if (spinner) spinner.stop()
|
|
37
|
+
logger.error(error.message)
|
|
38
|
+
process.exit(1)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
module.exports = move
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
const { logger } = require('../../../shared/logger')
|
|
2
|
+
const Session = require('./../../../db/session')
|
|
3
|
+
const ArmorPull = require('./../../../lib/services/armorPull')
|
|
4
|
+
const createSpinner = require('../../../lib/helpers/createSpinner')
|
|
5
|
+
const armoredKeyDisplay = require('../../../lib/helpers/armoredKeyDisplay')
|
|
6
|
+
|
|
7
|
+
async function pull () {
|
|
8
|
+
const options = this.opts()
|
|
9
|
+
const spinner = await createSpinner({ ...options, text: 'pulling' })
|
|
10
|
+
|
|
11
|
+
logger.debug(`options: ${JSON.stringify(options)}`)
|
|
12
|
+
|
|
13
|
+
const sesh = new Session()
|
|
14
|
+
await sesh.notifyUpdate()
|
|
15
|
+
const hostname = options.hostname || sesh.hostname()
|
|
16
|
+
const token = options.token || sesh.token()
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
const devicePublicKey = sesh.devicePublicKey()
|
|
20
|
+
|
|
21
|
+
const { changed, privateKeyName, publicKeyValue } = await new ArmorPull(hostname, token, devicePublicKey, options.envFile, options.team).run()
|
|
22
|
+
const keyDisplay = armoredKeyDisplay(publicKeyValue) || privateKeyName
|
|
23
|
+
|
|
24
|
+
if (spinner) spinner.stop()
|
|
25
|
+
if (changed) {
|
|
26
|
+
logger.success(`◇ pulled to .env.keys (${keyDisplay})`)
|
|
27
|
+
} else {
|
|
28
|
+
logger.info(`○ no change (${keyDisplay})`)
|
|
29
|
+
}
|
|
30
|
+
} catch (error) {
|
|
31
|
+
if (spinner) spinner.stop()
|
|
32
|
+
logger.error(error.message)
|
|
33
|
+
process.exit(1)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
module.exports = pull
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
const { logger } = require('../../../shared/logger')
|
|
2
|
+
const Session = require('./../../../db/session')
|
|
3
|
+
const ArmorPush = require('./../../../lib/services/armorPush')
|
|
4
|
+
const createSpinner = require('../../../lib/helpers/createSpinner')
|
|
5
|
+
const armoredKeyDisplay = require('../../../lib/helpers/armoredKeyDisplay')
|
|
6
|
+
|
|
7
|
+
async function push () {
|
|
8
|
+
const options = this.opts()
|
|
9
|
+
const spinner = await createSpinner({ ...options, text: 'pushing' })
|
|
10
|
+
|
|
11
|
+
logger.debug(`options: ${JSON.stringify(options)}`)
|
|
12
|
+
|
|
13
|
+
const sesh = new Session()
|
|
14
|
+
await sesh.notifyUpdate()
|
|
15
|
+
const hostname = options.hostname || sesh.hostname()
|
|
16
|
+
const token = options.token || sesh.token()
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
const devicePublicKey = sesh.devicePublicKey()
|
|
20
|
+
|
|
21
|
+
const { changed, privateKeyName, publicKeyValue } = await new ArmorPush(hostname, token, devicePublicKey, options.envFile, options.team).run()
|
|
22
|
+
const keyDisplay = armoredKeyDisplay(publicKeyValue) || privateKeyName
|
|
23
|
+
|
|
24
|
+
if (spinner) spinner.stop()
|
|
25
|
+
if (changed) {
|
|
26
|
+
logger.success(`⛨ pushed (${keyDisplay})`)
|
|
27
|
+
} else {
|
|
28
|
+
logger.info(`○ no change (${keyDisplay})`)
|
|
29
|
+
}
|
|
30
|
+
} catch (error) {
|
|
31
|
+
if (spinner) spinner.stop()
|
|
32
|
+
logger.error(error.message)
|
|
33
|
+
process.exit(1)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
module.exports = push
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
const { logger } = require('../../../shared/logger')
|
|
2
|
+
const Session = require('./../../../db/session')
|
|
3
|
+
const ArmorUp = require('./../../../lib/services/armorUp')
|
|
4
|
+
const createSpinner = require('../../../lib/helpers/createSpinner')
|
|
5
|
+
const armoredKeyDisplay = require('../../../lib/helpers/armoredKeyDisplay')
|
|
6
|
+
|
|
7
|
+
async function up () {
|
|
8
|
+
const options = this.opts()
|
|
9
|
+
const spinner = await createSpinner({ ...options, text: 'armoring' })
|
|
10
|
+
|
|
11
|
+
logger.debug(`options: ${JSON.stringify(options)}`)
|
|
12
|
+
|
|
13
|
+
const sesh = new Session()
|
|
14
|
+
await sesh.notifyUpdate()
|
|
15
|
+
const hostname = options.hostname || sesh.hostname()
|
|
16
|
+
const token = options.token || sesh.token()
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
const devicePublicKey = sesh.devicePublicKey()
|
|
20
|
+
|
|
21
|
+
const { changed, privateKeyName, publicKeyValue } = await new ArmorUp(hostname, token, devicePublicKey, options.envFile, options.team).run()
|
|
22
|
+
const keyDisplay = armoredKeyDisplay(publicKeyValue) || privateKeyName
|
|
23
|
+
|
|
24
|
+
if (spinner) spinner.stop()
|
|
25
|
+
if (changed) {
|
|
26
|
+
logger.success(`⛨ armored (${keyDisplay})`)
|
|
27
|
+
} else {
|
|
28
|
+
logger.info(`○ no change (${keyDisplay})`)
|
|
29
|
+
}
|
|
30
|
+
} catch (error) {
|
|
31
|
+
if (spinner) spinner.stop()
|
|
32
|
+
logger.error(error.message)
|
|
33
|
+
process.exit(1)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
module.exports = up
|
|
@@ -13,8 +13,8 @@ async function decrypt () {
|
|
|
13
13
|
|
|
14
14
|
logger.debug(`options: ${JSON.stringify(options)}`)
|
|
15
15
|
|
|
16
|
-
const sesh = new Session()
|
|
17
16
|
const envs = this.envs
|
|
17
|
+
const sesh = new Session()
|
|
18
18
|
const noArmor = options.armor === false || (await sesh.noArmor())
|
|
19
19
|
|
|
20
20
|
let errorCount = 0
|
|
@@ -46,8 +46,8 @@ async function encrypt () {
|
|
|
46
46
|
|
|
47
47
|
logger.debug(`options: ${JSON.stringify(options)}`)
|
|
48
48
|
|
|
49
|
-
const sesh = new Session()
|
|
50
49
|
const envs = this.envs
|
|
50
|
+
const sesh = new Session()
|
|
51
51
|
const noArmor = options.armor === false || (!options.token && (await sesh.noArmor()))
|
|
52
52
|
const noCreate = options.create === false
|
|
53
53
|
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
const { logger } = require('../../shared/logger')
|
|
2
|
+
|
|
3
|
+
const Session = require('../../db/session')
|
|
4
|
+
const Login = require('../../lib/services/login')
|
|
5
|
+
const LoginPoll = require('../../lib/services/loginPoll')
|
|
6
|
+
|
|
7
|
+
const createSpinner = require('../../lib/helpers/createSpinner')
|
|
8
|
+
const formatCode = require('../../lib/helpers/formatCode')
|
|
9
|
+
const listenForOpenKey = require('../../lib/helpers/listenForOpenKey')
|
|
10
|
+
const openUrl = require('../../lib/helpers/openUrl')
|
|
11
|
+
|
|
12
|
+
const FRAMES = ['◐', '◓', '◑', '◒']
|
|
13
|
+
|
|
14
|
+
async function login () {
|
|
15
|
+
const options = this.opts()
|
|
16
|
+
const spinner = await createSpinner({ ...options, text: 'logging in', frames: FRAMES })
|
|
17
|
+
|
|
18
|
+
logger.debug(`options: ${JSON.stringify(options)}`)
|
|
19
|
+
|
|
20
|
+
const sesh = new Session()
|
|
21
|
+
await sesh.notifyUpdate()
|
|
22
|
+
const hostname = options.hostname || sesh.hostname()
|
|
23
|
+
let cleanupOpenKeyListener = () => {}
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
const {
|
|
27
|
+
deviceCode,
|
|
28
|
+
userCode,
|
|
29
|
+
verificationUri,
|
|
30
|
+
verificationUriComplete,
|
|
31
|
+
interval
|
|
32
|
+
} = await new Login(hostname).run()
|
|
33
|
+
|
|
34
|
+
const promptMessage = `◌ press Enter to open [${verificationUri}] and enter code [${formatCode(userCode)}]...`
|
|
35
|
+
|
|
36
|
+
logger.debug(`POST ${hostname} with deviceCode ${deviceCode} at interval ${interval}`)
|
|
37
|
+
logger.info(promptMessage)
|
|
38
|
+
|
|
39
|
+
// begin polling
|
|
40
|
+
const pollPromise = new LoginPoll(hostname, deviceCode, interval).run()
|
|
41
|
+
cleanupOpenKeyListener = listenForOpenKey(() => openUrl(verificationUriComplete))
|
|
42
|
+
const data = await pollPromise
|
|
43
|
+
|
|
44
|
+
cleanupOpenKeyListener()
|
|
45
|
+
if (spinner) spinner.stop()
|
|
46
|
+
logger.success(`◉ logged in (${data.username})`)
|
|
47
|
+
process.exit(0)
|
|
48
|
+
} catch (error) {
|
|
49
|
+
cleanupOpenKeyListener()
|
|
50
|
+
if (spinner) spinner.stop()
|
|
51
|
+
if (error.message) {
|
|
52
|
+
logger.error(error.message)
|
|
53
|
+
} else {
|
|
54
|
+
logger.error(error)
|
|
55
|
+
}
|
|
56
|
+
if (error.stack) {
|
|
57
|
+
logger.debug(error.stack)
|
|
58
|
+
}
|
|
59
|
+
process.exit(1)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
module.exports = login
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
const { logger } = require('../../shared/logger')
|
|
2
|
+
|
|
3
|
+
const Session = require('../../db/session')
|
|
4
|
+
const Logout = require('../../lib/services/logout')
|
|
5
|
+
const createSpinner = require('../../lib/helpers/createSpinner')
|
|
6
|
+
|
|
7
|
+
const FRAMES = ['◐', '◓', '◑', '◒']
|
|
8
|
+
|
|
9
|
+
async function logout () {
|
|
10
|
+
const options = this.opts()
|
|
11
|
+
const spinner = await createSpinner({ ...options, text: 'logging out', frames: FRAMES })
|
|
12
|
+
|
|
13
|
+
logger.debug(`options: ${JSON.stringify(options)}`)
|
|
14
|
+
|
|
15
|
+
const sesh = new Session()
|
|
16
|
+
const hostname = options.hostname || sesh.hostname()
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
const data = await new Logout(hostname).run()
|
|
20
|
+
if (spinner) spinner.stop()
|
|
21
|
+
logger.success(`◌ logged out (${data.username})`)
|
|
22
|
+
} catch (error) {
|
|
23
|
+
if (spinner) spinner.stop()
|
|
24
|
+
if (error.message) {
|
|
25
|
+
logger.error(error.message)
|
|
26
|
+
} else {
|
|
27
|
+
logger.error(error)
|
|
28
|
+
}
|
|
29
|
+
if (error.stack) {
|
|
30
|
+
logger.debug(error.stack)
|
|
31
|
+
}
|
|
32
|
+
process.exit(1)
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
module.exports = logout
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
function normalizeArmorOptions (options) {
|
|
2
|
-
if (options.armor === false || options.ops === false
|
|
2
|
+
if (options.armor === false || options.ops === false) {
|
|
3
3
|
options.armor = false
|
|
4
4
|
options.ops = false
|
|
5
|
-
options.vlt = false
|
|
6
5
|
}
|
|
7
6
|
|
|
8
7
|
return options
|
package/src/cli/actions/set.js
CHANGED
|
@@ -24,9 +24,9 @@ async function set (key, value) {
|
|
|
24
24
|
logger.debug(`options: ${JSON.stringify(options)}`)
|
|
25
25
|
|
|
26
26
|
try {
|
|
27
|
-
const sesh = new Session()
|
|
28
27
|
const envs = this.envs
|
|
29
28
|
const envKeysFilepath = options.envKeysFile
|
|
29
|
+
const sesh = new Session()
|
|
30
30
|
const noArmor = options.armor === false || (await sesh.noArmor())
|
|
31
31
|
const noCreate = options.create === false
|
|
32
32
|
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
const Session = require('./../../db/session')
|
|
2
|
+
const executeDynamic = require('./../../lib/helpers/executeDynamic')
|
|
3
|
+
|
|
4
|
+
function configureArmorCommand (armor) {
|
|
5
|
+
armor
|
|
6
|
+
.description('move private keys off-device')
|
|
7
|
+
.allowUnknownOption()
|
|
8
|
+
.argument('[command]', 'dotenvx-armor command')
|
|
9
|
+
.argument('[args...]', 'dotenvx-armor command arguments')
|
|
10
|
+
.action(async function (command, args) {
|
|
11
|
+
if (command) {
|
|
12
|
+
return executeDynamic(armor, 'armor', [command, ...(args || [])])
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const sesh = new Session()
|
|
16
|
+
await sesh.notifyUpdate()
|
|
17
|
+
this.help()
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
// dotenvx armor up
|
|
21
|
+
const upAction = require('./../actions/armor/up')
|
|
22
|
+
armor
|
|
23
|
+
.command('up')
|
|
24
|
+
.description('armor key')
|
|
25
|
+
.option('-f, --env-file <path>', 'path to your env file')
|
|
26
|
+
.option('--token <token>', 'set token')
|
|
27
|
+
.option('--team <team>', 'team to armor private key for')
|
|
28
|
+
.action(upAction)
|
|
29
|
+
|
|
30
|
+
// dotenvx armor down
|
|
31
|
+
const downAction = require('./../actions/armor/down')
|
|
32
|
+
armor
|
|
33
|
+
.command('down')
|
|
34
|
+
.description('dearmor key')
|
|
35
|
+
.option('-f, --env-file <path>', 'path to your env file')
|
|
36
|
+
.option('--token <token>', 'set token')
|
|
37
|
+
.option('--team <team>', 'team to dearmor private key from')
|
|
38
|
+
.action(downAction)
|
|
39
|
+
|
|
40
|
+
// dotenvx armor push
|
|
41
|
+
const pushAction = require('./../actions/armor/push')
|
|
42
|
+
armor
|
|
43
|
+
.command('push')
|
|
44
|
+
.description('push armored key (from .env.keys)')
|
|
45
|
+
.option('-f, --env-file <path>', 'path to your env file')
|
|
46
|
+
.option('--token <token>', 'set token')
|
|
47
|
+
.option('--team <team>', 'team to push armored private key for')
|
|
48
|
+
.action(pushAction)
|
|
49
|
+
|
|
50
|
+
// dotenvx armor pull
|
|
51
|
+
const pullAction = require('./../actions/armor/pull')
|
|
52
|
+
armor
|
|
53
|
+
.command('pull')
|
|
54
|
+
.description('pull armored key (into .env.keys)')
|
|
55
|
+
.option('-f, --env-file <path>', 'path to your env file')
|
|
56
|
+
.option('--token <token>', 'set token')
|
|
57
|
+
.option('--team <team>', 'team to pull armored private key from')
|
|
58
|
+
.action(pullAction)
|
|
59
|
+
|
|
60
|
+
// dotenvx armor move
|
|
61
|
+
const moveAction = require('./../actions/armor/move')
|
|
62
|
+
armor
|
|
63
|
+
.command('move')
|
|
64
|
+
.description('move armored key (to other team)')
|
|
65
|
+
.option('-f, --env-file <path>', 'path to your env file')
|
|
66
|
+
.option('--token <token>', 'set token')
|
|
67
|
+
.action(moveAction)
|
|
68
|
+
|
|
69
|
+
return armor
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
module.exports = configureArmorCommand
|
package/src/cli/dotenvx.js
CHANGED
|
@@ -72,7 +72,6 @@ program.command('run')
|
|
|
72
72
|
.option('--ignore <errorCodes...>', 'error code(s) to ignore (example: --ignore=MISSING_ENV_FILE)')
|
|
73
73
|
.option('--token <token>', 'set Armor ⛨ token')
|
|
74
74
|
.option('--no-armor', 'disable dotenvx-armor features')
|
|
75
|
-
.addOption(new Option('--no-vlt', 'disable dotenvx-vlt features (deprecated. use --no-armor)').hideHelp())
|
|
76
75
|
.addOption(new Option('--no-ops', 'disable dotenvx-ops features (deprecated. use --no-armor)').hideHelp())
|
|
77
76
|
.action(function (...args) {
|
|
78
77
|
this.envs = envs
|
|
@@ -96,7 +95,6 @@ program.command('get')
|
|
|
96
95
|
.option('--pp', 'pretty print output (alias)')
|
|
97
96
|
.option('--format <type>', 'format of the output (json, shell, colon, eval)', 'json')
|
|
98
97
|
.option('--no-armor', 'disable dotenvx-armor features')
|
|
99
|
-
.addOption(new Option('--no-vlt', 'disable dotenvx-vlt features (deprecated. use --no-armor)').hideHelp())
|
|
100
98
|
.addOption(new Option('--no-ops', 'disable dotenvx-ops features (deprecated. use --no-armor)').hideHelp())
|
|
101
99
|
.action(function (...args) {
|
|
102
100
|
this.envs = envs
|
|
@@ -117,7 +115,6 @@ program.command('set')
|
|
|
117
115
|
.option('-p, --plain', 'store value as plain text', false)
|
|
118
116
|
.option('--no-create', 'do not create .env file(s) when missing')
|
|
119
117
|
.option('--no-armor', 'disable dotenvx-armor features')
|
|
120
|
-
.addOption(new Option('--no-vlt', 'disable dotenvx-vlt features (deprecated. use --no-armor)').hideHelp())
|
|
121
118
|
.addOption(new Option('--no-ops', 'disable dotenvx-ops features (deprecated. use --no-armor)').hideHelp())
|
|
122
119
|
.action(function (...args) {
|
|
123
120
|
this.envs = envs
|
|
@@ -126,7 +123,7 @@ program.command('set')
|
|
|
126
123
|
|
|
127
124
|
// dotenvx encrypt
|
|
128
125
|
program.command('encrypt')
|
|
129
|
-
.description('
|
|
126
|
+
.description('encrypt .env file(s)')
|
|
130
127
|
.option('-f, --env-file <paths...>', 'path(s) to your env file(s)', collectEnvs('envFile'), [])
|
|
131
128
|
.option('-fk, --env-keys-file <path>', 'path to your .env.keys file (default: same path as your env file)')
|
|
132
129
|
.option('-k, --key <keys...>', 'keys(s) to encrypt (default: all keys in file)')
|
|
@@ -135,7 +132,6 @@ program.command('encrypt')
|
|
|
135
132
|
.option('--token <token>', 'set Armor ⛨ token')
|
|
136
133
|
.option('--no-create', 'do not create .env file(s) when missing')
|
|
137
134
|
.option('--no-armor', 'disable dotenvx-armor features')
|
|
138
|
-
.addOption(new Option('--no-vlt', 'disable dotenvx-vlt features (deprecated. use --no-armor)').hideHelp())
|
|
139
135
|
.addOption(new Option('--no-ops', 'disable dotenvx-ops features (deprecated. use --no-armor)').hideHelp())
|
|
140
136
|
.action(function (...args) {
|
|
141
137
|
this.envs = envs
|
|
@@ -144,13 +140,12 @@ program.command('encrypt')
|
|
|
144
140
|
|
|
145
141
|
// dotenvx decrypt
|
|
146
142
|
program.command('decrypt')
|
|
147
|
-
.description('
|
|
143
|
+
.description('decrypt .env file(s)')
|
|
148
144
|
.option('-f, --env-file <paths...>', 'path(s) to your env file(s)', collectEnvs('envFile'), [])
|
|
149
145
|
.option('-fk, --env-keys-file <path>', 'path to your .env.keys file (default: same path as your env file)')
|
|
150
146
|
.option('-k, --key <keys...>', 'keys(s) to decrypt (default: all keys in file)')
|
|
151
147
|
.option('-ek, --exclude-key <excludeKeys...>', 'keys(s) to exclude from decryption (default: none)')
|
|
152
148
|
.option('--no-armor', 'disable dotenvx-armor features')
|
|
153
|
-
.addOption(new Option('--no-vlt', 'disable dotenvx-vlt features (deprecated. use --no-armor)').hideHelp())
|
|
154
149
|
.addOption(new Option('--no-ops', 'disable dotenvx-ops features (deprecated. use --no-armor)').hideHelp())
|
|
155
150
|
.option('--stdout', 'send to stdout')
|
|
156
151
|
.action(function (...args) {
|
|
@@ -166,7 +161,6 @@ program.command('rotate')
|
|
|
166
161
|
.option('-k, --key <keys...>', 'keys(s) to encrypt (default: all keys in file)')
|
|
167
162
|
.option('-ek, --exclude-key <excludeKeys...>', 'keys(s) to exclude from encryption (default: none)')
|
|
168
163
|
.option('--no-armor', 'disable dotenvx-armor features')
|
|
169
|
-
.addOption(new Option('--no-vlt', 'disable dotenvx-vlt features (deprecated. use --no-armor)').hideHelp())
|
|
170
164
|
.addOption(new Option('--no-ops', 'disable dotenvx-ops features (deprecated. use --no-armor)').hideHelp())
|
|
171
165
|
.option('--stdout', 'send to stdout')
|
|
172
166
|
.action(function (...args) {
|
|
@@ -182,7 +176,6 @@ program.command('keypair')
|
|
|
182
176
|
.option('-f, --env-file <paths...>', 'path(s) to your env file(s)')
|
|
183
177
|
.option('-fk, --env-keys-file <path>', 'path to your .env.keys file (default: same path as your env file)')
|
|
184
178
|
.option('--no-armor', 'disable dotenvx-armor features')
|
|
185
|
-
.addOption(new Option('--no-vlt', 'disable dotenvx-vlt features (deprecated. use --no-armor)').hideHelp())
|
|
186
179
|
.addOption(new Option('--no-ops', 'disable dotenvx-ops features (deprecated. use --no-armor)').hideHelp())
|
|
187
180
|
.option('-pp, --pretty-print', 'pretty print output')
|
|
188
181
|
.option('--pp', 'pretty print output (alias)')
|
|
@@ -211,20 +204,20 @@ program.command('doctor', { hidden: true })
|
|
|
211
204
|
|
|
212
205
|
// dotenvx login
|
|
213
206
|
program.command('login', { hidden: true })
|
|
214
|
-
.description('')
|
|
207
|
+
.description('log in to move keys off-device, share with your team, and audit access')
|
|
215
208
|
.allowUnknownOption()
|
|
216
|
-
.
|
|
217
|
-
|
|
218
|
-
|
|
209
|
+
.option('--hostname <hostname>', 'set Armor ⛨ hostname')
|
|
210
|
+
.action(function (...args) {
|
|
211
|
+
return require('./actions/login').apply(this, args)
|
|
219
212
|
})
|
|
220
213
|
|
|
221
214
|
// dotenvx logout
|
|
222
215
|
program.command('logout', { hidden: true })
|
|
223
|
-
.description('log out of
|
|
216
|
+
.description('log out of connected security features')
|
|
224
217
|
.allowUnknownOption()
|
|
225
|
-
.
|
|
226
|
-
|
|
227
|
-
|
|
218
|
+
.option('--hostname <hostname>', 'set Armor ⛨ hostname')
|
|
219
|
+
.action(function (...args) {
|
|
220
|
+
return require('./actions/logout').apply(this, args)
|
|
228
221
|
})
|
|
229
222
|
|
|
230
223
|
// dotenvx help
|
|
@@ -245,10 +238,15 @@ program.command('help [command]')
|
|
|
245
238
|
|
|
246
239
|
// dotenvx armor
|
|
247
240
|
program.addHelpText('after', ' ')
|
|
248
|
-
program.addHelpText('after', '
|
|
249
|
-
program.addHelpText('after', '
|
|
241
|
+
program.addHelpText('after', 'Professional Security: ')
|
|
242
|
+
program.addHelpText('after', ' login log in to move keys off-device, share with your team, and audit access')
|
|
243
|
+
program.addHelpText('after', ' logout log out of connected security features')
|
|
244
|
+
program.addHelpText('after', ' armor ⛨ move private keys off-device [www.dotenvx.com/armor]')
|
|
250
245
|
program.addHelpText('after', ' ext ⊕ extensions')
|
|
251
246
|
|
|
247
|
+
// dotenvx armor
|
|
248
|
+
require('./commands/armor')(program.command('armor', { hidden: true }))
|
|
249
|
+
|
|
252
250
|
// dotenvx ext
|
|
253
251
|
program.addCommand(require('./commands/ext'))
|
|
254
252
|
|