Skip to content

Commit 1e7a687

Browse files
authored
Merge pull request #149 from AndreaDiazCorreia/fix/nsec-issue
refactor: Make ADMIN_NSEC optional and rename from NSEC_PRIVKEY
2 parents 7ff07f3 + a94d0b1 commit 1e7a687

7 files changed

Lines changed: 74 additions & 22 deletions

File tree

.env-sample

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,7 @@
22
MOSTRO_PUBKEY='npub1...'
33
# Comma-separated list of relays
44
RELAYS='wss://relay.nostr.vision,wss://nostr.zebedee.cloud,wss://nostr.slothy.win,wss://nostr.rewardsbunny.com,wss://nostr.supremestack.xyz,wss://nostr.shawnyeager.net,wss://relay.nostrmoto.xyz,wss://nostr.roundrockbitcoiners.com'
5-
POW='0'
5+
POW='0'
6+
7+
# Admin private key in nsec format (only required for admin commands)
8+
# ADMIN_NSEC='nsec1...'

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,14 @@ sudo apt install -y cmake build-essential pkg-config
2020

2121
## Install
2222

23-
To install you need to fill the env vars (`.env`) on the with your own private key and add a Mostro pubkey.
23+
To install you need to fill the env vars (`.env`) with the Mostro pubkey and relays. For admin commands, you'll also need to set your admin private key.
2424

2525
```bash
2626
git clone https://github.com/MostroP2P/mostro-cli.git
2727
cd mostro-cli
2828
cp .env-sample .env
29+
# Edit .env and set MOSTRO_PUBKEY, RELAYS, and POW
30+
# For admin commands, also set ADMIN_NSEC
2931
cargo run
3032
```
3133

src/cli.rs

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ pub struct Context {
5454
pub trade_keys: Keys,
5555
pub trade_index: i64,
5656
pub pool: SqlitePool,
57-
pub context_keys: Keys,
57+
pub context_keys: Option<Keys>,
5858
pub mostro_pubkey: PublicKey,
5959
}
6060

@@ -391,11 +391,18 @@ async fn init_context(cli: &Cli) -> Result<Context> {
391391
.await
392392
.map_err(|e| anyhow::anyhow!("Failed to get trade keys: {}", e))?;
393393

394-
// Load private key of user or admin - must be present in .env file
395-
let context_keys = std::env::var("NSEC_PRIVKEY")
396-
.map_err(|e| anyhow::anyhow!("NSEC_PRIVKEY not set: {}", e))?
397-
.parse::<Keys>()
398-
.map_err(|e| anyhow::anyhow!("Failed to get context keys: {}", e))?;
394+
// Load private key of admin - only required for admin commands
395+
// For regular user commands, this will be None
396+
let context_keys = if is_admin_command(&cli.command) {
397+
Some(
398+
std::env::var("ADMIN_NSEC")
399+
.map_err(|e| anyhow::anyhow!("ADMIN_NSEC not set (required for admin commands): {}", e))?
400+
.parse::<Keys>()
401+
.map_err(|e| anyhow::anyhow!("Failed to parse ADMIN_NSEC: {}", e))?,
402+
)
403+
} else {
404+
None
405+
};
399406

400407
// Resolve Mostro pubkey from env (required for all flows)
401408
let mostro_pubkey = PublicKey::from_str(
@@ -417,6 +424,19 @@ async fn init_context(cli: &Cli) -> Result<Context> {
417424
})
418425
}
419426

427+
fn is_admin_command(command: &Option<Commands>) -> bool {
428+
matches!(
429+
command,
430+
Some(Commands::AdmCancel { .. })
431+
| Some(Commands::AdmSettle { .. })
432+
| Some(Commands::AdmListDisputes { .. })
433+
| Some(Commands::AdmAddSolver { .. })
434+
| Some(Commands::AdmTakeDispute { .. })
435+
| Some(Commands::AdmSendDm { .. })
436+
| Some(Commands::GetAdminDm { .. })
437+
)
438+
}
439+
420440
impl Commands {
421441
pub async fn run(&self, ctx: &Context) -> Result<()> {
422442
match self {

src/cli/adm_send_dm.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,17 @@ use anyhow::Result;
77
use nostr_sdk::prelude::*;
88

99
pub async fn execute_adm_send_dm(receiver: PublicKey, ctx: &Context, message: &str) -> Result<()> {
10+
let admin_keys = ctx.context_keys.as_ref()
11+
.ok_or_else(|| anyhow::anyhow!("Admin keys not available. ADMIN_NSEC must be set for admin commands."))?;
12+
1013
println!("👑 Admin Direct Message");
1114
println!("═══════════════════════════════════════");
1215
let mut table = create_standard_table();
1316
table.set_header(create_field_value_header());
1417
table.add_row(create_emoji_field_row(
1518
"🔑 ",
1619
"Admin Keys",
17-
&ctx.context_keys.public_key().to_hex(),
20+
&admin_keys.public_key().to_hex(),
1821
));
1922
table.add_row(create_emoji_field_row(
2023
"🎯 ",
@@ -25,7 +28,7 @@ pub async fn execute_adm_send_dm(receiver: PublicKey, ctx: &Context, message: &s
2528
println!("{table}");
2629
println!("💡 Sending admin gift wrap message...\n");
2730

28-
send_admin_gift_wrap_dm(&ctx.client, &ctx.context_keys, &receiver, message).await?;
31+
send_admin_gift_wrap_dm(&ctx.client, admin_keys, &receiver, message).await?;
2932

3033
println!(
3134
"✅ Admin gift wrap message sent successfully to {}",

src/cli/take_dispute.rs

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use anyhow::Result;
22
use mostro_core::prelude::*;
3+
use nostr_sdk::prelude::Keys;
34
use uuid::Uuid;
45

56
use crate::{
@@ -9,6 +10,19 @@ use crate::{
910
util::{admin_send_dm, send_dm, wait_for_dm},
1011
};
1112

13+
/// Helper function to retrieve and validate admin keys from context
14+
fn get_admin_keys(ctx: &Context) -> Result<&Keys> {
15+
let admin_keys = ctx.context_keys.as_ref()
16+
.ok_or_else(|| anyhow::anyhow!("Admin keys not available. ADMIN_NSEC must be set for admin commands."))?;
17+
18+
// Only log admin public key in verbose mode
19+
if std::env::var("RUST_LOG").is_ok() {
20+
println!("🔑 Admin Keys: {}", admin_keys.public_key);
21+
}
22+
23+
Ok(admin_keys)
24+
}
25+
1226
pub async fn execute_admin_add_solver(npubkey: &str, ctx: &Context) -> Result<()> {
1327
println!("👑 Admin Add Solver");
1428
println!("═══════════════════════════════════════");
@@ -22,6 +36,9 @@ pub async fn execute_admin_add_solver(npubkey: &str, ctx: &Context) -> Result<()
2236
));
2337
println!("{table}");
2438
println!("💡 Adding new solver to Mostro...\n");
39+
40+
let _admin_keys = get_admin_keys(ctx)?;
41+
2542
// Create takebuy message
2643
let take_dispute_message = Message::new_dispute(
2744
Some(Uuid::new_v4()),
@@ -57,14 +74,15 @@ pub async fn execute_admin_cancel_dispute(dispute_id: &Uuid, ctx: &Context) -> R
5774
));
5875
println!("{table}");
5976
println!("💡 Canceling dispute...\n");
77+
78+
let _admin_keys = get_admin_keys(ctx)?;
79+
6080
// Create takebuy message
6181
let take_dispute_message =
6282
Message::new_dispute(Some(*dispute_id), None, None, Action::AdminCancel, None)
6383
.as_json()
6484
.map_err(|_| anyhow::anyhow!("Failed to serialize message"))?;
6585

66-
println!("🔑 Admin PubKey: {}", ctx.context_keys.public_key);
67-
6886
admin_send_dm(ctx, take_dispute_message).await?;
6987

7088
println!("✅ Dispute canceled successfully!");
@@ -89,13 +107,14 @@ pub async fn execute_admin_settle_dispute(dispute_id: &Uuid, ctx: &Context) -> R
89107
));
90108
println!("{table}");
91109
println!("💡 Settling dispute...\n");
110+
111+
let _admin_keys = get_admin_keys(ctx)?;
112+
92113
// Create takebuy message
93114
let take_dispute_message =
94115
Message::new_dispute(Some(*dispute_id), None, None, Action::AdminSettle, None)
95116
.as_json()
96117
.map_err(|_| anyhow::anyhow!("Failed to serialize message"))?;
97-
98-
println!("🔑 Admin Keys: {}", ctx.context_keys.public_key);
99118
admin_send_dm(ctx, take_dispute_message).await?;
100119

101120
println!("✅ Dispute settled successfully!");
@@ -119,6 +138,9 @@ pub async fn execute_take_dispute(dispute_id: &Uuid, ctx: &Context) -> Result<()
119138
));
120139
println!("{table}");
121140
println!("💡 Taking dispute...\n");
141+
142+
let admin_keys = get_admin_keys(ctx)?;
143+
122144
// Create takebuy message
123145
let take_dispute_message = Message::new_dispute(
124146
Some(*dispute_id),
@@ -130,12 +152,10 @@ pub async fn execute_take_dispute(dispute_id: &Uuid, ctx: &Context) -> Result<()
130152
.as_json()
131153
.map_err(|_| anyhow::anyhow!("Failed to serialize message"))?;
132154

133-
println!("🔑 Admin Keys: {}", ctx.context_keys.public_key);
134-
135155
// Send the dispute message and wait for response
136156
let sent_message = send_dm(
137157
&ctx.client,
138-
Some(&ctx.context_keys),
158+
Some(admin_keys),
139159
&ctx.trade_keys,
140160
&ctx.mostro_pubkey,
141161
take_dispute_message,
@@ -144,10 +164,10 @@ pub async fn execute_take_dispute(dispute_id: &Uuid, ctx: &Context) -> Result<()
144164
);
145165

146166
// Wait for incoming DM response
147-
let recv_event = wait_for_dm(ctx, Some(&ctx.context_keys), sent_message).await?;
167+
let recv_event = wait_for_dm(ctx, Some(admin_keys), sent_message).await?;
148168

149169
// Parse the incoming DM
150-
let messages = parse_dm_events(recv_event, &ctx.context_keys, None).await;
170+
let messages = parse_dm_events(recv_event, admin_keys, None).await;
151171
if let Some((message, _, sender_pubkey)) = messages.first() {
152172
let message_kind = message.get_inner_message_kind();
153173
if *sender_pubkey != ctx.mostro_pubkey {

src/util/events.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,13 +87,15 @@ pub async fn fetch_events_list(
8787
Ok(orders.into_iter().map(Event::SmallOrder).collect())
8888
}
8989
ListKind::DirectMessagesAdmin => {
90-
let filters = create_filter(list_kind, ctx.context_keys.public_key(), None)?;
90+
let admin_keys = ctx.context_keys.as_ref()
91+
.ok_or_else(|| anyhow::anyhow!("Admin keys not available. ADMIN_NSEC must be set for admin commands."))?;
92+
let filters = create_filter(list_kind, admin_keys.public_key(), None)?;
9193
let fetched_events = ctx
9294
.client
9395
.fetch_events(filters, FETCH_EVENTS_TIMEOUT)
9496
.await?;
9597
let direct_messages_mostro =
96-
parse_dm_events(fetched_events, &ctx.context_keys, since).await;
98+
parse_dm_events(fetched_events, admin_keys, since).await;
9799
Ok(direct_messages_mostro
98100
.into_iter()
99101
.map(|(message, timestamp, sender_pubkey)| {

src/util/storage.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,11 @@ pub async fn run_simple_order_msg(
4444
}
4545

4646
pub async fn admin_send_dm(ctx: &Context, msg: String) -> Result<()> {
47+
let admin_keys = ctx.context_keys.as_ref()
48+
.ok_or_else(|| anyhow::anyhow!("Admin keys not available. ADMIN_NSEC must be set for admin commands."))?;
4749
super::messaging::send_dm(
4850
&ctx.client,
49-
Some(&ctx.context_keys),
51+
Some(admin_keys),
5052
&ctx.trade_keys,
5153
&ctx.mostro_pubkey,
5254
msg,

0 commit comments

Comments
 (0)