Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions sdk/assertion.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,41 @@ func (a Assertion) GetHash() ([]byte, error) {
return ocrypto.SHA256AsHex(transformedJSON), nil
}

func (s *Statement) UnmarshalJSON(data []byte) error {
// Define a custom struct for deserialization
type Alias Statement
aux := &struct {
Value json.RawMessage `json:"value,omitempty"`
*Alias
}{
Alias: (*Alias)(s),
}

if err := json.Unmarshal(data, &aux); err != nil {
return err
}

// Attempt to decode Value as an object
var temp map[string]interface{}
if json.Unmarshal(aux.Value, &temp) == nil {
// Re-encode the object as a string and assign to Value
objAsString, err := json.Marshal(temp)
if err != nil {
return err
}
s.Value = string(objAsString)
} else {
// Assign raw string to Value
var str string
if err := json.Unmarshal(aux.Value, &str); err != nil {
return fmt.Errorf("value is neither a valid JSON object nor a string: %s", string(aux.Value))
}
s.Value = str
}

return nil
}

// Statement includes information applying to the scope of the assertion.
// It could contain rights, handling instructions, or general metadata.
type Statement struct {
Expand Down
149 changes: 149 additions & 0 deletions sdk/assertion_test.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package sdk

import (
"encoding/json"
"testing"

"github.com/gowebpki/jcs"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
Expand Down Expand Up @@ -33,3 +35,150 @@ func TestTDFWithAssertion(t *testing.T) {

assert.Equal(t, "4a447a13c5a32730d20bdf7feecb9ffe16649bc731914b574d80035a3927f860", string(hashOfAssertion))
}

func TestTDFWithAssertionJsonObject(t *testing.T) {
// Define the assertion config with a JSON object in the statement value
value := `{
"ocl": {
"pol": "2ccf11cb-6c9a-4e49-9746-a7f0a295945d",
"cls": "SECRET",
"catl": [
{
"type": "P",
"name": "Releasable To",
"vals": ["usa"]
}
],
"dcr": "2024-12-17T13:00:52Z"
},
"context": {
"@base": "urn:nato:stanag:5636:A:1:elements:json"
}
}`
assertionConfig := AssertionConfig{
ID: "ab43266781e64b51a4c52ffc44d6152c",
Type: "handling",
Scope: "payload",
AppliesToState: "", // Use "" or a pointer to a string if necessary
Statement: Statement{
Format: "json-structured",
Value: value,
},
}

// Set up the assertion
assertion := Assertion{
ID: assertionConfig.ID,
Type: assertionConfig.Type,
Scope: assertionConfig.Scope,
AppliesToState: assertionConfig.AppliesToState,
Statement: assertionConfig.Statement,
}

var obj map[string]interface{}
err := json.Unmarshal([]byte(assertionConfig.Statement.Value), &obj)
require.NoError(t, err, "Unmarshaling the Value into a map should succeed")

ocl, ok := obj["ocl"].(map[string]interface{})
require.True(t, ok, "Parsed Value should contain 'ocl' as an object")
require.Equal(t, "SECRET", ocl["cls"], "'cls' field should match")
require.Equal(t, "2ccf11cb-6c9a-4e49-9746-a7f0a295945d", ocl["pol"], "'pol' field should match")

context, ok := obj["context"].(map[string]interface{})
require.True(t, ok, "Parsed Value should contain 'context' as an object")
require.Equal(t, "urn:nato:stanag:5636:A:1:elements:json", context["@base"], "'@base' field should match")

// Calculate the hash of the assertion
hashOfAssertion, err := assertion.GetHash()
require.NoError(t, err)

expectedHash := "722dd40a90a0f7ec718fb156207a647e64daa43c0ae1f033033473a172c72aee"
assert.Equal(t, expectedHash, string(hashOfAssertion))
}

func TestDeserializingAssertionWithJSONInStatementValue(t *testing.T) {
// the assertion has a JSON object in the statement value
assertionVal := ` {
"id": "bacbe31eab384df39d35a5fbe83778de",
"type": "handling",
"scope": "tdo",
"appliesToState": null,
"statement": {
"format": "json-structured",
"value": {
"ocl": {
"pol": "2ccf11cb-6c9a-4e49-9746-a7f0a295945d",
"cls": "SECRET",
"catl": [
{
"type": "P",
"name": "Releasable To",
"vals": [
"usa"
]
}
],
"dcr": "2024-12-17T13:00:52Z"
},
"context": {
"@base": "urn:nato:stanag:5636:A:1:elements:json"
}
}
},
"binding": {
"method": "jws",
"signature": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJDb25maWRlbnRpYWxpdHlJbmZvcm1hdGlvbiI6InsgXCJvY2xcIjogeyBcInBvbFwiOiBcIjJjY2YxMWNiLTZjOWEtNGU0OS05NzQ2LWE3ZjBhMjk1OTQ1ZFwiLCBcImNsc1wiOiBcIlNFQ1JFVFwiLCBcImNhdGxcIjogWyB7IFwidHlwZVwiOiBcIlBcIiwgXCJuYW1lXCI6IFwiUmVsZWFzYWJsZSBUb1wiLCBcInZhbHNcIjogWyBcInVzYVwiIF0gfSBdLCBcImRjclwiOiBcIjIwMjQtMTItMTdUMTM6MDA6NTJaXCIgfSwgXCJjb250ZXh0XCI6IHsgXCJAYmFzZVwiOiBcInVybjpuYXRvOnN0YW5hZzo1NjM2OkE6MTplbGVtZW50czpqc29uXCIgfSB9In0.LlOzRLKKXMAqXDNsx9Ha5915CGcAkNLuBfI7jJmx6CnfQrLXhlRHWW3_aLv5DPsKQC6vh9gDQBH19o7q7EcukvK4IabA4l0oP8ePgHORaajyj7ONjoeudv_zQ9XN7xU447S3QznzOoasuWAFoN4682Fhf99Kjl6rhDCzmZhTwQw9drP7s41nNA5SwgEhoZj-X9KkNW5GbWjA95eb8uVRRWk8dOnVje6j8mlJuOtKdhMxQ8N5n0vBYYhiss9c4XervBjWAxwAMdbRaQN0iPZtMzIkxKLYxBZDvTnYSAqzpvfGPzkSI-Ze_hUZs2hp-ADNnYUJBf_LzFmKyqHjPSFQ7A"
}
}`

var assertion Assertion
err := json.Unmarshal([]byte(assertionVal), &assertion)
require.NoError(t, err, "Error deserializing the assertion with a JSON object in the statement value")

var expectedAssertionValue, _ = jcs.Transform([]byte(`{
"ocl": {
"pol": "2ccf11cb-6c9a-4e49-9746-a7f0a295945d",
"cls": "SECRET",
"catl": [
{
"type": "P",
"name": "Releasable To",
"vals": [
"usa"
]
}
],
"dcr": "2024-12-17T13:00:52Z"
},
"context": {
"@base": "urn:nato:stanag:5636:A:1:elements:json"
}
}`))
actualAssertionValue, err := jcs.Transform([]byte(assertion.Statement.Value))
require.NoError(t, err, "Error transforming the assertion statement value")
assert.Equal(t, expectedAssertionValue, actualAssertionValue)
}

func TestDeserializingAssertionWithStringInStatementValue(t *testing.T) {
// the assertion has a JSON object in the statement value
assertionVal := ` {
"id": "bacbe31eab384df39d35a5fbe83778de",
"type": "handling",
"scope": "tdo",
"appliesToState": null,
"statement": {
"format": "json-structured",
"value": "this is a value"
},
"binding": {
"method": "jws",
"signature": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJDb25maWRlbnRpYWxpdHlJbmZvcm1hdGlvbiI6InsgXCJvY2xcIjogeyBcInBvbFwiOiBcIjJjY2YxMWNiLTZjOWEtNGU0OS05NzQ2LWE3ZjBhMjk1OTQ1ZFwiLCBcImNsc1wiOiBcIlNFQ1JFVFwiLCBcImNhdGxcIjogWyB7IFwidHlwZVwiOiBcIlBcIiwgXCJuYW1lXCI6IFwiUmVsZWFzYWJsZSBUb1wiLCBcInZhbHNcIjogWyBcInVzYVwiIF0gfSBdLCBcImRjclwiOiBcIjIwMjQtMTItMTdUMTM6MDA6NTJaXCIgfSwgXCJjb250ZXh0XCI6IHsgXCJAYmFzZVwiOiBcInVybjpuYXRvOnN0YW5hZzo1NjM2OkE6MTplbGVtZW50czpqc29uXCIgfSB9In0.LlOzRLKKXMAqXDNsx9Ha5915CGcAkNLuBfI7jJmx6CnfQrLXhlRHWW3_aLv5DPsKQC6vh9gDQBH19o7q7EcukvK4IabA4l0oP8ePgHORaajyj7ONjoeudv_zQ9XN7xU447S3QznzOoasuWAFoN4682Fhf99Kjl6rhDCzmZhTwQw9drP7s41nNA5SwgEhoZj-X9KkNW5GbWjA95eb8uVRRWk8dOnVje6j8mlJuOtKdhMxQ8N5n0vBYYhiss9c4XervBjWAxwAMdbRaQN0iPZtMzIkxKLYxBZDvTnYSAqzpvfGPzkSI-Ze_hUZs2hp-ADNnYUJBf_LzFmKyqHjPSFQ7A"
}
}`

var assertion Assertion
err := json.Unmarshal([]byte(assertionVal), &assertion)
require.NoError(t, err, "Error deserializing the assertion with a JSON object in the statement value")

assert.Equal(t, "this is a value", assertion.Statement.Value)
}
Loading