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