plain.auth 0.20.0__py3-none-any.whl → 0.20.2__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.
- plain/auth/CHANGELOG.md +20 -0
- plain/auth/README.md +16 -12
- plain/auth/requests.py +4 -8
- plain/auth/sessions.py +15 -8
- plain/auth/templates.py +8 -1
- plain/auth/test.py +8 -2
- plain/auth/utils.py +5 -1
- plain/auth/views.py +8 -10
- {plain_auth-0.20.0.dist-info → plain_auth-0.20.2.dist-info}/METADATA +17 -13
- plain_auth-0.20.2.dist-info/RECORD +14 -0
- plain_auth-0.20.0.dist-info/RECORD +0 -14
- {plain_auth-0.20.0.dist-info → plain_auth-0.20.2.dist-info}/WHEEL +0 -0
- {plain_auth-0.20.0.dist-info → plain_auth-0.20.2.dist-info}/licenses/LICENSE +0 -0
plain/auth/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# plain-auth changelog
|
|
2
2
|
|
|
3
|
+
## [0.20.2](https://github.com/dropseed/plain/releases/plain-auth@0.20.2) (2025-10-06)
|
|
4
|
+
|
|
5
|
+
### What's changed
|
|
6
|
+
|
|
7
|
+
- Added comprehensive type annotations across the entire package for improved IDE support and type checking ([786c1db](https://github.com/dropseed/plain/commit/786c1dbdbd))
|
|
8
|
+
|
|
9
|
+
### Upgrade instructions
|
|
10
|
+
|
|
11
|
+
- No changes required
|
|
12
|
+
|
|
13
|
+
## [0.20.1](https://github.com/dropseed/plain/releases/plain-auth@0.20.1) (2025-10-02)
|
|
14
|
+
|
|
15
|
+
### What's changed
|
|
16
|
+
|
|
17
|
+
- Updated README documentation to use `get_request_user()` and `get_current_user()` instead of `request.user` ([f6278d9](https://github.com/dropseed/plain/commit/f6278d9bb4))
|
|
18
|
+
|
|
19
|
+
### Upgrade instructions
|
|
20
|
+
|
|
21
|
+
- No changes required
|
|
22
|
+
|
|
3
23
|
## [0.20.0](https://github.com/dropseed/plain/releases/plain-auth@0.20.0) (2025-10-02)
|
|
4
24
|
|
|
5
25
|
### What's changed
|
plain/auth/README.md
CHANGED
|
@@ -17,8 +17,11 @@ The `plain.auth` package provides user authentication and authorization for Plai
|
|
|
17
17
|
|
|
18
18
|
```python
|
|
19
19
|
# In a view
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
from plain.auth import get_request_user
|
|
21
|
+
|
|
22
|
+
user = get_request_user(request)
|
|
23
|
+
if user:
|
|
24
|
+
print(f"Hello, {user.email}!")
|
|
22
25
|
else:
|
|
23
26
|
print("You are not logged in.")
|
|
24
27
|
```
|
|
@@ -33,7 +36,7 @@ class ProfileView(AuthViewMixin, View):
|
|
|
33
36
|
login_required = True
|
|
34
37
|
|
|
35
38
|
def get(self):
|
|
36
|
-
return f"Welcome, {self.
|
|
39
|
+
return f"Welcome, {self.user.email}!"
|
|
37
40
|
```
|
|
38
41
|
|
|
39
42
|
## Authentication setup
|
|
@@ -108,23 +111,24 @@ urlpatterns = [
|
|
|
108
111
|
|
|
109
112
|
## Checking if a user is logged in
|
|
110
113
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
In templates:
|
|
114
|
+
In templates, use the `get_current_user()` function:
|
|
114
115
|
|
|
115
116
|
```html
|
|
116
|
-
{% if
|
|
117
|
-
<p>Hello, {{
|
|
117
|
+
{% if get_current_user() %}
|
|
118
|
+
<p>Hello, {{ get_current_user().email }}!</p>
|
|
118
119
|
{% else %}
|
|
119
120
|
<p>You are not logged in.</p>
|
|
120
121
|
{% endif %}
|
|
121
122
|
```
|
|
122
123
|
|
|
123
|
-
In Python code
|
|
124
|
+
In Python code, use `get_request_user()`:
|
|
124
125
|
|
|
125
126
|
```python
|
|
126
|
-
|
|
127
|
-
|
|
127
|
+
from plain.auth import get_request_user
|
|
128
|
+
|
|
129
|
+
user = get_request_user(request)
|
|
130
|
+
if user:
|
|
131
|
+
print(f"Hello, {user.email}!")
|
|
128
132
|
else:
|
|
129
133
|
print("You are not logged in.")
|
|
130
134
|
```
|
|
@@ -151,7 +155,7 @@ class AdminOnlyView(AuthViewMixin, View):
|
|
|
151
155
|
class CustomPermissionView(AuthViewMixin, View):
|
|
152
156
|
def check_auth(self):
|
|
153
157
|
super().check_auth()
|
|
154
|
-
if not self.
|
|
158
|
+
if not self.user.is_special:
|
|
155
159
|
raise PermissionDenied("You're not special!")
|
|
156
160
|
```
|
|
157
161
|
|
plain/auth/requests.py
CHANGED
|
@@ -1,24 +1,20 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import TYPE_CHECKING
|
|
3
|
+
from typing import TYPE_CHECKING, Any
|
|
4
4
|
from weakref import WeakKeyDictionary
|
|
5
5
|
|
|
6
6
|
if TYPE_CHECKING:
|
|
7
7
|
from plain.http import Request
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
_request_users: WeakKeyDictionary[Request, Any | None] = WeakKeyDictionary()
|
|
10
10
|
|
|
11
|
-
User = get_user_model()
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
def set_request_user(request: Request, user: User | None) -> None:
|
|
12
|
+
def set_request_user(request: Request, user: Any | None) -> None:
|
|
17
13
|
"""Store the authenticated user for this request."""
|
|
18
14
|
_request_users[request] = user
|
|
19
15
|
|
|
20
16
|
|
|
21
|
-
def get_request_user(request: Request) ->
|
|
17
|
+
def get_request_user(request: Request) -> Any | None:
|
|
22
18
|
"""
|
|
23
19
|
Get the authenticated user for this request, if any.
|
|
24
20
|
|
plain/auth/sessions.py
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import hmac
|
|
4
|
+
from collections.abc import Generator
|
|
5
|
+
from typing import TYPE_CHECKING, Any
|
|
2
6
|
|
|
3
7
|
from plain.exceptions import ImproperlyConfigured
|
|
4
8
|
from plain.models import models_registry
|
|
@@ -9,18 +13,21 @@ from plain.utils.encoding import force_bytes
|
|
|
9
13
|
|
|
10
14
|
from .requests import get_request_user, set_request_user
|
|
11
15
|
|
|
16
|
+
if TYPE_CHECKING:
|
|
17
|
+
from plain.http import Request
|
|
18
|
+
|
|
12
19
|
USER_ID_SESSION_KEY = "_auth_user_id"
|
|
13
20
|
USER_HASH_SESSION_KEY = "_auth_user_hash"
|
|
14
21
|
|
|
15
22
|
|
|
16
|
-
def get_session_auth_hash(user):
|
|
23
|
+
def get_session_auth_hash(user: Any) -> str:
|
|
17
24
|
"""
|
|
18
25
|
Return an HMAC of the password field.
|
|
19
26
|
"""
|
|
20
27
|
return _get_session_auth_hash(user)
|
|
21
28
|
|
|
22
29
|
|
|
23
|
-
def update_session_auth_hash(request, user):
|
|
30
|
+
def update_session_auth_hash(request: Request, user: Any) -> None:
|
|
24
31
|
"""
|
|
25
32
|
Updating a user's password (for example) logs out all sessions for the user.
|
|
26
33
|
|
|
@@ -36,12 +43,12 @@ def update_session_auth_hash(request, user):
|
|
|
36
43
|
session[USER_HASH_SESSION_KEY] = get_session_auth_hash(user)
|
|
37
44
|
|
|
38
45
|
|
|
39
|
-
def get_session_auth_fallback_hash(user):
|
|
46
|
+
def get_session_auth_fallback_hash(user: Any) -> Generator[str, None, None]:
|
|
40
47
|
for fallback_secret in settings.SECRET_KEY_FALLBACKS:
|
|
41
48
|
yield _get_session_auth_hash(user, secret=fallback_secret)
|
|
42
49
|
|
|
43
50
|
|
|
44
|
-
def _get_session_auth_hash(user, secret=None):
|
|
51
|
+
def _get_session_auth_hash(user: Any, secret: str | None = None) -> str:
|
|
45
52
|
key_salt = "plain.auth.get_session_auth_hash"
|
|
46
53
|
return salted_hmac(
|
|
47
54
|
key_salt,
|
|
@@ -51,7 +58,7 @@ def _get_session_auth_hash(user, secret=None):
|
|
|
51
58
|
).hexdigest()
|
|
52
59
|
|
|
53
60
|
|
|
54
|
-
def login(request, user):
|
|
61
|
+
def login(request: Request, user: Any) -> None:
|
|
55
62
|
"""
|
|
56
63
|
Persist a user id and a backend in the request. This way a user doesn't
|
|
57
64
|
have to reauthenticate on every request. Note that data set during
|
|
@@ -87,7 +94,7 @@ def login(request, user):
|
|
|
87
94
|
set_request_user(request, user)
|
|
88
95
|
|
|
89
96
|
|
|
90
|
-
def logout(request):
|
|
97
|
+
def logout(request: Request) -> None:
|
|
91
98
|
"""
|
|
92
99
|
Remove the authenticated user's ID from the request and flush their session
|
|
93
100
|
data.
|
|
@@ -99,7 +106,7 @@ def logout(request):
|
|
|
99
106
|
set_request_user(request, None)
|
|
100
107
|
|
|
101
108
|
|
|
102
|
-
def get_user_model():
|
|
109
|
+
def get_user_model() -> type[Any]:
|
|
103
110
|
"""
|
|
104
111
|
Return the User model that is active in this project.
|
|
105
112
|
"""
|
|
@@ -115,7 +122,7 @@ def get_user_model():
|
|
|
115
122
|
)
|
|
116
123
|
|
|
117
124
|
|
|
118
|
-
def get_user(request):
|
|
125
|
+
def get_user(request: Request) -> Any | None:
|
|
119
126
|
"""
|
|
120
127
|
Return the user model instance associated with the given request session.
|
|
121
128
|
If no user is retrieved, return None.
|
plain/auth/templates.py
CHANGED
|
@@ -1,13 +1,20 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING, Any
|
|
4
|
+
|
|
1
5
|
from jinja2 import pass_context
|
|
2
6
|
|
|
3
7
|
from plain.templates import register_template_global
|
|
4
8
|
|
|
5
9
|
from .requests import get_request_user
|
|
6
10
|
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from jinja2.runtime import Context
|
|
13
|
+
|
|
7
14
|
|
|
8
15
|
@register_template_global
|
|
9
16
|
@pass_context
|
|
10
|
-
def get_current_user(context):
|
|
17
|
+
def get_current_user(context: Context) -> Any | None:
|
|
11
18
|
"""Get the authenticated user for the current request."""
|
|
12
19
|
request = context.get("request")
|
|
13
20
|
assert request is not None, "No request in template context"
|
plain/auth/test.py
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
from http.cookies import SimpleCookie
|
|
4
|
+
from typing import TYPE_CHECKING, Any
|
|
2
5
|
|
|
3
6
|
from plain.http.request import Request
|
|
4
7
|
from plain.runtime import settings
|
|
@@ -8,8 +11,11 @@ from plain.sessions.requests import get_request_session, set_request_session
|
|
|
8
11
|
from .requests import set_request_user
|
|
9
12
|
from .sessions import get_user, login, logout
|
|
10
13
|
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from plain.test.client import Client
|
|
16
|
+
|
|
11
17
|
|
|
12
|
-
def login_client(client, user):
|
|
18
|
+
def login_client(client: Client, user: Any) -> None:
|
|
13
19
|
"""Log a user into a test client."""
|
|
14
20
|
request = Request()
|
|
15
21
|
if client.session:
|
|
@@ -32,7 +38,7 @@ def login_client(client, user):
|
|
|
32
38
|
client.cookies[session_cookie].update(cookie_data)
|
|
33
39
|
|
|
34
40
|
|
|
35
|
-
def logout_client(client):
|
|
41
|
+
def logout_client(client: Client) -> None:
|
|
36
42
|
"""Log out a user from a test client."""
|
|
37
43
|
request = Request()
|
|
38
44
|
if client.session:
|
plain/auth/utils.py
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
1
5
|
from plain.urls import NoReverseMatch, reverse
|
|
2
6
|
from plain.utils.functional import Promise
|
|
3
7
|
|
|
4
8
|
|
|
5
|
-
def resolve_url(to, *args, **kwargs):
|
|
9
|
+
def resolve_url(to: Any, *args: Any, **kwargs: Any) -> str:
|
|
6
10
|
"""
|
|
7
11
|
Return a URL appropriate for the arguments passed.
|
|
8
12
|
|
plain/auth/views.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from functools import cached_property
|
|
4
|
-
from typing import TYPE_CHECKING
|
|
4
|
+
from typing import TYPE_CHECKING, Any
|
|
5
5
|
from urllib.parse import urlparse, urlunparse
|
|
6
6
|
|
|
7
7
|
from plain.exceptions import PermissionDenied
|
|
@@ -23,13 +23,9 @@ from .utils import resolve_url
|
|
|
23
23
|
if TYPE_CHECKING:
|
|
24
24
|
from plain.http import Request
|
|
25
25
|
|
|
26
|
-
from .sessions import get_user_model
|
|
27
|
-
|
|
28
|
-
User = get_user_model()
|
|
29
|
-
|
|
30
26
|
|
|
31
27
|
class LoginRequired(Exception):
|
|
32
|
-
def __init__(self, login_url=None, redirect_field_name="next"):
|
|
28
|
+
def __init__(self, login_url: str | None = None, redirect_field_name: str = "next"):
|
|
33
29
|
self.login_url = login_url or settings.AUTH_LOGIN_URL
|
|
34
30
|
self.redirect_field_name = redirect_field_name
|
|
35
31
|
|
|
@@ -42,7 +38,7 @@ class AuthViewMixin(SessionViewMixin):
|
|
|
42
38
|
request: Request
|
|
43
39
|
|
|
44
40
|
@cached_property
|
|
45
|
-
def user(self) ->
|
|
41
|
+
def user(self) -> Any | None:
|
|
46
42
|
"""Get the authenticated user for this request."""
|
|
47
43
|
from .requests import get_request_user
|
|
48
44
|
|
|
@@ -116,12 +112,14 @@ class AuthViewMixin(SessionViewMixin):
|
|
|
116
112
|
|
|
117
113
|
|
|
118
114
|
class LogoutView(View):
|
|
119
|
-
def post(self):
|
|
115
|
+
def post(self) -> ResponseRedirect:
|
|
120
116
|
logout(self.request)
|
|
121
117
|
return ResponseRedirect("/")
|
|
122
118
|
|
|
123
119
|
|
|
124
|
-
def redirect_to_login(
|
|
120
|
+
def redirect_to_login(
|
|
121
|
+
next: str, login_url: str | None = None, redirect_field_name: str = "next"
|
|
122
|
+
) -> ResponseRedirect:
|
|
125
123
|
"""
|
|
126
124
|
Redirect the user to the login page, passing the given 'next' page.
|
|
127
125
|
"""
|
|
@@ -133,4 +131,4 @@ def redirect_to_login(next, login_url=None, redirect_field_name="next"):
|
|
|
133
131
|
querystring[redirect_field_name] = next
|
|
134
132
|
login_url_parts[4] = querystring.urlencode(safe="/")
|
|
135
133
|
|
|
136
|
-
return ResponseRedirect(urlunparse(login_url_parts))
|
|
134
|
+
return ResponseRedirect(str(urlunparse(login_url_parts)))
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: plain.auth
|
|
3
|
-
Version: 0.20.
|
|
3
|
+
Version: 0.20.2
|
|
4
4
|
Summary: Add users to your app and decide what they can access.
|
|
5
5
|
Author-email: Dave Gaeddert <dave.gaeddert@dropseed.dev>
|
|
6
6
|
License-File: LICENSE
|
|
@@ -29,8 +29,11 @@ The `plain.auth` package provides user authentication and authorization for Plai
|
|
|
29
29
|
|
|
30
30
|
```python
|
|
31
31
|
# In a view
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
from plain.auth import get_request_user
|
|
33
|
+
|
|
34
|
+
user = get_request_user(request)
|
|
35
|
+
if user:
|
|
36
|
+
print(f"Hello, {user.email}!")
|
|
34
37
|
else:
|
|
35
38
|
print("You are not logged in.")
|
|
36
39
|
```
|
|
@@ -45,7 +48,7 @@ class ProfileView(AuthViewMixin, View):
|
|
|
45
48
|
login_required = True
|
|
46
49
|
|
|
47
50
|
def get(self):
|
|
48
|
-
return f"Welcome, {self.
|
|
51
|
+
return f"Welcome, {self.user.email}!"
|
|
49
52
|
```
|
|
50
53
|
|
|
51
54
|
## Authentication setup
|
|
@@ -120,23 +123,24 @@ urlpatterns = [
|
|
|
120
123
|
|
|
121
124
|
## Checking if a user is logged in
|
|
122
125
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
In templates:
|
|
126
|
+
In templates, use the `get_current_user()` function:
|
|
126
127
|
|
|
127
128
|
```html
|
|
128
|
-
{% if
|
|
129
|
-
<p>Hello, {{
|
|
129
|
+
{% if get_current_user() %}
|
|
130
|
+
<p>Hello, {{ get_current_user().email }}!</p>
|
|
130
131
|
{% else %}
|
|
131
132
|
<p>You are not logged in.</p>
|
|
132
133
|
{% endif %}
|
|
133
134
|
```
|
|
134
135
|
|
|
135
|
-
In Python code
|
|
136
|
+
In Python code, use `get_request_user()`:
|
|
136
137
|
|
|
137
138
|
```python
|
|
138
|
-
|
|
139
|
-
|
|
139
|
+
from plain.auth import get_request_user
|
|
140
|
+
|
|
141
|
+
user = get_request_user(request)
|
|
142
|
+
if user:
|
|
143
|
+
print(f"Hello, {user.email}!")
|
|
140
144
|
else:
|
|
141
145
|
print("You are not logged in.")
|
|
142
146
|
```
|
|
@@ -163,7 +167,7 @@ class AdminOnlyView(AuthViewMixin, View):
|
|
|
163
167
|
class CustomPermissionView(AuthViewMixin, View):
|
|
164
168
|
def check_auth(self):
|
|
165
169
|
super().check_auth()
|
|
166
|
-
if not self.
|
|
170
|
+
if not self.user.is_special:
|
|
167
171
|
raise PermissionDenied("You're not special!")
|
|
168
172
|
```
|
|
169
173
|
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
plain/auth/CHANGELOG.md,sha256=KEwd7C-ZHFlVY2Rv4G8tm_KFU6iPN-3-ZBs-W479_wA,4864
|
|
2
|
+
plain/auth/README.md,sha256=I1SeOyrBnF0GAjD7T0k5OlZ2bSHz9---nElinaobewc,4030
|
|
3
|
+
plain/auth/__init__.py,sha256=CrOsS74CPGN1nPTTfie13mPgdyVLRyZ1YwDPIA77uaA,179
|
|
4
|
+
plain/auth/default_settings.py,sha256=65VzDn3j61OMn78Lg6Zuds4A8QKzJJ_0G9KoFqAOIRo,466
|
|
5
|
+
plain/auth/requests.py,sha256=jUlMTOWFt0qfDF_uVkOqaP9rZiCLrAofsmirCwyRGEE,880
|
|
6
|
+
plain/auth/sessions.py,sha256=xDp1EiB0cV5w3L5XioqO8vs77wnF8cvreExms3-e744,6015
|
|
7
|
+
plain/auth/templates.py,sha256=bOMPfLrf8SSxOSWrKTkqKGaK3aNBTLxe62HJulghutU,556
|
|
8
|
+
plain/auth/test.py,sha256=SHawhwarJEMVfaLkjpiuFVSWZoGIMwhzXreU_T1zvCE,1599
|
|
9
|
+
plain/auth/utils.py,sha256=9kKWh1QqxA8Esct-jBvTCdjBYOHpO_Tg1YeV9WxYmxg,1362
|
|
10
|
+
plain/auth/views.py,sha256=vWLMeykTrA5LtA179uE7w-BY9Kv25r1VScLHooDvZUA,4792
|
|
11
|
+
plain_auth-0.20.2.dist-info/METADATA,sha256=BE1BOkDeM_Nw6Ym8w3VanuGn7uHN8wwnHkmuYhcEVBU,4390
|
|
12
|
+
plain_auth-0.20.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
13
|
+
plain_auth-0.20.2.dist-info/licenses/LICENSE,sha256=m0D5O7QoH9l5Vz_rrX_9r-C8d9UNr_ciK6Qwac7o6yo,3175
|
|
14
|
+
plain_auth-0.20.2.dist-info/RECORD,,
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
plain/auth/CHANGELOG.md,sha256=IyxuPyEHvnwqEu6GKtUEOtlu1iuLg5Xux6610lrRAIU,4200
|
|
2
|
-
plain/auth/README.md,sha256=Kr3pW6XDd9sp-b8DOH2uKRqCqrR8MYB98qRUxeiwn0k,3944
|
|
3
|
-
plain/auth/__init__.py,sha256=CrOsS74CPGN1nPTTfie13mPgdyVLRyZ1YwDPIA77uaA,179
|
|
4
|
-
plain/auth/default_settings.py,sha256=65VzDn3j61OMn78Lg6Zuds4A8QKzJJ_0G9KoFqAOIRo,466
|
|
5
|
-
plain/auth/requests.py,sha256=f8QUpqHueoTYnL2ITgRXxLFYLSxra9jW3p9pjFgj0B0,949
|
|
6
|
-
plain/auth/sessions.py,sha256=Pz27K2wFfij0H0nGg_2rq0WJpcgTWW22bG0YvHM-dfc,5679
|
|
7
|
-
plain/auth/templates.py,sha256=MQ9vdxE2fBXN-F043g8EGm93s6HRvEMtGHrFcbAr3Fs,400
|
|
8
|
-
plain/auth/test.py,sha256=bLxQEp1mM4t9b-bSSq2u9_Z07Wkl--7U_mSBb9VV7BU,1428
|
|
9
|
-
plain/auth/utils.py,sha256=eEON0Mo928l-aW5tqBuoTdVke8aP4majxVtAFoLroSE,1280
|
|
10
|
-
plain/auth/views.py,sha256=Gm91sB_Z47h-8SwxCMKVKl57FSjed_AM5fdeaiPmz-E,4761
|
|
11
|
-
plain_auth-0.20.0.dist-info/METADATA,sha256=9LQj-14o1wKsAbKp3xTd09vmjuJTzYvcD4xjiUqGRqY,4304
|
|
12
|
-
plain_auth-0.20.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
13
|
-
plain_auth-0.20.0.dist-info/licenses/LICENSE,sha256=m0D5O7QoH9l5Vz_rrX_9r-C8d9UNr_ciK6Qwac7o6yo,3175
|
|
14
|
-
plain_auth-0.20.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|