vpndetection-fastapi 2.1.8__tar.gz → 2.1.9__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.
- {vpndetection_fastapi-2.1.8 → vpndetection_fastapi-2.1.9}/CHANGELOG.md +6 -0
- {vpndetection_fastapi-2.1.8 → vpndetection_fastapi-2.1.9}/PKG-INFO +4 -4
- {vpndetection_fastapi-2.1.8 → vpndetection_fastapi-2.1.9}/README.md +2 -2
- vpndetection_fastapi-2.1.9/SECURITY.md +5 -0
- {vpndetection_fastapi-2.1.8 → vpndetection_fastapi-2.1.9}/pyproject.toml +1 -1
- {vpndetection_fastapi-2.1.8 → vpndetection_fastapi-2.1.9}/src/vpndetection_fastapi/__init__.py +1 -1
- {vpndetection_fastapi-2.1.8 → vpndetection_fastapi-2.1.9}/testdata/testdata.json +591 -2
- {vpndetection_fastapi-2.1.8 → vpndetection_fastapi-2.1.9}/.github/workflows/ci.yml +0 -0
- {vpndetection_fastapi-2.1.8 → vpndetection_fastapi-2.1.9}/.github/workflows/release.yml +0 -0
- {vpndetection_fastapi-2.1.8 → vpndetection_fastapi-2.1.9}/.gitignore +0 -0
- {vpndetection_fastapi-2.1.8 → vpndetection_fastapi-2.1.9}/LICENSE +0 -0
- {vpndetection_fastapi-2.1.8 → vpndetection_fastapi-2.1.9}/src/vpndetection_fastapi/py.typed +0 -0
- {vpndetection_fastapi-2.1.8 → vpndetection_fastapi-2.1.9}/testdata/bogons.json +0 -0
- {vpndetection_fastapi-2.1.8 → vpndetection_fastapi-2.1.9}/tests/test_middleware.py +0 -0
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
What each release changed for you, newest first. Each line is a commit's summary, linked to its full description and diff. Releases before 2.0.5 are described by their release commits.
|
|
4
4
|
|
|
5
|
+
## 2.1.9 - 2026-10-20
|
|
6
|
+
|
|
7
|
+
### Features
|
|
8
|
+
|
|
9
|
+
- Require vpndetection 5.11.0: lookup results carry location and asn ([`ada4345`](https://github.com/vpndetection-io/sdk-python-fastapi/commit/ada4345bde920539b2f279f03d790ae42a74998d))
|
|
10
|
+
|
|
5
11
|
## 2.1.8 - 2026-10-19
|
|
6
12
|
|
|
7
13
|
### Fixes
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: vpndetection-fastapi
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.9
|
|
4
4
|
Summary: Official FastAPI and Starlette middleware for the VPNDetection API. Detect VPNs, proxies, Tor, hosting and CDN visitors on every request.
|
|
5
5
|
Project-URL: Homepage, https://vpndetection.io
|
|
6
6
|
Project-URL: Source, https://github.com/vpndetection-io/sdk-python-fastapi
|
|
@@ -20,7 +20,7 @@ Classifier: Topic :: Security
|
|
|
20
20
|
Classifier: Typing :: Typed
|
|
21
21
|
Requires-Python: >=3.11
|
|
22
22
|
Requires-Dist: starlette>=0.37
|
|
23
|
-
Requires-Dist: vpndetection<6,>=5.
|
|
23
|
+
Requires-Dist: vpndetection<6,>=5.11.0
|
|
24
24
|
Provides-Extra: dev
|
|
25
25
|
Requires-Dist: fastapi>=0.115; extra == 'dev'
|
|
26
26
|
Requires-Dist: mypy>=1.11; extra == 'dev'
|
|
@@ -45,7 +45,7 @@ pip install vpndetection-fastapi
|
|
|
45
45
|
|
|
46
46
|
Requires Python 3.11 or newer.
|
|
47
47
|
|
|
48
|
-
You need an API key. Create one in the [console](https://app.vpndetection.io);
|
|
48
|
+
You need an API key. Create one in the [console](https://app.vpndetection.io); without one the allowance is counted per source address, and a server is a single source address, so a key is what makes this usable in production rather than optional.
|
|
49
49
|
|
|
50
50
|
```python
|
|
51
51
|
from fastapi import FastAPI
|
|
@@ -146,7 +146,7 @@ Beyond a few million distinct visitors a day, stop calling the API per request:
|
|
|
146
146
|
|
|
147
147
|
## Absent is not false
|
|
148
148
|
|
|
149
|
-
|
|
149
|
+
Without a key only `ip` and `is_vpn` come back, and a free key adds Tor, relay, `location` and `asn`. A field your plan does not include is `None`, which means "not in your plan" rather than "checked, and no".
|
|
150
150
|
|
|
151
151
|
```python
|
|
152
152
|
lookup(request).result.is_hosting # None when your plan does not include it
|
|
@@ -15,7 +15,7 @@ pip install vpndetection-fastapi
|
|
|
15
15
|
|
|
16
16
|
Requires Python 3.11 or newer.
|
|
17
17
|
|
|
18
|
-
You need an API key. Create one in the [console](https://app.vpndetection.io);
|
|
18
|
+
You need an API key. Create one in the [console](https://app.vpndetection.io); without one the allowance is counted per source address, and a server is a single source address, so a key is what makes this usable in production rather than optional.
|
|
19
19
|
|
|
20
20
|
```python
|
|
21
21
|
from fastapi import FastAPI
|
|
@@ -116,7 +116,7 @@ Beyond a few million distinct visitors a day, stop calling the API per request:
|
|
|
116
116
|
|
|
117
117
|
## Absent is not false
|
|
118
118
|
|
|
119
|
-
|
|
119
|
+
Without a key only `ip` and `is_vpn` come back, and a free key adds Tor, relay, `location` and `asn`. A field your plan does not include is `None`, which means "not in your plan" rather than "checked, and no".
|
|
120
120
|
|
|
121
121
|
```python
|
|
122
122
|
lookup(request).result.is_hosting # None when your plan does not include it
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# Security policy
|
|
2
|
+
|
|
3
|
+
Please report a security issue in this repository by email to security@vpndetection.io, not in a public issue, pull request or discussion. Include what you found and the steps that reproduce it.
|
|
4
|
+
|
|
5
|
+
Keep any testing against the VPNDetection API to your own account and API key, and give us a reasonable chance to fix the issue before you publish it.
|
|
@@ -296,7 +296,7 @@
|
|
|
296
296
|
}
|
|
297
297
|
],
|
|
298
298
|
"bogonResponse": {
|
|
299
|
-
"why": "A bogon is answered locally in the full
|
|
299
|
+
"why": "A bogon is answered locally in the full shape. Every flag is present and false, every detail object is present and empty, location and asn carry every key empty as the API answers a bogon (asn 0, strings empty), and is_bogon marks it as computed rather than served.",
|
|
300
300
|
"flagsFalse": [
|
|
301
301
|
"is_vpn",
|
|
302
302
|
"is_hosting",
|
|
@@ -318,7 +318,26 @@
|
|
|
318
318
|
"dcproxy",
|
|
319
319
|
"mobproxy",
|
|
320
320
|
"pubproxy"
|
|
321
|
-
]
|
|
321
|
+
],
|
|
322
|
+
"location": {
|
|
323
|
+
"continent": "",
|
|
324
|
+
"continent_name": "",
|
|
325
|
+
"country": "",
|
|
326
|
+
"country_name": "",
|
|
327
|
+
"timezone": "",
|
|
328
|
+
"currency_code": "",
|
|
329
|
+
"currency_name": "",
|
|
330
|
+
"currency_symbol": "",
|
|
331
|
+
"flag_emoji": "",
|
|
332
|
+
"flag_unicode": ""
|
|
333
|
+
},
|
|
334
|
+
"asn": {
|
|
335
|
+
"asn": 0,
|
|
336
|
+
"name": "",
|
|
337
|
+
"domain": "",
|
|
338
|
+
"type": "",
|
|
339
|
+
"prefix": ""
|
|
340
|
+
}
|
|
322
341
|
},
|
|
323
342
|
"lookup": [
|
|
324
343
|
{
|
|
@@ -618,6 +637,85 @@
|
|
|
618
637
|
"pubproxy"
|
|
619
638
|
]
|
|
620
639
|
}
|
|
640
|
+
},
|
|
641
|
+
{
|
|
642
|
+
"name": "free-location-asn",
|
|
643
|
+
"why": "A free key's shape since 2026-10-20: Tor and relay beside the VPN flag, and where the address is and which AS announces it. location and asn carry every key whenever present, so each maps whole.",
|
|
644
|
+
"status": 200,
|
|
645
|
+
"body": {
|
|
646
|
+
"ip": "146.70.116.130",
|
|
647
|
+
"is_vpn": true,
|
|
648
|
+
"is_relay": false,
|
|
649
|
+
"is_tor": false,
|
|
650
|
+
"relay": {},
|
|
651
|
+
"tor": {},
|
|
652
|
+
"location": {
|
|
653
|
+
"continent": "EU",
|
|
654
|
+
"continent_name": "Europe",
|
|
655
|
+
"country": "AT",
|
|
656
|
+
"country_name": "Austria",
|
|
657
|
+
"timezone": "Europe/Vienna",
|
|
658
|
+
"currency_code": "EUR",
|
|
659
|
+
"currency_name": "Euro",
|
|
660
|
+
"currency_symbol": "€",
|
|
661
|
+
"flag_emoji": "🇦🇹",
|
|
662
|
+
"flag_unicode": "U+1F1E6 U+1F1F9"
|
|
663
|
+
},
|
|
664
|
+
"asn": {
|
|
665
|
+
"asn": 9009,
|
|
666
|
+
"name": "M247 Europe SRL",
|
|
667
|
+
"domain": "m247global.com",
|
|
668
|
+
"type": "hosting",
|
|
669
|
+
"prefix": "146.70.116.0/24"
|
|
670
|
+
}
|
|
671
|
+
},
|
|
672
|
+
"expect": {
|
|
673
|
+
"ip": "146.70.116.130",
|
|
674
|
+
"isBogon": false,
|
|
675
|
+
"present": {
|
|
676
|
+
"is_vpn": true,
|
|
677
|
+
"is_relay": false,
|
|
678
|
+
"is_tor": false
|
|
679
|
+
},
|
|
680
|
+
"absent": [
|
|
681
|
+
"is_hosting",
|
|
682
|
+
"is_cdn",
|
|
683
|
+
"is_resproxy",
|
|
684
|
+
"is_dcproxy",
|
|
685
|
+
"is_mobproxy",
|
|
686
|
+
"is_pubproxy",
|
|
687
|
+
"vpn",
|
|
688
|
+
"hosting",
|
|
689
|
+
"cdn",
|
|
690
|
+
"resproxy",
|
|
691
|
+
"dcproxy",
|
|
692
|
+
"mobproxy",
|
|
693
|
+
"pubproxy"
|
|
694
|
+
],
|
|
695
|
+
"emptyPresent": [
|
|
696
|
+
"relay",
|
|
697
|
+
"tor"
|
|
698
|
+
],
|
|
699
|
+
"location": {
|
|
700
|
+
"continent": "EU",
|
|
701
|
+
"continent_name": "Europe",
|
|
702
|
+
"country": "AT",
|
|
703
|
+
"country_name": "Austria",
|
|
704
|
+
"timezone": "Europe/Vienna",
|
|
705
|
+
"currency_code": "EUR",
|
|
706
|
+
"currency_name": "Euro",
|
|
707
|
+
"currency_symbol": "€",
|
|
708
|
+
"flag_emoji": "🇦🇹",
|
|
709
|
+
"flag_unicode": "U+1F1E6 U+1F1F9"
|
|
710
|
+
},
|
|
711
|
+
"asn": {
|
|
712
|
+
"asn": 9009,
|
|
713
|
+
"name": "M247 Europe SRL",
|
|
714
|
+
"domain": "m247global.com",
|
|
715
|
+
"type": "hosting",
|
|
716
|
+
"prefix": "146.70.116.0/24"
|
|
717
|
+
}
|
|
718
|
+
}
|
|
621
719
|
}
|
|
622
720
|
],
|
|
623
721
|
"errors": [
|
|
@@ -6815,6 +6913,497 @@
|
|
|
6815
6913
|
}
|
|
6816
6914
|
}
|
|
6817
6915
|
]
|
|
6916
|
+
},
|
|
6917
|
+
"register": {
|
|
6918
|
+
"why": "Vectors for register, RFC 7591 dynamic client registration: the client_id a client gets when it cannot serve a Client ID Metadata Document. The one OAuth request whose body is JSON. Nothing is stored until a person approves the client, so registering again consumes nothing and the operation takes the client's retries. noCredential holds for it as for every OAuth operation. A runner that has not shipped register never reads this key; nothing outside it names the operation.",
|
|
6919
|
+
"endpoint": {
|
|
6920
|
+
"method": "POST",
|
|
6921
|
+
"path": "/oauth/register"
|
|
6922
|
+
},
|
|
6923
|
+
"contentType": "application/json",
|
|
6924
|
+
"bodies": {
|
|
6925
|
+
"why": "Decode the received body as JSON and compare it EXACTLY: same members, no extras, same values, redirect_uris in the order given. An optional argument given empty is left out, never sent empty. Values carrying a quote, a backslash, + & = % / space and non-ASCII catch an encoder that builds JSON by hand.",
|
|
6926
|
+
"cases": [
|
|
6927
|
+
{
|
|
6928
|
+
"name": "redirect-uris-only",
|
|
6929
|
+
"args": {
|
|
6930
|
+
"redirectUris": [
|
|
6931
|
+
"http://127.0.0.1:8765/callback"
|
|
6932
|
+
]
|
|
6933
|
+
},
|
|
6934
|
+
"body": {
|
|
6935
|
+
"redirect_uris": [
|
|
6936
|
+
"http://127.0.0.1:8765/callback"
|
|
6937
|
+
]
|
|
6938
|
+
}
|
|
6939
|
+
},
|
|
6940
|
+
{
|
|
6941
|
+
"name": "several-uris-and-a-name",
|
|
6942
|
+
"args": {
|
|
6943
|
+
"redirectUris": [
|
|
6944
|
+
"https://app.example.com/oauth/callback",
|
|
6945
|
+
"http://localhost/cb?a=1&b=two words%2B"
|
|
6946
|
+
],
|
|
6947
|
+
"clientName": "Exämple \"CLI\" + tools/\\ 中"
|
|
6948
|
+
},
|
|
6949
|
+
"body": {
|
|
6950
|
+
"redirect_uris": [
|
|
6951
|
+
"https://app.example.com/oauth/callback",
|
|
6952
|
+
"http://localhost/cb?a=1&b=two words%2B"
|
|
6953
|
+
],
|
|
6954
|
+
"client_name": "Exämple \"CLI\" + tools/\\ 中"
|
|
6955
|
+
}
|
|
6956
|
+
},
|
|
6957
|
+
{
|
|
6958
|
+
"name": "an-empty-client-name-is-left-out",
|
|
6959
|
+
"args": {
|
|
6960
|
+
"redirectUris": [
|
|
6961
|
+
"http://[::1]/cb"
|
|
6962
|
+
],
|
|
6963
|
+
"clientName": ""
|
|
6964
|
+
},
|
|
6965
|
+
"body": {
|
|
6966
|
+
"redirect_uris": [
|
|
6967
|
+
"http://[::1]/cb"
|
|
6968
|
+
]
|
|
6969
|
+
}
|
|
6970
|
+
}
|
|
6971
|
+
]
|
|
6972
|
+
},
|
|
6973
|
+
"refusals": {
|
|
6974
|
+
"why": "Refused before anything is sent, the way the SDK refuses a required value given empty in the code flow's methods: no request reaches the server. Only emptiness is checked here; which URIs are acceptable is the server's to say (invalid_redirect_uri).",
|
|
6975
|
+
"cases": [
|
|
6976
|
+
{
|
|
6977
|
+
"name": "no-redirect-uris",
|
|
6978
|
+
"args": {
|
|
6979
|
+
"redirectUris": []
|
|
6980
|
+
}
|
|
6981
|
+
},
|
|
6982
|
+
{
|
|
6983
|
+
"name": "an-empty-redirect-uri",
|
|
6984
|
+
"args": {
|
|
6985
|
+
"redirectUris": [
|
|
6986
|
+
"http://127.0.0.1:8765/callback",
|
|
6987
|
+
""
|
|
6988
|
+
]
|
|
6989
|
+
}
|
|
6990
|
+
}
|
|
6991
|
+
]
|
|
6992
|
+
},
|
|
6993
|
+
"responses": {
|
|
6994
|
+
"why": "Decoding a 2xx, as the other responses sections do: every listed member present with that value, every absent one the language's absence. client_id_issued_at is Unix seconds, so a 32-bit integer holds it only until 2038.",
|
|
6995
|
+
"cases": [
|
|
6996
|
+
{
|
|
6997
|
+
"name": "as-served",
|
|
6998
|
+
"status": 201,
|
|
6999
|
+
"body": {
|
|
7000
|
+
"client_id": "dcr_eyJ2IjoxLCJhIjoiaW50ZXJuZXRkYXRhIiwibiI6IkV4YW1wbGUgQ0xJIn0.bm90LWEtcmVhbC1tYWMtZXhhbXBsZS1vbmx5LTAxMjM",
|
|
7001
|
+
"client_id_issued_at": 1792304178,
|
|
7002
|
+
"client_name": "Example CLI",
|
|
7003
|
+
"redirect_uris": [
|
|
7004
|
+
"http://127.0.0.1:8765/callback"
|
|
7005
|
+
],
|
|
7006
|
+
"grant_types": [
|
|
7007
|
+
"authorization_code",
|
|
7008
|
+
"refresh_token"
|
|
7009
|
+
],
|
|
7010
|
+
"response_types": [
|
|
7011
|
+
"code"
|
|
7012
|
+
],
|
|
7013
|
+
"token_endpoint_auth_method": "none",
|
|
7014
|
+
"scope": "apikeys.use"
|
|
7015
|
+
},
|
|
7016
|
+
"expect": {
|
|
7017
|
+
"present": {
|
|
7018
|
+
"client_id": "dcr_eyJ2IjoxLCJhIjoiaW50ZXJuZXRkYXRhIiwibiI6IkV4YW1wbGUgQ0xJIn0.bm90LWEtcmVhbC1tYWMtZXhhbXBsZS1vbmx5LTAxMjM",
|
|
7019
|
+
"client_id_issued_at": 1792304178,
|
|
7020
|
+
"client_name": "Example CLI",
|
|
7021
|
+
"redirect_uris": [
|
|
7022
|
+
"http://127.0.0.1:8765/callback"
|
|
7023
|
+
],
|
|
7024
|
+
"grant_types": [
|
|
7025
|
+
"authorization_code",
|
|
7026
|
+
"refresh_token"
|
|
7027
|
+
],
|
|
7028
|
+
"response_types": [
|
|
7029
|
+
"code"
|
|
7030
|
+
],
|
|
7031
|
+
"token_endpoint_auth_method": "none",
|
|
7032
|
+
"scope": "apikeys.use"
|
|
7033
|
+
},
|
|
7034
|
+
"absent": []
|
|
7035
|
+
}
|
|
7036
|
+
},
|
|
7037
|
+
{
|
|
7038
|
+
"name": "rfc-minimum",
|
|
7039
|
+
"status": 201,
|
|
7040
|
+
"body": {
|
|
7041
|
+
"client_id": "dcr_eyJ2IjoxLCJhIjoiaW50ZXJuZXRkYXRhIiwibiI6IkV4YW1wbGUgQ0xJIn0.bm90LWEtcmVhbC1tYWMtZXhhbXBsZS1vbmx5LTAxMjM",
|
|
7042
|
+
"client_id_issued_at": 1792304178,
|
|
7043
|
+
"client_name": "Example CLI",
|
|
7044
|
+
"redirect_uris": [
|
|
7045
|
+
"http://127.0.0.1:8765/callback"
|
|
7046
|
+
],
|
|
7047
|
+
"token_endpoint_auth_method": "none"
|
|
7048
|
+
},
|
|
7049
|
+
"expect": {
|
|
7050
|
+
"present": {
|
|
7051
|
+
"client_id": "dcr_eyJ2IjoxLCJhIjoiaW50ZXJuZXRkYXRhIiwibiI6IkV4YW1wbGUgQ0xJIn0.bm90LWEtcmVhbC1tYWMtZXhhbXBsZS1vbmx5LTAxMjM",
|
|
7052
|
+
"client_id_issued_at": 1792304178,
|
|
7053
|
+
"client_name": "Example CLI",
|
|
7054
|
+
"redirect_uris": [
|
|
7055
|
+
"http://127.0.0.1:8765/callback"
|
|
7056
|
+
],
|
|
7057
|
+
"token_endpoint_auth_method": "none"
|
|
7058
|
+
},
|
|
7059
|
+
"absent": [
|
|
7060
|
+
"grant_types",
|
|
7061
|
+
"response_types",
|
|
7062
|
+
"scope"
|
|
7063
|
+
]
|
|
7064
|
+
}
|
|
7065
|
+
},
|
|
7066
|
+
{
|
|
7067
|
+
"name": "issued-after-2038",
|
|
7068
|
+
"status": 201,
|
|
7069
|
+
"body": {
|
|
7070
|
+
"client_id": "dcr_eyJ2IjoxLCJhIjoiaW50ZXJuZXRkYXRhIiwibiI6IkV4YW1wbGUgQ0xJIn0.bm90LWEtcmVhbC1tYWMtZXhhbXBsZS1vbmx5LTAxMjM",
|
|
7071
|
+
"client_id_issued_at": 4102444800,
|
|
7072
|
+
"client_name": "Example CLI",
|
|
7073
|
+
"redirect_uris": [
|
|
7074
|
+
"http://127.0.0.1:8765/callback"
|
|
7075
|
+
],
|
|
7076
|
+
"token_endpoint_auth_method": "none"
|
|
7077
|
+
},
|
|
7078
|
+
"expect": {
|
|
7079
|
+
"present": {
|
|
7080
|
+
"client_id_issued_at": 4102444800
|
|
7081
|
+
},
|
|
7082
|
+
"absent": [
|
|
7083
|
+
"scope"
|
|
7084
|
+
]
|
|
7085
|
+
}
|
|
7086
|
+
},
|
|
7087
|
+
{
|
|
7088
|
+
"name": "unknown-members-ignored",
|
|
7089
|
+
"status": 200,
|
|
7090
|
+
"body": {
|
|
7091
|
+
"client_id": "dcr_eyJ2IjoxLCJhIjoiaW50ZXJuZXRkYXRhIiwibiI6IkV4YW1wbGUgQ0xJIn0.bm90LWEtcmVhbC1tYWMtZXhhbXBsZS1vbmx5LTAxMjM",
|
|
7092
|
+
"client_id_issued_at": 1792304178,
|
|
7093
|
+
"client_name": "Example CLI",
|
|
7094
|
+
"redirect_uris": [
|
|
7095
|
+
"http://127.0.0.1:8765/callback"
|
|
7096
|
+
],
|
|
7097
|
+
"grant_types": [
|
|
7098
|
+
"authorization_code",
|
|
7099
|
+
"refresh_token"
|
|
7100
|
+
],
|
|
7101
|
+
"response_types": [
|
|
7102
|
+
"code"
|
|
7103
|
+
],
|
|
7104
|
+
"token_endpoint_auth_method": "none",
|
|
7105
|
+
"scope": "apikeys.use",
|
|
7106
|
+
"client_secret_expires_at": 0,
|
|
7107
|
+
"software_id": "example"
|
|
7108
|
+
},
|
|
7109
|
+
"expect": {
|
|
7110
|
+
"present": {
|
|
7111
|
+
"client_id": "dcr_eyJ2IjoxLCJhIjoiaW50ZXJuZXRkYXRhIiwibiI6IkV4YW1wbGUgQ0xJIn0.bm90LWEtcmVhbC1tYWMtZXhhbXBsZS1vbmx5LTAxMjM",
|
|
7112
|
+
"scope": "apikeys.use"
|
|
7113
|
+
},
|
|
7114
|
+
"absent": []
|
|
7115
|
+
}
|
|
7116
|
+
}
|
|
7117
|
+
]
|
|
7118
|
+
},
|
|
7119
|
+
"unreadable": {
|
|
7120
|
+
"why": "A 2xx register cannot read as its answer, with the client's retries at 0: the SDK's ordinary error (type client), kind server_error, carrying the status, after one request. Never a raw parser error, and never an empty registration. A member of the wrong type is unreadable at any depth, inside redirect_uris included, and an optional one too.",
|
|
7121
|
+
"cases": [
|
|
7122
|
+
{
|
|
7123
|
+
"name": "html-page",
|
|
7124
|
+
"status": 200,
|
|
7125
|
+
"rawBody": "<html><body>Sign in</body></html>"
|
|
7126
|
+
},
|
|
7127
|
+
{
|
|
7128
|
+
"name": "empty-body",
|
|
7129
|
+
"status": 201,
|
|
7130
|
+
"rawBody": ""
|
|
7131
|
+
},
|
|
7132
|
+
{
|
|
7133
|
+
"name": "cut-off",
|
|
7134
|
+
"status": 201,
|
|
7135
|
+
"rawBody": "{\"client_id\":\"dcr_x\",\"client_id_is"
|
|
7136
|
+
},
|
|
7137
|
+
{
|
|
7138
|
+
"name": "an-array",
|
|
7139
|
+
"status": 201,
|
|
7140
|
+
"body": []
|
|
7141
|
+
},
|
|
7142
|
+
{
|
|
7143
|
+
"name": "empty-object",
|
|
7144
|
+
"status": 201,
|
|
7145
|
+
"body": {}
|
|
7146
|
+
},
|
|
7147
|
+
{
|
|
7148
|
+
"name": "no-client-id",
|
|
7149
|
+
"status": 201,
|
|
7150
|
+
"body": {
|
|
7151
|
+
"client_id_issued_at": 1792304178,
|
|
7152
|
+
"client_name": "Example CLI",
|
|
7153
|
+
"redirect_uris": [
|
|
7154
|
+
"http://127.0.0.1:8765/callback"
|
|
7155
|
+
],
|
|
7156
|
+
"token_endpoint_auth_method": "none"
|
|
7157
|
+
}
|
|
7158
|
+
},
|
|
7159
|
+
{
|
|
7160
|
+
"name": "no-client-id-issued-at",
|
|
7161
|
+
"status": 201,
|
|
7162
|
+
"body": {
|
|
7163
|
+
"client_id": "dcr_eyJ2IjoxLCJhIjoiaW50ZXJuZXRkYXRhIiwibiI6IkV4YW1wbGUgQ0xJIn0.bm90LWEtcmVhbC1tYWMtZXhhbXBsZS1vbmx5LTAxMjM",
|
|
7164
|
+
"client_name": "Example CLI",
|
|
7165
|
+
"redirect_uris": [
|
|
7166
|
+
"http://127.0.0.1:8765/callback"
|
|
7167
|
+
],
|
|
7168
|
+
"token_endpoint_auth_method": "none"
|
|
7169
|
+
}
|
|
7170
|
+
},
|
|
7171
|
+
{
|
|
7172
|
+
"name": "no-client-name",
|
|
7173
|
+
"status": 201,
|
|
7174
|
+
"body": {
|
|
7175
|
+
"client_id": "dcr_eyJ2IjoxLCJhIjoiaW50ZXJuZXRkYXRhIiwibiI6IkV4YW1wbGUgQ0xJIn0.bm90LWEtcmVhbC1tYWMtZXhhbXBsZS1vbmx5LTAxMjM",
|
|
7176
|
+
"client_id_issued_at": 1792304178,
|
|
7177
|
+
"redirect_uris": [
|
|
7178
|
+
"http://127.0.0.1:8765/callback"
|
|
7179
|
+
],
|
|
7180
|
+
"token_endpoint_auth_method": "none"
|
|
7181
|
+
}
|
|
7182
|
+
},
|
|
7183
|
+
{
|
|
7184
|
+
"name": "no-redirect-uris",
|
|
7185
|
+
"status": 201,
|
|
7186
|
+
"body": {
|
|
7187
|
+
"client_id": "dcr_eyJ2IjoxLCJhIjoiaW50ZXJuZXRkYXRhIiwibiI6IkV4YW1wbGUgQ0xJIn0.bm90LWEtcmVhbC1tYWMtZXhhbXBsZS1vbmx5LTAxMjM",
|
|
7188
|
+
"client_id_issued_at": 1792304178,
|
|
7189
|
+
"client_name": "Example CLI",
|
|
7190
|
+
"token_endpoint_auth_method": "none"
|
|
7191
|
+
}
|
|
7192
|
+
},
|
|
7193
|
+
{
|
|
7194
|
+
"name": "no-token-endpoint-auth-method",
|
|
7195
|
+
"status": 201,
|
|
7196
|
+
"body": {
|
|
7197
|
+
"client_id": "dcr_eyJ2IjoxLCJhIjoiaW50ZXJuZXRkYXRhIiwibiI6IkV4YW1wbGUgQ0xJIn0.bm90LWEtcmVhbC1tYWMtZXhhbXBsZS1vbmx5LTAxMjM",
|
|
7198
|
+
"client_id_issued_at": 1792304178,
|
|
7199
|
+
"client_name": "Example CLI",
|
|
7200
|
+
"redirect_uris": [
|
|
7201
|
+
"http://127.0.0.1:8765/callback"
|
|
7202
|
+
]
|
|
7203
|
+
}
|
|
7204
|
+
},
|
|
7205
|
+
{
|
|
7206
|
+
"name": "issued-at-as-a-string",
|
|
7207
|
+
"status": 201,
|
|
7208
|
+
"body": {
|
|
7209
|
+
"client_id": "dcr_eyJ2IjoxLCJhIjoiaW50ZXJuZXRkYXRhIiwibiI6IkV4YW1wbGUgQ0xJIn0.bm90LWEtcmVhbC1tYWMtZXhhbXBsZS1vbmx5LTAxMjM",
|
|
7210
|
+
"client_id_issued_at": "1792304178",
|
|
7211
|
+
"client_name": "Example CLI",
|
|
7212
|
+
"redirect_uris": [
|
|
7213
|
+
"http://127.0.0.1:8765/callback"
|
|
7214
|
+
],
|
|
7215
|
+
"token_endpoint_auth_method": "none"
|
|
7216
|
+
}
|
|
7217
|
+
},
|
|
7218
|
+
{
|
|
7219
|
+
"name": "redirect-uris-not-a-list",
|
|
7220
|
+
"status": 201,
|
|
7221
|
+
"body": {
|
|
7222
|
+
"client_id": "dcr_eyJ2IjoxLCJhIjoiaW50ZXJuZXRkYXRhIiwibiI6IkV4YW1wbGUgQ0xJIn0.bm90LWEtcmVhbC1tYWMtZXhhbXBsZS1vbmx5LTAxMjM",
|
|
7223
|
+
"client_id_issued_at": 1792304178,
|
|
7224
|
+
"client_name": "Example CLI",
|
|
7225
|
+
"redirect_uris": "http://127.0.0.1:8765/callback",
|
|
7226
|
+
"token_endpoint_auth_method": "none"
|
|
7227
|
+
}
|
|
7228
|
+
},
|
|
7229
|
+
{
|
|
7230
|
+
"name": "a-redirect-uri-not-a-string",
|
|
7231
|
+
"status": 201,
|
|
7232
|
+
"body": {
|
|
7233
|
+
"client_id": "dcr_eyJ2IjoxLCJhIjoiaW50ZXJuZXRkYXRhIiwibiI6IkV4YW1wbGUgQ0xJIn0.bm90LWEtcmVhbC1tYWMtZXhhbXBsZS1vbmx5LTAxMjM",
|
|
7234
|
+
"client_id_issued_at": 1792304178,
|
|
7235
|
+
"client_name": "Example CLI",
|
|
7236
|
+
"redirect_uris": [
|
|
7237
|
+
1
|
|
7238
|
+
],
|
|
7239
|
+
"token_endpoint_auth_method": "none"
|
|
7240
|
+
}
|
|
7241
|
+
},
|
|
7242
|
+
{
|
|
7243
|
+
"name": "scope-not-a-string",
|
|
7244
|
+
"status": 201,
|
|
7245
|
+
"body": {
|
|
7246
|
+
"client_id": "dcr_eyJ2IjoxLCJhIjoiaW50ZXJuZXRkYXRhIiwibiI6IkV4YW1wbGUgQ0xJIn0.bm90LWEtcmVhbC1tYWMtZXhhbXBsZS1vbmx5LTAxMjM",
|
|
7247
|
+
"client_id_issued_at": 1792304178,
|
|
7248
|
+
"client_name": "Example CLI",
|
|
7249
|
+
"redirect_uris": [
|
|
7250
|
+
"http://127.0.0.1:8765/callback"
|
|
7251
|
+
],
|
|
7252
|
+
"token_endpoint_auth_method": "none",
|
|
7253
|
+
"scope": [
|
|
7254
|
+
"apikeys.use"
|
|
7255
|
+
]
|
|
7256
|
+
}
|
|
7257
|
+
}
|
|
7258
|
+
]
|
|
7259
|
+
},
|
|
7260
|
+
"retries": [
|
|
7261
|
+
{
|
|
7262
|
+
"name": "register-retries-a-5xx",
|
|
7263
|
+
"args": {
|
|
7264
|
+
"redirectUris": [
|
|
7265
|
+
"http://127.0.0.1:8765/callback"
|
|
7266
|
+
]
|
|
7267
|
+
},
|
|
7268
|
+
"responses": [
|
|
7269
|
+
{
|
|
7270
|
+
"status": 503,
|
|
7271
|
+
"rawBody": ""
|
|
7272
|
+
},
|
|
7273
|
+
{
|
|
7274
|
+
"status": 201,
|
|
7275
|
+
"body": {
|
|
7276
|
+
"client_id": "dcr_eyJ2IjoxLCJhIjoiaW50ZXJuZXRkYXRhIiwibiI6IkV4YW1wbGUgQ0xJIn0.bm90LWEtcmVhbC1tYWMtZXhhbXBsZS1vbmx5LTAxMjM",
|
|
7277
|
+
"client_id_issued_at": 1792304178,
|
|
7278
|
+
"client_name": "Example CLI",
|
|
7279
|
+
"redirect_uris": [
|
|
7280
|
+
"http://127.0.0.1:8765/callback"
|
|
7281
|
+
],
|
|
7282
|
+
"grant_types": [
|
|
7283
|
+
"authorization_code",
|
|
7284
|
+
"refresh_token"
|
|
7285
|
+
],
|
|
7286
|
+
"response_types": [
|
|
7287
|
+
"code"
|
|
7288
|
+
],
|
|
7289
|
+
"token_endpoint_auth_method": "none",
|
|
7290
|
+
"scope": "apikeys.use"
|
|
7291
|
+
}
|
|
7292
|
+
}
|
|
7293
|
+
],
|
|
7294
|
+
"expect": {
|
|
7295
|
+
"requests": 2,
|
|
7296
|
+
"outcome": "ok"
|
|
7297
|
+
}
|
|
7298
|
+
},
|
|
7299
|
+
{
|
|
7300
|
+
"name": "register-retries-an-unreadable-2xx",
|
|
7301
|
+
"args": {
|
|
7302
|
+
"redirectUris": [
|
|
7303
|
+
"http://127.0.0.1:8765/callback"
|
|
7304
|
+
]
|
|
7305
|
+
},
|
|
7306
|
+
"responses": [
|
|
7307
|
+
{
|
|
7308
|
+
"status": 200,
|
|
7309
|
+
"rawBody": "<html><body>Sign in</body></html>"
|
|
7310
|
+
},
|
|
7311
|
+
{
|
|
7312
|
+
"status": 201,
|
|
7313
|
+
"body": {
|
|
7314
|
+
"client_id": "dcr_eyJ2IjoxLCJhIjoiaW50ZXJuZXRkYXRhIiwibiI6IkV4YW1wbGUgQ0xJIn0.bm90LWEtcmVhbC1tYWMtZXhhbXBsZS1vbmx5LTAxMjM",
|
|
7315
|
+
"client_id_issued_at": 1792304178,
|
|
7316
|
+
"client_name": "Example CLI",
|
|
7317
|
+
"redirect_uris": [
|
|
7318
|
+
"http://127.0.0.1:8765/callback"
|
|
7319
|
+
],
|
|
7320
|
+
"grant_types": [
|
|
7321
|
+
"authorization_code",
|
|
7322
|
+
"refresh_token"
|
|
7323
|
+
],
|
|
7324
|
+
"response_types": [
|
|
7325
|
+
"code"
|
|
7326
|
+
],
|
|
7327
|
+
"token_endpoint_auth_method": "none",
|
|
7328
|
+
"scope": "apikeys.use"
|
|
7329
|
+
}
|
|
7330
|
+
}
|
|
7331
|
+
],
|
|
7332
|
+
"expect": {
|
|
7333
|
+
"requests": 2,
|
|
7334
|
+
"outcome": "ok"
|
|
7335
|
+
}
|
|
7336
|
+
},
|
|
7337
|
+
{
|
|
7338
|
+
"name": "register-oauth-error-is-never-retried",
|
|
7339
|
+
"args": {
|
|
7340
|
+
"redirectUris": [
|
|
7341
|
+
"http://127.0.0.1:8765/callback"
|
|
7342
|
+
]
|
|
7343
|
+
},
|
|
7344
|
+
"responses": [
|
|
7345
|
+
{
|
|
7346
|
+
"status": 400,
|
|
7347
|
+
"body": {
|
|
7348
|
+
"error": "slow_down",
|
|
7349
|
+
"error_description": "too many requests; slow down and try again"
|
|
7350
|
+
}
|
|
7351
|
+
}
|
|
7352
|
+
],
|
|
7353
|
+
"expect": {
|
|
7354
|
+
"requests": 1,
|
|
7355
|
+
"outcome": "oauth",
|
|
7356
|
+
"errorCode": "slow_down"
|
|
7357
|
+
}
|
|
7358
|
+
}
|
|
7359
|
+
],
|
|
7360
|
+
"errors": [
|
|
7361
|
+
{
|
|
7362
|
+
"name": "a-refused-redirect-uri",
|
|
7363
|
+
"status": 400,
|
|
7364
|
+
"body": {
|
|
7365
|
+
"error": "invalid_redirect_uri",
|
|
7366
|
+
"error_description": "redirect_uris[0] must be https, or http on a loopback address"
|
|
7367
|
+
},
|
|
7368
|
+
"expect": {
|
|
7369
|
+
"type": "oauth",
|
|
7370
|
+
"errorCode": "invalid_redirect_uri",
|
|
7371
|
+
"errorDescription": "redirect_uris[0] must be https, or http on a loopback address",
|
|
7372
|
+
"status": 400,
|
|
7373
|
+
"kind": "bad_request",
|
|
7374
|
+
"retryable": false,
|
|
7375
|
+
"message": "invalid_redirect_uri: redirect_uris[0] must be https, or http on a loopback address"
|
|
7376
|
+
}
|
|
7377
|
+
},
|
|
7378
|
+
{
|
|
7379
|
+
"name": "refused-metadata",
|
|
7380
|
+
"status": 400,
|
|
7381
|
+
"body": {
|
|
7382
|
+
"error": "invalid_client_metadata",
|
|
7383
|
+
"error_description": "grant_types must include authorization_code"
|
|
7384
|
+
},
|
|
7385
|
+
"expect": {
|
|
7386
|
+
"type": "oauth",
|
|
7387
|
+
"errorCode": "invalid_client_metadata",
|
|
7388
|
+
"errorDescription": "grant_types must include authorization_code",
|
|
7389
|
+
"status": 400,
|
|
7390
|
+
"kind": "bad_request",
|
|
7391
|
+
"retryable": false,
|
|
7392
|
+
"message": "invalid_client_metadata: grant_types must include authorization_code"
|
|
7393
|
+
}
|
|
7394
|
+
},
|
|
7395
|
+
{
|
|
7396
|
+
"name": "a-server-without-registration",
|
|
7397
|
+
"status": 404,
|
|
7398
|
+
"rawBody": "Not Found",
|
|
7399
|
+
"expect": {
|
|
7400
|
+
"type": "client",
|
|
7401
|
+
"status": 404,
|
|
7402
|
+
"kind": "bad_request",
|
|
7403
|
+
"retryable": false
|
|
7404
|
+
}
|
|
7405
|
+
}
|
|
7406
|
+
]
|
|
6818
7407
|
}
|
|
6819
7408
|
},
|
|
6820
7409
|
"bogons": {
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|