v0.0.42 - Add C qrexec client example using high-level nostr_signer API with nostr_index selector; sync nostr_core_lib with qrexec transport and index support

This commit is contained in:
Laan Tungir
2026-07-11 14:28:09 -04:00
parent 478c3a569e
commit 9a8657f663
4 changed files with 241 additions and 3 deletions

View File

@@ -0,0 +1,110 @@
/*
* get_pubkey_qrexec.c — connect to a running n_signer in another Qubes qube
* via qrexec, using the high-level nostr_signer API from nostr_core_lib.
*
* This demonstrates the new nostr_core_lib client features:
* - nostr_signer_nsigner_qrexec() — qrexec transport
* - nostr_signer_nsigner_set_nostr_index() — index-based key selection
*
* Usage:
* ./get_pubkey_qrexec <target_qube> [nostr_index]
* ./get_pubkey_qrexec nostr_signer 0
* ./get_pubkey_qrexec nostr_signer 1
*
* No auth envelope needed — qrexec identity comes from QREXEC_REMOTE_DOMAIN
* on the server side.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "nostr_common.h"
#include "nostr_signer.h"
#include "nip019.h"
int main(int argc, char **argv) {
const char *target_qube;
const char *service_name = "qubes.NsignerRpc";
int nostr_index = 0;
nostr_signer_t *signer = NULL;
char pubkey_hex[65];
unsigned char pubkey_bytes[32];
char npub[128];
int rc;
if (argc < 2) {
fprintf(stderr, "Usage: %s <target_qube> [nostr_index]\n", argv[0]);
return 1;
}
target_qube = argv[1];
if (argc > 2) {
nostr_index = atoi(argv[2]);
}
if (nostr_init() != NOSTR_SUCCESS) {
fprintf(stderr, "failed to initialize crypto subsystem\n");
return 1;
}
printf("Connecting to n_signer in qube \"%s\" via qrexec (index %d)...\n",
target_qube, nostr_index);
/* Create a high-level signer backed by qrexec transport */
signer = nostr_signer_nsigner_qrexec(target_qube, service_name, NULL, 30000);
if (signer == NULL) {
fprintf(stderr, "failed to create qrexec signer (is qrexec-client-vm available?)\n");
nostr_cleanup();
return 1;
}
/* Select key by nostr_index (NIP-06 m/44'/1237'/N'/0/0) */
if (nostr_signer_nsigner_set_nostr_index(signer, nostr_index) != NOSTR_SUCCESS) {
fprintf(stderr, "failed to set nostr_index\n");
nostr_signer_free(signer);
nostr_cleanup();
return 1;
}
/* Request the public key */
rc = nostr_signer_get_public_key(signer, pubkey_hex);
if (rc != NOSTR_SUCCESS) {
if (rc == NOSTR_ERROR_NSIGNER_INDEX_NOT_ALLOWED) {
fprintf(stderr, "DENIED: index %d is not in the signer's whitelist\n", nostr_index);
} else if (rc == NOSTR_ERROR_NSIGNER_POLICY_DENIED) {
fprintf(stderr, "DENIED: policy denied (caller not approved at signer terminal)\n");
} else {
fprintf(stderr, "get_public_key failed: error code %d\n", rc);
}
nostr_signer_free(signer);
nostr_cleanup();
return 1;
}
/* Convert hex pubkey to npub (bech32) */
{
int i;
for (i = 0; i < 32; i++) {
unsigned int byte;
if (sscanf(pubkey_hex + 2 * i, "%2x", &byte) != 1) {
fprintf(stderr, "failed to parse hex pubkey\n");
nostr_signer_free(signer);
nostr_cleanup();
return 1;
}
pubkey_bytes[i] = (unsigned char)byte;
}
}
if (nostr_key_to_bech32(pubkey_bytes, "npub", npub) != NOSTR_SUCCESS) {
fprintf(stderr, "failed to convert to npub\n");
nostr_signer_free(signer);
nostr_cleanup();
return 1;
}
printf("index %d: hex=%s npub=%s\n", nostr_index, pubkey_hex, npub);
nostr_signer_free(signer);
nostr_cleanup();
return 0;
}