From d5a16601d1eac6be5885ad68f7fb9c61fb6ebc35 Mon Sep 17 00:00:00 2001 From: magine Date: Mon, 4 Dec 2023 16:24:10 +0800 Subject: [PATCH] docs: update docs and add ci for docs (#499) --- .github/workflows/qaci.yml | 8 ++++ core/src/ecc/signers/secp256r1.rs | 2 +- core/src/lib.rs | 2 +- core/src/message/mod.rs | 1 + core/src/message/protocols/verify.rs | 5 +++ core/src/message/types.rs | 4 +- core/src/session.rs | 60 +++++++++++++++++++++------- core/src/swarm/callback.rs | 4 +- core/src/swarm/types.rs | 4 +- transport/src/connection_ref.rs | 4 +- transport/src/connections/mod.rs | 6 +-- transport/src/core/callback.rs | 14 +++---- transport/src/core/mod.rs | 6 +-- transport/src/core/transport.rs | 15 ++++--- transport/src/ice_server.rs | 2 +- transport/src/pool.rs | 4 +- 16 files changed, 94 insertions(+), 47 deletions(-) diff --git a/.github/workflows/qaci.yml b/.github/workflows/qaci.yml index 76d4fd679..022d9b4b9 100644 --- a/.github/workflows/qaci.yml +++ b/.github/workflows/qaci.yml @@ -78,6 +78,9 @@ jobs: - name: Build run: cargo build --all --verbose + - name: Run doc tests + run: cargo test --doc + - name: Run dummy tests run: cargo test -p rings-core --features dummy --verbose @@ -142,6 +145,11 @@ jobs: - name: Check formating run: cargo +nightly fmt --all -- --check + - name: Check docs + env: + RUSTDOCFLAGS: -Dwarnings + run: cargo doc --all --no-deps + - name: Install taplo run: cargo install taplo-cli --locked diff --git a/core/src/ecc/signers/secp256r1.rs b/core/src/ecc/signers/secp256r1.rs index 2a17ddbcb..9f31174eb 100644 --- a/core/src/ecc/signers/secp256r1.rs +++ b/core/src/ecc/signers/secp256r1.rs @@ -1,6 +1,6 @@ //! Sign and verify message with curve secp256r1 and ECDSA //! This module support WebCrypto API -//! ref: https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API +//! ref: //! To use this signature, message should be wrapped with prefix //! //! ```js diff --git a/core/src/lib.rs b/core/src/lib.rs index 479b8f23e..9741015b8 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -3,7 +3,7 @@ //! - [Chord](crate::dht::PeerRing) is a structured p2p network based on Chord protocol and expanded with secp256k1 based Did support. //! - [ElGamal](crate::ecc::elgamal) provides End2End encryption based on Chord Did. //! - [Swarm](crate::swarm) is a module for managing all transports. -//! - [Transport](crate::transports::Transport) is used for connection handshaking, which supports all platforms, including browser (wasm) and native runtime. +//! - [Connection](rings_transport::core::transport::ConnectionInterface) is used for connection handshaking, which supports all platforms, including browser (wasm) and native runtime. //! # Connection //! diff --git a/core/src/message/mod.rs b/core/src/message/mod.rs index b411137a6..4440d15e6 100644 --- a/core/src/message/mod.rs +++ b/core/src/message/mod.rs @@ -26,4 +26,5 @@ pub use handlers::MessageHandlerEvent; mod protocols; pub use protocols::MessageRelay; +pub use protocols::MessageVerification; pub use protocols::MessageVerificationExt; diff --git a/core/src/message/protocols/verify.rs b/core/src/message/protocols/verify.rs index daf5964eb..fef8537cb 100644 --- a/core/src/message/protocols/verify.rs +++ b/core/src/message/protocols/verify.rs @@ -18,9 +18,13 @@ use crate::utils::get_epoch_ms; /// it also included ttl time and created ts. #[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)] pub struct MessageVerification { + /// The [Session] of the [SessionSk]. Used to identify a sender and verify the signature. pub session: Session, + /// The time to live of the message in milliseconds. pub ttl_ms: u64, + /// The timestamp of the message in milliseconds. pub ts_ms: u128, + /// The signature of the message. Signed by [SessionSk]. Can be verified by [Session]. pub sig: Vec, } @@ -35,6 +39,7 @@ fn pack_msg(data: &[u8], ts_ms: u128, ttl_ms: u64) -> Vec { } impl MessageVerification { + /// Create a new MessageVerification. Should provide the data and the [SessionSk]. pub fn new(data: &[u8], session_sk: &SessionSk) -> Result { let ts_ms = get_epoch_ms(); let ttl_ms = DEFAULT_TTL_MS; diff --git a/core/src/message/types.rs b/core/src/message/types.rs index c8c79234e..e14832f89 100644 --- a/core/src/message/types.rs +++ b/core/src/message/types.rs @@ -78,7 +78,7 @@ pub enum QueryFor { Stabilization, } -/// MessageType for handle [RemoteAction::Queryforsuccessorlist] +/// MessageType for handle [crate::dht::PeerRingRemoteAction::QueryForSuccessorList] #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)] pub struct QueryForTopoInfoSend { /// The did for query target @@ -87,7 +87,7 @@ pub struct QueryForTopoInfoSend { pub then: QueryFor, } -/// MessageType for handle [RemoteAction::Queryforsuccessorlist] +/// MessageType for handle [crate::dht::PeerRingRemoteAction::QueryForSuccessorList] #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)] pub struct QueryForTopoInfoReport { /// The did for query target diff --git a/core/src/session.rs b/core/src/session.rs index 47b36ef2b..6c4504709 100644 --- a/core/src/session.rs +++ b/core/src/session.rs @@ -1,25 +1,57 @@ #![warn(missing_docs)] //! Understanding Abstract Account and Session keypair in Rings Network //! -//! The Rings network offers a unique mechanism to bolster security and abstract the user's keypair through a feature known as session keypair. +//! Rings network offers a unique mechanism to bolster security and abstract the user's keypair through a feature known as session keypair. +//! The fundamental concept behind session keypair is signing a generated keypair with a time period {ts, ttl} by user without access its private key in this program. +//! This can be conceptualized as a contract stating, "I delegate to a keypair for the time period {ts, ttl}". //! -//! The fundamental concept behind keypair session involves creating an association between a user's keypair and a randomly generated keypair. In our terminology: +//! In our terminology: +//! - `I` is [Account]. +//! - `keypair` is [SessionSk]. +//! - The time period {ts, ttl} is in `SessionSk.session` field. //! -//! The user's original keypair (private key, public key) is referred to as the "account" (sk, pk). -//! The randomly generated keypair by the Rings network is known as the "session" (sk, pk). +//! The following is an example to build a [SessionSk] in Rust and use it to sign a message. +//! It is not necessary to construct a secret_key in Rust. +//! User may manually set account_type, account_entity, and session_sig, instead of provide secret key. +//! ``` +//! use rings_core::dht::Did; +//! use rings_core::session::SessionSkBuilder; +//! +//! // We are generate an ethereum account for example. +//! // It's convenient because secp256k1 is also used in session_sk. +//! let user_secret_key = rings_core::ecc::SecretKey::random(); +//! let user_secret_key_did: Did = user_secret_key.address().into(); //! -//! * Here's how the process works: +//! // The account type is "secp256k1". +//! // The account entity is its address, also known as Did in rings network. +//! let account_type = "secp256k1".to_string(); +//! let account_entity = user_secret_key_did.to_string(); //! -//! 1. A random delegate private key (sk) is generated, along with its corresponding public key (pk). +//! let mut builder = SessionSkBuilder::new(account_entity, account_type); +//! let unsigned_proof = builder.unsigned_proof(); //! -//! 2. A session is formed based on the session's public key and the account's public key. This can be conceptualized as a contract stating, "I delegate to {pk} for the time period {ts, ttl}". +//! // Sign the unsigned proof with user's secret key. +//! let session_sig = user_secret_key.sign(&unsigned_proof).to_vec(); +//! let builder = builder.set_session_sig(session_sig); //! -//! 3. The account must sign the session, now termed "Session", using its private key. +//! let session_sk = builder.build().unwrap(); //! -//! 4. When sending and receiving messages, the Rings network will handle message signing and verification using the session's keypair (sk, pk). +//! // Check session_sk is valid. (The verify_self is already called in build().) +//! assert_eq!(session_sk.account_did(), user_secret_key_did); +//! assert!(session_sk.session().verify_self().is_ok()); //! +//! // Sign a message with session_sk. +//! let msg = "hello world".as_bytes(); +//! let msg_sig = session_sk.sign(msg).unwrap(); +//! let msg_session = session_sk.session(); +//! +//! // Verify the message with session. +//! assert_eq!(msg_session.account_did(), user_secret_key_did); +//! assert!(msg_session.verify(msg, msg_sig).is_ok()); +//! ``` //! -//! SessionSkBuilder, SessionSk was exported to wasm envirement, so in browser/wasm envirement it can be done with nodejs code: +//! [SessionSkBuilder], [SessionSk] is exported to wasm envirement. +//! To build a [SessionSk] in javascript: //! ```js //! // prepare auth & send to metamask for sign //! let sessionBuilder = SessionSkBuilder.new(account, 'eip191') @@ -61,7 +93,7 @@ fn pack_session(session_id: Did, ts_ms: u128, ttl_ms: u64) -> String { /// SessionSkBuilder is used to build a [SessionSk]. /// -/// Firstly, you need to provide the account's entity and type to `new` method. +/// Firstly, you need to provide the account's entity and type to [SessionSkBuilder::new] method. /// Then you can call `pack_session` to get the session dump for signing. /// After signing, you can call `sig` to set the signature back to builder. /// Finally, you can call `build` to get the [SessionSk]. @@ -126,7 +158,7 @@ pub enum Account { Secp256k1(Did), /// ref: Secp256r1(PublicKey), - /// ref: ref: https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API + /// ref: EIP191(Did), /// bitcoin bip137 ref: BIP137(Did), @@ -302,8 +334,8 @@ impl Session { } impl SessionSk { - /// Generate Session with private key. - /// Only use it for unittest. + /// Generate Session with private key. Only use it for unittest. + /// To protect your private key, please use [SessionSkBuilder] to generate session. pub fn new_with_seckey(key: &SecretKey) -> Result { let account_entity = Did::from(key.address()).to_string(); let account_type = "secp256k1".to_string(); diff --git a/core/src/swarm/callback.rs b/core/src/swarm/callback.rs index 227a783a3..897d24892 100644 --- a/core/src/swarm/callback.rs +++ b/core/src/swarm/callback.rs @@ -57,13 +57,15 @@ pub trait SwarmCallback { } } -pub(crate) struct InnerSwarmCallback { +/// [InnerSwarmCallback] wraps [SharedSwarmCallback] with inner handling for a specific connection. +pub struct InnerSwarmCallback { did: Did, transport_event_sender: TransportEventSender, callback: SharedSwarmCallback, } impl InnerSwarmCallback { + /// Create a new [InnerSwarmCallback] with the provided did, transport_event_sender and callback. pub fn new( did: Did, transport_event_sender: TransportEventSender, diff --git a/core/src/swarm/types.rs b/core/src/swarm/types.rs index 63eba42ad..aef00a875 100644 --- a/core/src/swarm/types.rs +++ b/core/src/swarm/types.rs @@ -9,11 +9,11 @@ use crate::measure::BehaviourJudgement; use crate::swarm::Swarm; use crate::types::Connection; -/// Type of Measure, see [Measure]. +/// Type of Measure, see [crate::measure::Measure]. #[cfg(not(feature = "wasm"))] pub type MeasureImpl = Box; -/// Type of Measure, see [Measure]. +/// Type of Measure, see [crate::measure::Measure]. #[cfg(feature = "wasm")] pub type MeasureImpl = Box; diff --git a/transport/src/connection_ref.rs b/transport/src/connection_ref.rs index 04dd46902..846aba132 100644 --- a/transport/src/connection_ref.rs +++ b/transport/src/connection_ref.rs @@ -13,9 +13,9 @@ use crate::core::transport::WebrtcConnectionState; use crate::error::Error; use crate::error::Result; -/// The[ConnectionRef] is a weak reference to a connection and implements the `ConnectionInterface` trait. +/// [ConnectionRef] is a weak reference to a connection and implements the `ConnectionInterface` trait. /// When the connection is dropped, it returns an error called [Error::ConnectionReleased]. -/// It serves as the return value for the `get_connection` method of [Transport](crate::Transport). +/// It serves as the return value for the `connection` method of [TransportInterface](crate::core::transport::TransportInterface). pub struct ConnectionRef { cid: String, conn: Weak, diff --git a/transport/src/connections/mod.rs b/transport/src/connections/mod.rs index af46d8c0a..bc7bbaf8a 100644 --- a/transport/src/connections/mod.rs +++ b/transport/src/connections/mod.rs @@ -1,6 +1,6 @@ -//! Default using [WebrtcConnection] for native environment. -//! Plus a [WebSysWebrtcConnection] for wasm environment. -//! Also provide a [DummyConnection] for testing. +//! Default using `WebrtcConnection` for native environment. +//! Plus a `WebSysWebrtcConnection` for wasm environment. +//! Also provide a `DummyConnection` for testing. #[cfg(feature = "dummy")] mod dummy; diff --git a/transport/src/core/callback.rs b/transport/src/core/callback.rs index b8651e7ac..076ed42ea 100644 --- a/transport/src/core/callback.rs +++ b/transport/src/core/callback.rs @@ -1,9 +1,9 @@ -//! The main entity of this module is the [Callback] trait, which defines +//! The main entity of this module is the [TransportCallback] trait, which defines //! a series of methods that receive connection events. //! //! The `new_connection` method of -//! [ConnectionCreation](super::transport::ConnectionCreation) trait will -//! accept boxed [Callback] trait object. +//! [TransportInterface](super::transport::TransportInterface) trait will +//! accept boxed [TransportCallback] trait object. use async_trait::async_trait; @@ -31,13 +31,13 @@ pub trait TransportCallback { } /// The `new_connection` method of -/// [ConnectionCreation](super::transport::ConnectionCreation) trait will -/// accept boxed [Callback] trait object. +/// [TransportInterface](super::transport::TransportInterface) trait will +/// accept boxed [TransportCallback] trait object. #[cfg(not(feature = "web-sys-webrtc"))] pub type BoxedTransportCallback = Box; /// The `new_connection` method of -/// [ConnectionCreation](super::transport::ConnectionCreation) trait will -/// accept boxed [Callback] trait object. +/// [TransportInterface](super::transport::TransportInterface) trait will +/// accept boxed [TransportCallback] trait object. #[cfg(feature = "web-sys-webrtc")] pub type BoxedTransportCallback = Box; diff --git a/transport/src/core/mod.rs b/transport/src/core/mod.rs index 303ca9aef..04978fd68 100644 --- a/transport/src/core/mod.rs +++ b/transport/src/core/mod.rs @@ -4,10 +4,10 @@ //! make webrtc ice handshake with a remote peer and then send data channel message to it. //! See the [transport] module. //! -//! The [ConnectionCreation](transport::ConnectionCreation) trait should be -//! implemented for each Transport. See the [transport] module. +//! The [TransportInterface](transport::TransportInterface) trait should be +//! implemented for each Transport of Connection implementation. See the [transport] module. //! -//! The [Callback](callback::Callback) trait is used to let user handle +//! The [TransportCallback](callback::TransportCallback) trait is used to let user handle //! the events of a connection, including connection state change, //! coming data channel message and etc. See the [callback] module. diff --git a/transport/src/core/transport.rs b/transport/src/core/transport.rs index cf0190132..e627dd279 100644 --- a/transport/src/core/transport.rs +++ b/transport/src/core/transport.rs @@ -1,8 +1,8 @@ //! The main entity of this module is the [ConnectionInterface] trait, which provides an //! interface for establishing connections with other nodes, send data channel message to it. //! -//! There is also a [ConnectionCreation] trait, which is used to specifies the creation of a -//! [ConnectionInterface] object for [Transport](crate::Transport). +//! There is also a [TransportInterface] trait, which is used to specify the management of all +//! [ConnectionInterface] objects. use async_trait::async_trait; use serde::de::DeserializeOwned; @@ -58,7 +58,7 @@ pub enum WebrtcConnectionState { Closed, } -/// The [ConnectionInterface](transport::ConnectionInterface) trait defines how to +/// The [ConnectionInterface] trait defines how to /// make webrtc ice handshake with a remote peer and then send data channel message to it. #[cfg_attr(feature = "web-sys-webrtc", async_trait(?Send))] #[cfg_attr(not(feature = "web-sys-webrtc"), async_trait)] @@ -113,7 +113,7 @@ pub trait ConnectionInterface { } } -/// This trait specifies the creation of a [ConnectionInterface] object for [Transport](crate::Transport). +/// This trait specifies how to management [ConnectionInterface] objects. /// Each platform must implement this trait for its own connection implementation. /// See [connections](crate::connections) module for examples. #[cfg_attr(feature = "web-sys-webrtc", async_trait(?Send))] @@ -125,11 +125,11 @@ pub trait TransportInterface { /// The error type that is returned by transport. type Error: std::error::Error; - /// Used to create a new connection and register it in [Transport](crate::Transport). + /// Used to create a new connection and register it in the transport. /// /// To avoid memory leak, this function will not return a connection object. - /// Instead, use should use `get_connection` method of [Transport](crate::Transport) - /// to get a [ConnectionRef](crate::connection_ref::ConnectionRef) after creation. + /// Instead, user should use `connection` method of to get a [ConnectionRef](crate::connection_ref::ConnectionRef) + /// after creation. /// /// See [connections](crate::connections) module for examples. async fn new_connection( @@ -140,7 +140,6 @@ pub trait TransportInterface { /// This method closes and releases the connection from transport. /// All references to this cid, created by `get_connection`, will be released. - /// The [ConnectionInterface] methods of them will return [Error::ConnectionReleased]. async fn close_connection(&self, cid: &str) -> Result<(), Self::Error>; /// Get a reference of the connection by its id. diff --git a/transport/src/ice_server.rs b/transport/src/ice_server.rs index 1e39a63e9..e1e66ae74 100644 --- a/transport/src/ice_server.rs +++ b/transport/src/ice_server.rs @@ -40,7 +40,7 @@ pub struct IceServer { } impl IceServer { - /// Convert String to Vec. Will split the string by `;` and parse each part. + /// Convert String to `Vec`. Will split the string by `;` and parse each part. pub fn vec_from_str(s: &str) -> Result, IceServerError> { s.split(';').map(IceServer::from_str).collect() } diff --git a/transport/src/pool.rs b/transport/src/pool.rs index 7c5204a23..5a46e78e7 100644 --- a/transport/src/pool.rs +++ b/transport/src/pool.rs @@ -63,9 +63,9 @@ where /// The `safely_insert` method is used to insert a connection into the pool. /// It ensures that the connection is not inserted twice in concurrent scenarios. /// - /// The implementation of match statement refers to Entry::insert in dashmap. + /// The implementation of match statement refers to `Entry::insert` in dashmap. /// An extra check is added to see if the connection is already connected. - /// See also: https://docs.rs/dashmap/latest/dashmap/mapref/entry/enum.Entry.html#method.insert + /// See also: pub fn safely_insert(&self, cid: &str, conn: C) -> Result<()> { let Some(entry) = self.connections.try_entry(cid.to_string()) else { return Err(Error::ConnectionAlreadyExists(cid.to_string()));