Source code for aries_cloudagent.vc.ld_proofs.check

"""Validator methods to check for properties without a context."""

from typing import Sequence, Tuple, Union
from pyld import jsonld


from .document_loader import DocumentLoaderMethod


[docs]def diff_dict_keys( full: dict, with_missing: dict, prefix: str = None, *, document_loader: DocumentLoaderMethod, context, ) -> Sequence[str]: """Get the difference in dict keys between full and with_missing. Checks recursively Args: full (dict): The full dict with all keys present with_missing (dict): The dict with possibly keys missing prefix (str, optional): The prefix. Mostly used for internal recursion. Returns: Sequence[str]: List of missing property names in with_missing """ def _normalize( full: Union[dict, list], with_missing: Union[dict, list] ) -> Tuple[Union[dict, list], Union[dict, list]]: full_type = type(full) with_missing_type = type(with_missing) if full_type == with_missing_type: return (full, with_missing) # First type is a list. Return first item if len is 1 if full_type == list and with_missing_type != list: return (full, [with_missing]) missing = [] # Loop trough all key/value pairs of the full document for key, value in full.items(): key_in_with_missing = key # skip json-ld keywords if jsonld._is_keyword(key): continue _prefix = f"{prefix}.{key}" if prefix else key # If the key is not present in the with_missing dict, add it to the list if key not in with_missing: # The key could change for compaction. We check for the expanded version doc = {"@context": context, key: value} if full.get("type"): doc["type"] = full.get("type") elif full.get("@type"): doc["@type"] = full.get("@type") expanded = jsonld.expand( doc, {"documentLoader": document_loader}, ) if len(expanded) > 0: expanded = expanded[0] expanded.pop("@context", None) expanded.pop("@type", None) if len(expanded) == 1 and list(expanded.keys())[0] in with_missing: key_in_with_missing = list(expanded.keys())[0] else: missing.append(_prefix) continue else: missing.append(_prefix) continue # If the key is present, but is a dict itself, recursively check nested keys if isinstance(value, dict): missing.extend( diff_dict_keys( value, with_missing.get(key_in_with_missing), prefix=_prefix, document_loader=document_loader, context=context, ) ) # If the key is present, but is a list, recursively check nested keys for entries elif isinstance(value, list): value, value_with_missing = _normalize( value, with_missing.get(key_in_with_missing) ) for i in range(len(value)): nested_value = value[i] # Only check for nested list or dict. We're not checking for string values if isinstance(nested_value, (dict, list)): __prefix = f"{_prefix}[{i}]" nested_value, nested_with_missing = _normalize( nested_value, value_with_missing[i] ) missing.extend( diff_dict_keys( nested_value, nested_with_missing, prefix=__prefix, document_loader=document_loader, context=context, ) ) return missing
[docs]def get_properties_without_context( document: dict, document_loader: DocumentLoaderMethod ) -> Sequence[str]: """Get the properties from document that don't have an context definition.""" # FIXME: this doesn't work with nested @context structures... if "verifiableCredential" in document: return [] document = document.copy() # Removes unknown keys from object compact = jsonld.compact( document, document["@context"], {"documentLoader": document_loader}, ) missing = diff_dict_keys( document, compact, document_loader=document_loader, context=document["@context"] ) return missing