@@ -242,11 +242,51 @@ public Mono<byte[]> encrypt(byte[] payload) {
242242 return encrypt (itemJObj );
243243 }
244244
245- public Mono <byte []> encrypt (ObjectNode itemJObj ) {
245+ public Mono <byte []> encrypt (JsonNode itemJObj ) {
246246 return encryptObjectNode (itemJObj ).map (encryptedObjectNode -> EncryptionUtils .serializeJsonToByteArray (EncryptionUtils .getSimpleObjectMapper (), encryptedObjectNode ));
247247 }
248248
249- public Mono <ObjectNode > encryptObjectNode (ObjectNode itemJObj ) {
249+ public Mono <JsonNode > encryptPatchNode (JsonNode itemObj , String patchPropertyPath ) {
250+ assert (itemObj != null );
251+ return initEncryptionSettingsIfNotInitializedAsync ().then (Mono .defer (() -> {
252+ for (ClientEncryptionIncludedPath includedPath : this .clientEncryptionPolicy .getIncludedPaths ()) {
253+ if (StringUtils .isEmpty (includedPath .getPath ()) || includedPath .getPath ().charAt (0 ) != '/' || includedPath .getPath ().lastIndexOf ('/' ) != 0 ) {
254+ return Mono .error (new IllegalArgumentException ("Invalid encryption path: " + includedPath .getPath ()));
255+ }
256+ }
257+
258+ for (ClientEncryptionIncludedPath includedPath : this .clientEncryptionPolicy .getIncludedPaths ()) {
259+ String propertyName = includedPath .getPath ().substring (1 );
260+ if (patchPropertyPath .substring (1 ).equals (propertyName )) {
261+ if (itemObj .isValueNode ()) {
262+ return this .encryptionSettings .getEncryptionSettingForPropertyAsync (propertyName ,
263+ this ).flatMap (settings -> {
264+ try {
265+ return Mono .just (EncryptionUtils .getSimpleObjectMapper ().readTree (EncryptionUtils .getSimpleObjectMapper ()
266+ .writeValueAsString (encryptAndSerializeValue (settings ,
267+ null , itemObj , propertyName ))));
268+ } catch (MicrosoftDataEncryptionException | JsonProcessingException ex ) {
269+ return Mono .error (ex );
270+ }
271+ });
272+ } else {
273+ return this .encryptionSettings .getEncryptionSettingForPropertyAsync (propertyName ,
274+ this ).flatMap (settings -> {
275+ try {
276+ return Mono .just (encryptAndSerializePatchProperty (settings ,
277+ itemObj , propertyName ));
278+ } catch (MicrosoftDataEncryptionException | JsonProcessingException ex ) {
279+ return Mono .error (ex );
280+ }
281+ });
282+ }
283+ }
284+ }
285+ return Mono .empty ();
286+ }));
287+ }
288+
289+ public Mono <JsonNode > encryptObjectNode (JsonNode itemJObj ) {
250290 assert (itemJObj != null );
251291 return initEncryptionSettingsIfNotInitializedAsync ().then (Mono .defer (() -> {
252292 for (ClientEncryptionIncludedPath includedPath : this .clientEncryptionPolicy .getIncludedPaths ()) {
@@ -265,7 +305,7 @@ public Mono<ObjectNode> encryptObjectNode(ObjectNode itemJObj) {
265305 this ).flatMap (settings -> {
266306 try {
267307 encryptAndSerializeProperty (settings , itemJObj , propertyValueHolder , propertyName );
268- } catch (MicrosoftDataEncryptionException ex ) {
308+ } catch (MicrosoftDataEncryptionException | JsonProcessingException ex ) {
269309 return Mono .error (ex );
270310 }
271311 return Mono .empty ();
@@ -278,8 +318,73 @@ public Mono<ObjectNode> encryptObjectNode(ObjectNode itemJObj) {
278318 }));
279319 }
280320
281- public void encryptAndSerializeProperty (EncryptionSettings encryptionSettings , ObjectNode objectNode ,
282- JsonNode propertyValueHolder , String propertyName ) throws MicrosoftDataEncryptionException {
321+ @ SuppressWarnings ("unchecked" )
322+ public JsonNode encryptAndSerializePatchProperty (EncryptionSettings encryptionSettings ,
323+ JsonNode propertyValueHolder , String propertyName ) throws MicrosoftDataEncryptionException , JsonProcessingException {
324+ if (propertyValueHolder .isObject ()) {
325+ for (Iterator <Map .Entry <String , JsonNode >> it = propertyValueHolder .fields (); it .hasNext (); ) {
326+ Map .Entry <String , JsonNode > child = it .next ();
327+ if (child .getValue ().isObject () || child .getValue ().isArray ()) {
328+ JsonNode encryptedValue = encryptAndSerializePatchProperty (encryptionSettings , child .getValue (), child .getKey ());
329+ assert propertyValueHolder instanceof ObjectNode ;
330+ ((ObjectNode ) propertyValueHolder ).put (child .getKey (), encryptedValue );
331+ } else if (!child .getValue ().isNull ()){
332+ assert propertyValueHolder instanceof ObjectNode ;
333+ encryptAndSerializeValue (encryptionSettings , (ObjectNode ) propertyValueHolder , child .getValue (),
334+ child .getKey ());
335+ }
336+ }
337+ }
338+
339+ else if (propertyValueHolder .isArray ()) {
340+ assert propertyValueHolder instanceof ArrayNode ;
341+ ArrayNode arrayNode = (ArrayNode ) propertyValueHolder ;
342+ if (arrayNode .elements ().next ().isObject () || arrayNode .elements ().next ().isArray ()) {
343+ List <JsonNode > encryptedArray = new ArrayList <>();
344+ for (Iterator <JsonNode > arrayIterator = arrayNode .elements (); arrayIterator .hasNext (); ) {
345+ JsonNode nodeInArray = arrayIterator .next ();
346+ if (nodeInArray .isArray ()) {
347+ encryptedArray .add (encryptAndSerializePatchProperty (encryptionSettings , nodeInArray , propertyName ));
348+ } else {
349+ for (Iterator <Map .Entry <String , JsonNode >> it = nodeInArray .fields (); it .hasNext (); ) {
350+ Map .Entry <String , JsonNode > child = it .next ();
351+ if (child .getValue ().isObject () || child .getValue ().isArray ()) {
352+ JsonNode encryptedValue = encryptAndSerializePatchProperty (encryptionSettings ,
353+ child .getValue (), child .getKey ());
354+ ((ObjectNode ) nodeInArray ).put (child .getKey (), encryptedValue );
355+
356+ } else if (!child .getValue ().isNull ()) {
357+ encryptAndSerializeValue (encryptionSettings , (ObjectNode ) nodeInArray , child .getValue (),
358+ child .getKey ());
359+ }
360+ }
361+ encryptedArray .add (nodeInArray );
362+ }
363+ }
364+ arrayNode .removeAll ();
365+ for (JsonNode encryptedValue : encryptedArray ) {
366+ arrayNode .add (encryptedValue );
367+ }
368+ } else {
369+ List <byte []> encryptedArray = new ArrayList <>();
370+ for (Iterator <JsonNode > it = arrayNode .elements (); it .hasNext (); ) {
371+ encryptedArray .add (encryptAndSerializeValue (encryptionSettings , null , it .next (),
372+ StringUtils .EMPTY ));
373+ }
374+ arrayNode .removeAll ();
375+ for (byte [] encryptedValue : encryptedArray ) {
376+ arrayNode .add (encryptedValue );
377+ }
378+ }
379+ return arrayNode ;
380+ } else {
381+ encryptAndSerializeValue (encryptionSettings , null , propertyValueHolder , propertyName );
382+ }
383+ return propertyValueHolder ;
384+ }
385+
386+ public void encryptAndSerializeProperty (EncryptionSettings encryptionSettings , JsonNode objectNode ,
387+ JsonNode propertyValueHolder , String propertyName ) throws MicrosoftDataEncryptionException , JsonProcessingException {
283388
284389 if (propertyValueHolder .isObject ()) {
285390 for (Iterator <Map .Entry <String , JsonNode >> it = propertyValueHolder .fields (); it .hasNext (); ) {
@@ -325,7 +430,7 @@ public void encryptAndSerializeProperty(EncryptionSettings encryptionSettings, O
325430 }
326431 }
327432 } else {
328- encryptAndSerializeValue (encryptionSettings , objectNode , propertyValueHolder , propertyName );
433+ encryptAndSerializeValue (encryptionSettings , ( ObjectNode ) objectNode , propertyValueHolder , propertyName );
329434 }
330435 }
331436
@@ -458,7 +563,6 @@ public JsonNode decryptAndSerializeValue(EncryptionSettings encryptionSettings,
458563 JsonNode propertyValueHolder , String propertyName ) throws MicrosoftDataEncryptionException , IOException {
459564 byte [] cipherText ;
460565 byte [] cipherTextWithTypeMarker ;
461-
462566 cipherTextWithTypeMarker = propertyValueHolder .binaryValue ();
463567 cipherText = new byte [cipherTextWithTypeMarker .length - 1 ];
464568 System .arraycopy (cipherTextWithTypeMarker , 1 , cipherText , 0 ,
0 commit comments