commit 429ba5ec8a93a493a29c592383a3d3cad80b9135
parent b705a954a0b6e1dde8cf54f5864cdbaaeeacdc1e
Author: triesap <triesap@radroots.dev>
Date: Tue, 6 Jan 2026 14:37:28 +0000
nip46: add nip04/nip44 rpc methods
- add nip04 encrypt/decrypt jsonrpc handlers
- add nip44 encrypt/decrypt jsonrpc handlers
- parse pubkeys and map nip46 responses to payloads
- register new nip46 methods alongside existing flow
Diffstat:
5 files changed, 306 insertions(+), 0 deletions(-)
diff --git a/src/api/jsonrpc/methods/nip46/mod.rs b/src/api/jsonrpc/methods/nip46/mod.rs
@@ -8,6 +8,10 @@ use crate::api::jsonrpc::{MethodRegistry, RpcContext};
pub mod status;
pub mod connect;
pub mod ping;
+pub mod nip04_encrypt;
+pub mod nip04_decrypt;
+pub mod nip44_encrypt;
+pub mod nip44_decrypt;
pub mod get_public_key;
pub mod sign_event;
pub mod session_status;
@@ -18,6 +22,10 @@ pub fn module(ctx: RpcContext, registry: MethodRegistry) -> Result<RpcModule<Rpc
status::register(&mut m, ®istry)?;
connect::register(&mut m, ®istry)?;
ping::register(&mut m, ®istry)?;
+ nip04_encrypt::register(&mut m, ®istry)?;
+ nip04_decrypt::register(&mut m, ®istry)?;
+ nip44_encrypt::register(&mut m, ®istry)?;
+ nip44_decrypt::register(&mut m, ®istry)?;
get_public_key::register(&mut m, ®istry)?;
sign_event::register(&mut m, ®istry)?;
session_status::register(&mut m, ®istry)?;
diff --git a/src/api/jsonrpc/methods/nip46/nip04_decrypt.rs b/src/api/jsonrpc/methods/nip46/nip04_decrypt.rs
@@ -0,0 +1,76 @@
+use anyhow::Result;
+use jsonrpsee::server::RpcModule;
+use serde::{Deserialize, Serialize};
+
+use crate::api::jsonrpc::{MethodRegistry, RpcContext, RpcError};
+use crate::nip46::client;
+use crate::nip46::session::Nip46Session;
+use radroots_nostr::prelude::radroots_nostr_parse_pubkey;
+use nostr::nips::nip46::{NostrConnectMethod, NostrConnectRequest, ResponseResult};
+
+#[derive(Debug, Deserialize)]
+struct Nip46Nip04DecryptParams {
+ session_id: String,
+ pubkey: String,
+ ciphertext: String,
+}
+
+#[derive(Clone, Debug, Serialize)]
+struct Nip46Nip04DecryptResponse {
+ plaintext: String,
+}
+
+pub fn register(m: &mut RpcModule<RpcContext>, registry: &MethodRegistry) -> Result<()> {
+ registry.track("nip46.nip04_decrypt");
+ m.register_async_method("nip46.nip04_decrypt", |params, ctx, _| async move {
+ let Nip46Nip04DecryptParams {
+ session_id,
+ pubkey,
+ ciphertext,
+ } = params
+ .parse()
+ .map_err(|e| RpcError::InvalidParams(e.to_string()))?;
+ let session = ctx
+ .state
+ .nip46_sessions
+ .get(&session_id)
+ .await
+ .ok_or_else(|| RpcError::InvalidParams("unknown session".to_string()))?;
+ let plaintext = request_nip04_decrypt(&session, pubkey, ciphertext).await?;
+ Ok::<Nip46Nip04DecryptResponse, RpcError>(Nip46Nip04DecryptResponse { plaintext })
+ })?;
+ Ok(())
+}
+
+async fn request_nip04_decrypt(
+ session: &Nip46Session,
+ pubkey: String,
+ ciphertext: String,
+) -> Result<String, RpcError> {
+ let public_key = radroots_nostr_parse_pubkey(&pubkey)
+ .map_err(|e| RpcError::InvalidParams(format!("invalid pubkey: {e}")))?;
+ let request = NostrConnectRequest::Nip04Decrypt {
+ public_key,
+ ciphertext,
+ };
+ let response = client::request(session, request, "nip04_decrypt").await?;
+ let response = response
+ .to_response(NostrConnectMethod::Nip04Decrypt)
+ .map_err(|e| RpcError::Other(format!("nip46 nip04_decrypt failed: {e}")))?;
+
+ if let Some(error) = response.error {
+ return Err(RpcError::Other(format!(
+ "nip46 nip04_decrypt error: {error}"
+ )));
+ }
+
+ match response.result {
+ Some(ResponseResult::Nip04Decrypt { plaintext }) => Ok(plaintext),
+ Some(_) => Err(RpcError::Other(
+ "nip46 nip04_decrypt unexpected response".to_string(),
+ )),
+ None => Err(RpcError::Other(
+ "nip46 nip04_decrypt missing response".to_string(),
+ )),
+ }
+}
diff --git a/src/api/jsonrpc/methods/nip46/nip04_encrypt.rs b/src/api/jsonrpc/methods/nip46/nip04_encrypt.rs
@@ -0,0 +1,73 @@
+use anyhow::Result;
+use jsonrpsee::server::RpcModule;
+use serde::{Deserialize, Serialize};
+
+use crate::api::jsonrpc::{MethodRegistry, RpcContext, RpcError};
+use crate::nip46::client;
+use crate::nip46::session::Nip46Session;
+use radroots_nostr::prelude::radroots_nostr_parse_pubkey;
+use nostr::nips::nip46::{NostrConnectMethod, NostrConnectRequest, ResponseResult};
+
+#[derive(Debug, Deserialize)]
+struct Nip46Nip04EncryptParams {
+ session_id: String,
+ pubkey: String,
+ text: String,
+}
+
+#[derive(Clone, Debug, Serialize)]
+struct Nip46Nip04EncryptResponse {
+ ciphertext: String,
+}
+
+pub fn register(m: &mut RpcModule<RpcContext>, registry: &MethodRegistry) -> Result<()> {
+ registry.track("nip46.nip04_encrypt");
+ m.register_async_method("nip46.nip04_encrypt", |params, ctx, _| async move {
+ let Nip46Nip04EncryptParams {
+ session_id,
+ pubkey,
+ text,
+ } = params
+ .parse()
+ .map_err(|e| RpcError::InvalidParams(e.to_string()))?;
+ let session = ctx
+ .state
+ .nip46_sessions
+ .get(&session_id)
+ .await
+ .ok_or_else(|| RpcError::InvalidParams("unknown session".to_string()))?;
+ let ciphertext = request_nip04_encrypt(&session, pubkey, text).await?;
+ Ok::<Nip46Nip04EncryptResponse, RpcError>(Nip46Nip04EncryptResponse { ciphertext })
+ })?;
+ Ok(())
+}
+
+async fn request_nip04_encrypt(
+ session: &Nip46Session,
+ pubkey: String,
+ text: String,
+) -> Result<String, RpcError> {
+ let public_key = radroots_nostr_parse_pubkey(&pubkey)
+ .map_err(|e| RpcError::InvalidParams(format!("invalid pubkey: {e}")))?;
+ let request = NostrConnectRequest::Nip04Encrypt { public_key, text };
+ let response = client::request(session, request, "nip04_encrypt").await?;
+ let response = response
+ .to_response(NostrConnectMethod::Nip04Encrypt)
+ .map_err(|e| RpcError::Other(format!("nip46 nip04_encrypt failed: {e}")))?;
+
+ if let Some(error) = response.error {
+ return Err(RpcError::Other(format!(
+ "nip46 nip04_encrypt error: {error}"
+ )));
+ }
+
+ match response.result {
+ Some(ResponseResult::Nip04Encrypt { ciphertext }) => Ok(ciphertext),
+ Some(_) => Err(RpcError::Other(
+ "nip46 nip04_encrypt unexpected response".to_string(),
+ )),
+ None => Err(RpcError::Other(
+ "nip46 nip04_encrypt missing response".to_string(),
+ )),
+ }
+}
diff --git a/src/api/jsonrpc/methods/nip46/nip44_decrypt.rs b/src/api/jsonrpc/methods/nip46/nip44_decrypt.rs
@@ -0,0 +1,76 @@
+use anyhow::Result;
+use jsonrpsee::server::RpcModule;
+use serde::{Deserialize, Serialize};
+
+use crate::api::jsonrpc::{MethodRegistry, RpcContext, RpcError};
+use crate::nip46::client;
+use crate::nip46::session::Nip46Session;
+use radroots_nostr::prelude::radroots_nostr_parse_pubkey;
+use nostr::nips::nip46::{NostrConnectMethod, NostrConnectRequest, ResponseResult};
+
+#[derive(Debug, Deserialize)]
+struct Nip46Nip44DecryptParams {
+ session_id: String,
+ pubkey: String,
+ ciphertext: String,
+}
+
+#[derive(Clone, Debug, Serialize)]
+struct Nip46Nip44DecryptResponse {
+ plaintext: String,
+}
+
+pub fn register(m: &mut RpcModule<RpcContext>, registry: &MethodRegistry) -> Result<()> {
+ registry.track("nip46.nip44_decrypt");
+ m.register_async_method("nip46.nip44_decrypt", |params, ctx, _| async move {
+ let Nip46Nip44DecryptParams {
+ session_id,
+ pubkey,
+ ciphertext,
+ } = params
+ .parse()
+ .map_err(|e| RpcError::InvalidParams(e.to_string()))?;
+ let session = ctx
+ .state
+ .nip46_sessions
+ .get(&session_id)
+ .await
+ .ok_or_else(|| RpcError::InvalidParams("unknown session".to_string()))?;
+ let plaintext = request_nip44_decrypt(&session, pubkey, ciphertext).await?;
+ Ok::<Nip46Nip44DecryptResponse, RpcError>(Nip46Nip44DecryptResponse { plaintext })
+ })?;
+ Ok(())
+}
+
+async fn request_nip44_decrypt(
+ session: &Nip46Session,
+ pubkey: String,
+ ciphertext: String,
+) -> Result<String, RpcError> {
+ let public_key = radroots_nostr_parse_pubkey(&pubkey)
+ .map_err(|e| RpcError::InvalidParams(format!("invalid pubkey: {e}")))?;
+ let request = NostrConnectRequest::Nip44Decrypt {
+ public_key,
+ ciphertext,
+ };
+ let response = client::request(session, request, "nip44_decrypt").await?;
+ let response = response
+ .to_response(NostrConnectMethod::Nip44Decrypt)
+ .map_err(|e| RpcError::Other(format!("nip46 nip44_decrypt failed: {e}")))?;
+
+ if let Some(error) = response.error {
+ return Err(RpcError::Other(format!(
+ "nip46 nip44_decrypt error: {error}"
+ )));
+ }
+
+ match response.result {
+ Some(ResponseResult::Nip44Decrypt { plaintext }) => Ok(plaintext),
+ Some(_) => Err(RpcError::Other(
+ "nip46 nip44_decrypt unexpected response".to_string(),
+ )),
+ None => Err(RpcError::Other(
+ "nip46 nip44_decrypt missing response".to_string(),
+ )),
+ }
+}
diff --git a/src/api/jsonrpc/methods/nip46/nip44_encrypt.rs b/src/api/jsonrpc/methods/nip46/nip44_encrypt.rs
@@ -0,0 +1,73 @@
+use anyhow::Result;
+use jsonrpsee::server::RpcModule;
+use serde::{Deserialize, Serialize};
+
+use crate::api::jsonrpc::{MethodRegistry, RpcContext, RpcError};
+use crate::nip46::client;
+use crate::nip46::session::Nip46Session;
+use radroots_nostr::prelude::radroots_nostr_parse_pubkey;
+use nostr::nips::nip46::{NostrConnectMethod, NostrConnectRequest, ResponseResult};
+
+#[derive(Debug, Deserialize)]
+struct Nip46Nip44EncryptParams {
+ session_id: String,
+ pubkey: String,
+ text: String,
+}
+
+#[derive(Clone, Debug, Serialize)]
+struct Nip46Nip44EncryptResponse {
+ ciphertext: String,
+}
+
+pub fn register(m: &mut RpcModule<RpcContext>, registry: &MethodRegistry) -> Result<()> {
+ registry.track("nip46.nip44_encrypt");
+ m.register_async_method("nip46.nip44_encrypt", |params, ctx, _| async move {
+ let Nip46Nip44EncryptParams {
+ session_id,
+ pubkey,
+ text,
+ } = params
+ .parse()
+ .map_err(|e| RpcError::InvalidParams(e.to_string()))?;
+ let session = ctx
+ .state
+ .nip46_sessions
+ .get(&session_id)
+ .await
+ .ok_or_else(|| RpcError::InvalidParams("unknown session".to_string()))?;
+ let ciphertext = request_nip44_encrypt(&session, pubkey, text).await?;
+ Ok::<Nip46Nip44EncryptResponse, RpcError>(Nip46Nip44EncryptResponse { ciphertext })
+ })?;
+ Ok(())
+}
+
+async fn request_nip44_encrypt(
+ session: &Nip46Session,
+ pubkey: String,
+ text: String,
+) -> Result<String, RpcError> {
+ let public_key = radroots_nostr_parse_pubkey(&pubkey)
+ .map_err(|e| RpcError::InvalidParams(format!("invalid pubkey: {e}")))?;
+ let request = NostrConnectRequest::Nip44Encrypt { public_key, text };
+ let response = client::request(session, request, "nip44_encrypt").await?;
+ let response = response
+ .to_response(NostrConnectMethod::Nip44Encrypt)
+ .map_err(|e| RpcError::Other(format!("nip46 nip44_encrypt failed: {e}")))?;
+
+ if let Some(error) = response.error {
+ return Err(RpcError::Other(format!(
+ "nip46 nip44_encrypt error: {error}"
+ )));
+ }
+
+ match response.result {
+ Some(ResponseResult::Nip44Encrypt { ciphertext }) => Ok(ciphertext),
+ Some(_) => Err(RpcError::Other(
+ "nip46 nip44_encrypt unexpected response".to_string(),
+ )),
+ None => Err(RpcError::Other(
+ "nip46 nip44_encrypt missing response".to_string(),
+ )),
+ }
+}