forked from hyperledger-archives/aries-framework-go
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: validate data model of objects saved in a wallet. (hyperledger-…
…archives#3261) Signed-off-by: Volodymyr Kubiv <volodymyr.kubiv@euristiq.com> Signed-off-by: Abdulbois <abdulbois.tursunov@avast.com>
- Loading branch information
Showing
28 changed files
with
617 additions
and
272 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
{ | ||
"@context": [ | ||
{ | ||
"@version": 1.1 | ||
}, | ||
{ | ||
"id": "@id", | ||
"type": "@type", | ||
|
||
"UniversalWallet2020": "https://w3id.org/wallet#UniversalWallet2020", | ||
"encryptedWalletContents": { | ||
"@id": "https://w3id.org/wallet#encryptedWalletContents", | ||
"@type": "@json" | ||
}, | ||
|
||
"Key": "https://w3id.org/wallet#Key", | ||
"Secret": "https://w3id.org/wallet#Secret", | ||
"Entropy": "https://w3id.org/wallet#Entropy", | ||
"Profile": "https://w3id.org/wallet#Profile", | ||
"Mnemonic": "https://w3id.org/wallet#Mnemonic", | ||
"MetaData": "https://w3id.org/wallet#MetaData", | ||
|
||
"correlation": "https://w3id.org/wallet#correlation", | ||
"tags": "https://w3id.org/wallet#tags", | ||
"note": "https://w3id.org/wallet#note", | ||
"target": "https://w3id.org/wallet#target", | ||
"quorum": "https://w3id.org/wallet#quorum", | ||
"multibase": "https://w3id.org/wallet#multibase", | ||
"hdPath": "https://w3id.org/wallet#hdPath", | ||
|
||
"amount": "https://schema.org/amount", | ||
"currency": "https://schema.org/currency", | ||
"value": "https://schema.org/value", | ||
|
||
"publicKeyJwk": { | ||
"@id": "https://w3id.org/security#publicKeyJwk", | ||
"@type": "@json" | ||
}, | ||
"privateKeyJwk": { | ||
"@id": "https://w3id.org/security#privateKeyJwk", | ||
"@type": "@json" | ||
}, | ||
"privateKeyBase58": "https://w3id.org/security#privateKeyBase58", | ||
"privateKeyWebKms": "https://w3id.org/security#privateKeyWebKms", | ||
"privateKeySecureEnclave": "https://w3id.org/security#privateKeySecureEnclave", | ||
|
||
"Organization": "http://schema.org/Organization", | ||
"Person": "http://schema.org/Person", | ||
"name": "http://schema.org/name", | ||
"description": "http://schema.org/description", | ||
"identifier": "http://schema.org/identifier", | ||
"image": { | ||
"@id": "http://schema.org/image", | ||
"@type": "@id" | ||
} | ||
} | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,189 @@ | ||
/* | ||
Copyright SecureKey Technologies Inc. All Rights Reserved. | ||
SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package jsonld | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"reflect" | ||
|
||
"github.com/piprate/json-gold/ld" | ||
|
||
"github.com/hyperledger/aries-framework-go/pkg/doc/signature/jsonld" | ||
"github.com/hyperledger/aries-framework-go/pkg/doc/util/json" | ||
) | ||
|
||
type validateOpts struct { | ||
strict bool | ||
jsonldDocumentLoader ld.DocumentLoader | ||
externalContext []string | ||
} | ||
|
||
// ValidateOpts sets jsonld validation options. | ||
type ValidateOpts func(opts *validateOpts) | ||
|
||
// WithDocumentLoader option is for passing custom JSON-LD document loader. | ||
func WithDocumentLoader(jsonldDocumentLoader ld.DocumentLoader) ValidateOpts { | ||
return func(opts *validateOpts) { | ||
opts.jsonldDocumentLoader = jsonldDocumentLoader | ||
} | ||
} | ||
|
||
// WithExternalContext option is for definition of external context when doing JSON-LD operations. | ||
func WithExternalContext(externalContext []string) ValidateOpts { | ||
return func(opts *validateOpts) { | ||
opts.externalContext = externalContext | ||
} | ||
} | ||
|
||
// WithStrictValidation sets if strict validation should be used. | ||
func WithStrictValidation(checkStructure bool) ValidateOpts { | ||
return func(opts *validateOpts) { | ||
opts.strict = checkStructure | ||
} | ||
} | ||
|
||
func getValidateOpts(options []ValidateOpts) *validateOpts { | ||
result := &validateOpts{ | ||
strict: true, | ||
} | ||
|
||
for _, opt := range options { | ||
opt(result) | ||
} | ||
|
||
return result | ||
} | ||
|
||
// ValidateJSONLD validates jsonld structure. | ||
func ValidateJSONLD(doc string, options ...ValidateOpts) error { | ||
opts := getValidateOpts(options) | ||
|
||
docMap, err := json.ToMap(doc) | ||
if err != nil { | ||
return fmt.Errorf("convert JSON-LD doc to map: %w", err) | ||
} | ||
|
||
jsonldProc := jsonld.Default() | ||
|
||
docCompactedMap, err := jsonldProc.Compact(docMap, | ||
nil, jsonld.WithDocumentLoader(opts.jsonldDocumentLoader), | ||
jsonld.WithExternalContext(opts.externalContext...)) | ||
if err != nil { | ||
return fmt.Errorf("compact JSON-LD document: %w", err) | ||
} | ||
|
||
if opts.strict && !mapsHaveSameStructure(docMap, docCompactedMap) { | ||
return errors.New("JSON-LD doc has different structure after compaction") | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func mapsHaveSameStructure(originalMap, compactedMap map[string]interface{}) bool { | ||
original := compactMap(originalMap) | ||
compacted := compactMap(compactedMap) | ||
|
||
if reflect.DeepEqual(original, compacted) { | ||
return true | ||
} | ||
|
||
if len(original) != len(compacted) { | ||
return false | ||
} | ||
|
||
for k, v1 := range original { | ||
v1Map, isMap := v1.(map[string]interface{}) | ||
if !isMap { | ||
continue | ||
} | ||
|
||
v2, present := compacted[k] | ||
if !present { // special case - the name of the map was mapped, cannot guess what's a new name | ||
continue | ||
} | ||
|
||
v2Map, isMap := v2.(map[string]interface{}) | ||
if !isMap { | ||
return false | ||
} | ||
|
||
if !mapsHaveSameStructure(v1Map, v2Map) { | ||
return false | ||
} | ||
} | ||
|
||
return true | ||
} | ||
|
||
func compactMap(m map[string]interface{}) map[string]interface{} { | ||
mCopy := make(map[string]interface{}) | ||
|
||
for k, v := range m { | ||
// ignore context | ||
if k == "@context" { | ||
continue | ||
} | ||
|
||
vNorm := compactValue(v) | ||
|
||
switch kv := vNorm.(type) { | ||
case []interface{}: | ||
mCopy[k] = compactSlice(kv) | ||
|
||
case map[string]interface{}: | ||
mCopy[k] = compactMap(kv) | ||
|
||
default: | ||
mCopy[k] = vNorm | ||
} | ||
} | ||
|
||
return mCopy | ||
} | ||
|
||
func compactSlice(s []interface{}) []interface{} { | ||
sCopy := make([]interface{}, len(s)) | ||
|
||
for i := range s { | ||
sItem := compactValue(s[i]) | ||
|
||
switch sItem := sItem.(type) { | ||
case map[string]interface{}: | ||
sCopy[i] = compactMap(sItem) | ||
|
||
default: | ||
sCopy[i] = sItem | ||
} | ||
} | ||
|
||
return sCopy | ||
} | ||
|
||
func compactValue(v interface{}) interface{} { | ||
switch cv := v.(type) { | ||
case []interface{}: | ||
// consists of only one element | ||
if len(cv) == 1 { | ||
return compactValue(cv[0]) | ||
} | ||
|
||
return cv | ||
|
||
case map[string]interface{}: | ||
// contains "id" element only | ||
if len(cv) == 1 { | ||
if _, ok := cv["id"]; ok { | ||
return cv["id"] | ||
} | ||
} | ||
|
||
return cv | ||
|
||
default: | ||
return cv | ||
} | ||
} |
Oops, something went wrong.