Skip to main content

openlark_security/
error.rs

1//! 安全服务错误处理模块
2//!
3//! 完全基于 CoreError 的现代化错误处理系统
4//! 直接集成统一错误体系,提供类型安全和可观测性
5
6use openlark_core::error::{
7    authentication_error, business_error, configuration_error, network_error_with_details,
8    permission_missing_error, rate_limit_error, token_expired_error, validation_error, CoreError,
9    ErrorCode, ErrorContext, ErrorTrait,
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!(
228            "安全配置参数 {} 无效: {}",
229            config_key_str, reason_str
230        ))
231    }
232
233    /// 时间同步错误
234    pub fn time_sync_failed(service: impl Into<String>, deviation_ms: i64) -> SecurityError {
235        let mut ctx = ErrorContext::new();
236        ctx.add_context("sync_service", service.into());
237        ctx.add_context("time_deviation_ms", deviation_ms.to_string());
238        ctx.add_context("operation", "time_sync");
239
240        business_error("时间同步失败,安全验证需要精确的时间同步")
241    }
242
243    /// 加密操作失败
244    pub fn crypto_operation_failed(
245        operation: impl Into<String>,
246        algorithm: impl Into<String>,
247        reason: impl Into<String>,
248    ) -> SecurityError {
249        let mut ctx = ErrorContext::new();
250        ctx.add_context("crypto_operation", operation.into());
251        ctx.add_context("algorithm", algorithm.into());
252        ctx.add_context("failure_reason", reason.into());
253        ctx.add_context("operation", "cryptography");
254
255        CoreError::Internal {
256            code: ErrorCode::InternalError,
257            message: "加密操作失败".to_string(),
258            source: None,
259            ctx: Box::new(ctx),
260        }
261    }
262
263    /// 安全检查超时
264    pub fn security_check_timeout(
265        check_type: impl Into<String>,
266        timeout_duration: Duration,
267    ) -> SecurityError {
268        let mut ctx = ErrorContext::new();
269        ctx.add_context("check_type", check_type.into());
270        ctx.add_context(
271            "timeout_duration_ms",
272            timeout_duration.as_millis().to_string(),
273        );
274        ctx.add_context("operation", "security_check");
275
276        CoreError::Timeout {
277            duration: timeout_duration,
278            operation: Some(format!(
279                "security_check:{}",
280                ctx.get_context("check_type").unwrap_or_default()
281            )),
282            ctx: Box::new(ctx),
283        }
284    }
285
286    /// 安全API调用限流
287    pub fn security_api_rate_limited(
288        endpoint: impl Into<String>,
289        limit: u32,
290        window_seconds: u64,
291    ) -> SecurityError {
292        let mut ctx = ErrorContext::new();
293        ctx.add_context("api_endpoint", endpoint.into());
294        ctx.add_context("rate_limit", limit.to_string());
295        ctx.add_context("window_seconds", window_seconds.to_string());
296
297        rate_limit_error(limit, Duration::from_secs(window_seconds), None)
298    }
299}
300
301/// 飞书安全服务错误码智能映射
302pub fn map_feishu_security_error(
303    feishu_code: i32,
304    message: &str,
305    request_id: Option<&str>,
306) -> SecurityError {
307    let mut ctx = ErrorContext::new();
308    if let Some(req_id) = request_id {
309        ctx.set_request_id(req_id);
310    }
311    ctx.add_context("feishu_code", feishu_code.to_string());
312    ctx.add_context("service", "security");
313
314    // 优先使用飞书通用错误码映射
315    match ErrorCode::from_feishu_code(feishu_code) {
316        // 权限相关错误
317        Some(ErrorCode::PermissionMissing) => CoreError::Authentication {
318            message: format!("安全权限不足: {}", message),
319            code: ErrorCode::PermissionMissing,
320            ctx: Box::new(ctx),
321        },
322        // 令牌相关错误
323        Some(ErrorCode::AccessTokenExpiredV2) => {
324            token_expired_error(format!("安全访问令牌已过期: {}", message))
325        }
326        // 参数验证错误
327        Some(ErrorCode::ValidationError) => validation_error("security_parameter", message),
328        // 业务逻辑错误
329        Some(ErrorCode::BusinessError) => {
330            SecurityErrorBuilder::compliance_check_failed("business_rule", message, None::<String>)
331        }
332        // 其他映射
333        _ => {
334            // 回退到HTTP状态码或内部业务码
335            CoreError::Api(Box::new(ApiError {
336                status: feishu_code as u16,
337                endpoint: "security".into(),
338                message: message.to_string(),
339                source: None,
340                code: ErrorCode::from_feishu_code(feishu_code).unwrap_or(ErrorCode::InternalError),
341                ctx: Box::new(ctx),
342            }))
343        }
344    }
345}
346
347/// 安全错误扩展特征
348pub trait SecurityErrorExt {
349    /// 检查是否为设备相关错误
350    fn is_device_error(&self) -> bool;
351
352    /// 检查是否为权限相关错误
353    fn is_permission_error(&self) -> bool;
354
355    /// 检查是否为合规相关错误
356    fn is_compliance_error(&self) -> bool;
357
358    /// 检查是否为认证相关错误
359    fn is_authentication_error(&self) -> bool;
360
361    /// 获取安全操作类型
362    fn security_operation(&self) -> Option<&str>;
363
364    /// 获取受影响的资源ID
365    fn affected_resource_id(&self) -> Option<&str>;
366
367    /// 生成安全事件报告
368    fn to_security_event(&self) -> SecurityEvent;
369}
370
371impl SecurityErrorExt for SecurityError {
372    fn is_device_error(&self) -> bool {
373        self.context().get_context("device_id").is_some()
374    }
375
376    fn is_permission_error(&self) -> bool {
377        matches!(
378            self,
379            CoreError::Authentication {
380                code: ErrorCode::PermissionMissing,
381                ..
382            }
383        )
384    }
385
386    fn is_compliance_error(&self) -> bool {
387        self.context().get_context("compliance_type").is_some()
388    }
389
390    fn is_authentication_error(&self) -> bool {
391        matches!(self, CoreError::Authentication { .. })
392    }
393
394    fn security_operation(&self) -> Option<&str> {
395        match self.context().get_context("operation") {
396            Some(s) => Some(s),
397            None => None,
398        }
399    }
400
401    fn affected_resource_id(&self) -> Option<&str> {
402        match self
403            .context()
404            .get_context("device_id")
405            .or_else(|| self.context().get_context("visitor_id"))
406        {
407            Some(s) => Some(s),
408            None => None,
409        }
410    }
411
412    fn to_security_event(&self) -> SecurityEvent {
413        SecurityEvent {
414            event_id: uuid::Uuid::new_v4().to_string(),
415            timestamp: chrono::Utc::now(),
416            event_type: "security_error".to_string(),
417            severity: "medium".to_string(),
418            operation: self.security_operation().unwrap_or("unknown").to_string(),
419            resource_id: self.affected_resource_id().map(|s| s.to_string()),
420            error_code: ErrorCode::InternalError,
421            message: "安全错误".to_string(),
422            context: serde_json::json!({}),
423        }
424    }
425}
426
427/// 安全事件记录
428#[derive(Debug, Clone, Serialize)]
429pub struct SecurityEvent {
430    /// 事件唯一标识符
431    pub event_id: String,
432    /// 事件发生时间戳
433    pub timestamp: chrono::DateTime<chrono::Utc>,
434    /// 事件类型
435    pub event_type: String,
436    /// 事件严重程度
437    pub severity: String,
438    /// 执行的操作类型
439    pub operation: String,
440    /// 受影响的资源ID(可选)
441    pub resource_id: Option<String>,
442    /// 错误代码
443    pub error_code: ErrorCode,
444    /// 事件描述消息
445    pub message: String,
446    /// 事件上下文信息
447    pub context: serde_json::Value,
448}
449
450/// 安全错误分析器
451#[derive(Debug, Clone, Copy)]
452pub struct SecurityErrorAnalyzer;
453
454impl SecurityErrorAnalyzer {
455    /// 分析安全错误的潜在风险
456    pub fn analyze_security_risk(error: &SecurityError) -> SecurityRiskAssessment {
457        let risk_level = match error {
458            CoreError::Authentication { .. } if error.is_permission_error() => {
459                SecurityRiskLevel::High
460            }
461            CoreError::Business { .. } => SecurityRiskLevel::Critical,
462            CoreError::Internal { .. } => SecurityRiskLevel::High,
463            CoreError::Validation { .. } => SecurityRiskLevel::Medium,
464            _ => SecurityRiskLevel::Low,
465        };
466
467        let risk_type = if error.is_permission_error() {
468            SecurityRiskType::AccessControl
469        } else if error.is_compliance_error() {
470            SecurityRiskType::Compliance
471        } else if error.is_device_error() {
472            SecurityRiskType::DeviceSecurity
473        } else {
474            SecurityRiskType::General
475        };
476
477        SecurityRiskAssessment {
478            risk_level,
479            risk_type,
480            immediate_action: SecurityAction::LogAndMonitor,
481            escalation_required: matches!(
482                error,
483                CoreError::Business { .. } | CoreError::Internal { .. }
484            ),
485            compliance_impact: ComplianceImpact::Low,
486        }
487    }
488}
489
490/// 安全风险评估
491#[derive(Debug, Clone, Copy, Serialize)]
492pub struct SecurityRiskAssessment {
493    /// 风险级别
494    pub risk_level: SecurityRiskLevel,
495    /// 风险类型
496    pub risk_type: SecurityRiskType,
497    /// 建议的立即行动
498    pub immediate_action: SecurityAction,
499    /// 是否需要升级处理
500    pub escalation_required: bool,
501    /// 合规性影响
502    pub compliance_impact: ComplianceImpact,
503}
504
505/// 安全风险级别
506#[derive(Debug, Clone, Copy, Serialize)]
507pub enum SecurityRiskLevel {
508    /// 低风险
509    Low,
510    /// 中等风险
511    Medium,
512    /// 高风险
513    High,
514    /// 严重风险
515    Critical,
516}
517
518/// 安全风险类型
519#[derive(Debug, Clone, Copy, Serialize)]
520pub enum SecurityRiskType {
521    /// 访问控制风险
522    AccessControl,
523    /// 身份认证风险
524    Authentication,
525    /// 设备安全风险
526    DeviceSecurity,
527    /// 合规性风险
528    Compliance,
529    /// 一般安全风险
530    General,
531}
532
533/// 安全行动建议
534#[derive(Debug, Clone, Copy, Serialize)]
535pub enum SecurityAction {
536    /// 撤销访问权限
537    RevokeAccess,
538    /// 启动调查程序
539    InitiateInvestigation,
540    /// 激活备份系统
541    ActivateBackup,
542    /// 记录并监控
543    LogAndMonitor,
544    /// 阻止请求
545    BlockRequest,
546}
547
548/// 合规性影响级别
549#[derive(Debug, Clone, Copy, Serialize)]
550pub enum ComplianceImpact {
551    /// 低影响
552    Low,
553    /// 中等影响
554    Medium,
555    /// 高影响
556    High,
557}
558
559#[cfg(test)]
560mod tests {
561    use super::*;
562
563    #[test]
564    fn test_security_error_creation() {
565        let error = SecurityErrorBuilder::device_not_found("device_123");
566        assert!(error.is_validation_error());
567        assert!(error.is_device_error());
568    }
569
570    #[test]
571    fn test_permission_error() {
572        let error = SecurityErrorBuilder::access_denied("admin_panel", "insufficient_role");
573        assert!(error.is_permission_error());
574    }
575
576    #[test]
577    fn test_compliance_error() {
578        let error = SecurityErrorBuilder::compliance_check_failed(
579            "gdpr",
580            "data_retention_violation",
581            Some("data_set_456"),
582        );
583        assert!(error.is_compliance_error());
584    }
585
586    #[test]
587    fn test_security_event_generation() {
588        let error = SecurityErrorBuilder::device_not_found("device_123");
589        let event = error.to_security_event();
590        assert_eq!(event.message, "安全错误");
591    }
592
593    #[test]
594    fn test_feishu_error_mapping() {
595        let error = map_feishu_security_error(99991672, "权限不足", Some("req_123"));
596        assert!(error.is_permission_error());
597    }
598
599    #[test]
600    fn test_security_risk_assessment() {
601        let error = SecurityErrorBuilder::access_denied("secure_area", "no_clearance");
602        let assessment = SecurityErrorAnalyzer::analyze_security_risk(&error);
603        assert!(matches!(assessment.risk_level, SecurityRiskLevel::High));
604    }
605}