final
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
"""Format validator for raw (JSON) documents in the es.4 format"""
|
||||
"""Document class for the es.4 format"""
|
||||
|
||||
from datetime import datetime, timezone
|
||||
from hashlib import sha256
|
||||
@@ -29,9 +29,7 @@ class RawDocument(TypedDict, total=False):
|
||||
|
||||
|
||||
class Es4Document(Document): # pylint: disable=too-many-instance-attributes
|
||||
"""Validator for the 'es.4' format
|
||||
|
||||
Checks if documents are spec-compliant before ingesting, and signs them according to spec.
|
||||
"""An es.4 format document
|
||||
|
||||
See https://earthstar-project.org/specs/data-spec
|
||||
"""
|
||||
@@ -129,7 +127,7 @@ class Es4Document(Document): # pylint: disable=too-many-instance-attributes
|
||||
signature: Optional[str] = None,
|
||||
delete_after: Optional[datetime] = None,
|
||||
):
|
||||
self.author: Identity = author
|
||||
self.author = author
|
||||
self.path = path
|
||||
self.signature = signature
|
||||
self._content = content or ''
|
||||
@@ -142,6 +140,8 @@ class Es4Document(Document): # pylint: disable=too-many-instance-attributes
|
||||
def from_json(cls, raw_document: Dict[str, Any]) -> 'Es4Document':
|
||||
"""Validate raw_document as an es.4 document and create an ``Es4Document`` from it
|
||||
|
||||
Checks if documents are spec-compliant before ingesting, and signs them according to spec.
|
||||
|
||||
:returns: a new ``Es4Document``
|
||||
:raises ValidationError: if anything is wrong
|
||||
"""
|
||||
@@ -245,14 +245,24 @@ class Es4Document(Document): # pylint: disable=too-many-instance-attributes
|
||||
hasher = sha256()
|
||||
|
||||
for key, value in sorted(hash_keys.items(), key=lambda elem: elem[0]):
|
||||
# Skip null fields
|
||||
if value is None:
|
||||
continue
|
||||
|
||||
# Otherwise, append the fieldname and value.
|
||||
# Tab and newline are our field separators.
|
||||
# Convert integers to strings here.
|
||||
# (The newline is included on the last field.)
|
||||
hasher.update(f'{key}\t{value}\n'.encode('utf-8'))
|
||||
|
||||
# Binary digest, not hex digest string! Then convert bytes to Earthstar b32 format with
|
||||
# leading 'b'.
|
||||
return base32_bytes_to_string(hasher.digest())
|
||||
|
||||
def sign(self, identity: Optional[Identity] = None) -> None:
|
||||
"""Sign the document and store the signature into the document (mutating it)
|
||||
"""
|
||||
|
||||
if identity and identity != self.author:
|
||||
raise ValidationError(
|
||||
"when signing a document, keypair address must match document author"
|
||||
@@ -358,3 +368,21 @@ class Es4Document(Document): # pylint: disable=too-many-instance-attributes
|
||||
|
||||
if content is not None and calculated_hash != content_hash:
|
||||
raise ValidationError("content does not match contentHash")
|
||||
|
||||
@staticmethod
|
||||
def compare_newest_first(doc_a, doc_b):
|
||||
"""Compare two documents based on their time stamp"""
|
||||
|
||||
if doc_a.timestamp < doc_b.timestamp:
|
||||
return Cmp.LT
|
||||
|
||||
if doc_b.timestamp > doc_b.timestamp:
|
||||
return Cmp.GT
|
||||
|
||||
if doc_a.signature < doc_b.signature:
|
||||
return Cmp.LT
|
||||
|
||||
if doc_a.signature > doc_b.signature:
|
||||
return Cmp.GT
|
||||
|
||||
return Cmp.EQ
|
||||
|
Reference in New Issue
Block a user