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//!
35//! `core` consumers wire the crate via `default-features = false,
36//! features = ["core"]` and get only the pure-logic surfaces (no
37//! tokio, no reqwest, no DNS resolver, no filesystem). See
38//! `RELEASE_NOTES.md` v0.4.0-alpha.3 for the absorbed surfaces map.
39//!
40//! ## Module overview
41//!
42//! | Module | Responsibility |
43//! |-----------------|--------------------------------------------------------------|
44//! | [`storage`] | `Storage` trait + FS / Memory / S3 backends. |
45//! | [`ldp`] | Resources, containers, content negotiation, PATCH, `Prefer`. |
46//! | [`wac`] | Access control evaluator + WAC 2.0 conditions framework. |
47//! | [`webid`] | WebID profile documents (emits `solid:oidcIssuer` + CID). |
48//! | [`auth`] | NIP-98 HTTP authentication. |
49//! | [`notifications`] | WebSocket, Webhook (RFC 9421 signed), legacy adapter. |
50//! | [`error`] | Crate-wide [`PodError`] error type. |
51//! | [`config`] | Layered configuration schema. |
52//! | [`security`] | SSRF guard, dotfile allowlist, CORS, rate limiter. |
53//! | [`quota`] | Per-pod byte-quota enforcement. |
54//! | [`multitenant`] | `PodResolver` trait; path + subdomain modes. |
55//! | [`interop`] | `.well-known/solid`, WebFinger, NodeInfo, did:nostr. |
56//! | [`provision`] | Pod bootstrap (WebID + containers + type indexes + ACL). |
57//!
58//! ## Quick start
59//!
60//! ```rust,no_run
61//! use solid_pod_rs::storage::memory::MemoryBackend;
62//! use solid_pod_rs::{Storage, evaluate_access, AccessMode};
63//! use bytes::Bytes;
64//! use std::sync::Arc;
65//!
66//! # tokio::runtime::Runtime::new().unwrap().block_on(async {
67//! // 1. Create a storage backend.
68//! let store = Arc::new(MemoryBackend::new());
69//!
70//! // 2. PUT a resource.
71//! store.put("/hello.txt", Bytes::from("world"), "text/plain").await.unwrap();
72//!
73//! // 3. GET it back.
74//! let (body, meta) = store.get("/hello.txt").await.unwrap();
75//! assert_eq!(&body[..], b"world");
76//! assert_eq!(meta.content_type, "text/plain");
77//!
78//! // 4. WAC evaluation (no ACL document = deny by default).
79//! let allowed = evaluate_access(None, Some("https://alice.example/profile/card#me"),
80//!     "/hello.txt", AccessMode::Read, None);
81//! assert!(!allowed);
82//! # });
83//! ```
84//!
85//! ## Attribution
86//!
87//! Rust port of JavaScriptSolidServer. See NOTICE for provenance.
88
89#![doc = include_str!("../README.md")]
90#![deny(unsafe_code)]
91#![warn(rust_2018_idioms)]
92
93// ---------------------------------------------------------------------------
94// Always-compiled (`core`) modules.
95//
96// Pure-logic surfaces: parsers, validators, type definitions. None of
97// these reach for tokio, reqwest, or notify directly. Wasm32 / CF
98// Workers consumers wire these via
99// `default-features = false, features = ["core"]`.
100// ---------------------------------------------------------------------------
101pub mod auth;
102pub mod config;
103pub mod error;
104pub mod interop;
105pub mod ldp;
106pub mod metrics;
107pub mod multitenant;
108pub mod security;
109pub mod wac;
110pub mod webid;
111
112// ---------------------------------------------------------------------------
113// `tokio-runtime`-gated modules.
114//
115// These pull tokio (mpsc, fs, broadcast) or reqwest (HTTP client) and
116// are unavailable to `core` consumers. They are wired in by the
117// `default` feature set so the existing surface from 0.4.0-alpha.2 is
118// preserved bit-for-bit on native builds.
119// ---------------------------------------------------------------------------
120#[cfg(feature = "notifications")]
121pub mod notifications;
122#[cfg(feature = "tokio-runtime")]
123pub mod provision;
124#[cfg(feature = "tokio-runtime")]
125pub mod quota;
126#[cfg(feature = "tokio-runtime")]
127pub mod storage;
128
129#[cfg(feature = "oidc")]
130pub mod oidc;
131
132/// Transport-agnostic HTTP / WebSocket handler drivers. Consumers wire
133/// these into their HTTP framework of choice. Feature-gated; present
134/// only when at least one handler is enabled. Respects the F7
135/// library-server boundary — this crate never mounts routes itself.
136#[cfg(feature = "legacy-notifications")]
137pub mod handlers;
138
139// ---------------------------------------------------------------------------
140// `core` re-exports — always available.
141// ---------------------------------------------------------------------------
142pub use auth::nip98::Nip98Verifier;
143pub use auth::self_signed::{
144    CidVerifier, ProofEnvelope, SelfSignedError, SelfSignedVerifier, VerifiedSubject,
145};
146pub use error::PodError;
147pub use metrics::SecurityMetrics;
148pub use security::{
149    is_path_allowed, DotfileAllowlist, DotfileError, DotfilePathError,
150};
151pub use wac::{
152    check_origin, evaluate_access, evaluate_access_with_groups, extract_origin_patterns,
153    method_to_mode, mode_name, parse_turtle_acl, serialize_turtle_acl, wac_allow_header,
154    AccessMode, AclDocument, GroupMembership, Origin, OriginDecision, OriginPattern,
155    StaticGroupMembership,
156};
157pub use ldp::{
158    apply_json_patch, apply_n3_patch, apply_patch_to_absent, apply_sparql_patch,
159    cache_control_for, evaluate_preconditions, is_rdf_content_type, link_headers,
160    negotiate_format, not_found_headers, options_for, parse_range_header, parse_range_header_v2,
161    patch_dialect_from_mime, server_managed_triples, slice_range, vary_header, ByteRange,
162    ConditionalOutcome, ContainerRepresentation, Graph, OptionsResponse, PatchCreateOutcome,
163    PatchDialect, PatchOutcome, PreferHeader, RangeOutcome, RdfFormat, Term, Triple, ACCEPT_PATCH,
164    ACCEPT_POST, CACHE_CONTROL_RDF,
165};
166pub use interop::{
167    dev_session, nip05_document, verify_nip05, webfinger_response, well_known_solid, DevSession,
168    Nip05Document, SolidWellKnown, WebFingerJrd, WebFingerLink,
169};
170pub use multitenant::{PathResolver, PodResolver, ResolvedPath, SubdomainResolver};
171pub use webid::{
172    extract_oidc_issuer, generate_webid_html, generate_webid_html_with_issuer,
173    validate_webid_html,
174};
175
176// ---------------------------------------------------------------------------
177// `tokio-runtime`-gated re-exports.
178// ---------------------------------------------------------------------------
179#[cfg(feature = "tokio-runtime")]
180pub use security::{is_safe_url, resolve_and_check, IpClass, SsrfError, SsrfPolicy};
181#[cfg(feature = "tokio-runtime")]
182pub use storage::{ResourceMeta, Storage, StorageEvent};
183#[cfg(feature = "tokio-runtime")]
184pub use provision::{
185    check_admin_override, provision_pod, AdminOverride, ProvisionOutcome, ProvisionPlan,
186    QuotaTracker,
187};
188#[cfg(feature = "tokio-runtime")]
189pub use quota::{QuotaExceeded, QuotaPolicy, QuotaUsage};
190#[cfg(feature = "quota")]
191pub use quota::FsQuotaStore;