notedeck

One damus client to rule them all
git clone git://jb55.com/notedeck
Log | Files | Refs | README | LICENSE

commit c055121e750b82e7a099b71ae8305b72b57680de
parent 805349013d731e423ad62e7cb3f20ec695fcd092
Author: William Casarin <jb55@jb55.com>
Date:   Wed, 10 Dec 2025 07:10:42 -0800

Add giftwrap support

Changelog-Added: Add support for processing and viewing giftwraps
Signed-off-by: William Casarin <jb55@jb55.com>

Diffstat:
MCargo.lock | 212+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
MCargo.toml | 2+-
Mcrates/notedeck/src/account/cache.rs | 4++++
Mcrates/notedeck/src/app.rs | 19++++++++++++-------
Mcrates/notedeck_ui/src/note/mod.rs | 36++++++++++++++++++++++++++++++------
5 files changed, 256 insertions(+), 17 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -44,6 +44,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] +name = "adler32" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" + +[[package]] name = "aead" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -189,6 +195,9 @@ name = "arbitrary" version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" +dependencies = [ + "derive_arbitrary", +] [[package]] name = "arboard" @@ -1203,6 +1212,15 @@ dependencies = [ ] [[package]] +name = "core2" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b49ba7ef1ad6107f8824dbe97de947cbaac53c44e7f9756a1fba0d37c1eec505" +dependencies = [ + "memchr", +] + +[[package]] name = "cpufeatures" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1335,6 +1353,12 @@ dependencies = [ ] [[package]] +name = "dary_heap" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06d2e3287df1c007e74221c49ca10a95d557349e54b3a75dc2fb14712c751f04" + +[[package]] name = "data-encoding" version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1379,6 +1403,17 @@ dependencies = [ ] [[package]] +name = "derive_arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + +[[package]] name = "derive_builder" version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1705,7 +1740,7 @@ checksum = "59a81c221a1e4dad06cb9c9deb19aea1193a5eea084e8cd42d869068132bf876" dependencies = [ "document-features", "js-sys", - "ureq", + "ureq 2.12.1", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", @@ -1973,6 +2008,18 @@ dependencies = [ ] [[package]] +name = "filetime" +version = "0.2.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc0505cd1b6fa6580283f6bdf70a73fcf4aba1184038c90902b92b3dd0df63ed" +dependencies = [ + "cfg-if", + "libc", + "libredox", + "windows-sys 0.60.2", +] + +[[package]] name = "flatbuffers" version = "23.5.26" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1989,6 +2036,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" dependencies = [ "crc32fast", + "libz-rs-sys", "miniz_oxide", ] @@ -2087,6 +2135,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" [[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] name = "foreign-types" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2523,7 +2577,18 @@ checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" dependencies = [ "allocator-api2", "equivalent", - "foldhash", + "foldhash 0.1.5", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.2.0", ] [[package]] @@ -3210,6 +3275,30 @@ dependencies = [ ] [[package]] +name = "libflate" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3248b8d211bd23a104a42d81b4fa8bb8ac4a3b75e7a43d85d2c9ccb6179cd74" +dependencies = [ + "adler32", + "core2", + "crc32fast", + "dary_heap", + "libflate_lz77", +] + +[[package]] +name = "libflate_lz77" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a599cb10a9cd92b1300debcef28da8f70b935ec937f44fcd1b70a7c986a11c5c" +dependencies = [ + "core2", + "hashbrown 0.16.1", + "rle-decode-fast", +] + +[[package]] name = "libfuzzer-sys" version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3241,6 +3330,32 @@ dependencies = [ ] [[package]] +name = "libsodium-sys-stable" +version = "1.22.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8119f38969584f49be1d1da6f011ed268cc64e3eac5b4f9374c40d9694ad1421" +dependencies = [ + "cc", + "libc", + "libflate", + "minisign-verify", + "pkg-config", + "tar", + "ureq 3.1.4", + "vcpkg", + "zip", +] + +[[package]] +name = "libz-rs-sys" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b484ba8d4f775eeca644c452a56650e544bf7e617f1d170fe7298122ead5222" +dependencies = [ + "zlib-rs", +] + +[[package]] name = "lightning-invoice" version = "0.33.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3488,6 +3603,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] +name = "minisign-verify" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e856fdd13623a2f5f2f54676a4ee49502a96a80ef4a62bcedd23d52427c44d43" + +[[package]] name = "miniz_oxide" version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3724,13 +3845,14 @@ dependencies = [ [[package]] name = "nostrdb" version = "0.8.0" -source = "git+https://github.com/damus-io/nostrdb-rs?rev=6956b9f955463404b8eff3b7abe0cc3092cb5958#6956b9f955463404b8eff3b7abe0cc3092cb5958" +source = "git+https://github.com/damus-io/nostrdb-rs?rev=78468aca8c263e50cae463743536d760239cc43d#78468aca8c263e50cae463743536d760239cc43d" dependencies = [ "bindgen 0.69.5", "cc", "flatbuffers", "futures", "libc", + "libsodium-sys-stable", "thiserror 2.0.12", "tokio", "tracing", @@ -5351,6 +5473,12 @@ dependencies = [ ] [[package]] +name = "rle-decode-fast" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3582f63211428f83597b51b2ddb88e2a91a9d52d12831f9d08f5e624e8977422" + +[[package]] name = "rmp" version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -6099,6 +6227,17 @@ dependencies = [ ] [[package]] +name = "tar" +version = "0.4.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a" +dependencies = [ + "filetime", + "libc", + "xattr", +] + +[[package]] name = "target-lexicon" version = "0.12.16" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -6742,6 +6881,31 @@ dependencies = [ ] [[package]] +name = "ureq" +version = "3.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d39cb1dbab692d82a977c0392ffac19e188bd9186a9f32806f0aaa859d75585a" +dependencies = [ + "base64 0.22.1", + "log", + "percent-encoding", + "ureq-proto", + "utf-8", +] + +[[package]] +name = "ureq-proto" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d81f9efa9df032be5934a46a068815a10a042b494b6a58cb0a1a97bb5467ed6f" +dependencies = [ + "base64 0.22.1", + "http", + "httparse", + "log", +] + +[[package]] name = "url" version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -7981,6 +8145,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec107c4503ea0b4a98ef47356329af139c0a4f7750e621cf2973cd3385ebcb3d" [[package]] +name = "xattr" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" +dependencies = [ + "libc", + "rustix 1.0.7", +] + +[[package]] name = "xcursor" version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -8202,6 +8376,38 @@ dependencies = [ ] [[package]] +name = "zip" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb2a05c7c36fde6c09b08576c9f7fb4cda705990f73b58fe011abf7dfb24168b" +dependencies = [ + "arbitrary", + "crc32fast", + "flate2", + "indexmap 2.9.0", + "memchr", + "zopfli", +] + +[[package]] +name = "zlib-rs" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36134c44663532e6519d7a6dfdbbe06f6f8192bde8ae9ed076e9b213f0e31df7" + +[[package]] +name = "zopfli" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edfc5ee405f504cd4984ecc6f14d02d55cfda60fa4b689434ef4102aae150cd7" +dependencies = [ + "bumpalo", + "crc32fast", + "log", + "simd-adler32", +] + +[[package]] name = "zune-core" version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/Cargo.toml b/Cargo.toml @@ -51,7 +51,7 @@ md5 = "0.7.0" nostr = { version = "0.37.0", default-features = false, features = ["std", "nip49"] } nwc = "0.39.0" mio = { version = "1.0.3", features = ["os-poll", "net"] } -nostrdb = { git = "https://github.com/damus-io/nostrdb-rs", rev = "6956b9f955463404b8eff3b7abe0cc3092cb5958" } +nostrdb = { git = "https://github.com/damus-io/nostrdb-rs", rev = "78468aca8c263e50cae463743536d760239cc43d" } #nostrdb = "0.6.1" notedeck = { path = "crates/notedeck" } notedeck_chrome = { path = "crates/notedeck_chrome" } diff --git a/crates/notedeck/src/account/cache.rs b/crates/notedeck/src/account/cache.rs @@ -110,6 +110,10 @@ impl AccountCache { &self.fallback } + pub fn accounts(&self) -> impl Iterator<Item = &UserAccount> { + self.accounts.values() + } + pub(super) fn accounts_mut(&mut self) -> impl Iterator<Item = &mut UserAccount> { self.accounts.values_mut() } diff --git a/crates/notedeck/src/app.rs b/crates/notedeck/src/app.rs @@ -252,13 +252,18 @@ impl Notedeck { &mut unknown_ids, ); - { - for key in &parsed_args.keys { - info!("adding account: {}", &key.pubkey); - if let Some(resp) = accounts.add_account(key.clone()) { - resp.unk_id_action - .process_action(&mut unknown_ids, &ndb, &txn); - } + for key in &parsed_args.keys { + info!("adding account: {}", &key.pubkey); + if let Some(resp) = accounts.add_account(key.clone()) { + resp.unk_id_action + .process_action(&mut unknown_ids, &ndb, &txn); + } + } + + /* add keys to nostrdb ingest threads for giftwrap processing */ + for account in accounts.cache.accounts() { + if let Some(seckey) = &account.key.secret_key { + ndb.add_key(&seckey.secret_bytes()); } } diff --git a/crates/notedeck_ui/src/note/mod.rs b/crates/notedeck_ui/src/note/mod.rs @@ -342,7 +342,8 @@ impl<'a, 'd> NoteView<'a, 'd> { #[profiling::function] fn note_header( ui: &mut egui::Ui, - i18n: &mut Localization, + txn: &Transaction, + note_context: &mut NoteContext, note: &Note, profile: &Result<nostrdb::ProfileRecord<'_>, nostrdb::Error>, flags: NoteOptions, @@ -350,10 +351,12 @@ impl<'a, 'd> NoteView<'a, 'd> { let horiz_resp = ui .horizontal_wrapped(|ui| { ui.spacing_mut().item_spacing.x = if is_narrow(ui.ctx()) { 1.0 } else { 2.0 }; - let response = ui - .add(Username::new(i18n, profile.as_ref().ok(), note.pubkey()).abbreviated(20)); + let response = ui.add( + Username::new(note_context.i18n, profile.as_ref().ok(), note.pubkey()) + .abbreviated(20), + ); if !flags.contains(NoteOptions::FullCreatedDate) { - return render_notetime(ui, i18n, note.created_at(), true); + return render_notetime(ui, note_context.i18n, note.created_at(), true); } response }) @@ -370,6 +373,25 @@ impl<'a, 'd> NoteView<'a, 'd> { ui.painter() .circle_filled(circle_center, radius, crate::colors::PINK); } + + if note.is_rumor() { + ui.horizontal_wrapped(|ui| { + ui.spacing_mut().item_spacing.x = if is_narrow(ui.ctx()) { 1.0 } else { 2.0 }; + + secondary_label(ui, "encrypted privately to"); + + crate::Mention::new( + note_context.ndb, + note_context.img_cache, + note_context.jobs, + txn, + note.rumor_receiver_pubkey().expect("expected pubkey"), + ) + .size(10.0) + .selectable(true) + .show(ui); + }); + } } fn wide_ui( @@ -400,7 +422,8 @@ impl<'a, 'd> NoteView<'a, 'd> { ui.horizontal_centered(|ui| { NoteView::note_header( ui, - self.note_context.i18n, + txn, + self.note_context, self.note, profile, self.flags, @@ -509,7 +532,8 @@ impl<'a, 'd> NoteView<'a, 'd> { if !self.flags.contains(NoteOptions::NotificationPreview) { NoteView::note_header( ui, - self.note_context.i18n, + txn, + self.note_context, self.note, profile, self.flags,