django-esi 8.1.0__py3-none-any.whl

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 (100) hide show
  1. django_esi-8.1.0.dist-info/METADATA +93 -0
  2. django_esi-8.1.0.dist-info/RECORD +100 -0
  3. django_esi-8.1.0.dist-info/WHEEL +4 -0
  4. django_esi-8.1.0.dist-info/licenses/LICENSE +674 -0
  5. esi/__init__.py +7 -0
  6. esi/admin.py +42 -0
  7. esi/aiopenapi3/client.py +79 -0
  8. esi/aiopenapi3/plugins.py +224 -0
  9. esi/app_settings.py +112 -0
  10. esi/apps.py +11 -0
  11. esi/checks.py +56 -0
  12. esi/clients.py +657 -0
  13. esi/decorators.py +271 -0
  14. esi/errors.py +22 -0
  15. esi/exceptions.py +51 -0
  16. esi/helpers.py +63 -0
  17. esi/locale/cs_CZ/LC_MESSAGES/django.mo +0 -0
  18. esi/locale/cs_CZ/LC_MESSAGES/django.po +53 -0
  19. esi/locale/de/LC_MESSAGES/django.mo +0 -0
  20. esi/locale/de/LC_MESSAGES/django.po +58 -0
  21. esi/locale/en/LC_MESSAGES/django.mo +0 -0
  22. esi/locale/en/LC_MESSAGES/django.po +54 -0
  23. esi/locale/es/LC_MESSAGES/django.mo +0 -0
  24. esi/locale/es/LC_MESSAGES/django.po +59 -0
  25. esi/locale/fr_FR/LC_MESSAGES/django.mo +0 -0
  26. esi/locale/fr_FR/LC_MESSAGES/django.po +59 -0
  27. esi/locale/it_IT/LC_MESSAGES/django.mo +0 -0
  28. esi/locale/it_IT/LC_MESSAGES/django.po +59 -0
  29. esi/locale/ja/LC_MESSAGES/django.mo +0 -0
  30. esi/locale/ja/LC_MESSAGES/django.po +58 -0
  31. esi/locale/ko_KR/LC_MESSAGES/django.mo +0 -0
  32. esi/locale/ko_KR/LC_MESSAGES/django.po +58 -0
  33. esi/locale/nl_NL/LC_MESSAGES/django.mo +0 -0
  34. esi/locale/nl_NL/LC_MESSAGES/django.po +53 -0
  35. esi/locale/pl_PL/LC_MESSAGES/django.mo +0 -0
  36. esi/locale/pl_PL/LC_MESSAGES/django.po +53 -0
  37. esi/locale/ru/LC_MESSAGES/django.mo +0 -0
  38. esi/locale/ru/LC_MESSAGES/django.po +61 -0
  39. esi/locale/sk/LC_MESSAGES/django.mo +0 -0
  40. esi/locale/sk/LC_MESSAGES/django.po +55 -0
  41. esi/locale/uk/LC_MESSAGES/django.mo +0 -0
  42. esi/locale/uk/LC_MESSAGES/django.po +57 -0
  43. esi/locale/zh_Hans/LC_MESSAGES/django.mo +0 -0
  44. esi/locale/zh_Hans/LC_MESSAGES/django.po +58 -0
  45. esi/management/commands/__init__.py +0 -0
  46. esi/management/commands/esi_clear_spec_cache.py +21 -0
  47. esi/management/commands/generate_esi_stubs.py +661 -0
  48. esi/management/commands/migrate_to_ssov2.py +188 -0
  49. esi/managers.py +303 -0
  50. esi/managers.pyi +85 -0
  51. esi/migrations/0001_initial.py +55 -0
  52. esi/migrations/0002_scopes_20161208.py +56 -0
  53. esi/migrations/0003_hide_tokens_from_admin_site.py +23 -0
  54. esi/migrations/0004_remove_unique_access_token.py +18 -0
  55. esi/migrations/0005_remove_token_length_limit.py +23 -0
  56. esi/migrations/0006_remove_url_length_limit.py +18 -0
  57. esi/migrations/0007_fix_mysql_8_migration.py +18 -0
  58. esi/migrations/0008_nullable_refresh_token.py +18 -0
  59. esi/migrations/0009_set_old_tokens_to_sso_v1.py +18 -0
  60. esi/migrations/0010_set_new_tokens_to_sso_v2.py +18 -0
  61. esi/migrations/0011_add_token_indices.py +28 -0
  62. esi/migrations/0012_fix_token_type_choices.py +18 -0
  63. esi/migrations/0013_squashed_0012_fix_token_type_choices.py +57 -0
  64. esi/migrations/__init__.py +0 -0
  65. esi/models.py +349 -0
  66. esi/openapi_clients.py +1225 -0
  67. esi/rate_limiting.py +107 -0
  68. esi/signals.py +21 -0
  69. esi/static/esi/img/EVE_SSO_Login_Buttons_Large_Black.png +0 -0
  70. esi/static/esi/img/EVE_SSO_Login_Buttons_Large_White.png +0 -0
  71. esi/static/esi/img/EVE_SSO_Login_Buttons_Small_Black.png +0 -0
  72. esi/static/esi/img/EVE_SSO_Login_Buttons_Small_White.png +0 -0
  73. esi/stubs.py +2 -0
  74. esi/stubs.pyi +6807 -0
  75. esi/tasks.py +78 -0
  76. esi/templates/esi/select_token.html +116 -0
  77. esi/templatetags/__init__.py +0 -0
  78. esi/templatetags/scope_tags.py +8 -0
  79. esi/tests/__init__.py +134 -0
  80. esi/tests/client_authed_pilot.py +63 -0
  81. esi/tests/client_public_pilot.py +53 -0
  82. esi/tests/factories.py +47 -0
  83. esi/tests/factories_2.py +60 -0
  84. esi/tests/jwt_factory.py +135 -0
  85. esi/tests/test_checks.py +48 -0
  86. esi/tests/test_clients.py +1019 -0
  87. esi/tests/test_decorators.py +578 -0
  88. esi/tests/test_management_command.py +307 -0
  89. esi/tests/test_managers.py +673 -0
  90. esi/tests/test_models.py +403 -0
  91. esi/tests/test_openapi.json +854 -0
  92. esi/tests/test_openapi.py +1017 -0
  93. esi/tests/test_swagger.json +489 -0
  94. esi/tests/test_swagger_full.json +51112 -0
  95. esi/tests/test_tasks.py +116 -0
  96. esi/tests/test_templatetags.py +22 -0
  97. esi/tests/test_views.py +331 -0
  98. esi/tests/threading_pilot.py +69 -0
  99. esi/urls.py +9 -0
  100. esi/views.py +129 -0
@@ -0,0 +1,135 @@
1
+ """Factory for generating Eve Onlie conformant JWTs for testing."""
2
+
3
+ import datetime as dt
4
+
5
+ from jose import jwt
6
+ from pytz import utc
7
+
8
+ _RSA_PRIVATE_KEY = """
9
+ -----BEGIN PRIVATE KEY-----
10
+ MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC7VJTUt9Us8cKj
11
+ MzEfYyjiWA4R4/M2bS1GB4t7NXp98C3SC6dVMvDuictGeurT8jNbvJZHtCSuYEvu
12
+ NMoSfm76oqFvAp8Gy0iz5sxjZmSnXyCdPEovGhLa0VzMaQ8s+CLOyS56YyCFGeJZ
13
+ qgtzJ6GR3eqoYSW9b9UMvkBpZODSctWSNGj3P7jRFDO5VoTwCQAWbFnOjDfH5Ulg
14
+ p2PKSQnSJP3AJLQNFNe7br1XbrhV//eO+t51mIpGSDCUv3E0DDFcWDTH9cXDTTlR
15
+ ZVEiR2BwpZOOkE/Z0/BVnhZYL71oZV34bKfWjQIt6V/isSMahdsAASACp4ZTGtwi
16
+ VuNd9tybAgMBAAECggEBAKTmjaS6tkK8BlPXClTQ2vpz/N6uxDeS35mXpqasqskV
17
+ laAidgg/sWqpjXDbXr93otIMLlWsM+X0CqMDgSXKejLS2jx4GDjI1ZTXg++0AMJ8
18
+ sJ74pWzVDOfmCEQ/7wXs3+cbnXhKriO8Z036q92Qc1+N87SI38nkGa0ABH9CN83H
19
+ mQqt4fB7UdHzuIRe/me2PGhIq5ZBzj6h3BpoPGzEP+x3l9YmK8t/1cN0pqI+dQwY
20
+ dgfGjackLu/2qH80MCF7IyQaseZUOJyKrCLtSD/Iixv/hzDEUPfOCjFDgTpzf3cw
21
+ ta8+oE4wHCo1iI1/4TlPkwmXx4qSXtmw4aQPz7IDQvECgYEA8KNThCO2gsC2I9PQ
22
+ DM/8Cw0O983WCDY+oi+7JPiNAJwv5DYBqEZB1QYdj06YD16XlC/HAZMsMku1na2T
23
+ N0driwenQQWzoev3g2S7gRDoS/FCJSI3jJ+kjgtaA7Qmzlgk1TxODN+G1H91HW7t
24
+ 0l7VnL27IWyYo2qRRK3jzxqUiPUCgYEAx0oQs2reBQGMVZnApD1jeq7n4MvNLcPv
25
+ t8b/eU9iUv6Y4Mj0Suo/AU8lYZXm8ubbqAlwz2VSVunD2tOplHyMUrtCtObAfVDU
26
+ AhCndKaA9gApgfb3xw1IKbuQ1u4IF1FJl3VtumfQn//LiH1B3rXhcdyo3/vIttEk
27
+ 48RakUKClU8CgYEAzV7W3COOlDDcQd935DdtKBFRAPRPAlspQUnzMi5eSHMD/ISL
28
+ DY5IiQHbIH83D4bvXq0X7qQoSBSNP7Dvv3HYuqMhf0DaegrlBuJllFVVq9qPVRnK
29
+ xt1Il2HgxOBvbhOT+9in1BzA+YJ99UzC85O0Qz06A+CmtHEy4aZ2kj5hHjECgYEA
30
+ mNS4+A8Fkss8Js1RieK2LniBxMgmYml3pfVLKGnzmng7H2+cwPLhPIzIuwytXywh
31
+ 2bzbsYEfYx3EoEVgMEpPhoarQnYPukrJO4gwE2o5Te6T5mJSZGlQJQj9q4ZB2Dfz
32
+ et6INsK0oG8XVGXSpQvQh3RUYekCZQkBBFcpqWpbIEsCgYAnM3DQf3FJoSnXaMhr
33
+ VBIovic5l0xFkEHskAjFTevO86Fsz1C2aSeRKSqGFoOQ0tmJzBEs1R6KqnHInicD
34
+ TQrKhArgLXX4v3CddjfTRJkFWDbE/CkvKZNOrcf1nhaGCPspRJj2KUkj1Fhl9Cnc
35
+ dn/RsYEONbwQSjIfMPkvxF+8HQ==
36
+ -----END PRIVATE KEY-----
37
+ """
38
+
39
+ _RSA_PUBLIC_KEY = """
40
+ -----BEGIN PUBLIC KEY-----
41
+ MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu1SU1LfVLPHCozMxH2Mo
42
+ 4lgOEePzNm0tRgeLezV6ffAt0gunVTLw7onLRnrq0/IzW7yWR7QkrmBL7jTKEn5u
43
+ +qKhbwKfBstIs+bMY2Zkp18gnTxKLxoS2tFczGkPLPgizskuemMghRniWaoLcyeh
44
+ kd3qqGElvW/VDL5AaWTg0nLVkjRo9z+40RQzuVaE8AkAFmxZzow3x+VJYKdjykkJ
45
+ 0iT9wCS0DRTXu269V264Vf/3jvredZiKRkgwlL9xNAwxXFg0x/XFw005UWVRIkdg
46
+ cKWTjpBP2dPwVZ4WWC+9aGVd+Gyn1o0CLelf4rEjGoXbAAEgAqeGUxrcIlbjXfbc
47
+ mwIDAQAB
48
+ -----END PUBLIC KEY-----
49
+ """
50
+ _JWK_PUBLIC_KEY = """u1SU1LfVLPHCozMxH2Mo4lgOEePzNm0tRgeLezV6ffAt0gunVTLw7onLRnrq0_IzW7yWR7QkrmBL7jTKEn5u-qKhbwKfBstIs-bMY2Zkp18gnTxKLxoS2tFczGkPLPgizskuemMghRniWaoLcyehkd3qqGElvW_VDL5AaWTg0nLVkjRo9z-40RQzuVaE8AkAFmxZzow3x-VJYKdjykkJ0iT9wCS0DRTXu269V264Vf_3jvredZiKRkgwlL9xNAwxXFg0x_XFw005UWVRIkdgcKWTjpBP2dPwVZ4WWC-9aGVd-Gyn1o0CLelf4rEjGoXbAAEgAqeGUxrcIlbjXfbcmw""" # noqa: E501
51
+ _ALGORITHM = jwt.ALGORITHMS.RS256
52
+ _AUDIENCE = "EVE Online"
53
+ _HEADERS = {"alg": "RS256", "kid": "JWT-Signature-Key", "typ": "JWT"}
54
+ _ISSUER = "login.eveonline.com"
55
+
56
+
57
+ def generate_jwk():
58
+ return {
59
+ "alg": _ALGORITHM,
60
+ "e": "AQAB",
61
+ "kid": "JWT-Signature-Key",
62
+ "kty": "RSA",
63
+ "n": _JWK_PUBLIC_KEY,
64
+ "use": "sig",
65
+ }
66
+
67
+
68
+ def _generate_claims(
69
+ issued_at: dt.datetime,
70
+ character_id: int,
71
+ character_name: str,
72
+ issuer=None,
73
+ audience=None,
74
+ ) -> dict:
75
+ if not issuer:
76
+ issuer = _ISSUER
77
+ expires_at = issued_at + dt.timedelta(minutes=20)
78
+ claims = {
79
+ "scp": "esi-characters.read_medals.v1",
80
+ "jti": "xxx",
81
+ "kid": "JWT-Signature-Key",
82
+ "sub": f"CHARACTER:EVE:{character_id}",
83
+ "azp": "yyy",
84
+ "tenant": "tranquility",
85
+ "tier": "live",
86
+ "region": "world",
87
+ "name": str(character_name),
88
+ "owner": "OWNER-HASH",
89
+ "exp": int(expires_at.timestamp()),
90
+ "iat": int(issued_at.timestamp()),
91
+ "iss": _ISSUER,
92
+ }
93
+ if audience is None:
94
+ audience = _AUDIENCE
95
+ if audience:
96
+ claims["aud"] = audience
97
+ return claims
98
+
99
+
100
+ def generate_token(
101
+ character_id: int,
102
+ character_name: str,
103
+ issued_at: dt.datetime = None,
104
+ issuer=None,
105
+ audience=None,
106
+ ) -> tuple[str, dict]:
107
+ """Generate a JWT for Eve Online."""
108
+ if not issued_at:
109
+ issued_at = dt.datetime.now(tz=utc)
110
+ claims = _generate_claims(
111
+ issued_at=issued_at,
112
+ character_id=character_id,
113
+ character_name=character_name,
114
+ issuer=issuer,
115
+ audience=audience,
116
+ )
117
+ token_string = jwt.encode(
118
+ claims=claims, key=_RSA_PRIVATE_KEY, algorithm=_ALGORITHM, headers=_HEADERS
119
+ )
120
+ return token_string, claims
121
+
122
+
123
+ def validate():
124
+ issued_at = dt.datetime.now(tz=utc)
125
+ token, claims = generate_token(
126
+ issued_at=issued_at, character_id=1001, character_name="Bruce Wayne"
127
+ )
128
+ new_claims = jwt.decode(
129
+ token=token, key=generate_jwk(), audience=_AUDIENCE, issuer=_ISSUER
130
+ )
131
+ print("Validate successful: ", claims == new_claims)
132
+
133
+
134
+ if __name__ == "__main__":
135
+ validate()
@@ -0,0 +1,48 @@
1
+ """unit tests for esi checks"""
2
+
3
+ from django.conf import settings
4
+ from django.test import TestCase, override_settings
5
+
6
+ from ..checks import check_sso_application_settings
7
+
8
+
9
+ class TestCheckSsoApplicationSettings(TestCase):
10
+
11
+ @override_settings(
12
+ ESI_SSO_CLIENT_ID='123', ESI_SSO_CLIENT_SECRET='abc', ESI_SSO_CALLBACK_URL='xyz'
13
+ )
14
+ def test_settings_ok(self):
15
+ errors = check_sso_application_settings()
16
+ self.assertEqual(len(errors), 0)
17
+
18
+ @override_settings(ESI_SSO_CLIENT_SECRET='abc', ESI_SSO_CALLBACK_URL='xyz')
19
+ def test_settings_incomplete_ESI_SSO_CLIENT_ID(self):
20
+ del settings.ESI_SSO_CLIENT_ID
21
+ errors = check_sso_application_settings()
22
+ self.assertEqual(len(errors), 1)
23
+
24
+ @override_settings(ESI_SSO_CLIENT_ID='123', ESI_SSO_CALLBACK_URL='xyz')
25
+ def test_settings_incomplete_ESI_SSO_CLIENT_SECRET(self):
26
+ del settings.ESI_SSO_CLIENT_SECRET
27
+ errors = check_sso_application_settings()
28
+ self.assertEqual(len(errors), 1)
29
+
30
+ @override_settings(ESI_SSO_CLIENT_ID='123', ESI_SSO_CLIENT_SECRET='abc')
31
+ def test_settings_incomplete_ESI_SSO_CALLBACK_URL(self):
32
+ del settings.ESI_SSO_CALLBACK_URL
33
+ errors = check_sso_application_settings()
34
+ self.assertEqual(len(errors), 1)
35
+
36
+ @override_settings(ESI_SSO_CLIENT_ID='123', ESI_SSO_CLIENT_SECRET='abc', DEBUG=True)
37
+ def test_settings_incomplete_debug_mode(self):
38
+ del settings.ESI_SSO_CALLBACK_URL
39
+ errors = check_sso_application_settings()
40
+ self.assertEqual(len(errors), 1)
41
+
42
+ @override_settings(
43
+ ESI_SSO_CLIENT_ID='123', ESI_SSO_CLIENT_SECRET='abc', DEBUG=False
44
+ )
45
+ def test_settings_incomplete_non_debug_mode(self):
46
+ del settings.ESI_SSO_CALLBACK_URL
47
+ errors = check_sso_application_settings()
48
+ self.assertEqual(len(errors), 1)