Spaces:
Paused
Paused
| import { | |
| randomBytes, | |
| createCipheriv, | |
| createDecipheriv, | |
| createHash, | |
| } from 'crypto'; | |
| import { deflateSync, inflateSync } from 'zlib'; | |
| import { Settings } from './settings'; | |
| const pad = (data: Buffer, blockSize: number): Buffer => { | |
| const padding = blockSize - (data.length % blockSize); | |
| return Buffer.concat([data, Buffer.alloc(padding, padding)]); | |
| }; | |
| const unpad = (data: Buffer): Buffer => { | |
| const padding = data[data.length - 1]; | |
| return data.subarray(0, data.length - padding); | |
| }; | |
| export const compressAndEncrypt = (data: string): string => { | |
| // First compress the data with Deflate compression | |
| const compressedData = deflateSync(Buffer.from(data, 'utf-8'), { level: 9 }); | |
| const secretKey = Settings.SECRET_KEY; | |
| if (!secretKey) { | |
| console.error('|ERR| crypto > compressAndEncrypt > No secret key provided'); | |
| throw new Error('No secret key provided'); | |
| } | |
| // Then encrypt the compressed data | |
| const iv = randomBytes(16); | |
| const cipher = createCipheriv('aes-256-cbc', secretKey, iv); | |
| // Ensure proper padding | |
| const paddedData = pad(compressedData, 16); | |
| const encryptedData = Buffer.concat([ | |
| cipher.update(paddedData), | |
| cipher.final(), | |
| ]); | |
| return `E-${iv.toString('hex')}-${encryptedData.toString('hex')}`; | |
| }; | |
| export const decryptAndDecompress = ( | |
| encryptedData: Buffer, | |
| iv: Buffer | |
| ): string => { | |
| const secretKey = Settings.SECRET_KEY; | |
| if (!secretKey) { | |
| console.error( | |
| '|ERR| crypto > decryptAndDecompress > No secret key provided' | |
| ); | |
| throw new Error('No secret key provided'); | |
| } | |
| const decipher = createDecipheriv('aes-256-cbc', secretKey, iv); | |
| // Decrypt the data | |
| const decryptedPaddedData = Buffer.concat([ | |
| decipher.update(encryptedData), | |
| decipher.final(), | |
| ]); | |
| // Remove padding | |
| const decryptedData = unpad(decryptedPaddedData); | |
| // Decompress the data with Deflate decompression | |
| const decompressedData = inflateSync(decryptedData); | |
| return decompressedData.toString('utf-8'); | |
| }; | |
| export function parseAndDecryptString(data: string): string | null { | |
| try { | |
| if (data.startsWith('E-')) { | |
| const [ivHex, encryptedHex] = data.replace('E-', '').split('-'); | |
| const iv = Buffer.from(ivHex, 'hex'); | |
| const encrypted = Buffer.from(encryptedHex, 'hex'); | |
| return decryptAndDecompress(encrypted, iv); | |
| } | |
| return data; | |
| } catch (error: any) { | |
| console.error( | |
| `|ERR| crypto > parseAndDecryptString > Failed to decrypt data: ${error.message}` | |
| ); | |
| return null; | |
| } | |
| } | |
| export function getTextHash(text: string): string { | |
| const hash = createHash('sha256'); | |
| hash.update(text); | |
| return hash.digest('hex'); | |
| } | |