@@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- Support signing using NIP-46 bunker - by Awiteb
|
- Support signing using NIP-46 bunker - by Awiteb
|
||||||
- Keyring the secret key `n34 config keyring --enable` - by Awiteb
|
- Keyring the secret key `n34 config keyring --enable` - by Awiteb
|
||||||
- New flag to `patch apply and merge` to mention patches - by Awiteb
|
- New flag to `patch apply and merge` to mention patches - by Awiteb
|
||||||
|
- Sign using NIP-07 - by Awiteb
|
||||||
|
|
||||||
### Dependencies
|
### Dependencies
|
||||||
|
|
||||||
|
|||||||
39
Cargo.lock
generated
39
Cargo.lock
generated
@@ -837,6 +837,12 @@ version = "1.10.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
|
checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "httpdate"
|
||||||
|
version = "1.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper"
|
name = "hyper"
|
||||||
version = "1.6.0"
|
version = "1.6.0"
|
||||||
@@ -850,6 +856,7 @@ dependencies = [
|
|||||||
"http",
|
"http",
|
||||||
"http-body",
|
"http-body",
|
||||||
"httparse",
|
"httparse",
|
||||||
|
"httpdate",
|
||||||
"itoa",
|
"itoa",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
@@ -1235,6 +1242,7 @@ dependencies = [
|
|||||||
"either",
|
"either",
|
||||||
"futures",
|
"futures",
|
||||||
"nostr",
|
"nostr",
|
||||||
|
"nostr-browser-signer-proxy",
|
||||||
"nostr-connect",
|
"nostr-connect",
|
||||||
"nostr-keyring",
|
"nostr-keyring",
|
||||||
"nostr-sdk",
|
"nostr-sdk",
|
||||||
@@ -1279,6 +1287,25 @@ dependencies = [
|
|||||||
"url",
|
"url",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nostr-browser-signer-proxy"
|
||||||
|
version = "0.43.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "36272167bc7aa8b87d0638675d1b0fd7bff04eb6ab49f97303229a06a7bbc849"
|
||||||
|
dependencies = [
|
||||||
|
"atomic-destructor",
|
||||||
|
"bytes",
|
||||||
|
"http-body-util",
|
||||||
|
"hyper",
|
||||||
|
"hyper-util",
|
||||||
|
"nostr",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"tokio",
|
||||||
|
"tracing",
|
||||||
|
"uuid",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nostr-connect"
|
name = "nostr-connect"
|
||||||
version = "0.43.0"
|
version = "0.43.0"
|
||||||
@@ -2494,6 +2521,18 @@ version = "0.2.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "uuid"
|
||||||
|
version = "1.17.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom 0.3.3",
|
||||||
|
"js-sys",
|
||||||
|
"serde",
|
||||||
|
"wasm-bindgen",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "valuable"
|
name = "valuable"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
|
|||||||
25
Cargo.toml
25
Cargo.toml
@@ -29,18 +29,19 @@ nostr-sdk = { version = "0.43.0", default-features = false }
|
|||||||
serde = { version = "1.0.219", features = ["derive"] }
|
serde = { version = "1.0.219", features = ["derive"] }
|
||||||
tokio = { version = "1.47.1", features = ["macros", "rt-multi-thread"] }
|
tokio = { version = "1.47.1", features = ["macros", "rt-multi-thread"] }
|
||||||
|
|
||||||
chrono = "0.4.41"
|
chrono = "0.4.41"
|
||||||
convert_case = "0.8.0"
|
convert_case = "0.8.0"
|
||||||
dirs = "6.0.0"
|
dirs = "6.0.0"
|
||||||
easy-ext = "1.0.2"
|
easy-ext = "1.0.2"
|
||||||
either = "1.15.0"
|
either = "1.15.0"
|
||||||
futures = "0.3.31"
|
futures = "0.3.31"
|
||||||
regex = "1.11.1"
|
nostr-browser-signer-proxy = "0.43.0"
|
||||||
tempfile = "3.20.0"
|
regex = "1.11.1"
|
||||||
thiserror = "2.0.12"
|
tempfile = "3.20.0"
|
||||||
toml = "0.9.4"
|
thiserror = "2.0.12"
|
||||||
tracing = "0.1.41"
|
toml = "0.9.4"
|
||||||
tracing-subscriber = "0.3.19"
|
tracing = "0.1.41"
|
||||||
|
tracing-subscriber = "0.3.19"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
lto = "fat"
|
lto = "fat"
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ details, see the following section.
|
|||||||
- [X] Proof of Work ([NIP-13])
|
- [X] Proof of Work ([NIP-13])
|
||||||
- [X] `nostr:` URI scheme, in the issue/reply content ([NIP-21])
|
- [X] `nostr:` URI scheme, in the issue/reply content ([NIP-21])
|
||||||
- [X] Signing using bunker ([NIP-46])
|
- [X] Signing using bunker ([NIP-46])
|
||||||
- [ ] Signing using [NIP-07] proxy ([nostr-browser-signer-proxy])
|
- [X] Signing using [NIP-07] proxy ([nostr-browser-signer-proxy])
|
||||||
- [ ] Code Snippets ([NIP-C0])
|
- [ ] Code Snippets ([NIP-C0])
|
||||||
- [X] In device relays and repos bookmark (`sets` command)
|
- [X] In device relays and repos bookmark (`sets` command)
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
- [Manage Configuration](config/README.md)
|
- [Manage Configuration](config/README.md)
|
||||||
- [Default PoW Difficulty](config/pow.md)
|
- [Default PoW Difficulty](config/pow.md)
|
||||||
- [Fallback Relays](config/relays.md)
|
- [Fallback Relays](config/relays.md)
|
||||||
|
- [NIP-07 Browser Signer Proxy](config/nip07.md)
|
||||||
- [NIP-46 Bunker](config/bunker.md)
|
- [NIP-46 Bunker](config/bunker.md)
|
||||||
- [Secret Key Keyring](config/keyring.md)
|
- [Secret Key Keyring](config/keyring.md)
|
||||||
- [Manage Repositories](repo/README.md)
|
- [Manage Repositories](repo/README.md)
|
||||||
|
|||||||
@@ -8,6 +8,9 @@ The `n34` command-line tool accepts the following options:
|
|||||||
signing events.
|
signing events.
|
||||||
- `-b`, `--bunker-url`: The URL of a NIP-46 bunker service used for remote
|
- `-b`, `--bunker-url`: The URL of a NIP-46 bunker service used for remote
|
||||||
signing of events.
|
signing of events.
|
||||||
|
- `-7`, `--nip07`: Enables signing events using the browser's NIP-07
|
||||||
|
extension. Listens on `127.0.0.1:51034`. You can configure the address with `n34
|
||||||
|
config nip07`
|
||||||
- `-r`, `--relays`: A relay to read from and write to. This option can be
|
- `-r`, `--relays`: A relay to read from and write to. This option can be
|
||||||
specified multiple times to connect to several relays.
|
specified multiple times to connect to several relays.
|
||||||
- `--pow`: Sets the Proof of Work difficulty required when creating events.
|
- `--pow`: Sets the Proof of Work difficulty required when creating events.
|
||||||
|
|||||||
22
docs/config/nip07.md
Normal file
22
docs/config/nip07.md
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# NIP-07 Browser Signer Proxy
|
||||||
|
|
||||||
|
> `n34 config nip07`
|
||||||
|
|
||||||
|
**Usage:**
|
||||||
|
```
|
||||||
|
Manage the NIP-07 browser signer proxy by enabling or disabling it and configuring the `ip:port` address.
|
||||||
|
|
||||||
|
Usage: n34 config nip07 [OPTIONS] <--enable|--disable>
|
||||||
|
|
||||||
|
Options:
|
||||||
|
--enable Enable NIP-07 as the default signer
|
||||||
|
--disable Disable NIP-07 as the default signer
|
||||||
|
--addr <ADDR> Set the `ip:port` for the browser signer proxy (default: 127.0.0.1:51034)
|
||||||
|
```
|
||||||
|
|
||||||
|
Use [NIP-07] (Browser Extension Signer) as your default signer. This is achieved
|
||||||
|
by running a proxy at the specified `ADDR`, which defaults to `127.0.0.1:51034`.
|
||||||
|
The proxy forwards `n34` requests to the browser signer and relays the responses
|
||||||
|
back.
|
||||||
|
|
||||||
|
[NIP-07]: https://github.com/nostr-protocol/nips/blob/master/07.md
|
||||||
@@ -390,7 +390,7 @@
|
|||||||
<span class="feature-text">Signing using bunker (<a href="https://github.com/nostr-protocol/nips/blob/master/46.md" target="_blank" rel="noreferrer">NIP-46</a>)</span>
|
<span class="feature-text">Signing using bunker (<a href="https://github.com/nostr-protocol/nips/blob/master/46.md" target="_blank" rel="noreferrer">NIP-46</a>)</span>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<span class="feature-check pending"></span>
|
<span class="feature-check completed"></span>
|
||||||
<span class="feature-text pending">Signing using <a href="https://github.com/nostr-protocol/nips/blob/master/07.md" target="_blank" rel="noreferrer">NIP-07</a> proxy (<a href="https://crates.io/crates/nostr-browser-signer-proxy" target="_blank" rel="noreferrer">nostr-browser-signer-proxy</a>)</span>
|
<span class="feature-text pending">Signing using <a href="https://github.com/nostr-protocol/nips/blob/master/07.md" target="_blank" rel="noreferrer">NIP-07</a> proxy (<a href="https://crates.io/crates/nostr-browser-signer-proxy" target="_blank" rel="noreferrer">nostr-browser-signer-proxy</a>)</span>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
|
|||||||
@@ -18,6 +18,8 @@
|
|||||||
mod bunker;
|
mod bunker;
|
||||||
/// `config keyring` subcommand
|
/// `config keyring` subcommand
|
||||||
mod keyring;
|
mod keyring;
|
||||||
|
/// `config nip07` subcommand
|
||||||
|
mod nip07;
|
||||||
/// `config pow` subcommand
|
/// `config pow` subcommand
|
||||||
mod pow;
|
mod pow;
|
||||||
/// `config relays` subcommand
|
/// `config relays` subcommand
|
||||||
@@ -27,6 +29,7 @@ use clap::Subcommand;
|
|||||||
|
|
||||||
use self::bunker::BunkerArgs;
|
use self::bunker::BunkerArgs;
|
||||||
use self::keyring::KeyringArgs;
|
use self::keyring::KeyringArgs;
|
||||||
|
use self::nip07::Nip07Args;
|
||||||
use self::pow::PowArgs;
|
use self::pow::PowArgs;
|
||||||
use self::relays::RelaysArgs;
|
use self::relays::RelaysArgs;
|
||||||
use super::CliOptions;
|
use super::CliOptions;
|
||||||
@@ -45,10 +48,13 @@ pub enum ConfigSubcommands {
|
|||||||
/// Managing the secret key keyring, including enabling, disabling, or
|
/// Managing the secret key keyring, including enabling, disabling, or
|
||||||
/// resetting it.
|
/// resetting it.
|
||||||
Keyring(KeyringArgs),
|
Keyring(KeyringArgs),
|
||||||
|
/// Controls the NIP-07 browser signer proxy, turning it on or off, and
|
||||||
|
/// configures the `ip:port` address.
|
||||||
|
Nip07(Nip07Args),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CommandRunner for ConfigSubcommands {
|
impl CommandRunner for ConfigSubcommands {
|
||||||
async fn run(self, options: CliOptions) -> N34Result<()> {
|
async fn run(self, options: CliOptions) -> N34Result<()> {
|
||||||
crate::run_command!(self, options, & Pow Relays Bunker Keyring)
|
crate::run_command!(self, options, & Pow Relays Bunker Keyring Nip07)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
58
src/cli/commands/config/nip07.rs
Normal file
58
src/cli/commands/config/nip07.rs
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
// n34 - A CLI to interact with NIP-34 and other stuff related to codes in nostr
|
||||||
|
// Copyright (C) 2025 Awiteb <a@4rs.nl>
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://gnu.org/licenses/gpl-3.0.html>.
|
||||||
|
|
||||||
|
use std::net::SocketAddr;
|
||||||
|
|
||||||
|
use clap::{ArgGroup, Args};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
cli::{CliOptions, options_state::DEFAULT_NIP07_PROXY_ADDR, traits::CommandRunner},
|
||||||
|
error::N34Result,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Args, Debug)]
|
||||||
|
#[clap(
|
||||||
|
group(
|
||||||
|
ArgGroup::new("options")
|
||||||
|
.required(true)
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
pub struct Nip07Args {
|
||||||
|
/// Enable NIP-07 as the default signer.
|
||||||
|
#[arg(long, group = "options")]
|
||||||
|
enable: bool,
|
||||||
|
/// Disable NIP-07 as the default signer.
|
||||||
|
#[arg(long, group = "options", group = "disable_options")]
|
||||||
|
disable: bool,
|
||||||
|
/// Set the default `ip:port` for the browser signer proxy.
|
||||||
|
#[arg(long, group = "disable_options")]
|
||||||
|
addr: Option<SocketAddr>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CommandRunner for Nip07Args {
|
||||||
|
const NEED_SIGNER: bool = false;
|
||||||
|
|
||||||
|
async fn run(self, mut options: CliOptions) -> N34Result<()> {
|
||||||
|
if self.enable {
|
||||||
|
let addr = self.addr.unwrap_or(DEFAULT_NIP07_PROXY_ADDR);
|
||||||
|
options.config.nip07 = Some(addr)
|
||||||
|
} else {
|
||||||
|
options.config.nip07 = None
|
||||||
|
}
|
||||||
|
|
||||||
|
options.config.dump()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -31,7 +31,7 @@ use std::fmt;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use clap::{ArgGroup, Args, Parser};
|
use clap::{Args, Parser};
|
||||||
use nostr::key::{Keys, PublicKey, SecretKey};
|
use nostr::key::{Keys, PublicKey, SecretKey};
|
||||||
use nostr::nips::nip46::NostrConnectURI;
|
use nostr::nips::nip46::NostrConnectURI;
|
||||||
use nostr::signer::{IntoNostrSigner, NostrSigner};
|
use nostr::signer::{IntoNostrSigner, NostrSigner};
|
||||||
@@ -44,6 +44,7 @@ use self::reply::ReplyArgs;
|
|||||||
use self::repo::RepoSubcommands;
|
use self::repo::RepoSubcommands;
|
||||||
use self::sets::SetsSubcommands;
|
use self::sets::SetsSubcommands;
|
||||||
use super::CliConfig;
|
use super::CliConfig;
|
||||||
|
use super::options_state::OptionsState;
|
||||||
use super::types::RelayOrSet;
|
use super::types::RelayOrSet;
|
||||||
use super::{parsers, traits::CommandRunner};
|
use super::{parsers, traits::CommandRunner};
|
||||||
use crate::cli::Cli;
|
use crate::cli::Cli;
|
||||||
@@ -59,21 +60,18 @@ pub const DEFAULT_FALLBACK_PATH: &str = "I_DO_NOT_KNOW_WHY_CLAP_DO_NOT_SUPPORT_L
|
|||||||
const BUNKER_TIMEOUT: Duration = Duration::from_secs(60 * 3);
|
const BUNKER_TIMEOUT: Duration = Duration::from_secs(60 * 3);
|
||||||
|
|
||||||
/// The command-line interface options
|
/// The command-line interface options
|
||||||
#[derive(Args, Clone)]
|
#[derive(Args)]
|
||||||
#[clap(
|
|
||||||
group(
|
|
||||||
ArgGroup::new("signer")
|
|
||||||
.args(&["secret_key", "bunker_url"])
|
|
||||||
.required(false)
|
|
||||||
)
|
|
||||||
)]
|
|
||||||
pub struct CliOptions {
|
pub struct CliOptions {
|
||||||
/// Your Nostr secret key
|
/// Your Nostr secret key
|
||||||
#[arg(short, long)]
|
#[arg(short, long, group = "signer")]
|
||||||
pub secret_key: Option<SecretKey>,
|
pub secret_key: Option<SecretKey>,
|
||||||
/// NIP-46 bunker url used for signing events
|
/// NIP-46 bunker url used for signing events
|
||||||
#[arg(short, long, value_parser=parsers::parse_bunker_url)]
|
#[arg(short, long, group = "signer", value_parser = parsers::parse_bunker_url)]
|
||||||
pub bunker_url: Option<NostrConnectURI>,
|
pub bunker_url: Option<NostrConnectURI>,
|
||||||
|
/// Enables signing events using the browser's NIP-07 extension. Listens on
|
||||||
|
/// `127.0.0.1:51034`.
|
||||||
|
#[arg(short = '7', long, group = "signer")]
|
||||||
|
pub nip07: bool,
|
||||||
/// Fallbacks relay to write and read from it. Multiple relays can be
|
/// Fallbacks relay to write and read from it. Multiple relays can be
|
||||||
/// passed.
|
/// passed.
|
||||||
#[arg(short, long)]
|
#[arg(short, long)]
|
||||||
@@ -86,6 +84,10 @@ pub struct CliOptions {
|
|||||||
hide_default_value = true, value_parser = parsers::parse_config_path
|
hide_default_value = true, value_parser = parsers::parse_config_path
|
||||||
)]
|
)]
|
||||||
pub config: CliConfig,
|
pub config: CliConfig,
|
||||||
|
/// The state of options. Some values that are used by them but should not
|
||||||
|
/// be entered via the CLI
|
||||||
|
#[arg(skip)]
|
||||||
|
pub state: OptionsState,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// N34 commands
|
/// N34 commands
|
||||||
@@ -124,7 +126,7 @@ pub enum Commands {
|
|||||||
impl CliOptions {
|
impl CliOptions {
|
||||||
/// Gets the public key of the user.
|
/// Gets the public key of the user.
|
||||||
pub async fn pubkey(&self) -> N34Result<PublicKey> {
|
pub async fn pubkey(&self) -> N34Result<PublicKey> {
|
||||||
let Some(signer) = self.signer()? else {
|
let Some(signer) = self.signer().await? else {
|
||||||
unreachable!(
|
unreachable!(
|
||||||
"This method should only be called when a signer is required. If this panic \
|
"This method should only be called when a signer is required. If this panic \
|
||||||
occurs, it indicates a bug where the command failed to properly require a signer \
|
occurs, it indicates a bug where the command failed to properly require a signer \
|
||||||
@@ -136,10 +138,21 @@ impl CliOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the signer
|
/// Returns the signer
|
||||||
pub fn signer(&self) -> N34Result<Option<Arc<dyn NostrSigner + 'static>>> {
|
pub async fn signer(&self) -> N34Result<Option<Arc<dyn NostrSigner + 'static>>> {
|
||||||
if self.config.keyring_secret_key {
|
if self.nip07 {
|
||||||
|
self.state.browser_signer_proxy.start().await?;
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"Browser signer proxy started at: {}",
|
||||||
|
self.state.browser_signer_proxy.url()
|
||||||
|
);
|
||||||
|
|
||||||
|
// FIXME: Use `BrowserSignerProxy::is_session_active` after it release
|
||||||
|
// nostr@0.44.0
|
||||||
|
tokio::time::sleep(Duration::from_secs(10)).await;
|
||||||
|
|
||||||
return Ok(Some(
|
return Ok(Some(
|
||||||
Cli::user_keypair(self.secret_key.clone())?.into_nostr_signer(),
|
self.state.browser_signer_proxy.clone().into_nostr_signer(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://gnu.org/licenses/gpl-3.0.html>.
|
// along with this program. If not, see <https://gnu.org/licenses/gpl-3.0.html>.
|
||||||
|
|
||||||
use std::{collections::HashSet, fs, path::PathBuf};
|
use std::{collections::HashSet, fs, net::SocketAddr, path::PathBuf};
|
||||||
|
|
||||||
use nostr::{
|
use nostr::{
|
||||||
nips::{nip19::Nip19Coordinate, nip46::NostrConnectURI},
|
nips::{nip19::Nip19Coordinate, nip46::NostrConnectURI},
|
||||||
@@ -76,6 +76,9 @@ pub struct CliConfig {
|
|||||||
/// Whether to use the system keyring to store the secret key.
|
/// Whether to use the system keyring to store the secret key.
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub keyring_secret_key: bool,
|
pub keyring_secret_key: bool,
|
||||||
|
/// Signs events using the browser's NIP-07 extension.
|
||||||
|
#[serde(default)]
|
||||||
|
pub nip07: Option<SocketAddr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A named group of repositories and relays.
|
/// A named group of repositories and relays.
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ pub mod config;
|
|||||||
pub mod defaults;
|
pub mod defaults;
|
||||||
/// Macros for CLI application.
|
/// Macros for CLI application.
|
||||||
pub mod macros;
|
pub mod macros;
|
||||||
|
/// Represents the state used for CLI options.
|
||||||
|
pub mod options_state;
|
||||||
/// CLI arguments parsers
|
/// CLI arguments parsers
|
||||||
pub mod parsers;
|
pub mod parsers;
|
||||||
/// CLI traits
|
/// CLI traits
|
||||||
@@ -31,10 +33,13 @@ pub mod traits;
|
|||||||
/// Common helper types used throughout the CLI.
|
/// Common helper types used throughout the CLI.
|
||||||
pub mod types;
|
pub mod types;
|
||||||
|
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use clap_verbosity_flag::Verbosity;
|
use clap_verbosity_flag::Verbosity;
|
||||||
use nostr::key::Keys;
|
use nostr::key::Keys;
|
||||||
use nostr::key::SecretKey;
|
use nostr::key::SecretKey;
|
||||||
|
use nostr_browser_signer_proxy::BrowserSignerProxy;
|
||||||
|
use nostr_browser_signer_proxy::BrowserSignerProxyOptions;
|
||||||
use nostr_keyring::KeyringError;
|
use nostr_keyring::KeyringError;
|
||||||
use nostr_keyring::NostrKeyring;
|
use nostr_keyring::NostrKeyring;
|
||||||
use types::RelayOrSet;
|
use types::RelayOrSet;
|
||||||
@@ -42,6 +47,7 @@ use types::RelayOrSet;
|
|||||||
pub use self::commands::*;
|
pub use self::commands::*;
|
||||||
pub use self::config::*;
|
pub use self::config::*;
|
||||||
use self::traits::CommandRunner;
|
use self::traits::CommandRunner;
|
||||||
|
use crate::cli::options_state::BROWSER_SIGNER_PROXY_TIMEOUT;
|
||||||
use crate::error::N34Error;
|
use crate::error::N34Error;
|
||||||
use crate::error::N34Result;
|
use crate::error::N34Result;
|
||||||
use crate::nostr_utils::traits::NostrKeyringErrorUtils;
|
use crate::nostr_utils::traits::NostrKeyringErrorUtils;
|
||||||
@@ -143,10 +149,29 @@ pub fn post_cli(mut cli: Cli) -> N34Result<Cli> {
|
|||||||
cli.options.relays = relays.iter().cloned().map(RelayOrSet::Relay).collect();
|
cli.options.relays = relays.iter().cloned().map(RelayOrSet::Relay).collect();
|
||||||
}
|
}
|
||||||
|
|
||||||
if cli.options.bunker_url.is_none()
|
// Automatically sets the signer based on the configuration if no signer
|
||||||
&& let Some(bunker_url) = &cli.options.config.bunker_url
|
// is provided.
|
||||||
|
if !cli.options.nip07
|
||||||
|
&& cli.options.bunker_url.is_none()
|
||||||
|
&& (cli.options.secret_key.is_none() || cli.options.config.keyring_secret_key)
|
||||||
{
|
{
|
||||||
cli.options.bunker_url = Some(bunker_url.clone());
|
if let Some(addr) = cli.options.config.nip07 {
|
||||||
|
cli.options.nip07 = true;
|
||||||
|
cli.options.state.browser_signer_proxy = BrowserSignerProxy::new(
|
||||||
|
BrowserSignerProxyOptions::default()
|
||||||
|
.timeout(BROWSER_SIGNER_PROXY_TIMEOUT)
|
||||||
|
.ip_addr(addr.ip())
|
||||||
|
.port(addr.port()),
|
||||||
|
);
|
||||||
|
} else if let Some(bunker_url) = &cli.options.config.bunker_url {
|
||||||
|
cli.options.bunker_url = Some(bunker_url.clone());
|
||||||
|
} else if cli.options.config.keyring_secret_key {
|
||||||
|
cli.options.secret_key = Some(
|
||||||
|
Cli::user_keypair(cli.options.secret_key)?
|
||||||
|
.secret_key()
|
||||||
|
.clone(),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(cli)
|
Ok(cli)
|
||||||
|
|||||||
56
src/cli/options_state.rs
Normal file
56
src/cli/options_state.rs
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
// n34 - A CLI to interact with NIP-34 and other stuff related to codes in nostr
|
||||||
|
// Copyright (C) 2025 Awiteb <a@4rs.nl>
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://gnu.org/licenses/gpl-3.0.html>.
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
net::{Ipv4Addr, SocketAddr, SocketAddrV4},
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
|
||||||
|
use nostr_browser_signer_proxy::{BrowserSignerProxy, BrowserSignerProxyOptions};
|
||||||
|
|
||||||
|
/// The default socket address used for the NIP-07 signer proxy, set to
|
||||||
|
/// localhost on port 51034.
|
||||||
|
pub const DEFAULT_NIP07_PROXY_ADDR: SocketAddr =
|
||||||
|
SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOCALHOST, 51034));
|
||||||
|
|
||||||
|
/// How long to wait for the proxy response (3 minutes).
|
||||||
|
pub const BROWSER_SIGNER_PROXY_TIMEOUT: Duration = Duration::from_secs(60 * 3);
|
||||||
|
|
||||||
|
|
||||||
|
/// Represents the state used for CLI options.
|
||||||
|
pub struct OptionsState {
|
||||||
|
/// The browser signer proxy, will be used if `--nip07` is enabled
|
||||||
|
pub browser_signer_proxy: BrowserSignerProxy,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for OptionsState {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
browser_signer_proxy: default_browser_signer_proxy(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Build the default browser signer proxy
|
||||||
|
#[inline]
|
||||||
|
fn default_browser_signer_proxy() -> BrowserSignerProxy {
|
||||||
|
BrowserSignerProxy::new(
|
||||||
|
BrowserSignerProxyOptions::default()
|
||||||
|
.timeout(BROWSER_SIGNER_PROXY_TIMEOUT)
|
||||||
|
.ip_addr(DEFAULT_NIP07_PROXY_ADDR.ip())
|
||||||
|
.port(DEFAULT_NIP07_PROXY_ADDR.port()),
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -75,8 +75,8 @@ pub fn parse_config_path(config_path: &str) -> N34Result<CliConfig> {
|
|||||||
CliConfig::load(path)
|
CliConfig::load(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parses a bunker URL and checks if it's a valid Nostr Connect URI.
|
/// Parses a bunker URL and checks if it's a valid Nostr Connect URI.
|
||||||
// Returns an error if the URL is not a valid bunker URL.
|
/// Returns an error if the URL is not a valid bunker URL.
|
||||||
pub fn parse_bunker_url(bunker_url: &str) -> N34Result<NostrConnectURI> {
|
pub fn parse_bunker_url(bunker_url: &str) -> N34Result<NostrConnectURI> {
|
||||||
match NostrConnectURI::parse(bunker_url) {
|
match NostrConnectURI::parse(bunker_url) {
|
||||||
Ok(url) if url.is_bunker() => Ok(url),
|
Ok(url) if url.is_bunker() => Ok(url),
|
||||||
|
|||||||
10
src/error.rs
10
src/error.rs
@@ -14,7 +14,7 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://gnu.org/licenses/gpl-3.0.html>.
|
// along with this program. If not, see <https://gnu.org/licenses/gpl-3.0.html>.
|
||||||
|
|
||||||
use std::process::ExitCode;
|
use std::{net::AddrParseError, process::ExitCode};
|
||||||
|
|
||||||
use nostr::{
|
use nostr::{
|
||||||
event::{Kind, builder::Error as EventBuilderError},
|
event::{Kind, builder::Error as EventBuilderError},
|
||||||
@@ -47,6 +47,10 @@ pub enum N34Error {
|
|||||||
Io(#[from] std::io::Error),
|
Io(#[from] std::io::Error),
|
||||||
#[error("Signer Error: {0}")]
|
#[error("Signer Error: {0}")]
|
||||||
SignerError(#[from] SignerError),
|
SignerError(#[from] SignerError),
|
||||||
|
#[error("Invalid Browser Signer Proxy Address: {0}")]
|
||||||
|
Addr(#[from] AddrParseError),
|
||||||
|
#[error("Browser Signer Proxy Error: {0}")]
|
||||||
|
BrowserSignerProxy(#[from] nostr_browser_signer_proxy::Error),
|
||||||
#[error("Keyring error: {0}")]
|
#[error("Keyring error: {0}")]
|
||||||
Keyring(#[from] nostr_keyring::Error),
|
Keyring(#[from] nostr_keyring::Error),
|
||||||
#[error("{0}")]
|
#[error("{0}")]
|
||||||
@@ -92,8 +96,8 @@ pub enum N34Error {
|
|||||||
#[error("One naddr is required for this command")]
|
#[error("One naddr is required for this command")]
|
||||||
EmptyNaddrs,
|
EmptyNaddrs,
|
||||||
#[error(
|
#[error(
|
||||||
"This command requires a signer to sign events. Use `--secret-key` or `--bunker-url` to \
|
"This command requires a signer to sign events. Use `--secret-key`, `--nip07` or \
|
||||||
provide a signer"
|
`--bunker-url` to provide a signer"
|
||||||
)]
|
)]
|
||||||
SignerRequired,
|
SignerRequired,
|
||||||
#[error(
|
#[error(
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ impl NostrClient {
|
|||||||
let mut client_builder =
|
let mut client_builder =
|
||||||
Client::builder().opts(ClientOptions::new().verify_subscriptions(true));
|
Client::builder().opts(ClientOptions::new().verify_subscriptions(true));
|
||||||
|
|
||||||
if let Ok(Some(signer)) = options.signer() {
|
if let Ok(Some(signer)) = options.signer().await {
|
||||||
client_builder = client_builder.signer(signer);
|
client_builder = client_builder.signer(signer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user