serverwallet

Unnamed repository; edit this file 'description' to name the repository.
Info | Log | Files | Refs

commit 2ff6136684c6500792abc6d3bdf235daec029212
parent cf1496662dd4e8049ae5489ead207f7752f0adfa
Author: lash <dev@holbrook.no>
Date:   Thu, 23 Oct 2025 04:24:22 +0100

Add message parse, addr entry in db

Diffstat:
Msrvaddrgen/app/app.py | 23++++++++++++++++++-----
Msrvaddrgen/btc.py | 33++++++++++++++++++++++++++++-----
Asrvaddrgen/msg.py | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 105 insertions(+), 10 deletions(-)

diff --git a/srvaddrgen/app/app.py b/srvaddrgen/app/app.py @@ -4,7 +4,8 @@ import re import lmdb from srvaddrgen import DbKey -from srvaddrgen.btc import btc_next +from srvaddrgen.btc import btc_reserve +from srvaddrgen.msg import Message logging.basicConfig(level=logging.DEBUG) logg = logging.getLogger() @@ -14,7 +15,6 @@ path_btc = re.compile('^/bitcoin$') reasons = { 400: 'Bad Request', } - class Responder(Exception): def __init__(self, responder_method): @@ -43,6 +43,7 @@ class Responder(Exception): def croak(self, code, err=None, reason=None): + self.code = code if reason != None: self.reason = reason else: @@ -77,13 +78,25 @@ def application(environ, start_response): method = environ['REQUEST_METHOD'] v = environ['PATH_INFO'] r = None + if path_btc.match(v): if method != 'POST': - r.croak(400, 'This endpoint accepts json POST only', reason='POST only') + o.croak(400, 'This endpoint accepts json POST only', reason='POST only') dbenv.close() - return r.flush() + return o.flush() + b = environ['wsgi.input'].read() + msg = None + try: + msg = Message.parse_json(b) + except KeyError as e: + o.croak(400, 'Missing message item: ' + str(e)) + dbenv.close() + return o.flush() + + logg.debug('msg! ' + str(msg)) + msg.set_origin(environ['REMOTE_ADDR']) try: - btc_next(o, dbenv) + btc_reserve(o, msg, dbenv) except Responder as e: logg.error('btc failed: ' + str(o)) o = e diff --git a/srvaddrgen/btc.py b/srvaddrgen/btc.py @@ -1,6 +1,7 @@ import os import logging import hashlib +import time from bip32 import BIP32 import base58 @@ -12,7 +13,7 @@ logg = logging.getLogger('btc') envkey = 'SRVADDRGEN_BTC_XPUB' -def btc_next(responder, dbenv): +def btc_reserve(responder, msg, dbenv): logg.debug('processing btc') xpub = os.environ.get(envkey, None) idx = -1 @@ -29,7 +30,7 @@ def btc_next(responder, dbenv): tx.put(k, v, dupdata=False) tx.commit() - tx = dbenv.begin() + tx = dbenv.begin(write=True) v = tx.get(k) idx = int.from_bytes(v[:8]) if v[8:] != xpub_bin: @@ -39,6 +40,28 @@ def btc_next(responder, dbenv): xpub = v[8:].decode('utf-8') o = BIP32.from_xpub(xpub) pubk_bytes = o.get_pubkey_from_path('m/0/' + str(idx)) - addr = b'\x00' + hashlib.new('ripemd160', hashlib.new('sha256', pubk_bytes).digest()).digest() - pfx = hashlib.new('sha256', hashlib.new('sha256', addr).digest()).digest()[:4] - responder.complete(content=base58.b58encode(addr + pfx)) + hsh = b'\x00' + hashlib.new('ripemd160', hashlib.new('sha256', pubk_bytes).digest()).digest() + pfx = hashlib.new('sha256', hashlib.new('sha256', hsh).digest()).digest()[:4] + addr = base58.b58encode(hsh + pfx) + + k = DbKey.ADDR.value + addr + v = int.to_bytes(idx, 8) + v += int(time.time()).to_bytes(8) + v += msg.serialize() + r = tx.put(k, v, dupdata=False) + if not r: + tx.abort() + return responder.croak(500, 'Database write error') + + idx = idx + 1 + k = DbKey.BTC_XPUB.value + v = idx.to_bytes(8) + v += xpub_bin + r = tx.put(k, v) + if not r: + tx.abort() + return responder.croak(500, 'Database write error') + + tx.commit() + + responder.complete(content=addr) diff --git a/srvaddrgen/msg.py b/srvaddrgen/msg.py @@ -0,0 +1,59 @@ +import json +import enum + +import rencode + + +class ContactType(enum.Enum): + NOSTR = 'nostr' + +class Contact: + + def __init__(self, k, v): + self.k = ContactType(k) + self.v = v + + + def typ(self): + return self.k.value + + + def val(self): + return self.v + + +class Message: + + def __init__(self, author, content, contact=None): + self.author = author + self.content = content + self.contact = contact + self.origin = None + + + def set_origin(self, v): + self.origin = v + + + @staticmethod + def parse_json(v): + if isinstance(v, bytes): + v = v.decode('utf-8') + o = json.loads(v) + return Message(o['author'], o['content'], contact=o.get('contact')) + + + def serialize(self): + o = { + 'n': self.author, + 'v': self.content, + } + if self.origin != None: + o['o'] = self.origin + if self.contact != None: + o[self.contact.typ()] = self.contact.val() + return rencode.dumps(o) + + + def __str__(self): + return self.author + " says: '" + self.content + "'"