diff --git a/crates/credential-management-proto/.gitignore b/crates/credential-management-proto/.gitignore new file mode 100644 index 0000000..4fffb2f --- /dev/null +++ b/crates/credential-management-proto/.gitignore @@ -0,0 +1,2 @@ +/target +/Cargo.lock diff --git a/crates/credential-management-proto/Cargo.toml b/crates/credential-management-proto/Cargo.toml new file mode 100644 index 0000000..54a9e7e --- /dev/null +++ b/crates/credential-management-proto/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "credential-management-proto" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/crates/credential-management-proto/src/credential.rs b/crates/credential-management-proto/src/credential.rs new file mode 100644 index 0000000..09fc136 --- /dev/null +++ b/crates/credential-management-proto/src/credential.rs @@ -0,0 +1,83 @@ +use std::rc::Rc; + +use crate::discovery; + +#[derive(Clone)] +pub enum Type { + Federated, + Identity, + Otp, + Password, + PublicKey, + Other(Rc), +} + +impl AsRef for Type { + fn as_ref(&self) -> &str { + match self { + Type::Federated => "federated", + Type::Identity => "identity", + Type::Otp => "otp", + Type::Password => "password", + Type::PublicKey => "public-key", + Type::Other(s) => s, + } + } +} + +/// > +pub trait Credential: Sized { + /// > The credential’s identifier. The requirements for the identifier are + /// > distinct for each type of credential. It might represent a username + /// > for username/password tuples, for example. + // TODO: The specs declare this as a "USVString" (presumably + // "Unicode-Scalar-Value String"), which is subtly different from a typical + // Rust str/String (which I believe allows for non-scalar unicode + // sequences). + fn id(&self) -> &str; + + /// > ...specifies the credential type represented by this object. + /// + /// Conforming types must be able to provide a String representation of + /// their name to use as an identifier for the credential type. + fn credential_type() -> Type; + + /// Origin-bound credentials can return the origin for which they are + /// effective, otherwise returns `None`. + // TODO: There's probably some structure to origins that can be encapsulated + // in the return type here + fn origin(&self) -> Option<&str>; +} + +/// > Developers retrieve [`Credential`]s and interact with the user agent’s +/// > credential store via methods exposed on the [`Container`] interface, which +/// > hangs off the Navigator object as `navigator.credentials`. +/// > +/// > +/// +/// [`Container`]s are bound to a particular origin. Calls to associated +/// functions have an implicit restriction to be scoped to the particular origin +/// associated with the [`Container`]. +pub trait Container { + type Credential: Credential; + type RequestOptions; + type CreateOptions; + + const DISCOVERY_MODE: discovery::Mode; + + async fn get(&self, options: Option<&Self::RequestOptions>) -> Option; + async fn store(&mut self, credential: Self::Credential) + -> Result; + async fn create(&mut self, options: Option<&Self::CreateOptions>) -> Option; + async fn prevent_silent_access(&mut self); + async fn discover_from_external_source( + origin: &str, + options: &Self::RequestOptions, + same_origin_with_ancestors: bool, + ) -> Result, discovery::Error>; +} + +// TODO: More types of errors here +pub enum StoreError { + NotAllowed, +} diff --git a/crates/credential-management-proto/src/discovery.rs b/crates/credential-management-proto/src/discovery.rs new file mode 100644 index 0000000..8a58af5 --- /dev/null +++ b/crates/credential-management-proto/src/discovery.rs @@ -0,0 +1,8 @@ +#[derive(Clone, Copy)] +pub enum Mode { + CredentialStore, + Remote, +} + +// TODO: Error types are not obviously specified in spec +pub enum Error {} diff --git a/crates/credential-management-proto/src/lib.rs b/crates/credential-management-proto/src/lib.rs new file mode 100644 index 0000000..2c8db97 --- /dev/null +++ b/crates/credential-management-proto/src/lib.rs @@ -0,0 +1,6 @@ +#![feature(associated_const_equality, async_fn_in_trait)] +#![allow(clippy::missing_errors_doc, incomplete_features)] + +pub mod credential; +pub mod discovery; +pub mod mediation; diff --git a/crates/credential-management-proto/src/mediation.rs b/crates/credential-management-proto/src/mediation.rs new file mode 100644 index 0000000..91c6536 --- /dev/null +++ b/crates/credential-management-proto/src/mediation.rs @@ -0,0 +1,36 @@ +use crate::credential::Credential; + +#[derive(Clone, Copy)] +// TODO: Add actual link for `get` +/// > When making a request via `get(options)`, developers can set a +/// > case-by-case requirement for user mediation by choosing the +/// > appropriate [`Requirement`] enum value. +/// > +/// > +pub enum Requirement { + /// > User mediation is suppressed for the given operation. If the + /// > operation can be performed without user involvement, wonderful. If + /// > user involvement is necessary, then the operation will return null + /// > rather than involving the user. + Silent, + /// > If credentials can be handed over for a given operation without + /// > user mediation, they will be. If user mediation is required, then + /// > the user agent will involve the user in the decision. + Optional, + /// > Discovered credentials are presented to the user in a non-modal + /// > dialog along with an indication of the origin which is requesting + /// > credentials. + Conditional, + /// > The user agent will not hand over credentials without user + /// > mediation, even if the prevent silent access flag is unset for an + /// > origin. + Required, +} + +/// Conformance to this trait indicates the Credential "...supports the +/// conditional approach to mediation of credential requests for the +/// credential type". This eliminates the need for the +/// `isConditionalMediationAvailable` function specified in the specs. +/// +/// +pub trait Conditional: Credential {}