11/* eslint-disable @typescript-eslint/no-explicit-any */
22/* eslint-disable @typescript-eslint/no-unused-vars */
33
4- import { NestedWriteVisitor , enumerate , getModelFields , resolveField , type PrismaWriteActionType } from '../../cross' ;
5- import { DbClientContract } from '../../types' ;
4+ import {
5+ FieldInfo ,
6+ NestedWriteVisitor ,
7+ enumerate ,
8+ getModelFields ,
9+ resolveField ,
10+ type PrismaWriteActionType ,
11+ } from '../../cross' ;
12+ import { DbClientContract , CustomEncryption , SimpleEncryption } from '../../types' ;
613import { InternalEnhancementOptions } from './create-enhancement' ;
714import { DefaultPrismaProxyHandler , PrismaProxyActions , makeProxy } from './proxy' ;
815import { QueryUtils } from './query-utils' ;
@@ -33,52 +40,65 @@ const getKey = async (secret: string): Promise<CryptoKey> => {
3340 'decrypt' ,
3441 ] ) ;
3542} ;
36- const encryptFunc = async ( data : string , secret : string ) : Promise < string > => {
37- const key = await getKey ( secret ) ;
38- const iv = crypto . getRandomValues ( new Uint8Array ( 12 ) ) ;
39-
40- const encrypted = await crypto . subtle . encrypt (
41- {
42- name : 'AES-GCM' ,
43- iv,
44- } ,
45- key ,
46- encoder . encode ( data )
47- ) ;
4843
49- // Combine IV and encrypted data into a single array of bytes
50- const bytes = [ ... iv , ... new Uint8Array ( encrypted ) ] ;
44+ class EncryptedHandler extends DefaultPrismaProxyHandler {
45+ private queryUtils : QueryUtils ;
5146
52- // Convert bytes to base64 string
53- return btoa ( String . fromCharCode ( ...bytes ) ) ;
54- } ;
47+ constructor ( prisma : DbClientContract , model : string , options : InternalEnhancementOptions ) {
48+ super ( prisma , model , options ) ;
5549
56- const decryptFunc = async ( encryptedData : string , secret : string ) : Promise < string > => {
57- const key = await getKey ( secret ) ;
50+ this . queryUtils = new QueryUtils ( prisma , options ) ;
51+ }
5852
59- // Convert base64 back to bytes
60- const bytes = Uint8Array . from ( atob ( encryptedData ) , ( c ) => c . charCodeAt ( 0 ) ) ;
53+ private isCustomEncryption ( encryption : CustomEncryption | SimpleEncryption ) : encryption is CustomEncryption {
54+ return 'encrypt' in encryption && 'decrypt' in encryption ;
55+ }
6156
62- // First 12 bytes are IV, rest is encrypted data
63- const decrypted = await crypto . subtle . decrypt (
64- {
65- name : 'AES-GCM' ,
66- iv : bytes . slice ( 0 , 12 ) ,
67- } ,
68- key ,
69- bytes . slice ( 12 )
70- ) ;
57+ private async encrypt ( field : FieldInfo , data : string ) : Promise < string > {
58+ if ( this . isCustomEncryption ( this . options . encryption ! ) ) {
59+ return this . options . encryption . encrypt ( this . model , field , data ) ;
60+ }
7161
72- return decoder . decode ( decrypted ) ;
73- } ;
62+ const key = await getKey ( this . options . encryption ! . encryptionKey ) ;
63+ const iv = crypto . getRandomValues ( new Uint8Array ( 12 ) ) ;
7464
75- class EncryptedHandler extends DefaultPrismaProxyHandler {
76- private queryUtils : QueryUtils ;
65+ const encrypted = await crypto . subtle . encrypt (
66+ {
67+ name : 'AES-GCM' ,
68+ iv,
69+ } ,
70+ key ,
71+ encoder . encode ( data )
72+ ) ;
7773
78- constructor ( prisma : DbClientContract , model : string , options : InternalEnhancementOptions ) {
79- super ( prisma , model , options ) ;
74+ // Combine IV and encrypted data into a single array of bytes
75+ const bytes = [ ... iv , ... new Uint8Array ( encrypted ) ] ;
8076
81- this . queryUtils = new QueryUtils ( prisma , options ) ;
77+ // Convert bytes to base64 string
78+ return btoa ( String . fromCharCode ( ...bytes ) ) ;
79+ }
80+
81+ private async decrypt ( field : FieldInfo , data : string ) : Promise < string > {
82+ if ( this . isCustomEncryption ( this . options . encryption ! ) ) {
83+ return this . options . encryption . decrypt ( this . model , field , data ) ;
84+ }
85+
86+ const key = await getKey ( this . options . encryption ! . encryptionKey ) ;
87+
88+ // Convert base64 back to bytes
89+ const bytes = Uint8Array . from ( atob ( data ) , ( c ) => c . charCodeAt ( 0 ) ) ;
90+
91+ // First 12 bytes are IV, rest is encrypted data
92+ const decrypted = await crypto . subtle . decrypt (
93+ {
94+ name : 'AES-GCM' ,
95+ iv : bytes . slice ( 0 , 12 ) ,
96+ } ,
97+ key ,
98+ bytes . slice ( 12 )
99+ ) ;
100+
101+ return decoder . decode ( decrypted ) ;
82102 }
83103
84104 // base override
@@ -115,9 +135,7 @@ class EncryptedHandler extends DefaultPrismaProxyHandler {
115135
116136 const shouldDecrypt = fieldInfo . attributes ?. find ( ( attr ) => attr . name === '@encrypted' ) ;
117137 if ( shouldDecrypt ) {
118- const descryptSecret = shouldDecrypt . args . find ( ( arg ) => arg . name === 'secret' ) ?. value as string ;
119-
120- entityData [ field ] = await decryptFunc ( entityData [ field ] , descryptSecret ) ;
138+ entityData [ field ] = await this . decrypt ( fieldInfo , entityData [ field ] ) ;
121139 }
122140 }
123141 }
@@ -131,7 +149,7 @@ class EncryptedHandler extends DefaultPrismaProxyHandler {
131149
132150 const secret : string = encAttr . args . find ( ( arg ) => arg . name === 'secret' ) ?. value as string ;
133151
134- context . parent [ field . name ] = await encryptFunc ( data , secret ) ;
152+ context . parent [ field . name ] = await this . encrypt ( field , data ) ;
135153 }
136154 } ,
137155 } ) ;
0 commit comments