@@ -13,7 +13,8 @@ function FieldLevelEncryption(config) {
13
13
this . decrypt = decrypt ;
14
14
this . config = config ;
15
15
this . crypto = new Crypto ( config ) ;
16
- this . isWithHeader = config . hasOwnProperty ( "ivHeaderName" ) && config . hasOwnProperty ( "encryptedKeyHeaderName" ) ;
16
+ this . isWithHeader = Object . prototype . hasOwnProperty . call ( config , "ivHeaderName" ) &&
17
+ Object . prototype . hasOwnProperty . call ( config , "encryptedKeyHeaderName" ) ;
17
18
this . encryptionResponseProperties = [ this . config . ivFieldName , this . config . encryptedKeyFieldName ,
18
19
this . config . publicKeyFingerprintFieldName , this . config . oaepHashingAlgorithmFieldName ] ;
19
20
}
@@ -25,7 +26,6 @@ function hasConfig(config, endpoint) {
25
26
if ( config && endpoint ) {
26
27
endpoint = endpoint . split ( "?" ) . shift ( ) ;
27
28
const conf = config . paths . find ( ( elem ) => {
28
- // TODO grep from last index
29
29
const regex = new RegExp ( elem . path , "g" ) ;
30
30
return endpoint . match ( regex ) ;
31
31
}
@@ -45,7 +45,7 @@ function elemFromPath(path, obj) {
45
45
if ( path && paths . length > 0 ) {
46
46
paths . forEach ( ( e ) => {
47
47
parent = obj ;
48
- obj = obj [ e ] ;
48
+ obj = isJsonRoot ( e ) ? obj : obj [ e ] ;
49
49
}
50
50
) ;
51
51
}
@@ -59,7 +59,7 @@ function elemFromPath(path, obj) {
59
59
}
60
60
61
61
/**
62
- * Set encrpytion header parameters
62
+ * Set encryption header parameters
63
63
*
64
64
* @param header HTTP header
65
65
* @param params Encryption parameters
@@ -81,23 +81,24 @@ function setHeader(header, params) {
81
81
* @returns {{header: *, body: *} }
82
82
*/
83
83
function encrypt ( endpoint , header , body ) {
84
+ let bodyMap = body ;
84
85
const fleConfig = hasConfig ( this . config , endpoint ) ;
85
86
if ( fleConfig ) {
86
87
if ( ! this . isWithHeader ) {
87
- fleConfig . toEncrypt . forEach ( ( v ) => {
88
- encryptBody . call ( this , v , body ) ;
88
+ bodyMap = fleConfig . toEncrypt . map ( ( v ) => {
89
+ return encryptBody . call ( this , v , body ) ;
89
90
} ) ;
90
91
} else {
91
92
const encParams = this . crypto . newEncryptionParams ( { } ) ;
92
- fleConfig . toEncrypt . forEach ( ( v ) => {
93
- body = encryptWithHeader . call ( this , encParams , v , body ) ;
93
+ bodyMap = fleConfig . toEncrypt . map ( ( v ) => {
94
+ return encryptWithHeader . call ( this , encParams , v , body ) ;
94
95
} ) ;
95
96
setHeader . call ( this , header , encParams ) ;
96
97
}
97
98
}
98
99
return {
99
100
header : header ,
100
- body : body
101
+ body : fleConfig ? computeBody ( fleConfig . toEncrypt , body , bodyMap ) : body
101
102
} ;
102
103
}
103
104
@@ -110,44 +111,44 @@ function encrypt(endpoint, header, body) {
110
111
*/
111
112
function decrypt ( response ) {
112
113
const body = response . body ;
114
+ let bodyMap = response . body ;
113
115
const fleConfig = hasConfig ( this . config , response . request . url ) ;
114
116
if ( fleConfig ) {
115
- if ( ! this . isWithHeader ) {
116
- fleConfig . toDecrypt . forEach ( ( v ) => {
117
- decryptBody . call ( this , v , body ) ;
118
- } ) ;
119
- } else {
120
- fleConfig . toDecrypt . forEach ( ( v ) => {
121
- decryptWithHeader . call ( this , v , body , response ) ;
122
- } ) ;
123
- }
117
+ bodyMap = fleConfig . toDecrypt . map ( ( v ) => {
118
+ if ( ! this . isWithHeader ) {
119
+ return decryptBody . call ( this , v , body ) ;
120
+ } else {
121
+ return decryptWithHeader . call ( this , v , body , response ) ;
122
+ }
123
+ } ) ;
124
124
}
125
- return body ;
125
+ return fleConfig ? computeBody ( fleConfig . toDecrypt , body , bodyMap ) : body
126
126
}
127
127
128
128
/**
129
- * Encrypt body nodes inplace with given path
129
+ * Encrypt body nodes with given path
130
130
*
131
131
* @private
132
132
* @param path Config json path
133
133
* @param body Body to encrypt
134
134
*/
135
135
function encryptBody ( path , body ) {
136
136
const elem = elemFromPath ( path . element , body ) ;
137
- if ( elem && elem . node ) {
137
+ if ( elem && elem . node ) {
138
138
const encryptedData = this . crypto . encryptData ( { data : elem . node } ) ;
139
- utils . mutateObjectProperty ( path . obj ,
139
+ body = utils . mutateObjectProperty ( path . obj ,
140
140
encryptedData ,
141
141
body ) ;
142
142
// delete encrypted field if not overridden
143
- if ( path . element !== path . obj + "." + this . config . encryptedValueFieldName ) {
143
+ if ( ! isJsonRoot ( path . obj ) && path . element !== path . obj + "." + this . config . encryptedValueFieldName ) {
144
144
utils . deleteNode ( path . element , body ) ;
145
145
}
146
146
}
147
+ return body ;
147
148
}
148
149
149
150
/**
150
- * Encrypt body nodes inplace with given path, without setting crypto info in the body
151
+ * Encrypt body nodes with given path, without setting crypto info in the body
151
152
*
152
153
* @private
153
154
* @param encParams encoding params to use
@@ -158,15 +159,17 @@ function encryptBody(path, body) {
158
159
function encryptWithHeader ( encParams , path , body ) {
159
160
const elem = elemFromPath ( path . element , body ) . node ;
160
161
const encrypted = this . crypto . encryptData ( { data : elem } , encParams ) ;
161
- return { [ path . obj ] : { [ this . config . encryptedValueFieldName ] : encrypted [ this . config . encryptedValueFieldName ] } } ;
162
+ const data = { [ this . config . encryptedValueFieldName ] : encrypted [ this . config . encryptedValueFieldName ] } ;
163
+ return isJsonRoot ( path . obj ) ? data : { [ path . obj ] : data } ;
162
164
}
163
165
164
166
/**
165
- * Decrypt body nodes inplace with given path
167
+ * Decrypt body nodes with given path
166
168
*
167
169
* @private
168
170
* @param path Config json path
169
171
* @param body encrypted body
172
+ * @returns {Object } Decrypted body
170
173
*/
171
174
function decryptBody ( path , body ) {
172
175
const elem = elemFromPath ( path . element , body ) ;
@@ -177,12 +180,13 @@ function decryptBody(path, body) {
177
180
elem . node [ this . config . oaepHashingAlgorithmFieldName ] , // oaepHashingAlgorithm
178
181
elem . node [ this . config . encryptedKeyFieldName ] // encryptedKey
179
182
) ;
180
- utils . mutateObjectProperty ( path . obj , decryptedObj , body , path . element , this . encryptionResponseProperties ) ;
183
+ return utils . mutateObjectProperty ( path . obj , decryptedObj , body , path . element , this . encryptionResponseProperties ) ;
181
184
}
185
+ return body ;
182
186
}
183
187
184
188
/**
185
- * Decrypt body nodes inplace with given path, getting crypto info from the header
189
+ * Decrypt body nodes with given path, getting crypto info from the header
186
190
*
187
191
* @private
188
192
* @param path Config json path
@@ -191,19 +195,33 @@ function decryptBody(path, body) {
191
195
*/
192
196
function decryptWithHeader ( path , body , response ) {
193
197
const elemEncryptedNode = elemFromPath ( path . obj , body ) ;
194
- if ( elemEncryptedNode . node [ path . element ] ) {
195
- const encryptedData = elemEncryptedNode . node [ path . element ] [ this . config . encryptedValueFieldName ] ;
198
+ const node = isJsonRoot ( path . element ) ? elemEncryptedNode . node : elemEncryptedNode . node [ path . element ] ;
199
+ if ( node ) {
200
+ const encryptedData = node [ this . config . encryptedValueFieldName ] ;
196
201
for ( const k in body ) {
197
202
// noinspection JSUnfilteredForInLoop
198
203
delete body [ k ] ;
199
204
}
200
- Object . assign ( body , this . crypto . decryptData (
205
+ const decrypted = this . crypto . decryptData (
201
206
encryptedData ,
202
207
response . header [ this . config . ivHeaderName ] ,
203
208
response . header [ this . config . oaepHashingAlgorithmHeaderName ] ,
204
209
response . header [ this . config . encryptedKeyHeaderName ]
205
- ) ) ;
210
+ ) ;
211
+ return isJsonRoot ( path . obj ) ? decrypted : Object . assign ( body , decrypted ) ;
206
212
}
207
213
}
208
214
215
+ function isJsonRoot ( elem ) {
216
+ return elem === "$" ;
217
+ }
218
+
219
+ function computeBody ( configParam , body , bodyMap ) {
220
+ return ( hasEncryptionParam ( configParam , bodyMap ) ) ? bodyMap . pop ( ) : body ;
221
+ }
222
+
223
+ function hasEncryptionParam ( encParams , bodyMap ) {
224
+ return encParams && encParams . length === 1 && bodyMap && bodyMap [ 0 ] ;
225
+ }
226
+
209
227
module . exports = FieldLevelEncryption ;
0 commit comments