Skip to main content

solid_pod_rs/
lib.rs

1//! Framework-agnostic Rust library for serving Solid Protocol 0.11 pods.
2//!
3//! `solid-pod-rs` provides LDP resource and container semantics, Web Access
4//! Control (WAC 1.x + 2.0), WebID profile documents, Solid-OIDC 0.1,
5//! NIP-98 HTTP auth, and Solid Notifications 0.2 -- all without coupling
6//! to a specific HTTP framework. Wire it into actix-web, axum, hyper, or
7//! anything else; the crate never mounts routes itself.
8//!
9//! For a turnkey binary, use the sibling crate
10//! [`solid-pod-rs-server`](https://docs.rs/solid-pod-rs-server).
11//!
12//! ## Feature flags
13//!
14//! | Flag | Default | Purpose |
15//! |-------------------------|:-------:|-----------------------------------------------|
16//! | `core` | off | Pure-logic surfaces only — wasm32 / CF Workers. |
17//! | `std` | on | std lib (always; reserved for future no_std).  |
18//! | `tokio-runtime` | on | Tokio + tokio-tungstenite + futures-util.       |
19//! | `notifications` | on | WebSocketChannel2023 + WebhookChannel2023.      |
20//! | `fs-backend` | on | POSIX filesystem storage. |
21//! | `memory-backend` | on | In-process `HashMap` storage (tests/demos). |
22//! | `s3-backend` | off | AWS S3 / S3-compatible object stores. |
23//! | `oidc` | off | Solid-OIDC 0.1 + DPoP. |
24//! | `dpop-replay-cache` | off | DPoP `jti` replay cache (pulls `oidc`). |
25//! | `nip98-schnorr` | off | BIP-340 signature verification for NIP-98. |
26//! | `acl-origin` | off | WAC `acl:origin` enforcement. |
27//! | `security-primitives` | off | SSRF guard + dotfile allowlist. |
28//! | `legacy-notifications` | off | `solid-0.1` WebSocket adapter (SolidOS). |
29//! | `config-loader` | off | Layered config loader with `JSS_*` env vars. |
30//! | `webhook-signing` | off | RFC 9421 Ed25519 webhook signing. |
31//! | `did-nostr` | off | did:nostr resolver in `interop`. |
32//! | `rate-limit` | off | Sliding-window LRU rate limiter. |
33//! | `quota` | off | Per-pod `.quota.json` sidecar (atomic writes). |
34//! | `lws-cid` | off | LWS 1.0 CID self-signed JWT verifier (ES256K). |
35//! | `lws-cid-p256` | off | LWS-CID + ES256 (P-256) algorithm. |
36//! | `lws-cid-eddsa` | off | LWS-CID + EdDSA (Ed25519) algorithm. |
37//! | `lws-cid-full` | off | LWS-CID with all algorithms. |
38//!
39//! `core` consumers wire the crate via `default-features = false,
40//! features = ["core"]` and get only the pure-logic surfaces (no
41//! tokio, no reqwest, no DNS resolver, no filesystem). See
42//! `RELEASE_NOTES.md` v0.4.0-alpha.3 for the absorbed surfaces map.
43//!
44//! ## Module overview
45//!
46//! | Module | Responsibility |
47//! |-----------------|--------------------------------------------------------------|
48//! | [`storage`] | `Storage` trait + FS / Memory / S3 backends. |
49//! | [`ldp`] | Resources, containers, content negotiation, PATCH, `Prefer`. |
50//! | [`wac`] | Access control evaluator + WAC 2.0 conditions framework. |
51//! | [`webid`] | WebID profile documents (emits `solid:oidcIssuer` + CID). |
52//! | [`mashlib`] | SolidOS data-browser HTML wrapper + data-island embed.    |
53//! | [`auth`] | NIP-98 HTTP auth + LWS-CID self-signed JWT verifier. |
54//! | [`payments`] | HTTP 402, Web Ledgers, MRC20 tokens, multi-chain TXO. |
55//! | [`notifications`] | WebSocket, Webhook (RFC 9421 signed), legacy adapter. |
56//! | [`error`] | Crate-wide [`PodError`] error type. |
57//! | [`config`] | Layered configuration schema. |
58//! | [`security`] | SSRF guard, dotfile allowlist, CORS, rate limiter. |
59//! | [`quota`] | Per-pod byte-quota enforcement. |
60//! | [`multitenant`] | `PodResolver` trait; path + subdomain modes. |
61//! | [`interop`] | `.well-known/solid`, WebFinger, NodeInfo, did:nostr. |
62//! | [`provision`] | Pod bootstrap (WebID + containers + type indexes + ACL). |
63//!
64//! ## Quick start
65//!
66//! ```rust,no_run
67//! use solid_pod_rs::storage::memory::MemoryBackend;
68//! use solid_pod_rs::{Storage, evaluate_access, AccessMode};
69//! use bytes::Bytes;
70//! use std::sync::Arc;
71//!
72//! # tokio::runtime::Runtime::new().unwrap().block_on(async {
73//! // 1. Create a storage backend.
74//! let store = Arc::new(MemoryBackend::new());
75//!
76//! // 2. PUT a resource.
77//! store.put("/hello.txt", Bytes::from("world"), "text/plain").await.unwrap();
78//!
79//! // 3. GET it back.
80//! let (body, meta) = store.get("/hello.txt").await.unwrap();
81//! assert_eq!(&body[..], b"world");
82//! assert_eq!(meta.content_type, "text/plain");
83//!
84//! // 4. WAC evaluation (no ACL document = deny by default).
85//! let allowed = evaluate_access(None, Some("https://alice.example/profile/card#me"),
86//!     "/hello.txt", AccessMode::Read, None);
87//! assert!(!allowed);
88//! # });
89//! ```
90//!
91//! ## Attribution
92//!
93//! Rust port of JavaScriptSolidServer. See NOTICE for provenance.
94
95#![doc = include_str!("../README.md")]
96#![deny(unsafe_code)]
97#![warn(rust_2018_idioms)]
98
99// ---------------------------------------------------------------------------
100// Always-compiled (`core`) modules.
101//
102// Pure-logic surfaces: parsers, validators, type definitions. None of
103// these reach for tokio, reqwest, or notify directly. Wasm32 / CF
104// Workers consumers wire these via
105// `default-features = false, features = ["core"]`.
106// ---------------------------------------------------------------------------
107pub mod auth;
108pub mod config;
109pub mod error;
110pub mod interop;
111pub mod ldp;
112pub mod mashlib;
113pub mod metrics;
114pub mod multitenant;
115pub mod payments;
116pub mod security;
117pub mod wac;
118pub mod webid;
119
120// ---------------------------------------------------------------------------
121// `tokio-runtime`-gated modules.
122//
123// These pull tokio (mpsc, fs, broadcast) or reqwest (HTTP client) and
124// are unavailable to `core` consumers. They are wired in by the
125// `default` feature set so the existing surface from 0.4.0-alpha.2 is
126// preserved bit-for-bit on native builds.
127// ---------------------------------------------------------------------------
128#[cfg(feature = "notifications")]
129pub mod notifications;
130#[cfg(feature = "tokio-runtime")]
131pub mod provision;
132#[cfg(feature = "tokio-runtime")]
133pub mod quota;
134#[cfg(feature = "tokio-runtime")]
135pub mod storage;
136
137#[cfg(feature = "oidc")]
138pub mod oidc;
139
140/// Transport-agnostic HTTP / WebSocket handler drivers. Consumers wire
141/// these into their HTTP framework of choice. Feature-gated; present
142/// only when at least one handler is enabled. Respects the F7
143/// library-server boundary — this crate never mounts routes itself.
144#[cfg(feature = "legacy-notifications")]
145pub mod handlers;
146
147// ---------------------------------------------------------------------------
148// `core` re-exports — always available.
149// ---------------------------------------------------------------------------
150pub use auth::nip98::Nip98Verifier;
151pub use auth::self_signed::{
152    CidVerifier, ProofEnvelope, SelfSignedError, SelfSignedVerifier, VerifiedSubject,
153};
154pub use error::PodError;
155pub use metrics::SecurityMetrics;
156pub use security::{
157    is_path_allowed, DotfileAllowlist, DotfileError, DotfilePathError,
158};
159pub use wac::{
160    check_origin, evaluate_access, evaluate_access_with_groups, extract_origin_patterns,
161    method_to_mode, mode_name, parse_turtle_acl, serialize_turtle_acl, wac_allow_header,
162    AccessMode, AclDocument, GroupMembership, Origin, OriginDecision, OriginPattern,
163    StaticGroupMembership,
164};
165pub use ldp::{
166    apply_json_patch, apply_n3_patch, apply_patch_to_absent, apply_sparql_patch,
167    cache_control_for, evaluate_preconditions, is_rdf_content_type, link_headers,
168    negotiate_format, not_found_headers, options_for, parse_range_header, parse_range_header_v2,
169    patch_dialect_from_mime, server_managed_triples, slice_range, vary_header, ByteRange,
170    ConditionalOutcome, ContainerRepresentation, Graph, OptionsResponse, PatchCreateOutcome,
171    PatchDialect, PatchOutcome, PreferHeader, RangeOutcome, RdfFormat, Term, Triple, ACCEPT_PATCH,
172    ACCEPT_POST, CACHE_CONTROL_RDF,
173};
174pub use interop::{
175    dev_session, nip05_document, verify_nip05, webfinger_response, well_known_solid, DevSession,
176    Nip05Document, SolidWellKnown, WebFingerJrd, WebFingerLink,
177};
178pub use multitenant::{PathResolver, PodResolver, ResolvedPath, SubdomainResolver};
179pub use webid::{
180    extract_oidc_issuer, generate_webid_html, generate_webid_html_with_issuer,
181    validate_webid_html,
182};
183pub use mashlib::{
184    MashlibConfig, MashlibMode, DATA_ISLAND_MAX_BYTES,
185};
186
187// ---------------------------------------------------------------------------
188// `tokio-runtime`-gated re-exports.
189// ---------------------------------------------------------------------------
190#[cfg(feature = "tokio-runtime")]
191pub use security::{is_safe_url, resolve_and_check, IpClass, SsrfError, SsrfPolicy};
192#[cfg(feature = "tokio-runtime")]
193pub use storage::{ResourceMeta, Storage, StorageEvent};
194#[cfg(feature = "tokio-runtime")]
195pub use provision::{
196    check_admin_override, provision_pod, AdminOverride, ProvisionOutcome, ProvisionPlan,
197    QuotaTracker,
198};
199#[cfg(feature = "tokio-runtime")]
200pub use quota::{QuotaExceeded, QuotaPolicy, QuotaUsage};
201#[cfg(feature = "quota")]
202pub use quota::FsQuotaStore;