From bdc25ade2931a00b12256be07c505cfa19df0bec Mon Sep 17 00:00:00 2001 From: halcy Date: Sat, 16 Aug 2025 23:17:53 +0300 Subject: [PATCH] add return type for oauth server info --- docs/02_return_values.rst | 3 + mastodon/authentication.py | 4 +- mastodon/return_types.py | 127 ++++++++++++++++++ mastodon/types_base.py | 28 ++-- srcgen/return_types.json | 24 ++-- .../test_entity_oauthserverinfo.yaml | 96 +++++++++++++ tests/test_entities.py | 17 +++ 7 files changed, 271 insertions(+), 28 deletions(-) create mode 100644 tests/cassettes_entity_tests/test_entity_oauthserverinfo.yaml diff --git a/docs/02_return_values.rst b/docs/02_return_values.rst index 08f6149..6510c20 100644 --- a/docs/02_return_values.rst +++ b/docs/02_return_values.rst @@ -383,6 +383,9 @@ Return types .. autoclass:: mastodon.return_types.SupportedLocale :members: +.. autoclass:: mastodon.return_types.OAuthServerInfo + :members: + Deprecated types ================ .. autoclass:: mastodon.return_types.Filter diff --git a/mastodon/authentication.py b/mastodon/authentication.py index a29cf23..6ed06dc 100644 --- a/mastodon/authentication.py +++ b/mastodon/authentication.py @@ -14,7 +14,7 @@ from mastodon.utility import parse_version_string, api_version from mastodon.internals import Mastodon as Internals from mastodon.utility import Mastodon as Utility from typing import List, Optional, Union, Tuple -from mastodon.return_types import Application, AttribAccessDict +from mastodon.return_types import Application, AttribAccessDict, OAuthServerInfo from mastodon.compat import PurePath class Mastodon(Internals): @@ -339,7 +339,7 @@ class Mastodon(Internals): oauth_url = oauth_info["authorization_endpoint"] + "?" + formatted_params return oauth_url - def oauth_authorization_server_info(self) -> AttribAccessDict: # TODO real type for this + def oauth_authorization_server_info(self) -> Union[OAuthServerInfo, AttribAccessDict]: """ Returns the OAuth authorization server information, including the supported grant types. This is useful to determine which authentication methods are available on the server, supported scopes, diff --git a/mastodon/return_types.py b/mastodon/return_types.py index 1678374..f55c49d 100644 --- a/mastodon/return_types.py +++ b/mastodon/return_types.py @@ -6758,6 +6758,131 @@ class SupportedLocale(AttribAccessDict): _version = "4.2.0" +class OAuthServerInfo(AttribAccessDict): + """ + Information about the OAuth authorization server. + + Example: + + .. code-block:: python + + # Returns a OAuthServerInfo object + mastodon.oauth_authorization_server_info() + + See also (Mastodon API documentation): https://docs.joinmastodon.org/methods/oauth/#authorization-server-metadata + """ + + issuer: "str" + """ + The issuer of the OAuth server. Can be used to avoid accidentally getting replies from a wrong server by comparing it against the `iss`field. Not currently used by Mastodon. + Should contain (as text): URL + + Version history: + * 4.3.0: added + """ + + authorization_endpoint: "str" + """ + The endpoint for authorization requests. + Should contain (as text): URL + + Version history: + * 4.3.0: added + """ + + token_endpoint: "str" + """ + The endpoint for token requests. + Should contain (as text): URL + + Version history: + * 4.3.0: added + """ + + revocation_endpoint: "str" + """ + The endpoint for revoking tokens. + Should contain (as text): URL + + Version history: + * 4.3.0: added + """ + + userinfo_endpoint: "str" + """ + The endpoint for retrieving OAuth user information for the logged in user. + Should contain (as text): URL + + Version history: + * 4.4.0: added + """ + + scopes_supported: "NonPaginatableList[str]" + """ + List of scopes supported by the OAuth server. + + Version history: + * 4.3.0: added + """ + + response_types_supported: "NonPaginatableList[str]" + """ + List of response types (i.e. what kind of parameters can the server get back to your callback) supported by the OAuth server. + + Version history: + * 4.3.0: added + """ + + response_modes_supported: "NonPaginatableList[str]" + """ + List of response modes (i.e. how does the server get callback parameters back to you) supported by the OAuth server. + + Version history: + * 4.3.0: added + """ + + grant_types_supported: "NonPaginatableList[str]" + """ + List of grant types (i.e. authorization methods) supported by the OAuth server. + + Version history: + * 4.3.0: added + """ + + token_endpoint_auth_methods_supported: "NonPaginatableList[str]" + """ + List of authentication methods supported by the token endpoint. + + Version history: + * 4.3.0: added + """ + + code_challenge_methods_supported: "NonPaginatableList[str]" + """ + List of code challenge methods supported by the OAuth server. + + Version history: + * 4.3.0: added + """ + + service_documentation: "Optional[str]" + """ + URL to the service documentation (e.g. the Mastodon API reference). (optional) + + Version history: + * 4.3.0: added + """ + + app_registration_endpoint: "Optional[str]" + """ + Endpoint for registering applications. (optional) + + Version history: + * 4.3.0: added + """ + + _version = "4.4.0" + ENTITY_NAME_MAP = { "Account": Account, "AccountField": AccountField, @@ -6870,6 +6995,7 @@ ENTITY_NAME_MAP = { "Appeal": Appeal, "NotificationRequest": NotificationRequest, "SupportedLocale": SupportedLocale, + "OAuthServerInfo": OAuthServerInfo, } __all__ = [ "Account", @@ -6983,5 +7109,6 @@ __all__ = [ "Appeal", "NotificationRequest", "SupportedLocale", + "OAuthServerInfo", ] diff --git a/mastodon/types_base.py b/mastodon/types_base.py index 2ee6514..2b7a75d 100644 --- a/mastodon/types_base.py +++ b/mastodon/types_base.py @@ -184,20 +184,20 @@ if sys.version_info < (3, 9): Poll, PollOption, Conversation, Tag, TagHistory, CustomEmoji, \ Application, Relationship, Filter, FilterV2, Notification, Context, \ UserList, MediaAttachment, MediaAttachmentMetadataContainer, MediaAttachmentImageMetadata, MediaAttachmentVideoMetadata, MediaAttachmentAudioMetadata, \ - MediaAttachmentFocusPoint, MediaAttachmentColors, PreviewCard, PreviewCardAuthor, Search, SearchV2, \ - Instance, InstanceConfiguration, InstanceURLs, InstanceV2, InstanceIcon, InstanceConfigurationV2, \ - InstanceVapidKey, InstanceURLsV2, InstanceThumbnail, InstanceThumbnailVersions, InstanceStatistics, InstanceUsage, \ - InstanceUsageUsers, Rule, InstanceRegistrations, InstanceContact, InstanceAccountConfiguration, InstanceStatusConfiguration, \ - InstanceTranslationConfiguration, InstanceMediaConfiguration, InstancePollConfiguration, Nodeinfo, NodeinfoSoftware, NodeinfoServices, \ - NodeinfoUsage, NodeinfoUsageUsers, NodeinfoMetadata, Activity, Report, AdminReport, \ - WebPushSubscription, WebPushSubscriptionAlerts, PushNotification, Preferences, FeaturedTag, Marker, \ - Announcement, Reaction, StreamReaction, FamiliarFollowers, AdminAccount, AdminIp, \ - AdminMeasure, AdminMeasureData, AdminDimension, AdminDimensionData, AdminRetention, AdminCohort, \ - AdminDomainBlock, AdminCanonicalEmailBlock, AdminDomainAllow, AdminEmailDomainBlock, AdminEmailDomainBlockHistory, AdminIpBlock, \ - DomainBlock, ExtendedDescription, FilterKeyword, FilterStatus, IdentityProof, StatusSource, \ - Suggestion, Translation, AccountCreationError, AccountCreationErrorDetails, AccountCreationErrorDetailsField, NotificationPolicy, \ - NotificationPolicySummary, RelationshipSeveranceEvent, GroupedNotificationsResults, PartialAccountWithAvatar, NotificationGroup, AccountWarning, \ - UnreadNotificationsCount, Appeal, TrendingLinkHistory, NotificationRequest, SupportedLocale + MediaAttachmentFocusPoint, MediaAttachmentColors, PreviewCard, TrendingLinkHistory, PreviewCardAuthor, Search, \ + SearchV2, Instance, InstanceConfiguration, InstanceURLs, InstanceV2, InstanceIcon, \ + InstanceConfigurationV2, InstanceVapidKey, InstanceURLsV2, InstanceThumbnail, InstanceThumbnailVersions, InstanceStatistics, \ + InstanceUsage, InstanceUsageUsers, Rule, InstanceRegistrations, InstanceContact, InstanceAccountConfiguration, \ + InstanceStatusConfiguration, InstanceTranslationConfiguration, InstanceMediaConfiguration, InstancePollConfiguration, Nodeinfo, NodeinfoSoftware, \ + NodeinfoServices, NodeinfoUsage, NodeinfoUsageUsers, NodeinfoMetadata, Activity, Report, \ + AdminReport, WebPushSubscription, WebPushSubscriptionAlerts, PushNotification, Preferences, FeaturedTag, \ + Marker, Announcement, Reaction, StreamReaction, FamiliarFollowers, AdminAccount, \ + AdminIp, AdminMeasure, AdminMeasureData, AdminDimension, AdminDimensionData, AdminRetention, \ + AdminCohort, AdminDomainBlock, AdminCanonicalEmailBlock, AdminDomainAllow, AdminEmailDomainBlock, AdminEmailDomainBlockHistory, \ + AdminIpBlock, DomainBlock, ExtendedDescription, FilterKeyword, FilterStatus, IdentityProof, \ + StatusSource, Suggestion, Translation, AccountCreationError, AccountCreationErrorDetails, AccountCreationErrorDetailsField, \ + NotificationPolicy, NotificationPolicySummary, RelationshipSeveranceEvent, GroupedNotificationsResults, PartialAccountWithAvatar, NotificationGroup, \ + AccountWarning, UnreadNotificationsCount, Appeal, NotificationRequest, SupportedLocale, OAuthServerInfo if isinstance(t, ForwardRef): try: t = t._evaluate(globals(), locals(), frozenset()) diff --git a/srcgen/return_types.json b/srcgen/return_types.json index 52c1503..5052c06 100644 --- a/srcgen/return_types.json +++ b/srcgen/return_types.json @@ -9991,12 +9991,12 @@ "description": "Information about the OAuth authorization server.", "fields": { "issuer": { - "description": "The issuer of the OAuth server.", + "description": "The issuer of the OAuth server. Can be used to avoid accidentally getting replies from a wrong server by comparing it against the `iss`field. Not currently used by Mastodon.", "enum": null, "version_history": [["4.3.0", "added"]], "field_type": "str", "field_subtype": null, - "field_structuretype": null, + "field_structuretype": "URL", "is_optional": false, "is_nullable": false }, @@ -10006,7 +10006,7 @@ "version_history": [["4.3.0", "added"]], "field_type": "str", "field_subtype": null, - "field_structuretype": null, + "field_structuretype": "URL", "is_optional": false, "is_nullable": false }, @@ -10016,7 +10016,7 @@ "version_history": [["4.3.0", "added"]], "field_type": "str", "field_subtype": null, - "field_structuretype": null, + "field_structuretype": "URL", "is_optional": false, "is_nullable": false }, @@ -10026,17 +10026,17 @@ "version_history": [["4.3.0", "added"]], "field_type": "str", "field_subtype": null, - "field_structuretype": null, + "field_structuretype": "URL", "is_optional": false, "is_nullable": false }, "userinfo_endpoint": { - "description": "The endpoint for retrieving user information.", + "description": "The endpoint for retrieving OAuth user information for the logged in user.", "enum": null, - "version_history": [["4.3.0", "added"]], + "version_history": [["4.4.0", "added"]], "field_type": "str", "field_subtype": null, - "field_structuretype": null, + "field_structuretype": "URL", "is_optional": false, "is_nullable": false }, @@ -10051,7 +10051,7 @@ "is_nullable": false }, "response_types_supported": { - "description": "List of response types supported by the OAuth server.", + "description": "List of response types (i.e. what kind of parameters can the server get back to your callback) supported by the OAuth server.", "enum": null, "version_history": [["4.3.0", "added"]], "field_type": "NonPaginatableList", @@ -10061,7 +10061,7 @@ "is_nullable": false }, "response_modes_supported": { - "description": "List of response modes supported by the OAuth server.", + "description": "List of response modes (i.e. how does the server get callback parameters back to you) supported by the OAuth server.", "enum": null, "version_history": [["4.3.0", "added"]], "field_type": "NonPaginatableList", @@ -10071,7 +10071,7 @@ "is_nullable": false }, "grant_types_supported": { - "description": "List of grant types supported by the OAuth server.", + "description": "List of grant types (i.e. authorization methods) supported by the OAuth server.", "enum": null, "version_history": [["4.3.0", "added"]], "field_type": "NonPaginatableList", @@ -10101,7 +10101,7 @@ "is_nullable": false }, "service_documentation": { - "description": "URL to the service documentation.", + "description": "URL to the service documentation (e.g. the Mastodon API reference).", "enum": null, "version_history": [["4.3.0", "added"]], "field_type": "str", diff --git a/tests/cassettes_entity_tests/test_entity_oauthserverinfo.yaml b/tests/cassettes_entity_tests/test_entity_oauthserverinfo.yaml new file mode 100644 index 0000000..31356c1 --- /dev/null +++ b/tests/cassettes_entity_tests/test_entity_oauthserverinfo.yaml @@ -0,0 +1,96 @@ +interactions: +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate, br + Authorization: + - DUMMY + Connection: + - keep-alive + User-Agent: + - mastodonpy + method: GET + uri: https://mastodon.social/.well-known/oauth-authorization-server + response: + body: + string: '{"issuer": "https://mastodon.social/", "authorization_endpoint": "https://mastodon.social/oauth/authorize", + "token_endpoint": "https://mastodon.social/oauth/token", "revocation_endpoint": + "https://mastodon.social/oauth/revoke", "userinfo_endpoint": "https://mastodon.social/oauth/userinfo", + "scopes_supported": ["read", "profile", "write", "write:accounts", "write:blocks", + "write:bookmarks", "write:conversations", "write:favourites", "write:filters", + "write:follows", "write:lists", "write:media", "write:mutes", "write:notifications", + "write:reports", "write:statuses", "read:accounts", "read:blocks", "read:bookmarks", + "read:favourites", "read:filters", "read:follows", "read:lists", "read:mutes", + "read:notifications", "read:search", "read:statuses", "follow", "push", "admin:read", + "admin:read:accounts", "admin:read:reports", "admin:read:domain_allows", "admin:read:domain_blocks", + "admin:read:ip_blocks", "admin:read:email_domain_blocks", "admin:read:canonical_email_blocks", + "admin:write", "admin:write:accounts", "admin:write:reports", "admin:write:domain_allows", + "admin:write:domain_blocks", "admin:write:ip_blocks", "admin:write:email_domain_blocks", + "admin:write:canonical_email_blocks"], "response_types_supported": ["code"], + "response_modes_supported": ["query", "fragment", "form_post"], "grant_types_supported": + ["authorization_code", "client_credentials"], "token_endpoint_auth_methods_supported": + ["client_secret_basic", "client_secret_post"], "code_challenge_methods_supported": + ["S256"], "service_documentation": "https://docs.joinmastodon.org/", "app_registration_endpoint": + "https://mastodon.social/api/v1/apps"}' + headers: + Connection: + - keep-alive + Date: + - Sat, 16 Aug 2025 20:12:23 GMT + Strict-Transport-Security: + - max-age=31557600 + Vary: + - Origin, Accept-Encoding + X-Cache: + - MISS, MISS, MISS + X-Cache-Hits: + - 0, 0, 0 + X-Served-By: + - cache-fra-eddf8230103-FRA, cache-fra-eddf8230103-FRA, cache-hel1410030-HEL + X-Timer: + - S1755375143.228865,VS0,VE83 + accept-ranges: + - none + alt-svc: + - h3=":443";ma=86400,h3-29=":443";ma=86400,h3-27=":443";ma=86400 + cache-control: + - max-age=0, private, must-revalidate + content-length: + - '1563' + content-security-policy: + - 'base-uri ''none''; default-src ''none''; frame-ancestors ''none''; font-src + ''self'' https://mastodon.social; img-src ''self'' data: blob: https://mastodon.social + https://files.mastodon.social; media-src ''self'' data: https://mastodon.social + https://files.mastodon.social; manifest-src ''self'' https://mastodon.social; + form-action ''self''; child-src ''self'' blob: https://mastodon.social; worker-src + ''self'' blob: https://mastodon.social; connect-src ''self'' data: blob: https://mastodon.social + https://files.mastodon.social wss://streaming.mastodon.social; script-src + ''self'' https://mastodon.social ''wasm-unsafe-eval''; frame-src ''self'' + https:; style-src ''self'' https://mastodon.social ''nonce-5yH82vADHKjnBUGAG/8YpQ==''' + content-type: + - application/json; charset=utf-8 + etag: + - W/"6039ea331b50e2b000b155f90aaead96" + referrer-policy: + - same-origin + transfer-encoding: + - chunked + via: + - 1.1 varnish, 1.1 varnish, 1.1 varnish + x-content-type-options: + - nosniff + x-frame-options: + - DENY + x-request-id: + - 8bc5e34e596581252d2d294d61a929c5 + x-runtime: + - '0.005838' + x-xss-protection: + - '0' + status: + code: 200 + message: OK +version: 1 diff --git a/tests/test_entities.py b/tests/test_entities.py index 4b0ecc9..1d2293a 100644 --- a/tests/test_entities.py +++ b/tests/test_entities.py @@ -1731,3 +1731,20 @@ def test_entity_supportedlocale(mastodon_base, mastodon_admin): if sys.version_info >= (3, 9): assert real_issubclass(type(result), SupportedLocale), str(type(result)) + ' is not a subclass of SupportedLocale after to_json/from_json' +@pytest.mark.vcr( + filter_query_parameters=[('access_token', 'DUMMY'), ('client_id', 'DUMMY'), ('client_secret', 'DUMMY')], + filter_post_data_parameters=[('access_token', 'DUMMY'), ('client_id', 'DUMMY'), ('client_secret', 'DUMMY')], + filter_headers=[('Authorization', 'DUMMY')], + before_record_request=vcr_filter, + before_record_response=token_scrubber, + match_on=['method', 'uri'], + cassette_library_dir='tests/cassettes_entity_tests' +) +def test_entity_oauthserverinfo(mastodon_base, mastodon_admin): + mastodon = mastodon_base + result = mastodon.oauth_authorization_server_info() + assert real_issubclass(type(result), OAuthServerInfo), str(type(result)) + ' is not a subclass of OAuthServerInfo' + result = Entity.from_json(result.to_json()) + if sys.version_info >= (3, 9): + assert real_issubclass(type(result), OAuthServerInfo), str(type(result)) + ' is not a subclass of OAuthServerInfo after to_json/from_json' +