Add nostr_signer_nsigner_from_client, nostr_signer_last_error, make from_transport public

- nostr_signer_nsigner_from_transport: made public (was static) so callers
  who open their own transport can create a signer from it.
- nostr_signer_nsigner_from_client: new constructor that creates a signer
  from an already-created low-level nsigner_client_t. Lets callers use both
  the high-level typed wrappers and the low-level nsigner_client_call for
  raw passthrough on the same connection.
- nostr_signer_last_error: returns the raw n_signer RPC error message
  (e.g. 'path_not_allowed', 'unknown_role') from the last failed call.
  Delegates to nsigner_client_last_error for the remote backend.
- Forward declarations for nsigner_transport_t and nsigner_client_t added
  to nostr_signer.h so the new constructors can be declared without
  pulling in the transport/client headers.
This commit is contained in:
Laan Tungir
2026-08-06 10:17:17 -04:00
parent d575e8cdbc
commit 71a72dc7ed
2 changed files with 47 additions and 8 deletions
+28 -8
View File
@@ -1442,22 +1442,15 @@ int nostr_signer_mine_event(nostr_signer_t* signer,
}
#if defined(NOSTR_ENABLE_NSIGNER_CLIENT)
static nostr_signer_t* nostr_signer_nsigner_from_transport(nsigner_transport_t* transport, const char* role) {
nsigner_client_t* client = NULL;
nostr_signer_t* nostr_signer_nsigner_from_client(nsigner_client_t* client, const char* role) {
nostr_signer_t* signer = NULL;
if (transport == NULL) {
return NULL;
}
client = nsigner_client_new(transport);
if (client == NULL) {
return NULL;
}
signer = (nostr_signer_t*)calloc(1, sizeof(*signer));
if (signer == NULL) {
nsigner_client_free(client);
return NULL;
}
@@ -1471,6 +1464,21 @@ static nostr_signer_t* nostr_signer_nsigner_from_transport(nsigner_transport_t*
return signer;
}
nostr_signer_t* nostr_signer_nsigner_from_transport(nsigner_transport_t* transport, const char* role) {
nsigner_client_t* client = NULL;
if (transport == NULL) {
return NULL;
}
client = nsigner_client_new(transport);
if (client == NULL) {
return NULL;
}
return nostr_signer_nsigner_from_client(client, role);
}
nostr_signer_t* nostr_signer_nsigner_unix(const char* socket_name, const char* role, int timeout_ms) {
nsigner_transport_t* transport = NULL;
char discovered[8][64];
@@ -1523,6 +1531,18 @@ int nostr_signer_nsigner_set_auth(nostr_signer_t* signer,
return nsigner_client_set_auth(signer->u.remote.client, auth_privkey, label);
}
const char* nostr_signer_last_error(const nostr_signer_t* signer) {
if (signer == NULL) {
return "null signer";
}
#if defined(NOSTR_ENABLE_NSIGNER_CLIENT)
if (signer->backend == NOSTR_SIGNER_BACKEND_NSIGNER_REMOTE && signer->u.remote.client != NULL) {
return nsigner_client_last_error(signer->u.remote.client);
}
#endif
return "no error details available";
}
nostr_signer_t* nostr_signer_nsigner_qrexec(const char* target_qube, const char* service_name, const char* role, int timeout_ms) {
nsigner_transport_t* transport;
+19
View File
@@ -15,6 +15,12 @@ typedef struct nostr_signer nostr_signer_t;
nostr_signer_t* nostr_signer_local(const unsigned char private_key[32]);
void nostr_signer_free(nostr_signer_t* signer);
/* Returns a human-readable error string from the last failed call. For the
* remote nsigner backend this is the raw n_signer RPC error message (e.g.
* "path_not_allowed", "unknown_role"). For the local backend returns a
* generic string. Safe to call after any wrapper returns non-NOSTR_SUCCESS. */
const char* nostr_signer_last_error(const nostr_signer_t* signer);
/* Core verbs */
int nostr_signer_get_public_key(nostr_signer_t* signer, char out_pubkey_hex[65]);
int nostr_signer_sign_event(nostr_signer_t* signer, const cJSON* unsigned_event, cJSON** signed_event_out);
@@ -137,6 +143,19 @@ int nostr_signer_mine_event(nostr_signer_t* signer,
cJSON** signed_event_out);
#if defined(NOSTR_ENABLE_NSIGNER_CLIENT)
/* Forward declaration so from_transport can be declared without including
* nsigner_transport.h (which would create a header dependency cycle). */
typedef struct nsigner_transport nsigner_transport_t;
typedef struct nsigner_client nsigner_client_t;
/* Create a remote nsigner signer from an already-opened transport. Takes
* ownership of the transport. This is the most flexible constructor — the
* caller opens the transport (unix/tcp/serial/fds/qrexec) and passes it in. */
nostr_signer_t* nostr_signer_nsigner_from_transport(nsigner_transport_t* transport, const char* role);
/* Create a remote nsigner signer from an already-created low-level client.
* Takes ownership of the client (freed by nostr_signer_free). Useful when
* the caller needs both the high-level typed wrappers and the low-level
* nsigner_client_call for raw passthrough on the same connection. */
nostr_signer_t* nostr_signer_nsigner_from_client(nsigner_client_t* client, const char* role);
nostr_signer_t* nostr_signer_nsigner_unix(const char* socket_name, const char* role, int timeout_ms);
nostr_signer_t* nostr_signer_nsigner_serial(const char* device_path, const char* role, int timeout_ms);
nostr_signer_t* nostr_signer_nsigner_tcp(const char* host, int port, const char* role, int timeout_ms);