commit 429b73bec76553ec64e9053fe0c0b6fb768aef7e
parent 6c9a15e011660f7abdc877fd1ddeaf9544db4c98
Author: lash <dev@holbrook.no>
Date: Wed, 18 Mar 2026 13:13:13 -0600
WIP attempt to add setup-wallet key to store directly
Diffstat:
7 files changed, 162 insertions(+), 81 deletions(-)
diff --git a/dummy/setup.cfg b/dummy/setup.cfg
@@ -25,8 +25,15 @@ include_package_data = True
python_requires = >= 3.7
packages =
usawa
+ usawa.core
usawa.resolve
usawa.runnable
+ usawa.gui
+ usawa.gui.components
+ usawa.gui.controllers
+ usawa.gui.models
+ usawa.gui.views
+ usawa.storage
[options.entry_points]
console_scripts =
diff --git a/dummy/tests/wallet.py b/dummy/tests/wallet.py
@@ -0,0 +1,51 @@
+import logging
+import unittest
+import os
+
+from usawa import DemoWallet
+from usawa.error import VerifyError
+
+logging.basicConfig(level=logging.DEBUG)
+logg = logging.getLogger()
+
+testdir = os.path.realpath(os.path.dirname(__file__))
+
+class TestWallet(unittest.TestCase):
+
+ def test_wallet_create(self):
+ wallet = DemoWallet()
+ v = b'foo'
+ r = wallet.sign(v)
+ wallet.verify(v, r)
+
+
+ def test_wallet_verify(self):
+ wallet = DemoWallet()
+ v = b'foo'
+ r = wallet.sign(v)
+
+ k = wallet.pubkey()
+ wallet = DemoWallet(publickey=k)
+ wallet.verify(v, r)
+
+
+ def test_wallet_export(self):
+ wallet = DemoWallet()
+ v = b'foo'
+ r = wallet.sign(v)
+
+ b = wallet.export()
+ with self.assertRaises(VerifyError):
+ wallet = DemoWallet.from_export(b, passphrase='baz')
+ wallet = DemoWallet.from_export(b)
+ wallet.verify(v, r)
+
+ b = wallet.export(passphrase='bar')
+ with self.assertRaises(VerifyError):
+ wallet = DemoWallet.from_export(b, passphrase='baz')
+ wallet = DemoWallet.from_export(b, passphrase='bar')
+ wallet.verify(v, r)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/dummy/usawa/data/usawa.ini b/dummy/usawa/data/usawa.ini
@@ -2,8 +2,8 @@
gpg_dir =
[valkey]
-host =
-port =
+host = localhost
+port = 6379
[server]
socket_file_path=
diff --git a/dummy/usawa/runnable/create.py b/dummy/usawa/runnable/create.py
@@ -143,15 +143,15 @@ pk = None
wallet = None
dt = datetime.datetime.now()
-cfg = usawa.config.load()
+cfg = usawa.config.load_config()
try:
#pk = store.get_key()
- wallet = store.get_key(DemoWallet, passphrase=cfg.get('SIGS_KEY_PASSPHRASE'))
+ wallet = store.get_key(DemoWallet, passphrase=cfg.get('WALLET_KEY_PASSPHRASE'))
except FileNotFoundError:
logg.info('no default key found')
wallet = DemoWallet()
- store.add_key(wallet, passphrase=cfg.get('SIGS_KEY_PASSPHRASE'))
+ store.add_key(wallet, passphrase=cfg.get('WALLET_KEY_PASSPHRASE'))
if wallet == None:
wallet = DemoWallet(privatekey=pk)
logg.info('loaded existing key. {}'.format(wallet.pubkey().hex()))
diff --git a/dummy/usawa/runnable/setup_wallet.py b/dummy/usawa/runnable/setup_wallet.py
@@ -5,6 +5,10 @@ from pathlib import Path
from nacl.signing import SigningKey
from nacl.secret import SecretBox
from nacl.pwhash import argon2i
+from whee.valkey import ValkeyStore
+
+from usawa.store import KeyStore
+from usawa.crypto import DemoWallet
logg = logging.getLogger("core.setup_wallet")
@@ -31,6 +35,9 @@ def encrypt_seed(seed: bytes, passphrase: str) -> bytes:
def setup_wallet(wallet_dir=None):
+ db = ValkeyStore('')
+ store = KeyStore(db)
+
wallet_dir = Path(wallet_dir) if wallet_dir else DEFAULT_WALLET_DIR
wallet_dir.mkdir(parents=True, exist_ok=True)
logg.info("wallet directory: %s", wallet_dir)
@@ -58,7 +65,12 @@ def setup_wallet(wallet_dir=None):
f.write(pk.encode())
logg.info("public key saved to: %s", publickey_path)
+ wallet = DemoWallet(privatekey=random_bytes)
+ store.add_key(wallet, passphrase=passphrase_confirm)
+ logg.info("key written to store")
+
logg.info("setup complete.")
logg.info("your 32-byte public key (hex): %s", pk.encode().hex())
+
return 0
diff --git a/dummy/usawa/storage/file_utils.py b/dummy/usawa/storage/file_utils.py
@@ -1,9 +1,14 @@
+import os
+
from urllib.request import url2pathname
from urllib.parse import urlparse
def path_from_uri(uri: str) -> str:
parsed = urlparse(uri)
+ if parsed.scheme == '':
+ uri = 'file://' + os.path.realpath(uri)
+ parsed = urlparse(uri)
if parsed.scheme != "file":
raise ValueError("unsupported scheme: {}".format(parsed.scheme))
return url2pathname(parsed.path)
diff --git a/dummy/usawa/store.py b/dummy/usawa/store.py
@@ -91,8 +91,79 @@ def pfx_asset(asset):
return PFX_ASSET + asset.get_digest(binary=True)
+class KeyStore(Interface):
-class LedgerStore(Interface):
+ def __init__(self, implementation):
+ if not isinstance(implementation, Interface):
+ raise ValueError('store must be whee interface instance')
+ self.db = implementation
+
+
+ """Add signing key to the store.
+
+ If this is the first key in the store, it will be set as default.
+
+ :param wallet: The wallet object to store keys for.
+ :type wallet: usawa.Wallet implementation
+ :param acl: Access control list data to retrieve the allowance and label for the key.
+ :type acl: usawa.ACL
+ :param default: If True, this key will be set as default key.
+ :type default: bool
+ :param passphrase: Passphrase to encrypt the key with.
+ :type passphrase: bytes
+ :todo: Implement the ACL lookup
+ """
+ def add_key(self, wallet, acl=None, default=False, passphrase=None):
+ k = pfx_key()
+ try:
+ self.db.get(k)
+ except FileNotFoundError:
+ default = True
+ pubkey = wallet.pubkey()
+ if default:
+ self.db.put(k, pubkey, exist_ok=True)
+ k = pfx_key(pubkey=pubkey)
+ v = wallet.export(passphrase=passphrase)
+ self.db.put(k, v)
+
+
+ """Get a newly instantiated wallet object from a private key in the store.
+
+ If public key is not supplied, will retrieve the default private key.
+
+ :param wallet_class: Wallet class to use to instantiate a Wallet object from private key material.
+ :type: usawa.crypto.Wallet
+ :param pubkey: Public key to retrieve private key for.
+ :type pubkey: bytes
+ :param passphrase: Passphrase to decrypt the key with.
+ :type passphrase: bytes
+ :raises FileNotFoundError: No key exists.
+ :raises usawa.error.VerifyError: Key decryption failed.
+ :return: Resulting wallet
+ :rtype: usawa.crypto.Wallet
+ """
+ def get_key(self, wallet_class, pubkey=None, passphrase=None):
+ if pubkey == None:
+ k = pfx_key()
+ pubkey = self.db.get(k)
+ k = pfx_key(pubkey=pubkey)
+ #return self.db.get(k)
+ r = self.db.get(k)
+ return wallet_class.from_export(r, passphrase=passphrase)
+
+
+ """Implements whee.Interface.put
+ """
+ def put(self, k, v):
+ return self.db.put(k, v)
+
+
+ """Implements whee.Interface.get
+ """
+ def get(self, k):
+ return self.db.get(k)
+
+class LedgerStore(KeyStore):
"""Wrapper for an implementation of the whee store that handles encoding of ledgers and entries.
:param implementation: Store implementation.
@@ -101,12 +172,10 @@ class LedgerStore(Interface):
:type ledger: usawa.Ledger
"""
def __init__(self, implementation, ledger):
- if not isinstance(implementation, Interface):
- raise ValueError('store must be whee interface instance')
+ super(LedgerStore, self).__init__(implementation)
if not isinstance(ledger, Ledger):
raise ValueError('invalid ledger')
self.ledger = ledger
- self.__o = implementation
"""Implements whee.Interface.start
@@ -115,11 +184,11 @@ class LedgerStore(Interface):
serial = 0
k = pfx_ledger_topic(self.ledger.topic)
try:
- b = self.__o.get(k)
+ b = self.db.get(k)
serial = int.from_bytes(8, byteorder='big')
except FileNotFoundError:
v = serial.to_bytes(8, byteorder='big')
- self.__o.put(k, v)
+ self.db.put(k, v)
self.ledger.serial = serial
@@ -130,10 +199,10 @@ class LedgerStore(Interface):
v = None
# TODO: needs to be an atomic routine
try:
- v = self.__o.get(k)
+ v = self.db.get(k)
except KeyError:
raise PermissionError()
- self.__o.put(k, 0x01, exist_ok)
+ self.db.put(k, 0x01, exist_ok)
# atomic until here
@@ -141,7 +210,7 @@ class LedgerStore(Interface):
"""
def unlock(self):
k = pfx_ledger_lock(self.ledger.topic)
- v = self.__o.delete(k)
+ v = self.db.delete(k)
"""Add an entry to the store.
@@ -156,7 +225,7 @@ class LedgerStore(Interface):
def add_entry(self, entry, update_ledger=False):
k = pfx_entry(self.ledger, entry)
v = entry.wrap()
- self.__o.put(k, v)
+ self.db.put(k, v)
if update_ledger:
self.ledger.add_entry(entry)
@@ -176,7 +245,7 @@ class LedgerStore(Interface):
"""
def get_entry(self, entry, acl=None):
k = pfx_entry(self.ledger, entry)
- v = self.__o.get(k)
+ v = self.db.get(k)
entry = Entry.unwrap(v)
# TODO: hacky!
i = 0
@@ -198,14 +267,14 @@ class LedgerStore(Interface):
def add_asset(self, asset):
k = pfx_asset(asset)
v = asset.serialize()
- self.__o.put(k, v)
+ self.db.put(k, v)
"""Restore an entry attachment asset from the store.
"""
def get_asset(self, asset):
k = pfx_asset(asset)
- v = self.__o.get(k)
+ v = self.db.get(k)
digest = asset.get_digest(binary=True)
return Asset.deserialize(v, digest)
@@ -246,69 +315,6 @@ class LedgerStore(Interface):
i -= 1
- """Add signing key to the store.
-
- If this is the first key in the store, it will be set as default.
-
- :param wallet: The wallet object to store keys for.
- :type wallet: usawa.Wallet implementation
- :param acl: Access control list data to retrieve the allowance and label for the key.
- :type acl: usawa.ACL
- :param default: If True, this key will be set as default key.
- :type default: bool
- :param passphrase: Passphrase to encrypt the key with.
- :type passphrase: bytes
- :todo: Implement the ACL lookup
- """
- def add_key(self, wallet, acl=None, default=False, passphrase=None):
- k = pfx_key()
- try:
- self.__o.get(k)
- except FileNotFoundError:
- default = True
- pubkey = wallet.pubkey()
- if default:
- self.__o.put(k, pubkey, exist_ok=True)
- k = pfx_key(pubkey=pubkey)
- v = wallet.export(passphrase=passphrase)
- self.__o.put(k, v)
-
-
- """Get a newly instantiated wallet object from a private key in the store.
-
- If public key is not supplied, will retrieve the default private key.
-
- :param wallet_class: Wallet class to use to instantiate a Wallet object from private key material.
- :type: usawa.crypto.Wallet
- :param pubkey: Public key to retrieve private key for.
- :type pubkey: bytes
- :param passphrase: Passphrase to decrypt the key with.
- :type passphrase: bytes
- :raises FileNotFoundError: No key exists.
- :raises usawa.error.VerifyError: Key decryption failed.
- :return: Resulting wallet
- :rtype: usawa.crypto.Wallet
- """
- def get_key(self, wallet_class, pubkey=None, passphrase=None):
- if pubkey == None:
- k = pfx_key()
- pubkey = self.__o.get(k)
- k = pfx_key(pubkey=pubkey)
- #return self.__o.get(k)
- r = self.__o.get(k)
- return wallet_class.from_export(r, passphrase=passphrase)
-
-
- """Implements whee.Interface.put
- """
- def put(self, k, v):
- return self.__o.put(k, v)
-
-
- """Implements whee.Interface.get
- """
- def get(self, k):
- return self.__o.get(k)
"""Store all entries in the ledger state.