74 lines
5.2 KiB
C
74 lines
5.2 KiB
C
#include <assert.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <openssl/evp.h>
|
|
#include "utun_instance.h"
|
|
#include "routing_layer/topo_group.h"
|
|
#include "routing_layer/topo_node_sqlite.h"
|
|
#include "chat/chat_devgroup.h"
|
|
#include "../lib/u_async.h"
|
|
#include "../lib/mem.h"
|
|
|
|
int main(void) {
|
|
debug_config_init(); debug_set_level(DEBUG_LEVEL_DEBUG);
|
|
struct UTUN_INSTANCE inst = {0}; struct TOPO_GROUPS groups = {.instance = &inst}; inst.topo_groups = &groups;
|
|
inst.ua = uasync_create(); assert(inst.ua);
|
|
groups.node_registry = queue_new(inst.ua, 16, 0, 8, "devgroup_nodes");
|
|
groups.group_list = queue_new(inst.ua, 0, 0, 0, "devgroup_groups");
|
|
assert(groups.node_registry && groups.group_list);
|
|
assert(sc_generate_keypair(&inst.my_keys) == SC_OK);
|
|
uint8_t xpub[32];
|
|
memcpy(inst.my_ed25519_privkey, inst.my_keys.private_key, 32);
|
|
assert(!devgroup_public_keys(inst.my_ed25519_privkey, inst.my_keys.private_key, inst.my_ed25519_pubkey, xpub));
|
|
inst.node_id = sc_derive_node_id_from_pubkey(inst.my_keys.public_key); strcpy(inst.name, "device");
|
|
assert(sqlite3_open(":memory:", &inst.topo_sqlite_db) == SQLITE_OK);
|
|
assert(!topo_node_sqlite_init(inst.topo_sqlite_db)); assert(!topo_node_init_self(&inst));
|
|
assert(!chat_devgroup_rename(&inst, "Мои устройства"));
|
|
struct devgroup_record r, loaded; uint8_t ep[32], xp[32]; struct devgroup_profile p;
|
|
assert(devgroup_load_local(&inst, &r, ep, xp) == 1);
|
|
assert(memcmp(ep, xp, 32) && !devgroup_profile_read(&r, &p) && p.version == 1);
|
|
struct TOPO_NODE* node = topo_node_registry_find(&groups, inst.node_id);
|
|
uint64_t before = node->timestamp;
|
|
assert(!chat_devgroup_rename(&inst, "Мои устройства") && node->timestamp == before);
|
|
assert(!devgroup_verify(&r, inst.node_id, inst.my_keys.public_key, inst.my_ed25519_pubkey));
|
|
assert(devgroup_verify(&r, inst.node_id + 1, inst.my_keys.public_key, inst.my_ed25519_pubkey) < 0);
|
|
r.json[10] ^= 1; assert(devgroup_profile_read(&r, &p) < 0); r.json[10] ^= 1;
|
|
struct devgroup_record conflict = r; struct devgroup_profile original, changed;
|
|
assert(!devgroup_profile_read(&r, &original));
|
|
assert(!devgroup_sign(&conflict, ep, "Concurrent name", original.version, original.timestamp,
|
|
inst.node_id, inst.my_keys.public_key, inst.my_ed25519_pubkey));
|
|
assert(!devgroup_profile_read(&conflict, &changed));
|
|
assert((devgroup_profile_compare(&original, &changed) > 0) == (memcmp(original.hash, changed.hash, 32) > 0));
|
|
changed.version++; assert(devgroup_profile_compare(&changed, &original) > 0);
|
|
changed.version--; changed.timestamp++; assert(devgroup_profile_compare(&changed, &original) > 0);
|
|
assert(devgroup_decode(&conflict, (const uint8_t*)"", 192) < 0);
|
|
uint8_t wire[TOPO_NODE_WIRE_MAX_SIZE]; struct TOPO_GROUP_NODE nq = {0};
|
|
int bytes = topo_node_serialize(node, &nq, 0, 0, wire, sizeof(wire), 0); assert(bytes > 0);
|
|
struct TOPO_GROUP group = {.instance = &inst}; struct TOPO_NODE* parsed = NULL;
|
|
assert(!topo_node_deserialize(&group, wire, bytes, &parsed, NULL, NULL, NULL, NULL));
|
|
assert(!topo_node_verify(parsed) && !memcmp(&parsed->devgroup, &r, sizeof(r))); topo_node_destroy(&groups, parsed);
|
|
assert(devgroup_latest(inst.topo_sqlite_db, r.ed, &loaded, &p) == 1 && p.version == 1);
|
|
assert(sqlite3_exec(inst.topo_sqlite_db, "CREATE TRIGGER deny_devgroup BEFORE UPDATE ON nodes BEGIN SELECT RAISE(ABORT,'test'); END",
|
|
NULL, NULL, NULL) == SQLITE_OK);
|
|
assert(chat_devgroup_rename(&inst, "Rejected") < 0 && node->timestamp == before);
|
|
assert(devgroup_load_local(&inst, &loaded, ep, xp) == 1 && !strcmp(loaded.json, r.json));
|
|
assert(sqlite3_exec(inst.topo_sqlite_db, "DROP TRIGGER deny_devgroup", NULL, NULL, NULL) == SQLITE_OK);
|
|
assert(!chat_devgroup_rename(&inst, "New name"));
|
|
assert(devgroup_load_local(&inst, &loaded, ep, xp) == 1 && !devgroup_profile_read(&loaded, &p) && p.version == 2);
|
|
/* Новый runtime восстанавливает обе пары и принадлежность до первой публикации. */
|
|
topo_node_registry_unref(&groups, inst.node_id); assert(!topo_node_init_self(&inst));
|
|
node = topo_node_registry_find(&groups, inst.node_id); assert(!strcmp(node->devgroup.json, loaded.json));
|
|
uint8_t receipt[16] = {1};
|
|
assert(!chat_devgroup_import(&inst, &loaded, ep, xp, receipt, 42));
|
|
assert(chat_devgroup_receipt(&inst, receipt, 42) == 1);
|
|
assert(!chat_devgroup_leave(&inst) && !node->devgroup.json[0]);
|
|
assert(!chat_devgroup_import(&inst, &loaded, ep, xp, receipt, 42) && !node->devgroup.json[0]);
|
|
assert(devgroup_latest(inst.topo_sqlite_db, r.ed, &loaded, &p) == 0);
|
|
assert(!chat_devgroup_leave(&inst));
|
|
topo_node_registry_unref(&groups, inst.node_id); assert(!topo_node_init_self(&inst));
|
|
node = topo_node_registry_find(&groups, inst.node_id); assert(!node->devgroup.json[0]);
|
|
topo_node_registry_unref(&groups, inst.node_id); queue_free(groups.node_registry); queue_free(groups.group_list);
|
|
assert(sqlite3_close(inst.topo_sqlite_db) == SQLITE_OK); uasync_destroy(inst.ua, 0);
|
|
puts("PASS devgroup: signatures, wire, transactional projection, restart, rename, leave and late import replay"); return 0;
|
|
}
|