diff options
| author | Fuwn <[email protected]> | 2026-01-24 13:09:50 +0000 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2026-01-24 13:09:50 +0000 |
| commit | 396acf3bbbe00a192cb0ea0a9ccf91b1d8d2850b (patch) | |
| tree | b9df4ca6a70db45cfffbae6fdd7252e20fb8e93c /src/lib/crypto.ts | |
| download | umami-main.tar.xz umami-main.zip | |
Created from https://vercel.com/new
Diffstat (limited to 'src/lib/crypto.ts')
| -rw-r--r-- | src/lib/crypto.ts | 65 |
1 files changed, 65 insertions, 0 deletions
diff --git a/src/lib/crypto.ts b/src/lib/crypto.ts new file mode 100644 index 0000000..a6d912b --- /dev/null +++ b/src/lib/crypto.ts @@ -0,0 +1,65 @@ +import crypto from 'node:crypto'; +import { v4, v5, v7 } from 'uuid'; + +const ALGORITHM = 'aes-256-gcm'; +const IV_LENGTH = 16; +const SALT_LENGTH = 64; +const TAG_LENGTH = 16; +const TAG_POSITION = SALT_LENGTH + IV_LENGTH; +const ENC_POSITION = TAG_POSITION + TAG_LENGTH; + +const HASH_ALGO = 'sha512'; +const HASH_ENCODING = 'hex'; + +const getKey = (password: string, salt: Buffer) => + crypto.pbkdf2Sync(password, salt, 10000, 32, 'sha512'); + +export function encrypt(value: any, secret: any) { + const iv = crypto.randomBytes(IV_LENGTH); + const salt = crypto.randomBytes(SALT_LENGTH); + const key = getKey(secret, salt); + + const cipher = crypto.createCipheriv(ALGORITHM, key, iv); + + const encrypted = Buffer.concat([cipher.update(String(value), 'utf8'), cipher.final()]); + + const tag = cipher.getAuthTag(); + + return Buffer.concat([salt, iv, tag, encrypted]).toString('base64'); +} + +export function decrypt(value: any, secret: any) { + const str = Buffer.from(String(value), 'base64'); + const salt = str.subarray(0, SALT_LENGTH); + const iv = str.subarray(SALT_LENGTH, TAG_POSITION); + const tag = str.subarray(TAG_POSITION, ENC_POSITION); + const encrypted = str.subarray(ENC_POSITION); + + const key = getKey(secret, salt); + + const decipher = crypto.createDecipheriv(ALGORITHM, key, iv); + + decipher.setAuthTag(tag); + + return decipher.update(encrypted) + decipher.final('utf8'); +} + +export function hash(...args: string[]) { + return crypto.createHash(HASH_ALGO).update(args.join('')).digest(HASH_ENCODING); +} + +export function md5(...args: string[]) { + return crypto.createHash('md5').update(args.join('')).digest('hex'); +} + +export function secret() { + return hash(process.env.APP_SECRET || process.env.DATABASE_URL); +} + +export function uuid(...args: any) { + if (args.length) { + return v5(hash(...args, secret()), v5.DNS); + } + + return process.env.USE_UUIDV7 ? v7() : v4(); +} |