修改后台权限
This commit is contained in:
77
node_modules/@dotenvx/dotenvx/src/cli/actions/decrypt.js
generated
vendored
Normal file
77
node_modules/@dotenvx/dotenvx/src/cli/actions/decrypt.js
generated
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
const fsx = require('./../../lib/helpers/fsx')
|
||||
const { logger } = require('./../../shared/logger')
|
||||
|
||||
const Decrypt = require('./../../lib/services/decrypt')
|
||||
const catchAndLog = require('../../lib/helpers/catchAndLog')
|
||||
|
||||
function decrypt () {
|
||||
const options = this.opts()
|
||||
logger.debug(`options: ${JSON.stringify(options)}`)
|
||||
|
||||
const envs = this.envs
|
||||
const opsOn = options.opsOff !== true
|
||||
|
||||
let errorCount = 0
|
||||
|
||||
// stdout - should not have a try so that exit codes can surface to stdout
|
||||
if (options.stdout) {
|
||||
const {
|
||||
processedEnvs
|
||||
} = new Decrypt(envs, options.key, options.excludeKey, options.envKeysFile, opsOn).run()
|
||||
|
||||
for (const processedEnv of processedEnvs) {
|
||||
if (processedEnv.error) {
|
||||
errorCount += 1
|
||||
logger.error(processedEnv.error.messageWithHelp)
|
||||
} else {
|
||||
console.log(processedEnv.envSrc)
|
||||
}
|
||||
}
|
||||
|
||||
if (errorCount > 0) {
|
||||
process.exit(1)
|
||||
} else {
|
||||
process.exit(0) // exit early
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
const {
|
||||
processedEnvs,
|
||||
changedFilepaths,
|
||||
unchangedFilepaths
|
||||
} = new Decrypt(envs, options.key, options.excludeKey, options.envKeysFile, opsOn).run()
|
||||
|
||||
for (const processedEnv of processedEnvs) {
|
||||
logger.verbose(`decrypting ${processedEnv.envFilepath} (${processedEnv.filepath})`)
|
||||
|
||||
if (processedEnv.error) {
|
||||
errorCount += 1
|
||||
logger.error(processedEnv.error.messageWithHelp)
|
||||
} else if (processedEnv.changed) {
|
||||
fsx.writeFileX(processedEnv.filepath, processedEnv.envSrc)
|
||||
|
||||
logger.verbose(`decrypted ${processedEnv.envFilepath} (${processedEnv.filepath})`)
|
||||
} else {
|
||||
logger.verbose(`no changes ${processedEnv.envFilepath} (${processedEnv.filepath})`)
|
||||
}
|
||||
}
|
||||
|
||||
if (changedFilepaths.length > 0) {
|
||||
logger.success(`◇ decrypted (${changedFilepaths.join(',')})`)
|
||||
} else if (unchangedFilepaths.length > 0) {
|
||||
logger.info(`○ no changes (${unchangedFilepaths})`)
|
||||
} else {
|
||||
// do nothing - scenario when no .env files found
|
||||
}
|
||||
|
||||
if (errorCount > 0) {
|
||||
process.exit(1)
|
||||
}
|
||||
} catch (error) {
|
||||
catchAndLog(error)
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = decrypt
|
||||
73
node_modules/@dotenvx/dotenvx/src/cli/actions/encrypt.js
generated
vendored
Normal file
73
node_modules/@dotenvx/dotenvx/src/cli/actions/encrypt.js
generated
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
const fsx = require('./../../lib/helpers/fsx')
|
||||
const { logger } = require('./../../shared/logger')
|
||||
|
||||
const Encrypt = require('./../../lib/services/encrypt')
|
||||
|
||||
const catchAndLog = require('../../lib/helpers/catchAndLog')
|
||||
const localDisplayPath = require('../../lib/helpers/localDisplayPath')
|
||||
|
||||
function encrypt () {
|
||||
const options = this.opts()
|
||||
logger.debug(`options: ${JSON.stringify(options)}`)
|
||||
|
||||
const envs = this.envs
|
||||
const opsOn = options.opsOff !== true
|
||||
|
||||
// stdout - should not have a try so that exit codes can surface to stdout
|
||||
if (options.stdout) {
|
||||
const {
|
||||
processedEnvs
|
||||
} = new Encrypt(envs, options.key, options.excludeKey, options.envKeysFile, opsOn).run()
|
||||
|
||||
for (const processedEnv of processedEnvs) {
|
||||
console.log(processedEnv.envSrc)
|
||||
}
|
||||
process.exit(0) // exit early
|
||||
} else {
|
||||
try {
|
||||
const {
|
||||
processedEnvs,
|
||||
changedFilepaths,
|
||||
unchangedFilepaths
|
||||
} = new Encrypt(envs, options.key, options.excludeKey, options.envKeysFile, opsOn).run()
|
||||
|
||||
for (const processedEnv of processedEnvs) {
|
||||
logger.verbose(`encrypting ${processedEnv.envFilepath} (${processedEnv.filepath})`)
|
||||
if (processedEnv.error) {
|
||||
logger.warn(processedEnv.error.messageWithHelp)
|
||||
} else if (processedEnv.changed) {
|
||||
fsx.writeFileX(processedEnv.filepath, processedEnv.envSrc)
|
||||
|
||||
logger.verbose(`encrypted ${processedEnv.envFilepath} (${processedEnv.filepath})`)
|
||||
} else {
|
||||
logger.verbose(`no changes ${processedEnv.envFilepath} (${processedEnv.filepath})`)
|
||||
}
|
||||
}
|
||||
|
||||
if (changedFilepaths.length > 0) {
|
||||
const keyAddedEnv = processedEnvs.find((processedEnv) => processedEnv.privateKeyAdded)
|
||||
let msg = `◈ encrypted (${changedFilepaths.join(',')})`
|
||||
if (keyAddedEnv) {
|
||||
const envKeysFilepath = localDisplayPath(keyAddedEnv.envKeysFilepath)
|
||||
msg += ` + key (${envKeysFilepath})`
|
||||
}
|
||||
logger.success(msg)
|
||||
} else if (unchangedFilepaths.length > 0) {
|
||||
logger.info(`○ no changes (${unchangedFilepaths})`)
|
||||
} else {
|
||||
// do nothing - scenario when no .env files found
|
||||
}
|
||||
|
||||
for (const processedEnv of processedEnvs) {
|
||||
if (processedEnv.privateKeyAdded) {
|
||||
// intentionally quiet: success line already communicates key creation
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
catchAndLog(error)
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = encrypt
|
||||
36
node_modules/@dotenvx/dotenvx/src/cli/actions/ext/genexample.js
generated
vendored
Normal file
36
node_modules/@dotenvx/dotenvx/src/cli/actions/ext/genexample.js
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
const fsx = require('./../../../lib/helpers/fsx')
|
||||
const path = require('path')
|
||||
const main = require('./../../../lib/main')
|
||||
const { logger } = require('./../../../shared/logger')
|
||||
const catchAndLog = require('./../../../lib/helpers/catchAndLog')
|
||||
|
||||
function genexample (directory) {
|
||||
logger.debug(`directory: ${directory}`)
|
||||
|
||||
const options = this.opts()
|
||||
logger.debug(`options: ${JSON.stringify(options)}`)
|
||||
|
||||
try {
|
||||
const {
|
||||
envExampleFile,
|
||||
envFile,
|
||||
exampleFilepath,
|
||||
addedKeys
|
||||
} = main.genexample(directory, options.envFile)
|
||||
|
||||
logger.verbose(`loading env from ${envFile}`)
|
||||
|
||||
fsx.writeFileX(exampleFilepath, envExampleFile)
|
||||
|
||||
if (addedKeys.length > 0) {
|
||||
logger.success(`▣ generated (${path.basename(exampleFilepath)})`)
|
||||
} else {
|
||||
logger.info('○ no changes (.env.example)')
|
||||
}
|
||||
} catch (error) {
|
||||
catchAndLog(error)
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = genexample
|
||||
105
node_modules/@dotenvx/dotenvx/src/cli/actions/ext/gitignore.js
generated
vendored
Normal file
105
node_modules/@dotenvx/dotenvx/src/cli/actions/ext/gitignore.js
generated
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
const fsx = require('./../../../lib/helpers/fsx')
|
||||
|
||||
const DEFAULT_PATTERNS = ['.env*']
|
||||
const { logger } = require('./../../../shared/logger')
|
||||
|
||||
class Generic {
|
||||
constructor (filename, patterns = DEFAULT_PATTERNS, touchFile = false) {
|
||||
this.filename = filename
|
||||
this.patterns = patterns
|
||||
this.touchFile = touchFile
|
||||
}
|
||||
|
||||
append (str) {
|
||||
fsx.appendFileSync(this.filename, `\n${str}`)
|
||||
}
|
||||
|
||||
run () {
|
||||
const changedPatterns = []
|
||||
if (!fsx.existsSync(this.filename)) {
|
||||
if (this.touchFile === true && this.patterns.length > 0) {
|
||||
fsx.writeFileX(this.filename, '')
|
||||
} else {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
const lines = fsx.readFileX(this.filename).split(/\r?\n/)
|
||||
this.patterns.forEach(pattern => {
|
||||
if (!lines.includes(pattern.trim())) {
|
||||
this.append(pattern)
|
||||
|
||||
changedPatterns.push(pattern.trim())
|
||||
}
|
||||
})
|
||||
|
||||
if (changedPatterns.length > 0) {
|
||||
logger.success(`▣ ignored ${this.patterns} (${this.filename})`)
|
||||
} else {
|
||||
logger.info(`○ no changes (${this.filename})`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Git {
|
||||
constructor (patterns = DEFAULT_PATTERNS) {
|
||||
this.patterns = patterns
|
||||
}
|
||||
|
||||
run () {
|
||||
logger.verbose('add to .gitignore')
|
||||
new Generic('.gitignore', this.patterns, true).run()
|
||||
}
|
||||
}
|
||||
|
||||
class Docker {
|
||||
constructor (patterns = DEFAULT_PATTERNS) {
|
||||
this.patterns = patterns
|
||||
}
|
||||
|
||||
run () {
|
||||
logger.verbose('add to .dockerignore (if exists)')
|
||||
new Generic('.dockerignore', this.patterns).run()
|
||||
}
|
||||
}
|
||||
|
||||
class Npm {
|
||||
constructor (patterns = DEFAULT_PATTERNS) {
|
||||
this.patterns = patterns
|
||||
}
|
||||
|
||||
run () {
|
||||
logger.verbose('add to .npmignore (if existing)')
|
||||
new Generic('.npmignore', this.patterns).run()
|
||||
}
|
||||
}
|
||||
|
||||
class Vercel {
|
||||
constructor (patterns = DEFAULT_PATTERNS) {
|
||||
this.patterns = patterns
|
||||
}
|
||||
|
||||
run () {
|
||||
logger.verbose('add to .vercelignore (if existing)')
|
||||
new Generic('.vercelignore', this.patterns).run()
|
||||
}
|
||||
}
|
||||
|
||||
function gitignore () {
|
||||
const options = this.opts()
|
||||
logger.debug(`options: ${JSON.stringify(options)}`)
|
||||
|
||||
const patterns = options.pattern
|
||||
|
||||
new Git(patterns).run()
|
||||
new Docker(patterns).run()
|
||||
new Npm(patterns).run()
|
||||
new Vercel(patterns).run()
|
||||
}
|
||||
|
||||
module.exports = gitignore
|
||||
module.exports.Git = Git
|
||||
module.exports.Docker = Docker
|
||||
module.exports.Npm = Npm
|
||||
module.exports.Vercel = Vercel
|
||||
module.exports.Generic = Generic
|
||||
30
node_modules/@dotenvx/dotenvx/src/cli/actions/ext/prebuild.js
generated
vendored
Normal file
30
node_modules/@dotenvx/dotenvx/src/cli/actions/ext/prebuild.js
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
const { logger } = require('./../../../shared/logger')
|
||||
|
||||
const Prebuild = require('./../../../lib/services/prebuild')
|
||||
const catchAndLog = require('./../../../lib/helpers/catchAndLog')
|
||||
|
||||
function prebuild (directory) {
|
||||
// debug args
|
||||
logger.debug(`directory: ${directory}`)
|
||||
|
||||
const options = this.opts()
|
||||
logger.debug(`options: ${JSON.stringify(options)}`)
|
||||
|
||||
try {
|
||||
const {
|
||||
successMessage,
|
||||
warnings
|
||||
} = new Prebuild(directory, options).run()
|
||||
|
||||
for (const warning of warnings) {
|
||||
logger.warn(warning.messageWithHelp)
|
||||
}
|
||||
|
||||
logger.success(successMessage)
|
||||
} catch (error) {
|
||||
catchAndLog(error)
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = prebuild
|
||||
30
node_modules/@dotenvx/dotenvx/src/cli/actions/ext/precommit.js
generated
vendored
Normal file
30
node_modules/@dotenvx/dotenvx/src/cli/actions/ext/precommit.js
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
const { logger } = require('./../../../shared/logger')
|
||||
|
||||
const Precommit = require('./../../../lib/services/precommit')
|
||||
const catchAndLog = require('./../../../lib/helpers/catchAndLog')
|
||||
|
||||
function precommit (directory) {
|
||||
// debug args
|
||||
logger.debug(`directory: ${directory}`)
|
||||
|
||||
const options = this.opts()
|
||||
logger.debug(`options: ${JSON.stringify(options)}`)
|
||||
|
||||
try {
|
||||
const {
|
||||
successMessage,
|
||||
warnings
|
||||
} = new Precommit(directory, options).run()
|
||||
|
||||
for (const warning of warnings) {
|
||||
logger.warn(warning.messageWithHelp)
|
||||
}
|
||||
|
||||
logger.success(successMessage)
|
||||
} catch (error) {
|
||||
catchAndLog(error)
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = precommit
|
||||
34
node_modules/@dotenvx/dotenvx/src/cli/actions/ext/scan.js
generated
vendored
Normal file
34
node_modules/@dotenvx/dotenvx/src/cli/actions/ext/scan.js
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
const childProcess = require('child_process')
|
||||
|
||||
const { logger } = require('./../../../shared/logger')
|
||||
const chomp = require('./../../../lib/helpers/chomp')
|
||||
|
||||
function scan () {
|
||||
const options = this.opts()
|
||||
logger.debug(`options: ${JSON.stringify(options)}`)
|
||||
|
||||
try {
|
||||
// redirect stderr to stdout to capture and ignore it
|
||||
childProcess.execSync('gitleaks version', { stdio: ['ignore', 'pipe', 'ignore'] })
|
||||
} catch (error) {
|
||||
logger.error('gitleaks: command not found')
|
||||
logger.help('fix: install gitleaks: [brew install gitleaks]')
|
||||
logger.help('fix: other install options: [https://github.com/gitleaks/gitleaks]')
|
||||
process.exit(1)
|
||||
return
|
||||
}
|
||||
|
||||
let output = ''
|
||||
try {
|
||||
output = childProcess.execSync('gitleaks detect --no-banner --verbose 2>&1').toString() // gitleaks sends exit code 1 but puts data on stdout for failures, so we catch later and resurface the stdout
|
||||
logger.info(chomp(output))
|
||||
} catch (error) {
|
||||
if (error.stdout) {
|
||||
logger.error(chomp(error.stdout.toString()))
|
||||
}
|
||||
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = scan
|
||||
81
node_modules/@dotenvx/dotenvx/src/cli/actions/get.js
generated
vendored
Normal file
81
node_modules/@dotenvx/dotenvx/src/cli/actions/get.js
generated
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
const { logger } = require('./../../shared/logger')
|
||||
|
||||
const conventions = require('./../../lib/helpers/conventions')
|
||||
const escape = require('./../../lib/helpers/escape')
|
||||
const catchAndLog = require('./../../lib/helpers/catchAndLog')
|
||||
|
||||
const Get = require('./../../lib/services/get')
|
||||
|
||||
function get (key) {
|
||||
if (key) {
|
||||
logger.debug(`key: ${key}`)
|
||||
}
|
||||
|
||||
const options = this.opts()
|
||||
logger.debug(`options: ${JSON.stringify(options)}`)
|
||||
const prettyPrint = options.prettyPrint || options.pp
|
||||
|
||||
const ignore = options.ignore || []
|
||||
|
||||
let envs = []
|
||||
// handle shorthand conventions - like --convention=nextjs
|
||||
if (options.convention) {
|
||||
envs = conventions(options.convention).concat(this.envs)
|
||||
} else {
|
||||
envs = this.envs
|
||||
}
|
||||
|
||||
try {
|
||||
const opsOn = options.opsOff !== true
|
||||
const { parsed, errors } = new Get(key, envs, options.overload, options.all, options.envKeysFile, opsOn).run()
|
||||
|
||||
for (const error of errors || []) {
|
||||
if (options.strict) throw error // throw immediately if strict
|
||||
|
||||
if (ignore.includes(error.code)) {
|
||||
continue // ignore error
|
||||
}
|
||||
|
||||
logger.error(error.messageWithHelp)
|
||||
}
|
||||
|
||||
if (key) {
|
||||
const single = parsed[key]
|
||||
if (single === undefined) {
|
||||
console.log('')
|
||||
} else {
|
||||
console.log(single)
|
||||
}
|
||||
} else {
|
||||
if (options.format === 'eval') {
|
||||
let inline = ''
|
||||
for (const [key, value] of Object.entries(parsed)) {
|
||||
inline += `${key}=${escape(value)}\n`
|
||||
}
|
||||
inline = inline.trim()
|
||||
|
||||
console.log(inline)
|
||||
} else if (options.format === 'shell') {
|
||||
let inline = ''
|
||||
for (const [key, value] of Object.entries(parsed)) {
|
||||
inline += `${key}=${value} `
|
||||
}
|
||||
inline = inline.trim()
|
||||
|
||||
console.log(inline)
|
||||
} else {
|
||||
let space = 0
|
||||
if (prettyPrint) {
|
||||
space = 2
|
||||
}
|
||||
|
||||
console.log(JSON.stringify(parsed, null, space))
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
catchAndLog(error)
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = get
|
||||
45
node_modules/@dotenvx/dotenvx/src/cli/actions/keypair.js
generated
vendored
Normal file
45
node_modules/@dotenvx/dotenvx/src/cli/actions/keypair.js
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
const { logger } = require('./../../shared/logger')
|
||||
|
||||
const main = require('./../../lib/main')
|
||||
|
||||
function keypair (key) {
|
||||
if (key) {
|
||||
logger.debug(`key: ${key}`)
|
||||
}
|
||||
|
||||
const options = this.opts()
|
||||
logger.debug(`options: ${JSON.stringify(options)}`)
|
||||
const prettyPrint = options.prettyPrint || options.pp
|
||||
|
||||
const results = main.keypair(options.envFile, key, options.envKeysFile, options.opsOff)
|
||||
|
||||
if (typeof results === 'object' && results !== null) {
|
||||
// inline shell format - env $(dotenvx keypair --format=shell) your-command
|
||||
if (options.format === 'shell') {
|
||||
let inline = ''
|
||||
for (const [key, value] of Object.entries(results)) {
|
||||
inline += `${key}=${value || ''} `
|
||||
}
|
||||
inline = inline.trim()
|
||||
|
||||
console.log(inline)
|
||||
// json format
|
||||
} else {
|
||||
let space = 0
|
||||
if (prettyPrint) {
|
||||
space = 2
|
||||
}
|
||||
|
||||
console.log(JSON.stringify(results, null, space))
|
||||
}
|
||||
} else {
|
||||
if (results === undefined) {
|
||||
console.log('')
|
||||
process.exit(1)
|
||||
} else {
|
||||
console.log(results)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = keypair
|
||||
24
node_modules/@dotenvx/dotenvx/src/cli/actions/ls.js
generated
vendored
Normal file
24
node_modules/@dotenvx/dotenvx/src/cli/actions/ls.js
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
const treeify = require('object-treeify')
|
||||
|
||||
const { logger } = require('./../../shared/logger')
|
||||
|
||||
const main = require('./../../lib/main')
|
||||
const ArrayToTree = require('./../../lib/helpers/arrayToTree')
|
||||
|
||||
function ls (directory) {
|
||||
// debug args
|
||||
logger.debug(`directory: ${directory}`)
|
||||
|
||||
const options = this.opts()
|
||||
logger.debug(`options: ${JSON.stringify(options)}`)
|
||||
|
||||
const filepaths = main.ls(directory, options.envFile, options.excludeEnvFile)
|
||||
logger.debug(`filepaths: ${JSON.stringify(filepaths)}`)
|
||||
|
||||
const tree = new ArrayToTree(filepaths).run()
|
||||
logger.debug(`tree: ${JSON.stringify(tree)}`)
|
||||
|
||||
logger.info(treeify(tree))
|
||||
}
|
||||
|
||||
module.exports = ls
|
||||
74
node_modules/@dotenvx/dotenvx/src/cli/actions/rotate.js
generated
vendored
Normal file
74
node_modules/@dotenvx/dotenvx/src/cli/actions/rotate.js
generated
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
const fsx = require('./../../lib/helpers/fsx')
|
||||
const { logger } = require('./../../shared/logger')
|
||||
|
||||
const Rotate = require('./../../lib/services/rotate')
|
||||
|
||||
const catchAndLog = require('../../lib/helpers/catchAndLog')
|
||||
const localDisplayPath = require('../../lib/helpers/localDisplayPath')
|
||||
|
||||
function rotate () {
|
||||
const options = this.opts()
|
||||
logger.debug(`options: ${JSON.stringify(options)}`)
|
||||
|
||||
const envs = this.envs
|
||||
const opsOn = options.opsOff !== true
|
||||
|
||||
// stdout - should not have a try so that exit codes can surface to stdout
|
||||
if (options.stdout) {
|
||||
const {
|
||||
processedEnvs
|
||||
} = new Rotate(envs, options.key, options.excludeKey, options.envKeysFile, opsOn).run()
|
||||
|
||||
for (const processedEnv of processedEnvs) {
|
||||
console.log(processedEnv.envSrc)
|
||||
if (processedEnv.privateKeyAdded) {
|
||||
console.log('')
|
||||
console.log(processedEnv.envKeysSrc)
|
||||
}
|
||||
}
|
||||
process.exit(0) // exit early
|
||||
} else {
|
||||
try {
|
||||
const {
|
||||
processedEnvs,
|
||||
changedFilepaths,
|
||||
unchangedFilepaths
|
||||
} = new Rotate(envs, options.key, options.excludeKey, options.envKeysFile, opsOn).run()
|
||||
|
||||
for (const processedEnv of processedEnvs) {
|
||||
logger.verbose(`rotating ${processedEnv.envFilepath} (${processedEnv.filepath})`)
|
||||
if (processedEnv.error) {
|
||||
logger.warn(processedEnv.error.messageWithHelp)
|
||||
} else if (processedEnv.changed) {
|
||||
fsx.writeFileX(processedEnv.filepath, processedEnv.envSrc)
|
||||
if (processedEnv.privateKeyAdded) {
|
||||
fsx.writeFileX(processedEnv.envKeysFilepath, processedEnv.envKeysSrc)
|
||||
}
|
||||
|
||||
logger.verbose(`rotated ${processedEnv.envFilepath} (${processedEnv.filepath})`)
|
||||
} else {
|
||||
logger.verbose(`no changes ${processedEnv.envFilepath} (${processedEnv.filepath})`)
|
||||
}
|
||||
}
|
||||
|
||||
if (changedFilepaths.length > 0) {
|
||||
const keyAddedEnv = processedEnvs.find((processedEnv) => processedEnv.privateKeyAdded)
|
||||
let msg = `⟳ rotated (${changedFilepaths.join(',')})`
|
||||
if (keyAddedEnv) {
|
||||
const envKeysFilepath = localDisplayPath(keyAddedEnv.envKeysFilepath)
|
||||
msg += ` + key (${envKeysFilepath})`
|
||||
}
|
||||
logger.success(msg)
|
||||
} else if (unchangedFilepaths.length > 0) {
|
||||
logger.info(`○ no changes (${unchangedFilepaths})`)
|
||||
} else {
|
||||
// do nothing - scenario when no .env files found
|
||||
}
|
||||
} catch (error) {
|
||||
catchAndLog(error)
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = rotate
|
||||
109
node_modules/@dotenvx/dotenvx/src/cli/actions/run.js
generated
vendored
Normal file
109
node_modules/@dotenvx/dotenvx/src/cli/actions/run.js
generated
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
const path = require('path')
|
||||
const { logger } = require('./../../shared/logger')
|
||||
|
||||
const executeCommand = require('./../../lib/helpers/executeCommand')
|
||||
const Run = require('./../../lib/services/run')
|
||||
const catchAndLog = require('./../../lib/helpers/catchAndLog')
|
||||
|
||||
const conventions = require('./../../lib/helpers/conventions')
|
||||
|
||||
async function run () {
|
||||
const commandArgs = this.args
|
||||
logger.debug(`process command [${commandArgs.join(' ')}]`)
|
||||
|
||||
const options = this.opts()
|
||||
logger.debug(`options: ${JSON.stringify(options)}`)
|
||||
|
||||
const ignore = options.ignore || []
|
||||
|
||||
// dotenvx-ops related
|
||||
const opsOn = options.opsOff !== true
|
||||
|
||||
if (commandArgs.length < 1) {
|
||||
const hasSeparator = process.argv.indexOf('--') !== -1
|
||||
|
||||
if (hasSeparator) {
|
||||
logger.error('missing command after [dotenvx run --]. try [dotenvx run -- yourcommand]')
|
||||
} else {
|
||||
const realExample = options.envFile[0] || '.env'
|
||||
logger.error(`ambiguous command due to missing '--' separator. try [dotenvx run -f ${realExample} -- yourcommand]`)
|
||||
}
|
||||
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
try {
|
||||
let envs = []
|
||||
// handle shorthand conventions - like --convention=nextjs
|
||||
if (options.convention) {
|
||||
envs = conventions(options.convention).concat(this.envs)
|
||||
} else {
|
||||
envs = this.envs
|
||||
}
|
||||
|
||||
const {
|
||||
processedEnvs,
|
||||
readableStrings,
|
||||
readableFilepaths,
|
||||
uniqueInjectedKeys
|
||||
} = new Run(envs, options.overload, process.env, options.envKeysFile, opsOn).run()
|
||||
|
||||
for (const processedEnv of processedEnvs) {
|
||||
if (processedEnv.type === 'envFile') {
|
||||
logger.verbose(`loading env from ${processedEnv.filepath} (${path.resolve(processedEnv.filepath)})`)
|
||||
}
|
||||
|
||||
if (processedEnv.type === 'env') {
|
||||
logger.verbose(`loading env from string (${processedEnv.string})`)
|
||||
}
|
||||
|
||||
for (const error of processedEnv.errors || []) {
|
||||
if (ignore.includes(error.code)) {
|
||||
logger.verbose(`ignored: ${error.message}`)
|
||||
continue // ignore error
|
||||
}
|
||||
|
||||
if (options.strict) throw error // throw if strict and not ignored
|
||||
|
||||
if (error.code === 'MISSING_ENV_FILE' && options.convention) { // do not output error for conventions (too noisy)
|
||||
// intentionally quiet
|
||||
} else {
|
||||
logger.error(error.messageWithHelp)
|
||||
}
|
||||
}
|
||||
|
||||
// debug parsed
|
||||
logger.debug(processedEnv.parsed)
|
||||
|
||||
// verbose/debug injected key/value
|
||||
for (const [key, value] of Object.entries(processedEnv.injected || {})) {
|
||||
logger.verbose(`${key} set`)
|
||||
logger.debug(`${key} set to ${value}`)
|
||||
}
|
||||
|
||||
// verbose/debug preExisted key/value
|
||||
for (const [key, value] of Object.entries(processedEnv.preExisted || {})) {
|
||||
logger.verbose(`${key} pre-exists (protip: use --overload to override)`)
|
||||
logger.debug(`${key} pre-exists as ${value} (protip: use --overload to override)`)
|
||||
}
|
||||
}
|
||||
|
||||
let msg = `injecting env (${uniqueInjectedKeys.length})`
|
||||
if (readableFilepaths.length > 0 && readableStrings.length > 0) {
|
||||
msg += ` from ${readableFilepaths.join(', ')}, and --env flag${readableStrings.length > 1 ? 's' : ''}`
|
||||
} else if (readableFilepaths.length > 0) {
|
||||
msg += ` from ${readableFilepaths.join(', ')}`
|
||||
} else if (readableStrings.length > 0) {
|
||||
msg += ` from --env flag${readableStrings.length > 1 ? 's' : ''}`
|
||||
}
|
||||
|
||||
logger.successv(msg)
|
||||
} catch (error) {
|
||||
catchAndLog(error)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
await executeCommand(commandArgs, process.env)
|
||||
}
|
||||
|
||||
module.exports = run
|
||||
77
node_modules/@dotenvx/dotenvx/src/cli/actions/set.js
generated
vendored
Normal file
77
node_modules/@dotenvx/dotenvx/src/cli/actions/set.js
generated
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
const fsx = require('./../../lib/helpers/fsx')
|
||||
const { logger } = require('./../../shared/logger')
|
||||
|
||||
const Sets = require('./../../lib/services/sets')
|
||||
|
||||
const catchAndLog = require('../../lib/helpers/catchAndLog')
|
||||
const localDisplayPath = require('../../lib/helpers/localDisplayPath')
|
||||
|
||||
function set (key, value) {
|
||||
logger.debug(`key: ${key}`)
|
||||
logger.debug(`value: ${value}`)
|
||||
|
||||
const options = this.opts()
|
||||
logger.debug(`options: ${JSON.stringify(options)}`)
|
||||
|
||||
// encrypt
|
||||
let encrypt = true
|
||||
if (options.plain) {
|
||||
encrypt = false
|
||||
}
|
||||
|
||||
try {
|
||||
const envs = this.envs
|
||||
const envKeysFilepath = options.envKeysFile
|
||||
const opsOn = options.opsOff !== true
|
||||
|
||||
const {
|
||||
processedEnvs,
|
||||
changedFilepaths,
|
||||
unchangedFilepaths
|
||||
} = new Sets(key, value, envs, encrypt, envKeysFilepath, opsOn).run()
|
||||
|
||||
let withEncryption = ''
|
||||
|
||||
if (encrypt) {
|
||||
withEncryption = ' with encryption'
|
||||
}
|
||||
|
||||
for (const processedEnv of processedEnvs) {
|
||||
logger.verbose(`setting for ${processedEnv.envFilepath}`)
|
||||
|
||||
if (processedEnv.error) {
|
||||
logger.warn(processedEnv.error.messageWithHelp)
|
||||
} else {
|
||||
fsx.writeFileX(processedEnv.filepath, processedEnv.envSrc)
|
||||
|
||||
logger.verbose(`${processedEnv.key} set${withEncryption} (${processedEnv.envFilepath})`)
|
||||
logger.debug(`${processedEnv.key} set${withEncryption} to ${processedEnv.value} (${processedEnv.envFilepath})`)
|
||||
}
|
||||
}
|
||||
|
||||
const keyAddedEnv = processedEnvs.find((processedEnv) => processedEnv.privateKeyAdded)
|
||||
const keyAddedSuffix = keyAddedEnv ? ` + key (${localDisplayPath(keyAddedEnv.envKeysFilepath)})` : ''
|
||||
|
||||
if (changedFilepaths.length > 0) {
|
||||
if (encrypt) {
|
||||
logger.success(`◈ encrypted ${key} (${changedFilepaths.join(',')})${keyAddedSuffix}`)
|
||||
} else {
|
||||
logger.success(`◇ set ${key} (${changedFilepaths.join(',')})`)
|
||||
}
|
||||
} else if (encrypt && keyAddedEnv) {
|
||||
const keyAddedEnvFilepath = keyAddedEnv.envFilepath || changedFilepaths[0] || '.env'
|
||||
logger.success(`◈ encrypted ${key} (${keyAddedEnvFilepath})${keyAddedSuffix}`)
|
||||
} else if (unchangedFilepaths.length > 0) {
|
||||
logger.info(`○ no changes (${unchangedFilepaths})`)
|
||||
} else {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
// intentionally quiet: success line communicates key creation
|
||||
} catch (error) {
|
||||
catchAndLog(error)
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = set
|
||||
73
node_modules/@dotenvx/dotenvx/src/cli/commands/ext.js
generated
vendored
Normal file
73
node_modules/@dotenvx/dotenvx/src/cli/commands/ext.js
generated
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
const { Command } = require('commander')
|
||||
|
||||
const examples = require('./../examples')
|
||||
const executeExtension = require('../../lib/helpers/executeExtension')
|
||||
const removeDynamicHelpSection = require('../../lib/helpers/removeDynamicHelpSection')
|
||||
|
||||
const ext = new Command('ext')
|
||||
|
||||
ext
|
||||
.description('🔌 extensions')
|
||||
.allowUnknownOption()
|
||||
|
||||
ext
|
||||
.argument('[command]', 'dynamic ext command')
|
||||
.argument('[args...]', 'dynamic ext command arguments')
|
||||
.action((command, args, cmdObj) => {
|
||||
const rawArgs = process.argv.slice(3) // adjust the index based on where actual args start
|
||||
executeExtension(ext, command, rawArgs)
|
||||
})
|
||||
|
||||
// dotenvx ext ls
|
||||
ext.command('ls')
|
||||
.description('print all .env files in a tree structure')
|
||||
.argument('[directory]', 'directory to list .env files from', '.')
|
||||
.option('-f, --env-file <filenames...>', 'path(s) to your env file(s)', '.env*')
|
||||
.option('-ef, --exclude-env-file <excludeFilenames...>', 'path(s) to exclude from your env file(s) (default: none)')
|
||||
.action(require('./../actions/ls'))
|
||||
|
||||
// dotenvx ext genexample
|
||||
ext.command('genexample')
|
||||
.description('generate .env.example')
|
||||
.argument('[directory]', 'directory to generate from', '.')
|
||||
.option('-f, --env-file <paths...>', 'path(s) to your env file(s)', '.env')
|
||||
.action(require('./../actions/ext/genexample'))
|
||||
|
||||
// dotenvx ext gitignore
|
||||
ext.command('gitignore')
|
||||
.description('append to .gitignore file (and if existing, .dockerignore, .npmignore, and .vercelignore)')
|
||||
.addHelpText('after', examples.gitignore)
|
||||
.option('--pattern <patterns...>', 'pattern(s) to gitignore', ['.env*'])
|
||||
.action(require('./../actions/ext/gitignore'))
|
||||
|
||||
// dotenvx ext prebuild
|
||||
ext.command('prebuild')
|
||||
.description('prevent including .env files in docker builds')
|
||||
.addHelpText('after', examples.prebuild)
|
||||
.argument('[directory]', 'directory to prevent including .env files from', '.')
|
||||
.action(require('./../actions/ext/prebuild'))
|
||||
|
||||
// dotenvx ext precommit
|
||||
ext.command('precommit')
|
||||
.description('prevent committing .env files to code')
|
||||
.addHelpText('after', examples.precommit)
|
||||
.argument('[directory]', 'directory to prevent committing .env files from', '.')
|
||||
.option('-i, --install', 'install to .git/hooks/pre-commit')
|
||||
.action(require('./../actions/ext/precommit'))
|
||||
|
||||
// dotenvx scan
|
||||
ext.command('scan')
|
||||
.description('scan for leaked secrets')
|
||||
.action(require('./../actions/ext/scan'))
|
||||
|
||||
// override helpInformation to hide dynamic commands
|
||||
ext.helpInformation = function () {
|
||||
const originalHelp = Command.prototype.helpInformation.call(this)
|
||||
const lines = originalHelp.split('\n')
|
||||
|
||||
removeDynamicHelpSection(lines)
|
||||
|
||||
return lines.join('\n')
|
||||
}
|
||||
|
||||
module.exports = ext
|
||||
262
node_modules/@dotenvx/dotenvx/src/cli/dotenvx.js
generated
vendored
Executable file
262
node_modules/@dotenvx/dotenvx/src/cli/dotenvx.js
generated
vendored
Executable file
@@ -0,0 +1,262 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/* c8 ignore start */
|
||||
const { Command } = require('commander')
|
||||
const program = new Command()
|
||||
|
||||
const { setLogLevel, logger } = require('../shared/logger')
|
||||
const examples = require('./examples')
|
||||
const packageJson = require('./../lib/helpers/packageJson')
|
||||
const Errors = require('./../lib/helpers/errors')
|
||||
const getCommanderVersion = require('./../lib/helpers/getCommanderVersion')
|
||||
const executeDynamic = require('./../lib/helpers/executeDynamic')
|
||||
const removeDynamicHelpSection = require('./../lib/helpers/removeDynamicHelpSection')
|
||||
const removeOptionsHelpParts = require('./../lib/helpers/removeOptionsHelpParts')
|
||||
|
||||
const Session = require('./../db/session')
|
||||
const sesh = new Session()
|
||||
|
||||
// for use with run
|
||||
const envs = []
|
||||
function collectEnvs (type) {
|
||||
return function (value, previous) {
|
||||
envs.push({ type, value })
|
||||
return previous.concat([value])
|
||||
}
|
||||
}
|
||||
|
||||
// surface hoisting problems
|
||||
const commanderVersion = getCommanderVersion()
|
||||
if (commanderVersion && parseInt(commanderVersion.split('.')[0], 10) >= 12) {
|
||||
const message = `dotenvx depends on commander@11.x.x but you are attempting to hoist commander@${commanderVersion}`
|
||||
const error = new Errors({ message }).dangerousDependencyHoist()
|
||||
logger.error(error.messageWithHelp)
|
||||
}
|
||||
|
||||
// global log levels
|
||||
program
|
||||
.usage('run -- yourcommand')
|
||||
.option('-l, --log-level <level>', 'set log level', 'info')
|
||||
.option('-q, --quiet', 'sets log level to error')
|
||||
.option('-v, --verbose', 'sets log level to verbose')
|
||||
.option('-d, --debug', 'sets log level to debug')
|
||||
.hook('preAction', (thisCommand, actionCommand) => {
|
||||
const options = thisCommand.opts()
|
||||
|
||||
setLogLevel(options)
|
||||
})
|
||||
|
||||
// for dynamic loading of dotenvx-ops, etc
|
||||
program
|
||||
.argument('[command]', 'dynamic command')
|
||||
.argument('[args...]', 'dynamic command arguments')
|
||||
.action((command, args, cmdObj) => {
|
||||
const rawArgs = process.argv.slice(3) // adjust the index based on where actual args start
|
||||
executeDynamic(program, command, rawArgs)
|
||||
})
|
||||
|
||||
// cli
|
||||
program
|
||||
.name('dotenvx')
|
||||
.description(packageJson.description)
|
||||
.version(packageJson.version)
|
||||
.allowUnknownOption()
|
||||
|
||||
// dotenvx run -- node index.js
|
||||
const runAction = require('./actions/run')
|
||||
program.command('run')
|
||||
.description('inject env at runtime [dotenvx run -- yourcommand]')
|
||||
.addHelpText('after', examples.run)
|
||||
.option('-e, --env <strings...>', 'environment variable(s) set as string (example: "HELLO=World")', collectEnvs('env'), [])
|
||||
.option('-f, --env-file <paths...>', 'path(s) to your env file(s)', collectEnvs('envFile'), [])
|
||||
.option('-fk, --env-keys-file <path>', 'path to your .env.keys file (default: same path as your env file)')
|
||||
.option('-o, --overload', 'override existing env variables (by default, existing env vars take precedence over .env files)')
|
||||
.option('--strict', 'process.exit(1) on any errors', false)
|
||||
.option('--convention <name>', 'load a .env convention (available conventions: [\'nextjs\', \'flow\'])')
|
||||
.option('--ignore <errorCodes...>', 'error code(s) to ignore (example: --ignore=MISSING_ENV_FILE)')
|
||||
.option('--ops-off', 'disable dotenvx-ops features', sesh.opsOff())
|
||||
.action(function (...args) {
|
||||
this.envs = envs
|
||||
runAction.apply(this, args)
|
||||
})
|
||||
|
||||
// dotenvx get
|
||||
const getAction = require('./actions/get')
|
||||
program.command('get')
|
||||
.usage('[KEY] [options]')
|
||||
.description('return a single environment variable')
|
||||
.argument('[KEY]', 'environment variable name')
|
||||
.option('-e, --env <strings...>', 'environment variable(s) set as string (example: "HELLO=World")', collectEnvs('env'), [])
|
||||
.option('-f, --env-file <paths...>', 'path(s) to your env file(s)', collectEnvs('envFile'), [])
|
||||
.option('-fk, --env-keys-file <path>', 'path to your .env.keys file (default: same path as your env file)')
|
||||
.option('-o, --overload', 'override existing env variables (by default, existing env vars take precedence over .env files)')
|
||||
.option('--strict', 'process.exit(1) on any errors', false)
|
||||
.option('--convention <name>', 'load a .env convention (available conventions: [\'nextjs\', \'flow\'])')
|
||||
.option('--ignore <errorCodes...>', 'error code(s) to ignore (example: --ignore=MISSING_ENV_FILE)')
|
||||
.option('-a, --all', 'include all machine envs as well')
|
||||
.option('-pp, --pretty-print', 'pretty print output')
|
||||
.option('--pp', 'pretty print output (alias)')
|
||||
.option('--format <type>', 'format of the output (json, shell, eval)', 'json')
|
||||
.option('--ops-off', 'disable dotenvx-ops features', sesh.opsOff())
|
||||
.action(function (...args) {
|
||||
this.envs = envs
|
||||
getAction.apply(this, args)
|
||||
})
|
||||
|
||||
// dotenvx set
|
||||
const setAction = require('./actions/set')
|
||||
program.command('set')
|
||||
.usage('<KEY> <value> [options]')
|
||||
.description('encrypt a single environment variable')
|
||||
.addHelpText('after', examples.set)
|
||||
.allowUnknownOption()
|
||||
.argument('KEY', 'KEY')
|
||||
.argument('value', 'value')
|
||||
.option('-f, --env-file <paths...>', 'path(s) to your env file(s)', collectEnvs('envFile'), [])
|
||||
.option('-fk, --env-keys-file <path>', 'path to your .env.keys file (default: same path as your env file)')
|
||||
.option('-c, --encrypt', 'encrypt value', true)
|
||||
.option('-p, --plain', 'store value as plain text', false)
|
||||
.option('--ops-off', 'disable dotenvx-ops features', sesh.opsOff())
|
||||
.action(function (...args) {
|
||||
this.envs = envs
|
||||
setAction.apply(this, args)
|
||||
})
|
||||
|
||||
// dotenvx encrypt
|
||||
const encryptAction = require('./actions/encrypt')
|
||||
program.command('encrypt')
|
||||
.description('convert .env file(s) to encrypted .env file(s)')
|
||||
.option('-f, --env-file <paths...>', 'path(s) to your env file(s)', collectEnvs('envFile'), [])
|
||||
.option('-fk, --env-keys-file <path>', 'path to your .env.keys file (default: same path as your env file)')
|
||||
.option('-k, --key <keys...>', 'keys(s) to encrypt (default: all keys in file)')
|
||||
.option('-ek, --exclude-key <excludeKeys...>', 'keys(s) to exclude from encryption (default: none)')
|
||||
.option('--ops-off', 'disable dotenvx-ops features', sesh.opsOff())
|
||||
.option('--stdout', 'send to stdout')
|
||||
.action(function (...args) {
|
||||
this.envs = envs
|
||||
encryptAction.apply(this, args)
|
||||
})
|
||||
|
||||
// dotenvx decrypt
|
||||
const decryptAction = require('./actions/decrypt')
|
||||
program.command('decrypt')
|
||||
.description('convert encrypted .env file(s) to plain .env file(s)')
|
||||
.option('-f, --env-file <paths...>', 'path(s) to your env file(s)', collectEnvs('envFile'), [])
|
||||
.option('-fk, --env-keys-file <path>', 'path to your .env.keys file (default: same path as your env file)')
|
||||
.option('-k, --key <keys...>', 'keys(s) to decrypt (default: all keys in file)')
|
||||
.option('-ek, --exclude-key <excludeKeys...>', 'keys(s) to exclude from decryption (default: none)')
|
||||
.option('--ops-off', 'disable dotenvx-ops features', sesh.opsOff())
|
||||
.option('--stdout', 'send to stdout')
|
||||
.action(function (...args) {
|
||||
this.envs = envs
|
||||
decryptAction.apply(this, args)
|
||||
})
|
||||
|
||||
// dotenvx rotate
|
||||
const rotateAction = require('./actions/rotate')
|
||||
program.command('rotate')
|
||||
.description('rotate keypair(s) and re-encrypt .env file(s)')
|
||||
.option('-f, --env-file <paths...>', 'path(s) to your env file(s)', collectEnvs('envFile'), [])
|
||||
.option('-fk, --env-keys-file <path>', 'path to your .env.keys file (default: same path as your env file)')
|
||||
.option('-k, --key <keys...>', 'keys(s) to encrypt (default: all keys in file)')
|
||||
.option('-ek, --exclude-key <excludeKeys...>', 'keys(s) to exclude from encryption (default: none)')
|
||||
.option('--ops-off', 'disable dotenvx-ops features', sesh.opsOff())
|
||||
.option('--stdout', 'send to stdout')
|
||||
.action(function (...args) {
|
||||
this.envs = envs
|
||||
rotateAction.apply(this, args)
|
||||
})
|
||||
|
||||
// dotenvx keypair
|
||||
const keypairAction = require('./actions/keypair')
|
||||
program.command('keypair')
|
||||
.usage('[KEY] [options]')
|
||||
.description('print public/private keys for .env file(s)')
|
||||
.argument('[KEY]', 'environment variable key name')
|
||||
.option('-f, --env-file <paths...>', 'path(s) to your env file(s)')
|
||||
.option('-fk, --env-keys-file <path>', 'path to your .env.keys file (default: same path as your env file)')
|
||||
.option('--ops-off', 'disable dotenvx-ops features', sesh.opsOff())
|
||||
.option('-pp, --pretty-print', 'pretty print output')
|
||||
.option('--pp', 'pretty print output (alias)')
|
||||
.option('--format <type>', 'format of the output (json, shell)', 'json')
|
||||
.action(keypairAction)
|
||||
|
||||
// dotenvx ls
|
||||
const lsAction = require('./actions/ls')
|
||||
program.command('ls')
|
||||
.description('print all .env files in a tree structure')
|
||||
.argument('[directory]', 'directory to list .env files from', '.')
|
||||
.option('-f, --env-file <filenames...>', 'path(s) to your env file(s)', '.env*')
|
||||
.option('-ef, --exclude-env-file <excludeFilenames...>', 'path(s) to exclude from your env file(s) (default: none)')
|
||||
.action(lsAction)
|
||||
|
||||
// dotenvx help
|
||||
program.command('help [command]')
|
||||
.description('display help for command')
|
||||
.action((command) => {
|
||||
if (command) {
|
||||
const subCommand = program.commands.find(c => c.name() === command)
|
||||
if (subCommand) {
|
||||
subCommand.outputHelp()
|
||||
} else {
|
||||
program.outputHelp()
|
||||
}
|
||||
} else {
|
||||
program.outputHelp()
|
||||
}
|
||||
})
|
||||
|
||||
// dotenvx pro
|
||||
program.addHelpText('after', ' ')
|
||||
program.addHelpText('after', 'Advanced: ')
|
||||
program.addHelpText('after', ' ops 🛡️ ops')
|
||||
program.addHelpText('after', ' ext 🔌 extensions')
|
||||
|
||||
// dotenvx ext
|
||||
program.addCommand(require('./commands/ext'))
|
||||
|
||||
//
|
||||
// MOVED
|
||||
//
|
||||
const prebuildAction = require('./actions/ext/prebuild')
|
||||
program.command('prebuild')
|
||||
.description('DEPRECATED: moved to [dotenvx ext prebuild]')
|
||||
.addHelpText('after', examples.prebuild)
|
||||
.action(function (...args) {
|
||||
logger.warn('DEPRECATION NOTICE: [prebuild] has moved to [dotenvx ext prebuild]')
|
||||
|
||||
prebuildAction.apply(this, args)
|
||||
})
|
||||
|
||||
const precommitAction = require('./actions/ext/precommit')
|
||||
program.command('precommit')
|
||||
.description('DEPRECATED: moved to [dotenvx ext precommit]')
|
||||
.addHelpText('after', examples.precommit)
|
||||
.option('-i, --install', 'install to .git/hooks/pre-commit')
|
||||
.action(function (...args) {
|
||||
logger.warn('DEPRECATION NOTICE: [precommit] has moved to [dotenvx ext precommit]')
|
||||
|
||||
precommitAction.apply(this, args)
|
||||
})
|
||||
|
||||
// override helpInformation to hide DEPRECATED and 'ext' commands
|
||||
program.helpInformation = function () {
|
||||
const originalHelp = Command.prototype.helpInformation.call(this)
|
||||
const lines = originalHelp.split('\n')
|
||||
|
||||
removeDynamicHelpSection(lines)
|
||||
removeOptionsHelpParts(lines)
|
||||
|
||||
// Filter out the hidden command from the help output
|
||||
const filteredLines = lines.filter(line =>
|
||||
!line.includes('DEPRECATED') &&
|
||||
!line.includes('help [command]') &&
|
||||
!line.includes('🔌 extensions') &&
|
||||
!/^\s*ls\b/.test(line)
|
||||
)
|
||||
|
||||
return filteredLines.join('\n')
|
||||
}
|
||||
/* c8 ignore stop */
|
||||
|
||||
program.parse(process.argv)
|
||||
99
node_modules/@dotenvx/dotenvx/src/cli/examples.js
generated
vendored
Normal file
99
node_modules/@dotenvx/dotenvx/src/cli/examples.js
generated
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
const run = function () {
|
||||
return `
|
||||
Examples:
|
||||
|
||||
\`\`\`
|
||||
$ dotenvx run -- npm run dev
|
||||
$ dotenvx run -- flask --app index run
|
||||
$ dotenvx run -- php artisan serve
|
||||
$ dotenvx run -- bin/rails s
|
||||
\`\`\`
|
||||
|
||||
Try it:
|
||||
|
||||
\`\`\`
|
||||
$ echo "HELLO=World" > .env
|
||||
$ echo "console.log('Hello ' + process.env.HELLO)" > index.js
|
||||
|
||||
$ dotenvx run -f .env -- node index.js
|
||||
[dotenvx] injecting env (1) from .env
|
||||
Hello World
|
||||
\`\`\`
|
||||
`
|
||||
}
|
||||
|
||||
const precommit = function () {
|
||||
return `
|
||||
Examples:
|
||||
|
||||
\`\`\`
|
||||
$ dotenvx ext precommit
|
||||
$ dotenvx ext precommit --install
|
||||
\`\`\`
|
||||
|
||||
Try it:
|
||||
|
||||
\`\`\`
|
||||
$ dotenvx ext precommit
|
||||
[dotenvx@0.45.0][precommit] success
|
||||
\`\`\`
|
||||
`
|
||||
}
|
||||
|
||||
const prebuild = function () {
|
||||
return `
|
||||
Examples:
|
||||
|
||||
\`\`\`
|
||||
$ dotenvx ext prebuild
|
||||
\`\`\`
|
||||
|
||||
Try it:
|
||||
|
||||
\`\`\`
|
||||
$ dotenvx ext prebuild
|
||||
[dotenvx@0.10.0][prebuild] success
|
||||
\`\`\`
|
||||
`
|
||||
}
|
||||
|
||||
const gitignore = function () {
|
||||
return `
|
||||
Examples:
|
||||
|
||||
\`\`\`
|
||||
$ dotenvx ext gitignore
|
||||
$ dotenvx ext gitignore --pattern .env.keys
|
||||
\`\`\`
|
||||
|
||||
Try it:
|
||||
|
||||
\`\`\`
|
||||
$ dotenvx ext gitignore
|
||||
▣ ignored .env* (.gitignore)
|
||||
\`\`\`
|
||||
`
|
||||
}
|
||||
|
||||
const set = function () {
|
||||
return `
|
||||
Examples:
|
||||
|
||||
\`\`\`
|
||||
$ dotenvx set KEY value
|
||||
$ dotenvx set KEY "value with spaces"
|
||||
$ dotenvx set KEY -- "---value with a dash---"
|
||||
$ dotenvx set KEY -- "-----BEGIN OPENSSH PRIVATE KEY-----
|
||||
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
|
||||
-----END OPENSSH PRIVATE KEY-----"
|
||||
\`\`\`
|
||||
`
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
run,
|
||||
precommit,
|
||||
prebuild,
|
||||
gitignore,
|
||||
set
|
||||
}
|
||||
21
node_modules/@dotenvx/dotenvx/src/db/session.js
generated
vendored
Normal file
21
node_modules/@dotenvx/dotenvx/src/db/session.js
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
const Ops = require('./../lib/extensions/ops')
|
||||
|
||||
class Session {
|
||||
constructor () {
|
||||
this.ops = new Ops()
|
||||
this.opsStatus = this.ops.status()
|
||||
}
|
||||
|
||||
//
|
||||
// opsOff/On
|
||||
//
|
||||
opsOn () {
|
||||
return this.opsStatus === 'on'
|
||||
}
|
||||
|
||||
opsOff () {
|
||||
return !this.opsOn()
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Session
|
||||
1
node_modules/@dotenvx/dotenvx/src/lib/config.d.ts
generated
vendored
Normal file
1
node_modules/@dotenvx/dotenvx/src/lib/config.d.ts
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export {};
|
||||
1
node_modules/@dotenvx/dotenvx/src/lib/config.js
generated
vendored
Normal file
1
node_modules/@dotenvx/dotenvx/src/lib/config.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
require('./main.js').config()
|
||||
98
node_modules/@dotenvx/dotenvx/src/lib/extensions/ops.js
generated
vendored
Normal file
98
node_modules/@dotenvx/dotenvx/src/lib/extensions/ops.js
generated
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
const path = require('path')
|
||||
const childProcess = require('child_process')
|
||||
|
||||
// const { logger } = require('./../../shared/logger')
|
||||
|
||||
class Ops {
|
||||
constructor () {
|
||||
this.opsLib = null
|
||||
|
||||
if (this._isForcedOff()) {
|
||||
return
|
||||
}
|
||||
|
||||
// check npm lib
|
||||
try { this.opsLib = this._opsNpm() } catch (_e) {}
|
||||
|
||||
// check binary cli
|
||||
if (!this.opsLib) {
|
||||
try { this.opsLib = this._opsCli() } catch (_e) {}
|
||||
}
|
||||
|
||||
if (this.opsLib) {
|
||||
// logger.successv(`🛡️ ops: ${this.opsLib.status()}`)
|
||||
}
|
||||
}
|
||||
|
||||
status () {
|
||||
if (this._isForcedOff() || !this.opsLib) {
|
||||
return 'off'
|
||||
}
|
||||
|
||||
return this.opsLib.status()
|
||||
}
|
||||
|
||||
keypair (publicKey) {
|
||||
if (this._isForcedOff() || !this.opsLib) {
|
||||
return {}
|
||||
}
|
||||
|
||||
return this.opsLib.keypair(publicKey)
|
||||
}
|
||||
|
||||
observe (payload) {
|
||||
if (!this._isForcedOff() && this.opsLib && this.opsLib.status() !== 'off') {
|
||||
const encoded = Buffer.from(JSON.stringify(payload)).toString('base64')
|
||||
this.opsLib.observe(encoded)
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// private
|
||||
//
|
||||
_opsNpm () {
|
||||
const npmBin = path.resolve(process.cwd(), 'node_modules/.bin/dotenvx-ops')
|
||||
return this._opsLib(npmBin)
|
||||
}
|
||||
|
||||
_opsCli () {
|
||||
return this._opsLib('dotenvx-ops')
|
||||
}
|
||||
|
||||
_opsLib (binary) {
|
||||
childProcess.execFileSync(binary, ['--version'], { stdio: ['pipe', 'pipe', 'ignore'] })
|
||||
|
||||
return {
|
||||
status: () => {
|
||||
return childProcess.execFileSync(binary, ['status'], { stdio: ['pipe', 'pipe', 'ignore'] }).toString().trim()
|
||||
},
|
||||
keypair: (publicKey) => {
|
||||
const args = ['keypair']
|
||||
if (publicKey) {
|
||||
args.push(publicKey)
|
||||
}
|
||||
const output = childProcess.execFileSync(binary, args, { stdio: ['pipe', 'pipe', 'ignore'] }).toString().trim()
|
||||
const parsed = JSON.parse(output.toString())
|
||||
return parsed
|
||||
},
|
||||
observe: (encoded) => {
|
||||
try {
|
||||
const subprocess = childProcess.spawn(binary, ['observe', encoded], {
|
||||
stdio: 'ignore',
|
||||
detached: true
|
||||
})
|
||||
|
||||
subprocess.unref() // let it run independently
|
||||
} catch (e) {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_isForcedOff () {
|
||||
return process.env.DOTENVX_OPS_OFF === 'true'
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Ops
|
||||
61
node_modules/@dotenvx/dotenvx/src/lib/helpers/append.js
generated
vendored
Normal file
61
node_modules/@dotenvx/dotenvx/src/lib/helpers/append.js
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
const quotes = require('./quotes')
|
||||
const dotenvParse = require('./dotenvParse')
|
||||
const escapeForRegex = require('./escapeForRegex')
|
||||
const escapeDollarSigns = require('./escapeDollarSigns')
|
||||
|
||||
function append (src, key, appendValue) {
|
||||
let output
|
||||
let newPart = ''
|
||||
|
||||
const parsed = dotenvParse(src, true, true) // skip expanding \n and skip converting \r\n
|
||||
const _quotes = quotes(src)
|
||||
if (Object.prototype.hasOwnProperty.call(parsed, key)) {
|
||||
const quote = _quotes[key]
|
||||
const originalValue = parsed[key]
|
||||
|
||||
newPart += `${key}=${quote}${originalValue},${appendValue}${quote}`
|
||||
|
||||
const escapedOriginalValue = escapeForRegex(originalValue)
|
||||
|
||||
// conditionally enforce end of line
|
||||
let enforceEndOfLine = ''
|
||||
if (escapedOriginalValue === '') {
|
||||
enforceEndOfLine = '$' // EMPTY scenario
|
||||
}
|
||||
|
||||
const currentPart = new RegExp(
|
||||
'^' + // start of line
|
||||
'(\\s*)?' + // spaces
|
||||
'(export\\s+)?' + // export
|
||||
key + // KEY
|
||||
'\\s*=\\s*' + // spaces (KEY = value)
|
||||
'["\'`]?' + // open quote
|
||||
escapedOriginalValue + // escaped value
|
||||
'["\'`]?' + // close quote
|
||||
enforceEndOfLine
|
||||
,
|
||||
'gm' // (g)lobal (m)ultiline
|
||||
)
|
||||
|
||||
const saferInput = escapeDollarSigns(newPart) // cleanse user inputted capture groups ($1, $2 etc)
|
||||
|
||||
// $1 preserves spaces
|
||||
// $2 preserves export
|
||||
output = src.replace(currentPart, `$1$2${saferInput}`)
|
||||
} else {
|
||||
newPart += `${key}="${appendValue}"`
|
||||
|
||||
// append
|
||||
if (src.endsWith('\n')) {
|
||||
newPart = newPart + '\n'
|
||||
} else {
|
||||
newPart = '\n' + newPart
|
||||
}
|
||||
|
||||
output = src + newPart
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
module.exports = append
|
||||
27
node_modules/@dotenvx/dotenvx/src/lib/helpers/arrayToTree.js
generated
vendored
Normal file
27
node_modules/@dotenvx/dotenvx/src/lib/helpers/arrayToTree.js
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
const path = require('path')
|
||||
|
||||
class ArrayToTree {
|
||||
constructor (arr) {
|
||||
this.arr = arr
|
||||
}
|
||||
|
||||
run () {
|
||||
const tree = {}
|
||||
|
||||
for (let i = 0; i < this.arr.length; i++) {
|
||||
const normalizedPath = path.normalize(this.arr[i]) // normalize any strange paths
|
||||
const parts = normalizedPath.split(path.sep) // use the platform-specific path segment separator
|
||||
let current = tree
|
||||
|
||||
for (let j = 0; j < parts.length; j++) {
|
||||
const part = parts[j]
|
||||
current[part] = current[part] || {}
|
||||
current = current[part]
|
||||
}
|
||||
}
|
||||
|
||||
return tree
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ArrayToTree
|
||||
20
node_modules/@dotenvx/dotenvx/src/lib/helpers/buildEnvs.js
generated
vendored
Normal file
20
node_modules/@dotenvx/dotenvx/src/lib/helpers/buildEnvs.js
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
const conventions = require('./conventions')
|
||||
const dotenvOptionPaths = require('./dotenvOptionPaths')
|
||||
|
||||
function buildEnvs (options) {
|
||||
// build envs using user set option.path
|
||||
const optionPaths = dotenvOptionPaths(options) // [ '.env' ]
|
||||
|
||||
let envs = []
|
||||
if (options.convention) { // handle shorthand conventions
|
||||
envs = conventions(options.convention).concat(envs)
|
||||
}
|
||||
|
||||
for (const optionPath of optionPaths) {
|
||||
envs.push({ type: 'envFile', value: optionPath })
|
||||
}
|
||||
|
||||
return envs
|
||||
}
|
||||
|
||||
module.exports = buildEnvs
|
||||
13
node_modules/@dotenvx/dotenvx/src/lib/helpers/catchAndLog.js
generated
vendored
Normal file
13
node_modules/@dotenvx/dotenvx/src/lib/helpers/catchAndLog.js
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
const { logger } = require('./../../shared/logger')
|
||||
|
||||
function catchAndLog (error) {
|
||||
logger.error(error.messageWithHelp)
|
||||
if (error.debug) {
|
||||
logger.debug(error.debug)
|
||||
}
|
||||
if (error.code) {
|
||||
logger.debug(`ERROR_CODE: ${error.code}`)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = catchAndLog
|
||||
5
node_modules/@dotenvx/dotenvx/src/lib/helpers/chomp.js
generated
vendored
Normal file
5
node_modules/@dotenvx/dotenvx/src/lib/helpers/chomp.js
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
function chomp (value) {
|
||||
return value.replace(/[\r\n]+$/, '')
|
||||
}
|
||||
|
||||
module.exports = chomp
|
||||
17
node_modules/@dotenvx/dotenvx/src/lib/helpers/colorDepth.js
generated
vendored
Normal file
17
node_modules/@dotenvx/dotenvx/src/lib/helpers/colorDepth.js
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
const { WriteStream } = require('tty')
|
||||
|
||||
const getColorDepth = () => {
|
||||
try {
|
||||
return WriteStream.prototype.getColorDepth()
|
||||
} catch (error) {
|
||||
const term = process.env.TERM
|
||||
|
||||
if (term && (term.includes('256color') || term.includes('xterm'))) {
|
||||
return 8 // 256 colors
|
||||
}
|
||||
|
||||
return 4
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { getColorDepth }
|
||||
28
node_modules/@dotenvx/dotenvx/src/lib/helpers/conventions.js
generated
vendored
Normal file
28
node_modules/@dotenvx/dotenvx/src/lib/helpers/conventions.js
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
const Errors = require('./errors')
|
||||
|
||||
function conventions (convention) {
|
||||
const env = process.env.DOTENV_ENV || process.env.NODE_ENV || 'development'
|
||||
|
||||
if (convention === 'nextjs') {
|
||||
const canonicalEnv = ['development', 'test', 'production'].includes(env) && env
|
||||
|
||||
return [
|
||||
canonicalEnv && { type: 'envFile', value: `.env.${canonicalEnv}.local` },
|
||||
canonicalEnv !== 'test' && { type: 'envFile', value: '.env.local' },
|
||||
canonicalEnv && { type: 'envFile', value: `.env.${canonicalEnv}` },
|
||||
{ type: 'envFile', value: '.env' }
|
||||
].filter(Boolean)
|
||||
} else if (convention === 'flow') {
|
||||
return [
|
||||
{ type: 'envFile', value: `.env.${env}.local` },
|
||||
{ type: 'envFile', value: `.env.${env}` },
|
||||
{ type: 'envFile', value: '.env.local' },
|
||||
{ type: 'envFile', value: '.env' },
|
||||
{ type: 'envFile', value: '.env.defaults' }
|
||||
]
|
||||
} else {
|
||||
throw new Errors({ convention }).invalidConvention()
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = conventions
|
||||
50
node_modules/@dotenvx/dotenvx/src/lib/helpers/cryptography/decryptKeyValue.js
generated
vendored
Normal file
50
node_modules/@dotenvx/dotenvx/src/lib/helpers/cryptography/decryptKeyValue.js
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
const { decrypt } = require('eciesjs')
|
||||
|
||||
const Errors = require('./../errors')
|
||||
|
||||
const PREFIX = 'encrypted:'
|
||||
|
||||
function decryptKeyValue (key, value, privateKeyName, privateKey) {
|
||||
let decryptedValue
|
||||
let decryptionError
|
||||
|
||||
if (!value.startsWith(PREFIX)) {
|
||||
return value
|
||||
}
|
||||
|
||||
privateKey = privateKey || ''
|
||||
if (privateKey.length <= 0) {
|
||||
decryptionError = new Errors({ key, privateKeyName, privateKey }).missingPrivateKey()
|
||||
} else {
|
||||
const privateKeys = privateKey.split(',')
|
||||
for (const privKey of privateKeys) {
|
||||
const secret = Buffer.from(privKey, 'hex')
|
||||
const encoded = value.substring(PREFIX.length)
|
||||
const ciphertext = Buffer.from(encoded, 'base64')
|
||||
|
||||
try {
|
||||
decryptedValue = decrypt(secret, ciphertext).toString()
|
||||
decryptionError = null // reset to null error (scenario for multiple private keys)
|
||||
break
|
||||
} catch (e) {
|
||||
if (e.message === 'Invalid private key') {
|
||||
decryptionError = new Errors({ key, privateKeyName, privateKey }).invalidPrivateKey()
|
||||
} else if (e.message === 'Unsupported state or unable to authenticate data') {
|
||||
decryptionError = new Errors({ key, privateKeyName, privateKey }).wrongPrivateKey()
|
||||
} else if (e.message === 'Point of length 65 was invalid. Expected 33 compressed bytes or 65 uncompressed bytes') {
|
||||
decryptionError = new Errors({ key, privateKeyName, privateKey }).malformedEncryptedData()
|
||||
} else {
|
||||
decryptionError = new Errors({ key, privateKeyName, privateKey, message: e.message }).decryptionFailed()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (decryptionError) {
|
||||
throw decryptionError
|
||||
}
|
||||
|
||||
return decryptedValue
|
||||
}
|
||||
|
||||
module.exports = decryptKeyValue
|
||||
12
node_modules/@dotenvx/dotenvx/src/lib/helpers/cryptography/encryptValue.js
generated
vendored
Normal file
12
node_modules/@dotenvx/dotenvx/src/lib/helpers/cryptography/encryptValue.js
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
const { encrypt } = require('eciesjs')
|
||||
|
||||
const PREFIX = 'encrypted:'
|
||||
|
||||
function encryptValue (value, publicKey) {
|
||||
const ciphertext = encrypt(publicKey, Buffer.from(value))
|
||||
const encoded = Buffer.from(ciphertext, 'hex').toString('base64') // base64 encode ciphertext
|
||||
|
||||
return `${PREFIX}${encoded}`
|
||||
}
|
||||
|
||||
module.exports = encryptValue
|
||||
14
node_modules/@dotenvx/dotenvx/src/lib/helpers/cryptography/index.js
generated
vendored
Normal file
14
node_modules/@dotenvx/dotenvx/src/lib/helpers/cryptography/index.js
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
module.exports = {
|
||||
opsKeypair: require('./opsKeypair'),
|
||||
localKeypair: require('./localKeypair'),
|
||||
encryptValue: require('./encryptValue'),
|
||||
decryptKeyValue: require('./decryptKeyValue'),
|
||||
isEncrypted: require('./isEncrypted'),
|
||||
isPublicKey: require('./isPublicKey'),
|
||||
provision: require('./provision'),
|
||||
provisionWithPrivateKey: require('./provisionWithPrivateKey'),
|
||||
mutateSrc: require('./mutateSrc'),
|
||||
|
||||
// other
|
||||
isFullyEncrypted: require('./../isFullyEncrypted')
|
||||
}
|
||||
7
node_modules/@dotenvx/dotenvx/src/lib/helpers/cryptography/isEncrypted.js
generated
vendored
Normal file
7
node_modules/@dotenvx/dotenvx/src/lib/helpers/cryptography/isEncrypted.js
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
const ENCRYPTION_PATTERN = /^encrypted:.+/
|
||||
|
||||
function isEncrypted (value) {
|
||||
return ENCRYPTION_PATTERN.test(value)
|
||||
}
|
||||
|
||||
module.exports = isEncrypted
|
||||
7
node_modules/@dotenvx/dotenvx/src/lib/helpers/cryptography/isPublicKey.js
generated
vendored
Normal file
7
node_modules/@dotenvx/dotenvx/src/lib/helpers/cryptography/isPublicKey.js
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
const PUBLIC_KEY_PATTERN = /^DOTENV_PUBLIC_KEY/
|
||||
|
||||
function isPublicKey (key) {
|
||||
return PUBLIC_KEY_PATTERN.test(key)
|
||||
}
|
||||
|
||||
module.exports = isPublicKey
|
||||
21
node_modules/@dotenvx/dotenvx/src/lib/helpers/cryptography/localKeypair.js
generated
vendored
Normal file
21
node_modules/@dotenvx/dotenvx/src/lib/helpers/cryptography/localKeypair.js
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
const { PrivateKey } = require('eciesjs')
|
||||
|
||||
function localKeypair (existingPrivateKey) {
|
||||
let kp
|
||||
|
||||
if (existingPrivateKey) {
|
||||
kp = new PrivateKey(Buffer.from(existingPrivateKey, 'hex'))
|
||||
} else {
|
||||
kp = new PrivateKey()
|
||||
}
|
||||
|
||||
const publicKey = kp.publicKey.toHex()
|
||||
const privateKey = kp.secret.toString('hex')
|
||||
|
||||
return {
|
||||
publicKey,
|
||||
privateKey
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = localKeypair
|
||||
38
node_modules/@dotenvx/dotenvx/src/lib/helpers/cryptography/mutateKeysSrc.js
generated
vendored
Normal file
38
node_modules/@dotenvx/dotenvx/src/lib/helpers/cryptography/mutateKeysSrc.js
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
const FIRST_TIME_KEYS_SRC = [
|
||||
'#/------------------!DOTENV_PRIVATE_KEYS!-------------------/',
|
||||
'#/ private decryption keys. DO NOT commit to source control /',
|
||||
'#/ [how it works](https://dotenvx.com/encryption) /',
|
||||
// '#/ backup with: `dotenvx ops backup` /',
|
||||
'#/----------------------------------------------------------/'
|
||||
].join('\n')
|
||||
|
||||
const path = require('path')
|
||||
const fsx = require('./../fsx')
|
||||
|
||||
function mutateKeysSrc ({ envFilepath, keysFilepath, privateKeyName, privateKeyValue }) {
|
||||
const filename = path.basename(envFilepath)
|
||||
const filepath = path.resolve(envFilepath)
|
||||
let resolvedKeysFilepath = path.join(path.dirname(filepath), '.env.keys')
|
||||
if (keysFilepath) {
|
||||
resolvedKeysFilepath = path.resolve(keysFilepath)
|
||||
}
|
||||
const appendPrivateKey = [`# ${filename}`, `${privateKeyName}=${privateKeyValue}`, ''].join('\n')
|
||||
|
||||
let keysSrc = ''
|
||||
if (fsx.existsSync(resolvedKeysFilepath)) {
|
||||
keysSrc = fsx.readFileX(resolvedKeysFilepath)
|
||||
}
|
||||
keysSrc = keysSrc.length > 1 ? keysSrc : `${FIRST_TIME_KEYS_SRC}\n`
|
||||
keysSrc = `${keysSrc}\n${appendPrivateKey}`
|
||||
|
||||
fsx.writeFileX(resolvedKeysFilepath, keysSrc) // TODO: don't write if ops
|
||||
|
||||
const envKeysFilepath = keysFilepath || path.join(path.dirname(envFilepath), path.basename(resolvedKeysFilepath))
|
||||
|
||||
return {
|
||||
keysSrc,
|
||||
envKeysFilepath
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = mutateKeysSrc
|
||||
24
node_modules/@dotenvx/dotenvx/src/lib/helpers/cryptography/mutateSrc.js
generated
vendored
Normal file
24
node_modules/@dotenvx/dotenvx/src/lib/helpers/cryptography/mutateSrc.js
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
const path = require('path')
|
||||
const preserveShebang = require('./../preserveShebang')
|
||||
const prependPublicKey = require('./../prependPublicKey')
|
||||
|
||||
function mutateSrc ({ envSrc, envFilepath, keysFilepath, publicKeyName, publicKeyValue }) {
|
||||
const filename = path.basename(envFilepath)
|
||||
const filepath = path.resolve(envFilepath)
|
||||
let resolvedKeysFilepath = path.join(path.dirname(filepath), '.env.keys')
|
||||
if (keysFilepath) {
|
||||
resolvedKeysFilepath = path.resolve(keysFilepath)
|
||||
}
|
||||
const relativeFilepath = path.relative(path.dirname(filepath), resolvedKeysFilepath)
|
||||
|
||||
const ps = preserveShebang(envSrc)
|
||||
const prependedPublicKey = prependPublicKey(publicKeyName, publicKeyValue, filename, relativeFilepath)
|
||||
|
||||
envSrc = `${ps.firstLinePreserved}${prependedPublicKey}\n${ps.envSrc}`
|
||||
|
||||
return {
|
||||
envSrc
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = mutateSrc
|
||||
14
node_modules/@dotenvx/dotenvx/src/lib/helpers/cryptography/opsKeypair.js
generated
vendored
Normal file
14
node_modules/@dotenvx/dotenvx/src/lib/helpers/cryptography/opsKeypair.js
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
const Ops = require('../../extensions/ops')
|
||||
|
||||
function opsKeypair (existingPublicKey) {
|
||||
const kp = new Ops().keypair(existingPublicKey)
|
||||
const publicKey = kp.public_key
|
||||
const privateKey = kp.private_key
|
||||
|
||||
return {
|
||||
publicKey,
|
||||
privateKey
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = opsKeypair
|
||||
47
node_modules/@dotenvx/dotenvx/src/lib/helpers/cryptography/provision.js
generated
vendored
Normal file
47
node_modules/@dotenvx/dotenvx/src/lib/helpers/cryptography/provision.js
generated
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
const mutateSrc = require('./mutateSrc')
|
||||
const mutateKeysSrc = require('./mutateKeysSrc')
|
||||
const opsKeypair = require('./opsKeypair')
|
||||
const localKeypair = require('./localKeypair')
|
||||
const { keyNames } = require('../keyResolution')
|
||||
|
||||
function provision ({ envSrc, envFilepath, keysFilepath, opsOn }) {
|
||||
opsOn = opsOn === true
|
||||
const { publicKeyName, privateKeyName } = keyNames(envFilepath)
|
||||
|
||||
let publicKey
|
||||
let privateKey
|
||||
let keysSrc
|
||||
let envKeysFilepath
|
||||
let privateKeyAdded = false
|
||||
|
||||
if (opsOn) {
|
||||
const kp = opsKeypair()
|
||||
publicKey = kp.publicKey
|
||||
privateKey = kp.privateKey
|
||||
} else {
|
||||
const kp = localKeypair()
|
||||
publicKey = kp.publicKey
|
||||
privateKey = kp.privateKey
|
||||
}
|
||||
|
||||
const mutated = mutateSrc({ envSrc, envFilepath, keysFilepath, publicKeyName, publicKeyValue: publicKey })
|
||||
envSrc = mutated.envSrc
|
||||
|
||||
if (!opsOn) {
|
||||
const mutated = mutateKeysSrc({ envFilepath, keysFilepath, privateKeyName, privateKeyValue: privateKey })
|
||||
keysSrc = mutated.keysSrc
|
||||
envKeysFilepath = mutated.envKeysFilepath
|
||||
privateKeyAdded = true
|
||||
}
|
||||
|
||||
return {
|
||||
envSrc,
|
||||
keysSrc,
|
||||
publicKey,
|
||||
privateKey,
|
||||
privateKeyAdded,
|
||||
envKeysFilepath
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = provision
|
||||
26
node_modules/@dotenvx/dotenvx/src/lib/helpers/cryptography/provisionWithPrivateKey.js
generated
vendored
Normal file
26
node_modules/@dotenvx/dotenvx/src/lib/helpers/cryptography/provisionWithPrivateKey.js
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
const Errors = require('./../errors')
|
||||
const mutateSrc = require('./mutateSrc')
|
||||
const localKeypair = require('./localKeypair')
|
||||
|
||||
function provisionWithPrivateKey ({ envSrc, envFilepath, keysFilepath, privateKeyValue, publicKeyValue, publicKeyName }) {
|
||||
const { publicKey, privateKey } = localKeypair(privateKeyValue) // opsOn doesn't matter here since privateKeyValue was already discovered prior (via ops and local) and passed as privateKeyValue
|
||||
|
||||
// if derivation doesn't match what's in the file (or preset in env)
|
||||
if (publicKeyValue && publicKeyValue !== publicKey) {
|
||||
throw new Errors({ publicKey, publicKeyExisting: publicKeyValue }).mispairedPrivateKey()
|
||||
}
|
||||
|
||||
// scenario when encrypting a monorepo second .env file from a prior generated -fk .env.keys file
|
||||
if (!publicKeyValue) {
|
||||
const mutated = mutateSrc({ envSrc, envFilepath, keysFilepath, publicKeyName, publicKeyValue: publicKey })
|
||||
envSrc = mutated.envSrc
|
||||
}
|
||||
|
||||
return {
|
||||
envSrc,
|
||||
publicKey,
|
||||
privateKey
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = provisionWithPrivateKey
|
||||
22
node_modules/@dotenvx/dotenvx/src/lib/helpers/detectEncoding.js
generated
vendored
Normal file
22
node_modules/@dotenvx/dotenvx/src/lib/helpers/detectEncoding.js
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
const fs = require('fs')
|
||||
|
||||
function detectEncoding (filepath) {
|
||||
const buffer = fs.readFileSync(filepath)
|
||||
|
||||
// check for UTF-16LE BOM (Byte Order Mark)
|
||||
if (buffer.length >= 2 && buffer[0] === 0xFF && buffer[1] === 0xFE) {
|
||||
return 'utf16le'
|
||||
}
|
||||
|
||||
/* c8 ignore start */
|
||||
// check for UTF-8 BOM
|
||||
if (buffer.length >= 3 && buffer[0] === 0xEF && buffer[1] === 0xBB && buffer[2] === 0xBF) {
|
||||
return 'utf8'
|
||||
}
|
||||
|
||||
/* c8 ignore stop */
|
||||
|
||||
return 'utf8'
|
||||
}
|
||||
|
||||
module.exports = detectEncoding
|
||||
21
node_modules/@dotenvx/dotenvx/src/lib/helpers/dotenvOptionPaths.js
generated
vendored
Normal file
21
node_modules/@dotenvx/dotenvx/src/lib/helpers/dotenvOptionPaths.js
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
const resolveHome = require('./resolveHome')
|
||||
|
||||
function dotenvOptionPaths (options) {
|
||||
let optionPaths = []
|
||||
|
||||
if (options && options.path) {
|
||||
if (!Array.isArray(options.path)) {
|
||||
optionPaths = [resolveHome(options.path)]
|
||||
} else {
|
||||
optionPaths = [] // reset default
|
||||
|
||||
for (const filepath of options.path) {
|
||||
optionPaths.push(resolveHome(filepath))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return optionPaths
|
||||
}
|
||||
|
||||
module.exports = dotenvOptionPaths
|
||||
55
node_modules/@dotenvx/dotenvx/src/lib/helpers/dotenvParse.js
generated
vendored
Normal file
55
node_modules/@dotenvx/dotenvx/src/lib/helpers/dotenvParse.js
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
// historical dotenv.parse - https://github.com/motdotla/dotenv)
|
||||
const LINE = /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/mg
|
||||
|
||||
function dotenvParse (src, skipExpandForDoubleQuotes = false, skipConvertingWindowsNewlines = false, collectAllValues = false) {
|
||||
const obj = {}
|
||||
|
||||
// Convert buffer to string
|
||||
let lines = src.toString()
|
||||
|
||||
// Convert line breaks to same format
|
||||
if (!skipConvertingWindowsNewlines) {
|
||||
lines = lines.replace(/\r\n?/mg, '\n')
|
||||
}
|
||||
|
||||
let match
|
||||
while ((match = LINE.exec(lines)) != null) {
|
||||
const key = match[1]
|
||||
|
||||
// Default undefined or null to empty string
|
||||
let value = (match[2] || '')
|
||||
|
||||
// Remove whitespace
|
||||
value = value.trim()
|
||||
|
||||
// Check if double quoted
|
||||
const maybeQuote = value[0]
|
||||
|
||||
// Remove surrounding quotes
|
||||
value = value.replace(/^(['"`])([\s\S]*)\1$/mg, '$2')
|
||||
|
||||
// Expand newlines if double quoted
|
||||
if (maybeQuote === '"' && !skipExpandForDoubleQuotes) {
|
||||
value = value.replace(/\\n/g, '\n') // newline
|
||||
value = value.replace(/\\r/g, '\r') // carriage return
|
||||
value = value.replace(/\\t/g, '\t') // tabs
|
||||
}
|
||||
|
||||
if (collectAllValues) {
|
||||
// handle scenario where user mistakenly includes plaintext duplicate in .env:
|
||||
//
|
||||
// # .env
|
||||
// HELLO="World"
|
||||
// HELLO="encrypted:1234"
|
||||
obj[key] = obj[key] || []
|
||||
obj[key].push(value)
|
||||
} else {
|
||||
// Add to object
|
||||
obj[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
return obj
|
||||
}
|
||||
|
||||
module.exports = dotenvParse
|
||||
7
node_modules/@dotenvx/dotenvx/src/lib/helpers/dotenvPrivateKeyNames.js
generated
vendored
Normal file
7
node_modules/@dotenvx/dotenvx/src/lib/helpers/dotenvPrivateKeyNames.js
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
const PRIVATE_KEY_NAME_SCHEMA = 'DOTENV_PRIVATE_KEY'
|
||||
|
||||
function dotenvPrivateKeyNames (processEnv) {
|
||||
return Object.keys(processEnv).filter(key => key.startsWith(PRIVATE_KEY_NAME_SCHEMA))
|
||||
}
|
||||
|
||||
module.exports = dotenvPrivateKeyNames
|
||||
46
node_modules/@dotenvx/dotenvx/src/lib/helpers/envResolution/determine.js
generated
vendored
Normal file
46
node_modules/@dotenvx/dotenvx/src/lib/helpers/envResolution/determine.js
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
const dotenvPrivateKeyNames = require('./../dotenvPrivateKeyNames')
|
||||
const guessPrivateKeyFilename = require('./../guessPrivateKeyFilename')
|
||||
|
||||
const TYPE_ENV_FILE = 'envFile'
|
||||
const DEFAULT_ENVS = [{ type: TYPE_ENV_FILE, value: '.env' }]
|
||||
|
||||
function envsFromDotenvPrivateKey (privateKeyNames) {
|
||||
const envs = []
|
||||
|
||||
for (const privateKeyName of privateKeyNames) {
|
||||
const filename = guessPrivateKeyFilename(privateKeyName)
|
||||
envs.push({ type: TYPE_ENV_FILE, value: filename })
|
||||
}
|
||||
|
||||
return envs
|
||||
}
|
||||
|
||||
function determine (envs = [], processEnv) {
|
||||
const privateKeyNames = dotenvPrivateKeyNames(processEnv)
|
||||
if (!envs || envs.length <= 0) {
|
||||
// if process.env.DOTENV_PRIVATE_KEY or process.env.DOTENV_PRIVATE_KEY_${environment} is set, assume inline encryption methodology
|
||||
if (privateKeyNames.length > 0) {
|
||||
return envsFromDotenvPrivateKey(privateKeyNames)
|
||||
}
|
||||
|
||||
return DEFAULT_ENVS // default to .env file expectation
|
||||
} else {
|
||||
let fileAlreadySpecified = false
|
||||
|
||||
for (const env of envs) {
|
||||
if (env.type === TYPE_ENV_FILE) {
|
||||
fileAlreadySpecified = true
|
||||
}
|
||||
}
|
||||
|
||||
// return early since envs array objects already contain 1 .env file
|
||||
if (fileAlreadySpecified) {
|
||||
return envs
|
||||
}
|
||||
|
||||
// no .env file specified as a flag so default to .env
|
||||
return [...DEFAULT_ENVS, ...envs]
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = determine
|
||||
27
node_modules/@dotenvx/dotenvx/src/lib/helpers/envResolution/environment.js
generated
vendored
Normal file
27
node_modules/@dotenvx/dotenvx/src/lib/helpers/envResolution/environment.js
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
const path = require('path')
|
||||
|
||||
function environment (filepath) {
|
||||
const filename = path.basename(filepath).toLowerCase()
|
||||
|
||||
const parts = filename.split('.')
|
||||
const possibleEnvironmentList = [...parts.slice(2)]
|
||||
|
||||
if (possibleEnvironmentList.length === 0) {
|
||||
// handle .env1 -> development1
|
||||
const environment = filename.replace('.env', 'development')
|
||||
|
||||
return environment
|
||||
}
|
||||
|
||||
if (possibleEnvironmentList.length === 1) {
|
||||
return possibleEnvironmentList[0]
|
||||
}
|
||||
|
||||
if (possibleEnvironmentList.length === 2) {
|
||||
return possibleEnvironmentList.join('_')
|
||||
}
|
||||
|
||||
return possibleEnvironmentList.slice(0, 2).join('_')
|
||||
}
|
||||
|
||||
module.exports = environment
|
||||
8
node_modules/@dotenvx/dotenvx/src/lib/helpers/envResolution/index.js
generated
vendored
Normal file
8
node_modules/@dotenvx/dotenvx/src/lib/helpers/envResolution/index.js
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
module.exports = {
|
||||
buildEnvs: require('./../buildEnvs'),
|
||||
determine: require('./determine'),
|
||||
findEnvFiles: require('./../findEnvFiles'),
|
||||
dotenvOptionPaths: require('./../dotenvOptionPaths'),
|
||||
environment: require('./environment'),
|
||||
conventions: require('./../conventions')
|
||||
}
|
||||
280
node_modules/@dotenvx/dotenvx/src/lib/helpers/errors.js
generated
vendored
Normal file
280
node_modules/@dotenvx/dotenvx/src/lib/helpers/errors.js
generated
vendored
Normal file
@@ -0,0 +1,280 @@
|
||||
const truncate = require('./truncate')
|
||||
|
||||
const ISSUE_BY_CODE = {
|
||||
COMMAND_EXITED_WITH_CODE: 'https://github.com/dotenvx/dotenvx/issues/new',
|
||||
COMMAND_SUBSTITUTION_FAILED: 'https://github.com/dotenvx/dotenvx/issues/532',
|
||||
DECRYPTION_FAILED: 'https://github.com/dotenvx/dotenvx/issues/757',
|
||||
DANGEROUS_DEPENDENCY_HOIST: 'https://github.com/dotenvx/dotenvx/issues/622',
|
||||
INVALID_COLOR: 'must be 256 colors',
|
||||
INVALID_CONVENTION: 'https://github.com/dotenvx/dotenvx/issues/761',
|
||||
INVALID_PRIVATE_KEY: 'https://github.com/dotenvx/dotenvx/issues/465',
|
||||
INVALID_PUBLIC_KEY: 'https://github.com/dotenvx/dotenvx/issues/756',
|
||||
MALFORMED_ENCRYPTED_DATA: 'https://github.com/dotenvx/dotenvx/issues/467',
|
||||
MISPAIRED_PRIVATE_KEY: 'https://github.com/dotenvx/dotenvx/issues/752',
|
||||
MISSING_DIRECTORY: 'https://github.com/dotenvx/dotenvx/issues/758',
|
||||
MISSING_ENV_FILE: 'https://github.com/dotenvx/dotenvx/issues/484',
|
||||
MISSING_ENV_FILES: 'https://github.com/dotenvx/dotenvx/issues/760',
|
||||
MISSING_KEY: 'https://github.com/dotenvx/dotenvx/issues/759',
|
||||
MISSING_LOG_LEVEL: 'must be valid log level',
|
||||
MISSING_PRIVATE_KEY: 'https://github.com/dotenvx/dotenvx/issues/464',
|
||||
PRECOMMIT_HOOK_MODIFY_FAILED: 'try again or report error',
|
||||
WRONG_PRIVATE_KEY: 'https://github.com/dotenvx/dotenvx/issues/466'
|
||||
}
|
||||
|
||||
class Errors {
|
||||
constructor (options = {}) {
|
||||
this.filepath = options.filepath
|
||||
this.envFilepath = options.envFilepath
|
||||
|
||||
this.key = options.key
|
||||
this.privateKey = options.privateKey
|
||||
this.privateKeyName = options.privateKeyName
|
||||
this.publicKeyName = options.publicKeyName
|
||||
this.publicKey = options.publicKey
|
||||
this.publicKeyExisting = options.publicKeyExisting
|
||||
this.command = options.command
|
||||
|
||||
this.message = options.message
|
||||
this.code = options.code
|
||||
this.help = options.help
|
||||
this.debug = options.debug
|
||||
|
||||
this.convention = options.convention
|
||||
this.directory = options.directory
|
||||
this.exitCode = options.exitCode
|
||||
this.level = options.level
|
||||
this.color = options.color
|
||||
this.error = options.error
|
||||
}
|
||||
|
||||
custom () {
|
||||
const e = new Error(this.message)
|
||||
if (this.code) e.code = this.code
|
||||
if (this.help) e.help = this.help
|
||||
if (this.code && !e.help) e.help = `fix: [${ISSUE_BY_CODE[this.code]}]`
|
||||
e.messageWithHelp = `${e.message}. ${e.help}`
|
||||
if (this.debug) e.debug = this.debug
|
||||
return e
|
||||
}
|
||||
|
||||
commandExitedWithCode () {
|
||||
const code = 'COMMAND_EXITED_WITH_CODE'
|
||||
const message = `[${code}] Command exited with exit code ${this.exitCode}`
|
||||
const help = `fix: [${ISSUE_BY_CODE[code]}]`
|
||||
|
||||
const e = new Error(message)
|
||||
e.code = code
|
||||
e.help = help
|
||||
e.messageWithHelp = `${message}. ${help}`
|
||||
return e
|
||||
}
|
||||
|
||||
commandSubstitutionFailed () {
|
||||
const code = 'COMMAND_SUBSTITUTION_FAILED'
|
||||
const message = `[${code}] could not eval ${this.key} containing command '${this.command}': ${this.message}`
|
||||
const help = `fix: [${ISSUE_BY_CODE[code]}]`
|
||||
|
||||
const e = new Error(message)
|
||||
e.code = code
|
||||
e.help = help
|
||||
e.messageWithHelp = `${message}. ${help}`
|
||||
return e
|
||||
}
|
||||
|
||||
decryptionFailed () {
|
||||
const code = 'DECRYPTION_FAILED'
|
||||
const message = `[${code}] ${this.message}`
|
||||
const help = `fix: [${ISSUE_BY_CODE[code]}]`
|
||||
|
||||
const e = new Error(message)
|
||||
e.code = code
|
||||
e.help = help
|
||||
e.messageWithHelp = `${message}. ${help}`
|
||||
return e
|
||||
}
|
||||
|
||||
dangerousDependencyHoist () {
|
||||
const code = 'DANGEROUS_DEPENDENCY_HOIST'
|
||||
const message = `[${code}] your environment has hoisted an incompatible version of a dotenvx dependency: ${this.message}`
|
||||
const help = `fix: [${ISSUE_BY_CODE[code]}]`
|
||||
|
||||
const e = new Error(message)
|
||||
e.code = code
|
||||
e.help = help
|
||||
e.messageWithHelp = `${message}. ${help}`
|
||||
return e
|
||||
}
|
||||
|
||||
invalidColor () {
|
||||
const code = 'INVALID_COLOR'
|
||||
const message = `[${code}] Invalid color ${this.color}`
|
||||
const help = `fix: [${ISSUE_BY_CODE[code]}]`
|
||||
|
||||
const e = new Error(message)
|
||||
e.code = code
|
||||
e.help = help
|
||||
e.messageWithHelp = `${message}. ${help}`
|
||||
return e
|
||||
}
|
||||
|
||||
invalidConvention () {
|
||||
const code = 'INVALID_CONVENTION'
|
||||
const message = `[${code}] invalid convention (${this.convention})`
|
||||
const help = `fix: [${ISSUE_BY_CODE[code]}]`
|
||||
|
||||
const e = new Error(message)
|
||||
e.code = code
|
||||
e.help = help
|
||||
e.messageWithHelp = `${message}. ${help}`
|
||||
return e
|
||||
}
|
||||
|
||||
invalidPrivateKey () {
|
||||
const code = 'INVALID_PRIVATE_KEY'
|
||||
const message = `[${code}] could not decrypt ${this.key} using private key '${this.privateKeyName}=${truncate(this.privateKey)}'`
|
||||
const help = `fix: [${ISSUE_BY_CODE[code]}]`
|
||||
|
||||
const e = new Error(message)
|
||||
e.code = code
|
||||
e.help = help
|
||||
e.messageWithHelp = `${message}. ${help}`
|
||||
return e
|
||||
}
|
||||
|
||||
invalidPublicKey () {
|
||||
const code = 'INVALID_PUBLIC_KEY'
|
||||
const message = `[${code}] could not encrypt using public key '${this.publicKeyName}=${truncate(this.publicKey)}'`
|
||||
const help = `fix: [${ISSUE_BY_CODE[code]}]`
|
||||
|
||||
const e = new Error(message)
|
||||
e.code = code
|
||||
e.help = help
|
||||
e.messageWithHelp = `${message}. ${help}`
|
||||
return e
|
||||
}
|
||||
|
||||
malformedEncryptedData () {
|
||||
const code = 'MALFORMED_ENCRYPTED_DATA'
|
||||
const message = `[${code}] could not decrypt ${this.key} because encrypted data appears malformed`
|
||||
const help = `fix: [${ISSUE_BY_CODE[code]}]`
|
||||
|
||||
const e = new Error(message)
|
||||
e.code = code
|
||||
e.help = help
|
||||
e.messageWithHelp = `${message}. ${help}`
|
||||
return e
|
||||
}
|
||||
|
||||
mispairedPrivateKey () {
|
||||
const code = 'MISPAIRED_PRIVATE_KEY'
|
||||
const message = `[${code}] private key's derived public key (${truncate(this.publicKey)}) does not match the existing public key (${truncate(this.publicKeyExisting)})`
|
||||
const help = `fix: [${ISSUE_BY_CODE[code]}]`
|
||||
|
||||
const e = new Error(message)
|
||||
e.code = code
|
||||
e.help = help
|
||||
e.messageWithHelp = `${message}. ${help}`
|
||||
return e
|
||||
}
|
||||
|
||||
missingDirectory () {
|
||||
const code = 'MISSING_DIRECTORY'
|
||||
const message = `[${code}] missing directory (${this.directory})`
|
||||
const help = `fix: [${ISSUE_BY_CODE[code]}]`
|
||||
|
||||
const e = new Error(message)
|
||||
e.code = code
|
||||
e.help = help
|
||||
e.messageWithHelp = `${message}. ${help}`
|
||||
return e
|
||||
}
|
||||
|
||||
missingEnvFile () {
|
||||
const code = 'MISSING_ENV_FILE'
|
||||
const envFilepath = this.envFilepath || '.env'
|
||||
const message = `[${code}] missing file (${envFilepath})`
|
||||
const help = `fix: [${ISSUE_BY_CODE[code]}]`
|
||||
|
||||
const e = new Error(message)
|
||||
e.code = code
|
||||
e.help = help
|
||||
e.messageWithHelp = `${message}. ${help}`
|
||||
return e
|
||||
}
|
||||
|
||||
missingEnvFiles () {
|
||||
const code = 'MISSING_ENV_FILES'
|
||||
const message = `[${code}] no .env* files found`
|
||||
const help = `fix: [${ISSUE_BY_CODE[code]}]`
|
||||
|
||||
const e = new Error(message)
|
||||
e.code = code
|
||||
e.help = help
|
||||
e.messageWithHelp = `${message}. ${help}`
|
||||
return e
|
||||
}
|
||||
|
||||
missingKey () {
|
||||
const code = 'MISSING_KEY'
|
||||
const message = `[${code}] missing key (${this.key})`
|
||||
const help = `fix: [${ISSUE_BY_CODE[code]}]`
|
||||
|
||||
const e = new Error(message)
|
||||
e.code = code
|
||||
e.help = help
|
||||
e.messageWithHelp = `${message}. ${help}`
|
||||
return e
|
||||
}
|
||||
|
||||
missingLogLevel () {
|
||||
const code = 'MISSING_LOG_LEVEL'
|
||||
const message = `[${code}] missing log level '${this.level}'. implement in logger`
|
||||
const help = `fix: [${ISSUE_BY_CODE[code]}]`
|
||||
|
||||
const e = new Error(message)
|
||||
e.code = code
|
||||
e.help = help
|
||||
e.messageWithHelp = `${message}. ${help}`
|
||||
return e
|
||||
}
|
||||
|
||||
missingPrivateKey () {
|
||||
const code = 'MISSING_PRIVATE_KEY'
|
||||
const message = `[${code}] could not decrypt ${this.key} using private key '${this.privateKeyName}=${truncate(this.privateKey)}'`
|
||||
const help = `fix: [${ISSUE_BY_CODE[code]}]`
|
||||
|
||||
const e = new Error(message)
|
||||
e.code = code
|
||||
e.help = help
|
||||
e.messageWithHelp = `${message}. ${help}`
|
||||
return e
|
||||
}
|
||||
|
||||
precommitHookModifyFailed () {
|
||||
const code = 'PRECOMMIT_HOOK_MODIFY_FAILED'
|
||||
const message = `[${code}] failed to modify pre-commit hook: ${this.error.message}`
|
||||
const help = `fix: [${ISSUE_BY_CODE[code]}]`
|
||||
|
||||
const e = new Error(message)
|
||||
e.code = code
|
||||
e.help = help
|
||||
e.messageWithHelp = `${message}. ${help}`
|
||||
return e
|
||||
}
|
||||
|
||||
wrongPrivateKey () {
|
||||
const code = 'WRONG_PRIVATE_KEY'
|
||||
const message = `[${code}] could not decrypt ${this.key} using private key '${this.privateKeyName}=${truncate(this.privateKey)}'`
|
||||
const help = `fix: [${ISSUE_BY_CODE[code]}]`
|
||||
|
||||
const e = new Error(message)
|
||||
e.code = code
|
||||
e.help = help
|
||||
e.messageWithHelp = `${message}. ${help}`
|
||||
return e
|
||||
}
|
||||
}
|
||||
|
||||
Errors.ISSUE_BY_CODE = ISSUE_BY_CODE
|
||||
|
||||
module.exports = Errors
|
||||
5
node_modules/@dotenvx/dotenvx/src/lib/helpers/escape.js
generated
vendored
Normal file
5
node_modules/@dotenvx/dotenvx/src/lib/helpers/escape.js
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
function escape (value) {
|
||||
return JSON.stringify(value)
|
||||
}
|
||||
|
||||
module.exports = escape
|
||||
5
node_modules/@dotenvx/dotenvx/src/lib/helpers/escapeDollarSigns.js
generated
vendored
Normal file
5
node_modules/@dotenvx/dotenvx/src/lib/helpers/escapeDollarSigns.js
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
function escapeDollarSigns (str) {
|
||||
return str.replace(/\$/g, '$$$$')
|
||||
}
|
||||
|
||||
module.exports = escapeDollarSigns
|
||||
5
node_modules/@dotenvx/dotenvx/src/lib/helpers/escapeForRegex.js
generated
vendored
Normal file
5
node_modules/@dotenvx/dotenvx/src/lib/helpers/escapeForRegex.js
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
function escapeForRegex (str) {
|
||||
return str.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&').replace(/-/g, '\\x2d')
|
||||
}
|
||||
|
||||
module.exports = escapeForRegex
|
||||
23
node_modules/@dotenvx/dotenvx/src/lib/helpers/evalKeyValue.js
generated
vendored
Normal file
23
node_modules/@dotenvx/dotenvx/src/lib/helpers/evalKeyValue.js
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
const { execSync } = require('child_process')
|
||||
const chomp = require('./chomp')
|
||||
const Errors = require('./errors')
|
||||
|
||||
function evalKeyValue (key, value, processEnv, runningParsed) {
|
||||
// Match everything between the outermost $() using a regex with non-capturing groups
|
||||
const matches = value.match(/\$\(([^)]+(?:\)[^(]*)*)\)/g) || []
|
||||
return matches.reduce((newValue, match) => {
|
||||
const command = match.slice(2, -1) // Extract command by removing $() wrapper
|
||||
let result
|
||||
|
||||
try {
|
||||
result = execSync(command, { env: { ...processEnv, ...runningParsed } }).toString() // execute command (including runningParsed)
|
||||
} catch (e) {
|
||||
throw new Errors({ key, command, message: e.message.trim() }).commandSubstitutionFailed()
|
||||
}
|
||||
|
||||
result = chomp(result) // chomp it
|
||||
return newValue.replace(match, result) // Replace match with result
|
||||
}, value)
|
||||
}
|
||||
|
||||
module.exports = evalKeyValue
|
||||
12
node_modules/@dotenvx/dotenvx/src/lib/helpers/execute.js
generated
vendored
Normal file
12
node_modules/@dotenvx/dotenvx/src/lib/helpers/execute.js
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
const execa = require('execa')
|
||||
/* c8 ignore start */
|
||||
const pkgArgs = process.pkg ? { PKG_EXECPATH: '' } : {}
|
||||
/* c8 ignore stop */
|
||||
|
||||
const execute = {
|
||||
execa (command, args, options) {
|
||||
return execa(command, args, { ...options, env: { ...options.env, ...pkgArgs } })
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = execute
|
||||
117
node_modules/@dotenvx/dotenvx/src/lib/helpers/executeCommand.js
generated
vendored
Normal file
117
node_modules/@dotenvx/dotenvx/src/lib/helpers/executeCommand.js
generated
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
const path = require('path')
|
||||
const which = require('which')
|
||||
const execute = require('./../../lib/helpers/execute')
|
||||
const { logger } = require('./../../shared/logger')
|
||||
const Errors = require('./errors')
|
||||
|
||||
async function executeCommand (commandArgs, env) {
|
||||
const signals = [
|
||||
'SIGHUP', 'SIGQUIT', 'SIGILL', 'SIGTRAP', 'SIGABRT',
|
||||
'SIGBUS', 'SIGFPE', 'SIGUSR1', 'SIGSEGV', 'SIGUSR2'
|
||||
]
|
||||
|
||||
logger.debug(`executing process command [${commandArgs.join(' ')}]`)
|
||||
|
||||
let child
|
||||
let signalSent
|
||||
|
||||
/* c8 ignore start */
|
||||
const sigintHandler = () => {
|
||||
logger.debug('received SIGINT')
|
||||
logger.debug('checking command process')
|
||||
logger.debug(child)
|
||||
|
||||
if (child) {
|
||||
logger.debug('sending SIGINT to command process')
|
||||
signalSent = 'SIGINT'
|
||||
child.kill('SIGINT') // Send SIGINT to the command process
|
||||
} else {
|
||||
logger.debug('no command process to send SIGINT to')
|
||||
}
|
||||
}
|
||||
|
||||
const sigtermHandler = () => {
|
||||
logger.debug('received SIGTERM')
|
||||
logger.debug('checking command process')
|
||||
logger.debug(child)
|
||||
|
||||
if (child) {
|
||||
logger.debug('sending SIGTERM to command process')
|
||||
signalSent = 'SIGTERM'
|
||||
child.kill('SIGTERM') // Send SIGTERM to the command process
|
||||
} else {
|
||||
logger.debug('no command process to send SIGTERM to')
|
||||
}
|
||||
}
|
||||
|
||||
const handleOtherSignal = (signal) => {
|
||||
logger.debug(`received ${signal}`)
|
||||
child.kill(signal)
|
||||
}
|
||||
/* c8 ignore stop */
|
||||
|
||||
try {
|
||||
// ensure the first command is expanded
|
||||
try {
|
||||
commandArgs[0] = path.resolve(which.sync(`${commandArgs[0]}`))
|
||||
logger.debug(`expanding process command to [${commandArgs.join(' ')}]`)
|
||||
} catch (e) {
|
||||
logger.debug(`could not expand process command. using [${commandArgs.join(' ')}]`)
|
||||
}
|
||||
|
||||
// expand any other commands that follow a --
|
||||
let expandNext = false
|
||||
for (let i = 0; i < commandArgs.length; i++) {
|
||||
if (commandArgs[i] === '--') {
|
||||
expandNext = true
|
||||
} else if (expandNext) {
|
||||
try {
|
||||
commandArgs[i] = path.resolve(which.sync(`${commandArgs[i]}`))
|
||||
logger.debug(`expanding process command to [${commandArgs.join(' ')}]`)
|
||||
} catch (e) {
|
||||
logger.debug(`could not expand process command. using [${commandArgs.join(' ')}]`)
|
||||
}
|
||||
expandNext = false
|
||||
}
|
||||
}
|
||||
|
||||
child = execute.execa(commandArgs[0], commandArgs.slice(1), {
|
||||
stdio: 'inherit',
|
||||
env: { ...process.env, ...env }
|
||||
})
|
||||
|
||||
process.on('SIGINT', sigintHandler)
|
||||
process.on('SIGTERM', sigtermHandler)
|
||||
|
||||
signals.forEach(signal => {
|
||||
process.on(signal, () => handleOtherSignal(signal))
|
||||
})
|
||||
|
||||
// Wait for the command process to finish
|
||||
const { exitCode } = await child
|
||||
|
||||
if (exitCode !== 0) {
|
||||
logger.debug(`received exitCode ${exitCode}`)
|
||||
throw new Errors({ exitCode }).commandExitedWithCode()
|
||||
}
|
||||
} catch (error) {
|
||||
// no color on these errors as they can be standard errors for things like jest exiting with exitCode 1 for a single failed test.
|
||||
if (!['SIGINT', 'SIGTERM'].includes(signalSent || error.signal)) {
|
||||
if (error.code === 'ENOENT') {
|
||||
logger.error(`Unknown command: ${error.command}`)
|
||||
} else {
|
||||
logger.error(error.message)
|
||||
}
|
||||
}
|
||||
|
||||
// Exit with the error code from the command process, or 1 if unavailable
|
||||
process.exit(error.exitCode || 1)
|
||||
} finally {
|
||||
// Clean up: Remove the SIGINT handler
|
||||
process.removeListener('SIGINT', sigintHandler)
|
||||
// Clean up: Remove the SIGTERM handler
|
||||
process.removeListener('SIGTERM', sigtermHandler)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = executeCommand
|
||||
65
node_modules/@dotenvx/dotenvx/src/lib/helpers/executeDynamic.js
generated
vendored
Normal file
65
node_modules/@dotenvx/dotenvx/src/lib/helpers/executeDynamic.js
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
const path = require('path')
|
||||
const childProcess = require('child_process')
|
||||
const { logger } = require('../../shared/logger')
|
||||
|
||||
function installCommandForOps () {
|
||||
return 'npm i -g @dotenvx/dotenvx-ops'
|
||||
}
|
||||
|
||||
function opsBanner (installCommand) {
|
||||
const lines = [
|
||||
'',
|
||||
' ██████╗ ██████╗ ███████╗',
|
||||
' ██╔═══██╗██╔══██╗██╔════╝',
|
||||
' ██║ ██║██████╔╝███████╗',
|
||||
' ██║ ██║██╔═══╝ ╚════██║',
|
||||
' ╚██████╔╝██║ ███████║',
|
||||
' ╚═════╝ ╚═╝ ╚══════╝',
|
||||
'',
|
||||
' KEYS OFF COMPUTER: Add hardened key protection with dotenvx-ops.',
|
||||
` Install now: [${installCommand}]`,
|
||||
' Learn more: [https://dotenvx.com/ops]'
|
||||
]
|
||||
|
||||
const innerWidth = Math.max(67, ...lines.map((line) => line.length))
|
||||
const top = ` ${'_'.repeat(innerWidth)}`
|
||||
const middle = lines.map((line) => `|${line.padEnd(innerWidth)}|`).join('\n')
|
||||
const bottom = `|${'_'.repeat(innerWidth)}|`
|
||||
|
||||
return `${top}\n${middle}\n${bottom}`
|
||||
}
|
||||
|
||||
function executeDynamic (program, command, rawArgs) {
|
||||
if (!command) {
|
||||
program.outputHelp()
|
||||
process.exit(1)
|
||||
return
|
||||
}
|
||||
|
||||
// construct the full command line manually including flags
|
||||
const commandIndex = rawArgs.indexOf(command)
|
||||
const forwardedArgs = rawArgs.slice(commandIndex + 1)
|
||||
|
||||
logger.debug(`command: ${command}`)
|
||||
logger.debug(`args: ${JSON.stringify(forwardedArgs)}`)
|
||||
|
||||
const binPath = path.join(process.cwd(), 'node_modules', '.bin')
|
||||
const newPath = `${binPath}:${process.env.PATH}`
|
||||
const env = { ...process.env, PATH: newPath }
|
||||
|
||||
const result = childProcess.spawnSync(`dotenvx-${command}`, forwardedArgs, { stdio: 'inherit', env })
|
||||
if (result.error) {
|
||||
if (command === 'ops') {
|
||||
const installCommand = installCommandForOps()
|
||||
console.log(opsBanner(installCommand))
|
||||
} else {
|
||||
logger.info(`error: unknown command '${command}'`)
|
||||
}
|
||||
}
|
||||
|
||||
if (result.status !== 0) {
|
||||
process.exit(result.status)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = executeDynamic
|
||||
39
node_modules/@dotenvx/dotenvx/src/lib/helpers/executeExtension.js
generated
vendored
Normal file
39
node_modules/@dotenvx/dotenvx/src/lib/helpers/executeExtension.js
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
const path = require('path')
|
||||
const childProcess = require('child_process')
|
||||
const { logger } = require('../../shared/logger')
|
||||
|
||||
function executeExtension (ext, command, rawArgs) {
|
||||
if (!command) {
|
||||
ext.outputHelp()
|
||||
process.exit(0)
|
||||
return
|
||||
}
|
||||
|
||||
// construct the full command line manually including flags
|
||||
const commandIndex = rawArgs.indexOf(command)
|
||||
const forwardedArgs = rawArgs.slice(commandIndex + 1)
|
||||
|
||||
logger.debug(`command: ${command}`)
|
||||
logger.debug(`args: ${JSON.stringify(forwardedArgs)}`)
|
||||
|
||||
const binPath = path.join(process.cwd(), 'node_modules', '.bin')
|
||||
const newPath = `${binPath}:${process.env.PATH}`
|
||||
const env = { ...process.env, PATH: newPath }
|
||||
|
||||
const result = childProcess.spawnSync(`dotenvx-ext-${command}`, forwardedArgs, { stdio: 'inherit', env })
|
||||
if (result.error) {
|
||||
// list known extension here for convenience to the user
|
||||
if (['vault', 'hub'].includes(command)) {
|
||||
logger.warn(`[INSTALLATION_NEEDED] install dotenvx-ext-${command} to use [dotenvx ext ${command}] commands`)
|
||||
logger.help('? see installation instructions [https://github.com/dotenvx/dotenvx-ext-vault]')
|
||||
} else {
|
||||
logger.info(`error: unknown command '${command}'`)
|
||||
}
|
||||
}
|
||||
|
||||
if (result.status !== 0) {
|
||||
process.exit(result.status)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = executeExtension
|
||||
25
node_modules/@dotenvx/dotenvx/src/lib/helpers/findEnvFiles.js
generated
vendored
Normal file
25
node_modules/@dotenvx/dotenvx/src/lib/helpers/findEnvFiles.js
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
const fsx = require('./fsx')
|
||||
const Errors = require('./errors')
|
||||
|
||||
const RESERVED_ENV_FILES = ['.env.project', '.env.keys', '.env.me', '.env.x', '.env.example']
|
||||
|
||||
function findEnvFiles (directory) {
|
||||
try {
|
||||
const files = fsx.readdirSync(directory)
|
||||
const envFiles = files.filter(file =>
|
||||
file.startsWith('.env') &&
|
||||
!file.endsWith('.previous') &&
|
||||
!RESERVED_ENV_FILES.includes(file)
|
||||
)
|
||||
|
||||
return envFiles
|
||||
} catch (e) {
|
||||
if (e.code === 'ENOENT') {
|
||||
throw new Errors({ directory }).missingDirectory()
|
||||
} else {
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = findEnvFiles
|
||||
30
node_modules/@dotenvx/dotenvx/src/lib/helpers/fsx.js
generated
vendored
Normal file
30
node_modules/@dotenvx/dotenvx/src/lib/helpers/fsx.js
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
const fs = require('fs')
|
||||
|
||||
const ENCODING = 'utf8'
|
||||
|
||||
function readFileX (filepath, encoding = null) {
|
||||
if (!encoding) {
|
||||
encoding = ENCODING
|
||||
}
|
||||
|
||||
return fs.readFileSync(filepath, encoding) // utf8 default so it returns a string
|
||||
}
|
||||
|
||||
function writeFileX (filepath, str) {
|
||||
return fs.writeFileSync(filepath, str, ENCODING) // utf8 always
|
||||
}
|
||||
|
||||
const fsx = {
|
||||
chmodSync: fs.chmodSync,
|
||||
existsSync: fs.existsSync,
|
||||
readdirSync: fs.readdirSync,
|
||||
readFileSync: fs.readFileSync,
|
||||
writeFileSync: fs.writeFileSync,
|
||||
appendFileSync: fs.appendFileSync,
|
||||
|
||||
// fsx special commands
|
||||
readFileX,
|
||||
writeFileX
|
||||
}
|
||||
|
||||
module.exports = fsx
|
||||
10
node_modules/@dotenvx/dotenvx/src/lib/helpers/getCommanderVersion.js
generated
vendored
Normal file
10
node_modules/@dotenvx/dotenvx/src/lib/helpers/getCommanderVersion.js
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
|
||||
function getCommanderVersion () {
|
||||
const commanderMain = require.resolve('commander')
|
||||
const pkgPath = path.join(commanderMain, '..', 'package.json')
|
||||
return JSON.parse(fs.readFileSync(pkgPath, 'utf8')).version
|
||||
}
|
||||
|
||||
module.exports = getCommanderVersion
|
||||
15
node_modules/@dotenvx/dotenvx/src/lib/helpers/guessPrivateKeyFilename.js
generated
vendored
Normal file
15
node_modules/@dotenvx/dotenvx/src/lib/helpers/guessPrivateKeyFilename.js
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
const PREFIX = 'DOTENV_PRIVATE_KEY'
|
||||
|
||||
function guessPrivateKeyFilename (privateKeyName) {
|
||||
// .env
|
||||
if (privateKeyName === PREFIX) {
|
||||
return '.env'
|
||||
}
|
||||
|
||||
const filenameSuffix = privateKeyName.substring(`${PREFIX}_`.length).split('_').join('.').toLowerCase()
|
||||
// .env.ENVIRONMENT
|
||||
|
||||
return `.env.${filenameSuffix}`
|
||||
}
|
||||
|
||||
module.exports = guessPrivateKeyFilename
|
||||
73
node_modules/@dotenvx/dotenvx/src/lib/helpers/installPrecommitHook.js
generated
vendored
Normal file
73
node_modules/@dotenvx/dotenvx/src/lib/helpers/installPrecommitHook.js
generated
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
const fsx = require('./fsx')
|
||||
const path = require('path')
|
||||
const Errors = require('./errors')
|
||||
|
||||
const HOOK_SCRIPT = `#!/bin/sh
|
||||
|
||||
if command -v dotenvx 2>&1 >/dev/null
|
||||
then
|
||||
dotenvx ext precommit
|
||||
elif npx dotenvx -V >/dev/null 2>&1
|
||||
then
|
||||
npx dotenvx ext precommit
|
||||
else
|
||||
echo "[dotenvx][precommit] 'dotenvx' command not found"
|
||||
echo "[dotenvx][precommit] ? install it with [curl -fsS https://dotenvx.sh | sh]"
|
||||
echo "[dotenvx][precommit] ? other install options [https://dotenvx.com/docs/install]"
|
||||
exit 1
|
||||
fi
|
||||
`
|
||||
|
||||
class InstallPrecommitHook {
|
||||
constructor () {
|
||||
this.hookPath = path.join('.git', 'hooks', 'pre-commit')
|
||||
}
|
||||
|
||||
run () {
|
||||
let successMessage
|
||||
|
||||
try {
|
||||
// Check if the pre-commit file already exists
|
||||
if (this._exists()) {
|
||||
// Check if 'dotenvx precommit' already exists in the file
|
||||
if (this._currentHook().includes('dotenvx ext precommit')) {
|
||||
// do nothing
|
||||
successMessage = `dotenvx ext precommit exists [${this.hookPath}]`
|
||||
} else {
|
||||
this._appendHook()
|
||||
successMessage = `dotenvx ext precommit appended [${this.hookPath}]`
|
||||
}
|
||||
} else {
|
||||
this._createHook()
|
||||
successMessage = `dotenvx ext precommit installed [${this.hookPath}]`
|
||||
}
|
||||
|
||||
return {
|
||||
successMessage
|
||||
}
|
||||
} catch (err) {
|
||||
throw new Errors({ error: err }).precommitHookModifyFailed()
|
||||
}
|
||||
}
|
||||
|
||||
_exists () {
|
||||
return fsx.existsSync(this.hookPath)
|
||||
}
|
||||
|
||||
_currentHook () {
|
||||
return fsx.readFileX(this.hookPath)
|
||||
}
|
||||
|
||||
_createHook () {
|
||||
// If the pre-commit file doesn't exist, create a new one with the hookScript
|
||||
fsx.writeFileX(this.hookPath, HOOK_SCRIPT)
|
||||
fsx.chmodSync(this.hookPath, '755') // Make the file executable
|
||||
}
|
||||
|
||||
_appendHook () {
|
||||
// Append 'dotenvx precommit' to the existing file
|
||||
fsx.appendFileSync(this.hookPath, '\n' + HOOK_SCRIPT)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = InstallPrecommitHook
|
||||
27
node_modules/@dotenvx/dotenvx/src/lib/helpers/isFullyEncrypted.js
generated
vendored
Normal file
27
node_modules/@dotenvx/dotenvx/src/lib/helpers/isFullyEncrypted.js
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
const dotenvParse = require('./dotenvParse')
|
||||
const isEncrypted = require('./cryptography/isEncrypted')
|
||||
const isPublicKey = require('./cryptography/isPublicKey')
|
||||
|
||||
function isFullyEncrypted (src) {
|
||||
const parsed = dotenvParse(src, false, false, true) // collect all values
|
||||
|
||||
for (const [key, values] of Object.entries(parsed)) {
|
||||
// handle scenario where user mistakenly includes plaintext duplicate in .env:
|
||||
//
|
||||
// # .env
|
||||
// HELLO="World"
|
||||
// HELLO="encrypted:1234"
|
||||
//
|
||||
// key => [value1, ...]
|
||||
for (const value of values) {
|
||||
const result = isEncrypted(value) || isPublicKey(key)
|
||||
if (!result) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
module.exports = isFullyEncrypted
|
||||
19
node_modules/@dotenvx/dotenvx/src/lib/helpers/isIgnoringDotenvKeys.js
generated
vendored
Normal file
19
node_modules/@dotenvx/dotenvx/src/lib/helpers/isIgnoringDotenvKeys.js
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
const fsx = require('./fsx')
|
||||
const ignore = require('ignore')
|
||||
|
||||
function isIgnoringDotenvKeys () {
|
||||
if (!fsx.existsSync('.gitignore')) {
|
||||
return false
|
||||
}
|
||||
|
||||
const gitignore = fsx.readFileX('.gitignore')
|
||||
const ig = ignore(gitignore).add(gitignore)
|
||||
|
||||
if (!ig.ignores('.env.keys')) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
module.exports = isIgnoringDotenvKeys
|
||||
13
node_modules/@dotenvx/dotenvx/src/lib/helpers/keyResolution/index.js
generated
vendored
Normal file
13
node_modules/@dotenvx/dotenvx/src/lib/helpers/keyResolution/index.js
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
module.exports = {
|
||||
keyNames: require('./keyNames'),
|
||||
keyValues: require('./keyValues'),
|
||||
|
||||
// private
|
||||
// private keys are resolved via keyValues()
|
||||
|
||||
// other
|
||||
readProcessKey: require('./readProcessKey'),
|
||||
readFileKey: require('./readFileKey'),
|
||||
guessPrivateKeyFilename: require('./../guessPrivateKeyFilename'),
|
||||
dotenvPrivateKeyNames: require('./../dotenvPrivateKeyNames')
|
||||
}
|
||||
24
node_modules/@dotenvx/dotenvx/src/lib/helpers/keyResolution/keyNames.js
generated
vendored
Normal file
24
node_modules/@dotenvx/dotenvx/src/lib/helpers/keyResolution/keyNames.js
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
const path = require('path')
|
||||
const environment = require('./../envResolution/environment')
|
||||
|
||||
function keyNames (filepath) {
|
||||
const filename = path.basename(filepath).toLowerCase()
|
||||
|
||||
// .env
|
||||
if (filename === '.env') {
|
||||
return {
|
||||
publicKeyName: 'DOTENV_PUBLIC_KEY',
|
||||
privateKeyName: 'DOTENV_PRIVATE_KEY'
|
||||
}
|
||||
}
|
||||
|
||||
// .env.ENVIRONMENT
|
||||
const resolvedEnvironment = environment(filename).toUpperCase()
|
||||
|
||||
return {
|
||||
publicKeyName: `DOTENV_PUBLIC_KEY_${resolvedEnvironment}`,
|
||||
privateKeyName: `DOTENV_PRIVATE_KEY_${resolvedEnvironment}`
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = keyNames
|
||||
85
node_modules/@dotenvx/dotenvx/src/lib/helpers/keyResolution/keyValues.js
generated
vendored
Normal file
85
node_modules/@dotenvx/dotenvx/src/lib/helpers/keyResolution/keyValues.js
generated
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
const path = require('path')
|
||||
|
||||
const fsx = require('./../fsx')
|
||||
const dotenvParse = require('./../dotenvParse')
|
||||
const keyNames = require('./keyNames')
|
||||
const readProcessKey = require('./readProcessKey')
|
||||
const readFileKey = require('./readFileKey')
|
||||
const opsKeypair = require('../cryptography/opsKeypair')
|
||||
|
||||
function invertForPrivateKeyName (filepath) {
|
||||
const PUBLIC_KEY_SCHEMA = 'DOTENV_PUBLIC_KEY'
|
||||
const PRIVATE_KEY_SCHEMA = 'DOTENV_PRIVATE_KEY'
|
||||
|
||||
if (!fsx.existsSync(filepath)) {
|
||||
return null
|
||||
}
|
||||
|
||||
const envSrc = fsx.readFileX(filepath)
|
||||
const envParsed = dotenvParse(envSrc)
|
||||
|
||||
let publicKeyName
|
||||
for (const keyName of Object.keys(envParsed)) {
|
||||
if (keyName === PUBLIC_KEY_SCHEMA || keyName.startsWith(PUBLIC_KEY_SCHEMA)) {
|
||||
publicKeyName = keyName // find DOTENV_PUBLIC_KEY* in filename
|
||||
}
|
||||
}
|
||||
|
||||
if (publicKeyName) {
|
||||
return publicKeyName.replace(PUBLIC_KEY_SCHEMA, PRIVATE_KEY_SCHEMA) // return inverted (DOTENV_PUBLIC_KEY* -> DOTENV_PRIVATE_KEY*) if found
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
function keyValues (filepath, opts = {}) {
|
||||
let keysFilepath = opts.keysFilepath || null
|
||||
const opsOn = opts.opsOn === true
|
||||
const names = keyNames(filepath)
|
||||
const publicKeyName = names.publicKeyName // DOTENV_PUBLIC_KEY_${ENVIRONMENT}
|
||||
let privateKeyName = names.privateKeyName // DOTENV_PRIVATE_KEY_${ENVIRONMENT}
|
||||
|
||||
let publicKey = null
|
||||
let privateKey = null
|
||||
|
||||
// public key: process.env first, then .env*
|
||||
publicKey = readProcessKey(publicKeyName)
|
||||
if (!publicKey) {
|
||||
publicKey = readFileKey(publicKeyName, filepath) || null
|
||||
}
|
||||
|
||||
// private key: process.env first, then .env.keys, then invert public key
|
||||
privateKey = readProcessKey(privateKeyName)
|
||||
if (!privateKey) {
|
||||
if (keysFilepath) { // user specified -fk flag
|
||||
keysFilepath = path.resolve(keysFilepath)
|
||||
} else {
|
||||
keysFilepath = path.resolve(path.dirname(filepath), '.env.keys') // typical scenario
|
||||
}
|
||||
|
||||
privateKey = readFileKey(privateKeyName, keysFilepath)
|
||||
}
|
||||
// invert
|
||||
if (!privateKey) {
|
||||
privateKeyName = invertForPrivateKeyName(filepath)
|
||||
if (privateKeyName) {
|
||||
privateKey = readProcessKey(privateKeyName)
|
||||
if (!privateKey) {
|
||||
privateKey = readFileKey(privateKeyName, keysFilepath)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ops
|
||||
if (opsOn && !privateKey && publicKey && publicKey.length > 0) {
|
||||
const kp = opsKeypair(publicKey)
|
||||
privateKey = kp.privateKey
|
||||
}
|
||||
|
||||
return {
|
||||
publicKeyValue: publicKey || null, // important to make sure name is rendered
|
||||
privateKeyValue: privateKey || null // importan to make sure name is rendered
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = keyValues
|
||||
15
node_modules/@dotenvx/dotenvx/src/lib/helpers/keyResolution/readFileKey.js
generated
vendored
Normal file
15
node_modules/@dotenvx/dotenvx/src/lib/helpers/keyResolution/readFileKey.js
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
const fsx = require('./../fsx')
|
||||
const dotenvParse = require('./../dotenvParse')
|
||||
|
||||
function readFileKey (keyName, filepath) {
|
||||
if (fsx.existsSync(filepath)) {
|
||||
const src = fsx.readFileX(filepath)
|
||||
const parsed = dotenvParse(src)
|
||||
|
||||
if (parsed[keyName] && parsed[keyName].length > 0) {
|
||||
return parsed[keyName]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = readFileKey
|
||||
7
node_modules/@dotenvx/dotenvx/src/lib/helpers/keyResolution/readProcessKey.js
generated
vendored
Normal file
7
node_modules/@dotenvx/dotenvx/src/lib/helpers/keyResolution/readProcessKey.js
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
function readProcessKey (keyName) {
|
||||
if (process.env[keyName] && process.env[keyName].length > 0) {
|
||||
return process.env[keyName]
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = readProcessKey
|
||||
11
node_modules/@dotenvx/dotenvx/src/lib/helpers/localDisplayPath.js
generated
vendored
Normal file
11
node_modules/@dotenvx/dotenvx/src/lib/helpers/localDisplayPath.js
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
const path = require('path')
|
||||
|
||||
function localDisplayPath (filepath) {
|
||||
if (!filepath) return '.env.keys'
|
||||
if (!path.isAbsolute(filepath)) return filepath
|
||||
|
||||
const relative = path.relative(process.cwd(), filepath)
|
||||
return relative || path.basename(filepath)
|
||||
}
|
||||
|
||||
module.exports = localDisplayPath
|
||||
3
node_modules/@dotenvx/dotenvx/src/lib/helpers/packageJson.js
generated
vendored
Normal file
3
node_modules/@dotenvx/dotenvx/src/lib/helpers/packageJson.js
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
const { name, version, description } = require('../../../package.json')
|
||||
|
||||
module.exports = { name, version, description }
|
||||
211
node_modules/@dotenvx/dotenvx/src/lib/helpers/parse.js
generated
vendored
Normal file
211
node_modules/@dotenvx/dotenvx/src/lib/helpers/parse.js
generated
vendored
Normal file
@@ -0,0 +1,211 @@
|
||||
const decryptKeyValue = require('./cryptography/decryptKeyValue')
|
||||
const evalKeyValue = require('./evalKeyValue')
|
||||
const resolveEscapeSequences = require('./resolveEscapeSequences')
|
||||
|
||||
class Parse {
|
||||
static LINE = /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/mg
|
||||
|
||||
constructor (src, privateKey = null, processEnv = process.env, overload = false, privateKeyName = null) {
|
||||
this.src = src
|
||||
this.privateKey = privateKey
|
||||
this.privateKeyName = privateKeyName
|
||||
this.processEnv = processEnv
|
||||
this.overload = overload
|
||||
|
||||
this.parsed = {}
|
||||
this.preExisted = {}
|
||||
this.injected = {}
|
||||
this.errors = []
|
||||
|
||||
// for use with progressive expansion
|
||||
this.runningParsed = {}
|
||||
// for use with stopping expansion for literals
|
||||
this.literals = {}
|
||||
}
|
||||
|
||||
run () {
|
||||
const lines = this.getLines()
|
||||
|
||||
let match
|
||||
while ((match = Parse.LINE.exec(lines)) !== null) {
|
||||
const key = match[1]
|
||||
const value = match[2]
|
||||
const quote = this.quote(value) // must be raw match
|
||||
this.parsed[key] = this.clean(value, quote) // file value
|
||||
|
||||
if (!this.overload && this.inProcessEnv(key)) {
|
||||
this.parsed[key] = this.processEnv[key] // use process.env pre-existing value
|
||||
}
|
||||
|
||||
// decrypt
|
||||
try {
|
||||
this.parsed[key] = this.decrypt(key, this.parsed[key])
|
||||
} catch (e) {
|
||||
this.errors.push(e)
|
||||
}
|
||||
|
||||
// eval empty, double, or backticks
|
||||
let evaled = false
|
||||
if (quote !== "'" && (!this.inProcessEnv(key) || this.processEnv[key] === this.parsed[key])) {
|
||||
const priorEvaled = this.parsed[key]
|
||||
// eval
|
||||
try {
|
||||
this.parsed[key] = this.eval(key, priorEvaled)
|
||||
} catch (e) {
|
||||
this.errors.push(e)
|
||||
}
|
||||
if (priorEvaled !== this.parsed[key]) {
|
||||
evaled = true
|
||||
}
|
||||
}
|
||||
|
||||
// expand empty, double, or backticks
|
||||
if (!evaled && quote !== "'" && (!this.processEnv[key] || this.overload)) {
|
||||
this.parsed[key] = resolveEscapeSequences(this.expand(this.parsed[key]))
|
||||
}
|
||||
|
||||
if (quote === "'") {
|
||||
this.literals[key] = this.parsed[key]
|
||||
}
|
||||
|
||||
// for use with progressive expansion
|
||||
this.runningParsed[key] = this.parsed[key]
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(this.processEnv, key) && !this.overload) {
|
||||
this.preExisted[key] = this.processEnv[key] // track preExisted
|
||||
} else {
|
||||
this.injected[key] = this.parsed[key] // track injected
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
parsed: this.parsed,
|
||||
processEnv: this.processEnv,
|
||||
injected: this.injected,
|
||||
preExisted: this.preExisted,
|
||||
errors: this.errors
|
||||
}
|
||||
}
|
||||
|
||||
trimmer (value) {
|
||||
// Default undefined or null to empty string
|
||||
return (value || '').trim()
|
||||
}
|
||||
|
||||
quote (value) {
|
||||
const v = this.trimmer(value)
|
||||
const maybeQuote = v[0]
|
||||
let q = ''
|
||||
switch (maybeQuote) {
|
||||
// single
|
||||
case "'":
|
||||
q = "'"
|
||||
break
|
||||
// double
|
||||
case '"':
|
||||
q = '"'
|
||||
break
|
||||
// backtick
|
||||
case '`':
|
||||
q = '`'
|
||||
break
|
||||
// empty
|
||||
default:
|
||||
q = ''
|
||||
}
|
||||
|
||||
return q
|
||||
}
|
||||
|
||||
clean (value, _quote) {
|
||||
let v = this.trimmer(value)
|
||||
|
||||
// Remove surrounding quotes
|
||||
v = v.replace(/^(['"`])([\s\S]*)\1$/mg, '$2')
|
||||
|
||||
// Expand newlines if double quoted
|
||||
if (_quote === '"') {
|
||||
v = v.replace(/\\n/g, '\n') // newline
|
||||
v = v.replace(/\\r/g, '\r') // carriage return
|
||||
v = v.replace(/\\t/g, '\t') // tabs
|
||||
}
|
||||
|
||||
return v
|
||||
}
|
||||
|
||||
decrypt (key, value) {
|
||||
return decryptKeyValue(key, value, this.privateKeyName, this.privateKey)
|
||||
}
|
||||
|
||||
eval (key, value) {
|
||||
return evalKeyValue(key, value, this.processEnv, this.runningParsed)
|
||||
}
|
||||
|
||||
expand (value) {
|
||||
let env = { ...this.runningParsed, ...this.processEnv } // typically process.env wins
|
||||
if (this.overload) {
|
||||
env = { ...this.processEnv, ...this.runningParsed } // parsed wins
|
||||
}
|
||||
|
||||
const regex = /(?<!\\)\${([^{}]+)}|(?<!\\)\$([A-Za-z_][A-Za-z0-9_]*)/g
|
||||
|
||||
let result = value
|
||||
let match
|
||||
|
||||
while ((match = regex.exec(result)) !== null) {
|
||||
const [template, bracedExpression, unbracedExpression] = match
|
||||
const expression = bracedExpression || unbracedExpression
|
||||
|
||||
// match the operators `:+`, `+`, `:-`, and `-`
|
||||
const opRegex = /(:\+|\+|:-|-)/
|
||||
// find first match
|
||||
const opMatch = expression.match(opRegex)
|
||||
const splitter = opMatch ? opMatch[0] : null
|
||||
|
||||
const r = expression.split(splitter)
|
||||
|
||||
let defaultValue
|
||||
let value
|
||||
const key = r.shift()
|
||||
|
||||
if ([':+', '+'].includes(splitter)) {
|
||||
defaultValue = env[key] ? r.join(splitter) : ''
|
||||
value = null
|
||||
} else {
|
||||
defaultValue = r.join(splitter)
|
||||
value = env[key]
|
||||
}
|
||||
|
||||
if (value) {
|
||||
result = result.replace(template, value)
|
||||
} else {
|
||||
result = result.replace(template, defaultValue)
|
||||
}
|
||||
|
||||
// if the result equaled what was in env then stop expanding - handle self-referential check as well
|
||||
if (result === env[key]) {
|
||||
break
|
||||
}
|
||||
|
||||
// if the result came from what was a literal value then stop expanding
|
||||
// BUT only if the literal value contains expansion patterns (${...} or $VAR)
|
||||
if (this.literals[key] && /\$\{[^}]+\}|\$[A-Za-z_][A-Za-z0-9_]*/.test(this.literals[key])) {
|
||||
break
|
||||
}
|
||||
|
||||
regex.lastIndex = 0 // reset regex search position to re-evaluate after each replacement
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
inProcessEnv (key) {
|
||||
return Object.prototype.hasOwnProperty.call(this.processEnv, key)
|
||||
}
|
||||
|
||||
getLines () {
|
||||
return (this.src || '').toString().replace(/\r\n?/mg, '\n') // Convert buffer to string and Convert line breaks to same format
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Parse
|
||||
10
node_modules/@dotenvx/dotenvx/src/lib/helpers/pluralize.js
generated
vendored
Normal file
10
node_modules/@dotenvx/dotenvx/src/lib/helpers/pluralize.js
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
function pluralize (word, count) {
|
||||
// simple pluralization: add 's' at the end
|
||||
if (count === 0 || count > 1) {
|
||||
return word + 's'
|
||||
} else {
|
||||
return word
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = pluralize
|
||||
17
node_modules/@dotenvx/dotenvx/src/lib/helpers/prependPublicKey.js
generated
vendored
Normal file
17
node_modules/@dotenvx/dotenvx/src/lib/helpers/prependPublicKey.js
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
function prependPublicKey (publicKeyName, publicKey, filename, relativeFilepath = '.env.keys') {
|
||||
const comment = relativeFilepath === '.env.keys'
|
||||
? ''
|
||||
: ` # -fk ${relativeFilepath}`
|
||||
|
||||
return [
|
||||
'#/-------------------[DOTENV_PUBLIC_KEY]--------------------/',
|
||||
'#/ public-key encryption for .env files /',
|
||||
'#/ [how it works](https://dotenvx.com/encryption) /',
|
||||
'#/----------------------------------------------------------/',
|
||||
`${publicKeyName}="${publicKey}"${comment}`,
|
||||
'',
|
||||
`# ${filename}`
|
||||
].join('\n')
|
||||
}
|
||||
|
||||
module.exports = prependPublicKey
|
||||
16
node_modules/@dotenvx/dotenvx/src/lib/helpers/preserveShebang.js
generated
vendored
Normal file
16
node_modules/@dotenvx/dotenvx/src/lib/helpers/preserveShebang.js
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
function preserveShebang (envSrc) {
|
||||
const [firstLine, ...remainingLines] = envSrc.split('\n')
|
||||
let firstLinePreserved = ''
|
||||
|
||||
if (firstLine.startsWith('#!')) {
|
||||
firstLinePreserved = firstLine + '\n'
|
||||
envSrc = remainingLines.join('\n')
|
||||
}
|
||||
|
||||
return {
|
||||
firstLinePreserved,
|
||||
envSrc
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = preserveShebang
|
||||
36
node_modules/@dotenvx/dotenvx/src/lib/helpers/quotes.js
generated
vendored
Normal file
36
node_modules/@dotenvx/dotenvx/src/lib/helpers/quotes.js
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
const LINE = /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/mg
|
||||
|
||||
function quotes (src) {
|
||||
const obj = {}
|
||||
// Convert buffer to string
|
||||
let lines = src.toString()
|
||||
|
||||
// Convert line breaks to same format
|
||||
lines = lines.replace(/\r\n?/mg, '\n')
|
||||
|
||||
let match
|
||||
while ((match = LINE.exec(lines)) != null) {
|
||||
const key = match[1]
|
||||
|
||||
// Default undefined or null to empty string
|
||||
let value = (match[2] || '')
|
||||
|
||||
// Remove whitespace
|
||||
value = value.trim()
|
||||
|
||||
// Check if double quoted
|
||||
const maybeQuote = value[0]
|
||||
|
||||
value = value.replace(/^(['"`])([\s\S]*)\1$/mg, '$2')
|
||||
|
||||
if (maybeQuote === value[0]) {
|
||||
obj[key] = ''
|
||||
} else {
|
||||
obj[key] = maybeQuote
|
||||
}
|
||||
}
|
||||
|
||||
return obj
|
||||
}
|
||||
|
||||
module.exports = quotes
|
||||
21
node_modules/@dotenvx/dotenvx/src/lib/helpers/removeDynamicHelpSection.js
generated
vendored
Normal file
21
node_modules/@dotenvx/dotenvx/src/lib/helpers/removeDynamicHelpSection.js
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
// Remove Arguments section from help text. example:
|
||||
// Arguments:
|
||||
// command dynamic command
|
||||
// args dynamic command arguments
|
||||
|
||||
function removeDynamicHelpSection (lines) {
|
||||
let argumentsHelpIndex
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
if (lines[i] === 'Arguments:') {
|
||||
argumentsHelpIndex = i
|
||||
break
|
||||
}
|
||||
}
|
||||
if (argumentsHelpIndex) {
|
||||
lines.splice(argumentsHelpIndex, 4) // remove Arguments and the following 3 lines
|
||||
}
|
||||
|
||||
return lines
|
||||
}
|
||||
|
||||
module.exports = removeDynamicHelpSection
|
||||
11
node_modules/@dotenvx/dotenvx/src/lib/helpers/removeOptionsHelpParts.js
generated
vendored
Normal file
11
node_modules/@dotenvx/dotenvx/src/lib/helpers/removeOptionsHelpParts.js
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
// Remove [options] from help text. example:
|
||||
|
||||
function removeOptionsHelpParts (lines) {
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
lines[i] = lines[i].replace(' [options]', '')
|
||||
}
|
||||
|
||||
return lines
|
||||
}
|
||||
|
||||
module.exports = removeOptionsHelpParts
|
||||
69
node_modules/@dotenvx/dotenvx/src/lib/helpers/replace.js
generated
vendored
Normal file
69
node_modules/@dotenvx/dotenvx/src/lib/helpers/replace.js
generated
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
const quotes = require('./quotes')
|
||||
const dotenvParse = require('./dotenvParse')
|
||||
const escapeForRegex = require('./escapeForRegex')
|
||||
const escapeDollarSigns = require('./escapeDollarSigns')
|
||||
|
||||
function replace (src, key, replaceValue) {
|
||||
let output
|
||||
let newPart = ''
|
||||
|
||||
const parsed = dotenvParse(src, true, true) // skip expanding \n and skip converting \r\n
|
||||
const _quotes = quotes(src)
|
||||
if (Object.prototype.hasOwnProperty.call(parsed, key)) {
|
||||
const quote = _quotes[key]
|
||||
newPart += `${key}=${quote}${replaceValue}${quote}`
|
||||
|
||||
const originalValue = parsed[key]
|
||||
const escapedOriginalValue = escapeForRegex(originalValue)
|
||||
|
||||
// conditionally enforce end of line
|
||||
let enforceEndOfLine = ''
|
||||
if (escapedOriginalValue === '') {
|
||||
enforceEndOfLine = '$' // EMPTY scenario
|
||||
|
||||
// if empty quote and consecutive newlines
|
||||
const newlineMatch = src.match(new RegExp(`${key}\\s*=\\s*\n\n`, 'm')) // match any consecutive newline scenario for a blank value
|
||||
if (quote === '' && newlineMatch) {
|
||||
const newlineCount = (newlineMatch[0].match(/\n/g)).length - 1
|
||||
for (let i = 0; i < newlineCount; i++) {
|
||||
newPart += '\n' // re-append the extra newline to preserve user's format choice
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const currentPart = new RegExp(
|
||||
'^' + // start of line
|
||||
'(\\s*)?' + // spaces
|
||||
'(export\\s+)?' + // export
|
||||
key + // KEY
|
||||
'\\s*=\\s*' + // spaces (KEY = value)
|
||||
'["\'`]?' + // open quote
|
||||
escapedOriginalValue + // escaped value
|
||||
'["\'`]?' + // close quote
|
||||
enforceEndOfLine
|
||||
,
|
||||
'gm' // (g)lobal (m)ultiline
|
||||
)
|
||||
|
||||
const saferInput = escapeDollarSigns(newPart) // cleanse user inputted capture groups ($1, $2 etc)
|
||||
|
||||
// $1 preserves spaces
|
||||
// $2 preserves export
|
||||
output = src.replace(currentPart, `$1$2${saferInput}`)
|
||||
} else {
|
||||
newPart += `${key}="${replaceValue}"`
|
||||
|
||||
// append
|
||||
if (src.endsWith('\n')) {
|
||||
newPart = newPart + '\n'
|
||||
} else {
|
||||
newPart = '\n' + newPart
|
||||
}
|
||||
|
||||
output = src + newPart
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
module.exports = replace
|
||||
5
node_modules/@dotenvx/dotenvx/src/lib/helpers/resolveEscapeSequences.js
generated
vendored
Normal file
5
node_modules/@dotenvx/dotenvx/src/lib/helpers/resolveEscapeSequences.js
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
function resolveEscapeSequences (value) {
|
||||
return value.replace(/\\\$/g, '$')
|
||||
}
|
||||
|
||||
module.exports = resolveEscapeSequences
|
||||
12
node_modules/@dotenvx/dotenvx/src/lib/helpers/resolveHome.js
generated
vendored
Normal file
12
node_modules/@dotenvx/dotenvx/src/lib/helpers/resolveHome.js
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
const os = require('os')
|
||||
const path = require('path')
|
||||
|
||||
function resolveHome (filepath) {
|
||||
if (filepath[0] === '~') {
|
||||
return path.join(os.homedir(), filepath.slice(1))
|
||||
}
|
||||
|
||||
return filepath
|
||||
}
|
||||
|
||||
module.exports = resolveHome
|
||||
5
node_modules/@dotenvx/dotenvx/src/lib/helpers/sleep.js
generated
vendored
Normal file
5
node_modules/@dotenvx/dotenvx/src/lib/helpers/sleep.js
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
function sleep (ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
|
||||
module.exports = sleep
|
||||
10
node_modules/@dotenvx/dotenvx/src/lib/helpers/truncate.js
generated
vendored
Normal file
10
node_modules/@dotenvx/dotenvx/src/lib/helpers/truncate.js
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
function truncate (str, showChar = 7) {
|
||||
if (str && str.length > 0) {
|
||||
const visiblePart = str.slice(0, showChar)
|
||||
return visiblePart + '…'
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = truncate
|
||||
336
node_modules/@dotenvx/dotenvx/src/lib/main.d.ts
generated
vendored
Normal file
336
node_modules/@dotenvx/dotenvx/src/lib/main.d.ts
generated
vendored
Normal file
@@ -0,0 +1,336 @@
|
||||
import type { URL } from 'url';
|
||||
|
||||
export interface DotenvParseOptions {
|
||||
/**
|
||||
* Override any environment variables that have already been set on your machine with values from your .env file.
|
||||
* @default false
|
||||
* @example require('@dotenvx/dotenvx').config({ overload: true })
|
||||
* @alias overload
|
||||
*/
|
||||
overload?: boolean;
|
||||
|
||||
/**
|
||||
* @default false
|
||||
* @alias override
|
||||
*/
|
||||
override?: boolean;
|
||||
|
||||
/**
|
||||
* Specify an object to read existing environment variables from. Defaults to process.env environment variables.
|
||||
*
|
||||
* @default process.env
|
||||
* @example const processEnv = {}; require('@dotenvx/dotenvx').parse('HELLO=World', { processEnv: processEnv })
|
||||
*/
|
||||
processEnv?: DotenvPopulateInput;
|
||||
|
||||
/**
|
||||
* Specify a privateKey to decrypt any encrypted contents with.
|
||||
*
|
||||
* @default undefined
|
||||
* @example require('@dotenvx/dotenvx').parse('HELLO="encrypted:BE9Y7LKANx77X1pv1HnEoil93fPa5c9rpL/1ps48uaRT9zM8VR6mHx9yM+HktKdsPGIZELuZ7rr2mn1gScsmWitppAgE/1lVprNYBCqiYeaTcKXjDUXU5LfsEsflnAsDhT/kWG1l"', { privateKey: 'a4547dcd9d3429615a3649bb79e87edb62ee6a74b007075e9141ae44f5fb412c' })
|
||||
*/
|
||||
privateKey?: string;
|
||||
}
|
||||
|
||||
export interface DotenvParseOutput {
|
||||
[name: string]: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a string or buffer in the .env file format into an object.
|
||||
*
|
||||
* @see https://dotenvx.com/docs
|
||||
* @param src - contents to be parsed. example: `'DB_HOST=localhost'`
|
||||
* @param options - additional options. example: `{ processEnv: {}, privateKey: '<privateKey>', overload: false }`
|
||||
* @returns an object with keys and values based on `src`. example: `{ DB_HOST : 'localhost' }`
|
||||
*/
|
||||
export function parse<T extends DotenvParseOutput = DotenvParseOutput>(
|
||||
src: string | Buffer,
|
||||
options?: DotenvParseOptions
|
||||
): T;
|
||||
|
||||
export interface DotenvConfigOptions {
|
||||
/**
|
||||
* Specify a custom path if your file containing environment variables is located elsewhere.
|
||||
* Can also be an array of strings, specifying multiple paths.
|
||||
*
|
||||
* @default require('path').resolve(process.cwd(), '.env')
|
||||
* @example require('@dotenvx/dotenvx').config({ path: '/custom/path/to/.env' })
|
||||
* @example require('@dotenvx/dotenvx').config({ path: ['/path/to/first.env', '/path/to/second.env'] })
|
||||
*/
|
||||
path?: string | string[] | URL;
|
||||
|
||||
/**
|
||||
* Specify the encoding of your file containing environment variables.
|
||||
*
|
||||
* @default 'utf8'
|
||||
* @example require('@dotenvx/dotenvx').config({ encoding: 'latin1' })
|
||||
*/
|
||||
encoding?: string;
|
||||
|
||||
/**
|
||||
* Override any environment variables that have already been set on your machine with values from your .env file.
|
||||
* @default false
|
||||
* @example require('@dotenvx/dotenvx').config({ overload: true })
|
||||
* @alias overload
|
||||
*/
|
||||
overload?: boolean;
|
||||
|
||||
/**
|
||||
* @default false
|
||||
* @alias override
|
||||
*/
|
||||
override?: boolean;
|
||||
|
||||
/**
|
||||
* Throw immediately if an error is encountered - like a missing .env file.
|
||||
* @default false
|
||||
* @example require('@dotenvx/dotenvx').config({ strict: true })
|
||||
*/
|
||||
strict?: boolean;
|
||||
|
||||
/**
|
||||
* Suppress specific errors like MISSING_ENV_FILE. The error keys can be found
|
||||
* in src/lib/helpers/errors.js
|
||||
* @default []
|
||||
* @example require('@dotenvx/dotenvx').config({ ignore: ['MISSING_ENV_FILE'] })
|
||||
*/
|
||||
ignore?: string[];
|
||||
|
||||
/**
|
||||
* Specify an object to write your secrets to. Defaults to process.env environment variables.
|
||||
*
|
||||
* @default process.env
|
||||
* @example const processEnv = {}; require('@dotenvx/dotenvx').config({ processEnv: processEnv })
|
||||
*/
|
||||
processEnv?: DotenvPopulateInput;
|
||||
|
||||
/**
|
||||
* Customize the path to your .env.keys file. This is useful with monorepos.
|
||||
* @default []
|
||||
* @example require('@dotenvx/dotenvx').config({ envKeysFile: '../../.env.keys'} })
|
||||
*/
|
||||
envKeysFile?: string;
|
||||
|
||||
/**
|
||||
* Legacy option retained for compatibility.
|
||||
*
|
||||
* @default undefined
|
||||
* @example require('@dotenvx/dotenvx').config({ DOTENV_KEY: 'dotenv://:key_1234…' })
|
||||
*/
|
||||
DOTENV_KEY?: string;
|
||||
|
||||
/**
|
||||
* Load a .env convention (available conventions: 'nextjs, flow')
|
||||
*/
|
||||
convention?: string;
|
||||
|
||||
/**
|
||||
* Turn on logging to help debug why certain keys or values are not being set as you expect.
|
||||
*
|
||||
* @default false
|
||||
* @example require('@dotenvx/dotenvx').config({ debug: process.env.DEBUG })
|
||||
*/
|
||||
debug?: boolean;
|
||||
|
||||
verbose?: boolean;
|
||||
|
||||
quiet?: boolean;
|
||||
|
||||
logLevel?:
|
||||
| 'error'
|
||||
| 'warn'
|
||||
| 'success'
|
||||
| 'successv'
|
||||
| 'info'
|
||||
| 'help'
|
||||
| 'verbose'
|
||||
| 'debug';
|
||||
|
||||
/**
|
||||
* Turn off Dotenvx Ops features - https://dotenvx.com/ops
|
||||
*
|
||||
* @default false
|
||||
* @example require('@dotenvx/dotenvx').config({ opsOff: true })
|
||||
*/
|
||||
opsOff?: boolean;
|
||||
}
|
||||
|
||||
export interface DotenvConfigOutput {
|
||||
error?: Error;
|
||||
parsed?: DotenvParseOutput;
|
||||
}
|
||||
|
||||
export interface DotenvPopulateInput {
|
||||
[name: string]: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads `.env` file contents into process.env by default.
|
||||
*
|
||||
* @see https://dotenvx.com/docs
|
||||
*
|
||||
* @param options - additional options. example: `{ path: './custom/path', encoding: 'latin1', debug: true, overload: false }`
|
||||
* @returns an object with a `parsed` key if successful or `error` key if an error occurred. example: { parsed: { KEY: 'value' } }
|
||||
*
|
||||
*/
|
||||
export function config(options?: DotenvConfigOptions): DotenvConfigOutput;
|
||||
|
||||
export interface SetOptions {
|
||||
/**
|
||||
* Specify a custom path if your file containing environment variables is located elsewhere.
|
||||
* Can also be an array of strings, specifying multiple paths.
|
||||
*
|
||||
* @default require('path').resolve(process.cwd(), '.env')
|
||||
* @example require('@dotenvx/dotenvx').set(key, value, { path: '/custom/path/to/.env' })
|
||||
* @example require('@dotenvx/dotenvx').set(key, value, { path: ['/path/to/first.env', '/path/to/second.env'] })
|
||||
*/
|
||||
path?: string | string[] | URL;
|
||||
|
||||
/**
|
||||
* Customize the path to your .env.keys file. This is useful with monorepos.
|
||||
* @default []
|
||||
* @example require('@dotenvx/dotenvx').config(key, value, { envKeysFile: '../../.env.keys'} })
|
||||
*/
|
||||
envKeysFile?: string;
|
||||
|
||||
/**
|
||||
* Set a .env convention (available conventions: 'nextjs, flow')
|
||||
*/
|
||||
convention?: string;
|
||||
|
||||
/**
|
||||
* Specify whether the variable has to be encrypted
|
||||
* @default true
|
||||
* @example require('@dotenvx/dotenvx').config(key, value, { encrypt: false } })
|
||||
*/
|
||||
encrypt?: boolean;
|
||||
|
||||
/**
|
||||
* Turn off Dotenvx Ops features - https://dotenvx.com/ops
|
||||
*
|
||||
* @default false
|
||||
* @example require('@dotenvx/dotenvx').set(key, value, { opsOff: true })
|
||||
*/
|
||||
opsOff?: boolean;
|
||||
}
|
||||
|
||||
export type SetProcessedEnv = {
|
||||
key: string;
|
||||
value: string;
|
||||
filepath: string;
|
||||
envFilepath: string;
|
||||
envSrc: string;
|
||||
changed: boolean;
|
||||
encryptedValue?: string;
|
||||
publicKey?: string;
|
||||
privateKey?: string;
|
||||
privateKeyAdded?: boolean;
|
||||
privateKeyName?: string;
|
||||
error?: Error;
|
||||
};
|
||||
|
||||
export type SetOutput = {
|
||||
processedEnvs: SetProcessedEnv[];
|
||||
changedFilepaths: string[];
|
||||
unchangedFilepaths: string[];
|
||||
};
|
||||
|
||||
/**
|
||||
* Set a single environment variable.
|
||||
*
|
||||
* @see https://dotenvx.com/docs
|
||||
* @param key - KEY
|
||||
* @param value - value
|
||||
* @param options - additional options. example: `{ encrypt: false }`
|
||||
*/
|
||||
export function set(
|
||||
key: string,
|
||||
value: string,
|
||||
options?: SetOptions
|
||||
): SetOutput;
|
||||
|
||||
export interface GetOptions {
|
||||
/**
|
||||
* Suppress specific errors like MISSING_ENV_FILE. The error keys can be found
|
||||
* in src/lib/helpers/errors.js
|
||||
* @default []
|
||||
* @example require('@dotenvx/dotenvx').get('KEY', { ignore: ['MISSING_ENV_FILE'] })
|
||||
*/
|
||||
ignore?: string[];
|
||||
|
||||
/**
|
||||
* Override any environment variables that have already been set on your machine with values from your .env file.
|
||||
* @default false
|
||||
* @example require('@dotenvx/dotenvx').get('KEY', { overload: true })
|
||||
* @alias overload
|
||||
*/
|
||||
overload?: boolean;
|
||||
|
||||
/**
|
||||
* Customize the path to your .env.keys file. This is useful with monorepos.
|
||||
* @default []
|
||||
* @example require('@dotenvx/dotenvx').get('KEY', { envKeysFile: '../../.env.keys'} })
|
||||
*/
|
||||
envKeysFile?: string;
|
||||
|
||||
/**
|
||||
* Throw immediately if an error is encountered - like a missing .env file.
|
||||
* @default false
|
||||
* @example require('@dotenvx/dotenvx').get('KEY', { strict: true })
|
||||
*/
|
||||
strict?: boolean;
|
||||
|
||||
/**
|
||||
* Turn off Dotenvx Ops features - https://dotenvx.com/ops
|
||||
*
|
||||
* @default false
|
||||
* @example require('@dotenvx/dotenvx').get('KEY', { opsOff: true })
|
||||
*/
|
||||
opsOff?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a single environment variable.
|
||||
*
|
||||
* @see https://dotenvx.com/docs
|
||||
* @param key - KEY
|
||||
* @param options - additional options. example: `{ overload: true }`
|
||||
*/
|
||||
export function get(
|
||||
key: string,
|
||||
options?: GetOptions
|
||||
): string;
|
||||
|
||||
/**
|
||||
* List all env files in the current working directory
|
||||
*
|
||||
* @param directory - current working directory
|
||||
* @param envFile - glob pattern to match env files
|
||||
* @param excludeEnvFile - glob pattern to exclude env files
|
||||
*/
|
||||
export function ls(
|
||||
directory: string,
|
||||
envFile: string | string[],
|
||||
excludeEnvFile: string | string[]
|
||||
): string[];
|
||||
|
||||
export type GenExampleOutput = {
|
||||
envExampleFile: string;
|
||||
envFile: string | string[];
|
||||
exampleFilepath: string;
|
||||
addedKeys: string[];
|
||||
injected: Record<string, string>;
|
||||
preExisted: Record<string, string>;
|
||||
};
|
||||
|
||||
/**
|
||||
* Generate an example .env file
|
||||
*
|
||||
* @param directory - current working directory
|
||||
* @param envFile - path to the .env file(s)
|
||||
*/
|
||||
export function genexample(
|
||||
directory: string,
|
||||
envFile: string
|
||||
): GenExampleOutput;
|
||||
314
node_modules/@dotenvx/dotenvx/src/lib/main.js
generated
vendored
Normal file
314
node_modules/@dotenvx/dotenvx/src/lib/main.js
generated
vendored
Normal file
@@ -0,0 +1,314 @@
|
||||
// @ts-check
|
||||
const path = require('path')
|
||||
|
||||
// shared
|
||||
const { setLogLevel, setLogName, setLogVersion, logger } = require('./../shared/logger')
|
||||
const { getColor, bold } = require('./../shared/colors')
|
||||
|
||||
// services
|
||||
const Ls = require('./services/ls')
|
||||
const Run = require('./services/run')
|
||||
const Sets = require('./services/sets')
|
||||
const Get = require('./services/get')
|
||||
const Keypair = require('./services/keypair')
|
||||
const Genexample = require('./services/genexample')
|
||||
|
||||
// helpers
|
||||
const buildEnvs = require('./helpers/buildEnvs')
|
||||
const Parse = require('./helpers/parse')
|
||||
const fsx = require('./helpers/fsx')
|
||||
const localDisplayPath = require('./helpers/localDisplayPath')
|
||||
|
||||
/** @type {import('./main').config} */
|
||||
const config = function (options = {}) {
|
||||
// allow user to set processEnv to write to
|
||||
let processEnv = process.env
|
||||
if (options && options.processEnv != null) {
|
||||
processEnv = options.processEnv
|
||||
}
|
||||
|
||||
// overload
|
||||
const overload = options.overload || options.override
|
||||
|
||||
// ignore
|
||||
const ignore = options.ignore || []
|
||||
|
||||
// strict
|
||||
const strict = options.strict
|
||||
|
||||
// envKeysFile
|
||||
const envKeysFile = options.envKeysFile
|
||||
|
||||
// dotenvx-ops related
|
||||
const opsOn = options.opsOff !== true
|
||||
|
||||
if (options) {
|
||||
setLogLevel(options)
|
||||
setLogName(options)
|
||||
setLogVersion(options)
|
||||
}
|
||||
|
||||
try {
|
||||
const envs = buildEnvs(options)
|
||||
const {
|
||||
processedEnvs,
|
||||
readableFilepaths,
|
||||
uniqueInjectedKeys
|
||||
} = new Run(envs, overload, processEnv, envKeysFile, opsOn).run()
|
||||
|
||||
if (opsOn) {
|
||||
// removed radar feature for now. contact me at mot@dotenvx.com if still needed for your organization.
|
||||
// try { new Ops().observe({ beforeEnv, processedEnvs, afterEnv }) } catch {}
|
||||
}
|
||||
|
||||
let lastError
|
||||
/** @type {Record<string, string>} */
|
||||
const parsedAll = {}
|
||||
for (const processedEnv of processedEnvs) {
|
||||
if (processedEnv.type === 'envFile') {
|
||||
logger.verbose(`loading env from ${processedEnv.filepath} (${path.resolve(processedEnv.filepath)})`)
|
||||
}
|
||||
|
||||
for (const error of processedEnv.errors || []) {
|
||||
if (ignore.includes(error.code)) {
|
||||
logger.verbose(`ignored: ${error.message}`)
|
||||
continue // ignore error
|
||||
}
|
||||
|
||||
if (strict) throw error // throw if strict and not ignored
|
||||
|
||||
lastError = error // surface later in { error }
|
||||
|
||||
if (error.code === 'MISSING_ENV_FILE') {
|
||||
if (!options.convention) { // do not output error for conventions (too noisy)
|
||||
logger.error(error.messageWithHelp)
|
||||
}
|
||||
} else {
|
||||
logger.error(error.messageWithHelp)
|
||||
}
|
||||
}
|
||||
|
||||
Object.assign(parsedAll, processedEnv.injected || {})
|
||||
Object.assign(parsedAll, processedEnv.preExisted || {}) // preExisted 'wins'
|
||||
|
||||
// debug parsed
|
||||
logger.debug(processedEnv.parsed)
|
||||
|
||||
// verbose/debug injected key/value
|
||||
for (const [key, value] of Object.entries(processedEnv.injected || {})) {
|
||||
logger.verbose(`${key} set`)
|
||||
logger.debug(`${key} set to ${value}`)
|
||||
}
|
||||
|
||||
// verbose/debug preExisted key/value
|
||||
for (const [key, value] of Object.entries(processedEnv.preExisted || {})) {
|
||||
logger.verbose(`${key} pre-exists (protip: use --overload to override)`)
|
||||
logger.debug(`${key} pre-exists as ${value} (protip: use --overload to override)`)
|
||||
}
|
||||
}
|
||||
|
||||
let msg = `injecting env (${uniqueInjectedKeys.length})`
|
||||
if (readableFilepaths.length > 0) {
|
||||
msg += ` from ${readableFilepaths.join(', ')}`
|
||||
}
|
||||
logger.successv(msg)
|
||||
|
||||
if (lastError) {
|
||||
return { parsed: parsedAll, error: lastError }
|
||||
} else {
|
||||
return { parsed: parsedAll }
|
||||
}
|
||||
} catch (error) {
|
||||
if (strict) throw error // throw immediately if strict
|
||||
|
||||
logger.error(error.messageWithHelp)
|
||||
|
||||
return { parsed: {}, error }
|
||||
}
|
||||
}
|
||||
|
||||
/** @type {import('./main').parse} */
|
||||
const parse = function (src, options = {}) {
|
||||
// allow user to set processEnv to read from
|
||||
let processEnv = process.env
|
||||
if (options && options.processEnv != null) {
|
||||
processEnv = options.processEnv
|
||||
}
|
||||
|
||||
// private decryption key
|
||||
const privateKey = options.privateKey || null
|
||||
|
||||
// overload
|
||||
const overload = options.overload || options.override
|
||||
|
||||
const { parsed, errors } = new Parse(src, privateKey, processEnv, overload).run()
|
||||
|
||||
// display any errors
|
||||
for (const error of errors) {
|
||||
logger.error(error.messageWithHelp)
|
||||
}
|
||||
|
||||
return parsed
|
||||
}
|
||||
|
||||
/* @type {import('./main').set} */
|
||||
const set = function (key, value, options = {}) {
|
||||
// encrypt
|
||||
let encrypt = true
|
||||
if (options.plain) {
|
||||
encrypt = false
|
||||
} else if (options.encrypt === false) {
|
||||
encrypt = false
|
||||
}
|
||||
|
||||
if (options) {
|
||||
setLogLevel(options)
|
||||
setLogName(options)
|
||||
setLogVersion(options)
|
||||
}
|
||||
|
||||
const envs = buildEnvs(options)
|
||||
const envKeysFilepath = options.envKeysFile
|
||||
const opsOn = options.opsOff !== true
|
||||
|
||||
const {
|
||||
processedEnvs,
|
||||
changedFilepaths,
|
||||
unchangedFilepaths
|
||||
} = new Sets(key, value, envs, encrypt, envKeysFilepath, opsOn).run()
|
||||
|
||||
let withEncryption = ''
|
||||
|
||||
if (encrypt) {
|
||||
withEncryption = ' with encryption'
|
||||
}
|
||||
|
||||
for (const processedEnv of processedEnvs) {
|
||||
logger.verbose(`setting for ${processedEnv.envFilepath}`)
|
||||
|
||||
if (processedEnv.error) {
|
||||
const error = processedEnv.error
|
||||
const message = error.messageWithHelp || (error.help ? `${error.message}. ${error.help}` : error.message)
|
||||
logger.warn(message)
|
||||
} else {
|
||||
fsx.writeFileX(processedEnv.filepath, processedEnv.envSrc)
|
||||
|
||||
logger.verbose(`${processedEnv.key} set${withEncryption} (${processedEnv.envFilepath})`)
|
||||
logger.debug(`${processedEnv.key} set${withEncryption} to ${processedEnv.value} (${processedEnv.envFilepath})`)
|
||||
}
|
||||
}
|
||||
|
||||
const keyAddedEnv = processedEnvs.find((processedEnv) => processedEnv.privateKeyAdded)
|
||||
const keyAddedSuffix = keyAddedEnv ? ` + key (${localDisplayPath(keyAddedEnv.envKeysFilepath)})` : ''
|
||||
|
||||
if (changedFilepaths.length > 0) {
|
||||
if (encrypt) {
|
||||
logger.success(`◈ encrypted ${key} (${changedFilepaths.join(',')})${keyAddedSuffix}`)
|
||||
} else {
|
||||
logger.success(`◇ set ${key} (${changedFilepaths.join(',')})`)
|
||||
}
|
||||
} else if (encrypt && keyAddedEnv) {
|
||||
const keyAddedEnvFilepath = keyAddedEnv.envFilepath || changedFilepaths[0] || '.env'
|
||||
logger.success(`◈ encrypted ${key} (${keyAddedEnvFilepath})${keyAddedSuffix}`)
|
||||
} else if (unchangedFilepaths.length > 0) {
|
||||
logger.info(`○ no changes (${unchangedFilepaths})`)
|
||||
} else {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
// intentionally quiet: success line communicates key creation
|
||||
|
||||
return {
|
||||
processedEnvs,
|
||||
changedFilepaths,
|
||||
unchangedFilepaths
|
||||
}
|
||||
}
|
||||
|
||||
/* @type {import('./main').get} */
|
||||
const get = function (key, options = {}) {
|
||||
const envs = buildEnvs(options)
|
||||
const opsOn = options.opsOff !== true
|
||||
|
||||
// ignore
|
||||
const ignore = options.ignore || []
|
||||
|
||||
const { parsed, errors } = new Get(key, envs, options.overload, options.all, options.envKeysFile, opsOn).run()
|
||||
|
||||
for (const error of errors || []) {
|
||||
if (ignore.includes(error.code)) {
|
||||
continue // ignore error
|
||||
}
|
||||
|
||||
if (options.strict) throw error // throw immediately if strict
|
||||
|
||||
logger.error(error.messageWithHelp)
|
||||
}
|
||||
|
||||
if (key) {
|
||||
const single = parsed[key]
|
||||
if (single === undefined) {
|
||||
return undefined
|
||||
} else {
|
||||
return single
|
||||
}
|
||||
} else {
|
||||
if (options.format === 'eval') {
|
||||
let inline = ''
|
||||
for (const [key, value] of Object.entries(parsed)) {
|
||||
inline += `${key}=${escape(value)}\n`
|
||||
}
|
||||
inline = inline.trim()
|
||||
|
||||
return inline
|
||||
} else if (options.format === 'shell') {
|
||||
let inline = ''
|
||||
for (const [key, value] of Object.entries(parsed)) {
|
||||
inline += `${key}=${value} `
|
||||
}
|
||||
inline = inline.trim()
|
||||
|
||||
return inline
|
||||
} else {
|
||||
return parsed
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @type {import('./main').ls} */
|
||||
const ls = function (directory, envFile, excludeEnvFile) {
|
||||
return new Ls(directory, envFile, excludeEnvFile).run()
|
||||
}
|
||||
|
||||
/** @type {import('./main').genexample} */
|
||||
const genexample = function (directory, envFile) {
|
||||
return new Genexample(directory, envFile).run()
|
||||
}
|
||||
|
||||
/** @type {import('./main').keypair} */
|
||||
const keypair = function (envFile, key, envKeysFile = null, opsOff = false) {
|
||||
const opsOn = opsOff !== true
|
||||
const keypairs = new Keypair(envFile, envKeysFile, opsOn).run()
|
||||
if (key) {
|
||||
return keypairs[key]
|
||||
} else {
|
||||
return keypairs
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
// dotenv proxies
|
||||
config,
|
||||
parse,
|
||||
// actions related
|
||||
set,
|
||||
get,
|
||||
ls,
|
||||
keypair,
|
||||
genexample,
|
||||
// expose for libs depending on @dotenvx/dotenvx - like dotenvx-ops
|
||||
setLogLevel,
|
||||
logger,
|
||||
getColor,
|
||||
bold
|
||||
}
|
||||
143
node_modules/@dotenvx/dotenvx/src/lib/services/decrypt.js
generated
vendored
Normal file
143
node_modules/@dotenvx/dotenvx/src/lib/services/decrypt.js
generated
vendored
Normal file
@@ -0,0 +1,143 @@
|
||||
const fsx = require('./../helpers/fsx')
|
||||
const path = require('path')
|
||||
const picomatch = require('picomatch')
|
||||
|
||||
const TYPE_ENV_FILE = 'envFile'
|
||||
|
||||
const Errors = require('./../helpers/errors')
|
||||
|
||||
const {
|
||||
determine
|
||||
} = require('./../helpers/envResolution')
|
||||
|
||||
const {
|
||||
keyNames,
|
||||
keyValues
|
||||
} = require('./../helpers/keyResolution')
|
||||
|
||||
const {
|
||||
decryptKeyValue,
|
||||
isEncrypted
|
||||
} = require('./../helpers/cryptography')
|
||||
|
||||
const replace = require('./../helpers/replace')
|
||||
const dotenvParse = require('./../helpers/dotenvParse')
|
||||
const detectEncoding = require('./../helpers/detectEncoding')
|
||||
|
||||
class Decrypt {
|
||||
constructor (envs = [], key = [], excludeKey = [], envKeysFilepath = null, opsOn = false) {
|
||||
this.envs = determine(envs, process.env)
|
||||
this.key = key
|
||||
this.excludeKey = excludeKey
|
||||
this.envKeysFilepath = envKeysFilepath
|
||||
this.opsOn = opsOn
|
||||
|
||||
this.processedEnvs = []
|
||||
this.changedFilepaths = new Set()
|
||||
this.unchangedFilepaths = new Set()
|
||||
}
|
||||
|
||||
run () {
|
||||
// example
|
||||
// envs [
|
||||
// { type: 'envFile', value: '.env' }
|
||||
// ]
|
||||
|
||||
this.keys = this._keys()
|
||||
const excludeKeys = this._excludeKeys()
|
||||
|
||||
this.exclude = picomatch(excludeKeys)
|
||||
this.include = picomatch(this.keys, { ignore: excludeKeys })
|
||||
|
||||
for (const env of this.envs) {
|
||||
if (env.type === TYPE_ENV_FILE) {
|
||||
this._decryptEnvFile(env.value)
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
processedEnvs: this.processedEnvs,
|
||||
changedFilepaths: [...this.changedFilepaths],
|
||||
unchangedFilepaths: [...this.unchangedFilepaths]
|
||||
}
|
||||
}
|
||||
|
||||
_decryptEnvFile (envFilepath) {
|
||||
const row = {}
|
||||
row.keys = []
|
||||
row.type = TYPE_ENV_FILE
|
||||
|
||||
const filepath = path.resolve(envFilepath)
|
||||
row.filepath = filepath
|
||||
row.envFilepath = envFilepath
|
||||
|
||||
try {
|
||||
const encoding = detectEncoding(filepath)
|
||||
let envSrc = fsx.readFileX(filepath, { encoding })
|
||||
const envParsed = dotenvParse(envSrc)
|
||||
|
||||
const { privateKeyName } = keyNames(envFilepath)
|
||||
const { privateKeyValue } = keyValues(envFilepath, { keysFilepath: this.envKeysFilepath, opsOn: this.opsOn })
|
||||
|
||||
row.privateKey = privateKeyValue
|
||||
row.privateKeyName = privateKeyName
|
||||
row.changed = false // track possible changes
|
||||
|
||||
for (const [key, value] of Object.entries(envParsed)) {
|
||||
// key excluded - don't decrypt it
|
||||
if (this.exclude(key)) {
|
||||
continue
|
||||
}
|
||||
|
||||
// key effectively excluded (by not being in the list of includes) - don't decrypt it
|
||||
if (this.keys.length > 0 && !this.include(key)) {
|
||||
continue
|
||||
}
|
||||
|
||||
const encrypted = isEncrypted(value)
|
||||
if (encrypted) {
|
||||
row.keys.push(key) // track key(s)
|
||||
|
||||
const decryptedValue = decryptKeyValue(key, value, privateKeyName, privateKeyValue)
|
||||
// once newSrc is built write it out
|
||||
envSrc = replace(envSrc, key, decryptedValue)
|
||||
|
||||
row.changed = true // track change
|
||||
}
|
||||
}
|
||||
|
||||
row.envSrc = envSrc
|
||||
if (row.changed) {
|
||||
this.changedFilepaths.add(envFilepath)
|
||||
} else {
|
||||
this.unchangedFilepaths.add(envFilepath)
|
||||
}
|
||||
} catch (e) {
|
||||
if (e.code === 'ENOENT') {
|
||||
row.error = new Errors({ envFilepath, filepath }).missingEnvFile()
|
||||
} else {
|
||||
row.error = e
|
||||
}
|
||||
}
|
||||
|
||||
this.processedEnvs.push(row)
|
||||
}
|
||||
|
||||
_keys () {
|
||||
if (!Array.isArray(this.key)) {
|
||||
return [this.key]
|
||||
}
|
||||
|
||||
return this.key
|
||||
}
|
||||
|
||||
_excludeKeys () {
|
||||
if (!Array.isArray(this.excludeKey)) {
|
||||
return [this.excludeKey]
|
||||
}
|
||||
|
||||
return this.excludeKey
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Decrypt
|
||||
173
node_modules/@dotenvx/dotenvx/src/lib/services/encrypt.js
generated
vendored
Normal file
173
node_modules/@dotenvx/dotenvx/src/lib/services/encrypt.js
generated
vendored
Normal file
@@ -0,0 +1,173 @@
|
||||
const fsx = require('./../helpers/fsx')
|
||||
const path = require('path')
|
||||
const picomatch = require('picomatch')
|
||||
|
||||
const TYPE_ENV_FILE = 'envFile'
|
||||
|
||||
const Errors = require('./../helpers/errors')
|
||||
|
||||
const {
|
||||
determine
|
||||
} = require('./../helpers/envResolution')
|
||||
|
||||
const {
|
||||
keyNames,
|
||||
keyValues
|
||||
} = require('./../helpers/keyResolution')
|
||||
|
||||
const {
|
||||
encryptValue,
|
||||
isEncrypted,
|
||||
isPublicKey,
|
||||
provision,
|
||||
provisionWithPrivateKey
|
||||
} = require('./../helpers/cryptography')
|
||||
|
||||
const replace = require('./../helpers/replace')
|
||||
const dotenvParse = require('./../helpers/dotenvParse')
|
||||
const detectEncoding = require('./../helpers/detectEncoding')
|
||||
|
||||
class Encrypt {
|
||||
constructor (envs = [], key = [], excludeKey = [], envKeysFilepath = null, opsOn = false) {
|
||||
this.envs = determine(envs, process.env)
|
||||
this.key = key
|
||||
this.excludeKey = excludeKey
|
||||
this.envKeysFilepath = envKeysFilepath
|
||||
this.opsOn = opsOn
|
||||
|
||||
this.processedEnvs = []
|
||||
this.changedFilepaths = new Set()
|
||||
this.unchangedFilepaths = new Set()
|
||||
}
|
||||
|
||||
run () {
|
||||
// example
|
||||
// envs [
|
||||
// { type: 'envFile', value: '.env' }
|
||||
// ]
|
||||
|
||||
this.keys = this._keys()
|
||||
const excludeKeys = this._excludeKeys()
|
||||
|
||||
this.exclude = picomatch(excludeKeys)
|
||||
this.include = picomatch(this.keys, { ignore: excludeKeys })
|
||||
|
||||
for (const env of this.envs) {
|
||||
if (env.type === TYPE_ENV_FILE) {
|
||||
this._encryptEnvFile(env.value)
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
processedEnvs: this.processedEnvs,
|
||||
changedFilepaths: [...this.changedFilepaths],
|
||||
unchangedFilepaths: [...this.unchangedFilepaths]
|
||||
}
|
||||
}
|
||||
|
||||
_encryptEnvFile (envFilepath) {
|
||||
const row = {}
|
||||
row.keys = []
|
||||
row.type = TYPE_ENV_FILE
|
||||
|
||||
const filepath = path.resolve(envFilepath)
|
||||
row.filepath = filepath
|
||||
row.envFilepath = envFilepath
|
||||
|
||||
try {
|
||||
const encoding = detectEncoding(filepath)
|
||||
let envSrc = fsx.readFileX(filepath, { encoding })
|
||||
const envParsed = dotenvParse(envSrc)
|
||||
|
||||
let publicKey
|
||||
let privateKey
|
||||
|
||||
const { publicKeyName, privateKeyName } = keyNames(envFilepath)
|
||||
const { publicKeyValue, privateKeyValue } = keyValues(envFilepath, { keysFilepath: this.envKeysFilepath, opsOn: this.opsOn })
|
||||
|
||||
// first pass - provision
|
||||
if (!privateKeyValue && !publicKeyValue) {
|
||||
const prov = provision({ envSrc, envFilepath, keysFilepath: this.envKeysFilepath, opsOn: this.opsOn })
|
||||
envSrc = prov.envSrc
|
||||
publicKey = prov.publicKey
|
||||
privateKey = prov.privateKey
|
||||
row.privateKeyAdded = prov.privateKeyAdded
|
||||
row.envKeysFilepath = prov.envKeysFilepath
|
||||
} else if (privateKeyValue) {
|
||||
const prov = provisionWithPrivateKey({ envSrc, envFilepath, keysFilepath: this.envKeysFilepath, privateKeyValue, publicKeyValue, publicKeyName })
|
||||
publicKey = prov.publicKey
|
||||
privateKey = prov.privateKey
|
||||
envSrc = prov.envSrc
|
||||
} else if (publicKeyValue) {
|
||||
publicKey = publicKeyValue
|
||||
}
|
||||
|
||||
row.publicKey = publicKey
|
||||
row.privateKey = privateKey
|
||||
row.privateKeyName = privateKeyName
|
||||
|
||||
// iterate over all non-encrypted values and encrypt them
|
||||
for (const [key, value] of Object.entries(envParsed)) {
|
||||
// key excluded - don't encrypt it
|
||||
if (this.exclude(key)) {
|
||||
continue
|
||||
}
|
||||
|
||||
// key effectively excluded (by not being in the list of includes) - don't encrypt it
|
||||
if (this.keys.length > 0 && !this.include(key)) {
|
||||
continue
|
||||
}
|
||||
|
||||
const encrypted = isEncrypted(value) || isPublicKey(key)
|
||||
if (!encrypted) {
|
||||
row.keys.push(key) // track key(s)
|
||||
|
||||
let encryptedValue
|
||||
try {
|
||||
encryptedValue = encryptValue(value, publicKey)
|
||||
} catch {
|
||||
throw new Errors({ publicKeyName, publicKey }).invalidPublicKey()
|
||||
}
|
||||
|
||||
// once newSrc is built write it out
|
||||
envSrc = replace(envSrc, key, encryptedValue)
|
||||
|
||||
row.changed = true // track change
|
||||
}
|
||||
}
|
||||
|
||||
row.envSrc = envSrc
|
||||
if (row.changed) {
|
||||
this.changedFilepaths.add(envFilepath)
|
||||
} else {
|
||||
this.unchangedFilepaths.add(envFilepath)
|
||||
}
|
||||
} catch (e) {
|
||||
if (e.code === 'ENOENT') {
|
||||
row.error = new Errors({ envFilepath, filepath }).missingEnvFile()
|
||||
} else {
|
||||
row.error = e
|
||||
}
|
||||
}
|
||||
|
||||
this.processedEnvs.push(row)
|
||||
}
|
||||
|
||||
_keys () {
|
||||
if (!Array.isArray(this.key)) {
|
||||
return [this.key]
|
||||
}
|
||||
|
||||
return this.key
|
||||
}
|
||||
|
||||
_excludeKeys () {
|
||||
if (!Array.isArray(this.excludeKey)) {
|
||||
return [this.excludeKey]
|
||||
}
|
||||
|
||||
return this.excludeKey
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Encrypt
|
||||
101
node_modules/@dotenvx/dotenvx/src/lib/services/genexample.js
generated
vendored
Normal file
101
node_modules/@dotenvx/dotenvx/src/lib/services/genexample.js
generated
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
const fsx = require('./../helpers/fsx')
|
||||
const path = require('path')
|
||||
|
||||
const Errors = require('../helpers/errors')
|
||||
const findEnvFiles = require('../helpers/findEnvFiles')
|
||||
const replace = require('../helpers/replace')
|
||||
const dotenvParse = require('../helpers/dotenvParse')
|
||||
|
||||
class Genexample {
|
||||
constructor (directory = '.', envFile) {
|
||||
this.directory = directory
|
||||
this.envFile = envFile || findEnvFiles(directory)
|
||||
|
||||
this.exampleFilename = '.env.example'
|
||||
this.exampleFilepath = path.resolve(this.directory, this.exampleFilename)
|
||||
}
|
||||
|
||||
run () {
|
||||
if (this.envFile.length < 1) {
|
||||
throw new Errors().missingEnvFiles()
|
||||
}
|
||||
|
||||
const keys = new Set()
|
||||
const addedKeys = new Set()
|
||||
const envFilepaths = this._envFilepaths()
|
||||
/** @type {Record<string, string>} */
|
||||
const injected = {}
|
||||
/** @type {Record<string, string>} */
|
||||
const preExisted = {}
|
||||
|
||||
let exampleSrc = `# ${this.exampleFilename} - generated with dotenvx\n`
|
||||
|
||||
for (const envFilepath of envFilepaths) {
|
||||
const filepath = path.resolve(this.directory, envFilepath)
|
||||
if (!fsx.existsSync(filepath)) {
|
||||
const error = new Errors({ envFilepath, filepath }).missingEnvFile()
|
||||
error.help = `? add it with [echo "HELLO=World" > ${envFilepath}] and then run [dotenvx genexample]`
|
||||
throw error
|
||||
}
|
||||
|
||||
// get the original src
|
||||
let src = fsx.readFileX(filepath)
|
||||
const parsed = dotenvParse(src)
|
||||
for (const key in parsed) {
|
||||
// used later
|
||||
keys.add(key)
|
||||
|
||||
// once newSrc is built write it out
|
||||
src = replace(src, key, '') // empty value
|
||||
}
|
||||
|
||||
exampleSrc += `\n${src}`
|
||||
}
|
||||
|
||||
if (!fsx.existsSync(this.exampleFilepath)) {
|
||||
// it doesn't exist so just write this first generated one
|
||||
// exampleSrc - already written to from the prior loop
|
||||
for (const key of [...keys]) {
|
||||
// every key is added since it's the first time generating .env.example
|
||||
addedKeys.add(key)
|
||||
|
||||
injected[key] = ''
|
||||
}
|
||||
} else {
|
||||
// it already exists (which means the user might have it modified a way in which they prefer, so replace exampleSrc with their existing .env.example)
|
||||
exampleSrc = fsx.readFileX(this.exampleFilepath)
|
||||
|
||||
const parsed = dotenvParse(exampleSrc)
|
||||
for (const key of [...keys]) {
|
||||
if (key in parsed) {
|
||||
preExisted[key] = parsed[key]
|
||||
} else {
|
||||
exampleSrc += `${key}=''\n`
|
||||
|
||||
addedKeys.add(key)
|
||||
|
||||
injected[key] = ''
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
envExampleFile: exampleSrc,
|
||||
envFile: this.envFile,
|
||||
exampleFilepath: this.exampleFilepath,
|
||||
addedKeys: [...addedKeys],
|
||||
injected,
|
||||
preExisted
|
||||
}
|
||||
}
|
||||
|
||||
_envFilepaths () {
|
||||
if (!Array.isArray(this.envFile)) {
|
||||
return [this.envFile]
|
||||
}
|
||||
|
||||
return this.envFile
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Genexample
|
||||
59
node_modules/@dotenvx/dotenvx/src/lib/services/get.js
generated
vendored
Normal file
59
node_modules/@dotenvx/dotenvx/src/lib/services/get.js
generated
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
const Run = require('./run')
|
||||
const Errors = require('./../helpers/errors')
|
||||
|
||||
class Get {
|
||||
constructor (key, envs = [], overload = false, all = false, envKeysFilepath = null, opsOn = true) {
|
||||
this.key = key
|
||||
this.envs = envs
|
||||
this.overload = overload
|
||||
this.all = all
|
||||
this.envKeysFilepath = envKeysFilepath
|
||||
this.opsOn = opsOn
|
||||
}
|
||||
|
||||
run () {
|
||||
const processEnv = { ...process.env }
|
||||
const { processedEnvs } = new Run(this.envs, this.overload, processEnv, this.envKeysFilepath, this.opsOn).run()
|
||||
|
||||
const errors = []
|
||||
for (const processedEnv of processedEnvs) {
|
||||
for (const error of processedEnv.errors) {
|
||||
errors.push(error)
|
||||
}
|
||||
}
|
||||
|
||||
if (this.key) {
|
||||
const parsed = {}
|
||||
const value = processEnv[this.key]
|
||||
parsed[this.key] = value
|
||||
|
||||
if (value === undefined) {
|
||||
errors.push(new Errors({ key: this.key }).missingKey())
|
||||
}
|
||||
|
||||
return { parsed, errors }
|
||||
} else {
|
||||
// if user wants to return ALL envs (even prior set on machine)
|
||||
if (this.all) {
|
||||
return { parsed: processEnv, errors }
|
||||
}
|
||||
|
||||
// typical scenario - return only envs that were identified in the .env file
|
||||
// iterate over all processedEnvs.parsed and grab from processEnv
|
||||
/** @type {Record<string, string>} */
|
||||
const parsed = {}
|
||||
for (const processedEnv of processedEnvs) {
|
||||
// parsed means we saw the key in a file or --env flag. this effectively filters out any preset machine envs - while still respecting complex evaluating, expansion, and overload. in other words, the value might be the machine value because the key was displayed in a .env file
|
||||
if (processedEnv.parsed) {
|
||||
for (const key of Object.keys(processedEnv.parsed)) {
|
||||
parsed[key] = processEnv[key]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { parsed, errors }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Get
|
||||
37
node_modules/@dotenvx/dotenvx/src/lib/services/keypair.js
generated
vendored
Normal file
37
node_modules/@dotenvx/dotenvx/src/lib/services/keypair.js
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
const {
|
||||
keyNames,
|
||||
keyValues
|
||||
} = require('./../helpers/keyResolution')
|
||||
|
||||
class Keypair {
|
||||
constructor (envFile = '.env', envKeysFilepath = null, opsOn = false) {
|
||||
this.envFile = envFile
|
||||
this.envKeysFilepath = envKeysFilepath
|
||||
this.opsOn = opsOn
|
||||
}
|
||||
|
||||
run () {
|
||||
const out = {}
|
||||
|
||||
const filepaths = this._filepaths()
|
||||
for (const filepath of filepaths) {
|
||||
const { publicKeyName, privateKeyName } = keyNames(filepath)
|
||||
const { publicKeyValue, privateKeyValue } = keyValues(filepath, { keysFilepath: this.envKeysFilepath, opsOn: this.opsOn })
|
||||
|
||||
out[publicKeyName] = publicKeyValue
|
||||
out[privateKeyName] = privateKeyValue
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
_filepaths () {
|
||||
if (!Array.isArray(this.envFile)) {
|
||||
return [this.envFile]
|
||||
}
|
||||
|
||||
return this.envFile
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Keypair
|
||||
57
node_modules/@dotenvx/dotenvx/src/lib/services/ls.js
generated
vendored
Normal file
57
node_modules/@dotenvx/dotenvx/src/lib/services/ls.js
generated
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
const { fdir: Fdir } = require('fdir')
|
||||
const path = require('path')
|
||||
const picomatch = require('picomatch')
|
||||
|
||||
class Ls {
|
||||
constructor (directory = './', envFile = ['.env*'], excludeEnvFile = []) {
|
||||
this.ignore = ['node_modules/**', '.git/**']
|
||||
|
||||
this.cwd = path.resolve(directory)
|
||||
this.envFile = envFile
|
||||
this.excludeEnvFile = excludeEnvFile
|
||||
}
|
||||
|
||||
run () {
|
||||
return this._filepaths()
|
||||
}
|
||||
|
||||
_filepaths () {
|
||||
const exclude = picomatch(this._exclude())
|
||||
const include = picomatch(this._patterns(), {
|
||||
ignore: this._exclude()
|
||||
})
|
||||
|
||||
return new Fdir()
|
||||
.withRelativePaths()
|
||||
.exclude((dir, path) => exclude(path))
|
||||
.filter((path) => include(path))
|
||||
.crawl(this.cwd)
|
||||
.sync()
|
||||
}
|
||||
|
||||
_patterns () {
|
||||
if (!Array.isArray(this.envFile)) {
|
||||
return [`**/${this.envFile}`]
|
||||
}
|
||||
|
||||
return this.envFile.map(part => `**/${part}`)
|
||||
}
|
||||
|
||||
_excludePatterns () {
|
||||
if (!Array.isArray(this.excludeEnvFile)) {
|
||||
return [`**/${this.excludeEnvFile}`]
|
||||
}
|
||||
|
||||
return this.excludeEnvFile.map(part => `**/${part}`)
|
||||
}
|
||||
|
||||
_exclude () {
|
||||
if (this._excludePatterns().length > 0) {
|
||||
return this.ignore.concat(this._excludePatterns())
|
||||
} else {
|
||||
return this.ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Ls
|
||||
91
node_modules/@dotenvx/dotenvx/src/lib/services/prebuild.js
generated
vendored
Normal file
91
node_modules/@dotenvx/dotenvx/src/lib/services/prebuild.js
generated
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
/* istanbul ignore file */
|
||||
const fsx = require('./../helpers/fsx')
|
||||
const path = require('path')
|
||||
const ignore = require('ignore')
|
||||
|
||||
const Ls = require('../services/ls')
|
||||
const Errors = require('../helpers/errors')
|
||||
|
||||
const isFullyEncrypted = require('./../helpers/isFullyEncrypted')
|
||||
const packageJson = require('./../helpers/packageJson')
|
||||
const MISSING_DOCKERIGNORE = '.env.keys' // by default only ignore .env.keys. all other .env* files COULD be included - as long as they are encrypted
|
||||
|
||||
class Prebuild {
|
||||
constructor (directory = './') {
|
||||
// args
|
||||
this.directory = directory
|
||||
|
||||
this.excludeEnvFile = ['test/**', 'tests/**', 'spec/**', 'specs/**', 'pytest/**', 'test_suite/**']
|
||||
}
|
||||
|
||||
run () {
|
||||
let count = 0
|
||||
const warnings = []
|
||||
let dockerignore = MISSING_DOCKERIGNORE
|
||||
|
||||
// 1. check for .dockerignore file
|
||||
if (!fsx.existsSync('.dockerignore')) {
|
||||
const warning = new Errors({
|
||||
message: `[dotenvx@${packageJson.version}][prebuild] .dockerignore missing`,
|
||||
help: 'fix: [touch .dockerignore]'
|
||||
}).custom()
|
||||
warnings.push(warning)
|
||||
} else {
|
||||
dockerignore = fsx.readFileX('.dockerignore')
|
||||
}
|
||||
|
||||
// 2. check .env* files against .dockerignore file
|
||||
const ig = ignore().add(dockerignore)
|
||||
const lsService = new Ls(this.directory, undefined, this.excludeEnvFile)
|
||||
const dotenvFiles = lsService.run()
|
||||
dotenvFiles.forEach(_file => {
|
||||
count += 1
|
||||
|
||||
const file = path.join(this.directory, _file) // to handle when directory argument passed
|
||||
|
||||
// check if that file is being ignored
|
||||
if (ig.ignores(file)) {
|
||||
if (file === '.env.example' || file === '.env.x') {
|
||||
const warning = new Errors({
|
||||
message: `[dotenvx@${packageJson.version}][prebuild] ${file} (currently ignored but should not be)`,
|
||||
help: `fix: [dotenvx ext gitignore --pattern !${file}]`
|
||||
}).custom()
|
||||
warnings.push(warning)
|
||||
}
|
||||
} else {
|
||||
if (file !== '.env.example' && file !== '.env.x') {
|
||||
const src = fsx.readFileX(file)
|
||||
const encrypted = isFullyEncrypted(src)
|
||||
|
||||
// if contents are encrypted don't raise an error
|
||||
if (!encrypted) {
|
||||
let errorMsg = `[dotenvx@${packageJson.version}][prebuild] ${file} not protected (encrypted or dockerignored)`
|
||||
let errorHelp = `fix: [dotenvx encrypt -f ${file}] or [dotenvx ext gitignore --pattern ${file}]`
|
||||
if (file.includes('.env.keys')) {
|
||||
errorMsg = `[dotenvx@${packageJson.version}][prebuild] ${file} not protected (dockerignored)`
|
||||
errorHelp = `fix: [dotenvx ext gitignore --pattern ${file}]`
|
||||
}
|
||||
|
||||
throw new Errors({ message: errorMsg, help: errorHelp }).custom()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
let successMessage = `[dotenvx@${packageJson.version}][prebuild] .env files (${count}) protected (encrypted or dockerignored)`
|
||||
|
||||
if (count === 0) {
|
||||
successMessage = `[dotenvx@${packageJson.version}][prebuild] zero .env files`
|
||||
}
|
||||
if (warnings.length > 0) {
|
||||
successMessage += ` with warnings (${warnings.length})`
|
||||
}
|
||||
|
||||
return {
|
||||
successMessage,
|
||||
warnings
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Prebuild
|
||||
137
node_modules/@dotenvx/dotenvx/src/lib/services/precommit.js
generated
vendored
Normal file
137
node_modules/@dotenvx/dotenvx/src/lib/services/precommit.js
generated
vendored
Normal file
@@ -0,0 +1,137 @@
|
||||
/* istanbul ignore file */
|
||||
const fsx = require('./../helpers/fsx')
|
||||
const path = require('path')
|
||||
const ignore = require('ignore')
|
||||
|
||||
const Ls = require('../services/ls')
|
||||
|
||||
const isFullyEncrypted = require('./../helpers/isFullyEncrypted')
|
||||
const packageJson = require('./../helpers/packageJson')
|
||||
const InstallPrecommitHook = require('./../helpers/installPrecommitHook')
|
||||
const Errors = require('./../helpers/errors')
|
||||
const childProcess = require('child_process')
|
||||
const MISSING_GITIGNORE = '.env.keys' // by default only ignore .env.keys. all other .env* files COULD be included - as long as they are encrypted
|
||||
|
||||
class Precommit {
|
||||
constructor (directory = './', options = {}) {
|
||||
// args
|
||||
this.directory = directory
|
||||
// options
|
||||
this.install = options.install
|
||||
this.excludeEnvFile = ['test/**', 'tests/**', 'spec/**', 'specs/**', 'pytest/**', 'test_suite/**']
|
||||
}
|
||||
|
||||
run () {
|
||||
if (this.install) {
|
||||
const {
|
||||
successMessage
|
||||
} = this._installPrecommitHook()
|
||||
|
||||
return {
|
||||
successMessage,
|
||||
warnings: []
|
||||
}
|
||||
} else {
|
||||
let count = 0
|
||||
const warnings = []
|
||||
let gitignore = MISSING_GITIGNORE
|
||||
|
||||
// 1. check for .gitignore file
|
||||
if (!fsx.existsSync('.gitignore')) {
|
||||
const warning = new Errors({
|
||||
message: `[dotenvx@${packageJson.version}][precommit] .gitignore missing`,
|
||||
help: 'fix: [touch .gitignore]'
|
||||
}).custom()
|
||||
warnings.push(warning)
|
||||
} else {
|
||||
gitignore = fsx.readFileX('.gitignore')
|
||||
}
|
||||
|
||||
// 2. check .env* files against .gitignore file
|
||||
const ig = ignore().add(gitignore)
|
||||
|
||||
const lsService = new Ls(this.directory, undefined, this.excludeEnvFile)
|
||||
const dotenvFiles = lsService.run()
|
||||
dotenvFiles.forEach(_file => {
|
||||
count += 1
|
||||
|
||||
const file = path.join(this.directory, _file) // to handle when directory argument passed
|
||||
|
||||
// check if file is going to be committed
|
||||
if (this._isFileToBeCommitted(file)) {
|
||||
// check if that file is being ignored
|
||||
if (ig.ignores(file)) {
|
||||
if (file === '.env.example' || file === '.env.x') {
|
||||
const warning = new Errors({
|
||||
message: `[dotenvx@${packageJson.version}][precommit] ${file} (currently ignored but should not be)`,
|
||||
help: `fix: [dotenvx ext gitignore --pattern !${file}]`
|
||||
}).custom()
|
||||
warnings.push(warning)
|
||||
}
|
||||
} else {
|
||||
if (file !== '.env.example' && file !== '.env.x') {
|
||||
const src = fsx.readFileX(file)
|
||||
const encrypted = isFullyEncrypted(src)
|
||||
|
||||
// if contents are encrypted don't raise an error
|
||||
if (!encrypted) {
|
||||
let errorMsg = `[dotenvx@${packageJson.version}][precommit] ${file} not protected (encrypted or gitignored)`
|
||||
let errorHelp = `fix: [dotenvx encrypt -f ${file}] or [dotenvx ext gitignore --pattern ${file}]`
|
||||
if (file.includes('.env.keys')) {
|
||||
errorMsg = `[dotenvx@${packageJson.version}][precommit] ${file} not protected (gitignored)`
|
||||
errorHelp = `fix: [dotenvx ext gitignore --pattern ${file}]`
|
||||
}
|
||||
|
||||
throw new Errors({ message: errorMsg, help: errorHelp }).custom()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
let successMessage = `[dotenvx@${packageJson.version}][precommit] .env files (${count}) protected (encrypted or gitignored)`
|
||||
if (count === 0) {
|
||||
successMessage = `[dotenvx@${packageJson.version}][precommit] zero .env files`
|
||||
}
|
||||
if (warnings.length > 0) {
|
||||
successMessage += ` with warnings (${warnings.length})`
|
||||
}
|
||||
|
||||
return {
|
||||
successMessage,
|
||||
warnings
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_isInGitRepo () {
|
||||
try {
|
||||
childProcess.execSync('git rev-parse --is-inside-work-tree', { stdio: 'ignore' })
|
||||
return true
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
_isFileToBeCommitted (filePath) {
|
||||
try {
|
||||
if (!this._isInGitRepo()) {
|
||||
// consider file to be committed if there is an error (not a git repo)
|
||||
return true
|
||||
}
|
||||
|
||||
const output = childProcess.execSync('git diff HEAD --name-only').toString()
|
||||
const files = output.split('\n')
|
||||
return files.includes(filePath)
|
||||
} catch (error) {
|
||||
// consider file to be committed if there is an error (not using git)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
_installPrecommitHook () {
|
||||
return new InstallPrecommitHook().run()
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Precommit
|
||||
184
node_modules/@dotenvx/dotenvx/src/lib/services/rotate.js
generated
vendored
Normal file
184
node_modules/@dotenvx/dotenvx/src/lib/services/rotate.js
generated
vendored
Normal file
@@ -0,0 +1,184 @@
|
||||
const fsx = require('./../helpers/fsx')
|
||||
const path = require('path')
|
||||
const picomatch = require('picomatch')
|
||||
|
||||
const TYPE_ENV_FILE = 'envFile'
|
||||
|
||||
const Errors = require('./../helpers/errors')
|
||||
|
||||
const {
|
||||
determine
|
||||
} = require('./../helpers/envResolution')
|
||||
|
||||
const {
|
||||
keyNames,
|
||||
keyValues
|
||||
} = require('./../helpers/keyResolution')
|
||||
|
||||
const {
|
||||
opsKeypair,
|
||||
localKeypair,
|
||||
encryptValue,
|
||||
decryptKeyValue,
|
||||
isEncrypted
|
||||
} = require('./../helpers/cryptography')
|
||||
|
||||
const append = require('./../helpers/append')
|
||||
const replace = require('./../helpers/replace')
|
||||
const dotenvParse = require('./../helpers/dotenvParse')
|
||||
const detectEncoding = require('./../helpers/detectEncoding')
|
||||
|
||||
class Rotate {
|
||||
constructor (envs = [], key = [], excludeKey = [], envKeysFilepath = null, opsOn = false) {
|
||||
this.envs = determine(envs, process.env)
|
||||
this.key = key
|
||||
this.excludeKey = excludeKey
|
||||
this.envKeysFilepath = envKeysFilepath
|
||||
this.opsOn = opsOn
|
||||
|
||||
this.processedEnvs = []
|
||||
this.changedFilepaths = new Set()
|
||||
this.unchangedFilepaths = new Set()
|
||||
|
||||
this.envKeysSources = {}
|
||||
}
|
||||
|
||||
run () {
|
||||
// example
|
||||
// envs [
|
||||
// { type: 'envFile', value: '.env' }
|
||||
// ]
|
||||
|
||||
this.keys = this._keys()
|
||||
const excludeKeys = this._excludeKeys()
|
||||
|
||||
this.exclude = picomatch(excludeKeys)
|
||||
this.include = picomatch(this.keys, { ignore: excludeKeys })
|
||||
|
||||
for (const env of this.envs) {
|
||||
if (env.type === TYPE_ENV_FILE) {
|
||||
this._rotateEnvFile(env.value)
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
processedEnvs: this.processedEnvs,
|
||||
changedFilepaths: [...this.changedFilepaths],
|
||||
unchangedFilepaths: [...this.unchangedFilepaths]
|
||||
}
|
||||
}
|
||||
|
||||
_rotateEnvFile (envFilepath) {
|
||||
const row = {}
|
||||
row.keys = []
|
||||
row.type = TYPE_ENV_FILE
|
||||
|
||||
const filepath = path.resolve(envFilepath)
|
||||
row.filepath = filepath
|
||||
row.envFilepath = envFilepath
|
||||
|
||||
try {
|
||||
const encoding = detectEncoding(filepath)
|
||||
let envSrc = fsx.readFileX(filepath, { encoding })
|
||||
const envParsed = dotenvParse(envSrc)
|
||||
|
||||
const { publicKeyName, privateKeyName } = keyNames(envFilepath)
|
||||
const { privateKeyValue } = keyValues(envFilepath, { keysFilepath: this.envKeysFilepath, opsOn: this.opsOn })
|
||||
|
||||
let newPublicKey
|
||||
let newPrivateKey
|
||||
let envKeysFilepath
|
||||
let envKeysSrc
|
||||
|
||||
if (this.opsOn) {
|
||||
const kp = opsKeypair()
|
||||
newPublicKey = kp.publicKey
|
||||
newPrivateKey = kp.privateKey
|
||||
|
||||
row.privateKeyAdded = false // TODO: change to localPrivateKeyAdded
|
||||
} else {
|
||||
envKeysFilepath = path.join(path.dirname(filepath), '.env.keys')
|
||||
if (this.envKeysFilepath) {
|
||||
envKeysFilepath = path.resolve(this.envKeysFilepath)
|
||||
}
|
||||
row.envKeysFilepath = envKeysFilepath
|
||||
this.envKeysSources[envKeysFilepath] ||= fsx.readFileX(envKeysFilepath, { encoding: detectEncoding(envKeysFilepath) })
|
||||
envKeysSrc = this.envKeysSources[envKeysFilepath]
|
||||
|
||||
const kp = localKeypair()
|
||||
newPublicKey = kp.publicKey
|
||||
newPrivateKey = kp.privateKey
|
||||
|
||||
row.privateKeyAdded = true
|
||||
}
|
||||
|
||||
// .env
|
||||
envSrc = replace(envSrc, publicKeyName, newPublicKey) // replace publicKey
|
||||
row.changed = true // track change
|
||||
|
||||
for (const [key, value] of Object.entries(envParsed)) { // re-encrypt each individual key
|
||||
// key excluded - don't re-encrypt it
|
||||
if (this.exclude(key)) {
|
||||
continue
|
||||
}
|
||||
|
||||
// key effectively excluded (by not being in the list of includes) - don't re-encrypt it
|
||||
if (this.keys.length > 0 && !this.include(key)) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (isEncrypted(value)) { // only re-encrypt those already encrypted
|
||||
row.keys.push(key) // track key(s)
|
||||
|
||||
const decryptedValue = decryptKeyValue(key, value, privateKeyName, privateKeyValue) // get decrypted value
|
||||
let encryptedValue
|
||||
try {
|
||||
encryptedValue = encryptValue(decryptedValue, newPublicKey) // encrypt with the new publicKey
|
||||
} catch {
|
||||
throw new Errors({ publicKeyName, publicKey: newPublicKey }).invalidPublicKey()
|
||||
}
|
||||
|
||||
envSrc = replace(envSrc, key, encryptedValue)
|
||||
}
|
||||
}
|
||||
row.envSrc = envSrc
|
||||
row.privateKeyName = privateKeyName
|
||||
row.privateKey = newPrivateKey
|
||||
|
||||
if (!this.opsOn) {
|
||||
// keys src only for ops
|
||||
envKeysSrc = append(envKeysSrc, privateKeyName, newPrivateKey) // append privateKey
|
||||
this.envKeysSources[envKeysFilepath] = envKeysSrc
|
||||
row.envKeysSrc = envKeysSrc
|
||||
}
|
||||
|
||||
this.changedFilepaths.add(envFilepath)
|
||||
} catch (e) {
|
||||
if (e.code === 'ENOENT') {
|
||||
row.error = new Errors({ envFilepath, filepath }).missingEnvFile()
|
||||
} else {
|
||||
row.error = e
|
||||
}
|
||||
}
|
||||
|
||||
this.processedEnvs.push(row)
|
||||
}
|
||||
|
||||
_keys () {
|
||||
if (!Array.isArray(this.key)) {
|
||||
return [this.key]
|
||||
}
|
||||
|
||||
return this.key
|
||||
}
|
||||
|
||||
_excludeKeys () {
|
||||
if (!Array.isArray(this.excludeKey)) {
|
||||
return [this.excludeKey]
|
||||
}
|
||||
|
||||
return this.excludeKey
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Rotate
|
||||
145
node_modules/@dotenvx/dotenvx/src/lib/services/run.js
generated
vendored
Normal file
145
node_modules/@dotenvx/dotenvx/src/lib/services/run.js
generated
vendored
Normal file
@@ -0,0 +1,145 @@
|
||||
const fsx = require('./../helpers/fsx')
|
||||
const path = require('path')
|
||||
|
||||
const TYPE_ENV = 'env'
|
||||
const TYPE_ENV_FILE = 'envFile'
|
||||
|
||||
const Parse = require('./../helpers/parse')
|
||||
const Errors = require('./../helpers/errors')
|
||||
const detectEncoding = require('./../helpers/detectEncoding')
|
||||
|
||||
const {
|
||||
keyNames,
|
||||
keyValues
|
||||
} = require('./../helpers/keyResolution')
|
||||
|
||||
const {
|
||||
determine
|
||||
} = require('./../helpers/envResolution')
|
||||
|
||||
class Run {
|
||||
constructor (envs = [], overload = false, processEnv = process.env, envKeysFilepath = null, opsOn = false) {
|
||||
this.envs = determine(envs, processEnv)
|
||||
this.overload = overload
|
||||
this.processEnv = processEnv
|
||||
this.envKeysFilepath = envKeysFilepath
|
||||
this.opsOn = opsOn
|
||||
|
||||
this.processedEnvs = []
|
||||
this.readableFilepaths = new Set()
|
||||
this.readableStrings = new Set()
|
||||
this.uniqueInjectedKeys = new Set()
|
||||
this.beforeEnv = { ...this.processEnv }
|
||||
}
|
||||
|
||||
run () {
|
||||
// example
|
||||
// envs [
|
||||
// { type: 'env', value: 'HELLO=one' },
|
||||
// { type: 'envFile', value: '.env' },
|
||||
// { type: 'env', value: 'HELLO=three' }
|
||||
// ]
|
||||
|
||||
for (const env of this.envs) {
|
||||
if (env.type === TYPE_ENV_FILE) {
|
||||
this._injectEnvFile(env.value)
|
||||
} else if (env.type === TYPE_ENV) {
|
||||
this._injectEnv(env.value)
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
processedEnvs: this.processedEnvs,
|
||||
readableStrings: [...this.readableStrings],
|
||||
readableFilepaths: [...this.readableFilepaths],
|
||||
uniqueInjectedKeys: [...this.uniqueInjectedKeys],
|
||||
beforeEnv: this.beforeEnv,
|
||||
afterEnv: { ...this.processEnv }
|
||||
}
|
||||
}
|
||||
|
||||
_injectEnv (env) {
|
||||
const row = {}
|
||||
row.type = TYPE_ENV
|
||||
row.string = env
|
||||
|
||||
try {
|
||||
const {
|
||||
parsed,
|
||||
errors,
|
||||
injected,
|
||||
preExisted
|
||||
} = new Parse(env, null, this.processEnv, this.overload).run()
|
||||
|
||||
row.parsed = parsed
|
||||
row.errors = errors
|
||||
row.injected = injected
|
||||
row.preExisted = preExisted
|
||||
|
||||
this.inject(row.parsed) // inject
|
||||
|
||||
this.readableStrings.add(env)
|
||||
|
||||
for (const key of Object.keys(injected)) {
|
||||
this.uniqueInjectedKeys.add(key) // track uniqueInjectedKeys across multiple files
|
||||
}
|
||||
} catch (e) {
|
||||
row.errors = [e]
|
||||
}
|
||||
|
||||
this.processedEnvs.push(row)
|
||||
}
|
||||
|
||||
_injectEnvFile (envFilepath) {
|
||||
const row = {}
|
||||
row.type = TYPE_ENV_FILE
|
||||
row.filepath = envFilepath
|
||||
|
||||
const filepath = path.resolve(envFilepath)
|
||||
try {
|
||||
const encoding = detectEncoding(filepath)
|
||||
const src = fsx.readFileX(filepath, { encoding })
|
||||
this.readableFilepaths.add(envFilepath)
|
||||
|
||||
const { privateKeyName } = keyNames(filepath)
|
||||
const { privateKeyValue } = keyValues(filepath, { keysFilepath: this.envKeysFilepath, opsOn: this.opsOn })
|
||||
|
||||
const {
|
||||
parsed,
|
||||
errors,
|
||||
injected,
|
||||
preExisted
|
||||
} = new Parse(src, privateKeyValue, this.processEnv, this.overload, privateKeyName).run()
|
||||
|
||||
row.privateKeyName = privateKeyName
|
||||
row.privateKey = privateKeyValue
|
||||
row.src = src
|
||||
row.parsed = parsed
|
||||
row.errors = errors
|
||||
row.injected = injected
|
||||
row.preExisted = preExisted
|
||||
|
||||
this.inject(row.parsed) // inject
|
||||
|
||||
for (const key of Object.keys(injected)) {
|
||||
this.uniqueInjectedKeys.add(key) // track uniqueInjectedKeys across multiple files
|
||||
}
|
||||
} catch (e) {
|
||||
if (e.code === 'ENOENT' || e.code === 'EISDIR') {
|
||||
row.errors = [new Errors({ envFilepath, filepath }).missingEnvFile()]
|
||||
} else {
|
||||
row.errors = [e]
|
||||
}
|
||||
}
|
||||
|
||||
this.processedEnvs.push(row)
|
||||
}
|
||||
|
||||
inject (parsed) {
|
||||
for (const key of Object.keys(parsed)) {
|
||||
this.processEnv[key] = parsed[key] // inject to process.env
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Run
|
||||
143
node_modules/@dotenvx/dotenvx/src/lib/services/sets.js
generated
vendored
Normal file
143
node_modules/@dotenvx/dotenvx/src/lib/services/sets.js
generated
vendored
Normal file
@@ -0,0 +1,143 @@
|
||||
const fsx = require('./../helpers/fsx')
|
||||
const path = require('path')
|
||||
|
||||
const TYPE_ENV_FILE = 'envFile'
|
||||
|
||||
const Errors = require('./../helpers/errors')
|
||||
|
||||
const {
|
||||
determine
|
||||
} = require('./../helpers/envResolution')
|
||||
|
||||
const {
|
||||
keyNames,
|
||||
keyValues
|
||||
} = require('./../helpers/keyResolution')
|
||||
|
||||
const {
|
||||
encryptValue,
|
||||
decryptKeyValue,
|
||||
isEncrypted,
|
||||
provision,
|
||||
provisionWithPrivateKey
|
||||
} = require('./../helpers/cryptography')
|
||||
|
||||
const replace = require('./../helpers/replace')
|
||||
const dotenvParse = require('./../helpers/dotenvParse')
|
||||
const detectEncoding = require('./../helpers/detectEncoding')
|
||||
|
||||
class Sets {
|
||||
constructor (key, value, envs = [], encrypt = true, envKeysFilepath = null, opsOn = false) {
|
||||
this.envs = determine(envs, process.env)
|
||||
this.key = key
|
||||
this.value = value
|
||||
this.encrypt = encrypt
|
||||
this.envKeysFilepath = envKeysFilepath
|
||||
this.opsOn = opsOn
|
||||
|
||||
this.processedEnvs = []
|
||||
this.changedFilepaths = new Set()
|
||||
this.unchangedFilepaths = new Set()
|
||||
this.readableFilepaths = new Set()
|
||||
}
|
||||
|
||||
run () {
|
||||
// example
|
||||
// envs [
|
||||
// { type: 'envFile', value: '.env' }
|
||||
// ]
|
||||
|
||||
for (const env of this.envs) {
|
||||
if (env.type === TYPE_ENV_FILE) {
|
||||
this._setEnvFile(env.value)
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
processedEnvs: this.processedEnvs,
|
||||
changedFilepaths: [...this.changedFilepaths],
|
||||
unchangedFilepaths: [...this.unchangedFilepaths]
|
||||
}
|
||||
}
|
||||
|
||||
_setEnvFile (envFilepath) {
|
||||
const row = {}
|
||||
row.key = this.key || null
|
||||
row.value = this.value || null
|
||||
row.type = TYPE_ENV_FILE
|
||||
|
||||
const filepath = path.resolve(envFilepath)
|
||||
row.filepath = filepath
|
||||
row.envFilepath = envFilepath
|
||||
row.changed = false
|
||||
|
||||
try {
|
||||
const encoding = detectEncoding(filepath)
|
||||
let envSrc = fsx.readFileX(filepath, { encoding })
|
||||
const envParsed = dotenvParse(envSrc)
|
||||
row.originalValue = envParsed[row.key] || null
|
||||
const wasPlainText = !isEncrypted(row.originalValue)
|
||||
this.readableFilepaths.add(envFilepath)
|
||||
|
||||
if (this.encrypt) {
|
||||
let publicKey
|
||||
let privateKey
|
||||
|
||||
const { publicKeyName, privateKeyName } = keyNames(filepath)
|
||||
const { publicKeyValue, privateKeyValue } = keyValues(filepath, { keysFilepath: this.envKeysFilepath, opsOn: this.opsOn })
|
||||
|
||||
// first pass - provision
|
||||
if (!privateKeyValue && !publicKeyValue) {
|
||||
const prov = provision({ envSrc, envFilepath, keysFilepath: this.envKeysFilepath, opsOn: this.opsOn })
|
||||
envSrc = prov.envSrc
|
||||
publicKey = prov.publicKey
|
||||
privateKey = prov.privateKey
|
||||
row.privateKeyAdded = prov.privateKeyAdded
|
||||
row.envKeysFilepath = prov.envKeysFilepath
|
||||
} else if (privateKeyValue) {
|
||||
const prov = provisionWithPrivateKey({ envSrc, envFilepath, keysFilepath: this.envKeysFilepath, privateKeyValue, publicKeyValue, publicKeyName })
|
||||
publicKey = prov.publicKey
|
||||
privateKey = prov.privateKey
|
||||
envSrc = prov.envSrc
|
||||
|
||||
if (row.originalValue) {
|
||||
row.originalValue = decryptKeyValue(row.key, row.originalValue, privateKeyName, privateKey)
|
||||
}
|
||||
} else if (publicKeyValue) {
|
||||
publicKey = publicKeyValue
|
||||
}
|
||||
|
||||
row.publicKey = publicKey
|
||||
row.privateKey = privateKey
|
||||
try {
|
||||
row.encryptedValue = encryptValue(this.value, publicKey)
|
||||
} catch {
|
||||
throw new Errors({ publicKeyName, publicKey }).invalidPublicKey()
|
||||
}
|
||||
row.privateKeyName = privateKeyName
|
||||
}
|
||||
|
||||
const goingFromPlainTextToEncrypted = wasPlainText && this.encrypt
|
||||
const valueChanged = this.value !== row.originalValue
|
||||
if (goingFromPlainTextToEncrypted || valueChanged) {
|
||||
row.envSrc = replace(envSrc, this.key, row.encryptedValue || this.value)
|
||||
this.changedFilepaths.add(envFilepath)
|
||||
row.changed = true
|
||||
} else {
|
||||
row.envSrc = envSrc
|
||||
this.unchangedFilepaths.add(envFilepath)
|
||||
row.changed = false
|
||||
}
|
||||
} catch (e) {
|
||||
if (e.code === 'ENOENT') {
|
||||
row.error = new Errors({ envFilepath, filepath }).missingEnvFile()
|
||||
} else {
|
||||
row.error = e
|
||||
}
|
||||
}
|
||||
|
||||
this.processedEnvs.push(row)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Sets
|
||||
67
node_modules/@dotenvx/dotenvx/src/shared/colors.js
generated
vendored
Normal file
67
node_modules/@dotenvx/dotenvx/src/shared/colors.js
generated
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
const depth = require('../lib/helpers/colorDepth')
|
||||
const Errors = require('../lib/helpers/errors')
|
||||
|
||||
const colors16 = new Map([
|
||||
['amber', 33],
|
||||
['blue', 34],
|
||||
['gray', 37],
|
||||
['green', 32],
|
||||
['olive', 33],
|
||||
['orangered', 33], // mapped to yellow/brown
|
||||
['plum', 35], // mapped to magenta
|
||||
['red', 31],
|
||||
['electricblue', 36],
|
||||
['dodgerblue', 36]
|
||||
])
|
||||
|
||||
const colors256 = new Map([
|
||||
['amber', 136],
|
||||
['blue', 21],
|
||||
['gray', 244],
|
||||
['green', 34],
|
||||
['olive', 142],
|
||||
['orangered', 130], // burnished copper
|
||||
['plum', 182],
|
||||
['red', 124], // brighter garnet
|
||||
['electricblue', 45],
|
||||
['dodgerblue', 33]
|
||||
])
|
||||
|
||||
const colorsTrueColor = new Map([
|
||||
['amber', [236, 213, 63]],
|
||||
['orangered', [138, 90, 43]], // #8A5A2B burnished copper
|
||||
['red', [140, 35, 50]] // #8C2332 brighter garnet
|
||||
])
|
||||
|
||||
function getColor (color) {
|
||||
const colorDepth = depth.getColorDepth()
|
||||
if (!colors256.has(color)) {
|
||||
throw new Errors({ color }).invalidColor()
|
||||
}
|
||||
if (colorDepth >= 24 && colorsTrueColor.has(color)) {
|
||||
const [r, g, b] = colorsTrueColor.get(color)
|
||||
return (message) => `\x1b[38;2;${r};${g};${b}m${message}\x1b[39m`
|
||||
}
|
||||
if (colorDepth >= 8) {
|
||||
const code = colors256.get(color)
|
||||
return (message) => `\x1b[38;5;${code}m${message}\x1b[39m`
|
||||
}
|
||||
if (colorDepth >= 4) {
|
||||
const code = colors16.get(color)
|
||||
return (message) => `\x1b[${code}m${message}\x1b[39m`
|
||||
}
|
||||
return (message) => message
|
||||
}
|
||||
|
||||
function bold (message) {
|
||||
if (depth.getColorDepth() >= 4) {
|
||||
return `\x1b[1m${message}\x1b[22m`
|
||||
}
|
||||
|
||||
return message
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getColor,
|
||||
bold
|
||||
}
|
||||
147
node_modules/@dotenvx/dotenvx/src/shared/logger.js
generated
vendored
Normal file
147
node_modules/@dotenvx/dotenvx/src/shared/logger.js
generated
vendored
Normal file
@@ -0,0 +1,147 @@
|
||||
const packageJson = require('../lib/helpers/packageJson')
|
||||
const Errors = require('../lib/helpers/errors')
|
||||
const { getColor, bold } = require('./colors')
|
||||
|
||||
const levels = {
|
||||
error: 0,
|
||||
warn: 1,
|
||||
success: 2,
|
||||
successv: 2,
|
||||
info: 2,
|
||||
help: 2,
|
||||
verbose: 4,
|
||||
debug: 5,
|
||||
silly: 6
|
||||
}
|
||||
|
||||
const error = (m) => bold(getColor('red')(`☠ ${m}`))
|
||||
const warn = (m) => getColor('orangered')(`⚠ ${m}`)
|
||||
const success = getColor('amber')
|
||||
const successv = getColor('amber')
|
||||
const info = getColor('gray')
|
||||
const help = getColor('dodgerblue')
|
||||
const verbose = getColor('plum')
|
||||
const debug = getColor('plum')
|
||||
|
||||
let currentLevel = levels.info // default log level
|
||||
let currentName = 'dotenvx' // default logger name
|
||||
let currentVersion = packageJson.version // default logger version
|
||||
|
||||
function stderr (level, message) {
|
||||
const formattedMessage = formatMessage(level, message)
|
||||
console.error(formattedMessage)
|
||||
}
|
||||
|
||||
function stdout (level, message) {
|
||||
if (levels[level] === undefined) {
|
||||
throw new Errors({ level }).missingLogLevel()
|
||||
}
|
||||
|
||||
if (levels[level] <= currentLevel) {
|
||||
const formattedMessage = formatMessage(level, message)
|
||||
console.log(formattedMessage)
|
||||
}
|
||||
}
|
||||
|
||||
function formatMessage (level, message) {
|
||||
const formattedMessage = typeof message === 'object' ? JSON.stringify(message) : message
|
||||
|
||||
switch (level.toLowerCase()) {
|
||||
// errors
|
||||
case 'error':
|
||||
return error(formattedMessage)
|
||||
// warns
|
||||
case 'warn':
|
||||
return warn(formattedMessage)
|
||||
// successes
|
||||
case 'success':
|
||||
return success(formattedMessage)
|
||||
case 'successv': // success with 'version'
|
||||
return successv(`[${currentName}@${currentVersion}] ${formattedMessage}`)
|
||||
// info
|
||||
case 'info':
|
||||
return info(formattedMessage)
|
||||
// help
|
||||
case 'help':
|
||||
return help(formattedMessage)
|
||||
// verbose
|
||||
case 'verbose':
|
||||
return verbose(formattedMessage)
|
||||
// debug
|
||||
case 'debug':
|
||||
return debug(formattedMessage)
|
||||
}
|
||||
}
|
||||
|
||||
const logger = {
|
||||
// track level
|
||||
level: 'info',
|
||||
|
||||
// errors
|
||||
error: (msg) => stderr('error', msg),
|
||||
// warns
|
||||
warn: (msg) => stdout('warn', msg),
|
||||
// success
|
||||
success: (msg) => stdout('success', msg),
|
||||
successv: (msg) => stdout('successv', msg),
|
||||
// info
|
||||
info: (msg) => stdout('info', msg),
|
||||
// help
|
||||
help: (msg) => stdout('help', msg),
|
||||
// verbose
|
||||
verbose: (msg) => stdout('verbose', msg),
|
||||
// debug
|
||||
debug: (msg) => stdout('debug', msg),
|
||||
setLevel: (level) => {
|
||||
if (levels[level] !== undefined) {
|
||||
currentLevel = levels[level]
|
||||
logger.level = level
|
||||
}
|
||||
},
|
||||
setName: (name) => {
|
||||
currentName = name
|
||||
logger.name = name
|
||||
},
|
||||
setVersion: (version) => {
|
||||
currentVersion = version
|
||||
logger.version = version
|
||||
}
|
||||
}
|
||||
|
||||
function setLogLevel (options) {
|
||||
const logLevel = options.debug
|
||||
? 'debug'
|
||||
: options.verbose
|
||||
? 'verbose'
|
||||
: options.quiet
|
||||
? 'error'
|
||||
: options.logLevel
|
||||
|
||||
if (!logLevel) return
|
||||
logger.setLevel(logLevel)
|
||||
// Only log which level it's setting if it's not set to quiet mode
|
||||
if (!options.quiet || (options.quiet && logLevel !== 'error')) {
|
||||
logger.debug(`Setting log level to ${logLevel}`)
|
||||
}
|
||||
}
|
||||
|
||||
function setLogName (options) {
|
||||
const logName = options.logName
|
||||
if (!logName) return
|
||||
logger.setName(logName)
|
||||
}
|
||||
|
||||
function setLogVersion (options) {
|
||||
const logVersion = options.logVersion
|
||||
if (!logVersion) return
|
||||
logger.setVersion(logVersion)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
logger,
|
||||
getColor,
|
||||
setLogLevel,
|
||||
setLogName,
|
||||
setLogVersion,
|
||||
levels
|
||||
}
|
||||
Reference in New Issue
Block a user