robius_authentication/error.rs
1/// The result of an authentication operation.
2pub type Result<T> = std::result::Result<T, Error>;
3
4/// An error produced during authentication.
5#[derive(Debug, Clone)]
6pub enum Error {
7 // TODO: Reexport jni::errors::Error
8 // TODO: Remove target cfg
9 #[cfg(target_os = "android")]
10 Java(std::sync::Arc<jni::errors::Error>),
11
12 // Common errors
13 /// The user failed to provide valid credentials.
14 Authentication,
15 /// Authentication failed because there were too many failed attempts.
16 #[doc(alias = "lockout")]
17 Exhausted,
18 /// The requested authentication method was unavailable.
19 Unavailable,
20 /// The user canceled authentication.
21 UserCanceled,
22 /// The provided action ID is not in the policy's allowed list.
23 InvalidActionId,
24 /// The prompt text is invalid for this platform — e.g. an empty
25 /// [`Text::apple`] reason or an empty [`AndroidText::title`], which the
26 /// platform APIs reject.
27 ///
28 /// [`Text::apple`]: crate::Text::apple
29 /// [`AndroidText::title`]: crate::AndroidText::title
30 InvalidText,
31
32 // Apple-specific errors
33 /// The app canceled authentication.
34 ///
35 /// This error can occur on:
36 /// - [Apple]
37 ///
38 /// [Apple]: https://developer.apple.com/documentation/localauthentication/laerror/laerrorappcancel
39 AppCanceled,
40 /// The system canceled authentication.
41 ///
42 /// This error can occur on:
43 /// - [Apple]
44 ///
45 /// [Apple]: https://developer.apple.com/documentation/localauthentication/laerror/laerrorsystemcancel
46 SystemCanceled,
47 /// The device supports biometry only using a removable accessory, but the
48 /// paired accessory isn’t connected.
49 ///
50 /// This error can occur on:
51 /// - [Apple]
52 ///
53 /// [Apple]: https://developer.apple.com/documentation/localauthentication/laerror/laerrorbiometrydisconnected
54 BiometryDisconnected,
55 /// The device supports biometry only using a removable accessory, but no
56 /// accessory is paired.
57 ///
58 /// This error can occur on:
59 /// - [Apple]
60 ///
61 /// [Apple]: https://developer.apple.com/documentation/localauthentication/laerror/laerrorbiometrynotpaired
62 NotPaired,
63 /// The user has no enrolled biometric identities.
64 ///
65 /// This error can occur on:
66 /// - [Apple]
67 ///
68 /// [Apple]: https://developer.apple.com/documentation/localauthentication/laerror/laerrorbiometrynotenrolled
69 NotEnrolled,
70 /// Displaying the required authentication user interface is forbidden.
71 ///
72 /// This error can occur on:
73 /// - [Apple]
74 ///
75 /// [Apple]: https://developer.apple.com/documentation/localauthentication/laerror/laerrornotinteractive
76 NotInteractive,
77 /// An attempt to authenticate with an Apple companion device (e.g., Apple Watch) failed.
78 ///
79 /// This error can occur on:
80 /// - [Apple], formerly known as `WatchNotAvailable`
81 ///
82 /// [Apple]: https://developer.apple.com/documentation/localauthentication/laerror-swift.struct/companionnotavailable
83 #[doc(alias = "WatchNotAvailable")]
84 CompanionNotAvailable,
85 /// This error can occur on:
86 /// - [Apple]
87 ///
88 /// [Apple]: https://developer.apple.com/documentation/localauthentication/laerror/laerrorinvaliddimensions
89 InvalidDimensions,
90 /// A passcode isn’t set on the device.
91 ///
92 /// This error can occur on:
93 /// - [Apple]
94 ///
95 /// [Apple]: https://developer.apple.com/documentation/localauthentication/laerror/laerrorpasscodenotset
96 PasscodeNotSet,
97 /// The user tapped the fallback button in the authentication dialog (e.g., "Use Password" instead),
98 /// but you selected an authentication policy that does not support password fallback.
99 ///
100 /// If you get this error, you either must handle the fallback yourself or enable the `password` option
101 /// in the policy builder, which will instruct the system to enable a password fallback option
102 /// in the authentication dialog.
103 ///
104 /// This error can occur on:
105 /// - [Apple]
106 ///
107 /// [Apple]: https://developer.apple.com/documentation/localauthentication/laerror/userfallback
108 UserFallback,
109
110 // Android-specific errors
111 UpdateRequired,
112 Timeout,
113
114 // Windows-specific errors
115 /// The biometric verifier device is performing an operation and is
116 /// unavailable.
117 ///
118 /// This error can occur on:
119 /// - [Windows]
120 ///
121 /// [Windows]: https://learn.microsoft.com/en-us/uwp/api/windows.security.credentials.ui.userconsentverificationresult
122 Busy,
123 /// Group policy has disabled the biometric verifier device.
124 ///
125 /// This error can occur on:
126 /// - [Windows]
127 ///
128 /// [Windows]: https://learn.microsoft.com/en-us/uwp/api/windows.security.credentials.ui.userconsentverificationresult
129 DisabledByPolicy,
130 /// A biometric verifier device is not configured for this user.
131 ///
132 /// This error can occur on:
133 /// - [Windows]
134 ///
135 /// [Windows]: https://learn.microsoft.com/en-us/uwp/api/windows.security.credentials.ui.userconsentverificationresult
136 NotConfigured,
137
138 /// An unknown error occurred.
139 Unknown,
140}
141
142impl std::fmt::Display for Error {
143 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
144 let description = match self {
145 #[cfg(target_os = "android")]
146 Self::Java(e) => return write!(f, "Java error during authentication: {e}"),
147 Self::Authentication => "the user failed to provide valid credentials",
148 Self::Exhausted => "authentication failed due to too many failed attempts",
149 Self::Unavailable => "the requested authentication method was unavailable",
150 Self::UserCanceled => "the user canceled authentication",
151 Self::InvalidActionId => "the provided action ID is not in the policy's allowed list",
152 Self::InvalidText => "the provided prompt text is invalid for the current platform",
153 Self::AppCanceled => "the app canceled authentication",
154 Self::SystemCanceled => "the system canceled authentication",
155 Self::BiometryDisconnected => {
156 "the paired biometric accessory required for authentication is not connected"
157 }
158 Self::NotPaired => "no biometric accessory required for authentication is paired",
159 Self::NotEnrolled => "the user has no enrolled biometric identities",
160 Self::NotInteractive => "displaying the required authentication UI is forbidden",
161 Self::CompanionNotAvailable => {
162 "authentication with a companion device (e.g., Apple Watch) failed"
163 }
164 Self::InvalidDimensions => "the authentication input has invalid dimensions",
165 Self::PasscodeNotSet => "no passcode is set on the device",
166 Self::UserFallback => {
167 "the user chose the fallback authentication method, \
168 but the policy does not support fallback"
169 }
170 Self::UpdateRequired => "a security update is required before authenticating",
171 Self::Timeout => "authentication timed out",
172 Self::Busy => "the biometric verifier device is busy",
173 Self::DisabledByPolicy => "group policy has disabled the biometric verifier device",
174 Self::NotConfigured => "no biometric verifier device is configured for this user",
175 Self::Unknown => "an unknown authentication error occurred",
176 };
177 f.write_str(description)
178 }
179}
180
181impl std::error::Error for Error {
182 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
183 #[cfg(target_os = "android")]
184 if let Self::Java(e) = self {
185 return Some(&**e);
186 }
187 None
188 }
189}
190
191#[cfg(target_os = "android")]
192impl From<jni::errors::Error> for Error {
193 fn from(value: jni::errors::Error) -> Self {
194 Self::Java(std::sync::Arc::new(value))
195 }
196}