django-restit 4.1.75__py3-none-any.whl → 4.1.77__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/migrations/0017_rename_requires_topt_member_requires_totp.py +18 -0
- account/models/member.py +9 -8
- account/periodic.py +3 -3
- account/rpc/auth.py +80 -28
- account/rpc/group.py +2 -2
- {django_restit-4.1.75.dist-info → django_restit-4.1.77.dist-info}/METADATA +1 -1
- {django_restit-4.1.75.dist-info → django_restit-4.1.77.dist-info}/RECORD +14 -13
- incident/models/incident.py +2 -2
- rest/__init__.py +1 -1
- rest/middleware/jwt.py +12 -0
- rest/models/base.py +6 -4
- telephony/models.py +1 -0
- {django_restit-4.1.75.dist-info → django_restit-4.1.77.dist-info}/LICENSE.md +0 -0
- {django_restit-4.1.75.dist-info → django_restit-4.1.77.dist-info}/WHEEL +0 -0
@@ -0,0 +1,18 @@
|
|
1
|
+
# Generated by Django 4.1.4 on 2023-11-28 23:26
|
2
|
+
|
3
|
+
from django.db import migrations
|
4
|
+
|
5
|
+
|
6
|
+
class Migration(migrations.Migration):
|
7
|
+
|
8
|
+
dependencies = [
|
9
|
+
('account', '0016_authsession_buid'),
|
10
|
+
]
|
11
|
+
|
12
|
+
operations = [
|
13
|
+
migrations.RenameField(
|
14
|
+
model_name='member',
|
15
|
+
old_name='requires_topt',
|
16
|
+
new_name='requires_totp',
|
17
|
+
),
|
18
|
+
]
|
account/models/member.py
CHANGED
@@ -68,7 +68,7 @@ class User(AbstractUser, RestModel):
|
|
68
68
|
class Member(User, RestModel, MetaDataModel):
|
69
69
|
class RestMeta:
|
70
70
|
NO_SHOW_FIELDS = ["password", "auth_code", "security_token"]
|
71
|
-
SEARCH_FIELDS = ["username", "email", "first_name", "last_name", "display_name"]
|
71
|
+
SEARCH_FIELDS = ["username", "email", "first_name", "last_name", "display_name", "phone_number"]
|
72
72
|
VIEW_PERMS = ["view_members", "manage_members", "manage_users", "owner"]
|
73
73
|
SAVE_PERMS = ["invite_members", "manage_members", "manage_users", "owner"]
|
74
74
|
LIST_DEFAULT_FILTERS = {
|
@@ -125,13 +125,13 @@ class Member(User, RestModel, MetaDataModel):
|
|
125
125
|
'is_blocked',
|
126
126
|
'is_staff',
|
127
127
|
'is_superuser',
|
128
|
-
'
|
128
|
+
'requires_totp',
|
129
129
|
'last_login',
|
130
130
|
'last_activity',
|
131
131
|
('date_joined', 'created'),
|
132
132
|
("hasLoggedIn", "has_logged_in"),
|
133
133
|
'avatar',
|
134
|
-
'
|
134
|
+
'has_totp',
|
135
135
|
'auth_token'
|
136
136
|
],
|
137
137
|
"extra": ["metadata", "password_expires_in"],
|
@@ -152,7 +152,7 @@ class Member(User, RestModel, MetaDataModel):
|
|
152
152
|
|
153
153
|
password_changed = models.DateTimeField(blank=True, null=True, default=None)
|
154
154
|
last_activity = models.DateTimeField(blank=True, null=True, default=None)
|
155
|
-
|
155
|
+
requires_totp = models.BooleanField(blank=True, null=True, default=False)
|
156
156
|
|
157
157
|
def __str__(self):
|
158
158
|
return self.username
|
@@ -214,9 +214,10 @@ class Member(User, RestModel, MetaDataModel):
|
|
214
214
|
return None
|
215
215
|
|
216
216
|
@property
|
217
|
-
def
|
218
|
-
token = self.
|
219
|
-
|
217
|
+
def has_totp(self):
|
218
|
+
token = self.getProperty("totp_token", category="secrets", default=None)
|
219
|
+
verified = self.getProperty("totp_verified", default=False)
|
220
|
+
return token is not None and verified
|
220
221
|
|
221
222
|
@property
|
222
223
|
def password_expires_in(self):
|
@@ -667,7 +668,7 @@ class Member(User, RestModel, MetaDataModel):
|
|
667
668
|
|
668
669
|
# time based one time passwords / GOOGLE Authenticator
|
669
670
|
def totp_getSecret(self, reset=False):
|
670
|
-
token = self.
|
671
|
+
token = self.getSecretProperty("totp_token", default=None)
|
671
672
|
if token is None or reset:
|
672
673
|
token = pyotp.random_base32()
|
673
674
|
self.setProperty("totp_token", token, category="secrets")
|
account/periodic.py
CHANGED
@@ -8,9 +8,9 @@ from sessionlog.models import SessionLog
|
|
8
8
|
def run_cleanup_tokens(force=False, verbose=False, now=None):
|
9
9
|
# we want to nuke invite tokens every 15 minutes
|
10
10
|
# we do not want to do this if using invite
|
11
|
-
stale = datetime.now() - timedelta(hours=
|
12
|
-
qset = Member.objects.filter(
|
13
|
-
qset.update(
|
11
|
+
stale = datetime.now() - timedelta(hours=48)
|
12
|
+
qset = Member.objects.filter(auth_code__isnull=False).filter(modified__lte=stale)
|
13
|
+
qset.update(auth_code=None)
|
14
14
|
|
15
15
|
# lets prune old non active sessions
|
16
16
|
SessionLog.Clean(limit=10000)
|
account/rpc/auth.py
CHANGED
@@ -38,13 +38,24 @@ def jwt_login(request):
|
|
38
38
|
return restStatus(request, False, error="Password and/or Username is incorrect", error_code=422)
|
39
39
|
password = request.DATA.get('password', None)
|
40
40
|
member.canLogin(request) # throws exception if cannot login
|
41
|
+
if member.requires_totp:
|
42
|
+
resp = checkForTOTP(request, member)
|
43
|
+
if resp is not None:
|
44
|
+
return resp
|
41
45
|
if not member.login(request=request, password=password, use_jwt=True):
|
42
46
|
member.log("login_failed", "incorrect password", request, method="login", level=31)
|
43
|
-
return restStatus(request, False, error="
|
47
|
+
return restStatus(request, False, error="Invalid Credentials", error_code=401)
|
48
|
+
return on_complete_jwt(request, member)
|
49
|
+
|
50
|
+
|
51
|
+
def on_complete_jwt(request, member):
|
44
52
|
if member.security_token is None or member.security_token == JWT_KEY:
|
45
53
|
member.refreshSecurityToken()
|
46
|
-
|
47
|
-
|
54
|
+
|
55
|
+
member.log(
|
56
|
+
"jwt_login", "jwt login succesful",
|
57
|
+
request, method="login", level=7)
|
58
|
+
|
48
59
|
device_id = request.DATA.get(["device_id", "deviceID"])
|
49
60
|
token = JWToken(user_id=member.pk, key=member.security_token, device_id=device_id)
|
50
61
|
|
@@ -58,7 +69,12 @@ def jwt_login(request):
|
|
58
69
|
am.MemberDevice.register(request, member, device_id)
|
59
70
|
|
60
71
|
request.jwt_token = token.access_token # this tells the middleware to store in cookie
|
61
|
-
return restGet(
|
72
|
+
return restGet(
|
73
|
+
request,
|
74
|
+
dict(
|
75
|
+
access=token.access_token,
|
76
|
+
refresh=token.refresh_token,
|
77
|
+
id=member.pk))
|
62
78
|
|
63
79
|
|
64
80
|
@rd.urlPOST(r'^jwt/logout$')
|
@@ -107,19 +123,38 @@ def getMemberByUsername(username):
|
|
107
123
|
return member
|
108
124
|
|
109
125
|
|
126
|
+
def checkForTOTP(request, member):
|
127
|
+
if not member.has_totp and not member.phone_number:
|
128
|
+
member.reportIncident(
|
129
|
+
"account", f"{member.username} TOTP not set", level=8,
|
130
|
+
error_code=455,
|
131
|
+
request=request)
|
132
|
+
return None
|
133
|
+
if not member.has_totp:
|
134
|
+
# we have a phone number so tell them to login with code
|
135
|
+
# they will need to request a code
|
136
|
+
return restStatus(
|
137
|
+
request, False, error=member.phone_number[-4:],
|
138
|
+
error_code=454)
|
139
|
+
totp_code = request.DATA.get("totp_code", None)
|
140
|
+
if totp_code is None:
|
141
|
+
# member.log("login_blocked", "requires MFA (TOTP)", request, method="login", level=31)
|
142
|
+
return restStatus(request, False, error="Requires MFA (TOTP)", error_code=455)
|
143
|
+
if not member.totp_verify(totp_code):
|
144
|
+
member.log("login_blocked", "Invalid MFA code", request, method="login", level=31)
|
145
|
+
return restStatus(request, False, error="Invalid Credentials", error_code=456)
|
146
|
+
return None
|
147
|
+
|
148
|
+
|
110
149
|
def member_login_uname_pword(request, username, password):
|
111
150
|
member = getMemberByUsername(username)
|
112
151
|
if not member:
|
113
152
|
return restStatus(request, False, error="Password or Username is not correct", error_code=422)
|
114
153
|
member.canLogin(request) # throws exception if cannot login
|
115
154
|
if member.requires_topt:
|
116
|
-
|
117
|
-
if
|
118
|
-
|
119
|
-
return restStatus(request, False, error="requires MFA (TOTP)", error_code=455)
|
120
|
-
if not member.totp_verify(totp_code):
|
121
|
-
member.log("login_blocked", "invalid MFA code", request, method="login", level=31)
|
122
|
-
return restStatus(request, False, error="invalid MFA code", error_code=456)
|
155
|
+
resp = checkForTOTP(request, member)
|
156
|
+
if resp is not None:
|
157
|
+
return resp
|
123
158
|
if not member.login(request=request, password=password, use_jwt=False):
|
124
159
|
member.log("login_failed", "incorrect password", request, method="login", level=31)
|
125
160
|
return restStatus(request, False, error="Password or Username is incorrect", error_code=401)
|
@@ -157,11 +192,7 @@ def member_login_uname_code(request, username, auth_code):
|
|
157
192
|
if request.DATA.get("auth_method") == "basic":
|
158
193
|
return restGet(request, dict(id=member.pk, session_key=request.session.session_key))
|
159
194
|
|
160
|
-
|
161
|
-
if member.security_token is None:
|
162
|
-
member.refreshSecurityToken()
|
163
|
-
token = JWToken(user_id=member.pk, key=member.security_token)
|
164
|
-
return restGet(request, dict(access=token.access_token, refresh=token.refresh_token, id=member.pk))
|
195
|
+
return on_complete_jwt(request, member)
|
165
196
|
|
166
197
|
|
167
198
|
@rd.url(r'^logout$')
|
@@ -196,22 +227,24 @@ def is_member_logged_in(request):
|
|
196
227
|
return restStatus(request, False)
|
197
228
|
|
198
229
|
|
199
|
-
@rd.urlPOST
|
200
|
-
@rd.urlPOST (r'^forget/$')
|
230
|
+
@rd.urlPOST('mfa/request_code')
|
201
231
|
@rd.never_cache
|
202
|
-
def
|
203
|
-
|
204
|
-
|
205
|
-
|
232
|
+
def member_request_code(request):
|
233
|
+
member = member_from_request(request)
|
234
|
+
resp = member_check_can_login(request, member)
|
235
|
+
if resp is not None:
|
236
|
+
return resp
|
237
|
+
return member_forgot_password_code(request, member)
|
206
238
|
|
207
|
-
| Return: status + error
|
208
239
|
|
209
|
-
|
210
|
-
"""
|
240
|
+
def member_from_request(request):
|
211
241
|
username = request.DATA.get('username', None)
|
212
242
|
if not username:
|
213
|
-
|
214
|
-
|
243
|
+
raise restPermissionDenied("Username is required")
|
244
|
+
return getMemberByUsername(username)
|
245
|
+
|
246
|
+
|
247
|
+
def member_check_can_login(request, member):
|
215
248
|
if not member:
|
216
249
|
return restStatus(request, False, error="Password or Username is incorrect", error_code=422)
|
217
250
|
if not member.is_active:
|
@@ -220,6 +253,24 @@ def member_forgot_password(request):
|
|
220
253
|
if member.is_blocked:
|
221
254
|
member.log("login_blocked", "account is locked out", request, method="login", level=31)
|
222
255
|
return restStatus(request, False, error="Account locked out", error_code=411)
|
256
|
+
return None
|
257
|
+
|
258
|
+
|
259
|
+
@rd.urlPOST('forgot')
|
260
|
+
@rd.never_cache
|
261
|
+
def member_forgot_password(request):
|
262
|
+
"""
|
263
|
+
| param: username = use the username as the lookup
|
264
|
+
| param: email = use the email as the lookup
|
265
|
+
|
266
|
+
| Return: status + error
|
267
|
+
|
268
|
+
| Send fgroupet password reset instructions
|
269
|
+
"""
|
270
|
+
member = member_from_request(request)
|
271
|
+
resp = member_check_can_login(request, member)
|
272
|
+
if resp is not None:
|
273
|
+
return resp
|
223
274
|
|
224
275
|
if request.DATA.get("use_code", False):
|
225
276
|
return member_forgot_password_code(request, member)
|
@@ -264,7 +315,7 @@ def member_forgot_password_code(request, member):
|
|
264
315
|
|
265
316
|
|
266
317
|
# time based one time passwords
|
267
|
-
@rd.urlGET(
|
318
|
+
@rd.urlGET('totp/qrcode')
|
268
319
|
@rd.login_required
|
269
320
|
def totp_qrcode(request):
|
270
321
|
token = request.member.getProperty("totp_token", category="secrets", default=None)
|
@@ -301,6 +352,7 @@ def totp_verify(request):
|
|
301
352
|
return restPermissionDenied(request, "invalid code format")
|
302
353
|
if not request.member.totp_verify(code):
|
303
354
|
return restPermissionDenied(request, "invalid code")
|
355
|
+
request.member.setProperty("totp_verified", 1)
|
304
356
|
return restStatus(request, True)
|
305
357
|
|
306
358
|
|
account/rpc/group.py
CHANGED
@@ -46,9 +46,9 @@ def rest_on_group_invite(request, group_id=None):
|
|
46
46
|
if not data or not data.email:
|
47
47
|
return rv.restPermissionDenied(request, "missing fields")
|
48
48
|
if data.email:
|
49
|
-
member = Member.GetMember(data.email.lower())
|
49
|
+
member = Member.GetMember(data.email.lower().strip())
|
50
50
|
elif data.username:
|
51
|
-
member = Member.GetMember(data.username)
|
51
|
+
member = Member.GetMember(data.username.lower().strip())
|
52
52
|
elif data.phone_number:
|
53
53
|
member = Member.GetMemberByPhone(data.phone_number)
|
54
54
|
if member is None:
|
@@ -16,24 +16,25 @@ account/migrations/0013_memberdevice_ip.py,sha256=5Dxm5uNy7D1RnZeTYRYhU_7WlDQCme
|
|
16
16
|
account/migrations/0014_alter_notificationmemberrecord_member.py,sha256=q3CHimwbhTk8rHkqaaOOcNrsHE7hSkVL7JDH6KmxWZs,541
|
17
17
|
account/migrations/0015_memberdevice_buid.py,sha256=O3M3mS_O1zn4gQahC3ebRu8tMySo3cUbfO3X1-vLFMk,460
|
18
18
|
account/migrations/0016_authsession_buid.py,sha256=wZdiH_87Ik3jAXYUgtafeAo9IbJq35xDVOlQ_UiTC8k,424
|
19
|
+
account/migrations/0017_rename_requires_topt_member_requires_totp.py,sha256=GksGiF7OQDV2RihyC2OTBzSmDwzCzenThkNs6FKni4M,375
|
19
20
|
account/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
20
21
|
account/models/__init__.py,sha256=OxQbDkVcZogwgNj3bQWljOxAkkt15KgBYVrsumzek8Q,341
|
21
22
|
account/models/device.py,sha256=XipNpByreGubB5-d4ZBOoIV5Xw14b2Btcgn6fXz8HAc,4105
|
22
23
|
account/models/feeds.py,sha256=4n4Mv8HjcXpUmMPWafHlsGbVQ1fDKdtblL1hp30sDrg,1437
|
23
24
|
account/models/group.py,sha256=X_ij8moxmtH9qwH3w2EL8siuy-prsyxQVv1JIhBp3hI,19399
|
24
25
|
account/models/legacy.py,sha256=zYdtv4LC0ooxPVqWM-uToPwV-lYWQLorSE6p6yn1xDw,2720
|
25
|
-
account/models/member.py,sha256=
|
26
|
+
account/models/member.py,sha256=7z6RAW9vVl7FX1q6KfW02I6VvAzsxkJy_i2ULYfBNHo,48574
|
26
27
|
account/models/membership.py,sha256=l7suW6kRCfa3KqdbqjOIO2jVhxjkPbEENdJIlj2WomY,7378
|
27
28
|
account/models/notify.py,sha256=YnZujSHJHY7B09e6FIyZIEJRWLPYk1Sk1e92tFzB1IA,12078
|
28
29
|
account/models/session.py,sha256=swhxcx_lWzOpGCmfifXoACgWYqmKmS7eZsD9s9jSToc,3509
|
29
30
|
account/models/settings.py,sha256=gOyRWBVd3BQpjfj_hJPtqX3H46ztyRAFxBrPbv11lQg,2137
|
30
31
|
account/oauth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
31
32
|
account/oauth/google.py,sha256=q5M6Qhpfp9QslKRVYFZBvtG6kgXV6vYMrR5fp6Xdb9I,2078
|
32
|
-
account/periodic.py,sha256
|
33
|
+
account/periodic.py,sha256=-u0n-7QTJgDOkasGhBAPwHAwjpqWGA-MZLEFkVTqCGU,874
|
33
34
|
account/rpc/__init__.py,sha256=L_AqHC0WbgUgLoqvNz6pY0E34eqh7sRaX77I6TxhRZ4,152
|
34
|
-
account/rpc/auth.py,sha256=
|
35
|
+
account/rpc/auth.py,sha256=TL74o-LH8ETqF0EzLb6Bis_lsLx9VEirA-ZvivBUPaE,13652
|
35
36
|
account/rpc/device.py,sha256=fbbZFp3cUdhVXvD7gVFOqFWj4hKS3bjZKD_aF5fQxd8,2852
|
36
|
-
account/rpc/group.py,sha256=
|
37
|
+
account/rpc/group.py,sha256=Y_Ii-vlDx09neMd95AmC7xBwDf3wdFgXjB-kIG2jMdE,3472
|
37
38
|
account/rpc/member.py,sha256=oKdXSGhQ7AOPTwisZ5RvHhQ1SdZoXWlBQY0lIlDXJY0,1150
|
38
39
|
account/rpc/notify.py,sha256=Q2YWejP36egeF060Hih5uX4Psv_B8NWlLLPi7iDYlIw,3344
|
39
40
|
account/rpc/oauth.py,sha256=-BW38HjYwSQhOs31ubnBxO0yCKVpczEMoHq54NC9uOU,2610
|
@@ -94,7 +95,7 @@ incident/migrations/0011_ticket.py,sha256=Ml5E_Qi4Z0MD89fetoOFOL3rPlVQdjaaDCcFBf
|
|
94
95
|
incident/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
95
96
|
incident/models/__init__.py,sha256=NMphuhb0RTMf7Ov4QkNv7iv6_I8Wtr3xQ54yjX_a31M,209
|
96
97
|
incident/models/event.py,sha256=AXFV92OtnVi3opSZcRX1o3qZ8uBvqGFL549AXH2gjY8,6792
|
97
|
-
incident/models/incident.py,sha256=
|
98
|
+
incident/models/incident.py,sha256=zaq81_ZdGAeUDKpmP2c9Du8TPTMt2EW5e-Oyt8q2Lwo,14390
|
98
99
|
incident/models/ossec.py,sha256=pWMqcuTRxPFTEF-OZQSMn7YpNEE9mfsI4GMhWWjJs5I,2187
|
99
100
|
incident/models/rules.py,sha256=Ua-hC78_D6YikJjP3DXfA8ghi6zu__Qud8H1bk7MRG0,5342
|
100
101
|
incident/models/ticket.py,sha256=S3kqGQpYLE6Y4M9IKu_60sgW-f592xNr8uufqHnvDoU,2302
|
@@ -350,7 +351,7 @@ pushit/utils.py,sha256=IeTCGa-164nmB1jIsK1lu1O1QzUhS3BKfuXHGjCW-ck,2121
|
|
350
351
|
rest/.gitignore,sha256=TbEvWRMnAiajCTOdhiNrd9eeCAaIjRp9PRjE_VkMM5g,118
|
351
352
|
rest/README.md,sha256=V3ETc-cJu8PZIbKr9xSe_pA4JEUpC8Dhw4bQeVCDJPw,5460
|
352
353
|
rest/RemoteEvents.py,sha256=nL46U7AuxIrlw2JunphR1tsXyqi-ep_gD9CYGpYbNgE,72
|
353
|
-
rest/__init__.py,sha256=
|
354
|
+
rest/__init__.py,sha256=42ez8LEkgPOOkm7pc1ftpMfoo52l5H5XggNBtlOWYYs,121
|
354
355
|
rest/arc4.py,sha256=y644IbF1ec--e4cUJ3KEYsewTCITK0gmlwa5mJruFC0,1967
|
355
356
|
rest/cache.py,sha256=1Qg0rkaCJCaVP0-l5hZg2CIblTdeBSlj_0fP6vlKUpU,83
|
356
357
|
rest/crypto/__init__.py,sha256=Tl0U11rgj1eBYqd6OXJ2_XSdNLumW_JkBZnaJqI6Ldw,72
|
@@ -377,12 +378,12 @@ rest/management/commands/rpc.py,sha256=bQRisv4z34LyRR5xiS63glY5tgZC4SkYr7UWoCtHl
|
|
377
378
|
rest/middleware/__init__.py,sha256=u4Z8Fl9uOuX2yHT_uISCLjLDofdGWrpaDNYrc6T1xE4,33
|
378
379
|
rest/middleware/cors.py,sha256=sNAgZ3chnXI5WKYdcbTc8eXqxZLdM1tHns7lIoI5BPE,3513
|
379
380
|
rest/middleware/db_router.py,sha256=jd0ywJK0PX6hz3Jy3DGRWfGr6v53tV-BtRIPm_32f0w,2345
|
380
|
-
rest/middleware/jwt.py,sha256=
|
381
|
+
rest/middleware/jwt.py,sha256=dR8rWnb1BrJmlvCVz2I9d0GD2CfnbxutGlqItbZWs1E,6017
|
381
382
|
rest/middleware/request.py,sha256=JchRNy5L-bGd-7h-KFYekGRvREe2eCkZXKOYqIkP2hI,4189
|
382
383
|
rest/middleware/session.py,sha256=zHSoQpIzRLmpqr_JvW406wzpvU3W3gDbm5JhtzLAMlE,10240
|
383
384
|
rest/middleware/session_store.py,sha256=X_i06TnZLW1srV0vkjjLhZ7fl1G56PswXxRpVzdFasw,1874
|
384
385
|
rest/models/__init__.py,sha256=M8pvFDq-WCF-QcM58X7pMufYYe0aaQ3U0PwGe9TKbbY,130
|
385
|
-
rest/models/base.py,sha256=
|
386
|
+
rest/models/base.py,sha256=pjilLSXpkNVdyOVm8ipExYpjW-P--w4yKW36j3-EOdY,65787
|
386
387
|
rest/models/cacher.py,sha256=eKz8TINVhWEqKhJGMsRkKZTtBUIv5rN3NHbZwOC56Uk,578
|
387
388
|
rest/models/metadata.py,sha256=VM5t3I1DYgvwLAOjaYcMdVZ2JWrrcJUMU3o3gATkPYk,12626
|
388
389
|
rest/net.py,sha256=LTF4ip-ur8C2G7NETVOg7ioACegBGo4sDJA18PfF5kQ,1691
|
@@ -447,7 +448,7 @@ telephony/decorators.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
447
448
|
telephony/migrations/0001_initial.py,sha256=YRiNtpeqj-4uvq19sfI64Q-KRnQ_T53kNzyt-CZUl14,3030
|
448
449
|
telephony/migrations/0002_alter_sms_sid.py,sha256=QAnMG-UZ5emssZwdJ8XwfaRh3872zUUR55maDMD4RkE,424
|
449
450
|
telephony/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
450
|
-
telephony/models.py,sha256=
|
451
|
+
telephony/models.py,sha256=68BWPyTZ_bNptuCqhFEv3iraMp6bcWKXfJ7jnj_pUpo,8142
|
451
452
|
telephony/phone_util.py,sha256=15IWkTSqkjDWT9edPAYogAxHc1OdjOziPSxsJ8vfpfE,2426
|
452
453
|
telephony/rpc.py,sha256=GVPWH5XSPNar-ICu5oq-yF6FBmJbju3XJr6gSXA6ZVU,3535
|
453
454
|
wiki/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
@@ -482,7 +483,7 @@ ws4redis/servers/uwsgi.py,sha256=VyhoCI1DnVFqBiJYHoxqn5Idlf6uJPHvfBKgkjs34mo,172
|
|
482
483
|
ws4redis/settings.py,sha256=K0yBiLUuY81iDM4Yr-k8hbvjn5VVHu5zQhmMK8Dtz0s,1536
|
483
484
|
ws4redis/utf8validator.py,sha256=S0OlfjeGRP75aO6CzZsF4oTjRQAgR17OWE9rgZdMBZA,5122
|
484
485
|
ws4redis/websocket.py,sha256=R0TUyPsoVRD7Y_oU7w2I6NL4fPwiz5Vl94-fUkZgLHA,14848
|
485
|
-
django_restit-4.1.
|
486
|
-
django_restit-4.1.
|
487
|
-
django_restit-4.1.
|
488
|
-
django_restit-4.1.
|
486
|
+
django_restit-4.1.77.dist-info/LICENSE.md,sha256=VHN4hhEeVOoFjtG-5fVv4jesA4SWi0Z-KgOzzN6a1ps,1068
|
487
|
+
django_restit-4.1.77.dist-info/METADATA,sha256=AM9Kck1ngBJZB2d2puHI-_yNU9dFtFfjbbpr5onZm60,7573
|
488
|
+
django_restit-4.1.77.dist-info/WHEEL,sha256=Zb28QaM1gQi8f4VCBhsUklF61CTlNYfs9YAZn-TOGFk,88
|
489
|
+
django_restit-4.1.77.dist-info/RECORD,,
|
incident/models/incident.py
CHANGED
@@ -168,8 +168,8 @@ class Incident(models.Model, rm.RestModel, rm.MetaDataModel):
|
|
168
168
|
action, perm = self.rule.action.split(":")
|
169
169
|
members = Member.GetWithNotification(perm)
|
170
170
|
# count = self.getProperty("event_count", default=1, field_type=int)
|
171
|
-
url = F"{settings.INCIDENT_PORTAL_URL}"
|
172
|
-
msg = f"Incident #{self.pk}\n{self.description}\n
|
171
|
+
url = F"{settings.INCIDENT_PORTAL_URL}?incident={self.pk}"
|
172
|
+
msg = f"Incident #{self.pk}\n{self.description}\n{url}"
|
173
173
|
for m in members:
|
174
174
|
m.sendSMS(msg)
|
175
175
|
except Exception:
|
rest/__init__.py
CHANGED
rest/middleware/jwt.py
CHANGED
@@ -112,6 +112,18 @@ class JWTokenMiddleware(object):
|
|
112
112
|
if atoken is None:
|
113
113
|
helpers.log_error("login failed with authtoken")
|
114
114
|
return
|
115
|
+
if atoken.member.requires_totp:
|
116
|
+
reason = F"auth failed bacause requires_totp prevents auth_token login for {atoken.member.username}"
|
117
|
+
atoken.member.log(
|
118
|
+
"login_blocked",
|
119
|
+
reason,
|
120
|
+
request, method="login", level=31)
|
121
|
+
atoken.member.reportIncident(
|
122
|
+
"account", reason, level=2,
|
123
|
+
error_code=444,
|
124
|
+
request=request,
|
125
|
+
details=reason)
|
126
|
+
return
|
115
127
|
if not atoken.member.canLogin(request, False):
|
116
128
|
helpers.log_error("user cannot login via authtoken", request.token)
|
117
129
|
return
|
rest/models/base.py
CHANGED
@@ -199,11 +199,13 @@ class RestModel(object):
|
|
199
199
|
|
200
200
|
@classmethod
|
201
201
|
def getGraph(cls, name):
|
202
|
-
|
203
|
-
|
204
|
-
|
202
|
+
if name is None:
|
203
|
+
name = "default"
|
204
|
+
graph_key = f"_graph_{name}__"
|
205
|
+
if hasattr(cls._meta, graph_key):
|
206
|
+
return getattr(cls._meta, graph_key)
|
205
207
|
graph = cls.buildGraph(name)
|
206
|
-
setattr(cls, graph_key, graph)
|
208
|
+
setattr(cls._meta, graph_key, graph)
|
207
209
|
return graph
|
208
210
|
|
209
211
|
def toGraph(self, request=None, graph="basic"):
|
telephony/models.py
CHANGED
File without changes
|
File without changes
|