зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1676679 - support virtual authenticator functions in webdriver r=webdriver-reviewers,jgraham,whimboo
Depends on D185198 Differential Revision: https://phabricator.services.mozilla.com/D162624
This commit is contained in:
Родитель
3aafc7b14f
Коммит
113ef375b0
|
@ -129,6 +129,52 @@ impl Default for PrintMargins {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub enum WebAuthnProtocol {
|
||||
#[serde(rename = "ctap1/u2f")]
|
||||
Ctap1U2f,
|
||||
#[serde(rename = "ctap2")]
|
||||
Ctap2,
|
||||
#[serde(rename = "ctap2_1")]
|
||||
Ctap2_1,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub enum AuthenticatorTransport {
|
||||
Usb,
|
||||
Nfc,
|
||||
Ble,
|
||||
SmartCard,
|
||||
Hybrid,
|
||||
Internal,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub struct AuthenticatorParameters {
|
||||
pub protocol: WebAuthnProtocol,
|
||||
pub transport: AuthenticatorTransport,
|
||||
pub has_resident_key: bool,
|
||||
pub has_user_verification: bool,
|
||||
pub is_user_consenting: bool,
|
||||
pub is_user_verified: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub struct CredentialParameters {
|
||||
pub credential_id: String,
|
||||
pub is_resident_credential: bool,
|
||||
pub rp_id: String,
|
||||
pub private_key: String,
|
||||
pub user_handle: String,
|
||||
pub sign_count: u64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub struct UserVerificationParameters {
|
||||
pub is_user_verified: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct ScreenshotOptions {
|
||||
pub id: Option<String>,
|
||||
|
@ -296,6 +342,20 @@ pub enum Command {
|
|||
TakeFullScreenshot(ScreenshotOptions),
|
||||
#[serde(rename = "WebDriver:TakeScreenshot")]
|
||||
TakeScreenshot(ScreenshotOptions),
|
||||
#[serde(rename = "WebAuthn:AddVirtualAuthenticator")]
|
||||
WebAuthnAddVirtualAuthenticator(AuthenticatorParameters),
|
||||
#[serde(rename = "WebAuthn:RemoveVirtualAuthenticator")]
|
||||
WebAuthnRemoveVirtualAuthenticator,
|
||||
#[serde(rename = "WebAuthn:AddCredential")]
|
||||
WebAuthnAddCredential(CredentialParameters),
|
||||
#[serde(rename = "WebAuthn:GetCredentials")]
|
||||
WebAuthnGetCredentials,
|
||||
#[serde(rename = "WebAuthn:RemoveCredential")]
|
||||
WebAuthnRemoveCredential,
|
||||
#[serde(rename = "WebAuthn:RemoveAllCredentials")]
|
||||
WebAuthnRemoveAllCredentials,
|
||||
#[serde(rename = "WebAuthn:SetUserVerified")]
|
||||
WebAuthnSetUserVerified(UserVerificationParameters),
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -184,6 +184,26 @@ impl<'a> BrowserCapabilities for FirefoxCapabilities<'a> {
|
|||
Ok(true)
|
||||
}
|
||||
|
||||
fn webauthn_virtual_authenticators(&mut self, _: &Capabilities) -> WebDriverResult<bool> {
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
fn webauthn_extension_uvm(&mut self, _: &Capabilities) -> WebDriverResult<bool> {
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
fn webauthn_extension_prf(&mut self, _: &Capabilities) -> WebDriverResult<bool> {
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
fn webauthn_extension_large_blob(&mut self, _: &Capabilities) -> WebDriverResult<bool> {
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
fn webauthn_extension_cred_blob(&mut self, _: &Capabilities) -> WebDriverResult<bool> {
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
fn validate_custom(&mut self, name: &str, value: &Value) -> WebDriverResult<()> {
|
||||
if !name.starts_with("moz:") {
|
||||
return Ok(());
|
||||
|
|
|
@ -17,11 +17,15 @@ use marionette_rs::common::{
|
|||
use marionette_rs::marionette::AppStatus;
|
||||
use marionette_rs::message::{Command, Message, MessageId, Request};
|
||||
use marionette_rs::webdriver::{
|
||||
Command as MarionetteWebDriverCommand, Keys as MarionetteKeys, Locator as MarionetteLocator,
|
||||
NewWindow as MarionetteNewWindow, PrintMargins as MarionettePrintMargins,
|
||||
PrintOrientation as MarionettePrintOrientation, PrintPage as MarionettePrintPage,
|
||||
PrintParameters as MarionettePrintParameters, ScreenshotOptions, Script as MarionetteScript,
|
||||
Selector as MarionetteSelector, Url as MarionetteUrl, WindowRect as MarionetteWindowRect,
|
||||
AuthenticatorParameters as MarionetteAuthenticatorParameters,
|
||||
AuthenticatorTransport as MarionetteAuthenticatorTransport,
|
||||
Command as MarionetteWebDriverCommand, CredentialParameters as MarionetteCredentialParameters,
|
||||
Keys as MarionetteKeys, Locator as MarionetteLocator, NewWindow as MarionetteNewWindow,
|
||||
PrintMargins as MarionettePrintMargins, PrintOrientation as MarionettePrintOrientation,
|
||||
PrintPage as MarionettePrintPage, PrintParameters as MarionettePrintParameters,
|
||||
ScreenshotOptions, Script as MarionetteScript, Selector as MarionetteSelector,
|
||||
Url as MarionetteUrl, UserVerificationParameters as MarionetteUserVerificationParameters,
|
||||
WebAuthnProtocol as MarionetteWebAuthnProtocol, WindowRect as MarionetteWindowRect,
|
||||
};
|
||||
use mozdevice::AndroidStorageInput;
|
||||
use serde::de::{self, Deserialize, Deserializer};
|
||||
|
@ -49,18 +53,21 @@ use webdriver::command::WebDriverCommand::{
|
|||
GetWindowRect, GoBack, GoForward, IsDisplayed, IsEnabled, IsSelected, MaximizeWindow,
|
||||
MinimizeWindow, NewSession, NewWindow, PerformActions, Print, Refresh, ReleaseActions,
|
||||
SendAlertText, SetTimeouts, SetWindowRect, Status, SwitchToFrame, SwitchToParentFrame,
|
||||
SwitchToWindow, TakeElementScreenshot, TakeScreenshot,
|
||||
SwitchToWindow, TakeElementScreenshot, TakeScreenshot, WebAuthnAddCredential,
|
||||
WebAuthnAddVirtualAuthenticator, WebAuthnGetCredentials, WebAuthnRemoveAllCredentials,
|
||||
WebAuthnRemoveCredential, WebAuthnRemoveVirtualAuthenticator, WebAuthnSetUserVerified,
|
||||
};
|
||||
use webdriver::command::{
|
||||
ActionsParameters, AddCookieParameters, GetNamedCookieParameters, GetParameters,
|
||||
JavascriptCommandParameters, LocatorParameters, NewSessionParameters, NewWindowParameters,
|
||||
PrintMargins, PrintOrientation, PrintPage, PrintParameters, SendKeysParameters,
|
||||
SwitchToFrameParameters, SwitchToWindowParameters, TimeoutsParameters, WindowRectParameters,
|
||||
ActionsParameters, AddCookieParameters, AuthenticatorParameters, AuthenticatorTransport,
|
||||
GetNamedCookieParameters, GetParameters, JavascriptCommandParameters, LocatorParameters,
|
||||
NewSessionParameters, NewWindowParameters, PrintMargins, PrintOrientation, PrintPage,
|
||||
PrintParameters, SendKeysParameters, SwitchToFrameParameters, SwitchToWindowParameters,
|
||||
TimeoutsParameters, UserVerificationParameters, WebAuthnProtocol, WindowRectParameters,
|
||||
};
|
||||
use webdriver::command::{WebDriverCommand, WebDriverMessage};
|
||||
use webdriver::common::{
|
||||
Cookie, Date, FrameId, LocatorStrategy, ShadowRoot, WebElement, ELEMENT_KEY, FRAME_KEY,
|
||||
SHADOW_KEY, WINDOW_KEY,
|
||||
Cookie, CredentialParameters, Date, FrameId, LocatorStrategy, ShadowRoot, WebElement,
|
||||
ELEMENT_KEY, FRAME_KEY, SHADOW_KEY, WINDOW_KEY,
|
||||
};
|
||||
use webdriver::error::{ErrorStatus, WebDriverError, WebDriverResult};
|
||||
use webdriver::response::{
|
||||
|
@ -447,7 +454,14 @@ impl MarionetteSession {
|
|||
| GetAlertText
|
||||
| TakeScreenshot
|
||||
| Print(_)
|
||||
| TakeElementScreenshot(_) => {
|
||||
| TakeElementScreenshot(_)
|
||||
| WebAuthnAddVirtualAuthenticator(_)
|
||||
| WebAuthnRemoveVirtualAuthenticator
|
||||
| WebAuthnAddCredential(_)
|
||||
| WebAuthnGetCredentials
|
||||
| WebAuthnRemoveCredential
|
||||
| WebAuthnRemoveAllCredentials
|
||||
| WebAuthnSetUserVerified(_) => {
|
||||
WebDriverResponse::Generic(resp.into_value_response(true)?)
|
||||
}
|
||||
GetTimeouts => {
|
||||
|
@ -949,6 +963,27 @@ fn try_convert_to_marionette_message(
|
|||
Print(ref x) => Some(Command::WebDriver(MarionetteWebDriverCommand::Print(
|
||||
x.to_marionette()?,
|
||||
))),
|
||||
WebAuthnAddVirtualAuthenticator(ref x) => Some(Command::WebDriver(
|
||||
MarionetteWebDriverCommand::WebAuthnAddVirtualAuthenticator(x.to_marionette()?),
|
||||
)),
|
||||
WebAuthnRemoveVirtualAuthenticator => Some(Command::WebDriver(
|
||||
MarionetteWebDriverCommand::WebAuthnRemoveVirtualAuthenticator,
|
||||
)),
|
||||
WebAuthnAddCredential(ref x) => Some(Command::WebDriver(
|
||||
MarionetteWebDriverCommand::WebAuthnAddCredential(x.to_marionette()?),
|
||||
)),
|
||||
WebAuthnGetCredentials => Some(Command::WebDriver(
|
||||
MarionetteWebDriverCommand::WebAuthnGetCredentials,
|
||||
)),
|
||||
WebAuthnRemoveCredential => Some(Command::WebDriver(
|
||||
MarionetteWebDriverCommand::WebAuthnRemoveCredential,
|
||||
)),
|
||||
WebAuthnRemoveAllCredentials => Some(Command::WebDriver(
|
||||
MarionetteWebDriverCommand::WebAuthnRemoveAllCredentials,
|
||||
)),
|
||||
WebAuthnSetUserVerified(ref x) => Some(Command::WebDriver(
|
||||
MarionetteWebDriverCommand::WebAuthnSetUserVerified(x.to_marionette()?),
|
||||
)),
|
||||
Refresh => Some(Command::WebDriver(MarionetteWebDriverCommand::Refresh)),
|
||||
ReleaseActions => Some(Command::WebDriver(
|
||||
MarionetteWebDriverCommand::ReleaseActions,
|
||||
|
@ -1467,6 +1502,63 @@ impl ToMarionette<MarionettePrintMargins> for PrintMargins {
|
|||
}
|
||||
}
|
||||
|
||||
impl ToMarionette<MarionetteAuthenticatorParameters> for AuthenticatorParameters {
|
||||
fn to_marionette(&self) -> WebDriverResult<MarionetteAuthenticatorParameters> {
|
||||
Ok(MarionetteAuthenticatorParameters {
|
||||
protocol: self.protocol.to_marionette()?,
|
||||
transport: self.transport.to_marionette()?,
|
||||
has_resident_key: self.has_resident_key,
|
||||
has_user_verification: self.has_user_verification,
|
||||
is_user_consenting: self.is_user_consenting,
|
||||
is_user_verified: self.is_user_verified,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ToMarionette<MarionetteAuthenticatorTransport> for AuthenticatorTransport {
|
||||
fn to_marionette(&self) -> WebDriverResult<MarionetteAuthenticatorTransport> {
|
||||
Ok(match self {
|
||||
AuthenticatorTransport::Usb => MarionetteAuthenticatorTransport::Usb,
|
||||
AuthenticatorTransport::Nfc => MarionetteAuthenticatorTransport::Nfc,
|
||||
AuthenticatorTransport::Ble => MarionetteAuthenticatorTransport::Ble,
|
||||
AuthenticatorTransport::SmartCard => MarionetteAuthenticatorTransport::SmartCard,
|
||||
AuthenticatorTransport::Hybrid => MarionetteAuthenticatorTransport::Hybrid,
|
||||
AuthenticatorTransport::Internal => MarionetteAuthenticatorTransport::Internal,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ToMarionette<MarionetteCredentialParameters> for CredentialParameters {
|
||||
fn to_marionette(&self) -> WebDriverResult<MarionetteCredentialParameters> {
|
||||
Ok(MarionetteCredentialParameters {
|
||||
credential_id: self.credential_id.clone(),
|
||||
is_resident_credential: self.is_resident_credential,
|
||||
rp_id: self.rp_id.clone(),
|
||||
private_key: self.private_key.clone(),
|
||||
user_handle: self.user_handle.clone(),
|
||||
sign_count: self.sign_count,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ToMarionette<MarionetteUserVerificationParameters> for UserVerificationParameters {
|
||||
fn to_marionette(&self) -> WebDriverResult<MarionetteUserVerificationParameters> {
|
||||
Ok(MarionetteUserVerificationParameters {
|
||||
is_user_verified: self.is_user_verified,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ToMarionette<MarionetteWebAuthnProtocol> for WebAuthnProtocol {
|
||||
fn to_marionette(&self) -> WebDriverResult<MarionetteWebAuthnProtocol> {
|
||||
Ok(match self {
|
||||
WebAuthnProtocol::Ctap1U2f => MarionetteWebAuthnProtocol::Ctap1U2f,
|
||||
WebAuthnProtocol::Ctap2 => MarionetteWebAuthnProtocol::Ctap2,
|
||||
WebAuthnProtocol::Ctap2_1 => MarionetteWebAuthnProtocol::Ctap2_1,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ToMarionette<Map<String, Value>> for ActionsParameters {
|
||||
fn to_marionette(&self) -> WebDriverResult<Map<String, Value>> {
|
||||
Ok(try_opt!(
|
||||
|
|
|
@ -48,10 +48,11 @@ from .protocol import (AccessibilityProtocolPart,
|
|||
|
||||
|
||||
def do_delayed_imports():
|
||||
global errors, marionette, Addons
|
||||
global errors, marionette, Addons, WebAuthn
|
||||
|
||||
from marionette_driver import marionette, errors
|
||||
from marionette_driver.addons import Addons
|
||||
from marionette_driver.webauthn import WebAuthn
|
||||
|
||||
|
||||
def _switch_to_window(marionette, handle):
|
||||
|
@ -590,28 +591,28 @@ class MarionetteGenerateTestReportProtocolPart(GenerateTestReportProtocolPart):
|
|||
|
||||
class MarionetteVirtualAuthenticatorProtocolPart(VirtualAuthenticatorProtocolPart):
|
||||
def setup(self):
|
||||
self.marionette = self.parent.marionette
|
||||
self.webauthn = WebAuthn(self.parent.marionette)
|
||||
|
||||
def add_virtual_authenticator(self, config):
|
||||
raise NotImplementedError("add_virtual_authenticator not yet implemented")
|
||||
return self.webauthn.add_virtual_authenticator(config)
|
||||
|
||||
def remove_virtual_authenticator(self, authenticator_id):
|
||||
raise NotImplementedError("remove_virtual_authenticator not yet implemented")
|
||||
self.webauthn.remove_virtual_authenticator(authenticator_id)
|
||||
|
||||
def add_credential(self, authenticator_id, credential):
|
||||
raise NotImplementedError("add_credential not yet implemented")
|
||||
self.webauthn.add_credential(authenticator_id, credential)
|
||||
|
||||
def get_credentials(self, authenticator_id):
|
||||
raise NotImplementedError("get_credentials not yet implemented")
|
||||
return self.webauthn.get_credentials(authenticator_id)
|
||||
|
||||
def remove_credential(self, authenticator_id, credential_id):
|
||||
raise NotImplementedError("remove_credential not yet implemented")
|
||||
self.webauthn.remove_credential(authenticator_id, credential_id)
|
||||
|
||||
def remove_all_credentials(self, authenticator_id):
|
||||
raise NotImplementedError("remove_all_credentials not yet implemented")
|
||||
self.webauthn.remove_all_credentials(authenticator_id)
|
||||
|
||||
def set_user_verified(self, authenticator_id, uv):
|
||||
raise NotImplementedError("set_user_verified not yet implemented")
|
||||
self.webauthn.set_user_verified(authenticator_id, uv)
|
||||
|
||||
|
||||
class MarionetteSetPermissionProtocolPart(SetPermissionProtocolPart):
|
||||
|
|
|
@ -53,6 +53,25 @@ pub trait BrowserCapabilities {
|
|||
/// Whether a WebSocket URL for the created session has to be returned
|
||||
fn web_socket_url(&mut self, _: &Capabilities) -> WebDriverResult<bool>;
|
||||
|
||||
/// Indicates whether the endpoint node supports all Virtual Authenticators commands.
|
||||
fn webauthn_virtual_authenticators(&mut self, _: &Capabilities) -> WebDriverResult<bool>;
|
||||
|
||||
/// Indicates whether the endpoint node WebAuthn WebDriver implementation supports the User
|
||||
/// Verification Method extension.
|
||||
fn webauthn_extension_uvm(&mut self, _: &Capabilities) -> WebDriverResult<bool>;
|
||||
|
||||
/// Indicates whether the endpoint node WebAuthn WebDriver implementation supports the prf
|
||||
/// extension.
|
||||
fn webauthn_extension_prf(&mut self, _: &Capabilities) -> WebDriverResult<bool>;
|
||||
|
||||
/// Indicates whether the endpoint node WebAuthn WebDriver implementation supports the
|
||||
/// largeBlob extension.
|
||||
fn webauthn_extension_large_blob(&mut self, _: &Capabilities) -> WebDriverResult<bool>;
|
||||
|
||||
/// Indicates whether the endpoint node WebAuthn WebDriver implementation supports the credBlob
|
||||
/// extension.
|
||||
fn webauthn_extension_cred_blob(&mut self, _: &Capabilities) -> WebDriverResult<bool>;
|
||||
|
||||
fn accept_proxy(
|
||||
&mut self,
|
||||
proxy_settings: &Map<String, Value>,
|
||||
|
@ -136,7 +155,12 @@ impl SpecNewSessionParameters {
|
|||
x @ "acceptInsecureCerts"
|
||||
| x @ "setWindowRect"
|
||||
| x @ "strictFileInteractability"
|
||||
| x @ "webSocketUrl" => {
|
||||
| x @ "webSocketUrl"
|
||||
| x @ "webauthn:virtualAuthenticators"
|
||||
| x @ "webauthn:extension:uvm"
|
||||
| x @ "webauthn:extension:prf"
|
||||
| x @ "webauthn:extension:largeBlob"
|
||||
| x @ "webauthn:extension:credBlob" => {
|
||||
if !value.is_boolean() {
|
||||
return Err(WebDriverError::new(
|
||||
ErrorStatus::InvalidArgument,
|
||||
|
@ -533,6 +557,51 @@ impl CapabilitiesMatching for SpecNewSessionParameters {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
"webauthn:virtualAuthenticators" => {
|
||||
if value.as_bool().unwrap_or(false)
|
||||
&& !browser_capabilities
|
||||
.webauthn_virtual_authenticators(merged)
|
||||
.unwrap_or(false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
"webauthn:extension:uvm" => {
|
||||
if value.as_bool().unwrap_or(false)
|
||||
&& !browser_capabilities
|
||||
.webauthn_extension_uvm(merged)
|
||||
.unwrap_or(false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
"webauthn:extension:prf" => {
|
||||
if value.as_bool().unwrap_or(false)
|
||||
&& !browser_capabilities
|
||||
.webauthn_extension_prf(merged)
|
||||
.unwrap_or(false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
"webauthn:extension:largeBlob" => {
|
||||
if value.as_bool().unwrap_or(false)
|
||||
&& !browser_capabilities
|
||||
.webauthn_extension_large_blob(merged)
|
||||
.unwrap_or(false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
"webauthn:extension:credBlob" => {
|
||||
if value.as_bool().unwrap_or(false)
|
||||
&& !browser_capabilities
|
||||
.webauthn_extension_cred_blob(merged)
|
||||
.unwrap_or(false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
name => {
|
||||
if name.contains(':') {
|
||||
if !browser_capabilities
|
||||
|
|
|
@ -7,7 +7,9 @@ use crate::capabilities::{
|
|||
BrowserCapabilities, Capabilities, CapabilitiesMatching, LegacyNewSessionParameters,
|
||||
SpecNewSessionParameters,
|
||||
};
|
||||
use crate::common::{Date, FrameId, LocatorStrategy, ShadowRoot, WebElement, MAX_SAFE_INTEGER};
|
||||
use crate::common::{
|
||||
CredentialParameters, Date, FrameId, LocatorStrategy, ShadowRoot, WebElement, MAX_SAFE_INTEGER,
|
||||
};
|
||||
use crate::error::{ErrorStatus, WebDriverError, WebDriverResult};
|
||||
use crate::httpapi::{Route, VoidWebDriverExtensionRoute, WebDriverExtensionRoute};
|
||||
use crate::Parameters;
|
||||
|
@ -79,6 +81,13 @@ pub enum WebDriverCommand<T: WebDriverExtensionCommand> {
|
|||
Print(PrintParameters),
|
||||
Status,
|
||||
Extension(T),
|
||||
WebAuthnAddVirtualAuthenticator(AuthenticatorParameters),
|
||||
WebAuthnRemoveVirtualAuthenticator,
|
||||
WebAuthnAddCredential(CredentialParameters),
|
||||
WebAuthnGetCredentials,
|
||||
WebAuthnRemoveCredential,
|
||||
WebAuthnRemoveAllCredentials,
|
||||
WebAuthnSetUserVerified(UserVerificationParameters),
|
||||
}
|
||||
|
||||
pub trait WebDriverExtensionCommand: Clone + Send {
|
||||
|
@ -401,6 +410,21 @@ impl<U: WebDriverExtensionRoute> WebDriverMessage<U> {
|
|||
Route::Print => WebDriverCommand::Print(serde_json::from_str(raw_body)?),
|
||||
Route::Status => WebDriverCommand::Status,
|
||||
Route::Extension(ref extension) => extension.command(params, &body_data)?,
|
||||
Route::WebAuthnAddVirtualAuthenticator => {
|
||||
WebDriverCommand::WebAuthnAddVirtualAuthenticator(serde_json::from_str(raw_body)?)
|
||||
}
|
||||
Route::WebAuthnRemoveVirtualAuthenticator => {
|
||||
WebDriverCommand::WebAuthnRemoveVirtualAuthenticator
|
||||
}
|
||||
Route::WebAuthnAddCredential => {
|
||||
WebDriverCommand::WebAuthnAddCredential(serde_json::from_str(raw_body)?)
|
||||
}
|
||||
Route::WebAuthnGetCredentials => WebDriverCommand::WebAuthnGetCredentials,
|
||||
Route::WebAuthnRemoveCredential => WebDriverCommand::WebAuthnRemoveCredential,
|
||||
Route::WebAuthnRemoveAllCredentials => WebDriverCommand::WebAuthnRemoveAllCredentials,
|
||||
Route::WebAuthnSetUserVerified => {
|
||||
WebDriverCommand::WebAuthnSetUserVerified(serde_json::from_str(raw_body)?)
|
||||
}
|
||||
};
|
||||
Ok(WebDriverMessage::new(session_id, command))
|
||||
}
|
||||
|
@ -630,6 +654,52 @@ impl Default for PrintMargins {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub enum WebAuthnProtocol {
|
||||
#[serde(rename = "ctap1/u2f")]
|
||||
Ctap1U2f,
|
||||
#[serde(rename = "ctap2")]
|
||||
Ctap2,
|
||||
#[serde(rename = "ctap2_1")]
|
||||
Ctap2_1,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub enum AuthenticatorTransport {
|
||||
Usb,
|
||||
Nfc,
|
||||
Ble,
|
||||
SmartCard,
|
||||
Hybrid,
|
||||
Internal,
|
||||
}
|
||||
|
||||
fn default_as_true() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AuthenticatorParameters {
|
||||
pub protocol: WebAuthnProtocol,
|
||||
pub transport: AuthenticatorTransport,
|
||||
#[serde(default)]
|
||||
pub has_resident_key: bool,
|
||||
#[serde(default)]
|
||||
pub has_user_verification: bool,
|
||||
#[serde(default = "default_as_true")]
|
||||
pub is_user_consenting: bool,
|
||||
#[serde(default)]
|
||||
pub is_user_verified: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub struct UserVerificationParameters {
|
||||
#[serde(rename = "isUserVerified")]
|
||||
pub is_user_verified: bool,
|
||||
}
|
||||
|
||||
fn deserialize_to_positive_f64<'de, D>(deserializer: D) -> Result<f64, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
|
@ -1310,6 +1380,47 @@ mod tests {
|
|||
assert!(serde_json::from_value::<PrintParameters>(json!({"scale": 3})).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_json_authenticator() {
|
||||
let params = AuthenticatorParameters {
|
||||
protocol: WebAuthnProtocol::Ctap1U2f,
|
||||
transport: AuthenticatorTransport::Usb,
|
||||
has_resident_key: false,
|
||||
has_user_verification: false,
|
||||
is_user_consenting: false,
|
||||
is_user_verified: false,
|
||||
};
|
||||
assert_de(
|
||||
¶ms,
|
||||
json!({"protocol": "ctap1/u2f", "transport": "usb", "hasResidentKey": false, "hasUserVerification": false, "isUserConsenting": false, "isUserVerified": false}),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_json_credential() {
|
||||
let encoded_string = base64::encode_config(b"hello internet~", base64::URL_SAFE);
|
||||
let params = CredentialParameters {
|
||||
credential_id: r"c3VwZXIgcmVhZGVy".to_string(),
|
||||
is_resident_credential: true,
|
||||
rp_id: "valid.rpid".to_string(),
|
||||
private_key: encoded_string.clone(),
|
||||
user_handle: encoded_string.clone(),
|
||||
sign_count: 0,
|
||||
};
|
||||
assert_de(
|
||||
¶ms,
|
||||
json!({"credentialId": r"c3VwZXIgcmVhZGVy", "isResidentCredential": true, "rpId": "valid.rpid", "privateKey": encoded_string, "userHandle": encoded_string, "signCount": 0}),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_json_user_verification() {
|
||||
let params = UserVerificationParameters {
|
||||
is_user_verified: false,
|
||||
};
|
||||
assert_de(¶ms, json!({"isUserVerified": false}));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_json_send_keys_parameters_with_value() {
|
||||
assert_de(
|
||||
|
|
|
@ -32,6 +32,23 @@ pub struct Cookie {
|
|||
pub same_site: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub struct CredentialParameters {
|
||||
#[serde(rename = "credentialId")]
|
||||
pub credential_id: String,
|
||||
#[serde(rename = "isResidentCredential")]
|
||||
pub is_resident_credential: bool,
|
||||
#[serde(rename = "rpId")]
|
||||
pub rp_id: String,
|
||||
#[serde(rename = "privateKey")]
|
||||
pub private_key: String,
|
||||
#[serde(rename = "userHandle")]
|
||||
#[serde(default)]
|
||||
pub user_handle: String,
|
||||
#[serde(rename = "signCount")]
|
||||
pub sign_count: u64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Date(pub u64);
|
||||
|
||||
|
|
|
@ -308,6 +308,41 @@ pub fn standard_routes<U: WebDriverExtensionRoute>() -> Vec<(Method, &'static st
|
|||
Route::ReleaseActions,
|
||||
),
|
||||
(Method::POST, "/session/{sessionId}/print", Route::Print),
|
||||
(
|
||||
Method::POST,
|
||||
"/sessions/{sessionId}/webauthn/authenticator",
|
||||
Route::WebAuthnAddVirtualAuthenticator,
|
||||
),
|
||||
(
|
||||
Method::DELETE,
|
||||
"/sessions/{sessionId}/webauthn/authenticator/{authenticatorId}",
|
||||
Route::WebAuthnRemoveVirtualAuthenticator,
|
||||
),
|
||||
(
|
||||
Method::POST,
|
||||
"/sessions/{sessionId}/webauthn/authenticator/{authenticatorId}/credential",
|
||||
Route::WebAuthnAddCredential,
|
||||
),
|
||||
(
|
||||
Method::GET,
|
||||
"/sessions/{sessionId}/webauthn/authenticator/{authenticatorId}/credentials",
|
||||
Route::WebAuthnGetCredentials,
|
||||
),
|
||||
(
|
||||
Method::DELETE,
|
||||
"/sessions/{sessionId}/webauthn/authenticator/{authenticatorId}/credentials/{credentialId}",
|
||||
Route::WebAuthnRemoveCredential,
|
||||
),
|
||||
(
|
||||
Method::DELETE,
|
||||
"/sessions/{sessionId}/webauthn/authenticator/{authenticatorId}/credentials",
|
||||
Route::WebAuthnRemoveAllCredentials,
|
||||
),
|
||||
(
|
||||
Method::POST,
|
||||
"/sessions/{sessionId}/webauthn/authenticator/{authenticatorId}/uv",
|
||||
Route::WebAuthnSetUserVerified,
|
||||
),
|
||||
(Method::GET, "/status", Route::Status),
|
||||
]
|
||||
}
|
||||
|
@ -381,6 +416,13 @@ pub enum Route<U: WebDriverExtensionRoute> {
|
|||
Print,
|
||||
Status,
|
||||
Extension(U),
|
||||
WebAuthnAddVirtualAuthenticator,
|
||||
WebAuthnRemoveVirtualAuthenticator,
|
||||
WebAuthnAddCredential,
|
||||
WebAuthnGetCredentials,
|
||||
WebAuthnRemoveCredential,
|
||||
WebAuthnRemoveAllCredentials,
|
||||
WebAuthnSetUserVerified,
|
||||
}
|
||||
|
||||
pub trait WebDriverExtensionRoute: Clone + Send + PartialEq {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use crate::common::Cookie;
|
||||
use crate::common::{Cookie, CredentialParameters};
|
||||
use serde::ser::{Serialize, Serializer};
|
||||
use serde_json::Value;
|
||||
|
||||
|
@ -16,6 +16,8 @@ pub enum WebDriverResponse {
|
|||
DeleteSession,
|
||||
ElementRect(ElementRectResponse),
|
||||
Generic(ValueResponse),
|
||||
WebAuthnAddVirtualAuthenticator(u64),
|
||||
WebAuthnGetCredentials(GetCredentialsResponse),
|
||||
NewSession(NewSessionResponse),
|
||||
Timeouts(TimeoutsResponse),
|
||||
Void,
|
||||
|
@ -78,6 +80,9 @@ pub struct ElementRectResponse {
|
|||
pub height: f64,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize)]
|
||||
pub struct GetCredentialsResponse(pub Vec<CredentialParameters>);
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize)]
|
||||
pub struct NewSessionResponse {
|
||||
#[serde(rename = "sessionId")]
|
||||
|
|
Загрузка…
Ссылка в новой задаче