Spaces:
Running
Running
Download src/utils/crypto.js from AndreaNotes1/auth-app-api: direct link, hf CLI and curl.
- Browser
- Download file 2.24 kB
-
https://huggingface.co/spaces/AndreaNotes1/auth-app-api/resolve/main/src/utils/crypto.js
- Command line
-
hf download hf://spaces/AndreaNotes1/auth-app-api/src/utils/crypto.js
-
curl -L -o crypto.js https://huggingface.co/spaces/AndreaNotes1/auth-app-api/resolve/main/src/utils/crypto.js
2.24 kB
| const crypto = require("crypto"); | |
| const { env } = require("../config/env"); | |
| const ALGORITHM = "aes-256-gcm"; | |
| const IV_LENGTH = 12; // 96-bit IV recommended for GCM | |
| function getKey() { | |
| const key = Buffer.from(env.fieldEncryptionKey || "", "hex"); | |
| if (key.length !== 32) { | |
| throw new Error( | |
| "FIELD_ENCRYPTION_KEY must be a 32-byte value encoded as 64 hex characters. " + | |
| "Generate one with: node -e \"console.log(require('crypto').randomBytes(32).toString('hex'))\"" | |
| ); | |
| } | |
| return key; | |
| } | |
| /** | |
| * Encrypts a plaintext string for storage at rest (e.g. bank wire | |
| * reference numbers, Payoneer transaction IDs). Returns a single | |
| * base64 payload containing iv + authTag + ciphertext so it can be | |
| * stored as one string field in MongoDB. | |
| */ | |
| function encryptField(plaintext) { | |
| if (plaintext === undefined || plaintext === null || plaintext === "") return null; | |
| const iv = crypto.randomBytes(IV_LENGTH); | |
| const cipher = crypto.createCipheriv(ALGORITHM, getKey(), iv); | |
| const ciphertext = Buffer.concat([cipher.update(String(plaintext), "utf8"), cipher.final()]); | |
| const authTag = cipher.getAuthTag(); | |
| return Buffer.concat([iv, authTag, ciphertext]).toString("base64"); | |
| } | |
| /** | |
| * Decrypts a payload produced by encryptField. Returns null if the | |
| * input is empty rather than throwing, so callers can treat "no | |
| * payment reference yet" gracefully. | |
| */ | |
| function decryptField(payload) { | |
| if (!payload) return null; | |
| const raw = Buffer.from(payload, "base64"); | |
| const iv = raw.subarray(0, IV_LENGTH); | |
| const authTag = raw.subarray(IV_LENGTH, IV_LENGTH + 16); | |
| const ciphertext = raw.subarray(IV_LENGTH + 16); | |
| const decipher = crypto.createDecipheriv(ALGORITHM, getKey(), iv); | |
| decipher.setAuthTag(authTag); | |
| const plaintext = Buffer.concat([decipher.update(ciphertext), decipher.final()]); | |
| return plaintext.toString("utf8"); | |
| } | |
| /** One-way hash used for equality lookups on encrypted fields (e.g. duplicate detection) without decrypting. */ | |
| function hmacIndex(value) { | |
| if (!value) return null; | |
| return crypto.createHmac("sha256", getKey()).update(String(value)).digest("hex"); | |
| } | |
| module.exports = { encryptField, decryptField, hmacIndex }; | |