/* * get_pubkey_tcp.c — connect to a running n_signer over TCP and call * get_public_key for nostr_index 0 and 1, printing both hex pubkey and * bech32 npub for each. * * This is a cross-qube test client for Qubes OS: the signer runs in the * nostr_signer qube listening on tcp:[::]:11111, and this client runs in * a different qube connecting to the signer's FIPS address. * * Usage: * ./get_pubkey_tcp * ./get_pubkey_tcp npub1xxx...fips 11111 * * If no arguments are given, defaults to localhost:11111. * * Output: for each index, prints: * index 0: hex=<64 hex chars> npub=npub1... */ #include #include #include #include "nostr_common.h" #include "nsigner_transport.h" #include "nsigner_client.h" #include "nip019.h" #include "../cjson/cJSON.h" /* Demo caller key (32 bytes). Replace with your stable caller key in real use. */ static const unsigned char DEMO_PRIVKEY[32] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 }; static int hex_to_bytes(const char *hex, unsigned char *out, size_t out_len) { size_t len = strlen(hex); if (len != out_len * 2) { return -1; } for (size_t i = 0; i < out_len; i++) { unsigned int byte; if (sscanf(hex + 2 * i, "%2x", &byte) != 1) { return -1; } out[i] = (unsigned char)byte; } return 0; } static int query_pubkey(const char *host, int port, int nostr_index, char *out_hex, size_t hex_size, char *out_npub, size_t npub_size) { (void)npub_size; /* npub buffer size is enforced by nostr_key_to_bech32 output */ nsigner_transport_t *transport = NULL; nsigner_client_t *client = NULL; cJSON *params = NULL; cJSON *opts = NULL; cJSON *result = NULL; const char *hex_pubkey = NULL; unsigned char pubkey_bytes[32]; int rc = -1; transport = nsigner_transport_open_tcp(host, port, 10000); if (transport == NULL) { fprintf(stderr, "connect failed: cannot open TCP transport to %s:%d\n", host, port); goto cleanup; } client = nsigner_client_new(transport); if (client == NULL) { fprintf(stderr, "connect failed: cannot create nsigner client\n"); transport->close(transport); goto cleanup; } transport = NULL; /* owned by client now */ /* Set auth envelope — required for TCP listeners */ if (nsigner_client_set_auth(client, DEMO_PRIVKEY, "get_pubkey_tcp") != NOSTR_SUCCESS) { fprintf(stderr, "failed to set auth envelope\n"); goto cleanup; } /* params: [{"nostr_index": N}] */ params = cJSON_CreateArray(); if (params == NULL) { fprintf(stderr, "out of memory\n"); goto cleanup; } opts = cJSON_CreateObject(); if (opts == NULL) { fprintf(stderr, "out of memory\n"); goto cleanup; } cJSON_AddNumberToObject(opts, "nostr_index", nostr_index); cJSON_AddItemToArray(params, opts); opts = NULL; if (nsigner_client_call(client, "get_public_key", params, &result) != NOSTR_SUCCESS) { fprintf(stderr, "request failed for index %d: %s\n", nostr_index, nsigner_client_last_error(client)); params = NULL; /* nsigner_client_call took ownership even on failure */ goto cleanup; } params = NULL; /* nsigner_client_call took ownership */ if (!cJSON_IsString(result)) { fprintf(stderr, "index %d: unexpected result type\n", nostr_index); goto cleanup; } hex_pubkey = result->valuestring; if (strlen(hex_pubkey) != 64) { fprintf(stderr, "index %d: unexpected pubkey length: %zu\n", nostr_index, strlen(hex_pubkey)); goto cleanup; } strncpy(out_hex, hex_pubkey, hex_size - 1); out_hex[hex_size - 1] = '\0'; /* Convert hex pubkey to npub (bech32) */ if (hex_to_bytes(hex_pubkey, pubkey_bytes, 32) != 0) { fprintf(stderr, "index %d: failed to parse hex pubkey\n", nostr_index); goto cleanup; } if (nostr_key_to_bech32(pubkey_bytes, "npub", out_npub) != NOSTR_SUCCESS) { fprintf(stderr, "index %d: failed to convert to npub\n", nostr_index); goto cleanup; } rc = 0; cleanup: cJSON_Delete(opts); cJSON_Delete(params); cJSON_Delete(result); nsigner_client_free(client); return rc; } int main(int argc, char **argv) { const char *host = "127.0.0.1"; int port = 11111; char hex0[65], npub0[128]; char hex1[65], npub1[128]; int failures = 0; if (argc > 1) { host = argv[1]; } if (argc > 2) { port = atoi(argv[2]); if (port <= 0 || port > 65535) { fprintf(stderr, "Invalid port: %s\n", argv[2]); return 1; } } if (nostr_init() != NOSTR_SUCCESS) { fprintf(stderr, "failed to initialize crypto subsystem\n"); return 1; } printf("Connecting to n_signer at %s:%d\n", host, port); printf("Querying get_public_key for nostr_index 0 and 1...\n\n"); /* Query index 0 */ hex0[0] = '\0'; npub0[0] = '\0'; if (query_pubkey(host, port, 0, hex0, sizeof(hex0), npub0, sizeof(npub0)) == 0) { printf("index 0: hex=%s npub=%s\n", hex0, npub0); } else { printf("index 0: FAILED\n"); failures++; } /* Query index 1 */ hex1[0] = '\0'; npub1[0] = '\0'; if (query_pubkey(host, port, 1, hex1, sizeof(hex1), npub1, sizeof(npub1)) == 0) { printf("index 1: hex=%s npub=%s\n", hex1, npub1); } else { printf("index 1: FAILED\n"); failures++; } nostr_cleanup(); if (failures > 0) { printf("\n%d query(s) failed\n", failures); return 1; } printf("\nAll queries succeeded\n"); return 0; }