diff --git a/sop-java-testfixtures/src/main/java/sop/testsuite/assertions/VerificationAssert.java b/sop-java-testfixtures/src/main/java/sop/testsuite/assertions/VerificationAssert.java index 63fd237..5267148 100644 --- a/sop-java-testfixtures/src/main/java/sop/testsuite/assertions/VerificationAssert.java +++ b/sop-java-testfixtures/src/main/java/sop/testsuite/assertions/VerificationAssert.java @@ -45,12 +45,12 @@ public final class VerificationAssert { } public VerificationAssert hasDescription(String description) { - assertEquals(description, verification.getDescription().get()); + assertEquals(description, verification.getJsonOrDescription().get()); return this; } public VerificationAssert hasDescriptionOrNull(String description) { - if (verification.getDescription().isEmpty()) { + if (verification.getJsonOrDescription().isEmpty()) { return this; } diff --git a/sop-java/src/main/kotlin/sop/Verification.kt b/sop-java/src/main/kotlin/sop/Verification.kt index 20401a9..a8db800 100644 --- a/sop-java/src/main/kotlin/sop/Verification.kt +++ b/sop-java/src/main/kotlin/sop/Verification.kt @@ -15,8 +15,9 @@ data class Verification( val signingKeyFingerprint: String, val signingCertFingerprint: String, val signatureMode: Optional, - val description: Optional + val jsonOrDescription: Optional ) { + @JvmOverloads constructor( creationTime: Date, @@ -31,10 +32,48 @@ data class Verification( Optional.ofNullable(signatureMode), Optional.ofNullable(description?.trim())) + @JvmOverloads + constructor( + creationTime: Date, + signingKeyFingerprint: String, + signingCertFingerprint: String, + signatureMode: SignatureMode? = null, + json: JSON, + jsonSerializer: JSONSerializer + ) : this( + creationTime, + signingKeyFingerprint, + signingCertFingerprint, + Optional.ofNullable(signatureMode), + Optional.of(jsonSerializer.serialize(json))) + + @Deprecated("Replaced by jsonOrDescription", + replaceWith = ReplaceWith("jsonOrDescription") + ) + val description = jsonOrDescription + + /** + * Attempt to parse the [jsonOrDescription] field using the provided [JSONParser] and return the result. + * This method returns `null` if parsing fails. + * + * @param parser [JSONParser] implementation + * @return successfully parsed [JSON] POJO or `null`. + */ + fun getJson(parser: JSONParser): JSON? { + return jsonOrDescription.get() + ?.let { + try { + parser.parse(it) + } catch (e: ParseException) { + null + } + } + } + override fun toString(): String = "${UTCUtil.formatUTCDate(creationTime)} $signingKeyFingerprint $signingCertFingerprint" + (if (signatureMode.isPresent) " mode:${signatureMode.get()}" else "") + - (if (description.isPresent) " ${description.get()}" else "") + (if (jsonOrDescription.isPresent) " ${jsonOrDescription.get()}" else "") companion object { @JvmStatic @@ -73,4 +112,48 @@ data class Verification( } } } + + /** + * POJO data class representing JSON metadata. + * + * @param signers list of supplied CERTS objects that could have issued the signature, identified by + * the name given on the command line. + * @param comment a freeform UTF-8 encoded text describing the verification + * @param ext an extension object containing arbitrary, implementation-specific data + */ + data class JSON( + val signers: List, + val comment: String?, + val ext: Any?) + + /** + * Interface abstracting a JSON parser that parses [JSON] POJOs from single-line strings. + */ + fun interface JSONParser { + /** + * Parse a [JSON] POJO from the given single-line [string]. + * If the string does not represent a JSON object matching the [JSON] definition, + * this method throws a [ParseException]. + * + * @param string [String] representation of the [JSON] object. + * @return parsed [JSON] POJO + * @throws ParseException if the [string] is not a JSON string representing the [JSON] object. + */ + @Throws(ParseException::class) + fun parse(string: String): JSON + } + + /** + * Interface abstracting a JSON serializer that converts [JSON] POJOs into single-line JSON strings. + */ + fun interface JSONSerializer { + + /** + * Serialize the given [JSON] object into a single-line JSON string. + * + * @param json JSON POJO + * @return JSON string + */ + fun serialize(json: JSON): String + } }