feat: add meta and settings endpoints for improved API functionality
- Introduced new meta endpoints: `/api/alive`, `/api/now`, `/api/version`, and `/api/hibp/breach` for health checks and versioning. - Added settings endpoints: `/api/settings/domains` for retrieving and managing equivalent domains, with stub implementations for future persistence. - Updated router to include new handlers and ensure proper routing for the added endpoints.
This commit is contained in:
parent
5694d87a45
commit
dfa82a0918
5 changed files with 132 additions and 2 deletions
58
src/handlers/meta.rs
Normal file
58
src/handlers/meta.rs
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
use axum::{extract::State, Json};
|
||||
use chrono::{SecondsFormat, Utc};
|
||||
use serde::Deserialize;
|
||||
use serde_json::{json, Value};
|
||||
use std::sync::Arc;
|
||||
use worker::Env;
|
||||
|
||||
use crate::{db, error::AppError};
|
||||
|
||||
/// GET /api/now
|
||||
///
|
||||
/// Mirrors vaultwarden's `/api/now`: returns current UTC timestamp as an RFC3339 string.
|
||||
#[worker::send]
|
||||
pub async fn now() -> Json<String> {
|
||||
Json(Utc::now().to_rfc3339_opts(SecondsFormat::Millis, true))
|
||||
}
|
||||
|
||||
/// GET /api/alive
|
||||
///
|
||||
/// Simple healthcheck. Vaultwarden uses this to also verify DB connectivity.
|
||||
#[worker::send]
|
||||
pub async fn alive(
|
||||
State(env): State<Arc<Env>>,
|
||||
) -> Result<Json<String>, AppError> {
|
||||
// Verify D1 binding is present + basic query works.
|
||||
let db = db::get_db(&env)?;
|
||||
db.prepare("SELECT 1 as ok")
|
||||
.first::<i32>(Some("ok"))
|
||||
.await
|
||||
.map_err(|_| AppError::Database)?;
|
||||
Ok(now().await)
|
||||
}
|
||||
|
||||
/// GET /api/version
|
||||
///
|
||||
/// Returns a Bitwarden-server-like version string. Clients sometimes call this endpoint.
|
||||
#[worker::send]
|
||||
pub async fn version() -> Json<&'static str> {
|
||||
// Keep this in sync with `src/handlers/config.rs`'s `version`.
|
||||
Json("2025.12.0")
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct HibpBreachQuery {
|
||||
#[allow(dead_code)] // stub endpoint doesn't use it yet
|
||||
pub username: String,
|
||||
}
|
||||
|
||||
/// GET /api/hibp/breach?username=...
|
||||
///
|
||||
/// Vaultwarden can proxy HaveIBeenPwned if configured. This minimal server doesn't.
|
||||
/// We return an empty array to indicate "no breach data" without surfacing an error in clients.
|
||||
#[worker::send]
|
||||
pub async fn hibp_breach(_query: axum::extract::Query<HibpBreachQuery>) -> Json<Value> {
|
||||
Json(json!([]))
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -7,7 +7,9 @@ pub mod emergency_access;
|
|||
pub mod folders;
|
||||
pub mod identity;
|
||||
pub mod import;
|
||||
pub mod meta;
|
||||
pub mod purge;
|
||||
pub mod settings;
|
||||
pub mod sync;
|
||||
pub mod twofactor;
|
||||
pub mod webauth;
|
||||
|
|
|
|||
61
src/handlers/settings.rs
Normal file
61
src/handlers/settings.rs
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
use axum::Json;
|
||||
use serde::Deserialize;
|
||||
use serde_json::{json, Value};
|
||||
|
||||
use crate::{auth::Claims, error::AppError};
|
||||
|
||||
/// GET /api/settings/domains
|
||||
///
|
||||
/// Equivalent domains (eq_domains) are used by clients to treat some domains as interchangeable
|
||||
/// for URI matching (e.g. `google.com` vs `youtube.com` in predefined "global" groups).
|
||||
///
|
||||
/// Vaultwarden persists per-user:
|
||||
/// - `equivalentDomains`: custom groups set by the user
|
||||
/// - `excludedGlobalEquivalentDomains`: which predefined groups are disabled
|
||||
///
|
||||
/// This minimal server currently does not persist these settings. We return empty data to
|
||||
/// prevent 404s. In the future, we can implement storage by adding two `users` columns:
|
||||
/// - `equivalent_domains` (TEXT JSON, default "[]")
|
||||
/// - `excluded_globals` (TEXT JSON, default "[]")
|
||||
/// and (optionally) embedding/updating the global domains dataset.
|
||||
#[worker::send]
|
||||
pub async fn get_domains(_claims: Claims) -> Result<Json<Value>, AppError> {
|
||||
Ok(Json(json!({
|
||||
"equivalentDomains": [],
|
||||
"globalEquivalentDomains": [],
|
||||
"object": "domains"
|
||||
})))
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct EquivDomainData {
|
||||
#[allow(dead_code)] // stub endpoint doesn't persist these yet
|
||||
pub excluded_global_equivalent_domains: Option<Vec<i32>>,
|
||||
#[allow(dead_code)] // stub endpoint doesn't persist these yet
|
||||
pub equivalent_domains: Option<Vec<Vec<String>>>,
|
||||
}
|
||||
|
||||
/// POST /api/settings/domains
|
||||
///
|
||||
/// Stub: accept payload but do not persist yet.
|
||||
#[worker::send]
|
||||
pub async fn post_domains(
|
||||
_claims: Claims,
|
||||
_payload: Json<EquivDomainData>,
|
||||
) -> Result<Json<Value>, AppError> {
|
||||
Ok(Json(json!({})))
|
||||
}
|
||||
|
||||
/// PUT /api/settings/domains
|
||||
///
|
||||
/// Stub: behaves like POST.
|
||||
#[worker::send]
|
||||
pub async fn put_domains(
|
||||
claims: Claims,
|
||||
payload: Json<EquivDomainData>,
|
||||
) -> Result<Json<Value>, AppError> {
|
||||
post_domains(claims, payload).await
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -92,7 +92,7 @@ pub async fn get_sync_data(
|
|||
.map_err(|_| AppError::Internal)?;
|
||||
|
||||
let response = format!(
|
||||
r#"{{"profile":{},"folders":{},"collections":[],"policies":[],"ciphers":{},"domains":null,"sends":[],"userDecryption":{},"object":"sync"}}"#,
|
||||
r#"{{"profile":{},"folders":{},"collections":[],"policies":[],"ciphers":{},"domains":{{"equivalentDomains":[],"globalEquivalentDomains":[],"object":"domains"}},"sends":[],"userDecryption":{},"object":"sync"}}"#,
|
||||
profile_json, folders_json, ciphers_json, user_decryption_json
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use worker::Env;
|
|||
|
||||
use crate::handlers::{
|
||||
accounts, attachments, ciphers, config, devices, emergency_access, folders, identity, import,
|
||||
sync, twofactor, webauth,
|
||||
meta, settings, sync, twofactor, webauth,
|
||||
};
|
||||
|
||||
pub fn api_router(env: Env) -> Router {
|
||||
|
|
@ -138,6 +138,15 @@ pub fn api_router(env: Env) -> Router {
|
|||
.route("/api/folders/{id}", delete(folders::delete_folder))
|
||||
.route("/api/folders/{id}/delete", post(folders::delete_folder))
|
||||
.route("/api/config", get(config::config))
|
||||
// Meta endpoints (mirrors a subset of vaultwarden core/mod.rs)
|
||||
.route("/api/alive", get(meta::alive))
|
||||
.route("/api/now", get(meta::now))
|
||||
.route("/api/version", get(meta::version))
|
||||
.route("/api/hibp/breach", get(meta::hibp_breach))
|
||||
// Settings (stubbed)
|
||||
.route("/api/settings/domains", get(settings::get_domains))
|
||||
.route("/api/settings/domains", post(settings::post_domains))
|
||||
.route("/api/settings/domains", put(settings::put_domains))
|
||||
// Emergency access (stub - returns empty lists, feature not supported)
|
||||
.route(
|
||||
"/api/emergency-access/trusted",
|
||||
|
|
|
|||
Loading…
Reference in a new issue