All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
- ADR-T-006: Document rationale for error system refactor.
- 188 crate-level tests for the domain error system (
src/tests/errors/): status-code mapping, display messages,Fromimpl coverage, andApiErrordelegation (ADR-T-006 §1–§4). - ADR-T-007: Document rationale for JWT system refactor.
- Centralised JWT module (
src/jwt.rs) consolidating alljsonwebtokenusage: key loading, signing, verification, and algorithm configuration. SessionClaimswith RFC 7519 registered claims (sub,iss,aud,iat,exp) plus advisoryrole,username, and revocationgenfields.VerifyClaimswithaud: "email-verification"for purpose separation.- RSA key pair configuration:
auth.private_key_path/auth.public_key_path(or inline PEM viaauth.private_key_pem/auth.public_key_pem). - Ephemeral auto-generated RSA-2048 key pair when no keys are configured. Sessions do not survive server restarts with ephemeral keys. Deployers who want persistent sessions supply their own key pair via config.
torrust-generate-auth-keypairCLI binary for generating RSA-2048 key pairs. Outputs both PEM blocks to stdout; refuses to run if stdout is a terminal.- Container auto-generation of persistent auth keys on first boot. The entry
script runs
torrust-generate-auth-keypairand writes the PEM files to/etc/torrust/index/auth/on the volume. Sessions survive restarts with no manual setup. kid(Key ID) header in every JWT for future key rotation support.- Configurable token lifetimes:
auth.session_token_lifetime_secs(default: 2 weeks) andauth.email_verification_token_lifetime_secs(default: ~10 years). token_generationcolumn ontorrust_users(migration for SQLite and MySQL).- Token revocation: password changes, role changes (admin grant), and bans
increment
token_generation; tokens with an oldergenclaim are rejected. - Consolidated session validation:
JsonWebToken::validate_sessionis the sole entry point for verifying a session JWT, checking the token-generation counter, and rejecting banned users. All callers delegate here. BearerTokenextractor rejects missing/malformedAuthorizationheaders at the extraction boundary (AuthError::TokenNotFound/AuthError::TokenInvalid).ExtractOptionalLoggedInUsercatches extraction rejection and returnsNonefor anonymous requests.AuthError::TokenRevokedvariant for revoked-token responses.- Crate tests for the JWT module (session + email-verification round-trips, audience cross-contamination, tampered/garbage tokens).
- Crate tests for
parse_token(valid extraction, whitespace trimming, empty bearer, missing prefix, non-ASCII rejection).
- BREAKING: Raise MSRV from 1.85 to 1.88.
- BREAKING: JWT signing algorithm changed from HMAC-HS256 to RS256 (RSA + SHA-256). Existing HS256 tokens are invalidated; users must re-login.
- BREAKING: JWT claims redesigned from
UserClaims { user, exp }toSessionClaims { sub, iss, aud, iat, exp, role, username, gen }. Existing tokens without the new claims fail deserialization. - BREAKING: Configuration keys changed —
auth.user_claim_token_pepper/auth.session_signing_key/auth.email_verification_signing_keyreplaced byauth.private_key_pathandauth.public_key_path(or inline PEM). Deployers must generate an RSA key pair. - BREAKING: Replace
ServiceError(41 variants) andServiceResultwith domain-scoped error enums:AuthError,UserError,TorrentError,CategoryTagError, and a thinApiErrorwrapper (ADR-T-006). Authentication::get_user_id_from_bearer_tokennow takesBearerTokendirectly instead ofOption<BearerToken>.ExtractLoggedInUserandExtractOptionalLoggedInUseruseBearerTokendirectly instead of the oldExtractwrapper.parse_tokenreturnsResultinstead of panicking on malformed headers.- JWT
expvalidation relies solely on thejsonwebtokenlibrary; redundant manual expiration check removed. - Token signing uses
Resultpropagation instead of.unwrap()/.expect(). UserClaimsis now a type alias forSessionClaims(backward-compatible).VerifyClaimsmoved frommailerinto thejwtmodule (re-exported for backward compatibility).- Service functions now return domain-specific
Result<T, DomainError>instead ofResult<T, ServiceError>. - Each domain error co-locates its HTTP status-code mapping via a
status_code()method. - Error
Fromimpls usetracing::error!instead ofeprintln!. - Standardise all error derives on
thiserror.
bearer_token::Extractwrapper struct (replaced byBearerTokendirectly).get_optional_logged_in_userfree function (logic moved into extractors).get_claims_from_bearer_tokenprivate method onAuthentication(inlined).ClaimTokenPepper/JwtSigningSecret/user_claim_token_pepperconfig keys (replaced by RSA key pair configuration).ServiceErrorenum andServiceResulttype alias fromsrc/errors.rs.http_status_code_for_service_errorandmap_database_error_to_service_errorhelper functions.IntoResponseimpl fordatabase::Error(now handled by domain errors).
- ADR-T-004: Document rationale for removing
located-errorpackage. - ADR-T-005: Document rationale for Rust edition 2024 migration.
- BREAKING: Raise MSRV from 1.83 to 1.85.
- BREAKING: Migrate workspace to Rust edition 2024.
- BREAKING: Bump workspace version from
3.1.0-developto4.0.0-develop. - Upgrade
jsonwebtokenfrom 9.3 to 10 (withrust_cryptofeature). - Upgrade
randfrom 0.9 to 0.10; renamerand::Rngtorand::RngExt. - Promote
rust-2024-compatibilitylint group fromwarntodeny. - Reformat imports across ~55 files to edition 2024 style.
- Simplify error types in
configandweb::api::server— replaceLocatedError<'static, dyn Error + Send + Sync>withArc<dyn Error + Send + Sync>. - Emit
tracing::error!events whereLocatedErrorpreviously logged context.
- BREAKING: Remove first-party
torrust-index-located-errorpackage (packages/located-error/). Usetracingfor error-origin context instead.