fix: stabilize admin tracking event display

This commit is contained in:
2026-05-08 11:15:42 +08:00
parent a71df45437
commit 0235200d32
6 changed files with 297 additions and 18 deletions

View File

@@ -1456,9 +1456,19 @@ fn build_aliyun_sms_url(endpoint: &str) -> Result<String, SmsProviderError> {
}
fn current_aliyun_timestamp() -> String {
OffsetDateTime::now_utc()
.format(&time::format_description::well_known::Rfc3339)
.unwrap_or_else(|_| "1970-01-01T00:00:00Z".to_string())
// 阿里云 OpenAPI ACS3 签名头 x-acs-date 要求使用不带小数秒的 UTC ISO 8601 格式,
// 即 yyyy-MM-dd'T'HH:mm:ss'Z'。time crate 的 Rfc3339 会保留纳秒,
// 形如 2026-05-07T14:23:59.364767Z,阿里云网关会判定为时间格式非法。
let now = OffsetDateTime::now_utc();
format!(
"{:04}-{:02}-{:02}T{:02}:{:02}:{:02}Z",
now.year(),
u8::from(now.month()),
now.day(),
now.hour(),
now.minute(),
now.second()
)
}
fn canonicalize_aliyun_form_params(params: &BTreeMap<String, String>) -> String {
@@ -1480,8 +1490,9 @@ fn build_aliyun_form_body(params: &BTreeMap<String, String>) -> String {
}
fn hmac_sha256_hex(key: &[u8], content: &[u8]) -> Result<String, SmsProviderError> {
let mut signer = HmacSha256::new_from_slice(key)
.map_err(|error| SmsProviderError::InvalidConfig(format!("初始化短信签名器失败:{error}")))?;
let mut signer = HmacSha256::new_from_slice(key).map_err(|error| {
SmsProviderError::InvalidConfig(format!("初始化短信签名器失败:{error}"))
})?;
signer.update(content);
Ok(hex_lower(&signer.finalize().into_bytes()))
}
@@ -2146,6 +2157,23 @@ mod tests {
assert!(headers.get("x-acs-content-sha256").is_some());
}
#[test]
fn current_aliyun_timestamp_uses_acs_iso8601_format_without_fractional_seconds() {
let timestamp = current_aliyun_timestamp();
assert_eq!(timestamp.len(), "2026-05-07T12:34:56Z".len());
assert_eq!(timestamp.as_bytes()[4], b'-');
assert_eq!(timestamp.as_bytes()[7], b'-');
assert_eq!(timestamp.as_bytes()[10], b'T');
assert_eq!(timestamp.as_bytes()[13], b':');
assert_eq!(timestamp.as_bytes()[16], b':');
assert!(timestamp.ends_with('Z'));
assert!(!timestamp.contains('.'));
assert!(timestamp.chars().enumerate().all(|(index, value)| {
matches!(index, 4 | 7 | 10 | 13 | 16 | 19) || value.is_ascii_digit()
}));
}
#[test]
fn aliyun_send_response_deserializes_pascal_case_fields() {
let payload = serde_json::from_str::<AliyunSendSmsVerifyCodeResponse>(