-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #33 from 1Password/refactor-extension-types
Refactor extension types (PRF#1)
- Loading branch information
Showing
10 changed files
with
258 additions
and
71 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
//! WebAuthn extensions as defined in [WebAuthn Defined Extensions][webauthn] | ||
//! and [CTAP2 Defined Extensions][ctap2]. | ||
//! | ||
//! The currently supported extensions are: | ||
//! * [`Credential Properties`][credprops] | ||
//! | ||
//! [ctap2]: https://fidoalliance.org/specs/fido-v2.1-ps-20210615/fido-client-to-authenticator-protocol-v2.1-ps-errata-20220621.html#sctn-defined-extensions | ||
//! [webauthn]: https://w3c.github.io/webauthn/#sctn-defined-extensions | ||
//! [credprops]: https://w3c.github.io/webauthn/#sctn-authenticator-credential-properties-extension | ||
|
||
use passkey_authenticator::{ | ||
CredentialStore, DiscoverabilitySupport, StoreInfo, UserValidationMethod, | ||
}; | ||
use passkey_types::{ | ||
ctap2::{get_assertion, make_credential}, | ||
webauthn::{ | ||
AuthenticationExtensionsClientInputs, AuthenticationExtensionsClientOutputs, | ||
CredentialPropertiesOutput, | ||
}, | ||
Passkey, | ||
}; | ||
|
||
use crate::Client; | ||
|
||
impl<S, U, P> Client<S, U, P> | ||
where | ||
S: CredentialStore + Sync, | ||
U: UserValidationMethod + Sync, | ||
P: public_suffix::EffectiveTLDProvider + Sync + 'static, | ||
Passkey: TryFrom<<S as CredentialStore>::PasskeyItem>, | ||
{ | ||
/// Create the extension inputs to be passed to an authenticator over CTAP2 | ||
/// during a registration request. | ||
pub(super) fn registration_extension_ctap2_input( | ||
&self, | ||
request: Option<&AuthenticationExtensionsClientInputs>, | ||
) -> Option<make_credential::ExtensionInputs> { | ||
request.map(|_| make_credential::ExtensionInputs {}) | ||
} | ||
|
||
/// Build the extension outputs for the WebAuthn client in a registration request. | ||
pub(super) fn registration_extension_outputs( | ||
&self, | ||
request: Option<&AuthenticationExtensionsClientInputs>, | ||
store_info: StoreInfo, | ||
rk: bool, | ||
) -> AuthenticationExtensionsClientOutputs { | ||
let cred_props_requested = request.and_then(|ext| ext.cred_props) == Some(true); | ||
let cred_props = if cred_props_requested { | ||
let discoverable = match store_info.discoverability { | ||
DiscoverabilitySupport::Full => rk, | ||
DiscoverabilitySupport::OnlyNonDiscoverable => false, | ||
DiscoverabilitySupport::ForcedDiscoverable => true, | ||
}; | ||
|
||
Some(CredentialPropertiesOutput { | ||
discoverable: Some(discoverable), | ||
authenticator_display_name: self.authenticator.display_name().cloned(), | ||
}) | ||
} else { | ||
None | ||
}; | ||
|
||
AuthenticationExtensionsClientOutputs { | ||
cred_props, | ||
prf: None, | ||
} | ||
} | ||
|
||
/// Create the extension inputs to be passed to an authenticator over CTAP2 | ||
/// during an authentication request. | ||
pub(super) fn auth_extension_ctap2_input( | ||
&self, | ||
request: Option<&AuthenticationExtensionsClientInputs>, | ||
) -> Option<get_assertion::ExtensionInputs> { | ||
request.map(|_| get_assertion::ExtensionInputs {}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
use serde::{Deserialize, Serialize}; | ||
use typeshare::typeshare; | ||
|
||
mod credential_properties; | ||
mod pseudo_random_function; | ||
|
||
pub use credential_properties::*; | ||
pub use pseudo_random_function::*; | ||
|
||
/// This is a dictionary containing the client extension input values for zero or more | ||
/// [WebAuthn Extensions]. There are currently none supported. | ||
/// | ||
/// <https://w3c.github.io/webauthn/#dictdef-authenticationextensionsclientinputs> | ||
/// | ||
/// [WebAuthn Extensions]: https://w3c.github.io/webauthn/#webauthn-extensions | ||
#[derive(Debug, Default, Deserialize, Serialize)] | ||
#[serde(rename_all = "camelCase")] | ||
#[typeshare] | ||
pub struct AuthenticationExtensionsClientInputs { | ||
/// Boolean to indicate that this extension is requested by the relying party. | ||
/// | ||
/// See [`CredentialPropertiesOutput`] for more information. | ||
#[serde(default, skip_serializing_if = "Option::is_none")] | ||
pub cred_props: Option<bool>, | ||
|
||
/// Inputs for the pseudo-random function extensions. | ||
/// | ||
/// See [`AuthenticationExtensionsPrfInputs`] for more information. | ||
#[serde(default, skip_serializing_if = "Option::is_none")] | ||
pub prf: Option<AuthenticationExtensionsPrfInputs>, | ||
} | ||
|
||
impl AuthenticationExtensionsClientInputs { | ||
/// Validates that there is at least one extension field that is `Some` | ||
/// and that they are in turn not empty. If all fields are `None` | ||
/// then this returns `None` as well. | ||
pub fn zip_contents(self) -> Option<Self> { | ||
let Self { cred_props, prf } = &self; | ||
|
||
let has_cred_props = cred_props.is_some(); | ||
let has_prf = prf.is_some(); | ||
|
||
(has_cred_props || has_prf).then_some(self) | ||
} | ||
} | ||
|
||
/// This is a dictionary containing the client extension output values for zero or more | ||
/// [WebAuthn Extensions]. | ||
/// | ||
/// <https://w3c.github.io/webauthn/#dictdef-authenticationextensionsclientoutputs> | ||
/// | ||
/// [WebAuthn Extensions]: https://w3c.github.io/webauthn/#webauthn-extensions | ||
#[derive(Debug, Default, Deserialize, Serialize)] | ||
#[serde(rename_all = "camelCase")] | ||
#[typeshare] | ||
pub struct AuthenticationExtensionsClientOutputs { | ||
/// Contains properties of the given [`PublicKeyCredential`] when it is included. | ||
/// | ||
/// See [`CredentialPropertiesOutput`] for more information | ||
#[serde(default, skip_serializing_if = "Option::is_none")] | ||
pub cred_props: Option<CredentialPropertiesOutput>, | ||
|
||
/// Contains the results of evaluating the PRF. | ||
/// | ||
/// See [`AuthenticationExtensionsPrfOutputs`] for more information. | ||
#[serde(default, skip_serializing_if = "Option::is_none")] | ||
pub prf: Option<AuthenticationExtensionsPrfOutputs>, | ||
} |
Oops, something went wrong.