tmuntaner_webauthn/
lib.rs

1/*
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
5 */
6
7mod utils;
8
9pub trait WebauthnNotifier {
10    fn notify_start(&self) -> Result<()>;
11    fn notify_end(&self) -> Result<()>;
12}
13
14#[cfg(feature = "progress_bar")]
15mod progress_bar;
16
17#[cfg(feature = "progress_bar")]
18use crate::progress_bar::ProgressBarFallbackNotifier;
19
20#[cfg(feature = "notifications")]
21mod desktop_notifications;
22
23#[cfg(feature = "notifications")]
24use crate::desktop_notifications::DesktopNotificationsFallbackNotifier;
25
26#[cfg(target_os = "windows")]
27mod windows;
28
29#[cfg(any(target_os = "linux", target_os = "macos"))]
30mod mozilla;
31
32use anyhow::Result;
33use serde::{Deserialize, Serialize};
34
35/// <https://www.w3.org/TR/webauthn-2/#dictdef-collectedclientdata>
36#[derive(Debug, Serialize, Clone, Deserialize)]
37#[serde(rename_all = "camelCase")]
38struct CollectedClientData {
39    #[serde(rename = "type")]
40    sign_type: String,
41    challenge: String,
42    origin: String,
43    #[serde(skip_serializing_if = "Option::is_none")]
44    cross_origin: Option<bool>,
45    token_binding: Option<TokenBinding>,
46}
47
48/// <https://www.w3.org/TR/webauthn-2/#dom-collectedclientdata-tokenbinding>
49#[derive(Debug, Clone, Deserialize, Serialize)]
50struct TokenBinding {
51    status: String,
52    id: Option<String>,
53}
54
55pub struct SignatureResponse {
56    pub client_data: String,
57    pub signature_data: String,
58    pub authenticator_data: String,
59}
60
61#[derive(Default)]
62pub struct WebauthnClient {
63    notifiers: Vec<Box<dyn WebauthnNotifier>>,
64}
65
66impl WebauthnClient {
67    pub fn new() -> Self {
68        Self::default()
69    }
70
71    pub fn add_notifier(&mut self, notifier: Box<dyn WebauthnNotifier>) -> &mut WebauthnClient {
72        self.notifiers.push(notifier);
73
74        self
75    }
76
77    #[cfg(feature = "progress_bar")]
78    pub fn add_progress_bar_notifier(&mut self) -> &mut WebauthnClient {
79        let notifier = Box::new(ProgressBarFallbackNotifier::new());
80
81        self.add_notifier(notifier)
82    }
83
84    #[cfg(feature = "notifications")]
85    pub fn add_desktop_notification_notifier(&mut self) -> &mut WebauthnClient {
86        let notifier = Box::new(DesktopNotificationsFallbackNotifier::new());
87
88        self.add_notifier(notifier)
89    }
90
91    #[cfg(target_os = "windows")]
92    pub fn sign(
93        self,
94        challenge_str: String,
95        host: String,
96        credential_ids: Vec<String>,
97    ) -> Result<SignatureResponse> {
98        windows::sign(challenge_str, host, credential_ids)
99    }
100
101    #[cfg(any(target_os = "linux", target_os = "macos"))]
102    pub fn sign(
103        self,
104        challenge_str: String,
105        host: String,
106        credential_ids: Vec<String>,
107    ) -> Result<SignatureResponse> {
108        mozilla::sign(challenge_str, host, credential_ids, self.notifiers)
109    }
110}