import crypto from "crypto"; import bcrypt from "bcryptjs"; import jwt from "jsonwebtoken"; import env from "../enviroment/env"; const maxAgeAccess = 60 * 1000 * 20 + 1000 * 60; const maxAgeRefresh = 60 * 1000 * 60 * 24 * 30 + 1000 * 60; const maxAgeAccessStreamVideo = 60 * 1000 * 60 * 24; export interface CryptoUser { _id: any; email: string; password: string; privateKey?: string; publicKey?: string; emailVerified?: boolean; } export const encryptToken = (token: string, key: any, iv: any): string => { iv = Buffer.from(iv, "hex"); const TOKEN_CIPHER_KEY = crypto.createHash("sha256").update(key).digest(); const cipher = crypto.createCipheriv("aes-256-cbc", TOKEN_CIPHER_KEY, iv); const encryptedText = cipher.update(token); return Buffer.concat([encryptedText, cipher.final()]).toString("hex"); }; export const decryptToken = ( encryptedToken: any, key: string, iv: any ): string => { encryptedToken = Buffer.from(encryptedToken, "hex"); iv = Buffer.from(iv, "hex"); const TOKEN_CIPHER_KEY = crypto.createHash("sha256").update(key).digest(); const decipher = crypto.createDecipheriv("aes-256-cbc", TOKEN_CIPHER_KEY, iv); const tokenDecrypted = decipher.update(encryptedToken); return Buffer.concat([tokenDecrypted, decipher.final()]).toString(); }; export const getEncryptionKey = (user: any): Buffer | undefined => { try { const userPassword = user.password; const masterEncryptedText = user.privateKey as string; const masterPassword = env.key!; const iv = Buffer.from(user.publicKey as string, "hex"); const USER_CIPHER_KEY = crypto .createHash("sha256") .update(userPassword) .digest(); const MASTER_CIPHER_KEY = crypto .createHash("sha256") .update(masterPassword) .digest(); const unhexMasterText = Buffer.from(masterEncryptedText, "hex"); const masterDecipher = crypto.createDecipheriv( "aes-256-cbc", MASTER_CIPHER_KEY, iv ); let masterDecrypted = masterDecipher.update(unhexMasterText); masterDecrypted = Buffer.concat([masterDecrypted, masterDecipher.final()]); const decipher = crypto.createDecipheriv("aes-256-cbc", USER_CIPHER_KEY, iv); let decrypted = decipher.update(masterDecrypted); decrypted = Buffer.concat([decrypted, decipher.final()]); return decrypted; } catch (e) { console.log("Get Encryption Key Error", e); return undefined; } }; export const generateEncryptionKeyMaterial = ( userPassword: string, randomKey: Buffer ): { privateKey: string; publicKey: string } => { const masterPassword = env.key!; const iv = crypto.randomBytes(16); const USER_CIPHER_KEY = crypto .createHash("sha256") .update(userPassword) .digest(); const cipher = crypto.createCipheriv("aes-256-cbc", USER_CIPHER_KEY, iv); let encryptedText = cipher.update(randomKey); encryptedText = Buffer.concat([encryptedText, cipher.final()]); const MASTER_CIPHER_KEY = crypto .createHash("sha256") .update(masterPassword) .digest(); const masterCipher = crypto.createCipheriv( "aes-256-cbc", MASTER_CIPHER_KEY, iv ); const masterEncryptedText = masterCipher.update(encryptedText); const privateKey = Buffer.concat([ masterEncryptedText, masterCipher.final(), ]).toString("hex"); const publicKey = iv.toString("hex"); return { privateKey, publicKey }; }; export const hashPassword = async (password: string): Promise => { return bcrypt.hash(password, 8); }; export const comparePassword = async ( password: string, hash: string ): Promise => { return bcrypt.compare(password, hash); }; export const signAuthTokens = ( user: any ): { accessToken: string; refreshToken: string; encryptedRefreshToken: string; iv: string; time: number; } => { const iv = crypto.randomBytes(16); const time = new Date().getTime(); const userObj = { _id: user._id, emailVerified: user.emailVerified, email: user.email, }; const accessToken = jwt.sign({ user: userObj, iv }, env.passwordAccess!, { expiresIn: maxAgeAccess.toString(), }); const refreshToken = jwt.sign( { _id: user._id.toString(), iv, time }, env.passwordRefresh!, { expiresIn: maxAgeRefresh.toString() } ); const encryptionKey = getEncryptionKey(user); const encryptedRefreshToken = encryptToken(refreshToken, encryptionKey, iv); return { accessToken, refreshToken, encryptedRefreshToken, iv: iv.toString("hex"), time, }; }; export const signStreamVideoToken = ( user: any ): { token: string; encryptedToken: string; iv: string; time: number } => { const iv = crypto.randomBytes(16); const time = new Date().getTime(); const token = jwt.sign( { _id: user._id.toString(), iv, time }, env.passwordAccess!, { expiresIn: maxAgeAccessStreamVideo.toString() } ); const encryptionKey = getEncryptionKey(user); const encryptedToken = encryptToken(token, encryptionKey, iv); return { token, encryptedToken, iv: iv.toString("hex"), time }; }; export const signTempAuthToken = ( user: any ): { token: string; encryptedToken: string } => { const iv = crypto.randomBytes(16); const token = jwt.sign({ _id: user._id.toString(), iv }, env.passwordAccess!, { expiresIn: "3000ms", }); const encryptionKey = getEncryptionKey(user); const encryptedToken = encryptToken(token, encryptionKey, iv); return { token, encryptedToken }; }; export const signEmailVerifyToken = ( user: any ): { token: string; encryptedToken: string } => { const iv = crypto.randomBytes(16); const token = jwt.sign({ _id: user._id.toString(), iv }, env.passwordAccess!, { expiresIn: "1d", }); const encryptionKey = getEncryptionKey(user); const encryptedToken = encryptToken(token, encryptionKey, iv); return { token, encryptedToken }; }; export const signPasswordResetToken = ( user: any ): { token: string; encryptedToken: string } => { const iv = crypto.randomBytes(16); const token = jwt.sign({ _id: user._id.toString(), iv }, env.passwordAccess!, { expiresIn: "1h", }); const encryptionKey = getEncryptionKey(user); const encryptedToken = encryptToken(token, encryptionKey, iv); return { token, encryptedToken }; };