django-restit 4.2.15__py3-none-any.whl → 4.2.17__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.
- account/models/member.py +2 -0
- account/passkeys/core.py +13 -4
- account/rpc/passkeys.py +1 -1
- {django_restit-4.2.15.dist-info → django_restit-4.2.17.dist-info}/METADATA +2 -1
- {django_restit-4.2.15.dist-info → django_restit-4.2.17.dist-info}/RECORD +12 -12
- rest/__init__.py +1 -1
- rest/helpers.py +10 -1
- rest/jwtoken.py +4 -2
- rest/models/base.py +2 -0
- rest/rpc.py +8 -0
- {django_restit-4.2.15.dist-info → django_restit-4.2.17.dist-info}/LICENSE.md +0 -0
- {django_restit-4.2.15.dist-info → django_restit-4.2.17.dist-info}/WHEEL +0 -0
account/models/member.py
CHANGED
@@ -88,6 +88,7 @@ class Member(User, RestModel, MetaDataModel):
|
|
88
88
|
("perms", "properties|permissions.")]
|
89
89
|
QUERY_FIELDS_SPECIAL = {
|
90
90
|
"ip": "auth_sessions__ip",
|
91
|
+
"login_country": "auth_sessions__location__country"
|
91
92
|
}
|
92
93
|
UNIQUE_LOOKUP = ["username", "email"]
|
93
94
|
METADATA_FIELD_PROPERTIES = settings.USER_METADATA_PROPERTIES
|
@@ -474,6 +475,7 @@ class Member(User, RestModel, MetaDataModel):
|
|
474
475
|
|
475
476
|
def disable(self, by="system", reason="", notify=True):
|
476
477
|
self.is_active = False
|
478
|
+
self.security_token = None
|
477
479
|
self.save()
|
478
480
|
self.memberships.update(state=-25)
|
479
481
|
|
account/passkeys/core.py
CHANGED
@@ -6,6 +6,8 @@ try:
|
|
6
6
|
import fido2
|
7
7
|
from fido2.server import Fido2Server
|
8
8
|
from fido2.utils import websafe_decode, websafe_encode
|
9
|
+
from fido2 import cbor
|
10
|
+
fido2.features.webauthn_json_mapping.enabled = True
|
9
11
|
except Exception:
|
10
12
|
pass
|
11
13
|
|
@@ -21,7 +23,6 @@ FIDO_KEY_ATTACHMENT = settings.get("FIDO_KEY_ATTACHMENT", "cross-platform")
|
|
21
23
|
|
22
24
|
FIDO_SERVER_ID = settings.get("FIDO_SERVER_ID", settings.SERVER_NAME)
|
23
25
|
FIDO_SERVER_NAME = settings.get("FIDO_SERVER_NAME", settings.SITE_LABEL)
|
24
|
-
fido2.features.webauthn_json_mapping.enabled = True
|
25
26
|
|
26
27
|
|
27
28
|
def verify_origin(id):
|
@@ -52,6 +53,9 @@ def registerBegin(member, request, attachment=FIDO_KEY_ATTACHMENT):
|
|
52
53
|
authenticator_attachment=attachment,
|
53
54
|
resident_key_requirement=webauthn.ResidentKeyRequirement.PREFERRED)
|
54
55
|
rp = objict(server.rp)
|
56
|
+
data = objict.fromdict(dict(data))
|
57
|
+
data.excludeCredentials = getUserCredentials(member, websafe=True)
|
58
|
+
rh.debug("data", data)
|
55
59
|
# rh.debug("registerBegin", rp, server.rp.id_hash)
|
56
60
|
return data, state, rp
|
57
61
|
|
@@ -80,10 +84,15 @@ def registerComplete(request, fido2_state, rp_id):
|
|
80
84
|
return user_key
|
81
85
|
|
82
86
|
|
83
|
-
def getUserCredentials(member):
|
87
|
+
def getUserCredentials(member, websafe=False):
|
84
88
|
if member is None:
|
85
89
|
return []
|
86
|
-
|
90
|
+
creds = [webauthn.AttestedCredentialData(websafe_decode(uk.token)) for uk in member.passkeys.all()]
|
91
|
+
if websafe:
|
92
|
+
return [dict(
|
93
|
+
type="public-key",
|
94
|
+
id=rh.toBase64(acd.credential_id)) for acd in creds]
|
95
|
+
return creds
|
87
96
|
|
88
97
|
|
89
98
|
def authBegin(request):
|
@@ -97,7 +106,7 @@ def authComplete(request, fido2_state, rp_id):
|
|
97
106
|
credential = request.DATA.get("credential")
|
98
107
|
upk = UserPassKey.objects.filter(uuid=credential.id, is_enabled=1).last()
|
99
108
|
if upk is None:
|
100
|
-
raise Exception(
|
109
|
+
raise Exception("PassKey not found on host.")
|
101
110
|
stored_credentials = [webauthn.AttestedCredentialData(websafe_decode(upk.token))]
|
102
111
|
server = getServer(request, rp_id)
|
103
112
|
cred = server.authenticate_complete(
|
account/rpc/passkeys.py
CHANGED
@@ -21,7 +21,7 @@ def rest_on_passkeys_reg_begin(request):
|
|
21
21
|
# or in redis with expires in 5m?
|
22
22
|
request.session["fido2_state"] = state
|
23
23
|
request.session["fido2_rp_id"] = rp.id
|
24
|
-
return rv.restResult(request,
|
24
|
+
return rv.restResult(request, data)
|
25
25
|
|
26
26
|
|
27
27
|
@rd.url('passkeys/register/end')
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: django-restit
|
3
|
-
Version: 4.2.
|
3
|
+
Version: 4.2.17
|
4
4
|
Summary: A Rest Framework for DJANGO
|
5
5
|
License: MIT
|
6
6
|
Author: Ian Starnes
|
@@ -16,6 +16,7 @@ Requires-Dist: boto3 (>=1.26.160,<2.0.0)
|
|
16
16
|
Requires-Dist: django
|
17
17
|
Requires-Dist: django-redis-cache (>=3.0.1,<4.0.0)
|
18
18
|
Requires-Dist: django-redis-sessions (>=0.6.2,<0.7.0)
|
19
|
+
Requires-Dist: fido2
|
19
20
|
Requires-Dist: gevent (>=23.7.0,<24.0.0)
|
20
21
|
Requires-Dist: hashids (>=1.3.1,<2.0.0)
|
21
22
|
Requires-Dist: inlinestyler
|
@@ -24,7 +24,7 @@ account/models/device.py,sha256=XipNpByreGubB5-d4ZBOoIV5Xw14b2Btcgn6fXz8HAc,4105
|
|
24
24
|
account/models/feeds.py,sha256=4n4Mv8HjcXpUmMPWafHlsGbVQ1fDKdtblL1hp30sDrg,1437
|
25
25
|
account/models/group.py,sha256=aG4qxqvuIEztZuNx5zw4R2EAQw5z8jZ4UBBpt9R3h1w,20218
|
26
26
|
account/models/legacy.py,sha256=zYdtv4LC0ooxPVqWM-uToPwV-lYWQLorSE6p6yn1xDw,2720
|
27
|
-
account/models/member.py,sha256=
|
27
|
+
account/models/member.py,sha256=Vv2z3QNzY201OvIRjo8tIPi4mv_T1YCuBfeRAhakRbg,49629
|
28
28
|
account/models/membership.py,sha256=Qmp0xQa_3ObB581L83gce69t9eSfyH-mZZuGqW3ueI8,7763
|
29
29
|
account/models/notify.py,sha256=YnZujSHJHY7B09e6FIyZIEJRWLPYk1Sk1e92tFzB1IA,12078
|
30
30
|
account/models/passkeys.py,sha256=TJxITUi4DT4_1tW2K7ZlOcRjJuMVl2NtKz7pKQU8-Tw,1516
|
@@ -33,7 +33,7 @@ account/models/settings.py,sha256=gOyRWBVd3BQpjfj_hJPtqX3H46ztyRAFxBrPbv11lQg,21
|
|
33
33
|
account/oauth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
34
34
|
account/oauth/google.py,sha256=q5M6Qhpfp9QslKRVYFZBvtG6kgXV6vYMrR5fp6Xdb9I,2078
|
35
35
|
account/passkeys/__init__.py,sha256=FwXYJXwSJXfkLojGBcVpF1dFpgFhzDdd9N_3naYQ0cc,89
|
36
|
-
account/passkeys/core.py,sha256=
|
36
|
+
account/passkeys/core.py,sha256=X8y1TCXupZZV-GF10nuPVmdpN0qYuzKe03RnaDlepP4,4116
|
37
37
|
account/periodic.py,sha256=-u0n-7QTJgDOkasGhBAPwHAwjpqWGA-MZLEFkVTqCGU,874
|
38
38
|
account/rpc/__init__.py,sha256=SGF0M_-H0dKh3b1apSX29BotNWAvITYccGQVC0MIjL8,336
|
39
39
|
account/rpc/auth.py,sha256=hINQS6BC04tZS5G0A-XXn2zAWxjWnba0l3zKNKZUsJM,14934
|
@@ -42,7 +42,7 @@ account/rpc/group.py,sha256=Y_Ii-vlDx09neMd95AmC7xBwDf3wdFgXjB-kIG2jMdE,3472
|
|
42
42
|
account/rpc/member.py,sha256=2HwARWk_1HHgZga3Y0Ii2NoTyzj1e3BuHpQ5miUQmCI,1260
|
43
43
|
account/rpc/notify.py,sha256=Q2YWejP36egeF060Hih5uX4Psv_B8NWlLLPi7iDYlIw,3344
|
44
44
|
account/rpc/oauth.py,sha256=qhXgrGrmg966_WTg7c4ZuldgWZEaub0dI3u102vX0wg,2669
|
45
|
-
account/rpc/passkeys.py,sha256=
|
45
|
+
account/rpc/passkeys.py,sha256=5x28nYILJUMMSwfVuWYL66hfoGUXahMqOwiHhM4I3Do,1729
|
46
46
|
account/rpc/settings.py,sha256=EvPuwW63Gp_Va0ANIPAZ894tnS_JCctQ0FzqYRdKUNM,271
|
47
47
|
account/settings.py,sha256=XEvZdcA6p_iUpDq9NmICK8rxzIQ8NViKfrpyuYgSV4o,53
|
48
48
|
account/templates/email/base.html,sha256=GnqUkoOYLDmaL370E1M-Q0PKJ60VH0MzkcjUyg9DdyY,9709
|
@@ -358,7 +358,7 @@ pushit/utils.py,sha256=IeTCGa-164nmB1jIsK1lu1O1QzUhS3BKfuXHGjCW-ck,2121
|
|
358
358
|
rest/.gitignore,sha256=TbEvWRMnAiajCTOdhiNrd9eeCAaIjRp9PRjE_VkMM5g,118
|
359
359
|
rest/README.md,sha256=V3ETc-cJu8PZIbKr9xSe_pA4JEUpC8Dhw4bQeVCDJPw,5460
|
360
360
|
rest/RemoteEvents.py,sha256=nL46U7AuxIrlw2JunphR1tsXyqi-ep_gD9CYGpYbNgE,72
|
361
|
-
rest/__init__.py,sha256=
|
361
|
+
rest/__init__.py,sha256=iCDDA2gsIQ-HuEDv5Vhp2KFKS-VjymncBkOg3ZURSvA,121
|
362
362
|
rest/arc4.py,sha256=y644IbF1ec--e4cUJ3KEYsewTCITK0gmlwa5mJruFC0,1967
|
363
363
|
rest/cache.py,sha256=1Qg0rkaCJCaVP0-l5hZg2CIblTdeBSlj_0fP6vlKUpU,83
|
364
364
|
rest/crypto/__init__.py,sha256=Tl0U11rgj1eBYqd6OXJ2_XSdNLumW_JkBZnaJqI6Ldw,72
|
@@ -373,9 +373,9 @@ rest/extra/__init__.py,sha256=YzmNsch5H5FFLkUK9mIAKyoRK_rJCA9HGb0kubp4h30,54
|
|
373
373
|
rest/extra/json_metadata.py,sha256=p_ffzmANmOFix_oC3voR6_NNTjcn7-T7aXcH-I4_Npg,1078
|
374
374
|
rest/fields.py,sha256=_v1TJVc6vyWlqmwFRJ6mtuR5Fo-lS0KcUhPWIrzKZUo,9719
|
375
375
|
rest/forms.py,sha256=66Wm5cdy8tKib_mGicjq_yd-gNVMFWRECnrDksnNnwU,6316
|
376
|
-
rest/helpers.py,sha256=
|
376
|
+
rest/helpers.py,sha256=3zYt3NVQosv7r0MWsxQHpWjMRQ9xk1P_wxqrVJIPwZc,28021
|
377
377
|
rest/joke.py,sha256=0PpKaX2iN7jlS62kgjfmmqkFBYLPURz15aQ8R7OJkJ8,260
|
378
|
-
rest/jwtoken.py,sha256=
|
378
|
+
rest/jwtoken.py,sha256=2BjRrnQSzm7ydHgYl6LIjfGW1YPmqjt-gDIo21O0WTk,2388
|
379
379
|
rest/log.py,sha256=hd1_4HBOS395sfXJIL6BTw9yekm1SLgBwYx_PdfIhKA,20930
|
380
380
|
rest/mail.py,sha256=O9x4ggr5pQjpjJP1zwV6sv5-2_JNTvU877GLih6ceBY,7737
|
381
381
|
rest/mailman.py,sha256=v5O1G5s3HiAKmz-J1z0uT6_q3xsONPpxVl9saEyQQ2I,9174
|
@@ -390,13 +390,13 @@ rest/middleware/request.py,sha256=JchRNy5L-bGd-7h-KFYekGRvREe2eCkZXKOYqIkP2hI,41
|
|
390
390
|
rest/middleware/session.py,sha256=zHSoQpIzRLmpqr_JvW406wzpvU3W3gDbm5JhtzLAMlE,10240
|
391
391
|
rest/middleware/session_store.py,sha256=1nSdeXK8PyuYgGgIufqrS6j6QpIrQ7zbMNT0ol75e6U,1901
|
392
392
|
rest/models/__init__.py,sha256=M8pvFDq-WCF-QcM58X7pMufYYe0aaQ3U0PwGe9TKbbY,130
|
393
|
-
rest/models/base.py,sha256=
|
393
|
+
rest/models/base.py,sha256=Os_qWTvFedZQddulSsSdebheLIg9EGiYOGijofscTxQ,66539
|
394
394
|
rest/models/cacher.py,sha256=eKz8TINVhWEqKhJGMsRkKZTtBUIv5rN3NHbZwOC56Uk,578
|
395
395
|
rest/models/metadata.py,sha256=ui0962oaWbYGIbkNs7oaUGKyaca9epsW2H-ywgyH7rg,12631
|
396
396
|
rest/net.py,sha256=LTF4ip-ur8C2G7NETVOg7ioACegBGo4sDJA18PfF5kQ,1691
|
397
397
|
rest/regexes.yaml,sha256=VoGb4E-P_K9f82Yzcpltgzekpt9usRtwu9PYlo46nUw,149463
|
398
398
|
rest/requestex.py,sha256=qtm6vpvbHzNYqMj8271TyelnWagZ5i0q50TfXW943F8,15834
|
399
|
-
rest/rpc.py,sha256=
|
399
|
+
rest/rpc.py,sha256=os1hDll9c-tQMh2r4ZwWeVOiDT50pVPxX0iqXHqpxC8,3951
|
400
400
|
rest/search.py,sha256=QVjk2b5tZLgf1zM2MHvJTyRjwUbY5ZD7HXSTmSPXtvU,8362
|
401
401
|
rest/serializers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
402
402
|
rest/serializers/collection.py,sha256=86AaICz8JylFUzhqouRpp_7v0cNzWcZpsW9yWZQ3w6Q,4648
|
@@ -490,7 +490,7 @@ ws4redis/servers/uwsgi.py,sha256=VyhoCI1DnVFqBiJYHoxqn5Idlf6uJPHvfBKgkjs34mo,172
|
|
490
490
|
ws4redis/settings.py,sha256=K0yBiLUuY81iDM4Yr-k8hbvjn5VVHu5zQhmMK8Dtz0s,1536
|
491
491
|
ws4redis/utf8validator.py,sha256=S0OlfjeGRP75aO6CzZsF4oTjRQAgR17OWE9rgZdMBZA,5122
|
492
492
|
ws4redis/websocket.py,sha256=R0TUyPsoVRD7Y_oU7w2I6NL4fPwiz5Vl94-fUkZgLHA,14848
|
493
|
-
django_restit-4.2.
|
494
|
-
django_restit-4.2.
|
495
|
-
django_restit-4.2.
|
496
|
-
django_restit-4.2.
|
493
|
+
django_restit-4.2.17.dist-info/LICENSE.md,sha256=VHN4hhEeVOoFjtG-5fVv4jesA4SWi0Z-KgOzzN6a1ps,1068
|
494
|
+
django_restit-4.2.17.dist-info/METADATA,sha256=ip7XGy-01eL9WI3vHoccBRjfVumkF-oHlm5gdWUkrhA,7594
|
495
|
+
django_restit-4.2.17.dist-info/WHEEL,sha256=Zb28QaM1gQi8f4VCBhsUklF61CTlNYfs9YAZn-TOGFk,88
|
496
|
+
django_restit-4.2.17.dist-info/RECORD,,
|
rest/__init__.py
CHANGED
rest/helpers.py
CHANGED
@@ -863,6 +863,13 @@ def getBlockedHosts():
|
|
863
863
|
return blocked
|
864
864
|
|
865
865
|
|
866
|
+
def toInteger(value):
|
867
|
+
if isinstance(value, str):
|
868
|
+
if "." in value:
|
869
|
+
return int(float(value))
|
870
|
+
return int(value)
|
871
|
+
|
872
|
+
|
866
873
|
def toString(value):
|
867
874
|
if isinstance(value, bytes):
|
868
875
|
value = value.decode()
|
@@ -897,7 +904,9 @@ def hexToByteArray(value):
|
|
897
904
|
def hexToString(value):
|
898
905
|
return bytes.fromhex(value).decode('utf-8')
|
899
906
|
|
900
|
-
def toBase64(value):
|
907
|
+
def toBase64(value, as_str=True):
|
908
|
+
if as_str:
|
909
|
+
return toString(base64.b64encode(toBytes(value)))
|
901
910
|
return base64.b64encode(toBytes(value))
|
902
911
|
|
903
912
|
def fromBase64(value):
|
rest/jwtoken.py
CHANGED
@@ -6,14 +6,16 @@ from rest import settings
|
|
6
6
|
|
7
7
|
|
8
8
|
JWT_EXP_1_DAY = 86400
|
9
|
+
JWT_EXP_2_DAY = 172800
|
9
10
|
JWT_EXP_7_DAY = 604800
|
10
11
|
JWT_EXP_30_MIN = 1800
|
11
12
|
JWT_KEY = settings.SECRET_KEY
|
12
|
-
|
13
|
+
JWT_EXPIRES = settings.get("JWT_EXPIRES", JWT_EXP_30_MIN)
|
14
|
+
JWT_REFRESH_EXPIRES = settings.get("JWT_REFRESH_EXPIRES", JWT_EXP_2_DAY)
|
13
15
|
|
14
16
|
|
15
17
|
class JWToken():
|
16
|
-
def __init__(self, token=None, user_id=None, key=JWT_KEY, device_id=None, alg="HS256", access_expires_in=
|
18
|
+
def __init__(self, token=None, user_id=None, key=JWT_KEY, device_id=None, alg="HS256", access_expires_in=JWT_EXPIRES, refresh_expires_in=JWT_REFRESH_EXPIRES):
|
17
19
|
# takes full JWT token header.payload.signature
|
18
20
|
self.token = token
|
19
21
|
self.key = key
|
rest/models/base.py
CHANGED
@@ -1573,6 +1573,8 @@ class RestModel(object):
|
|
1573
1573
|
ft = cls.get_field_type(fn)
|
1574
1574
|
if ft == "DateTimeField":
|
1575
1575
|
value = rh.parseDateTime(value)
|
1576
|
+
elif ft == "IntegerField":
|
1577
|
+
value = rh.toInteger(value)
|
1576
1578
|
q[key] = value
|
1577
1579
|
if bool(q):
|
1578
1580
|
# rh.debug("queryFromRequest", q, "default_filters:", request.default_rest_filters)
|
rest/rpc.py
CHANGED
@@ -42,6 +42,14 @@ def on_get_version(request):
|
|
42
42
|
return views.restStatus(request, True, {"data": versions})
|
43
43
|
|
44
44
|
|
45
|
+
@url('test/session')
|
46
|
+
def on_get_my_session(request):
|
47
|
+
echo = request.DATA.get("echo", None)
|
48
|
+
if echo:
|
49
|
+
request.session["echo"] = echo
|
50
|
+
return views.restReturn(request, dict(echo=request.session.get("echo", "not set")))
|
51
|
+
|
52
|
+
|
45
53
|
@url(r'^joke$')
|
46
54
|
def on_get_joke(request):
|
47
55
|
return views.restGet(request, {"joke": joke.getRandomJoke()})
|
File without changes
|
File without changes
|