- 拆分 web.rs 为 web/ 子模块;统一 client_ip 提取 - core: user_scope SQL 复用、env_map N+1 消除、FETCH_ALL 上限调整 - entries 列表页并行查询;PgPool 去 Arc;结构化 NotFound 等错误 - CI: SSH 私钥安全写入;crypto/hex 与依赖清理;MCP 输入长度校验 - AGENTS: API Key 明文存储设计说明
74 lines
2.2 KiB
Rust
74 lines
2.2 KiB
Rust
use axum::{
|
|
body::Body,
|
|
extract::State,
|
|
http::{StatusCode, header},
|
|
response::{IntoResponse, Response},
|
|
};
|
|
|
|
use crate::AppState;
|
|
|
|
pub(super) fn text_asset_response(content: &'static str, content_type: &'static str) -> Response {
|
|
Response::builder()
|
|
.status(StatusCode::OK)
|
|
.header(header::CONTENT_TYPE, content_type)
|
|
.header(header::CACHE_CONTROL, "public, max-age=86400")
|
|
.body(Body::from(content))
|
|
.expect("text asset response")
|
|
}
|
|
|
|
pub(super) async fn robots_txt() -> Response {
|
|
text_asset_response(
|
|
include_str!("../../static/robots.txt"),
|
|
"text/plain; charset=utf-8",
|
|
)
|
|
}
|
|
|
|
pub(super) async fn llms_txt() -> Response {
|
|
text_asset_response(
|
|
include_str!("../../static/llms.txt"),
|
|
"text/markdown; charset=utf-8",
|
|
)
|
|
}
|
|
|
|
pub(super) async fn ai_txt() -> Response {
|
|
llms_txt().await
|
|
}
|
|
|
|
pub(super) async fn i18n_js() -> Response {
|
|
text_asset_response(
|
|
include_str!("../../templates/i18n.js"),
|
|
"application/javascript; charset=utf-8",
|
|
)
|
|
}
|
|
|
|
pub(super) 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")
|
|
}
|
|
|
|
/// RFC 9728 — OAuth 2.0 Protected Resource Metadata.
|
|
///
|
|
/// Advertises that this server accepts Bearer tokens in the `Authorization`
|
|
/// header. We deliberately omit `authorization_servers` because this service
|
|
/// issues its own API keys (no external OAuth AS is involved). MCP clients
|
|
/// that probe this endpoint will see the resource identifier and stop looking
|
|
/// for a delegated OAuth flow.
|
|
pub(super) async fn oauth_protected_resource_metadata(
|
|
State(state): State<AppState>,
|
|
) -> impl IntoResponse {
|
|
let body = serde_json::json!({
|
|
"resource": state.base_url,
|
|
"bearer_methods_supported": ["header"],
|
|
"resource_documentation": format!("{}/dashboard", state.base_url),
|
|
});
|
|
(
|
|
StatusCode::OK,
|
|
[(header::CONTENT_TYPE, "application/json")],
|
|
axum::Json(body),
|
|
)
|
|
}
|