17
17
18
18
package org .apache .openwhisk .core .entity
19
19
20
- import org . apache . openwhisk . core . entity . size .{ SizeInt , SizeString }
20
+ import scala . util .{ Failure , Success , Try }
21
21
import spray .json .DefaultJsonProtocol ._
22
22
import spray .json ._
23
23
24
- import scala .collection .immutable .ListMap
25
24
import scala .language .postfixOps
26
- import scala .util .{Failure , Success , Try }
25
+ import org .apache .openwhisk .core .entity .size .SizeInt
26
+ import org .apache .openwhisk .core .entity .size .SizeString
27
27
28
28
/**
29
29
* Parameters is a key-value map from parameter names to parameter values. The value of a
@@ -32,7 +32,7 @@ import scala.util.{Failure, Success, Try}
32
32
* @param key the parameter name, assured to be non-null because it is a value
33
33
* @param value the parameter value, assured to be non-null because it is a value
34
34
*/
35
- protected [core] class Parameters protected [entity] (private val params : Map [ParameterName , ParameterValue ])
35
+ protected [core] class Parameters protected [entity] (protected [entity] val params : Map [ParameterName , ParameterValue ])
36
36
extends AnyVal {
37
37
38
38
/**
@@ -46,13 +46,6 @@ protected[core] class Parameters protected[entity] (private val params: Map[Para
46
46
.foldLeft(0 B )(_ + _)
47
47
}
48
48
49
- protected [entity] def + (p : (ParameterName , ParameterValue )) = {
50
-
51
- Option (p) map { p =>
52
- new Parameters (params + (p._1 -> p._2))
53
- } getOrElse this
54
- }
55
-
56
49
protected [entity] def + (p : ParameterName , v : ParameterValue ) = {
57
50
new Parameters (params + (p -> v))
58
51
}
@@ -71,43 +64,35 @@ protected[core] class Parameters protected[entity] (private val params: Map[Para
71
64
Try (new Parameters (params - new ParameterName (p))) getOrElse this
72
65
}
73
66
74
- /** Gets list all defined parameters. */
67
+ /** Gets set of all defined parameters. */
75
68
protected [core] def definedParameters : Set [String ] = {
76
69
params.keySet filter (params(_).isDefined) map (_.name)
77
70
}
78
71
79
- /** Gets list all defined parameters. */
72
+ /** Gets set of all defined parameters. */
80
73
protected [core] def initParameters : Set [String ] = {
81
74
params.keySet filter (params(_).init) map (_.name)
82
75
}
83
76
84
- protected [core] def getMap = {
85
- params
77
+ /**
78
+ * Gets map of all locked (encrypted) parameters, excluding parameters from given set.
79
+ */
80
+ protected [core] def lockedParameters (exclude : Set [String ] = Set .empty): Map [String , String ] = {
81
+ params.collect {
82
+ case p if p._2.encryption.isDefined && ! exclude.contains(p._1.name) => (p._1.name -> p._2.encryption.get)
83
+ }
86
84
}
85
+
87
86
protected [core] def toJsArray = {
88
87
JsArray (params map { p =>
89
- val init = p._2.init match {
90
- case true => Some (" init" -> p._2.init.toJson)
91
- case _ => None
92
- }
93
- val encrypt = p._2.encryption match {
94
- case (JsNull ) => None
95
- case _ => Some (" encryption" -> p._2.encryption)
96
- }
97
- // Have do use this slightly strange construction to get the json object order identical.
98
- JsObject (ListMap () ++ encrypt ++ init ++ Map (" key" -> p._1.name.toJson, " value" -> p._2.value.toJson))
88
+ val init = if (p._2.init) Some (" init" -> JsTrue ) else None
89
+ val encrypt = p._2.encryption.map(e => (" encryption" -> JsString (e)))
90
+
91
+ JsObject (Map (" key" -> p._1.name.toJson, " value" -> p._2.value) ++ init ++ encrypt)
99
92
} toSeq : _* )
100
93
}
101
94
102
- protected [core] def toJsObject =
103
- JsObject (params.map(p => {
104
- val newValue =
105
- if (p._2.encryption == JsNull )
106
- p._2.value.toJson
107
- else
108
- JsObject (" value" -> p._2.value.toJson, " encryption" -> p._2.encryption, " init" -> p._2.init.toJson)
109
- (p._1.name, newValue)
110
- }))
95
+ protected [core] def toJsObject = JsObject (params.map(p => (p._1.name -> p._2.value.toJson)))
111
96
112
97
override def toString = toJsArray.compactPrint
113
98
@@ -144,6 +129,40 @@ protected[core] class Parameters protected[entity] (private val params: Map[Para
144
129
case _ => true
145
130
} getOrElse valueForNonExistent
146
131
}
132
+
133
+ /**
134
+ * Encrypts any parameters that are not yet encoded.
135
+ *
136
+ * @param encoder the encoder to transform parameter values with
137
+ * @return parameters with all values encrypted
138
+ */
139
+ def lock (encoder : Option [Encrypter ] = None ): Parameters = {
140
+ encoder
141
+ .map { coder =>
142
+ new Parameters (params.map {
143
+ case (paramName, paramValue) if paramValue.encryption.isEmpty =>
144
+ paramName -> coder.encrypt(paramValue)
145
+ case p => p
146
+ })
147
+ }
148
+ .getOrElse(this )
149
+ }
150
+
151
+ /**
152
+ * Decodes parameters. If the encryption scheme for a parameter is not recognized, it is not modified.
153
+ *
154
+ * @param decoder the decoder to use to transform locked values
155
+ * @return parameters will all values decoded (where scheme is known)
156
+ */
157
+ def unlock (decoder : ParameterEncryption ): Parameters = {
158
+ new Parameters (params.map {
159
+ case p @ (paramName, paramValue) =>
160
+ paramValue.encryption
161
+ .map(paramName -> decoder.encryptor(_).decrypt(paramValue))
162
+ .getOrElse(p)
163
+ })
164
+ }
165
+
147
166
}
148
167
149
168
/**
@@ -175,21 +194,18 @@ protected[entity] class ParameterName protected[entity] (val name: String) exten
175
194
*
176
195
* @param v the value of the parameter, may be null
177
196
* @param init if true, this parameter value is only offered to the action during initialization
178
- * @param encryptionDetails the name of the encrypter used to store the parameter.
197
+ * @param encryption the name of the encryption algorithm used to store the parameter or none (plain text)
179
198
*/
180
199
protected [entity] case class ParameterValue protected [entity] (private val v : JsValue ,
181
200
val init : Boolean ,
182
- val encryptionDetails : Option [JsString ] = None ) {
201
+ val encryption : Option [String ] = None ) {
183
202
184
203
/** @return JsValue if defined else JsNull. */
185
204
protected [entity] def value = Option (v) getOrElse JsNull
186
205
187
206
/** @return true iff value is not JsNull. */
188
207
protected [entity] def isDefined = value != JsNull
189
208
190
- /** @return JsValue if defined else JsNull. */
191
- protected [entity] def encryption = encryptionDetails getOrElse JsNull
192
-
193
209
/**
194
210
* The size of the ParameterValue entity as ByteSize.
195
211
*/
@@ -208,8 +224,8 @@ protected[core] object Parameters extends ArgNormalizer[Parameters] {
208
224
* Creates a parameter tuple from a pair of strings.
209
225
* A convenience method for tests.
210
226
*
211
- * @param p the parameter name
212
- * @param v the parameter value
227
+ * @param p the parameter name
228
+ * @param v the parameter value
213
229
* @param init the parameter is for initialization
214
230
* @return (ParameterName, ParameterValue)
215
231
* @throws IllegalArgumentException if key is not defined
@@ -224,8 +240,8 @@ protected[core] object Parameters extends ArgNormalizer[Parameters] {
224
240
/**
225
241
* Creates a parameter tuple from a parameter name and JsValue.
226
242
*
227
- * @param p the parameter name
228
- * @param v the parameter value
243
+ * @param p the parameter name
244
+ * @param v the parameter value
229
245
* @param init the parameter is for initialization
230
246
* @return (ParameterName, ParameterValue)
231
247
* @throws IllegalArgumentException if key is not defined
@@ -252,29 +268,6 @@ protected[core] object Parameters extends ArgNormalizer[Parameters] {
252
268
ParameterValue (Option (v).getOrElse(JsNull ), false , None ))
253
269
}
254
270
255
- def readMergedList (value : JsValue ): Parameters =
256
- Try {
257
-
258
- val JsObject (obj) = value
259
- new Parameters (
260
- obj
261
- .map((tuple : (String , JsValue )) => {
262
- val key = new ParameterName (tuple._1)
263
- val paramVal : ParameterValue = tuple._2 match {
264
- case o : JsObject =>
265
- o.getFields(" value" , " init" , " encryption" ) match {
266
- case Seq (v : JsValue , JsBoolean (i), e : JsString ) =>
267
- ParameterValue (v, i, Some (e))
268
- case _ => ParameterValue (o, false , None )
269
- }
270
- case v : JsValue => ParameterValue (v, false , None )
271
- }
272
- (key, paramVal)
273
- })
274
- .toMap)
275
- } getOrElse deserializationError(
276
- " parameters malformed, could not get a JsObject from: " + (if (value != null ) value.toString() else " " ))
277
-
278
271
override protected [core] implicit val serdes = new RootJsonFormat [Parameters ] {
279
272
def write (p : Parameters ) = p.toJsArray
280
273
@@ -285,35 +278,12 @@ protected[core] object Parameters extends ArgNormalizer[Parameters] {
285
278
* @param parameters the JSON representation of an parameter array
286
279
* @return Parameters instance if parameters conforms to schema
287
280
*/
288
- def read (value : JsValue ) =
289
- Try {
290
- val JsArray (params) = value
291
- params
292
- } flatMap {
293
- read(_)
294
- } getOrElse {
295
- Try {
296
- var converted = new ListMap [ParameterName , ParameterValue ]()
297
- val JsObject (o) = value
298
- o.foreach(i =>
299
- i._2.asJsObject.getFields(" value" , " init" , " encryption" ) match {
300
- case Seq (v : JsValue , JsBoolean (init), e : JsValue ) if e != JsNull =>
301
- val key = new ParameterName (i._1)
302
- val value = ParameterValue (v, init, Some (JsString (e.convertTo[String ])))
303
- converted = converted + (key -> value)
304
- case Seq (v : JsValue , JsBoolean (init), e : JsValue ) =>
305
- val key = new ParameterName (i._1)
306
- val value = ParameterValue (v, init, None )
307
- converted = converted + (key -> value)
308
- })
309
- if (converted.size == 0 ) {
310
- deserializationError(" parameters malformed no parameters available: " + value.toString())
311
- } else {
312
- new Parameters (converted)
313
- }
314
- } getOrElse deserializationError(
315
- " parameters malformed could not read directly: " + (if (value != null ) value.toString() else " " ))
281
+ def read (value : JsValue ): Parameters = {
282
+ value match {
283
+ case JsArray (params) => read(params).getOrElse(deserializationError(" parameters malformed!" ))
284
+ case _ => deserializationError(" parameters malformed!" )
316
285
}
286
+ }
317
287
318
288
/**
319
289
* Gets parameters as a Parameters instances.
@@ -323,29 +293,33 @@ protected[core] object Parameters extends ArgNormalizer[Parameters] {
323
293
* @return Parameters instance if parameters conforms to schema
324
294
*/
325
295
def read (params : Vector [JsValue ]) = Try {
326
- new Parameters (
327
- params
328
- .map(i => {
329
- i.asJsObject.getFields(" key" , " value" , " init" , " encryption" ) match {
330
- case Seq (JsString (k), v : JsValue ) =>
331
- val key = new ParameterName (k)
332
- val value = ParameterValue (v, false )
333
- (key, value)
334
- case Seq (JsString (k), v : JsValue , JsBoolean (i), e : JsString ) =>
335
- val key = new ParameterName (k)
336
- val value = ParameterValue (v, i, Some (e))
337
- (key, value)
338
- case Seq (JsString (k), v : JsValue , JsBoolean (i)) =>
339
- val key = new ParameterName (k)
340
- val value = ParameterValue (v, i)
341
- (key, value)
342
- case Seq (JsString (k), v : JsValue , e : JsString ) if (i.asJsObject.fields.contains(" encryption" )) =>
343
- val key = new ParameterName (k)
344
- val value = ParameterValue (v, false , Some (e))
345
- (key, value)
346
- }
347
- })
348
- .toMap)
296
+ new Parameters (params.map {
297
+ case o @ JsObject (fields) =>
298
+ o.getFields(" key" , " value" , " init" , " encryption" ) match {
299
+ case Seq (JsString (k), v : JsValue ) if fields.contains(" value" ) =>
300
+ val key = new ParameterName (k)
301
+ val value = ParameterValue (v, false )
302
+ (key, value)
303
+ case Seq (JsString (k), v : JsValue , JsBoolean (i)) =>
304
+ val key = new ParameterName (k)
305
+ val value = ParameterValue (v, i)
306
+ (key, value)
307
+ case Seq (JsString (k), v : JsValue , JsBoolean (i), JsString (e)) =>
308
+ val key = new ParameterName (k)
309
+ val value = ParameterValue (v, i, Some (e))
310
+ (key, value)
311
+ case Seq (JsString (k), v : JsValue , JsBoolean (i), JsNull ) =>
312
+ val key = new ParameterName (k)
313
+ val value = ParameterValue (v, i, None )
314
+ (key, value)
315
+ case Seq (JsString (k), v : JsValue , JsString (e))
316
+ if fields.contains(" value" ) && fields.contains(" encryption" ) =>
317
+ val key = new ParameterName (k)
318
+ val value = ParameterValue (v, false , Some (e))
319
+ (key, value)
320
+ }
321
+ case _ => deserializationError(" invalid parameter" )
322
+ }.toMap)
349
323
}
350
324
}
351
325
}
0 commit comments