Implement NIP-46 remote signing API, tests/example, build integration, and refresh README docs
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* NIP-46 Remote Signer Example
|
||||
*
|
||||
* Demonstrates signer session setup, bunker URL generation,
|
||||
* request parsing, request handling, and encrypted response event creation.
|
||||
*/
|
||||
|
||||
#include "../nostr_core/nostr_core.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static int parse_hex_key(const char* hex, unsigned char out[32]) {
|
||||
if (!hex || strlen(hex) != 64) return -1;
|
||||
return nostr_hex_to_bytes(hex, out, 32);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc < 3) {
|
||||
fprintf(stderr, "Usage: %s <signer_privkey_hex> <user_privkey_hex> [relay_url]\n", argv[0]);
|
||||
fprintf(stderr, "Example: %s <64hex> <64hex> wss://relay.example.com\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char* relay = (argc >= 4) ? argv[3] : "wss://relay.example.com";
|
||||
|
||||
unsigned char signer_sk[32];
|
||||
unsigned char user_sk[32];
|
||||
if (parse_hex_key(argv[1], signer_sk) != 0 || parse_hex_key(argv[2], user_sk) != 0) {
|
||||
fprintf(stderr, "Invalid private key hex; expected 64 hex characters for each key\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (nostr_init() != NOSTR_SUCCESS) {
|
||||
fprintf(stderr, "Failed to initialize nostr library\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char* relays[] = { relay };
|
||||
nostr_nip46_signer_session_t signer;
|
||||
int rc = nostr_nip46_signer_session_init(&signer, signer_sk, user_sk, relays, 1);
|
||||
if (rc != NOSTR_SUCCESS) {
|
||||
fprintf(stderr, "signer init failed: %s\n", nostr_strerror(rc));
|
||||
nostr_cleanup();
|
||||
return 1;
|
||||
}
|
||||
|
||||
char bunker_url[1024];
|
||||
rc = nostr_nip46_signer_create_bunker_url(&signer, "demo-secret", bunker_url, sizeof(bunker_url));
|
||||
if (rc != NOSTR_SUCCESS) {
|
||||
fprintf(stderr, "failed to create bunker url: %s\n", nostr_strerror(rc));
|
||||
nostr_nip46_signer_session_destroy(&signer);
|
||||
nostr_cleanup();
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("NIP-46 signer initialized\n");
|
||||
printf("Signer pubkey: %s\n", signer.signer_pubkey_hex);
|
||||
printf("User pubkey: %s\n", signer.user_pubkey_hex);
|
||||
printf("Relay: %s\n", relay);
|
||||
printf("Bunker URL: %s\n\n", bunker_url);
|
||||
|
||||
// Simulate receiving a connect request and producing a response
|
||||
const char* connect_params[] = { signer.signer_pubkey_hex, "demo-secret", "sign_event:1,get_public_key" };
|
||||
nostr_nip46_request_t req;
|
||||
rc = nostr_nip46_create_request("demo-req-1", NOSTR_NIP46_METHOD_CONNECT, connect_params, 3, &req);
|
||||
if (rc != NOSTR_SUCCESS) {
|
||||
fprintf(stderr, "failed to create demo request: %s\n", nostr_strerror(rc));
|
||||
nostr_nip46_signer_session_destroy(&signer);
|
||||
nostr_cleanup();
|
||||
return 1;
|
||||
}
|
||||
|
||||
nostr_nip46_response_t resp;
|
||||
rc = nostr_nip46_signer_handle_request(&signer, &req, &resp);
|
||||
if (rc != NOSTR_SUCCESS) {
|
||||
fprintf(stderr, "failed to handle demo request: %s\n", nostr_strerror(rc));
|
||||
nostr_nip46_free_request(&req);
|
||||
nostr_nip46_signer_session_destroy(&signer);
|
||||
nostr_cleanup();
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("Handled method: %s\n", req.method_str);
|
||||
printf("Response result: %s\n", resp.result ? resp.result : "<none>");
|
||||
printf("Response error: %s\n", resp.error ? resp.error : "<none>");
|
||||
|
||||
// Simulate building encrypted response event back to a client
|
||||
unsigned char client_sk[32];
|
||||
unsigned char client_pk[32];
|
||||
memset(client_sk, 0, sizeof(client_sk));
|
||||
client_sk[31] = 1; // deterministic demo key
|
||||
if (nostr_ec_public_key_from_private_key(client_sk, client_pk) != 0) {
|
||||
fprintf(stderr, "failed to derive demo client pubkey\n");
|
||||
nostr_nip46_free_response(&resp);
|
||||
nostr_nip46_free_request(&req);
|
||||
nostr_nip46_signer_session_destroy(&signer);
|
||||
nostr_cleanup();
|
||||
return 1;
|
||||
}
|
||||
|
||||
cJSON* response_event = nostr_nip46_create_response_event(&resp, signer.signer_private_key, client_pk, 0);
|
||||
if (!response_event) {
|
||||
fprintf(stderr, "failed to create encrypted response event\n");
|
||||
nostr_nip46_free_response(&resp);
|
||||
nostr_nip46_free_request(&req);
|
||||
nostr_nip46_signer_session_destroy(&signer);
|
||||
nostr_cleanup();
|
||||
return 1;
|
||||
}
|
||||
|
||||
char* response_event_json = cJSON_Print(response_event);
|
||||
if (response_event_json) {
|
||||
printf("\nEncrypted response event (publish this to relays):\n%s\n", response_event_json);
|
||||
free(response_event_json);
|
||||
}
|
||||
|
||||
cJSON_Delete(response_event);
|
||||
nostr_nip46_free_response(&resp);
|
||||
nostr_nip46_free_request(&req);
|
||||
nostr_nip46_signer_session_destroy(&signer);
|
||||
nostr_cleanup();
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user