Skip to content

Shared key chat and attachment feature#157

Open
arkanoider wants to merge 9 commits intomainfrom
dm-with-attachment
Open

Shared key chat and attachment feature#157
arkanoider wants to merge 9 commits intomainfrom
dm-with-attachment

Conversation

@arkanoider
Copy link
Collaborator

@arkanoider arkanoider commented Mar 2, 2026

Summary

Add shared-key DM attachment flow and improve DM handling/documentation in mostro-cli.

Details

  • New admin DM attachment command

    • Add send_admin_dm_attach CLI command and src/cli/send_admin_dm_attach.rs.
    • Implement shared-key custom wrap flow using ECDH (trade keys + admin pubkey) with NIP‑44/NIP‑59.
    • Introduce shared-key helpers in src/util/messaging.rs (deriving shared keys, building/wrapping/unwrapping gift wraps, fetching gift wrap events).
  • DM receive path improvements

    • Extend get_dm_user to:
      • Fetch and decrypt shared-key DMs for (trade_keys, identity_keys) so user‑targeted shared-key messages are visible.
      • Fetch and decrypt shared-key DMs for (trade_keys, mostro_pubkey) so admin replies from the attachment flow are also shown.
    • Keep existing classic DM flow intact while merging shared-key messages into the same output.
  • CLI and utility wiring

    • Wire new command into src/cli.rs and re‑export helpers from src/util/mod.rs.
    • Adjust existing CLI commands (dm_to_user, get_dm, add_invoice, last_trade_index, list_orders, new_order, rate_user, take_dispute) to use the new messaging helpers where appropriate.
    • Add DB helper in src/db.rs to retrieve trade keys used by the shared-key flows.
  • Documentation and DX

    • Add high‑level docs: docs/overview.md, docs/architecture.md, docs/commands.md, docs/database.md.
    • Document flows in depth: docs/send_admin_dm_attach_flow.md, docs/senddm_flow.md.
    • Add .cursor/commands/{build,update_docs,pull_request}.md for contributor workflows.
    • Bump Cargo.toml dependencies and update Cargo.lock accordingly.

Testing

  • Built the CLI with cargo build.
  • Manually exercised:
    • getdmuser to confirm both classic and shared-key DMs are returned.
    • dm_to_user and send_admin_dm_attach to verify shared-key send/receive paths interoperate correctly.

Summary by CodeRabbit

  • New Features

    • Send encrypted file attachments to admin contacts via secure upload and shared-key messaging
    • Shared-key based direct messaging for per-order encrypted chats
    • Improved DM retrieval showing counterparty and order context
  • Documentation

    • Added architecture, commands, database, overview, and DM/send-attach flow docs
    • Added developer guides for building, PRs, and keeping docs in sync
  • Dependencies

    • Added cryptography and Bitcoin-related libraries and nostr SDK feature flag

arkanoider and others added 6 commits February 11, 2026 15:53
…putes solving - added some docs for AI generated code
- Use BUD-01 Blossom auth: kind 24242 with tags t=upload, expiration, x=sha256
  (servers reject NIP-98 kind 27235; require human-readable content)
- Add Content-Type fallback: try application/zip then image/png when
  application/octet-stream is rejected (415/400)
- Accept 200 OK JSON blob descriptor: parse response and use 'url' field
  when present (blossom.primal.net, nostr.media return JSON not blossom://)
- Add nip98 and base64 deps for auth; add bitcoin_hashes for payload hash

Co-authored-by: Cursor <cursoragent@cursor.com>
…muser - Derive shared key from (trade_keys, identity_keys) and fetch/unwrap gift wraps so DMs sent to the user's identity appear in getdmuser. - Also derive (trade_keys, mostro_pubkey) and fetch so admin replies from the send_admin_dm_attach flow are shown. - Reuse derive_shared_key_bytes from util/messaging (same ECDH as send_admin_dm_attach). No longer use get_all_trade_and_counterparty_keys; counterparty_pubkey is not used in this setup.
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 2, 2026

Warning

Rate limit exceeded

@arkanoider has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 4 minutes and 36 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 7b270a6 and b74adc4.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (7)
  • Cargo.toml
  • docs/commands.md
  • docs/senddm_flow.md
  • src/cli/dm_to_user.rs
  • src/cli/get_dm_user.rs
  • src/cli/send_admin_dm_attach.rs
  • src/util/messaging.rs

Walkthrough

Adds documentation, a new SendAdminDmAttach CLI command (encrypts and uploads attachments to Blossom, sends via shared-key DM), refactors DM retrieval to use per-order shared keys, extends messaging utilities for shared-key gift-wraps, updates deps for crypto, and introduces DB and misc helpers.

Changes

Cohort / File(s) Summary
Documentation
.cursor/commands/build.md, .cursor/commands/pull_request.md, .cursor/commands/update_docs.md
Added contributor/maintenance workflow docs (build, PR, docs update procedures).
Project Docs
docs/overview.md, docs/architecture.md, docs/commands.md, docs/database.md, docs/senddm_flow.md, docs/send_admin_dm_attach_flow.md
Added extensive architecture, commands, DB, and DM/attachment flow documentation.
Dependencies
Cargo.toml
Added crypto and Bitcoin-related deps (chacha20poly1305, rand_core, bitcoin, bitcoin_hashes, base64) and enabled nip98 feature for nostr-sdk.
CLI Wiring
src/cli.rs
Added SendAdminDmAttach variant, extended GetDmUser args, registered new module and dispatch paths.
Send Admin DM Attachment
src/cli/send_admin_dm_attach.rs
New module: reads/validates file, derives shared key, ChaCha20-Poly1305 encrypt, upload to Blossom (content-type negotiation, signed auth), build payload and send via shared-key DM.
Shared-Key Messaging Utilities
src/util/messaging.rs, src/util/mod.rs
Added shared-key derivation (ECDH), helpers to build/send NIP-59 custom gift-wraps, unwrap/fetch gift-wraps for shared keys, and re-exported new functions.
DM Retrieval & Sending
src/cli/get_dm_user.rs, src/cli/dm_to_user.rs
Refactored get_dm_user signature to accept counterparty pubkey and order_id, derive shared key, fetch/decrypt gift-wraps; dm_to_user now uses shared-key send path.
Database Helper
src/db.rs
Added Order::get_all_trade_and_counterparty_keys to query distinct (trade_keys, counterparty_pubkey) pairs.
Misc CLI Edits
src/cli/{add_invoice,get_dm,last_trade_index,list_orders,new_order,rate_user,take_dispute}.rs
Mostly comment tweaks and small parsing/validation improvements (e.g., Status/Kind parsing in list_orders).
Config Path
src/util/misc.rs
Changed mcli path from ~/.mcliUserA to ~/.mcli.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant CLI as CLI Handler
    participant DB as Database
    participant Crypto as Crypto (ECDH / ChaCha20-Poly1305)
    participant Blossom as Blossom Server
    participant Messaging as Messaging Utils
    participant Relay as Nostr Relay

    User->>CLI: sendadmindmattach --pubkey --order-id --file
    CLI->>CLI: Validate file size & metadata
    CLI->>DB: Load order by order_id -> trade_keys
    DB-->>CLI: Return order with trade_keys
    CLI->>Crypto: Derive shared_key(trade_keys, admin_pubkey)
    Crypto-->>CLI: shared_key
    CLI->>Crypto: Encrypt file -> encrypted_blob, nonce
    CLI->>Blossom: Upload encrypted_blob (signed PUT)
    Blossom-->>CLI: blossom_url
    CLI->>Messaging: Build attachment payload (url, nonce, mime, sizes)
    CLI->>Messaging: Send payload via shared-key NIP-59 gift-wrap
    Messaging->>Relay: Publish wrapped event
    Relay-->>Messaging: Ack
    Messaging-->>CLI: Success
    CLI-->>User: Display summary / success
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~70 minutes

Possibly related PRs

Suggested Reviewers

  • Catrya
  • grunch

Poem

🐰 I hopped a file through crypto light,
Wrapped it tight for Blossom's sight.
Shared keys hummed, relays sang bright,
A DM danced into the night.
Hooray — an encrypted delight! 🌸

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main feature additions: shared-key chat functionality and an attachment feature, which are the primary changes in this PR.
Docstring Coverage ✅ Passed Docstring coverage is 93.55% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch dm-with-attachment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/util/misc.rs (1)

13-23: ⚠️ Potential issue | 🟠 Major

Add one-time migration from legacy data directory.

Switching the home subpath without fallback can strand existing mcli.db data for current users.

Proposed compatibility fix
 pub fn get_mcli_path() -> String {
     let home_dir = dirs::home_dir().expect("Couldn't get home directory");
     let mcli_path = format!("{}/.mcli", home_dir.display());
+    let legacy_mcli_path = format!("{}/.mcliUserA", home_dir.display());
+
+    if !Path::new(&mcli_path).exists() && Path::new(&legacy_mcli_path).exists() {
+        fs::rename(&legacy_mcli_path, &mcli_path)
+            .unwrap_or_else(|e| panic!("Couldn't migrate legacy mcli directory: {}", e));
+    }
+
     if !Path::new(&mcli_path).exists() {
         match fs::create_dir(&mcli_path) {
             Ok(_) => println!("Directory {} created.", mcli_path),
🧹 Nitpick comments (5)
.cursor/commands/pull_request.md (1)

26-31: Consider making the PR template more project-specific.

The current template uses generic placeholders. Consider aligning with the project's actual CI checks:

📝 Suggested template improvement
 ## PR Template
 
-- [ ] Feature A
-- [ ] Bug fix B
-- [ ] Unit tests pass
-- [ ] Manual testing completed
+- [ ] Changes description
+- [ ] `cargo fmt --all` passes
+- [ ] `cargo clippy --all-targets --all-features` passes  
+- [ ] `cargo test` passes
+- [ ] Manual testing completed
+- [ ] Documentation updated (if applicable)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.cursor/commands/pull_request.md around lines 26 - 31, Update the generic
"## PR Template" checklist in .cursor/commands/pull_request.md to use
project-specific checks: replace the placeholders "- [ ] Feature A", "- [ ] Bug
fix B", "- [ ] Unit tests pass", "- [ ] Manual testing completed" with concrete
items like referencing the related issue/PR number, CI status
(unit/integration/e2e), lint/format checks, changelog or release notes entry,
migration steps if any, and required approvers/reviewers; ensure the new
checklist names are explicit and reflect the repository's actual CI and release
processes so contributors follow the correct verification steps.
src/cli/send_admin_dm_attach.rs (1)

74-82: Consider adding a timeout to HTTP requests.

The reqwest::Client::new() uses default settings without an explicit timeout. If a Blossom server becomes unresponsive, this could cause the CLI to hang indefinitely.

Suggested fix
 async fn upload_to_blossom(trade_keys: &Keys, encrypted_blob: Vec<u8>) -> Result<String> {
     use reqwest::StatusCode;
+    use std::time::Duration;

-    let client = reqwest::Client::new();
+    let client = reqwest::Client::builder()
+        .timeout(Duration::from_secs(60))
+        .build()
+        .map_err(|e| anyhow::anyhow!("failed to create HTTP client: {e}"))?;
     let payload_hash = Sha256Hash::hash(&encrypted_blob);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/cli/send_admin_dm_attach.rs` around lines 74 - 82, The HTTP client in
upload_to_blossom currently uses reqwest::Client::new() with no timeout; change
it to construct the client via reqwest::Client::builder() and set a sensible
timeout (e.g., Duration::from_secs(10) or 30) so requests cannot hang
indefinitely, and ensure you import std::time::Duration; update uses of the
client variable accordingly in upload_to_blossom to use the new client instance.
docs/send_admin_dm_attach_flow.md (1)

30-44: Remove local filesystem paths from documentation.

The code block contains absolute paths to a developer's local machine (/home/pinballwizard/rust_prj/mostro_p2p/mostro-cli/...). These should be removed or converted to relative paths for cleaner documentation.

Suggested fix example
-```198:335:/home/pinballwizard/rust_prj/mostro_p2p/mostro-cli/src/cli/send_admin_dm_attach.rs
+```rust
 pub async fn execute_send_admin_dm_attach(

This pattern appears throughout the document (lines 54-57, 68-77, 89-105, 118-151, 167-172, 186-296). Consider cleaning up all instances.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/send_admin_dm_attach_flow.md` around lines 30 - 44, Remove all absolute
local filesystem prefixes from code fences in the documentation so they don't
leak developer machine paths; for each code block (e.g., the block starting with
"pub async fn execute_send_admin_dm_attach" and other occurrences listed in the
comment) strip the leading "/home/..." portion and present either the raw code
fence (```rust) or a relative path if a file reference is needed, ensuring
symbols like execute_send_admin_dm_attach remain intact and no absolute paths
remain in the document.
src/util/messaging.rs (2)

166-175: Fixed fetch bounds can silently truncate shared-key chat history.

Using a hardcoded 7-day window with limit(100) can drop messages in active disputes with no indication to callers. Consider caller-configurable bounds and/or pagination.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/util/messaging.rs` around lines 166 - 175, The hardcoded 7-day window
(seven_days_secs/wide_since) and fixed .limit(100) in the Filter built for
shared_keys.public_key() can silently truncate active chat history; change the
API around the function that constructs this Filter (the use of
Timestamp::now(), seven_days_secs, wide_since, Filter::new() with .since(...)
and .limit(...)) to accept caller-configurable time range and page size
parameters and implement pagination (looped/continuation fetches) when the
result count equals the page limit so callers can request older events, or
alternatively expose these bounds via configuration defaults instead of the
fixed 7-day/100 limit.

31-55: Return explicit errors from shared-key helper APIs instead of collapsing to None.

These helpers currently hide root causes (missing keys, parse errors, ECDH failures), which makes CLI failures harder to debug. Prefer Result with context.

♻️ Proposed refactor
-pub fn derive_shared_keys(
-    admin_keys: Option<&Keys>,
-    counterparty_pubkey: Option<&PublicKey>,
-) -> Option<Keys> {
-    let admin = admin_keys?;
-    let cp_pk = counterparty_pubkey?;
-    let shared_bytes = nostr_sdk::util::generate_shared_key(admin.secret_key(), cp_pk).ok()?;
-    let sk = nostr_sdk::SecretKey::from_slice(&shared_bytes).ok()?;
-    Some(Keys::new(sk))
+pub fn derive_shared_keys(
+    admin_keys: Option<&Keys>,
+    counterparty_pubkey: Option<&PublicKey>,
+) -> Result<Keys> {
+    let admin = admin_keys.ok_or_else(|| anyhow::anyhow!("missing local keys"))?;
+    let cp_pk = counterparty_pubkey.ok_or_else(|| anyhow::anyhow!("missing counterparty pubkey"))?;
+    let shared_bytes = nostr_sdk::util::generate_shared_key(admin.secret_key(), cp_pk)
+        .map_err(|e| anyhow::anyhow!("failed to derive shared key bytes: {e}"))?;
+    let sk = nostr_sdk::SecretKey::from_slice(&shared_bytes)
+        .map_err(|e| anyhow::anyhow!("invalid shared key scalar: {e}"))?;
+    Ok(Keys::new(sk))
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/util/messaging.rs` around lines 31 - 55, The three helpers
(derive_shared_keys, derive_shared_key_hex, keys_from_shared_hex) should return
Result types with contextual errors instead of Option so callers can see root
causes: change derive_shared_keys to return Result<Keys, YourError> and
explicitly check for missing admin_keys and missing counterparty_pubkey
returning distinct errors (e.g., MissingAdminKey, MissingCounterpartyPubkey),
propagate nostr_sdk::util::generate_shared_key errors as EcdhError, map
SecretKey::from_slice failure to SecretKeyParseError, change
derive_shared_key_hex to parse the counterparty string with PublicKey::parse and
return ParsePublicKeyError on failure before calling derive_shared_keys, and
change keys_from_shared_hex to return Result<Keys, YourError> mapping
nostr_sdk::Keys::parse errors to ParseSharedHexError; implement or use a small
error enum (or anyhow with context) and replace .ok()? with proper ? and map_err
calls in each referenced function name.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@Cargo.toml`:
- Around line 50-54: Update the outdated cryptographic crates in Cargo.toml by
bumping rand_core from 0.6.4 to the latest stable (e.g., 0.10.0) and bitcoin
from 0.32.2 to the latest stable (e.g., 0.32.8) while keeping other pins
(chacha20poly1305, bitcoin_hashes, base64) unchanged; after updating the
rand_core and bitcoin versions, run cargo update and add a CI step to run cargo
audit to validate the full dependency tree for RustSec advisories and ensure no
breaking changes affect code referencing those crates (search for uses of
rand_core and bitcoin types/functions to fix any API changes).

In `@docs/commands.md`:
- Around line 171-181: Update the docs for admcancel and admsettle so the flags
and description use "dispute" rather than "order": change the arg from
`--order-id <UUID>` to `--dispute-id <UUID>` and adjust the Description lines to
say "Cancel a dispute" and "Settle a dispute" respectively; ensure the Handler
references remain `execute_admin_cancel_dispute(order_id, ctx)` and
`execute_admin_settle_dispute(order_id, ctx)` so readers know these handlers
operate on dispute IDs.

In `@docs/senddm_flow.md`:
- Around line 33-45: Remove machine-local absolute paths from all code
references in the docs (e.g., the Rust fences that currently start with paths
like "12:69:/home/pinballwizard/.../send_dm.rs" and similar entries for
util/messaging.rs); replace them with plain Rust code fences (```rust) or
repo-relative references and keep the function/method names (e.g.,
execute_send_dm in send_dm.rs and functions in util/messaging.rs) so readers can
locate the code without machine-specific paths. Ensure every occurrence listed
(including ranges 59-69, 78-91, 100-111, 125-179, 190-199, 209-248, 274-276) is
updated consistently.

In `@src/cli/dm_to_user.rs`:
- Around line 45-51: The success message is inconsistent with the new shared-key
flow: update the call to print_success_message to reflect the shared-key custom
wrap instead of "Gift wrap message sent successfully!"; locate the block where
print_info_line("💡", "Sending shared-key custom wrap message...") and
send_admin_chat_message_via_shared_key(...) are used and change the final
print_success_message invocation to a matching message such as "Shared-key
custom wrap message sent successfully!" so the messaging aligns with
send_admin_chat_message_via_shared_key.

In `@src/cli/get_dm_user.rs`:
- Line 76: Replace the println! call that currently prints an empty string
literal by calling println!() with no arguments; locate the println!("")
invocation in src/cli/get_dm_user.rs (the empty-line print) and remove the ""
argument so the macro is invoked as println!() to satisfy Clippy.
- Line 64: The retain closure in messages.retain currently does an unnecessary
cast (*ts as i64); remove the redundant cast and compare the existing i64 value
directly against cutoff_ts (e.g., change the closure used by messages.retain to
use *ts or ts instead of (*ts as i64)) so the comparison is between two i64
values and clippy CI will be satisfied; keep the same variables (messages, ts,
cutoff_ts) and only remove the `as i64` cast.
- Line 80: The clippy warning flags an unnecessary cast in the DateTime
creation; in the invocation of chrono::DateTime::from_timestamp inside
get_dm_user.rs (the line using from_timestamp(*ts as i64, 0)), remove the
redundant "as i64" cast and pass *ts directly (matching the earlier similar fix
at line 64) so the call becomes from_timestamp(*ts, 0).

In `@src/util/messaging.rs`:
- Around line 103-106: Replace the silent fallback for POW so invalid values
surface: instead of unwrapping var("POW") and using .parse().unwrap_or(0), parse
the env value and return or propagate a proper error (or log and exit) when
parsing fails; locate the POW handling around the let pow: u8 = var("POW") ...
expression in messaging.rs and change it to explicitly handle
VarError/ParseIntError (e.g., map_err with a descriptive error message or use
expect with a clear message) so malformed POW values are not silently coerced to
0.

---

Nitpick comments:
In @.cursor/commands/pull_request.md:
- Around line 26-31: Update the generic "## PR Template" checklist in
.cursor/commands/pull_request.md to use project-specific checks: replace the
placeholders "- [ ] Feature A", "- [ ] Bug fix B", "- [ ] Unit tests pass", "- [
] Manual testing completed" with concrete items like referencing the related
issue/PR number, CI status (unit/integration/e2e), lint/format checks, changelog
or release notes entry, migration steps if any, and required
approvers/reviewers; ensure the new checklist names are explicit and reflect the
repository's actual CI and release processes so contributors follow the correct
verification steps.

In `@docs/send_admin_dm_attach_flow.md`:
- Around line 30-44: Remove all absolute local filesystem prefixes from code
fences in the documentation so they don't leak developer machine paths; for each
code block (e.g., the block starting with "pub async fn
execute_send_admin_dm_attach" and other occurrences listed in the comment) strip
the leading "/home/..." portion and present either the raw code fence (```rust)
or a relative path if a file reference is needed, ensuring symbols like
execute_send_admin_dm_attach remain intact and no absolute paths remain in the
document.

In `@src/cli/send_admin_dm_attach.rs`:
- Around line 74-82: The HTTP client in upload_to_blossom currently uses
reqwest::Client::new() with no timeout; change it to construct the client via
reqwest::Client::builder() and set a sensible timeout (e.g.,
Duration::from_secs(10) or 30) so requests cannot hang indefinitely, and ensure
you import std::time::Duration; update uses of the client variable accordingly
in upload_to_blossom to use the new client instance.

In `@src/util/messaging.rs`:
- Around line 166-175: The hardcoded 7-day window (seven_days_secs/wide_since)
and fixed .limit(100) in the Filter built for shared_keys.public_key() can
silently truncate active chat history; change the API around the function that
constructs this Filter (the use of Timestamp::now(), seven_days_secs,
wide_since, Filter::new() with .since(...) and .limit(...)) to accept
caller-configurable time range and page size parameters and implement pagination
(looped/continuation fetches) when the result count equals the page limit so
callers can request older events, or alternatively expose these bounds via
configuration defaults instead of the fixed 7-day/100 limit.
- Around line 31-55: The three helpers (derive_shared_keys,
derive_shared_key_hex, keys_from_shared_hex) should return Result types with
contextual errors instead of Option so callers can see root causes: change
derive_shared_keys to return Result<Keys, YourError> and explicitly check for
missing admin_keys and missing counterparty_pubkey returning distinct errors
(e.g., MissingAdminKey, MissingCounterpartyPubkey), propagate
nostr_sdk::util::generate_shared_key errors as EcdhError, map
SecretKey::from_slice failure to SecretKeyParseError, change
derive_shared_key_hex to parse the counterparty string with PublicKey::parse and
return ParsePublicKeyError on failure before calling derive_shared_keys, and
change keys_from_shared_hex to return Result<Keys, YourError> mapping
nostr_sdk::Keys::parse errors to ParseSharedHexError; implement or use a small
error enum (or anyhow with context) and replace .ok()? with proper ? and map_err
calls in each referenced function name.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9b0ecb2 and cb10d77.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (25)
  • .cursor/commands/build.md
  • .cursor/commands/pull_request.md
  • .cursor/commands/update_docs.md
  • Cargo.toml
  • docs/architecture.md
  • docs/commands.md
  • docs/database.md
  • docs/overview.md
  • docs/send_admin_dm_attach_flow.md
  • docs/senddm_flow.md
  • src/cli.rs
  • src/cli/add_invoice.rs
  • src/cli/dm_to_user.rs
  • src/cli/get_dm.rs
  • src/cli/get_dm_user.rs
  • src/cli/last_trade_index.rs
  • src/cli/list_orders.rs
  • src/cli/new_order.rs
  • src/cli/rate_user.rs
  • src/cli/send_admin_dm_attach.rs
  • src/cli/take_dispute.rs
  • src/db.rs
  • src/util/messaging.rs
  • src/util/misc.rs
  • src/util/mod.rs

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/cli/get_dm_user.rs (1)

67-89: Sender label branch is dead after pre-filtering by sender_pk == pubkey.

After messages.retain(|(_, _, sender_pk)| *sender_pk == pubkey), the else ("🧑 You") branch cannot execute. Simplify the label logic, or remove the retain if full conversation output is intended.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/cli/get_dm_user.rs` around lines 67 - 89, The sender label branch is dead
because messages are pre-filtered with messages.retain(|(_, _, sender_pk)|
*sender_pk == pubkey), so in the loop for (idx, (content, ts, sender_pk)) the
else branch (🧑 You) will never run; fix by either removing the retain to keep
both parties in messages (so the existing from_label logic in the loop remains
valid) or simplify the loop label to always render the counterparty label (e.g.,
replace the conditional in the from_label computation to a single counterparty
label) — modify the code around messages.retain and the from_label calculation
to choose one of those two approaches and remove the unreachable branch.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/cli/get_dm_user.rs`:
- Around line 56-65: The command allows arbitrary minute lookback but
fetch_gift_wraps_for_shared_key only returns the last 7 days, so add an explicit
guard that validates the requested since value (minutes) before or immediately
after calling fetch_gift_wraps_for_shared_key and return an informative error or
warning when the requested window exceeds the helper's 7-day window; for
example, compute max_minutes = 7 * 24 * 60 and if *since > max_minutes, return
an Err (or print and exit) explaining that lookback is limited to 7 days,
referencing the fetch_gift_wraps_for_shared_key call and the messages variable
so reviewers can find where to apply the check.
- Around line 60-63: The cutoff timestamp computation using
chrono::Utc::now().checked_sub_signed(...).unwrap() in src/cli/get_dm_user.rs
can panic for extreme user-provided `since` values; replace the unwrap with
explicit error handling in the function that computes/uses cutoff_ts (e.g.,
return a user-facing error or exit with a clear message) when checked_sub_signed
returns None, and validate/clamp `since` if appropriate before calling
checked_sub_signed. Also remove the unreachable else branch in the
sender-labeling logic (the branch that runs when messages are not from the
counterparty) because earlier filtering to the counterparty already guarantees
only counterparty messages; simplify the label code in the function that assigns
sender labels to only the expected branch.

---

Nitpick comments:
In `@src/cli/get_dm_user.rs`:
- Around line 67-89: The sender label branch is dead because messages are
pre-filtered with messages.retain(|(_, _, sender_pk)| *sender_pk == pubkey), so
in the loop for (idx, (content, ts, sender_pk)) the else branch (🧑 You) will
never run; fix by either removing the retain to keep both parties in messages
(so the existing from_label logic in the loop remains valid) or simplify the
loop label to always render the counterparty label (e.g., replace the
conditional in the from_label computation to a single counterparty label) —
modify the code around messages.retain and the from_label calculation to choose
one of those two approaches and remove the unreachable branch.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cb10d77 and 7b270a6.

📒 Files selected for processing (1)
  • src/cli/get_dm_user.rs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant