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:
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 + "'"