fix: 移除订单自动确认,仅依赖支付宝回调验签;rsa2_verify 支持裸 base64 DER 公钥;.env 取消 git 跟踪
This commit is contained in:
19
.env
19
.env
@@ -1,19 +0,0 @@
|
|||||||
# .env
|
|
||||||
DATABASE_URL=postgres://milkydata:44n6FdB8CdDAk5rk@154.37.213.24:5432/milkydata
|
|
||||||
WECHAT_APPID="wx5b00eb90621802f7"
|
|
||||||
WECHAT_SECRET="494efc513faa310bfba588bda2849bfd"
|
|
||||||
JWT_SECRET="your_super_secret_key"
|
|
||||||
SSL_KEY_PATH=/etc/ssl/private/private.key
|
|
||||||
SSL_CERT_PATH=/etc/ssl/certs/full_chain.pem
|
|
||||||
RUST_LOG=info
|
|
||||||
APP_VERSION="0.2.0"
|
|
||||||
FREE_USER_DATA_LIMIT=20
|
|
||||||
SSH_SERVER=root@1panel-server
|
|
||||||
|
|
||||||
# 支付宝生产环境配置
|
|
||||||
# 支付宝生产环境配置
|
|
||||||
ALIPAY_APP_ID=2021006148681106
|
|
||||||
ALIPAY_PRIVATE_KEY="MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCImX4Zj18whXYi6l29caq+ShjqT7JwWDbOoz/hEqZqPxQNu6KF59OswcUIv3It4CxJ0/kXsiC/pc6mrN9GedOAPIaz6YydgII/nwHl4OdPPxW8jeomBuiSmcbPcZ4AJTi1YTxrj//8YDIQInVc5/I4HPg+osN4qkqy+xrJ4vGrmyy+ClwHh3OxglGDLhbprH4WCgxKjwTDfR1A84w+pbrST1YaWI7sqqPhVxuYQQPjaLOpXMgrJu5ctnlFVTC27mY2wSIrxajB/6w1SQ+Z+Z149frk47PBOwL+xfKT4gwy3yj/t7WZStzH0gEhG7mXjc6qIjZ8uH5OxUZ+f6gMDpKBAgMBAAECggEAYnI87y7k65NEEOXXqTDCXWIJktTdRRpOZZ5B63QFe4z6ZutTti3d4CPGXQecwnNNd+fNHcbC01wsEvOD9sbWJxV3/zHSpbB4LmHqfEIacoKEp9+fYMiZ1Q3+uoKn3HL268GoSdz+IGUzr20mKE8Bwm8eegXT2qLgMx3FsLpecc3WXmwgMDI/alknO81+xZenLH1Y6+XdsoPVWsS3OY3gnzfYz40n1LaLCQiklBu6AUjSQupSUJ53rGtYpZnp+ImYwBVcYeFL0mZZVId/lzDI2K8eaM/RGVZYsU1vkP6CeSJzWhpr6ftSRRl3VJQou0ytLLX/YeUoXIhsfZ+x3cPKAQKBgQC9ub1z+T/+0lHZwm360otNHQNeEq3FYjnx1x7WOWTXCsAqVZizfmpUYSHoNZeNlyLpbXVsYp22xJmLBArB9LBMvjY1z2iOQJW7F46O6cY38AcgWC41YalLcrk2y4jny6rJZRMjvmDOM67SH01pzZQ6eGJpzSZpTj2Jm/tBsH7gGwKBgQC4UPK5a32ov9YuyzfQXcW341JFlTK2k2D1ewilYSZifpTDqdVpH1gSzGpfoXI7K6Z26xkx1n5rOIe+SxOKaNBj/5PJuEzmMVvUWkFU0IutoqVc2R6h4Rb+9q7llzAavFZ5Ssj1u9Q5Pjhc5Jr8zM6xXk55/4CuqYuBMCcte4fZkwKBgF/kVSEcxX+iBcSuRLAVYlrjYyRVBIdTEj5toCRedd1Kjb3X7YorRsrHHUAkdikWTor0y/iwD06lJ4Xf0SAe8EyZhwTDg/ECK6uYSHFrLshvBOsQJqrMZajAn2RWkye1BOktsPLL8lnGPYHuWE41ncm/tt4K1nM7HFdFA0U8U6QpAoGAe0gRgboG+6cMoJHmjCUciUmwDsCjggEDuk4H024umXSnFlRzXPPNGg3GHJ7E5BTnK+VGHdKlDhxqlvpqYIqI0EnzVNpD/TgIfvm7dvpiYspGJttGpOoEUpc3FnPQhiFxCYHe9pYidgNK+b8id3KZ0YMNpIYkUS8wE0HdAov8qqcCgYEAtRjXzj4JZ5we6aOqv4bcr7xLw4a7wzS99K5EcrbYRxvibUhelooQdgdY40FmdtfuY/4rpHC3R9/13aqcD/WSTFOdOsZAcfTi738y13h3dCy3FZisLYM7rgjUSnQnEGlyR0TYE4Yda490rpYJBjyQIE3EcIlWPerm8vh1wx1Rh90="
|
|
||||||
ALIPAY_ALIPAY_PUBLIC_KEY="MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkhLqABUN1E2PCmOznQp+53T3x4j27I96hdatl6lWbCBPwyXnZVW4uYZ4kV+34+i2wCzEtMpUiNQaIsQXx2qD8x0d8szsj7pEZuY+xUUJTzm95fYO2nq4aaQ38T/kxdYrW12is8vwY83rlghdlkvVP2XZCuYoFq9UVieTu6LTDk6v91Mt2xr1Zw1Oj+yg8VpBFXkcS7ORJjiufWzCEoxzlb2KK2AGOLhdc8BJsBfrQ0JAqFB6b0uteUF21DDdPN/sblD8GoRAGuSpDhyQLG+0fDNdcIMyHpsq7bIDNjgYGS8RbKAtb6WyV6vriIemZ0fMvzN5Mpqv2jwCe/31ar//PwIDAQAB"
|
|
||||||
ALIPAY_GATEWAY="https://openapi.alipay.com/gateway.do"
|
|
||||||
APP_BASE_URL="https://dev.xmclassmate.top"
|
|
||||||
39
src/db.rs
39
src/db.rs
@@ -371,45 +371,6 @@ pub async fn get_user_orders(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 扫描超过 10 分钟的待支付订单,尝试自动确认(用于回调重试)
|
/// 扫描超过 10 分钟的待支付订单,尝试自动确认(用于回调重试)
|
||||||
/// 返回成功确认的订单数量
|
|
||||||
pub async fn check_and_retry_pending_orders(pool: &PgPool) -> Result<u64, AppError> {
|
|
||||||
// 查找超过 10 分钟仍为 pending 的订单
|
|
||||||
let stuck_orders: Vec<(String,)> = sqlx::query_as(
|
|
||||||
r#"
|
|
||||||
SELECT order_no FROM payment_orders
|
|
||||||
WHERE status = 'pending'
|
|
||||||
AND created_at < NOW() - INTERVAL '10 minutes'
|
|
||||||
AND created_at > NOW() - INTERVAL '24 hours'
|
|
||||||
ORDER BY created_at ASC
|
|
||||||
"#,
|
|
||||||
)
|
|
||||||
.fetch_all(pool)
|
|
||||||
.await
|
|
||||||
.map_err(|e| AppError::Database(format!("查询待处理订单失败: {}", e)))?;
|
|
||||||
|
|
||||||
if stuck_orders.is_empty() {
|
|
||||||
return Ok(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
tracing::info!(
|
|
||||||
"发现 {} 个待处理订单,尝试自动确认...",
|
|
||||||
stuck_orders.len()
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut confirmed: u64 = 0;
|
|
||||||
for (order_no,) in &stuck_orders {
|
|
||||||
match confirm_payment_order_by_orderno(pool, order_no).await {
|
|
||||||
Ok(_) => {
|
|
||||||
confirmed += 1;
|
|
||||||
tracing::info!("定时任务自动确认订单: {}", order_no);
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
tracing::warn!("定时任务无法确认订单 {}: {}", order_no, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(confirmed)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 检查会员到期前 7 天的用户,发送即将到期通知
|
/// 检查会员到期前 7 天的用户,发送即将到期通知
|
||||||
pub async fn check_member_expiry_soon(pool: &PgPool) -> Result<u64, AppError> {
|
pub async fn check_member_expiry_soon(pool: &PgPool) -> Result<u64, AppError> {
|
||||||
|
|||||||
@@ -153,9 +153,15 @@ fn rsa2_verify(content: &str, sign: &str, public_key_pem: &str) -> Result<bool,
|
|||||||
use rsa::pkcs8::DecodePublicKey;
|
use rsa::pkcs8::DecodePublicKey;
|
||||||
use rsa::RsaPublicKey;
|
use rsa::RsaPublicKey;
|
||||||
use sha2::Digest;
|
use sha2::Digest;
|
||||||
let public_key =
|
let public_key = RsaPublicKey::from_public_key_pem(public_key_pem).or_else(|_| {
|
||||||
RsaPublicKey::from_public_key_pem(public_key_pem)
|
base64::Engine::decode(&base64::engine::general_purpose::STANDARD, public_key_pem)
|
||||||
.map_err(|e| format!("支付宝公钥解析失败: {}", e))?;
|
.map_err(|e| format!("支付宝公钥 base64 解码失败: {}", e))
|
||||||
|
.and_then(|der| {
|
||||||
|
RsaPublicKey::from_public_key_der(&der)
|
||||||
|
.map_err(|e| format!("支付宝公钥 DER 解析失败: {}", e))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.map_err(|e| format!("支付宝公钥解析失败: {}", e))?;
|
||||||
let sig_bytes = base64::Engine::decode(&base64::engine::general_purpose::STANDARD, sign)
|
let sig_bytes = base64::Engine::decode(&base64::engine::general_purpose::STANDARD, sign)
|
||||||
.map_err(|e| format!("签名 Base64 解码失败: {}", e))?;
|
.map_err(|e| format!("签名 Base64 解码失败: {}", e))?;
|
||||||
let hashed = Sha256::digest(content.as_bytes());
|
let hashed = Sha256::digest(content.as_bytes());
|
||||||
|
|||||||
11
src/main.rs
11
src/main.rs
@@ -244,22 +244,13 @@ async fn main() -> std::io::Result<()> {
|
|||||||
Err(e) => warn!("启动时清理 web 登录码失败: {}", e),
|
Err(e) => warn!("启动时清理 web 登录码失败: {}", e),
|
||||||
}
|
}
|
||||||
|
|
||||||
// 后台定时扫描待支付订单(每 5 分钟)
|
|
||||||
let pool_clone = pool.clone();
|
let pool_clone = pool.clone();
|
||||||
actix_web::rt::spawn(async move {
|
actix_web::rt::spawn(async move {
|
||||||
let mut interval = actix_web::rt::time::interval(std::time::Duration::from_secs(300));
|
let mut interval = actix_web::rt::time::interval(std::time::Duration::from_secs(300));
|
||||||
interval.tick().await; // 跳过立即执行
|
interval.tick().await; // 跳过立即执行
|
||||||
loop {
|
loop {
|
||||||
interval.tick().await;
|
interval.tick().await;
|
||||||
tracing::info!("[定时任务] 开始扫描待支付订单...");
|
tracing::info!("[定时任务] 开始...");
|
||||||
match db::check_and_retry_pending_orders(&pool_clone).await {
|
|
||||||
Ok(confirmed) => {
|
|
||||||
if confirmed > 0 {
|
|
||||||
tracing::info!("[定时任务] 自动确认了 {} 个待支付订单", confirmed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(e) => tracing::warn!("[定时任务] 扫描待支付订单失败: {}", e),
|
|
||||||
}
|
|
||||||
|
|
||||||
// 会员到期前 7 天提醒
|
// 会员到期前 7 天提醒
|
||||||
if let Err(e) = db::check_member_expiry_soon(&pool_clone).await {
|
if let Err(e) = db::check_member_expiry_soon(&pool_clone).await {
|
||||||
|
|||||||
Reference in New Issue
Block a user