feat: 所有页面添加ICP备案号 浙ICP备2026052792号
Some checks failed
Deploy Backend / deploy (push) Has been cancelled
Some checks failed
Deploy Backend / deploy (push) Has been cancelled
This commit is contained in:
@@ -283,13 +283,19 @@ pub async fn mock_login(
|
||||
|
||||
let user_id = match query.user_id {
|
||||
Some(id) => {
|
||||
// 验证用户存在
|
||||
match sqlx::query_as::<_, (i32,)>("SELECT id FROM users WHERE id = $1" )
|
||||
// 验证用户存在,同时检查是否管理员
|
||||
match sqlx::query_as::<_, (i32, bool)>("SELECT id, is_admin FROM users WHERE id = $1" )
|
||||
.bind(id)
|
||||
.fetch_optional(pool.get_ref())
|
||||
.await
|
||||
{
|
||||
Ok(Some((uid,))) => uid,
|
||||
Ok(Some((uid, is_admin))) => {
|
||||
if is_admin {
|
||||
return HttpResponse::Forbidden()
|
||||
.json(ErrorResponse::<()>::error("模拟登录不能用于管理员账户"));
|
||||
}
|
||||
uid
|
||||
},
|
||||
Ok(None) => {
|
||||
return HttpResponse::BadRequest()
|
||||
.json(ErrorResponse::<()>::error("用户不存在"));
|
||||
|
||||
@@ -1,24 +1,90 @@
|
||||
use actix_web::{web, get, HttpResponse, Responder};
|
||||
use sqlx::postgres::PgPool;
|
||||
use chrono::{NaiveDateTime, Utc};
|
||||
use openssl::x509::X509;
|
||||
use serde::Serialize;
|
||||
use sqlx::postgres::PgPool;
|
||||
use std::path::Path;
|
||||
|
||||
/// SSL 证书文件路径(生产环境优先)
|
||||
const SSL_CERT_PATHS: &[&str] = &[
|
||||
"/www/sites/xmclassmate.top/ssl/fullchain.pem",
|
||||
"/etc/nginx/sites/xmclassmate.top/ssl/fullchain.pem",
|
||||
];
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct HealthResponse {
|
||||
pub status: String,
|
||||
pub database: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub ssl_cert: Option<SslCertInfo>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub error: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub hint: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct SslCertInfo {
|
||||
pub subject: String,
|
||||
pub issuer: String,
|
||||
pub not_before: String,
|
||||
pub not_after: String,
|
||||
pub days_remaining: i64,
|
||||
pub valid: bool,
|
||||
}
|
||||
|
||||
/// 读取 SSL 证书文件并提取有效期信息
|
||||
fn check_ssl_cert() -> Option<SslCertInfo> {
|
||||
let cert_path = SSL_CERT_PATHS.iter().find(|p| Path::new(p).exists())?;
|
||||
|
||||
let pem_bytes = std::fs::read(cert_path).ok()?;
|
||||
let cert = X509::from_pem(&pem_bytes).ok()?;
|
||||
|
||||
let subject = cert
|
||||
.subject_name()
|
||||
.entries()
|
||||
.next()
|
||||
.and_then(|e| e.data().as_utf8().ok())
|
||||
.map(|s| s.to_string())
|
||||
.unwrap_or_default();
|
||||
|
||||
let issuer = cert
|
||||
.issuer_name()
|
||||
.entries()
|
||||
.next()
|
||||
.and_then(|e| e.data().as_utf8().ok())
|
||||
.map(|s| s.to_string())
|
||||
.unwrap_or_default();
|
||||
|
||||
// OpenSSL Display 格式: "Jun 17 02:39:23 2026 GMT"
|
||||
let nb_str = format!("{}", cert.not_before());
|
||||
let na_str = format!("{}", cert.not_after());
|
||||
let not_before = NaiveDateTime::parse_from_str(&nb_str, "%b %e %H:%M:%S %Y GMT").ok()?;
|
||||
let not_after = NaiveDateTime::parse_from_str(&na_str, "%b %e %H:%M:%S %Y GMT").ok()?;
|
||||
let now = Utc::now().naive_utc();
|
||||
let days_remaining = (not_after - now).num_days();
|
||||
let valid = now >= not_before && now <= not_after;
|
||||
|
||||
Some(SslCertInfo {
|
||||
subject,
|
||||
issuer,
|
||||
not_before: not_before.format("%Y-%m-%d %H:%M UTC").to_string(),
|
||||
not_after: not_after.format("%Y-%m-%d %H:%M UTC").to_string(),
|
||||
days_remaining,
|
||||
valid,
|
||||
})
|
||||
}
|
||||
|
||||
#[get("/health")]
|
||||
pub async fn health_check(pool: web::Data<PgPool>) -> impl Responder {
|
||||
let ssl_cert = check_ssl_cert();
|
||||
|
||||
match sqlx::query("SELECT 1").fetch_one(pool.get_ref()).await {
|
||||
Ok(_) => {
|
||||
HttpResponse::Ok().json(HealthResponse {
|
||||
status: "ok".to_string(),
|
||||
database: "connected".to_string(),
|
||||
ssl_cert,
|
||||
error: None,
|
||||
hint: None,
|
||||
})
|
||||
@@ -54,6 +120,7 @@ pub async fn health_check(pool: web::Data<PgPool>) -> impl Responder {
|
||||
HttpResponse::ServiceUnavailable().json(HealthResponse {
|
||||
status: "error".to_string(),
|
||||
database: "disconnected".to_string(),
|
||||
ssl_cert,
|
||||
error: Some(error_msg),
|
||||
hint: Some(hint_msg),
|
||||
})
|
||||
|
||||
@@ -209,6 +209,7 @@ const HTML_TEMPLATE: &str = r#"<!DOCTYPE html>
|
||||
|
||||
<div class="footer">
|
||||
<p>环境计算助手 · v{version}</p>
|
||||
<p style="margin-top:4px;"><a href="http://beian.miit.gov.cn/" target="_blank" style="color:#999;text-decoration:none;">浙ICP备2026052792号</a></p>
|
||||
<p style="margin-top:4px;">如有问题请联系客服</p>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -143,6 +143,7 @@ function confirmMockPay() {{
|
||||
}});
|
||||
}}
|
||||
</script>
|
||||
<div style="text-align:center;margin-top:32px;padding:16px;color:#999;font-size:12px;"><a href="http://beian.miit.gov.cn/" target="_blank" style="color:#999;text-decoration:none;">浙ICP备2026052792号</a></div>
|
||||
</body>
|
||||
</html>"#, order_no, display_name, jwt, order_no)
|
||||
}
|
||||
@@ -234,6 +235,7 @@ fn build_alipay_form_html(
|
||||
{}
|
||||
</form>
|
||||
<script>document.getElementById('alipay').submit();</script>
|
||||
<div style="text-align:center;margin-top:16px;color:#999;font-size:12px;"><a href="http://beian.miit.gov.cn/" target="_blank" style="color:#999;text-decoration:none;">浙ICP备2026052792号</a></div>
|
||||
</body>
|
||||
</html>"##,
|
||||
config.gateway, form_fields
|
||||
@@ -467,6 +469,9 @@ pub async fn payment_index() -> Result<HttpResponse, AppError> {
|
||||
<div class="footer-links">
|
||||
<button class="btn-logout" onclick="logout()">退出登录</button>
|
||||
</div>
|
||||
<div style="text-align:center;margin-top:12px;padding:8px 16px;color:#aaa;font-size:11px;">
|
||||
<a href="http://beian.miit.gov.cn/" target="_blank" style="color:#aaa;text-decoration:none;">浙ICP备2026052792号</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
@@ -1014,6 +1019,9 @@ fn build_success_html(order_no: &str, jwt_token: &str) -> String {
|
||||
}}
|
||||
}}, 30000);
|
||||
</script>
|
||||
<div style="text-align:center;margin-top:24px;padding:12px;color:#999;font-size:11px;">
|
||||
<a href="http://beian.miit.gov.cn/" target="_blank" style="color:#999;text-decoration:none;">浙ICP备2026052792号</a>
|
||||
</div>
|
||||
</body>
|
||||
</html>"##,
|
||||
green, white, order_no, orange, jwt_token
|
||||
@@ -1031,6 +1039,9 @@ fn format_error_html(msg: &str, order_no: &str) -> String {
|
||||
<p style="color:#666">{}</p>
|
||||
<p style="color:#999;font-size:13px">订单号: {}</p>
|
||||
<p><a href="/payment" style="color:#1677ff">返回重试</a></p>
|
||||
<div style="text-align:center;margin-top:24px;padding:12px;color:#999;font-size:11px;">
|
||||
<a href="http://beian.miit.gov.cn/" target="_blank" style="color:#999;text-decoration:none;">浙ICP备2026052792号</a>
|
||||
</div>
|
||||
</body>
|
||||
</html>"##,
|
||||
msg, order_no
|
||||
|
||||
Reference in New Issue
Block a user