diff --git a/robosystems_client/api/auth/delete_user_passkey.py b/robosystems_client/api/auth/delete_user_passkey.py new file mode 100644 index 0000000..e0006d9 --- /dev/null +++ b/robosystems_client/api/auth/delete_user_passkey.py @@ -0,0 +1,220 @@ +from http import HTTPStatus +from typing import Any +from urllib.parse import quote + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.error_response import ErrorResponse +from ...models.http_validation_error import HTTPValidationError +from ...models.passkey_delete_request import PasskeyDeleteRequest +from ...models.success_response import SuccessResponse +from ...types import Response + + +def _get_kwargs( + passkey_id: str, + *, + body: PasskeyDeleteRequest, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "delete", + "url": "/v1/auth/passkeys/{passkey_id}".format( + passkey_id=quote(str(passkey_id), safe=""), + ), + } + + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> ErrorResponse | HTTPValidationError | SuccessResponse | None: + if response.status_code == 200: + response_200 = SuccessResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = ErrorResponse.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = ErrorResponse.from_dict(response.json()) + + return response_401 + + if response.status_code == 409: + response_409 = ErrorResponse.from_dict(response.json()) + + return response_409 + + if response.status_code == 422: + response_422 = HTTPValidationError.from_dict(response.json()) + + return response_422 + + if response.status_code == 429: + response_429 = ErrorResponse.from_dict(response.json()) + + return response_429 + + if response.status_code == 500: + response_500 = ErrorResponse.from_dict(response.json()) + + return response_500 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[ErrorResponse | HTTPValidationError | SuccessResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + passkey_id: str, + *, + client: AuthenticatedClient, + body: PasskeyDeleteRequest, +) -> Response[ErrorResponse | HTTPValidationError | SuccessResponse]: + """Remove Passkey + + Remove one passkey after re-authentication (password or fresh assertion). The last passkey of an + MFA-required role cannot be removed while enforcement is active. + + Args: + passkey_id (str): + body (PasskeyDeleteRequest): Re-authentication proof for removing a passkey. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[ErrorResponse | HTTPValidationError | SuccessResponse] + """ + + kwargs = _get_kwargs( + passkey_id=passkey_id, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + passkey_id: str, + *, + client: AuthenticatedClient, + body: PasskeyDeleteRequest, +) -> ErrorResponse | HTTPValidationError | SuccessResponse | None: + """Remove Passkey + + Remove one passkey after re-authentication (password or fresh assertion). The last passkey of an + MFA-required role cannot be removed while enforcement is active. + + Args: + passkey_id (str): + body (PasskeyDeleteRequest): Re-authentication proof for removing a passkey. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + ErrorResponse | HTTPValidationError | SuccessResponse + """ + + return sync_detailed( + passkey_id=passkey_id, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + passkey_id: str, + *, + client: AuthenticatedClient, + body: PasskeyDeleteRequest, +) -> Response[ErrorResponse | HTTPValidationError | SuccessResponse]: + """Remove Passkey + + Remove one passkey after re-authentication (password or fresh assertion). The last passkey of an + MFA-required role cannot be removed while enforcement is active. + + Args: + passkey_id (str): + body (PasskeyDeleteRequest): Re-authentication proof for removing a passkey. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[ErrorResponse | HTTPValidationError | SuccessResponse] + """ + + kwargs = _get_kwargs( + passkey_id=passkey_id, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + passkey_id: str, + *, + client: AuthenticatedClient, + body: PasskeyDeleteRequest, +) -> ErrorResponse | HTTPValidationError | SuccessResponse | None: + """Remove Passkey + + Remove one passkey after re-authentication (password or fresh assertion). The last passkey of an + MFA-required role cannot be removed while enforcement is active. + + Args: + passkey_id (str): + body (PasskeyDeleteRequest): Re-authentication proof for removing a passkey. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + ErrorResponse | HTTPValidationError | SuccessResponse + """ + + return ( + await asyncio_detailed( + passkey_id=passkey_id, + client=client, + body=body, + ) + ).parsed diff --git a/robosystems_client/api/auth/get_mfa_options.py b/robosystems_client/api/auth/get_mfa_options.py new file mode 100644 index 0000000..cf39ea7 --- /dev/null +++ b/robosystems_client/api/auth/get_mfa_options.py @@ -0,0 +1,195 @@ +from http import HTTPStatus +from typing import Any + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.ceremony_options_response import CeremonyOptionsResponse +from ...models.error_response import ErrorResponse +from ...models.http_validation_error import HTTPValidationError +from ...models.mfa_options_request import MfaOptionsRequest +from ...types import Response + + +def _get_kwargs( + *, + body: MfaOptionsRequest, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/v1/auth/mfa/options", + } + + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> CeremonyOptionsResponse | ErrorResponse | HTTPValidationError | None: + if response.status_code == 200: + response_200 = CeremonyOptionsResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = ErrorResponse.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = ErrorResponse.from_dict(response.json()) + + return response_401 + + if response.status_code == 422: + response_422 = HTTPValidationError.from_dict(response.json()) + + return response_422 + + if response.status_code == 429: + response_429 = ErrorResponse.from_dict(response.json()) + + return response_429 + + if response.status_code == 500: + response_500 = ErrorResponse.from_dict(response.json()) + + return response_500 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[CeremonyOptionsResponse | ErrorResponse | HTTPValidationError]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient | Client, + body: MfaOptionsRequest, +) -> Response[CeremonyOptionsResponse | ErrorResponse | HTTPValidationError]: + """MFA Assertion Options + + Exchange an mfa_required login token for passkey assertion options. + + Args: + body (MfaOptionsRequest): Request assertion options for the second factor. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[CeremonyOptionsResponse | ErrorResponse | HTTPValidationError] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient | Client, + body: MfaOptionsRequest, +) -> CeremonyOptionsResponse | ErrorResponse | HTTPValidationError | None: + """MFA Assertion Options + + Exchange an mfa_required login token for passkey assertion options. + + Args: + body (MfaOptionsRequest): Request assertion options for the second factor. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + CeremonyOptionsResponse | ErrorResponse | HTTPValidationError + """ + + return sync_detailed( + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient | Client, + body: MfaOptionsRequest, +) -> Response[CeremonyOptionsResponse | ErrorResponse | HTTPValidationError]: + """MFA Assertion Options + + Exchange an mfa_required login token for passkey assertion options. + + Args: + body (MfaOptionsRequest): Request assertion options for the second factor. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[CeremonyOptionsResponse | ErrorResponse | HTTPValidationError] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient | Client, + body: MfaOptionsRequest, +) -> CeremonyOptionsResponse | ErrorResponse | HTTPValidationError | None: + """MFA Assertion Options + + Exchange an mfa_required login token for passkey assertion options. + + Args: + body (MfaOptionsRequest): Request assertion options for the second factor. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + CeremonyOptionsResponse | ErrorResponse | HTTPValidationError + """ + + return ( + await asyncio_detailed( + client=client, + body=body, + ) + ).parsed diff --git a/robosystems_client/api/auth/get_mfa_status.py b/robosystems_client/api/auth/get_mfa_status.py new file mode 100644 index 0000000..dbd39c2 --- /dev/null +++ b/robosystems_client/api/auth/get_mfa_status.py @@ -0,0 +1,152 @@ +from http import HTTPStatus +from typing import Any + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.error_response import ErrorResponse +from ...models.mfa_status_response import MfaStatusResponse +from ...types import Response + + +def _get_kwargs() -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/v1/auth/mfa/status", + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> ErrorResponse | MfaStatusResponse | None: + if response.status_code == 200: + response_200 = MfaStatusResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = ErrorResponse.from_dict(response.json()) + + return response_400 + + if response.status_code == 429: + response_429 = ErrorResponse.from_dict(response.json()) + + return response_429 + + if response.status_code == 500: + response_500 = ErrorResponse.from_dict(response.json()) + + return response_500 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[ErrorResponse | MfaStatusResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient, +) -> Response[ErrorResponse | MfaStatusResponse]: + """MFA Status + + The authenticated user's MFA posture for account settings. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[ErrorResponse | MfaStatusResponse] + """ + + kwargs = _get_kwargs() + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient, +) -> ErrorResponse | MfaStatusResponse | None: + """MFA Status + + The authenticated user's MFA posture for account settings. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + ErrorResponse | MfaStatusResponse + """ + + return sync_detailed( + client=client, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient, +) -> Response[ErrorResponse | MfaStatusResponse]: + """MFA Status + + The authenticated user's MFA posture for account settings. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[ErrorResponse | MfaStatusResponse] + """ + + kwargs = _get_kwargs() + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient, +) -> ErrorResponse | MfaStatusResponse | None: + """MFA Status + + The authenticated user's MFA posture for account settings. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + ErrorResponse | MfaStatusResponse + """ + + return ( + await asyncio_detailed( + client=client, + ) + ).parsed diff --git a/robosystems_client/api/auth/get_passkey_login_options.py b/robosystems_client/api/auth/get_passkey_login_options.py new file mode 100644 index 0000000..30961b1 --- /dev/null +++ b/robosystems_client/api/auth/get_passkey_login_options.py @@ -0,0 +1,152 @@ +from http import HTTPStatus +from typing import Any + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.ceremony_options_response import CeremonyOptionsResponse +from ...models.error_response import ErrorResponse +from ...types import Response + + +def _get_kwargs() -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/v1/auth/passkeys/login/options", + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> CeremonyOptionsResponse | ErrorResponse | None: + if response.status_code == 200: + response_200 = CeremonyOptionsResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = ErrorResponse.from_dict(response.json()) + + return response_400 + + if response.status_code == 429: + response_429 = ErrorResponse.from_dict(response.json()) + + return response_429 + + if response.status_code == 500: + response_500 = ErrorResponse.from_dict(response.json()) + + return response_500 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[CeremonyOptionsResponse | ErrorResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient | Client, +) -> Response[CeremonyOptionsResponse | ErrorResponse]: + """Passwordless Login Options + + Usernameless assertion options for passwordless (passkey) login. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[CeremonyOptionsResponse | ErrorResponse] + """ + + kwargs = _get_kwargs() + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient | Client, +) -> CeremonyOptionsResponse | ErrorResponse | None: + """Passwordless Login Options + + Usernameless assertion options for passwordless (passkey) login. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + CeremonyOptionsResponse | ErrorResponse + """ + + return sync_detailed( + client=client, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient | Client, +) -> Response[CeremonyOptionsResponse | ErrorResponse]: + """Passwordless Login Options + + Usernameless assertion options for passwordless (passkey) login. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[CeremonyOptionsResponse | ErrorResponse] + """ + + kwargs = _get_kwargs() + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient | Client, +) -> CeremonyOptionsResponse | ErrorResponse | None: + """Passwordless Login Options + + Usernameless assertion options for passwordless (passkey) login. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + CeremonyOptionsResponse | ErrorResponse + """ + + return ( + await asyncio_detailed( + client=client, + ) + ).parsed diff --git a/robosystems_client/api/auth/get_passkey_reauth_options.py b/robosystems_client/api/auth/get_passkey_reauth_options.py new file mode 100644 index 0000000..674c030 --- /dev/null +++ b/robosystems_client/api/auth/get_passkey_reauth_options.py @@ -0,0 +1,152 @@ +from http import HTTPStatus +from typing import Any + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.ceremony_options_response import CeremonyOptionsResponse +from ...models.error_response import ErrorResponse +from ...types import Response + + +def _get_kwargs() -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/v1/auth/passkeys/reauth/options", + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> CeremonyOptionsResponse | ErrorResponse | None: + if response.status_code == 200: + response_200 = CeremonyOptionsResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = ErrorResponse.from_dict(response.json()) + + return response_400 + + if response.status_code == 429: + response_429 = ErrorResponse.from_dict(response.json()) + + return response_429 + + if response.status_code == 500: + response_500 = ErrorResponse.from_dict(response.json()) + + return response_500 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[CeremonyOptionsResponse | ErrorResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient, +) -> Response[CeremonyOptionsResponse | ErrorResponse]: + """Re-authentication Options + + Fresh-assertion options for destructive passkey lifecycle actions. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[CeremonyOptionsResponse | ErrorResponse] + """ + + kwargs = _get_kwargs() + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient, +) -> CeremonyOptionsResponse | ErrorResponse | None: + """Re-authentication Options + + Fresh-assertion options for destructive passkey lifecycle actions. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + CeremonyOptionsResponse | ErrorResponse + """ + + return sync_detailed( + client=client, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient, +) -> Response[CeremonyOptionsResponse | ErrorResponse]: + """Re-authentication Options + + Fresh-assertion options for destructive passkey lifecycle actions. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[CeremonyOptionsResponse | ErrorResponse] + """ + + kwargs = _get_kwargs() + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient, +) -> CeremonyOptionsResponse | ErrorResponse | None: + """Re-authentication Options + + Fresh-assertion options for destructive passkey lifecycle actions. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + CeremonyOptionsResponse | ErrorResponse + """ + + return ( + await asyncio_detailed( + client=client, + ) + ).parsed diff --git a/robosystems_client/api/auth/get_passkey_registration_options.py b/robosystems_client/api/auth/get_passkey_registration_options.py new file mode 100644 index 0000000..2bc5393 --- /dev/null +++ b/robosystems_client/api/auth/get_passkey_registration_options.py @@ -0,0 +1,203 @@ +from http import HTTPStatus +from typing import Any + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.ceremony_options_response import CeremonyOptionsResponse +from ...models.error_response import ErrorResponse +from ...models.http_validation_error import HTTPValidationError +from ...models.passkey_register_options_request import PasskeyRegisterOptionsRequest +from ...types import Response + + +def _get_kwargs( + *, + body: PasskeyRegisterOptionsRequest, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/v1/auth/passkeys/register/options", + } + + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> CeremonyOptionsResponse | ErrorResponse | HTTPValidationError | None: + if response.status_code == 200: + response_200 = CeremonyOptionsResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = ErrorResponse.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = ErrorResponse.from_dict(response.json()) + + return response_401 + + if response.status_code == 422: + response_422 = HTTPValidationError.from_dict(response.json()) + + return response_422 + + if response.status_code == 429: + response_429 = ErrorResponse.from_dict(response.json()) + + return response_429 + + if response.status_code == 500: + response_500 = ErrorResponse.from_dict(response.json()) + + return response_500 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[CeremonyOptionsResponse | ErrorResponse | HTTPValidationError]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient, + body: PasskeyRegisterOptionsRequest, +) -> Response[CeremonyOptionsResponse | ErrorResponse | HTTPValidationError]: + """Passkey Registration Options + + Begin a passkey enrollment ceremony. + + Args: + body (PasskeyRegisterOptionsRequest): Begin enrollment. mfa_token is the forced-enrollment + lane; omitted for + an authenticated settings-flow enrollment. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[CeremonyOptionsResponse | ErrorResponse | HTTPValidationError] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient, + body: PasskeyRegisterOptionsRequest, +) -> CeremonyOptionsResponse | ErrorResponse | HTTPValidationError | None: + """Passkey Registration Options + + Begin a passkey enrollment ceremony. + + Args: + body (PasskeyRegisterOptionsRequest): Begin enrollment. mfa_token is the forced-enrollment + lane; omitted for + an authenticated settings-flow enrollment. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + CeremonyOptionsResponse | ErrorResponse | HTTPValidationError + """ + + return sync_detailed( + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient, + body: PasskeyRegisterOptionsRequest, +) -> Response[CeremonyOptionsResponse | ErrorResponse | HTTPValidationError]: + """Passkey Registration Options + + Begin a passkey enrollment ceremony. + + Args: + body (PasskeyRegisterOptionsRequest): Begin enrollment. mfa_token is the forced-enrollment + lane; omitted for + an authenticated settings-flow enrollment. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[CeremonyOptionsResponse | ErrorResponse | HTTPValidationError] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient, + body: PasskeyRegisterOptionsRequest, +) -> CeremonyOptionsResponse | ErrorResponse | HTTPValidationError | None: + """Passkey Registration Options + + Begin a passkey enrollment ceremony. + + Args: + body (PasskeyRegisterOptionsRequest): Begin enrollment. mfa_token is the forced-enrollment + lane; omitted for + an authenticated settings-flow enrollment. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + CeremonyOptionsResponse | ErrorResponse | HTTPValidationError + """ + + return ( + await asyncio_detailed( + client=client, + body=body, + ) + ).parsed diff --git a/robosystems_client/api/auth/list_user_passkeys.py b/robosystems_client/api/auth/list_user_passkeys.py new file mode 100644 index 0000000..a5d8064 --- /dev/null +++ b/robosystems_client/api/auth/list_user_passkeys.py @@ -0,0 +1,152 @@ +from http import HTTPStatus +from typing import Any + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.error_response import ErrorResponse +from ...models.passkey_list_response import PasskeyListResponse +from ...types import Response + + +def _get_kwargs() -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/v1/auth/passkeys", + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> ErrorResponse | PasskeyListResponse | None: + if response.status_code == 200: + response_200 = PasskeyListResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = ErrorResponse.from_dict(response.json()) + + return response_400 + + if response.status_code == 429: + response_429 = ErrorResponse.from_dict(response.json()) + + return response_429 + + if response.status_code == 500: + response_500 = ErrorResponse.from_dict(response.json()) + + return response_500 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[ErrorResponse | PasskeyListResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient, +) -> Response[ErrorResponse | PasskeyListResponse]: + """List Passkeys + + The authenticated user's enrolled passkeys. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[ErrorResponse | PasskeyListResponse] + """ + + kwargs = _get_kwargs() + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient, +) -> ErrorResponse | PasskeyListResponse | None: + """List Passkeys + + The authenticated user's enrolled passkeys. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + ErrorResponse | PasskeyListResponse + """ + + return sync_detailed( + client=client, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient, +) -> Response[ErrorResponse | PasskeyListResponse]: + """List Passkeys + + The authenticated user's enrolled passkeys. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[ErrorResponse | PasskeyListResponse] + """ + + kwargs = _get_kwargs() + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient, +) -> ErrorResponse | PasskeyListResponse | None: + """List Passkeys + + The authenticated user's enrolled passkeys. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + ErrorResponse | PasskeyListResponse + """ + + return ( + await asyncio_detailed( + client=client, + ) + ).parsed diff --git a/robosystems_client/api/auth/regenerate_mfa_recovery_codes.py b/robosystems_client/api/auth/regenerate_mfa_recovery_codes.py new file mode 100644 index 0000000..52d13f4 --- /dev/null +++ b/robosystems_client/api/auth/regenerate_mfa_recovery_codes.py @@ -0,0 +1,195 @@ +from http import HTTPStatus +from typing import Any + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.error_response import ErrorResponse +from ...models.http_validation_error import HTTPValidationError +from ...models.recovery_codes_request import RecoveryCodesRequest +from ...models.recovery_codes_response import RecoveryCodesResponse +from ...types import Response + + +def _get_kwargs( + *, + body: RecoveryCodesRequest, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/v1/auth/mfa/recovery-codes/regenerate", + } + + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> ErrorResponse | HTTPValidationError | RecoveryCodesResponse | None: + if response.status_code == 200: + response_200 = RecoveryCodesResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = ErrorResponse.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = ErrorResponse.from_dict(response.json()) + + return response_401 + + if response.status_code == 422: + response_422 = HTTPValidationError.from_dict(response.json()) + + return response_422 + + if response.status_code == 429: + response_429 = ErrorResponse.from_dict(response.json()) + + return response_429 + + if response.status_code == 500: + response_500 = ErrorResponse.from_dict(response.json()) + + return response_500 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[ErrorResponse | HTTPValidationError | RecoveryCodesResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient, + body: RecoveryCodesRequest, +) -> Response[ErrorResponse | HTTPValidationError | RecoveryCodesResponse]: + """Regenerate Recovery Codes + + Replace the recovery-code set after re-authentication; codes are shown once. + + Args: + body (RecoveryCodesRequest): Re-authentication proof for regenerating recovery codes. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[ErrorResponse | HTTPValidationError | RecoveryCodesResponse] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient, + body: RecoveryCodesRequest, +) -> ErrorResponse | HTTPValidationError | RecoveryCodesResponse | None: + """Regenerate Recovery Codes + + Replace the recovery-code set after re-authentication; codes are shown once. + + Args: + body (RecoveryCodesRequest): Re-authentication proof for regenerating recovery codes. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + ErrorResponse | HTTPValidationError | RecoveryCodesResponse + """ + + return sync_detailed( + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient, + body: RecoveryCodesRequest, +) -> Response[ErrorResponse | HTTPValidationError | RecoveryCodesResponse]: + """Regenerate Recovery Codes + + Replace the recovery-code set after re-authentication; codes are shown once. + + Args: + body (RecoveryCodesRequest): Re-authentication proof for regenerating recovery codes. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[ErrorResponse | HTTPValidationError | RecoveryCodesResponse] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient, + body: RecoveryCodesRequest, +) -> ErrorResponse | HTTPValidationError | RecoveryCodesResponse | None: + """Regenerate Recovery Codes + + Replace the recovery-code set after re-authentication; codes are shown once. + + Args: + body (RecoveryCodesRequest): Re-authentication proof for regenerating recovery codes. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + ErrorResponse | HTTPValidationError | RecoveryCodesResponse + """ + + return ( + await asyncio_detailed( + client=client, + body=body, + ) + ).parsed diff --git a/robosystems_client/api/auth/verify_mfa.py b/robosystems_client/api/auth/verify_mfa.py new file mode 100644 index 0000000..e722da3 --- /dev/null +++ b/robosystems_client/api/auth/verify_mfa.py @@ -0,0 +1,195 @@ +from http import HTTPStatus +from typing import Any + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.auth_response import AuthResponse +from ...models.error_response import ErrorResponse +from ...models.http_validation_error import HTTPValidationError +from ...models.mfa_verify_request import MfaVerifyRequest +from ...types import Response + + +def _get_kwargs( + *, + body: MfaVerifyRequest, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/v1/auth/mfa/verify", + } + + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> AuthResponse | ErrorResponse | HTTPValidationError | None: + if response.status_code == 200: + response_200 = AuthResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = ErrorResponse.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = ErrorResponse.from_dict(response.json()) + + return response_401 + + if response.status_code == 422: + response_422 = HTTPValidationError.from_dict(response.json()) + + return response_422 + + if response.status_code == 429: + response_429 = ErrorResponse.from_dict(response.json()) + + return response_429 + + if response.status_code == 500: + response_500 = ErrorResponse.from_dict(response.json()) + + return response_500 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[AuthResponse | ErrorResponse | HTTPValidationError]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient | Client, + body: MfaVerifyRequest, +) -> Response[AuthResponse | ErrorResponse | HTTPValidationError]: + """MFA Verify + + Complete the second factor with a passkey assertion or a recovery code. + + Args: + body (MfaVerifyRequest): Complete the second factor with an assertion or a recovery code. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[AuthResponse | ErrorResponse | HTTPValidationError] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient | Client, + body: MfaVerifyRequest, +) -> AuthResponse | ErrorResponse | HTTPValidationError | None: + """MFA Verify + + Complete the second factor with a passkey assertion or a recovery code. + + Args: + body (MfaVerifyRequest): Complete the second factor with an assertion or a recovery code. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + AuthResponse | ErrorResponse | HTTPValidationError + """ + + return sync_detailed( + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient | Client, + body: MfaVerifyRequest, +) -> Response[AuthResponse | ErrorResponse | HTTPValidationError]: + """MFA Verify + + Complete the second factor with a passkey assertion or a recovery code. + + Args: + body (MfaVerifyRequest): Complete the second factor with an assertion or a recovery code. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[AuthResponse | ErrorResponse | HTTPValidationError] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient | Client, + body: MfaVerifyRequest, +) -> AuthResponse | ErrorResponse | HTTPValidationError | None: + """MFA Verify + + Complete the second factor with a passkey assertion or a recovery code. + + Args: + body (MfaVerifyRequest): Complete the second factor with an assertion or a recovery code. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + AuthResponse | ErrorResponse | HTTPValidationError + """ + + return ( + await asyncio_detailed( + client=client, + body=body, + ) + ).parsed diff --git a/robosystems_client/api/auth/verify_passkey_login.py b/robosystems_client/api/auth/verify_passkey_login.py new file mode 100644 index 0000000..67f741b --- /dev/null +++ b/robosystems_client/api/auth/verify_passkey_login.py @@ -0,0 +1,199 @@ +from http import HTTPStatus +from typing import Any + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.auth_response import AuthResponse +from ...models.error_response import ErrorResponse +from ...models.http_validation_error import HTTPValidationError +from ...models.passkey_login_verify_request import PasskeyLoginVerifyRequest +from ...types import Response + + +def _get_kwargs( + *, + body: PasskeyLoginVerifyRequest, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/v1/auth/passkeys/login/verify", + } + + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> AuthResponse | ErrorResponse | HTTPValidationError | None: + if response.status_code == 200: + response_200 = AuthResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = ErrorResponse.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = ErrorResponse.from_dict(response.json()) + + return response_401 + + if response.status_code == 422: + response_422 = HTTPValidationError.from_dict(response.json()) + + return response_422 + + if response.status_code == 429: + response_429 = ErrorResponse.from_dict(response.json()) + + return response_429 + + if response.status_code == 500: + response_500 = ErrorResponse.from_dict(response.json()) + + return response_500 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[AuthResponse | ErrorResponse | HTTPValidationError]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient | Client, + body: PasskeyLoginVerifyRequest, +) -> Response[AuthResponse | ErrorResponse | HTTPValidationError]: + """Passwordless Login Verify + + Complete a passwordless login. A user-verified passkey assertion is two factors in one gesture. + + Args: + body (PasskeyLoginVerifyRequest): Complete a passwordless login with a discoverable- + credential assertion. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[AuthResponse | ErrorResponse | HTTPValidationError] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient | Client, + body: PasskeyLoginVerifyRequest, +) -> AuthResponse | ErrorResponse | HTTPValidationError | None: + """Passwordless Login Verify + + Complete a passwordless login. A user-verified passkey assertion is two factors in one gesture. + + Args: + body (PasskeyLoginVerifyRequest): Complete a passwordless login with a discoverable- + credential assertion. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + AuthResponse | ErrorResponse | HTTPValidationError + """ + + return sync_detailed( + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient | Client, + body: PasskeyLoginVerifyRequest, +) -> Response[AuthResponse | ErrorResponse | HTTPValidationError]: + """Passwordless Login Verify + + Complete a passwordless login. A user-verified passkey assertion is two factors in one gesture. + + Args: + body (PasskeyLoginVerifyRequest): Complete a passwordless login with a discoverable- + credential assertion. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[AuthResponse | ErrorResponse | HTTPValidationError] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient | Client, + body: PasskeyLoginVerifyRequest, +) -> AuthResponse | ErrorResponse | HTTPValidationError | None: + """Passwordless Login Verify + + Complete a passwordless login. A user-verified passkey assertion is two factors in one gesture. + + Args: + body (PasskeyLoginVerifyRequest): Complete a passwordless login with a discoverable- + credential assertion. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + AuthResponse | ErrorResponse | HTTPValidationError + """ + + return ( + await asyncio_detailed( + client=client, + body=body, + ) + ).parsed diff --git a/robosystems_client/api/auth/verify_passkey_registration.py b/robosystems_client/api/auth/verify_passkey_registration.py new file mode 100644 index 0000000..0c654d7 --- /dev/null +++ b/robosystems_client/api/auth/verify_passkey_registration.py @@ -0,0 +1,203 @@ +from http import HTTPStatus +from typing import Any + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.error_response import ErrorResponse +from ...models.http_validation_error import HTTPValidationError +from ...models.passkey_register_verify_request import PasskeyRegisterVerifyRequest +from ...models.passkey_register_verify_response import PasskeyRegisterVerifyResponse +from ...types import Response + + +def _get_kwargs( + *, + body: PasskeyRegisterVerifyRequest, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/v1/auth/passkeys/register/verify", + } + + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> ErrorResponse | HTTPValidationError | PasskeyRegisterVerifyResponse | None: + if response.status_code == 200: + response_200 = PasskeyRegisterVerifyResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = ErrorResponse.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = ErrorResponse.from_dict(response.json()) + + return response_401 + + if response.status_code == 422: + response_422 = HTTPValidationError.from_dict(response.json()) + + return response_422 + + if response.status_code == 429: + response_429 = ErrorResponse.from_dict(response.json()) + + return response_429 + + if response.status_code == 500: + response_500 = ErrorResponse.from_dict(response.json()) + + return response_500 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[ErrorResponse | HTTPValidationError | PasskeyRegisterVerifyResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient, + body: PasskeyRegisterVerifyRequest, +) -> Response[ErrorResponse | HTTPValidationError | PasskeyRegisterVerifyResponse]: + """Passkey Registration Verify + + Finish enrollment. The first passkey returns recovery codes (once); the forced-enrollment lane also + completes the login. + + Args: + body (PasskeyRegisterVerifyRequest): Finish enrollment with the authenticator's + attestation response. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[ErrorResponse | HTTPValidationError | PasskeyRegisterVerifyResponse] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient, + body: PasskeyRegisterVerifyRequest, +) -> ErrorResponse | HTTPValidationError | PasskeyRegisterVerifyResponse | None: + """Passkey Registration Verify + + Finish enrollment. The first passkey returns recovery codes (once); the forced-enrollment lane also + completes the login. + + Args: + body (PasskeyRegisterVerifyRequest): Finish enrollment with the authenticator's + attestation response. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + ErrorResponse | HTTPValidationError | PasskeyRegisterVerifyResponse + """ + + return sync_detailed( + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient, + body: PasskeyRegisterVerifyRequest, +) -> Response[ErrorResponse | HTTPValidationError | PasskeyRegisterVerifyResponse]: + """Passkey Registration Verify + + Finish enrollment. The first passkey returns recovery codes (once); the forced-enrollment lane also + completes the login. + + Args: + body (PasskeyRegisterVerifyRequest): Finish enrollment with the authenticator's + attestation response. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[ErrorResponse | HTTPValidationError | PasskeyRegisterVerifyResponse] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient, + body: PasskeyRegisterVerifyRequest, +) -> ErrorResponse | HTTPValidationError | PasskeyRegisterVerifyResponse | None: + """Passkey Registration Verify + + Finish enrollment. The first passkey returns recovery codes (once); the forced-enrollment lane also + completes the login. + + Args: + body (PasskeyRegisterVerifyRequest): Finish enrollment with the authenticator's + attestation response. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + ErrorResponse | HTTPValidationError | PasskeyRegisterVerifyResponse + """ + + return ( + await asyncio_detailed( + client=client, + body=body, + ) + ).parsed diff --git a/robosystems_client/models/__init__.py b/robosystems_client/models/__init__.py index 0586c28..77c790c 100644 --- a/robosystems_client/models/__init__.py +++ b/robosystems_client/models/__init__.py @@ -16,6 +16,7 @@ from .auth_providers_response import AuthProvidersResponse from .auth_response import AuthResponse from .auth_response_org_type_0 import AuthResponseOrgType0 +from .auth_response_status import AuthResponseStatus from .auth_response_user import AuthResponseUser from .auto_map_elements_operation import AutoMapElementsOperation from .available_extension import AvailableExtension @@ -44,6 +45,8 @@ CancelOperationResponseCanceloperation, ) from .cancel_subscription_request import CancelSubscriptionRequest +from .ceremony_options_response import CeremonyOptionsResponse +from .ceremony_options_response_options import CeremonyOptionsResponseOptions from .change_reporting_style_request import ChangeReportingStyleRequest from .change_reporting_style_response import ChangeReportingStyleResponse from .change_tier_op import ChangeTierOp @@ -348,6 +351,10 @@ from .memory_record_provenance_type_0 import MemoryRecordProvenanceType0 from .metric_mechanics import MetricMechanics from .metric_observation import MetricObservation +from .mfa_options_request import MfaOptionsRequest +from .mfa_status_response import MfaStatusResponse +from .mfa_verify_request import MfaVerifyRequest +from .mfa_verify_request_assertion_type_0 import MfaVerifyRequestAssertionType0 from .o_auth_callback_request import OAuthCallbackRequest from .o_auth_callback_response import OAuthCallbackResponse from .o_auth_init_request import OAuthInitRequest @@ -625,6 +632,18 @@ from .org_usage_response_daily_trend_item import OrgUsageResponseDailyTrendItem from .org_usage_response_graph_details_item import OrgUsageResponseGraphDetailsItem from .org_usage_summary import OrgUsageSummary +from .passkey_delete_request import PasskeyDeleteRequest +from .passkey_delete_request_assertion_type_0 import PasskeyDeleteRequestAssertionType0 +from .passkey_info import PasskeyInfo +from .passkey_list_response import PasskeyListResponse +from .passkey_login_verify_request import PasskeyLoginVerifyRequest +from .passkey_login_verify_request_assertion import PasskeyLoginVerifyRequestAssertion +from .passkey_register_options_request import PasskeyRegisterOptionsRequest +from .passkey_register_verify_request import PasskeyRegisterVerifyRequest +from .passkey_register_verify_request_credential import ( + PasskeyRegisterVerifyRequestCredential, +) +from .passkey_register_verify_response import PasskeyRegisterVerifyResponse from .password_check_request import PasswordCheckRequest from .password_check_response import PasswordCheckResponse from .password_check_response_character_types import PasswordCheckResponseCharacterTypes @@ -660,6 +679,9 @@ from .quick_books_connection_config import QuickBooksConnectionConfig from .rate_limits import RateLimits from .rebuild_schedule_request import RebuildScheduleRequest +from .recovery_codes_request import RecoveryCodesRequest +from .recovery_codes_request_assertion_type_0 import RecoveryCodesRequestAssertionType0 +from .recovery_codes_response import RecoveryCodesResponse from .regenerate_report_operation import RegenerateReportOperation from .register_request import RegisterRequest from .remember_op import RememberOp @@ -893,6 +915,7 @@ "AuthProvidersResponse", "AuthResponse", "AuthResponseOrgType0", + "AuthResponseStatus", "AuthResponseUser", "AutoMapElementsOperation", "AvailableExtension", @@ -917,6 +940,8 @@ "BlockSourceGraphResult", "CancelOperationResponseCanceloperation", "CancelSubscriptionRequest", + "CeremonyOptionsResponse", + "CeremonyOptionsResponseOptions", "ChangeReportingStyleRequest", "ChangeReportingStyleResponse", "ChangeTierOp", @@ -1169,6 +1194,10 @@ "MemoryRecordProvenanceType0", "MetricMechanics", "MetricObservation", + "MfaOptionsRequest", + "MfaStatusResponse", + "MfaVerifyRequest", + "MfaVerifyRequestAssertionType0", "OAuthCallbackRequest", "OAuthCallbackResponse", "OAuthInitRequest", @@ -1294,6 +1323,16 @@ "OrgUsageResponseDailyTrendItem", "OrgUsageResponseGraphDetailsItem", "OrgUsageSummary", + "PasskeyDeleteRequest", + "PasskeyDeleteRequestAssertionType0", + "PasskeyInfo", + "PasskeyListResponse", + "PasskeyLoginVerifyRequest", + "PasskeyLoginVerifyRequestAssertion", + "PasskeyRegisterOptionsRequest", + "PasskeyRegisterVerifyRequest", + "PasskeyRegisterVerifyRequestCredential", + "PasskeyRegisterVerifyResponse", "PasswordCheckRequest", "PasswordCheckResponse", "PasswordCheckResponseCharacterTypes", @@ -1325,6 +1364,9 @@ "QuickBooksConnectionConfig", "RateLimits", "RebuildScheduleRequest", + "RecoveryCodesRequest", + "RecoveryCodesRequestAssertionType0", + "RecoveryCodesResponse", "RegenerateReportOperation", "RegisterRequest", "RememberOp", diff --git a/robosystems_client/models/auth_response.py b/robosystems_client/models/auth_response.py index 9826124..b95882e 100644 --- a/robosystems_client/models/auth_response.py +++ b/robosystems_client/models/auth_response.py @@ -6,6 +6,7 @@ from attrs import define as _attrs_define from attrs import field as _attrs_field +from ..models.auth_response_status import AuthResponseStatus from ..types import UNSET, Unset if TYPE_CHECKING: @@ -25,6 +26,10 @@ class AuthResponse: message (str): Success message org (AuthResponseOrgType0 | None | Unset): Organization information (personal org created automatically on registration) + status (AuthResponseStatus | Unset): Login flow state: authenticated (token present), or a passkey MFA step is + required before a session is issued (mfa_token present) Default: AuthResponseStatus.AUTHENTICATED. + mfa_token (None | str | Unset): Short-lived token authorizing the MFA second step or forced enrollment; present + only when status is not 'authenticated' token (None | str | Unset): JWT authentication token (optional for cookie-based auth) expires_in (int | None | Unset): Token expiry time in seconds from now refresh_threshold (int | None | Unset): Recommended refresh threshold in seconds before expiry @@ -33,6 +38,8 @@ class AuthResponse: user: AuthResponseUser message: str org: AuthResponseOrgType0 | None | Unset = UNSET + status: AuthResponseStatus | Unset = AuthResponseStatus.AUTHENTICATED + mfa_token: None | str | Unset = UNSET token: None | str | Unset = UNSET expires_in: int | None | Unset = UNSET refresh_threshold: int | None | Unset = UNSET @@ -53,6 +60,16 @@ def to_dict(self) -> dict[str, Any]: else: org = self.org + status: str | Unset = UNSET + if not isinstance(self.status, Unset): + status = self.status.value + + mfa_token: None | str | Unset + if isinstance(self.mfa_token, Unset): + mfa_token = UNSET + else: + mfa_token = self.mfa_token + token: None | str | Unset if isinstance(self.token, Unset): token = UNSET @@ -81,6 +98,10 @@ def to_dict(self) -> dict[str, Any]: ) if org is not UNSET: field_dict["org"] = org + if status is not UNSET: + field_dict["status"] = status + if mfa_token is not UNSET: + field_dict["mfa_token"] = mfa_token if token is not UNSET: field_dict["token"] = token if expires_in is not UNSET: @@ -117,6 +138,22 @@ def _parse_org(data: object) -> AuthResponseOrgType0 | None | Unset: org = _parse_org(d.pop("org", UNSET)) + _status = d.pop("status", UNSET) + status: AuthResponseStatus | Unset + if isinstance(_status, Unset): + status = UNSET + else: + status = AuthResponseStatus(_status) + + def _parse_mfa_token(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + mfa_token = _parse_mfa_token(d.pop("mfa_token", UNSET)) + def _parse_token(data: object) -> None | str | Unset: if data is None: return data @@ -148,6 +185,8 @@ def _parse_refresh_threshold(data: object) -> int | None | Unset: user=user, message=message, org=org, + status=status, + mfa_token=mfa_token, token=token, expires_in=expires_in, refresh_threshold=refresh_threshold, diff --git a/robosystems_client/models/auth_response_status.py b/robosystems_client/models/auth_response_status.py new file mode 100644 index 0000000..c75a3e3 --- /dev/null +++ b/robosystems_client/models/auth_response_status.py @@ -0,0 +1,10 @@ +from enum import Enum + + +class AuthResponseStatus(str, Enum): + AUTHENTICATED = "authenticated" + MFA_ENROLLMENT_REQUIRED = "mfa_enrollment_required" + MFA_REQUIRED = "mfa_required" + + def __str__(self) -> str: + return str(self.value) diff --git a/robosystems_client/models/ceremony_options_response.py b/robosystems_client/models/ceremony_options_response.py new file mode 100644 index 0000000..3967b0d --- /dev/null +++ b/robosystems_client/models/ceremony_options_response.py @@ -0,0 +1,70 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.ceremony_options_response_options import CeremonyOptionsResponseOptions + + +T = TypeVar("T", bound="CeremonyOptionsResponse") + + +@_attrs_define +class CeremonyOptionsResponse: + """WebAuthn options for the browser, verbatim from the RP library. + + Attributes: + options (CeremonyOptionsResponseOptions): PublicKeyCredential options (browser JSON, opaque) + """ + + options: CeremonyOptionsResponseOptions + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + options = self.options.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "options": options, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.ceremony_options_response_options import ( + CeremonyOptionsResponseOptions, + ) + + d = dict(src_dict) + options = CeremonyOptionsResponseOptions.from_dict(d.pop("options")) + + ceremony_options_response = cls( + options=options, + ) + + ceremony_options_response.additional_properties = d + return ceremony_options_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/ceremony_options_response_options.py b/robosystems_client/models/ceremony_options_response_options.py new file mode 100644 index 0000000..68f4b00 --- /dev/null +++ b/robosystems_client/models/ceremony_options_response_options.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="CeremonyOptionsResponseOptions") + + +@_attrs_define +class CeremonyOptionsResponseOptions: + """PublicKeyCredential options (browser JSON, opaque)""" + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + ceremony_options_response_options = cls() + + ceremony_options_response_options.additional_properties = d + return ceremony_options_response_options + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/mfa_options_request.py b/robosystems_client/models/mfa_options_request.py new file mode 100644 index 0000000..a4b013b --- /dev/null +++ b/robosystems_client/models/mfa_options_request.py @@ -0,0 +1,62 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="MfaOptionsRequest") + + +@_attrs_define +class MfaOptionsRequest: + """Request assertion options for the second factor. + + Attributes: + mfa_token (str): Token from a login that returned mfa_required + """ + + mfa_token: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + mfa_token = self.mfa_token + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "mfa_token": mfa_token, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + mfa_token = d.pop("mfa_token") + + mfa_options_request = cls( + mfa_token=mfa_token, + ) + + mfa_options_request.additional_properties = d + return mfa_options_request + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/mfa_status_response.py b/robosystems_client/models/mfa_status_response.py new file mode 100644 index 0000000..db00791 --- /dev/null +++ b/robosystems_client/models/mfa_status_response.py @@ -0,0 +1,78 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="MfaStatusResponse") + + +@_attrs_define +class MfaStatusResponse: + """The user's MFA posture, for account settings. + + Attributes: + passkey_count (int): Enrolled passkey count + recovery_codes_remaining (int): Unused recovery codes remaining + enforcement_applies (bool): Whether the MFA requirement applies to this user's roles + """ + + passkey_count: int + recovery_codes_remaining: int + enforcement_applies: bool + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + passkey_count = self.passkey_count + + recovery_codes_remaining = self.recovery_codes_remaining + + enforcement_applies = self.enforcement_applies + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "passkey_count": passkey_count, + "recovery_codes_remaining": recovery_codes_remaining, + "enforcement_applies": enforcement_applies, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + passkey_count = d.pop("passkey_count") + + recovery_codes_remaining = d.pop("recovery_codes_remaining") + + enforcement_applies = d.pop("enforcement_applies") + + mfa_status_response = cls( + passkey_count=passkey_count, + recovery_codes_remaining=recovery_codes_remaining, + enforcement_applies=enforcement_applies, + ) + + mfa_status_response.additional_properties = d + return mfa_status_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/mfa_verify_request.py b/robosystems_client/models/mfa_verify_request.py new file mode 100644 index 0000000..d85b1fd --- /dev/null +++ b/robosystems_client/models/mfa_verify_request.py @@ -0,0 +1,128 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.mfa_verify_request_assertion_type_0 import ( + MfaVerifyRequestAssertionType0, + ) + + +T = TypeVar("T", bound="MfaVerifyRequest") + + +@_attrs_define +class MfaVerifyRequest: + """Complete the second factor with an assertion or a recovery code. + + Attributes: + mfa_token (str): Token from a login that returned mfa_required + assertion (MfaVerifyRequestAssertionType0 | None | Unset): WebAuthn assertion (browser JSON, opaque) + recovery_code (None | str | Unset): Single-use recovery code + """ + + mfa_token: str + assertion: MfaVerifyRequestAssertionType0 | None | Unset = UNSET + recovery_code: None | str | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.mfa_verify_request_assertion_type_0 import ( + MfaVerifyRequestAssertionType0, + ) + + mfa_token = self.mfa_token + + assertion: dict[str, Any] | None | Unset + if isinstance(self.assertion, Unset): + assertion = UNSET + elif isinstance(self.assertion, MfaVerifyRequestAssertionType0): + assertion = self.assertion.to_dict() + else: + assertion = self.assertion + + recovery_code: None | str | Unset + if isinstance(self.recovery_code, Unset): + recovery_code = UNSET + else: + recovery_code = self.recovery_code + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "mfa_token": mfa_token, + } + ) + if assertion is not UNSET: + field_dict["assertion"] = assertion + if recovery_code is not UNSET: + field_dict["recovery_code"] = recovery_code + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.mfa_verify_request_assertion_type_0 import ( + MfaVerifyRequestAssertionType0, + ) + + d = dict(src_dict) + mfa_token = d.pop("mfa_token") + + def _parse_assertion(data: object) -> MfaVerifyRequestAssertionType0 | None | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, dict): + raise TypeError() + assertion_type_0 = MfaVerifyRequestAssertionType0.from_dict(data) + + return assertion_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(MfaVerifyRequestAssertionType0 | None | Unset, data) + + assertion = _parse_assertion(d.pop("assertion", UNSET)) + + def _parse_recovery_code(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + recovery_code = _parse_recovery_code(d.pop("recovery_code", UNSET)) + + mfa_verify_request = cls( + mfa_token=mfa_token, + assertion=assertion, + recovery_code=recovery_code, + ) + + mfa_verify_request.additional_properties = d + return mfa_verify_request + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/mfa_verify_request_assertion_type_0.py b/robosystems_client/models/mfa_verify_request_assertion_type_0.py new file mode 100644 index 0000000..181293d --- /dev/null +++ b/robosystems_client/models/mfa_verify_request_assertion_type_0.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="MfaVerifyRequestAssertionType0") + + +@_attrs_define +class MfaVerifyRequestAssertionType0: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + mfa_verify_request_assertion_type_0 = cls() + + mfa_verify_request_assertion_type_0.additional_properties = d + return mfa_verify_request_assertion_type_0 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/passkey_delete_request.py b/robosystems_client/models/passkey_delete_request.py new file mode 100644 index 0000000..0b604fb --- /dev/null +++ b/robosystems_client/models/passkey_delete_request.py @@ -0,0 +1,121 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.passkey_delete_request_assertion_type_0 import ( + PasskeyDeleteRequestAssertionType0, + ) + + +T = TypeVar("T", bound="PasskeyDeleteRequest") + + +@_attrs_define +class PasskeyDeleteRequest: + """Re-authentication proof for removing a passkey. + + Attributes: + password (None | str | Unset): Current password (password-holding users) + assertion (None | PasskeyDeleteRequestAssertionType0 | Unset): Fresh WebAuthn assertion from the re-auth + ceremony + """ + + password: None | str | Unset = UNSET + assertion: None | PasskeyDeleteRequestAssertionType0 | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.passkey_delete_request_assertion_type_0 import ( + PasskeyDeleteRequestAssertionType0, + ) + + password: None | str | Unset + if isinstance(self.password, Unset): + password = UNSET + else: + password = self.password + + assertion: dict[str, Any] | None | Unset + if isinstance(self.assertion, Unset): + assertion = UNSET + elif isinstance(self.assertion, PasskeyDeleteRequestAssertionType0): + assertion = self.assertion.to_dict() + else: + assertion = self.assertion + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if password is not UNSET: + field_dict["password"] = password + if assertion is not UNSET: + field_dict["assertion"] = assertion + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.passkey_delete_request_assertion_type_0 import ( + PasskeyDeleteRequestAssertionType0, + ) + + d = dict(src_dict) + + def _parse_password(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + password = _parse_password(d.pop("password", UNSET)) + + def _parse_assertion( + data: object, + ) -> None | PasskeyDeleteRequestAssertionType0 | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, dict): + raise TypeError() + assertion_type_0 = PasskeyDeleteRequestAssertionType0.from_dict(data) + + return assertion_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(None | PasskeyDeleteRequestAssertionType0 | Unset, data) + + assertion = _parse_assertion(d.pop("assertion", UNSET)) + + passkey_delete_request = cls( + password=password, + assertion=assertion, + ) + + passkey_delete_request.additional_properties = d + return passkey_delete_request + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/passkey_delete_request_assertion_type_0.py b/robosystems_client/models/passkey_delete_request_assertion_type_0.py new file mode 100644 index 0000000..b570901 --- /dev/null +++ b/robosystems_client/models/passkey_delete_request_assertion_type_0.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="PasskeyDeleteRequestAssertionType0") + + +@_attrs_define +class PasskeyDeleteRequestAssertionType0: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + passkey_delete_request_assertion_type_0 = cls() + + passkey_delete_request_assertion_type_0.additional_properties = d + return passkey_delete_request_assertion_type_0 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/passkey_info.py b/robosystems_client/models/passkey_info.py new file mode 100644 index 0000000..e77eebd --- /dev/null +++ b/robosystems_client/models/passkey_info.py @@ -0,0 +1,116 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="PasskeyInfo") + + +@_attrs_define +class PasskeyInfo: + """One enrolled passkey, as listed in account settings. + + Attributes: + id (str): Passkey identifier + name (str): User-facing label + created_at (str): Enrollment time (ISO 8601) + backup_eligible (bool): Whether the credential is synced (multi-device) capable + backup_state (bool): Whether the credential is currently backed up + last_used_at (None | str | Unset): Last successful assertion time (ISO 8601) + """ + + id: str + name: str + created_at: str + backup_eligible: bool + backup_state: bool + last_used_at: None | str | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + name = self.name + + created_at = self.created_at + + backup_eligible = self.backup_eligible + + backup_state = self.backup_state + + last_used_at: None | str | Unset + if isinstance(self.last_used_at, Unset): + last_used_at = UNSET + else: + last_used_at = self.last_used_at + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "id": id, + "name": name, + "created_at": created_at, + "backup_eligible": backup_eligible, + "backup_state": backup_state, + } + ) + if last_used_at is not UNSET: + field_dict["last_used_at"] = last_used_at + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + id = d.pop("id") + + name = d.pop("name") + + created_at = d.pop("created_at") + + backup_eligible = d.pop("backup_eligible") + + backup_state = d.pop("backup_state") + + def _parse_last_used_at(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + last_used_at = _parse_last_used_at(d.pop("last_used_at", UNSET)) + + passkey_info = cls( + id=id, + name=name, + created_at=created_at, + backup_eligible=backup_eligible, + backup_state=backup_state, + last_used_at=last_used_at, + ) + + passkey_info.additional_properties = d + return passkey_info + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/passkey_list_response.py b/robosystems_client/models/passkey_list_response.py new file mode 100644 index 0000000..d3bd362 --- /dev/null +++ b/robosystems_client/models/passkey_list_response.py @@ -0,0 +1,76 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.passkey_info import PasskeyInfo + + +T = TypeVar("T", bound="PasskeyListResponse") + + +@_attrs_define +class PasskeyListResponse: + """The user's enrolled passkeys. + + Attributes: + passkeys (list[PasskeyInfo]): Enrolled passkeys + """ + + passkeys: list[PasskeyInfo] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + passkeys = [] + for passkeys_item_data in self.passkeys: + passkeys_item = passkeys_item_data.to_dict() + passkeys.append(passkeys_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "passkeys": passkeys, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.passkey_info import PasskeyInfo + + d = dict(src_dict) + passkeys = [] + _passkeys = d.pop("passkeys") + for passkeys_item_data in _passkeys: + passkeys_item = PasskeyInfo.from_dict(passkeys_item_data) + + passkeys.append(passkeys_item) + + passkey_list_response = cls( + passkeys=passkeys, + ) + + passkey_list_response.additional_properties = d + return passkey_list_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/passkey_login_verify_request.py b/robosystems_client/models/passkey_login_verify_request.py new file mode 100644 index 0000000..82323df --- /dev/null +++ b/robosystems_client/models/passkey_login_verify_request.py @@ -0,0 +1,72 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.passkey_login_verify_request_assertion import ( + PasskeyLoginVerifyRequestAssertion, + ) + + +T = TypeVar("T", bound="PasskeyLoginVerifyRequest") + + +@_attrs_define +class PasskeyLoginVerifyRequest: + """Complete a passwordless login with a discoverable-credential assertion. + + Attributes: + assertion (PasskeyLoginVerifyRequestAssertion): WebAuthn assertion (browser JSON, opaque) + """ + + assertion: PasskeyLoginVerifyRequestAssertion + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + assertion = self.assertion.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "assertion": assertion, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.passkey_login_verify_request_assertion import ( + PasskeyLoginVerifyRequestAssertion, + ) + + d = dict(src_dict) + assertion = PasskeyLoginVerifyRequestAssertion.from_dict(d.pop("assertion")) + + passkey_login_verify_request = cls( + assertion=assertion, + ) + + passkey_login_verify_request.additional_properties = d + return passkey_login_verify_request + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/passkey_login_verify_request_assertion.py b/robosystems_client/models/passkey_login_verify_request_assertion.py new file mode 100644 index 0000000..ea75505 --- /dev/null +++ b/robosystems_client/models/passkey_login_verify_request_assertion.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="PasskeyLoginVerifyRequestAssertion") + + +@_attrs_define +class PasskeyLoginVerifyRequestAssertion: + """WebAuthn assertion (browser JSON, opaque)""" + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + passkey_login_verify_request_assertion = cls() + + passkey_login_verify_request_assertion.additional_properties = d + return passkey_login_verify_request_assertion + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/passkey_register_options_request.py b/robosystems_client/models/passkey_register_options_request.py new file mode 100644 index 0000000..d43142a --- /dev/null +++ b/robosystems_client/models/passkey_register_options_request.py @@ -0,0 +1,75 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="PasskeyRegisterOptionsRequest") + + +@_attrs_define +class PasskeyRegisterOptionsRequest: + """Begin enrollment. mfa_token is the forced-enrollment lane; omitted for + an authenticated settings-flow enrollment. + + Attributes: + mfa_token (None | str | Unset): Enrollment token from a login that returned mfa_enrollment_required + """ + + mfa_token: None | str | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + mfa_token: None | str | Unset + if isinstance(self.mfa_token, Unset): + mfa_token = UNSET + else: + mfa_token = self.mfa_token + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if mfa_token is not UNSET: + field_dict["mfa_token"] = mfa_token + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + + def _parse_mfa_token(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + mfa_token = _parse_mfa_token(d.pop("mfa_token", UNSET)) + + passkey_register_options_request = cls( + mfa_token=mfa_token, + ) + + passkey_register_options_request.additional_properties = d + return passkey_register_options_request + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/passkey_register_verify_request.py b/robosystems_client/models/passkey_register_verify_request.py new file mode 100644 index 0000000..086c408 --- /dev/null +++ b/robosystems_client/models/passkey_register_verify_request.py @@ -0,0 +1,114 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.passkey_register_verify_request_credential import ( + PasskeyRegisterVerifyRequestCredential, + ) + + +T = TypeVar("T", bound="PasskeyRegisterVerifyRequest") + + +@_attrs_define +class PasskeyRegisterVerifyRequest: + """Finish enrollment with the authenticator's attestation response. + + Attributes: + credential (PasskeyRegisterVerifyRequestCredential): WebAuthn registration credential (browser JSON, opaque) + name (None | str | Unset): User-facing label for this passkey + mfa_token (None | str | Unset): Enrollment token when finishing a forced enrollment + """ + + credential: PasskeyRegisterVerifyRequestCredential + name: None | str | Unset = UNSET + mfa_token: None | str | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + credential = self.credential.to_dict() + + name: None | str | Unset + if isinstance(self.name, Unset): + name = UNSET + else: + name = self.name + + mfa_token: None | str | Unset + if isinstance(self.mfa_token, Unset): + mfa_token = UNSET + else: + mfa_token = self.mfa_token + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "credential": credential, + } + ) + if name is not UNSET: + field_dict["name"] = name + if mfa_token is not UNSET: + field_dict["mfa_token"] = mfa_token + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.passkey_register_verify_request_credential import ( + PasskeyRegisterVerifyRequestCredential, + ) + + d = dict(src_dict) + credential = PasskeyRegisterVerifyRequestCredential.from_dict(d.pop("credential")) + + def _parse_name(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + name = _parse_name(d.pop("name", UNSET)) + + def _parse_mfa_token(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + mfa_token = _parse_mfa_token(d.pop("mfa_token", UNSET)) + + passkey_register_verify_request = cls( + credential=credential, + name=name, + mfa_token=mfa_token, + ) + + passkey_register_verify_request.additional_properties = d + return passkey_register_verify_request + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/passkey_register_verify_request_credential.py b/robosystems_client/models/passkey_register_verify_request_credential.py new file mode 100644 index 0000000..dc45430 --- /dev/null +++ b/robosystems_client/models/passkey_register_verify_request_credential.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="PasskeyRegisterVerifyRequestCredential") + + +@_attrs_define +class PasskeyRegisterVerifyRequestCredential: + """WebAuthn registration credential (browser JSON, opaque)""" + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + passkey_register_verify_request_credential = cls() + + passkey_register_verify_request_credential.additional_properties = d + return passkey_register_verify_request_credential + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/passkey_register_verify_response.py b/robosystems_client/models/passkey_register_verify_response.py new file mode 100644 index 0000000..13add93 --- /dev/null +++ b/robosystems_client/models/passkey_register_verify_response.py @@ -0,0 +1,137 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.auth_response import AuthResponse + from ..models.passkey_info import PasskeyInfo + + +T = TypeVar("T", bound="PasskeyRegisterVerifyResponse") + + +@_attrs_define +class PasskeyRegisterVerifyResponse: + """Enrollment result; the first passkey also carries recovery codes and, + in the forced-enrollment lane, the completed login. + + Attributes: + passkey (PasskeyInfo): One enrolled passkey, as listed in account settings. + recovery_codes (list[str] | None | Unset): Single-use recovery codes — returned exactly once, at first + enrollment + auth (AuthResponse | None | Unset): Completed login (forced-enrollment lane only) + """ + + passkey: PasskeyInfo + recovery_codes: list[str] | None | Unset = UNSET + auth: AuthResponse | None | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.auth_response import AuthResponse + + passkey = self.passkey.to_dict() + + recovery_codes: list[str] | None | Unset + if isinstance(self.recovery_codes, Unset): + recovery_codes = UNSET + elif isinstance(self.recovery_codes, list): + recovery_codes = self.recovery_codes + + else: + recovery_codes = self.recovery_codes + + auth: dict[str, Any] | None | Unset + if isinstance(self.auth, Unset): + auth = UNSET + elif isinstance(self.auth, AuthResponse): + auth = self.auth.to_dict() + else: + auth = self.auth + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "passkey": passkey, + } + ) + if recovery_codes is not UNSET: + field_dict["recovery_codes"] = recovery_codes + if auth is not UNSET: + field_dict["auth"] = auth + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.auth_response import AuthResponse + from ..models.passkey_info import PasskeyInfo + + d = dict(src_dict) + passkey = PasskeyInfo.from_dict(d.pop("passkey")) + + def _parse_recovery_codes(data: object) -> list[str] | None | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, list): + raise TypeError() + recovery_codes_type_0 = cast(list[str], data) + + return recovery_codes_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(list[str] | None | Unset, data) + + recovery_codes = _parse_recovery_codes(d.pop("recovery_codes", UNSET)) + + def _parse_auth(data: object) -> AuthResponse | None | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, dict): + raise TypeError() + auth_type_0 = AuthResponse.from_dict(data) + + return auth_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(AuthResponse | None | Unset, data) + + auth = _parse_auth(d.pop("auth", UNSET)) + + passkey_register_verify_response = cls( + passkey=passkey, + recovery_codes=recovery_codes, + auth=auth, + ) + + passkey_register_verify_response.additional_properties = d + return passkey_register_verify_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/portal_session_response.py b/robosystems_client/models/portal_session_response.py index 105dfe7..c2a3514 100644 --- a/robosystems_client/models/portal_session_response.py +++ b/robosystems_client/models/portal_session_response.py @@ -1,11 +1,13 @@ from __future__ import annotations from collections.abc import Mapping -from typing import Any, TypeVar +from typing import Any, TypeVar, cast from attrs import define as _attrs_define from attrs import field as _attrs_field +from ..types import UNSET, Unset + T = TypeVar("T", bound="PortalSessionResponse") @@ -14,32 +16,52 @@ class PortalSessionResponse: """Response for customer portal session creation. Attributes: - portal_url (str): Stripe Customer Portal URL where user can manage payment methods + portal_url (None | str | Unset): Stripe Customer Portal URL where user can manage payment methods + billing_disabled (bool | Unset): True when billing is disabled on this deployment (no portal exists) Default: + False. """ - portal_url: str + portal_url: None | str | Unset = UNSET + billing_disabled: bool | Unset = False additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> dict[str, Any]: - portal_url = self.portal_url + portal_url: None | str | Unset + if isinstance(self.portal_url, Unset): + portal_url = UNSET + else: + portal_url = self.portal_url + + billing_disabled = self.billing_disabled field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) - field_dict.update( - { - "portal_url": portal_url, - } - ) + field_dict.update({}) + if portal_url is not UNSET: + field_dict["portal_url"] = portal_url + if billing_disabled is not UNSET: + field_dict["billing_disabled"] = billing_disabled return field_dict @classmethod def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: d = dict(src_dict) - portal_url = d.pop("portal_url") + + def _parse_portal_url(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + portal_url = _parse_portal_url(d.pop("portal_url", UNSET)) + + billing_disabled = d.pop("billing_disabled", UNSET) portal_session_response = cls( portal_url=portal_url, + billing_disabled=billing_disabled, ) portal_session_response.additional_properties = d diff --git a/robosystems_client/models/recovery_codes_request.py b/robosystems_client/models/recovery_codes_request.py new file mode 100644 index 0000000..6ad1819 --- /dev/null +++ b/robosystems_client/models/recovery_codes_request.py @@ -0,0 +1,121 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.recovery_codes_request_assertion_type_0 import ( + RecoveryCodesRequestAssertionType0, + ) + + +T = TypeVar("T", bound="RecoveryCodesRequest") + + +@_attrs_define +class RecoveryCodesRequest: + """Re-authentication proof for regenerating recovery codes. + + Attributes: + password (None | str | Unset): Current password (password-holding users) + assertion (None | RecoveryCodesRequestAssertionType0 | Unset): Fresh WebAuthn assertion from the re-auth + ceremony + """ + + password: None | str | Unset = UNSET + assertion: None | RecoveryCodesRequestAssertionType0 | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.recovery_codes_request_assertion_type_0 import ( + RecoveryCodesRequestAssertionType0, + ) + + password: None | str | Unset + if isinstance(self.password, Unset): + password = UNSET + else: + password = self.password + + assertion: dict[str, Any] | None | Unset + if isinstance(self.assertion, Unset): + assertion = UNSET + elif isinstance(self.assertion, RecoveryCodesRequestAssertionType0): + assertion = self.assertion.to_dict() + else: + assertion = self.assertion + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if password is not UNSET: + field_dict["password"] = password + if assertion is not UNSET: + field_dict["assertion"] = assertion + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.recovery_codes_request_assertion_type_0 import ( + RecoveryCodesRequestAssertionType0, + ) + + d = dict(src_dict) + + def _parse_password(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + password = _parse_password(d.pop("password", UNSET)) + + def _parse_assertion( + data: object, + ) -> None | RecoveryCodesRequestAssertionType0 | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, dict): + raise TypeError() + assertion_type_0 = RecoveryCodesRequestAssertionType0.from_dict(data) + + return assertion_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(None | RecoveryCodesRequestAssertionType0 | Unset, data) + + assertion = _parse_assertion(d.pop("assertion", UNSET)) + + recovery_codes_request = cls( + password=password, + assertion=assertion, + ) + + recovery_codes_request.additional_properties = d + return recovery_codes_request + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/recovery_codes_request_assertion_type_0.py b/robosystems_client/models/recovery_codes_request_assertion_type_0.py new file mode 100644 index 0000000..fc9b66a --- /dev/null +++ b/robosystems_client/models/recovery_codes_request_assertion_type_0.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="RecoveryCodesRequestAssertionType0") + + +@_attrs_define +class RecoveryCodesRequestAssertionType0: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + recovery_codes_request_assertion_type_0 = cls() + + recovery_codes_request_assertion_type_0.additional_properties = d + return recovery_codes_request_assertion_type_0 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/recovery_codes_response.py b/robosystems_client/models/recovery_codes_response.py new file mode 100644 index 0000000..1319f9d --- /dev/null +++ b/robosystems_client/models/recovery_codes_response.py @@ -0,0 +1,62 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="RecoveryCodesResponse") + + +@_attrs_define +class RecoveryCodesResponse: + """A fresh recovery-code set — shown exactly once. + + Attributes: + codes (list[str]): Single-use recovery codes + """ + + codes: list[str] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + codes = self.codes + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "codes": codes, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + codes = cast(list[str], d.pop("codes")) + + recovery_codes_response = cls( + codes=codes, + ) + + recovery_codes_response.additional_properties = d + return recovery_codes_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties