commit 2c1cac3b1c2825d0838a320b19b68f8ee4b42359
parent a2ab491b7076208e5984a8ebedd3628e353dd2e8
Author: Carlosokumu <carlosokumu254@gmail.com>
Date: Mon, 16 Mar 2026 07:15:39 +0300
chane hash algo to 512 for uniformity
Diffstat:
2 files changed, 73 insertions(+), 74 deletions(-)
diff --git a/dummy/usawa/asset.py b/dummy/usawa/asset.py
@@ -11,7 +11,7 @@ import magic
from .constant import NSPREFIX
from .xml import nsmap
-logg = logging.getLogger('usawa.asset')
+logg = logging.getLogger("usawa.asset")
BLOCKSIZE = 512
@@ -29,16 +29,21 @@ Does not check whether or not the file exists.
:return: Stem name and extension.
:rtype: Tuple
"""
+
+
def parse_path(path):
if len(path) == 0 or path == None:
- raise ValueError('empty path')
+ raise ValueError("empty path")
s = os.path.basename(path)
- v = s.rsplit('.', maxsplit=1)
+ v = s.rsplit(".", maxsplit=1)
slug = v[0]
ext = None
if len(v) == 2:
ext = v[1]
- return (slug, ext,)
+ return (
+ slug,
+ ext,
+ )
class Asset:
@@ -50,6 +55,7 @@ class Asset:
Asset.from_io() - Read from a io.BufferedIOBase input stream.
Asset.from_tree() - Recreate from an XML tree.
"""
+
def __init__(self, digest=None):
self.digest = digest
self.mime = None
@@ -60,7 +66,6 @@ class Asset:
self.uuid = None
self.description = None
-
"""Return the preferred filename with extension for the asset.
Must always return a value. The filename may or may not have an extension.
@@ -68,13 +73,13 @@ class Asset:
:return: Filename
:rtype: str
"""
+
def get_filename(self):
s = self.slug
if self.ext != None:
- s += '.' + self.ext
+ s += "." + self.ext
return s
-
"""Return the mime type.
The encoding specifier will be added if it exists.
@@ -84,28 +89,28 @@ class Asset:
:return: Mime string
:rtype: str
"""
+
def get_mimestring(self):
s = self.mime
if s != None:
if self.enc != None:
- s += ';charset=' + self.enc
+ s += ";charset=" + self.enc
return s
-
"""Return the digest of the asset, in hex.
:raises AttributeError: Digest not set
:return: Digest hex
:rtype: str
"""
+
def get_digest(self, binary=False):
if self.digest == None:
- raise AttributeError('')
+ raise AttributeError("")
if binary:
return self.digest
return self.digest.hex()
-
"""Instantiate an asset object from a local file.
File is opened and the file object is passed on to the from_io() method.
@@ -121,11 +126,19 @@ class Asset:
:raises IsADirectoryError: Path is a directory.
:raises PermissionError: File cannot be read.
"""
+
@staticmethod
def from_file(filepath, description=None, slug=None, mimetype=None, extref=None):
- f = open(filepath, 'rb')
- return Asset.from_io(f, filepath, closer=f.close, description=description, slug=slug, mimetype=mimetype, extref=extref)
-
+ f = open(filepath, "rb")
+ return Asset.from_io(
+ f,
+ filepath,
+ closer=f.close,
+ description=description,
+ slug=slug,
+ mimetype=mimetype,
+ extref=extref,
+ )
"""Instantiate an asset object from an input stream.
@@ -149,10 +162,13 @@ class Asset:
:todo: make path uri/remote url friendly when implementing remote stream.
:todo: document possible exceptions.
"""
+
@staticmethod
- def from_io(io, src, closer=None, description=None, slug=None, mimetype=None, extref=None):
+ def from_io(
+ io, src, closer=None, description=None, slug=None, mimetype=None, extref=None
+ ):
o = Asset()
- h = hashlib.sha256()
+ h = hashlib.sha512()
b = io.read(BLOCKSIZE)
if mimetype == None:
v = mimetypes.guess_file_type(src, strict=True)
@@ -176,23 +192,22 @@ class Asset:
s = mimetypes.guess_extension(o.mime, strict=True)
if s != None:
- o.ext = s[1:]
+ o.ext = s[1:]
(o.slug, o.ext) = parse_path(src)
if slug != None:
- logg.info('overriding file base name {} -> {}'.format(o.slug, slug))
+ logg.info("overriding file base name {} -> {}".format(o.slug, slug))
o.slug = slug
- logg.debug('asset read {} bytes from path {} mime {}'.format(c, src, o.mime))
+ logg.debug("asset read {} bytes from path {} mime {}".format(c, src, o.mime))
h = hashlib.sha1()
h.update(o.digest)
- #o.uuid = str(uuid.uuid1(h.digest()))
+ # o.uuid = str(uuid.uuid1(h.digest()))
o.extref = extref
o.description = description
return o
-
"""Return canonical XML for use in signature message calculation.
Elements in canonical XML for the asset is data that can be recreated by the actual file data.
@@ -201,19 +216,19 @@ class Asset:
For custom or arcane MIME types, the data needed to recreate the MIME type has to be retained outside the application.
"""
+
def canon(self):
- tree = lxml.etree.Element(NSPREFIX + 'attachment', nsmap=nsmap())
+ tree = lxml.etree.Element(NSPREFIX + "attachment", nsmap=nsmap())
if self.mime != None:
- tree.set('mime', self.get_mimestring())
+ tree.set("mime", self.get_mimestring())
- o = lxml.etree.SubElement(tree, 'digest')
- o.set('algo', 'sha256')
+ o = lxml.etree.SubElement(tree, "digest")
+ o.set("algo", "sha512")
o.text = self.digest.hex()
tree.append(o)
return tree
-
"""Generate and return an XML representation of the asset.
:param canon: Return canonical results to use in signature material.
@@ -223,31 +238,31 @@ class Asset:
:todo: implement sigs
:todo: implement lookup
"""
+
def to_tree(self, canon=False):
- tree = self.canon()
+ tree = self.canon()
if canon:
return tree
- #if self.uuid != None:
+ # if self.uuid != None:
# tree.set('uuid', self.uuid)
if self.extref != None:
- o = lxml.etree.SubElement(tree, 'extref')
+ o = lxml.etree.SubElement(tree, "extref")
o.text = self.extref
tree.append(o)
- o = lxml.etree.SubElement(tree, 'filename')
+ o = lxml.etree.SubElement(tree, "filename")
o.text = self.get_filename()
tree.append(o)
if self.description != None:
- o = lxml.etree.SubElement(tree, 'description')
+ o = lxml.etree.SubElement(tree, "description")
o.text = self.description
tree.append(o)
return tree
-
"""Create object from an asset part defined as an XML tree.
The XML expected is an ledger/entry[]/attachment[] element (in schema defined as the Attachment complexType)
@@ -260,59 +275,59 @@ class Asset:
:todo: implement sigs
:todo: implement lookup
"""
+
@staticmethod
def from_tree(tree):
o = Asset()
- #o.uuid = tree.get('uuid')
- o.mime = tree.get('mime')
- v = tree.find('digest', namespaces=nsmap()).text
+ # o.uuid = tree.get('uuid')
+ o.mime = tree.get("mime")
+ v = tree.find("digest", namespaces=nsmap()).text
o.digest = bytes.fromhex(v)
- v = tree.find('extref', namespaces=nsmap())
+ v = tree.find("extref", namespaces=nsmap())
if v != None:
o.extref = v.text
- v = tree.find('filename', namespaces=nsmap())
+ v = tree.find("filename", namespaces=nsmap())
if v != None:
v = parse_path(v.text)
o.slug = v[0]
o.ext = v[1]
- v = tree.find('description', namespaces=nsmap())
+ v = tree.find("description", namespaces=nsmap())
if v != None:
o.description = v.text
- logg.warning('asset sigs not yet implemented')
- for v in tree.findall('sig', namespaces=nsmap()):
- logg.debug('skipping sig from ' . v.get('keyid'))
+ logg.warning("asset sigs not yet implemented")
+ for v in tree.findall("sig", namespaces=nsmap()):
+ logg.debug("skipping sig from ".v.get("keyid"))
return o
-
"""Generate the simple data structure used for rencode serialization.
:returns: data structure
:rtype: list
"""
+
def to_list(self):
d = []
- #for k in ['mime', 'uuid', 'slug', 'ext', 'description', 'extref', 'enc']:
- for k in ['mime', 'slug', 'ext', 'description', 'extref', 'enc']:
+ # for k in ['mime', 'uuid', 'slug', 'ext', 'description', 'extref', 'enc']:
+ for k in ["mime", "slug", "ext", "description", "extref", "enc"]:
v = getattr(self, k)
d.append(v)
return d
-
"""Generate the serialization format used to calculate the digest for the asset.
:returns: String representation of the entry, in rencode format.
:rtype: str
"""
+
def serialize(self):
b = self.to_list()
return rencode.dumps(b)
-
"""Create an entry object from serialized data.
:param data: rencoded entry object, as produced by the serialize() method.
@@ -320,16 +335,17 @@ class Asset:
:returns: Entry object.
:rtype: usawa.Entry
"""
+
@staticmethod
def deserialize(data, digest):
o = Asset()
v = rencode.loads(data)
i = 0
- #for k in ['mime', 'uuid', 'slug', 'ext', 'description', 'extref', 'enc']:
- for k in ['mime', 'slug', 'ext', 'description', 'extref', 'enc']:
+ # for k in ['mime', 'uuid', 'slug', 'ext', 'description', 'extref', 'enc']:
+ for k in ["mime", "slug", "ext", "description", "extref", "enc"]:
vv = v[i]
if isinstance(vv, bytes):
- vv = vv.decode('utf-8')
+ vv = vv.decode("utf-8")
setattr(o, k, vv)
i += 1
if isinstance(digest, str):
@@ -337,6 +353,12 @@ class Asset:
o.digest = digest
return o
-
def __str__(self):
- return 'file ̈́' + self.get_filename() + ' mime ' + self.get_mimestring() + ' digest ' + self.digest.hex()
+ return (
+ "file ̈́"
+ + self.get_filename()
+ + " mime "
+ + self.get_mimestring()
+ + " digest "
+ + self.digest.hex()
+ )
diff --git a/dummy/usawa/storage/ledger_repository.py b/dummy/usawa/storage/ledger_repository.py
@@ -1,19 +1,15 @@
-import hashlib
import logging
from typing import List
from usawa.core.usawa_wallet import UsawaWallet
-import hexathon
from usawa.storage.xml_utils import (
_build_export_root,
_build_incoming_element,
- _find_child,
_find_entry_by_serial,
_write_xml_to_file,
resolve_namespace,
)
from usawa.asset import Asset
from usawa.crypto import ACL, DemoWallet, Wallet
-from usawa.error import VerifyError
from usawa.ledger import Ledger
from usawa.resolve.fs import FSResolver
from usawa.service import UnixClient
@@ -27,30 +23,11 @@ import mimetypes
import lxml.etree as ET
from pathlib import Path
import lxml.etree as ET
-from copy import deepcopy
logg = logging.getLogger("storage.ledger_repository")
-# def sha256_verify(k, v=None):
-# if isinstance(k, str):
-# k = bytes.fromhex(k)
-
-# if len(k) != 32:
-# raise ValueError("expect 256 bit key")
-
-# khx = hexathon.uniform(k.hex())
-
-# if v is not None:
-# h = hashlib.sha256()
-# h.update(v)
-# if k != h.digest():
-# raise VerifyError(khx)
-
-# return khx
-
-
class LedgerRepository:
"""Repository that wraps LedgerStore and handles mapping"""