kee

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

commit a2768840eee91118e31af48c825fe8f32c13c2b2
parent 9eb5c0e41d3f49d1581b8974572a80f790bd722c
Author: lash <dev@holbrook.no>
Date:   Wed,  3 Apr 2024 17:07:29 +0100

Correct varint parsing in entry item

Diffstat:
Msrc/db.c | 12+++++++-----
Msrc/db.h | 5+++--
Msrc/digest.c | 2--
Msrc/gtk/kee-entry-store.c | 9++++++++-
Msrc/gtk/kee-entry.c | 172++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Msrc/gtk/kee-entry.h | 10+++++++++-
Msrc/gtk/nav.c | 34+++++++++++++++++-----------------
Msrc/gtk/nav.h | 2+-
Mtestdata.py | 36+++++++++++++++++++-----------------
9 files changed, 231 insertions(+), 51 deletions(-)

diff --git a/src/db.c b/src/db.c @@ -136,11 +136,11 @@ int db_next(struct db_ctx *ctx, enum DbKey pfx, char **key, size_t *key_len, cha //if (ctx->current_key == DbNoKey) { if (!ctx->browsing) { -// if (ctx->started) { -// mdb_cursor_close(ctx->crsr); -// mdb_dbi_close(ctx->env, ctx->dbi); -// mdb_txn_abort(ctx->tx); -// } + if (ctx->started) { + mdb_cursor_close(ctx->crsr); + mdb_dbi_close(ctx->env, ctx->dbi); + mdb_txn_abort(ctx->tx); + } r = mdb_txn_begin(ctx->env, NULL, MDB_RDONLY, &ctx->tx); if (r) { @@ -157,6 +157,7 @@ int db_next(struct db_ctx *ctx, enum DbKey pfx, char **key, size_t *key_len, cha } ctx->current_key = pfx; + /// \todo add to else case below start[0] = (char)pfx; ctx->k.mv_size = 1; // if (!ctx->browsing) { @@ -179,6 +180,7 @@ int db_next(struct db_ctx *ctx, enum DbKey pfx, char **key, size_t *key_len, cha if (r) { return ERR_DB_FAIL; } + ctx->started = 1; start[0] = (char)*((char*)ctx->k.mv_data); if (start[0] != ctx->current_key) { //db_reset(ctx); diff --git a/src/db.h b/src/db.h @@ -4,11 +4,12 @@ #include <lmdb.h> #ifndef DB_KEY_SIZE_LIMIT -#define DB_KEY_SIZE_LIMIT 64 +#define DB_KEY_SIZE_LIMIT 128 #endif #ifndef DB_VALUE_SIZE_LIMIT -#define DB_VALUE_SIZE_LIMIT 1048576 +//#define DB_VALUE_SIZE_LIMIT 1048576 +#define DB_VALUE_SIZE_LIMIT 1024 #endif enum DbErr { diff --git a/src/digest.c b/src/digest.c @@ -32,5 +32,3 @@ int calculate_digest_algo(const char *in, size_t in_len, char *out, enum gcry_md int calculate_digest(const char *in, size_t in_len, char *out) { return calculate_digest_algo(in, in_len, out, GCRY_MD_NONE); } - - diff --git a/src/gtk/kee-entry-store.c b/src/gtk/kee-entry-store.c @@ -66,7 +66,8 @@ static gpointer kee_entry_store_get_item(GListModel *list, guint index) { //kee_entry_load(o, list->db); store = KEE_ENTRY_STORE(list); - o = kee_entry_new(&store->resolver); + o = kee_entry_new(store->db); + kee_entry_set_resolver(o, &store->resolver); kee_entry_store_seek(store, index); kee_entry_deserialize(o, store->last_key, 9, store->last_value, store->last_value_length); @@ -110,6 +111,7 @@ static int kee_entry_store_seek(KeeEntryStore *o, int idx) { o->last_value_length = 1024; r = db_next(o->db, DbKeyLedgerHead, &o->last_key, &key_len, &o->last_value, &o->last_value_length); if (r) { + db_rewind(o->db); o->last_state = 0; return i; } @@ -140,3 +142,8 @@ void kee_entry_store_finalize(GObject *go) { free(o->resolver.locator); free(o->last); } + + +void kee_entry_store_foo(KeeEntryStore* o) { + g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "foo db = %p", o->db); +} diff --git a/src/gtk/kee-entry.c b/src/gtk/kee-entry.c @@ -1,3 +1,6 @@ +#include <gcrypt.h> +#include <stddef.h> + #include <glib-object.h> #include <gtk/gtk.h> @@ -9,6 +12,8 @@ #include "export.h" #include "hex.h" #include "cadiz.h" +#include "db.h" +#include "digest.h" typedef struct { @@ -20,11 +25,11 @@ struct _KeeEntryClass { struct _KeeEntry { GtkWidget parent; - char *current_id; int state; long long timestamp; char mem[4096]; char header[1024]; + char *current_id; char *unit_of_account; char *alice; char *bob; @@ -32,6 +37,7 @@ struct _KeeEntry { char *subject; char decimals; struct Cadiz *resolver; + struct db_ctx *db; }; G_DEFINE_TYPE(KeeEntry, kee_entry, GTK_TYPE_BOX); @@ -54,20 +60,136 @@ static void kee_entry_class_init(KeeEntryClass *kls) { static void kee_entry_init(KeeEntry *o) { o->current_id = (char*)o->mem; - o->unit_of_account = (char*)((o->mem)+64); + o->unit_of_account = (char*)((o->mem)+128); o->state = 2; o->resolver = NULL; o->subject = NULL; } -KeeEntry* kee_entry_new(struct Cadiz *resolver) { +KeeEntry* kee_entry_new(struct db_ctx *db) { KeeEntry *o; o = KEE_ENTRY(g_object_new(KEE_TYPE_ENTRY, NULL)); - o->resolver = resolver; + o->db = db; return o; } -int kee_entry_load(KeeEntry *o, struct db_ctx *db, const char *id) { +void kee_entry_set_resolver(KeeEntry *o, struct Cadiz *resolver) { + o->resolver = resolver; +} + +//int kee_entry_load(KeeEntry *o, struct db_ctx *db, const char *id) { +// return ERR_OK; +//} + + +/// \todo replace with struct +static int kee_entry_deserialize_item(KeeEntry *o, const char *data, size_t data_len) { + GtkWidget *item; + int remaining; + int r; + uint64_t alice_u; + uint64_t bob_u; + long long alice; + long long bob; + char mem[1024]; + size_t out_len; + char *s = (char*)mem; + char *flags = s + 512; + char *parent = flags + 1; + char *ts = parent + 64; + char *signs = ts + 8; + char *alice_delta = signs + 1; + char *bob_delta = alice_delta + 10; + struct kee_import im; + + alice = 0; + bob = 0; + + import_init(&im, data, data_len); + + remaining = 1024; + out_len = remaining; + r = import_read(&im, flags, out_len); + if (!r) { + return ERR_FAIL; + } + + remaining -= r; + out_len = remaining; + r = import_read(&im, parent, out_len); + if (!r) { + return ERR_FAIL; + } + + remaining -= r; + out_len = remaining; + r = import_read(&im, ts, out_len); + if (!r) { + return ERR_FAIL; + } + + remaining -= r; + out_len = remaining; + r = import_read(&im, signs, out_len); + if (!r) { + return ERR_FAIL; + } + + remaining -= r; + out_len = remaining; + r = import_read(&im, alice_delta, out_len); + if (!r) { + return ERR_FAIL; + } + if (r > 7) { + return ERR_FAIL; + } + + remaining -= r; + out_len = remaining; + r = varint_read_u(alice_delta, r, &alice_u); + if (!r) { + return ERR_FAIL; + } + alice = (long long)alice_u; + if (alice > 0 && *signs & ALICE_CREDIT_NEGATIVE) { + alice *= -1; + } + + remaining -= r; + out_len = remaining; + r = import_read(&im, bob_delta, out_len); + if (!r) { + return ERR_FAIL; + } + if (r > 7) { + return ERR_FAIL; + } + + remaining -= r; + out_len = remaining; + r = varint_read_u(bob_delta, r, &bob_u); + if (!r) { + return ERR_FAIL; + } + bob = (long long)bob_u; + if (bob > 0 && *signs & BOB_CREDIT_NEGATIVE) { + bob *= -1; + } + +// remaining -= r; +// out_len = remaining; +// r = varint_read_u(alice_delta, r, &alice); +// if (!r) { +// return ERR_FAIL; +// } + + sprintf(s, "alice %i bob %i", alice, bob); + + item = gtk_label_new(s); + gtk_widget_set_hexpand(item, true); + gtk_box_append(GTK_BOX(o), item); + return ERR_OK; } @@ -82,6 +204,12 @@ int kee_entry_deserialize(KeeEntry *o, const char *key, size_t key_len, const ch char *p; CMimeMessage_T *msg; + // copy entry hash + r = calculate_digest_algo(data, data_len, o->current_id, GCRY_MD_SHA512); + if (r) { + return ERR_DIGESTFAIL; + } + o->state = 1; import_init(&im, data, data_len); @@ -159,9 +287,38 @@ void kee_entry_apply_list_item_widget(KeeEntry *o) { return; } +static int kee_entry_load_items(KeeEntry *o) { + GtkWidget *widget; + int r; + size_t key_len; + char *mem = malloc(4096); + char *last_key; + char *last_value; + size_t last_value_length; + + key_len = 73; + last_key = (char*)mem; + last_value = last_key + 128; + *last_key = DbKeyLedgerEntry; + memcpy(last_key+1, o->current_id, key_len - 1); + while (1) { + last_value_length = 2048; + r = db_next(o->db, DbKeyLedgerEntry, &last_key, &key_len, &last_value, &last_value_length); + if (r) { + break; + } + r = kee_entry_deserialize_item(o, last_value, last_value_length); + if (r) { + g_log(G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, "corrupt entry!"); + } + } + free(mem); +} + void kee_entry_apply_display_widget(KeeEntry *o) { GtkWidget *widget; + kee_entry_load_items(o); widget = gtk_label_new(o->subject); gtk_box_append(GTK_BOX(o), widget); return; @@ -171,7 +328,12 @@ void kee_entry_apply_display_widget(KeeEntry *o) { void kee_entry_apply_entry(KeeEntry *target, KeeEntry *orig) { KeeEntry *o; + target->db = orig->db; + target->current_id = orig->current_id; target->resolver = orig->resolver; target->subject = orig->subject; + target->unit_of_account = orig->unit_of_account; + target->alice = orig->alice; + target->bob = orig->bob; return target; } diff --git a/src/gtk/kee-entry.h b/src/gtk/kee-entry.h @@ -14,6 +14,13 @@ enum KEE_ENTRY_PROPS { KEE_N_ENTRY_PROPS, }; +enum KEE_ENTRY_SIGNS { + ALICE_CREDIT_NEGATIVE = 1, + BOB_CREDIT_NEGATIVE = 2, + ALICE_COLLATERAL_NEGATIVE = 4, + BOB_COLLATERAL_NEGATIVE = 8, +}; + #define KEE_TYPE_ENTRY kee_entry_get_type() G_DECLARE_FINAL_TYPE(KeeEntry, kee_entry, KEE, ENTRY, GtkBox); @@ -21,7 +28,8 @@ 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); void kee_entry_apply_display_widget(KeeEntry *o); -KeeEntry* kee_entry_new(struct Cadiz *resolver); +KeeEntry* kee_entry_new(struct db_ctx *db); +void kee_entry_set_resolver(KeeEntry *o, struct Cadiz *resolver); G_END_DECLS diff --git a/src/gtk/nav.c b/src/gtk/nav.c @@ -2,26 +2,26 @@ #include "nav.h" -static void kee_nav_log(struct KeeNav *nav) { - char s[128]; - char out[1024]; - int c; - int i; - - c = 0; - for (i = 0; i < nav->c + 1; i++) { - sprintf(s, "[%d:%p] ", i, nav->widgets[i]); - sprintf(out+c, s); - c += strlen(s); - } - g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "nav now %p: %s", nav->now, out); -} +//static void kee_nav_log(struct KeeNav *nav) { +// char s[128]; +// char out[1024]; +// int c; +// int i; +// +// c = 0; +// for (i = 0; i < nav->c + 1; i++) { +// sprintf(s, "[%d:%p] ", i, nav->widgets[i]); +// sprintf(out+c, s); +// c += strlen(s); +// } +// g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "nav now %p: %s", nav->now, out); +//} -void kee_nav_push(struct KeeNav *nav, GtkWidget *page) { +int kee_nav_push(struct KeeNav *nav, GtkWidget *page) { nav->c++; nav->widgets[nav->c] = page; nav->now = nav->widgets[nav->c]; - kee_nav_log(nav); +// kee_nav_log(nav); } GtkWidget* kee_nav_pop(struct KeeNav *nav) { @@ -33,7 +33,7 @@ GtkWidget* kee_nav_pop(struct KeeNav *nav) { r = nav->widgets[nav->c]; nav->c--; nav->now = nav->widgets[nav->c]; - kee_nav_log(nav); +// kee_nav_log(nav); } diff --git a/src/gtk/nav.h b/src/gtk/nav.h @@ -11,7 +11,7 @@ struct KeeNav { int c; }; -void kee_nav_push(struct KeeNav *nav, GtkWidget *page); +int kee_nav_push(struct KeeNav *nav, GtkWidget *page); GtkWidget* kee_nav_pop(struct KeeNav *nav); int kee_nav_is_top(struct KeeNav *nav); diff --git a/testdata.py b/testdata.py @@ -142,6 +142,7 @@ class LedgerEntry: collateral_delta_max = 0 def __init__(self, head, parent=None, body=NOBODY, signer=None): + random.seed(int(time.time_ns())) self.head = head self.flags = 0 self.signs = 0 @@ -206,31 +207,32 @@ class LedgerEntry: b = self.signs.to_bytes(1) self.__serialize_add(b, w) - realvalue = self.credit_delta - if self.flags & FLAGS_SIGNER_IS_BOB: - if (self.signs & SIGNS_BOB_CREDIT_DELTA_NEGATIVE): - realvalue *= -1 - else: - if (self.signs & SIGNS_ALICE_CREDIT_DELTA_NEGATIVE): - realvalue *= -1 +# realvalue = self.credit_delta +# if self.flags & FLAGS_SIGNER_IS_BOB: +# if (self.signs & SIGNS_BOB_CREDIT_DELTA_NEGATIVE): +# realvalue *= -1 +# else: +# if (self.signs & SIGNS_ALICE_CREDIT_DELTA_NEGATIVE): +# realvalue *= -1 - logg.debug('encoding credit delta {}'.format(realvalue)) + b = varint.encode(self.credit_delta) if self.flags: - self.__serialize_add(b'\x00', w) + self.__serialize_add(varint.encode(0), w) self.__serialize_add(b, w) if not self.flags: - self.__serialize_add(b'\x00', w) - + self.__serialize_add(varint.encode(0), w) - if self.flags: - self.__serialize_add(b'\x00', w) - logg.debug('encoding collateral delta {}'.format(self.collateral_delta)) + #if self.flags: + # self.__serialize_add(b'\x00', w) + #logg.debug('encode flags {} credit {} collateral {}'.format(self.flags, self.credit_delta, self.collateral_delta)) b = varint.encode(self.collateral_delta) + if not self.flags: + self.__serialize_add(varint.encode(0), w) self.__serialize_add(b, w) if not self.flags: - self.__serialize_add(b'\x00', w) + self.__serialize_add(varint.encode(0), w) #if self.signer != None: # self.signature = self.signer(b) @@ -254,8 +256,8 @@ class LedgerEntry: r = b'' r += PFX_LEDGER_ENTRY r += k - ts = v[65:65+8] - #logg.debug('ts {}: of {}'.format(ts.hex(), v.hex())) + ts = v[68:68+8] + logg.debug('ts {}: of {}'.format(ts.hex(), v.hex())) r += ts return r