1
1
import { FieldInfo } from '@zenstackhq/runtime' ;
2
- import { loadSchema } from '@zenstackhq/testtools' ;
2
+ import { loadSchema , loadModelWithError } from '@zenstackhq/testtools' ;
3
3
import path from 'path' ;
4
4
5
5
describe ( 'Encrypted test' , ( ) => {
6
6
let origDir : string ;
7
+ const encryptionKey = new Uint8Array ( Buffer . from ( 'AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8=' , 'base64' ) ) ;
7
8
8
9
beforeAll ( async ( ) => {
9
10
origDir = path . resolve ( '.' ) ;
@@ -14,21 +15,25 @@ describe('Encrypted test', () => {
14
15
} ) ;
15
16
16
17
it ( 'Simple encryption test' , async ( ) => {
17
- const { enhance } = await loadSchema ( `
18
+ const { enhance, prisma } = await loadSchema (
19
+ `
18
20
model User {
19
21
id String @id @default(cuid())
20
22
encrypted_value String @encrypted()
21
23
22
24
@@allow('all', true)
23
- }` ) ;
25
+ }` ,
26
+ {
27
+ enhancements : [ 'encryption' ] ,
28
+ enhanceOptions : {
29
+ encryption : { encryptionKey } ,
30
+ } ,
31
+ }
32
+ ) ;
24
33
25
34
const sudoDb = enhance ( undefined , { kinds : [ ] } ) ;
26
- const encryptionKey = new Uint8Array ( Buffer . from ( 'AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8=' , 'base64' ) ) ;
27
35
28
- const db = enhance ( undefined , {
29
- kinds : [ 'encrypted' ] ,
30
- encryption : { encryptionKey } ,
31
- } ) ;
36
+ const db = enhance ( ) ;
32
37
33
38
const create = await db . user . create ( {
34
39
data : {
@@ -49,9 +54,50 @@ describe('Encrypted test', () => {
49
54
} ,
50
55
} ) ;
51
56
57
+ const rawRead = await prisma . user . findUnique ( { where : { id : '1' } } ) ;
58
+
52
59
expect ( create . encrypted_value ) . toBe ( 'abc123' ) ;
53
60
expect ( read . encrypted_value ) . toBe ( 'abc123' ) ;
54
61
expect ( sudoRead . encrypted_value ) . not . toBe ( 'abc123' ) ;
62
+ expect ( rawRead . encrypted_value ) . not . toBe ( 'abc123' ) ;
63
+ } ) ;
64
+
65
+ it ( 'Multi-field encryption test' , async ( ) => {
66
+ const { enhance } = await loadSchema (
67
+ `
68
+ model User {
69
+ id String @id @default(cuid())
70
+ x1 String @encrypted()
71
+ x2 String @encrypted()
72
+
73
+ @@allow('all', true)
74
+ }` ,
75
+ {
76
+ enhancements : [ 'encryption' ] ,
77
+ enhanceOptions : {
78
+ encryption : { encryptionKey } ,
79
+ } ,
80
+ }
81
+ ) ;
82
+
83
+ const db = enhance ( ) ;
84
+
85
+ const create = await db . user . create ( {
86
+ data : {
87
+ id : '1' ,
88
+ x1 : 'abc123' ,
89
+ x2 : '123abc' ,
90
+ } ,
91
+ } ) ;
92
+
93
+ const read = await db . user . findUnique ( {
94
+ where : {
95
+ id : '1' ,
96
+ } ,
97
+ } ) ;
98
+
99
+ expect ( create ) . toMatchObject ( { x1 : 'abc123' , x2 : '123abc' } ) ;
100
+ expect ( read ) . toMatchObject ( { x1 : 'abc123' , x2 : '123abc' } ) ;
55
101
} ) ;
56
102
57
103
it ( 'Custom encryption test' , async ( ) => {
@@ -65,7 +111,7 @@ describe('Encrypted test', () => {
65
111
66
112
const sudoDb = enhance ( undefined , { kinds : [ ] } ) ;
67
113
const db = enhance ( undefined , {
68
- kinds : [ 'encrypted ' ] ,
114
+ kinds : [ 'encryption ' ] ,
69
115
encryption : {
70
116
encrypt : async ( model : string , field : FieldInfo , data : string ) => {
71
117
// Add _enc to the end of the input
@@ -105,4 +151,104 @@ describe('Encrypted test', () => {
105
151
expect ( read . encrypted_value ) . toBe ( 'abc123' ) ;
106
152
expect ( sudoRead . encrypted_value ) . toBe ( 'abc123_enc' ) ;
107
153
} ) ;
154
+
155
+ it ( 'Only supports string fields' , async ( ) => {
156
+ await expect (
157
+ loadModelWithError (
158
+ `
159
+ model User {
160
+ id String @id @default(cuid())
161
+ encrypted_value Bytes @encrypted()
162
+ }`
163
+ )
164
+ ) . resolves . toContain ( `attribute \"@encrypted\" cannot be used on this type of field` ) ;
165
+ } ) ;
166
+
167
+ it ( 'Returns cipher text when decryption fails' , async ( ) => {
168
+ const { enhance, enhanceRaw, prisma } = await loadSchema (
169
+ `
170
+ model User {
171
+ id String @id @default(cuid())
172
+ encrypted_value String @encrypted()
173
+
174
+ @@allow('all', true)
175
+ }` ,
176
+ { enhancements : [ 'encryption' ] }
177
+ ) ;
178
+
179
+ const db = enhance ( undefined , {
180
+ kinds : [ 'encryption' ] ,
181
+ encryption : { encryptionKey } ,
182
+ } ) ;
183
+
184
+ const create = await db . user . create ( {
185
+ data : {
186
+ id : '1' ,
187
+ encrypted_value : 'abc123' ,
188
+ } ,
189
+ } ) ;
190
+ expect ( create . encrypted_value ) . toBe ( 'abc123' ) ;
191
+
192
+ const db1 = enhanceRaw ( prisma , undefined , {
193
+ encryption : { encryptionKey : crypto . getRandomValues ( new Uint8Array ( 32 ) ) } ,
194
+ } ) ;
195
+ const read = await db1 . user . findUnique ( { where : { id : '1' } } ) ;
196
+ expect ( read . encrypted_value ) . toBeTruthy ( ) ;
197
+ expect ( read . encrypted_value ) . not . toBe ( 'abc123' ) ;
198
+ } ) ;
199
+
200
+ it ( 'Works with length validation' , async ( ) => {
201
+ const { enhance } = await loadSchema (
202
+ `
203
+ model User {
204
+ id String @id @default(cuid())
205
+ encrypted_value String @encrypted() @length(0, 6)
206
+
207
+ @@allow('all', true)
208
+ }` ,
209
+ {
210
+ enhanceOptions : { encryption : { encryptionKey } } ,
211
+ }
212
+ ) ;
213
+
214
+ const db = enhance ( ) ;
215
+
216
+ const create = await db . user . create ( {
217
+ data : {
218
+ id : '1' ,
219
+ encrypted_value : 'abc123' ,
220
+ } ,
221
+ } ) ;
222
+ expect ( create . encrypted_value ) . toBe ( 'abc123' ) ;
223
+
224
+ await expect (
225
+ db . user . create ( {
226
+ data : { id : '2' , encrypted_value : 'abc1234' } ,
227
+ } )
228
+ ) . toBeRejectedByPolicy ( ) ;
229
+ } ) ;
230
+
231
+ it ( 'Complains when encrypted fields are used in model-level policy rules' , async ( ) => {
232
+ await expect (
233
+ loadModelWithError ( `
234
+ model User {
235
+ id String @id @default(cuid())
236
+ encrypted_value String @encrypted()
237
+ @@allow('all', encrypted_value != 'abc123')
238
+ }
239
+ ` )
240
+ ) . resolves . toContain ( `Encrypted fields cannot be used in policy rules` ) ;
241
+ } ) ;
242
+
243
+ it ( 'Complains when encrypted fields are used in field-level policy rules' , async ( ) => {
244
+ await expect (
245
+ loadModelWithError ( `
246
+ model User {
247
+ id String @id @default(cuid())
248
+ encrypted_value String @encrypted()
249
+ value Int @allow('all', encrypted_value != 'abc123')
250
+ }
251
+ ` )
252
+ ) . resolves . toContain ( `Encrypted fields cannot be used in policy rules` ) ;
253
+ } ) ;
108
254
} ) ;
0 commit comments