kee

Offline IOU signer with QR as transport
git clone https://holbrook.no/src/kee
Info | Log | Files | Refs | README | LICENSE

commit b3abbb45c93ecc7a26a781c18781e61d9270c736
parent a465d02f7cd692138649501e856d85937ad9f97b
Author: lash <dev@holbrook.no>
Date:   Fri, 29 Mar 2024 10:50:00 +0000

Add resource data generation, generalize resolve interface

Diffstat:
M.gitignore | 2+-
MMakefile | 2+-
Mrequirements.txt | 1+
Msrc/cadir.c | 13++++++++-----
Msrc/cadir.h | 7+++----
Asrc/cadiz.h | 18++++++++++++++++++
Msrc/gtk/kee-entry-store.c | 26+++++++++++++++++++-------
Msrc/gtk/kee-entry-store.h | 2++
Msrc/gtk/kee-entry.c | 23+++++++++++++++++++----
Msrc/gtk/kee-entry.h | 2++
Msrc/gtk/main.c | 3+++
Msrc/tests/cadir.c | 4++--
Mtestdata.py | 92+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------
13 files changed, 155 insertions(+), 40 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -1,6 +1,6 @@ src/gtk/*.ui **/*.o -testdata_mdb +testdata_* *\~ **/test_* **/*.out diff --git a/Makefile b/Makefile @@ -18,7 +18,7 @@ run: gtk all G_MESSAGES_DEBUG=all ./src/gtk/a.out debug: gtk all - G_DEBUG=3 G_MESSAGES_DEBUG=all ./src/gtk/a.out + G_DEBUG=all G_MESSAGES_DEBUG=all ./src/gtk/a.out #test: gtk all test_src test_gtk test: test_src diff --git a/requirements.txt b/requirements.txt @@ -1,2 +1,3 @@ varint~=1.0.2 lmdb~=1.4.0 +faker~=24.0.0 diff --git a/src/cadir.c b/src/cadir.c @@ -2,21 +2,24 @@ #include <fcntl.h> #include <unistd.h> -#include "cadir.h" +#include "cadiz.h" #include "hex.h" -/// \todo check hex leftover space -int cadir_get(const char *dirpath, enum CadirKeyType key_type, const char *key, char *out, size_t *out_len) { +/// \todo replace with fadfada +//int cadiz_resolve(const char *locator, enum CadizKeyType key_type, const char *key, char *out, size_t *out_len) { +int cadiz_resolve(Cadiz *cadiz, const char *key, char *out, size_t *out_len) { int r; int c; int fd; char *p; char path[1024]; size_t l; + const char *locator = cadiz->locator; + enum CadizKeyType key_type = cadiz->key_type; - strcpy(path, dirpath); - c = strlen(dirpath) - 1; + strcpy(path, locator); + c = strlen(locator) - 1; p = path + c; if (*p != '/') { *(p+1) = '/'; diff --git a/src/cadir.h b/src/cadir.h @@ -1,10 +1,9 @@ #ifndef _CADIR_H #define _CADIR_H -enum CadirKeyType { - CADIR_KEYTYPE_ANY, -}; +#include "cadiz.h" + +typedef struct Cadiz Cadir; -int cadir_get(const char *dirpath, enum CadirKeyType key_type, const char *key, char *out, size_t *out_len); #endif // _CADIR_H diff --git a/src/cadiz.h b/src/cadiz.h @@ -0,0 +1,18 @@ +#ifndef _CADIZ_H +#define _CADIZ_H + + +enum CadizKeyType { + CADIZ_KEY_TYPE_ANY, +}; + + +typedef struct Cadiz { + char *locator; + enum CadizKeyType key_type; +} Cadiz; + +typedef int (*cadiz_resolve_fn)(Cadiz *cadiz, const char *key, char *out, size_t *out_len); +int cadiz_resolve(Cadiz *cadiz, const char *key, char *out, size_t *out_len); + +#endif // _CADIZ_H diff --git a/src/gtk/kee-entry-store.c b/src/gtk/kee-entry-store.c @@ -6,6 +6,7 @@ #include "kee-entry-store.h" #include "kee-entry.h" #include "err.h" +#include "cadiz.h" typedef struct { @@ -22,20 +23,30 @@ struct _KeeEntryStore { char *last_digest; char *last_value; size_t last_value_length; + struct Cadiz resolver; }; static void kee_entry_store_iface_init(GListModelInterface *ifc); G_DEFINE_TYPE_WITH_CODE(KeeEntryStore, kee_entry_store, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE(G_TYPE_LIST_MODEL, kee_entry_store_iface_init)); +static void kee_entry_store_finalize(GObject *o); +static int kee_entry_store_seek(KeeEntryStore *o, int idx); + // \todo add construct pointer for db static void kee_entry_store_class_init(KeeEntryStoreClass *kls) { -} - + GObjectClass *oc = G_OBJECT_CLASS(kls); -static int kee_entry_store_seek(KeeEntryStore *o, int idx); + oc->finalize = kee_entry_store_finalize; +} static void kee_entry_store_init(KeeEntryStore *o) { + o->resolver.key_type = CADIZ_KEY_TYPE_ANY; + o->resolver.locator = malloc(1024); +} + +void kee_entry_store_set_resolve(KeeEntryStore *o, const char *locator) { + strcpy(o->resolver.locator, locator); } @@ -53,10 +64,9 @@ static gpointer kee_entry_store_get_item(GListModel *list, guint index) { KeeEntry *o; KeeEntryStore *store; - o = g_object_new(KEE_TYPE_ENTRY, NULL); - //kee_entry_load(o, list->db); store = KEE_ENTRY_STORE(list); + o = g_object_new(KEE_TYPE_ENTRY, NULL); kee_entry_store_seek(store, index); kee_entry_deserialize(o, store->last_key, 9, store->last_value, store->last_value_length); @@ -66,6 +76,7 @@ static gpointer kee_entry_store_get_item(GListModel *list, guint index) { return o; } + static void kee_entry_store_iface_init(GListModelInterface *ifc) { ifc->get_item_type = kee_entry_store_get_item_type; ifc->get_n_items = kee_entry_store_get_n_items; @@ -123,8 +134,9 @@ KeeEntryStore* kee_entry_store_new(struct db_ctx *db) { return o; } -void kee_entry_store_finalize(KeeEntryStore *o) { +void kee_entry_store_finalize(GObject *go) { + KeeEntryStore *o = KEE_ENTRY_STORE(go); g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "freeing entry store"); - free(o->last); + free(o->resolver.locator); free(o->last); } diff --git a/src/gtk/kee-entry-store.h b/src/gtk/kee-entry-store.h @@ -4,12 +4,14 @@ #include <glib-object.h> #include "db.h" + G_BEGIN_DECLS #define KEE_TYPE_ENTRY_STORE kee_entry_store_get_type() G_DECLARE_FINAL_TYPE(KeeEntryStore, kee_entry_store, KEE, ENTRY_STORE, GObject); KeeEntryStore* kee_entry_store_new(struct db_ctx *db); +void kee_entry_store_set_resolve(KeeEntryStore *o, const char *locator); G_END_DECLS diff --git a/src/gtk/kee-entry.c b/src/gtk/kee-entry.c @@ -6,6 +6,8 @@ #include "err.h" #include "export.h" #include "hex.h" +#include "cadiz.h" + typedef struct { } KeeEntryPrivate; @@ -24,7 +26,9 @@ struct _KeeEntry { char *unit_of_account; char *alice; char *bob; + char *body; char decimals; + struct Cadiz *resolver; }; G_DEFINE_TYPE(KeeEntry, kee_entry, GTK_TYPE_BOX); @@ -49,8 +53,15 @@ static void kee_entry_init(KeeEntry *o) { o->current_id = (char*)o->mem; o->unit_of_account = (char*)((o->mem)+64); o->state = 2; + o->resolver = NULL; } +KeeEntry* kee_entry_new(struct Cadiz *resolver) { + KeeEntry *o; + o = KEE_ENTRY(g_object_new(KEE_TYPE_ENTRY, NULL)); + o->resolver = resolver; + return o; +} int kee_entry_load(KeeEntry *o, struct db_ctx *db, const char *id) { return ERR_OK; @@ -88,6 +99,10 @@ int kee_entry_deserialize(KeeEntry *o, const char *key, size_t key_len, const ch o->bob = p; r = import_read(&im, o->bob, out_len); + out_len = remaining; + o->body = p; + r = import_read(&im, o->body, out_len); + o->state = 0; import_free(&im); @@ -98,8 +113,8 @@ int kee_entry_deserialize(KeeEntry *o, const char *key, size_t key_len, const ch void kee_entry_apply_list_item_widget(KeeEntry *o) { GtkWidget *widget; size_t l; - char alice_hex[129]; - char bob_hex[129]; + unsigned char alice_hex[129]; + unsigned char bob_hex[129]; if (o->state) { g_log(G_LOG_DOMAIN, G_LOG_LEVEL_ERROR, "entry must be loaded first"); @@ -108,9 +123,9 @@ void kee_entry_apply_list_item_widget(KeeEntry *o) { //widget = gtk_label_new(o->unit_of_account); l = 129; - bin_to_hex(o->alice, 64, alice_hex, &l); + bin_to_hex((unsigned char*)o->alice, 64, alice_hex, &l); l = 129; - bin_to_hex(o->bob, 64, bob_hex, &l); + bin_to_hex((unsigned char*)o->bob, 64, bob_hex, &l); sprintf(o->header, "[%s] %s -> %s", o->unit_of_account, alice_hex, bob_hex); widget = gtk_label_new(o->header); gtk_box_append(GTK_BOX(o), widget); diff --git a/src/gtk/kee-entry.h b/src/gtk/kee-entry.h @@ -5,6 +5,7 @@ #include <gtk/gtk.h> #include "db.h" +#include "cadiz.h" G_BEGIN_DECLS @@ -19,6 +20,7 @@ G_DECLARE_FINAL_TYPE(KeeEntry, kee_entry, KEE, ENTRY, GtkBox); int kee_entry_load(KeeEntry *o, struct db_ctx *db, const char *id); int kee_entry_deserialize(KeeEntry *o, const char *key, size_t key_len, const char *data, size_t data_len); void kee_entry_apply_list_item_widget(KeeEntry *o); +KeeEntry* kee_entry_new(struct Cadiz *resolver); G_END_DECLS diff --git a/src/gtk/main.c b/src/gtk/main.c @@ -8,6 +8,7 @@ #include "settings.h" #include "context.h" #include "kee-entry-store.h" +#include "cadir.h" //static void state_log(KeeUicontext *uctx, char state_hint, kee_state_t *new_state, kee_state_t *old_state) { @@ -46,8 +47,10 @@ int main(int argc, char **argv) { if (r) { return r; } + db_connect(&ctx.db, "./testdata_mdb"); store = kee_entry_store_new(&ctx.db); + kee_entry_store_set_resolve(store, "./testdata_resource"); g_signal_connect (gapp, "startup", G_CALLBACK (startup), &ctx); g_signal_connect (gapp, "activate", G_CALLBACK (activate), store); diff --git a/src/tests/cadir.c b/src/tests/cadir.c @@ -1,7 +1,7 @@ #include <gcrypt.h> #include "digest.h" -#include "cadir.h" +#include "cadiz.h" int main(int argc, char **argv) { int r; @@ -12,7 +12,7 @@ int main(int argc, char **argv) { calculate_digest_algo(data, 3, digest, GCRY_MD_SHA512); l = 256; - r = cadir_get("./testdata_resource", CADIR_KEYTYPE_ANY, digest, result, &l); + r = cadiz_resolve("./testdata_resource", CADIZ_KEY_TYPE_ANY, digest, result, &l); if (r) { return 1; } diff --git a/testdata.py b/testdata.py @@ -7,6 +7,9 @@ import sys import io import random import time +import email.message +from faker import Faker +from faker.providers import lorem import lmdb import varint @@ -26,6 +29,9 @@ PFX_LEDGER_ENTRY = b'\x02' logging.basicConfig(level=logging.DEBUG) logg = logging.getLogger() +fake = Faker() +fake.add_provider(lorem) + def db_init(d): d = os.path.join(d, 'testdata_mdb') @@ -46,6 +52,31 @@ def to_absflag(v): return (abs(v), flag,) +class LedgerContent(email.message.EmailMessage): + + def __init__(self): + super(LedgerContent, self).__init__() + self.set_default_type("text/plain") + self.add_header("Subject", fake.sentence()) + self.set_content(fake.paragraph()) + + + def kv(self): + b = self.as_bytes() + h = hashlib.new("sha512") + h.update(b) + z = h.digest() + return (z, b,) + + +class LedgerHeadContent(LedgerContent): + pass + + +class LedgerEntryContent(LedgerContent): + pass + + class LedgerHead: def __init__(self, alice_key=None, bob_key=None, body=NOBODY): @@ -57,7 +88,7 @@ class LedgerHead: if bob_key == None: bob_key = os.urandom(65) self.bob_pubkey_ref = bob_key - self.body = body + self.body = LedgerHeadContent() def __serialize_add(self, b, w): @@ -66,7 +97,15 @@ class LedgerHead: w.write(b) - def serialize(self, w=sys.stdout.buffer): + def __data_add(self, data_dir, k, v): + fp = os.path.join(data_dir, k.hex()) + f = open(fp, 'wb') + logg.info("fp {}".format(fp)) + f.write(v) + f.close() + + + def serialize(self, data_dir, w=sys.stdout.buffer): b = self.uoa.encode('utf-8') self.__serialize_add(b, w) @@ -79,8 +118,9 @@ class LedgerHead: b = self.bob_pubkey_ref self.__serialize_add(b, w) - b = self.body - self.__serialize_add(b, w) + (k, b) = self.body.kv() + self.__data_add(data_dir, k, b) + self.__serialize_add(k, w) @staticmethod @@ -110,7 +150,7 @@ class LedgerEntry: self.parent = b'\x00' * 64 self.timestamp = time.time_ns() - self.body = body + self.body = LedgerEntryContent() v = random.randint(self.credit_delta_min, self.credit_delta_max) self.flags = v % 2 @@ -145,7 +185,15 @@ class LedgerEntry: w.write(b) - def serialize(self, w=sys.stdout.buffer): + def __data_add(self, data_dir, k, v): + fp = os.path.join(data_dir, k.hex()) + f = open(fp, 'wb') + logg.info("fp {}".format(fp)) + f.write(v) + f.close() + + + def serialize(self, data_dir, w=sys.stdout.buffer): b = self.flags.to_bytes(1) self.__serialize_add(b, w) @@ -174,19 +222,23 @@ class LedgerEntry: if not self.flags: self.__serialize_add(b'\x00', w) - logg.debug('encoding collateral delta {}'.format(self.collateral_delta)) - b = varint.encode(self.collateral_delta) - self.__serialize_add(b, w) + if self.flags: self.__serialize_add(b'\x00', w) - self.__serialize_add(self.body, w) + logg.debug('encoding collateral delta {}'.format(self.collateral_delta)) + b = varint.encode(self.collateral_delta) + self.__serialize_add(b, w) if not self.flags: self.__serialize_add(b'\x00', w) #if self.signer != None: # self.signature = self.signer(b) + (k, b) = self.body.kv() + self.__data_add(data_dir, k, b) + self.__serialize_add(k, w) + self.__serialize_add(self.request_signature, w) b = self.response_value.to_bytes(1) @@ -208,10 +260,10 @@ class LedgerEntry: return r -def generate_entry(head, parent): +def generate_entry(data_dir, head, parent): o = LedgerEntry(head, parent=parent) w = io.BytesIO() - r = o.serialize(w=w) + r = o.serialize(data_dir, w=w) h = hashlib.new('sha512') b = w.getvalue() h.update(b) @@ -219,11 +271,11 @@ def generate_entry(head, parent): return (z, b,) -def generate_ledger(entry_count=3): +def generate_ledger(data_dir, entry_count=3): r = [] o = LedgerHead() w = io.BytesIO() - o.serialize(w=w) + o.serialize(data_dir, w=w) h = hashlib.new('sha512') b = w.getvalue() h.update(b) @@ -233,7 +285,7 @@ def generate_ledger(entry_count=3): k = z parent = None for i in range(entry_count): - v = generate_entry(k, parent=parent) + v = generate_entry(data_dir, k, parent=parent) # \todo generate key value already here parent = v[0] r.append(v) @@ -243,17 +295,25 @@ def generate_ledger(entry_count=3): if __name__ == '__main__': d = os.path.dirname(__file__) + data_dir = os.path.join(d, 'testdata_resource') + try: + shutil.rmtree(data_dir) + except FileNotFoundError: + pass + os.makedirs(data_dir) + d = db_init(d) env = lmdb.open(d) dbi = env.open_db() + count_ledgers = os.environ.get('COUNT', '1') with env.begin(write=True) as tx: for i in range(int(count_ledgers)): c = random.randint(1, 20) - r = generate_ledger(entry_count=c) + r = generate_ledger(data_dir, entry_count=c) v = r.pop(0)