6
6
MAGIC_BYTE_V0 ,
7
7
RuleContext ,
8
8
RuleError ,
9
+ RuleExecutor ,
9
10
} from "../../serde/serde" ;
10
11
import { RuleMode , } from "../../schemaregistry-client" ;
11
12
import { DekClient , Dek , DekRegistryClient , Kek } from "./dekregistry/dekregistry-client" ;
@@ -61,29 +62,29 @@ export class Clock {
61
62
}
62
63
}
63
64
64
- export class FieldEncryptionExecutor extends FieldRuleExecutor {
65
+ export class EncryptionExecutor implements RuleExecutor {
66
+ config : Map < string , string > | null = null
65
67
client : DekClient | null = null
66
68
clock : Clock
67
69
68
70
/**
69
71
* Register the field encryption executor with the rule registry.
70
72
*/
71
- static register ( ) : FieldEncryptionExecutor {
73
+ static register ( ) : EncryptionExecutor {
72
74
return this . registerWithClock ( new Clock ( ) )
73
75
}
74
76
75
- static registerWithClock ( clock : Clock ) : FieldEncryptionExecutor {
76
- const executor = new FieldEncryptionExecutor ( clock )
77
+ static registerWithClock ( clock : Clock ) : EncryptionExecutor {
78
+ const executor = new EncryptionExecutor ( clock )
77
79
RuleRegistry . registerRuleExecutor ( executor )
78
80
return executor
79
81
}
80
82
81
83
constructor ( clock : Clock = new Clock ( ) ) {
82
- super ( )
83
84
this . clock = clock
84
85
}
85
86
86
- override configure ( clientConfig : ClientConfig , config : Map < string , string > ) {
87
+ configure ( clientConfig : ClientConfig , config : Map < string , string > ) {
87
88
if ( this . client != null ) {
88
89
if ( ! deepEqual ( this . client . config ( ) , clientConfig ) ) {
89
90
throw new RuleError ( 'executor already configured' )
@@ -110,20 +111,23 @@ export class FieldEncryptionExecutor extends FieldRuleExecutor {
110
111
}
111
112
}
112
113
113
- override type ( ) : string {
114
- return 'ENCRYPT '
114
+ type ( ) : string {
115
+ return 'ENCRYPT_PAYLOAD '
115
116
}
116
117
117
- override newTransform ( ctx : RuleContext ) : FieldTransform {
118
+ async transform ( ctx : RuleContext , msg : any ) : Promise < any > {
119
+ const transform = this . newTransform ( ctx )
120
+ return await transform . transform ( ctx , FieldType . BYTES , msg )
121
+ }
122
+
123
+ newTransform ( ctx : RuleContext ) : EncryptionExecutorTransform {
118
124
const cryptor = this . getCryptor ( ctx )
119
125
const kekName = this . getKekName ( ctx )
120
126
const dekExpiryDays = this . getDekExpiryDays ( ctx )
121
- const transform =
122
- new FieldEncryptionExecutorTransform ( this , cryptor , kekName , dekExpiryDays )
123
- return transform
127
+ return new EncryptionExecutorTransform ( this , cryptor , kekName , dekExpiryDays )
124
128
}
125
129
126
- override async close ( ) : Promise < void > {
130
+ async close ( ) : Promise < void > {
127
131
if ( this . client != null ) {
128
132
await this . client . close ( )
129
133
}
@@ -135,8 +139,7 @@ export class FieldEncryptionExecutor extends FieldRuleExecutor {
135
139
if ( dekAlgorithmStr != null ) {
136
140
dekAlgorithm = DekFormat [ dekAlgorithmStr as keyof typeof DekFormat ]
137
141
}
138
- const cryptor = new Cryptor ( dekAlgorithm )
139
- return cryptor
142
+ return new Cryptor ( dekAlgorithm )
140
143
}
141
144
142
145
private getKekName ( ctx : RuleContext ) : string {
@@ -269,15 +272,15 @@ export class Cryptor {
269
272
}
270
273
}
271
274
272
- export class FieldEncryptionExecutorTransform implements FieldTransform {
273
- private executor : FieldEncryptionExecutor
275
+ export class EncryptionExecutorTransform {
276
+ private executor : EncryptionExecutor
274
277
private cryptor : Cryptor
275
278
private kekName : string
276
279
private kek : Kek | null = null
277
280
private dekExpiryDays : number
278
281
279
282
constructor (
280
- executor : FieldEncryptionExecutor ,
283
+ executor : EncryptionExecutor ,
281
284
cryptor : Cryptor ,
282
285
kekName : string ,
283
286
dekExpiryDays : number ,
@@ -481,15 +484,15 @@ export class FieldEncryptionExecutorTransform implements FieldTransform {
481
484
( now - dek . ts ! ) / MILLIS_IN_DAY >= this . dekExpiryDays
482
485
}
483
486
484
- async transform ( ctx : RuleContext , fieldCtx : FieldContext , fieldValue : any ) : Promise < any > {
487
+ async transform ( ctx : RuleContext , fieldType : FieldType , fieldValue : any ) : Promise < any > {
485
488
if ( fieldValue == null ) {
486
489
return null
487
490
}
488
491
switch ( ctx . ruleMode ) {
489
492
case RuleMode . WRITE : {
490
- let plaintext = this . toBytes ( fieldCtx . type , fieldValue )
493
+ let plaintext = this . toBytes ( fieldType , fieldValue )
491
494
if ( plaintext == null ) {
492
- throw new RuleError ( `type ${ fieldCtx . type } not supported for encryption` )
495
+ throw new RuleError ( `type ${ fieldType } not supported for encryption` )
493
496
}
494
497
let version : number | null = null
495
498
if ( this . isDekRotated ( ) ) {
@@ -501,18 +504,18 @@ export class FieldEncryptionExecutorTransform implements FieldTransform {
501
504
if ( this . isDekRotated ( ) ) {
502
505
ciphertext = this . prefixVersion ( dek . version ! , ciphertext )
503
506
}
504
- if ( fieldCtx . type === FieldType . STRING ) {
507
+ if ( fieldType === FieldType . STRING ) {
505
508
return ciphertext . toString ( 'base64' )
506
509
} else {
507
- return this . toObject ( fieldCtx . type , ciphertext )
510
+ return this . toObject ( fieldType , ciphertext )
508
511
}
509
512
}
510
513
case RuleMode . READ : {
511
514
let ciphertext
512
- if ( fieldCtx . type === FieldType . STRING ) {
515
+ if ( fieldType === FieldType . STRING ) {
513
516
ciphertext = Buffer . from ( fieldValue , 'base64' )
514
517
} else {
515
- ciphertext = this . toBytes ( fieldCtx . type , fieldValue )
518
+ ciphertext = this . toBytes ( fieldType , fieldValue )
516
519
}
517
520
if ( ciphertext == null ) {
518
521
return fieldValue
@@ -528,7 +531,7 @@ export class FieldEncryptionExecutorTransform implements FieldTransform {
528
531
let dek = await this . getOrCreateDek ( ctx , version )
529
532
let keyMaterialBytes = await this . executor . client ! . getDekKeyMaterialBytes ( dek )
530
533
let plaintext = await this . cryptor . decrypt ( keyMaterialBytes ! , ciphertext )
531
- return this . toObject ( fieldCtx . type , plaintext )
534
+ return this . toObject ( fieldType , plaintext )
532
535
}
533
536
default :
534
537
throw new RuleError ( `unsupported rule mode ${ ctx . ruleMode } ` )
@@ -586,3 +589,55 @@ function getKmsClient(config: Map<string, string>, kek: Kek): KmsClient {
586
589
}
587
590
return kmsClient
588
591
}
592
+
593
+ export class FieldEncryptionExecutor extends FieldRuleExecutor {
594
+ executor : EncryptionExecutor
595
+
596
+ /**
597
+ * Register the field encryption executor with the rule registry.
598
+ */
599
+ static register ( ) : FieldEncryptionExecutor {
600
+ return this . registerWithClock ( new Clock ( ) )
601
+ }
602
+
603
+ static registerWithClock ( clock : Clock ) : FieldEncryptionExecutor {
604
+ const executor = new FieldEncryptionExecutor ( clock )
605
+ RuleRegistry . registerRuleExecutor ( executor )
606
+ return executor
607
+ }
608
+
609
+ constructor ( clock : Clock = new Clock ( ) ) {
610
+ super ( )
611
+ this . executor = new EncryptionExecutor ( clock )
612
+ }
613
+
614
+ override configure ( clientConfig : ClientConfig , config : Map < string , string > ) {
615
+ this . executor . configure ( clientConfig , config )
616
+ }
617
+
618
+ override type ( ) : string {
619
+ return 'ENCRYPT'
620
+ }
621
+
622
+ override newTransform ( ctx : RuleContext ) : FieldTransform {
623
+ const executorTransform = this . executor . newTransform ( ctx )
624
+ return new FieldEncryptionExecutorTransform ( executorTransform )
625
+ }
626
+
627
+ override async close ( ) : Promise < void > {
628
+ return this . executor . close ( )
629
+ }
630
+ }
631
+
632
+ export class FieldEncryptionExecutorTransform implements FieldTransform {
633
+ private executorTransform : EncryptionExecutorTransform
634
+
635
+ constructor ( executorTransform : EncryptionExecutorTransform ) {
636
+ this . executorTransform = executorTransform
637
+ }
638
+
639
+ async transform ( ctx : RuleContext , fieldCtx : FieldContext , fieldValue : any ) : Promise < any > {
640
+ return await this . executorTransform . transform ( ctx , fieldCtx . type , fieldValue )
641
+ }
642
+ }
643
+
0 commit comments