commit 217317dbb4073cca3dceef5e15a873c66810c14f
parent 224d472023aad3f5e5c4fff5d7dcae3540ea7cf8
Author: lash <dev@holbrook.no>
Date: Fri, 7 Nov 2025 01:07:52 +0000
Add ACL for acceptable public key signatures
Diffstat:
2 files changed, 62 insertions(+), 12 deletions(-)
diff --git a/dummy/create.py b/dummy/create.py
@@ -5,7 +5,7 @@ import lxml.etree
import confini
import nacl.signing
-from svcontas import Ledger, Entry, DemoWallet, State, get_units, init_ledger, nsmap
+from svcontas import Ledger, Entry, DemoWallet, ACL, State, get_units, init_ledger, nsmap
seed = bytes.fromhex('2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae')
@@ -26,12 +26,15 @@ if __name__ == '__main__':
tree = lxml.etree.parse(arg.xml_file)
root = tree.getroot()
units = get_units(root)
- ledger = init_ledger(root, units)
+ acl = ACL()
+ wallet = DemoWallet(privatekey=seed)
+ fakepub = bytes.fromhex('7d865e959b2466918c9863afca942d0fb89d7c9ac0c99bafc3749504ded97730')
+ acl.add(wallet.pubkey(), 1, label='foo')
+ ledger = init_ledger(root, units, acl=acl)
amount = units.from_floatstring(arg.u, arg.amount, allow_negative=False)
entry = Entry(arg.t, amount, arg.u, ledger.state.serial + 1, arg.a, arg.date, parent=ledger.state.base)
- wallet = DemoWallet(privatekey=seed)
entry.sign(wallet)
ledger.add_entry(entry)
tree = ledger.to_tree()
diff --git a/dummy/svcontas/__init__.py b/dummy/svcontas/__init__.py
@@ -16,9 +16,12 @@ NS = 'http://svcontas.defalsify.org'
NAMESPACES = {None: NS}
NSPREFIX = '{' + NS + '}'
+AXX_ALL = 0xffffffff
+
def nsmap():
return NAMESPACES
+
class State:
def __init__(self):
@@ -72,7 +75,8 @@ class DemoWallet:
else:
publickey = nacl.signing.VerifyKey(publickey)
self.pubk = publickey
-
+
+
def sign(self, v):
r = self.pk.sign(v)
return r.signature
@@ -339,9 +343,40 @@ class RunningTotal:
return 'running total {}: income {} expense {} asset {} liability {}'.format(self.sym, self.income, self.expense, self.asset, self.liability)
+class ACL:
+
+ def __init__(self):
+ self.axx = {}
+
+
+ def add(self, who, what=None, label=None):
+ if label == None:
+ label = who
+ if what == None:
+ what = AXX_ALL
+ self.axx[label] = (who, what,)
+
+
+ def may(self, who, what):
+ label = who
+ if isinstance(label, bytes):
+ label = who.hex()
+ return (self.axx[label][1] & what) == what
+
+
+ def pubkeys(self, binary=True):
+ r = []
+ for k in self.axx.values():
+ v = k[0]
+ if not binary:
+ v = v.hex()
+ r.append(v)
+ return r
+
+
class Ledger:
- def __init__(self, serial, base, unitindex, tree=None):
+ def __init__(self, serial, base, unitindex, tree=None, acl=None):
self.uidx = unitindex
self.sigs = {}
self.entries = {}
@@ -349,18 +384,30 @@ class Ledger:
self.tree = tree
self.state = State()
self.state.poke(serial, base)
+ self.acl = acl
# TODO: add check against trusted pubkey list
def check_sigs(self, entry):
- for k in entry.sigs.keys():
+ have = False
+ valid_keys = None
+ if self.acl == None:
+ valid_keys = list(entry.sigs.keys())
+ else:
+ valid_keys = list(self.acl.pubkeys(binary=False))
+ #for k in entry.sigs.keys():
+ for k in valid_keys:
b = bytes.fromhex(k)
- sig = entry.sigs[k]
+ try:
+ sig = entry.sigs[k]
+ except KeyError:
+ continue
wallet = DemoWallet(publickey=b)
v = entry.sum()
r = wallet.verify(v, sig)
+ have = True
logg.debug('having sig {}'.format(r.hex()))
- return True
+ return have
def add_entry(self, entry, modify_tree=True):
@@ -385,11 +432,11 @@ class Ledger:
@staticmethod
- def from_tree(tree, unitindex):
+ def from_tree(tree, unitindex, acl=None):
part = tree.find('incoming', namespaces=nsmap())
serial = int(part.get('serial'))
o = part.find('digest', namespaces=nsmap()).text # verify that is sha512
- r = Ledger(serial, bytes.fromhex(o), unitindex, tree=tree)
+ r = Ledger(serial, bytes.fromhex(o), unitindex, tree=tree, acl=acl)
for sig in part.iter(NSPREFIX + 'sig'):
keyid = sig.get('keyid')
@@ -434,8 +481,8 @@ class Ledger:
return "state: " + self.state.base.hex()
-def init_ledger(tree, units):
- return Ledger.from_tree(tree, units)
+def init_ledger(tree, units, acl=None):
+ return Ledger.from_tree(tree, units, acl=acl)
def get_units(tree):