diff --git a/src/spaces/routes.rs b/src/spaces/routes.rs index 0e927ae..9eef440 100644 --- a/src/spaces/routes.rs +++ b/src/spaces/routes.rs @@ -1333,9 +1333,25 @@ async fn list_repos( claims: XrpcClaims, Query(params): Query, ) -> Result { - let _did = require_auth_or_credential(&state, &claims).await?; let space = resolve_space(&state, ¶ms.space).await?; + // The repo list is the space's participant list. Its visibility follows the + // `membershipPublic` config (like `get_space` / `listMembers`): public when + // set, otherwise the caller must be an authenticated member (or authority / + // space-credential holder). Previously this required *some* auth but never + // checked membership, leaking any private space's participants (M2). + if !space.config.membership_public { + let did = require_auth_or_credential(&state, &claims).await?; + require_membership( + &state, + &space, + &did, + false, + claims.space_credential.as_deref(), + ) + .await?; + } + let repos = db::list_space_repos(&state.db, state.db_backend, &space.id).await?; Ok(Json(serde_json::json!({ "repos": repos }))) } diff --git a/tests/spaces_list_repos_auth.rs b/tests/spaces_list_repos_auth.rs new file mode 100644 index 0000000..7dc6378 --- /dev/null +++ b/tests/spaces_list_repos_auth.rs @@ -0,0 +1,161 @@ +mod common; + +use axum::body::Body; +use axum::http::{HeaderName, HeaderValue, Request, StatusCode}; +use happyview::db::now_rfc3339; +use happyview::spaces::db as spaces_db; +use happyview::spaces::types::*; +use serde_json::json; +use serial_test::serial; +use tower::ServiceExt; +use uuid::Uuid; + +use common::app::TestApp; + +const AUTHORITY: &str = "did:plc:listrepos-authority"; +const MEMBER: &str = "did:plc:listrepos-member"; +const OUTSIDER: &str = "did:plc:listrepos-outsider"; + +fn space_uri(skey: &str) -> String { + format!("at://{AUTHORITY}/space/com.example.listrepos/{skey}") +} + +async fn enable_spaces(app: &TestApp) { + let (name, value) = app.admin_cookie(); + let req = Request::builder() + .method("PUT") + .uri("/admin/settings/feature.spaces_enabled") + .header(name, value) + .header("content-type", "application/json") + .body(Body::from(json!({ "value": "true" }).to_string())) + .unwrap(); + assert!( + app.router + .clone() + .oneshot(req) + .await + .unwrap() + .status() + .is_success(), + "failed to enable spaces" + ); +} + +/// Create a space with the given skey and `membership_public`. Returns its id. +async fn create_space(app: &TestApp, skey: &str, membership_public: bool) -> String { + let now = now_rfc3339(); + let id = Uuid::new_v4().to_string(); + let space = Space { + id: id.clone(), + did: AUTHORITY.to_string(), + authority_did: AUTHORITY.to_string(), + creator_did: AUTHORITY.to_string(), + type_nsid: "com.example.listrepos".to_string(), + skey: skey.to_string(), + display_name: None, + description: None, + mint_policy: MintPolicy::MemberList, + app_access: AppAccess::Open, + managing_app_did: None, + config: SpaceConfig { + membership_public, + ..Default::default() + }, + revision: None, + created_at: now.clone(), + updated_at: now, + }; + spaces_db::create_space(&app.state.db, app.state.db_backend, &space) + .await + .expect("create_space failed"); + id +} + +async fn add_member(app: &TestApp, space_id: &str, did: &str) { + spaces_db::add_member( + &app.state.db, + app.state.db_backend, + &SpaceMember { + id: Uuid::new_v4().to_string(), + space_id: space_id.to_string(), + did: did.to_string(), + access: SpaceAccess::Read, + is_delegation: false, + granted_by: Some(AUTHORITY.to_string()), + created_at: now_rfc3339(), + }, + ) + .await + .expect("add_member failed"); +} + +fn cookie_for(app: &TestApp, did: &str) -> (HeaderName, HeaderValue) { + common::auth::admin_cookie_header(did, &app.state.cookie_key) +} + +fn list_repos_req(skey: &str, cookie: Option<(HeaderName, HeaderValue)>) -> Request { + let mut b = Request::builder().method("GET").uri(format!( + "/xrpc/com.atproto.space.listRepos?space={}", + urlencoding::encode(&space_uri(skey)) + )); + if let Some((name, value)) = cookie { + b = b.header(name, value); + } + b.body(Body::empty()).unwrap() +} + +/// A private space must not leak its participant list to an authenticated +/// non-member. Before the fix this returned 200. +#[tokio::test] +#[serial] +async fn list_repos_private_rejects_non_member() { + common::require_db!(); + let app = TestApp::new().await; + enable_spaces(&app).await; + create_space(&app, "priv", false).await; + + let resp = app + .router + .clone() + .oneshot(list_repos_req("priv", Some(cookie_for(&app, OUTSIDER)))) + .await + .unwrap(); + assert_eq!(resp.status(), StatusCode::FORBIDDEN); +} + +/// A member of the private space can list its repos. +#[tokio::test] +#[serial] +async fn list_repos_private_allows_member() { + common::require_db!(); + let app = TestApp::new().await; + enable_spaces(&app).await; + let id = create_space(&app, "priv2", false).await; + add_member(&app, &id, MEMBER).await; + + let resp = app + .router + .clone() + .oneshot(list_repos_req("priv2", Some(cookie_for(&app, MEMBER)))) + .await + .unwrap(); + assert_eq!(resp.status(), StatusCode::OK); +} + +/// When `membershipPublic` is set, the repo list is public — no auth required. +#[tokio::test] +#[serial] +async fn list_repos_public_allows_anonymous() { + common::require_db!(); + let app = TestApp::new().await; + enable_spaces(&app).await; + create_space(&app, "pub", true).await; + + let resp = app + .router + .clone() + .oneshot(list_repos_req("pub", None)) + .await + .unwrap(); + assert_eq!(resp.status(), StatusCode::OK); +} -- 2.51.2 From 10037f63507c2032374f74045d28d3a690689f88 Mon Sep 17 00:00:00 2001 From: Trezy Date: Tue, 7 Jul 2026 21:15:36 -0500 Subject: [PATCH 02/14] fix: implement revocation for space credentials Signed-off-by: Trezy --- ...00_add_revoked_at_to_space_credentials.sql | 4 + ...00_add_revoked_at_to_space_credentials.sql | 4 + .../docs/experimental/spaces/credentials.md | 14 +- src/spaces/db.rs | 40 ++++++ src/spaces/routes.rs | 22 ++- src/spaces/simplespace.rs | 6 + tests/spaces_credential_revocation.rs | 136 ++++++++++++++++++ tests/spaces_db.rs | 49 +++++++ 8 files changed, 271 insertions(+), 4 deletions(-) create mode 100644 migrations/postgres/20260707000000_add_revoked_at_to_space_credentials.sql create mode 100644 migrations/sqlite/20260707000000_add_revoked_at_to_space_credentials.sql create mode 100644 tests/spaces_credential_revocation.rs diff --git a/migrations/postgres/20260707000000_add_revoked_at_to_space_credentials.sql b/migrations/postgres/20260707000000_add_revoked_at_to_space_credentials.sql new file mode 100644 index 0000000..6911f07 --- /dev/null +++ b/migrations/postgres/20260707000000_add_revoked_at_to_space_credentials.sql @@ -0,0 +1,4 @@ +-- Add revocation support to space credentials (M3). +-- A NULL revoked_at means active; a timestamp means the credential (and any +-- other credential sharing the row) has been revoked and must be rejected. +ALTER TABLE happyview_space_credentials ADD COLUMN revoked_at TEXT; diff --git a/migrations/sqlite/20260707000000_add_revoked_at_to_space_credentials.sql b/migrations/sqlite/20260707000000_add_revoked_at_to_space_credentials.sql new file mode 100644 index 0000000..6911f07 --- /dev/null +++ b/migrations/sqlite/20260707000000_add_revoked_at_to_space_credentials.sql @@ -0,0 +1,4 @@ +-- Add revocation support to space credentials (M3). +-- A NULL revoked_at means active; a timestamp means the credential (and any +-- other credential sharing the row) has been revoked and must be rejected. +ALTER TABLE happyview_space_credentials ADD COLUMN revoked_at TEXT; diff --git a/packages/docs/content/docs/experimental/spaces/credentials.md b/packages/docs/content/docs/experimental/spaces/credentials.md index 81d6621..50876e8 100644 --- a/packages/docs/content/docs/experimental/spaces/credentials.md +++ b/packages/docs/content/docs/experimental/spaces/credentials.md @@ -197,7 +197,19 @@ The JWT payload contains: | `sub` | The full `at://` space URI | | `iat` | Issued at (Unix timestamp) | | `exp` | Expiry (Unix timestamp) | -| `jti` | Random nonce for replay protection | +| `jti` | Random nonce making each issued credential unique | + +The credential is a bearer token: it is reused for the full 2-hour TTL and is not +bound to a specific client or audience, so any service holding it can read the +space's records. Containment relies on the short TTL and on revocation. + +## Revocation + +A credential is invalidated before its TTL expires when its holder is removed +from the space (`com.atproto.simplespace.removeMember`): HappyView records the +revocation and rejects the credential on subsequent reads. Because a credential +is an opaque bearer token, revocation is scoped to a member — removing (and, if +needed, re-adding) a member revokes all of that member's outstanding credentials. ## Using a credential diff --git a/src/spaces/db.rs b/src/spaces/db.rs index adb4473..ace617c 100644 --- a/src/spaces/db.rs +++ b/src/spaces/db.rs @@ -307,6 +307,46 @@ pub async fn remove_member( Ok(result.rows_affected() > 0) } +/// Returns true if a space credential with the given token hash has been revoked. +pub async fn is_space_credential_revoked( + pool: &sqlx::AnyPool, + backend: DatabaseBackend, + token_hash: &str, +) -> Result { + let sql = adapt_sql( + "SELECT revoked_at FROM happyview_space_credentials WHERE token_hash = ? AND revoked_at IS NOT NULL LIMIT 1", + backend, + ); + let row: Option<(String,)> = sqlx::query_as(&sql) + .bind(token_hash) + .fetch_optional(pool) + .await + .map_err(|e| AppError::Internal(format!("failed to check credential revocation: {e}")))?; + Ok(row.is_some()) +} + +/// Revoke all active space credentials issued to `did` within `space_id`. +/// Returns the number of credentials revoked. +pub async fn revoke_space_credentials_for_member( + pool: &sqlx::AnyPool, + backend: DatabaseBackend, + space_id: &str, + did: &str, +) -> Result { + let sql = adapt_sql( + "UPDATE happyview_space_credentials SET revoked_at = ? WHERE space_id = ? AND issued_to = ? AND revoked_at IS NULL", + backend, + ); + let result = sqlx::query(&sql) + .bind(now_rfc3339()) + .bind(space_id) + .bind(did) + .execute(pool) + .await + .map_err(|e| AppError::Internal(format!("failed to revoke space credentials: {e}")))?; + Ok(result.rows_affected()) +} + pub async fn get_member( pool: &sqlx::AnyPool, backend: DatabaseBackend, diff --git a/src/spaces/routes.rs b/src/spaces/routes.rs index 9eef440..ef1be5a 100644 --- a/src/spaces/routes.rs +++ b/src/spaces/routes.rs @@ -357,6 +357,14 @@ fn require_auth(claims: &XrpcClaims) -> Result<&crate::auth::Claims, AppError> { /// Like `require_auth`, but also accepts a verified space credential as an /// identity source. Use this in space endpoints that support `Bearer /// ` in addition to DPoP auth. +/// Whether a verified space credential has been revoked (e.g. its holder was +/// removed from the space). Consulted after signature/exp verification so a +/// leaked or stale credential can be invalidated before its TTL expires (M3). +async fn space_credential_revoked(state: &AppState, token: &str) -> Result { + let token_hash = hex::encode(Sha256::digest(token.as_bytes())); + db::is_space_credential_revoked(&state.db, state.db_backend, &token_hash).await +} + async fn require_auth_or_credential( state: &AppState, claims: &XrpcClaims, @@ -372,6 +380,9 @@ async fn require_auth_or_credential( &state.config.plc_url, ) .await?; + if space_credential_revoked(state, token).await? { + return Err(AppError::Auth("space credential has been revoked".into())); + } return Ok(verified.sub); } @@ -450,13 +461,18 @@ async fn require_membership( .await { Ok(claims) if claims.sub == space_uri => { - // External credential grants read access; write is not supported via space credential - if require_write { + // A revoked credential is treated as invalid — fall through to + // the local membership check rather than granting access. + if space_credential_revoked(state, token).await? { + // fall through + } else if require_write { + // External credential grants read access only. return Err(AppError::Forbidden( "Write access is required for this action".into(), )); + } else { + return Ok(SpaceAccess::Read); } - return Ok(SpaceAccess::Read); } Ok(_) => { // Credential is valid but for a different space — fall through diff --git a/src/spaces/simplespace.rs b/src/spaces/simplespace.rs index d285233..55c5c25 100644 --- a/src/spaces/simplespace.rs +++ b/src/spaces/simplespace.rs @@ -422,6 +422,12 @@ async fn remove_member( return Err(AppError::NotFound("Member not found in this space".into())); } + // Revoke any outstanding space credentials the removed member holds so their + // cross-service access ends immediately rather than lingering for the + // credential's 2h TTL (M3). + db::revoke_space_credentials_for_member(&state.db, state.db_backend, &space.id, &input.did) + .await?; + Ok(Json(serde_json::json!({ "success": true }))) } diff --git a/tests/spaces_credential_revocation.rs b/tests/spaces_credential_revocation.rs new file mode 100644 index 0000000..f6df382 --- /dev/null +++ b/tests/spaces_credential_revocation.rs @@ -0,0 +1,136 @@ +mod common; + +use axum::body::Body; +use axum::http::{Request, StatusCode}; +use happyview::db::now_rfc3339; +use happyview::spaces::db as spaces_db; +use happyview::spaces::types::*; +use serde_json::json; +use serial_test::serial; +use tower::ServiceExt; +use uuid::Uuid; + +use common::app::TestApp; + +const AUTHORITY: &str = "did:plc:cred-authority"; +const MEMBER: &str = "did:plc:cred-holder"; + +fn space_uri() -> String { + format!("at://{AUTHORITY}/space/com.example.cred/main") +} + +async fn enable_spaces(app: &TestApp) { + let (name, value) = app.admin_cookie(); + let req = Request::builder() + .method("PUT") + .uri("/admin/settings/feature.spaces_enabled") + .header(name, value) + .header("content-type", "application/json") + .body(Body::from(json!({ "value": "true" }).to_string())) + .unwrap(); + assert!( + app.router + .clone() + .oneshot(req) + .await + .unwrap() + .status() + .is_success(), + "failed to enable spaces" + ); +} + +/// Removing a member from a space revokes their outstanding space credentials. +/// Before the fix, removeMember left the credential active for its full TTL. +#[tokio::test] +#[serial] +async fn remove_member_revokes_credentials() { + common::require_db!(); + let app = TestApp::new().await; + enable_spaces(&app).await; + + // Create a space and a member. + let space_id = Uuid::new_v4().to_string(); + let now = now_rfc3339(); + let space = Space { + id: space_id.clone(), + did: AUTHORITY.to_string(), + authority_did: AUTHORITY.to_string(), + creator_did: AUTHORITY.to_string(), + type_nsid: "com.example.cred".to_string(), + skey: "main".to_string(), + display_name: None, + description: None, + mint_policy: MintPolicy::MemberList, + app_access: AppAccess::Open, + managing_app_did: None, + config: SpaceConfig::default(), + revision: None, + created_at: now.clone(), + updated_at: now.clone(), + }; + spaces_db::create_space(&app.state.db, app.state.db_backend, &space) + .await + .unwrap(); + spaces_db::add_member( + &app.state.db, + app.state.db_backend, + &SpaceMember { + id: Uuid::new_v4().to_string(), + space_id: space_id.clone(), + did: MEMBER.to_string(), + access: SpaceAccess::Read, + is_delegation: false, + granted_by: Some(AUTHORITY.to_string()), + created_at: now.clone(), + }, + ) + .await + .unwrap(); + + // The member holds an outstanding credential (represented by its hash). + let token_hash = "member-credential-hash"; + let sql = happyview::db::adapt_sql( + "INSERT INTO happyview_space_credentials (id, space_id, issued_to, token_hash, expires_at, created_at) VALUES (?, ?, ?, ?, ?, ?)", + app.state.db_backend, + ); + sqlx::query(&sql) + .bind(Uuid::new_v4().to_string()) + .bind(&space_id) + .bind(MEMBER) + .bind(token_hash) + .bind(&now) + .bind(&now) + .execute(&app.state.db) + .await + .unwrap(); + + assert!( + !spaces_db::is_space_credential_revoked(&app.state.db, app.state.db_backend, token_hash) + .await + .unwrap() + ); + + // The authority removes the member. + let (cookie_name, cookie_val) = + common::auth::admin_cookie_header(AUTHORITY, &app.state.cookie_key); + let req = Request::builder() + .method("POST") + .uri("/xrpc/com.atproto.simplespace.removeMember") + .header(cookie_name, cookie_val) + .header("content-type", "application/json") + .body(Body::from( + json!({ "space": space_uri(), "did": MEMBER }).to_string(), + )) + .unwrap(); + let resp = app.router.clone().oneshot(req).await.unwrap(); + assert_eq!(resp.status(), StatusCode::OK); + + // The credential is now revoked. + assert!( + spaces_db::is_space_credential_revoked(&app.state.db, app.state.db_backend, token_hash) + .await + .unwrap(), + "removing a member must revoke their outstanding credentials" + ); +} diff --git a/tests/spaces_db.rs b/tests/spaces_db.rs index 7bdebd3..363532b 100644 --- a/tests/spaces_db.rs +++ b/tests/spaces_db.rs @@ -557,6 +557,55 @@ async fn resolve_members_preserves_read_self() { assert_eq!(access, Some(SpaceAccess::ReadSelf)); } +#[tokio::test] +#[serial] +async fn space_credential_revocation_round_trip() { + common::require_db!(); + let pool = test_db::test_pool().await; + let backend = test_db::test_backend(); + test_db::truncate_all(&pool).await; + + let space_id = new_id(); + let space = make_space(&space_id, "did:plc:cred-owner", "com.example.cred", "cred"); + spaces_db::create_space(&pool, backend, &space) + .await + .expect("create_space failed"); + + let member = "did:plc:cred-member"; + let token_hash = "abc123hash"; + let sql = happyview::db::adapt_sql( + "INSERT INTO happyview_space_credentials (id, space_id, issued_to, token_hash, expires_at, created_at) VALUES (?, ?, ?, ?, ?, ?)", + backend, + ); + sqlx::query(&sql) + .bind(new_id()) + .bind(&space_id) + .bind(member) + .bind(token_hash) + .bind(now_rfc3339()) + .bind(now_rfc3339()) + .execute(&pool) + .await + .expect("insert credential row"); + + assert!( + !spaces_db::is_space_credential_revoked(&pool, backend, token_hash) + .await + .unwrap() + ); + + let revoked = spaces_db::revoke_space_credentials_for_member(&pool, backend, &space_id, member) + .await + .unwrap(); + assert_eq!(revoked, 1); + + assert!( + spaces_db::is_space_credential_revoked(&pool, backend, token_hash) + .await + .unwrap() + ); +} + #[tokio::test] #[serial] async fn remove_member() { -- 2.51.2 From f016508974288f5ff28c8c81efb9c75af0d6f881 Mon Sep 17 00:00:00 2001 From: Trezy Date: Tue, 7 Jul 2026 21:43:36 -0500 Subject: [PATCH 03/14] fix: issue space credentials for `iss`, not for the caller Signed-off-by: Trezy --- src/spaces/routes.rs | 17 ++++ tests/spaces_credential_mint.rs | 168 ++++++++++++++++++++++++++++++++ 2 files changed, 185 insertions(+) create mode 100644 tests/spaces_credential_mint.rs diff --git a/src/spaces/routes.rs b/src/spaces/routes.rs index ef1be5a..a602a80 100644 --- a/src/spaces/routes.rs +++ b/src/spaces/routes.rs @@ -1543,8 +1543,25 @@ async fn get_space_credential( )? }; + // The credential is minted for the delegation token's subject (`iss`). + // Require the authenticated caller to *be* that subject — otherwise anyone + // who captures a member's short-lived (60s) delegation token could mint a 2h + // credential in that member's name (M4). The documented flow has the same + // member's app perform both steps; only the final credential is handed to an + // external service. + if claims.did() != delegation_claims.iss.as_str() { + return Err(AppError::Forbidden( + "delegation token was issued to a different account".into(), + )); + } + let space = resolve_space(&state, &delegation_claims.sub).await?; + // Re-verify current membership before minting. The `MemberList` mint policy + // is a no-op that trusts the delegation token, so a member removed within the + // token's 60s window would otherwise still be able to mint. + require_membership(&state, &space, &delegation_claims.iss, false, None).await?; + let client_id = if let Some(key) = claims.client_key() { resolve_client_id_url(&state, key).await? } else { diff --git a/tests/spaces_credential_mint.rs b/tests/spaces_credential_mint.rs new file mode 100644 index 0000000..4ca0e96 --- /dev/null +++ b/tests/spaces_credential_mint.rs @@ -0,0 +1,168 @@ +mod common; + +use axum::body::Body; +use axum::http::{HeaderName, HeaderValue, Request, StatusCode}; +use happyview::db::now_rfc3339; +use happyview::spaces::db as spaces_db; +use happyview::spaces::types::*; +use http_body_util::BodyExt; +use serde_json::{Value, json}; +use serial_test::serial; +use tower::ServiceExt; +use uuid::Uuid; + +use common::app::TestApp; + +const AUTHORITY: &str = "did:plc:mint-authority"; +const MEMBER: &str = "did:plc:mint-member"; +const ATTACKER: &str = "did:plc:mint-attacker"; + +fn space_uri() -> String { + format!("at://{AUTHORITY}/space/com.example.mint/main") +} + +async fn enable_spaces(app: &TestApp) { + let (name, value) = app.admin_cookie(); + let req = Request::builder() + .method("PUT") + .uri("/admin/settings/feature.spaces_enabled") + .header(name, value) + .header("content-type", "application/json") + .body(Body::from(json!({ "value": "true" }).to_string())) + .unwrap(); + assert!( + app.router + .clone() + .oneshot(req) + .await + .unwrap() + .status() + .is_success(), + "failed to enable spaces" + ); +} + +fn cookie_for(app: &TestApp, did: &str) -> (HeaderName, HeaderValue) { + common::auth::admin_cookie_header(did, &app.state.cookie_key) +} + +async fn json_of(resp: axum::http::Response) -> Value { + let body = resp.into_body().collect().await.unwrap().to_bytes(); + serde_json::from_slice(&body).unwrap_or(json!(null)) +} + +/// Set up a space with `MEMBER` as a read member, and return a fresh delegation +/// token issued to `MEMBER`. +async fn setup_and_get_delegation_token(app: &TestApp) -> String { + enable_spaces(app).await; + + let space_id = Uuid::new_v4().to_string(); + let now = now_rfc3339(); + let space = Space { + id: space_id.clone(), + did: AUTHORITY.to_string(), + authority_did: AUTHORITY.to_string(), + creator_did: AUTHORITY.to_string(), + type_nsid: "com.example.mint".to_string(), + skey: "main".to_string(), + display_name: None, + description: None, + mint_policy: MintPolicy::MemberList, + app_access: AppAccess::Open, + managing_app_did: None, + config: SpaceConfig::default(), + revision: None, + created_at: now.clone(), + updated_at: now.clone(), + }; + spaces_db::create_space(&app.state.db, app.state.db_backend, &space) + .await + .unwrap(); + spaces_db::add_member( + &app.state.db, + app.state.db_backend, + &SpaceMember { + id: Uuid::new_v4().to_string(), + space_id, + did: MEMBER.to_string(), + access: SpaceAccess::Read, + is_delegation: false, + granted_by: Some(AUTHORITY.to_string()), + created_at: now, + }, + ) + .await + .unwrap(); + + // MEMBER obtains a delegation token (proof of membership). + let (name, value) = cookie_for(app, MEMBER); + let req = Request::builder() + .method("GET") + .uri(format!( + "/xrpc/com.atproto.space.getDelegationToken?space={}", + urlencoding::encode(&space_uri()) + )) + .header(name, value) + .body(Body::empty()) + .unwrap(); + let resp = app.router.clone().oneshot(req).await.unwrap(); + assert_eq!(resp.status(), StatusCode::OK, "getDelegationToken failed"); + json_of(resp).await["delegationToken"] + .as_str() + .expect("delegationToken") + .to_string() +} + +fn get_credential_req(grant: &str, cookie: (HeaderName, HeaderValue)) -> Request { + Request::builder() + .method("POST") + .uri("/xrpc/com.atproto.space.getSpaceCredential") + .header(cookie.0, cookie.1) + .header("content-type", "application/json") + .body(Body::from(json!({ "grant": grant }).to_string())) + .unwrap() +} + +/// An attacker who captures a member's delegation token cannot mint a credential +/// in the member's name. Before the fix this returned 200. +#[tokio::test] +#[serial] +async fn get_space_credential_rejects_foreign_caller() { + common::require_db!(); + let app = TestApp::new_with_encryption().await; + let grant = setup_and_get_delegation_token(&app).await; + + let resp = app + .router + .clone() + .oneshot(get_credential_req(&grant, cookie_for(&app, ATTACKER))) + .await + .unwrap(); + assert_eq!( + resp.status(), + StatusCode::FORBIDDEN, + "a caller must not mint a credential from another member's delegation token" + ); +} + +/// The member the delegation token was issued to can mint their own credential. +#[tokio::test] +#[serial] +async fn get_space_credential_allows_own_caller() { + common::require_db!(); + let app = TestApp::new_with_encryption().await; + let grant = setup_and_get_delegation_token(&app).await; + + let resp = app + .router + .clone() + .oneshot(get_credential_req(&grant, cookie_for(&app, MEMBER))) + .await + .unwrap(); + assert_eq!(resp.status(), StatusCode::OK); + let body = json_of(resp).await; + assert!( + body["credential"].as_str().is_some(), + "expected a credential" + ); +} -- 2.51.2 From 6dc6dc680185162cf7d5926be33e3c61633ade03 Mon Sep 17 00:00:00 2001 From: Trezy Date: Tue, 7 Jul 2026 21:49:56 -0500 Subject: [PATCH 04/14] fix: prevent lockouts from failed super admin transfer Signed-off-by: Trezy --- src/admin/users.rs | 57 ++++++++++-------- tests/transfer_super.rs | 124 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 156 insertions(+), 25 deletions(-) create mode 100644 tests/transfer_super.rs diff --git a/src/admin/users.rs b/src/admin/users.rs index 6fb6504..cf82b98 100644 --- a/src/admin/users.rs +++ b/src/admin/users.rs @@ -413,47 +413,50 @@ pub(super) async fn transfer_super( let backend = state.db_backend; let now = now_rfc3339(); - // Remove super from current user - let update1_sql = adapt_sql( - "UPDATE happyview_users SET is_super = ? WHERE id = ?", - backend, - ); - sqlx::query(&update1_sql) - .bind(0_i32) - .bind(&auth.user_id) - .execute(&state.db) + // Run every mutation in a single transaction so a failure or crash can never + // leave the instance with zero super users (M6). On any early return the + // transaction is dropped and rolled back, preserving the current super. + let mut tx = state + .db + .begin() .await - .map_err(|e| AppError::Internal(format!("failed to remove super: {e}")))?; + .map_err(|e| AppError::Internal(format!("failed to begin transaction: {e}")))?; - // Set super on target user - let update2_sql = adapt_sql( + // Promote the target first (and require it to exist) so a missing target + // aborts before the current super is touched. + let set_super_sql = adapt_sql( "UPDATE happyview_users SET is_super = ? WHERE id = ?", backend, ); - let result = sqlx::query(&update2_sql) + let result = sqlx::query(&set_super_sql) .bind(1_i32) .bind(&body.target_user_id) - .execute(&state.db) + .execute(&mut *tx) .await .map_err(|e| AppError::Internal(format!("failed to set super: {e}")))?; if result.rows_affected() == 0 { - // Restore super on current user - let restore_sql = adapt_sql( - "UPDATE happyview_users SET is_super = ? WHERE id = ?", - backend, - ); - let _ = sqlx::query(&restore_sql) - .bind(1_i32) - .bind(&auth.user_id) - .execute(&state.db) - .await; return Err(AppError::NotFound(format!( "user '{}' not found", body.target_user_id ))); } + // Demote the current super — unless they are transferring to themselves, in + // which case demoting would undo the promotion above. + if body.target_user_id != auth.user_id { + let remove_super_sql = adapt_sql( + "UPDATE happyview_users SET is_super = ? WHERE id = ?", + backend, + ); + sqlx::query(&remove_super_sql) + .bind(0_i32) + .bind(&auth.user_id) + .execute(&mut *tx) + .await + .map_err(|e| AppError::Internal(format!("failed to remove super: {e}")))?; + } + // Ensure target has all permissions let perm_sql = adapt_sql( "INSERT INTO happyview_user_permissions (user_id, permission, granted_by, granted_at) VALUES (?, ?, ?, ?) ON CONFLICT DO NOTHING", @@ -466,11 +469,15 @@ pub(super) async fn transfer_super( .bind(perm.as_str()) .bind(&auth.user_id) .bind(&now) - .execute(&state.db) + .execute(&mut *tx) .await .map_err(|e| AppError::Internal(format!("failed to grant permission: {e}")))?; } + tx.commit() + .await + .map_err(|e| AppError::Internal(format!("failed to commit super transfer: {e}")))?; + log_event( &state.db, EventLog { diff --git a/tests/transfer_super.rs b/tests/transfer_super.rs new file mode 100644 index 0000000..a33caa7 --- /dev/null +++ b/tests/transfer_super.rs @@ -0,0 +1,124 @@ +mod common; + +use axum::body::Body; +use axum::http::{Request, StatusCode}; +use serde_json::json; +use serial_test::serial; +use tower::ServiceExt; +use uuid::Uuid; + +use common::app::TestApp; + +async fn user_id_for_did(app: &TestApp, did: &str) -> String { + let sql = happyview::db::adapt_sql( + "SELECT id FROM happyview_users WHERE did = ?", + app.state.db_backend, + ); + let row: (String,) = sqlx::query_as(&sql) + .bind(did) + .fetch_one(&app.state.db) + .await + .unwrap(); + row.0 +} + +async fn is_super(app: &TestApp, user_id: &str) -> bool { + let sql = happyview::db::adapt_sql( + "SELECT is_super FROM happyview_users WHERE id = ?", + app.state.db_backend, + ); + let row: (i32,) = sqlx::query_as(&sql) + .bind(user_id) + .fetch_one(&app.state.db) + .await + .unwrap(); + row.0 != 0 +} + +async fn insert_user(app: &TestApp, did: &str) -> String { + let id = Uuid::new_v4().to_string(); + let sql = happyview::db::adapt_sql( + "INSERT INTO happyview_users (id, did, is_super, created_at) VALUES (?, ?, ?, ?)", + app.state.db_backend, + ); + sqlx::query(&sql) + .bind(&id) + .bind(did) + .bind(0_i32) + .bind(happyview::db::now_rfc3339()) + .execute(&app.state.db) + .await + .unwrap(); + id +} + +fn transfer_req(app: &TestApp, target_user_id: &str) -> Request { + let (name, value) = app.admin_cookie(); + Request::builder() + .method("POST") + .uri("/admin/users/transfer-super") + .header(name, value) + .header("content-type", "application/json") + .body(Body::from( + json!({ "target_user_id": target_user_id }).to_string(), + )) + .unwrap() +} + +/// A successful transfer promotes the target (with all permissions) and demotes +/// the previous super. +#[tokio::test] +#[serial] +async fn transfer_super_moves_super_and_grants_permissions() { + common::require_db!(); + let app = TestApp::new().await; + let admin_id = user_id_for_did(&app, &app.admin_did).await; + let target_id = insert_user(&app, "did:plc:new-super").await; + + let resp = app + .router + .clone() + .oneshot(transfer_req(&app, &target_id)) + .await + .unwrap(); + assert_eq!(resp.status(), StatusCode::NO_CONTENT); + + assert!(is_super(&app, &target_id).await, "target should be super"); + assert!( + !is_super(&app, &admin_id).await, + "previous super should be demoted" + ); + + let sql = happyview::db::adapt_sql( + "SELECT COUNT(*) FROM happyview_user_permissions WHERE user_id = ?", + app.state.db_backend, + ); + let count: (i64,) = sqlx::query_as(&sql) + .bind(&target_id) + .fetch_one(&app.state.db) + .await + .unwrap(); + assert!(count.0 > 0, "target should have permissions granted"); +} + +/// Transferring to a non-existent user fails without demoting the current super +/// — the transaction rolls back, so the instance is never left without a super. +#[tokio::test] +#[serial] +async fn transfer_super_to_missing_user_preserves_current_super() { + common::require_db!(); + let app = TestApp::new().await; + let admin_id = user_id_for_did(&app, &app.admin_did).await; + + let resp = app + .router + .clone() + .oneshot(transfer_req(&app, "does-not-exist")) + .await + .unwrap(); + assert_eq!(resp.status(), StatusCode::NOT_FOUND); + assert!( + is_super(&app, &admin_id).await, + "current super must be preserved when the transfer fails (no lockout)" + ); +} -- 2.51.2 From 05fe15c7b8394025fcec1185b98e22ec52370577 Mon Sep 17 00:00:00 2001 From: Trezy Date: Tue, 7 Jul 2026 22:12:42 -0500 Subject: [PATCH 05/14] docs: capture security concerns with record signing Signed-off-by: Trezy --- .../docs/api-reference/lua/atproto-api.md | 2 ++ .../docs/guides/attestation-signing.md | 23 +++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/packages/docs/content/docs/api-reference/lua/atproto-api.md b/packages/docs/content/docs/api-reference/lua/atproto-api.md index 7be0f7a..69ebcd6 100644 --- a/packages/docs/content/docs/api-reference/lua/atproto-api.md +++ b/packages/docs/content/docs/api-reference/lua/atproto-api.md @@ -214,6 +214,8 @@ local sig = atproto.sign(record) Signs a record and returns the inline signature object. Only available when an attestation signer is configured — if no signer is configured, `atproto.sign` is `nil`. +> **Privileged capability.** This signs *exactly* the content you pass with the instance's key; it proves only that this instance signed the content, not that the content is authentic. Only sign data you have verified, and be careful in scripts that run on untrusted input (record-event/label scripts, anonymous queries). See [Attestation Signing — Security considerations](../../guides/attestation-signing.md#security-considerations). + | Parameter | Type | Description | | --------- | ----- | ----------------------- | | `record` | table | The record data to sign | diff --git a/packages/docs/content/docs/guides/attestation-signing.md b/packages/docs/content/docs/guides/attestation-signing.md index d8c7f98..8325ea6 100644 --- a/packages/docs/content/docs/guides/attestation-signing.md +++ b/packages/docs/content/docs/guides/attestation-signing.md @@ -104,6 +104,29 @@ Signatures are stored as objects in the record's `signatures` array: | `key` | string | Key identifier (DID with fragment) | | `signature` | table | Contains `$bytes` (base64-encoded) | +## Security considerations + +`atproto.sign` exposes the instance's signing key to Lua scripts. Treat it as a +privileged capability: + +- **It signs exactly what you give it.** A signature only proves *"this HappyView + instance signed this content"* — it does **not** prove the content is authentic, + is present in anyone's repo, or was authored by any particular DID. Only sign + content you have already verified. +- **It's available to any script**, including ones that run on untrusted input — + record-event and label scripts (triggered by arbitrary firehose records) and + anonymous XRPC queries. In those contexts there is no authenticated caller, so + the signature's `repository` binding is empty. Don't sign untrusted input (a + firehose record, an anonymous request parameter) unless you intend the instance + to vouch for it. +- **Creating scripts requires the `scripts:manage` permission.** The signing key + is therefore only reachable by operators you have trusted with that permission — + grant it accordingly, and review scripts that call `atproto.sign`. + +If you need signatures scoped to a specific verified subject, have the script +verify the subject itself (e.g. confirm the record's `did` and content against the +source) before calling `atproto.sign`. + ## Next steps - [atproto API reference](../api-reference/lua/atproto-api.md#atprotosign) — `atproto.sign` and `atproto.verify_signature` parameter docs -- 2.51.2 From 5a7fa4dcd42e3eeb59fc4d76e34d2f5e81c08848 Mon Sep 17 00:00:00 2001 From: Trezy Date: Tue, 7 Jul 2026 22:32:16 -0500 Subject: [PATCH 06/14] fix: prevent error details from leaking to external users Signed-off-by: Trezy --- src/error.rs | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/src/error.rs b/src/error.rs index 7f722ee..1a9eaab 100644 --- a/src/error.rs +++ b/src/error.rs @@ -175,6 +175,19 @@ impl IntoResponse for AppError { }); (StatusCode::SERVICE_UNAVAILABLE, axum::Json(body)).into_response() } + AppError::Internal(msg) => { + // Never leak internal details (SQL/driver errors, decryption + // failures, crypto/config state) to clients. Log the real message + // server-side with a correlation id and return only that id so an + // operator can find it in the logs. + let correlation_id = format!("{:016x}", rand::random::()); + tracing::error!(correlation_id, "internal error: {msg}"); + let body = serde_json::json!({ + "error": "Internal server error", + "correlationId": correlation_id, + }); + (StatusCode::INTERNAL_SERVER_ERROR, axum::Json(body)).into_response() + } AppError::RateLimited { retry_after, limit, @@ -200,15 +213,12 @@ impl IntoResponse for AppError { AppError::BadRequest(msg) => (StatusCode::BAD_REQUEST, msg.clone()), AppError::Conflict(msg) => (StatusCode::CONFLICT, msg.clone()), AppError::Forbidden(msg) => (StatusCode::FORBIDDEN, msg.clone()), - AppError::Internal(msg) => { - tracing::error!("{msg}"); - (StatusCode::INTERNAL_SERVER_ERROR, msg.clone()) - } AppError::NotFound(msg) => (StatusCode::NOT_FOUND, msg.clone()), AppError::PdsError(..) | AppError::AuthDpopNonce(..) | AppError::FeatureDisabled(..) | AppError::InsufficientPermissions(..) + | AppError::Internal(..) | AppError::ServerMisconfigured(..) | AppError::RateLimited { .. } | AppError::ScriptError { .. } => unreachable!(), @@ -261,10 +271,23 @@ mod tests { } #[tokio::test] - async fn internal_error_returns_500_with_message() { - let (status, body) = response_parts(AppError::Internal("secret details".into())).await; + async fn internal_error_returns_500_without_leaking_details() { + let (status, body) = + response_parts(AppError::Internal("secret SQL driver details".into())).await; assert_eq!(status, StatusCode::INTERNAL_SERVER_ERROR); - assert_eq!(body["error"], "secret details"); + // The raw internal message must not appear anywhere in the response body. + assert_eq!(body["error"], "Internal server error"); + assert!( + !body.to_string().contains("secret SQL driver details"), + "internal error details must not be leaked to the client" + ); + // A correlation id is returned so the operator can find the real error in logs. + assert!( + body["correlationId"] + .as_str() + .is_some_and(|s| !s.is_empty()), + "expected a non-empty correlationId" + ); } #[tokio::test] -- 2.51.2 From 2a11841dee01514b84271d13a97a27f2d182a0bb Mon Sep 17 00:00:00 2001 From: Trezy Date: Tue, 7 Jul 2026 22:58:42 -0500 Subject: [PATCH 07/14] fix: better handling for empty TOKEN_ENCRYPTION_KEY Signed-off-by: Trezy --- src/config.rs | 68 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 61 insertions(+), 7 deletions(-) diff --git a/src/config.rs b/src/config.rs index dfa2150..3a6827c 100644 --- a/src/config.rs +++ b/src/config.rs @@ -44,6 +44,25 @@ fn validate_session_secret(secret: &str) -> Result<(), String> { Ok(()) } +/// Parse the optional `TOKEN_ENCRYPTION_KEY`, distinguishing "unset" +/// (`Ok(None)` — encryption-dependent features are simply off) from "set but +/// invalid" (`Err`), so a botched key is reported loudly at startup instead of +/// being silently discarded and failing per-call later (M12). +fn parse_token_encryption_key(raw: Option<&str>) -> Result, String> { + use base64::Engine; + let raw = match raw { + None | Some("") => return Ok(None), + Some(s) => s, + }; + let bytes = base64::engine::general_purpose::STANDARD + .decode(raw) + .map_err(|e| format!("TOKEN_ENCRYPTION_KEY is not valid base64: {e}"))?; + let len = bytes.len(); + <[u8; 32]>::try_from(bytes) + .map(Some) + .map_err(|_| format!("TOKEN_ENCRYPTION_KEY must decode to exactly 32 bytes (got {len})")) +} + #[derive(Clone, Debug)] pub struct Config { pub host: String, @@ -111,13 +130,20 @@ impl Config { logo_uri: env::var("LOGO_URI").ok(), tos_uri: env::var("TOS_URI").ok(), policy_uri: env::var("POLICY_URI").ok(), - token_encryption_key: env::var("TOKEN_ENCRYPTION_KEY").ok().and_then(|s| { - use base64::Engine; - base64::engine::general_purpose::STANDARD - .decode(&s) - .ok() - .and_then(|bytes| bytes.try_into().ok()) - }), + token_encryption_key: match parse_token_encryption_key( + env::var("TOKEN_ENCRYPTION_KEY").ok().as_deref(), + ) { + Ok(key) => key, + Err(reason) => { + // Set-but-invalid is an operator mistake: surface it loudly at + // startup instead of silently disabling encryption. + tracing::error!( + "{reason}. The key is being IGNORED — encryption-dependent features \ + (DPoP sessions, spaces, service identity) are DISABLED until it is fixed." + ); + None + } + }, default_rate_limit_capacity: env::var("DEFAULT_RATE_LIMIT_CAPACITY") .ok() .and_then(|v| v.parse().ok()) @@ -293,6 +319,34 @@ mod tests { Config::from_env(); } + #[test] + fn token_encryption_key_unset_or_empty_is_none() { + assert!(parse_token_encryption_key(None).unwrap().is_none()); + assert!(parse_token_encryption_key(Some("")).unwrap().is_none()); + } + + #[test] + fn token_encryption_key_valid_32_bytes_parses() { + use base64::Engine; + let encoded = base64::engine::general_purpose::STANDARD.encode([7u8; 32]); + let parsed = parse_token_encryption_key(Some(&encoded)).unwrap().unwrap(); + assert_eq!(parsed, [7u8; 32]); + } + + #[test] + fn token_encryption_key_invalid_base64_is_err() { + assert!(parse_token_encryption_key(Some("not valid base64 @@@")).is_err()); + } + + #[test] + fn token_encryption_key_wrong_length_is_err() { + use base64::Engine; + // 16 bytes, not 32. + let encoded = base64::engine::general_purpose::STANDARD.encode([7u8; 16]); + let err = parse_token_encryption_key(Some(&encoded)).unwrap_err(); + assert!(err.contains("32 bytes"), "got: {err}"); + } + #[test] fn validate_session_secret_accepts_strong_secret() { assert!(validate_session_secret("a-securely-generated-32plus-byte-secret!!").is_ok()); -- 2.51.2 From 2348c5cc2bd84cffd52d32678796e38c5264de58 Mon Sep 17 00:00:00 2001 From: Trezy Date: Wed, 8 Jul 2026 07:00:56 -0500 Subject: [PATCH 08/14] fix: add replay protection to dpop proofs Signed-off-by: Trezy --- src/oauth/dpop_proof.rs | 97 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 92 insertions(+), 5 deletions(-) diff --git a/src/oauth/dpop_proof.rs b/src/oauth/dpop_proof.rs index 376680d..3f938e5 100644 --- a/src/oauth/dpop_proof.rs +++ b/src/oauth/dpop_proof.rs @@ -3,9 +3,41 @@ use base64::engine::general_purpose::URL_SAFE_NO_PAD; use p256::ecdsa::{Signature, VerifyingKey, signature::Verifier}; use serde::Deserialize; use sha2::{Digest, Sha256}; +use std::collections::HashMap; +use std::sync::{LazyLock, Mutex}; use crate::error::AppError; +/// How far in the past a DPoP proof's `iat` may be and still be accepted. +const DPOP_IAT_PAST_TOLERANCE_SECS: u64 = 300; +/// How far in the future a DPoP proof's `iat` may be — small clock-skew slack. +/// Previously the past tolerance (300s) was also applied to the future via +/// `abs_diff`, accepting proofs issued up to 5 minutes ahead (M13). +const DPOP_IAT_FUTURE_TOLERANCE_SECS: u64 = 30; + +/// Seen DPoP proof `jti`s mapped to the time they can be forgotten (the past +/// acceptance horizon). In-memory and per-process — RFC 9449 §11.1 permits +/// storing the `jti` for the window in which the proof would be accepted. A +/// multi-instance deployment behind a load balancer would need a shared store +/// for cross-instance replay protection; single-instance is fully covered. +static DPOP_JTI_SEEN: LazyLock>> = + LazyLock::new(|| Mutex::new(HashMap::new())); + +/// Reject a DPoP proof whose `jti` has already been seen within its acceptance +/// window (replay). On first sight the `jti` is recorded until `expires_at`. +fn check_and_record_jti(jti: &str, expires_at: u64, now: u64) -> Result<(), AppError> { + let mut seen = DPOP_JTI_SEEN.lock().unwrap_or_else(|e| e.into_inner()); + if seen.get(jti).is_some_and(|&exp| exp > now) { + return Err(AppError::Auth("DPoP proof replay detected".into())); + } + // Bound memory: drop entries past their horizon once the map grows large. + if seen.len() > 10_000 { + seen.retain(|_, &mut exp| exp > now); + } + seen.insert(jti.to_string(), expires_at); + Ok(()) +} + #[derive(Debug, Deserialize)] struct DpopHeader { alg: String, @@ -96,15 +128,17 @@ pub fn validate_dpop_proof( return Err(AppError::Auth("DPoP proof htu mismatch".into())); } - // Check iat (within 5 minutes) + // Check iat: a generous past tolerance for the proof to reach us, but only a + // small future tolerance for clock skew. let now = std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) .unwrap() .as_secs(); - if now.abs_diff(payload.iat) > 300 { - return Err(AppError::Auth( - "DPoP proof expired or too far in the future".into(), - )); + if payload.iat > now + DPOP_IAT_FUTURE_TOLERANCE_SECS { + return Err(AppError::Auth("DPoP proof iat is in the future".into())); + } + if now > payload.iat + DPOP_IAT_PAST_TOLERANCE_SECS { + return Err(AppError::Auth("DPoP proof expired".into())); } // Check ath (access token hash) — required per RFC 9449 section 4.2 @@ -133,6 +167,16 @@ pub fn validate_dpop_proof( verify_es256_jwk(&message, &sig_bytes, &header.jwk)?; + // Replay protection (RFC 9449 §11.1): only after the proof is fully valid, + // reject it if this `jti` was already used within its acceptance window. + // Remember the `jti` until its `iat` falls outside the past tolerance (after + // which the `iat` check alone would reject a replay). + check_and_record_jti( + &payload.jti, + payload.iat + DPOP_IAT_PAST_TOLERANCE_SECS, + now, + )?; + Ok(()) } @@ -208,6 +252,49 @@ mod tests { ); } + #[test] + fn check_and_record_jti_rejects_replay_within_window() { + // Unique jti per test to stay independent of the shared cache. + let jti = "m13-unit-replay"; + assert!(check_and_record_jti(jti, 1300, 1000).is_ok()); + // Same jti again while still within its window → replay. + assert!(check_and_record_jti(jti, 1300, 1000).is_err()); + // Once past the horizon it is accepted again. + assert!(check_and_record_jti(jti, 1700, 1400).is_ok()); + } + + #[test] + fn check_and_record_jti_allows_distinct_jtis() { + assert!(check_and_record_jti("m13-unit-distinct-a", 1300, 1000).is_ok()); + assert!(check_and_record_jti("m13-unit-distinct-b", 1300, 1000).is_ok()); + } + + #[test] + fn valid_proof_rejected_on_replay() { + let keypair = crate::oauth::keys::generate_dpop_keypair().unwrap(); + let url = "https://example.com/xrpc/com.example.test"; + let proof = crate::oauth::pds_write::generate_dpop_proof( + &keypair.private_jwk, + "POST", + url, + "access-token", + None, + ) + .unwrap(); + + // First use is accepted. + assert!( + validate_dpop_proof(&proof, "POST", url, "access-token", &keypair.thumbprint).is_ok() + ); + // Replaying the exact same proof is rejected. + let err = validate_dpop_proof(&proof, "POST", url, "access-token", &keypair.thumbprint) + .unwrap_err(); + assert!( + err.to_string().contains("replay"), + "expected a replay error, got: {err}" + ); + } + #[test] fn rejects_invalid_format() { let result = validate_dpop_proof( -- 2.51.2 From 365705650cd0f4a7367e45314d94ae008c326b2e Mon Sep 17 00:00:00 2001 From: Trezy Date: Wed, 8 Jul 2026 09:57:48 -0500 Subject: [PATCH 09/14] fix: Run Docker image as non-root user Signed-off-by: Trezy --- Dockerfile | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index ad103be..b2d8e91 100644 --- a/Dockerfile +++ b/Dockerfile @@ -30,17 +30,32 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ ca-certificates \ && rm -rf /var/lib/apt/lists/* +# Run the service as a non-root system user; the binary needs no root privileges +# at runtime and binds an unprivileged port (3000). +RUN groupadd --system --gid 10001 app \ + && useradd --system --uid 10001 --gid app --home-dir /app --no-create-home \ + --shell /usr/sbin/nologin app + WORKDIR /app COPY --from=builder /app/target/release/happyview /usr/local/bin/happyview RUN chmod +x /usr/local/bin/happyview COPY migrations/ /app/migrations -COPY --from=frontend /app/web/out /srv/static +# The static dir is writable at runtime: the entrypoint rewrites the base-path +# sentinel in place and removes the marker. +COPY --from=frontend --chown=app:app /app/web/out /srv/static COPY entrypoint.sh /entrypoint.sh RUN chmod +x /entrypoint.sh && touch /srv/static/.base-path-pending +# Data dir for the default SQLite backend (DATABASE_URL=sqlite://data/...). +# A named volume mounted here inherits this ownership on first creation; a bind +# mount must be chown'd to uid 10001 by the operator. +RUN mkdir -p /app/data && chown app:app /app/data + ENV STATIC_DIR=/srv/static +USER app + EXPOSE 3000 ENTRYPOINT ["/entrypoint.sh"] -- 2.51.2 From f62ccfd9ab4b476d2281c897f5209cb895a02f5e Mon Sep 17 00:00:00 2001 From: Trezy Date: Wed, 8 Jul 2026 11:57:14 -0500 Subject: [PATCH 10/14] fix: revoke member credentials before removing them from a space Signed-off-by: Trezy --- src/oauth/dpop_proof.rs | 38 ++++++++++++++++++++++++++++++-------- src/spaces/simplespace.rs | 15 +++++++++------ 2 files changed, 39 insertions(+), 14 deletions(-) diff --git a/src/oauth/dpop_proof.rs b/src/oauth/dpop_proof.rs index 3f938e5..f97e819 100644 --- a/src/oauth/dpop_proof.rs +++ b/src/oauth/dpop_proof.rs @@ -25,16 +25,27 @@ static DPOP_JTI_SEEN: LazyLock>> = /// Reject a DPoP proof whose `jti` has already been seen within its acceptance /// window (replay). On first sight the `jti` is recorded until `expires_at`. -fn check_and_record_jti(jti: &str, expires_at: u64, now: u64) -> Result<(), AppError> { +/// +/// The cache key is scoped by the proof's JWK thumbprint so that a `jti` +/// collision between two distinct keys/clients cannot false-positive as a +/// replay — a true replay reuses the same proof key. `thumbprint` is base64url +/// (no `:`), so the join is unambiguous. +fn check_and_record_jti( + thumbprint: &str, + jti: &str, + expires_at: u64, + now: u64, +) -> Result<(), AppError> { + let key = format!("{thumbprint}:{jti}"); let mut seen = DPOP_JTI_SEEN.lock().unwrap_or_else(|e| e.into_inner()); - if seen.get(jti).is_some_and(|&exp| exp > now) { + if seen.get(&key).is_some_and(|&exp| exp > now) { return Err(AppError::Auth("DPoP proof replay detected".into())); } // Bound memory: drop entries past their horizon once the map grows large. if seen.len() > 10_000 { seen.retain(|_, &mut exp| exp > now); } - seen.insert(jti.to_string(), expires_at); + seen.insert(key, expires_at); Ok(()) } @@ -172,6 +183,7 @@ pub fn validate_dpop_proof( // Remember the `jti` until its `iat` falls outside the past tolerance (after // which the `iat` check alone would reject a replay). check_and_record_jti( + &proof_thumbprint, &payload.jti, payload.iat + DPOP_IAT_PAST_TOLERANCE_SECS, now, @@ -256,17 +268,27 @@ mod tests { fn check_and_record_jti_rejects_replay_within_window() { // Unique jti per test to stay independent of the shared cache. let jti = "m13-unit-replay"; - assert!(check_and_record_jti(jti, 1300, 1000).is_ok()); + let tp = "m13-unit-tp"; + assert!(check_and_record_jti(tp, jti, 1300, 1000).is_ok()); // Same jti again while still within its window → replay. - assert!(check_and_record_jti(jti, 1300, 1000).is_err()); + assert!(check_and_record_jti(tp, jti, 1300, 1000).is_err()); // Once past the horizon it is accepted again. - assert!(check_and_record_jti(jti, 1700, 1400).is_ok()); + assert!(check_and_record_jti(tp, jti, 1700, 1400).is_ok()); } #[test] fn check_and_record_jti_allows_distinct_jtis() { - assert!(check_and_record_jti("m13-unit-distinct-a", 1300, 1000).is_ok()); - assert!(check_and_record_jti("m13-unit-distinct-b", 1300, 1000).is_ok()); + let tp = "m13-unit-distinct-tp"; + assert!(check_and_record_jti(tp, "m13-unit-distinct-a", 1300, 1000).is_ok()); + assert!(check_and_record_jti(tp, "m13-unit-distinct-b", 1300, 1000).is_ok()); + } + + #[test] + fn check_and_record_jti_scopes_by_thumbprint() { + // Same jti under two different thumbprints must not collide as a replay. + let jti = "m13-unit-shared-jti"; + assert!(check_and_record_jti("m13-tp-alpha", jti, 1300, 1000).is_ok()); + assert!(check_and_record_jti("m13-tp-beta", jti, 1300, 1000).is_ok()); } #[test] diff --git a/src/spaces/simplespace.rs b/src/spaces/simplespace.rs index 55c5c25..8b7c8f5 100644 --- a/src/spaces/simplespace.rs +++ b/src/spaces/simplespace.rs @@ -416,18 +416,21 @@ async fn remove_member( let space = resolve_space(&state, &input.space).await?; require_space_admin(&state, &space, claims.did()).await?; + // Revoke any outstanding space credentials before removing the membership + // row. If revocation fails we bail out with the member still present, so a + // retry can complete both steps — the reverse order could leave a removed + // member holding valid credentials until their 2h TTL (M3). Revoking for a + // non-member is a harmless no-op, so the NotFound check still gates on the + // delete below. + db::revoke_space_credentials_for_member(&state.db, state.db_backend, &space.id, &input.did) + .await?; + let removed = db::remove_member(&state.db, state.db_backend, &space.id, &input.did).await?; if !removed { return Err(AppError::NotFound("Member not found in this space".into())); } - // Revoke any outstanding space credentials the removed member holds so their - // cross-service access ends immediately rather than lingering for the - // credential's 2h TTL (M3). - db::revoke_space_credentials_for_member(&state.db, state.db_backend, &space.id, &input.did) - .await?; - Ok(Json(serde_json::json!({ "success": true }))) } -- 2.51.2 From db6e1d5598c0876710910f14dcb0548e587c7d7b Mon Sep 17 00:00:00 2001 From: Trezy Date: Wed, 8 Jul 2026 12:34:36 -0500 Subject: [PATCH 11/14] ci: run e2e as root in CI Signed-off-by: Trezy --- docker-compose.e2e.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docker-compose.e2e.yml b/docker-compose.e2e.yml index 8135487..6dc3cec 100644 --- a/docker-compose.e2e.yml +++ b/docker-compose.e2e.yml @@ -63,6 +63,10 @@ services: build: context: . dockerfile: Dockerfile + # The image runs as the non-root `app` user, but the e2e entrypoint needs + # root to read Caddy's root-owned CA and install it into the trust store. It + # drops back to `app` before launching the server. + user: root entrypoint: ["/bin/sh", "/e2e-entrypoint.sh"] environment: DATABASE_URL: postgres://happyview:happyview@postgres:5432/happyview_test -- 2.51.2 From 862b36dcf7a2fd8fa4acb4cc45b55e1033d1344d Mon Sep 17 00:00:00 2001 From: Trezy Date: Wed, 8 Jul 2026 12:34:36 -0500 Subject: [PATCH 12/14] fix: update deps Signed-off-by: Trezy --- .cargo/audit.toml | 22 + .github/workflows/ci.yml | 18 + Cargo.lock | 1743 +++++++++++++---------------------- Cargo.toml | 3 +- scripts/e2e-entrypoint.sh | 13 +- src/plugin/encryption.rs | 10 +- src/verification_methods.rs | 2 +- 7 files changed, 691 insertions(+), 1120 deletions(-) create mode 100644 .cargo/audit.toml diff --git a/.cargo/audit.toml b/.cargo/audit.toml new file mode 100644 index 0000000..d8fc779 --- /dev/null +++ b/.cargo/audit.toml @@ -0,0 +1,22 @@ +# cargo-audit configuration. +# +# Each ignored advisory below has been triaged and is either unreachable in our +# build, has no upstream fix, or the fix is a deferred breaking migration. Every +# other advisory must fail CI (see .github/workflows/ci.yml `audit` job) so new +# ones are caught. Re-review this list when dependencies are updated. +[advisories] +ignore = [ + # rsa (Marvin timing side-channel). Pulled in ONLY by sqlx-mysql, an optional + # sqlx dependency that is NOT enabled — `cargo tree` confirms rsa is never in + # the build graph, so it is never compiled or linked. No upstream fix exists. + "RUSTSEC-2023-0071", + # hickory-proto: no fixed upstream release is available. + "RUSTSEC-2026-0118", + # hickory-proto: fixed in hickory-resolver 0.26, but that removes the + # `txt_lookup` API and requires an (untested-in-CI) rewrite of DNS handle + # resolution. Deferred; revisit with the hickory 0.26 upgrade. + "RUSTSEC-2026-0119", + # fxhash: unmaintained (warning, not a vulnerability). Transitive dependency + # of wasmtime (via fxprof-processed-profile); not removable independently. + "RUSTSEC-2025-0057", +] diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0acf11d..8dd3f70 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -233,6 +233,24 @@ jobs: - name: Clippy run: cargo clippy --all-targets -- -D warnings + audit: + needs: changes + if: always() && (needs.changes.outputs.server == 'true' || (github.event_name == 'workflow_dispatch' && inputs.server)) + runs-on: depot-ubuntu-24.04 + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Install cargo-audit + uses: taiki-e/install-action@v2 + with: + tool: cargo-audit + + # Fails on any advisory not triaged in .cargo/audit.toml, so newly + # disclosed vulnerabilities in our dependencies are caught. + - name: Audit dependencies + run: cargo audit + playwright: needs: [changes, frontend, build-server] if: >- diff --git a/Cargo.lock b/Cargo.lock index c1db34b..10ea568 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 4 [[package]] name = "addr2line" -version = "0.24.2" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" dependencies = [ "gimli", ] @@ -52,18 +52,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "ahash" -version = "0.8.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy", -] - [[package]] name = "aho-corasick" version = "1.1.4" @@ -79,12 +67,6 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" -[[package]] -name = "ambient-authority" -version = "0.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9d4ee0d472d1cd2e28c97dfa124b3d8d992e10eb0a035f33f5d12e3a177ba3b" - [[package]] name = "android_system_properties" version = "0.1.5" @@ -96,17 +78,17 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.101" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e0fee31ef5ed1ba1316088939cea399010ed7731dba877ed44aeb407a75ea" +checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3" [[package]] name = "ar_archive_writer" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb93bbb63b9c227414f6eb3a0adfddca591a8ce1e9b60661bb08969b87e340b" +checksum = "4087686b4b0a3427190bae57a1d9a478dbb2d40c5dc1bd6e2b6d797913bdd348" dependencies = [ - "object 0.37.3", + "object", ] [[package]] @@ -117,9 +99,9 @@ checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" [[package]] name = "arc-swap" -version = "1.8.2" +version = "1.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9f3647c145568cec02c42054e07bdf9a5a698e15b466fb2341bfc393cd24aa5" +checksum = "c049c0be4daef0b145cb3555416b3b8ef5b7888a38aea1a3a155801fe7b0810b" dependencies = [ "rustversion", ] @@ -132,9 +114,9 @@ checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" [[package]] name = "arrayvec" -version = "0.7.7" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f02882884d3e1bc524fb12c79f107f6ad0e1cfd498c536ffb494301740995dfe" +checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56" [[package]] name = "assert-json-diff" @@ -148,9 +130,9 @@ dependencies = [ [[package]] name = "async-compression" -version = "0.4.41" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0f9ee0f6e02ffd7ad5816e9464499fba7b3effd01123b515c41d1697c43dad1" +checksum = "e79b3f8a79cccc2898f31920fc69f304859b3bd567490f75ebf51ae1c792a9ac" dependencies = [ "compression-codecs", "compression-core", @@ -219,9 +201,9 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "atrium-api" -version = "0.25.7" +version = "0.25.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f182d9437cd447ed87eca75540151653e332d6753a2a4749d72c0f15aa1f179" +checksum = "e04c38c6bfc922a7950a13ad52f8d21bee77020b90e822364c7ec8625c4cd403" dependencies = [ "atrium-common", "atrium-xrpc", @@ -240,9 +222,9 @@ dependencies = [ [[package]] name = "atrium-common" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eff94b4ce3e9ba11d8bda83674e75ccaca281d5251ec3816d03e6bb23583ff4f" +checksum = "98466259d2e6189ddf3439b96432d5303668b4d51c2a78996934d981065550f3" dependencies = [ "dashmap", "lru", @@ -255,9 +237,9 @@ dependencies = [ [[package]] name = "atrium-identity" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e7cfd14c15bda5087b340a4a8825a7315bbf06a4f879a02186f10481e8a22a6" +checksum = "c11c7225bc15376200cbb81fb9c91a9ce8000edac76484dc636cca2ec200f673" dependencies = [ "atrium-api", "atrium-common", @@ -271,15 +253,15 @@ dependencies = [ [[package]] name = "atrium-oauth" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0189ceacad86c3f19e79a548e75897d95d33286857d9f692d83cf9b094cf83d" +checksum = "8d027eb47a804181f5a0632cf0af816227a89a64aa0c1ac99e92e999dcc4939b" dependencies = [ "atrium-api", "atrium-common", "atrium-identity", "atrium-xrpc", - "base64 0.22.1", + "base64", "chrono", "dashmap", "ecdsa", @@ -287,7 +269,7 @@ dependencies = [ "jose-jwa", "jose-jwk", "p256", - "rand 0.8.5", + "rand 0.8.6", "reqwest", "serde", "serde_html_form", @@ -314,15 +296,15 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" [[package]] name = "aws-lc-rs" -version = "1.16.1" +version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94bffc006df10ac2a68c83692d734a465f8ee6c5b384d8545a636f81d858f4bf" +checksum = "4342d8937fc7e5dd9b1c60292261c0670c882a2cd1719cfc11b1af41731e32ad" dependencies = [ "aws-lc-sys", "zeroize", @@ -330,21 +312,22 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.38.0" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4321e568ed89bb5a7d291a7f37997c2c0df89809d7b6d12062c81ddb54aa782e" +checksum = "6d9ceb1da931507a12f4fccea479dccd00da1943e1b4ae72d8e502d707361444" dependencies = [ "cc", "cmake", "dunce", "fs_extra", + "pkg-config", ] [[package]] name = "axum" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b52af3cb4058c895d37317bb27508dccc8e5f2d39454016b297bf4a400597b8" +checksum = "31b698c5f9a010f6573133b09e0de5408834d0c82f8d7475a89fc1867a71cd90" dependencies = [ "axum-core", "bytes", @@ -442,10 +425,10 @@ dependencies = [ ] [[package]] -name = "base64" -version = "0.21.7" +name = "base45" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +checksum = "240e56f4d3c453c36faacb695c535a4d5f8c7d23dac175014f32eb0a71012a03" [[package]] name = "base64" @@ -461,9 +444,9 @@ checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" [[package]] name = "bitflags" -version = "2.10.0" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" dependencies = [ "serde_core", ] @@ -493,19 +476,19 @@ dependencies = [ [[package]] name = "bstr" -version = "1.12.1" +version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" +checksum = "5cee35f73844aa3014bb606320a6c1f010249dbdf43342fe54b5a4f6a8ed4b79" dependencies = [ "memchr", - "serde", + "serde_core", ] [[package]] name = "bumpalo" -version = "3.19.1" +version = "3.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" dependencies = [ "allocator-api2", ] @@ -518,87 +501,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" - -[[package]] -name = "cap-fs-ext" -version = "3.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5528f85b1e134ae811704e41ef80930f56e795923f866813255bc342cc20654" -dependencies = [ - "cap-primitives", - "cap-std", - "io-lifetimes", - "windows-sys 0.59.0", -] - -[[package]] -name = "cap-net-ext" -version = "3.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20a158160765c6a7d0d8c072a53d772e4cb243f38b04bfcf6b4939cfbe7482e7" -dependencies = [ - "cap-primitives", - "cap-std", - "rustix 1.1.3", - "smallvec", -] - -[[package]] -name = "cap-primitives" -version = "3.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6cf3aea8a5081171859ef57bc1606b1df6999df4f1110f8eef68b30098d1d3a" -dependencies = [ - "ambient-authority", - "fs-set-times", - "io-extras", - "io-lifetimes", - "ipnet", - "maybe-owned", - "rustix 1.1.3", - "rustix-linux-procfs", - "windows-sys 0.59.0", - "winx", -] - -[[package]] -name = "cap-rand" -version = "3.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8144c22e24bbcf26ade86cb6501a0916c46b7e4787abdb0045a467eb1645a1d" -dependencies = [ - "ambient-authority", - "rand 0.8.5", -] - -[[package]] -name = "cap-std" -version = "3.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6dc3090992a735d23219de5c204927163d922f42f575a0189b005c62d37549a" -dependencies = [ - "cap-primitives", - "io-extras", - "io-lifetimes", - "rustix 1.1.3", -] - -[[package]] -name = "cap-time-ext" -version = "3.4.5" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "def102506ce40c11710a9b16e614af0cde8e76ae51b1f48c04b8d79f4b671a80" -dependencies = [ - "ambient-authority", - "cap-primitives", - "iana-time-zone", - "once_cell", - "rustix 1.1.3", - "winx", -] +checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" [[package]] name = "cbor4ii" @@ -611,9 +516,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.55" +version = "1.2.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47b26a0954ae34af09b50f0de26458fa95369a0d478d8236d3f93082b219bd29" +checksum = "f5d6cac793997bd970000024b2934968efe83b382de4fdcf4fcb46b6ee4ad996" dependencies = [ "find-msvc-tools", "jobserver", @@ -629,9 +534,9 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "chrono" -version = "0.4.43" +version = "0.4.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fac4744fb15ae8337dc853fee7fb3f4e48c0fbaa23d0afe49c447b4fab126118" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" dependencies = [ "iana-time-zone", "js-sys", @@ -670,11 +575,10 @@ dependencies = [ [[package]] name = "cid" -version = "0.11.1" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3147d8272e8fa0ccd29ce51194dd98f79ddfb8191ba9e3409884e751798acf3a" +checksum = "21a304f95f84d169a6f31c4d0a30d784643aaa0bbc9c1e449a2c23e963ec4971" dependencies = [ - "core2", "multibase", "multihash", "serde", @@ -694,9 +598,9 @@ dependencies = [ [[package]] name = "cmake" -version = "0.1.57" +version = "0.1.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d" +checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678" dependencies = [ "cc", ] @@ -712,9 +616,9 @@ dependencies = [ [[package]] name = "compression-codecs" -version = "0.4.37" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb7b51a7d9c967fc26773061ba86150f19c50c0d65c887cb1fbe295fd16619b7" +checksum = "ce2548391e9c1929c21bf6aa2680af86fe4c1b33e6cea9ac1cfeec0bd11218cf" dependencies = [ "compression-core", "flate2", @@ -723,9 +627,9 @@ dependencies = [ [[package]] name = "compression-core" -version = "0.4.31" +version = "0.4.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75984efb6ed102a0d42db99afb6c1948f0380d1d91808d5529916e6c08b49d8d" +checksum = "cc14f565cf027a105f7a44ccf9e5b424348421a1d8952a8fc9d499d313107789" [[package]] name = "concurrent-queue" @@ -760,11 +664,11 @@ version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" dependencies = [ - "base64 0.22.1", + "base64", "hkdf", "hmac", "percent-encoding", - "rand 0.8.5", + "rand 0.8.6", "sha2", "subtle", "time", @@ -782,19 +686,20 @@ dependencies = [ ] [[package]] -name = "core-foundation-sys" -version = "0.8.7" +name = "core-foundation" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] [[package]] -name = "core2" -version = "0.4.0" +name = "core-foundation-sys" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b49ba7ef1ad6107f8824dbe97de947cbaac53c44e7f9756a1fba0d37c1eec505" -dependencies = [ - "memchr", -] +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpp_demangle" @@ -823,20 +728,38 @@ dependencies = [ "libc", ] +[[package]] +name = "cranelift-assembler-x64" +version = "0.123.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cd990d8a6304475bbad64534a0d418f5572f44d5f011437e6b9f1ee7d5c2570" +dependencies = [ + "cranelift-assembler-x64-meta", +] + +[[package]] +name = "cranelift-assembler-x64-meta" +version = "0.123.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccabe4636007296721080e02d7dab46d4319638ec4e3f6f7402fcb46dc5122c6" +dependencies = [ + "cranelift-srcgen", +] + [[package]] name = "cranelift-bforest" -version = "0.116.1" +version = "0.123.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e15d04a0ce86cb36ead88ad68cf693ffd6cda47052b9e0ac114bc47fd9cd23c4" +checksum = "da7ed173c870c0aea202a9830880156905a028a88df076e35ce383a8acbf90a7" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-bitset" -version = "0.116.1" +version = "0.123.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c6e3969a7ce267259ce244b7867c5d3bc9e65b0a87e81039588dfdeaede9f34" +checksum = "800cc586df98b12c502e76707c96565e40629a5322eaa15aaa34ba05f5721e31" dependencies = [ "serde", "serde_derive", @@ -844,11 +767,12 @@ dependencies = [ [[package]] name = "cranelift-codegen" -version = "0.116.1" +version = "0.123.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c22032c4cb42558371cf516bb47f26cdad1819d3475c133e93c49f50ebf304e" +checksum = "ae93f863f9094ae34d2567f9edb0ae2c41d35228b286598354dd78b198868ebd" dependencies = [ "bumpalo", + "cranelift-assembler-x64", "cranelift-bforest", "cranelift-bitset", "cranelift-codegen-meta", @@ -857,44 +781,50 @@ dependencies = [ "cranelift-entity", "cranelift-isle", "gimli", - "hashbrown 0.14.5", + "hashbrown 0.15.5", "log", + "pulley-interpreter", "regalloc2", "rustc-hash", "serde", "smallvec", "target-lexicon", + "wasmtime-internal-math", ] [[package]] name = "cranelift-codegen-meta" -version = "0.116.1" +version = "0.123.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c904bc71c61b27fc57827f4a1379f29de64fe95653b620a3db77d59655eee0b8" +checksum = "38c505162bcf77dcb859905b3eac56a1917fc3cf326424fb06e7732031e3a8ae" dependencies = [ + "cranelift-assembler-x64-meta", "cranelift-codegen-shared", + "cranelift-srcgen", + "heck", + "pulley-interpreter", ] [[package]] name = "cranelift-codegen-shared" -version = "0.116.1" +version = "0.123.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40180f5497572f644ce88c255480981ae2ec1d7bb4d8e0c0136a13b87a2f2ceb" +checksum = "e3b786958bcb79bdb5fbae095af58f0c2da7d7895c475c991f6a6bb5a9c7e6d9" [[package]] name = "cranelift-control" -version = "0.116.1" +version = "0.123.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d132c6d0bd8a489563472afc171759da0707804a65ece7ceb15a8c6d7dd5ef" +checksum = "2faf9a5009bce7f725ce2af7a08c4883ebac6af933e7e0aa7d84f976f4e6deb5" dependencies = [ "arbitrary", ] [[package]] name = "cranelift-entity" -version = "0.116.1" +version = "0.123.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b2d0d9618275474fbf679dd018ac6e009acbd6ae6850f6a67be33fb3b00b323" +checksum = "017271194ba5e101d626560d0d6767efd341468d1ba0f4d015f19fe64020b65b" dependencies = [ "cranelift-bitset", "serde", @@ -903,9 +833,9 @@ dependencies = [ [[package]] name = "cranelift-frontend" -version = "0.116.1" +version = "0.123.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fac41e16729107393174b0c9e3730fb072866100e1e64e80a1a963b2e484d57" +checksum = "f80847f0929967f0cec82f9e0543b3901e0f0063690405891f22107b5a130fd8" dependencies = [ "cranelift-codegen", "log", @@ -915,21 +845,27 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.116.1" +version = "0.123.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ca20d576e5070044d0a72a9effc2deacf4d6aa650403189d8ea50126483944d" +checksum = "75904abbc0e7b46d20f7a49c8042c8a4481c0db4253b99889c723c566295d506" [[package]] name = "cranelift-native" -version = "0.116.1" +version = "0.123.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8dee82f3f1f2c4cba9177f1cc5e350fe98764379bcd29340caa7b01f85076c7" +checksum = "6e0135923540574362e16f01bf40000664263840991039ff3041ba717de6cf3a" dependencies = [ "cranelift-codegen", "libc", "target-lexicon", ] +[[package]] +name = "cranelift-srcgen" +version = "0.123.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fb12f76c482e034f6ebefa843c914e74112f088215d8d36d33a649f9fab99b" + [[package]] name = "crc" version = "3.4.0" @@ -941,9 +877,9 @@ dependencies = [ [[package]] name = "crc-catalog" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" +checksum = "217698eaf96b4a3f0bc4f3662aaa55bdf913cd54d7204591faa790070c6d0853" [[package]] name = "crc32fast" @@ -962,18 +898,18 @@ checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" [[package]] name = "crossbeam-channel" -version = "0.5.15" +version = "0.5.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +checksum = "d85363c37faeca707aef026efa9f3b34d077bce547e48f770770625c6013679e" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-deque" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +checksum = "5181e0de7b61eb03a81e347d6dd8797bae9da5146707b51077e2d71a54ec0ceb" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -981,27 +917,27 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.18" +version = "0.9.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +checksum = "2d6914041f254d6e9176c01941b21115dcfb7089e55135a35411081bd106ef3f" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-queue" -version = "0.3.12" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" +checksum = "803d13fb3b09d88be9f4dbc29062c66b19bf7170867ceb746d2a8689bf6c7a26" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.21" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17" [[package]] name = "crunchy" @@ -1023,9 +959,9 @@ dependencies = [ [[package]] name = "crypto-common" -version = "0.1.7" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", "rand_core 0.6.4", @@ -1043,9 +979,9 @@ dependencies = [ [[package]] name = "dashmap" -version = "6.1.0" +version = "6.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" +checksum = "e6361d5c062261c78a176addb82d4c821ae42bed6089de0e12603cd25de2059c" dependencies = [ "cfg-if", "crossbeam-utils", @@ -1057,15 +993,15 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.10.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" +checksum = "a4ae5f15dda3c708c0ade84bfee31ccab44a3da4f88015ed22f63732abe300c8" [[package]] name = "data-encoding-macro" -version = "0.1.19" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8142a83c17aa9461d637e649271eae18bf2edd00e91f2e105df36c3c16355bdb" +checksum = "3259c913752a86488b501ed8680446a5ed2d5aeac6e596cb23ba3800768ea32c" dependencies = [ "data-encoding", "data-encoding-macro-internal", @@ -1073,9 +1009,9 @@ dependencies = [ [[package]] name = "data-encoding-macro-internal" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ab67060fc6b8ef687992d439ca0fa36e7ed17e9a0b16b25b601e8757df720de" +checksum = "ccc2776f0c61eca1ca32528f85548abd1a4be8fb53d1b21c013e4f18da1e7090" dependencies = [ "data-encoding", "syn", @@ -1121,12 +1057,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.5.6" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc3dc5ad92c2e2d1c193bbbbdf2ea477cb81331de4f3103f267ca18368b988c4" -dependencies = [ - "powerfmt", -] +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" [[package]] name = "digest" @@ -1150,26 +1083,6 @@ dependencies = [ "dirs-sys-next", ] -[[package]] -name = "dirs" -version = "4.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" -dependencies = [ - "dirs-sys", -] - -[[package]] -name = "dirs-sys" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" -dependencies = [ - "libc", - "redox_users", - "winapi", -] - [[package]] name = "dirs-sys-next" version = "0.1.2" @@ -1183,9 +1096,9 @@ dependencies = [ [[package]] name = "displaydoc" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f" dependencies = [ "proc-macro2", "quote", @@ -1220,9 +1133,9 @@ dependencies = [ [[package]] name = "either" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" dependencies = [ "serde", ] @@ -1280,12 +1193,6 @@ dependencies = [ "syn", ] -[[package]] -name = "env_home" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7f84e12ccf0a7ddc17a6c41c93326024c42920d7ee630d04950e6926645c0fe" - [[package]] name = "equivalent" version = "1.0.2" @@ -1294,9 +1201,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "erased-serde" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89e8918065695684b2b0702da20382d5ae6065cf3327bc2d6436bd49a71ce9f3" +checksum = "d2add8a07dd6a8d93ff627029c51de145e12686fbc36ecb298ac22e74cf02dec" dependencies = [ "serde", "serde_core", @@ -1353,20 +1260,9 @@ checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" [[package]] name = "fastrand" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" - -[[package]] -name = "fd-lock" -version = "4.0.4" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce92ff622d6dadf7349484f42c93271a0d49b7cc4d466a936405bacbe10aa78" -dependencies = [ - "cfg-if", - "rustix 1.1.3", - "windows-sys 0.59.0", -] +checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" [[package]] name = "ff" @@ -1417,6 +1313,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + [[package]] name = "foreign-types" version = "0.3.2" @@ -1441,17 +1343,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "fs-set-times" -version = "0.20.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94e7099f6313ecacbe1256e8ff9d617b75d1bcb16a6fddef94866d225a01a14a" -dependencies = [ - "io-lifetimes", - "rustix 1.1.3", - "windows-sys 0.59.0", -] - [[package]] name = "fs_extra" version = "1.3.0" @@ -1460,9 +1351,9 @@ checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" [[package]] name = "futures" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" dependencies = [ "futures-channel", "futures-core", @@ -1475,9 +1366,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" dependencies = [ "futures-core", "futures-sink", @@ -1485,15 +1376,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" [[package]] name = "futures-executor" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" dependencies = [ "futures-core", "futures-task", @@ -1513,15 +1404,15 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" [[package]] name = "futures-macro" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" dependencies = [ "proc-macro2", "quote", @@ -1530,21 +1421,21 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" [[package]] name = "futures-task" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" [[package]] name = "futures-util" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ "futures-channel", "futures-core", @@ -1554,7 +1445,6 @@ dependencies = [ "futures-task", "memchr", "pin-project-lite", - "pin-utils", "slab", ] @@ -1582,9 +1472,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.7" +version = "0.14.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" dependencies = [ "typenum", "version_check", @@ -1612,21 +1502,19 @@ checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", "libc", - "r-efi", + "r-efi 5.3.0", "wasip2", ] [[package]] name = "getrandom" -version = "0.4.1" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" dependencies = [ "cfg-if", "libc", - "r-efi", - "wasip2", - "wasip3", + "r-efi 6.0.0", ] [[package]] @@ -1641,9 +1529,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.31.1" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" dependencies = [ "fallible-iterator", "indexmap", @@ -1663,9 +1551,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.13" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54" +checksum = "6cb093c84e8bd9b188d4c4a8cb6579fc016968d14c99882163cd3ff402a4f155" dependencies = [ "atomic-waker", "bytes", @@ -1706,7 +1594,7 @@ dependencies = [ "atrium-xrpc", "axum", "axum-extra", - "base64 0.22.1", + "base64", "blake3", "bytes", "chrono", @@ -1729,7 +1617,7 @@ dependencies = [ "mlua", "multibase", "p256", - "rand 0.9.2", + "rand 0.9.4", "rcgen", "regex", "reqwest", @@ -1753,7 +1641,6 @@ dependencies = [ "urlencoding", "uuid", "wasmtime", - "wasmtime-wasi", "webpki-roots 0.26.11", "wiremock", ] @@ -1763,9 +1650,6 @@ name = "hashbrown" version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" -dependencies = [ - "ahash", -] [[package]] name = "hashbrown" @@ -1775,7 +1659,7 @@ checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ "allocator-api2", "equivalent", - "foldhash", + "foldhash 0.1.5", "serde", ] @@ -1784,6 +1668,17 @@ name = "hashbrown" version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.2.0", +] + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" [[package]] name = "hashlink" @@ -1828,7 +1723,7 @@ dependencies = [ "idna", "ipnet", "once_cell", - "rand 0.9.2", + "rand 0.9.4", "ring", "thiserror 2.0.18", "tinyvec", @@ -1850,7 +1745,7 @@ dependencies = [ "moka", "once_cell", "parking_lot", - "rand 0.9.2", + "rand 0.9.4", "resolv-conf", "smallvec", "thiserror 2.0.18", @@ -1887,9 +1782,9 @@ dependencies = [ [[package]] name = "http" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +checksum = "6970f50e31d6fc17d3fa27329444bfa74e196cf62e95052a3f6fee181dba6425" dependencies = [ "bytes", "itoa", @@ -1938,9 +1833,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "1.8.1" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" +checksum = "55281c53a1894c864990125767da440a4e630446785086f52523b20033b74498" dependencies = [ "atomic-waker", "bytes", @@ -1953,7 +1848,6 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "pin-utils", "smallvec", "tokio", "want", @@ -1961,15 +1855,14 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.7" +version = "0.27.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" +checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f" dependencies = [ "http", "hyper", "hyper-util", "rustls", - "rustls-pki-types", "tokio", "tokio-rustls", "tower-service", @@ -1997,7 +1890,7 @@ version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" dependencies = [ - "base64 0.22.1", + "base64", "bytes", "futures-channel", "futures-util", @@ -2008,7 +1901,7 @@ dependencies = [ "libc", "percent-encoding", "pin-project-lite", - "socket2 0.6.2", + "socket2", "system-configuration", "tokio", "tower-service", @@ -2042,12 +1935,13 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" dependencies = [ "displaydoc", "potential_utf", + "utf8_iter", "yoke", "zerofrom", "zerovec", @@ -2055,9 +1949,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" dependencies = [ "displaydoc", "litemap", @@ -2068,9 +1962,9 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" dependencies = [ "icu_collections", "icu_normalizer_data", @@ -2082,15 +1976,15 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" +checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" [[package]] name = "icu_properties" -version = "2.1.2" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" +checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" dependencies = [ "icu_collections", "icu_locale_core", @@ -2102,15 +1996,15 @@ dependencies = [ [[package]] name = "icu_properties_data" -version = "2.1.2" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" +checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" [[package]] name = "icu_provider" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" dependencies = [ "displaydoc", "icu_locale_core", @@ -2140,9 +2034,9 @@ dependencies = [ [[package]] name = "idna_adapter" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" dependencies = [ "icu_normalizer", "icu_properties", @@ -2150,12 +2044,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.13.0" +version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" dependencies = [ "equivalent", - "hashbrown 0.16.1", + "hashbrown 0.17.1", "serde", "serde_core", ] @@ -2169,32 +2063,17 @@ dependencies = [ "generic-array", ] -[[package]] -name = "io-extras" -version = "0.18.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2285ddfe3054097ef4b2fe909ef8c3bcd1ea52a8f0d274416caebeef39f04a65" -dependencies = [ - "io-lifetimes", - "windows-sys 0.59.0", -] - -[[package]] -name = "io-lifetimes" -version = "2.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06432fb54d3be7964ecd3649233cddf80db2832f47fec34c01f65b3d9d774983" - [[package]] name = "ipconfig" -version = "0.3.2" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" +checksum = "4d40460c0ce33d6ce4b0630ad68ff63d6661961c48b6dba35e5a4d81cfb48222" dependencies = [ - "socket2 0.5.10", + "socket2", "widestring", - "windows-sys 0.48.0", - "winreg", + "windows-registry", + "windows-result", + "windows-sys 0.61.2", ] [[package]] @@ -2210,34 +2089,24 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.11.0" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" - -[[package]] -name = "iri-string" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a" -dependencies = [ - "memchr", - "serde", -] +checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" [[package]] name = "itertools" -version = "0.12.1" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" dependencies = [ "either", ] [[package]] name = "itoa" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "ittapi" @@ -2261,11 +2130,11 @@ dependencies = [ [[package]] name = "jobserver" -version = "0.1.34" +version = "0.1.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +checksum = "1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3" dependencies = [ - "getrandom 0.3.4", + "getrandom 0.4.3", "libc", ] @@ -2305,11 +2174,12 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.85" +version = "0.3.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" +checksum = "53b44bfcdb3f8d5837a46dae1ca9660a837176eee74a28b229bc626816589102" dependencies = [ - "once_cell", + "cfg-if", + "futures-util", "wasm-bindgen", ] @@ -2319,7 +2189,7 @@ version = "9.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a87cc7a48537badeae96744432de36f4be2b4a34a05a5ef32e9dd8a1c169dde" dependencies = [ - "base64 0.22.1", + "base64", "js-sys", "pem", "ring", @@ -2360,12 +2230,6 @@ dependencies = [ "spin", ] -[[package]] -name = "leb128" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" - [[package]] name = "leb128fmt" version = "0.1.0" @@ -2374,9 +2238,9 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "libc" -version = "0.2.181" +version = "0.2.186" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "459427e2af2b9c839b132acb702a1c654d95e10f8c326bfc2ad11310e458b1c5" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" [[package]] name = "libm" @@ -2386,13 +2250,14 @@ checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] name = "libredox" -version = "0.1.12" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" +checksum = "c943259e342f1e06ff2da7a83eabdfe7f92ce10262688dbf1895ff0b3e6e4652" dependencies = [ "bitflags", "libc", - "redox_syscall 0.7.1", + "plain", + "redox_syscall 0.9.0", ] [[package]] @@ -2408,21 +2273,15 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.4.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" - -[[package]] -name = "linux-raw-sys" -version = "0.11.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" [[package]] name = "litemap" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" [[package]] name = "lock_api" @@ -2435,17 +2294,17 @@ dependencies = [ [[package]] name = "log" -version = "0.4.29" +version = "0.4.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" [[package]] name = "lru" -version = "0.12.5" +version = "0.16.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" +checksum = "7f66e8d5d03f609abc3a39e6f08e4164ebf1447a732906d39eb9b99b7919ef39" dependencies = [ - "hashbrown 0.15.5", + "hashbrown 0.16.1", ] [[package]] @@ -2502,12 +2361,6 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" -[[package]] -name = "maybe-owned" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4facc753ae494aeb6e3c22f839b158aebd4f9270f55cd3c79906c45476c47ab4" - [[package]] name = "md-5" version = "0.10.6" @@ -2520,9 +2373,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.8.0" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" [[package]] name = "memfd" @@ -2530,7 +2383,7 @@ version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad38eb12aea514a0466ea40a80fd8cc83637065948eb4a426e4aa46261175227" dependencies = [ - "rustix 1.1.3", + "rustix", ] [[package]] @@ -2561,9 +2414,9 @@ dependencies = [ [[package]] name = "mio" -version = "1.1.1" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" +checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda" dependencies = [ "libc", "wasi", @@ -2606,9 +2459,9 @@ dependencies = [ [[package]] name = "moka" -version = "0.12.13" +version = "0.12.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ac832c50ced444ef6be0767a008b02c106a909ba79d1d830501e94b96f6b7e" +checksum = "957228ad12042ee839f93c8f257b62b4c0ab5eaae1d4fa60de53b27c9d7c5046" dependencies = [ "async-lock", "crossbeam-channel", @@ -2643,32 +2496,32 @@ dependencies = [ [[package]] name = "multibase" -version = "0.9.2" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8694bb4835f452b0e3bb06dbebb1d6fc5385b6ca1caf2e55fd165c042390ec77" +checksum = "7e0e4a371cbf1dfd666b658ba137763edb23c45beb43cfe369b5593cd6b437b6" dependencies = [ "base-x", "base256emoji", + "base45", "data-encoding", "data-encoding-macro", ] [[package]] name = "multihash" -version = "0.19.3" +version = "0.19.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b430e7953c29dd6a09afc29ff0bb69c6e306329ee6794700aee27b76a1aea8d" +checksum = "577c63b00ad74d57e8c9aa870b5fccebf2fd64a308a5aee9f1bb88e4aea19447" dependencies = [ - "core2", "serde", "unsigned-varint", ] [[package]] name = "native-tls" -version = "0.2.14" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" +checksum = "465500e14ea162429d264d44189adc38b199b62b1c21eea9f69e4b73cb03bbf2" dependencies = [ "libc", "log", @@ -2692,9 +2545,9 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.6" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +checksum = "c89e69e7e0f03bea5ef08013795c25018e101932225a656383bd384495ecc367" dependencies = [ "num-integer", "num-traits", @@ -2711,16 +2564,16 @@ dependencies = [ "num-integer", "num-iter", "num-traits", - "rand 0.8.5", + "rand 0.8.6", "smallvec", "zeroize", ] [[package]] name = "num-conv" -version = "0.2.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" [[package]] name = "num-integer" @@ -2733,11 +2586,10 @@ dependencies = [ [[package]] name = "num-iter" -version = "0.1.45" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +checksum = "c92800bd69a1eac91786bcfe9da64a897eb72911b8dc3095decbd07429e8048b" dependencies = [ - "autocfg", "num-integer", "num-traits", ] @@ -2764,9 +2616,9 @@ dependencies = [ [[package]] name = "object" -version = "0.36.7" +version = "0.37.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" dependencies = [ "crc32fast", "hashbrown 0.15.5", @@ -2774,20 +2626,11 @@ dependencies = [ "memchr", ] -[[package]] -name = "object" -version = "0.37.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" -dependencies = [ - "memchr", -] - [[package]] name = "once_cell" -version = "1.21.3" +version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" dependencies = [ "critical-section", "portable-atomic", @@ -2801,15 +2644,14 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "openssl" -version = "0.10.75" +version = "0.10.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" +checksum = "77823a27f0babb03091cb9ed9ef80af3b39dbc82f97e8fa530374b7dafd87a45" dependencies = [ "bitflags", "cfg-if", "foreign-types", "libc", - "once_cell", "openssl-macros", "openssl-sys", ] @@ -2827,15 +2669,15 @@ dependencies = [ [[package]] name = "openssl-probe" -version = "0.1.6" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" [[package]] name = "openssl-sys" -version = "0.9.111" +version = "0.9.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321" +checksum = "b47e7e6bb2c38cd930d25a23b40fa52e068c10e85f3e03a7f5ba5aaca5713695" dependencies = [ "cc", "libc", @@ -2894,18 +2736,12 @@ dependencies = [ ] [[package]] -name = "paste" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" - -[[package]] -name = "pem" -version = "3.0.6" +name = "pem" +version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be" dependencies = [ - "base64 0.22.1", + "base64", "serde_core", ] @@ -2926,15 +2762,9 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pin-project-lite" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" - -[[package]] -name = "pin-utils" -version = "0.1.0" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] name = "pkcs1" @@ -2959,9 +2789,15 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" + +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" [[package]] name = "polyval" @@ -2995,9 +2831,9 @@ dependencies = [ [[package]] name = "potential_utf" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" dependencies = [ "zerovec", ] @@ -3017,16 +2853,6 @@ dependencies = [ "zerocopy", ] -[[package]] -name = "prettyplease" -version = "0.2.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" -dependencies = [ - "proc-macro2", - "syn", -] - [[package]] name = "primeorder" version = "0.13.6" @@ -3047,9 +2873,9 @@ dependencies = [ [[package]] name = "psm" -version = "0.1.30" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3852766467df634d74f0b2d7819bf8dc483a0eb2e3b0f50f756f9cfe8b0d18d8" +checksum = "645dbe486e346d9b5de3ef16ede18c26e6c70ad97418f4874b8b1889d6e761ea" dependencies = [ "ar_archive_writer", "cc", @@ -3057,21 +2883,32 @@ dependencies = [ [[package]] name = "pulley-interpreter" -version = "29.0.1" +version = "36.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62d95f8575df49a2708398182f49a888cf9dc30210fb1fd2df87c889edcee75d" +checksum = "558181096e0df4984f45cfc3a7087052df4a61c36089b135a08ceca9cbd352fb" dependencies = [ "cranelift-bitset", "log", - "sptr", - "wasmtime-math", + "pulley-macros", + "wasmtime-internal-math", +] + +[[package]] +name = "pulley-macros" +version = "36.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5d52e2f14e168d75cdabe9bd5fb1ff18a1b119dc6699684aee895dbc3524da9" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] name = "quote" -version = "1.0.44" +version = "1.0.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" +checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368" dependencies = [ "proc-macro2", ] @@ -3082,11 +2919,17 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + [[package]] name = "rand" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" dependencies = [ "libc", "rand_chacha 0.3.1", @@ -3095,9 +2938,9 @@ dependencies = [ [[package]] name = "rand" -version = "0.9.2" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" dependencies = [ "rand_chacha 0.9.0", "rand_core 0.9.5", @@ -3143,9 +2986,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" +checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d" dependencies = [ "either", "rayon-core", @@ -3205,9 +3048,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.7.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35985aa610addc02e24fc232012c86fd11f14111180f902b67e2d5331f8ebf2b" +checksum = "c5102a6aaa05aa011a238e178e6bca86d2cb56fc9f586d37cb80f5bca6e07759" dependencies = [ "bitflags", ] @@ -3225,9 +3068,9 @@ dependencies = [ [[package]] name = "regalloc2" -version = "0.11.2" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc06e6b318142614e4a48bc725abbf08ff166694835c43c9dae5a9009704639a" +checksum = "5216b1837de2149f8bc8e6d5f88a9326b63b8c836ed58ce4a0a29ec736a59734" dependencies = [ "allocator-api2", "bumpalo", @@ -3239,9 +3082,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.12.3" +version = "1.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +checksum = "f1292b7759ae1cb9ec195452d1390a074f0cd8541ab7a5a8c31cd6db45d4a6ba" dependencies = [ "aho-corasick", "memchr", @@ -3262,9 +3105,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.9" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a96887878f22d7bad8a3b6dc5b7440e0ada9a245242924394987b21cf2210a4c" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" [[package]] name = "reqwest" @@ -3272,7 +3115,7 @@ version = "0.12.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" dependencies = [ - "base64 0.22.1", + "base64", "bytes", "encoding_rs", "futures-core", @@ -3358,57 +3201,34 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d" +checksum = "b74b56ffa8bb2830709a538c2cbcae9aa062db0d2a42563bfb09bdaae44020eb" [[package]] name = "rustc-hash" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" - -[[package]] -name = "rustix" -version = "0.38.44" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" -dependencies = [ - "bitflags", - "errno", - "libc", - "linux-raw-sys 0.4.15", - "windows-sys 0.59.0", -] +checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" [[package]] name = "rustix" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ "bitflags", "errno", "libc", - "linux-raw-sys 0.11.0", + "linux-raw-sys", "windows-sys 0.61.2", ] -[[package]] -name = "rustix-linux-procfs" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fc84bf7e9aa16c4f2c758f27412dc9841341e16aa682d9c7ac308fe3ee12056" -dependencies = [ - "once_cell", - "rustix 1.1.3", -] - [[package]] name = "rustls" -version = "0.23.36" +version = "0.23.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c665f33d38cea657d9614f766881e4d510e0eda4239891eea56b4cadcf01801b" +checksum = "6b92b125634d9b795e7beca796cc790df15a7fb38323bf3196fda83292d06b1f" dependencies = [ "aws-lc-rs", "log", @@ -3422,18 +3242,18 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.14.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" +checksum = "764899a24af3980067ee14bc143654f297b22eaebfe3c7b6b211920a5a59b046" dependencies = [ "zeroize", ] [[package]] name = "rustls-webpki" -version = "0.103.9" +version = "0.103.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53" +checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" dependencies = [ "aws-lc-rs", "ring", @@ -3443,9 +3263,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" [[package]] name = "ryu" @@ -3453,20 +3273,11 @@ version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" -[[package]] -name = "scc" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46e6f046b7fef48e2660c57ed794263155d713de679057f2d0c169bfc6e756cc" -dependencies = [ - "sdd", -] - [[package]] name = "schannel" -version = "0.1.28" +version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" +checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" dependencies = [ "windows-sys 0.61.2", ] @@ -3477,12 +3288,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" -[[package]] -name = "sdd" -version = "3.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "490dcfcbfef26be6800d11870ff2df8774fa6e86d047e3e8c8a76b25655e41ca" - [[package]] name = "sec1" version = "0.7.3" @@ -3499,12 +3304,12 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.11.1" +version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" dependencies = [ "bitflags", - "core-foundation", + "core-foundation 0.10.1", "core-foundation-sys", "libc", "security-framework-sys", @@ -3512,9 +3317,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.15.0" +version = "2.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" dependencies = [ "core-foundation-sys", "libc", @@ -3522,9 +3327,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.27" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" dependencies = [ "serde", "serde_core", @@ -3607,9 +3412,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.149" +version = "1.0.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" dependencies = [ "itoa", "memchr", @@ -3652,24 +3457,23 @@ dependencies = [ [[package]] name = "serial_test" -version = "3.3.1" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d0b343e184fc3b7bb44dff0705fffcf4b3756ba6aff420dddd8b24ca145e555" +checksum = "699f4197115b8a7e7ff19c9a315a4bd6fffec26cc4626ef45ecaea389e081c6d" dependencies = [ "futures-executor", "futures-util", "log", "once_cell", "parking_lot", - "scc", "serial_test_derive", ] [[package]] name = "serial_test_derive" -version = "3.3.1" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f50427f258fb77356e4cd4aa0e87e2bd2c66dbcee41dc405282cae2bfc26c83" +checksum = "94e153fc76e1c6a068703d6d29c508a0b15c061c4b7e43da59cc097bc342673c" dependencies = [ "proc-macro2", "quote", @@ -3707,20 +3511,11 @@ dependencies = [ "lazy_static", ] -[[package]] -name = "shellexpand" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ccc8076840c4da029af4f87e4e8daeb0fca6b87bbb02e10cb60b791450e11e4" -dependencies = [ - "dirs", -] - [[package]] name = "shlex" -version = "1.3.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" [[package]] name = "signal-hook-registry" @@ -3744,15 +3539,15 @@ dependencies = [ [[package]] name = "simd-adler32" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" +checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" [[package]] name = "simple_asn1" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "297f631f50729c8c99b84667867963997ec0b50f32b2a7dbcab828ef0541e8bb" +checksum = "0d585997b0ac10be3c5ee635f1bab02d512760d14b7c468801ac8a01d9ae5f1d" dependencies = [ "num-bigint", "num-traits", @@ -3768,31 +3563,21 @@ checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "smallvec" -version = "1.15.1" +version = "1.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" dependencies = [ "serde", ] [[package]] name = "socket2" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "socket2" -version = "0.6.2" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0" +checksum = "52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -3814,12 +3599,6 @@ dependencies = [ "der", ] -[[package]] -name = "sptr" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b9b39299b249ad65f3b7e96443bad61c02ca5cd3589f46cb6d610a0fd6c0d6a" - [[package]] name = "sqlparser" version = "0.62.0" @@ -3849,7 +3628,7 @@ version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee6798b1838b6a0f69c007c133b8df5866302197e404e8b6ee8ed3e3a5e68dc6" dependencies = [ - "base64 0.22.1", + "base64", "bytes", "chrono", "crc", @@ -3925,7 +3704,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa003f0038df784eb8fecbbac13affe3da23b45194bd57dba231c8f48199c526" dependencies = [ "atoi", - "base64 0.22.1", + "base64", "bitflags", "byteorder", "bytes", @@ -3948,7 +3727,7 @@ dependencies = [ "memchr", "once_cell", "percent-encoding", - "rand 0.8.5", + "rand 0.8.6", "rsa", "serde", "sha1", @@ -3968,7 +3747,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db58fcd5a53cf07c184b154801ff91347e4c30d17a3562a635ff028ad5deda46" dependencies = [ "atoi", - "base64 0.22.1", + "base64", "bitflags", "byteorder", "chrono", @@ -3987,7 +3766,7 @@ dependencies = [ "md-5", "memchr", "once_cell", - "rand 0.8.5", + "rand 0.8.6", "serde", "serde_json", "sha2", @@ -4062,9 +3841,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.115" +version = "2.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e614ed320ac28113fa64972c4262d5dbc89deacdfd00c34a3e4cea073243c12" +checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422" dependencies = [ "proc-macro2", "quote", @@ -4098,7 +3877,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b" dependencies = [ "bitflags", - "core-foundation", + "core-foundation 0.9.4", "system-configuration-sys", ] @@ -4112,22 +3891,6 @@ dependencies = [ "libc", ] -[[package]] -name = "system-interface" -version = "0.27.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc4592f674ce18521c2a81483873a49596655b179f71c5e05d10c1fe66c78745" -dependencies = [ - "bitflags", - "cap-fs-ext", - "cap-std", - "fd-lock", - "io-lifetimes", - "rustix 0.38.44", - "windows-sys 0.59.0", - "winx", -] - [[package]] name = "tagptr" version = "0.2.0" @@ -4142,14 +3905,14 @@ checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca" [[package]] name = "tempfile" -version = "3.25.0" +version = "3.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0136791f7c95b1f6dd99f9cc786b91bb81c3800b639b3478e561ddb7be95e5f1" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" dependencies = [ "fastrand", - "getrandom 0.4.1", + "getrandom 0.4.3", "once_cell", - "rustix 1.1.3", + "rustix", "windows-sys 0.61.2", ] @@ -4213,12 +3976,11 @@ dependencies = [ [[package]] name = "time" -version = "0.3.47" +version = "0.3.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" +checksum = "18dfaaeddcb932337b5e7866ee7d0ce9b76d2fd092997146f187ec09b4558a50" dependencies = [ "deranged", - "itoa", "num-conv", "powerfmt", "serde_core", @@ -4228,15 +3990,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" +checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" [[package]] name = "time-macros" -version = "0.2.27" +version = "0.2.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" +checksum = "c431b87111666e491a90baa837f914fb45cd5dc3c268591b0220ff5057f2085f" dependencies = [ "num-conv", "time-core", @@ -4244,9 +4006,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" dependencies = [ "displaydoc", "zerovec", @@ -4254,9 +4016,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" +checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" dependencies = [ "tinyvec_macros", ] @@ -4269,9 +4031,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.49.0" +version = "1.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" +checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe" dependencies = [ "bytes", "libc", @@ -4279,16 +4041,16 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.6.2", + "socket2", "tokio-macros", "windows-sys 0.61.2", ] [[package]] name = "tokio-macros" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" +checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" dependencies = [ "proc-macro2", "quote", @@ -4414,9 +4176,9 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.6.8" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" +checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" dependencies = [ "async-compression", "bitflags", @@ -4428,7 +4190,6 @@ dependencies = [ "http-body-util", "http-range-header", "httpdate", - "iri-string", "mime", "mime_guess", "percent-encoding", @@ -4439,6 +4200,7 @@ dependencies = [ "tower-layer", "tower-service", "tracing", + "url", ] [[package]] @@ -4509,9 +4271,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.22" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" +checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" dependencies = [ "matchers", "nu-ansi-term", @@ -4556,7 +4318,7 @@ dependencies = [ "http", "httparse", "log", - "rand 0.9.2", + "rand 0.9.4", "rustls", "rustls-pki-types", "sha1", @@ -4572,9 +4334,9 @@ checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" [[package]] name = "typenum" -version = "1.19.0" +version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" [[package]] name = "unicase" @@ -4590,9 +4352,9 @@ checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" [[package]] name = "unicode-ident" -version = "1.0.23" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "537dd038a89878be9b64dd4bd1b260315c1bb94f4d784956b81e27a088d9a09e" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "unicode-normalization" @@ -4675,11 +4437,11 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "uuid" -version = "1.20.0" +version = "1.23.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee48d38b119b0cd71fe4141b30f5ba9c7c5d9f4e7a3a8b4a674e4b6ef789976f" +checksum = "bf80a72845275afea99e7f2b434723d3bc7e38470fcd1c7ed39a599c73319a53" dependencies = [ - "getrandom 0.3.4", + "getrandom 0.4.3", "js-sys", "wasm-bindgen", ] @@ -4719,18 +4481,9 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasip2" -version = "1.0.2+wasi-0.2.9" +version = "1.0.4+wasi-0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" -dependencies = [ - "wit-bindgen", -] - -[[package]] -name = "wasip3" -version = "0.4.0+wasi-0.3.0-rc-2026-01-06" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" dependencies = [ "wit-bindgen", ] @@ -4743,9 +4496,9 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.108" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" +checksum = "4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4" dependencies = [ "cfg-if", "once_cell", @@ -4756,23 +4509,19 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.58" +version = "0.4.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70a6e77fd0ae8029c9ea0063f87c46fde723e7d887703d74ad2616d792e51e6f" +checksum = "c62df1340f32221cb9c54d6a27b030e3dba64361d4a95bed55f9aacb44da291d" dependencies = [ - "cfg-if", - "futures-util", "js-sys", - "once_cell", "wasm-bindgen", - "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.108" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608" +checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -4780,9 +4529,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.108" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55" +checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e" dependencies = [ "bumpalo", "proc-macro2", @@ -4793,60 +4542,38 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.108" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12" +checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24" dependencies = [ "unicode-ident", ] [[package]] name = "wasm-encoder" -version = "0.221.3" +version = "0.236.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc8444fe4920de80a4fe5ab564fff2ae58b6b73166b89751f8c6c93509da32e5" -dependencies = [ - "leb128", - "wasmparser 0.221.3", -] - -[[package]] -name = "wasm-encoder" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +checksum = "724fccfd4f3c24b7e589d333fc0429c68042897a7e8a5f8694f31792471841e7" dependencies = [ "leb128fmt", - "wasmparser 0.244.0", + "wasmparser 0.236.1", ] [[package]] name = "wasm-encoder" -version = "0.245.1" +version = "0.253.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9dca005e69bf015e45577e415b9af8c67e8ee3c0e38b5b0add5aa92581ed5c" +checksum = "59972d6cd272259de647b7c1f1912e45e289c75ffd4be04e10695507cd7e1b59" dependencies = [ "leb128fmt", - "wasmparser 0.245.1", -] - -[[package]] -name = "wasm-metadata" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" -dependencies = [ - "anyhow", - "indexmap", - "wasm-encoder 0.244.0", - "wasmparser 0.244.0", + "wasmparser 0.253.0", ] [[package]] name = "wasmparser" -version = "0.221.3" +version = "0.236.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d06bfa36ab3ac2be0dee563380147a5b81ba10dd8885d7fbbc9eb574be67d185" +checksum = "a9b1e81f3eb254cf7404a82cee6926a4a3ccc5aad80cc3d43608a070c67aa1d7" dependencies = [ "bitflags", "hashbrown 0.15.5", @@ -4857,21 +4584,9 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.244.0" +version = "0.253.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" -dependencies = [ - "bitflags", - "hashbrown 0.15.5", - "indexmap", - "semver", -] - -[[package]] -name = "wasmparser" -version = "0.245.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f08c9adee0428b7bddf3890fc27e015ac4b761cc608c822667102b8bfd6995e" +checksum = "19db11f87d2486580e1e8b6f494c54df7e0566b87d0b599db843c24019667339" dependencies = [ "bitflags", "indexmap", @@ -4880,20 +4595,20 @@ dependencies = [ [[package]] name = "wasmprinter" -version = "0.221.3" +version = "0.236.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7343c42a97f2926c7819ff81b64012092ae954c5d83ddd30c9fcdefd97d0b283" +checksum = "2df225df06a6df15b46e3f73ca066ff92c2e023670969f7d50ce7d5e695abbb1" dependencies = [ "anyhow", "termcolor", - "wasmparser 0.221.3", + "wasmparser 0.236.1", ] [[package]] name = "wasmtime" -version = "29.0.1" +version = "36.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11976a250672556d1c4c04c6d5d7656ac9192ac9edc42a4587d6c21460010e69" +checksum = "4b4442dc12aa2473def8334f0e0f2b489be52c52507c938bbdc8be69ded4ded6" dependencies = [ "addr2line", "anyhow", @@ -4905,103 +4620,127 @@ dependencies = [ "encoding_rs", "fxprof-processed-profile", "gimli", - "hashbrown 0.14.5", + "hashbrown 0.15.5", "indexmap", "ittapi", "libc", "log", "mach2", "memfd", - "object 0.36.7", + "object", "once_cell", - "paste", "postcard", - "psm", "pulley-interpreter", "rayon", - "rustix 0.38.44", + "rustix", "semver", "serde", "serde_derive", "serde_json", "smallvec", - "sptr", "target-lexicon", - "trait-variant", - "wasm-encoder 0.221.3", - "wasmparser 0.221.3", - "wasmtime-asm-macros", - "wasmtime-cache", - "wasmtime-component-macro", - "wasmtime-component-util", - "wasmtime-cranelift", + "wasm-encoder 0.236.1", + "wasmparser 0.236.1", "wasmtime-environ", - "wasmtime-fiber", - "wasmtime-jit-debug", - "wasmtime-jit-icache-coherence", - "wasmtime-math", - "wasmtime-slab", - "wasmtime-versioned-export-macros", - "wasmtime-winch", + "wasmtime-internal-asm-macros", + "wasmtime-internal-cache", + "wasmtime-internal-component-macro", + "wasmtime-internal-component-util", + "wasmtime-internal-cranelift", + "wasmtime-internal-fiber", + "wasmtime-internal-jit-debug", + "wasmtime-internal-jit-icache-coherence", + "wasmtime-internal-math", + "wasmtime-internal-slab", + "wasmtime-internal-unwinder", + "wasmtime-internal-versioned-export-macros", + "wasmtime-internal-winch", "wat", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] -name = "wasmtime-asm-macros" -version = "29.0.1" +name = "wasmtime-environ" +version = "36.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f178b0d125201fbe9f75beaf849bd3e511891f9e45ba216a5b620802ccf64f2" +checksum = "5d881c3d6205898a226cc487b117f23b9ed1c7da39952d65bd5eeb6745b3789c" +dependencies = [ + "anyhow", + "cpp_demangle", + "cranelift-bitset", + "cranelift-entity", + "gimli", + "indexmap", + "log", + "object", + "postcard", + "rustc-demangle", + "semver", + "serde", + "serde_derive", + "smallvec", + "target-lexicon", + "wasm-encoder 0.236.1", + "wasmparser 0.236.1", + "wasmprinter", + "wasmtime-internal-component-util", +] + +[[package]] +name = "wasmtime-internal-asm-macros" +version = "36.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ab1876bcfa51d6a05dea1c13933f53cbc1e316c783fddebc859f56a736eae07" dependencies = [ "cfg-if", ] [[package]] -name = "wasmtime-cache" -version = "29.0.1" +name = "wasmtime-internal-cache" +version = "36.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b1161c8f62880deea07358bc40cceddc019f1c81d46007bc390710b2fe24ffc" +checksum = "2195a1521a5214a71b67ca2ba2d9317ae15917288ea9d8e5836142b921c9d155" dependencies = [ "anyhow", - "base64 0.21.7", + "base64", "directories-next", "log", "postcard", - "rustix 0.38.44", + "rustix", "serde", "serde_derive", "sha2", "toml", - "windows-sys 0.59.0", + "windows-sys 0.60.2", "zstd", ] [[package]] -name = "wasmtime-component-macro" -version = "29.0.1" +name = "wasmtime-internal-component-macro" +version = "36.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d74de6592ed945d0a602f71243982a304d5d02f1e501b638addf57f42d57dfaf" +checksum = "8ae1407944a0b13a8a77930b5b951aa7134beccecad7efac1ef9f03adb7d1a0f" dependencies = [ "anyhow", "proc-macro2", "quote", "syn", - "wasmtime-component-util", - "wasmtime-wit-bindgen", - "wit-parser 0.221.3", + "wasmtime-internal-component-util", + "wasmtime-internal-wit-bindgen", + "wit-parser", ] [[package]] -name = "wasmtime-component-util" -version = "29.0.1" +name = "wasmtime-internal-component-util" +version = "36.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707dc7b3c112ab5a366b30cfe2fb5b2f8e6a0f682f16df96a5ec582bfe6f056e" +checksum = "646a53678ce6aaf6f097e18ca51f650f2841aea6d2bcd7b61931397b8b8f30db" [[package]] -name = "wasmtime-cranelift" -version = "29.0.1" +name = "wasmtime-internal-cranelift" +version = "36.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "366be722674d4bf153290fbcbc4d7d16895cc82fb3e869f8d550ff768f9e9e87" +checksum = "ab3495aa8300e4ca6b53f81a53ce5eff6621fd5ff8378ef9ae552d1479d57371" dependencies = [ "anyhow", "cfg-if", @@ -5013,202 +4752,153 @@ dependencies = [ "gimli", "itertools", "log", - "object 0.36.7", + "object", + "pulley-interpreter", "smallvec", "target-lexicon", - "thiserror 1.0.69", - "wasmparser 0.221.3", + "thiserror 2.0.18", + "wasmparser 0.236.1", "wasmtime-environ", - "wasmtime-versioned-export-macros", + "wasmtime-internal-math", + "wasmtime-internal-versioned-export-macros", ] [[package]] -name = "wasmtime-environ" -version = "29.0.1" +name = "wasmtime-internal-fiber" +version = "36.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdadc1af7097347aa276a4f008929810f726b5b46946971c660b6d421e9994ad" -dependencies = [ - "anyhow", - "cpp_demangle", - "cranelift-bitset", - "cranelift-entity", - "gimli", - "indexmap", - "log", - "object 0.36.7", - "postcard", - "rustc-demangle", - "semver", - "serde", - "serde_derive", - "smallvec", - "target-lexicon", - "wasm-encoder 0.221.3", - "wasmparser 0.221.3", - "wasmprinter", - "wasmtime-component-util", -] - -[[package]] -name = "wasmtime-fiber" -version = "29.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccba90d4119f081bca91190485650730a617be1fff5228f8c4757ce133d21117" +checksum = "29b5e4023a6b167da157338f5f0f505945eb45e78f1cac2d4dcce0922457d7d4" dependencies = [ "anyhow", "cc", "cfg-if", - "rustix 0.38.44", - "wasmtime-asm-macros", - "wasmtime-versioned-export-macros", - "windows-sys 0.59.0", + "libc", + "rustix", + "wasmtime-internal-asm-macros", + "wasmtime-internal-versioned-export-macros", + "windows-sys 0.60.2", ] [[package]] -name = "wasmtime-jit-debug" -version = "29.0.1" +name = "wasmtime-internal-jit-debug" +version = "36.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e7b61488a5ee00c35c8c22de707c36c0aecacf419a3be803a6a2ba5e860f56a" +checksum = "9da71e2d573e3cc6f753a3b7bff98f425ca060c0e8071cc55c3d867a9edf3ecc" dependencies = [ - "object 0.36.7", - "rustix 0.38.44", - "wasmtime-versioned-export-macros", + "cc", + "object", + "rustix", + "wasmtime-internal-versioned-export-macros", ] [[package]] -name = "wasmtime-jit-icache-coherence" -version = "29.0.1" +name = "wasmtime-internal-jit-icache-coherence" +version = "36.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec5e8552e01692e6c2e5293171704fed8abdec79d1a6995a0870ab190e5747d1" +checksum = "627d8f57909a4f9bb1dbe57a96229a54b89d5995353d0b321f3cb9a1a118977a" dependencies = [ "anyhow", "cfg-if", "libc", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] -name = "wasmtime-math" -version = "29.0.1" +name = "wasmtime-internal-math" +version = "36.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29210ec2aa25e00f4d54605cedaf080f39ec01a872c5bd520ad04c67af1dde17" +checksum = "45b99315585a8a27125dd9b0150edb115d6f6ff0baae453c21d30822aab77f00" dependencies = [ "libm", ] [[package]] -name = "wasmtime-slab" -version = "29.0.1" +name = "wasmtime-internal-slab" +version = "36.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb5821a96fa04ac14bc7b158bb3d5cd7729a053db5a74dad396cd513a5e5ccf" +checksum = "8eaee97281dd3fe47ec3d46c16fb9fe2dd32f37d0523c2d5c484f11b348734e4" [[package]] -name = "wasmtime-versioned-export-macros" -version = "29.0.1" +name = "wasmtime-internal-unwinder" +version = "36.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86ff86db216dc0240462de40c8290887a613dddf9685508eb39479037ba97b5b" +checksum = "d0c005f82c48492b6b44fa19ee5205bd933c4f8baca41e314eca8331dd3c4fd9" dependencies = [ - "proc-macro2", - "quote", - "syn", + "anyhow", + "cfg-if", + "cranelift-codegen", + "log", + "object", ] [[package]] -name = "wasmtime-wasi" -version = "29.0.1" +name = "wasmtime-internal-versioned-export-macros" +version = "36.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d1be69bfcab1bdac74daa7a1f9695ab992b9c8e21b9b061e7d66434097e0ca4" +checksum = "7b73639a9c0c0e33a2ef942ca99b6772b48393be92bebbd0767c607e5b0a68e0" dependencies = [ - "anyhow", - "async-trait", - "bitflags", - "bytes", - "cap-fs-ext", - "cap-net-ext", - "cap-rand", - "cap-std", - "cap-time-ext", - "fs-set-times", - "futures", - "io-extras", - "io-lifetimes", - "rustix 0.38.44", - "system-interface", - "thiserror 1.0.69", - "tokio", - "tracing", - "trait-variant", - "url", - "wasmtime", - "wiggle", - "windows-sys 0.59.0", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "wasmtime-winch" -version = "29.0.1" +name = "wasmtime-internal-winch" +version = "36.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdbabfb8f20502d5e1d81092b9ead3682ae59988487aafcd7567387b7a43cf8f" +checksum = "392ca021d084c7426616ef77e1284315555f11bcbb34f416d74b0732db622811" dependencies = [ "anyhow", "cranelift-codegen", "gimli", - "object 0.36.7", + "object", "target-lexicon", - "wasmparser 0.221.3", - "wasmtime-cranelift", + "wasmparser 0.236.1", "wasmtime-environ", + "wasmtime-internal-cranelift", "winch-codegen", ] [[package]] -name = "wasmtime-wit-bindgen" -version = "29.0.1" +name = "wasmtime-internal-wit-bindgen" +version = "36.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8358319c2dd1e4db79e3c1c5d3a5af84956615343f9f89f4e4996a36816e06e6" +checksum = "7fd4703351476262d715b72431e80d10289908e3494050071d6521267f522d97" dependencies = [ "anyhow", + "bitflags", "heck", "indexmap", - "wit-parser 0.221.3", -] - -[[package]] -name = "wast" -version = "35.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ef140f1b49946586078353a453a1d28ba90adfc54dde75710bc1931de204d68" -dependencies = [ - "leb128", + "wit-parser", ] [[package]] name = "wast" -version = "245.0.1" +version = "253.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cf1149285569120b8ce39db8b465e8a2b55c34cbb586bd977e43e2bc7300bf" +checksum = "d3264542f8965c5d84fb1085d924bfba9a6314bb228eff13a2de14d7627664d0" dependencies = [ "bumpalo", "leb128fmt", "memchr", "unicode-width", - "wasm-encoder 0.245.1", + "wasm-encoder 0.253.0", ] [[package]] name = "wat" -version = "1.245.1" +version = "1.253.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd48d1679b6858988cb96b154dda0ec5bbb09275b71db46057be37332d5477be" +checksum = "4bfc5ce906144200c972ec617470aa35bd847472e170b26dde3e80541c674055" dependencies = [ - "wast 245.0.1", + "wast", ] [[package]] name = "web-sys" -version = "0.3.85" +version = "0.3.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "312e32e551d92129218ea9a2452120f4aabc03529ef03e4d0d82fb2780608598" +checksum = "8622dcb61c0bcc9fffa6938bed81210af2da9a7e4a1a834b2e37a59b6dfb6141" dependencies = [ "js-sys", "wasm-bindgen", @@ -5230,27 +4920,25 @@ version = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" dependencies = [ - "webpki-roots 1.0.6", + "webpki-roots 1.0.8", ] [[package]] name = "webpki-roots" -version = "1.0.6" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed" +checksum = "bf85cb06032201fa7c6f829d7db5a7e5aa45bcc0655327713065f6f0576731bf" dependencies = [ "rustls-pki-types", ] [[package]] name = "which" -version = "8.0.0" +version = "8.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3fabb953106c3c8eea8306e4393700d7657561cb43122571b172bbfb7c7ba1d" +checksum = "48d7cd18d4acb58fb3cdfe9ea54e6cd96a4e7d4cc45c56338b236e82dad47248" dependencies = [ - "env_home", - "rustix 1.1.3", - "winsafe", + "libc", ] [[package]] @@ -5269,48 +4957,6 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72069c3113ab32ab29e5584db3c6ec55d416895e60715417b5b883a357c3e471" -[[package]] -name = "wiggle" -version = "29.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b9af35bc9629c52c261465320a9a07959164928b4241980ba1cf923b9e6751d" -dependencies = [ - "anyhow", - "async-trait", - "bitflags", - "thiserror 1.0.69", - "tracing", - "wasmtime", - "wiggle-macro", -] - -[[package]] -name = "wiggle-generate" -version = "29.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cf267dd05673912c8138f4b54acabe6bd53407d9d1536f0fadb6520dd16e101" -dependencies = [ - "anyhow", - "heck", - "proc-macro2", - "quote", - "shellexpand", - "syn", - "witx", -] - -[[package]] -name = "wiggle-macro" -version = "29.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08c5c473d4198e6c2d377f3809f713ff0c110cab88a0805ae099a82119ee250c" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "wiggle-generate", -] - [[package]] name = "winapi" version = "0.3.9" @@ -5344,20 +4990,22 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "winch-codegen" -version = "29.0.1" +version = "36.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f849ef2c5f46cb0a20af4b4487aaa239846e52e2c03f13fa3c784684552859c" +checksum = "61ec880b20caaa72245944b54cfb22aca111f8c805e12a7542b40d66921e5323" dependencies = [ "anyhow", + "cranelift-assembler-x64", "cranelift-codegen", "gimli", "regalloc2", "smallvec", "target-lexicon", - "thiserror 1.0.69", - "wasmparser 0.221.3", - "wasmtime-cranelift", + "thiserror 2.0.18", + "wasmparser 0.236.1", "wasmtime-environ", + "wasmtime-internal-cranelift", + "wasmtime-internal-math", ] [[package]] @@ -5448,15 +5096,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets 0.52.6", -] - [[package]] name = "windows-sys" version = "0.60.2" @@ -5670,32 +5309,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "winreg" -version = "0.50.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] - -[[package]] -name = "winsafe" -version = "0.0.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" - -[[package]] -name = "winx" -version = "0.36.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f3fd376f71958b862e7afb20cfe5a22830e1963462f3a17f49d82a6c1d1f42d" -dependencies = [ - "bitflags", - "windows-sys 0.59.0", -] - [[package]] name = "wiremock" version = "0.6.5" @@ -5703,7 +5316,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08db1edfb05d9b3c1542e521aea074442088292f00b5f28e435c714a98f85031" dependencies = [ "assert-json-diff", - "base64 0.22.1", + "base64", "deadpool", "futures", "http", @@ -5721,79 +5334,15 @@ dependencies = [ [[package]] name = "wit-bindgen" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" -dependencies = [ - "wit-bindgen-rust-macro", -] - -[[package]] -name = "wit-bindgen-core" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" -dependencies = [ - "anyhow", - "heck", - "wit-parser 0.244.0", -] - -[[package]] -name = "wit-bindgen-rust" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" -dependencies = [ - "anyhow", - "heck", - "indexmap", - "prettyplease", - "syn", - "wasm-metadata", - "wit-bindgen-core", - "wit-component", -] - -[[package]] -name = "wit-bindgen-rust-macro" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" -dependencies = [ - "anyhow", - "prettyplease", - "proc-macro2", - "quote", - "syn", - "wit-bindgen-core", - "wit-bindgen-rust", -] - -[[package]] -name = "wit-component" -version = "0.244.0" +version = "0.57.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" -dependencies = [ - "anyhow", - "bitflags", - "indexmap", - "log", - "serde", - "serde_derive", - "serde_json", - "wasm-encoder 0.244.0", - "wasm-metadata", - "wasmparser 0.244.0", - "wit-parser 0.244.0", -] +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" [[package]] name = "wit-parser" -version = "0.221.3" +version = "0.236.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "896112579ed56b4a538b07a3d16e562d101ff6265c46b515ce0c701eef16b2ac" +checksum = "16e4833a20cd6e85d6abfea0e63a399472d6f88c6262957c17f546879a80ba15" dependencies = [ "anyhow", "id-arena", @@ -5804,44 +5353,14 @@ dependencies = [ "serde_derive", "serde_json", "unicode-xid", - "wasmparser 0.221.3", -] - -[[package]] -name = "wit-parser" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" -dependencies = [ - "anyhow", - "id-arena", - "indexmap", - "log", - "semver", - "serde", - "serde_derive", - "serde_json", - "unicode-xid", - "wasmparser 0.244.0", -] - -[[package]] -name = "witx" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e366f27a5cabcddb2706a78296a40b8fcc451e1a6aba2fc1d94b4a01bdaaef4b" -dependencies = [ - "anyhow", - "log", - "thiserror 1.0.69", - "wast 35.0.2", + "wasmparser 0.236.1", ] [[package]] name = "writeable" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" [[package]] name = "yasna" @@ -5854,9 +5373,9 @@ dependencies = [ [[package]] name = "yoke" -version = "0.8.1" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" dependencies = [ "stable_deref_trait", "yoke-derive", @@ -5865,9 +5384,9 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" dependencies = [ "proc-macro2", "quote", @@ -5877,18 +5396,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.39" +version = "0.8.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db6d35d663eadb6c932438e763b262fe1a70987f9ae936e60158176d710cae4a" +checksum = "75726053136156d419e285b9b7eddaaea9e3fea6ce32eed44a89901f0bd98de1" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.39" +version = "0.8.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4122cd3169e94605190e77839c9a40d40ed048d305bfdc146e7df40ab0f3e517" +checksum = "4714fd92cf900833d49538023a9b3915155210801d1c1169eba513b2addefd71" dependencies = [ "proc-macro2", "quote", @@ -5897,18 +5416,18 @@ dependencies = [ [[package]] name = "zerofrom" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" dependencies = [ "proc-macro2", "quote", @@ -5918,18 +5437,18 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.8.2" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" +checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" dependencies = [ "serde", ] [[package]] name = "zerotrie" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" dependencies = [ "displaydoc", "yoke", @@ -5938,9 +5457,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.5" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" dependencies = [ "yoke", "zerofrom", @@ -5949,9 +5468,9 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" +checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index c4f3023..571d79d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,8 +53,7 @@ tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter", "json"] } urlencoding = "2.1.3" webpki-roots = "0.26" -wasmtime = { version = "29", features = ["async"] } -wasmtime-wasi = "29" +wasmtime = { version = ">=36.0.7, <37", features = ["async"] } regex = "1.12.3" semver = "1.0" async-stream = "0.3.6" diff --git a/scripts/e2e-entrypoint.sh b/scripts/e2e-entrypoint.sh index 663927f..73574e7 100644 --- a/scripts/e2e-entrypoint.sh +++ b/scripts/e2e-entrypoint.sh @@ -4,6 +4,12 @@ set -e # Wait for Caddy's internal CA certificate to appear in the shared volume, # then install it so reqwest (native-tls / OpenSSL) trusts TLS connections # proxied through Caddy (e.g. the PDS OAuth endpoints). +# +# Reading Caddy's CA (its pki/ tree is root-owned, mode 0700 to protect the CA +# key) and installing it into the system trust store both require root. The +# image now runs as the non-root `app` user, so the e2e compose overrides the +# container user back to root for this bootstrap; we install the CA as root and +# then drop to `app` to run the server, keeping the non-root runtime under test. CA_CERT=/caddy-data/caddy/pki/authorities/local/root.crt if [ -d /caddy-data ]; then echo "Waiting for Caddy CA certificate..." @@ -13,4 +19,9 @@ if [ -d /caddy-data ]; then echo "Caddy CA certificate installed." fi -exec /entrypoint.sh +# Drop back to the unprivileged app user (uid 10001) to run the server when we +# started as root; run directly otherwise (already unprivileged). +if [ "$(id -u)" = "0" ]; then + exec runuser -u app -- /entrypoint.sh "$@" +fi +exec /entrypoint.sh "$@" diff --git a/src/plugin/encryption.rs b/src/plugin/encryption.rs index c91fd30..951c60b 100644 --- a/src/plugin/encryption.rs +++ b/src/plugin/encryption.rs @@ -26,11 +26,11 @@ pub fn encrypt(key: &[u8; 32], plaintext: &[u8]) -> Result, EncryptionEr // Generate random nonce let mut nonce_bytes = [0u8; NONCE_SIZE]; rand::rng().fill_bytes(&mut nonce_bytes); - let nonce = Nonce::from_slice(&nonce_bytes); + let nonce = Nonce::from(nonce_bytes); // Encrypt let ciphertext = cipher - .encrypt(nonce, plaintext) + .encrypt(&nonce, plaintext) .map_err(|_| EncryptionError::EncryptionFailed)?; // Concatenate: nonce || ciphertext @@ -50,11 +50,13 @@ pub fn decrypt(key: &[u8; 32], ciphertext: &[u8]) -> Result, EncryptionE let cipher = Aes256Gcm::new_from_slice(key).map_err(|_| EncryptionError::DecryptionFailed)?; - let nonce = Nonce::from_slice(&ciphertext[..NONCE_SIZE]); + let mut nonce_bytes = [0u8; NONCE_SIZE]; + nonce_bytes.copy_from_slice(&ciphertext[..NONCE_SIZE]); + let nonce = Nonce::from(nonce_bytes); let encrypted = &ciphertext[NONCE_SIZE..]; cipher - .decrypt(nonce, encrypted) + .decrypt(&nonce, encrypted) .map_err(|_| EncryptionError::DecryptionFailed) } diff --git a/src/verification_methods.rs b/src/verification_methods.rs index 730d4b4..6916c71 100644 --- a/src/verification_methods.rs +++ b/src/verification_methods.rs @@ -234,7 +234,7 @@ mod tests { let (key_bytes, _) = generate_p256_keypair().unwrap(); let signing_key = private_key_bytes_to_signing_key(&key_bytes).unwrap(); // Re-derive bytes should equal original - assert_eq!(signing_key.to_bytes().as_slice(), key_bytes.as_slice()); + assert_eq!(&signing_key.to_bytes()[..], &key_bytes[..]); } #[test] -- 2.51.2 From 295ca488bb39497106261332145a6666a7c1fe42 Mon Sep 17 00:00:00 2001 From: Trezy Date: Wed, 8 Jul 2026 14:55:03 -0500 Subject: [PATCH 13/14] chore: update _so many_ deps Signed-off-by: Trezy --- .cargo/audit.toml | 17 +- .github/workflows/ci.yml | 6 +- Cargo.lock | 1336 ++++++++++++++++++------- Cargo.toml | 35 +- Dockerfile | 2 +- docker-compose.yml | 2 +- rust-toolchain.toml | 3 + src/admin/api_clients.rs | 26 +- src/admin/api_keys.rs | 8 +- src/admin/auth.rs | 16 +- src/admin/backfill.rs | 97 +- src/admin/dead_letters.rs | 74 +- src/admin/domains.rs | 16 +- src/admin/events.rs | 21 +- src/admin/labelers.rs | 10 +- src/admin/lexicons.rs | 8 +- src/admin/network_lexicons.rs | 6 +- src/admin/plugins.rs | 14 +- src/admin/proxy_config.rs | 2 +- src/admin/records.rs | 10 +- src/admin/script_variables.rs | 6 +- src/admin/scripts.rs | 31 +- src/admin/service_entries.rs | 8 +- src/admin/settings.rs | 16 +- src/admin/stats.rs | 4 +- src/admin/users.rs | 39 +- src/auth/client_registry.rs | 2 +- src/auth/middleware.rs | 2 +- src/auth/oauth_store.rs | 16 +- src/auth/routes.rs | 16 +- src/auth/service_auth.rs | 14 +- src/db.rs | 49 +- src/delegation/db.rs | 20 +- src/delegation/link_account.rs | 2 +- src/dev_happyview/create_client.rs | 10 +- src/dev_happyview/delete_client.rs | 6 +- src/dev_happyview/get_client.rs | 2 +- src/dev_happyview/list_clients.rs | 4 +- src/dns.rs | 13 +- src/event_log.rs | 4 +- src/external_auth/routes.rs | 2 +- src/external_auth/state.rs | 11 +- src/external_auth/sync.rs | 2 +- src/external_auth/tokens.rs | 12 +- src/jetstream.rs | 4 +- src/jobs/db.rs | 22 +- src/jobs/worker.rs | 2 +- src/labeler.rs | 23 +- src/lexicon.rs | 2 +- src/lua/atproto_api.rs | 8 +- src/lua/db_api.rs | 24 +- src/lua/execute.rs | 2 +- src/lua/record.rs | 23 +- src/lua/scripts.rs | 6 +- src/lua/xrpc_api.rs | 4 +- src/main.rs | 24 +- src/oauth/client_auth.rs | 6 +- src/oauth/dpop_proof.rs | 2 +- src/oauth/keys.rs | 18 +- src/oauth/pds_write.rs | 6 +- src/oauth/sessions.rs | 29 +- src/plc.rs | 8 +- src/plugin/attestation.rs | 25 +- src/plugin/encryption.rs | 2 +- src/plugin/host/kv.rs | 6 +- src/plugin/host/lookup.rs | 2 +- src/plugin/mod.rs | 4 +- src/plugin/sync.rs | 2 +- src/record_handler.rs | 10 +- src/record_refs.rs | 4 +- src/repo/session.rs | 2 +- src/resolve.rs | 11 +- src/server.rs | 4 +- src/service_entries.rs | 26 +- src/service_identity.rs | 6 +- src/setup.rs | 28 +- src/spaces/auth.rs | 12 +- src/spaces/client_attestation.rs | 2 +- src/spaces/commit.rs | 15 +- src/spaces/credential.rs | 20 +- src/spaces/db.rs | 74 +- src/spaces/integration_tests.rs | 6 +- src/spaces/oplog.rs | 6 +- src/spaces/routes.rs | 15 +- src/spaces/simplespace.rs | 2 +- src/verification_methods.rs | 18 +- src/xrpc/procedure.rs | 8 +- src/xrpc/query.rs | 6 +- tests/common/app.rs | 33 +- tests/common/db.rs | 6 +- tests/common/tls.rs | 2 +- tests/dev_happyview.rs | 4 +- tests/e2e_admin.rs | 14 +- tests/e2e_admin_service_entries.rs | 7 +- tests/e2e_api_clients.rs | 10 +- tests/e2e_delegation.rs | 2 +- tests/e2e_domains.rs | 2 +- tests/e2e_jobs.rs | 4 +- tests/e2e_labelers.rs | 4 +- tests/e2e_network_lexicons.rs | 4 +- tests/e2e_scripts.rs | 19 +- tests/e2e_service_identity.rs | 24 +- tests/e2e_xrpc.rs | 4 +- tests/lua_atproto_api.rs | 30 +- tests/lua_db_api.rs | 2 +- tests/lua_record_api.rs | 6 +- tests/plugin_logging.rs | 4 +- tests/spaces_credential_revocation.rs | 2 +- tests/spaces_db.rs | 2 +- tests/transfer_super.rs | 8 +- 110 files changed, 1672 insertions(+), 1050 deletions(-) create mode 100644 rust-toolchain.toml diff --git a/.cargo/audit.toml b/.cargo/audit.toml index d8fc779..f73feec 100644 --- a/.cargo/audit.toml +++ b/.cargo/audit.toml @@ -1,21 +1,10 @@ # cargo-audit configuration. # -# Each ignored advisory below has been triaged and is either unreachable in our -# build, has no upstream fix, or the fix is a deferred breaking migration. Every -# other advisory must fail CI (see .github/workflows/ci.yml `audit` job) so new -# ones are caught. Re-review this list when dependencies are updated. +# The single ignored advisory below has been triaged and has no upstream fix. +# Every other advisory must fail CI (see .github/workflows/ci.yml `audit` job) so +# new ones are caught. Re-review this list when dependencies are updated. [advisories] ignore = [ - # rsa (Marvin timing side-channel). Pulled in ONLY by sqlx-mysql, an optional - # sqlx dependency that is NOT enabled — `cargo tree` confirms rsa is never in - # the build graph, so it is never compiled or linked. No upstream fix exists. - "RUSTSEC-2023-0071", - # hickory-proto: no fixed upstream release is available. - "RUSTSEC-2026-0118", - # hickory-proto: fixed in hickory-resolver 0.26, but that removes the - # `txt_lookup` API and requires an (untested-in-CI) rewrite of DNS handle - # resolution. Deferred; revisit with the hickory 0.26 upgrade. - "RUSTSEC-2026-0119", # fxhash: unmaintained (warning, not a vulnerability). Transitive dependency # of wasmtime (via fxprof-processed-profile); not removable independently. "RUSTSEC-2025-0057", diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8dd3f70..fa66021 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -114,7 +114,7 @@ jobs: -v "$HOME/.cargo/git:/usr/local/cargo/git" \ -w /app \ -e SQLX_OFFLINE=true \ - rust:1.93-bookworm \ + rust:1.96.1-bookworm \ cargo build --release - name: Upload server binary @@ -368,7 +368,7 @@ jobs: -v "$HOME/.cargo/git:/usr/local/cargo/git" \ -w /app \ -e SQLX_OFFLINE=true \ - rust:1.93-bookworm \ + rust:1.96.1-bookworm \ cargo build --release - name: Upload artifact @@ -561,7 +561,7 @@ jobs: -w /app \ -e SQLX_OFFLINE=true \ -e HAPPYVIEW_VERSION="v${{ needs.release.outputs.version }}" \ - rust:1.93-bookworm \ + rust:1.96.1-bookworm \ cargo build --release - name: Upload binary to release diff --git a/Cargo.lock b/Cargo.lock index 10ea568..8b0b21e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,30 +19,30 @@ checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "aead" -version = "0.5.2" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +checksum = "1973cfbc1a2daf9cf550e74e1f088c28e7f7d8c1e1418fb6c9dc5184b7e84c99" dependencies = [ - "crypto-common", - "generic-array", + "crypto-common 0.2.2", + "inout", ] [[package]] name = "aes" -version = "0.8.4" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +checksum = "f1fc76eaeac4c9164506c466d4ffdd8ec9d0c5bf57ee97177c4d8eceb3a0e138" dependencies = [ - "cfg-if", "cipher", - "cpufeatures 0.2.17", + "cpubits", + "cpufeatures 0.3.0", ] [[package]] name = "aes-gcm" -version = "0.10.3" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" +checksum = "fdf011db2e21ce0d575593d749db5554b47fed37aff429e4dc50bc91ac93a028" dependencies = [ "aead", "aes", @@ -118,6 +118,45 @@ version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56" +[[package]] +name = "asn1-rs" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7f43a50ac4fdca5df8e885c21b835997f0a1cdee65494a6847694a98652d9d8" +dependencies = [ + "asn1-rs-derive", + "asn1-rs-impl", + "displaydoc", + "nom", + "num-traits", + "rusticata-macros", + "thiserror 2.0.18", + "time", +] + +[[package]] +name = "asn1-rs-derive" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "asn1-rs-impl" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "assert-json-diff" version = "2.0.2" @@ -264,17 +303,17 @@ dependencies = [ "base64", "chrono", "dashmap", - "ecdsa", - "elliptic-curve", + "ecdsa 0.16.9", + "elliptic-curve 0.13.8", "jose-jwa", "jose-jwk", - "p256", + "p256 0.13.2", "rand 0.8.6", - "reqwest", + "reqwest 0.12.28", "serde", "serde_html_form", "serde_json", - "sha2", + "sha2 0.10.9", "thiserror 1.0.69", "tokio", "trait-variant", @@ -378,22 +417,22 @@ dependencies = [ [[package]] name = "axum-extra" -version = "0.10.3" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9963ff19f40c6102c76756ef0a46004c0d58957d87259fc9208ff8441c12ab96" +checksum = "be44683b41ccb9ab2d23a5230015c9c3c55be97a25e4428366de8873103f7970" dependencies = [ "axum", "axum-core", "bytes", "cookie", "form_urlencoded", + "futures-core", "futures-util", "http", "http-body", "http-body-util", "mime", "pin-project-lite", - "rustversion", "serde_core", "serde_html_form", "serde_path_to_error", @@ -414,6 +453,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" +[[package]] +name = "base16ct" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd307490d624467aa6f74b0eabb77633d1f758a7b25f12bceb0b22e08d9726f6" + [[package]] name = "base256emoji" version = "1.0.2" @@ -442,6 +487,15 @@ version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" +[[package]] +name = "bit-vec" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71798fca2c1fe1086445a7258a4bc81e6e49dcd24c8d0dd9a1e57395b603f51" +dependencies = [ + "serde", +] + [[package]] name = "bitflags" version = "2.13.0" @@ -474,6 +528,15 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-buffer" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" +dependencies = [ + "hybrid-array", +] + [[package]] name = "bstr" version = "1.12.3" @@ -532,6 +595,23 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chacha20" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d524456ba66e72eb8b115ff89e01e497f8e6d11d78b70b1aa13c0fbd97540a81" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "rand_core 0.10.1", +] + [[package]] name = "chrono" version = "0.4.45" @@ -588,11 +668,12 @@ dependencies = [ [[package]] name = "cipher" -version = "0.4.4" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +checksum = "e8cf2a2c93cd704877c0858356ed03480ff301ee950b43f1cbe4573b088bfa6c" dependencies = [ - "crypto-common", + "block-buffer 0.12.1", + "crypto-common 0.2.2", "inout", ] @@ -605,6 +686,12 @@ dependencies = [ "cc", ] +[[package]] +name = "cmov" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a" + [[package]] name = "cobs" version = "0.3.0" @@ -614,6 +701,16 @@ dependencies = [ "thiserror 2.0.18", ] +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + [[package]] name = "compression-codecs" version = "0.4.38" @@ -646,6 +743,12 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "const-oid" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" + [[package]] name = "const-str" version = "0.4.3" @@ -665,11 +768,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" dependencies = [ "base64", - "hkdf", - "hmac", + "hkdf 0.12.4", + "hmac 0.12.1", "percent-encoding", "rand 0.8.6", - "sha2", + "sha2 0.10.9", "subtle", "time", "version_check", @@ -710,6 +813,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "cpubits" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15b85f9c39137c3a891689859392b1bd49812121d0d61c9caf00d46ed5ce06ae" + [[package]] name = "cpufeatures" version = "0.2.17" @@ -957,6 +1066,22 @@ dependencies = [ "zeroize", ] +[[package]] +name = "crypto-bigint" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a52aa3fcda4e6302a9f48734f234d35d4721b96f8fe07d073f07ce9df4f0271" +dependencies = [ + "cpubits", + "ctutils", + "getrandom 0.4.3", + "hybrid-array", + "num-traits", + "rand_core 0.10.1", + "subtle", + "zeroize", +] + [[package]] name = "crypto-common" version = "0.1.6" @@ -964,19 +1089,39 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", - "rand_core 0.6.4", "typenum", ] +[[package]] +name = "crypto-common" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" +dependencies = [ + "getrandom 0.4.3", + "hybrid-array", + "rand_core 0.10.1", +] + [[package]] name = "ctr" -version = "0.9.2" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +checksum = "baaca1c4b237092596f64d571e9db6ce4109c4ef9742e27590f1709594461f21" dependencies = [ "cipher", ] +[[package]] +name = "ctutils" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5515a3834141de9eafb9717ad39eea8247b5674e6066c404e8c4b365d2a29e" +dependencies = [ + "cmov", + "subtle", +] + [[package]] name = "dashmap" version = "6.2.1" @@ -1050,11 +1195,35 @@ version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" dependencies = [ - "const-oid", + "const-oid 0.9.6", + "zeroize", +] + +[[package]] +name = "der" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71fd89660b2dc699704064e59e9dba0147b903e85319429e131620d022be411b" +dependencies = [ + "const-oid 0.10.2", "pem-rfc7468", "zeroize", ] +[[package]] +name = "der-parser" +version = "10.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07da5016415d5a3c4dd39b11ed26f915f52fc4e0dc197d87908bc916e51bc1a6" +dependencies = [ + "asn1-rs", + "displaydoc", + "nom", + "num-bigint", + "num-traits", + "rusticata-macros", +] + [[package]] name = "deranged" version = "0.5.8" @@ -1067,12 +1236,24 @@ version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer", - "const-oid", - "crypto-common", + "block-buffer 0.10.4", + "const-oid 0.9.6", + "crypto-common 0.1.6", "subtle", ] +[[package]] +name = "digest" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" +dependencies = [ + "block-buffer 0.12.1", + "const-oid 0.10.2", + "crypto-common 0.2.2", + "ctutils", +] + [[package]] name = "directories-next" version = "2.0.0" @@ -1123,12 +1304,26 @@ version = "0.16.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" dependencies = [ - "der", - "digest", - "elliptic-curve", - "rfc6979", - "signature", + "der 0.7.10", + "digest 0.10.7", + "elliptic-curve 0.13.8", + "rfc6979 0.4.0", + "signature 2.2.0", +] + +[[package]] +name = "ecdsa" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0681a4fc24c767085329728d8dfba959af91228aa4610cca4f8ce317ba46ae0" +dependencies = [ + "der 0.8.0", + "digest 0.11.3", + "elliptic-curve 0.14.1", + "rfc6979 0.6.0", + "signature 3.0.0", "spki", + "zeroize", ] [[package]] @@ -1146,16 +1341,35 @@ version = "0.13.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" dependencies = [ - "base16ct", - "crypto-bigint", - "digest", - "ff", + "base16ct 0.2.0", + "crypto-bigint 0.5.5", + "digest 0.10.7", + "ff 0.13.1", "generic-array", - "group", + "group 0.13.0", + "rand_core 0.6.4", + "sec1 0.7.3", + "subtle", + "zeroize", +] + +[[package]] +name = "elliptic-curve" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d65aa39b3a5c1c9c1b745c9a019234bb7a21b77abcb4f4d266d706e2d577d65" +dependencies = [ + "base16ct 1.0.0", + "crypto-bigint 0.7.5", + "crypto-common 0.2.2", + "digest 0.11.3", + "ff 0.14.0", + "group 0.14.0", + "hybrid-array", "pem-rfc7468", "pkcs8", - "rand_core 0.6.4", - "sec1", + "rand_core 0.10.1", + "sec1 0.8.1", "subtle", "zeroize", ] @@ -1181,18 +1395,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "enum-as-inner" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "equivalent" version = "1.0.2" @@ -1222,13 +1424,12 @@ dependencies = [ [[package]] name = "etcetera" -version = "0.8.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" +checksum = "de48cc4d1c1d97a20fd819def54b890cadde72ed3ad0c614822a0a433361be96" dependencies = [ "cfg-if", - "home", - "windows-sys 0.48.0", + "windows-sys 0.61.2", ] [[package]] @@ -1274,6 +1475,16 @@ dependencies = [ "subtle", ] +[[package]] +name = "ff" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f686ab92a9fb0eaf188f6c6c87b89490baa6fdb0db4544ba4dc47f7942489f" +dependencies = [ + "rand_core 0.10.1", + "subtle", +] + [[package]] name = "find-msvc-tools" version = "0.1.9" @@ -1292,9 +1503,9 @@ dependencies = [ [[package]] name = "flume" -version = "0.11.1" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" +checksum = "5e139bc46ca777eb5efaf62df0ab8cc5fd400866427e56c68b22e414e53bd3be" dependencies = [ "futures-core", "futures-sink", @@ -1513,17 +1724,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" dependencies = [ "cfg-if", + "js-sys", "libc", "r-efi 6.0.0", + "rand_core 0.10.1", + "wasm-bindgen", ] [[package]] name = "ghash" -version = "0.5.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" +checksum = "2eecf2d5dc9b66b732b97707a0210906b1d30523eb773193ab777c0c84b3e8d5" dependencies = [ - "opaque-debug", "polyval", ] @@ -1544,11 +1757,22 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ - "ff", + "ff 0.13.1", "rand_core 0.6.4", "subtle", ] +[[package]] +name = "group" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fd1a1c7a5206c5b7a3f5a0d7ccd3ff85d0c8f5133d62a02680255b0004af5f4" +dependencies = [ + "ff 0.14.0", + "rand_core 0.10.1", + "subtle", +] + [[package]] name = "h2" version = "0.4.15" @@ -1607,8 +1831,8 @@ dependencies = [ "futures-util", "hex", "hickory-resolver", - "hkdf", - "hmac", + "hkdf 0.13.0", + "hmac 0.13.0", "http-body-util", "ipnet", "jose-jwk", @@ -1616,18 +1840,18 @@ dependencies = [ "k256", "mlua", "multibase", - "p256", - "rand 0.9.4", + "p256 0.14.0", + "rand 0.10.2", "rcgen", "regex", - "reqwest", + "reqwest 0.13.4", "rustls", "semver", "serde", "serde_ipld_dagcbor", "serde_json", "serial_test", - "sha2", + "sha2 0.11.0", "sqlparser", "sqlx", "thiserror 2.0.18", @@ -1635,13 +1859,13 @@ dependencies = [ "tokio-rustls", "tokio-tungstenite", "tower", - "tower-http", + "tower-http 0.7.0", "tracing", "tracing-subscriber", "urlencoding", "uuid", "wasmtime", - "webpki-roots 0.26.11", + "webpki-roots 1.0.8", "wiremock", ] @@ -1657,8 +1881,6 @@ version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ - "allocator-api2", - "equivalent", "foldhash 0.1.5", "serde", ] @@ -1682,11 +1904,11 @@ checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" [[package]] name = "hashlink" -version = "0.10.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" +checksum = "824e001ac4f3012dd16a264bec811403a67ca9deb6c102fc5049b32c4574b35f" dependencies = [ - "hashbrown 0.15.5", + "hashbrown 0.16.1", ] [[package]] @@ -1708,46 +1930,70 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] -name = "hickory-proto" -version = "0.25.2" +name = "hickory-net" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8a6fe56c0038198998a6f217ca4e7ef3a5e51f46163bd6dd60b5c71ca6c6502" +checksum = "e2295ed2f9c31e471e1428a8f88a3f0e1f4b27c15049592138d1eebe9c35b183" dependencies = [ "async-trait", "cfg-if", "data-encoding", - "enum-as-inner", "futures-channel", "futures-io", "futures-util", + "hickory-proto", + "idna", + "ipnet", + "jni", + "rand 0.10.2", + "thiserror 2.0.18", + "tinyvec", + "tokio", + "tracing", + "url", +] + +[[package]] +name = "hickory-proto" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bab31817bfb44672a252e97fe81cd0c18d1b2cf892108922f6818820df8c643" +dependencies = [ + "data-encoding", "idna", "ipnet", + "jni", "once_cell", - "rand 0.9.4", + "prefix-trie", + "rand 0.10.2", "ring", "thiserror 2.0.18", "tinyvec", - "tokio", "tracing", "url", ] [[package]] name = "hickory-resolver" -version = "0.25.2" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc62a9a99b0bfb44d2ab95a7208ac952d31060efc16241c87eaf36406fecf87a" +checksum = "f0d58d28879ceecde6607729660c2667a081ccdc082e082675042793960f178c" dependencies = [ "cfg-if", "futures-util", + "hickory-net", "hickory-proto", "ipconfig", + "ipnet", + "jni", "moka", + "ndk-context", "once_cell", "parking_lot", - "rand 0.9.4", + "rand 0.10.2", "resolv-conf", "smallvec", + "system-configuration", "thiserror 2.0.18", "tokio", "tracing", @@ -1759,7 +2005,16 @@ version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" dependencies = [ - "hmac", + "hmac 0.12.1", +] + +[[package]] +name = "hkdf" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4aaa26c720c68b866f2c96ef5c1264b3e6f473fe5d4ce61cd44bbe913e553018" +dependencies = [ + "hmac 0.13.0", ] [[package]] @@ -1768,16 +2023,16 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest", + "digest 0.10.7", ] [[package]] -name = "home" -version = "0.5.12" +name = "hmac" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" +checksum = "6303bc9732ae41b04cb554b844a762b4115a61bfaa81e3e83050991eeb56863f" dependencies = [ - "windows-sys 0.61.2", + "digest 0.11.3", ] [[package]] @@ -1831,6 +2086,17 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +[[package]] +name = "hybrid-array" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "818356c5132c1fede50f837ca96afbe78ff42413047f4abb886217845e1b6c8c" +dependencies = [ + "subtle", + "typenum", + "zeroize", +] + [[package]] name = "hyper" version = "1.10.1" @@ -2056,11 +2322,11 @@ dependencies = [ [[package]] name = "inout" -version = "0.1.4" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +checksum = "4250ce6452e92010fdf7268ccc5d14faa80bb12fc741938534c58f16804e03c7" dependencies = [ - "generic-array", + "hybrid-array", ] [[package]] @@ -2092,6 +2358,9 @@ name = "ipnet" version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" +dependencies = [ + "serde", +] [[package]] name = "itertools" @@ -2128,6 +2397,55 @@ dependencies = [ "cc", ] +[[package]] +name = "jni" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5efd9a482cf3a427f00d6b35f14332adc7902ce91efb778580e180ff90fa3498" +dependencies = [ + "cfg-if", + "combine", + "jni-macros", + "jni-sys", + "log", + "simd_cesu8", + "thiserror 2.0.18", + "walkdir", + "windows-link", +] + +[[package]] +name = "jni-macros" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "simd_cesu8", + "syn", +] + +[[package]] +name = "jni-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2" +dependencies = [ + "jni-sys-macros", +] + +[[package]] +name = "jni-sys-macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" +dependencies = [ + "quote", + "syn", +] + [[package]] name = "jobserver" version = "0.1.35" @@ -2167,7 +2485,7 @@ checksum = "280fa263807fe0782ecb6f2baadc28dffc04e00558a58e33bfdb801d11fd58e7" dependencies = [ "jose-b64", "jose-jwa", - "p256", + "p256 0.13.2", "serde", "zeroize", ] @@ -2185,31 +2503,34 @@ dependencies = [ [[package]] name = "jsonwebtoken" -version = "9.3.1" +version = "10.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a87cc7a48537badeae96744432de36f4be2b4a34a05a5ef32e9dd8a1c169dde" +checksum = "eba32bfb4ffdeaca3e34431072faf01745c9b26d25504aa7a6cf5684334fc4fc" dependencies = [ "base64", + "getrandom 0.2.17", "js-sys", "pem", - "ring", "serde", "serde_json", + "signature 2.2.0", "simple_asn1", + "zeroize", ] [[package]] name = "k256" -version = "0.13.4" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" +checksum = "93f50113171a713f4a4231ef82eb26703607139b35dcb56241f0ceab2ae1f7d8" dependencies = [ - "cfg-if", - "ecdsa", - "elliptic-curve", - "once_cell", - "sha2", - "signature", + "cpubits", + "ecdsa 0.17.0", + "elliptic-curve 0.14.1", + "primeorder 0.14.0", + "sha2 0.11.0", + "signature 3.0.0", + "wnaf", ] [[package]] @@ -2226,9 +2547,6 @@ name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" -dependencies = [ - "spin", -] [[package]] name = "leb128fmt" @@ -2254,10 +2572,7 @@ version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c943259e342f1e06ff2da7a83eabdfe7f92ce10262688dbf1895ff0b3e6e4652" dependencies = [ - "bitflags", "libc", - "plain", - "redox_syscall 0.9.0", ] [[package]] @@ -2307,20 +2622,26 @@ dependencies = [ "hashbrown 0.16.1", ] +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + [[package]] name = "lua-src" -version = "550.0.0" +version = "550.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e836dc8ae16806c9bdcf42003a88da27d163433e3f9684c52f0301258004a4fb" +checksum = "75c110c2fa33f34e0de05448e1f3eb2e0631e7a69e2d8ae1586cffc9fc9f9949" dependencies = [ "cc", ] [[package]] name = "luajit-src" -version = "210.6.6+707c12b" +version = "210.7.2+b925b3e" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a86cc925d4053d0526ae7f5bc765dbd0d7a5d1a63d43974f4966cb349ca63295" +checksum = "920cf654b23d217c550ceea57c32cd2a413ea27b6d47ed77b5ee0cf655adefa6" dependencies = [ "cc", "which", @@ -2363,12 +2684,12 @@ checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" [[package]] name = "md-5" -version = "0.10.6" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +checksum = "69b6441f590336821bb897fb28fc622898ccceb1d6cea3fde5ea86b090c4de98" dependencies = [ "cfg-if", - "digest", + "digest 0.11.3", ] [[package]] @@ -2402,6 +2723,12 @@ dependencies = [ "unicase", ] +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" version = "0.8.9" @@ -2425,9 +2752,9 @@ dependencies = [ [[package]] name = "mlua" -version = "0.11.6" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccd36acfa49ce6ee56d1307a061dd302c564eee757e6e4cd67eb4f7204846fab" +checksum = "ad72ffa037cf5970c9860674f32f703fda25d86cf217475fe7a79c5f9961bcaa" dependencies = [ "bstr", "either", @@ -2438,16 +2765,15 @@ dependencies = [ "num-traits", "parking_lot", "rustc-hash", - "rustversion", "serde", "serde-value", ] [[package]] name = "mlua-sys" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f1c3a7fc7580227ece249fd90aa2fa3b39eb2b49d3aec5e103b3e85f2c3dfc8" +checksum = "92136787b906d4e55cfe96cd6c62e010bb1a56889d0d6cf83eb016dbad07576b" dependencies = [ "cc", "cfg-if", @@ -2534,6 +2860,22 @@ dependencies = [ "tempfile", ] +[[package]] +name = "ndk-context" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "nu-ansi-term" version = "0.50.3" @@ -2553,22 +2895,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "num-bigint-dig" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7" -dependencies = [ - "lazy_static", - "libm", - "num-integer", - "num-iter", - "num-traits", - "rand 0.8.6", - "smallvec", - "zeroize", -] - [[package]] name = "num-conv" version = "0.2.2" @@ -2584,16 +2910,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "num-iter" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c92800bd69a1eac91786bcfe9da64a897eb72911b8dc3095decbd07429e8048b" -dependencies = [ - "num-integer", - "num-traits", -] - [[package]] name = "num-traits" version = "0.2.19" @@ -2601,7 +2917,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", - "libm", ] [[package]] @@ -2626,6 +2941,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "oid-registry" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f40cff3dde1b6087cc5d5f5d4d65712f34016a03ed60e9c08dcc392736b5b7" +dependencies = [ + "asn1-rs", +] + [[package]] name = "once_cell" version = "1.21.4" @@ -2636,12 +2960,6 @@ dependencies = [ "portable-atomic", ] -[[package]] -name = "opaque-debug" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" - [[package]] name = "openssl" version = "0.10.81" @@ -2700,10 +3018,23 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" dependencies = [ - "ecdsa", - "elliptic-curve", - "primeorder", - "sha2", + "ecdsa 0.16.9", + "elliptic-curve 0.13.8", + "primeorder 0.13.6", + "sha2 0.10.9", +] + +[[package]] +name = "p256" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2c9239b2dbc807adbbe147e8cf72ea7450c3a0aabe62cb8e75ff4ec22e1f72a" +dependencies = [ + "ecdsa 0.17.0", + "elliptic-curve 0.14.1", + "primefield", + "primeorder 0.14.0", + "sha2 0.11.0", ] [[package]] @@ -2730,7 +3061,7 @@ checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.18", + "redox_syscall", "smallvec", "windows-link", ] @@ -2747,9 +3078,9 @@ dependencies = [ [[package]] name = "pem-rfc7468" -version = "0.7.0" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +checksum = "a6305423e0e7738146434843d1694d621cce767262b2a86910beab705e4493d9" dependencies = [ "base64ct", ] @@ -2766,24 +3097,13 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" -[[package]] -name = "pkcs1" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" -dependencies = [ - "der", - "pkcs8", - "spki", -] - [[package]] name = "pkcs8" -version = "0.10.2" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +checksum = "451913da69c775a56034ea8d9003d27ee8948e12443eae7c038ba100a4f21cb7" dependencies = [ - "der", + "der 0.8.0", "spki", ] @@ -2793,21 +3113,14 @@ version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" -[[package]] -name = "plain" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" - [[package]] name = "polyval" -version = "0.6.2" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +checksum = "7dfc63250416fea14f5749b90725916a6c903f599d51cb635aa7a52bfd03eede" dependencies = [ - "cfg-if", - "cpufeatures 0.2.17", - "opaque-debug", + "cpubits", + "cpufeatures 0.3.0", "universal-hash", ] @@ -2853,13 +3166,51 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "prefix-trie" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cf6e3177f0684016a5c209b00882e15f8bdd3f3bb48f0491df10cd102d0c6e7" +dependencies = [ + "either", + "ipnet", + "num-traits", +] + +[[package]] +name = "primefield" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c555a6e4eb7d4e158fcb028c835c3b8642206ddc279b5c6b202ef9a8bdb592f4" +dependencies = [ + "crypto-bigint 0.7.5", + "crypto-common 0.2.2", + "ff 0.14.0", + "rand_core 0.10.1", + "subtle", + "zeroize", +] + [[package]] name = "primeorder" version = "0.13.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" dependencies = [ - "elliptic-curve", + "elliptic-curve 0.13.8", +] + +[[package]] +name = "primeorder" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c9f42978c78a00e3d68f69fc03e57a234debae69da4020a4fb588fcdcd07b06" +dependencies = [ + "elliptic-curve 0.14.1", + "once_cell", + "primefield", + "serdect", + "wnaf", ] [[package]] @@ -2904,6 +3255,63 @@ dependencies = [ "syn", ] +[[package]] +name = "quinn" +version = "0.11.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c1a41e437b6bbd489372cd4971de128e85c855f56c57f283d20ff016cf7c0a8" +dependencies = [ + "bytes", + "cfg_aliases", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "socket2", + "thiserror 2.0.18", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f4bfc015262b9df63c8845072ce59068853ff5872180c2ce2f13038b970e560" +dependencies = [ + "aws-lc-rs", + "bytes", + "getrandom 0.4.3", + "lru-slab", + "rand 0.10.2", + "rand_pcg", + "ring", + "rustc-hash", + "rustls", + "rustls-pki-types", + "slab", + "thiserror 2.0.18", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35a133f956daabe89a61a685c2649f13d82d5aa4bd5d12d1277e1072a21c0694" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.61.2", +] + [[package]] name = "quote" version = "1.0.46" @@ -2946,6 +3354,17 @@ dependencies = [ "rand_core 0.9.5", ] +[[package]] +name = "rand" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80" +dependencies = [ + "chacha20", + "getrandom 0.4.3", + "rand_core 0.10.1", +] + [[package]] name = "rand_chacha" version = "0.3.1" @@ -2984,6 +3403,21 @@ dependencies = [ "getrandom 0.3.4", ] +[[package]] +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + +[[package]] +name = "rand_pcg" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caa0f4137e1c0a72f4c651489402276c8e8e1cf081f3b0ba156d2cbeef09e86a" +dependencies = [ + "rand_core 0.10.1", +] + [[package]] name = "rayon" version = "1.12.0" @@ -3006,14 +3440,15 @@ dependencies = [ [[package]] name = "rcgen" -version = "0.13.2" +version = "0.14.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75e669e5202259b5314d1ea5397316ad400819437857b90861765f24c4cf80a2" +checksum = "57f6d249aad744e274e682777a50283a225a32705394ee6d5fcc01efa25e4055" dependencies = [ "pem", "ring", "rustls-pki-types", "time", + "x509-parser", "yasna", ] @@ -3046,15 +3481,6 @@ dependencies = [ "bitflags", ] -[[package]] -name = "redox_syscall" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5102a6aaa05aa011a238e178e6bca86d2cb56fc9f586d37cb80f5bca6e07759" -dependencies = [ - "bitflags", -] - [[package]] name = "redox_users" version = "0.4.6" @@ -3114,6 +3540,42 @@ name = "reqwest" version = "0.12.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" +dependencies = [ + "base64", + "bytes", + "futures-core", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-tls", + "hyper-util", + "js-sys", + "log", + "native-tls", + "percent-encoding", + "pin-project-lite", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-native-tls", + "tower", + "tower-http 0.6.11", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "reqwest" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219c5811de6525e5416c7d5d53bb656d3afdbc6c5af816e0802bcfa42dbdc1c3" dependencies = [ "base64", "bytes", @@ -3125,23 +3587,24 @@ dependencies = [ "http-body-util", "hyper", "hyper-rustls", - "hyper-tls", "hyper-util", "js-sys", "log", "mime", - "native-tls", "percent-encoding", "pin-project-lite", + "quinn", + "rustls", "rustls-pki-types", + "rustls-platform-verifier", "serde", "serde_json", "serde_urlencoded", "sync_wrapper", "tokio", - "tokio-native-tls", + "tokio-rustls", "tower", - "tower-http", + "tower-http 0.6.11", "tower-service", "url", "wasm-bindgen", @@ -3161,10 +3624,20 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" dependencies = [ - "hmac", + "hmac 0.12.1", "subtle", ] +[[package]] +name = "rfc6979" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4a459cddafb3fe76b31fd8f1108007566c40301feb64dc7b54656eb7388172b" +dependencies = [ + "crypto-bigint 0.7.5", + "hmac 0.13.0", +] + [[package]] name = "ring" version = "0.17.14" @@ -3179,26 +3652,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "rsa" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" -dependencies = [ - "const-oid", - "digest", - "num-bigint-dig", - "num-integer", - "num-traits", - "pkcs1", - "pkcs8", - "rand_core 0.6.4", - "signature", - "spki", - "subtle", - "zeroize", -] - [[package]] name = "rustc-demangle" version = "0.1.28" @@ -3211,6 +3664,24 @@ version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rusticata-macros" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" +dependencies = [ + "nom", +] + [[package]] name = "rustix" version = "1.1.4" @@ -3240,15 +3711,55 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rustls-native-certs" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dab5152771c58876a2146916e53e35057e1a4dfa2b9df0f0305b07f611fdea4d" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework", +] + [[package]] name = "rustls-pki-types" version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "764899a24af3980067ee14bc143654f297b22eaebfe3c7b6b211920a5a59b046" dependencies = [ + "web-time", "zeroize", ] +[[package]] +name = "rustls-platform-verifier" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d1e2536ce4f35f4846aa13bff16bd0ff40157cdb14cc056c7b14ba41233ba0" +dependencies = [ + "core-foundation 0.10.1", + "core-foundation-sys", + "jni", + "log", + "once_cell", + "rustls", + "rustls-native-certs", + "rustls-platform-verifier-android", + "rustls-webpki", + "security-framework", + "security-framework-sys", + "webpki-root-certs", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls-platform-verifier-android" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" + [[package]] name = "rustls-webpki" version = "0.103.13" @@ -3273,6 +3784,15 @@ version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "schannel" version = "0.1.29" @@ -3294,10 +3814,23 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ - "base16ct", - "der", + "base16ct 0.2.0", + "der 0.7.10", "generic-array", - "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "sec1" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d56d437c2f19203ce5f7122e507831de96f3d2d4d3be5af44a0b0a09d8a80e4d" +dependencies = [ + "base16ct 1.0.0", + "ctutils", + "der 0.8.0", + "hybrid-array", "subtle", "zeroize", ] @@ -3455,6 +3988,16 @@ dependencies = [ "serde", ] +[[package]] +name = "serdect" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66cf8fedced2fcf12406bcb34223dffb92eaf34908ede12fed414c82b7f00b3e" +dependencies = [ + "base16ct 1.0.0", + "serde", +] + [[package]] name = "serial_test" version = "3.5.0" @@ -3488,7 +4031,18 @@ checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", "cpufeatures 0.2.17", - "digest", + "digest 0.10.7", +] + +[[package]] +name = "sha1" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aacc4cc499359472b4abe1bf11d0b12e688af9a805fa5e3016f9a386dc2d0214" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "digest 0.11.3", ] [[package]] @@ -3499,7 +4053,18 @@ checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", "cpufeatures 0.2.17", - "digest", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "digest 0.11.3", ] [[package]] @@ -3533,16 +4098,42 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ - "digest", + "digest 0.10.7", "rand_core 0.6.4", ] +[[package]] +name = "signature" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d567dcbaf0049cb8ac2608a76cd95ff9e4412e1899d389ee400918ca7537f5" +dependencies = [ + "digest 0.11.3", + "rand_core 0.10.1", +] + [[package]] name = "simd-adler32" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" +[[package]] +name = "simd_cesu8" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94f90157bb87cddf702797c5dadfa0be7d266cdf49e22da2fcaa32eff75b2c33" +dependencies = [ + "rustc_version", + "simdutf8", +] + +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + [[package]] name = "simple_asn1" version = "0.6.4" @@ -3591,12 +4182,12 @@ dependencies = [ [[package]] name = "spki" -version = "0.7.3" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +checksum = "1d9efca8738c78ee9484207732f728b1ef517bbb1833d6fc0879ca898a522f6f" dependencies = [ "base64ct", - "der", + "der 0.8.0", ] [[package]] @@ -3611,9 +4202,9 @@ dependencies = [ [[package]] name = "sqlx" -version = "0.8.6" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fefb893899429669dcdd979aff487bd78f4064e5e7907e4269081e0ef7d97dc" +checksum = "378620ccc25c62c89d8be1c819e76a88d59bdcc3304733330788948e619bfd71" dependencies = [ "sqlx-core", "sqlx-macros", @@ -3624,12 +4215,13 @@ dependencies = [ [[package]] name = "sqlx-core" -version = "0.8.6" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee6798b1838b6a0f69c007c133b8df5866302197e404e8b6ee8ed3e3a5e68dc6" +checksum = "05b44e85bf579a8eeb4ceaa77a3a523baf2bf0e9bac7e40f405d537b5d2d5ccb" dependencies = [ "base64", "bytes", + "cfg-if", "chrono", "crc", "crossbeam-queue", @@ -3639,31 +4231,30 @@ dependencies = [ "futures-intrusive", "futures-io", "futures-util", - "hashbrown 0.15.5", + "hashbrown 0.16.1", "hashlink", "indexmap", "log", "memchr", - "once_cell", "percent-encoding", "rustls", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "smallvec", "thiserror 2.0.18", "tokio", "tokio-stream", "tracing", "url", - "webpki-roots 0.26.11", + "webpki-roots 1.0.8", ] [[package]] name = "sqlx-macros" -version = "0.8.6" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2d452988ccaacfbf5e0bdbc348fb91d7c8af5bee192173ac3636b5fb6e6715d" +checksum = "bd2b84f2bc39a5705ef27ec785a11c934a41bbd4a24941e257927cddc26b60bf" dependencies = [ "proc-macro2", "quote", @@ -3674,77 +4265,62 @@ dependencies = [ [[package]] name = "sqlx-macros-core" -version = "0.8.6" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19a9c1841124ac5a61741f96e1d9e2ec77424bf323962dd894bdb93f37d5219b" +checksum = "fb8d96de5fdc85a5c4ec813432b523ec637e80ba98f046555f75f7908ddac7c3" dependencies = [ + "cfg-if", "dotenvy", "either", "heck", "hex", - "once_cell", "proc-macro2", "quote", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "sqlx-core", "sqlx-mysql", "sqlx-postgres", "sqlx-sqlite", "syn", + "thiserror 2.0.18", "tokio", "url", ] [[package]] name = "sqlx-mysql" -version = "0.8.6" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa003f0038df784eb8fecbbac13affe3da23b45194bd57dba231c8f48199c526" +checksum = "90b8020fe17c5f2c245bfa2505d7ef59c5604839527c740266ad2214acebea27" dependencies = [ - "atoi", - "base64", "bitflags", "byteorder", "bytes", "chrono", "crc", - "digest", + "digest 0.11.3", "dotenvy", "either", - "futures-channel", "futures-core", - "futures-io", "futures-util", "generic-array", - "hex", - "hkdf", - "hmac", - "itoa", "log", - "md-5", - "memchr", - "once_cell", "percent-encoding", - "rand 0.8.6", - "rsa", "serde", - "sha1", - "sha2", - "smallvec", + "sha1 0.11.0", + "sha2 0.11.0", "sqlx-core", - "stringprep", "thiserror 2.0.18", "tracing", - "whoami", ] [[package]] name = "sqlx-postgres" -version = "0.8.6" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db58fcd5a53cf07c184b154801ff91347e4c30d17a3562a635ff028ad5deda46" +checksum = "87a2bdd6e83f6b3ea525ca9fee568030508b58355a43d0b2c1674d5f79dcd65e" dependencies = [ "atoi", "base64", @@ -3758,18 +4334,16 @@ dependencies = [ "futures-core", "futures-util", "hex", - "hkdf", - "hmac", - "home", + "hkdf 0.13.0", + "hmac 0.13.0", "itoa", "log", "md-5", "memchr", - "once_cell", - "rand 0.8.6", + "rand 0.10.2", "serde", "serde_json", - "sha2", + "sha2 0.11.0", "smallvec", "sqlx-core", "stringprep", @@ -3780,13 +4354,14 @@ dependencies = [ [[package]] name = "sqlx-sqlite" -version = "0.8.6" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2d12fe70b2c1b4401038055f90f151b78208de1f9f89a7dbfd41587a10c3eea" +checksum = "488e99c397a62007e4229aec669a179816339afc6d2620ca6fa420dbee2e982c" dependencies = [ "atoi", "chrono", "flume", + "form_urlencoded", "futures-channel", "futures-core", "futures-executor", @@ -3796,7 +4371,6 @@ dependencies = [ "log", "percent-encoding", "serde", - "serde_urlencoded", "sqlx-core", "thiserror 2.0.18", "tracing", @@ -4090,9 +4664,9 @@ dependencies = [ [[package]] name = "tokio-tungstenite" -version = "0.26.2" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a9daff607c6d2bf6c16fd681ccb7eecc83e4e2cdc1ca067ffaadfca5de7f084" +checksum = "8f72a05e828585856dacd553fba484c242c46e391fb0e58917c942ee9202915c" dependencies = [ "futures-util", "log", @@ -4181,6 +4755,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" dependencies = [ "async-compression", + "bitflags", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-body-util", + "pin-project-lite", + "tokio", + "tokio-util", + "tower", + "tower-layer", + "tower-service", + "url", +] + +[[package]] +name = "tower-http" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b11f75e912b0c2be01b63d8cf8057b8c3f97cf34abb3d431a3a4c8675498e233" +dependencies = [ "bitflags", "bytes", "futures-core", @@ -4196,11 +4792,9 @@ dependencies = [ "pin-project-lite", "tokio", "tokio-util", - "tower", "tower-layer", "tower-service", "tracing", - "url", ] [[package]] @@ -4309,9 +4903,9 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "tungstenite" -version = "0.26.2" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4793cb5e56680ecbb1d843515b23b6de9a75eb04b66643e256a396d43be33c13" +checksum = "6c01152af293afb9c7c2a57e4b559c5620b421f6d133261c60dd2d0cdb38e6b8" dependencies = [ "bytes", "data-encoding", @@ -4321,9 +4915,8 @@ dependencies = [ "rand 0.9.4", "rustls", "rustls-pki-types", - "sha1", + "sha1 0.10.6", "thiserror 2.0.18", - "utf-8", ] [[package]] @@ -4385,12 +4978,12 @@ checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "universal-hash" -version = "0.5.1" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +checksum = "f4987bdc12753382e0bec4a65c50738ffaabc998b9cdd1f952fb5f39b0048a96" dependencies = [ - "crypto-common", - "subtle", + "crypto-common 0.2.2", + "ctutils", ] [[package]] @@ -4423,12 +5016,6 @@ version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" -[[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - [[package]] name = "utf8_iter" version = "1.0.4" @@ -4464,6 +5051,16 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "want" version = "0.3.1" @@ -4488,12 +5085,6 @@ dependencies = [ "wit-bindgen", ] -[[package]] -name = "wasite" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" - [[package]] name = "wasm-bindgen" version = "0.2.126" @@ -4709,7 +5300,7 @@ dependencies = [ "rustix", "serde", "serde_derive", - "sha2", + "sha2 0.10.9", "toml", "windows-sys 0.60.2", "zstd", @@ -4914,6 +5505,15 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webpki-root-certs" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d46a5a140e6f7afeccd8eae97eff335163939eac8b929834875168b29b3d267" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "webpki-roots" version = "0.26.11" @@ -4943,13 +5543,9 @@ dependencies = [ [[package]] name = "whoami" -version = "1.6.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d4a4db5077702ca3015d3d02d74974948aba2ad9e12ab7df718ee64ccd7e97d" -dependencies = [ - "libredox", - "wasite", -] +checksum = "998767ef88740d1f5b0682a9c53c24431453923962269c2db68ee43788c5a40d" [[package]] name = "widestring" @@ -5078,15 +5674,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - [[package]] name = "windows-sys" version = "0.52.0" @@ -5114,21 +5701,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - [[package]] name = "windows-targets" version = "0.52.6" @@ -5162,12 +5734,6 @@ dependencies = [ "windows_x86_64_msvc 0.53.1", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" @@ -5180,12 +5746,6 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - [[package]] name = "windows_aarch64_msvc" version = "0.52.6" @@ -5198,12 +5758,6 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -5228,12 +5782,6 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - [[package]] name = "windows_i686_msvc" version = "0.52.6" @@ -5246,12 +5794,6 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - [[package]] name = "windows_x86_64_gnu" version = "0.52.6" @@ -5264,12 +5806,6 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" @@ -5282,12 +5818,6 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - [[package]] name = "windows_x86_64_msvc" version = "0.52.6" @@ -5356,18 +5886,48 @@ dependencies = [ "wasmparser 0.236.1", ] +[[package]] +name = "wnaf" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab12e7090f27e2ffd9322651492942d50c2926094af30601e1964337db39daf1" +dependencies = [ + "ff 0.14.0", + "group 0.14.0", + "hybrid-array", +] + [[package]] name = "writeable" version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" +[[package]] +name = "x509-parser" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d43b0f71ce057da06bc0851b23ee24f3f86190b07203dd8f567d0b706a185202" +dependencies = [ + "asn1-rs", + "data-encoding", + "der-parser", + "lazy_static", + "nom", + "oid-registry", + "ring", + "rusticata-macros", + "thiserror 2.0.18", + "time", +] + [[package]] name = "yasna" -version = "0.5.2" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" +checksum = "b5f6765e852b9b4dc8e2a76843e4d64d1cea8e79bcde0b6901aea8e7c7f08282" dependencies = [ + "bit-vec", "time", ] @@ -5442,6 +6002,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" dependencies = [ "serde", + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c50655cbb0fe3fc43170059e702f1ce5e19b84cec58dc87b037a09935c2f328" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 571d79d..7bc93bc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,10 +2,11 @@ name = "happyview" version = "0.1.0" edition = "2024" +rust-version = "1.96" default-run = "happyview" [dependencies] -aes-gcm = "0.10" +aes-gcm = "0.11" anyhow = "1" arc-swap = "1" atrium-oauth = { version = "0.1", features = ["default-client"] } @@ -14,7 +15,7 @@ atrium-common = "0.1" atrium-api = { version = "0.25", features = ["agent"] } atrium-xrpc = "0.12" axum = { version = "0.8", features = ["multipart"] } -axum-extra = { version = "0.10", features = ["cookie", "cookie-signed", "cookie-key-expansion", "query"] } +axum-extra = { version = "0.12", features = ["cookie", "cookie-signed", "cookie-key-expansion", "query"] } base64 = "0.22" dashmap = "6" data-encoding = "2" @@ -22,44 +23,44 @@ dotenvy = "0.15" hex = "0.4" futures-util = "0.3" jose-jwk = { version = "0.1", default-features = false, features = ["p256"] } -jsonwebtoken = "9" +jsonwebtoken = "10" bytes = "1" chrono = { version = "0.4", features = ["serde"] } cid = "0.11" ciborium = "0.2" -k256 = { version = "0.13", features = ["ecdsa"] } +k256 = { version = "0.14", features = ["ecdsa"] } multibase = "0.9" -p256 = { version = "0.13", features = ["pkcs8", "ecdsa"] } +p256 = { version = "0.14", features = ["pkcs8", "ecdsa"] } uuid = { version = "1", features = ["v4"] } -rand = "0.9" -reqwest = { version = "0.12", features = ["json"] } +rand = "0.10" +reqwest = { version = "0.13", features = ["json", "form"] } rustls = { version = "0.23", default-features = false, features = ["ring", "std", "tls12"] } serde = { version = "1", features = ["derive"] } serde_ipld_dagcbor = "0.6" serde_json = "1" -sha2 = "0.10" -sqlx = { version = "0.8", features = ["runtime-tokio", "tls-rustls", "postgres", "sqlite", "any", "json", "chrono", "migrate"] } +sha2 = "0.11" +sqlx = { version = "0.9", features = ["runtime-tokio", "tls-rustls", "postgres", "sqlite", "any", "json", "chrono", "migrate"] } tokio = { version = "1", features = ["full"] } tokio-rustls = "0.26" -tokio-tungstenite = { version = "0.26", features = ["rustls-tls-webpki-roots"] } +tokio-tungstenite = { version = "0.29", features = ["rustls-tls-webpki-roots"] } thiserror = "2" tower = { version = "0.5", features = ["util"] } -tower-http = { version = "0.6", features = ["cors", "fs", "trace"] } +tower-http = { version = "0.7", features = ["cors", "fs", "trace"] } http-body-util = "0.1" -hickory-resolver = "0.25" +hickory-resolver = "0.26" ipnet = "2" -mlua = { version = "0.11", features = ["lua54", "async", "serialize", "vendored", "send"] } +mlua = { version = "0.12", features = ["lua54", "async", "serialize", "vendored", "send"] } tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter", "json"] } urlencoding = "2.1.3" -webpki-roots = "0.26" +webpki-roots = "1.0" wasmtime = { version = ">=36.0.7, <37", features = ["async"] } regex = "1.12.3" semver = "1.0" async-stream = "0.3.6" blake3 = "1" -hkdf = "0.12" -hmac = "0.12" +hkdf = "0.13" +hmac = "0.13" sqlparser = "0.62.0" [[bin]] @@ -73,4 +74,4 @@ http-body-util = "0.1" serial_test = "3" urlencoding = "2.1.3" futures = "0.3" -rcgen = "0.13" +rcgen = "0.14" diff --git a/Dockerfile b/Dockerfile index b2d8e91..971edbc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,7 +7,7 @@ COPY web/ . ENV NEXT_PUBLIC_BASE_PATH=/__HAPPYVIEW_BP__ RUN npm run build -FROM rust:1.93-bookworm AS builder +FROM rust:1.96.1-bookworm AS builder WORKDIR /app diff --git a/docker-compose.yml b/docker-compose.yml index a2c843f..786a9bd 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -20,7 +20,7 @@ services: # retries: 5 happyview: - image: rust:1.93 + image: rust:1.96.1 working_dir: /app entrypoint: ["sh", "/scripts/entrypoint.sh"] command: cargo watch -x run diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..9403822 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,3 @@ +[toolchain] +channel = "1.96.1" +components = ["clippy", "rustfmt"] diff --git a/src/admin/api_clients.rs b/src/admin/api_clients.rs index 891bd3f..3dcfd2e 100644 --- a/src/admin/api_clients.rs +++ b/src/admin/api_clients.rs @@ -41,13 +41,13 @@ pub(super) async fn create_api_client( // Generate the client key: "hvc_" + 32 random hex chars. let mut random_bytes = [0u8; 16]; - rand::rng().fill(&mut random_bytes); + rand::rng().fill_bytes(&mut random_bytes); let client_key = format!("hvc_{}", hex::encode(random_bytes)); // Generate the client secret for confidential clients only. let (client_secret, client_secret_hash) = if body.client_type == "confidential" { let mut secret_bytes = [0u8; 32]; - rand::rng().fill(&mut secret_bytes); + rand::rng().fill_bytes(&mut secret_bytes); let secret = format!("hvs_{}", hex::encode(secret_bytes)); let hash = hex::encode(Sha256::digest(secret.as_bytes())); (Some(secret), hash) @@ -70,7 +70,7 @@ pub(super) async fn create_api_client( state.db_backend, ); - sqlx::query(&insert_sql) + crate::db::query(&insert_sql) .bind(&id) .bind(&client_key) .bind(&client_secret_hash) @@ -188,7 +188,7 @@ pub(super) async fn list_api_clients( ) }; - let q = sqlx::query(&select_sql); + let q = crate::db::query(&select_sql); let q = if let Some(ref pid) = parent_filter { q.bind(pid) } else { @@ -249,7 +249,7 @@ pub(super) async fn get_api_client( state.db_backend, ); - let row = sqlx::query(&select_sql) + let row = crate::db::query(&select_sql) .bind(&id) .fetch_optional(&state.db) .await @@ -316,7 +316,7 @@ pub(super) async fn update_api_client( Option, i32, ); - let row: Option = sqlx::query_as(&select_sql) + let row: Option = crate::db::query_as(&select_sql) .bind(&id) .fetch_optional(&state.db) .await @@ -366,7 +366,7 @@ pub(super) async fn update_api_client( state.db_backend, ); - sqlx::query(&update_sql) + crate::db::query(&update_sql) .bind(&name) .bind(&client_uri) .bind(&redirect_uris_json) @@ -438,7 +438,7 @@ pub(super) async fn update_api_client( "UPDATE happyview_api_clients SET is_active = 0, updated_at = ? WHERE parent_client_id = ? AND is_active = 1", state.db_backend, ); - let _ = sqlx::query(&deactivate_children_sql) + let _ = crate::db::query(&deactivate_children_sql) .bind(&now) .bind(&id) .execute(&state.db) @@ -448,7 +448,7 @@ pub(super) async fn update_api_client( "SELECT client_id_url, client_key FROM happyview_api_clients WHERE parent_client_id = ?", state.db_backend, ); - if let Ok(children) = sqlx::query_as::<_, (String, String)>(&children_sql) + if let Ok(children) = crate::db::query_as::<(String, String)>(&children_sql) .bind(&id) .fetch_all(&state.db) .await @@ -490,7 +490,7 @@ pub(super) async fn delete_api_client( "SELECT client_id_url, client_key FROM happyview_api_clients WHERE id = ?", state.db_backend, ); - let client_info: Option<(String, String)> = sqlx::query_as(&lookup_sql) + let client_info: Option<(String, String)> = crate::db::query_as(&lookup_sql) .bind(&id) .fetch_optional(&state.db) .await @@ -501,7 +501,7 @@ pub(super) async fn delete_api_client( "SELECT client_id_url, client_key FROM happyview_api_clients WHERE parent_client_id = ?", state.db_backend, ); - let children: Vec<(String, String)> = sqlx::query_as(&children_sql) + let children: Vec<(String, String)> = crate::db::query_as(&children_sql) .bind(&id) .fetch_all(&state.db) .await @@ -512,7 +512,7 @@ pub(super) async fn delete_api_client( state.db_backend, ); - let result = sqlx::query(&delete_sql) + let result = crate::db::query(&delete_sql) .bind(&id) .execute(&state.db) .await @@ -557,7 +557,7 @@ mod tests { #[test] fn test_client_key_prefix() { let mut random_bytes = [0u8; 16]; - rand::Rng::fill(&mut rand::rng(), &mut random_bytes); + rand::Rng::fill_bytes(&mut rand::rng(), &mut random_bytes); let key = format!("hvc_{}", hex::encode(random_bytes)); assert!(key.starts_with("hvc_")); assert_eq!(key.len(), 4 + 32); // "hvc_" + 32 hex chars diff --git a/src/admin/api_keys.rs b/src/admin/api_keys.rs index e46150c..6e5277a 100644 --- a/src/admin/api_keys.rs +++ b/src/admin/api_keys.rs @@ -41,7 +41,7 @@ pub(super) async fn create_api_key( // Generate the raw key: "hv_" + 32 random hex chars. let mut random_bytes = [0u8; 16]; - rand::rng().fill(&mut random_bytes); + rand::rng().fill_bytes(&mut random_bytes); let raw_key = format!("hv_{}", hex::encode(random_bytes)); // SHA-256 hash for storage. @@ -60,7 +60,7 @@ pub(super) async fn create_api_key( state.db_backend, ); - sqlx::query(&insert_sql) + crate::db::query(&insert_sql) .bind(&id) .bind(&auth.user_id) .bind(&body.name) @@ -118,7 +118,7 @@ pub(super) async fn list_api_keys( String, Option, Option, - )> = sqlx::query_as(&select_sql) + )> = crate::db::query_as(&select_sql) .bind(&auth.did) .fetch_all(&state.db) .await @@ -160,7 +160,7 @@ pub(super) async fn revoke_api_key( state.db_backend, ); - let result = sqlx::query(&update_sql) + let result = crate::db::query(&update_sql) .bind(&now) .bind(&id) .bind(&auth.did) diff --git a/src/admin/auth.rs b/src/admin/auth.rs index d6a1536..9801306 100644 --- a/src/admin/auth.rs +++ b/src/admin/auth.rs @@ -57,7 +57,7 @@ impl UserAuth { "SELECT permission FROM happyview_user_permissions WHERE user_id = ?", backend, ); - let rows: Vec<(String,)> = sqlx::query_as(&sql) + let rows: Vec<(String,)> = crate::db::query_as(&sql) .bind(user_id) .fetch_all(db) .await @@ -110,7 +110,7 @@ impl FromRequestParts for UserAuth { let did = claims.did().to_string(); let backend = state.db_backend; - let count: (i64,) = sqlx::query_as("SELECT COUNT(*) FROM happyview_users") + let count: (i64,) = crate::db::query_as("SELECT COUNT(*) FROM happyview_users") .fetch_one(&state.db) .await .map_err(|e| AppError::Internal(format!("user count query failed: {e}")))?; @@ -125,7 +125,7 @@ impl FromRequestParts for UserAuth { backend, ); - let result = sqlx::query(&insert_sql) + let result = crate::db::query(&insert_sql) .bind(&id) .bind(&did) .bind(1_i32) @@ -139,7 +139,7 @@ impl FromRequestParts for UserAuth { backend, ); for perm in Permission::all() { - let _ = sqlx::query(&perm_sql) + let _ = crate::db::query(&perm_sql) .bind(&id) .bind(perm.as_str()) .bind(&now) @@ -168,7 +168,7 @@ impl FromRequestParts for UserAuth { "SELECT id, is_super FROM happyview_users WHERE did = ?", backend, ); - let found: Option<(String, i32)> = sqlx::query_as(&select_sql) + let found: Option<(String, i32)> = crate::db::query_as(&select_sql) .bind(&did) .fetch_optional(&state.db) .await @@ -193,7 +193,7 @@ impl FromRequestParts for UserAuth { backend, ); tokio::spawn(async move { - let _ = sqlx::query(&update_sql) + let _ = crate::db::query(&update_sql) .bind(&now) .bind(&uid) .execute(&db) @@ -239,7 +239,7 @@ impl UserAuth { backend, ); - let row: Option<(String, String, String, i32, String)> = sqlx::query_as(&select_sql) + let row: Option<(String, String, String, i32, String)> = crate::db::query_as(&select_sql) .bind(&hash) .fetch_optional(&state.db) .await @@ -272,7 +272,7 @@ impl UserAuth { backend, ); tokio::spawn(async move { - let _ = sqlx::query(&update_sql) + let _ = crate::db::query(&update_sql) .bind(&now) .bind(&key_id) .execute(&db) diff --git a/src/admin/backfill.rs b/src/admin/backfill.rs index 8c0844e..2f4e00f 100644 --- a/src/admin/backfill.rs +++ b/src/admin/backfill.rs @@ -12,7 +12,7 @@ use serde_json::Value; use tokio::sync::mpsc; use uuid::Uuid; -use rand::Rng; +use rand::RngExt; use crate::AppState; use crate::db::{adapt_sql, now_rfc3339}; @@ -62,7 +62,7 @@ async fn set_stage(state: &AppState, job_id: &str, stage: &str) { "UPDATE happyview_backfill_jobs SET stage = ? WHERE id = ?", state.db_backend, ); - let _ = sqlx::query(&sql) + let _ = crate::db::query(&sql) .bind(stage) .bind(job_id) .execute(&state.backfill_db) @@ -91,7 +91,7 @@ async fn update_job_counter(state: &AppState, job_id: &str, column: &str, value: } }; let sql = adapt_sql(query, state.db_backend); - let _ = sqlx::query(&sql) + let _ = crate::db::query(&sql) .bind(value) .bind(job_id) .execute(&state.backfill_db) @@ -103,7 +103,7 @@ async fn count_repos(state: &AppState, job_id: &str) -> i32 { "SELECT COUNT(*) FROM happyview_backfill_repos WHERE job_id = ?", state.db_backend, ); - sqlx::query_as::<_, (i32,)>(&sql) + crate::db::query_as::<(i32,)>(&sql) .bind(job_id) .fetch_one(&state.backfill_db) .await @@ -163,7 +163,7 @@ async fn fail_job(state: &AppState, job_id: &str, error: &str) { "UPDATE happyview_backfill_jobs SET status = 'failed', completed_at = ?, error = ? WHERE id = ?", state.db_backend, ); - let _ = sqlx::query(&sql) + let _ = crate::db::query(&sql) .bind(&now) .bind(error) .bind(job_id) @@ -184,7 +184,7 @@ async fn should_stop(state: &AppState, job_id: &str) -> Option<&'static str> { "SELECT status FROM happyview_backfill_jobs WHERE id = ?", state.db_backend, ); - let status = sqlx::query_as::<_, (String,)>(&sql) + let status = crate::db::query_as::<(String,)>(&sql) .bind(job_id) .fetch_optional(&state.backfill_db) .await @@ -207,7 +207,7 @@ async fn request_cancel(state: &AppState, job_id: &str) { "UPDATE happyview_backfill_jobs SET status = 'cancelling' WHERE id = ? AND status IN ('running', 'paused')", state.db_backend, ); - let _ = sqlx::query(&sql) + let _ = crate::db::query(&sql) .bind(job_id) .execute(&state.backfill_db) .await; @@ -219,7 +219,7 @@ async fn finalise_cancel(state: &AppState, job_id: &str) { "UPDATE happyview_backfill_jobs SET status = 'cancelled', completed_at = ?, error = 'cancelled by user' WHERE id = ?", state.db_backend, ); - let _ = sqlx::query(&sql) + let _ = crate::db::query(&sql) .bind(&now) .bind(job_id) .execute(&state.backfill_db) @@ -239,7 +239,7 @@ async fn request_pause(state: &AppState, job_id: &str) { "UPDATE happyview_backfill_jobs SET status = 'pausing' WHERE id = ? AND status = 'running'", state.db_backend, ); - let _ = sqlx::query(&sql) + let _ = crate::db::query(&sql) .bind(job_id) .execute(&state.backfill_db) .await; @@ -250,7 +250,7 @@ async fn finalise_pause(state: &AppState, job_id: &str) { "UPDATE happyview_backfill_jobs SET status = 'paused' WHERE id = ?", state.db_backend, ); - let _ = sqlx::query(&sql) + let _ = crate::db::query(&sql) .bind(job_id) .execute(&state.backfill_db) .await; @@ -276,7 +276,7 @@ async fn complete_job( "UPDATE happyview_backfill_jobs SET status = 'completed', stage = 'completed', completed_at = ?, processed_repos = ?, total_records = ?, error = ? WHERE id = ?", state.db_backend, ); - let _ = sqlx::query(&sql) + let _ = crate::db::query(&sql) .bind(&now) .bind(processed_repos) .bind(total_records) @@ -311,7 +311,7 @@ async fn run_discovery_phase( "INSERT INTO happyview_backfill_repos (job_id, did) VALUES (?, ?) ON CONFLICT DO NOTHING", state.db_backend, ); - let _ = sqlx::query(&sql) + let _ = crate::db::query(&sql) .bind(job_id) .bind(did) .execute(&state.backfill_db) @@ -422,7 +422,7 @@ async fn discover_repos_from_relay( placeholders.join(", ") ); - let mut query = sqlx::query(&sql); + let mut query = crate::db::query(&sql); for repo in chunk { query = query.bind(job_id).bind(&repo.did); } @@ -475,7 +475,7 @@ async fn run_pipelined_resolve_and_fetch( "SELECT COUNT(*) FROM happyview_backfill_repos WHERE job_id = ? AND pds_endpoint IS NOT NULL", state.db_backend, ); - sqlx::query_as::<_, (i32,)>(&sql) + crate::db::query_as::<(i32,)>(&sql) .bind(job_id) .fetch_one(&state.backfill_db) .await @@ -488,7 +488,7 @@ async fn run_pipelined_resolve_and_fetch( "SELECT COUNT(*) FROM happyview_backfill_repos WHERE job_id = ? AND status = 'completed'", state.db_backend, ); - sqlx::query_as::<_, (i32,)>(&sql) + crate::db::query_as::<(i32,)>(&sql) .bind(job_id) .fetch_one(&state.backfill_db) .await @@ -504,7 +504,7 @@ async fn run_pipelined_resolve_and_fetch( "SELECT total_records FROM happyview_backfill_jobs WHERE id = ?", state.db_backend, ); - sqlx::query_as::<_, (Option,)>(&sql) + crate::db::query_as::<(Option,)>(&sql) .bind(job_id) .fetch_one(&state.backfill_db) .await @@ -534,7 +534,7 @@ async fn run_pipelined_resolve_and_fetch( "SELECT did FROM happyview_backfill_repos WHERE job_id = ? AND pds_endpoint IS NULL", resolver_state.db_backend, ); - let unresolved: Vec<(String,)> = sqlx::query_as(&sql) + let unresolved: Vec<(String,)> = crate::db::query_as(&sql) .bind(&resolver_job_id) .fetch_all(&resolver_state.backfill_db) .await @@ -573,7 +573,7 @@ async fn run_pipelined_resolve_and_fetch( "UPDATE happyview_backfill_repos SET pds_endpoint = ? WHERE job_id = ? AND did = ?", resolver_state.db_backend, ); - let _ = sqlx::query(&sql) + let _ = crate::db::query(&sql) .bind(&pds) .bind(&resolver_job_id) .bind(&did) @@ -647,7 +647,7 @@ async fn run_pipelined_resolve_and_fetch( "SELECT did, pds_endpoint FROM happyview_backfill_repos WHERE job_id = ? AND status = 'pending' AND pds_endpoint IS NOT NULL", state.db_backend, ); - let pending_rows: Vec<(String, String)> = sqlx::query_as(&pending_sql) + let pending_rows: Vec<(String, String)> = crate::db::query_as(&pending_sql) .bind(job_id) .fetch_all(&state.backfill_db) .await @@ -830,7 +830,7 @@ async fn run_pipelined_resolve_and_fetch( "UPDATE happyview_backfill_jobs SET processed_repos = ?, total_records = ? WHERE id = ?", state.db_backend, ); - let _ = sqlx::query(&sql) + let _ = crate::db::query(&sql) .bind(final_repos) .bind(final_records) .bind(job_id) @@ -877,7 +877,7 @@ async fn run_pds_worker(ctx: FetchContext, pds_endpoint: String, mut rx: mpsc::R "UPDATE happyview_backfill_repos SET status = 'completed', records_fetched = ? WHERE job_id = ? AND did = ?", state.db_backend, ); - let _ = sqlx::query(&sql) + let _ = crate::db::query(&sql) .bind(records) .bind(job_id.as_str()) .bind(&did) @@ -898,7 +898,7 @@ async fn run_pds_worker(ctx: FetchContext, pds_endpoint: String, mut rx: mpsc::R "UPDATE happyview_backfill_jobs SET processed_repos = ?, total_records = ? WHERE id = ?", state.db_backend, ); - let _ = sqlx::query(&sql) + let _ = crate::db::query(&sql) .bind(repos) .bind(records) .bind(job_id.as_str()) @@ -976,7 +976,7 @@ async fn run_pds_worker(ctx: FetchContext, pds_endpoint: String, mut rx: mpsc::R "UPDATE happyview_backfill_repos SET status = 'completed', records_fetched = ? WHERE job_id = ? AND did = ?", state.db_backend, ); - let _ = sqlx::query(&sql) + let _ = crate::db::query(&sql) .bind(records) .bind(job_id.as_str()) .bind(&did) @@ -1014,7 +1014,7 @@ async fn run_fetching_phase( "SELECT did, pds_endpoint FROM happyview_backfill_repos WHERE job_id = ? AND status = 'pending' AND pds_endpoint IS NOT NULL", state.db_backend, ); - let rows: Vec<(String, String)> = sqlx::query_as(&sql) + let rows: Vec<(String, String)> = crate::db::query_as(&sql) .bind(job_id) .fetch_all(&state.backfill_db) .await @@ -1030,7 +1030,7 @@ async fn run_fetching_phase( "SELECT COUNT(*) FROM happyview_backfill_repos WHERE job_id = ? AND status = 'completed'", state.db_backend, ); - let already_completed: i32 = sqlx::query_as::<_, (i32,)>(&sql) + let already_completed: i32 = crate::db::query_as::<(i32,)>(&sql) .bind(job_id) .fetch_one(&state.backfill_db) .await @@ -1046,7 +1046,7 @@ async fn run_fetching_phase( "SELECT total_records FROM happyview_backfill_jobs WHERE id = ?", state.db_backend, ); - sqlx::query_as::<_, (Option,)>(&sql) + crate::db::query_as::<(Option,)>(&sql) .bind(job_id) .fetch_one(&state.backfill_db) .await @@ -1130,7 +1130,7 @@ async fn run_fetching_phase( "UPDATE happyview_backfill_repos SET status = 'completed', records_fetched = ? WHERE job_id = ? AND did = ?", state.db_backend, ); - let _ = sqlx::query(&sql) + let _ = crate::db::query(&sql) .bind(did_records) .bind(job_id.as_str()) .bind(&did) @@ -1149,7 +1149,7 @@ async fn run_fetching_phase( "UPDATE happyview_backfill_jobs SET processed_repos = ?, total_records = ? WHERE id = ?", backend, ); - let _ = sqlx::query(&sql) + let _ = crate::db::query(&sql) .bind(repos) .bind(records) .bind(job_id.as_str()) @@ -1183,7 +1183,7 @@ async fn run_fetching_phase( "UPDATE happyview_backfill_jobs SET processed_repos = ?, total_records = ? WHERE id = ?", state.db_backend, ); - let _ = sqlx::query(&sql) + let _ = crate::db::query(&sql) .bind(final_repos) .bind(final_records) .bind(job_id) @@ -1220,7 +1220,7 @@ async fn batch_upsert_records(state: &AppState, batch: &[PreparedRecord]) { ); let sql = adapt_sql(&raw_sql, backend); - let mut query = sqlx::query(&sql); + let mut query = crate::db::query(&sql); for rec in batch { query = query .bind(&rec.uri) @@ -1245,7 +1245,7 @@ async fn batch_upsert_records(state: &AppState, batch: &[PreparedRecord]) { delete_placeholders.join(", ") ); let delete_sql = adapt_sql(&delete_raw, backend); - let mut del_query = sqlx::query(&delete_sql); + let mut del_query = crate::db::query(&delete_sql); for uri in &uris { del_query = del_query.bind(*uri); } @@ -1269,7 +1269,7 @@ async fn batch_upsert_records(state: &AppState, batch: &[PreparedRecord]) { ref_placeholders.join(", ") ); let ref_sql = adapt_sql(&ref_raw, backend); - let mut ref_query = sqlx::query(&ref_sql); + let mut ref_query = crate::db::query(&ref_sql); for (source, target, collection) in chunk { ref_query = ref_query.bind(*source).bind(target).bind(*collection); } @@ -1278,7 +1278,7 @@ async fn batch_upsert_records(state: &AppState, batch: &[PreparedRecord]) { // Queue label backfill only if there are active labeler subscriptions. // Check once per batch instead of spawning a task per record. - let has_subscriptions: bool = sqlx::query_as::<_, (i64,)>( + let has_subscriptions: bool = crate::db::query_as::<(i64,)>( "SELECT COUNT(*) FROM happyview_labeler_subscriptions WHERE status = 'active'", ) .fetch_one(&state.db) @@ -1398,7 +1398,7 @@ async fn run_backfill_job(state: AppState, job_id: String) { "SELECT collection, did, stage FROM happyview_backfill_jobs WHERE id = ?", backend, ); - let job: Option<(Option, Option, String)> = sqlx::query_as(&sql) + let job: Option<(Option, Option, String)> = crate::db::query_as(&sql) .bind(&job_id) .fetch_optional(&state.backfill_db) .await @@ -1428,7 +1428,10 @@ async fn run_backfill_job(state: AppState, job_id: String) { "SELECT id FROM happyview_lexicons WHERE json_extract(lexicon_json, '$.defs.main.type') = 'record'", backend, ); - let rows: Vec<(String,)> = match sqlx::query_as(&sql).fetch_all(&state.backfill_db).await { + let rows: Vec<(String,)> = match crate::db::query_as(&sql) + .fetch_all(&state.backfill_db) + .await + { Ok(rows) => rows, Err(e) => { let error = format!("failed to query backfill-eligible lexicons: {e}"); @@ -1556,7 +1559,7 @@ pub(super) async fn create_backfill( "INSERT INTO happyview_backfill_jobs (id, collection, did, status, stage, started_at, created_at) VALUES (?, ?, ?, 'running', 'pending', ?, ?) RETURNING id", backend, ); - let row: (String,) = sqlx::query_as(&sql) + let row: (String,) = crate::db::query_as(&sql) .bind(&job_id) .bind(&body.collection) .bind(&body.did) @@ -1610,7 +1613,7 @@ pub(super) async fn cancel_backfill( "SELECT status FROM happyview_backfill_jobs WHERE id = ?", state.db_backend, ); - let row: Option<(String,)> = sqlx::query_as(&sql) + let row: Option<(String,)> = crate::db::query_as(&sql) .bind(&job_id) .fetch_optional(&state.db) .await @@ -1675,7 +1678,7 @@ pub(super) async fn pause_backfill( "SELECT status FROM happyview_backfill_jobs WHERE id = ?", state.db_backend, ); - let row: Option<(String,)> = sqlx::query_as(&sql) + let row: Option<(String,)> = crate::db::query_as(&sql) .bind(&job_id) .fetch_optional(&state.backfill_db) .await @@ -1722,7 +1725,7 @@ pub(super) async fn resume_backfill( "SELECT status FROM happyview_backfill_jobs WHERE id = ?", state.db_backend, ); - let row: Option<(String,)> = sqlx::query_as(&sql) + let row: Option<(String,)> = crate::db::query_as(&sql) .bind(&job_id) .fetch_optional(&state.backfill_db) .await @@ -1738,7 +1741,7 @@ pub(super) async fn resume_backfill( "UPDATE happyview_backfill_jobs SET status = 'running' WHERE id = ?", state.db_backend, ); - let _ = sqlx::query(&sql) + let _ = crate::db::query(&sql) .bind(&job_id) .execute(&state.backfill_db) .await; @@ -1795,7 +1798,7 @@ pub(super) async fn backfill_status( Option, Option, String, - )> = sqlx::query_as(&sql) + )> = crate::db::query_as(&sql) .fetch_all(&state.backfill_db) .await .map_err(|e| AppError::Internal(format!("failed to list backfill jobs: {e}")))?; @@ -1925,7 +1928,7 @@ pub(super) async fn backfill_repos( ); let sql = adapt_sql(&sql_str, state.db_backend); - let mut q = sqlx::query_as::<_, (String, Option, String, i32)>(&sql).bind(&job_id); + let mut q = crate::db::query_as::<(String, Option, String, i32)>(&sql).bind(&job_id); if let Some(ref cursor) = query.cursor { q = q.bind(cursor); } @@ -1971,7 +1974,7 @@ pub(super) async fn backfill_pds_summary( state.db_backend, ); - let rows: Vec<(String, i32, i32, i64)> = sqlx::query_as(&sql) + let rows: Vec<(String, i32, i32, i64)> = crate::db::query_as(&sql) .bind(&job_id) .fetch_all(&state.backfill_db) .await @@ -2009,7 +2012,7 @@ pub(super) async fn flush_backfill_details( "DELETE FROM happyview_backfill_repos WHERE job_id = ?", state.db_backend, ); - let _ = sqlx::query(&sql) + let _ = crate::db::query(&sql) .bind(&job_id) .execute(&state.backfill_db) .await; @@ -2027,7 +2030,7 @@ pub(super) async fn flush_all_backfill_details( "DELETE FROM happyview_backfill_repos WHERE job_id IN (SELECT id FROM happyview_backfill_jobs WHERE status IN ('completed', 'cancelled', 'failed'))", state.db_backend, ); - let _ = sqlx::query(&sql).execute(&state.backfill_db).await; + let _ = crate::db::query(&sql).execute(&state.backfill_db).await; Ok(StatusCode::NO_CONTENT) } @@ -2064,7 +2067,7 @@ pub async fn run_backfill_retention_cleanup(state: &AppState) { "DELETE FROM happyview_backfill_repos WHERE job_id IN (SELECT id FROM happyview_backfill_jobs WHERE completed_at IS NOT NULL AND completed_at < ?)", state.db_backend, ); - match sqlx::query(&sql) + match crate::db::query(&sql) .bind(&cutoff_str) .execute(&state.backfill_db) .await @@ -2097,7 +2100,7 @@ pub async fn resume_backfill_jobs(state: &AppState) { "SELECT id, status FROM happyview_backfill_jobs WHERE status IN ('running', 'cancelling', 'pausing')", state.db_backend, ); - let rows: Vec<(String, String)> = sqlx::query_as(&sql) + let rows: Vec<(String, String)> = crate::db::query_as(&sql) .fetch_all(&state.backfill_db) .await .unwrap_or_default(); diff --git a/src/admin/dead_letters.rs b/src/admin/dead_letters.rs index 8838727..774af84 100644 --- a/src/admin/dead_letters.rs +++ b/src/admin/dead_letters.rs @@ -224,7 +224,7 @@ pub(super) async fn count( &format!("SELECT COUNT(*) FROM {table} WHERE 1=1{resolved_clause}{collection_clause}"), backend, ); - let mut q = sqlx::query_as::<_, (i64,)>(&sql); + let mut q = crate::db::query_as::<(i64,)>(&sql); if let Some(ref c) = query.collection { q = q.bind(c); } @@ -303,7 +303,7 @@ pub(super) async fn bulk_dismiss( sql.push_str(" AND collection = ?"); } let sql = adapt_sql(&sql, backend); - let mut q = sqlx::query(&sql).bind(&now); + let mut q = crate::db::query(&sql).bind(&now); if let Some(ref c) = body.collection { q = q.bind(c); } @@ -383,22 +383,19 @@ async fn list_legacy( let sql = adapt_sql(&sql, backend); #[allow(clippy::type_complexity)] - let mut q = sqlx::query_as::< - _, - ( - String, - String, - String, - String, - String, - String, - String, - String, - i64, - String, - Option, - ), - >(&sql); + let mut q = crate::db::query_as::<( + String, + String, + String, + String, + String, + String, + String, + String, + i64, + String, + Option, + )>(&sql); if let Some(c) = collection { q = q.bind(c); } @@ -457,20 +454,17 @@ async fn list_scripts( let sql = adapt_sql(&sql, backend); #[allow(clippy::type_complexity)] - let mut q = sqlx::query_as::< - _, - ( - i64, - String, - String, - String, - String, - String, - i64, - String, - Option, - ), - >(&sql); + let mut q = crate::db::query_as::<( + i64, + String, + String, + String, + String, + String, + i64, + String, + Option, + )>(&sql); if let Some(c) = collection { q = q.bind(c); } @@ -595,7 +589,7 @@ async fn detail_legacy(state: &AppState, id: &str) -> Result, Option, - ) = sqlx::query_as(&sql) + ) = crate::db::query_as(&sql) .bind(id) .fetch_optional(&state.db) .await @@ -642,7 +636,7 @@ async fn detail_scripts(state: &AppState, id: &str) -> Result, - ) = sqlx::query_as(&sql) + ) = crate::db::query_as(&sql) .bind(id_int) .fetch_optional(&state.db) .await @@ -703,7 +697,7 @@ async fn fetch_dead_letter_for_action( Option, String, i64, - ) = sqlx::query_as(&sql) + ) = crate::db::query_as(&sql) .bind(id) .fetch_optional(&state.db) .await @@ -731,7 +725,7 @@ async fn fetch_dead_letter_for_action( WHERE id = ? AND resolved_at IS NULL", backend, ); - let row: (i64, String, String) = sqlx::query_as(&sql) + let row: (i64, String, String) = crate::db::query_as(&sql) .bind(id_int) .fetch_optional(&state.db) .await @@ -781,7 +775,7 @@ async fn mark_resolved( &format!("UPDATE {table} SET resolved_at = ? WHERE id = ?"), backend, ); - let q = sqlx::query(&sql).bind(&now); + let q = crate::db::query(&sql).bind(&now); let q = match source { // Scripts table has INTEGER ids; bind as i64 to avoid sqlite's // implicit-conversion quirks. @@ -810,7 +804,7 @@ async fn update_error( &format!("UPDATE {table} SET error = ?, attempts = attempts + 1 WHERE id = ?"), backend, ); - let q = sqlx::query(&sql).bind(error); + let q = crate::db::query(&sql).bind(error); let q = match source { DeadLetterSource::Scripts => q.bind(id.parse::().unwrap_or(0)), DeadLetterSource::LegacyHooks => q.bind(id), @@ -833,7 +827,7 @@ async fn resolve_bulk_ids(state: &AppState, body: &BulkRequest) -> Result(&sql); + let mut q = crate::db::query_as::<(String,)>(&sql); if let Some(ref c) = body.collection { q = q.bind(c); } @@ -851,7 +845,7 @@ async fn resolve_bulk_ids(state: &AppState, body: &BulkRequest) -> Result(&sql); + let mut q = crate::db::query_as::<(i64,)>(&sql); if let Some(ref c) = body.collection { q = q.bind(c); } diff --git a/src/admin/domains.rs b/src/admin/domains.rs index 7b2c9bc..a4cb02e 100644 --- a/src/admin/domains.rs +++ b/src/admin/domains.rs @@ -33,7 +33,7 @@ pub(super) async fn list( "SELECT id, url, is_primary, created_at, updated_at FROM happyview_domains ORDER BY created_at", state.db_backend, ); - let rows: Vec<(String, String, i32, String, String)> = sqlx::query_as(&sql) + let rows: Vec<(String, String, i32, String, String)> = crate::db::query_as(&sql) .fetch_all(&state.db) .await .map_err(|e| AppError::Internal(format!("failed to list domains: {e}")))?; @@ -84,7 +84,7 @@ pub(super) async fn create( } // Check for duplicates - let existing: Option<(String,)> = sqlx::query_as(&adapt_sql( + let existing: Option<(String,)> = crate::db::query_as(&adapt_sql( "SELECT id FROM happyview_domains WHERE url = ?", state.db_backend, )) @@ -106,7 +106,7 @@ pub(super) async fn create( "INSERT INTO happyview_domains (id, url, is_primary, created_at, updated_at) VALUES (?, ?, 0, ?, ?)", state.db_backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(&id) .bind(&url) .bind(&now) @@ -198,7 +198,7 @@ pub(super) async fn delete( "SELECT id, url, is_primary, created_at, updated_at FROM happyview_domains WHERE id = ?", state.db_backend, ); - let row: Option<(String, String, i32, String, String)> = sqlx::query_as(&sql) + let row: Option<(String, String, i32, String, String)> = crate::db::query_as(&sql) .bind(&id) .fetch_optional(&state.db) .await @@ -217,7 +217,7 @@ pub(super) async fn delete( "DELETE FROM happyview_domains WHERE id = ?", state.db_backend, ); - sqlx::query(&delete_sql) + crate::db::query(&delete_sql) .bind(&id) .execute(&state.db) .await @@ -264,7 +264,7 @@ pub(super) async fn set_primary( "SELECT id, url, is_primary, created_at, updated_at FROM happyview_domains WHERE id = ?", state.db_backend, ); - let row: Option<(String, String, i32, String, String)> = sqlx::query_as(&sql) + let row: Option<(String, String, i32, String, String)> = crate::db::query_as(&sql) .bind(&id) .fetch_optional(&state.db) .await @@ -278,7 +278,7 @@ pub(super) async fn set_primary( "UPDATE happyview_domains SET is_primary = 0, updated_at = ? WHERE is_primary = 1", state.db_backend, ); - sqlx::query(&unset_sql) + crate::db::query(&unset_sql) .bind(&now) .execute(&state.db) .await @@ -288,7 +288,7 @@ pub(super) async fn set_primary( "UPDATE happyview_domains SET is_primary = 1, updated_at = ? WHERE id = ?", state.db_backend, ); - sqlx::query(&set_sql) + crate::db::query(&set_sql) .bind(&now) .bind(&id) .execute(&state.db) diff --git a/src/admin/events.rs b/src/admin/events.rs index a051293..e248efa 100644 --- a/src/admin/events.rs +++ b/src/admin/events.rs @@ -82,18 +82,15 @@ pub(super) async fn list_events( let sql = adapt_sql(&sql, backend); #[allow(clippy::type_complexity)] - let mut q = sqlx::query_as::< - _, - ( - String, - String, - String, - Option, - Option, - String, - String, - ), - >(&sql); + let mut q = crate::db::query_as::<( + String, + String, + String, + Option, + Option, + String, + String, + )>(&sql); if let Some(ref event_type) = query.event_type { q = q.bind(event_type); diff --git a/src/admin/labelers.rs b/src/admin/labelers.rs index 0aa9bf6..0582616 100644 --- a/src/admin/labelers.rs +++ b/src/admin/labelers.rs @@ -23,7 +23,7 @@ pub(super) async fn list( "SELECT did, status, cursor, created_at, updated_at FROM happyview_labeler_subscriptions ORDER BY created_at", backend, ); - let rows: Vec<(String, String, Option, String, String)> = sqlx::query_as(&sql) + let rows: Vec<(String, String, Option, String, String)> = crate::db::query_as(&sql) .fetch_all(&state.db) .await .map_err(|e| AppError::Internal(format!("failed to list labeler subscriptions: {e}")))?; @@ -62,7 +62,7 @@ pub(super) async fn add( "#, backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(&body.did) .bind(&now) .bind(&now) @@ -104,7 +104,7 @@ pub(super) async fn update( "UPDATE happyview_labeler_subscriptions SET status = ?, updated_at = ? WHERE did = ?", backend, ); - let result = sqlx::query(&sql) + let result = crate::db::query(&sql) .bind(&body.status) .bind(&now) .bind(&did) @@ -149,7 +149,7 @@ pub(super) async fn delete( "DELETE FROM happyview_labeler_subscriptions WHERE did = ?", backend, ); - let result = sqlx::query(&delete_sql) + let result = crate::db::query(&delete_sql) .bind(&did) .execute(&state.db) .await @@ -163,7 +163,7 @@ pub(super) async fn delete( // Also remove all labels from this labeler. let delete_labels_sql = adapt_sql("DELETE FROM happyview_labels WHERE src = ?", backend); - let _ = sqlx::query(&delete_labels_sql) + let _ = crate::db::query(&delete_labels_sql) .bind(&did) .execute(&state.db) .await; diff --git a/src/admin/lexicons.rs b/src/admin/lexicons.rs index 054d94d..aceff54 100644 --- a/src/admin/lexicons.rs +++ b/src/admin/lexicons.rs @@ -86,7 +86,7 @@ pub(super) async fn upload_lexicon( "#, backend, ); - let row: (i32,) = sqlx::query_as(&sql) + let row: (i32,) = crate::db::query_as(&sql) .bind(&id) .bind(&lexicon_json_str) .bind(if body.backfill { 1_i32 } else { 0_i32 }) @@ -178,7 +178,7 @@ pub(super) async fn list_lexicons( String, String, Option, - )> = sqlx::query_as(&sql) + )> = crate::db::query_as(&sql) .fetch_all(&state.db) .await .map_err(|e| AppError::Internal(format!("failed to list lexicons: {e}")))?; @@ -260,7 +260,7 @@ pub(super) async fn get_lexicon( String, String, Option, - )> = sqlx::query_as(&sql) + )> = crate::db::query_as(&sql) .bind(&id) .fetch_optional(&state.db) .await @@ -319,7 +319,7 @@ pub(super) async fn delete_lexicon( auth.require(Permission::LexiconsDelete).await?; let backend = state.db_backend; let sql = adapt_sql("DELETE FROM happyview_lexicons WHERE id = ?", backend); - let result = sqlx::query(&sql) + let result = crate::db::query(&sql) .bind(&id) .execute(&state.db) .await diff --git a/src/admin/network_lexicons.rs b/src/admin/network_lexicons.rs index ca7d43c..64b1d29 100644 --- a/src/admin/network_lexicons.rs +++ b/src/admin/network_lexicons.rs @@ -96,7 +96,7 @@ pub(super) async fn add( "#, backend, ); - let row: (i32,) = sqlx::query_as(&sql) + let row: (i32,) = crate::db::query_as(&sql) .bind(nsid) .bind(&lexicon_json_str) .bind(&body.target_collection) @@ -156,7 +156,7 @@ pub(super) async fn list( Option, Option, String, - )> = sqlx::query_as(&sql) + )> = crate::db::query_as(&sql) .fetch_all(&state.db) .await .map_err(|e| AppError::Internal(format!("failed to list network lexicons: {e}")))?; @@ -192,7 +192,7 @@ pub(super) async fn remove( "DELETE FROM happyview_lexicons WHERE id = ? AND source = 'network'", backend, ); - let result = sqlx::query(&sql) + let result = crate::db::query(&sql) .bind(&nsid) .execute(&state.db) .await diff --git a/src/admin/plugins.rs b/src/admin/plugins.rs index 59df06b..4d11721 100644 --- a/src/admin/plugins.rs +++ b/src/admin/plugins.rs @@ -93,7 +93,7 @@ pub(super) async fn list( "SELECT plugin_id FROM happyview_plugin_configs WHERE config IS NOT NULL", state.db_backend, ); - sqlx::query_scalar::<_, String>(&sql) + crate::db::query_scalar::(&sql) .fetch_all(&state.db) .await .unwrap_or_default() @@ -312,7 +312,7 @@ pub(super) async fn remove( "DELETE FROM happyview_plugins WHERE id = ?", state.db_backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(&plugin_id) .execute(&state.db) .await @@ -404,7 +404,7 @@ pub(super) async fn reload( "SELECT 1 FROM happyview_plugin_configs WHERE plugin_id = ?", state.db_backend, ); - sqlx::query_scalar::<_, i32>(&sql) + crate::db::query_scalar::(&sql) .bind(&plugin.info.id) .fetch_optional(&state.db) .await @@ -435,7 +435,7 @@ pub(super) async fn reload( "UPDATE happyview_plugins SET url = ?, sha256 = NULL WHERE id = ?", state.db_backend, ); - sqlx::query(&persist_sql) + crate::db::query(&persist_sql) .bind(&url) .bind(&plugin.info.id) .execute(&state.db) @@ -488,7 +488,7 @@ pub(super) async fn get_secrets( state.db_backend, ); - let row: Option<(String,)> = sqlx::query_as(&sql) + let row: Option<(String,)> = crate::db::query_as(&sql) .bind(&plugin_id) .fetch_optional(&state.db) .await @@ -558,7 +558,7 @@ pub(super) async fn update_secrets( state.db_backend, ); - let row: Option<(String,)> = sqlx::query_as(&sql) + let row: Option<(String,)> = crate::db::query_as(&sql) .bind(&plugin_id) .fetch_optional(&state.db) .await @@ -613,7 +613,7 @@ pub(super) async fn update_secrets( state.db_backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(&plugin_id) .bind(&config_json) .bind(now_rfc3339()) diff --git a/src/admin/proxy_config.rs b/src/admin/proxy_config.rs index 4b1f4e6..1ed87d9 100644 --- a/src/admin/proxy_config.rs +++ b/src/admin/proxy_config.rs @@ -55,7 +55,7 @@ pub(super) async fn put( "#, backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(SETTING_KEY) .bind(&json) .bind(&now) diff --git a/src/admin/records.rs b/src/admin/records.rs index 36a1887..9cfa6ad 100644 --- a/src/admin/records.rs +++ b/src/admin/records.rs @@ -80,7 +80,7 @@ pub(super) async fn list_records( "SELECT uri, did, collection, rkey, cid, indexed_at, record FROM happyview_records WHERE collection = ? ORDER BY indexed_at DESC LIMIT ? OFFSET ?", backend, ); - let rows: Vec = sqlx::query_as(&sql) + let rows: Vec = crate::db::query_as(&sql) .bind(¶ms.collection) .bind(limit + 1) .bind(offset) @@ -106,7 +106,7 @@ pub(super) async fn list_records( "SELECT uri, src, val, cts FROM happyview_labels WHERE uri IN ({ph_str}) AND (exp IS NULL OR exp > ?)" ); let sql = adapt_sql(&raw_sql, backend); - let mut q = sqlx::query_as(&sql); + let mut q = crate::db::query_as(&sql); for uri in &uris { q = q.bind(*uri); } @@ -190,7 +190,7 @@ pub(super) async fn delete_collection_records( "DELETE FROM happyview_records WHERE collection = ?", backend, ); - let result = sqlx::query(&sql) + let result = crate::db::query(&sql) .bind(¶ms.collection) .execute(&state.db) .await @@ -210,7 +210,7 @@ pub(super) async fn delete_record( auth.require(Permission::RecordsDelete).await?; let backend = state.db_backend; let sql = adapt_sql("DELETE FROM happyview_records WHERE uri = ?", backend); - let result = sqlx::query(&sql) + let result = crate::db::query(&sql) .bind(¶ms.uri) .execute(&state.db) .await @@ -234,7 +234,7 @@ pub(super) async fn list_collections( "SELECT id FROM happyview_lexicons WHERE json_extract(lexicon_json, '$.defs.main.type') = 'record' ORDER BY id", state.db_backend, ); - let rows: Vec<(String,)> = sqlx::query_as(&sql) + let rows: Vec<(String,)> = crate::db::query_as(&sql) .fetch_all(&state.db) .await .map_err(|e| AppError::Internal(format!("failed to list collections: {e}")))?; diff --git a/src/admin/script_variables.rs b/src/admin/script_variables.rs index 5c71e5c..11e53d6 100644 --- a/src/admin/script_variables.rs +++ b/src/admin/script_variables.rs @@ -23,7 +23,7 @@ pub(super) async fn list( "SELECT key, value, created_at, updated_at FROM happyview_script_variables ORDER BY key", backend, ); - let rows: Vec<(String, String, String, String)> = sqlx::query_as(&sql) + let rows: Vec<(String, String, String, String)> = crate::db::query_as(&sql) .fetch_all(&state.db) .await .map_err(|e| AppError::Internal(format!("failed to list script variables: {e}")))?; @@ -62,7 +62,7 @@ pub(super) async fn upsert( "#, backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(&body.key) .bind(&body.value) .bind(&now) @@ -101,7 +101,7 @@ pub(super) async fn delete( "DELETE FROM happyview_script_variables WHERE key = ?", backend, ); - let result = sqlx::query(&sql) + let result = crate::db::query(&sql) .bind(&key) .execute(&state.db) .await diff --git a/src/admin/scripts.rs b/src/admin/scripts.rs index 8a25d71..def2ce4 100644 --- a/src/admin/scripts.rs +++ b/src/admin/scripts.rs @@ -116,18 +116,15 @@ pub(super) async fn list( let sql = adapt_sql(&sql, backend); #[allow(clippy::type_complexity)] - let mut q = sqlx::query_as::< - _, - ( - String, - String, - String, - Option, - Option, - String, - String, - ), - >(&sql); + let mut q = crate::db::query_as::<( + String, + String, + String, + Option, + Option, + String, + String, + )>(&sql); if let Some(ref suffix) = query.suffix { q = q.bind(format!("%:{suffix}")); } @@ -207,7 +204,7 @@ pub(super) async fn upsert( let description = body.description.as_deref().filter(|s| !s.is_empty()); // Distinguish create vs update so we can return 201 vs 200. - let pre_exists: Option<(String,)> = sqlx::query_as(&adapt_sql( + let pre_exists: Option<(String,)> = crate::db::query_as(&adapt_sql( "SELECT id FROM happyview_scripts WHERE id = ?", backend, )) @@ -230,7 +227,7 @@ pub(super) async fn upsert( "#, backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(&body.id) .bind(script_type.as_str()) .bind(&body.body) @@ -343,7 +340,7 @@ pub(super) async fn patch( "#, backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(&new_script_type) .bind(&new_body) .bind(new_description.as_deref()) @@ -384,7 +381,7 @@ pub(super) async fn delete( let backend = state.db_backend; let sql = adapt_sql("DELETE FROM happyview_scripts WHERE id = ?", backend); - let result = sqlx::query(&sql) + let result = crate::db::query(&sql) .bind(&id) .execute(&state.db) .await @@ -429,7 +426,7 @@ async fn fetch_one(state: &AppState, id: &str) -> Result, String, String, - )> = sqlx::query_as(&sql) + )> = crate::db::query_as(&sql) .bind(id) .fetch_optional(&state.db) .await diff --git a/src/admin/service_entries.rs b/src/admin/service_entries.rs index 097f905..7bdfcc7 100644 --- a/src/admin/service_entries.rs +++ b/src/admin/service_entries.rs @@ -263,7 +263,7 @@ pub(super) async fn sync_plc( "SELECT rotation_key_enc FROM happyview_service_identity WHERE id = 1", state.db_backend, ); - let row: Option<(Option,)> = sqlx::query_as(&rotation_key_enc_sql) + let row: Option<(Option,)> = crate::db::query_as(&rotation_key_enc_sql) .fetch_optional(&state.db) .await .map_err(|e| AppError::Internal(format!("failed to fetch rotation key: {e}")))?; @@ -272,7 +272,7 @@ pub(super) async fn sync_plc( .ok_or_else(|| AppError::Internal("no rotation key stored".into()))?; let rotation_key_bytes = crate::plc::decrypt_key(&rotation_key_enc, encryption_key)?; let rotation_signing_key = - p256::ecdsa::SigningKey::from_bytes(rotation_key_bytes.as_slice().into()) + p256::ecdsa::SigningKey::from_slice(rotation_key_bytes.as_slice()) .map_err(|e| AppError::Internal(format!("invalid rotation key: {e}")))?; let signed = crate::plc::sign_operation(&unsigned, &rotation_signing_key)?; @@ -313,7 +313,7 @@ pub(super) async fn sync_plc_request( "SELECT attached_account_did FROM happyview_service_identity WHERE id = 1", state.db_backend, ); - let row: Option<(Option,)> = sqlx::query_as(&sql) + let row: Option<(Option,)> = crate::db::query_as(&sql) .fetch_optional(&state.db) .await .map_err(|e| AppError::Internal(format!("failed to fetch identity: {e}")))?; @@ -377,7 +377,7 @@ pub(super) async fn sync_plc_submit( "SELECT attached_account_did FROM happyview_service_identity WHERE id = 1", state.db_backend, ); - let row: Option<(Option,)> = sqlx::query_as(&sql) + let row: Option<(Option,)> = crate::db::query_as(&sql) .fetch_optional(&state.db) .await .map_err(|e| AppError::Internal(format!("failed to fetch identity: {e}")))?; diff --git a/src/admin/settings.rs b/src/admin/settings.rs index 848fe90..00d8b00 100644 --- a/src/admin/settings.rs +++ b/src/admin/settings.rs @@ -40,7 +40,7 @@ pub async fn get_setting(pool: &AnyPool, key: &str, backend: DatabaseBackend) -> "SELECT value FROM happyview_instance_settings WHERE key = ?", backend, ); - let row: Option<(String,)> = sqlx::query_as(&sql) + let row: Option<(String,)> = crate::db::query_as(&sql) .bind(key) .fetch_optional(pool) .await @@ -73,7 +73,7 @@ pub(super) async fn list( "SELECT key, value FROM happyview_instance_settings ORDER BY key", backend, ); - let rows: Vec<(String, String)> = sqlx::query_as(&sql) + let rows: Vec<(String, String)> = crate::db::query_as(&sql) .fetch_all(&state.db) .await .map_err(|e| AppError::Internal(format!("failed to list settings: {e}")))?; @@ -124,7 +124,7 @@ pub(super) async fn upsert( "#, backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(&key) .bind(&body.value) .bind(&now) @@ -163,7 +163,7 @@ pub(super) async fn delete( "DELETE FROM happyview_instance_settings WHERE key = ?", backend, ); - let result = sqlx::query(&sql) + let result = crate::db::query(&sql) .bind(&key) .execute(&state.db) .await @@ -197,7 +197,7 @@ pub(super) async fn db_info( auth.require(Permission::SettingsManage).await?; let server_max: Option = if state.db_backend == DatabaseBackend::Postgres { - sqlx::query_as::<_, (String,)>("SHOW max_connections") + crate::db::query_as::<(String,)>("SHOW max_connections") .fetch_optional(&state.db) .await .ok() @@ -290,7 +290,7 @@ pub(super) async fn upload_logo( ("logo_data", encoded.as_str()), ("logo_content_type", content_type.as_str()), ] { - sqlx::query(&sql) + crate::db::query(&sql) .bind(key) .bind(value) .bind(&now) @@ -329,7 +329,7 @@ pub(super) async fn delete_logo( "DELETE FROM happyview_instance_settings WHERE key IN (?, ?)", backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind("logo_data") .bind("logo_content_type") .execute(&state.db) @@ -361,7 +361,7 @@ pub(crate) async fn serve_logo( "SELECT key, value FROM happyview_instance_settings WHERE key IN (?, ?)", backend, ); - let rows: Vec<(String, String)> = sqlx::query_as(&sql) + let rows: Vec<(String, String)> = crate::db::query_as(&sql) .bind("logo_data") .bind("logo_content_type") .fetch_all(&state.db) diff --git a/src/admin/stats.rs b/src/admin/stats.rs index 461c40b..a14060a 100644 --- a/src/admin/stats.rs +++ b/src/admin/stats.rs @@ -15,7 +15,7 @@ pub(super) async fn stats( auth: UserAuth, ) -> Result, AppError> { auth.require(Permission::StatsRead).await?; - let total: (i64,) = sqlx::query_as("SELECT COUNT(*) FROM happyview_records") + let total: (i64,) = crate::db::query_as("SELECT COUNT(*) FROM happyview_records") .fetch_one(&state.db) .await .map_err(|e| AppError::Internal(format!("failed to count records: {e}")))?; @@ -35,7 +35,7 @@ pub(super) async fn stats( state.db_backend, ); - let collections: Vec<(String, i64)> = sqlx::query_as(&collection_sql) + let collections: Vec<(String, i64)> = crate::db::query_as(&collection_sql) .fetch_all(&state.db) .await .map_err(|e| AppError::Internal(format!("failed to count by collection: {e}")))?; diff --git a/src/admin/users.rs b/src/admin/users.rs index cf82b98..197febf 100644 --- a/src/admin/users.rs +++ b/src/admin/users.rs @@ -64,7 +64,7 @@ pub(super) async fn create_user( backend, ); - sqlx::query(&insert_sql) + crate::db::query(&insert_sql) .bind(&user_id) .bind(&body.did) .bind(0_i32) @@ -79,7 +79,7 @@ pub(super) async fn create_user( ); for perm_str in &perms_to_grant { - sqlx::query(&perm_sql) + crate::db::query(&perm_sql) .bind(&user_id) .bind(perm_str) .bind(&auth.user_id) @@ -133,7 +133,7 @@ pub(super) async fn list_users( backend, ); - let rows: Vec<(String, String, i32, String, Option)> = sqlx::query_as(&select_sql) + let rows: Vec<(String, String, i32, String, Option)> = crate::db::query_as(&select_sql) .fetch_all(&state.db) .await .map_err(|e| AppError::Internal(format!("failed to list users: {e}")))?; @@ -145,7 +145,7 @@ pub(super) async fn list_users( let mut users = Vec::new(); for (id, did, is_super_int, created_at, last_used_at) in rows { - let perm_rows: Vec<(String,)> = sqlx::query_as(&perm_sql) + let perm_rows: Vec<(String,)> = crate::db::query_as(&perm_sql) .bind(&id) .fetch_all(&state.db) .await @@ -179,11 +179,12 @@ pub(super) async fn get_user( backend, ); - let found: Option<(String, String, i32, String, Option)> = sqlx::query_as(&select_sql) - .bind(&id) - .fetch_optional(&state.db) - .await - .map_err(|e| AppError::Internal(format!("failed to get user: {e}")))?; + let found: Option<(String, String, i32, String, Option)> = + crate::db::query_as(&select_sql) + .bind(&id) + .fetch_optional(&state.db) + .await + .map_err(|e| AppError::Internal(format!("failed to get user: {e}")))?; let Some((uid, did, is_super_int, created_at, last_used_at)) = found else { return Err(AppError::NotFound(format!("user '{id}' not found"))); @@ -194,7 +195,7 @@ pub(super) async fn get_user( backend, ); - let perm_rows: Vec<(String,)> = sqlx::query_as(&perm_sql) + let perm_rows: Vec<(String,)> = crate::db::query_as(&perm_sql) .bind(&uid) .fetch_all(&state.db) .await @@ -230,7 +231,7 @@ pub(super) async fn update_permissions( // Cannot modify super user's permissions let select_sql = adapt_sql("SELECT is_super FROM happyview_users WHERE id = ?", backend); - let target: Option<(i32,)> = sqlx::query_as(&select_sql) + let target: Option<(i32,)> = crate::db::query_as(&select_sql) .bind(&id) .fetch_optional(&state.db) .await @@ -281,7 +282,7 @@ pub(super) async fn update_permissions( ); for perm_str in &body.grant { - sqlx::query(&grant_sql) + crate::db::query(&grant_sql) .bind(&id) .bind(perm_str) .bind(&auth.user_id) @@ -297,7 +298,7 @@ pub(super) async fn update_permissions( ); for perm_str in &body.revoke { - sqlx::query(&revoke_sql) + crate::db::query(&revoke_sql) .bind(&id) .bind(perm_str) .execute(&state.db) @@ -341,7 +342,7 @@ pub(super) async fn delete_user( // Cannot delete super user let select_sql = adapt_sql("SELECT is_super FROM happyview_users WHERE id = ?", backend); - let target: Option<(i32,)> = sqlx::query_as(&select_sql) + let target: Option<(i32,)> = crate::db::query_as(&select_sql) .bind(&id) .fetch_optional(&state.db) .await @@ -363,7 +364,7 @@ pub(super) async fn delete_user( backend, ); - sqlx::query(&revoke_keys_sql) + crate::db::query(&revoke_keys_sql) .bind(&now) .bind(&id) .execute(&state.db) @@ -372,7 +373,7 @@ pub(super) async fn delete_user( let delete_sql = adapt_sql("DELETE FROM happyview_users WHERE id = ?", backend); - let result = sqlx::query(&delete_sql) + let result = crate::db::query(&delete_sql) .bind(&id) .execute(&state.db) .await @@ -428,7 +429,7 @@ pub(super) async fn transfer_super( "UPDATE happyview_users SET is_super = ? WHERE id = ?", backend, ); - let result = sqlx::query(&set_super_sql) + let result = crate::db::query(&set_super_sql) .bind(1_i32) .bind(&body.target_user_id) .execute(&mut *tx) @@ -449,7 +450,7 @@ pub(super) async fn transfer_super( "UPDATE happyview_users SET is_super = ? WHERE id = ?", backend, ); - sqlx::query(&remove_super_sql) + crate::db::query(&remove_super_sql) .bind(0_i32) .bind(&auth.user_id) .execute(&mut *tx) @@ -464,7 +465,7 @@ pub(super) async fn transfer_super( ); for perm in Permission::all() { - sqlx::query(&perm_sql) + crate::db::query(&perm_sql) .bind(&body.target_user_id) .bind(perm.as_str()) .bind(&auth.user_id) diff --git a/src/auth/client_registry.rs b/src/auth/client_registry.rs index 7062772..e00c1f4 100644 --- a/src/auth/client_registry.rs +++ b/src/auth/client_registry.rs @@ -247,7 +247,7 @@ impl OAuthClientRegistry { ); let rows: Vec<(String, String, String, String)> = - match sqlx::query_as(&sql).fetch_all(db).await { + match crate::db::query_as(&sql).fetch_all(db).await { Ok(r) => r, Err(e) => { tracing::error!("Failed to load API clients from database: {e}"); diff --git a/src/auth/middleware.rs b/src/auth/middleware.rs index aecc3df..cdcebb0 100644 --- a/src/auth/middleware.rs +++ b/src/auth/middleware.rs @@ -158,7 +158,7 @@ async fn resolve_api_key_did(state: &AppState, token: &str) -> Result = sqlx::query_as(&sql) + let row: Option<(String,)> = crate::db::query_as(&sql) .bind(&hash) .fetch_optional(&state.db) .await diff --git a/src/auth/oauth_store.rs b/src/auth/oauth_store.rs index 6b548b9..3bb216b 100644 --- a/src/auth/oauth_store.rs +++ b/src/auth/oauth_store.rs @@ -62,7 +62,7 @@ impl Store for DbSessionStore { type Error = StoreError; async fn get(&self, key: &Did) -> Result, Self::Error> { - let row: Option<(String,)> = sqlx::query_as(&adapt_sql( + let row: Option<(String,)> = crate::db::query_as(&adapt_sql( "SELECT session_data FROM happyview_oauth_sessions WHERE did = ?", self.backend, )) @@ -78,7 +78,7 @@ impl Store for DbSessionStore { async fn set(&self, key: Did, value: Session) -> Result<(), Self::Error> { let json = serde_json::to_string(&value)?; - sqlx::query(&adapt_sql( + crate::db::query(&adapt_sql( "INSERT INTO happyview_oauth_sessions (did, session_data, updated_at) VALUES (?, ?, datetime('now')) ON CONFLICT (did) DO UPDATE SET session_data = EXCLUDED.session_data, updated_at = datetime('now')", self.backend, @@ -91,7 +91,7 @@ impl Store for DbSessionStore { } async fn del(&self, key: &Did) -> Result<(), Self::Error> { - sqlx::query(&adapt_sql( + crate::db::query(&adapt_sql( "DELETE FROM happyview_oauth_sessions WHERE did = ?", self.backend, )) @@ -102,7 +102,7 @@ impl Store for DbSessionStore { } async fn clear(&self) -> Result<(), Self::Error> { - sqlx::query("DELETE FROM happyview_oauth_sessions") + crate::db::query("DELETE FROM happyview_oauth_sessions") .execute(&self.pool) .await?; Ok(()) @@ -145,7 +145,7 @@ impl Store for DbStateStore { type Error = StoreError; async fn get(&self, key: &String) -> Result, Self::Error> { - let row: Option<(String,)> = sqlx::query_as(&adapt_sql( + let row: Option<(String,)> = crate::db::query_as(&adapt_sql( "SELECT state_data FROM happyview_oauth_state WHERE state_key = ?", self.backend, )) @@ -161,7 +161,7 @@ impl Store for DbStateStore { async fn set(&self, key: String, value: InternalStateData) -> Result<(), Self::Error> { let json = serde_json::to_string(&value)?; - sqlx::query(&adapt_sql( + crate::db::query(&adapt_sql( "INSERT INTO happyview_oauth_state (state_key, state_data) VALUES (?, ?) ON CONFLICT (state_key) DO UPDATE SET state_data = EXCLUDED.state_data", self.backend, @@ -175,7 +175,7 @@ impl Store for DbStateStore { } async fn del(&self, key: &String) -> Result<(), Self::Error> { - sqlx::query(&adapt_sql( + crate::db::query(&adapt_sql( "DELETE FROM happyview_oauth_state WHERE state_key = ?", self.backend, )) @@ -186,7 +186,7 @@ impl Store for DbStateStore { } async fn clear(&self) -> Result<(), Self::Error> { - sqlx::query("DELETE FROM happyview_oauth_state") + crate::db::query("DELETE FROM happyview_oauth_state") .execute(&self.pool) .await?; Ok(()) diff --git a/src/auth/routes.rs b/src/auth/routes.rs index 5d2ad8c..90d2c2c 100644 --- a/src/auth/routes.rs +++ b/src/auth/routes.rs @@ -140,7 +140,7 @@ async fn login( "INSERT INTO happyview_auth_login_redirects (state, redirect_uri, client_id, created_at, expires_at) VALUES (?, ?, ?, ?, ?)", state.db_backend, ); - let _ = sqlx::query(&sql) + let _ = crate::db::query(&sql) .bind(&oauth_state) .bind(redirect_uri) .bind(effective_client_id.as_deref()) @@ -178,7 +178,7 @@ async fn callback( state.db_backend, ); let now = now_rfc3339(); - let row: Option<(String, Option)> = sqlx::query_as(&sql) + let row: Option<(String, Option)> = crate::db::query_as(&sql) .bind(oauth_state) .bind(&now) .fetch_optional(&state.db) @@ -191,7 +191,7 @@ async fn callback( "DELETE FROM happyview_auth_login_redirects WHERE state = ?", state.db_backend, ); - let _ = sqlx::query(&delete_sql) + let _ = crate::db::query(&delete_sql) .bind(oauth_state) .execute(&state.db) .await; @@ -234,13 +234,13 @@ async fn callback( // Allow login when no users exist yet (first user will be bootstrapped as admin). // Also allow login for the configured attached account DID (setup attach-auth flow). // Otherwise, only allow users already in the users table. - let user_count: (i64,) = sqlx::query_as("SELECT COUNT(*) FROM happyview_users") + let user_count: (i64,) = crate::db::query_as("SELECT COUNT(*) FROM happyview_users") .fetch_one(&state.db) .await .map_err(|e| AppError::Internal(format!("user count query failed: {e}")))?; if user_count.0 > 0 { - let user_exists: Option<(i32,)> = sqlx::query_as(&adapt_sql( + let user_exists: Option<(i32,)> = crate::db::query_as(&adapt_sql( "SELECT 1 FROM happyview_users WHERE did = ?", state.db_backend, )) @@ -251,7 +251,7 @@ async fn callback( if user_exists.is_none() { // Allow login if this DID is the configured attached account (setup flow) - let is_attached_account: Option<(i32,)> = sqlx::query_as(&adapt_sql( + let is_attached_account: Option<(i32,)> = crate::db::query_as(&adapt_sql( "SELECT 1 FROM happyview_service_identity WHERE attached_account_did = ?", state.db_backend, )) @@ -279,7 +279,7 @@ async fn callback( "SELECT client_key FROM happyview_api_clients WHERE client_id_url = ? AND is_active = 1", state.db_backend, ); - let row: Option<(String,)> = sqlx::query_as(&sql) + let row: Option<(String,)> = crate::db::query_as(&sql) .bind(cid) .fetch_optional(&state.db) .await @@ -376,7 +376,7 @@ async fn me( let did = raw.split('\n').next().unwrap_or(&raw).to_string(); let backend = state.db_backend; - let user: Option<(i32,)> = sqlx::query_as(&adapt_sql( + let user: Option<(i32,)> = crate::db::query_as(&adapt_sql( "SELECT 1 FROM happyview_users WHERE did = ?", backend, )) diff --git a/src/auth/service_auth.rs b/src/auth/service_auth.rs index 7edaaa8..b0254d7 100644 --- a/src/auth/service_auth.rs +++ b/src/auth/service_auth.rs @@ -268,15 +268,14 @@ fn verify_es256(msg: &[u8], sig_bytes: &[u8], key_bytes: &[u8]) -> bool { return false; }; - if let Ok(sig) = P256Signature::from_bytes(sig_bytes.into()) + if let Ok(sig) = P256Signature::from_slice(sig_bytes) && verifying_key.verify(msg, &sig).is_ok() { return true; } - if let Ok(sig) = P256Signature::from_bytes(sig_bytes.into()) - && let Some(normalized) = sig.normalize_s() - && verifying_key.verify(msg, &normalized).is_ok() + if let Ok(sig) = P256Signature::from_slice(sig_bytes) + && verifying_key.verify(msg, &sig.normalize_s()).is_ok() { return true; } @@ -316,15 +315,14 @@ fn verify_es256k(msg: &[u8], sig_bytes: &[u8], key_bytes: &[u8]) -> bool { return false; }; - if let Ok(sig) = K256Signature::from_bytes(sig_bytes.into()) + if let Ok(sig) = K256Signature::from_slice(sig_bytes) && verifying_key.verify(msg, &sig).is_ok() { return true; } - if let Ok(sig) = K256Signature::from_bytes(sig_bytes.into()) - && let Some(normalized) = sig.normalize_s() - && verifying_key.verify(msg, &normalized).is_ok() + if let Ok(sig) = K256Signature::from_slice(sig_bytes) + && verifying_key.verify(msg, &sig.normalize_s()).is_ok() { return true; } diff --git a/src/db.rs b/src/db.rs index a4a6938..e381034 100644 --- a/src/db.rs +++ b/src/db.rs @@ -3,11 +3,48 @@ use chrono::{DateTime, Utc}; use regex::Regex; use serde::Deserialize; use sqlx::AnyPool; +use sqlx::any::{AnyArguments, AnyRow}; use sqlx::migrate::Migrator; use sqlx::pool::PoolOptions; +use sqlx::query::{Query, QueryAs, QueryScalar}; +use sqlx::{Any, AssertSqlSafe, FromRow}; +use sqlx::{query as sqlx_query, query_as as sqlx_query_as, query_scalar as sqlx_query_scalar}; use std::path::Path; use std::sync::LazyLock; +// --------------------------------------------------------------------------- +// SQL query helpers (sqlx 0.9 `SqlSafeStr`) +// --------------------------------------------------------------------------- +// +// sqlx 0.9 requires the SQL passed to `query*` to implement `SqlSafeStr`, which +// only `&'static str` satisfies directly — runtime strings must be wrapped in +// `AssertSqlSafe`. HappyView builds every query from a static SQLite template +// run through `adapt_sql` (only bound `?` placeholders vary; no user input is +// concatenated into the SQL), so the strings are safe to assert. Routing all +// dynamic queries through these three helpers keeps that assertion in one +// audited place instead of at ~460 call sites. Backend is always `Any`. + +/// `sqlx::query` for a runtime-built (adapted) SQL string. +pub fn query<'q>(sql: &str) -> Query<'q, Any, AnyArguments> { + sqlx_query(AssertSqlSafe(sql.to_owned())) +} + +/// `sqlx::query_as` for a runtime-built (adapted) SQL string. +pub fn query_as<'q, O>(sql: &str) -> QueryAs<'q, Any, O, AnyArguments> +where + O: for<'r> FromRow<'r, AnyRow>, +{ + sqlx_query_as(AssertSqlSafe(sql.to_owned())) +} + +/// `sqlx::query_scalar` for a runtime-built (adapted) SQL string. +pub fn query_scalar<'q, O>(sql: &str) -> QueryScalar<'q, Any, O, AnyArguments> +where + (O,): for<'r> FromRow<'r, AnyRow>, +{ + sqlx_query_scalar(AssertSqlSafe(sql.to_owned())) +} + /// Database backend type, auto-detected from DATABASE_URL or set via DATABASE_BACKEND. #[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize)] #[serde(rename_all = "lowercase")] @@ -252,17 +289,17 @@ pub async fn connect(url: &str, backend: DatabaseBackend) -> AnyPool { // Enable foreign keys and WAL mode for SQLite if backend == DatabaseBackend::Sqlite { - sqlx::query("PRAGMA foreign_keys = ON") + crate::db::query("PRAGMA foreign_keys = ON") .execute(&pool) .await .expect("Failed to enable foreign keys"); - sqlx::query("PRAGMA journal_mode = WAL") + crate::db::query("PRAGMA journal_mode = WAL") .execute(&pool) .await .expect("Failed to enable WAL mode"); - sqlx::query("PRAGMA busy_timeout = 5000") + crate::db::query("PRAGMA busy_timeout = 5000") .execute(&pool) .await .expect("Failed to set busy timeout"); @@ -336,17 +373,17 @@ pub async fn connect_backfill_pool(url: &str, backend: DatabaseBackend) -> AnyPo .expect("Failed to connect backfill database pool"); if backend == DatabaseBackend::Sqlite { - sqlx::query("PRAGMA foreign_keys = ON") + crate::db::query("PRAGMA foreign_keys = ON") .execute(&pool) .await .expect("Failed to enable foreign keys on backfill pool"); - sqlx::query("PRAGMA journal_mode = WAL") + crate::db::query("PRAGMA journal_mode = WAL") .execute(&pool) .await .expect("Failed to enable WAL mode on backfill pool"); - sqlx::query("PRAGMA busy_timeout = 5000") + crate::db::query("PRAGMA busy_timeout = 5000") .execute(&pool) .await .expect("Failed to set busy timeout on backfill pool"); diff --git a/src/delegation/db.rs b/src/delegation/db.rs index d6a4fdb..2f5afc5 100644 --- a/src/delegation/db.rs +++ b/src/delegation/db.rs @@ -16,7 +16,7 @@ pub async fn create_delegated_account( "INSERT INTO happyview_delegated_accounts (account_did, linked_by, api_client_id, created_at) VALUES (?, ?, ?, ?)", backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(account_did) .bind(linked_by) .bind(api_client_id) @@ -36,7 +36,7 @@ pub async fn delete_delegated_account( "DELETE FROM happyview_delegated_accounts WHERE account_did = ?", backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(account_did) .execute(pool) .await @@ -53,7 +53,7 @@ pub async fn get_delegated_account_owner( "SELECT linked_by FROM happyview_delegated_accounts WHERE account_did = ?", backend, ); - let row: Option<(String,)> = sqlx::query_as(&sql) + let row: Option<(String,)> = crate::db::query_as(&sql) .bind(account_did) .fetch_optional(pool) .await @@ -79,7 +79,7 @@ pub async fn get_api_client_id( "SELECT api_client_id FROM happyview_delegated_accounts WHERE account_did = ?", backend, ); - let row: Option<(String,)> = sqlx::query_as(&sql) + let row: Option<(String,)> = crate::db::query_as(&sql) .bind(account_did) .fetch_optional(pool) .await @@ -100,7 +100,7 @@ pub async fn add_delegate( "INSERT INTO happyview_account_delegates (account_did, user_did, role, granted_by, created_at) VALUES (?, ?, ?, ?, ?)", backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(account_did) .bind(user_did) .bind(role.as_str()) @@ -122,7 +122,7 @@ pub async fn remove_delegate( "DELETE FROM happyview_account_delegates WHERE account_did = ? AND user_did = ?", backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(account_did) .bind(user_did) .execute(pool) @@ -141,7 +141,7 @@ pub async fn get_delegate_role( "SELECT role FROM happyview_account_delegates WHERE account_did = ? AND user_did = ?", backend, ); - let row: Option<(String,)> = sqlx::query_as(&sql) + let row: Option<(String,)> = crate::db::query_as(&sql) .bind(account_did) .bind(user_did) .fetch_optional(pool) @@ -160,7 +160,7 @@ pub async fn list_accounts_for_user( "SELECT ad.account_did, ad.role, ad.created_at FROM happyview_account_delegates ad JOIN happyview_delegated_accounts da ON da.account_did = ad.account_did WHERE ad.user_did = ? AND da.api_client_id = ? ORDER BY ad.created_at DESC", backend, ); - let rows: Vec<(String, String, String)> = sqlx::query_as(&sql) + let rows: Vec<(String, String, String)> = crate::db::query_as(&sql) .bind(user_did) .bind(api_client_id) .fetch_all(pool) @@ -187,7 +187,7 @@ pub async fn get_account_for_user( "SELECT da.linked_by, ad.role, ad.created_at FROM happyview_delegated_accounts da JOIN happyview_account_delegates ad ON da.account_did = ad.account_did WHERE da.account_did = ? AND ad.user_did = ?", backend, ); - let row: Option<(String, String, String)> = sqlx::query_as(&sql) + let row: Option<(String, String, String)> = crate::db::query_as(&sql) .bind(account_did) .bind(user_did) .fetch_optional(pool) @@ -205,7 +205,7 @@ pub async fn list_delegates( "SELECT user_did, role, granted_by, created_at FROM happyview_account_delegates WHERE account_did = ? ORDER BY created_at ASC", backend, ); - let rows: Vec<(String, String, String, String)> = sqlx::query_as(&sql) + let rows: Vec<(String, String, String, String)> = crate::db::query_as(&sql) .bind(account_did) .fetch_all(pool) .await diff --git a/src/delegation/link_account.rs b/src/delegation/link_account.rs index 7ad8b74..8101784 100644 --- a/src/delegation/link_account.rs +++ b/src/delegation/link_account.rs @@ -50,7 +50,7 @@ pub async fn link_account( "SELECT id FROM happyview_dpop_sessions WHERE api_client_id = ? AND user_did = ?", state.db_backend, ); - let session_exists: Option<(String,)> = sqlx::query_as(&session_check_sql) + let session_exists: Option<(String,)> = crate::db::query_as(&session_check_sql) .bind(&api_client_id) .bind(account_did) .fetch_optional(&state.db) diff --git a/src/dev_happyview/create_client.rs b/src/dev_happyview/create_client.rs index 3ff3d61..3cc40ad 100644 --- a/src/dev_happyview/create_client.rs +++ b/src/dev_happyview/create_client.rs @@ -64,7 +64,7 @@ pub async fn create_api_client( "SELECT parent_client_id, created_by FROM happyview_api_clients WHERE id = ?", state.db_backend, ); - let parent_row: Option<(Option, String)> = sqlx::query_as(&parent_check_sql) + let parent_row: Option<(Option, String)> = crate::db::query_as(&parent_check_sql) .bind(&parent_client.id) .fetch_optional(&state.db) .await @@ -94,7 +94,7 @@ pub async fn create_api_client( "SELECT id FROM happyview_api_clients WHERE client_id_url = ?", state.db_backend, ); - let dup: Option<(String,)> = sqlx::query_as(&dup_check_sql) + let dup: Option<(String,)> = crate::db::query_as(&dup_check_sql) .bind(&input.client_id_url) .fetch_optional(&state.db) .await @@ -108,12 +108,12 @@ pub async fn create_api_client( // 6. Generate `hvc_` client key and optional `hvs_` client secret let mut random_bytes = [0u8; 16]; - rand::rng().fill(&mut random_bytes); + rand::rng().fill_bytes(&mut random_bytes); let child_client_key = format!("hvc_{}", hex::encode(random_bytes)); let (client_secret, client_secret_hash) = if input.client_type == "confidential" { let mut secret_bytes = [0u8; 32]; - rand::rng().fill(&mut secret_bytes); + rand::rng().fill_bytes(&mut secret_bytes); let secret = format!("hvs_{}", hex::encode(secret_bytes)); let hash = hex::encode(Sha256::digest(secret.as_bytes())); (Some(secret), hash) @@ -135,7 +135,7 @@ pub async fn create_api_client( "INSERT INTO happyview_api_clients (id, client_key, client_secret_hash, name, client_id_url, client_uri, redirect_uris, scopes, rate_limit_capacity, rate_limit_refill_rate, client_type, allowed_origins, is_active, created_by, created_at, updated_at, parent_client_id, owner_did) VALUES (?, ?, ?, ?, ?, ?, ?, ?, NULL, NULL, ?, ?, 1, ?, ?, ?, ?, ?)", state.db_backend, ); - sqlx::query(&insert_sql) + crate::db::query(&insert_sql) .bind(&id) .bind(&child_client_key) .bind(&client_secret_hash) diff --git a/src/dev_happyview/delete_client.rs b/src/dev_happyview/delete_client.rs index f4b92b8..6e2fef6 100644 --- a/src/dev_happyview/delete_client.rs +++ b/src/dev_happyview/delete_client.rs @@ -51,7 +51,7 @@ pub async fn delete_api_client( "SELECT client_id_url, client_key FROM happyview_api_clients WHERE id = ? AND owner_did = ?", state.db_backend, ); - let client_info: Option<(String, String)> = sqlx::query_as(&lookup_sql) + let client_info: Option<(String, String)> = crate::db::query_as(&lookup_sql) .bind(&id) .bind(&user_did) .fetch_optional(&state.db) @@ -63,7 +63,7 @@ pub async fn delete_api_client( "SELECT client_id_url, client_key FROM happyview_api_clients WHERE parent_client_id = ?", state.db_backend, ); - let children: Vec<(String, String)> = sqlx::query_as(&children_sql) + let children: Vec<(String, String)> = crate::db::query_as(&children_sql) .bind(&id) .fetch_all(&state.db) .await @@ -74,7 +74,7 @@ pub async fn delete_api_client( "DELETE FROM happyview_api_clients WHERE id = ? AND owner_did = ?", state.db_backend, ); - let result = sqlx::query(&delete_sql) + let result = crate::db::query(&delete_sql) .bind(&id) .bind(&user_did) .execute(&state.db) diff --git a/src/dev_happyview/get_client.rs b/src/dev_happyview/get_client.rs index 47ced61..aa6f627 100644 --- a/src/dev_happyview/get_client.rs +++ b/src/dev_happyview/get_client.rs @@ -55,7 +55,7 @@ pub async fn get_api_client( state.db_backend, ); - let row = sqlx::query(&sql) + let row = crate::db::query(&sql) .bind(¶ms.id) .bind(did) .fetch_optional(&state.db) diff --git a/src/dev_happyview/list_clients.rs b/src/dev_happyview/list_clients.rs index 4b0a6d9..bfc06c7 100644 --- a/src/dev_happyview/list_clients.rs +++ b/src/dev_happyview/list_clients.rs @@ -47,7 +47,7 @@ pub async fn list_api_clients( "SELECT parent_client_id FROM happyview_api_clients WHERE client_key = $1", state.db_backend, ); - let parent_check: Option> = sqlx::query_scalar(&sql) + let parent_check: Option> = crate::db::query_scalar(&sql) .bind(client_key) .fetch_optional(&state.db) .await @@ -69,7 +69,7 @@ pub async fn list_api_clients( state.db_backend, ); - let rows = sqlx::query(&sql) + let rows = crate::db::query(&sql) .bind(did) .fetch_all(&state.db) .await diff --git a/src/dns.rs b/src/dns.rs index 9a26260..1283819 100644 --- a/src/dns.rs +++ b/src/dns.rs @@ -1,5 +1,6 @@ use atrium_identity::handle::DnsTxtResolver; use hickory_resolver::TokioResolver; +use hickory_resolver::proto::rr::RData; /// Native DNS TXT resolver using system DNS configuration. /// Implements atrium's `DnsTxtResolver` trait for use with `AtprotoHandleResolver`, @@ -20,7 +21,8 @@ impl NativeDnsResolver { Self { resolver: TokioResolver::builder_tokio() .expect("Failed to read system DNS config") - .build(), + .build() + .expect("Failed to build DNS resolver"), } } @@ -32,7 +34,14 @@ impl NativeDnsResolver { .await .map_err(|e| format!("DNS TXT lookup failed for {name}: {e}"))?; - Ok(response.iter().map(|txt| txt.to_string()).collect()) + Ok(response + .answers() + .iter() + .filter_map(|r| match &r.data { + RData::TXT(txt) => Some(txt.to_string()), + _ => None, + }) + .collect()) } } diff --git a/src/event_log.rs b/src/event_log.rs index 7a9aa51..0a16c24 100644 --- a/src/event_log.rs +++ b/src/event_log.rs @@ -56,7 +56,7 @@ pub async fn spawn_retention_cleanup(db: AnyPool, retention_days: u32, backend: loop { tokio::time::sleep(interval).await; - let result = sqlx::query(&cleanup_sql) + let result = crate::db::query(&cleanup_sql) .bind(retention_days as i32) .execute(&db) .await; @@ -86,7 +86,7 @@ pub async fn log_event(db: &AnyPool, event: EventLog, backend: DatabaseBackend) backend, ); - let result = sqlx::query(&sql) + let result = crate::db::query(&sql) .bind(&id) .bind(&event.event_type) .bind(&severity) diff --git a/src/external_auth/routes.rs b/src/external_auth/routes.rs index 56127f0..834b151 100644 --- a/src/external_auth/routes.rs +++ b/src/external_auth/routes.rs @@ -465,7 +465,7 @@ async fn load_plugin_secrets( db_backend, ); - if let Ok(Some((config_json,))) = sqlx::query_as::<_, (String,)>(&sql) + if let Ok(Some((config_json,))) = crate::db::query_as::<(String,)>(&sql) .bind(plugin_id) .fetch_optional(db) .await diff --git a/src/external_auth/state.rs b/src/external_auth/state.rs index d8b7674..4b8a5b1 100644 --- a/src/external_auth/state.rs +++ b/src/external_auth/state.rs @@ -43,7 +43,7 @@ pub async fn store_state( backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(state) .bind(did) .bind(plugin_id) @@ -72,7 +72,7 @@ pub async fn consume_state( backend, ); - let row: Option<(String, String, String)> = sqlx::query_as(&sql) + let row: Option<(String, String, String)> = crate::db::query_as(&sql) .bind(state) .bind(&now) .fetch_optional(db) @@ -85,7 +85,10 @@ pub async fn consume_state( "DELETE FROM happyview_external_auth_state WHERE state = ?", backend, ); - sqlx::query(&delete_sql).bind(state).execute(db).await?; + crate::db::query(&delete_sql) + .bind(state) + .execute(db) + .await?; Ok(StoredState { did, @@ -105,7 +108,7 @@ pub async fn cleanup_expired( "DELETE FROM happyview_external_auth_state WHERE expires_at <= ?", backend, ); - let result = sqlx::query(&sql).bind(&now).execute(db).await?; + let result = crate::db::query(&sql).bind(&now).execute(db).await?; Ok(result.rows_affected()) } diff --git a/src/external_auth/sync.rs b/src/external_auth/sync.rs index a6ea24f..45bc179 100644 --- a/src/external_auth/sync.rs +++ b/src/external_auth/sync.rs @@ -39,7 +39,7 @@ pub async fn process_sync_records( db_backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(plugin_id) .bind(user_did) .bind(dedup_key) diff --git a/src/external_auth/tokens.rs b/src/external_auth/tokens.rs index 86dbe2e..a6c7650 100644 --- a/src/external_auth/tokens.rs +++ b/src/external_auth/tokens.rs @@ -69,7 +69,7 @@ pub async fn store_tokens( backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(&id) .bind(did) .bind(plugin_id) @@ -102,7 +102,7 @@ pub async fn get_tokens( backend, ); - let row: Option = sqlx::query_as(&sql) + let row: Option = crate::db::query_as(&sql) .bind(did) .bind(plugin_id) .fetch_optional(db) @@ -144,7 +144,7 @@ pub async fn delete_tokens( backend, ); - let result = sqlx::query(&sql) + let result = crate::db::query(&sql) .bind(did) .bind(plugin_id) .execute(db) @@ -165,7 +165,7 @@ pub async fn is_linked( backend, ); - let exists: Option<(i32,)> = sqlx::query_as(&sql) + let exists: Option<(i32,)> = crate::db::query_as(&sql) .bind(did) .bind(plugin_id) .fetch_optional(db) @@ -186,7 +186,7 @@ pub async fn get_account_id( backend, ); - let row: Option<(String,)> = sqlx::query_as(&sql) + let row: Option<(String,)> = crate::db::query_as(&sql) .bind(did) .bind(plugin_id) .fetch_optional(db) @@ -216,7 +216,7 @@ pub async fn list_linked_accounts( ); let rows: Vec<(String, String, String, String)> = - sqlx::query_as(&sql).bind(did).fetch_all(db).await?; + crate::db::query_as(&sql).bind(did).fetch_all(db).await?; Ok(rows .into_iter() diff --git a/src/jetstream.rs b/src/jetstream.rs index 8acfd98..43fd5b2 100644 --- a/src/jetstream.rs +++ b/src/jetstream.rs @@ -51,7 +51,7 @@ async fn load_cursor(db: &AnyPool, backend: DatabaseBackend) -> Option { "SELECT value FROM happyview_instance_settings WHERE key = ?", backend, ); - let row: Option<(String,)> = sqlx::query_as(&sql) + let row: Option<(String,)> = crate::db::query_as(&sql) .bind("jetstream_cursor") .fetch_optional(db) .await @@ -69,7 +69,7 @@ async fn save_cursor(db: &AnyPool, backend: DatabaseBackend, cursor: i64) { "#, backend, ); - if let Err(e) = sqlx::query(&sql) + if let Err(e) = crate::db::query(&sql) .bind("jetstream_cursor") .bind(cursor.to_string()) .bind(&now) diff --git a/src/jobs/db.rs b/src/jobs/db.rs index 6d00d6a..bb89962 100644 --- a/src/jobs/db.rs +++ b/src/jobs/db.rs @@ -70,7 +70,7 @@ pub async fn create_job( "INSERT INTO happyview_jobs (id, job_type, status, input, created_by, created_at, inherit_auth) VALUES (?, ?, 'pending', ?, ?, ?, ?)", state.db_backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(&id) .bind(job_type) .bind(&input_str) @@ -89,7 +89,7 @@ pub async fn get_job(state: &AppState, id: &str) -> Result, AppError "SELECT * FROM happyview_jobs WHERE id = ?", state.db_backend, ); - let row: Option = sqlx::query_as(&sql) + let row: Option = crate::db::query_as(&sql) .bind(id) .fetch_optional(&state.db) .await @@ -120,7 +120,7 @@ pub async fn list_jobs( adapt_sql(base, state.db_backend) }; - let mut query = sqlx::query_as::<_, JobRow>(&sql); + let mut query = crate::db::query_as::(&sql); if let Some(status) = status_filter { query = query.bind(status); @@ -170,7 +170,7 @@ pub async fn set_status(state: &AppState, id: &str, status: &str) -> Result<(), match status { "running" | "completed" | "failed" | "cancelled" => { - sqlx::query(&sql) + crate::db::query(&sql) .bind(status) .bind(&now) .bind(id) @@ -183,7 +183,7 @@ pub async fn set_status(state: &AppState, id: &str, status: &str) -> Result<(), "UPDATE happyview_jobs SET status = ? WHERE id = ?", state.db_backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(status) .bind(id) .execute(&state.db) @@ -202,7 +202,7 @@ pub async fn update_progress(state: &AppState, id: &str, progress: &Value) -> Re "UPDATE happyview_jobs SET progress = ? WHERE id = ?", state.db_backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(&progress_str) .bind(id) .execute(&state.db) @@ -219,7 +219,7 @@ pub async fn set_result(state: &AppState, id: &str, result: &Value) -> Result<() "UPDATE happyview_jobs SET status = 'completed', result = ?, completed_at = ? WHERE id = ?", state.db_backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(&result_str) .bind(&now) .bind(id) @@ -235,7 +235,7 @@ pub async fn set_error(state: &AppState, id: &str, error: &str) -> Result<(), Ap "UPDATE happyview_jobs SET status = 'failed', error = ?, completed_at = ? WHERE id = ?", state.db_backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(error) .bind(&now) .bind(id) @@ -252,7 +252,7 @@ pub async fn should_stop(state: &AppState, id: &str) -> Option<&'static str> { "SELECT status FROM happyview_jobs WHERE id = ?", state.db_backend, ); - let status = sqlx::query_as::<_, (String,)>(&sql) + let status = crate::db::query_as::<(String,)>(&sql) .bind(id) .fetch_optional(&state.db) .await @@ -272,7 +272,7 @@ pub async fn find_interrupted_jobs(state: &AppState) -> Vec { "SELECT * FROM happyview_jobs WHERE status IN ('running', 'cancelling', 'pausing')", state.db_backend, ); - let rows: Vec = sqlx::query_as(&sql) + let rows: Vec = crate::db::query_as(&sql) .fetch_all(&state.db) .await .unwrap_or_default(); @@ -295,7 +295,7 @@ pub async fn claim_next_job(state: &AppState) -> Result, AppError> { ), }; - let row: Option = sqlx::query_as(&sql) + let row: Option = crate::db::query_as(&sql) .bind(&now) .fetch_optional(&state.db) .await diff --git a/src/jobs/worker.rs b/src/jobs/worker.rs index 89a8051..8abf2ee 100644 --- a/src/jobs/worker.rs +++ b/src/jobs/worker.rs @@ -331,7 +331,7 @@ async fn load_env_vars( backend: crate::db::DatabaseBackend, ) -> std::collections::HashMap { let sql = adapt_sql("SELECT key, value FROM happyview_script_variables", backend); - sqlx::query_as::<_, (String, String)>(&sql) + crate::db::query_as::<(String, String)>(&sql) .fetch_all(db) .await .unwrap_or_default() diff --git a/src/labeler.rs b/src/labeler.rs index ceea642..ffda327 100644 --- a/src/labeler.rs +++ b/src/labeler.rs @@ -59,7 +59,7 @@ pub fn spawn(state: AppState, mut subscriptions_rx: watch::Receiver<()>) { loop { // Read all active subscriptions from the database. - let active: Vec<(String,)> = sqlx::query_as( + let active: Vec<(String,)> = crate::db::query_as( "SELECT did FROM happyview_labeler_subscriptions WHERE status = 'active'", ) .fetch_all(&state.db) @@ -153,7 +153,7 @@ async fn run_subscription_once( "SELECT cursor FROM happyview_labeler_subscriptions WHERE did = ?", state.db_backend, ); - let cursor: Option<(Option,)> = sqlx::query_as(&cursor_sql) + let cursor: Option<(Option,)> = crate::db::query_as(&cursor_sql) .bind(did) .fetch_optional(&state.db) .await?; @@ -362,7 +362,7 @@ async fn apply_label(state: &AppState, label: &Label) { "DELETE FROM happyview_labels WHERE src = ? AND uri = ? AND val = ?", backend, ); - if let Err(e) = sqlx::query(&delete_sql) + if let Err(e) = crate::db::query(&delete_sql) .bind(&final_label.src) .bind(&final_label.uri) .bind(&final_label.val) @@ -387,7 +387,7 @@ async fn apply_label(state: &AppState, label: &Label) { backend, ); - if let Err(e) = sqlx::query(&insert_sql) + if let Err(e) = crate::db::query(&insert_sql) .bind(&final_label.src) .bind(&final_label.uri) .bind(&final_label.val) @@ -410,7 +410,7 @@ async fn persist_cursor(db: &sqlx::AnyPool, did: &str, seq: i64, backend: Databa "UPDATE happyview_labeler_subscriptions SET cursor = ?, updated_at = ? WHERE did = ?", backend, ); - if let Err(e) = sqlx::query(&update_sql) + if let Err(e) = crate::db::query(&update_sql) .bind(seq) .bind(&now) .bind(did) @@ -439,10 +439,11 @@ async fn backfill_labels_for_uri_inner( state: &AppState, uri: &str, ) -> Result<(), Box> { - let subscriptions: Vec<(String,)> = - sqlx::query_as("SELECT did FROM happyview_labeler_subscriptions WHERE status = 'active'") - .fetch_all(&state.db) - .await?; + let subscriptions: Vec<(String,)> = crate::db::query_as( + "SELECT did FROM happyview_labeler_subscriptions WHERE status = 'active'", + ) + .fetch_all(&state.db) + .await?; for (labeler_did,) in subscriptions { if let Err(e) = backfill_from_labeler(state, &labeler_did, uri).await { @@ -515,7 +516,7 @@ pub async fn spawn_label_gc(db: sqlx::AnyPool, backend: DatabaseBackend) { tokio::time::sleep(interval).await; // Delete expired labels. - let expired = sqlx::query(&expired_sql).execute(&db).await; + let expired = crate::db::query(&expired_sql).execute(&db).await; let expired_count = match expired { Ok(r) => r.rows_affected(), @@ -526,7 +527,7 @@ pub async fn spawn_label_gc(db: sqlx::AnyPool, backend: DatabaseBackend) { }; // Delete orphaned labels (no matching record). - let orphaned = sqlx::query( + let orphaned = crate::db::query( "DELETE FROM happyview_labels WHERE NOT EXISTS (SELECT 1 FROM happyview_records WHERE happyview_records.uri = happyview_labels.uri)", ) .execute(&db) diff --git a/src/lexicon.rs b/src/lexicon.rs index 7374f81..a4b25dc 100644 --- a/src/lexicon.rs +++ b/src/lexicon.rs @@ -219,7 +219,7 @@ impl LexiconRegistry { Option, Option, Option, - )> = sqlx::query_as( + )> = crate::db::query_as( "SELECT id, lexicon_json, revision, target_collection, action, token_cost FROM happyview_lexicons", ) .fetch_all(db) diff --git a/src/lua/atproto_api.rs b/src/lua/atproto_api.rs index e58f8b8..e5d1f6f 100644 --- a/src/lua/atproto_api.rs +++ b/src/lua/atproto_api.rs @@ -122,7 +122,7 @@ pub fn register_atproto_api( "SELECT src, uri, val, cts FROM happyview_labels WHERE uri = ? AND (exp IS NULL OR exp > ?)", backend, ); - let rows: Vec<(String, String, String, String)> = sqlx::query_as(&sql) + let rows: Vec<(String, String, String, String)> = crate::db::query_as(&sql) .bind(&uri) .bind(&now) .fetch_all(&state.db) @@ -144,7 +144,7 @@ pub fn register_atproto_api( // Check for self-labels in the record itself. let record_sql = adapt_sql("SELECT did, record FROM happyview_records WHERE uri = ?", backend); - let record: Option<(String, String)> = sqlx::query_as(&record_sql) + let record: Option<(String, String)> = crate::db::query_as(&record_sql) .bind(&uri) .fetch_optional(&state.db) .await @@ -197,7 +197,7 @@ pub fn register_atproto_api( let mut rows: Vec<(String, String, String, String)> = Vec::new(); for uri in &uri_list { let mut uri_rows: Vec<(String, String, String, String)> = - sqlx::query_as(&label_sql) + crate::db::query_as(&label_sql) .bind(uri) .bind(&now) .fetch_all(&state.db) @@ -215,7 +215,7 @@ pub fn register_atproto_api( ); let mut records: Vec<(String, String, String)> = Vec::new(); for uri in &uri_list { - let mut uri_records: Vec<(String, String, String)> = sqlx::query_as(&record_sql) + let mut uri_records: Vec<(String, String, String)> = crate::db::query_as(&record_sql) .bind(uri) .fetch_all(&state.db) .await diff --git a/src/lua/db_api.rs b/src/lua/db_api.rs index 2c44261..1e9e6a9 100644 --- a/src/lua/db_api.rs +++ b/src/lua/db_api.rs @@ -295,7 +295,7 @@ pub fn register_db_api(lua: &Lua, state: Arc) -> LuaResult<()> { &format!("SELECT uri, did, record FROM happyview_records WHERE collection = ?{did_clause}{filter_clause} ORDER BY {order_expr} LIMIT ? OFFSET ?"), backend, ); - let mut q = sqlx::query_as(&sql).bind(&collection); + let mut q = crate::db::query_as(&sql).bind(&collection); if let Some(ref did) = did { q = q.bind(did); } for val in &filter_binds { q = q.bind(val); } let rows: Vec<(String, String, String)> = q @@ -351,7 +351,7 @@ pub fn register_db_api(lua: &Lua, state: Arc) -> LuaResult<()> { ), backend, ); - let mut q = sqlx::query_as::<_, RowType>(&sql).bind(&collection); + let mut q = crate::db::query_as::(&sql).bind(&collection); if let Some(ref did) = did { q = q.bind(did); } if let Some((cursor_ts, cursor_uri)) = &cursor_parts { q = q.bind(cursor_ts).bind(cursor_ts).bind(cursor_uri); @@ -407,7 +407,7 @@ pub fn register_db_api(lua: &Lua, state: Arc) -> LuaResult<()> { "SELECT record FROM happyview_records WHERE uri = ?", backend, ); - let row: Option<(String,)> = sqlx::query_as(&sql) + let row: Option<(String,)> = crate::db::query_as(&sql) .bind(&uri) .fetch_optional(&state.db) .await @@ -463,7 +463,7 @@ pub fn register_db_api(lua: &Lua, state: Arc) -> LuaResult<()> { json_extract(record, '$.{field}') \ LIMIT ?" ); - sqlx::query_as(&sql) + crate::db::query_as(&sql) .bind(&collection) .bind(&like_pattern) .bind(&query) @@ -487,7 +487,7 @@ pub fn register_db_api(lua: &Lua, state: Arc) -> LuaResult<()> { record::jsonb->>'{field}' \ LIMIT $4" ); - sqlx::query_as(&sql) + crate::db::query_as(&sql) .bind(&collection) .bind(&like_pattern) .bind(&query) @@ -536,7 +536,7 @@ pub fn register_db_api(lua: &Lua, state: Arc) -> LuaResult<()> { "SELECT COUNT(*) FROM happyview_records WHERE collection = ? AND did = ?", backend, ); - sqlx::query_as(&sql) + crate::db::query_as(&sql) .bind(&collection) .bind(did) .fetch_one(&state.db) @@ -547,7 +547,7 @@ pub fn register_db_api(lua: &Lua, state: Arc) -> LuaResult<()> { "SELECT COUNT(*) FROM happyview_records WHERE collection = ?", backend, ); - sqlx::query_as(&sql) + crate::db::query_as(&sql) .bind(&collection) .fetch_one(&state.db) .await @@ -586,7 +586,7 @@ pub fn register_db_api(lua: &Lua, state: Arc) -> LuaResult<()> { LIMIT ?", backend, ); - sqlx::query_as(&sql) + crate::db::query_as(&sql) .bind(&uri) .bind(&collection) .bind(did) @@ -607,7 +607,7 @@ pub fn register_db_api(lua: &Lua, state: Arc) -> LuaResult<()> { LIMIT ?", backend, ); - sqlx::query_as(&sql) + crate::db::query_as(&sql) .bind(&uri) .bind(&collection) .bind(did) @@ -626,7 +626,7 @@ pub fn register_db_api(lua: &Lua, state: Arc) -> LuaResult<()> { LIMIT ?", backend, ); - sqlx::query_as(&sql) + crate::db::query_as(&sql) .bind(&uri) .bind(&collection) .bind(cursor_ts) @@ -646,7 +646,7 @@ pub fn register_db_api(lua: &Lua, state: Arc) -> LuaResult<()> { LIMIT ?", backend, ); - sqlx::query_as(&sql) + crate::db::query_as(&sql) .bind(&uri) .bind(&collection) .bind(limit) @@ -699,7 +699,7 @@ pub fn register_db_api(lua: &Lua, state: Arc) -> LuaResult<()> { // AppView bookkeeping) from raw access; own tables are fine. check_raw_sql_tables(&sql).map_err(mlua::Error::runtime)?; - let mut query = sqlx::query(&sql); + let mut query = crate::db::query(&sql); if let Some(ref params_table) = params { for value in params_table.sequence_values::() { let value = value?; diff --git a/src/lua/execute.rs b/src/lua/execute.rs index 5997665..b275cd4 100644 --- a/src/lua/execute.rs +++ b/src/lua/execute.rs @@ -24,7 +24,7 @@ use super::sandbox; /// Load all script variables from the database as a key-value map. async fn load_env_vars(db: &sqlx::AnyPool, backend: DatabaseBackend) -> HashMap { let sql = adapt_sql("SELECT key, value FROM happyview_script_variables", backend); - sqlx::query_as::<_, (String, String)>(&sql) + crate::db::query_as::<(String, String)>(&sql) .fetch_all(db) .await .unwrap_or_default() diff --git a/src/lua/record.rs b/src/lua/record.rs index 6bd1298..a58a983 100644 --- a/src/lua/record.rs +++ b/src/lua/record.rs @@ -156,7 +156,7 @@ pub(crate) fn register_record_api( indexed_at = ?"#, backend, ); - let _ = sqlx::query(&upsert_sql) + let _ = crate::db::query(&upsert_sql) .bind(uri) .bind(repo) .bind(&collection) @@ -219,7 +219,7 @@ pub(crate) fn register_record_api( cid = EXCLUDED.cid"#, backend, ); - let _ = sqlx::query(&upsert_sql) + let _ = crate::db::query(&upsert_sql) .bind(uri) .bind(repo) .bind(&collection) @@ -318,7 +318,10 @@ pub(crate) fn register_record_api( // Always delete locally — operator's logical action is // "remove this record from view" regardless of PDS outcome. let delete_sql = adapt_sql("DELETE FROM happyview_records WHERE uri = ?", backend); - let _ = sqlx::query(&delete_sql).bind(&uri).execute(&state.db).await; + let _ = crate::db::query(&delete_sql) + .bind(&uri) + .execute(&state.db) + .await; this.raw_set("_uri", mlua::Value::Nil)?; this.raw_set("_cid", mlua::Value::Nil)?; @@ -425,7 +428,7 @@ pub(crate) fn register_record_api( indexed_at = ?"#, backend, ); - sqlx::query(&upsert_sql) + crate::db::query(&upsert_sql) .bind(&uri) .bind(&repo) .bind(&collection) @@ -463,7 +466,7 @@ pub(crate) fn register_record_api( })?; let delete_sql = adapt_sql("DELETE FROM happyview_records WHERE uri = ?", backend); - sqlx::query(&delete_sql) + crate::db::query(&delete_sql) .bind(&uri) .execute(&state.db) .await @@ -757,7 +760,7 @@ pub(crate) fn register_record_api( indexed_at = ?"#, backend, ); - let _ = sqlx::query(&upsert_sql) + let _ = crate::db::query(&upsert_sql) .bind(uri.as_str()) .bind(repo) .bind(&collection) @@ -825,7 +828,7 @@ pub(crate) fn register_record_api( cid = EXCLUDED.cid"#, backend, ); - let _ = sqlx::query(&upsert_sql) + let _ = crate::db::query(&upsert_sql) .bind(uri) .bind(repo) .bind(&collection) @@ -877,7 +880,7 @@ pub(crate) fn register_record_api( "SELECT collection, record, cid FROM happyview_records WHERE uri = ?", backend, ); - let row: Option<(String, String, String)> = sqlx::query_as(&sql) + let row: Option<(String, String, String)> = crate::db::query_as(&sql) .bind(&uri) .fetch_optional(&state.db) .await @@ -944,7 +947,7 @@ pub(crate) fn register_record_api( "SELECT collection, record, cid FROM happyview_records WHERE uri = ?", backend, ); - let row: Option<(String, String, String)> = sqlx::query_as(&sql) + let row: Option<(String, String, String)> = crate::db::query_as(&sql) .bind(&uri) .fetch_optional(&state.db) .await @@ -1021,7 +1024,7 @@ pub(crate) fn register_record_api( async move { let backend = state.db_backend; let delete_sql = adapt_sql("DELETE FROM happyview_records WHERE uri = ?", backend); - let res = sqlx::query(&delete_sql) + let res = crate::db::query(&delete_sql) .bind(&uri) .execute(&state.db) .await diff --git a/src/lua/scripts.rs b/src/lua/scripts.rs index 439c7c0..c60f491 100644 --- a/src/lua/scripts.rs +++ b/src/lua/scripts.rs @@ -250,7 +250,7 @@ pub async fn resolve(state: &AppState, trigger_id: &str) -> Option = match sqlx::query_as(&sql) + let row: Option<(String, String, String)> = match crate::db::query_as(&sql) .bind(trigger_id) .fetch_optional(&state.db) .await @@ -818,7 +818,7 @@ async fn load_env_vars( backend: DatabaseBackend, ) -> std::collections::HashMap { let sql = adapt_sql("SELECT key, value FROM happyview_script_variables", backend); - sqlx::query_as::<_, (String, String)>(&sql) + crate::db::query_as::<(String, String)>(&sql) .fetch_all(db) .await .unwrap_or_default() @@ -844,7 +844,7 @@ async fn write_dead_letter(state: &AppState, entry: &DeadLetterEntry<'_>) { VALUES (?, ?, ?, ?, ?, ?, ?, ?)", state.db_backend, ); - if let Err(e) = sqlx::query(&sql) + if let Err(e) = crate::db::query(&sql) .bind(entry.script.id.as_str()) .bind(entry.host_kind) .bind(entry.host_id) diff --git a/src/lua/xrpc_api.rs b/src/lua/xrpc_api.rs index baaecf0..5ffe128 100644 --- a/src/lua/xrpc_api.rs +++ b/src/lua/xrpc_api.rs @@ -311,7 +311,7 @@ mod tests { /// inert (kept on the struct for forward-compat with row loaders but /// not consulted by dispatch). async fn seed_script(state: &AppState, trigger: &str, body: &str) { - sqlx::query( + crate::db::query( r#" CREATE TABLE IF NOT EXISTS happyview_scripts ( id TEXT PRIMARY KEY, @@ -326,7 +326,7 @@ mod tests { .execute(&state.db) .await .unwrap(); - sqlx::query( + crate::db::query( "INSERT OR REPLACE INTO happyview_scripts (id, body, script_type, created_at, updated_at) VALUES (?, ?, 'lua', datetime('now'), datetime('now'))", ) diff --git a/src/main.rs b/src/main.rs index c5baa94..25ce22e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -53,14 +53,14 @@ async fn main() { let db_bg = db_pool.clone(); let backend = db_backend; tokio::spawn(async move { - let count: (i64,) = sqlx::query_as("SELECT COUNT(*) FROM happyview_record_refs") + let count: (i64,) = crate::db::query_as("SELECT COUNT(*) FROM happyview_record_refs") .fetch_one(&db_bg) .await .expect("failed to count record_refs"); if count.0 == 0 { info!("backfilling record_refs table in background..."); - let total: (i64,) = sqlx::query_as("SELECT COUNT(*) FROM happyview_records") + let total: (i64,) = crate::db::query_as("SELECT COUNT(*) FROM happyview_records") .fetch_one(&db_bg) .await .expect("failed to count records"); @@ -76,7 +76,7 @@ async fn main() { ); loop { - let batch: Vec<(String, String, String)> = sqlx::query_as(&query) + let batch: Vec<(String, String, String)> = crate::db::query_as(&query) .bind(batch_size) .bind(offset) .fetch_all(&db_bg) @@ -120,7 +120,7 @@ async fn main() { // Re-fetch all network lexicons from their respective PDSes. let http = reqwest::Client::new(); - let network_rows: Vec<(String, Option, Option)> = sqlx::query_as( + let network_rows: Vec<(String, Option, Option)> = crate::db::query_as( "SELECT id, authority_did, target_collection FROM happyview_lexicons WHERE source = 'network'", ) .fetch_all(&db_pool) @@ -147,7 +147,7 @@ async fn main() { ); let lexicon_json_str = serde_json::to_string(&lexicon_json).unwrap_or_default(); - if let Err(e) = sqlx::query(&update_sql) + if let Err(e) = crate::db::query(&update_sql) .bind(&lexicon_json_str) .bind(&now) .bind(&now) @@ -282,7 +282,7 @@ async fn main() { Option, Option, ); - let client_rows: Vec = sqlx::query_as( + let client_rows: Vec = crate::db::query_as( "SELECT client_key, client_secret_hash, client_uri, rate_limit_capacity, rate_limit_refill_rate, parent_client_id FROM happyview_api_clients WHERE is_active = 1", ) .fetch_all(&db_pool) @@ -328,7 +328,7 @@ async fn main() { { let count_sql = happyview::db::adapt_sql("SELECT COUNT(*) FROM happyview_domains", db_backend); - let row = sqlx::query(&count_sql) + let row = crate::db::query(&count_sql) .fetch_one(&db_pool) .await .expect("Failed to count domains"); @@ -341,7 +341,7 @@ async fn main() { "INSERT INTO happyview_domains (id, url, is_primary, created_at, updated_at) VALUES (?, ?, 1, ?, ?)", db_backend, ); - sqlx::query(&insert_sql) + crate::db::query(&insert_sql) .bind(&id) .bind(&config.public_url) .bind(&now) @@ -356,7 +356,7 @@ async fn main() { "SELECT id, url FROM happyview_domains WHERE is_primary = 1", db_backend, ); - if let Some(row) = sqlx::query(&primary_sql) + if let Some(row) = crate::db::query(&primary_sql) .fetch_optional(&db_pool) .await .expect("Failed to check primary domain") @@ -369,7 +369,7 @@ async fn main() { "UPDATE happyview_domains SET url = ?, updated_at = ? WHERE id = ?", db_backend, ); - sqlx::query(&update_sql) + crate::db::query(&update_sql) .bind(&config.public_url) .bind(&now) .bind(&primary_id) @@ -388,7 +388,7 @@ async fn main() { "SELECT id, url, is_primary, created_at, updated_at FROM happyview_domains", db_backend, ); - let rows = sqlx::query(&select_sql) + let rows = crate::db::query(&select_sql) .fetch_all(&db_pool) .await .expect("Failed to load domains"); @@ -734,7 +734,7 @@ async fn seed_and_load_rate_limit_defaults( "INSERT INTO happyview_instance_settings (key, value, updated_at) VALUES (?, ?, ?) ON CONFLICT (key) DO NOTHING", backend, ); - if let Err(e) = sqlx::query(&sql) + if let Err(e) = crate::db::query(&sql) .bind(key) .bind(seed.to_string()) .bind(&now) diff --git a/src/oauth/client_auth.rs b/src/oauth/client_auth.rs index 8149645..36841c1 100644 --- a/src/oauth/client_auth.rs +++ b/src/oauth/client_auth.rs @@ -27,7 +27,7 @@ pub async fn authenticate_confidential( ); let row: Option<(String, String, String, String, Option, String)> = - sqlx::query_as(&sql) + crate::db::query_as(&sql) .bind(client_key) .fetch_optional(pool) .await @@ -71,7 +71,7 @@ pub async fn authenticate_public( backend, ); - let row: Option<(String, String, String, String, Option)> = sqlx::query_as(&sql) + let row: Option<(String, String, String, String, Option)> = crate::db::query_as(&sql) .bind(client_key) .fetch_optional(pool) .await @@ -130,7 +130,7 @@ pub async fn resolve_client_by_key( backend, ); - let row: Option<(String, String, String, String, Option)> = sqlx::query_as(&sql) + let row: Option<(String, String, String, String, Option)> = crate::db::query_as(&sql) .bind(client_key) .fetch_optional(pool) .await diff --git a/src/oauth/dpop_proof.rs b/src/oauth/dpop_proof.rs index f97e819..0280c0a 100644 --- a/src/oauth/dpop_proof.rs +++ b/src/oauth/dpop_proof.rs @@ -221,7 +221,7 @@ fn verify_es256_jwk( let verifying_key = VerifyingKey::from_sec1_bytes(&sec1) .map_err(|_| AppError::Auth("invalid DPoP public key".into()))?; - let signature = Signature::from_bytes(sig_bytes.into()) + let signature = Signature::from_slice(sig_bytes) .map_err(|_| AppError::Auth("invalid DPoP signature format".into()))?; verifying_key diff --git a/src/oauth/keys.rs b/src/oauth/keys.rs index b2d3baf..c993a46 100644 --- a/src/oauth/keys.rs +++ b/src/oauth/keys.rs @@ -1,5 +1,5 @@ use p256::ecdsa::SigningKey; -use rand::RngCore; +use rand::Rng; use serde::Serialize; use sha2::{Digest, Sha256}; @@ -23,11 +23,11 @@ pub fn generate_dpop_keypair() -> Result { let mut rng_bytes = [0u8; 32]; rand::rng().fill_bytes(&mut rng_bytes); - let signing_key = SigningKey::from_bytes((&rng_bytes[..]).into()) + let signing_key = SigningKey::from_slice(&rng_bytes[..]) .map_err(|e| AppError::Internal(format!("failed to generate signing key: {e}")))?; let verifying_key = signing_key.verifying_key(); - let public_point = verifying_key.to_encoded_point(false); + let public_point = verifying_key.to_sec1_point(false); let x_bytes = public_point .x() @@ -121,7 +121,7 @@ pub async fn store_dpop_key( backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(id) .bind(provision_id) .bind(api_client_id) @@ -150,7 +150,7 @@ pub async fn get_dpop_key( ); #[allow(clippy::type_complexity)] - let row: Option<(String, String, Vec, String, Option)> = sqlx::query_as(&sql) + let row: Option<(String, String, Vec, String, Option)> = crate::db::query_as(&sql) .bind(provision_id) .fetch_optional(pool) .await @@ -179,7 +179,7 @@ pub async fn get_dpop_key_thumbprint( backend, ); - let row: Option<(String,)> = sqlx::query_as(&sql) + let row: Option<(String,)> = crate::db::query_as(&sql) .bind(key_id) .fetch_optional(pool) .await @@ -201,7 +201,7 @@ pub async fn get_dpop_key_id_by_thumbprint( backend, ); - let row: Option<(String,)> = sqlx::query_as(&sql) + let row: Option<(String,)> = crate::db::query_as(&sql) .bind(api_client_id) .bind(thumbprint) .fetch_optional(pool) @@ -223,13 +223,13 @@ pub async fn delete_dpop_key( "DELETE FROM happyview_dpop_sessions WHERE dpop_key_id = ?", backend, ); - let _ = sqlx::query(&session_sql) + let _ = crate::db::query(&session_sql) .bind(dpop_key_id) .execute(pool) .await; let key_sql = adapt_sql("DELETE FROM happyview_dpop_keys WHERE id = ?", backend); - sqlx::query(&key_sql) + crate::db::query(&key_sql) .bind(dpop_key_id) .execute(pool) .await diff --git a/src/oauth/pds_write.rs b/src/oauth/pds_write.rs index a104271..7f172c1 100644 --- a/src/oauth/pds_write.rs +++ b/src/oauth/pds_write.rs @@ -50,7 +50,7 @@ async fn resolve_credentials( "SELECT private_key_enc FROM happyview_dpop_keys WHERE id = ?", backend, ); - let row: Option<(Vec,)> = sqlx::query_as(&key_sql) + let row: Option<(Vec,)> = crate::db::query_as(&key_sql) .bind(&session.dpop_key_id) .fetch_optional(pool) .await @@ -596,7 +596,7 @@ async fn lookup_client_id_url( "SELECT client_id_url FROM happyview_api_clients WHERE id = ?", backend, ); - let row: Option<(String,)> = sqlx::query_as(&sql) + let row: Option<(String,)> = crate::db::query_as(&sql) .bind(api_client_id) .fetch_optional(pool) .await @@ -649,7 +649,7 @@ fn generate_dpop_proof_inner( .decode(d_b64) .map_err(|_| AppError::Internal("invalid DPoP key d parameter".into()))?; - let signing_key = SigningKey::from_bytes((&d_bytes[..]).into()) + let signing_key = SigningKey::from_slice(&d_bytes[..]) .map_err(|e| AppError::Internal(format!("invalid DPoP signing key: {e}")))?; let public_jwk = serde_json::json!({ diff --git a/src/oauth/sessions.rs b/src/oauth/sessions.rs index 4588dab..a258cd4 100644 --- a/src/oauth/sessions.rs +++ b/src/oauth/sessions.rs @@ -70,7 +70,7 @@ pub async fn store_dpop_session( backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(id) .bind(api_client_id) .bind(dpop_key_id) @@ -113,7 +113,7 @@ pub async fn get_dpop_session( String, Option, Option, - )> = sqlx::query_as(&sql) + )> = crate::db::query_as(&sql) .bind(api_client_id) .bind(user_did) .bind(dpop_key_id) @@ -177,7 +177,7 @@ pub async fn get_dpop_session_by_key_id( String, Option, Option, - )> = sqlx::query_as(&sql) + )> = crate::db::query_as(&sql) .bind(api_client_id) .bind(dpop_key_id) .fetch_optional(pool) @@ -228,7 +228,7 @@ pub async fn delete_dpop_session( "DELETE FROM happyview_dpop_sessions WHERE api_client_id = ? AND user_did = ? AND dpop_key_id = ?", backend, ); - sqlx::query(&del_session_sql) + crate::db::query(&del_session_sql) .bind(api_client_id) .bind(user_did) .bind(dpop_key_id) @@ -237,7 +237,7 @@ pub async fn delete_dpop_session( .map_err(|e| AppError::Internal(format!("failed to delete DPoP session: {e}")))?; let del_key_sql = adapt_sql("DELETE FROM happyview_dpop_keys WHERE id = ?", backend); - sqlx::query(&del_key_sql) + crate::db::query(&del_key_sql) .bind(dpop_key_id) .execute(pool) .await @@ -257,7 +257,7 @@ pub async fn delete_all_dpop_sessions( "SELECT dpop_key_id FROM happyview_dpop_sessions WHERE api_client_id = ? AND user_did = ?", backend, ); - let key_ids: Vec<(String,)> = sqlx::query_as(&key_ids_sql) + let key_ids: Vec<(String,)> = crate::db::query_as(&key_ids_sql) .bind(api_client_id) .bind(user_did) .fetch_all(pool) @@ -268,7 +268,7 @@ pub async fn delete_all_dpop_sessions( "DELETE FROM happyview_dpop_sessions WHERE api_client_id = ? AND user_did = ?", backend, ); - sqlx::query(&del_sessions_sql) + crate::db::query(&del_sessions_sql) .bind(api_client_id) .bind(user_did) .execute(pool) @@ -277,7 +277,10 @@ pub async fn delete_all_dpop_sessions( let del_key_sql = adapt_sql("DELETE FROM happyview_dpop_keys WHERE id = ?", backend); for (key_id,) in key_ids { - let _ = sqlx::query(&del_key_sql).bind(&key_id).execute(pool).await; + let _ = crate::db::query(&del_key_sql) + .bind(&key_id) + .execute(pool) + .await; } Ok(()) @@ -295,7 +298,7 @@ pub async fn list_dpop_sessions( backend, ); - let rows: Vec<(String, String, String, String, String)> = sqlx::query_as(&sql) + let rows: Vec<(String, String, String, String, String)> = crate::db::query_as(&sql) .bind(api_client_id) .bind(user_did) .fetch_all(pool) @@ -341,7 +344,7 @@ pub async fn get_dpop_session_for_user( String, Option, Option, - )> = sqlx::query_as(&sql) + )> = crate::db::query_as(&sql) .bind(api_client_id) .bind(user_did) .fetch_optional(pool) @@ -392,7 +395,7 @@ pub async fn delete_dpop_session_by_id( "SELECT dpop_key_id FROM happyview_dpop_sessions WHERE id = ? AND api_client_id = ? AND user_did = ?", backend, ); - let row: Option<(String,)> = sqlx::query_as(&lookup_sql) + let row: Option<(String,)> = crate::db::query_as(&lookup_sql) .bind(session_id) .bind(api_client_id) .bind(user_did) @@ -403,14 +406,14 @@ pub async fn delete_dpop_session_by_id( let (dpop_key_id,) = row.ok_or_else(|| AppError::NotFound("DPoP session not found".into()))?; let del_session_sql = adapt_sql("DELETE FROM happyview_dpop_sessions WHERE id = ?", backend); - sqlx::query(&del_session_sql) + crate::db::query(&del_session_sql) .bind(session_id) .execute(pool) .await .map_err(|e| AppError::Internal(format!("failed to delete DPoP session: {e}")))?; let del_key_sql = adapt_sql("DELETE FROM happyview_dpop_keys WHERE id = ?", backend); - sqlx::query(&del_key_sql) + crate::db::query(&del_key_sql) .bind(&dpop_key_id) .execute(pool) .await diff --git a/src/plc.rs b/src/plc.rs index 7000272..32e00eb 100644 --- a/src/plc.rs +++ b/src/plc.rs @@ -188,10 +188,10 @@ pub fn decrypt_key(enc_b64: &str, encryption_key: &[u8; 32]) -> Result, /// Uses the same multikey format as `extract_public_key_multibase` in server.rs: /// multicodec varint prefix 0x8024 (P-256) + compressed public key, base58btc-encoded. pub fn private_key_to_did_key(key_bytes: &[u8]) -> Result { - let signing_key = SigningKey::from_bytes(key_bytes.into()) + let signing_key = SigningKey::from_slice(key_bytes) .map_err(|e| AppError::Internal(format!("invalid signing key: {e}")))?; let public_key = signing_key.verifying_key(); - let compressed = public_key.to_encoded_point(true); + let compressed = public_key.to_sec1_point(true); // Multikey: 0x8024 varint prefix for P-256 + compressed public key bytes let mut multikey_bytes = vec![0x80, 0x24]; @@ -203,14 +203,14 @@ pub fn private_key_to_did_key(key_bytes: &[u8]) -> Result { #[cfg(test)] mod tests { use super::*; - use rand::RngCore; + use rand::Rng; /// Generate a test P-256 signing key using rand 0.9 (avoids rand_core version mismatch /// with p256's SigningKey::random which expects rand_core 0.6). fn test_signing_key() -> SigningKey { let mut bytes = [0u8; 32]; rand::rng().fill_bytes(&mut bytes); - SigningKey::from_bytes((&bytes[..]).into()).unwrap() + SigningKey::from_slice(&bytes[..]).unwrap() } #[test] diff --git a/src/plugin/attestation.rs b/src/plugin/attestation.rs index cdcd58f..d89e20b 100644 --- a/src/plugin/attestation.rs +++ b/src/plugin/attestation.rs @@ -48,7 +48,7 @@ impl AttestationSigner { let key_bytes = hex::decode(private_key_hex) .map_err(|e| AttestationError::InvalidKey(format!("invalid hex: {}", e)))?; - let signing_key = SigningKey::from_bytes((&key_bytes[..]).into()) + let signing_key = SigningKey::from_slice(&key_bytes[..]) .map_err(|e| AttestationError::InvalidKey(format!("invalid key: {}", e)))?; Ok(Self { @@ -63,8 +63,7 @@ impl AttestationSigner { pub fn for_testing(key_id: String, sig_type: String) -> Self { // Fixed test key (32 bytes of 0x01) - DO NOT USE IN PRODUCTION let test_key_bytes = [0x01u8; 32]; - let signing_key = - SigningKey::from_bytes((&test_key_bytes[..]).into()).expect("valid test key"); + let signing_key = SigningKey::from_slice(&test_key_bytes[..]).expect("valid test key"); Self { signing_key, key_id, @@ -76,7 +75,7 @@ impl AttestationSigner { pub fn public_key_bytes(&self) -> Vec { use k256::ecdsa::VerifyingKey; let verifying_key = VerifyingKey::from(&self.signing_key); - verifying_key.to_encoded_point(true).as_bytes().to_vec() + verifying_key.to_sec1_point(true).as_bytes().to_vec() } /// Sign a record and add the signature to the signatures array. @@ -222,7 +221,7 @@ impl AttestationSigner { base64::Engine::decode(&base64::engine::general_purpose::STANDARD, sig_bytes_b64) .map_err(|e| AttestationError::Encoding(format!("invalid base64: {e}")))?; - let signature = Signature::from_bytes((&sig_bytes[..]).into()) + let signature = Signature::from_slice(&sig_bytes[..]) .map_err(|e| AttestationError::Signing(format!("invalid signature bytes: {e}")))?; // Recompute CID from record (same as signing) @@ -366,7 +365,7 @@ pub async fn load_or_generate( "SELECT value FROM happyview_instance_settings WHERE key = ?", backend, ); - let existing: Option<(String,)> = sqlx::query_as(&sql) + let existing: Option<(String,)> = crate::db::query_as(&sql) .bind("attestation_private_key") .fetch_optional(db) .await @@ -374,12 +373,12 @@ pub async fn load_or_generate( if let Some((hex_key,)) = existing { // Load key_id and sig_type from DB too (or use defaults) - let key_id: Option<(String,)> = sqlx::query_as(&sql) + let key_id: Option<(String,)> = crate::db::query_as(&sql) .bind("attestation_key_id") .fetch_optional(db) .await .map_err(|e| AttestationError::Encoding(format!("db query failed: {e}")))?; - let sig_type: Option<(String,)> = sqlx::query_as(&sql) + let sig_type: Option<(String,)> = crate::db::query_as(&sql) .bind("attestation_sig_type") .fetch_optional(db) .await @@ -397,11 +396,11 @@ pub async fn load_or_generate( tracing::info!("Generating new attestation signing key"); let hex_key = { // Generate 32 random bytes for a K-256 private key - use rand::RngCore; + use rand::Rng; let mut key_bytes = [0u8; 32]; rand::rng().fill_bytes(&mut key_bytes); // Validate it's a valid K-256 scalar by trying to construct a SigningKey - let _ = SigningKey::from_bytes((&key_bytes[..]).into()) + let _ = SigningKey::from_slice(&key_bytes[..]) .map_err(|e| AttestationError::InvalidKey(format!("generated invalid key: {e}")))?; hex::encode(key_bytes) }; @@ -418,7 +417,7 @@ pub async fn load_or_generate( ("attestation_key_id", default_key_id.as_str()), ("attestation_sig_type", default_sig_type.as_str()), ] { - sqlx::query(&upsert_sql) + crate::db::query(&upsert_sql) .bind(k) .bind(v) .bind(&now) @@ -598,7 +597,7 @@ mod tests { .connect("sqlite::memory:") .await .unwrap(); - sqlx::query( + crate::db::query( "CREATE TABLE happyview_instance_settings (key TEXT PRIMARY KEY, value TEXT NOT NULL, updated_at TEXT NOT NULL DEFAULT '')", ) .execute(&pool) @@ -637,7 +636,7 @@ mod tests { .connect("sqlite::memory:") .await .unwrap(); - sqlx::query( + crate::db::query( "CREATE TABLE happyview_instance_settings (key TEXT PRIMARY KEY, value TEXT NOT NULL, updated_at TEXT NOT NULL DEFAULT '')", ) .execute(&pool) diff --git a/src/plugin/encryption.rs b/src/plugin/encryption.rs index 951c60b..875ea36 100644 --- a/src/plugin/encryption.rs +++ b/src/plugin/encryption.rs @@ -2,7 +2,7 @@ use aes_gcm::{ Aes256Gcm, Nonce, aead::{Aead, KeyInit}, }; -use rand::RngCore; +use rand::Rng; #[derive(Debug, thiserror::Error)] pub enum EncryptionError { diff --git a/src/plugin/host/kv.rs b/src/plugin/host/kv.rs index 1ec7d39..d492347 100644 --- a/src/plugin/host/kv.rs +++ b/src/plugin/host/kv.rs @@ -17,7 +17,7 @@ pub async fn kv_get(ctx: &HostContext, key: &str) -> Result>, KvE ctx.db_backend, ); - let result: Option<(Vec,)> = sqlx::query_as(&sql) + let result: Option<(Vec,)> = crate::db::query_as(&sql) .bind(&ctx.plugin_id) .bind(&ctx.scope) .bind(key) @@ -52,7 +52,7 @@ pub async fn kv_set( ctx.db_backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(&ctx.plugin_id) .bind(&ctx.scope) .bind(key) @@ -70,7 +70,7 @@ pub async fn kv_delete(ctx: &HostContext, key: &str) -> Result<(), KvError> { ctx.db_backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(&ctx.plugin_id) .bind(&ctx.scope) .bind(key) diff --git a/src/plugin/host/lookup.rs b/src/plugin/host/lookup.rs index 9e62818..0a35536 100644 --- a/src/plugin/host/lookup.rs +++ b/src/plugin/host/lookup.rs @@ -47,7 +47,7 @@ pub async fn lookup_record( ctx.db_backend, ); - let result: Option<(String, String)> = sqlx::query_as(&sql) + let result: Option<(String, String)> = crate::db::query_as(&sql) .bind(collection) .bind(&json_path) .bind(external_id_value) diff --git a/src/plugin/mod.rs b/src/plugin/mod.rs index f838b56..2008a09 100644 --- a/src/plugin/mod.rs +++ b/src/plugin/mod.rs @@ -93,7 +93,7 @@ impl PluginRegistry { self.db_backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(&plugin.info.id) .bind(source) .bind(url) @@ -130,7 +130,7 @@ impl PluginRegistry { self.db_backend, ); - let rows: Vec<(String, String, Option, Option)> = sqlx::query_as(&sql) + let rows: Vec<(String, String, Option, Option)> = crate::db::query_as(&sql) .fetch_all(db) .await .map_err(|e| format!("Failed to load plugins from DB: {}", e))?; diff --git a/src/plugin/sync.rs b/src/plugin/sync.rs index 3d391bb..672453c 100644 --- a/src/plugin/sync.rs +++ b/src/plugin/sync.rs @@ -231,7 +231,7 @@ async fn lookup_game_by_external_id( backend, ); - let result: Option<(String, String)> = sqlx::query_as(&sql) + let result: Option<(String, String)> = crate::db::query_as(&sql) .bind(external_id) .fetch_optional(db) .await diff --git a/src/record_handler.rs b/src/record_handler.rs index 2f73cd7..a93035c 100644 --- a/src/record_handler.rs +++ b/src/record_handler.rs @@ -112,7 +112,7 @@ pub async fn handle_record_event(state: &AppState, record: &RecordEvent) { "#, backend, ); - match sqlx::query(&insert_sql) + match crate::db::query(&insert_sql) .bind(&uri) .bind(&record.did) .bind(&record.collection) @@ -217,7 +217,7 @@ pub async fn handle_record_event(state: &AppState, record: &RecordEvent) { } let delete_sql = adapt_sql("DELETE FROM happyview_records WHERE uri = ?", backend); - match sqlx::query(&delete_sql).bind(&uri).execute(db).await { + match crate::db::query(&delete_sql).bind(&uri).execute(db).await { Ok(_) => { if state.verbose_event_logging.load(Ordering::Relaxed) { log_event( @@ -278,7 +278,7 @@ pub async fn handle_lexicon_schema_event(state: &AppState, did: &str, record: &R "SELECT target_collection FROM happyview_lexicons WHERE id = ? AND source = 'network' AND authority_did = ?", backend, ); - let tracked: Option<(Option,)> = sqlx::query_as(&select_sql) + let tracked: Option<(Option,)> = crate::db::query_as(&select_sql) .bind(nsid) .bind(did) .fetch_optional(db) @@ -328,7 +328,7 @@ pub async fn handle_lexicon_schema_event(state: &AppState, did: &str, record: &R "#, backend, ); - if let Err(e) = sqlx::query(&upsert_sql) + if let Err(e) = crate::db::query(&upsert_sql) .bind(nsid) .bind(serde_json::to_string(rec).unwrap_or_default()) .bind(&target_collection) @@ -355,7 +355,7 @@ pub async fn handle_lexicon_schema_event(state: &AppState, did: &str, record: &R "delete" => { // Remove from lexicons table and registry. let delete_sql = adapt_sql("DELETE FROM happyview_lexicons WHERE id = ?", backend); - let _ = sqlx::query(&delete_sql).bind(nsid).execute(db).await; + let _ = crate::db::query(&delete_sql).bind(nsid).execute(db).await; let was_present = lexicons.remove(nsid).await; if was_present { diff --git a/src/record_refs.rs b/src/record_refs.rs index dfc3ccf..a48ab2b 100644 --- a/src/record_refs.rs +++ b/src/record_refs.rs @@ -44,7 +44,7 @@ pub async fn sync_refs( "DELETE FROM happyview_record_refs WHERE source_uri = ?", backend, ); - sqlx::query(&delete_sql) + crate::db::query(&delete_sql) .bind(source_uri) .execute(db) .await?; @@ -55,7 +55,7 @@ pub async fn sync_refs( backend, ); for target_uri in &uris { - sqlx::query(&insert_sql) + crate::db::query(&insert_sql) .bind(source_uri) .bind(target_uri) .bind(collection) diff --git a/src/repo/session.rs b/src/repo/session.rs index bc66a96..e9bbbfa 100644 --- a/src/repo/session.rs +++ b/src/repo/session.rs @@ -16,7 +16,7 @@ pub(crate) async fn get_dpop_client_id( state.db_backend, ); - let row: Option<(String,)> = sqlx::query_as(&sql) + let row: Option<(String,)> = crate::db::query_as(&sql) .bind(client_key) .fetch_optional(&state.db) .await diff --git a/src/resolve.rs b/src/resolve.rs index e01bace..f67b738 100644 --- a/src/resolve.rs +++ b/src/resolve.rs @@ -1,4 +1,5 @@ use hickory_resolver::Resolver; +use hickory_resolver::proto::rr::RData; use crate::error::AppError; use crate::profile::resolve_pds_endpoint; @@ -30,15 +31,21 @@ pub async fn resolve_nsid_authority( let resolver = Resolver::builder_tokio() .map_err(|e| AppError::Internal(format!("failed to create DNS resolver: {e}")))? - .build(); + .build() + .map_err(|e| AppError::Internal(format!("failed to build DNS resolver: {e}")))?; let txt_lookup = resolver.txt_lookup(&lookup_name).await.map_err(|e| { AppError::BadRequest(format!("DNS TXT lookup failed for {lookup_name}: {e}")) })?; let did = txt_lookup + .answers() .iter() - .flat_map(|txt| txt.txt_data().iter()) + .filter_map(|r| match &r.data { + RData::TXT(txt) => Some(txt), + _ => None, + }) + .flat_map(|txt| txt.txt_data.iter()) .filter_map(|data| { let s = std::str::from_utf8(data).ok()?; s.strip_prefix("did=") diff --git a/src/server.rs b/src/server.rs index 2bab835..dddfa2b 100644 --- a/src/server.rs +++ b/src/server.rs @@ -431,10 +431,10 @@ fn extract_public_key_multibase( let private_bytes = crate::plugin::encryption::decrypt(encryption_key, &encrypted) .map_err(|e| AppError::Internal(format!("failed to decrypt signing key: {e}")))?; - let signing_key = p256::ecdsa::SigningKey::from_bytes(private_bytes.as_slice().into()) + let signing_key = p256::ecdsa::SigningKey::from_slice(private_bytes.as_slice()) .map_err(|e| AppError::Internal(format!("invalid signing key: {e}")))?; let public_key = signing_key.verifying_key(); - let compressed = public_key.to_encoded_point(true); + let compressed = public_key.to_sec1_point(true); // Multikey format: multicodec varint prefix for P-256 (0x1200) then base58btc with 'z' prefix let mut multikey_bytes = vec![0x80, 0x24]; diff --git a/src/service_entries.rs b/src/service_entries.rs index a272187..377d260 100644 --- a/src/service_entries.rs +++ b/src/service_entries.rs @@ -63,7 +63,7 @@ pub async fn list_entries( backend, ); - let rows: Vec = sqlx::query_as(&sql) + let rows: Vec = crate::db::query_as(&sql) .fetch_all(db) .await .map_err(|e| AppError::Internal(format!("failed to list service entries: {e}")))?; @@ -84,7 +84,7 @@ pub async fn create_entry( backend, ); - let row: (i64,) = sqlx::query_as(&insert_sql) + let row: (i64,) = crate::db::query_as(&insert_sql) .bind(&body.fragment_id) .bind(&body.service_type) .bind(&now) @@ -100,7 +100,7 @@ pub async fn create_entry( backend, ); - let entry_row: ServiceEntryRow = sqlx::query_as(&fetch_sql) + let entry_row: ServiceEntryRow = crate::db::query_as(&fetch_sql) .bind(id) .fetch_one(db) .await @@ -145,7 +145,7 @@ pub async fn update_entry( "SELECT id, fragment_id, service_type, access_mode, created_at, updated_at FROM happyview_service_entries WHERE id = ?", backend, ); - let row: Option = sqlx::query_as(&fetch_sql) + let row: Option = crate::db::query_as(&fetch_sql) .bind(id) .fetch_optional(db) .await @@ -161,7 +161,7 @@ pub async fn update_entry( ); let update_sql = adapt_sql(&raw, backend); - let mut query = sqlx::query(&update_sql); + let mut query = crate::db::query(&update_sql); if let Some(v) = &body.fragment_id { query = query.bind(v.as_str()); } @@ -186,7 +186,7 @@ pub async fn update_entry( "SELECT id, fragment_id, service_type, access_mode, created_at, updated_at FROM happyview_service_entries WHERE id = ?", backend, ); - let row: ServiceEntryRow = sqlx::query_as(&fetch_sql) + let row: ServiceEntryRow = crate::db::query_as(&fetch_sql) .bind(id) .fetch_one(db) .await @@ -206,7 +206,7 @@ pub async fn delete_entry( backend, ); - let result = sqlx::query(&sql) + let result = crate::db::query(&sql) .bind(id) .execute(db) .await @@ -230,7 +230,7 @@ pub async fn list_entry_xrpcs( backend, ); - let rows: Vec<(String,)> = sqlx::query_as(&sql) + let rows: Vec<(String,)> = crate::db::query_as(&sql) .bind(entry_id) .fetch_all(db) .await @@ -252,7 +252,7 @@ pub async fn add_entry_xrpcs( ); for lexicon_id in lexicon_ids { - sqlx::query(&sql) + crate::db::query(&sql) .bind(entry_id) .bind(lexicon_id.as_str()) .execute(db) @@ -276,7 +276,7 @@ pub async fn remove_entry_xrpcs( ); for lexicon_id in lexicon_ids { - sqlx::query(&sql) + crate::db::query(&sql) .bind(entry_id) .bind(lexicon_id.as_str()) .execute(db) @@ -306,7 +306,7 @@ pub async fn check_access( backend, ); - let row: Option<(i64, String)> = sqlx::query_as(&sql) + let row: Option<(i64, String)> = crate::db::query_as(&sql) .bind(fragment_id) .fetch_optional(db) .await @@ -327,7 +327,7 @@ pub async fn check_access( backend, ); - let found: Option<(i32,)> = sqlx::query_as(&check_sql) + let found: Option<(i32,)> = crate::db::query_as(&check_sql) .bind(entry_id) .bind(xrpc_method) .fetch_optional(db) @@ -350,7 +350,7 @@ pub async fn services_for_lexicon( backend, ); - let rows: Vec = sqlx::query_as(&sql) + let rows: Vec = crate::db::query_as(&sql) .bind(lexicon_id) .fetch_all(db) .await diff --git a/src/service_identity.rs b/src/service_identity.rs index ee72032..744d220 100644 --- a/src/service_identity.rs +++ b/src/service_identity.rs @@ -86,7 +86,7 @@ pub async fn get_identity( backend, ); - let row: Option = sqlx::query_as(&sql) + let row: Option = crate::db::query_as(&sql) .fetch_optional(db) .await .map_err(|e| AppError::Internal(format!("failed to get service identity: {e}")))?; @@ -152,7 +152,7 @@ pub async fn upsert_identity( backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(mode.as_str()) .bind(did) .bind(signing_key_enc) @@ -175,7 +175,7 @@ pub async fn mark_setup_complete(db: &AnyPool, backend: DatabaseBackend) -> Resu backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(&now) .execute(db) .await diff --git a/src/setup.rs b/src/setup.rs index 2923f14..99578cd 100644 --- a/src/setup.rs +++ b/src/setup.rs @@ -8,7 +8,7 @@ use axum::{ routing::{get, post}, }; use axum_extra::extract::cookie::{Cookie, Key, SignedCookieJar}; -use rand::RngCore; +use rand::Rng; use serde::Deserialize; use crate::admin::auth::UserAuth; @@ -124,7 +124,7 @@ fn generate_encrypted_signing_key(state: &AppState) -> Result rand::rng().fill_bytes(&mut rng_bytes); // Validate the key bytes produce a valid signing key - SigningKey::from_bytes((&rng_bytes[..]).into()) + SigningKey::from_slice(&rng_bytes[..]) .map_err(|e| AppError::Internal(format!("failed to generate signing key: {e}")))?; let encryption_key = state @@ -194,7 +194,7 @@ async fn plc_register( "SELECT rotation_key_enc FROM happyview_service_identity WHERE id = 1", state.db_backend, ); - let row: Option<(Option,)> = sqlx::query_as(&sql) + let row: Option<(Option,)> = crate::db::query_as(&sql) .fetch_optional(&state.db) .await .map_err(|e| AppError::Internal(format!("failed to fetch rotation key: {e}")))?; @@ -205,7 +205,7 @@ async fn plc_register( let rotation_key_did = crate::plc::private_key_to_did_key(&rotation_key_bytes)?; let rotation_signing_key = - p256::ecdsa::SigningKey::from_bytes(rotation_key_bytes.as_slice().into()) + p256::ecdsa::SigningKey::from_slice(rotation_key_bytes.as_slice()) .map_err(|e| AppError::Internal(format!("invalid rotation key: {e}")))?; // Build service entries from the database @@ -263,7 +263,7 @@ async fn plc_request( "SELECT attached_account_did FROM happyview_service_identity WHERE id = 1", state.db_backend, ); - let row: Option<(Option,)> = sqlx::query_as(&sql) + let row: Option<(Option,)> = crate::db::query_as(&sql) .fetch_optional(&state.db) .await .map_err(|e| AppError::Internal(format!("failed to fetch identity: {e}")))?; @@ -321,7 +321,7 @@ async fn plc_submit( "SELECT attached_account_did FROM happyview_service_identity WHERE id = 1", state.db_backend, ); - let row: Option<(Option,)> = sqlx::query_as(&sql) + let row: Option<(Option,)> = crate::db::query_as(&sql) .fetch_optional(&state.db) .await .map_err(|e| AppError::Internal(format!("failed to fetch identity: {e}")))?; @@ -495,7 +495,7 @@ async fn attach_auth_confirm( "SELECT attached_account_did FROM happyview_service_identity WHERE id = 1", state.db_backend, ); - let row: Option<(Option,)> = sqlx::query_as(&sql) + let row: Option<(Option,)> = crate::db::query_as(&sql) .fetch_optional(&state.db) .await .map_err(|e| AppError::Internal(format!("failed to fetch identity: {e}")))?; @@ -517,7 +517,7 @@ async fn attach_auth_confirm( } // Verify the original DID is a known admin user - let user_exists: Option<(i32,)> = sqlx::query_as(&crate::db::adapt_sql( + let user_exists: Option<(i32,)> = crate::db::query_as(&crate::db::adapt_sql( "SELECT 1 FROM happyview_users WHERE did = ?", state.db_backend, )) @@ -567,7 +567,7 @@ async fn export_rotation_key( "SELECT rotation_key_enc FROM happyview_service_identity WHERE id = 1", state.db_backend, ); - let row: Option<(Option,)> = sqlx::query_as(&sql) + let row: Option<(Option,)> = crate::db::query_as(&sql) .fetch_optional(&state.db) .await .map_err(|e| AppError::Internal(format!("failed to fetch rotation key: {e}")))?; @@ -711,13 +711,19 @@ async fn resolve_handle_to_did(http: &reqwest::Client, handle: &str) -> Option` use hickory_resolver::Resolver; + use hickory_resolver::proto::rr::RData; let lookup_name = format!("_atproto.{}.", handle); - if let Ok(resolver) = Resolver::builder_tokio().map(|b| b.build()) + if let Ok(resolver) = Resolver::builder_tokio().and_then(|b| b.build()) && let Ok(txt_lookup) = resolver.txt_lookup(&lookup_name).await { let did = txt_lookup + .answers() .iter() - .flat_map(|txt| txt.txt_data().iter()) + .filter_map(|r| match &r.data { + RData::TXT(txt) => Some(txt), + _ => None, + }) + .flat_map(|txt| txt.txt_data.iter()) .filter_map(|data| { let s = std::str::from_utf8(data).ok()?; s.strip_prefix("did=") diff --git a/src/spaces/auth.rs b/src/spaces/auth.rs index 7b4abdc..a8a041a 100644 --- a/src/spaces/auth.rs +++ b/src/spaces/auth.rs @@ -1,7 +1,7 @@ use base64::Engine; use base64::engine::general_purpose::URL_SAFE_NO_PAD; use p256::ecdsa::SigningKey; -use rand::RngCore; +use rand::Rng; use sha2::{Digest, Sha256}; use uuid::Uuid; @@ -268,7 +268,7 @@ async fn get_or_create_signing_key( "SELECT signing_key_enc FROM happyview_space_dids WHERE space_id = ?", backend, ); - let row: Option<(Vec,)> = sqlx::query_as(&sql) + let row: Option<(Vec,)> = crate::db::query_as(&sql) .bind(&space.id) .fetch_optional(pool) .await @@ -301,7 +301,7 @@ async fn get_or_create_signing_key( backend, ); - sqlx::query(&insert_sql) + crate::db::query(&insert_sql) .bind(Uuid::new_v4().to_string()) .bind(&space.did) .bind(&space.id) @@ -324,11 +324,11 @@ fn generate_space_keypair() -> Result { let mut rng_bytes = [0u8; 32]; rand::rng().fill_bytes(&mut rng_bytes); - let signing_key = SigningKey::from_bytes((&rng_bytes[..]).into()) + let signing_key = SigningKey::from_slice(&rng_bytes[..]) .map_err(|e| AppError::Internal(format!("failed to generate signing key: {e}")))?; let verifying_key = signing_key.verifying_key(); - let public_point = verifying_key.to_encoded_point(false); + let public_point = verifying_key.to_sec1_point(false); let x_bytes = public_point .x() @@ -370,7 +370,7 @@ async fn store_credential_record( backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(Uuid::new_v4().to_string()) .bind(space_id) .bind(issued_to) diff --git a/src/spaces/client_attestation.rs b/src/spaces/client_attestation.rs index d635340..2a42c4e 100644 --- a/src/spaces/client_attestation.rs +++ b/src/spaces/client_attestation.rs @@ -112,7 +112,7 @@ pub async fn verify_client_attestation( let sig_bytes = URL_SAFE_NO_PAD .decode(parts[2]) .map_err(|_| AppError::Auth("invalid attestation signature encoding".into()))?; - let sig = p256::ecdsa::Signature::from_bytes(sig_bytes.as_slice().into()) + let sig = p256::ecdsa::Signature::from_slice(sig_bytes.as_slice()) .map_err(|_| AppError::Auth("invalid attestation signature format".into()))?; use p256::ecdsa::signature::Verifier; jwk.verify(message.as_bytes(), &sig) diff --git a/src/spaces/commit.rs b/src/spaces/commit.rs index bfc6810..e7e90b1 100644 --- a/src/spaces/commit.rs +++ b/src/spaces/commit.rs @@ -1,6 +1,7 @@ use hkdf::Hkdf; -use hmac::{Hmac, Mac}; +use hmac::{Hmac, KeyInit, Mac}; use k256::ecdsa::{Signature, SigningKey, VerifyingKey, signature::Signer, signature::Verifier}; +use rand::Rng; use sha2::Sha256; use crate::error::AppError; @@ -50,7 +51,7 @@ pub fn sign_commit( signing_key: &SigningKey, ) -> Result { let mut ikm = [0u8; 32]; - rand::RngCore::fill_bytes(&mut rand::rng(), &mut ikm); + rand::rng().fill_bytes(&mut ikm); let ctx = build_context(space_uri, author_did, rev, &ikm); @@ -63,7 +64,7 @@ pub fn sign_commit( hk.expand(&ctx, &mut derived_key) .map_err(|e| AppError::Internal(format!("HKDF expand failed: {e}")))?; - let mut mac_hasher = as Mac>::new_from_slice(&derived_key) + let mut mac_hasher = as KeyInit>::new_from_slice(&derived_key) .map_err(|e| AppError::Internal(format!("HMAC init failed: {e}")))?; mac_hasher.update(hash); let mac: [u8; 32] = mac_hasher.finalize().into_bytes().into(); @@ -93,7 +94,7 @@ pub fn verify_commit( let ctx = build_context(space_uri, author_did, &commit.rev, &commit.ikm); - let sig = Signature::from_bytes(commit.sig.as_slice().into()) + let sig = Signature::from_slice(commit.sig.as_slice()) .map_err(|_| AppError::Auth("invalid commit signature format".into()))?; verifying_key .verify(&ctx, &sig) @@ -105,7 +106,7 @@ pub fn verify_commit( hk.expand(&ctx, &mut derived_key) .map_err(|e| AppError::Internal(format!("HKDF expand failed: {e}")))?; - let mut mac_hasher = as Mac>::new_from_slice(&derived_key) + let mut mac_hasher = as KeyInit>::new_from_slice(&derived_key) .map_err(|e| AppError::Internal(format!("HMAC init failed: {e}")))?; mac_hasher.update(&commit.hash); @@ -124,7 +125,7 @@ mod tests { fn test_signing_key() -> SigningKey { let mut bytes = [0u8; 32]; bytes[31] = 1; // valid non-zero scalar - SigningKey::from_bytes((&bytes[..]).into()).unwrap() + SigningKey::from_slice(&bytes[..]).unwrap() } #[test] @@ -226,7 +227,7 @@ mod tests { let sk1 = test_signing_key(); let mut bytes2 = [0u8; 32]; bytes2[31] = 2; - let sk2 = SigningKey::from_bytes((&bytes2[..]).into()).unwrap(); + let sk2 = SigningKey::from_slice(&bytes2[..]).unwrap(); let vk2 = *sk2.verifying_key(); let hash = [0xDD; 32]; diff --git a/src/spaces/credential.rs b/src/spaces/credential.rs index beb02f2..05d2ec0 100644 --- a/src/spaces/credential.rs +++ b/src/spaces/credential.rs @@ -109,15 +109,13 @@ pub fn verify_delegation_token( .map_err(|_| AppError::Auth("invalid delegation token signature encoding".into()))?; // Try direct verify, then with low-S normalization - let verified = if let Ok(sig) = K256Signature::from_bytes(sig_bytes.as_slice().into()) { + let verified = if let Ok(sig) = K256Signature::from_slice(sig_bytes.as_slice()) { if verifying_key.verify(message.as_bytes(), &sig).is_ok() { true - } else if let Some(normalized) = sig.normalize_s() { + } else { verifying_key - .verify(message.as_bytes(), &normalized) + .verify(message.as_bytes(), &sig.normalize_s()) .is_ok() - } else { - false } } else { false @@ -174,7 +172,7 @@ pub fn sign_credential( .decode(d_b64) .map_err(|_| AppError::Internal("invalid signing key d parameter".into()))?; - let signing_key = SigningKey::from_bytes((&d_bytes[..]).into()) + let signing_key = SigningKey::from_slice(&d_bytes[..]) .map_err(|e| AppError::Internal(format!("invalid signing key: {e}")))?; let header = serde_json::json!({ @@ -224,7 +222,7 @@ pub fn verify_credential( let sig_bytes = URL_SAFE_NO_PAD .decode(parts[2]) .map_err(|_| AppError::Auth("invalid credential signature encoding".into()))?; - let signature = Signature::from_bytes(sig_bytes.as_slice().into()) + let signature = Signature::from_slice(sig_bytes.as_slice()) .map_err(|_| AppError::Auth("invalid credential signature format".into()))?; verifying_key @@ -291,7 +289,7 @@ pub fn multikey_to_p256_jwk(public_key_multibase: &str) -> Result K256SigningKey { let key_bytes = [0x42u8; 32]; - K256SigningKey::from_bytes((&key_bytes[..]).into()).expect("valid key") + K256SigningKey::from_slice(&key_bytes[..]).expect("valid key") } fn make_delegation_claims() -> DelegationTokenClaims { @@ -477,7 +475,7 @@ mod tests { #[test] fn delegation_rejects_wrong_key() { let signing_key = make_k256_signing_key(); - let other_key = K256SigningKey::from_bytes((&[0x99u8; 32][..]).into()).unwrap(); + let other_key = K256SigningKey::from_slice(&[0x99u8; 32][..]).unwrap(); let verifying_key = K256VerifyingKey::from(&other_key); let claims = make_delegation_claims(); @@ -591,7 +589,7 @@ mod tests { let d_b64 = keypair.private_jwk["d"].as_str().unwrap(); let d_bytes = URL_SAFE_NO_PAD.decode(d_b64).unwrap(); - let signing_key = p256::ecdsa::SigningKey::from_bytes((&d_bytes[..]).into()).unwrap(); + let signing_key = p256::ecdsa::SigningKey::from_slice(&d_bytes[..]).unwrap(); let header = serde_json::json!({ "alg": "ES256", "typ": "JWT" }); let header_b64 = URL_SAFE_NO_PAD.encode(serde_json::to_vec(&header).unwrap()); diff --git a/src/spaces/db.rs b/src/spaces/db.rs index ace617c..2ebb75c 100644 --- a/src/spaces/db.rs +++ b/src/spaces/db.rs @@ -22,7 +22,7 @@ pub async fn create_space( backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(&space.id) .bind(&space.did) .bind(&space.authority_did) @@ -54,7 +54,7 @@ pub async fn get_space( backend, ); - let row: Option = sqlx::query_as(&sql) + let row: Option = crate::db::query_as(&sql) .bind(id) .fetch_optional(pool) .await @@ -75,7 +75,7 @@ pub async fn get_space_by_address( backend, ); - let row: Option = sqlx::query_as(&sql) + let row: Option = crate::db::query_as(&sql) .bind(did) .bind(type_nsid) .bind(skey) @@ -96,7 +96,7 @@ pub async fn list_spaces_by_owner( backend, ); - let rows: Vec = sqlx::query_as(&sql) + let rows: Vec = crate::db::query_as(&sql) .bind(authority_did) .fetch_all(pool) .await @@ -132,7 +132,7 @@ pub async fn list_spaces_for_user( ) }; - let mut query = sqlx::query_as::<_, (String, String, String, String, String)>(&sql).bind(did); + let mut query = crate::db::query_as::<(String, String, String, String, String)>(&sql).bind(did); if let Some((ref ts, ref uri)) = decoded_cursor { query = query.bind(ts.as_str()).bind(ts.as_str()).bind(uri.as_str()); } @@ -179,7 +179,7 @@ pub async fn update_space( backend, ); - let result = sqlx::query(&sql) + let result = crate::db::query(&sql) .bind(&space.display_name) .bind(&space.description) .bind(space.mint_policy.as_str()) @@ -202,7 +202,7 @@ pub async fn delete_space( ) -> Result { let sql = adapt_sql("DELETE FROM happyview_spaces WHERE id = ?", backend); - let result = sqlx::query(&sql) + let result = crate::db::query(&sql) .bind(id) .execute(pool) .await @@ -271,7 +271,7 @@ pub async fn add_member( backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(&member.id) .bind(&member.space_id) .bind(&member.did) @@ -297,7 +297,7 @@ pub async fn remove_member( backend, ); - let result = sqlx::query(&sql) + let result = crate::db::query(&sql) .bind(space_id) .bind(did) .execute(pool) @@ -317,7 +317,7 @@ pub async fn is_space_credential_revoked( "SELECT revoked_at FROM happyview_space_credentials WHERE token_hash = ? AND revoked_at IS NOT NULL LIMIT 1", backend, ); - let row: Option<(String,)> = sqlx::query_as(&sql) + let row: Option<(String,)> = crate::db::query_as(&sql) .bind(token_hash) .fetch_optional(pool) .await @@ -337,7 +337,7 @@ pub async fn revoke_space_credentials_for_member( "UPDATE happyview_space_credentials SET revoked_at = ? WHERE space_id = ? AND issued_to = ? AND revoked_at IS NULL", backend, ); - let result = sqlx::query(&sql) + let result = crate::db::query(&sql) .bind(now_rfc3339()) .bind(space_id) .bind(did) @@ -358,7 +358,7 @@ pub async fn get_member( backend, ); - let row: Option = sqlx::query_as(&sql) + let row: Option = crate::db::query_as(&sql) .bind(space_id) .bind(did) .fetch_optional(pool) @@ -378,7 +378,7 @@ pub async fn list_direct_members( backend, ); - let rows: Vec = sqlx::query_as(&sql) + let rows: Vec = crate::db::query_as(&sql) .bind(space_id) .fetch_all(pool) .await @@ -397,7 +397,7 @@ pub async fn list_spaces_for_member( backend, ); - let rows: Vec = sqlx::query_as(&sql) + let rows: Vec = crate::db::query_as(&sql) .bind(did) .fetch_all(pool) .await @@ -446,7 +446,7 @@ pub async fn upsert_space_record( ), }; - sqlx::query(&sql) + crate::db::query(&sql) .bind(&record.uri) .bind(&record.space_id) .bind(&record.author_did) @@ -472,7 +472,7 @@ pub async fn get_space_record( backend, ); - let row: Option = sqlx::query_as(&sql) + let row: Option = crate::db::query_as(&sql) .bind(uri) .fetch_optional(pool) .await @@ -493,7 +493,7 @@ pub async fn get_space_record_by_parts( backend, ); - let row: Option = sqlx::query_as(&sql) + let row: Option = crate::db::query_as(&sql) .bind(space_id) .bind(collection) .bind(rkey) @@ -538,7 +538,7 @@ pub async fn list_space_records( ); let sql = adapt_sql(&raw, backend); - let mut query = sqlx::query_as::<_, RecordRow>(&sql).bind(space_id); + let mut query = crate::db::query_as::(&sql).bind(space_id); if let Some(r) = repo { query = query.bind(r); } @@ -580,7 +580,7 @@ pub async fn list_all_space_records( backend, ); - let rows: Vec = sqlx::query_as(&sql) + let rows: Vec = crate::db::query_as(&sql) .bind(space_id) .bind(author_did) .fetch_all(pool) @@ -604,7 +604,7 @@ pub async fn insert_space_record( backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(&record.uri) .bind(&record.space_id) .bind(&record.author_did) @@ -642,7 +642,7 @@ pub async fn upsert_space_record_with_swap( backend, ); - let result = sqlx::query(&sql) + let result = crate::db::query(&sql) .bind(&record_json) .bind(&record.cid) .bind(&now) @@ -670,7 +670,7 @@ pub async fn delete_space_record( ) -> Result { let sql = adapt_sql("DELETE FROM happyview_space_records WHERE uri = ?", backend); - let result = sqlx::query(&sql) + let result = crate::db::query(&sql) .bind(uri) .execute(pool) .await @@ -690,7 +690,7 @@ pub async fn delete_space_record_with_swap( backend, ); - let result = sqlx::query(&sql) + let result = crate::db::query(&sql) .bind(uri) .bind(swap_cid) .execute(pool) @@ -720,7 +720,7 @@ pub async fn update_space_revision( backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(revision) .bind(&now) .bind(space_id) @@ -746,7 +746,7 @@ pub async fn get_or_create_repo_state( backend, ); - let row: Option = sqlx::query_as(&sql) + let row: Option = crate::db::query_as(&sql) .bind(space_id) .bind(author_did) .fetch_optional(pool) @@ -764,7 +764,7 @@ pub async fn get_or_create_repo_state( "INSERT INTO happyview_space_repo_state (id, space_id, author_did, lthash_state, rev, hash, ikm, sig, mac, updated_at) VALUES (?, ?, ?, ?, NULL, NULL, NULL, NULL, NULL, ?)", backend, ); - sqlx::query(&insert_sql) + crate::db::query(&insert_sql) .bind(&id) .bind(space_id) .bind(author_did) @@ -799,7 +799,7 @@ pub async fn update_repo_state( backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(&state.lthash_state) .bind(&state.rev) .bind(&state.hash) @@ -858,7 +858,7 @@ pub async fn register_notify( backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(®.id) .bind(®.space_id) .bind(®.author_did) @@ -891,7 +891,7 @@ pub async fn list_notify_registrations( ) }; - let mut query = sqlx::query_as::<_, NotifyRow>(&sql).bind(space_id); + let mut query = crate::db::query_as::(&sql).bind(space_id); if let Some(did) = author_did { query = query.bind(did); } @@ -914,7 +914,7 @@ pub async fn delete_notify_registration( backend, ); - let result = sqlx::query(&sql) + let result = crate::db::query(&sql) .bind(id) .execute(pool) .await @@ -986,7 +986,7 @@ pub async fn find_blob_author_did( "SELECT author_did FROM happyview_space_records WHERE space_id = ? AND record LIKE ? LIMIT 1", backend, ); - let row: Option<(String,)> = sqlx::query_as(&sql) + let row: Option<(String,)> = crate::db::query_as(&sql) .bind(space_id) .bind(&pattern) .fetch_optional(pool) @@ -1009,7 +1009,7 @@ pub async fn list_space_repos( backend, ); - let rows: Vec<(String, Option)> = sqlx::query_as(&sql) + let rows: Vec<(String, Option)> = crate::db::query_as(&sql) .bind(space_id) .fetch_all(pool) .await @@ -1036,7 +1036,7 @@ pub async fn create_invite( backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(&invite.id) .bind(&invite.space_id) .bind(&invite.token_hash) @@ -1064,7 +1064,7 @@ pub async fn get_invite_by_token_hash( backend, ); - let row: Option = sqlx::query_as(&sql) + let row: Option = crate::db::query_as(&sql) .bind(token_hash) .fetch_optional(pool) .await @@ -1083,7 +1083,7 @@ pub async fn increment_invite_uses( backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(invite_id) .execute(pool) .await @@ -1102,7 +1102,7 @@ pub async fn revoke_invite( backend, ); - let result = sqlx::query(&sql) + let result = crate::db::query(&sql) .bind(invite_id) .execute(pool) .await @@ -1121,7 +1121,7 @@ pub async fn list_invites( backend, ); - let rows: Vec = sqlx::query_as(&sql) + let rows: Vec = crate::db::query_as(&sql) .bind(space_id) .fetch_all(pool) .await diff --git a/src/spaces/integration_tests.rs b/src/spaces/integration_tests.rs index c5afda8..84914e6 100644 --- a/src/spaces/integration_tests.rs +++ b/src/spaces/integration_tests.rs @@ -14,7 +14,7 @@ mod tests { fn test_signing_key() -> SigningKey { let mut bytes = [0u8; 32]; bytes[31] = 1; - SigningKey::from_bytes((&bytes[..]).into()).unwrap() + SigningKey::from_slice(&bytes[..]).unwrap() } /// Add two records, generate a commit over the hash, verify it. @@ -117,7 +117,7 @@ mod tests { use k256::ecdsa::{SigningKey as K256SigningKey, VerifyingKey as K256VerifyingKey}; fn k256_key() -> K256SigningKey { - K256SigningKey::from_bytes((&[0x42u8; 32][..]).into()).unwrap() + K256SigningKey::from_slice(&[0x42u8; 32][..]).unwrap() } fn now_secs() -> u64 { @@ -530,7 +530,7 @@ mod tests { // Can reconstruct verifying key from public JWK let vk = p256_jwk_to_verifying_key(&keypair.public_jwk).unwrap(); - let point = vk.to_encoded_point(false); + let point = vk.to_sec1_point(false); assert!(point.x().is_some()); assert!(point.y().is_some()); } diff --git a/src/spaces/oplog.rs b/src/spaces/oplog.rs index 2beb320..3c9299d 100644 --- a/src/spaces/oplog.rs +++ b/src/spaces/oplog.rs @@ -11,7 +11,7 @@ pub async fn append_op( "INSERT INTO happyview_space_record_oplog (id, space_id, author_did, rev, idx, action, collection, rkey, cid, prev, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(&entry.id) .bind(&entry.space_id) .bind(&entry.author_did) @@ -63,7 +63,7 @@ pub async fn list_ops( String, ); - let mut query = sqlx::query_as::<_, OplogRow>(&sql) + let mut query = crate::db::query_as::(&sql) .bind(space_id) .bind(author_did); if let Some(rev) = since_rev { @@ -133,7 +133,7 @@ pub async fn list_ops_with_values( Option, ); - let mut query = sqlx::query_as::<_, OplogWithValueRow>(&sql) + let mut query = crate::db::query_as::(&sql) .bind(space_id) .bind(author_did); if let Some(rev) = since_rev { diff --git a/src/spaces/routes.rs b/src/spaces/routes.rs index a602a80..d96b1a4 100644 --- a/src/spaces/routes.rs +++ b/src/spaces/routes.rs @@ -428,7 +428,7 @@ async fn require_space_admin(state: &AppState, space: &Space, did: &str) -> Resu "SELECT is_super FROM happyview_users WHERE did = ?", state.db_backend, ); - let row: Option<(i32,)> = sqlx::query_as(&sql) + let row: Option<(i32,)> = crate::db::query_as(&sql) .bind(did) .fetch_optional(&state.db) .await @@ -508,7 +508,7 @@ async fn resolve_client_id_url( "SELECT client_id_url FROM happyview_api_clients WHERE client_key = ?", state.db_backend, ); - let row: Option<(String,)> = sqlx::query_as(&sql) + let row: Option<(String,)> = crate::db::query_as(&sql) .bind(client_key) .fetch_optional(&state.db) .await @@ -974,7 +974,7 @@ async fn create_invite( require_space_admin(&state, &space, claims.did()).await?; let mut token_bytes = [0u8; 24]; - rand::Fill::fill(&mut token_bytes, &mut rand::rng()); + rand::Rng::fill_bytes(&mut rand::rng(), &mut token_bytes); let token = hex::encode(token_bytes); let token_hash = hex::encode(Sha256::digest(token.as_bytes())); @@ -1137,7 +1137,7 @@ async fn get_delegation_token( AppError::Internal("TOKEN_ENCRYPTION_KEY is required for space credentials".into()) })?; - let signing_key = k256::ecdsa::SigningKey::from_bytes(encryption_key.into()) + let signing_key = k256::ecdsa::SigningKey::from_slice(encryption_key) .map_err(|e| AppError::Internal(format!("failed to derive delegation signing key: {e}")))?; let now = std::time::SystemTime::now() @@ -1522,10 +1522,9 @@ async fn get_space_credential( })?; let verifying_key = { - let signing_key = - k256::ecdsa::SigningKey::from_bytes(encryption_key.into()).map_err(|e| { - AppError::Internal(format!("failed to derive delegation signing key: {e}")) - })?; + let signing_key = k256::ecdsa::SigningKey::from_slice(encryption_key).map_err(|e| { + AppError::Internal(format!("failed to derive delegation signing key: {e}")) + })?; k256::ecdsa::VerifyingKey::from(&signing_key) }; diff --git a/src/spaces/simplespace.rs b/src/spaces/simplespace.rs index 8b7c8f5..17b94c4 100644 --- a/src/spaces/simplespace.rs +++ b/src/spaces/simplespace.rs @@ -182,7 +182,7 @@ async fn require_space_admin(state: &AppState, space: &Space, did: &str) -> Resu "SELECT is_super FROM happyview_users WHERE did = ?", state.db_backend, ); - let row: Option<(i32,)> = sqlx::query_as(&sql) + let row: Option<(i32,)> = crate::db::query_as(&sql) .bind(did) .fetch_optional(&state.db) .await diff --git a/src/verification_methods.rs b/src/verification_methods.rs index 6916c71..75d5031 100644 --- a/src/verification_methods.rs +++ b/src/verification_methods.rs @@ -2,7 +2,7 @@ use base64::Engine; use base64::engine::general_purpose::STANDARD; use chrono::Utc; use p256::ecdsa::SigningKey; -use rand::RngCore; +use rand::Rng; use serde::{Deserialize, Serialize}; use sqlx::AnyPool; use uuid::Uuid; @@ -50,7 +50,7 @@ pub async fn list_methods( backend, ); - let rows: Vec = sqlx::query_as(&sql) + let rows: Vec = crate::db::query_as(&sql) .fetch_all(db) .await .map_err(|e| AppError::Internal(format!("failed to list verification methods: {e}")))?; @@ -68,7 +68,7 @@ pub async fn get_method_by_fragment( backend, ); - let row: Option = sqlx::query_as(&sql) + let row: Option = crate::db::query_as(&sql) .bind(fragment_id) .fetch_optional(db) .await @@ -97,7 +97,7 @@ pub async fn create_method( backend, ); - sqlx::query(&sql) + crate::db::query(&sql) .bind(&id) .bind(fragment_id) .bind(&public_key_multibase) @@ -126,7 +126,7 @@ pub async fn delete_method( backend, ); - let result = sqlx::query(&sql) + let result = crate::db::query(&sql) .bind(fragment_id) .execute(db) .await @@ -146,7 +146,7 @@ pub async fn get_private_key_bytes( backend, ); - let row: Option<(Vec,)> = sqlx::query_as(&sql) + let row: Option<(Vec,)> = crate::db::query_as(&sql) .bind(fragment_id) .fetch_optional(db) .await @@ -175,11 +175,11 @@ fn generate_p256_keypair() -> Result<(Vec, String), AppError> { let mut rng_bytes = [0u8; 32]; rand::rng().fill_bytes(&mut rng_bytes); - let signing_key = SigningKey::from_bytes((&rng_bytes[..]).into()) + let signing_key = SigningKey::from_slice(&rng_bytes[..]) .map_err(|e| AppError::Internal(format!("failed to generate verification key: {e}")))?; let verifying_key = signing_key.verifying_key(); - let compressed = verifying_key.to_encoded_point(true); + let compressed = verifying_key.to_sec1_point(true); // Multikey format: 0x8024 varint for P-256 + compressed public key, base58btc let mut multikey_bytes = vec![0x80, 0x24]; @@ -190,7 +190,7 @@ fn generate_p256_keypair() -> Result<(Vec, String), AppError> { } pub fn private_key_bytes_to_signing_key(key_bytes: &[u8]) -> Result { - SigningKey::from_bytes(key_bytes.into()) + SigningKey::from_slice(key_bytes) .map_err(|e| AppError::Internal(format!("invalid verification signing key: {e}"))) } diff --git a/src/xrpc/procedure.rs b/src/xrpc/procedure.rs index 8dfdf3f..c9c6c86 100644 --- a/src/xrpc/procedure.rs +++ b/src/xrpc/procedure.rs @@ -85,7 +85,7 @@ pub(crate) async fn handle_procedure( "SELECT outbound_xrpcs FROM happyview_scripts WHERE id = ?", state.db_backend, ); - if let Ok(Some((Some(json_str),))) = sqlx::query_as::<_, (Option,)>(&outbound_sql) + if let Ok(Some((Some(json_str),))) = crate::db::query_as::<(Option,)>(&outbound_sql) .bind(&trigger) .fetch_optional(&state.db) .await @@ -278,7 +278,7 @@ async fn handle_create_record( backend, ); let now = now_rfc3339(); - let _ = sqlx::query(&sql) + let _ = crate::db::query(&sql) .bind(uri) .bind(claims.did()) .bind(collection) @@ -365,7 +365,7 @@ async fn handle_put_record( "#, backend, ); - let _ = sqlx::query(&sql) + let _ = crate::db::query(&sql) .bind(&uri) .bind(claims.did()) .bind(collection) @@ -423,7 +423,7 @@ async fn handle_delete_record( let backend = state.db_backend; let sql = adapt_sql("DELETE FROM happyview_records WHERE uri = ?", backend); - let _ = sqlx::query(&sql).bind(&uri).execute(&state.db).await; + let _ = crate::db::query(&sql).bind(&uri).execute(&state.db).await; Ok(( StatusCode::OK, diff --git a/src/xrpc/query.rs b/src/xrpc/query.rs index 437acc0..3b45a45 100644 --- a/src/xrpc/query.rs +++ b/src/xrpc/query.rs @@ -69,7 +69,7 @@ pub(crate) async fn handle_query( "SELECT uri, did, record FROM happyview_records WHERE collection = ? AND did = ? ORDER BY indexed_at DESC LIMIT ? OFFSET ?", backend, ); - sqlx::query_as(&sql) + crate::db::query_as(&sql) .bind(collection) .bind(did) .bind(limit) @@ -82,7 +82,7 @@ pub(crate) async fn handle_query( "SELECT uri, did, record FROM happyview_records WHERE collection = ? ORDER BY indexed_at DESC LIMIT ? OFFSET ?", backend, ); - sqlx::query_as(&sql) + crate::db::query_as(&sql) .bind(collection) .bind(limit) .bind(offset) @@ -122,7 +122,7 @@ pub(super) async fn handle_get_record(state: &AppState, uri: &str) -> Result = sqlx::query_as(&sql) + let row: Option<(String,)> = crate::db::query_as(&sql) .bind(uri) .fetch_optional(&state.db) .await diff --git a/tests/common/app.rs b/tests/common/app.rs index a5b9bfd..ba6cbc3 100644 --- a/tests/common/app.rs +++ b/tests/common/app.rs @@ -11,6 +11,7 @@ use happyview::config::Config; use happyview::db::{DatabaseBackend, adapt_sql, now_rfc3339}; use happyview::lexicon::LexiconRegistry; use happyview::{AppState, server}; +use p256::elliptic_curve::sec1::ToSec1Point; use tokio::sync::watch; use wiremock::MockServer; @@ -73,7 +74,7 @@ impl TestApp { "INSERT INTO happyview_users (id, did, is_super, created_at) VALUES (?, ?, ?, ?) ON CONFLICT DO NOTHING", backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(uuid::Uuid::new_v4().to_string()) .bind(&admin_did) .bind(1_i32) @@ -233,7 +234,7 @@ impl TestApp { allowed_origins: Option>, ) -> (String, String, String) { use happyview::db::{adapt_sql, now_rfc3339}; - use rand::RngCore; + use rand::Rng; use sha2::{Digest, Sha256}; let mut key_bytes = [0u8; 16]; @@ -256,7 +257,7 @@ impl TestApp { self.state.db_backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(&id) .bind(&client_key) .bind(&secret_hash) @@ -290,14 +291,14 @@ impl TestApp { pub async fn setup_did_web(&mut self) -> String { use p256::ecdsa::SigningKey; - use rand::RngCore; + use rand::Rng; let encryption_key = [0x42u8; 32]; self.state.config.token_encryption_key = Some(encryption_key); let mut key_bytes = [0u8; 32]; rand::rng().fill_bytes(&mut key_bytes); - let signing_key = SigningKey::from_bytes((&key_bytes[..]).into()).unwrap(); + let signing_key = SigningKey::from_slice(&key_bytes[..]).unwrap(); let private_bytes = signing_key.to_bytes(); let encrypted = happyview::plugin::encryption::encrypt(&encryption_key, &private_bytes) .expect("encryption failed"); @@ -388,13 +389,13 @@ impl TestApp { use base64::Engine; use base64::engine::general_purpose::URL_SAFE_NO_PAD; use p256::ecdsa::{SigningKey, signature::Signer}; - use rand::RngCore; + use rand::Rng; let mut key_bytes = [0u8; 32]; rand::rng().fill_bytes(&mut key_bytes); - let signing_key = SigningKey::from_bytes((&key_bytes[..]).into()).unwrap(); + let signing_key = SigningKey::from_slice(&key_bytes[..]).unwrap(); let public_key = signing_key.verifying_key(); - let compressed = public_key.to_encoded_point(true); + let compressed = public_key.to_sec1_point(true); let did_doc = crate::common::plc::test_did_document(issuer_did, compressed.as_bytes()); plc_store @@ -441,14 +442,14 @@ impl TestApp { pub async fn setup_did_plc(&mut self) -> String { use p256::ecdsa::SigningKey; - use rand::RngCore; + use rand::Rng; let encryption_key = [0x42u8; 32]; self.state.config.token_encryption_key = Some(encryption_key); let mut key_bytes = [0u8; 32]; rand::rng().fill_bytes(&mut key_bytes); - let signing_key = SigningKey::from_bytes((&key_bytes[..]).into()).unwrap(); + let signing_key = SigningKey::from_slice(&key_bytes[..]).unwrap(); let private_bytes = signing_key.to_bytes(); let encrypted = happyview::plugin::encryption::encrypt(&encryption_key, &private_bytes) .expect("encryption failed"); @@ -487,13 +488,13 @@ impl TestApp { use base64::Engine; use base64::engine::general_purpose::URL_SAFE_NO_PAD; use p256::ecdsa::{SigningKey, signature::Signer}; - use rand::RngCore; + use rand::Rng; let mut key_bytes = [0u8; 32]; rand::rng().fill_bytes(&mut key_bytes); - let signing_key = SigningKey::from_bytes((&key_bytes[..]).into()).unwrap(); + let signing_key = SigningKey::from_slice(&key_bytes[..]).unwrap(); let public_key = signing_key.verifying_key(); - let compressed = public_key.to_encoded_point(true); + let compressed = public_key.to_sec1_point(true); let did_doc = crate::common::plc::test_did_document(issuer_did, compressed.as_bytes()); plc_store @@ -528,13 +529,13 @@ impl TestApp { use base64::Engine; use base64::engine::general_purpose::URL_SAFE_NO_PAD; use p256::ecdsa::{SigningKey, signature::Signer}; - use rand::RngCore; + use rand::Rng; let mut key_bytes = [0u8; 32]; rand::rng().fill_bytes(&mut key_bytes); - let signing_key = SigningKey::from_bytes((&key_bytes[..]).into()).unwrap(); + let signing_key = SigningKey::from_slice(&key_bytes[..]).unwrap(); let public_key = signing_key.verifying_key(); - let compressed = public_key.to_encoded_point(true); + let compressed = public_key.to_sec1_point(true); let did_doc = crate::common::plc::test_did_document(issuer_did, compressed.as_bytes()); plc_store diff --git a/tests/common/db.rs b/tests/common/db.rs index 1f5dcd0..5194d58 100644 --- a/tests/common/db.rs +++ b/tests/common/db.rs @@ -35,7 +35,7 @@ pub async fn acquire_test_lock() -> Option { .await .expect("failed to create advisory lock pool"); - sqlx::query("SELECT pg_advisory_lock(42)") + happyview::db::query("SELECT pg_advisory_lock(42)") .execute(&lock_pool) .await .expect("failed to acquire advisory lock"); @@ -47,7 +47,7 @@ pub async fn truncate_all(pool: &AnyPool) { let backend = test_backend(); match backend { DatabaseBackend::Postgres => { - sqlx::query( + happyview::db::query( "TRUNCATE happyview_records, happyview_lexicons, happyview_backfill_jobs, happyview_users, happyview_user_permissions, happyview_api_keys, happyview_event_logs, happyview_script_variables, happyview_scripts, happyview_dead_letter_scripts, happyview_dead_letter_hooks, happyview_record_refs, happyview_labeler_subscriptions, happyview_labels, happyview_instance_settings, happyview_domains, happyview_dpop_sessions, happyview_dpop_keys, happyview_api_clients, happyview_delegated_accounts, happyview_account_delegates, happyview_service_identity, happyview_service_entries, happyview_service_entry_xrpcs, happyview_jobs, happyview_spaces, happyview_space_members, happyview_space_records, happyview_space_repo_state, happyview_space_record_oplog, happyview_space_notify_registrations, happyview_space_invites RESTART IDENTITY CASCADE", ) .execute(pool) @@ -93,7 +93,7 @@ pub async fn truncate_all(pool: &AnyPool) { "happyview_jobs", ]; for table in tables { - sqlx::query(&format!("DELETE FROM {table}")) + happyview::db::query(&format!("DELETE FROM {table}")) .execute(pool) .await .unwrap_or_else(|e| panic!("failed to delete from {table}: {e}")); diff --git a/tests/common/tls.rs b/tests/common/tls.rs index 7ab1eb2..e146655 100644 --- a/tests/common/tls.rs +++ b/tests/common/tls.rs @@ -28,7 +28,7 @@ pub async fn start_did_web_server( let cert = rcgen::generate_simple_self_signed(vec!["localhost".into()]) .expect("failed to generate self-signed cert"); let cert_der = cert.cert.der().to_vec(); - let key_der = cert.key_pair.serialize_der(); + let key_der = cert.signing_key.serialize_der(); let tls_config = rustls::ServerConfig::builder() .with_no_client_auth() diff --git a/tests/dev_happyview.rs b/tests/dev_happyview.rs index b5797fe..fdf87a9 100644 --- a/tests/dev_happyview.rs +++ b/tests/dev_happyview.rs @@ -305,7 +305,7 @@ async fn delete_api_client_success() { VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?)", app.state.db_backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(&client_id) .bind("hvc_delete_test_key") .bind("dummyhash") @@ -418,7 +418,7 @@ async fn get_api_client_returns_client() { VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?)", app.state.db_backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(&client_id) .bind("hvc_owned_test_key") .bind("dummyhash") diff --git a/tests/e2e_admin.rs b/tests/e2e_admin.rs index 1e5ea6a..1abb938 100644 --- a/tests/e2e_admin.rs +++ b/tests/e2e_admin.rs @@ -220,7 +220,7 @@ async fn admin_auto_bootstrap_first_user() { let backend = app.state.db_backend; // Clear the seeded user so the table is empty. - sqlx::query("DELETE FROM happyview_users") + happyview::db::query("DELETE FROM happyview_users") .execute(&app.state.db) .await .unwrap(); @@ -246,7 +246,7 @@ async fn admin_auto_bootstrap_first_user() { "SELECT COUNT(*) FROM happyview_users WHERE did = ?", backend, ); - let count: (i64,) = sqlx::query_as(&sql) + let count: (i64,) = happyview::db::query_as(&sql) .bind(bootstrap_did) .fetch_one(&app.state.db) .await @@ -524,7 +524,7 @@ async fn stats_with_seeded_records() { "INSERT INTO happyview_lexicons (id, lexicon_json, created_at) VALUES (?, ?, ?)", backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind("test.collection") .bind(serde_json::to_string(&lexicon_json_val).unwrap_or_default()) .bind(&now) @@ -538,7 +538,7 @@ async fn stats_with_seeded_records() { "INSERT INTO happyview_records (uri, did, collection, rkey, record, cid, created_at) VALUES (?, ?, ?, ?, ?, ?, ?)", backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind("at://did:plc:test/test.collection/1") .bind("did:plc:test") .bind("test.collection") @@ -649,7 +649,7 @@ async fn backfill_cancel_running_job() { "INSERT INTO happyview_backfill_jobs (id, status, stage, started_at, created_at) VALUES (?, 'running', 'discovering_repos', ?, ?)", backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(&job_id) .bind(&now) .bind(&now) @@ -687,7 +687,7 @@ async fn backfill_cancel_already_cancelling_is_idempotent() { "INSERT INTO happyview_backfill_jobs (id, status, stage, started_at, created_at) VALUES (?, 'cancelling', 'fetching_records', ?, ?)", backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(&job_id) .bind(&now) .bind(&now) @@ -724,7 +724,7 @@ async fn backfill_cancel_completed_returns_400() { "INSERT INTO happyview_backfill_jobs (id, status, stage, completed_at, created_at) VALUES (?, 'completed', 'completed', ?, ?)", backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(&job_id) .bind(&now) .bind(&now) diff --git a/tests/e2e_admin_service_entries.rs b/tests/e2e_admin_service_entries.rs index 9fe21d5..c4132fe 100644 --- a/tests/e2e_admin_service_entries.rs +++ b/tests/e2e_admin_service_entries.rs @@ -810,9 +810,8 @@ async fn sync_plc_updates_did_document() { let encryption_key = [0x42u8; 32]; let mut rotation_key_bytes = [0u8; 32]; - rand::RngCore::fill_bytes(&mut rand::rng(), &mut rotation_key_bytes); - let _rotation_key = - p256::ecdsa::SigningKey::from_bytes((&rotation_key_bytes[..]).into()).unwrap(); + rand::Rng::fill_bytes(&mut rand::rng(), &mut rotation_key_bytes); + let _rotation_key = p256::ecdsa::SigningKey::from_slice(&rotation_key_bytes[..]).unwrap(); let encrypted = happyview::plugin::encryption::encrypt(&encryption_key, &rotation_key_bytes) .expect("encryption failed"); let rotation_key_enc = @@ -822,7 +821,7 @@ async fn sync_plc_updates_did_document() { "UPDATE happyview_service_identity SET rotation_key_enc = ? WHERE id = 1", app.state.db_backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(&rotation_key_enc) .execute(&app.state.db) .await diff --git a/tests/e2e_api_clients.rs b/tests/e2e_api_clients.rs index 28c0865..6f92248 100644 --- a/tests/e2e_api_clients.rs +++ b/tests/e2e_api_clients.rs @@ -694,7 +694,7 @@ async fn test_deactivate_parent_cascades_to_children() { "INSERT INTO happyview_api_clients (id, client_key, client_secret_hash, name, client_id_url, client_uri, redirect_uris, scopes, client_type, is_active, created_by, created_at, updated_at, parent_client_id, owner_did) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?, ?)", app.state.db_backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(&child_id) .bind(&child_key) .bind(&child_hash) @@ -799,7 +799,7 @@ async fn test_delete_parent_cascades_to_children() { "INSERT INTO happyview_api_clients (id, client_key, client_secret_hash, name, client_id_url, client_uri, redirect_uris, scopes, client_type, is_active, created_by, created_at, updated_at, parent_client_id, owner_did) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?, ?)", app.state.db_backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(&child_id) .bind(&child_key) .bind(&child_hash) @@ -919,7 +919,7 @@ async fn test_list_api_clients_filter_by_parent() { "INSERT INTO happyview_api_clients (id, client_key, client_secret_hash, name, client_id_url, client_uri, redirect_uris, scopes, client_type, is_active, created_by, created_at, updated_at, parent_client_id, owner_did) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?, ?)", app.state.db_backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(&child1_id) .bind(&child1_key) .bind(&child1_hash) @@ -947,7 +947,7 @@ async fn test_list_api_clients_filter_by_parent() { "INSERT INTO happyview_api_clients (id, client_key, client_secret_hash, name, client_id_url, client_uri, redirect_uris, scopes, client_type, is_active, created_by, created_at, updated_at, parent_client_id, owner_did) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?, ?)", app.state.db_backend, ); - sqlx::query(&sql2) + happyview::db::query(&sql2) .bind(&child2_id) .bind(&child2_key) .bind(&child2_hash) @@ -1048,7 +1048,7 @@ async fn test_list_api_clients_includes_parent_and_owner_fields() { "INSERT INTO happyview_api_clients (id, client_key, client_secret_hash, name, client_id_url, client_uri, redirect_uris, scopes, client_type, is_active, created_by, created_at, updated_at, parent_client_id, owner_did) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?, ?)", app.state.db_backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(&child_id) .bind(&child_key) .bind(&child_hash) diff --git a/tests/e2e_delegation.rs b/tests/e2e_delegation.rs index 98424c1..b05b207 100644 --- a/tests/e2e_delegation.rs +++ b/tests/e2e_delegation.rs @@ -975,7 +975,7 @@ async fn update_session_pds_url(app: &common::app::TestApp, user_did: &str, pds_ "UPDATE happyview_dpop_sessions SET pds_url = ? WHERE user_did = ?", app.state.db_backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(pds_url) .bind(user_did) .execute(&app.state.db) diff --git a/tests/e2e_domains.rs b/tests/e2e_domains.rs index 97de213..5d18aeb 100644 --- a/tests/e2e_domains.rs +++ b/tests/e2e_domains.rs @@ -69,7 +69,7 @@ async fn seed_domain(app: &TestApp, id: &str, url: &str, is_primary: bool) { "INSERT INTO happyview_domains (id, url, is_primary, created_at, updated_at) VALUES (?, ?, ?, ?, ?)", app.state.db_backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(id) .bind(url) .bind(if is_primary { 1i32 } else { 0i32 }) diff --git a/tests/e2e_jobs.rs b/tests/e2e_jobs.rs index eead318..bd93b7e 100644 --- a/tests/e2e_jobs.rs +++ b/tests/e2e_jobs.rs @@ -50,7 +50,7 @@ async fn seed_job(app: &TestApp, job_type: &str, status: &str) -> String { "INSERT INTO happyview_jobs (id, job_type, status, input, progress, created_by, created_at) VALUES (?, ?, ?, ?, '{}', ?, ?)", app.state.db_backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(&id) .bind(job_type) .bind(status) @@ -69,7 +69,7 @@ async fn set_job_status(app: &TestApp, id: &str, status: &str) { "UPDATE happyview_jobs SET status = ? WHERE id = ?", app.state.db_backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(status) .bind(id) .execute(&app.state.db) diff --git a/tests/e2e_labelers.rs b/tests/e2e_labelers.rs index 21c95f3..e80245d 100644 --- a/tests/e2e_labelers.rs +++ b/tests/e2e_labelers.rs @@ -368,7 +368,7 @@ async fn labeler_delete_removes_labels() { "INSERT INTO happyview_labels (src, uri, val, cts) VALUES (?, ?, ?, ?)", backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind("did:plc:lab1") .bind("at://did:plc:user/test.collection/rkey1") .bind("adult-content") @@ -393,7 +393,7 @@ async fn labeler_delete_removes_labels() { "SELECT COUNT(*) FROM happyview_labels WHERE src = ?", backend, ); - let count: (i64,) = sqlx::query_as(&sql) + let count: (i64,) = happyview::db::query_as(&sql) .bind("did:plc:lab1") .fetch_one(&app.state.db) .await diff --git a/tests/e2e_network_lexicons.rs b/tests/e2e_network_lexicons.rs index 9010e1b..3fee0d3 100644 --- a/tests/e2e_network_lexicons.rs +++ b/tests/e2e_network_lexicons.rs @@ -55,7 +55,7 @@ async fn seed_network_lexicon(app: &TestApp, nsid: &str, authority_did: &str) { backend, ); let now = now_rfc3339(); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(nsid) .bind(serde_json::to_string(&lexicon_json).unwrap_or_default()) .bind(authority_did) @@ -139,7 +139,7 @@ async fn network_lexicon_delete_removes_tracking_and_lexicon() { "SELECT COUNT(*) FROM happyview_lexicons WHERE id = ? AND source = 'network'", backend, ); - let count: (i64,) = sqlx::query_as(&sql) + let count: (i64,) = happyview::db::query_as(&sql) .bind(nsid) .fetch_one(&app.state.db) .await diff --git a/tests/e2e_scripts.rs b/tests/e2e_scripts.rs index 654821a..cb78016 100644 --- a/tests/e2e_scripts.rs +++ b/tests/e2e_scripts.rs @@ -147,7 +147,7 @@ async fn seed_record_row( VALUES (?, ?, ?, ?, ?, ?, ?)", app.state.db_backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(uri) .bind(did) .bind(collection) @@ -161,7 +161,7 @@ async fn seed_record_row( } async fn count_records(app: &TestApp, uri: &str) -> i64 { - let (count,): (i64,) = sqlx::query_as(&adapt_sql( + let (count,): (i64,) = happyview::db::query_as(&adapt_sql( "SELECT COUNT(*) FROM happyview_records WHERE uri = ?", app.state.db_backend, )) @@ -173,7 +173,7 @@ async fn count_records(app: &TestApp, uri: &str) -> i64 { } async fn fetch_record_body(app: &TestApp, uri: &str) -> Option { - let row: Option<(String,)> = sqlx::query_as(&adapt_sql( + let row: Option<(String,)> = happyview::db::query_as(&adapt_sql( "SELECT record FROM happyview_records WHERE uri = ?", app.state.db_backend, )) @@ -588,7 +588,7 @@ async fn record_event_script_log_writes_event_log_row() { // The script's log("hello from script") should land in event_logs // as a `script.log` row whose subject is the trigger id. - let row: (String, String) = sqlx::query_as(&adapt_sql( + let row: (String, String) = happyview::db::query_as(&adapt_sql( "SELECT subject, detail FROM happyview_event_logs WHERE event_type = 'script.log' ORDER BY id DESC LIMIT 1", @@ -736,10 +736,11 @@ async fn label_script_uri_routes_actor_special_case() { assert!(matches!(outcome, LabelHookOutcome::Continue(_))); // Sentinel row should exist if the script ran. - let (count,): (i64,) = sqlx::query_as("SELECT COUNT(*) FROM script_sentinel WHERE k = 'fired'") - .fetch_one(&app.state.db) - .await - .unwrap(); + let (count,): (i64,) = + happyview::db::query_as("SELECT COUNT(*) FROM script_sentinel WHERE k = 'fired'") + .fetch_one(&app.state.db) + .await + .unwrap(); assert_eq!( count, 1, "labeler.apply:_actor should have fired for bare-DID label" @@ -795,7 +796,7 @@ async fn label_script_calling_record_save_dead_letters_with_clear_message() { assert_eq!(body["text"], "untouched"); // A dead-letter row exists with the NO_PDS_AUTH message. - let dl: (String,) = sqlx::query_as(&adapt_sql( + let dl: (String,) = happyview::db::query_as(&adapt_sql( "SELECT error FROM happyview_dead_letter_scripts WHERE host_kind = 'label' \ AND host_id = 'did:plc:labeler' ORDER BY id DESC LIMIT 1", app.state.db_backend, diff --git a/tests/e2e_service_identity.rs b/tests/e2e_service_identity.rs index 0941e98..4c468b3 100644 --- a/tests/e2e_service_identity.rs +++ b/tests/e2e_service_identity.rs @@ -3,6 +3,7 @@ mod common; use axum::body::Body; use axum::http::{Request, StatusCode}; use http_body_util::BodyExt; +use p256::elliptic_curve::sec1::ToSec1Point; use serde_json::{Value, json}; use serial_test::serial; use tower::ServiceExt; @@ -1448,11 +1449,10 @@ async fn did_web_issuer_resolved_via_https() { .await; let mut key_bytes = [0u8; 32]; - rand::RngCore::fill_bytes(&mut rand::rng(), &mut key_bytes); - let issuer_key = p256::ecdsa::SigningKey::from_bytes((&key_bytes[..]).into()).unwrap(); - use p256::elliptic_curve::sec1::ToEncodedPoint; + rand::Rng::fill_bytes(&mut rand::rng(), &mut key_bytes); + let issuer_key = p256::ecdsa::SigningKey::from_slice(&key_bytes[..]).unwrap(); let public_key = p256::PublicKey::from(issuer_key.verifying_key()); - let compressed = public_key.to_encoded_point(true); + let compressed = public_key.to_sec1_point(true); let pub_bytes = compressed.as_bytes().to_vec(); let server = @@ -1581,13 +1581,13 @@ async fn service_auth_es256k_query_allowed() { // Generate a secp256k1 key pair use k256::ecdsa::{SigningKey as K256SigningKey, signature::Signer as K256Signer}; - use rand::RngCore; + use rand::Rng; let mut key_bytes = [0u8; 32]; rand::rng().fill_bytes(&mut key_bytes); - let k256_signing_key = K256SigningKey::from_bytes((&key_bytes[..]).into()).unwrap(); + let k256_signing_key = K256SigningKey::from_slice(&key_bytes[..]).unwrap(); let k256_verifying_key = k256_signing_key.verifying_key(); - let compressed = k256_verifying_key.to_encoded_point(true); + let compressed = k256_verifying_key.to_sec1_point(true); let pub_bytes = compressed.as_bytes(); // Build a DID document with secp256k1 key using EcdsaSecp256k1VerificationKey2019 @@ -2027,11 +2027,11 @@ async fn did_doc_missing_atproto_vm_rejected() { use base64::Engine; use base64::engine::general_purpose::URL_SAFE_NO_PAD; use p256::ecdsa::{SigningKey, signature::Signer}; - use rand::RngCore; + use rand::Rng; let mut key_bytes = [0u8; 32]; rand::rng().fill_bytes(&mut key_bytes); - let signing_key = SigningKey::from_bytes((&key_bytes[..]).into()).unwrap(); + let signing_key = SigningKey::from_slice(&key_bytes[..]).unwrap(); let issuer_did = "did:plc:noatprotovm"; let did_doc = json!({ @@ -2098,11 +2098,11 @@ async fn did_doc_missing_public_key_multibase_rejected() { use base64::Engine; use base64::engine::general_purpose::URL_SAFE_NO_PAD; use p256::ecdsa::{SigningKey, signature::Signer}; - use rand::RngCore; + use rand::Rng; let mut key_bytes = [0u8; 32]; rand::rng().fill_bytes(&mut key_bytes); - let signing_key = SigningKey::from_bytes((&key_bytes[..]).into()).unwrap(); + let signing_key = SigningKey::from_slice(&key_bytes[..]).unwrap(); let issuer_did = "did:plc:nokeymultibase"; let did_doc = json!({ @@ -2215,7 +2215,7 @@ async fn seed_super_user(app: &TestApp, did: &str) { "INSERT INTO happyview_users (id, did, is_super, created_at) VALUES (?, ?, ?, ?)", app.state.db_backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(uuid::Uuid::new_v4().to_string()) .bind(did) .bind(1_i32) diff --git a/tests/e2e_xrpc.rs b/tests/e2e_xrpc.rs index b051edf..6f8d364 100644 --- a/tests/e2e_xrpc.rs +++ b/tests/e2e_xrpc.rs @@ -90,7 +90,7 @@ async fn seed_record(app: &TestApp, uri: &str, did: &str, collection: &str, reco "INSERT INTO happyview_records (uri, did, collection, rkey, record, cid, created_at) VALUES (?, ?, ?, ?, ?, ?, ?)", backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(uri) .bind(did) .bind(collection) @@ -443,7 +443,7 @@ async fn xrpc_delete_procedure_removes_record() { "SELECT COUNT(*) FROM happyview_records WHERE uri = ?", backend, ); - let count: (i64,) = sqlx::query_as(&sql) + let count: (i64,) = happyview::db::query_as(&sql) .bind(uri) .fetch_one(&app.state.db) .await diff --git a/tests/lua_atproto_api.rs b/tests/lua_atproto_api.rs index 5fe1d80..30b82c7 100644 --- a/tests/lua_atproto_api.rs +++ b/tests/lua_atproto_api.rs @@ -118,7 +118,7 @@ async fn seed_record( "INSERT INTO happyview_records (uri, did, collection, rkey, record, cid, created_at) VALUES (?, ?, ?, ?, ?, ?, ?)", backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(uri) .bind(did) .bind("test.collection") @@ -144,7 +144,7 @@ async fn seed_label( "INSERT INTO happyview_labels (src, uri, val, cts, exp) VALUES (?, ?, ?, ?, ?)", backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(src) .bind(uri) .bind(val) @@ -158,7 +158,7 @@ async fn seed_label( "INSERT INTO happyview_labels (src, uri, val, cts) VALUES (?, ?, ?, ?)", backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(src) .bind(uri) .bind(val) @@ -208,7 +208,7 @@ async fn get_labels_returns_external_labels() { "SELECT src, uri, val FROM happyview_labels WHERE uri = ? AND (exp IS NULL OR exp > ?)", backend, ); - let rows: Vec<(String, String, String)> = sqlx::query_as(&sql) + let rows: Vec<(String, String, String)> = happyview::db::query_as(&sql) .bind(uri) .bind(&now) .fetch_all(&state.db) @@ -258,7 +258,7 @@ async fn get_labels_filters_expired() { "SELECT src, uri, val FROM happyview_labels WHERE uri = ? AND (exp IS NULL OR exp > ?)", backend, ); - let rows: Vec<(String, String, String)> = sqlx::query_as(&sql) + let rows: Vec<(String, String, String)> = happyview::db::query_as(&sql) .bind(uri) .bind(&now) .fetch_all(&state.db) @@ -293,7 +293,7 @@ async fn get_labels_includes_self_labels() { "SELECT did, record FROM happyview_records WHERE uri = ?", backend, ); - let fetched: Option<(String, String)> = sqlx::query_as(&sql) + let fetched: Option<(String, String)> = happyview::db::query_as(&sql) .bind(uri) .fetch_optional(&pool) .await @@ -338,7 +338,7 @@ async fn get_labels_empty_for_unlabeled_record() { "SELECT src, uri, val FROM happyview_labels WHERE uri = ? AND (exp IS NULL OR exp > ?)", backend, ); - let rows: Vec<(String, String, String)> = sqlx::query_as(&sql) + let rows: Vec<(String, String, String)> = happyview::db::query_as(&sql) .bind(uri) .bind(&now) .fetch_all(&pool) @@ -376,7 +376,7 @@ async fn get_labels_batch_returns_labels_per_uri() { "INSERT INTO happyview_records (uri, did, collection, rkey, record, cid, created_at) VALUES (?, ?, ?, ?, ?, ?, ?)", backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(uri2) .bind("did:plc:test") .bind("test.collection") @@ -397,7 +397,7 @@ async fn get_labels_batch_returns_labels_per_uri() { "SELECT src, uri, val FROM happyview_labels WHERE uri IN (?, ?) AND (exp IS NULL OR exp > ?)", backend, ); - let rows: Vec<(String, String, String)> = sqlx::query_as(&sql) + let rows: Vec<(String, String, String)> = happyview::db::query_as(&sql) .bind(uri1) .bind(uri2) .bind(&now) @@ -430,7 +430,7 @@ async fn get_labels_batch_empty_for_no_labels() { "SELECT src, uri, val FROM happyview_labels WHERE uri IN (?, ?) AND (exp IS NULL OR exp > ?)", backend, ); - let rows: Vec<(String, String, String)> = sqlx::query_as(&sql) + let rows: Vec<(String, String, String)> = happyview::db::query_as(&sql) .bind(uri1) .bind(uri2) .bind(&now) @@ -463,7 +463,7 @@ async fn label_negation_removes_row() { "SELECT COUNT(*) FROM happyview_labels WHERE src = ? AND uri = ? AND val = ?", backend, ); - let count: (i64,) = sqlx::query_as(&sql) + let count: (i64,) = happyview::db::query_as(&sql) .bind("did:plc:labeler1") .bind(uri) .bind("nudity") @@ -477,7 +477,7 @@ async fn label_negation_removes_row() { "DELETE FROM happyview_labels WHERE src = ? AND uri = ? AND val = ?", backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind("did:plc:labeler1") .bind(uri) .bind("nudity") @@ -490,7 +490,7 @@ async fn label_negation_removes_row() { "SELECT COUNT(*) FROM happyview_labels WHERE src = ? AND uri = ? AND val = ?", backend, ); - let count: (i64,) = sqlx::query_as(&sql) + let count: (i64,) = happyview::db::query_as(&sql) .bind("did:plc:labeler1") .bind(uri) .bind("nudity") @@ -525,7 +525,7 @@ async fn label_upsert_is_idempotent() { // Insert same label twice (upsert pattern from labeler.rs) for _ in 0..2 { - sqlx::query(&upsert_sql) + happyview::db::query(&upsert_sql) .bind("did:plc:labeler1") .bind(uri) .bind("nudity") @@ -539,7 +539,7 @@ async fn label_upsert_is_idempotent() { "SELECT COUNT(*) FROM happyview_labels WHERE src = ? AND uri = ? AND val = ?", backend, ); - let count: (i64,) = sqlx::query_as(&sql) + let count: (i64,) = happyview::db::query_as(&sql) .bind("did:plc:labeler1") .bind(uri) .bind("nudity") diff --git a/tests/lua_db_api.rs b/tests/lua_db_api.rs index d0d4cda..91a51c5 100644 --- a/tests/lua_db_api.rs +++ b/tests/lua_db_api.rs @@ -144,7 +144,7 @@ async fn seed_records(pool: &sqlx::AnyPool, backend: DatabaseBackend) { backend, ); for (uri, did, collection, rkey, record, cid) in &records { - sqlx::query(&sql) + happyview::db::query(&sql) .bind(uri) .bind(did) .bind(collection) diff --git a/tests/lua_record_api.rs b/tests/lua_record_api.rs index f64c592..fd54e63 100644 --- a/tests/lua_record_api.rs +++ b/tests/lua_record_api.rs @@ -129,7 +129,7 @@ async fn seed_record( VALUES (?, ?, ?, ?, ?, ?, ?)", backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(uri) .bind(did) .bind(collection) @@ -147,7 +147,7 @@ async fn count_records(pool: &sqlx::AnyPool, backend: DatabaseBackend, uri: &str "SELECT COUNT(*) FROM happyview_records WHERE uri = ?", backend, ); - let (count,): (i64,) = sqlx::query_as(&sql) + let (count,): (i64,) = happyview::db::query_as(&sql) .bind(uri) .fetch_one(pool) .await @@ -164,7 +164,7 @@ async fn fetch_record_body( "SELECT record FROM happyview_records WHERE uri = ?", backend, ); - let row: Option<(String,)> = sqlx::query_as(&sql) + let row: Option<(String,)> = happyview::db::query_as(&sql) .bind(uri) .fetch_optional(pool) .await diff --git a/tests/plugin_logging.rs b/tests/plugin_logging.rs index fa029cf..a915a27 100644 --- a/tests/plugin_logging.rs +++ b/tests/plugin_logging.rs @@ -64,7 +64,7 @@ async fn plugin_log_writes_all_four_levels_to_event_logs() { "SELECT severity, subject, detail FROM happyview_event_logs WHERE event_type = ? ORDER BY created_at ASC", backend, ); - let rows: Vec<(String, Option, String)> = sqlx::query_as(&sql) + let rows: Vec<(String, Option, String)> = happyview::db::query_as(&sql) .bind("plugin.log") .fetch_all(&pool) .await @@ -125,7 +125,7 @@ async fn plugin_log_with_none_db_does_not_write_event_log() { "SELECT COUNT(*) FROM happyview_event_logs WHERE event_type = ?", backend, ); - let count: i64 = sqlx::query_scalar(&sql) + let count: i64 = happyview::db::query_scalar(&sql) .bind("plugin.log") .fetch_one(&pool) .await diff --git a/tests/spaces_credential_revocation.rs b/tests/spaces_credential_revocation.rs index f6df382..ed2abd5 100644 --- a/tests/spaces_credential_revocation.rs +++ b/tests/spaces_credential_revocation.rs @@ -94,7 +94,7 @@ async fn remove_member_revokes_credentials() { "INSERT INTO happyview_space_credentials (id, space_id, issued_to, token_hash, expires_at, created_at) VALUES (?, ?, ?, ?, ?, ?)", app.state.db_backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(Uuid::new_v4().to_string()) .bind(&space_id) .bind(MEMBER) diff --git a/tests/spaces_db.rs b/tests/spaces_db.rs index 363532b..ae6d6d0 100644 --- a/tests/spaces_db.rs +++ b/tests/spaces_db.rs @@ -577,7 +577,7 @@ async fn space_credential_revocation_round_trip() { "INSERT INTO happyview_space_credentials (id, space_id, issued_to, token_hash, expires_at, created_at) VALUES (?, ?, ?, ?, ?, ?)", backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(new_id()) .bind(&space_id) .bind(member) diff --git a/tests/transfer_super.rs b/tests/transfer_super.rs index a33caa7..333bcb9 100644 --- a/tests/transfer_super.rs +++ b/tests/transfer_super.rs @@ -14,7 +14,7 @@ async fn user_id_for_did(app: &TestApp, did: &str) -> String { "SELECT id FROM happyview_users WHERE did = ?", app.state.db_backend, ); - let row: (String,) = sqlx::query_as(&sql) + let row: (String,) = happyview::db::query_as(&sql) .bind(did) .fetch_one(&app.state.db) .await @@ -27,7 +27,7 @@ async fn is_super(app: &TestApp, user_id: &str) -> bool { "SELECT is_super FROM happyview_users WHERE id = ?", app.state.db_backend, ); - let row: (i32,) = sqlx::query_as(&sql) + let row: (i32,) = happyview::db::query_as(&sql) .bind(user_id) .fetch_one(&app.state.db) .await @@ -41,7 +41,7 @@ async fn insert_user(app: &TestApp, did: &str) -> String { "INSERT INTO happyview_users (id, did, is_super, created_at) VALUES (?, ?, ?, ?)", app.state.db_backend, ); - sqlx::query(&sql) + happyview::db::query(&sql) .bind(&id) .bind(did) .bind(0_i32) @@ -93,7 +93,7 @@ async fn transfer_super_moves_super_and_grants_permissions() { "SELECT COUNT(*) FROM happyview_user_permissions WHERE user_id = ?", app.state.db_backend, ); - let count: (i64,) = sqlx::query_as(&sql) + let count: (i64,) = happyview::db::query_as(&sql) .bind(&target_id) .fetch_one(&app.state.db) .await -- 2.51.2 From 61c03cd2ce14762d1b57fcb4790b060874fd94c9 Mon Sep 17 00:00:00 2001 From: Trezy Date: Wed, 8 Jul 2026 15:33:52 -0500 Subject: [PATCH 14/14] ci: prevent disk from filling during e2e tests Signed-off-by: Trezy --- .github/workflows/ci.yml | 12 +++ Cargo.lock | 178 ++------------------------------------- Cargo.toml | 2 +- 3 files changed, 18 insertions(+), 174 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fa66021..5b282f4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -180,6 +180,15 @@ jobs: restore-keys: | cargo-${{ runner.os }}- + # Reclaim ~20 GB of preinstalled tooling the Rust build never uses. The + # e2e build (all test binaries in debug) plus the restored target cache + # otherwise exhausts the runner disk ("No space left on device"). + - name: Free disk space + run: | + sudo rm -rf /usr/local/lib/android /usr/share/dotnet /opt/ghc \ + /usr/local/.ghcup /opt/hostedtoolcache/CodeQL + df -h / + - name: Add WASM target run: rustup target add wasm32-unknown-unknown @@ -189,6 +198,9 @@ jobs: - name: Run e2e tests env: TEST_DATABASE_URL: postgres://happyview:happyview@localhost:5432/happyview_test + # Drop debuginfo from the test build — it dominates target/ size and is + # unnecessary in CI. Keeps the enlarged dependency build within disk. + CARGO_PROFILE_DEV_DEBUG: "0" run: cargo test --tests frontend: diff --git a/Cargo.lock b/Cargo.lock index 8b0b21e..0005bff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -309,7 +309,7 @@ dependencies = [ "jose-jwk", "p256 0.13.2", "rand 0.8.6", - "reqwest 0.12.28", + "reqwest", "serde", "serde_html_form", "serde_json", @@ -595,12 +595,6 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" -[[package]] -name = "cfg_aliases" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" - [[package]] name = "chacha20" version = "0.10.1" @@ -1699,10 +1693,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", - "js-sys", "libc", "wasi", - "wasm-bindgen", ] [[package]] @@ -1724,11 +1716,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" dependencies = [ "cfg-if", - "js-sys", "libc", "r-efi 6.0.0", "rand_core 0.10.1", - "wasm-bindgen", ] [[package]] @@ -1844,7 +1834,7 @@ dependencies = [ "rand 0.10.2", "rcgen", "regex", - "reqwest 0.13.4", + "reqwest", "rustls", "semver", "serde", @@ -2622,12 +2612,6 @@ dependencies = [ "hashbrown 0.16.1", ] -[[package]] -name = "lru-slab" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" - [[package]] name = "lua-src" version = "550.1.1" @@ -3255,63 +3239,6 @@ dependencies = [ "syn", ] -[[package]] -name = "quinn" -version = "0.11.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c1a41e437b6bbd489372cd4971de128e85c855f56c57f283d20ff016cf7c0a8" -dependencies = [ - "bytes", - "cfg_aliases", - "pin-project-lite", - "quinn-proto", - "quinn-udp", - "rustc-hash", - "rustls", - "socket2", - "thiserror 2.0.18", - "tokio", - "tracing", - "web-time", -] - -[[package]] -name = "quinn-proto" -version = "0.11.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f4bfc015262b9df63c8845072ce59068853ff5872180c2ce2f13038b970e560" -dependencies = [ - "aws-lc-rs", - "bytes", - "getrandom 0.4.3", - "lru-slab", - "rand 0.10.2", - "rand_pcg", - "ring", - "rustc-hash", - "rustls", - "rustls-pki-types", - "slab", - "thiserror 2.0.18", - "tinyvec", - "tracing", - "web-time", -] - -[[package]] -name = "quinn-udp" -version = "0.5.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35a133f956daabe89a61a685c2649f13d82d5aa4bd5d12d1277e1072a21c0694" -dependencies = [ - "cfg_aliases", - "libc", - "once_cell", - "socket2", - "tracing", - "windows-sys 0.61.2", -] - [[package]] name = "quote" version = "1.0.46" @@ -3409,15 +3336,6 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" -[[package]] -name = "rand_pcg" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caa0f4137e1c0a72f4c651489402276c8e8e1cf081f3b0ba156d2cbeef09e86a" -dependencies = [ - "rand_core 0.10.1", -] - [[package]] name = "rayon" version = "1.12.0" @@ -3540,42 +3458,6 @@ name = "reqwest" version = "0.12.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" -dependencies = [ - "base64", - "bytes", - "futures-core", - "http", - "http-body", - "http-body-util", - "hyper", - "hyper-tls", - "hyper-util", - "js-sys", - "log", - "native-tls", - "percent-encoding", - "pin-project-lite", - "rustls-pki-types", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper", - "tokio", - "tokio-native-tls", - "tower", - "tower-http 0.6.11", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "reqwest" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "219c5811de6525e5416c7d5d53bb656d3afdbc6c5af816e0802bcfa42dbdc1c3" dependencies = [ "base64", "bytes", @@ -3587,22 +3469,21 @@ dependencies = [ "http-body-util", "hyper", "hyper-rustls", + "hyper-tls", "hyper-util", "js-sys", "log", "mime", + "native-tls", "percent-encoding", "pin-project-lite", - "quinn", - "rustls", "rustls-pki-types", - "rustls-platform-verifier", "serde", "serde_json", "serde_urlencoded", "sync_wrapper", "tokio", - "tokio-rustls", + "tokio-native-tls", "tower", "tower-http 0.6.11", "tower-service", @@ -3711,55 +3592,15 @@ dependencies = [ "zeroize", ] -[[package]] -name = "rustls-native-certs" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dab5152771c58876a2146916e53e35057e1a4dfa2b9df0f0305b07f611fdea4d" -dependencies = [ - "openssl-probe", - "rustls-pki-types", - "schannel", - "security-framework", -] - [[package]] name = "rustls-pki-types" version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "764899a24af3980067ee14bc143654f297b22eaebfe3c7b6b211920a5a59b046" dependencies = [ - "web-time", "zeroize", ] -[[package]] -name = "rustls-platform-verifier" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d1e2536ce4f35f4846aa13bff16bd0ff40157cdb14cc056c7b14ba41233ba0" -dependencies = [ - "core-foundation 0.10.1", - "core-foundation-sys", - "jni", - "log", - "once_cell", - "rustls", - "rustls-native-certs", - "rustls-platform-verifier-android", - "rustls-webpki", - "security-framework", - "security-framework-sys", - "webpki-root-certs", - "windows-sys 0.61.2", -] - -[[package]] -name = "rustls-platform-verifier-android" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" - [[package]] name = "rustls-webpki" version = "0.103.13" @@ -5505,15 +5346,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "webpki-root-certs" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d46a5a140e6f7afeccd8eae97eff335163939eac8b929834875168b29b3d267" -dependencies = [ - "rustls-pki-types", -] - [[package]] name = "webpki-roots" version = "0.26.11" diff --git a/Cargo.toml b/Cargo.toml index 7bc93bc..127d634 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,7 +33,7 @@ multibase = "0.9" p256 = { version = "0.14", features = ["pkcs8", "ecdsa"] } uuid = { version = "1", features = ["v4"] } rand = "0.10" -reqwest = { version = "0.13", features = ["json", "form"] } +reqwest = { version = "0.12", features = ["json"] } rustls = { version = "0.23", default-features = false, features = ["ring", "std", "tls12"] } serde = { version = "1", features = ["derive"] } serde_ipld_dagcbor = "0.6"