From 7883f6c85633f99a19242a8a08f1390329d04edd Mon Sep 17 00:00:00 2001 From: Chris Tran Date: Mon, 23 Dec 2024 14:46:40 -0600 Subject: [PATCH 1/5] feat!: removes deprecated code from the Passage class --- passageidentity/passage.py | 227 ------------------------------------- 1 file changed, 227 deletions(-) diff --git a/passageidentity/passage.py b/passageidentity/passage.py index b164709..5501458 100644 --- a/passageidentity/passage.py +++ b/passageidentity/passage.py @@ -2,37 +2,10 @@ from __future__ import annotations -from typing import TYPE_CHECKING, cast - -import typing_extensions - from passageidentity.auth import Auth from passageidentity.errors import PassageError -from passageidentity.helper import get_auth_token_from_request -from passageidentity.models.magic_link_args import MagicLinkWithEmailArgs, MagicLinkWithPhoneArgs, MagicLinkWithUserArgs -from passageidentity.models.magic_link_options import MagicLinkOptions -from passageidentity.openapi_client.models.magic_link_channel import MagicLinkChannel from passageidentity.user import User -from .openapi_client.api import ( - AppsApi, -) -from .openapi_client.models import ( - CreateMagicLinkRequest, - CreateUserArgs, - MagicLinkType, -) - -if TYPE_CHECKING: - from requests.sessions import Request - - from .openapi_client.models import ( - AppInfo, - PassageUser, - UpdateUserArgs, - WebAuthnDevices, - ) - class Passage: """Passage class for interacting with the Passage API.""" @@ -53,203 +26,3 @@ def __init__(self, app_id: str, api_key: str = "", auth_strategy: int = COOKIE_A self.auth = Auth(app_id, self.request_headers) self.user = User(app_id, self.request_headers) - - @typing_extensions.deprecated("Passage.validateJwt() will be deprecated. Use Passage.auth.validate_jwt() instead.") - def validateJwt(self, token: str): # noqa: ANN201, N802 - """Verify the JWT and return the user ID for the authenticated user, or throw a PassageError. - - Takes the place of the deprecated authenticateRequest() function. - """ - return self.auth.validate_jwt(token) - - @typing_extensions.deprecated( - "Passage.authenticateRequest() will be deprecated. Use Passage.auth.validate_jwt() instead.", - ) - def authenticateRequest(self, request: Request) -> str | PassageError: # noqa: N802 - """Authenticate a Flask or Django request that uses Passage for authentication. - - This function will verify the JWT and return the user ID for the authenticated user, or throw - a PassageError. - """ - # check for authorization header - token = get_auth_token_from_request(request, self.auth_strategy) - if not token: - msg = "Could not find JWT." - raise PassageError(msg) - - # load and parse the JWT - try: - return self.auth.validate_jwt(token) - except Exception as e: - msg = f"JWT is not valid: {e}" - raise PassageError(msg) from e - - @typing_extensions.deprecated( - "Passage.authenticateJWT() will be deprecated. Use Passage.auth.validate_jwt() instead.", - ) - def authenticateJWT(self, token: str) -> str | PassageError: # noqa: N802 - """Authenticate a JWT from Passage. - - This function will verify the JWT and return the user ID for the authenticated user, or throw a PassageError. - This function can be used to authenticate JWTs from Passage if they are not sent in a typical cookie or - authorization header. - """ - return self.auth.validate_jwt(token) - - @typing_extensions.deprecated( - "Passage.createMagicLink() will be deprecated. Use Passage.auth.create_magic_link() instead.", - ) - def createMagicLink( # noqa: N802 - self, - magicLinkAttributes: CreateMagicLinkRequest, # noqa: N803 - ) -> MagicLinkType | PassageError: - """Create Passage MagicLink.""" - # if no api key, fail - if self.passage_apikey == "": - msg = "No Passage API key provided." - raise PassageError(msg) - - magic_link_attrs_dict = ( - magicLinkAttributes.to_dict() - if isinstance(magicLinkAttributes, CreateMagicLinkRequest) - else magicLinkAttributes - ) - - if email := magic_link_attrs_dict.get("email"): - args = MagicLinkWithEmailArgs() - args.email = email - elif phone := magic_link_attrs_dict.get("phone"): - args = MagicLinkWithPhoneArgs() - args.phone = phone - elif user_id := magic_link_attrs_dict.get("user_id"): - args = MagicLinkWithUserArgs() - args.user_id = user_id - args.channel = magic_link_attrs_dict.get("channel") or MagicLinkChannel.EMAIL - else: - msg = "Could not create a magic link for this app: must provide one of: email, phone, userID" - raise TypeError(msg) - - args.send = magic_link_attrs_dict.get("send") or False - args.type = magic_link_attrs_dict.get("type") or MagicLinkType.LOGIN - - options = MagicLinkOptions() - options.language = magic_link_attrs_dict.get("language") - options.magic_link_path = magic_link_attrs_dict.get("magic_link_path") - options.redirect_url = magic_link_attrs_dict.get("redirect_url") - options.ttl = magic_link_attrs_dict.get("ttl") - - return self.auth.create_magic_link(args, options) # type: ignore[attr-defined] - - @typing_extensions.deprecated("Passage.getApp() will be removed without replacement.") - def getApp(self) -> AppInfo | PassageError: # noqa: N802 - """Use Passage API to get info for their app.""" - client = AppsApi() - return client.get_app(self.app_id).app - - @typing_extensions.deprecated("Passage.getUser() will be deprecated. Use Passage.user.get() instead.") - def getUser(self, user_id: str) -> PassageUser | PassageError: # noqa: N802 - """Use Passage API to get info for a user, look up by user ID.""" - return self.user.get(user_id) - - @typing_extensions.deprecated( - "Passage.getUserByIdentifier() will be deprecated. Use Passage.user.get_by_identifier() instead.", - ) - def getUserByIdentifier(self, userIdentifier: str) -> PassageUser | PassageError: # noqa: N802, N803 - """Use Passage API to get info for a user, look up by user identifier.""" - return self.user.get_by_identifier(userIdentifier) - - @typing_extensions.deprecated( - "Passage.listUserDevices() will be deprecated. Use Passage.user.list_devices() instead.", - ) - def listUserDevices( # noqa: N802 - self, - user_id: str, - ) -> list[WebAuthnDevices] | PassageError: - """Use Passage API to list user devices, look up by user ID.""" - return self.user.list_devices(user_id) - - @typing_extensions.deprecated( - "Passage.deleteUserDevice() will be deprecated. Use Passage.user.revoke_device() instead.", - ) - def deleteUserDevice( # noqa: N802 - self, - user_id: str, - device_id: str, - ) -> bool | PassageError: - """Use Passage API to revoke user devices, look up by user ID.""" - self.user.revoke_device(user_id, device_id) - return True - - @typing_extensions.deprecated( - "Passage.revokeUserDevice() will be deprecated. Use Passage.user.revoke_device() instead.", - ) - def revokeUserDevice( # noqa: N802 - self, - user_id: str, - device_id: str, - ) -> bool | PassageError: - """Use Passage API to revoke user devices, look up by user ID.""" - self.user.revoke_device(user_id, device_id) - return True - - @typing_extensions.deprecated( - "Passage.revokeUserRefreshTokens() will be deprecated. Use Passage.user.revoke_refresh_tokens() instead.", - ) - def revokeUserRefreshTokens(self, user_id: str) -> bool | PassageError: # noqa: N802 - """Use Passage API to revoke all of a user's refresh tokens, look up by user ID.""" - self.user.revoke_refresh_tokens(user_id) - return True - - @typing_extensions.deprecated( - "Passage.signOut() will be deprecated. Use Passage.user.revoke_refresh_tokens() instead.", - ) - def signOut( # noqa: N802 - self, - user_id: str, - ) -> bool | PassageError: - """Use Passage API to revoke all of a user's refresh tokens, look up by user ID.""" - self.user.revoke_refresh_tokens(user_id) - return True - - @typing_extensions.deprecated("Passage.activateUser() will be deprecated. Use Passage.user.activate() instead.") - def activateUser(self, user_id: str) -> PassageUser | PassageError: # noqa: N802 - """Activate Passage User.""" - return self.user.activate(user_id) - - @typing_extensions.deprecated("Passage.deactivateUser() will be deprecated. Use Passage.user.deactivate() instead.") - def deactivateUser(self, user_id: str) -> PassageUser | PassageError: # noqa: N802 - """Deactivate Passage User.""" - return self.user.deactivate(user_id) - - @typing_extensions.deprecated("Passage.updateUser() will be deprecated. Use Passage.user.update() instead.") - def updateUser( # noqa: N802 - self, - user_id: str, - attributes: UpdateUserArgs, - ) -> PassageUser | PassageError: - """Update Passage User.""" - return self.user.update(user_id, attributes) - - @typing_extensions.deprecated("Passage.deleteUser() will be deprecated. Use Passage.user.delete() instead.") - def deleteUser(self, user_id: str) -> bool | PassageError: # noqa: N802 - """Delete Passage User.""" - self.user.delete(user_id) - return True - - @typing_extensions.deprecated("Passage.createUser() will be deprecated. Use Passage.user.create() instead.") - def createUser( # noqa: N802 - self, - userAttributes: CreateUserArgs, # noqa: N803 - ) -> PassageUser | PassageError: - """Create Passage User.""" - if not ("phone" in userAttributes or "email" in userAttributes): # type: ignore[dict-item] - msg = "either phone or email must be provided to create the user" - raise PassageError(msg) - - user_args = ( - cast(CreateUserArgs, CreateUserArgs.from_dict(userAttributes)) - if isinstance(userAttributes, dict) - else userAttributes - ) - - return self.user.create(user_args) From 975f3ea334b5bca11e318f0fac458ea622aea014 Mon Sep 17 00:00:00 2001 From: Chris Tran Date: Mon, 23 Dec 2024 14:46:51 -0600 Subject: [PATCH 2/5] test: remove tests for deprecated code --- tests/auth_test.py | 66 ------------------ tests/user_test.py | 166 --------------------------------------------- 2 files changed, 232 deletions(-) delete mode 100644 tests/auth_test.py delete mode 100644 tests/user_test.py diff --git a/tests/auth_test.py b/tests/auth_test.py deleted file mode 100644 index 65ac8b3..0000000 --- a/tests/auth_test.py +++ /dev/null @@ -1,66 +0,0 @@ -import os -from typing import cast - -import pytest -from dotenv import load_dotenv -from faker import Faker - -from passageidentity import MagicLink, Passage, PassageError -from passageidentity.openapi_client.models.app_info import AppInfo - -load_dotenv() -f = Faker() - -PASSAGE_USER_ID = os.environ.get("PASSAGE_USER_ID") or "" -PASSAGE_APP_ID = os.environ.get("PASSAGE_APP_ID") or "" -PASSAGE_API_KEY = os.environ.get("PASSAGE_API_KEY") or "" -PASSAGE_AUTH_TOKEN = os.environ.get("PASSAGE_AUTH_TOKEN") or "" - - -def test_valid_jwt() -> None: - psg = Passage(PASSAGE_APP_ID, auth_strategy=Passage.HEADER_AUTH) - user = psg.authenticateJWT(PASSAGE_AUTH_TOKEN) - assert user == PASSAGE_USER_ID - - -def test_invalid_jwt() -> None: - psg = Passage(PASSAGE_APP_ID, auth_strategy=Passage.HEADER_AUTH) - with pytest.raises(PassageError): - psg.authenticateJWT("invalid_token") - - -def test_validate_jwt() -> None: - psg = Passage(PASSAGE_APP_ID, auth_strategy=Passage.HEADER_AUTH) - user = psg.validateJwt(PASSAGE_AUTH_TOKEN) - assert user == PASSAGE_USER_ID - - -def test_get_app() -> None: - psg = Passage(PASSAGE_APP_ID, PASSAGE_API_KEY) - app = cast(AppInfo, psg.getApp()) - assert app.id == PASSAGE_APP_ID - - -def test_create_magic_link() -> None: - psg = Passage(PASSAGE_APP_ID, PASSAGE_API_KEY) - magic_link = cast( - MagicLink, - psg.createMagicLink( - { - "email": "chris@passage.id", - "channel": "email", - "ttl": 12, - }, # type: ignore[arg-type] - ), - ) - assert magic_link.identifier == "chris@passage.id" - assert magic_link.ttl == 12 - - -def test_smart_link_valid() -> None: - psg = Passage(PASSAGE_APP_ID, PASSAGE_API_KEY) - - email = f.email() - magic_link = cast(MagicLink, psg.createMagicLink({"email": email})) # type: ignore[arg-type] - assert magic_link.identifier == email - assert not magic_link.activated diff --git a/tests/user_test.py b/tests/user_test.py deleted file mode 100644 index d0a29b4..0000000 --- a/tests/user_test.py +++ /dev/null @@ -1,166 +0,0 @@ -import os -from typing import cast - -import pytest -from dotenv import load_dotenv -from faker import Faker - -from passageidentity import Passage, PassageError, PassageUser, UpdateUserArgs - -load_dotenv() -f = Faker() - -PASSAGE_USER_ID = os.environ.get("PASSAGE_USER_ID") or "" -PASSAGE_APP_ID = os.environ.get("PASSAGE_APP_ID") or "" -PASSAGE_API_KEY = os.environ.get("PASSAGE_API_KEY") or "" -PASSAGE_AUTH_TOKEN = os.environ.get("PASSAGE_AUTH_TOKEN") or "" - - -def test_get_by_identifier_valid_upper_case() -> None: - psg = Passage(PASSAGE_APP_ID, PASSAGE_API_KEY) - - email = f.email() - new_user = cast(PassageUser, psg.createUser({"email": email})) # type: ignore[arg-type] - assert new_user.email == email - - user_by_identifier = cast(PassageUser, psg.getUserByIdentifier(email.upper())) - assert user_by_identifier.id == new_user.id - - user = cast(PassageUser, psg.user.get(new_user.id)) - assert user.id == new_user.id - - assert user_by_identifier == user - assert psg.user.delete(new_user.id) is None - - -def test_get_by_identifier_user_not_exist() -> None: - psg = Passage(PASSAGE_APP_ID, PASSAGE_API_KEY) - - with pytest.raises(PassageError, match="User not found."): - psg.user.get_by_identifier("error@passage.id") - - -def test_get_user_info_valid() -> None: - psg = Passage(PASSAGE_APP_ID, PASSAGE_API_KEY) - user = cast(PassageUser, psg.getUser(PASSAGE_USER_ID)) - assert user.id == PASSAGE_USER_ID - - -def test_get_user_info_by_identifier_valid() -> None: - psg = Passage(PASSAGE_APP_ID, PASSAGE_API_KEY) - - email = f.email() - new_user = cast(PassageUser, psg.createUser({"email": email})) # type: ignore[arg-type] - assert new_user.email == email - - user_by_identifier = cast(PassageUser, psg.getUserByIdentifier(email)) - assert user_by_identifier.id == new_user.id - - user = cast(PassageUser, psg.getUser(new_user.id)) - assert user.id == new_user.id - - assert user_by_identifier == user - assert psg.deleteUser(new_user.id) - - -def test_get_user_info_by_identifier_phone_valid() -> None: - psg = Passage(PASSAGE_APP_ID, PASSAGE_API_KEY) - - phone = "+15005550030" - new_user = cast(PassageUser, psg.createUser({"phone": phone})) # type: ignore[arg-type] - assert new_user.phone == phone - - user_by_identifier = cast(PassageUser, psg.getUserByIdentifier(phone)) - assert user_by_identifier.id == new_user.id - - user = cast(PassageUser, psg.getUser(new_user.id)) - assert user.id == new_user.id - - assert user_by_identifier == user - assert psg.deleteUser(new_user.id) - - -def test_activate_user() -> None: - psg = Passage(PASSAGE_APP_ID, PASSAGE_API_KEY) - user = cast(PassageUser, psg.activateUser(PASSAGE_USER_ID)) - assert user.status == "active" - - -def test_deactivate_user() -> None: - psg = Passage(PASSAGE_APP_ID, PASSAGE_API_KEY) - - user = cast(PassageUser, psg.getUser(PASSAGE_USER_ID)) - user = cast(PassageUser, psg.deactivateUser(user.id)) - assert user.status == "inactive" - - -def test_list_user_devices() -> None: - psg = Passage(PASSAGE_APP_ID, PASSAGE_API_KEY) - - devices = cast(list, psg.listUserDevices(PASSAGE_USER_ID)) - assert len(devices) == 2 - - -def test_update_user_phone() -> None: - psg = Passage(PASSAGE_APP_ID, PASSAGE_API_KEY) - - phone = "+15005550021" - new_user = cast(PassageUser, psg.createUser({"phone": phone})) # type: ignore[arg-type] - - phone = "+15005550022" - user = cast(PassageUser, psg.updateUser(new_user.id, {"phone": phone})) # type: ignore[arg-type] - assert user.phone == phone - assert psg.deleteUser(new_user.id) - - -def test_update_user_email() -> None: - psg = Passage(PASSAGE_APP_ID, PASSAGE_API_KEY) - - email = f.email() - req = UpdateUserArgs(email=email) - user = cast(PassageUser, psg.updateUser(PASSAGE_USER_ID, req)) - assert user.email == email - - -def test_update_user_with_metadata() -> None: - psg = Passage(PASSAGE_APP_ID, PASSAGE_API_KEY) - - email = f.email() - user = cast(PassageUser, psg.updateUser(PASSAGE_USER_ID, {"email": email, "user_metadata": {"example1": "qwe"}})) # type: ignore[arg-type] - assert user.email == email - assert user.user_metadata["example1"] == "qwe" # type: ignore[index] - - user = cast(PassageUser, psg.updateUser(PASSAGE_USER_ID, {"email": email, "user_metadata": {"example1": "asd"}})) # type: ignore[arg-type] - assert user.email == email - assert user.user_metadata["example1"] == "asd" # type: ignore[index] - - -def test_create_user_with_metadata() -> None: - psg = Passage(PASSAGE_APP_ID, PASSAGE_API_KEY) - - email = f.email() - user = cast(PassageUser, psg.createUser({"email": email, "user_metadata": {"example1": "qwe"}})) # type: ignore[arg-type] - assert user.email == email - assert user.user_metadata["example1"] == "qwe" # type: ignore[index] - assert psg.deleteUser(user.id) - - -def test_create_and_delete_user() -> None: - psg = Passage(PASSAGE_APP_ID, PASSAGE_API_KEY) - - email = f.email() - new_user = cast(PassageUser, psg.createUser({"email": email})) # type: ignore[arg-type] - assert new_user.email == email - assert psg.deleteUser(new_user.id) - - -def test_sign_out() -> None: - psg = Passage(PASSAGE_APP_ID, PASSAGE_API_KEY) - - assert psg.signOut(PASSAGE_USER_ID) - - -def test_revoke_user_refresh_tokens() -> None: - psg = Passage(PASSAGE_APP_ID, PASSAGE_API_KEY) - - assert psg.revokeUserRefreshTokens(PASSAGE_USER_ID) From f0af626d5c08e159dcbdd27db133162b18faf639 Mon Sep 17 00:00:00 2001 From: Chris Tran Date: Mon, 23 Dec 2024 14:47:44 -0600 Subject: [PATCH 3/5] feat!: removes deprecated models --- .../models/update_magic_link_auth_method.py | 95 ------------------- .../models/update_otp_auth_method.py | 95 ------------------- .../models/update_passkey_auth_method.py | 84 ---------------- 3 files changed, 274 deletions(-) delete mode 100644 passageidentity/models/update_magic_link_auth_method.py delete mode 100644 passageidentity/models/update_otp_auth_method.py delete mode 100644 passageidentity/models/update_passkey_auth_method.py diff --git a/passageidentity/models/update_magic_link_auth_method.py b/passageidentity/models/update_magic_link_auth_method.py deleted file mode 100644 index a365fa0..0000000 --- a/passageidentity/models/update_magic_link_auth_method.py +++ /dev/null @@ -1,95 +0,0 @@ -# coding: utf-8 - -""" -Passage Management API - -Passage's management API to manage your Passage apps and users. - -The version of the OpenAPI document: 1 -Contact: support@passage.id -Generated by OpenAPI Generator (https://openapi-generator.tech) - -Do not edit the class manually. -""" # noqa: E501 - -from __future__ import annotations -import pprint -import re # noqa: F401 -import json - - -from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictBool -from pydantic import Field -from typing_extensions import Annotated -from passageidentity.openapi_client.models.ttl_display_unit import TtlDisplayUnit - -try: - from typing import Self -except ImportError: - from typing_extensions import Self - - -@DeprecationWarning -class UpdateMagicLinkAuthMethod(BaseModel): - """ - UpdateMagicLinkAuthMethod - """ # noqa: E501 - - enabled: Optional[StrictBool] = None - ttl: Optional[Annotated[int, Field(strict=True, ge=60)]] = Field( - default=300, description="Maximum time (IN SECONDS) for the auth to expire." - ) - ttl_display_unit: Optional[TtlDisplayUnit] = None - __properties: ClassVar[List[str]] = ["enabled", "ttl", "ttl_display_unit"] - - model_config = {"populate_by_name": True, "validate_assignment": True} - - def to_str(self) -> str: - """Returns the string representation of the model using alias""" - return pprint.pformat(self.model_dump(by_alias=True)) - - def to_json(self) -> str: - """Returns the JSON representation of the model using alias""" - # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead - return json.dumps(self.to_dict()) - - @classmethod - def from_json(cls, json_str: str) -> Self: - """Create an instance of UpdateMagicLinkAuthMethod from a JSON string""" - return cls.from_dict(json.loads(json_str)) - - def to_dict(self) -> Dict[str, Any]: - """Return the dictionary representation of the model using alias. - - This has the following differences from calling pydantic's - `self.model_dump(by_alias=True)`: - - * `None` is only added to the output dict for nullable fields that - were set at model initialization. Other fields with value `None` - are ignored. - """ - _dict = self.model_dump( - by_alias=True, - exclude={}, - exclude_none=True, - ) - return _dict - - @classmethod - def from_dict(cls, obj: Dict) -> Self: - """Create an instance of UpdateMagicLinkAuthMethod from a dict""" - if obj is None: - return None - - if not isinstance(obj, dict): - return cls.model_validate(obj) - - _obj = cls.model_validate( - { - "enabled": obj.get("enabled"), - "ttl": obj.get("ttl") if obj.get("ttl") is not None else 300, - "ttl_display_unit": obj.get("ttl_display_unit"), - } - ) - return _obj \ No newline at end of file diff --git a/passageidentity/models/update_otp_auth_method.py b/passageidentity/models/update_otp_auth_method.py deleted file mode 100644 index 059f507..0000000 --- a/passageidentity/models/update_otp_auth_method.py +++ /dev/null @@ -1,95 +0,0 @@ -# coding: utf-8 - -""" -Passage Management API - -Passage's management API to manage your Passage apps and users. - -The version of the OpenAPI document: 1 -Contact: support@passage.id -Generated by OpenAPI Generator (https://openapi-generator.tech) - -Do not edit the class manually. -""" # noqa: E501 - -from __future__ import annotations -import pprint -import re # noqa: F401 -import json - - -from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictBool -from pydantic import Field -from typing_extensions import Annotated -from passageidentity.openapi_client.models.ttl_display_unit import TtlDisplayUnit - -try: - from typing import Self -except ImportError: - from typing_extensions import Self - - -@DeprecationWarning -class UpdateOtpAuthMethod(BaseModel): - """ - the UpdateOtpAuthMethod to exchange for an authentication token - """ # noqa: E501 - - enabled: Optional[StrictBool] = None - ttl: Optional[Annotated[int, Field(strict=True, ge=60)]] = Field( - default=300, description="Maximum time (IN SECONDS) for the auth to expire." - ) - ttl_display_unit: Optional[TtlDisplayUnit] = None - __properties: ClassVar[List[str]] = ["enabled", "ttl", "ttl_display_unit"] - - model_config = {"populate_by_name": True, "validate_assignment": True} - - def to_str(self) -> str: - """Returns the string representation of the model using alias""" - return pprint.pformat(self.model_dump(by_alias=True)) - - def to_json(self) -> str: - """Returns the JSON representation of the model using alias""" - # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead - return json.dumps(self.to_dict()) - - @classmethod - def from_json(cls, json_str: str) -> Self: - """Create an instance of UpdateOtpAuthMethod from a JSON string""" - return cls.from_dict(json.loads(json_str)) - - def to_dict(self) -> Dict[str, Any]: - """Return the dictionary representation of the model using alias. - - This has the following differences from calling pydantic's - `self.model_dump(by_alias=True)`: - - * `None` is only added to the output dict for nullable fields that - were set at model initialization. Other fields with value `None` - are ignored. - """ - _dict = self.model_dump( - by_alias=True, - exclude={}, - exclude_none=True, - ) - return _dict - - @classmethod - def from_dict(cls, obj: Dict) -> Self: - """Create an instance of UpdateOtpAuthMethod from a dict""" - if obj is None: - return None - - if not isinstance(obj, dict): - return cls.model_validate(obj) - - _obj = cls.model_validate( - { - "enabled": obj.get("enabled"), - "ttl": obj.get("ttl") if obj.get("ttl") is not None else 300, - "ttl_display_unit": obj.get("ttl_display_unit"), - } - ) - return _obj \ No newline at end of file diff --git a/passageidentity/models/update_passkey_auth_method.py b/passageidentity/models/update_passkey_auth_method.py deleted file mode 100644 index 4220bee..0000000 --- a/passageidentity/models/update_passkey_auth_method.py +++ /dev/null @@ -1,84 +0,0 @@ -# coding: utf-8 - -""" -Passage Management API - -Passage's management API to manage your Passage apps and users. - -The version of the OpenAPI document: 1 -Contact: support@passage.id -Generated by OpenAPI Generator (https://openapi-generator.tech) - -Do not edit the class manually. -""" # noqa: E501 - -from __future__ import annotations -import pprint -import re # noqa: F401 -import json - - -from typing import Any, ClassVar, Dict, List, Optional -from pydantic import BaseModel, StrictBool - -try: - from typing import Self -except ImportError: - from typing_extensions import Self - - -@DeprecationWarning -class UpdatePasskeysAuthMethod(BaseModel): - """ - UpdatePasskeysAuthMethod - """ # noqa: E501 - - enabled: Optional[StrictBool] = True - __properties: ClassVar[List[str]] = ["enabled"] - - model_config = {"populate_by_name": True, "validate_assignment": True} - - def to_str(self) -> str: - """Returns the string representation of the model using alias""" - return pprint.pformat(self.model_dump(by_alias=True)) - - def to_json(self) -> str: - """Returns the JSON representation of the model using alias""" - # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead - return json.dumps(self.to_dict()) - - @classmethod - def from_json(cls, json_str: str) -> Self: - """Create an instance of UpdatePasskeysAuthMethod from a JSON string""" - return cls.from_dict(json.loads(json_str)) - - def to_dict(self) -> Dict[str, Any]: - """Return the dictionary representation of the model using alias. - - This has the following differences from calling pydantic's - `self.model_dump(by_alias=True)`: - - * `None` is only added to the output dict for nullable fields that - were set at model initialization. Other fields with value `None` - are ignored. - """ - _dict = self.model_dump( - by_alias=True, - exclude={}, - exclude_none=True, - ) - return _dict - - @classmethod - def from_dict(cls, obj: Dict) -> Self: - """Create an instance of UpdatePasskeysAuthMethod from a dict""" - if obj is None: - return None - - if not isinstance(obj, dict): - return cls.model_validate(obj) - - _obj = cls.model_validate( - {"enabled": obj.get("enabled") if obj.get("enabled") is not None else True} - ) - return _obj \ No newline at end of file From 06a1b73fc9d0673c54b7bd24b3b7d537b1637342 Mon Sep 17 00:00:00 2001 From: Chris Tran Date: Mon, 23 Dec 2024 14:49:47 -0600 Subject: [PATCH 4/5] chore: removes unused helper methods --- passageidentity/helper.py | 40 ------------------------------------- passageidentity/requests.py | 24 ---------------------- 2 files changed, 64 deletions(-) diff --git a/passageidentity/helper.py b/passageidentity/helper.py index 5941cfe..ff12fa8 100644 --- a/passageidentity/helper.py +++ b/passageidentity/helper.py @@ -1,50 +1,10 @@ """Provides helper functions for interacting with the Passage Identity API.""" -import re from http import HTTPStatus -from requests.sessions import Request - from passageidentity import requests from passageidentity.errors import PassageError -BEARER_PATTERN = r"Bearer ([^\s,]+)" - - -def extract_token(auth_header: str) -> str: - """Extract the JWT from an Authorization header.""" - expression = re.escape(BEARER_PATTERN) - match = re.search(expression, auth_header) - - if match: - return match.group(1) - - msg = "No Passage authorization header." - raise PassageError(msg) - - -def get_auth_token_from_request(request: Request, auth_strategy: int) -> str: - """Get the auth token from a request. - - Checks the Authorization header first, then the psg_auth_token cookie. - """ - if auth_strategy == 2: # noqa: PLR2004 - auth_header = request.headers["Authorization"] - expression = re.escape(BEARER_PATTERN) - match = re.search(expression, auth_header) - - if match: - return match.group(1) - - msg = "No Passage authorization header." - raise PassageError(msg) - - if "psg_auth_token" not in request.cookies: - msg = "No Passage authentication token." - raise PassageError(msg) - - return request.cookies["psg_auth_token"] - def fetch_app(app_id: str) -> dict: """Fetch the public key for the given app id from Passage.""" diff --git a/passageidentity/requests.py b/passageidentity/requests.py index f1cfec9..c152440 100644 --- a/passageidentity/requests.py +++ b/passageidentity/requests.py @@ -2,7 +2,6 @@ from __future__ import annotations -import json from importlib import metadata import requests @@ -22,26 +21,3 @@ def get_headers(api_key: str | None = None) -> dict[str, str]: def get(url: str, api_key: str | None = None) -> requests.Response: """Send a GET request with API key in Authorization header if provided.""" return requests.get(url, headers=get_headers(api_key)) # noqa: S113 - - -def post(url: str, api_key: str | None = None, data: dict | None = None) -> requests.Response: - """Send a POST request with API key in Authorization header if provided, and the JSON-encoded data in the body.""" - return requests.post( # noqa: S113 - url, - headers=get_headers(api_key), - data=json.dumps(data) if data else None, - ) - - -def patch(url: str, api_key: str | None = None, data: dict | None = None) -> requests.Response: - """Send a PATCH request with API key in Authorization header if provided, and the JSON-encoded data in the body.""" - return requests.patch( # noqa: S113 - url, - headers=get_headers(api_key), - data=json.dumps(data) if data else None, - ) - - -def delete(url: str, api_key: str | None = None) -> requests.Response: - """Send a DELETE request with API key in Authorization header if provided.""" - return requests.delete(url, headers=get_headers(api_key)) # noqa: S113 From 8616475482a29537d02404abb7693960bfc9c578 Mon Sep 17 00:00:00 2001 From: Chris Tran Date: Fri, 3 Jan 2025 11:21:31 -0600 Subject: [PATCH 5/5] chore: remove deprecated models from init file --- passageidentity/models/__init__.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/passageidentity/models/__init__.py b/passageidentity/models/__init__.py index a10b24f..42f25f7 100644 --- a/passageidentity/models/__init__.py +++ b/passageidentity/models/__init__.py @@ -14,11 +14,6 @@ """ # noqa: E501 # import models into model package -from passageidentity.models.update_magic_link_auth_method import ( - UpdateMagicLinkAuthMethod, -) -from passageidentity.models.update_passkey_auth_method import UpdatePasskeysAuthMethod -from passageidentity.models.update_otp_auth_method import UpdateOtpAuthMethod from passageidentity.models.magic_link_args import ( MagicLinkArgs, MagicLinkWithEmailArgs,