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 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
- return [webauthn.AttestedCredentialData(websafe_decode(uk.token)) for uk in member.passkeys.all()]
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(f"could not find UserPassKey {credential.id}")
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, dict(data))
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.15
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=xrt9iJWvIdxVF7mxN3Ic-LOfsDIBc9nFo2NVJhbgVzs,49530
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=bmYNcY0hWI3DbmqDWJV8lk13RE3JOzwE0nzwhmAmbn4,3798
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=84sDS_IqBQklINqZvYdEBh7-pCOv7Ea9JUKZoAgaQT0,1735
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=YUjJZkCFllNo8iNv5AyvpOjypb7uYi7DkUmmmIdv5eY,121
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=S2jo13NkDz00D7mPdMd9e-HceoSNu0jcfAhke_1IvtU,27796
376
+ rest/helpers.py,sha256=3zYt3NVQosv7r0MWsxQHpWjMRQ9xk1P_wxqrVJIPwZc,28021
377
377
  rest/joke.py,sha256=0PpKaX2iN7jlS62kgjfmmqkFBYLPURz15aQ8R7OJkJ8,260
378
- rest/jwtoken.py,sha256=1ruZGPTXnodb85ywPd8ZmRiRYCskopA8EhcbX7Adixc,2298
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=F_Tl8Wgso53T-vgwsPgMXIiZPEic7F99739M2QIO0OM,66456
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=1rfwBnqt-NN0o4M4IhpZbEI4QfQDQFEUbFGzY8haFCo,3714
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.15.dist-info/LICENSE.md,sha256=VHN4hhEeVOoFjtG-5fVv4jesA4SWi0Z-KgOzzN6a1ps,1068
494
- django_restit-4.2.15.dist-info/METADATA,sha256=2-dS4Q3qnwlkM2FYOHgc-sxCd6eERTTmVUsxeYZ6ilA,7573
495
- django_restit-4.2.15.dist-info/WHEEL,sha256=Zb28QaM1gQi8f4VCBhsUklF61CTlNYfs9YAZn-TOGFk,88
496
- django_restit-4.2.15.dist-info/RECORD,,
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
@@ -1,4 +1,4 @@
1
1
  from .uberdict import UberDict # noqa: F401
2
2
  from .settings_helper import settings # noqa: F401
3
3
 
4
- __version__ = "4.2.15"
4
+ __version__ = "4.2.17"
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
- JWT_EXP_DEFAULT = settings.get("JWT_EXP_DEFAULT", JWT_EXP_30_MIN)
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=JWT_EXP_DEFAULT, refresh_expires_in=JWT_EXP_7_DAY):
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()})