internetdata 2.7.5__tar.gz → 2.8.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. {internetdata-2.7.5 → internetdata-2.8.0}/PKG-INFO +1 -1
  2. {internetdata-2.7.5 → internetdata-2.8.0}/spec/openapi.yaml +132 -9
  3. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/__init__.py +1 -1
  4. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/api/authorization/oauth_authorize.py +20 -10
  5. internetdata-2.8.0/src/internetdata/_generated/api/authorization/oauth_register.py +246 -0
  6. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/models/__init__.py +4 -0
  7. internetdata-2.8.0/src/internetdata/_generated/models/client_registration.py +126 -0
  8. internetdata-2.8.0/src/internetdata/_generated/models/client_registration_request.py +104 -0
  9. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/models/oauth_metadata.py +10 -0
  10. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/models/token_response.py +2 -1
  11. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/models.py +2 -0
  12. {internetdata-2.7.5 → internetdata-2.8.0}/.gitignore +0 -0
  13. {internetdata-2.7.5 → internetdata-2.8.0}/LICENSE +0 -0
  14. {internetdata-2.7.5 → internetdata-2.8.0}/README.md +0 -0
  15. {internetdata-2.7.5 → internetdata-2.8.0}/pyproject.toml +0 -0
  16. {internetdata-2.7.5 → internetdata-2.8.0}/scripts/download-spec.sh +0 -0
  17. {internetdata-2.7.5 → internetdata-2.8.0}/scripts/generate.sh +0 -0
  18. {internetdata-2.7.5 → internetdata-2.8.0}/scripts/publish.sh +0 -0
  19. {internetdata-2.7.5 → internetdata-2.8.0}/scripts/v2_subset.py +0 -0
  20. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_core.py +0 -0
  21. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/__init__.py +0 -0
  22. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/api/__init__.py +0 -0
  23. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/api/account/__init__.py +0 -0
  24. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/api/account/account_identity.py +0 -0
  25. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/api/api_keys/__init__.py +0 -0
  26. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/api/api_keys/account_create_apikey.py +0 -0
  27. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/api/api_keys/account_list_apikeys.py +0 -0
  28. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/api/api_keys/account_reveal_apikey.py +0 -0
  29. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/api/api_keys/account_revoke_apikey.py +0 -0
  30. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/api/api_keys/account_rotate_apikey.py +0 -0
  31. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/api/authorization/__init__.py +0 -0
  32. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/api/authorization/oauth_device_authorization.py +0 -0
  33. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/api/authorization/oauth_metadata.py +0 -0
  34. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/api/authorization/oauth_revoke.py +0 -0
  35. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/api/authorization/oauth_token.py +0 -0
  36. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/api/database_v_2/__init__.py +0 -0
  37. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/api/database_v_2/database_checksum_v2.py +0 -0
  38. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/api/database_v_2/database_metadata_v2.py +0 -0
  39. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/api/database_v_2/download_database_v2.py +0 -0
  40. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/api/database_v_2/list_databases.py +0 -0
  41. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/api/database_v_2/list_downloads.py +0 -0
  42. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/api/organization/__init__.py +0 -0
  43. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/api/organization/account_org.py +0 -0
  44. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/api/organization/account_org_members.py +0 -0
  45. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/client.py +0 -0
  46. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/errors.py +0 -0
  47. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/models/account_create_apikey_request.py +0 -0
  48. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/models/account_created_apikey.py +0 -0
  49. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/models/account_org.py +0 -0
  50. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/models/account_org_ref.py +0 -0
  51. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/models/account_org_wrap.py +0 -0
  52. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/models/account_rc.py +0 -0
  53. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/models/account_revealed_apikey.py +0 -0
  54. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/models/account_user.py +0 -0
  55. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/models/apikey_detail.py +0 -0
  56. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/models/apikey_list.py +0 -0
  57. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/models/database.py +0 -0
  58. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/models/database_checksum_v2_response_200.py +0 -0
  59. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/models/database_format.py +0 -0
  60. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/models/database_license_type_type_1.py +0 -0
  61. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/models/database_license_type_type_2_type_1.py +0 -0
  62. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/models/database_license_type_type_3_type_1.py +0 -0
  63. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/models/database_metadata.py +0 -0
  64. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/models/database_metadata_column.py +0 -0
  65. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/models/database_metadata_sample.py +0 -0
  66. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/models/database_metadata_sample_additional_property_item.py +0 -0
  67. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/models/database_metadata_sample_size.py +0 -0
  68. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/models/database_metadata_schema.py +0 -0
  69. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/models/database_metadata_size.py +0 -0
  70. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/models/database_version.py +0 -0
  71. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/models/db_checksums.py +0 -0
  72. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/models/device_authorization.py +0 -0
  73. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/models/device_authorization_request.py +0 -0
  74. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/models/download.py +0 -0
  75. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/models/download_outcome.py +0 -0
  76. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/models/error.py +0 -0
  77. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/models/identity.py +0 -0
  78. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/models/list_databases_response_200.py +0 -0
  79. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/models/list_downloads_response_200.py +0 -0
  80. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/models/oauth_authorize_code_challenge_method.py +0 -0
  81. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/models/oauth_authorize_response_type.py +0 -0
  82. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/models/oauth_error.py +0 -0
  83. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/models/oauth_revoke_response_200.py +0 -0
  84. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/models/revoke_request.py +0 -0
  85. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/models/standing.py +0 -0
  86. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/models/token_request.py +0 -0
  87. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/_generated/types.py +0 -0
  88. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/aio.py +0 -0
  89. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/client.py +0 -0
  90. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/errors.py +0 -0
  91. {internetdata-2.7.5 → internetdata-2.8.0}/src/internetdata/py.typed +0 -0
  92. {internetdata-2.7.5 → internetdata-2.8.0}/testdata/testdata.json +0 -0
  93. {internetdata-2.7.5 → internetdata-2.8.0}/tests/conftest.py +0 -0
  94. {internetdata-2.7.5 → internetdata-2.8.0}/tests/helpers.py +0 -0
  95. {internetdata-2.7.5 → internetdata-2.8.0}/tests/test_client.py +0 -0
  96. {internetdata-2.7.5 → internetdata-2.8.0}/tests/test_conformance.py +0 -0
  97. {internetdata-2.7.5 → internetdata-2.8.0}/tests/test_download.py +0 -0
  98. {internetdata-2.7.5 → internetdata-2.8.0}/tests/test_oauth.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: internetdata
3
- Version: 2.7.5
3
+ Version: 2.8.0
4
4
  Summary: Official Python client library for the InternetData API. Download and verify licensed IP datasets.
5
5
  Project-URL: Homepage, https://internetdata.io
6
6
  Project-URL: Documentation, https://docs.internetdata.io
@@ -12,7 +12,7 @@ info:
12
12
  email: support@internetdata.io
13
13
  url: https://internetdata.io
14
14
  termsOfService: https://internetdata.io/terms
15
- version: 2026.10.15
15
+ version: 2026.10.16
16
16
  servers:
17
17
  - url: https://internetdata.io
18
18
  tags:
@@ -653,6 +653,56 @@ paths:
653
653
  application/json:
654
654
  schema:
655
655
  $ref: '#/components/schemas/OauthError'
656
+ /oauth/register:
657
+ post:
658
+ operationId: oauthRegister
659
+ tags:
660
+ - Authorization
661
+ summary: Register
662
+ description: |
663
+ RFC 7591 dynamic client registration, for a client that cannot use a
664
+ Client ID Metadata Document. Post your client's metadata as JSON, then
665
+ use the `client_id` in the answer at `/oauth/authorize` and
666
+ `/oauth/token`. Nothing is kept until a person approves your client, so
667
+ registering again costs nothing and leaves nothing to clean up.
668
+
669
+ Each redirect URI must be https on a public host name, or http on a
670
+ loopback address (`127.0.0.1`, `[::1]`, `localhost`), which then
671
+ matches on any port. A custom URI scheme is refused: use a loopback
672
+ redirect instead. So is a host on one of our own domains.
673
+
674
+ `client_name` is shown to the person as your client's own claim, with
675
+ where its redirect goes beside it. A name that renders blank, or mixes
676
+ Latin letters with Cyrillic or Greek ones, is shown as an unnamed
677
+ application.
678
+
679
+ The client is public whatever you ask for: `token_endpoint_auth_method`
680
+ comes back `none`, there is no client secret, and every authorization
681
+ proves itself with PKCE. It may be granted `apikeys.use` at most.
682
+ security: []
683
+ requestBody:
684
+ required: true
685
+ content:
686
+ application/json:
687
+ schema:
688
+ $ref: '#/components/schemas/ClientRegistrationRequest'
689
+ responses:
690
+ '201':
691
+ description: The client, as registered.
692
+ content:
693
+ application/json:
694
+ schema:
695
+ $ref: '#/components/schemas/ClientRegistration'
696
+ '400':
697
+ description: |
698
+ `invalid_redirect_uri` names the redirect URI refused and why, and
699
+ `invalid_client_metadata` anything else, such as a client that
700
+ does not use the authorization code flow. `slow_down` means this
701
+ address registered too many clients in the last minute.
702
+ content:
703
+ application/json:
704
+ schema:
705
+ $ref: '#/components/schemas/OauthError'
656
706
  /oauth/authorize:
657
707
  get:
658
708
  operationId: oauthAuthorize
@@ -669,13 +719,18 @@ paths:
669
719
  with `token_endpoint_auth_method` `none` and your `redirect_uris`. An
670
720
  https redirect URI must be on the same origin as the `client_id`; a
671
721
  loopback one (`http://127.0.0.1`, `http://[::1]`, `http://localhost`)
672
- matches on any port. Such a client is granted `apikeys.use` at most.
722
+ matches on any port. Such a client is granted `apikeys.use` at most. A
723
+ client registered at `/oauth/register` uses the `client_id` it was
724
+ given and one of the `redirect_uris` it registered.
673
725
 
674
726
  An unknown `client_id` or an unregistered `redirect_uri` is shown to the
675
- USER and never redirected, because sending an error to an address we
676
- have not verified belongs to you is how an open redirector works.
677
- Everything else comes back to your `redirect_uri` with `error`, your
678
- `state`, and `iss`.
727
+ person and never redirected, because sending an error to an address we
728
+ have not verified belongs to you is how an open redirector works. Any
729
+ other error in the request is shown to the person too: anyone can make a
730
+ client, so its `redirect_uri` is verified only as its own (RFC 9700
731
+ section 4.11.2). Only the person's answer comes back to your
732
+ `redirect_uri`: a `code`, or `error` `access_denied`, each with your
733
+ `state` and `iss`.
679
734
  security: []
680
735
  parameters:
681
736
  - name: client_id
@@ -731,9 +786,9 @@ paths:
731
786
  given that server.
732
787
  responses:
733
788
  '302':
734
- description: A redirect to the consent screen, or back to your redirect_uri with an error.
789
+ description: A redirect to the consent screen.
735
790
  '400':
736
- description: Shown to the user. An unverified redirect target is never sent an error.
791
+ description: Shown to the person. No error in the request is sent to your redirect_uri.
737
792
  '429':
738
793
  description: Shown to the user. Too many authorizations from one address.
739
794
  /oauth/token:
@@ -1485,6 +1540,9 @@ components:
1485
1540
  client_id_metadata_document_supported:
1486
1541
  type: boolean
1487
1542
  description: Any client may sign in with an https `client_id` serving its own metadata.
1543
+ registration_endpoint:
1544
+ type: string
1545
+ description: RFC 7591 dynamic client registration, for a client that cannot serve its own metadata.
1488
1546
  token_endpoint_auth_methods_supported:
1489
1547
  type: array
1490
1548
  items:
@@ -1600,7 +1658,8 @@ components:
1600
1658
  type: string
1601
1659
  description: |
1602
1660
  Not part of OAuth, and only for our own clients: a client that signed
1603
- in with a Client ID Metadata Document never receives a key. The API
1661
+ in with a Client ID Metadata Document or registered itself never
1662
+ receives a key. The API
1604
1663
  key itself, so a device ends up holding an ordinary key. Returned by
1605
1664
  the device code and authorization code grants only, never by a
1606
1665
  refresh, and only alongside
@@ -1611,6 +1670,70 @@ components:
1611
1670
  - access_token
1612
1671
  - token_type
1613
1672
  - expires_in
1673
+ ClientRegistrationRequest:
1674
+ type: object
1675
+ properties:
1676
+ redirect_uris:
1677
+ type: array
1678
+ items:
1679
+ type: string
1680
+ description: One to ten, each matched exactly, apart from a loopback one's port.
1681
+ client_name:
1682
+ type: string
1683
+ description: >-
1684
+ Shown to the person as your client's own claim, marked unverified, beside where its
1685
+ redirect goes.
1686
+ grant_types:
1687
+ type: array
1688
+ items:
1689
+ type: string
1690
+ description: Must include `authorization_code` when given.
1691
+ response_types:
1692
+ type: array
1693
+ items:
1694
+ type: string
1695
+ description: Must include `code` when given.
1696
+ token_endpoint_auth_method:
1697
+ type: string
1698
+ description: Read as `none`, whatever is sent.
1699
+ required:
1700
+ - redirect_uris
1701
+ ClientRegistration:
1702
+ type: object
1703
+ properties:
1704
+ client_id:
1705
+ type: string
1706
+ client_id_issued_at:
1707
+ type: integer
1708
+ description: Unix seconds.
1709
+ client_name:
1710
+ type: string
1711
+ description: As the person will see it.
1712
+ redirect_uris:
1713
+ type: array
1714
+ items:
1715
+ type: string
1716
+ grant_types:
1717
+ type: array
1718
+ items:
1719
+ type: string
1720
+ description: '`authorization_code` and `refresh_token`.'
1721
+ response_types:
1722
+ type: array
1723
+ items:
1724
+ type: string
1725
+ token_endpoint_auth_method:
1726
+ type: string
1727
+ description: Always `none`.
1728
+ scope:
1729
+ type: string
1730
+ description: 'The most this client may be granted: `apikeys.use`.'
1731
+ required:
1732
+ - client_id
1733
+ - client_id_issued_at
1734
+ - client_name
1735
+ - redirect_uris
1736
+ - token_endpoint_auth_method
1614
1737
  RevokeRequest:
1615
1738
  type: object
1616
1739
  properties:
@@ -39,7 +39,7 @@ from .models import (
39
39
  TokenResponse,
40
40
  )
41
41
 
42
- __version__ = "2.7.5"
42
+ __version__ = "2.8.0"
43
43
 
44
44
  __all__ = [
45
45
  "DATABASE_FORMATS",
@@ -105,13 +105,18 @@ def sync_detailed(
105
105
  with `token_endpoint_auth_method` `none` and your `redirect_uris`. An
106
106
  https redirect URI must be on the same origin as the `client_id`; a
107
107
  loopback one (`http://127.0.0.1`, `http://[::1]`, `http://localhost`)
108
- matches on any port. Such a client is granted `apikeys.use` at most.
108
+ matches on any port. Such a client is granted `apikeys.use` at most. A
109
+ client registered at `/oauth/register` uses the `client_id` it was
110
+ given and one of the `redirect_uris` it registered.
109
111
 
110
112
  An unknown `client_id` or an unregistered `redirect_uri` is shown to the
111
- USER and never redirected, because sending an error to an address we
112
- have not verified belongs to you is how an open redirector works.
113
- Everything else comes back to your `redirect_uri` with `error`, your
114
- `state`, and `iss`.
113
+ person and never redirected, because sending an error to an address we
114
+ have not verified belongs to you is how an open redirector works. Any
115
+ other error in the request is shown to the person too: anyone can make a
116
+ client, so its `redirect_uri` is verified only as its own (RFC 9700
117
+ section 4.11.2). Only the person's answer comes back to your
118
+ `redirect_uri`: a `code`, or `error` `access_denied`, each with your
119
+ `state` and `iss`.
115
120
 
116
121
  Args:
117
122
  client_id (str):
@@ -172,13 +177,18 @@ async def asyncio_detailed(
172
177
  with `token_endpoint_auth_method` `none` and your `redirect_uris`. An
173
178
  https redirect URI must be on the same origin as the `client_id`; a
174
179
  loopback one (`http://127.0.0.1`, `http://[::1]`, `http://localhost`)
175
- matches on any port. Such a client is granted `apikeys.use` at most.
180
+ matches on any port. Such a client is granted `apikeys.use` at most. A
181
+ client registered at `/oauth/register` uses the `client_id` it was
182
+ given and one of the `redirect_uris` it registered.
176
183
 
177
184
  An unknown `client_id` or an unregistered `redirect_uri` is shown to the
178
- USER and never redirected, because sending an error to an address we
179
- have not verified belongs to you is how an open redirector works.
180
- Everything else comes back to your `redirect_uri` with `error`, your
181
- `state`, and `iss`.
185
+ person and never redirected, because sending an error to an address we
186
+ have not verified belongs to you is how an open redirector works. Any
187
+ other error in the request is shown to the person too: anyone can make a
188
+ client, so its `redirect_uri` is verified only as its own (RFC 9700
189
+ section 4.11.2). Only the person's answer comes back to your
190
+ `redirect_uri`: a `code`, or `error` `access_denied`, each with your
191
+ `state` and `iss`.
182
192
 
183
193
  Args:
184
194
  client_id (str):
@@ -0,0 +1,246 @@
1
+ from http import HTTPStatus
2
+ from typing import Any
3
+
4
+ import httpx
5
+
6
+ from ... import errors
7
+ from ...client import AuthenticatedClient, Client
8
+ from ...models.client_registration import ClientRegistration
9
+ from ...models.client_registration_request import ClientRegistrationRequest
10
+ from ...models.oauth_error import OauthError
11
+ from ...types import Response
12
+
13
+
14
+ def _get_kwargs(
15
+ *,
16
+ body: ClientRegistrationRequest,
17
+ ) -> dict[str, Any]:
18
+ headers: dict[str, Any] = {}
19
+
20
+ _kwargs: dict[str, Any] = {
21
+ "method": "post",
22
+ "url": "/oauth/register",
23
+ }
24
+
25
+ _kwargs["json"] = body.to_dict()
26
+
27
+ headers["Content-Type"] = "application/json"
28
+
29
+ _kwargs["headers"] = headers
30
+ return _kwargs
31
+
32
+
33
+ def _parse_response(
34
+ *, client: AuthenticatedClient | Client, response: httpx.Response
35
+ ) -> ClientRegistration | OauthError | None:
36
+ if response.status_code == 201:
37
+ response_201 = ClientRegistration.from_dict(response.json())
38
+
39
+ return response_201
40
+
41
+ if response.status_code == 400:
42
+ response_400 = OauthError.from_dict(response.json())
43
+
44
+ return response_400
45
+
46
+ if client.raise_on_unexpected_status:
47
+ raise errors.UnexpectedStatus(response.status_code, response.content)
48
+ else:
49
+ return None
50
+
51
+
52
+ def _build_response(
53
+ *, client: AuthenticatedClient | Client, response: httpx.Response
54
+ ) -> Response[ClientRegistration | OauthError]:
55
+ return Response(
56
+ status_code=HTTPStatus(response.status_code),
57
+ content=response.content,
58
+ headers=response.headers,
59
+ parsed=_parse_response(client=client, response=response),
60
+ )
61
+
62
+
63
+ def sync_detailed(
64
+ *,
65
+ client: AuthenticatedClient | Client,
66
+ body: ClientRegistrationRequest,
67
+ ) -> Response[ClientRegistration | OauthError]:
68
+ """Register
69
+
70
+ RFC 7591 dynamic client registration, for a client that cannot use a
71
+ Client ID Metadata Document. Post your client's metadata as JSON, then
72
+ use the `client_id` in the answer at `/oauth/authorize` and
73
+ `/oauth/token`. Nothing is kept until a person approves your client, so
74
+ registering again costs nothing and leaves nothing to clean up.
75
+
76
+ Each redirect URI must be https on a public host name, or http on a
77
+ loopback address (`127.0.0.1`, `[::1]`, `localhost`), which then
78
+ matches on any port. A custom URI scheme is refused: use a loopback
79
+ redirect instead. So is a host on one of our own domains.
80
+
81
+ `client_name` is shown to the person as your client's own claim, with
82
+ where its redirect goes beside it. A name that renders blank, or mixes
83
+ Latin letters with Cyrillic or Greek ones, is shown as an unnamed
84
+ application.
85
+
86
+ The client is public whatever you ask for: `token_endpoint_auth_method`
87
+ comes back `none`, there is no client secret, and every authorization
88
+ proves itself with PKCE. It may be granted `apikeys.use` at most.
89
+
90
+ Args:
91
+ body (ClientRegistrationRequest):
92
+
93
+ Raises:
94
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
95
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
96
+
97
+ Returns:
98
+ Response[ClientRegistration | OauthError]
99
+ """
100
+
101
+ kwargs = _get_kwargs(
102
+ body=body,
103
+ )
104
+
105
+ response = client.get_httpx_client().request(
106
+ **kwargs,
107
+ )
108
+
109
+ return _build_response(client=client, response=response)
110
+
111
+
112
+ def sync(
113
+ *,
114
+ client: AuthenticatedClient | Client,
115
+ body: ClientRegistrationRequest,
116
+ ) -> ClientRegistration | OauthError | None:
117
+ """Register
118
+
119
+ RFC 7591 dynamic client registration, for a client that cannot use a
120
+ Client ID Metadata Document. Post your client's metadata as JSON, then
121
+ use the `client_id` in the answer at `/oauth/authorize` and
122
+ `/oauth/token`. Nothing is kept until a person approves your client, so
123
+ registering again costs nothing and leaves nothing to clean up.
124
+
125
+ Each redirect URI must be https on a public host name, or http on a
126
+ loopback address (`127.0.0.1`, `[::1]`, `localhost`), which then
127
+ matches on any port. A custom URI scheme is refused: use a loopback
128
+ redirect instead. So is a host on one of our own domains.
129
+
130
+ `client_name` is shown to the person as your client's own claim, with
131
+ where its redirect goes beside it. A name that renders blank, or mixes
132
+ Latin letters with Cyrillic or Greek ones, is shown as an unnamed
133
+ application.
134
+
135
+ The client is public whatever you ask for: `token_endpoint_auth_method`
136
+ comes back `none`, there is no client secret, and every authorization
137
+ proves itself with PKCE. It may be granted `apikeys.use` at most.
138
+
139
+ Args:
140
+ body (ClientRegistrationRequest):
141
+
142
+ Raises:
143
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
144
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
145
+
146
+ Returns:
147
+ ClientRegistration | OauthError
148
+ """
149
+
150
+ return sync_detailed(
151
+ client=client,
152
+ body=body,
153
+ ).parsed
154
+
155
+
156
+ async def asyncio_detailed(
157
+ *,
158
+ client: AuthenticatedClient | Client,
159
+ body: ClientRegistrationRequest,
160
+ ) -> Response[ClientRegistration | OauthError]:
161
+ """Register
162
+
163
+ RFC 7591 dynamic client registration, for a client that cannot use a
164
+ Client ID Metadata Document. Post your client's metadata as JSON, then
165
+ use the `client_id` in the answer at `/oauth/authorize` and
166
+ `/oauth/token`. Nothing is kept until a person approves your client, so
167
+ registering again costs nothing and leaves nothing to clean up.
168
+
169
+ Each redirect URI must be https on a public host name, or http on a
170
+ loopback address (`127.0.0.1`, `[::1]`, `localhost`), which then
171
+ matches on any port. A custom URI scheme is refused: use a loopback
172
+ redirect instead. So is a host on one of our own domains.
173
+
174
+ `client_name` is shown to the person as your client's own claim, with
175
+ where its redirect goes beside it. A name that renders blank, or mixes
176
+ Latin letters with Cyrillic or Greek ones, is shown as an unnamed
177
+ application.
178
+
179
+ The client is public whatever you ask for: `token_endpoint_auth_method`
180
+ comes back `none`, there is no client secret, and every authorization
181
+ proves itself with PKCE. It may be granted `apikeys.use` at most.
182
+
183
+ Args:
184
+ body (ClientRegistrationRequest):
185
+
186
+ Raises:
187
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
188
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
189
+
190
+ Returns:
191
+ Response[ClientRegistration | OauthError]
192
+ """
193
+
194
+ kwargs = _get_kwargs(
195
+ body=body,
196
+ )
197
+
198
+ response = await client.get_async_httpx_client().request(**kwargs)
199
+
200
+ return _build_response(client=client, response=response)
201
+
202
+
203
+ async def asyncio(
204
+ *,
205
+ client: AuthenticatedClient | Client,
206
+ body: ClientRegistrationRequest,
207
+ ) -> ClientRegistration | OauthError | None:
208
+ """Register
209
+
210
+ RFC 7591 dynamic client registration, for a client that cannot use a
211
+ Client ID Metadata Document. Post your client's metadata as JSON, then
212
+ use the `client_id` in the answer at `/oauth/authorize` and
213
+ `/oauth/token`. Nothing is kept until a person approves your client, so
214
+ registering again costs nothing and leaves nothing to clean up.
215
+
216
+ Each redirect URI must be https on a public host name, or http on a
217
+ loopback address (`127.0.0.1`, `[::1]`, `localhost`), which then
218
+ matches on any port. A custom URI scheme is refused: use a loopback
219
+ redirect instead. So is a host on one of our own domains.
220
+
221
+ `client_name` is shown to the person as your client's own claim, with
222
+ where its redirect goes beside it. A name that renders blank, or mixes
223
+ Latin letters with Cyrillic or Greek ones, is shown as an unnamed
224
+ application.
225
+
226
+ The client is public whatever you ask for: `token_endpoint_auth_method`
227
+ comes back `none`, there is no client secret, and every authorization
228
+ proves itself with PKCE. It may be granted `apikeys.use` at most.
229
+
230
+ Args:
231
+ body (ClientRegistrationRequest):
232
+
233
+ Raises:
234
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
235
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
236
+
237
+ Returns:
238
+ ClientRegistration | OauthError
239
+ """
240
+
241
+ return (
242
+ await asyncio_detailed(
243
+ client=client,
244
+ body=body,
245
+ )
246
+ ).parsed
@@ -10,6 +10,8 @@ from .account_revealed_apikey import AccountRevealedApikey
10
10
  from .account_user import AccountUser
11
11
  from .apikey_detail import ApikeyDetail
12
12
  from .apikey_list import ApikeyList
13
+ from .client_registration import ClientRegistration
14
+ from .client_registration_request import ClientRegistrationRequest
13
15
  from .database import Database
14
16
  from .database_checksum_v2_response_200 import DatabaseChecksumV2Response200
15
17
  from .database_format import DatabaseFormat
@@ -56,6 +58,8 @@ __all__ = (
56
58
  "AccountUser",
57
59
  "ApikeyDetail",
58
60
  "ApikeyList",
61
+ "ClientRegistration",
62
+ "ClientRegistrationRequest",
59
63
  "Database",
60
64
  "DatabaseChecksumV2Response200",
61
65
  "DatabaseFormat",
@@ -0,0 +1,126 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Mapping
4
+ from typing import Any, Self, TypeVar, cast
5
+
6
+ from attrs import define as _attrs_define
7
+ from attrs import field as _attrs_field
8
+
9
+ from ..types import UNSET, Unset
10
+
11
+ T = TypeVar("T", bound="ClientRegistration")
12
+
13
+
14
+ @_attrs_define
15
+ class ClientRegistration:
16
+ """
17
+ Attributes:
18
+ client_id (str):
19
+ client_id_issued_at (int): Unix seconds.
20
+ client_name (str): As the person will see it.
21
+ redirect_uris (list[str]):
22
+ token_endpoint_auth_method (str): Always `none`.
23
+ grant_types (list[str] | Unset): `authorization_code` and `refresh_token`.
24
+ response_types (list[str] | Unset):
25
+ scope (str | Unset): The most this client may be granted: `apikeys.use`.
26
+ """
27
+
28
+ client_id: str
29
+ client_id_issued_at: int
30
+ client_name: str
31
+ redirect_uris: list[str]
32
+ token_endpoint_auth_method: str
33
+ grant_types: list[str] | Unset = UNSET
34
+ response_types: list[str] | Unset = UNSET
35
+ scope: str | Unset = UNSET
36
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
37
+
38
+ def to_dict(self) -> dict[str, Any]:
39
+ client_id = self.client_id
40
+
41
+ client_id_issued_at = self.client_id_issued_at
42
+
43
+ client_name = self.client_name
44
+
45
+ redirect_uris = self.redirect_uris
46
+
47
+ token_endpoint_auth_method = self.token_endpoint_auth_method
48
+
49
+ grant_types: list[str] | Unset = UNSET
50
+ if not isinstance(self.grant_types, Unset):
51
+ grant_types = self.grant_types
52
+
53
+ response_types: list[str] | Unset = UNSET
54
+ if not isinstance(self.response_types, Unset):
55
+ response_types = self.response_types
56
+
57
+ scope = self.scope
58
+
59
+ field_dict: dict[str, Any] = {}
60
+ field_dict.update(self.additional_properties)
61
+ field_dict.update(
62
+ {
63
+ "client_id": client_id,
64
+ "client_id_issued_at": client_id_issued_at,
65
+ "client_name": client_name,
66
+ "redirect_uris": redirect_uris,
67
+ "token_endpoint_auth_method": token_endpoint_auth_method,
68
+ }
69
+ )
70
+ if grant_types is not UNSET:
71
+ field_dict["grant_types"] = grant_types
72
+ if response_types is not UNSET:
73
+ field_dict["response_types"] = response_types
74
+ if scope is not UNSET:
75
+ field_dict["scope"] = scope
76
+
77
+ return field_dict
78
+
79
+ @classmethod
80
+ def from_dict(cls, src_dict: Mapping[str, Any]) -> Self:
81
+ d = dict(src_dict)
82
+ client_id = d.pop("client_id")
83
+
84
+ client_id_issued_at = d.pop("client_id_issued_at")
85
+
86
+ client_name = d.pop("client_name")
87
+
88
+ redirect_uris = cast(list[str], d.pop("redirect_uris"))
89
+
90
+ token_endpoint_auth_method = d.pop("token_endpoint_auth_method")
91
+
92
+ grant_types = cast(list[str], d.pop("grant_types", UNSET))
93
+
94
+ response_types = cast(list[str], d.pop("response_types", UNSET))
95
+
96
+ scope = d.pop("scope", UNSET)
97
+
98
+ client_registration = cls(
99
+ client_id=client_id,
100
+ client_id_issued_at=client_id_issued_at,
101
+ client_name=client_name,
102
+ redirect_uris=redirect_uris,
103
+ token_endpoint_auth_method=token_endpoint_auth_method,
104
+ grant_types=grant_types,
105
+ response_types=response_types,
106
+ scope=scope,
107
+ )
108
+
109
+ client_registration.additional_properties = d
110
+ return client_registration
111
+
112
+ @property
113
+ def additional_keys(self) -> list[str]:
114
+ return list(self.additional_properties.keys())
115
+
116
+ def __getitem__(self, key: str) -> Any:
117
+ return self.additional_properties[key]
118
+
119
+ def __setitem__(self, key: str, value: Any) -> None:
120
+ self.additional_properties[key] = value
121
+
122
+ def __delitem__(self, key: str) -> None:
123
+ del self.additional_properties[key]
124
+
125
+ def __contains__(self, key: str) -> bool:
126
+ return key in self.additional_properties
@@ -0,0 +1,104 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Mapping
4
+ from typing import Any, Self, TypeVar, cast
5
+
6
+ from attrs import define as _attrs_define
7
+ from attrs import field as _attrs_field
8
+
9
+ from ..types import UNSET, Unset
10
+
11
+ T = TypeVar("T", bound="ClientRegistrationRequest")
12
+
13
+
14
+ @_attrs_define
15
+ class ClientRegistrationRequest:
16
+ """
17
+ Attributes:
18
+ redirect_uris (list[str]): One to ten, each matched exactly, apart from a loopback one's port.
19
+ client_name (str | Unset): Shown to the person as your client's own claim, marked unverified, beside where its
20
+ redirect goes.
21
+ grant_types (list[str] | Unset): Must include `authorization_code` when given.
22
+ response_types (list[str] | Unset): Must include `code` when given.
23
+ token_endpoint_auth_method (str | Unset): Read as `none`, whatever is sent.
24
+ """
25
+
26
+ redirect_uris: list[str]
27
+ client_name: str | Unset = UNSET
28
+ grant_types: list[str] | Unset = UNSET
29
+ response_types: list[str] | Unset = UNSET
30
+ token_endpoint_auth_method: str | Unset = UNSET
31
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
32
+
33
+ def to_dict(self) -> dict[str, Any]:
34
+ redirect_uris = self.redirect_uris
35
+
36
+ client_name = self.client_name
37
+
38
+ grant_types: list[str] | Unset = UNSET
39
+ if not isinstance(self.grant_types, Unset):
40
+ grant_types = self.grant_types
41
+
42
+ response_types: list[str] | Unset = UNSET
43
+ if not isinstance(self.response_types, Unset):
44
+ response_types = self.response_types
45
+
46
+ token_endpoint_auth_method = self.token_endpoint_auth_method
47
+
48
+ field_dict: dict[str, Any] = {}
49
+ field_dict.update(self.additional_properties)
50
+ field_dict.update(
51
+ {
52
+ "redirect_uris": redirect_uris,
53
+ }
54
+ )
55
+ if client_name is not UNSET:
56
+ field_dict["client_name"] = client_name
57
+ if grant_types is not UNSET:
58
+ field_dict["grant_types"] = grant_types
59
+ if response_types is not UNSET:
60
+ field_dict["response_types"] = response_types
61
+ if token_endpoint_auth_method is not UNSET:
62
+ field_dict["token_endpoint_auth_method"] = token_endpoint_auth_method
63
+
64
+ return field_dict
65
+
66
+ @classmethod
67
+ def from_dict(cls, src_dict: Mapping[str, Any]) -> Self:
68
+ d = dict(src_dict)
69
+ redirect_uris = cast(list[str], d.pop("redirect_uris"))
70
+
71
+ client_name = d.pop("client_name", UNSET)
72
+
73
+ grant_types = cast(list[str], d.pop("grant_types", UNSET))
74
+
75
+ response_types = cast(list[str], d.pop("response_types", UNSET))
76
+
77
+ token_endpoint_auth_method = d.pop("token_endpoint_auth_method", UNSET)
78
+
79
+ client_registration_request = cls(
80
+ redirect_uris=redirect_uris,
81
+ client_name=client_name,
82
+ grant_types=grant_types,
83
+ response_types=response_types,
84
+ token_endpoint_auth_method=token_endpoint_auth_method,
85
+ )
86
+
87
+ client_registration_request.additional_properties = d
88
+ return client_registration_request
89
+
90
+ @property
91
+ def additional_keys(self) -> list[str]:
92
+ return list(self.additional_properties.keys())
93
+
94
+ def __getitem__(self, key: str) -> Any:
95
+ return self.additional_properties[key]
96
+
97
+ def __setitem__(self, key: str, value: Any) -> None:
98
+ self.additional_properties[key] = value
99
+
100
+ def __delitem__(self, key: str) -> None:
101
+ del self.additional_properties[key]
102
+
103
+ def __contains__(self, key: str) -> bool:
104
+ return key in self.additional_properties
@@ -26,6 +26,8 @@ class OauthMetadata:
26
26
  code_challenge_methods_supported (list[str] | Unset):
27
27
  client_id_metadata_document_supported (bool | Unset): Any client may sign in with an https `client_id` serving
28
28
  its own metadata.
29
+ registration_endpoint (str | Unset): RFC 7591 dynamic client registration, for a client that cannot serve its
30
+ own metadata.
29
31
  token_endpoint_auth_methods_supported (list[str] | Unset): Always `none`. Every client is public and has no
30
32
  secret.
31
33
  authorization_response_iss_parameter_supported (bool | Unset): RFC 9207. A redirect back from the authorization
@@ -43,6 +45,7 @@ class OauthMetadata:
43
45
  grant_types_supported: list[str] | Unset = UNSET
44
46
  code_challenge_methods_supported: list[str] | Unset = UNSET
45
47
  client_id_metadata_document_supported: bool | Unset = UNSET
48
+ registration_endpoint: str | Unset = UNSET
46
49
  token_endpoint_auth_methods_supported: list[str] | Unset = UNSET
47
50
  authorization_response_iss_parameter_supported: bool | Unset = UNSET
48
51
  service_documentation: str | Unset = UNSET
@@ -77,6 +80,8 @@ class OauthMetadata:
77
80
 
78
81
  client_id_metadata_document_supported = self.client_id_metadata_document_supported
79
82
 
83
+ registration_endpoint = self.registration_endpoint
84
+
80
85
  token_endpoint_auth_methods_supported: list[str] | Unset = UNSET
81
86
  if not isinstance(self.token_endpoint_auth_methods_supported, Unset):
82
87
  token_endpoint_auth_methods_supported = self.token_endpoint_auth_methods_supported
@@ -112,6 +117,8 @@ class OauthMetadata:
112
117
  field_dict["client_id_metadata_document_supported"] = (
113
118
  client_id_metadata_document_supported
114
119
  )
120
+ if registration_endpoint is not UNSET:
121
+ field_dict["registration_endpoint"] = registration_endpoint
115
122
  if token_endpoint_auth_methods_supported is not UNSET:
116
123
  field_dict["token_endpoint_auth_methods_supported"] = (
117
124
  token_endpoint_auth_methods_supported
@@ -152,6 +159,8 @@ class OauthMetadata:
152
159
  "client_id_metadata_document_supported", UNSET
153
160
  )
154
161
 
162
+ registration_endpoint = d.pop("registration_endpoint", UNSET)
163
+
155
164
  token_endpoint_auth_methods_supported = cast(
156
165
  list[str], d.pop("token_endpoint_auth_methods_supported", UNSET)
157
166
  )
@@ -173,6 +182,7 @@ class OauthMetadata:
173
182
  grant_types_supported=grant_types_supported,
174
183
  code_challenge_methods_supported=code_challenge_methods_supported,
175
184
  client_id_metadata_document_supported=client_id_metadata_document_supported,
185
+ registration_endpoint=registration_endpoint,
176
186
  token_endpoint_auth_methods_supported=token_endpoint_auth_methods_supported,
177
187
  authorization_response_iss_parameter_supported=authorization_response_iss_parameter_supported,
178
188
  service_documentation=service_documentation,
@@ -26,7 +26,8 @@ class TokenResponse:
26
26
  no key was picked, or when the person's role no longer allows
27
27
  reading keys back.
28
28
  mslmapikey (str | Unset): Not part of OAuth, and only for our own clients: a client that signed
29
- in with a Client ID Metadata Document never receives a key. The API
29
+ in with a Client ID Metadata Document or registered itself never
30
+ receives a key. The API
30
31
  key itself, so a device ends up holding an ordinary key. Returned by
31
32
  the device code and authorization code grants only, never by a
32
33
  refresh, and only alongside
@@ -311,6 +311,7 @@ class OauthMetadata:
311
311
  authorization_response_iss_parameter_supported: bool | None = None
312
312
  service_documentation: str | None = None
313
313
  client_id_metadata_document_supported: bool | None = None
314
+ registration_endpoint: str | None = None
314
315
 
315
316
 
316
317
  @dataclass(frozen=True, slots=True)
@@ -389,6 +390,7 @@ _OAUTH_METADATA: dict[str, _Member] = {
389
390
  "authorization_response_iss_parameter_supported": ("bool", False),
390
391
  "service_documentation": ("str", False),
391
392
  "client_id_metadata_document_supported": ("bool", False),
393
+ "registration_endpoint": ("str", False),
392
394
  }
393
395
 
394
396
  _DEVICE_AUTHORIZATION: dict[str, _Member] = {
File without changes
File without changes
File without changes