cqr-env
Version:
Have multiple env files that can be encrypted and included in version control
115 lines (94 loc) • 2.89 kB
JavaScript
/* imports */
const fs = require('fs')
const joi = require('joi')
const JSON5 = require('json5')
const path = require('path')
/* lib */
const { get, set } = require('./lib/getset')
/* modules */
const cryptor = require('./cryptor')
function loadJs (data) {
return eval(data) // eslint-disable-line no-eval
}
function loadJSON (data) {
return JSON5.parse(data)
}
function loadRaw (data) {
let lastKey
/* skip multiline comments */
data = data.replace(/<!-- (.+?\r*\n*)+ -->/gm, '')
data = data.replace(/\/\*(.+?\r*\n*)+\*\//gm, '')
return data.split(/(?:\r?\n)+/).reduce(function (r, line) {
/* skip singleline comments */
line = line.replace(/[ \t]*\/\/.*$/g, '') // this allows "x=1 // 2"
line = line.replace(/[ \t]*#.*$/g, '')
if (!line.length) return r // skip blank
const match = line.match(/[ \t]*(.+?)[ \t]*=[ \t]*(.+?)$/)
if (match) {
const [m, key, value] = match
try {
r[key] = JSON.parse(value)
} catch (e) {
r[key] = value
}
lastKey = key
} else {
r[lastKey] += '\n' + line
}
return r
}, {})
}
function load (file, name, ext, encryptedFile, envvar) {
let data
if (encryptedFile && typeof envvar == 'string') {
if (!envvar) throw new Error('Envvar not informed for encrypted env file')
data = cryptor.decryptFile(file, envvar)
} else {
data = Buffer.from(fs.readFileSync(file)).toString()
}
switch (ext) {
case '.js': data = loadJs(data); break
case '.json': data = loadJSON(data); break
default: data = { ...loadRaw(data) }
}
if (typeof envvar == 'object') {
for (const key in envvar) {
const path = key.split('.')
if (path.shift() != name) continue
set(data, path, cryptor.decrypt(get(data, path), envvar[key]))
}
}
return data
}
function getKey (options) {
if (options.envvar) {
return {
medium: 'var',
value: options.envvar
}
} else if (options.pwfile) {
return {
medium: 'file',
value: options.pwfile
}
}
}
function loader (gloob, options) {
const env = {}
for (const f of gloob) {
const encryptedFile = (f.slice(-10) == '.encrypted')
const ext = encryptedFile ? path.parse(f.replace('.env', '').replace('.encrypted', '')).ext : path.parse(f.replace('.env', '').replace('.exposed', '')).ext
const name = (typeof options.name == 'string') ? options.name : path.basename(f).split('.')[0]
if (options.name === false || ext == '') {
const newEnv = load(f, name, ext, encryptedFile, options.envvar)
if (joi.object().validate(newEnv).error) throw new Error('When "name" option is false, content must be an object')
for (const k in newEnv) {
env[k] = newEnv[k]
}
} else {
env[name] = load(f, name, ext, encryptedFile, options.envvar)
}
}
return env
}
module.exports = loader