django-trusted-devices 1.1__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 (26) hide show
  1. django_trusted_devices-1.1/LICENSE +21 -0
  2. django_trusted_devices-1.1/PKG-INFO +277 -0
  3. django_trusted_devices-1.1/README.md +238 -0
  4. django_trusted_devices-1.1/pyproject.toml +68 -0
  5. django_trusted_devices-1.1/setup.cfg +4 -0
  6. django_trusted_devices-1.1/src/django_trusted_devices.egg-info/PKG-INFO +277 -0
  7. django_trusted_devices-1.1/src/django_trusted_devices.egg-info/SOURCES.txt +24 -0
  8. django_trusted_devices-1.1/src/django_trusted_devices.egg-info/dependency_links.txt +1 -0
  9. django_trusted_devices-1.1/src/django_trusted_devices.egg-info/requires.txt +19 -0
  10. django_trusted_devices-1.1/src/django_trusted_devices.egg-info/top_level.txt +1 -0
  11. django_trusted_devices-1.1/src/trusted_devices/__init__.py +0 -0
  12. django_trusted_devices-1.1/src/trusted_devices/admin.py +0 -0
  13. django_trusted_devices-1.1/src/trusted_devices/apps.py +9 -0
  14. django_trusted_devices-1.1/src/trusted_devices/authentication.py +74 -0
  15. django_trusted_devices-1.1/src/trusted_devices/migrations/0001_initial.py +116 -0
  16. django_trusted_devices-1.1/src/trusted_devices/migrations/__init__.py +0 -0
  17. django_trusted_devices-1.1/src/trusted_devices/models.py +100 -0
  18. django_trusted_devices-1.1/src/trusted_devices/permissions.py +127 -0
  19. django_trusted_devices-1.1/src/trusted_devices/serializers.py +183 -0
  20. django_trusted_devices-1.1/src/trusted_devices/settings.py +36 -0
  21. django_trusted_devices-1.1/src/trusted_devices/signals.py +15 -0
  22. django_trusted_devices-1.1/src/trusted_devices/tests.py +0 -0
  23. django_trusted_devices-1.1/src/trusted_devices/tokens.py +17 -0
  24. django_trusted_devices-1.1/src/trusted_devices/urls.py +30 -0
  25. django_trusted_devices-1.1/src/trusted_devices/utils.py +76 -0
  26. django_trusted_devices-1.1/src/trusted_devices/views.py +73 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Jakhongir Ganiev
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,277 @@
1
+ Metadata-Version: 2.4
2
+ Name: django-trusted-devices
3
+ Version: 1.1
4
+ Summary: Secure and manage trusted login devices for Django users
5
+ Author-email: Jakhongir Ganiev <contact@jakhongir.dev>
6
+ License: MIT
7
+ Keywords: django,trusted devices,user security,sessions,login,djangorestframework
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Framework :: Django
10
+ Classifier: Framework :: Django :: 4.2
11
+ Classifier: Framework :: Django :: 5.0
12
+ Classifier: Framework :: Django :: 5.1
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Requires-Python: >=3.13
19
+ Description-Content-Type: text/markdown
20
+ License-File: LICENSE
21
+ Requires-Dist: django<5.3,>=4.2
22
+ Requires-Dist: djangorestframework>=3.14.0
23
+ Requires-Dist: djangorestframework-simplejwt>=5.5.0
24
+ Requires-Dist: drf-yasg>=1.21.10
25
+ Requires-Dist: httpx>=0.28.1
26
+ Provides-Extra: docs
27
+ Requires-Dist: mkdocs; extra == "docs"
28
+ Requires-Dist: mkdocs-material; extra == "docs"
29
+ Provides-Extra: dev
30
+ Requires-Dist: black>=25.1.0; extra == "dev"
31
+ Requires-Dist: build>=1.2.2.post1; extra == "dev"
32
+ Requires-Dist: flake8>=7.2.0; extra == "dev"
33
+ Requires-Dist: isort>=6.0.1; extra == "dev"
34
+ Requires-Dist: pytest>=8.3.5; extra == "dev"
35
+ Requires-Dist: pytest-cov>=6.1.1; extra == "dev"
36
+ Requires-Dist: pytest-django>=4.11.1; extra == "dev"
37
+ Requires-Dist: twine>=6.1.0; extra == "dev"
38
+ Dynamic: license-file
39
+
40
+ # πŸ” Django Trusted Device
41
+
42
+ A plug-and-play Django app that adds **trusted device management** to your API authentication system using
43
+ `djangorestframework-simplejwt`. Automatically associates tokens with user devices, tracks login locations,
44
+ and enables per-device control over access and session management.
45
+
46
+ ---
47
+ [![Docs](https://img.shields.io/badge/docs-view-green?style=for-the-badge&logo=readthedocs)](https://ganiyevuz.github.io/django-trusted-devices/)
48
+
49
+
50
+ ## πŸš€ Features
51
+
52
+ * πŸ”‘ **JWT tokens** include a unique `device_uid`
53
+ * 🌍 **Auto-detect IP, region, and city** via [ipapi.co](https://ipapi.co)
54
+ * πŸ›‘οΈ **Per-device session tracking** with update/delete restrictions
55
+ * πŸ”„ **Custom** `TokenObtainPair`, `TokenRefresh`, and `TokenVerify` views
56
+ * πŸšͺ **Logout unwanted sessions** from the device list
57
+ * 🧼 **Automatic cleanup**, optional global control rules
58
+ * 🧩 **API-ready** – supports DRF out of the box
59
+ * βš™οΈ **Fully customizable** via `TRUSTED_DEVICE` Django settings
60
+ * 🚫 **Rejects refresh/verify** from unknown or expired devices
61
+
62
+ ---
63
+
64
+ ## πŸ“¦ Installation
65
+
66
+ ```bash
67
+ pip install django-trusted-device
68
+ ```
69
+
70
+ Add to your `INSTALLED_APPS`:
71
+
72
+ ```python
73
+ INSTALLED_APPS = [
74
+ ...
75
+ 'trusted_devices',
76
+ 'rest_framework_simplejwt.token_blacklist',
77
+ ]
78
+ ```
79
+
80
+ Run migrations:
81
+
82
+ ```bash
83
+ python manage.py migrate
84
+ ```
85
+
86
+ ---
87
+
88
+ ## βš™οΈ Configuration
89
+
90
+ Customize behavior in `settings.py`:
91
+
92
+ ```python
93
+ TRUSTED_DEVICE = {
94
+ "DELETE_DELAY_MINUTES": 60 * 24 * 7, # 7 days
95
+ "UPDATE_DELAY_MINUTES": 60, # 1 hour
96
+ "ALLOW_GLOBAL_DELETE": True,
97
+ "ALLOW_GLOBAL_UPDATE": True,
98
+ }
99
+ ```
100
+
101
+ ---
102
+
103
+ ## 🧩 Usage
104
+
105
+
106
+ ## πŸ” SimpleJWT configuration
107
+
108
+ Replace default SimpleJWT serializers with TrustedDevice serializers.:
109
+
110
+ ```python
111
+ from datetime import timedelta
112
+
113
+ REST_FRAMEWORK = {
114
+ 'DEFAULT_AUTHENTICATION_CLASSES': (
115
+ 'trusted_devices.authentication.TrustedDeviceAuthentication',
116
+ ),
117
+ }
118
+
119
+ SIMPLE_JWT = {
120
+ "ACCESS_TOKEN_LIFETIME": timedelta(minutes=60),
121
+ "REFRESH_TOKEN_LIFETIME": timedelta(days=30),
122
+ "AUTH_HEADER_TYPES": ("Bearer",),
123
+ "TOKEN_OBTAIN_SERIALIZER": 'trusted_devices.serializers.TrustedDeviceTokenObtainPairSerializer',
124
+ "TOKEN_REFRESH_SERIALIZER": 'trusted_devices.serializers.TrustedDeviceTokenRefreshSerializer',
125
+ "TOKEN_VERIFY_SERIALIZER": 'trusted_devices.serializers.TrustedDeviceTokenVerifySerializer',
126
+ }
127
+
128
+ ```
129
+
130
+ ### πŸ” Custom Token Views
131
+
132
+ Replace the default SimpleJWT views with:
133
+
134
+ ```python
135
+ from trusted_devices.views import (
136
+ TrustedDeviceTokenObtainPairView,
137
+ TrustedDeviceTokenRefreshView,
138
+ TrustedDeviceTokenVerifyView,
139
+ )
140
+
141
+ urlpatterns = [
142
+ path('api/token/', TrustedDeviceTokenObtainPairView.as_view(), name='token_obtain_pair'),
143
+ path('api/token/refresh/', TrustedDeviceTokenRefreshView.as_view(), name='token_refresh'),
144
+ path('api/token/verify/', TrustedDeviceTokenVerifyView.as_view(), name='token_verify'),
145
+ ]
146
+ ```
147
+
148
+ ---
149
+
150
+ ### πŸ“‘ Device Management API
151
+
152
+ Use the provided `TrustedDeviceViewSet`:
153
+
154
+ ```python
155
+ from trusted_devices.views import TrustedDeviceViewSet
156
+
157
+ router.register(r'trusted-devices', TrustedDeviceViewSet, basename='trusted-device')
158
+ ```
159
+
160
+ Endpoints:
161
+
162
+ * `GET /trusted-devices` β€” List all trusted devices
163
+ * `DELETE /trusted-devices/{device_uid}` β€” Delete a device
164
+ * `PATCH /trusted-devices/{device_uid}` β€” Update device permissions
165
+
166
+ ---
167
+
168
+ ## πŸ‘€ Device Model
169
+
170
+ Each trusted device includes:
171
+
172
+ * `device_uid`: Unique UUID
173
+ * `user_agent`: Browser or device string
174
+ * `ip_address`: IP address
175
+ * `country`, `region`, `city`: Geolocation (via `ipapi.co`)
176
+ * `last_seen`, `created_at`: Timestamps
177
+ * `can_delete_other_devices`, `can_update_other_devices`: Optional privileges
178
+
179
+ ---
180
+
181
+ ## 🧠 How It Works
182
+
183
+ 1. During login, a `device_uid` is generated and embedded in the token.
184
+ 2. Clients use that token (with `device_uid`) for refresh/verify.
185
+ 3. Each request is linked to a known device.
186
+ 4. Users can manage or restrict their devices via API or Admin.
187
+
188
+ ---
189
+
190
+ ## πŸ§ͺ Testing Locally
191
+
192
+ ```bash
193
+ # 🧩 Create and activate a uv-managed virtual environment
194
+ uv venv
195
+ source .venv/bin/activate # Windows: .venv\Scripts\activate
196
+
197
+ # πŸ“¦ Install the package in editable mode with dev extras
198
+ uv pip install -e ".[dev]"
199
+
200
+ # πŸ§ͺ Run the test suite
201
+ pytest
202
+ ```
203
+
204
+ ---
205
+
206
+ ## 🧱 Dependencies
207
+
208
+ * Django
209
+ * Django REST Framework
210
+ * djangorestframework-simplejwt
211
+ * [ipapi.co](https://ipapi.co) (for IP geolocation)
212
+
213
+ ---
214
+
215
+ ## πŸ—ƒοΈ Model Snapshot
216
+
217
+ | Field | Purpose |
218
+ | -------------------------- | ------------------- |
219
+ | `device_uid` | UUID primary key |
220
+ | `user_agent`, `ip_address` | Device fingerprint |
221
+ | `country / region / city` | Geo‑lookup |
222
+ | `last_seen / created_at` | Activity timestamps |
223
+ | `can_update_other_devices` | Granular permission |
224
+ | `can_delete_other_devices` | Granular permission |
225
+
226
+ ---
227
+
228
+ ## 🀝 Collaboration & Contributing
229
+
230
+ We love community contributions! To collaborate:
231
+
232
+ 1. **Fork** the repo and create a feature branch:
233
+
234
+ ```bash
235
+ git checkout -b feature/my-amazing-idea
236
+ ```
237
+
238
+ 2. **Follow code style** – run:
239
+
240
+ ```bash
241
+ make lint # runs flake8, isort, black
242
+ ```
243
+
244
+ 3. **Write & run tests**:
245
+
246
+ ```bash
247
+ pytest
248
+ ```
249
+
250
+ 4. **Commit** with clear messages and open a **Pull Request**.
251
+ GitHub Actions will lint + test your branch automatically.
252
+
253
+ ---
254
+
255
+ ### πŸ—£οΈ Discussions & Issues
256
+
257
+ * πŸ’‘ Questions / ideas β†’ [GitHub Discussions](https://github.com/ganiyevuz/django-trusted-devices/discussions)
258
+ * πŸ› Bugs / feature requests β†’ [GitHub Issues](https://github.com/ganiyevuz/django-trusted-devices/issues)
259
+
260
+ ---
261
+
262
+ ### πŸ›  Maintainer Workflow
263
+
264
+ * PRs require at least one approval and passing CI
265
+ * We **squash‑merge** to keep history clean
266
+ * Follows **Semantic Versioning** (`MAJOR.MINOR.PATCH`), tagged as `vX.Y.Z`
267
+
268
+ ---
269
+
270
+ ## πŸ“„ License
271
+
272
+ [MIT](LICENSE)
273
+
274
+ ---
275
+
276
+ Made with ❀️ by [Jahongir Ganiev](https://github.com/ganiyevuz)
277
+ Security questions or commercial support? Open an issue or email **[contact@jakhongir.dev](mailto:contact@jakhongir.dev)**
@@ -0,0 +1,238 @@
1
+ # πŸ” Django Trusted Device
2
+
3
+ A plug-and-play Django app that adds **trusted device management** to your API authentication system using
4
+ `djangorestframework-simplejwt`. Automatically associates tokens with user devices, tracks login locations,
5
+ and enables per-device control over access and session management.
6
+
7
+ ---
8
+ [![Docs](https://img.shields.io/badge/docs-view-green?style=for-the-badge&logo=readthedocs)](https://ganiyevuz.github.io/django-trusted-devices/)
9
+
10
+
11
+ ## πŸš€ Features
12
+
13
+ * πŸ”‘ **JWT tokens** include a unique `device_uid`
14
+ * 🌍 **Auto-detect IP, region, and city** via [ipapi.co](https://ipapi.co)
15
+ * πŸ›‘οΈ **Per-device session tracking** with update/delete restrictions
16
+ * πŸ”„ **Custom** `TokenObtainPair`, `TokenRefresh`, and `TokenVerify` views
17
+ * πŸšͺ **Logout unwanted sessions** from the device list
18
+ * 🧼 **Automatic cleanup**, optional global control rules
19
+ * 🧩 **API-ready** – supports DRF out of the box
20
+ * βš™οΈ **Fully customizable** via `TRUSTED_DEVICE` Django settings
21
+ * 🚫 **Rejects refresh/verify** from unknown or expired devices
22
+
23
+ ---
24
+
25
+ ## πŸ“¦ Installation
26
+
27
+ ```bash
28
+ pip install django-trusted-device
29
+ ```
30
+
31
+ Add to your `INSTALLED_APPS`:
32
+
33
+ ```python
34
+ INSTALLED_APPS = [
35
+ ...
36
+ 'trusted_devices',
37
+ 'rest_framework_simplejwt.token_blacklist',
38
+ ]
39
+ ```
40
+
41
+ Run migrations:
42
+
43
+ ```bash
44
+ python manage.py migrate
45
+ ```
46
+
47
+ ---
48
+
49
+ ## βš™οΈ Configuration
50
+
51
+ Customize behavior in `settings.py`:
52
+
53
+ ```python
54
+ TRUSTED_DEVICE = {
55
+ "DELETE_DELAY_MINUTES": 60 * 24 * 7, # 7 days
56
+ "UPDATE_DELAY_MINUTES": 60, # 1 hour
57
+ "ALLOW_GLOBAL_DELETE": True,
58
+ "ALLOW_GLOBAL_UPDATE": True,
59
+ }
60
+ ```
61
+
62
+ ---
63
+
64
+ ## 🧩 Usage
65
+
66
+
67
+ ## πŸ” SimpleJWT configuration
68
+
69
+ Replace default SimpleJWT serializers with TrustedDevice serializers.:
70
+
71
+ ```python
72
+ from datetime import timedelta
73
+
74
+ REST_FRAMEWORK = {
75
+ 'DEFAULT_AUTHENTICATION_CLASSES': (
76
+ 'trusted_devices.authentication.TrustedDeviceAuthentication',
77
+ ),
78
+ }
79
+
80
+ SIMPLE_JWT = {
81
+ "ACCESS_TOKEN_LIFETIME": timedelta(minutes=60),
82
+ "REFRESH_TOKEN_LIFETIME": timedelta(days=30),
83
+ "AUTH_HEADER_TYPES": ("Bearer",),
84
+ "TOKEN_OBTAIN_SERIALIZER": 'trusted_devices.serializers.TrustedDeviceTokenObtainPairSerializer',
85
+ "TOKEN_REFRESH_SERIALIZER": 'trusted_devices.serializers.TrustedDeviceTokenRefreshSerializer',
86
+ "TOKEN_VERIFY_SERIALIZER": 'trusted_devices.serializers.TrustedDeviceTokenVerifySerializer',
87
+ }
88
+
89
+ ```
90
+
91
+ ### πŸ” Custom Token Views
92
+
93
+ Replace the default SimpleJWT views with:
94
+
95
+ ```python
96
+ from trusted_devices.views import (
97
+ TrustedDeviceTokenObtainPairView,
98
+ TrustedDeviceTokenRefreshView,
99
+ TrustedDeviceTokenVerifyView,
100
+ )
101
+
102
+ urlpatterns = [
103
+ path('api/token/', TrustedDeviceTokenObtainPairView.as_view(), name='token_obtain_pair'),
104
+ path('api/token/refresh/', TrustedDeviceTokenRefreshView.as_view(), name='token_refresh'),
105
+ path('api/token/verify/', TrustedDeviceTokenVerifyView.as_view(), name='token_verify'),
106
+ ]
107
+ ```
108
+
109
+ ---
110
+
111
+ ### πŸ“‘ Device Management API
112
+
113
+ Use the provided `TrustedDeviceViewSet`:
114
+
115
+ ```python
116
+ from trusted_devices.views import TrustedDeviceViewSet
117
+
118
+ router.register(r'trusted-devices', TrustedDeviceViewSet, basename='trusted-device')
119
+ ```
120
+
121
+ Endpoints:
122
+
123
+ * `GET /trusted-devices` β€” List all trusted devices
124
+ * `DELETE /trusted-devices/{device_uid}` β€” Delete a device
125
+ * `PATCH /trusted-devices/{device_uid}` β€” Update device permissions
126
+
127
+ ---
128
+
129
+ ## πŸ‘€ Device Model
130
+
131
+ Each trusted device includes:
132
+
133
+ * `device_uid`: Unique UUID
134
+ * `user_agent`: Browser or device string
135
+ * `ip_address`: IP address
136
+ * `country`, `region`, `city`: Geolocation (via `ipapi.co`)
137
+ * `last_seen`, `created_at`: Timestamps
138
+ * `can_delete_other_devices`, `can_update_other_devices`: Optional privileges
139
+
140
+ ---
141
+
142
+ ## 🧠 How It Works
143
+
144
+ 1. During login, a `device_uid` is generated and embedded in the token.
145
+ 2. Clients use that token (with `device_uid`) for refresh/verify.
146
+ 3. Each request is linked to a known device.
147
+ 4. Users can manage or restrict their devices via API or Admin.
148
+
149
+ ---
150
+
151
+ ## πŸ§ͺ Testing Locally
152
+
153
+ ```bash
154
+ # 🧩 Create and activate a uv-managed virtual environment
155
+ uv venv
156
+ source .venv/bin/activate # Windows: .venv\Scripts\activate
157
+
158
+ # πŸ“¦ Install the package in editable mode with dev extras
159
+ uv pip install -e ".[dev]"
160
+
161
+ # πŸ§ͺ Run the test suite
162
+ pytest
163
+ ```
164
+
165
+ ---
166
+
167
+ ## 🧱 Dependencies
168
+
169
+ * Django
170
+ * Django REST Framework
171
+ * djangorestframework-simplejwt
172
+ * [ipapi.co](https://ipapi.co) (for IP geolocation)
173
+
174
+ ---
175
+
176
+ ## πŸ—ƒοΈ Model Snapshot
177
+
178
+ | Field | Purpose |
179
+ | -------------------------- | ------------------- |
180
+ | `device_uid` | UUID primary key |
181
+ | `user_agent`, `ip_address` | Device fingerprint |
182
+ | `country / region / city` | Geo‑lookup |
183
+ | `last_seen / created_at` | Activity timestamps |
184
+ | `can_update_other_devices` | Granular permission |
185
+ | `can_delete_other_devices` | Granular permission |
186
+
187
+ ---
188
+
189
+ ## 🀝 Collaboration & Contributing
190
+
191
+ We love community contributions! To collaborate:
192
+
193
+ 1. **Fork** the repo and create a feature branch:
194
+
195
+ ```bash
196
+ git checkout -b feature/my-amazing-idea
197
+ ```
198
+
199
+ 2. **Follow code style** – run:
200
+
201
+ ```bash
202
+ make lint # runs flake8, isort, black
203
+ ```
204
+
205
+ 3. **Write & run tests**:
206
+
207
+ ```bash
208
+ pytest
209
+ ```
210
+
211
+ 4. **Commit** with clear messages and open a **Pull Request**.
212
+ GitHub Actions will lint + test your branch automatically.
213
+
214
+ ---
215
+
216
+ ### πŸ—£οΈ Discussions & Issues
217
+
218
+ * πŸ’‘ Questions / ideas β†’ [GitHub Discussions](https://github.com/ganiyevuz/django-trusted-devices/discussions)
219
+ * πŸ› Bugs / feature requests β†’ [GitHub Issues](https://github.com/ganiyevuz/django-trusted-devices/issues)
220
+
221
+ ---
222
+
223
+ ### πŸ›  Maintainer Workflow
224
+
225
+ * PRs require at least one approval and passing CI
226
+ * We **squash‑merge** to keep history clean
227
+ * Follows **Semantic Versioning** (`MAJOR.MINOR.PATCH`), tagged as `vX.Y.Z`
228
+
229
+ ---
230
+
231
+ ## πŸ“„ License
232
+
233
+ [MIT](LICENSE)
234
+
235
+ ---
236
+
237
+ Made with ❀️ by [Jahongir Ganiev](https://github.com/ganiyevuz)
238
+ Security questions or commercial support? Open an issue or email **[contact@jakhongir.dev](mailto:contact@jakhongir.dev)**
@@ -0,0 +1,68 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "django-trusted-devices"
7
+ version = "v1.1"
8
+ description = "Secure and manage trusted login devices for Django users"
9
+ readme = "README.md"
10
+ requires-python = ">=3.13"
11
+ license = { text = "MIT" }
12
+ authors = [
13
+ { name = "Jakhongir Ganiev", email = "contact@jakhongir.dev" }
14
+ ]
15
+ classifiers = [
16
+ "Development Status :: 3 - Alpha",
17
+ "Framework :: Django",
18
+ "Framework :: Django :: 4.2",
19
+ "Framework :: Django :: 5.0",
20
+ "Framework :: Django :: 5.1",
21
+ "Intended Audience :: Developers",
22
+ "License :: OSI Approved :: MIT License",
23
+ "Programming Language :: Python :: 3.10",
24
+ "Programming Language :: Python :: 3.11",
25
+ "Programming Language :: Python :: 3.12",
26
+ ]
27
+ keywords = ["django", "trusted devices", "user security", "sessions", "login", "djangorestframework"]
28
+
29
+ dependencies = [
30
+ "django>=4.2,<5.3",
31
+ "djangorestframework>=3.14.0",
32
+ "djangorestframework-simplejwt>=5.5.0",
33
+ "drf-yasg>=1.21.10",
34
+ "httpx>=0.28.1",
35
+ ]
36
+
37
+
38
+ [project.optional-dependencies]
39
+ docs = ["mkdocs", "mkdocs-material"]
40
+ dev = [
41
+ "black>=25.1.0",
42
+ "build>=1.2.2.post1",
43
+ "flake8>=7.2.0",
44
+ "isort>=6.0.1",
45
+ "pytest>=8.3.5",
46
+ "pytest-cov>=6.1.1",
47
+ "pytest-django>=4.11.1",
48
+ "twine>=6.1.0",
49
+ ]
50
+
51
+ [tool.mkdcos-gh-deploy]
52
+ remote = "origin"
53
+ branch = "gh-pages"
54
+
55
+ [tool.setuptools]
56
+ packages = { find = { where = ["src"] } }
57
+
58
+ [tool.black]
59
+ line-length = 88
60
+ target-version = ["py310", "py311", "py312"]
61
+
62
+ [tool.isort]
63
+ profile = "black"
64
+ multi_line_output = 3
65
+
66
+ [tool.pytest.ini_options]
67
+ testpaths = ["tests"]
68
+ python_files = ["test_*.py"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+