Skip to main content

openlark_security/
error.rs

1//! 安全服务错误处理模块
2//!
3//! 完全基于 CoreError 的现代化错误处理系统
4//! 直接集成统一错误体系,提供类型安全和可观测性
5
6use openlark_core::error::{
7    CoreError, ErrorCode, ErrorContext, ErrorTrait, authentication_error, business_error,
8    configuration_error, network_error_with_details, permission_missing_error, rate_limit_error,
9    token_expired_error, validation_error,
10};
11use serde::Serialize;
12use std::time::Duration;
13
14// 导入内部结构体
15use openlark_core::error::ApiError;
16
17/// 安全服务错误类型 - 完全基于 CoreError
18pub type SecurityError = CoreError;
19
20/// 安全服务结果类型
21pub type SecurityResult<T> = Result<T, SecurityError>;
22
23/// 安全错误构建器 - 专门用于安全场景的便利函数
24#[derive(Debug, Copy, Clone)]
25pub struct SecurityErrorBuilder;
26
27impl SecurityErrorBuilder {
28    /// 设备未找到
29    pub fn device_not_found(device_id: impl Into<String>) -> SecurityError {
30        let mut ctx = ErrorContext::new();
31        ctx.add_context("device_id", device_id.into());
32        ctx.add_context("operation", "device_lookup");
33
34        CoreError::Validation {
35            field: "device_id".into(),
36            message: "设备未找到,请检查设备ID是否正确".to_string(),
37            code: ErrorCode::ValidationError,
38            ctx: Box::new(ctx),
39        }
40    }
41
42    /// 设备连接失败
43    pub fn device_connection_failed(
44        device_id: impl Into<String>,
45        reason: impl Into<String>,
46    ) -> SecurityError {
47        let mut ctx = ErrorContext::new();
48        ctx.add_context("device_id", device_id.into());
49        ctx.add_context("connection_reason", reason.into());
50        ctx.add_context("operation", "device_connection");
51
52        network_error_with_details(
53            "设备连接失败",
54            None::<String>,
55            Some(format!(
56                "device:{}",
57                ctx.get_context("device_id").unwrap_or_default()
58            )),
59        )
60    }
61
62    /// 设备临时不可用(可重试)
63    pub fn device_temporarily_unavailable(
64        device_id: impl Into<String>,
65        retry_after: Option<Duration>,
66    ) -> SecurityError {
67        let mut ctx = ErrorContext::new();
68        ctx.add_context("device_id", device_id.into());
69        ctx.add_context("availability", "temporary");
70
71        CoreError::ServiceUnavailable {
72            service: "security_device".into(),
73            retry_after,
74            code: ErrorCode::ServiceUnavailable,
75            ctx: Box::new(ctx),
76        }
77    }
78
79    /// 访问控制被拒绝
80    pub fn access_denied(resource: impl Into<String>, reason: impl Into<String>) -> SecurityError {
81        let mut ctx = ErrorContext::new();
82        ctx.add_context("resource", resource.into());
83        ctx.add_context("deny_reason", reason.into());
84        ctx.add_context("operation", "access_control");
85
86        permission_missing_error(&["security:access"])
87    }
88
89    /// 权限范围不足
90    pub fn insufficient_permissions(
91        required_permissions: &[impl AsRef<str>],
92        current_permissions: &[impl AsRef<str>],
93    ) -> SecurityError {
94        let mut ctx = ErrorContext::new();
95        ctx.add_context(
96            "required_permissions",
97            required_permissions
98                .iter()
99                .map(|s| s.as_ref())
100                .collect::<Vec<_>>()
101                .join(","),
102        );
103        ctx.add_context(
104            "current_permissions",
105            current_permissions
106                .iter()
107                .map(|s| s.as_ref())
108                .collect::<Vec<_>>()
109                .join(","),
110        );
111
112        CoreError::Authentication {
113            message: "安全权限不足".to_string(),
114            code: ErrorCode::PermissionMissing,
115            ctx: Box::new(ctx),
116        }
117    }
118
119    /// 人脸识别失败
120    pub fn face_recognition_failed(
121        reason: impl Into<String>,
122        image_id: Option<impl Into<String>>,
123    ) -> SecurityError {
124        let mut ctx = ErrorContext::new();
125        ctx.add_context("recognition_reason", reason.into());
126        if let Some(id) = image_id {
127            ctx.add_context("image_id", id.into());
128        }
129        ctx.add_context("operation", "face_recognition");
130
131        validation_error("face_image", "人脸识别失败,请重新上传清晰的人脸照片")
132    }
133
134    /// 人脸识别服务不可用
135    pub fn face_recognition_service_unavailable() -> SecurityError {
136        let mut ctx = ErrorContext::new();
137        ctx.add_context("service", "face_recognition");
138        ctx.add_context("operation", "face_recognition");
139
140        CoreError::ServiceUnavailable {
141            service: "face_recognition".into(),
142            retry_after: Some(Duration::from_secs(30)),
143            code: ErrorCode::ServiceUnavailable,
144            ctx: Box::new(ctx),
145        }
146    }
147
148    /// 访客权限过期
149    pub fn visitor_permission_expired(
150        visitor_id: impl Into<String>,
151        visit_type: impl Into<String>,
152    ) -> SecurityError {
153        let mut ctx = ErrorContext::new();
154        ctx.add_context("visitor_id", visitor_id.into());
155        ctx.add_context("visit_type", visit_type.into());
156        ctx.add_context("operation", "visitor_access");
157
158        business_error("访客权限已过期,请重新申请")
159    }
160
161    /// 访客身份验证失败
162    pub fn visitor_authentication_failed(
163        visitor_id: impl Into<String>,
164        reason: impl Into<String>,
165    ) -> SecurityError {
166        let mut ctx = ErrorContext::new();
167        ctx.add_context("visitor_id", visitor_id.into());
168        ctx.add_context("auth_reason", reason.into());
169        ctx.add_context("operation", "visitor_authentication");
170
171        authentication_error("访客身份验证失败")
172    }
173
174    /// 合规检查失败
175    pub fn compliance_check_failed(
176        compliance_type: impl Into<String>,
177        reason: impl Into<String>,
178        resource_id: Option<impl Into<String>>,
179    ) -> SecurityError {
180        let compliance_type_str = compliance_type.into();
181        let reason_str = reason.into();
182        let mut ctx = ErrorContext::new();
183        ctx.add_context("compliance_type", compliance_type_str);
184        ctx.add_context("violation_reason", reason_str.clone());
185        if let Some(id) = resource_id {
186            ctx.add_context("resource_id", id.into());
187        }
188        ctx.add_context("operation", "compliance_check");
189
190        CoreError::Business {
191            message: format!("合规检查失败: {reason_str}"),
192            code: ErrorCode::BusinessError,
193            ctx: Box::new(ctx),
194        }
195    }
196
197    /// 审计日志写入失败
198    pub fn audit_log_failed(
199        log_type: impl Into<String>,
200        reason: impl Into<String>,
201    ) -> SecurityError {
202        let mut ctx = ErrorContext::new();
203        ctx.add_context("log_type", log_type.into());
204        ctx.add_context("failure_reason", reason.into());
205        ctx.add_context("operation", "audit_logging");
206
207        CoreError::Internal {
208            code: ErrorCode::InternalError,
209            message: "审计日志写入失败".to_string(),
210            source: None,
211            ctx: Box::new(ctx),
212        }
213    }
214
215    /// 配置错误
216    pub fn security_config_invalid(
217        config_key: impl Into<String>,
218        reason: impl Into<String>,
219    ) -> SecurityError {
220        let config_key_str = config_key.into();
221        let reason_str = reason.into();
222        let mut ctx = ErrorContext::new();
223        ctx.add_context("config_key", config_key_str.clone());
224        ctx.add_context("error_reason", reason_str.clone());
225        ctx.add_context("operation", "security_config");
226
227        configuration_error(format!("安全配置参数 {config_key_str} 无效: {reason_str}"))
228    }
229
230    /// 时间同步错误
231    pub fn time_sync_failed(service: impl Into<String>, deviation_ms: i64) -> SecurityError {
232        let mut ctx = ErrorContext::new();
233        ctx.add_context("sync_service", service.into());
234        ctx.add_context("time_deviation_ms", deviation_ms.to_string());
235        ctx.add_context("operation", "time_sync");
236
237        business_error("时间同步失败,安全验证需要精确的时间同步")
238    }
239
240    /// 加密操作失败
241    pub fn crypto_operation_failed(
242        operation: impl Into<String>,
243        algorithm: impl Into<String>,
244        reason: impl Into<String>,
245    ) -> SecurityError {
246        let mut ctx = ErrorContext::new();
247        ctx.add_context("crypto_operation", operation.into());
248        ctx.add_context("algorithm", algorithm.into());
249        ctx.add_context("failure_reason", reason.into());
250        ctx.add_context("operation", "cryptography");
251
252        CoreError::Internal {
253            code: ErrorCode::InternalError,
254            message: "加密操作失败".to_string(),
255            source: None,
256            ctx: Box::new(ctx),
257        }
258    }
259
260    /// 安全检查超时
261    pub fn security_check_timeout(
262        check_type: impl Into<String>,
263        timeout_duration: Duration,
264    ) -> SecurityError {
265        let mut ctx = ErrorContext::new();
266        ctx.add_context("check_type", check_type.into());
267        ctx.add_context(
268            "timeout_duration_ms",
269            timeout_duration.as_millis().to_string(),
270        );
271        ctx.add_context("operation", "security_check");
272
273        CoreError::Timeout {
274            duration: timeout_duration,
275            operation: Some(format!(
276                "security_check:{}",
277                ctx.get_context("check_type").unwrap_or_default()
278            )),
279            ctx: Box::new(ctx),
280        }
281    }
282
283    /// 安全API调用限流
284    pub fn security_api_rate_limited(
285        endpoint: impl Into<String>,
286        limit: u32,
287        window_seconds: u64,
288    ) -> SecurityError {
289        let mut ctx = ErrorContext::new();
290        ctx.add_context("api_endpoint", endpoint.into());
291        ctx.add_context("rate_limit", limit.to_string());
292        ctx.add_context("window_seconds", window_seconds.to_string());
293
294        rate_limit_error(limit, Duration::from_secs(window_seconds), None)
295    }
296}
297
298/// 飞书安全服务错误码智能映射
299pub fn map_feishu_security_error(
300    feishu_code: i32,
301    message: &str,
302    request_id: Option<&str>,
303) -> SecurityError {
304    let mut ctx = ErrorContext::new();
305    if let Some(req_id) = request_id {
306        ctx.set_request_id(req_id);
307    }
308    ctx.add_context("feishu_code", feishu_code.to_string());
309    ctx.add_context("service", "security");
310
311    // 优先使用飞书通用错误码映射
312    match ErrorCode::from_feishu_code(feishu_code) {
313        // 权限相关错误
314        Some(ErrorCode::PermissionMissing) => CoreError::Authentication {
315            message: format!("安全权限不足: {message}"),
316            code: ErrorCode::PermissionMissing,
317            ctx: Box::new(ctx),
318        },
319        // 令牌相关错误
320        Some(ErrorCode::AccessTokenExpiredV2) => {
321            token_expired_error(format!("安全访问令牌已过期: {message}"))
322        }
323        // 参数验证错误
324        Some(ErrorCode::ValidationError) => validation_error("security_parameter", message),
325        // 业务逻辑错误
326        Some(ErrorCode::BusinessError) => {
327            SecurityErrorBuilder::compliance_check_failed("business_rule", message, None::<String>)
328        }
329        // 其他映射
330        _ => {
331            // 回退到HTTP状态码或内部业务码
332            CoreError::Api(Box::new(ApiError {
333                status: feishu_code as u16,
334                endpoint: "security".into(),
335                message: message.to_string(),
336                source: None,
337                code: ErrorCode::from_feishu_code(feishu_code).unwrap_or(ErrorCode::InternalError),
338                ctx: Box::new(ctx),
339            }))
340        }
341    }
342}
343
344/// 安全错误扩展特征
345pub trait SecurityErrorExt {
346    /// 检查是否为设备相关错误
347    fn is_device_error(&self) -> bool;
348
349    /// 检查是否为权限相关错误
350    fn is_permission_error(&self) -> bool;
351
352    /// 检查是否为合规相关错误
353    fn is_compliance_error(&self) -> bool;
354
355    /// 检查是否为认证相关错误
356    fn is_authentication_error(&self) -> bool;
357
358    /// 获取安全操作类型
359    fn security_operation(&self) -> Option<&str>;
360
361    /// 获取受影响的资源ID
362    fn affected_resource_id(&self) -> Option<&str>;
363
364    /// 生成安全事件报告
365    fn to_security_event(&self) -> SecurityEvent;
366}
367
368impl SecurityErrorExt for SecurityError {
369    fn is_device_error(&self) -> bool {
370        self.context().get_context("device_id").is_some()
371    }
372
373    fn is_permission_error(&self) -> bool {
374        matches!(
375            self,
376            CoreError::Authentication {
377                code: ErrorCode::PermissionMissing,
378                ..
379            }
380        )
381    }
382
383    fn is_compliance_error(&self) -> bool {
384        self.context().get_context("compliance_type").is_some()
385    }
386
387    fn is_authentication_error(&self) -> bool {
388        matches!(self, CoreError::Authentication { .. })
389    }
390
391    fn security_operation(&self) -> Option<&str> {
392        match self.context().get_context("operation") {
393            Some(s) => Some(s),
394            None => None,
395        }
396    }
397
398    fn affected_resource_id(&self) -> Option<&str> {
399        match self
400            .context()
401            .get_context("device_id")
402            .or_else(|| self.context().get_context("visitor_id"))
403        {
404            Some(s) => Some(s),
405            None => None,
406        }
407    }
408
409    fn to_security_event(&self) -> SecurityEvent {
410        SecurityEvent {
411            event_id: uuid::Uuid::new_v4().to_string(),
412            timestamp: chrono::Utc::now(),
413            event_type: "security_error".to_string(),
414            severity: "medium".to_string(),
415            operation: self.security_operation().unwrap_or("unknown").to_string(),
416            resource_id: self.affected_resource_id().map(|s| s.to_string()),
417            error_code: ErrorCode::InternalError,
418            message: "安全错误".to_string(),
419            context: serde_json::json!({}),
420        }
421    }
422}
423
424/// 安全事件记录
425#[derive(Debug, Clone, Serialize)]
426pub struct SecurityEvent {
427    /// 事件唯一标识符
428    pub event_id: String,
429    /// 事件发生时间戳
430    pub timestamp: chrono::DateTime<chrono::Utc>,
431    /// 事件类型
432    pub event_type: String,
433    /// 事件严重程度
434    pub severity: String,
435    /// 执行的操作类型
436    pub operation: String,
437    /// 受影响的资源ID(可选)
438    pub resource_id: Option<String>,
439    /// 错误代码
440    pub error_code: ErrorCode,
441    /// 事件描述消息
442    pub message: String,
443    /// 事件上下文信息
444    pub context: serde_json::Value,
445}
446
447/// 安全错误分析器
448#[derive(Debug, Clone, Copy)]
449pub struct SecurityErrorAnalyzer;
450
451impl SecurityErrorAnalyzer {
452    /// 分析安全错误的潜在风险
453    pub fn analyze_security_risk(error: &SecurityError) -> SecurityRiskAssessment {
454        let risk_level = match error {
455            CoreError::Authentication { .. } if error.is_permission_error() => {
456                SecurityRiskLevel::High
457            }
458            CoreError::Business { .. } => SecurityRiskLevel::Critical,
459            CoreError::Internal { .. } => SecurityRiskLevel::High,
460            CoreError::Validation { .. } => SecurityRiskLevel::Medium,
461            _ => SecurityRiskLevel::Low,
462        };
463
464        let risk_type = if error.is_permission_error() {
465            SecurityRiskType::AccessControl
466        } else if error.is_compliance_error() {
467            SecurityRiskType::Compliance
468        } else if error.is_device_error() {
469            SecurityRiskType::DeviceSecurity
470        } else {
471            SecurityRiskType::General
472        };
473
474        SecurityRiskAssessment {
475            risk_level,
476            risk_type,
477            immediate_action: SecurityAction::LogAndMonitor,
478            escalation_required: matches!(
479                error,
480                CoreError::Business { .. } | CoreError::Internal { .. }
481            ),
482            compliance_impact: ComplianceImpact::Low,
483        }
484    }
485}
486
487/// 安全风险评估
488#[derive(Debug, Clone, Copy, Serialize)]
489pub struct SecurityRiskAssessment {
490    /// 风险级别
491    pub risk_level: SecurityRiskLevel,
492    /// 风险类型
493    pub risk_type: SecurityRiskType,
494    /// 建议的立即行动
495    pub immediate_action: SecurityAction,
496    /// 是否需要升级处理
497    pub escalation_required: bool,
498    /// 合规性影响
499    pub compliance_impact: ComplianceImpact,
500}
501
502/// 安全风险级别
503#[derive(Debug, Clone, Copy, Serialize)]
504pub enum SecurityRiskLevel {
505    /// 低风险
506    Low,
507    /// 中等风险
508    Medium,
509    /// 高风险
510    High,
511    /// 严重风险
512    Critical,
513}
514
515/// 安全风险类型
516#[derive(Debug, Clone, Copy, Serialize)]
517pub enum SecurityRiskType {
518    /// 访问控制风险
519    AccessControl,
520    /// 身份认证风险
521    Authentication,
522    /// 设备安全风险
523    DeviceSecurity,
524    /// 合规性风险
525    Compliance,
526    /// 一般安全风险
527    General,
528}
529
530/// 安全行动建议
531#[derive(Debug, Clone, Copy, Serialize)]
532pub enum SecurityAction {
533    /// 撤销访问权限
534    RevokeAccess,
535    /// 启动调查程序
536    InitiateInvestigation,
537    /// 激活备份系统
538    ActivateBackup,
539    /// 记录并监控
540    LogAndMonitor,
541    /// 阻止请求
542    BlockRequest,
543}
544
545/// 合规性影响级别
546#[derive(Debug, Clone, Copy, Serialize)]
547pub enum ComplianceImpact {
548    /// 低影响
549    Low,
550    /// 中等影响
551    Medium,
552    /// 高影响
553    High,
554}
555
556#[cfg(test)]
557mod tests {
558    use super::*;
559
560    #[test]
561    fn test_security_error_creation() {
562        let error = SecurityErrorBuilder::device_not_found("device_123");
563        assert!(error.is_validation_error());
564        assert!(error.is_device_error());
565    }
566
567    #[test]
568    fn test_permission_error() {
569        let error = SecurityErrorBuilder::access_denied("admin_panel", "insufficient_role");
570        assert!(error.is_permission_error());
571    }
572
573    #[test]
574    fn test_compliance_error() {
575        let error = SecurityErrorBuilder::compliance_check_failed(
576            "gdpr",
577            "data_retention_violation",
578            Some("data_set_456"),
579        );
580        assert!(error.is_compliance_error());
581    }
582
583    #[test]
584    fn test_security_event_generation() {
585        let error = SecurityErrorBuilder::device_not_found("device_123");
586        let event = error.to_security_event();
587        assert_eq!(event.message, "安全错误");
588    }
589
590    #[test]
591    fn test_feishu_error_mapping() {
592        let error = map_feishu_security_error(99991672, "权限不足", Some("req_123"));
593        assert!(error.is_permission_error());
594    }
595
596    #[test]
597    fn test_security_risk_assessment() {
598        let error = SecurityErrorBuilder::access_denied("secure_area", "no_clearance");
599        let assessment = SecurityErrorAnalyzer::analyze_security_risk(&error);
600        assert!(matches!(assessment.risk_level, SecurityRiskLevel::High));
601    }
602}