Skip to main content

ma_core/
lib.rs

1//! # ma-core
2//!
3//! A lean `DIDComm` service library for the ma ecosystem.
4//!
5//! `ma-core` provides the building blocks for ma-capable endpoints:
6//!
7//! - **DID documents** — create, validate, resolve, and publish `did:ma:` documents
8//!   to IPFS/IPNS (via Kubo on native targets). Use [`MaExtension`] to build the
9//!   `ma:` extension field, and [`config::SecretBundle::build_document`] (`config`
10//!   feature) as the single entry point for a complete, signed document.
11//! - **Service inboxes** — bounded, TTL-aware FIFO queues ([`Inbox`])
12//!   for receiving validated messages on named protocol services.
13//! - **Outbound sending** — fire-and-forget delivery of validated [`Message`] objects
14//!   to remote endpoints, serialized to CBOR on the wire.
15//! - **Endpoint abstraction** — the [`MaEndpoint`] trait with pluggable
16//!   transport backends.
17//! - **Transport parsing** — extract endpoint IDs and protocols from DID document
18//!   service strings (`/iroh/<id>/<protocol>`).
19//! - **Identity bootstrap** — secure secret key generation and persistence.
20//!
21//! ## Services
22//!
23//! Every endpoint should provide `/ma/inbox/0.0.1` (the default inbox) when it
24//! wants to receive direct messages. Endpoints may optionally provide
25//! `/ma/ipfs/0.0.1` to publish DID documents
26//! on behalf of others.
27//!
28//! ## Feature flags
29//!
30//! - **`kubo`** — enables native IPFS RPC backend for publishing (native only).
31//! - **`iroh`** — enables the internal iroh QUIC transport backend.
32//! - **`acl`** — enables [`AclMap`], [`check_cap`], capability constants, and
33//!   ACL validation helpers.
34//! - **`config`** — enables [`Config`], [`SecretBundle`], and [`MaArgs`] for
35//!   YAML-based daemon configuration, encrypted secret bundles, and CLI
36//!   argument parsing. Also provides [`config::SecretBundle::build_document`] and
37//!   [`config::SecretBundle::signing_key`] for constructing ready-to-publish DID documents.
38//!
39//! ## Platform support
40//!
41//! Core types (`Inbox`, `Service`, transport parsing, validation)
42//! compile on all targets including `wasm32-unknown-unknown`.
43//!
44//! ### wasm vs native
45//!
46//! - `ma-core` supports both wasm and native targets.
47//! - `IpfsGatewayResolver` (HTTP gateway DID fetch) is available on wasm and native.
48//! - Native IPFS RPC write/pin APIs are native-only (`not(wasm32)` + `kubo` feature).
49//! - wasm builds expose only `ipfs::gateway_resolver` (no native RPC helpers).
50//! - `config` serialization and `SecretBundle` crypto work on wasm.
51//! - `config` filesystem paths, CLI/env merging, and file I/O are native-only.
52//! - If your wasm application needs native IPFS RPC write/pin operations, provide
53//!   them in a native companion layer.
54
55#![forbid(unsafe_code)]
56#![allow(
57    clippy::cast_possible_truncation,
58    clippy::cast_precision_loss,
59    clippy::if_not_else,
60    clippy::items_after_statements,
61    clippy::manual_let_else,
62    clippy::map_unwrap_or,
63    clippy::missing_errors_doc,
64    clippy::must_use_candidate,
65    clippy::uninlined_format_args
66)]
67
68#[cfg(feature = "acl")]
69pub mod acl;
70#[cfg(feature = "config")]
71pub mod config;
72pub mod constants;
73pub mod did;
74pub mod doc;
75pub mod endpoint;
76pub mod error;
77pub mod identity;
78pub mod inbox;
79pub mod interfaces;
80pub mod ipfs;
81#[cfg(feature = "iroh")]
82// inbound-only items (accept, open, endpoint_id, read-timeout) are unused on wasm;
83// wasm endpoints send but do not accept raw inbound connections.
84#[allow(dead_code)]
85mod iroh;
86pub mod key;
87#[cfg(all(feature = "kubo", not(target_arch = "wasm32")))]
88mod kubo;
89#[cfg(all(feature = "kubo", not(target_arch = "wasm32")))]
90pub use kubo::{
91    cat_bytes, delete_local_pins_named_in_background, delete_remote_pins_named_in_background,
92    in_flight_pin_name, ipfs_add, remote_pin_add_named, remote_pin_replace_named,
93};
94pub mod msg;
95mod multiformat;
96#[cfg(feature = "iroh")]
97// OutboxWire and related helpers are only consumed by the native iroh inbound path.
98#[allow(dead_code)]
99mod outbox;
100pub mod service;
101pub mod transport;
102pub(crate) mod ttl_queue;
103
104// ─── Re-export DID/message primitives ───────────────────────────────────────
105
106pub use did::{Did, DID_PREFIX};
107pub use doc::{
108    now_iso_utc, Document, MaExtension, Proof, VerificationMethod, DEFAULT_DID_CONTEXT,
109    DEFAULT_PROOF_PURPOSE, DEFAULT_PROOF_TYPE,
110};
111pub use error::{Error, MaError, Result};
112pub use identity::{
113    generate_identity, generate_identity_from_secret, ipns_from_secret, GeneratedIdentity,
114};
115pub use ipld_core::ipld::Ipld;
116pub use key::{
117    EncryptionKey, SigningKey, ASSERTION_METHOD_KEY_TYPE, CODEC_ED25519_PUB, CODEC_EDDSA_SIG,
118    CODEC_X25519_PUB, KEY_AGREEMENT_KEY_TYPE,
119};
120pub use msg::{
121    decode_content, encode_content, Envelope, Headers, Message, ReplayGuard,
122    DEFAULT_MAX_CLOCK_SKEW_SECS, DEFAULT_MESSAGE_TTL_SECS, DEFAULT_REPLAY_WINDOW_SECS,
123    MESSAGE_PREFIX,
124};
125pub use multiformat::{
126    CODEC_CBOR, CODEC_DAG_CBOR, CODEC_DAG_JSON, CODEC_IDENTITY, CODEC_JSON, CODEC_RAW,
127};
128
129#[cfg(feature = "acl")]
130pub use acl::{
131    check_cap, is_principal_key, is_valid_acl_key, normalize_principal, validate_acl_map, AclMap,
132    CapabilityEntry, CAP_ACL, CAP_CREATE, CAP_CRUD, CAP_DELETE, CAP_IDENTITY_PUBLISH, CAP_INBOX,
133    CAP_IPFS, CAP_READ, CAP_RPC, CAP_UPDATE, GROUP_PREFIX, LOCAL_ENTITY_WILDCARD,
134};
135
136// ─── Re-export service constants ────────────────────────────────────────────
137
138pub use service::{
139    Service, CONTENT_TYPE_CBOR, CONTENT_TYPE_TERM, CONTENT_TYPE_TERM_CBOR, CONTENT_TYPE_TERM_YAML,
140    CRUD_PROTOCOL_ID, INBOX_PROTOCOL_ID, IPFS_PROTOCOL_ID, MESSAGE_TYPE_BROADCAST,
141    MESSAGE_TYPE_CHAT, MESSAGE_TYPE_CRUD, MESSAGE_TYPE_CRUD_REPLY, MESSAGE_TYPE_DOC,
142    MESSAGE_TYPE_EMOTE, MESSAGE_TYPE_IDENTITY_PUBLISH_REQUEST, MESSAGE_TYPE_IPFS_REQUEST,
143    MESSAGE_TYPE_MESSAGE, MESSAGE_TYPE_RPC, MESSAGE_TYPE_RPC_REPLY, RPC_PROTOCOL_ID,
144};
145
146// ─── Re-export Inbox ────────────────────────────────────────────────────────
147
148pub use inbox::Inbox;
149
150// ─── Re-export endpoint trait and implementations ───────────────────────────
151
152pub use endpoint::MaEndpoint;
153#[cfg(feature = "iroh")]
154pub use outbox::Outbox;
155
156/// Create a default ma endpoint backend from 32-byte secret key material.
157///
158/// This keeps the transport backend type internal while exposing
159/// [`MaEndpoint`] and [`Outbox`] as stable API surfaces.
160#[cfg(feature = "iroh")]
161pub async fn new_ma_endpoint(
162    secret_bytes: [u8; 32],
163    recipient_key: EncryptionKey,
164    resolver: std::sync::Arc<dyn DidDocumentResolver>,
165    ipv6: bool,
166) -> Result<Box<dyn MaEndpoint>> {
167    let endpoint = iroh::new_endpoint(secret_bytes, recipient_key, resolver, ipv6).await?;
168    Ok(Box::new(endpoint))
169}
170
171// ─── Re-export transport parsing ────────────────────────────────────────────
172
173pub use transport::{
174    endpoint_id_from_transport, endpoint_id_from_transport_value, normalize_endpoint_id,
175    protocol_from_transport, resolve_endpoint_for_protocol, resolve_inbox_endpoint_id,
176    transport_string,
177};
178
179// ─── Re-export identity helpers ─────────────────────────────────────────────
180
181pub use identity::{generate_secret_key_file, load_secret_key_bytes, socket_addr_to_multiaddr};
182
183// ─── Re-export config types ──────────────────────────────────────────────────
184
185#[cfg(all(feature = "config", not(target_arch = "wasm32")))]
186pub use config::MaArgs;
187#[cfg(feature = "config")]
188pub use config::{BrowserIdentityExport, Config, SecretBundle};
189
190// ─── Re-export DID resolution ───────────────────────────────────────────────
191
192pub use ipfs::gateway::GatewayPool;
193pub use ipfs::gateway_resolver::{DidDocumentResolver, IpfsGatewayResolver, IpnsPathResolver};
194
195// ─── Re-export existing modules ─────────────────────────────────────────────
196
197pub use interfaces::{DidPublisher, IpfsPublisher};
198pub use ipfs::*;