196 lines
5.8 KiB
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:[::]:8080, 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 8080
|
|
*
|
|
* If no arguments are given, defaults to localhost:8080.
|
|
*
|
|
* 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 = 8080;
|
|
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;
|
|
}
|