feat: user-scoped history/delete/rollback, dashboard & login UI, ignore *.pem
- Filter history/rollback/delete by user_id in secrets-core - MCP tools/web pass user context; dashboard refresh; favicon static - .gitignore *.pem; vscode tasks tweaks - clippy: collapse else-if in rollback latest-history branch Made-with: Cursor
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
use askama::Template;
|
||||
use axum::{
|
||||
Json, Router,
|
||||
body::Body,
|
||||
extract::{Path, Query, State},
|
||||
http::StatusCode,
|
||||
http::{StatusCode, header},
|
||||
response::{Html, IntoResponse, Redirect, Response},
|
||||
routing::{get, post},
|
||||
};
|
||||
@@ -33,6 +34,7 @@ const SESSION_LOGIN_PROVIDER: &str = "login_provider";
|
||||
#[template(path = "login.html")]
|
||||
struct LoginTemplate {
|
||||
has_google: bool,
|
||||
version: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Template)]
|
||||
@@ -42,6 +44,7 @@ struct DashboardTemplate {
|
||||
user_email: String,
|
||||
has_passphrase: bool,
|
||||
base_url: String,
|
||||
version: &'static str,
|
||||
}
|
||||
|
||||
// ── App state helpers ─────────────────────────────────────────────────────────
|
||||
@@ -63,6 +66,11 @@ async fn current_user_id(session: &Session) -> Option<Uuid> {
|
||||
|
||||
pub fn web_router() -> Router<AppState> {
|
||||
Router::new()
|
||||
.route("/favicon.svg", get(favicon_svg))
|
||||
.route(
|
||||
"/favicon.ico",
|
||||
get(|| async { Redirect::permanent("/favicon.svg") }),
|
||||
)
|
||||
.route("/", get(login_page))
|
||||
.route("/auth/google", get(auth_google))
|
||||
.route("/auth/google/callback", get(auth_google_callback))
|
||||
@@ -80,6 +88,15 @@ pub fn web_router() -> Router<AppState> {
|
||||
.route("/api/apikey/regenerate", post(api_apikey_regenerate))
|
||||
}
|
||||
|
||||
async fn favicon_svg() -> Response {
|
||||
Response::builder()
|
||||
.status(StatusCode::OK)
|
||||
.header(header::CONTENT_TYPE, "image/svg+xml")
|
||||
.header(header::CACHE_CONTROL, "public, max-age=86400")
|
||||
.body(Body::from(include_str!("../static/favicon.svg")))
|
||||
.expect("favicon response")
|
||||
}
|
||||
|
||||
// ── Login page ────────────────────────────────────────────────────────────────
|
||||
|
||||
async fn login_page(
|
||||
@@ -92,6 +109,7 @@ async fn login_page(
|
||||
|
||||
let tmpl = LoginTemplate {
|
||||
has_google: state.google_config.is_some(),
|
||||
version: env!("CARGO_PKG_VERSION"),
|
||||
};
|
||||
render_template(tmpl)
|
||||
}
|
||||
@@ -272,20 +290,24 @@ async fn dashboard(
|
||||
State(state): State<AppState>,
|
||||
session: Session,
|
||||
) -> Result<Response, StatusCode> {
|
||||
let user_id = current_user_id(&session)
|
||||
.await
|
||||
.ok_or(StatusCode::UNAUTHORIZED)?;
|
||||
let Some(user_id) = current_user_id(&session).await else {
|
||||
return Ok(Redirect::to("/").into_response());
|
||||
};
|
||||
|
||||
let user = get_user_by_id(&state.pool, user_id)
|
||||
let user = match get_user_by_id(&state.pool, user_id)
|
||||
.await
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
|
||||
.ok_or(StatusCode::UNAUTHORIZED)?;
|
||||
{
|
||||
Some(u) => u,
|
||||
None => return Ok(Redirect::to("/").into_response()),
|
||||
};
|
||||
|
||||
let tmpl = DashboardTemplate {
|
||||
user_name: user.name.clone(),
|
||||
user_email: user.email.clone().unwrap_or_default(),
|
||||
has_passphrase: user.key_salt.is_some(),
|
||||
base_url: state.base_url.clone(),
|
||||
version: env!("CARGO_PKG_VERSION"),
|
||||
};
|
||||
|
||||
render_template(tmpl)
|
||||
|
||||
Reference in New Issue
Block a user