Some type updates and an improvement to encryption to allow selecting the secret from an option list.

This commit is contained in:
mike12345567 2023-01-16 18:15:43 +00:00
parent 5e68a4d814
commit c645a9bc21
3 changed files with 39 additions and 5 deletions

View File

@ -37,6 +37,7 @@ const environment = {
}, },
JS_BCRYPT: process.env.JS_BCRYPT, JS_BCRYPT: process.env.JS_BCRYPT,
JWT_SECRET: process.env.JWT_SECRET, JWT_SECRET: process.env.JWT_SECRET,
ENCRYPTION_KEY: process.env.ENCRYPTION_KEY,
COUCH_DB_URL: process.env.COUCH_DB_URL || "http://localhost:4005", COUCH_DB_URL: process.env.COUCH_DB_URL || "http://localhost:4005",
COUCH_DB_USERNAME: process.env.COUCH_DB_USER, COUCH_DB_USERNAME: process.env.COUCH_DB_USER,
COUCH_DB_PASSWORD: process.env.COUCH_DB_PASSWORD, COUCH_DB_PASSWORD: process.env.COUCH_DB_PASSWORD,

View File

@ -2,19 +2,45 @@ import crypto from "crypto"
import env from "../environment" import env from "../environment"
const ALGO = "aes-256-ctr" const ALGO = "aes-256-ctr"
const SECRET = env.JWT_SECRET
const SEPARATOR = "-" const SEPARATOR = "-"
const ITERATIONS = 10000 const ITERATIONS = 10000
const RANDOM_BYTES = 16 const RANDOM_BYTES = 16
const STRETCH_LENGTH = 32 const STRETCH_LENGTH = 32
export enum SecretOption {
JWT = "jwt",
ENCRYPTION = "encryption",
}
function getSecret(secretOption: SecretOption): string {
let secret, secretName
switch (secretOption) {
case SecretOption.ENCRYPTION:
secret = env.ENCRYPTION_KEY
secretName = "ENCRYPTION_KEY"
break
case SecretOption.JWT:
default:
secret = env.JWT_SECRET
secretName = "JWT_SECRET"
break
}
if (!secret) {
throw new Error(`Secret "${secretName}" has not been set in environment.`)
}
return secret
}
function stretchString(string: string, salt: Buffer) { function stretchString(string: string, salt: Buffer) {
return crypto.pbkdf2Sync(string, salt, ITERATIONS, STRETCH_LENGTH, "sha512") return crypto.pbkdf2Sync(string, salt, ITERATIONS, STRETCH_LENGTH, "sha512")
} }
export function encrypt(input: string, secret: string | undefined = SECRET) { export function encrypt(
input: string,
secretOption: SecretOption = SecretOption.JWT
) {
const salt = crypto.randomBytes(RANDOM_BYTES) const salt = crypto.randomBytes(RANDOM_BYTES)
const stretched = stretchString(secret!, salt) const stretched = stretchString(getSecret(secretOption), salt)
const cipher = crypto.createCipheriv(ALGO, stretched, salt) const cipher = crypto.createCipheriv(ALGO, stretched, salt)
const base = cipher.update(input) const base = cipher.update(input)
const final = cipher.final() const final = cipher.final()
@ -22,10 +48,13 @@ export function encrypt(input: string, secret: string | undefined = SECRET) {
return `${salt.toString("hex")}${SEPARATOR}${encrypted}` return `${salt.toString("hex")}${SEPARATOR}${encrypted}`
} }
export function decrypt(input: string, secret: string | undefined = SECRET) { export function decrypt(
input: string,
secretOption: SecretOption = SecretOption.JWT
) {
const [salt, encrypted] = input.split(SEPARATOR) const [salt, encrypted] = input.split(SEPARATOR)
const saltBuffer = Buffer.from(salt, "hex") const saltBuffer = Buffer.from(salt, "hex")
const stretched = stretchString(secret!, saltBuffer) const stretched = stretchString(getSecret(secretOption), saltBuffer)
const decipher = crypto.createDecipheriv(ALGO, stretched, saltBuffer) const decipher = crypto.createDecipheriv(ALGO, stretched, saltBuffer)
const base = decipher.update(Buffer.from(encrypted, "hex")) const base = decipher.update(Buffer.from(encrypted, "hex"))
const final = decipher.final() const final = decipher.final()

View File

@ -14,3 +14,7 @@ export type EnvironmentVariablesDecrypted = Record<
string, string,
EnvironmentVariableValue EnvironmentVariableValue
> >
export interface EnvironmentVariablesDocDecrypted extends Document {
variables: EnvironmentVariablesDecrypted
}