fix(presenter): M114 错误分类只看结构化字段(status/kind/server_message),不再 Debug 整条错误
- `AuthError::Response` 的判据从 `format!("{detail:?}")`(连中文 what/digest 一起扫)
改成读 `ResponseDetail{status, kind, server_message, digest}`
- 5xx 与拦截页(Html/Text)归 `Unreachable`(「连不上」而不是「服务器拒绝了你」),
AADSTS/consent/whitelist 标记仍优先判 `NotWhitelisted`
- 补两条分类用例:AADSTS 优先于一般拒绝、5xx/拦截页归不可达
This commit is contained in:
1 parent
73badb8a02
commit
178f6ebbff
1 file changed
+59
-2
@@ -5,6 +5,8 @@
|
|||||||
|
|
||||||
use unlucky_core::auth::AuthError;
|
use unlucky_core::auth::AuthError;
|
||||||
|
|
||||||
|
use unlucky_core::auth::BodyKind;
|
||||||
|
|
||||||
use crate::dto::{AccountNoticeCode, LoginFailure};
|
use crate::dto::{AccountNoticeCode, LoginFailure};
|
||||||
|
|
||||||
/// 账户写操作的失败:**结构化码 + 原文**(原文只进日志/详细信息,不上屏)。
|
/// 账户写操作的失败:**结构化码 + 原文**(原文只进日志/详细信息,不上屏)。
|
||||||
@@ -44,10 +46,17 @@ pub(super) fn classify(error: &AuthError) -> LoginFailure {
|
|||||||
LoginFailure::Denied
|
LoginFailure::Denied
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 只看 `ResponseDetail` 的**结构化字段**(status / kind / server_message),
|
||||||
|
// 不把整条错误 Debug 成字符串再去扫——那会把中文 `what`/`digest` 也算进判据里。
|
||||||
AuthError::Response(detail) => {
|
AuthError::Response(detail) => {
|
||||||
let blob = format!("{detail:?}");
|
let server = detail.server_message.as_deref().unwrap_or_default();
|
||||||
if mentions_whitelist(&blob) {
|
let digest = detail.digest.as_str();
|
||||||
|
if mentions_whitelist(server) || mentions_whitelist(digest) {
|
||||||
LoginFailure::NotWhitelisted
|
LoginFailure::NotWhitelisted
|
||||||
|
} else if detail.status >= 500 || matches!(detail.kind, BodyKind::Html | BodyKind::Text)
|
||||||
|
{
|
||||||
|
// 5xx / 拦截页:服务器或链路出了问题,不是「它拒绝了你」。
|
||||||
|
LoginFailure::Unreachable
|
||||||
} else {
|
} else {
|
||||||
LoginFailure::Denied
|
LoginFailure::Denied
|
||||||
}
|
}
|
||||||
@@ -67,3 +76,51 @@ pub(super) fn mentions_whitelist(text: &str) -> bool {
|
|||||||
|| lowered.contains("whitelist")
|
|| lowered.contains("whitelist")
|
||||||
|| lowered.contains("not approved")
|
|| lowered.contains("not approved")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use unlucky_core::auth::body::ResponseDetail;
|
||||||
|
|
||||||
|
fn response(status: u16, kind: BodyKind, server_message: Option<&str>) -> AuthError {
|
||||||
|
AuthError::Response(Box::new(ResponseDetail {
|
||||||
|
step: "xsts".to_string(),
|
||||||
|
what: "XSTS 授权".to_string(),
|
||||||
|
status,
|
||||||
|
content_type: None,
|
||||||
|
kind,
|
||||||
|
server_message: server_message.map(str::to_string),
|
||||||
|
digest: "digest".to_string(),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 403 带 AADSTS 码 → 白名单未批;403 不带 → 一般性拒绝。
|
||||||
|
#[test]
|
||||||
|
fn aadsts_markers_win_over_the_generic_denial() {
|
||||||
|
assert_eq!(
|
||||||
|
classify(&response(
|
||||||
|
403,
|
||||||
|
BodyKind::Json,
|
||||||
|
Some("AADSTS7000218: app not approved")
|
||||||
|
)),
|
||||||
|
LoginFailure::NotWhitelisted
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
classify(&response(403, BodyKind::Json, Some("invalid_grant"))),
|
||||||
|
LoginFailure::Denied
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 5xx 与「拦截页」(HTML/纯文本)归「连不上」,不是「服务器拒绝了你」。
|
||||||
|
#[test]
|
||||||
|
fn upstream_failures_and_intercept_pages_are_unreachable() {
|
||||||
|
assert_eq!(
|
||||||
|
classify(&response(503, BodyKind::Json, None)),
|
||||||
|
LoginFailure::Unreachable
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
classify(&response(200, BodyKind::Html, None)),
|
||||||
|
LoginFailure::Unreachable
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user