1
0
forked from GRIN/grim

Build 22: security hardening follow-ups

From the audit's deferred P2 list:
- Global gift-wrap decrypt ceiling (~120/min across all senders) so
  fresh-keypair spam can't force unbounded NIP-44 decrypts. The per-sender
  limit only applied after the decrypt revealed the sender; this caps total
  decrypt work up front.
- NostrStore reads tolerate a poisoned lock (unwrap_or_else into_inner) so a
  single panic can't cascade into taking down all nostr storage for the session.
- Avatar upload/delete reuse the service's keys directly instead of
  round-tripping the secret through a plaintext nsec String.

34 lib tests green.
This commit is contained in:
Claude
2026-06-11 23:23:26 -04:00
parent 413746dde3
commit f2402eb24d
3 changed files with 49 additions and 31 deletions
+9 -21
View File
@@ -2580,13 +2580,9 @@ fn start_claim_flow(claim: &mut ClaimState, name: &str, wallet: &Wallet) {
return;
};
let server = service.config.read().nip05_server();
let keys = match service
.nsec()
.and_then(|nsec| nostr_sdk::Keys::parse(&nsec).ok())
{
Some(k) => k,
None => return,
};
// Reuse the service's keys directly — never round-trip the secret through a
// plaintext nsec String to rebuild keys the service already holds.
let keys = service.keys();
claim.checking = true;
claim.message = None;
claim.available = None;
@@ -2626,13 +2622,9 @@ fn start_release(claim: &mut ClaimState, name: &str, wallet: &Wallet) {
return;
};
let server = service.config.read().nip05_server();
let keys = match service
.nsec()
.and_then(|nsec| nostr_sdk::Keys::parse(&nsec).ok())
{
Some(k) => k,
None => return,
};
// Reuse the service's keys directly — never round-trip the secret through a
// plaintext nsec String to rebuild keys the service already holds.
let keys = service.keys();
claim.checking = true;
claim.message = None;
let slot = claim.result.clone();
@@ -2664,13 +2656,9 @@ fn start_avatar_upload(
return;
};
let server = service.config.read().nip05_server();
let keys = match service
.nsec()
.and_then(|nsec| nostr_sdk::Keys::parse(&nsec).ok())
{
Some(k) => k,
None => return,
};
// Reuse the service's keys directly — never round-trip the secret through a
// plaintext nsec String to rebuild keys the service already holds.
let keys = service.keys();
std::thread::spawn(move || {
let res = (|| {
let png = crate::nostr::avatar::process_avatar_file(&path)?;