171 lines
6.3 KiB
C
171 lines
6.3 KiB
C
#include "../src/dispatcher.h"
|
|
|
|
#include "../src/enforcement.h"
|
|
#include "../src/role_table.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
static int g_passes = 0;
|
|
static int g_total = 0;
|
|
|
|
static void check_condition(const char *name, int condition) {
|
|
g_total++;
|
|
if (condition) {
|
|
printf("PASS: %s\n", name);
|
|
g_passes++;
|
|
} else {
|
|
printf("FAIL: %s\n", name);
|
|
}
|
|
}
|
|
|
|
static int response_has(const char *response, const char *needle) {
|
|
return (response != NULL && needle != NULL && strstr(response, needle) != NULL);
|
|
}
|
|
|
|
static role_entry_t make_nostr_entry(const char *name, int idx) {
|
|
role_entry_t e;
|
|
|
|
memset(&e, 0, sizeof(e));
|
|
strncpy(e.name, name, sizeof(e.name) - 1);
|
|
strncpy(e.purpose_str, "nostr", sizeof(e.purpose_str) - 1);
|
|
strncpy(e.curve_str, "secp256k1", sizeof(e.curve_str) - 1);
|
|
e.purpose = role_purpose_from_str(e.purpose_str);
|
|
e.curve = role_curve_from_str(e.curve_str);
|
|
e.selector_type = SELECTOR_NOSTR_INDEX;
|
|
e.nostr_index = idx;
|
|
e.derived = 0;
|
|
|
|
return e;
|
|
}
|
|
|
|
static role_entry_t make_path_entry(const char *name, const char *purpose, const char *curve, const char *path) {
|
|
role_entry_t e;
|
|
|
|
memset(&e, 0, sizeof(e));
|
|
strncpy(e.name, name, sizeof(e.name) - 1);
|
|
strncpy(e.purpose_str, purpose, sizeof(e.purpose_str) - 1);
|
|
strncpy(e.curve_str, curve, sizeof(e.curve_str) - 1);
|
|
strncpy(e.role_path, path, sizeof(e.role_path) - 1);
|
|
e.purpose = role_purpose_from_str(e.purpose_str);
|
|
e.curve = role_curve_from_str(e.curve_str);
|
|
e.selector_type = SELECTOR_ROLE_PATH;
|
|
e.nostr_index = -1;
|
|
e.derived = 0;
|
|
|
|
return e;
|
|
}
|
|
|
|
int main(void) {
|
|
role_table_t table;
|
|
role_entry_t main_role;
|
|
role_entry_t ssh_role;
|
|
mnemonic_state_t mnemonic;
|
|
dispatcher_ctx_t dispatcher;
|
|
key_store_t key_store;
|
|
const char *valid_12 = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";
|
|
char *resp;
|
|
int derived;
|
|
|
|
role_table_init(&table);
|
|
|
|
main_role = make_nostr_entry("main", 0);
|
|
ssh_role = make_path_entry("ssh_key", "ssh", "ed25519", "m/44'/822'/0'/0/0");
|
|
|
|
role_table_add(&table, &main_role);
|
|
role_table_add(&table, &ssh_role);
|
|
|
|
mnemonic_init(&mnemonic);
|
|
mnemonic_load(&mnemonic, valid_12);
|
|
|
|
memset(&key_store, 0, sizeof(key_store));
|
|
dispatcher_init(&dispatcher, &table, &mnemonic, &key_store);
|
|
|
|
derived = crypto_init();
|
|
check_condition("crypto_init succeeds", derived == 0);
|
|
|
|
derived = crypto_derive_all(&key_store, &table, &mnemonic);
|
|
check_condition("crypto_derive_all derives at least one key", derived >= 1);
|
|
|
|
/* 1. Valid get_public_key no selector -> default main, real pubkey */
|
|
resp = dispatcher_handle_request(&dispatcher,
|
|
"{\"id\":\"1\",\"method\":\"get_public_key\",\"params\":[\"\"]}");
|
|
check_condition("get_public_key default role returns derived hex",
|
|
response_has(resp, "\"id\":\"1\"") && !response_has(resp, "not_yet_derived") && response_has(resp, "\"result\":\""));
|
|
free(resp);
|
|
|
|
/* 2. sign_event with role main */
|
|
resp = dispatcher_handle_request(&dispatcher,
|
|
"{\"id\":\"2\",\"method\":\"sign_event\",\"params\":[\"{\\\"kind\\\":1,\\\"content\\\":\\\"hello\\\",\\\"tags\\\":[]}\",{\"role\":\"main\"}]}");
|
|
check_condition("sign_event with role=main returns signed event",
|
|
response_has(resp, "\"id\":\"2\"") && response_has(resp, "pubkey") && response_has(resp, "sig") && response_has(resp, "created_at"));
|
|
free(resp);
|
|
|
|
/* 3. sign_event with nostr_index 0 */
|
|
resp = dispatcher_handle_request(&dispatcher,
|
|
"{\"id\":\"3\",\"method\":\"sign_event\",\"params\":[\"{\\\"kind\\\":1,\\\"content\\\":\\\"hello2\\\",\\\"tags\\\":[]}\",{\"nostr_index\":0}]}");
|
|
check_condition("sign_event with nostr_index=0 returns signed event",
|
|
response_has(resp, "\"id\":\"3\"") && response_has(resp, "pubkey") && response_has(resp, "sig") && response_has(resp, "created_at"));
|
|
free(resp);
|
|
|
|
/* 4. ambiguous selector role + nostr_index */
|
|
resp = dispatcher_handle_request(&dispatcher,
|
|
"{\"id\":\"4\",\"method\":\"sign_event\",\"params\":[\"{}\",{\"role\":\"main\",\"nostr_index\":0}]}");
|
|
check_condition("ambiguous selector returns 1001",
|
|
response_has(resp, "\"id\":\"4\"") && response_has(resp, "\"code\":1001"));
|
|
free(resp);
|
|
|
|
/* 5. role not found */
|
|
resp = dispatcher_handle_request(&dispatcher,
|
|
"{\"id\":\"5\",\"method\":\"sign_event\",\"params\":[\"{}\",{\"role\":\"nonexistent\"}]}");
|
|
check_condition("role not found returns 1002",
|
|
response_has(resp, "\"id\":\"5\"") && response_has(resp, "\"code\":1002"));
|
|
free(resp);
|
|
|
|
/* 6. purpose mismatch: sign_event against ssh role */
|
|
resp = dispatcher_handle_request(&dispatcher,
|
|
"{\"id\":\"6\",\"method\":\"sign_event\",\"params\":[\"{}\",{\"role\":\"ssh_key\"}]}");
|
|
check_condition("purpose mismatch returns 1004",
|
|
response_has(resp, "\"id\":\"6\"") && response_has(resp, "\"code\":1004"));
|
|
free(resp);
|
|
|
|
/* 7. invalid JSON */
|
|
resp = dispatcher_handle_request(&dispatcher,
|
|
"{\"id\":\"7\",\"method\":\"sign_event\",\"params\":[\"{}\"]");
|
|
check_condition("invalid JSON returns -32700",
|
|
response_has(resp, "\"code\":-32700"));
|
|
free(resp);
|
|
|
|
/* 8. missing method */
|
|
resp = dispatcher_handle_request(&dispatcher,
|
|
"{\"id\":\"8\",\"params\":[\"{}\"]}");
|
|
check_condition("missing method returns -32600",
|
|
response_has(resp, "\"id\":\"8\"") && response_has(resp, "\"code\":-32600"));
|
|
free(resp);
|
|
|
|
/* 9. mnemonic not loaded */
|
|
mnemonic_unload(&mnemonic);
|
|
resp = dispatcher_handle_request(&dispatcher,
|
|
"{\"id\":\"9\",\"method\":\"get_public_key\",\"params\":[\"\"]}");
|
|
check_condition("mnemonic not loaded returns 1006",
|
|
response_has(resp, "\"id\":\"9\"") && response_has(resp, "\"code\":1006"));
|
|
free(resp);
|
|
|
|
mnemonic_load(&mnemonic, valid_12);
|
|
|
|
/* 10. unknown verb via enforcement */
|
|
resp = dispatcher_handle_request(&dispatcher,
|
|
"{\"id\":\"10\",\"method\":\"foo_bar\",\"params\":[\"\"]}");
|
|
check_condition("unknown verb returns -32601",
|
|
response_has(resp, "\"id\":\"10\"") && response_has(resp, "\"code\":-32601"));
|
|
free(resp);
|
|
|
|
crypto_wipe(&key_store);
|
|
crypto_cleanup();
|
|
|
|
printf("%d/12 tests passed\n", g_passes);
|
|
|
|
return (g_passes == 12 && g_total == 12) ? 0 : 1;
|
|
}
|