Skip to main content

webgates_core/permissions/
errors.rs

1//! Permission-related error values.
2//!
3//! These errors describe problems in the permission system itself, not ordinary
4//! authorization denials. In practice, the main case is a duplicate or hash
5//! collision discovered during permission validation.
6//!
7//! # Example
8//!
9//! ```rust
10//! use webgates_core::errors_core::{ErrorSeverity, UserFriendlyError};
11//! use webgates_core::permissions::errors::PermissionsError;
12//!
13//! let err = PermissionsError::collision(42, vec!["read:alpha".into(), "read:beta".into()]);
14//! assert!(err.support_code().starts_with("PERM-COLLISION-"));
15//! assert_eq!(err.severity(), ErrorSeverity::Critical);
16//! ```
17
18use crate::errors_core::{ErrorSeverity, UserFriendlyError};
19use thiserror::Error;
20
21/// Permission-domain errors.
22///
23/// Use these errors when the permission system detects an unsafe or invalid
24/// condition, such as a collision between permission names.
25#[derive(Debug, Error)]
26#[non_exhaustive]
27pub enum PermissionsError {
28    /// Permission collision detected when multiple permissions hash to the same value.
29    #[error("Permission collision: {collision_count} permissions map to hash {hash_id}")]
30    Collision {
31        /// Number of permissions that collide.
32        collision_count: usize,
33        /// The 64-bit hash ID that has collisions.
34        hash_id: u64,
35        /// List of permission names that collide.
36        permissions: Vec<String>,
37    },
38}
39
40impl PermissionsError {
41    /// Creates a permission collision error from the colliding permission names.
42    ///
43    /// The constructor derives `collision_count` from the provided list.
44    pub fn collision(hash_id: u64, permissions: Vec<String>) -> Self {
45        PermissionsError::Collision {
46            collision_count: permissions.len(),
47            hash_id,
48            permissions,
49        }
50    }
51
52    /// Generate a deterministic support code based on error content.
53    fn support_code_inner(&self) -> String {
54        match self {
55            PermissionsError::Collision { hash_id, .. } => {
56                format!("PERM-COLLISION-{}", hash_id)
57            }
58        }
59    }
60}
61
62impl UserFriendlyError for PermissionsError {
63    fn user_message(&self) -> String {
64        match self {
65            PermissionsError::Collision { .. } => {
66                "There's a technical issue with your account permissions. Our support team has been notified and will resolve this shortly. Please contact support if you need immediate assistance.".to_string()
67            }
68        }
69    }
70
71    fn developer_message(&self) -> String {
72        match self {
73            PermissionsError::Collision {
74                collision_count,
75                hash_id,
76                permissions,
77            } => {
78                format!(
79                    "Permission collision detected: {} permissions [{}] map to hash ID {}. This indicates a critical hash collision in the permission system requiring immediate administrator attention.",
80                    collision_count,
81                    permissions.join(", "),
82                    hash_id
83                )
84            }
85        }
86    }
87
88    fn support_code(&self) -> String {
89        self.support_code_inner()
90    }
91
92    fn severity(&self) -> ErrorSeverity {
93        match self {
94            PermissionsError::Collision { .. } => ErrorSeverity::Critical,
95        }
96    }
97
98    fn suggested_actions(&self) -> Vec<String> {
99        match self {
100            PermissionsError::Collision { .. } => vec![
101                "Contact our support team immediately with the reference code below".to_string(),
102                "Do not attempt to retry this operation".to_string(),
103                "This is a critical system issue requiring immediate administrator attention"
104                    .to_string(),
105            ],
106        }
107    }
108
109    fn is_retryable(&self) -> bool {
110        match self {
111            PermissionsError::Collision { .. } => false, // Critical system-level issue
112        }
113    }
114}