@dotenvx/dotenvx 1.75.1 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +39 -1
- package/README.md +4 -114
- package/package.json +8 -7
- package/src/cli/actions/decrypt.js +35 -17
- package/src/cli/actions/doctor.js +2 -2
- package/src/cli/actions/encrypt.js +64 -85
- package/src/cli/actions/ext/genexample.js +2 -2
- package/src/cli/actions/get.js +22 -7
- package/src/cli/actions/keypair.js +55 -42
- package/src/cli/actions/login.js +4 -3
- package/src/cli/actions/normalizeArmorAliases.js +9 -0
- package/src/cli/actions/run.js +65 -22
- package/src/cli/actions/set.js +87 -37
- package/src/cli/dotenvx.js +8 -23
- package/src/lib/api/{postKeypair.js → postArmorKeyring.js} +4 -14
- package/src/lib/{helpers/envResolution → conventions}/environment.js +1 -1
- package/src/lib/conventions/filepaths.js +9 -0
- package/src/lib/conventions/keynames.js +38 -0
- package/src/lib/helpers/catchAndLog.js +4 -1
- package/src/lib/helpers/cryptography/index.js +2 -9
- package/src/lib/helpers/cryptography/{isPublicKey.js → isDotenvPublicKey.js} +2 -2
- package/src/lib/helpers/cryptography/isPlainKey.js +7 -0
- package/src/lib/helpers/cryptography/mutateKeysSrc.js +5 -21
- package/src/lib/helpers/envResolution/index.js +1 -1
- package/src/lib/helpers/errors.js +26 -0
- package/src/lib/helpers/keypairMetadata.js +1 -1
- package/src/lib/helpers/prompts.js +46 -0
- package/src/lib/main.d.ts +2 -39
- package/src/lib/main.js +83 -46
- package/src/lib/providers/armor/index.js +29 -0
- package/src/lib/providers/index.js +46 -0
- package/src/lib/providers/worker.js +6 -0
- package/src/lib/resolvers/envs.js +302 -0
- package/src/lib/resolvers/get.js +69 -0
- package/src/lib/resolvers/keypair.js +81 -0
- package/src/lib/resolvers/ls.js +41 -0
- package/src/lib/services/armorDown.js +2 -2
- package/src/lib/services/{armorKeypair.js → armorKeyring.js} +14 -51
- package/src/lib/services/armorMove.js +2 -2
- package/src/lib/services/armorPull.js +2 -2
- package/src/lib/services/armorPush.js +2 -2
- package/src/lib/services/armorUp.js +2 -2
- package/src/lib/services/genexample.js +5 -6
- package/src/lib/services/login.js +25 -0
- package/src/lib/services/prebuild.js +9 -3
- package/src/lib/services/precommit.js +9 -3
- package/src/lib/transforms/decrypt.js +83 -0
- package/src/lib/transforms/encrypt.js +178 -0
- package/src/lib/transforms/set.js +179 -0
- package/src/shared/logger.js +5 -0
- package/src/cli/actions/normalizeArmorOptions.js +0 -10
- package/src/cli/actions/rotate.js +0 -87
- package/src/lib/helpers/append.js +0 -62
- package/src/lib/helpers/cryptography/armorKeypair.js +0 -42
- package/src/lib/helpers/cryptography/armorKeypairSync.js +0 -55
- package/src/lib/helpers/cryptography/encryptValue.js +0 -7
- package/src/lib/helpers/cryptography/localKeypair.js +0 -14
- package/src/lib/helpers/cryptography/mutateKeysSrcSync.js +0 -38
- package/src/lib/helpers/cryptography/provision.js +0 -56
- package/src/lib/helpers/cryptography/provisionSync.js +0 -51
- package/src/lib/helpers/cryptography/provisionWithPrivateKey.js +0 -26
- package/src/lib/helpers/escapeDollarSigns.js +0 -5
- package/src/lib/helpers/escapeForRegex.js +0 -5
- package/src/lib/helpers/evalKeyValue.js +0 -23
- package/src/lib/helpers/isIgnoringDotenvKeys.js +0 -19
- package/src/lib/helpers/keyResolution/index.js +0 -16
- package/src/lib/helpers/keyResolution/keyNamesForEnvFile.js +0 -24
- package/src/lib/helpers/keyResolution/keyValues.js +0 -99
- package/src/lib/helpers/keyResolution/keyValuesFromEnvSrc.js +0 -85
- package/src/lib/helpers/keyResolution/keyValuesSync.js +0 -103
- package/src/lib/helpers/keyResolution/readFileKey.js +0 -19
- package/src/lib/helpers/keyResolution/readFileKeySync.js +0 -17
- package/src/lib/helpers/keyResolution/readProcessKey.js +0 -7
- package/src/lib/helpers/localDisplayPath.js +0 -11
- package/src/lib/helpers/parse.js +0 -214
- package/src/lib/helpers/pluralize.js +0 -10
- package/src/lib/helpers/quotes.js +0 -36
- package/src/lib/helpers/replace.js +0 -82
- package/src/lib/helpers/resolveEscapeSequences.js +0 -5
- package/src/lib/services/decrypt.js +0 -156
- package/src/lib/services/encrypt.js +0 -213
- package/src/lib/services/get.js +0 -76
- package/src/lib/services/keypair.js +0 -60
- package/src/lib/services/loginPoll.js +0 -36
- package/src/lib/services/ls.js +0 -57
- package/src/lib/services/rotate.js +0 -197
- package/src/lib/services/run.js +0 -255
- package/src/lib/services/sets.js +0 -328
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
const fsx = require('./../../lib/helpers/fsx')
|
|
2
|
-
const { logger } = require('./../../shared/logger')
|
|
3
|
-
|
|
4
|
-
const Rotate = require('./../../lib/services/rotate')
|
|
5
|
-
|
|
6
|
-
const catchAndLog = require('../../lib/helpers/catchAndLog')
|
|
7
|
-
const createSpinner = require('../../lib/helpers/createSpinner')
|
|
8
|
-
const Session = require('../../db/session')
|
|
9
|
-
const normalizeArmorOptions = require('./normalizeArmorOptions')
|
|
10
|
-
|
|
11
|
-
async function rotate () {
|
|
12
|
-
const options = normalizeArmorOptions(this.opts())
|
|
13
|
-
const spinner = await createSpinner({ ...options, text: 'rotating', frames: ['⟳', '⤾', '⥁'] })
|
|
14
|
-
|
|
15
|
-
logger.debug(`options: ${JSON.stringify(options)}`)
|
|
16
|
-
|
|
17
|
-
const envs = this.envs
|
|
18
|
-
const sesh = new Session()
|
|
19
|
-
const noArmor = options.armor === false || (await sesh.noArmor())
|
|
20
|
-
|
|
21
|
-
// stdout - should not have a try so that exit codes can surface to stdout
|
|
22
|
-
if (options.stdout) {
|
|
23
|
-
if (spinner) spinner.stop()
|
|
24
|
-
const {
|
|
25
|
-
processedEnvs
|
|
26
|
-
} = await new Rotate(envs, options.key, options.excludeKey, options.envKeysFile, noArmor, {
|
|
27
|
-
command: process.argv.slice(2)
|
|
28
|
-
}).run()
|
|
29
|
-
if (spinner) spinner.stop()
|
|
30
|
-
for (const processedEnv of processedEnvs) {
|
|
31
|
-
console.log(processedEnv.envSrc)
|
|
32
|
-
if (processedEnv.localPrivateKeyAdded) {
|
|
33
|
-
console.log('')
|
|
34
|
-
console.log(processedEnv.envKeysSrc)
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
process.exit(0) // exit early
|
|
38
|
-
} else {
|
|
39
|
-
try {
|
|
40
|
-
if (spinner) spinner.stop()
|
|
41
|
-
const {
|
|
42
|
-
processedEnvs,
|
|
43
|
-
changedFilepaths,
|
|
44
|
-
unchangedFilepaths
|
|
45
|
-
} = await new Rotate(envs, options.key, options.excludeKey, options.envKeysFile, noArmor, {
|
|
46
|
-
command: process.argv.slice(2)
|
|
47
|
-
}).run()
|
|
48
|
-
|
|
49
|
-
for (const processedEnv of processedEnvs) {
|
|
50
|
-
logger.verbose(`rotating ${processedEnv.envFilepath} (${processedEnv.filepath})`)
|
|
51
|
-
if (processedEnv.error) {
|
|
52
|
-
logger.warn(processedEnv.error.messageWithHelp)
|
|
53
|
-
} else if (processedEnv.changed) {
|
|
54
|
-
await fsx.writeFileX(processedEnv.filepath, processedEnv.envSrc)
|
|
55
|
-
if (processedEnv.localPrivateKeyAdded) {
|
|
56
|
-
await fsx.writeFileX(processedEnv.envKeysFilepath, processedEnv.envKeysSrc)
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
logger.verbose(`rotated ${processedEnv.envFilepath} (${processedEnv.filepath})`)
|
|
60
|
-
} else {
|
|
61
|
-
logger.verbose(`no change ${processedEnv.envFilepath} (${processedEnv.filepath})`)
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if (spinner) spinner.stop()
|
|
66
|
-
if (changedFilepaths.length > 0) {
|
|
67
|
-
const remoteKeyAddedEnv = processedEnvs.find((processedEnv) => processedEnv.remotePrivateKeyAdded)
|
|
68
|
-
|
|
69
|
-
let msg = `⟳ rotated (${changedFilepaths.join(',')})`
|
|
70
|
-
if (remoteKeyAddedEnv) {
|
|
71
|
-
msg += ' · armored ⛨'
|
|
72
|
-
}
|
|
73
|
-
logger.success(msg)
|
|
74
|
-
} else if (unchangedFilepaths.length > 0) {
|
|
75
|
-
logger.info(`○ no change (${unchangedFilepaths})`)
|
|
76
|
-
} else {
|
|
77
|
-
// do nothing - scenario when no .env files found
|
|
78
|
-
}
|
|
79
|
-
} catch (error) {
|
|
80
|
-
if (spinner) spinner.stop()
|
|
81
|
-
catchAndLog(error)
|
|
82
|
-
process.exit(1)
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
module.exports = rotate
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
const quotes = require('./quotes')
|
|
2
|
-
const { scan } = require('@dotenvx/primitives')
|
|
3
|
-
const escapeForRegex = require('./escapeForRegex')
|
|
4
|
-
const escapeDollarSigns = require('./escapeDollarSigns')
|
|
5
|
-
|
|
6
|
-
function append (src, key, appendValue) {
|
|
7
|
-
let output
|
|
8
|
-
let newPart = ''
|
|
9
|
-
|
|
10
|
-
const { parsed } = scan(src, { expandDoubleQuotedNewlines: false, convertWindowsNewlines: false })
|
|
11
|
-
const _quotes = quotes(src)
|
|
12
|
-
if (Object.prototype.hasOwnProperty.call(parsed, key)) {
|
|
13
|
-
const quote = _quotes[key]
|
|
14
|
-
const values = parsed[key]
|
|
15
|
-
const originalValue = values[values.length - 1]
|
|
16
|
-
|
|
17
|
-
newPart += `${key}=${quote}${originalValue},${appendValue}${quote}`
|
|
18
|
-
|
|
19
|
-
const escapedOriginalValue = escapeForRegex(originalValue)
|
|
20
|
-
|
|
21
|
-
// conditionally enforce end of line
|
|
22
|
-
let enforceEndOfLine = ''
|
|
23
|
-
if (escapedOriginalValue === '') {
|
|
24
|
-
enforceEndOfLine = '$' // EMPTY scenario
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const currentPart = new RegExp(
|
|
28
|
-
'^' + // start of line
|
|
29
|
-
'(\\s*)?' + // spaces
|
|
30
|
-
'(export\\s+)?' + // export
|
|
31
|
-
key + // KEY
|
|
32
|
-
'\\s*=\\s*' + // spaces (KEY = value)
|
|
33
|
-
'["\'`]?' + // open quote
|
|
34
|
-
escapedOriginalValue + // escaped value
|
|
35
|
-
'["\'`]?' + // close quote
|
|
36
|
-
enforceEndOfLine
|
|
37
|
-
,
|
|
38
|
-
'gm' // (g)lobal (m)ultiline
|
|
39
|
-
)
|
|
40
|
-
|
|
41
|
-
const saferInput = escapeDollarSigns(newPart) // cleanse user inputted capture groups ($1, $2 etc)
|
|
42
|
-
|
|
43
|
-
// $1 preserves spaces
|
|
44
|
-
// $2 preserves export
|
|
45
|
-
output = src.replace(currentPart, `$1$2${saferInput}`)
|
|
46
|
-
} else {
|
|
47
|
-
newPart += `${key}="${appendValue}"`
|
|
48
|
-
|
|
49
|
-
// append
|
|
50
|
-
if (src.endsWith('\n')) {
|
|
51
|
-
newPart = newPart + '\n'
|
|
52
|
-
} else {
|
|
53
|
-
newPart = '\n' + newPart
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
output = src + newPart
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
return output
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
module.exports = append
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
const Session = require('../../../db/session')
|
|
2
|
-
const ArmorKeypair = require('../../services/armorKeypair')
|
|
3
|
-
const sanitizeCommandForMetadata = require('../sanitizeCommandForMetadata')
|
|
4
|
-
|
|
5
|
-
function metadataFromOptions (options) {
|
|
6
|
-
if (options.metadata) return options.metadata
|
|
7
|
-
if (!options.command) return undefined
|
|
8
|
-
|
|
9
|
-
return JSON.stringify({
|
|
10
|
-
command: sanitizeCommandForMetadata(options.command)
|
|
11
|
-
})
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
async function armorKeypair (existingPublicKey, options = {}) {
|
|
15
|
-
const sesh = new Session()
|
|
16
|
-
const token = options.token || sesh.token()
|
|
17
|
-
if (!token) {
|
|
18
|
-
return {
|
|
19
|
-
publicKey: undefined,
|
|
20
|
-
privateKey: undefined
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const json = await new ArmorKeypair(
|
|
25
|
-
options.hostname || sesh.hostname(),
|
|
26
|
-
token,
|
|
27
|
-
sesh.devicePublicKey(),
|
|
28
|
-
existingPublicKey,
|
|
29
|
-
{
|
|
30
|
-
envFile: options.envFilepath,
|
|
31
|
-
team: options.team,
|
|
32
|
-
metadata: metadataFromOptions(options)
|
|
33
|
-
}
|
|
34
|
-
).run()
|
|
35
|
-
|
|
36
|
-
return {
|
|
37
|
-
publicKey: json.public_key,
|
|
38
|
-
privateKey: json.private_key
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
module.exports = armorKeypair
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
const path = require('path')
|
|
2
|
-
const childProcess = require('child_process')
|
|
3
|
-
|
|
4
|
-
const EXEC_TIMEOUT = 5 * 60 * 1000
|
|
5
|
-
|
|
6
|
-
function cliPath () {
|
|
7
|
-
return path.resolve(__dirname, '../../../cli/dotenvx.js')
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
function execEnv () {
|
|
11
|
-
const env = { ...process.env }
|
|
12
|
-
env._TAPJS_PROCESSINFO_COVERAGE_ = '0'
|
|
13
|
-
|
|
14
|
-
if (env.NODE_OPTIONS && env.NODE_OPTIONS.includes('@tapjs/processinfo')) {
|
|
15
|
-
const nodeOptions = env.NODE_OPTIONS
|
|
16
|
-
.split(/\s+/)
|
|
17
|
-
.filter((option) => !option.includes('@tapjs/processinfo'))
|
|
18
|
-
.join(' ')
|
|
19
|
-
.trim()
|
|
20
|
-
|
|
21
|
-
if (nodeOptions) {
|
|
22
|
-
env.NODE_OPTIONS = nodeOptions
|
|
23
|
-
} else {
|
|
24
|
-
delete env.NODE_OPTIONS
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
return env
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function armorKeypairSync (_existingPublicKey, options = {}) {
|
|
32
|
-
const args = [cliPath(), 'keypair', '--format', 'json']
|
|
33
|
-
if (options.envFilepath) args.push('-f', options.envFilepath)
|
|
34
|
-
|
|
35
|
-
let keypairs = {}
|
|
36
|
-
try {
|
|
37
|
-
keypairs = JSON.parse(childProcess.execFileSync(process.execPath, args, {
|
|
38
|
-
env: execEnv(),
|
|
39
|
-
stdio: ['inherit', 'pipe', 'inherit'],
|
|
40
|
-
timeout: EXEC_TIMEOUT
|
|
41
|
-
}).toString().trim())
|
|
42
|
-
} catch (_error) {
|
|
43
|
-
keypairs = {}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const publicKeyName = Object.keys(keypairs).find((key) => key === 'DOTENV_PUBLIC_KEY' || key.startsWith('DOTENV_PUBLIC_KEY_'))
|
|
47
|
-
const privateKeyName = Object.keys(keypairs).find((key) => key === 'DOTENV_PRIVATE_KEY' || key.startsWith('DOTENV_PRIVATE_KEY_'))
|
|
48
|
-
|
|
49
|
-
return {
|
|
50
|
-
publicKey: keypairs[publicKeyName],
|
|
51
|
-
privateKey: keypairs[privateKeyName]
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
module.exports = armorKeypairSync
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
const { derive, keypair } = require('@dotenvx/primitives')
|
|
2
|
-
|
|
3
|
-
function localKeypair (existingPrivateKey) {
|
|
4
|
-
if (existingPrivateKey) {
|
|
5
|
-
return {
|
|
6
|
-
publicKey: derive(existingPrivateKey),
|
|
7
|
-
privateKey: existingPrivateKey
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
return keypair()
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
module.exports = localKeypair
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
const FIRST_TIME_KEYS_SRC = [
|
|
2
|
-
'#/------------------!DOTENV_PRIVATE_KEYS!-------------------/',
|
|
3
|
-
'#/ private decryption keys. DO NOT commit to source control /',
|
|
4
|
-
'#/ [how it works](https://dotenvx.com/encryption) /',
|
|
5
|
-
'#/ ⛨ ARMORED KEYS: `dotenvx armor up` /',
|
|
6
|
-
'#/----------------------------------------------------------/'
|
|
7
|
-
].join('\n')
|
|
8
|
-
|
|
9
|
-
const path = require('path')
|
|
10
|
-
const fsx = require('./../fsx')
|
|
11
|
-
|
|
12
|
-
function mutateKeysSrcSync ({ envFilepath, keysFilepath, privateKeyName, privateKeyValue }) {
|
|
13
|
-
const filename = path.basename(envFilepath)
|
|
14
|
-
const filepath = path.resolve(envFilepath)
|
|
15
|
-
let resolvedKeysFilepath = path.join(path.dirname(filepath), '.env.keys')
|
|
16
|
-
if (keysFilepath) {
|
|
17
|
-
resolvedKeysFilepath = path.resolve(keysFilepath)
|
|
18
|
-
}
|
|
19
|
-
const appendPrivateKey = [`# ${filename}`, `${privateKeyName}=${privateKeyValue}`, ''].join('\n')
|
|
20
|
-
|
|
21
|
-
let keysSrc = ''
|
|
22
|
-
if (fsx.existsSync(resolvedKeysFilepath)) {
|
|
23
|
-
keysSrc = fsx.readFileXSync(resolvedKeysFilepath)
|
|
24
|
-
}
|
|
25
|
-
keysSrc = keysSrc.length > 1 ? keysSrc : `${FIRST_TIME_KEYS_SRC}\n`
|
|
26
|
-
keysSrc = `${keysSrc}\n${appendPrivateKey}`
|
|
27
|
-
|
|
28
|
-
fsx.writeFileXSync(resolvedKeysFilepath, keysSrc) // TODO: don't write if armor
|
|
29
|
-
|
|
30
|
-
const envKeysFilepath = keysFilepath || path.join(path.dirname(envFilepath), path.basename(resolvedKeysFilepath))
|
|
31
|
-
|
|
32
|
-
return {
|
|
33
|
-
keysSrc,
|
|
34
|
-
envKeysFilepath
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
module.exports = mutateKeysSrcSync
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
const mutateSrc = require('./mutateSrc')
|
|
2
|
-
const mutateKeysSrc = require('./mutateKeysSrc')
|
|
3
|
-
const armorKeypair = require('./armorKeypair')
|
|
4
|
-
const localKeypair = require('./localKeypair')
|
|
5
|
-
const { keyNamesForEnvFile } = require('../keyResolution')
|
|
6
|
-
|
|
7
|
-
async function provision ({ envSrc, envFilepath, keysFilepath, noArmor, token, selectKeyStorage, command }) {
|
|
8
|
-
noArmor = noArmor !== false
|
|
9
|
-
if (!noArmor && selectKeyStorage) {
|
|
10
|
-
noArmor = await selectKeyStorage() !== 'armored'
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const { publicKeyName, privateKeyName } = keyNamesForEnvFile(envFilepath)
|
|
14
|
-
|
|
15
|
-
let publicKey
|
|
16
|
-
let privateKey
|
|
17
|
-
let keysSrc
|
|
18
|
-
let envKeysFilepath
|
|
19
|
-
let localPrivateKeyAdded = false
|
|
20
|
-
let remotePrivateKeyAdded = false
|
|
21
|
-
|
|
22
|
-
if (noArmor) {
|
|
23
|
-
const kp = localKeypair()
|
|
24
|
-
publicKey = kp.publicKey
|
|
25
|
-
privateKey = kp.privateKey
|
|
26
|
-
} else {
|
|
27
|
-
const armorOptions = { token, envFilepath, command }
|
|
28
|
-
const kp = await armorKeypair(undefined, armorOptions)
|
|
29
|
-
publicKey = kp.publicKey
|
|
30
|
-
privateKey = kp.privateKey
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const mutated = mutateSrc({ envSrc, envFilepath, keysFilepath, publicKeyName, publicKeyValue: publicKey })
|
|
34
|
-
envSrc = mutated.envSrc
|
|
35
|
-
|
|
36
|
-
if (noArmor) {
|
|
37
|
-
const mutated = await mutateKeysSrc({ envFilepath, keysFilepath, privateKeyName, privateKeyValue: privateKey })
|
|
38
|
-
keysSrc = mutated.keysSrc
|
|
39
|
-
envKeysFilepath = mutated.envKeysFilepath
|
|
40
|
-
localPrivateKeyAdded = true
|
|
41
|
-
} else {
|
|
42
|
-
remotePrivateKeyAdded = true
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return {
|
|
46
|
-
envSrc,
|
|
47
|
-
keysSrc,
|
|
48
|
-
publicKey,
|
|
49
|
-
privateKey,
|
|
50
|
-
envKeysFilepath,
|
|
51
|
-
localPrivateKeyAdded,
|
|
52
|
-
remotePrivateKeyAdded
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
module.exports = provision
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
const mutateSrc = require('./mutateSrc')
|
|
2
|
-
const mutateKeysSrcSync = require('./mutateKeysSrcSync')
|
|
3
|
-
const armorKeypairSync = require('./armorKeypairSync')
|
|
4
|
-
const localKeypair = require('./localKeypair')
|
|
5
|
-
const { keyNamesForEnvFile } = require('../keyResolution')
|
|
6
|
-
|
|
7
|
-
function provisionSync ({ envSrc, envFilepath, keysFilepath, noArmor, command }) {
|
|
8
|
-
noArmor = noArmor !== false
|
|
9
|
-
const { publicKeyName, privateKeyName } = keyNamesForEnvFile(envFilepath)
|
|
10
|
-
|
|
11
|
-
let publicKey
|
|
12
|
-
let privateKey
|
|
13
|
-
let keysSrc
|
|
14
|
-
let envKeysFilepath
|
|
15
|
-
let localPrivateKeyAdded = false
|
|
16
|
-
let remotePrivateKeyAdded = false
|
|
17
|
-
|
|
18
|
-
if (noArmor) {
|
|
19
|
-
const kp = localKeypair()
|
|
20
|
-
publicKey = kp.publicKey
|
|
21
|
-
privateKey = kp.privateKey
|
|
22
|
-
} else {
|
|
23
|
-
const kp = armorKeypairSync(undefined, { envFilepath, command })
|
|
24
|
-
publicKey = kp.publicKey
|
|
25
|
-
privateKey = kp.privateKey
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const mutated = mutateSrc({ envSrc, envFilepath, keysFilepath, publicKeyName, publicKeyValue: publicKey })
|
|
29
|
-
envSrc = mutated.envSrc
|
|
30
|
-
|
|
31
|
-
if (noArmor) {
|
|
32
|
-
const mutated = mutateKeysSrcSync({ envFilepath, keysFilepath, privateKeyName, privateKeyValue: privateKey })
|
|
33
|
-
keysSrc = mutated.keysSrc
|
|
34
|
-
envKeysFilepath = mutated.envKeysFilepath
|
|
35
|
-
localPrivateKeyAdded = true
|
|
36
|
-
} else {
|
|
37
|
-
remotePrivateKeyAdded = true
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
return {
|
|
41
|
-
envSrc,
|
|
42
|
-
keysSrc,
|
|
43
|
-
publicKey,
|
|
44
|
-
privateKey,
|
|
45
|
-
envKeysFilepath,
|
|
46
|
-
localPrivateKeyAdded,
|
|
47
|
-
remotePrivateKeyAdded
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
module.exports = provisionSync
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
const Errors = require('./../errors')
|
|
2
|
-
const mutateSrc = require('./mutateSrc')
|
|
3
|
-
const localKeypair = require('./localKeypair')
|
|
4
|
-
|
|
5
|
-
function provisionWithPrivateKey ({ envSrc, envFilepath, keysFilepath, privateKeyValue, publicKeyValue, publicKeyName }) {
|
|
6
|
-
const { publicKey, privateKey } = localKeypair(privateKeyValue) // noArmor doesn't matter here since privateKeyValue was already discovered prior (via armor and local) and passed as privateKeyValue
|
|
7
|
-
|
|
8
|
-
// if derivation doesn't match what's in the file (or preset in env)
|
|
9
|
-
if (publicKeyValue && publicKeyValue !== publicKey) {
|
|
10
|
-
throw new Errors({ publicKey, publicKeyExisting: publicKeyValue }).mispairedPrivateKey()
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
// scenario when encrypting a monorepo second .env file from a prior generated -fk .env.keys file
|
|
14
|
-
if (!publicKeyValue) {
|
|
15
|
-
const mutated = mutateSrc({ envSrc, envFilepath, keysFilepath, publicKeyName, publicKeyValue: publicKey })
|
|
16
|
-
envSrc = mutated.envSrc
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
return {
|
|
20
|
-
envSrc,
|
|
21
|
-
publicKey,
|
|
22
|
-
privateKey
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
module.exports = provisionWithPrivateKey
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
const { execSync } = require('child_process')
|
|
2
|
-
const chomp = require('./chomp')
|
|
3
|
-
const Errors = require('./errors')
|
|
4
|
-
|
|
5
|
-
function evalKeyValue (key, value, processEnv, runningParsed) {
|
|
6
|
-
// Match everything between the outermost $() using a regex with non-capturing groups
|
|
7
|
-
const matches = value.match(/\$\(([^)]+(?:\)[^(]*)*)\)/g) || []
|
|
8
|
-
return matches.reduce((newValue, match) => {
|
|
9
|
-
const command = match.slice(2, -1) // Extract command by removing $() wrapper
|
|
10
|
-
let result
|
|
11
|
-
|
|
12
|
-
try {
|
|
13
|
-
result = execSync(command, { env: { ...processEnv, ...runningParsed } }).toString() // execute command (including runningParsed)
|
|
14
|
-
} catch (e) {
|
|
15
|
-
throw new Errors({ key, command, message: e.message.trim() }).commandSubstitutionFailed()
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
result = chomp(result) // chomp it
|
|
19
|
-
return newValue.replace(match, result) // Replace match with result
|
|
20
|
-
}, value)
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
module.exports = evalKeyValue
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
const fsx = require('./fsx')
|
|
2
|
-
const ignore = require('ignore')
|
|
3
|
-
|
|
4
|
-
function isIgnoringDotenvKeys () {
|
|
5
|
-
if (!fsx.existsSync('.gitignore')) {
|
|
6
|
-
return false
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
const gitignore = fsx.readFileXSync('.gitignore')
|
|
10
|
-
const ig = ignore(gitignore).add(gitignore)
|
|
11
|
-
|
|
12
|
-
if (!ig.ignores('.env.keys')) {
|
|
13
|
-
return false
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
return true
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
module.exports = isIgnoringDotenvKeys
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
module.exports = {
|
|
2
|
-
keyNamesForEnvFile: require('./keyNamesForEnvFile'),
|
|
3
|
-
keyValues: require('./keyValues'),
|
|
4
|
-
keyValuesSync: require('./keyValuesSync'),
|
|
5
|
-
keyValuesFromEnvSrc: require('./keyValuesFromEnvSrc'),
|
|
6
|
-
|
|
7
|
-
// private
|
|
8
|
-
// private keys are resolved via keyValuesSync()
|
|
9
|
-
|
|
10
|
-
// other
|
|
11
|
-
readProcessKey: require('./readProcessKey'),
|
|
12
|
-
readFileKey: require('./readFileKey'),
|
|
13
|
-
readFileKeySync: require('./readFileKeySync'),
|
|
14
|
-
guessPrivateKeyFilename: require('./../guessPrivateKeyFilename'),
|
|
15
|
-
dotenvPrivateKeyNames: require('./../dotenvPrivateKeyNames')
|
|
16
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
const canonicalEnvFilename = require('./../canonicalEnvFilename')
|
|
2
|
-
const environment = require('./../envResolution/environment')
|
|
3
|
-
|
|
4
|
-
function keyNamesForEnvFile (filepath) {
|
|
5
|
-
const filename = canonicalEnvFilename(filepath)
|
|
6
|
-
|
|
7
|
-
// .env
|
|
8
|
-
if (filename === '.env') {
|
|
9
|
-
return {
|
|
10
|
-
publicKeyName: 'DOTENV_PUBLIC_KEY',
|
|
11
|
-
privateKeyName: 'DOTENV_PRIVATE_KEY'
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
// .env.ENVIRONMENT
|
|
16
|
-
const resolvedEnvironment = environment(filename).toUpperCase()
|
|
17
|
-
|
|
18
|
-
return {
|
|
19
|
-
publicKeyName: `DOTENV_PUBLIC_KEY_${resolvedEnvironment}`,
|
|
20
|
-
privateKeyName: `DOTENV_PRIVATE_KEY_${resolvedEnvironment}`
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
module.exports = keyNamesForEnvFile
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
const path = require('path')
|
|
2
|
-
const { scan } = require('@dotenvx/primitives')
|
|
3
|
-
|
|
4
|
-
const fsx = require('./../fsx')
|
|
5
|
-
const keyNamesForEnvFile = require('./keyNamesForEnvFile')
|
|
6
|
-
const readProcessKey = require('./readProcessKey')
|
|
7
|
-
const readFileKey = require('./readFileKey')
|
|
8
|
-
const armorKeypair = require('../cryptography/armorKeypair')
|
|
9
|
-
|
|
10
|
-
async function invertForPrivateKeyName (filepath) {
|
|
11
|
-
const PUBLIC_KEY_SCHEMA = 'DOTENV_PUBLIC_KEY'
|
|
12
|
-
const PRIVATE_KEY_SCHEMA = 'DOTENV_PRIVATE_KEY'
|
|
13
|
-
|
|
14
|
-
if (!(await fsx.exists(filepath))) {
|
|
15
|
-
return null
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const envSrc = await fsx.readFileX(filepath)
|
|
19
|
-
const { parsed: envParsed } = scan(envSrc)
|
|
20
|
-
|
|
21
|
-
let publicKeyName
|
|
22
|
-
for (const keyName of Object.keys(envParsed)) {
|
|
23
|
-
if (keyName === PUBLIC_KEY_SCHEMA || keyName.startsWith(PUBLIC_KEY_SCHEMA)) {
|
|
24
|
-
publicKeyName = keyName // find DOTENV_PUBLIC_KEY* in filename
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
if (publicKeyName) {
|
|
29
|
-
return publicKeyName.replace(PUBLIC_KEY_SCHEMA, PRIVATE_KEY_SCHEMA) // return inverted (DOTENV_PUBLIC_KEY* -> DOTENV_PRIVATE_KEY*) if found
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
return null
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
async function keyValues (filepath, opts = {}) {
|
|
36
|
-
let keysFilepath = opts.keysFilepath || null
|
|
37
|
-
const noArmor = opts.noArmor === true
|
|
38
|
-
const names = keyNamesForEnvFile(filepath)
|
|
39
|
-
const publicKeyName = names.publicKeyName // DOTENV_PUBLIC_KEY_${ENVIRONMENT}
|
|
40
|
-
let privateKeyName = names.privateKeyName // DOTENV_PRIVATE_KEY_${ENVIRONMENT}
|
|
41
|
-
|
|
42
|
-
let publicKey = null
|
|
43
|
-
let privateKey = null
|
|
44
|
-
let privateKeySource = null
|
|
45
|
-
|
|
46
|
-
// public key: process.env first, then .env*
|
|
47
|
-
publicKey = readProcessKey(publicKeyName)
|
|
48
|
-
if (!publicKey) {
|
|
49
|
-
publicKey = await readFileKey(publicKeyName, filepath) || null
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// private key: process.env first, then .env.keys, then invert public key
|
|
53
|
-
privateKey = readProcessKey(privateKeyName)
|
|
54
|
-
if (!privateKey) {
|
|
55
|
-
if (keysFilepath) { // user specified -fk flag
|
|
56
|
-
keysFilepath = path.resolve(keysFilepath)
|
|
57
|
-
} else {
|
|
58
|
-
keysFilepath = path.resolve(path.dirname(filepath), '.env.keys') // typical scenario
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
privateKey = await readFileKey(privateKeyName, keysFilepath)
|
|
62
|
-
}
|
|
63
|
-
// invert
|
|
64
|
-
if (!privateKey) {
|
|
65
|
-
privateKeyName = await invertForPrivateKeyName(filepath)
|
|
66
|
-
if (privateKeyName) {
|
|
67
|
-
privateKey = readProcessKey(privateKeyName)
|
|
68
|
-
if (!privateKey) {
|
|
69
|
-
privateKey = await readFileKey(privateKeyName, keysFilepath)
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// armor
|
|
75
|
-
if (!noArmor && !privateKey && publicKey && publicKey.length > 0) {
|
|
76
|
-
const armorOptions = { envFilepath: filepath }
|
|
77
|
-
if (opts.token) {
|
|
78
|
-
armorOptions.token = opts.token
|
|
79
|
-
}
|
|
80
|
-
if (opts.command) {
|
|
81
|
-
armorOptions.command = opts.command
|
|
82
|
-
}
|
|
83
|
-
const kp = await armorKeypair(publicKey, armorOptions)
|
|
84
|
-
privateKey = kp.privateKey
|
|
85
|
-
privateKeySource = 'armor'
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
const result = {
|
|
89
|
-
publicKeyValue: publicKey || null, // important to make sure name is rendered
|
|
90
|
-
privateKeyValue: privateKey || null // important to make sure name is rendered
|
|
91
|
-
}
|
|
92
|
-
if (privateKeySource) {
|
|
93
|
-
result.privateKeySource = privateKeySource
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
return result
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
module.exports = keyValues
|