Skip to content

Commit

Permalink
fix: 🎨 support number/boolean encryption
Browse files Browse the repository at this point in the history
  • Loading branch information
Morgbn committed Aug 15, 2024
1 parent 49a7b75 commit 0d9a7c5
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 12 deletions.
6 changes: 3 additions & 3 deletions playground/schemas/Todo.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@
}
},
"required": ["text"],
"encryptedProperties": ["text"],
"trackedProperties": ["text", "updatedBy"],
"encryptedProperties": ["text", "cost"],
"trackedProperties": ["text", "updatedBy", "cost"],
"timestamps": true,
"userstamps": true
}
}
25 changes: 16 additions & 9 deletions src/runtime/server/helpers/cipher.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { createCipheriv, createDecipheriv } from 'node:crypto'
import type { CipherGCMTypes } from 'node:crypto'

type TypeCode = '' | 'n' | 'bi' | 'b' | 's' | 'o' | 'f'

/**
* Encrypt data
* @returns encrypted data
*/
export function encrypt(data: any, iv: string, key: Buffer, algorithm: CipherGCMTypes): string {
export function encrypt(data: unknown, iv: string, key: Buffer, algorithm: CipherGCMTypes) {
if (data === null || typeof data === 'undefined') return data
const isObj = typeof data === 'object'
if (isObj) data = JSON.stringify(data)
const type = typeof data
if (type != 'string') data = JSON.stringify(data)
const typeCode = type === 'bigint' ? 'bi' : type === 'string' ? '' : type.slice(0, 1) as TypeCode
const ivBuffer = Buffer.from(iv, 'base64')
let encrypted: Buffer | undefined
let encryptedStr = ''
try {
const cipher = createCipheriv(algorithm, key, ivBuffer)
encrypted = Buffer.concat([cipher.update(data), cipher.final()])
encryptedStr = `${isObj ? 'o' : ''}$${encrypted.toString('base64')}$${cipher.getAuthTag().toString('base64')}`
encrypted = Buffer.concat([cipher.update(data as string), cipher.final()])
encryptedStr = `${typeCode}$${encrypted.toString('base64')}$${cipher.getAuthTag().toString('base64')}`
} finally { // erase sensitive data
ivBuffer.fill(0)
if (Buffer.isBuffer(encrypted)) encrypted.fill(0)
Expand All @@ -28,9 +30,9 @@ export function encrypt(data: any, iv: string, key: Buffer, algorithm: CipherGCM
* Decrypt data
* @returns decrypted data
*/
export function decrypt(data: any, iv: string, key: Buffer, algorithm: CipherGCMTypes): string | Record<string, any> | undefined {
export function decrypt(data: string | undefined | null, iv: string, key: Buffer, algorithm: CipherGCMTypes) {
if (typeof data !== 'string') return data
const [isObj, encrypted, authTag] = data.split('$')
const [type, encrypted, authTag] = data.split('$') as [TypeCode, string, string]
if (!encrypted) return undefined
const ivBuffer = Buffer.from(iv, 'base64')
const authTagBuffer = Buffer.from(authTag, 'base64')
Expand All @@ -48,5 +50,10 @@ export function decrypt(data: any, iv: string, key: Buffer, algorithm: CipherGCM
encryptedBuffer.fill(0)
if (Buffer.isBuffer(decrypted)) decrypted.fill(0)
}
return isObj && decryptedStr ? JSON.parse(decryptedStr) : decryptedStr
if (!decryptedStr) return undefined
if (type === 'o') return JSON.parse(decryptedStr) as Record<string, unknown>
if (type === 'b') return JSON.parse(decryptedStr) as boolean
if (type === 'n') return Number(decryptedStr)
// don't support bigint/symbol/function
return decryptedStr
}

0 comments on commit 0d9a7c5

Please sign in to comment.