usawa

Signed, immutable accounting.
Log | Files | Refs | Submodules | LICENSE

commit 973ef22345dfce7e9154909e8bc4238564a81176
parent 91a81dbd00ddb8f4c678860fcad21611ef3c836f
Author: lash <dev@holbrook.no>
Date:   Sun, 29 Mar 2026 15:34:30 -0600

Impl password in ctx, add readonly wallet opt in cli

Diffstat:
Mdummy/usawa/context.py | 23+++++++++++++++++++++--
Mdummy/usawa/runnable/create.py | 16+++++++++++++---
Mdummy/usawa/runnable/export.py | 28++++++++++++++++++++++++----
Mdummy/usawa/runnable/view.py | 21++++++++++++++++-----
Mdummy/usawa/store.py | 14++++++++++++++
5 files changed, 88 insertions(+), 14 deletions(-)

diff --git a/dummy/usawa/context.py b/dummy/usawa/context.py @@ -1,3 +1,5 @@ +import getpass + from whee.valkey import ValkeyStore from whee.fs import FsStore from usawa import DemoWallet, Ledger @@ -6,9 +8,15 @@ from usawa.store import LedgerStore, EntryStore, KeyStore from usawa.resolve.fs import FSResolver +def pwgetter(): + return getpass.getpass('passphrase: ') + + class UsawaContext: - def __init__(self, cfg): + pwget = pwgetter + + def __init__(self, cfg, askpass=None): self.cfg = cfg self.db = None self.ledger = None @@ -21,6 +29,7 @@ class UsawaContext: self.keystore = None self.aidx = None self.o = {} + self.askpass = False def set(self, k, v): @@ -51,15 +60,25 @@ class UsawaContext: self.create_store(store_scope=store_scope) self.create_resolver() self.load_accounts() + + self.askpass = args.p self.load_wallet() + def getpw(self): + pw = self.cfg.get('WALLET_KEY_PASSPHRASE') + if pw == None: + if self.askpass: + pw = UsawaContext.pwget() + return pw + + def load_wallet(self): if self.wallet != None: raise AttributeError('wallet set') ops = int(self.cfg.get('WALLET_OPSLIMIT', 0)) mem = int(self.cfg.get('WALLET_MEMLIMIT', 0)) - pw = self.cfg.get('WALLET_KEY_PASSPHRASE') + pw = self.getpw() self.wallet = self.keystore.get_key(DemoWallet, passphrase=pw, opslimit=ops, memlimit=mem) if self.ledger != None: self.ledger.set_wallet(self.wallet) diff --git a/dummy/usawa/runnable/create.py b/dummy/usawa/runnable/create.py @@ -5,6 +5,7 @@ import urllib.parse import argparse import datetime import uuid +import getpass from usawa import Ledger, DemoWallet, UnitIndex, ACL import usawa.config @@ -13,7 +14,7 @@ from whee.valkey import ValkeyStore from whee.fs import FsStore from xdg_base_dirs import xdg_data_home -logging.basicConfig(level=logging.DEBUG) +logging.basicConfig(level=logging.WARNING) logg = logging.getLogger() @@ -135,11 +136,17 @@ def input_or_default(prompt, default=None, postfix=': ', validate_fn=None): argp = argparse.ArgumentParser() argp.add_argument('-i', action='store_true', help='interactive edit') argp.add_argument('-t', dest='topic', type=str, help='ledger topic') +argp.add_argument('-v', type=str, choices=['info','debug','warning','error'], help='be verbose') argp.add_argument('-u', '--unit', type=str, action='append', default=[], help='Units to use for transaction') +argp.add_argument('-p', action='store_true', help='Use passphrase to open wallet') argp.add_argument('-o', type=str, dest='output', help='output file for updated XML document') argp.add_argument('-l', type=str, dest='src_uri', help='URI for data source') argp.add_argument('-c', type=str, help='override config dir') arg = argp.parse_args() + +if arg.v: + logg.setLevel(getattr(logging, arg.v.upper())) + ctx = Context.from_args(arg) cfg = usawa.config.load_config(config_dir=arg.c) @@ -186,13 +193,16 @@ cfg = usawa.config.load_config(config_dir=arg.c) ops = int(cfg.get('WALLET_OPSLIMIT', 0)) mem = int(cfg.get('WALLET_MEMLIMIT', 0)) +pw = cfg.get('WALLET_KEY_PASSPHRASE') +if arg.p and pw == None: + pw = getpass.getpass("passphrase: ") logg.debug('ops {}'.format(ops)) try: - wallet = store.get_key(DemoWallet, passphrase=cfg.get('WALLET_KEY_PASSPHRASE'), opslimit=ops, memlimit=mem) + wallet = store.get_key(DemoWallet, passphrase=pw, opslimit=ops, memlimit=mem) except FileNotFoundError: logg.info('no default key found') wallet = DemoWallet() - store.add_key(wallet, passphrase=cfg.get('WALLET_KEY_PASSPHRASE'), opslimit=ops, memlimit=mem) + store.add_key(wallet, passphrase=pw, opslimit=ops, memlimit=mem) if wallet == None: wallet = DemoWallet(privatekey=pk) logg.info('loaded existing key. {}'.format(wallet.pubkey().hex())) diff --git a/dummy/usawa/runnable/export.py b/dummy/usawa/runnable/export.py @@ -6,11 +6,14 @@ import argparse import uuid import datetime +from whee.valkey import ValkeyStore +from whee.fs import FsStore +from xdg_base_dirs import xdg_data_home + import usawa.config from usawa import Ledger, Entry, EntryPart, DemoWallet, UnitIndex, load, ACL from usawa.constant import CATEGORIES from usawa.store import LedgerStore -from whee.valkey import ValkeyStore from usawa.resolve.fs import FSResolver logging.basicConfig(level=logging.DEBUG) @@ -70,11 +73,28 @@ ctx = Context.from_args(arg) ledger = Ledger.from_file(arg.ledger_xml_file) cfg = usawa.config.load_config(config_dir=arg.c) -storedb = ValkeyStore('', host=ctx.valkey_host, port=ctx.valkey_port) -store = LedgerStore(storedb, ledger) +store_type = cfg.get('STORE_TYPE') +db = None +if store_type == 'valkey': + db = ValkeyStore( + "", + host=cfg.get("VALKEY_HOST"), + port=cfg.get("VALKEY_PORT"), + ) +elif store_type == 'fs': + db = FsStore( + base=cfg.get('FSSTORE_BASE', xdg_data_home()), + dbname='usawa', + ) +else: + raise ValueError('invalid store type: ' + store_type) +store = LedgerStore(db, ledger) +#storedb = ValkeyStore('', host=ctx.valkey_host, port=ctx.valkey_port) +#store = LedgerStore(storedb, ledger) #pk = store.get_key() #wallet = DemoWallet(privatekey=pk) -wallet = store.get_key(DemoWallet, passphrase=cfg.get('WALLET_KEY_PASSPHRASE')) +#wallet = store.get_key(DemoWallet, passphrase=cfg.get('WALLET_KEY_PASSPHRASE')) +wallet = store.get_default_key(DemoWallet) acl = ACL.from_wallet(wallet) store.load(acl=acl) resolve = FSResolver(ctx.output) diff --git a/dummy/usawa/runnable/view.py b/dummy/usawa/runnable/view.py @@ -5,6 +5,7 @@ import urllib.parse import argparse import uuid import datetime +#import getpass import usawa.config from usawa import Ledger, Entry, EntryPart, DemoWallet, UnitIndex, load, ACL @@ -14,7 +15,7 @@ from whee.valkey import ValkeyStore from whee.fs import FsStore from xdg_base_dirs import xdg_data_home -logging.basicConfig(level=logging.DEBUG) +logging.basicConfig(level=logging.WARNING) logg = logging.getLogger() @@ -58,11 +59,17 @@ class Context: argp = argparse.ArgumentParser() argp.add_argument('-o', type=str, dest='output', help='output file for resulting XML document') +#argp.add_argument('-p', action='store_true', help='prompt for password to open wallet') argp.add_argument('-c', type=str, help='override config dir') +argp.add_argument('-v', type=str, choices=['info','debug','warning','error'], help='be verbose') argp.add_argument('--valkey-host', dest='valkey_host', type=str, default='localhost', help='Valkey host') argp.add_argument('--valkey-port', dest='valkey_port', type=int, default=6379, help='Valkey port') argp.add_argument('ledger_xml_file', type=str, help='load ledger metadata from XML file') arg = argp.parse_args() + +if arg.v: + logg.setLevel(getattr(logging, arg.v.upper())) + ctx = Context.from_args(arg) #ledger = None @@ -90,10 +97,14 @@ else: store = LedgerStore(db, ledger) #pk = store.get_key() #wallet = DemoWallet(privatekey=pk) -ops = int(cfg.get('WALLET_OPSLIMIT', 0)) -mem = int(cfg.get('WALLET_MEMLIMIT', 0)) -logg.debug('ops {}'.format(ops)) -wallet = store.get_key(DemoWallet, passphrase=cfg.get('WALLET_KEY_PASSPHRASE'), opslimit=ops, memlimit=mem) +#ops = int(cfg.get('WALLET_OPSLIMIT', 0)) +#mem = int(cfg.get('WALLET_MEMLIMIT', 0)) +#pw = cfg.get('WALLET_KEY_PASSPHRASE') +#if arg.p and pw == None: +# pw = getpass.getpass("passphrase: ") +#logg.debug('ops {}'.format(ops)) +#wallet = store.get_key(DemoWallet, passphrase=pw, opslimit=ops, memlimit=mem) +wallet = store.get_default_key(DemoWallet) acl = ACL.from_wallet(wallet) store.load(acl=acl) sys.stdout.write(ledger.to_string()) diff --git a/dummy/usawa/store.py b/dummy/usawa/store.py @@ -210,6 +210,20 @@ class KeyStore(BaseStore): return wallet_class.from_export(r, passphrase=passphrase, opslimit=opslimit, memlimit=memlimit) + """Get the public key of the default key in the store. + + :param wallet_class: Wallet class to use to instantiate a Wallet object from private key material. + :type: usawa.crypto.Wallet + :raises FileNotFoundError: No key exists. + :return: Resulting wallet + :rtype: usawa.crypto.Wallet + """ + def get_default_key(self, wallet_class): + k = pfx_key() + pubkey = self.db.get(k) + return wallet_class(publickey=pubkey) + + class AssetStore(BaseStore): """Add an entry attachment asset to the store.