File: //proc/676643/root/usr/local/CyberCP/lib/python3.10/site-packages/google/oauth2/webauthn_types.py
from dataclasses import dataclass
import json
from typing import Any, Dict, List, Optional
from google.auth import exceptions
@dataclass(frozen=True)
class PublicKeyCredentialDescriptor:
"""Descriptor for a security key based credential.
https://www.w3.org/TR/webauthn-3/#dictionary-credential-descriptor
Args:
id: <url-safe base64-encoded> credential id (key handle).
transports: <'usb'|'nfc'|'ble'|'internal'> List of supported transports.
"""
id: str
transports: Optional[List[str]] = None
def to_dict(self):
cred = {"type": "public-key", "id": self.id}
if self.transports:
cred["transports"] = self.transports
return cred
@dataclass
class AuthenticationExtensionsClientInputs:
"""Client extensions inputs for WebAuthn extensions.
Args:
appid: app id that can be asserted with in addition to rpid.
https://www.w3.org/TR/webauthn-3/#sctn-appid-extension
"""
appid: Optional[str] = None
def to_dict(self):
extensions = {}
if self.appid:
extensions["appid"] = self.appid
return extensions
@dataclass
class GetRequest:
"""WebAuthn get request
Args:
origin: Origin where the WebAuthn get assertion takes place.
rpid: Relying Party ID.
challenge: <url-safe base64-encoded> raw challenge.
timeout_ms: Timeout number in millisecond.
allow_credentials: List of allowed credentials.
user_verification: <'required'|'preferred'|'discouraged'> User verification requirement.
extensions: WebAuthn authentication extensions inputs.
"""
origin: str
rpid: str
challenge: str
timeout_ms: Optional[int] = None
allow_credentials: Optional[List[PublicKeyCredentialDescriptor]] = None
user_verification: Optional[str] = None
extensions: Optional[AuthenticationExtensionsClientInputs] = None
def to_json(self) -> str:
req_options: Dict[str, Any] = {"rpid": self.rpid, "challenge": self.challenge}
if self.timeout_ms:
req_options["timeout"] = self.timeout_ms
if self.allow_credentials:
req_options["allowCredentials"] = [
c.to_dict() for c in self.allow_credentials
]
if self.user_verification:
req_options["userVerification"] = self.user_verification
if self.extensions:
req_options["extensions"] = self.extensions.to_dict()
return json.dumps(
{"type": "get", "origin": self.origin, "requestData": req_options}
)
@dataclass(frozen=True)
class AuthenticatorAssertionResponse:
"""Authenticator response to a WebAuthn get (assertion) request.
https://www.w3.org/TR/webauthn-3/#authenticatorassertionresponse
Args:
client_data_json: <url-safe base64-encoded> client data JSON.
authenticator_data: <url-safe base64-encoded> authenticator data.
signature: <url-safe base64-encoded> signature.
user_handle: <url-safe base64-encoded> user handle.
"""
client_data_json: str
authenticator_data: str
signature: str
user_handle: Optional[str]
@dataclass(frozen=True)
class GetResponse:
"""WebAuthn get (assertion) response.
Args:
id: <url-safe base64-encoded> credential id (key handle).
response: The authenticator assertion response.
authenticator_attachment: <'cross-platform'|'platform'> The attachment status of the authenticator.
client_extension_results: WebAuthn authentication extensions output results in a dictionary.
"""
id: str
response: AuthenticatorAssertionResponse
authenticator_attachment: Optional[str]
client_extension_results: Optional[Dict]
@staticmethod
def from_json(json_str: str):
"""Verify and construct GetResponse from a JSON string."""
try:
resp_json = json.loads(json_str)
except ValueError:
raise exceptions.MalformedError("Invalid Get JSON response")
if resp_json.get("type") != "getResponse":
raise exceptions.MalformedError(
"Invalid Get response type: {}".format(resp_json.get("type"))
)
pk_cred = resp_json.get("responseData")
if pk_cred is None:
if resp_json.get("error"):
raise exceptions.ReauthFailError(
"WebAuthn.get failure: {}".format(resp_json["error"])
)
else:
raise exceptions.MalformedError("Get response is empty")
if pk_cred.get("type") != "public-key":
raise exceptions.MalformedError(
"Invalid credential type: {}".format(pk_cred.get("type"))
)
assertion_json = pk_cred["response"]
assertion_resp = AuthenticatorAssertionResponse(
client_data_json=assertion_json["clientDataJSON"],
authenticator_data=assertion_json["authenticatorData"],
signature=assertion_json["signature"],
user_handle=assertion_json.get("userHandle"),
)
return GetResponse(
id=pk_cred["id"],
response=assertion_resp,
authenticator_attachment=pk_cred.get("authenticatorAttachment"),
client_extension_results=pk_cred.get("clientExtensionResults"),
)