adesse

Signed testimonials for certifications.
Log | Files | Refs

commit c5e844b97f386dc531e67d3453ee1c8021574301
parent 45818068a86bd0c6cb30e3de53e7ad7ad7d888c3
Author: lash <dev@holbrook.no>
Date:   Sun,  6 Sep 2026 16:36:43 -0600

Add deterministic uuid in xmp parse, keyword bag

Diffstat:
Madesse/__init__.py | 2+-
Madesse/attachment.py | 32++++++++++++++++++++++++--------
Madesse/base.py | 7++++++-
Aadesse/crypto.py | 12++++++++++++
Madesse/ns/__init__.py | 1+
Madesse/ns/df.py | 3++-
Aadesse/ns/pdf.py | 8++++++++
Madesse/util/xmp.py | 36++++++++++++++++++++++++------------
Mtest/test_xmp.py | 5+++--
9 files changed, 81 insertions(+), 25 deletions(-)

diff --git a/adesse/__init__.py b/adesse/__init__.py @@ -1,4 +1,4 @@ -from .base import Serializer +from .base import Serializer, rdfn from .entity import Entity from .org import Org from .cert import Cert diff --git a/adesse/attachment.py b/adesse/attachment.py @@ -1,8 +1,9 @@ import datetime import hashlib -from rdflib import Literal, DC, DCTERMS, XSD, RDF -from adesse import Entity +from rdflib import Literal, DC, DCTERMS, XSD, RDF, BNode, Bag +from adesse import Entity, rdfn +from adesse.crypto import Sums, sum_from_urn from adesse.uri import to_uuid_uri from adesse.ns import DF @@ -16,11 +17,14 @@ class Attachment(Entity): self.mime = mime self.typ = typ self.sum = None + self.tag = [] - def set_sum(self, v): + def set_sum(self, v, typ=None): if not isinstance(v, bytes): raise TypeError('sum not bytes') + if typ != None and typ != Sums.SHA256: + raise ValueError('sum must be sha256') if len(v) > 32: raise ValueError('sum must be sha256') self.sum = v @@ -30,10 +34,21 @@ class Attachment(Entity): raise NotImplementedError() - def set_sum_from_urn(self, v): - if v[:11] != 'URN:sha256:': - raise ValueError('only sha256 urn supported') - return self.set_sum(bytes.fromhex(v[11:])) + def set_sum_from_urn(self, v, scheme=None): + r = sum_from_urn(v, scheme=scheme) + return self.set_sum(r) + + + def add_tag(self, v): + self.tag.append(v) + + + def _apply_tags(self, o, uu): + nod = BNode() + r = Bag(o, nod) + for v in self.tag: + r.append(Literal(v)) + o.add((uu, DC.subject, nod)) def apply(self, g): @@ -41,7 +56,8 @@ class Attachment(Entity): g.add((uu, DC.format, Literal(self.mime))) g.add((uu, DCTERMS.title, Literal(self.common_name))) g.add((uu, DCTERMS.description, Literal(self.description))) - g.add((uu, DF.sum, Literal(self.sum.hex(), datatype=XSD.hexBinary))) + g.add((uu, DF.sumSHA256, Literal(self.sum.hex(), datatype=XSD.hexBinary))) g.add((uu, DCTERMS.created, Literal(self.dt.isoformat(timespec='seconds'), datatype=XSD.dateTime))) g.add((uu, RDF.type, DF.AttachmentData)) + self._apply_tags(g.g, uu) super().apply(g) diff --git a/adesse/base.py b/adesse/base.py @@ -1,4 +1,4 @@ -from rdflib import Graph +from rdflib import Graph, RDF, URIRef from rdflib.namespace import NamespaceManager from rdflib.namespace import FOAF, XSD, PROV, DC, DCTERMS @@ -26,3 +26,8 @@ class Serializer: def __str__(self): return self.g.serialize(format=serialize_format) + + +def rdfn(v): + s = str(RDF) + '_' + str(int(v)) + return URIRef(s) diff --git a/adesse/crypto.py b/adesse/crypto.py @@ -0,0 +1,12 @@ +import enum + + +class Sums(enum.Enum): + SHA256 = 32 + SHA512 = 64 + + +def sum_from_urn(v, scheme=None): + if v[:11] != 'URN:sha256:': + raise ValueError('only sha256 urn supported') + return bytes.fromhex(v[11:]) diff --git a/adesse/ns/__init__.py b/adesse/ns/__init__.py @@ -8,3 +8,4 @@ from .wot import WOT from .df import DF from .pss import PSS from .xmp import XMP +from .pdf import PDF diff --git a/adesse/ns/df.py b/adesse/ns/df.py @@ -10,7 +10,8 @@ class DF(DefinedNamespace): verdict: URIRef hasClaim: URIRef testimonyFor: URIRef - sum: URIRef + sumSHA256: URIRef + sumSHA512: URIRef # classes Event: URIRef diff --git a/adesse/ns/pdf.py b/adesse/ns/pdf.py @@ -0,0 +1,8 @@ +from .inc import * + + +class PDF(DefinedNamespace): + + Keywords: URIRef + + _NS = Namespace('http://ns.adobe.com/pdf/1.3/') diff --git a/adesse/util/xmp.py b/adesse/util/xmp.py @@ -3,11 +3,13 @@ import logging import hashlib import mimetypes import datetime +import uuid import lxml.etree from rdflib import Graph, Namespace, RDF, URIRef, DC, Literal -from adesse import Attachment -from adesse.ns import XMP +from adesse import Attachment, rdfn +from adesse.ns import XMP, PDF +from adesse.crypto import sum_from_urn logg = logging.getLogger('util.xmp') @@ -45,12 +47,6 @@ def _parse_xmp(xmp_file, resource_file, search_dir=None): return (uu, mime, s,) - -def rdfn(v): - s = str(RDF) + '_' + str(int(v)) - return URIRef(s) - - def _get_alt_lang(sbj, prd, o, lang=None): v = o.value(sbj, prd) typ = o.value(v, RDF.type) @@ -82,6 +78,7 @@ def _get_bag(sbj, prd, o): break r.append(v.value) i += 1 + logg.debug('bag for {} {} is {}'.format(sbj, prd, r)) return r @@ -107,7 +104,16 @@ def scan_lang(sbj, o): return (r, v,) -def attachment_from_xmp(xml_file, resource_file=None, search_dir=None): +def get_tags(sbj, o): + #return _get_bag(sbj, PDF.Keywords, o) + v = o.value(sbj, PDF.Keywords) + r = [] + for s in v.split(','): + r.append(s.strip()) + return r + + +def attachment_from_xmp(xml_file, resource_file=None, search_dir=None, uuidns=None): if search_dir == None: search_dir = ['.'] r = _parse_xmp(xml_file, resource_file=resource_file, search_dir=search_dir) @@ -124,6 +130,12 @@ def attachment_from_xmp(xml_file, resource_file=None, search_dir=None): mime = str(r[1][0]) logg.debug('have title {} desc {} mime {}'.format(title, desc, mime)) slug = os.path.splitext(xml_file)[0] - v = Attachment(title, desc, date, mime, lang=default_lang) - v.set_sum_from_urn(z) - return v + + uu = None + if uuidns != None: + uu = uuid.uuid5(uuidns, sum_from_urn(z)) + r = Attachment(title, desc, date, mime, lang=default_lang, uu=uu) + r.set_sum_from_urn(z) + for v in get_tags(sbj, o): + r.add_tag(v) + return r diff --git a/test/test_xmp.py b/test/test_xmp.py @@ -3,6 +3,7 @@ import datetime import hashlib import os import logging +import uuid from rdflib.term import URIRef from rdflib import Graph @@ -18,12 +19,12 @@ thisdir = os.path.realpath(os.path.dirname(__file__)) class TestXmpLoad(unittest.TestCase): def setUp(self): - pass + self.uubase = uuid.UUID('f253542c-78d1-4187-84f6-e15f3e686591') def test_parse(self): fp = os.path.join(thisdir, 'import.xmp') - r = xmp.attachment_from_xmp(fp, 'import.pdf', search_dir=[thisdir]) + r = xmp.attachment_from_xmp(fp, 'import.pdf', search_dir=[thisdir], uuidns=self.uubase) z = Serializer() r.apply(z) print(z)