Skip to content

Commit 79e3ddf

Browse files
erskingardneryukibtc
authored andcommitted
Add nostr-mls-storage crate
This adds just the nostr-mls-storage crate. This crate provides a storage abstraction layer (traits) and wrapper around the OpenMLS StorageProvider traits. Pull-Request: rust-nostr#836 Signed-off-by: Yuki Kishimoto <[email protected]>
1 parent 48de47b commit 79e3ddf

File tree

20 files changed

+1172
-18
lines changed

20 files changed

+1172
-18
lines changed

.gitignore

+4-1
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,7 @@ many-events.json
99
many-events.json.zst
1010
.idea/
1111
.vscode/
12-
env/
12+
env/
13+
.repomix-*.txt
14+
vibe-tools.config.json
15+
.cursor/rules/

CHANGELOG.md

+21-15
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@
2525
2626
-->
2727

28+
## Unreleased
29+
30+
### Added
31+
32+
* mls-storage: add new crate with traits and types for mls storage implementations ([JeffG])
33+
2834
## v0.41.0 - 2025/04/15
2935

3036
### Breaking changes
@@ -73,8 +79,8 @@
7379

7480
### Summary
7581

76-
Add NIP-38 and NIP-62 support, add nostr parser, to easily parse any text and extract nostr URIs, URLs and more,
77-
extend `Tags` capabilities (i.e., add deduplication support), add admission policies, to selectively select which events to allow receiving and which to reject,
82+
Add NIP-38 and NIP-62 support, add nostr parser, to easily parse any text and extract nostr URIs, URLs and more,
83+
extend `Tags` capabilities (i.e., add deduplication support), add admission policies, to selectively select which events to allow receiving and which to reject,
7884
add Mac Catalyst support for Swift package, many cleanups, refactoring and performance improvements and more!
7985

8086
### Breaking changes
@@ -99,7 +105,7 @@ add Mac Catalyst support for Swift package, many cleanups, refactoring and perfo
99105
* pool: remove `Relay` constructors ([Yuki Kishimoto])
100106
* pool: change `RelayPool::new` signature ([Yuki Kishimoto])
101107
* pool: now can set the notification channel size of a single `Relay` using `RelayOptions` ([magine])
102-
* sdk: change `Client::fetch_metadata` output ([Yuki Kishimoto])
108+
* sdk: change `Client::fetch_metadata` output ([Yuki Kishimoto])
103109
* sdk: remove `Client::state` ([Yuki Kishimoto])
104110

105111
### Changed
@@ -183,7 +189,7 @@ add Mac Catalyst support for Swift package, many cleanups, refactoring and perfo
183189
### Summary
184190

185191
Add NIP96 support, add NIP22 helpers, NIP01 adjustments, add `try_connect` and `wait_for_connection` methods for better connection handling,
186-
support for custom WebSocket clients (both in Rust, Python, Kotlin and Swift), new JVM bindings,
192+
support for custom WebSocket clients (both in Rust, Python, Kotlin and Swift), new JVM bindings,
187193
huge reduction of UniFFI bindings binaries size, many cleanups, refactoring and performance improvements and more!
188194

189195
### Breaking changes
@@ -345,7 +351,7 @@ NIP35 support, better logs and docs, performance improvements, bugs fix and more
345351
* nostr: include public key of root and parent author in `EventBuilder::comment` ([Yuki Kishimoto])
346352
* nostr: dedup tags in `EventBuilder::text_note_reply` and `EventBuilder::comment` ([Yuki Kishimoto])
347353
* nostr: don't use reply event as root `e` tag i no root is set in `EventBuilder::text_note_reply` ([Yuki Kishimoto])
348-
* database: add manual trait implementations for `BTreeCappedSet` ([Yuki Kishimoto])
354+
* database: add manual trait implementations for `BTreeCappedSet` ([Yuki Kishimoto])
349355
* database: replace LRU with custom memory cache for IDs tracking ([Yuki Kishimoto])
350356
* lmdb: use `async-utility` to spawn blocking tasks ([Yuki Kishimoto])
351357
* ndb: bump `nostr-ndb` to 0.5 ([Yuki Kishimoto])
@@ -362,7 +368,7 @@ NIP35 support, better logs and docs, performance improvements, bugs fix and more
362368
* sdk: refactor POW difficulty management ([Yuki Kishimoto])
363369
* connect: require `fmt::Debug`, `Send` and `Sync` for `AuthUrlHandler` ([Yuki Kishimoto])
364370
* connect: improve secret matching for `NostrConnectRemoteSigner` ([Yuki Kishimoto])
365-
* connect: support both NIP04 and NIP44 for message decryption ([erskingardner])
371+
* connect: support both NIP04 and NIP44 for message decryption ([JeffG])
366372
* zapper: bump `webln` to 0.4 ([Yuki Kishimoto])
367373
* zapper: require `fmt::Debug`, `Send` and `Sync` for `NostrZapper` ([Yuki Kishimoto])
368374
* bindings: refactor `SendEventOutput` and `SubscribeOutput` ([Yuki Kishimoto])
@@ -371,7 +377,7 @@ NIP35 support, better logs and docs, performance improvements, bugs fix and more
371377

372378
* nostr: add `Tags::challenge` method ([Yuki Kishimoto])
373379
* nostr: add `RelayUrl::is_local_addr` ([Yuki Kishimoto])
374-
* nostr: add `TagKind::k` constructor ([Yuki Kishimoto])
380+
* nostr: add `TagKind::k` constructor ([Yuki Kishimoto])
375381
* nostr: impl `IntoIterator` for `Tag` ([Yuki Kishimoto])
376382
* nostr: add NIP35 support ([1wErt3r])
377383
* nostr: add `Kind::is_addressable` and `ADDRESSABLE_RANGE` ([Yuki Kishimoto])
@@ -425,15 +431,15 @@ NIP35 support, better logs and docs, performance improvements, bugs fix and more
425431

426432
### Summary
427433

428-
Add support to NIP17 relay list in SDK (when `gossip` option is enabled), add NIP22 and NIP73 support,
434+
Add support to NIP17 relay list in SDK (when `gossip` option is enabled), add NIP22 and NIP73 support,
429435
fix Swift Package, many performance improvements and bug fixes and more!
430436

431437
From this release all the rust features are disabled by default (except `std` feature in `nostr` crate).
432438

433439
### Breaking changes
434440

435441
* Use `RelayUrl` struct instead of `Url` for relay urls ([Yuki Kishimoto])
436-
* nostr: change `EventBuilder::gift_wrap` (and linked methods) args to take `extra_tags` instead of `expiration` ([erskingardner])
442+
* nostr: change `EventBuilder::gift_wrap` (and linked methods) args to take `extra_tags` instead of `expiration` ([JeffG])
437443
* nostr: change `EventBuilder::gift_wrap` (and linked methods) args to take an `EventBuilder` rumor instead of `UnsignedEvent` ([Yuki Kishimoto])
438444
* nostr: change `EventBuilder::private_msg_rumor` arg to take `extra_tags` instead of `reply_to` ([Yuki Kishimoto])
439445
* nostr: remove `tags` arg from `EventBuilder::new` ([Yuki Kishimoto])
@@ -467,7 +473,7 @@ From this release all the rust features are disabled by default (except `std` fe
467473
* pool: update retry interval calculation ([Yuki Kishimoto])
468474
* pool: try fetch relay information document only once every hour ([Yuki Kishimoto])
469475
* pool: not allow to add relays after `RelayPool` shutdown ([Yuki Kishimoto])
470-
* pool: rename `RelayOptions::retry_sec` to `RelayOptions::retry_interval` ([Yuki Kishimoto])
476+
* pool: rename `RelayOptions::retry_sec` to `RelayOptions::retry_interval` ([Yuki Kishimoto])
471477
* pool: rename `RelayOptions::adjust_retry_sec` to `RelayOptions::adjust_retry_interval` ([Yuki Kishimoto])
472478
* pool: request NIP11 document only after a successful WebSocket connection ([Yuki Kishimoto])
473479
* pool: immediately terminate relay connection on `Relay::disconnect` call ([Yuki Kishimoto])
@@ -485,7 +491,7 @@ From this release all the rust features are disabled by default (except `std` fe
485491

486492
### Added
487493

488-
* nostr: add NIP104 tag and event kinds ([erskingardner])
494+
* nostr: add NIP104 tag and event kinds ([JeffG])
489495
* nostr: add `SingleLetterTag::as_str` and `TagKind::as_str` ([Yuki Kishimoto])
490496
* nostr: add `Kind::Comment` ([reyamir])
491497
* nostr: add `EventBuilder::comment` ([reyamir])
@@ -674,7 +680,7 @@ Note for devs who are using `nostr-protocol` (Python), `org.rust-nostr:nostr` (K
674680

675681
### Summary
676682

677-
Add gossip model support, deprecate `SQLite` database in favor of `LMDB`
683+
Add gossip model support, deprecate `SQLite` database in favor of `LMDB`
678684
(fork of [pocket](https://github.com/mikedilger/pocket) database),
679685
add support to negentropy v1 (old version is still supported!), add `MockRelay` (a local disposable relay for tests),
680686
allow usage of embedded tor client on mobile devices, many improvements, bugs fix and more!
@@ -811,7 +817,7 @@ allow usage of embedded tor client on mobile devices, many improvements, bugs fi
811817
Add embedded tor client support, allow to open databases with a limited capacity (automatically discard old events when max capacity is reached),
812818
add `Client::stream_events_of` as alternative method to `Client::get_events_of` (stream events instead of waiting for `EOSE` and collect into a list),
813819
add search capability (NIP50) support to `Filter::match_event` and databases, add NIP31 and NIP70 support,
814-
add option to autoconnect relay on `Client::add_relay` method call (currently disabled by default), rework the `get_events_of` methods behaviour for
820+
add option to autoconnect relay on `Client::add_relay` method call (currently disabled by default), rework the `get_events_of` methods behaviour for
815821
better consistency (`RelayPool::get_events_of` and `Relay::get_events_of` get events only from remote relay/s while
816822
`Client::get_events_of` allow to choose the source of events: `database`, `relays` or `both`), bugs fix and more!
817823

@@ -895,7 +901,7 @@ better consistency (`RelayPool::get_events_of` and `Relay::get_events_of` get ev
895901

896902
Better outputs for send/batch/reconcile methods (ex. you can now easily know where a message/event is successfully published and where/why failed),
897903
allow to change NIP42 option after client initialization, increase max stack size for JS bindings to prevent "memory access out of bounds" error,
898-
expose more objects/methods for JS bindings, dry run option for negentropy reconciliation, get NIP46 relay from NIP05 profile,
904+
expose more objects/methods for JS bindings, dry run option for negentropy reconciliation, get NIP46 relay from NIP05 profile,
899905
bug fixes (NIP-42 auth not works correctly, NIP-46 "ACK" message not handled, ...) and more!
900906

901907
### Changed
@@ -1214,7 +1220,7 @@ added `nostrdb` storage backend, added NIP32 and completed NIP51 support and mor
12141220
[w3irdrobot]: <https://github.com/w3irdrobot> (nostr:npub17q5n2z8naw0xl6vu9lvt560lg33pdpe29k0k09umlfxm3vc4tqrq466f2y)
12151221
[nanikamado]: <https://github.com/nanikamado> (?)
12161222
[rodant]: <https://github.com/rodant> (nostr:npub1w80jzxf36fhwgyfp622m6s7tcl3cy5z7xva4cy75q9kwm92zm8tsclzqjv)
1217-
[erskingardner]: <https://github.com/erskingardner> (nostr:npub1zuuajd7u3sx8xu92yav9jwxpr839cs0kc3q6t56vd5u9q033xmhsk6c2uc)
1223+
[JeffG]: <https://github.com/erskingardner> (nostr:npub1zuuajd7u3sx8xu92yav9jwxpr839cs0kc3q6t56vd5u9q033xmhsk6c2uc)
12181224
[J. Azad EMERY]: <https://github.com/ethicnology> (?)
12191225
[v0l]: <https://github.com/v0l> (nostr:npub1v0lxxxxutpvrelsksy8cdhgfux9l6a42hsj2qzquu2zk7vc9qnkszrqj49)
12201226
[arkanoider]: <https://github.com/arkanoider> (nostr:npub1qqpn4ym6tc5ul6d2kjxnzx3sv9trekp53678ut9fe3wrxa6yvhjsnql2ng)

Cargo.lock

+42
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,12 @@ nostr-connect = { version = "0.41", path = "./crates/nostr-connect", default-fea
2323
nostr-database = { version = "0.41", path = "./crates/nostr-database", default-features = false }
2424
nostr-indexeddb = { version = "0.41", path = "./crates/nostr-indexeddb", default-features = false }
2525
nostr-lmdb = { version = "0.41", path = "./crates/nostr-lmdb", default-features = false }
26+
nostr-mls-storage = { version = "0.41", path = "./crates/nostr-mls-storage", default-features = false }
2627
nostr-ndb = { version = "0.41", path = "./crates/nostr-ndb", default-features = false }
2728
nostr-relay-builder = { version = "0.41", path = "./crates/nostr-relay-builder", default-features = false }
2829
nostr-relay-pool = { version = "0.41", path = "./crates/nostr-relay-pool", default-features = false }
2930
nostr-sdk = { version = "0.41", path = "./crates/nostr-sdk", default-features = false }
31+
serde = { version = "1.0", default-features = false }
3032
serde_json = { version = "1.0", default-features = false }
3133
tokio = { version = ">=1.37", default-features = false }
3234
tracing = { version = "0.1", default-features = false }

README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ The project is split up into several crates in the `crates/` directory:
1111
* [**nostr-lmdb**](./crates/nostr-lmdb): LMDB storage backend
1212
* [**nostr-ndb**](./crates/nostr-ndb): [nostrdb](https://github.com/damus-io/nostrdb) storage backend
1313
* [**nostr-indexeddb**](./crates/nostr-indexeddb): IndexedDB storage backend
14+
* [**nostr-mls-storage**](./crates/nostr-mls-storage): Storage traits for using MLS messaging
1415
* [**nostr-keyring**](./crates/nostr-keyring): Nostr Keyring
1516
* [**nostr-relay-pool**](./crates/nostr-relay-pool): Nostr Relay Pool
1617
* [**nostr-sdk**](./crates/nostr-sdk): High level client library
@@ -20,7 +21,7 @@ The project is split up into several crates in the `crates/` directory:
2021

2122
### Embedded
2223

23-
**nostr** crate can be used in [`no_std`](https://docs.rust-embedded.org/book/intro/no-std.html) environments.
24+
**nostr** crate can be used in [`no_std`](https://docs.rust-embedded.org/book/intro/no-std.html) environments.
2425
Check the example in the [`embedded/`](./crates/nostr/examples/embedded) directory.
2526

2627
## Book

contrib/scripts/check-crates.sh

+2
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ buildargs=(
4141
"-p nostr --all-features" # All features
4242
"-p nostr-database"
4343
"-p nostr-lmdb"
44+
"-p nostr-mls-storage"
4445
"-p nostr-indexeddb --target wasm32-unknown-unknown"
4546
"-p nostr-ndb"
4647
"-p nostr-keyring"
@@ -58,6 +59,7 @@ buildargs=(
5859

5960
skip_msrv=(
6061
"-p nostr-lmdb" # MSRV: 1.72.0
62+
"-p nostr-mls-storage" # MSRV: 1.74.0
6163
"-p nostr-keyring" # MSRV: 1.75.0
6264
"-p nostr-keyring --features async" # MSRV: 1.75.0
6365
"-p nostr-sdk --features tor" # MSRV: 1.77.0

contrib/scripts/release.sh

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ args=(
66
"-p nostr"
77
"-p nostr-database"
88
"-p nostr-lmdb"
9+
"-p nostr-mls-storage"
910
"-p nostr-ndb"
1011
"-p nostr-indexeddb"
1112
"-p nostr-keyring"

crates/nostr-mls-storage/Cargo.toml

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
[package]
2+
name = "nostr-mls-storage"
3+
version = "0.41.0"
4+
edition = "2021"
5+
description = "Storage abstraction for nostr-mls that wraps OpenMLS storage backends"
6+
authors = ["Jeff Gardner <[email protected]>", "Yuki Kishimoto <[email protected]>", "Rust Nostr Developers"]
7+
homepage.workspace = true
8+
repository.workspace = true
9+
license.workspace = true
10+
readme = "README.md"
11+
rust-version = "1.74.0"
12+
keywords = ["nostr", "mls", "openmls"]
13+
14+
[dependencies]
15+
nostr = { workspace = true, features = ["std"] }
16+
openmls_traits = { version = "0.3", default-features = false }
17+
serde = { workspace = true, features = ["derive"] }
18+
serde_json = { workspace = true, features = ["std"] }

crates/nostr-mls-storage/README.md

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Nostr MLS Storage
2+
3+
This crate provides an abstraction for the storage layer that MLS requires.
4+
5+
## NostrMlsStorageProvider trait
6+
7+
THis library contains the `NostrMlsStorageProvider` trait.
8+
9+
## State
10+
11+
**This library is in an ALPHA state**, things that are implemented generally work but the API will change in breaking ways.
12+
13+
## Donations
14+
15+
`rust-nostr` is free and open-source. This means we do not earn any revenue by selling it. Instead, we rely on your financial support. If you actively use any of the `rust-nostr` libs/software/services, then please [donate](https://rust-nostr.org/donate).
16+
17+
## License
18+
19+
This project is distributed under the MIT software license - see the [LICENSE](../../LICENSE) file for details
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//! Error types for the groups module
2+
3+
use std::fmt;
4+
5+
/// Error types for the groups module
6+
#[derive(Debug)]
7+
pub enum GroupError {
8+
/// Invalid parameters
9+
InvalidParameters(String),
10+
/// Database error
11+
DatabaseError(String),
12+
/// Group not found
13+
NotFound,
14+
}
15+
16+
impl std::error::Error for GroupError {}
17+
18+
impl fmt::Display for GroupError {
19+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
20+
match self {
21+
Self::InvalidParameters(message) => write!(f, "Invalid parameters: {}", message),
22+
Self::DatabaseError(message) => write!(f, "Database error: {}", message),
23+
Self::NotFound => write!(f, "Group not found"),
24+
}
25+
}
26+
}
+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
//! Groups module
2+
//!
3+
//! This module is responsible for storing and retrieving groups
4+
//! It also handles the parsing of group content
5+
//!
6+
//! The groups are stored in the database and can be retrieved by MLS group ID or Nostr group ID
7+
//!
8+
//! Here we also define the storage traits that are used to store and retrieve groups
9+
10+
use nostr::PublicKey;
11+
12+
pub mod error;
13+
pub mod types;
14+
15+
use self::error::GroupError;
16+
use self::types::*;
17+
use crate::messages::types::Message;
18+
19+
/// Storage traits for the groups module
20+
pub trait GroupStorage {
21+
/// Get all groups
22+
fn all_groups(&self) -> Result<Vec<Group>, GroupError>;
23+
24+
/// Find a group by MLS group ID
25+
fn find_group_by_mls_group_id(&self, mls_group_id: &[u8]) -> Result<Group, GroupError>;
26+
27+
/// Find a group by Nostr group ID
28+
fn find_group_by_nostr_group_id(&self, nostr_group_id: &str) -> Result<Group, GroupError>;
29+
30+
/// Save a group
31+
fn save_group(&self, group: Group) -> Result<Group, GroupError>;
32+
33+
/// Get all messages for a group
34+
fn messages(&self, mls_group_id: &[u8]) -> Result<Vec<Message>, GroupError>;
35+
36+
/// Get all admins for a group
37+
fn admins(&self, mls_group_id: &[u8]) -> Result<Vec<PublicKey>, GroupError>;
38+
39+
/// Get all relays for a group
40+
fn group_relays(&self, mls_group_id: &[u8]) -> Result<Vec<GroupRelay>, GroupError>;
41+
42+
/// Save a group relay
43+
fn save_group_relay(&self, group_relay: GroupRelay) -> Result<GroupRelay, GroupError>;
44+
}

0 commit comments

Comments
 (0)