Files
n_signer/examples/get_pubkey_tcp.c

196 lines
5.8 KiB
C

/*
* 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 <host> <port>
* ./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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#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;
}