/* * 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 [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 #include #include #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 [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; }