core.user.UserItem.on_put()   F
last analyzed

Complexity

Conditions 24

Size

Total Lines 112
Code Lines 86

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 24
eloc 86
nop 3
dl 0
loc 112
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like core.user.UserItem.on_put() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
import falcon
2
import simplejson as json
3
import mysql.connector
4
import config
5
import uuid
6
import hashlib
7
import re
8
import os
9
from datetime import datetime, timedelta
10
11
12
class UserCollection:
13
    @staticmethod
14
    def __init__():
15
        pass
16
17
    @staticmethod
18
    def on_options(req, resp):
19
        resp.status = falcon.HTTP_200
20
21
    @staticmethod
22
    def on_get(req, resp):
23
        cnx = mysql.connector.connect(**config.myems_user_db)
24
        cursor = cnx.cursor()
25
26
        query = (" SELECT u.id, u.name, u.display_name, u.uuid, "
27
                 "        u.email, u.is_admin, p.id,p.name "
28
                 " FROM tbl_users u "
29
                 " LEFT JOIN tbl_privileges p ON u.privilege_id = p.id "
30
                 " ORDER BY u.name ")
31
        cursor.execute(query)
32
        rows = cursor.fetchall()
33
        cursor.close()
34
        cnx.disconnect()
35
36
        result = list()
37
        if rows is not None and len(rows) > 0:
38
            for row in rows:
39
                meta_result = {"id": row[0],
40
                               "name": row[1],
41
                               "display_name": row[2],
42
                               "uuid": row[3],
43
                               "email": row[4],
44
                               "is_admin": True if row[5] else False,
45
                               "privilege": {
46
                                   "id": row[6],
47
                                   "name": row[7]} if row[6] is not None else None}
48
                result.append(meta_result)
49
50
        resp.body = json.dumps(result)
51
52
    @staticmethod
53
    def on_post(req, resp):
54
        """Handles POST requests"""
55
        try:
56
            raw_json = req.stream.read().decode('utf-8')
57
        except Exception as ex:
58
            raise falcon.HTTPError(falcon.HTTP_400, title='API.EXCEPTION', description=ex)
59
60
        new_values = json.loads(raw_json)
61
62
        if 'name' not in new_values['data'].keys() or \
63
                not isinstance(new_values['data']['name'], str) or \
64
                len(str.strip(new_values['data']['name'])) == 0:
65
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
66
                                   description='API.INVALID_USER_NAME')
67
        name = str.strip(new_values['data']['name'])
68
69
        if 'display_name' not in new_values['data'].keys() or \
70
                not isinstance(new_values['data']['display_name'], str) or \
71
                len(str.strip(new_values['data']['display_name'])) == 0:
72
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
73
                                   description='API.INVALID_DISPLAY_NAME')
74
        display_name = str.strip(new_values['data']['display_name'])
75
76
        if 'email' not in new_values['data'].keys() or \
77
                not isinstance(new_values['data']['email'], str) or \
78
                len(str.strip(new_values['data']['email'])) == 0:
79
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
80
                                   description='API.INVALID_EMAIL')
81
        email = str.lower(str.strip(new_values['data']['email']))
82
83
        match = re.match(r'^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4})$', email)
84
        if match is None:
85
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
86
                                   description='API.INVALID_EMAIL')
87
88
        if 'is_admin' not in new_values['data'].keys() or \
89
                not isinstance(new_values['data']['is_admin'], bool):
90
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
91
                                   description='API.INVALID_IS_ADMIN_VALUE')
92
        is_admin = new_values['data']['is_admin']
93
94
        if 'privilege_id' in new_values['data'].keys():
95
            if not isinstance(new_values['data']['privilege_id'], int) or \
96
                    new_values['data']['privilege_id'] <= 0:
97
                raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
98
                                       description='API.INVALID_PRIVILEGE_ID')
99
            privilege_id = new_values['data']['privilege_id']
100
        else:
101
            privilege_id = None
102
103
        cnx = mysql.connector.connect(**config.myems_user_db)
104
        cursor = cnx.cursor()
105
106
        cursor.execute(" SELECT name "
107
                       " FROM tbl_users "
108
                       " WHERE name = %s ", (name,))
109
        if cursor.fetchone() is not None:
110
            cursor.close()
111
            cnx.disconnect()
112
            raise falcon.HTTPError(falcon.HTTP_404, title='API.BAD_REQUEST',
113
                                   description='API.USER_NAME_IS_ALREADY_IN_USE')
114
115
        cursor.execute(" SELECT name "
116
                       " FROM tbl_users "
117
                       " WHERE email = %s ", (email,))
118
        if cursor.fetchone() is not None:
119
            cursor.close()
120
            cnx.disconnect()
121
            raise falcon.HTTPError(falcon.HTTP_404, title='API.BAD_REQUEST',
122
                                   description='API.EMAIL_IS_ALREADY_IN_USE')
123
124
        if privilege_id is not None:
125
            cursor.execute(" SELECT name "
126
                           " FROM tbl_privileges "
127
                           " WHERE id = %s ",
128
                           (privilege_id,))
129
            if cursor.fetchone() is None:
130
                cursor.close()
131
                cnx.disconnect()
132
                raise falcon.HTTPError(falcon.HTTP_404, title='API.NOT_FOUND',
133
                                       description='API.PRIVILEGE_NOT_FOUND')
134
135
        add_row = (" INSERT INTO tbl_users "
136
                   "     (name, uuid, display_name, email, salt, password, is_admin, privilege_id) "
137
                   " VALUES (%s, %s, %s, %s, %s, %s, %s, %s) ")
138
139
        salt = uuid.uuid4().hex
140
        password = new_values['data']['password']
141
        hashed_password = hashlib.sha512(salt.encode() + password.encode()).hexdigest()
142
143
        cursor.execute(add_row, (name,
144
                                 str(uuid.uuid4()),
145
                                 display_name,
146
                                 email,
147
                                 salt,
148
                                 hashed_password,
149
                                 is_admin,
150
                                 privilege_id))
151
        new_id = cursor.lastrowid
152
        cnx.commit()
153
        cursor.close()
154
        cnx.disconnect()
155
156
        resp.status = falcon.HTTP_201
157
        resp.location = '/users/' + str(new_id)
158
159
160
class UserItem:
161
    @staticmethod
162
    def __init__():
163
        pass
164
165
    @staticmethod
166
    def on_options(req, resp, id_):
167
        resp.status = falcon.HTTP_200
168
169
    @staticmethod
170
    def on_get(req, resp, id_):
171
        if not id_.isdigit() or int(id_) <= 0:
172
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
173
                                   description='API.INVALID_USER_ID')
174
175
        cnx = mysql.connector.connect(**config.myems_user_db)
176
        cursor = cnx.cursor()
177
178
        query = (" SELECT id, name, display_name, uuid, email "
179
                 " FROM tbl_users "
180
                 " WHERE id =%s ")
181
        cursor.execute(query, (id_,))
182
        row = cursor.fetchone()
183
        cursor.close()
184
        cnx.disconnect()
185
186
        if row is None:
187
            raise falcon.HTTPError(falcon.HTTP_404, title='API.NOT_FOUND',
188
                                   description='API.USER_NOT_FOUND')
189
190
        result = {"id": row[0],
191
                  "name": row[1],
192
                  "display_name": row[2],
193
                  "uuid": row[3],
194
                  "email": row[4]}
195
        resp.body = json.dumps(result)
196
197 View Code Duplication
    @staticmethod
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
198
    def on_delete(req, resp, id_):
199
        if not id_.isdigit() or int(id_) <= 0:
200
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
201
                                   description='API.INVALID_USER_ID')
202
203
        cnx = mysql.connector.connect(**config.myems_user_db)
204
        cursor = cnx.cursor()
205
206
        cursor.execute(" SELECT name "
207
                       " FROM tbl_users "
208
                       " WHERE id = %s ", (id_,))
209
        if cursor.fetchone() is None:
210
            cursor.close()
211
            cnx.disconnect()
212
            raise falcon.HTTPError(falcon.HTTP_404, title='API.NOT_FOUND',
213
                                   description='API.USER_NOT_FOUND')
214
215
        # TODO: delete associated objects
216
        cursor.execute(" DELETE FROM tbl_users WHERE id = %s ", (id_,))
217
        cnx.commit()
218
219
        cursor.close()
220
        cnx.disconnect()
221
222
        resp.status = falcon.HTTP_204
223
224
    @staticmethod
225
    def on_put(req, resp, id_):
226
        """Handles PUT requests"""
227
        try:
228
            raw_json = req.stream.read().decode('utf-8')
229
        except Exception as ex:
230
            raise falcon.HTTPError(falcon.HTTP_400, title='API.EXCEPTION', description=ex)
231
232
        if not id_.isdigit() or int(id_) <= 0:
233
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
234
                                   description='API.INVALID_')
235
236
        new_values = json.loads(raw_json)
237
238
        if 'name' not in new_values['data'].keys() or \
239
                not isinstance(new_values['data']['name'], str) or \
240
                len(str.strip(new_values['data']['name'])) == 0:
241
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
242
                                   description='API.INVALID_USER_NAME')
243
        name = str.strip(new_values['data']['name'])
244
245
        if 'display_name' not in new_values['data'].keys() or \
246
                not isinstance(new_values['data']['display_name'], str) or \
247
                len(str.strip(new_values['data']['display_name'])) == 0:
248
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
249
                                   description='API.INVALID_DISPLAY_NAME')
250
        display_name = str.strip(new_values['data']['display_name'])
251
252
        if 'email' not in new_values['data'].keys() or \
253
                not isinstance(new_values['data']['email'], str) or \
254
                len(str.strip(new_values['data']['email'])) == 0:
255
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
256
                                   description='API.INVALID_EMAIL')
257
        email = str.lower(str.strip(new_values['data']['email']))
258
259
        match = re.match(r'^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4})$', email)
260
        if match is None:
261
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
262
                                   description='API.INVALID_EMAIL')
263
264
        if 'is_admin' not in new_values['data'].keys() or \
265
                not isinstance(new_values['data']['is_admin'], bool):
266
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
267
                                   description='API.INVALID_IS_ADMIN_VALUE')
268
        is_admin = new_values['data']['is_admin']
269
270
        if 'privilege_id' in new_values['data'].keys():
271
            if not isinstance(new_values['data']['privilege_id'], int) or \
272
                    new_values['data']['privilege_id'] <= 0:
273
                raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
274
                                       description='API.INVALID_PRIVILEGE_ID')
275
            privilege_id = new_values['data']['privilege_id']
276
        else:
277
            privilege_id = None
278
279
        cnx = mysql.connector.connect(**config.myems_user_db)
280
        cursor = cnx.cursor()
281
282
        cursor.execute(" SELECT name "
283
                       " FROM tbl_users "
284
                       " WHERE id = %s ", (id_,))
285
        if cursor.fetchone() is None:
286
            cursor.close()
287
            cnx.disconnect()
288
            raise falcon.HTTPError(falcon.HTTP_404, title='API.NOT_FOUND',
289
                                   description='API.USER_NOT_FOUND')
290
291
        cursor.execute(" SELECT name "
292
                       " FROM tbl_users "
293
                       " WHERE name = %s AND id != %s ", (name, id_))
294
        if cursor.fetchone() is not None:
295
            cursor.close()
296
            cnx.disconnect()
297
            raise falcon.HTTPError(falcon.HTTP_404, title='API.BAD_REQUEST',
298
                                   description='API.USER_NAME_IS_ALREADY_IN_USE')
299
300
        cursor.execute(" SELECT name "
301
                       " FROM tbl_users "
302
                       " WHERE email = %s AND id != %s ", (email, id_))
303
        if cursor.fetchone() is not None:
304
            cursor.close()
305
            cnx.disconnect()
306
            raise falcon.HTTPError(falcon.HTTP_404, title='API.BAD_REQUEST',
307
                                   description='API.EMAIL_IS_ALREADY_IN_USE')
308
309
        if privilege_id is not None:
310
            cursor.execute(" SELECT name "
311
                           " FROM tbl_privileges "
312
                           " WHERE id = %s ",
313
                           (privilege_id,))
314
            if cursor.fetchone() is None:
315
                cursor.close()
316
                cnx.disconnect()
317
                raise falcon.HTTPError(falcon.HTTP_404, title='API.NOT_FOUND',
318
                                       description='API.PRIVILEGE_NOT_FOUND')
319
320
        update_row = (" UPDATE tbl_users "
321
                      " SET name = %s, display_name = %s, email = %s, "
322
                      "     is_admin = %s, privilege_id = %s "
323
                      " WHERE id = %s ")
324
        cursor.execute(update_row, (name,
325
                                    display_name,
326
                                    email,
327
                                    is_admin,
328
                                    privilege_id,
329
                                    id_,))
330
        cnx.commit()
331
332
        cursor.close()
333
        cnx.disconnect()
334
335
        resp.status = falcon.HTTP_200
336
337
338
class UserLogin:
339
    @staticmethod
340
    def __init__():
341
        pass
342
343
    @staticmethod
344
    def on_options(req, resp):
345
        resp.status = falcon.HTTP_200
346
347
    @staticmethod
348
    def on_put(req, resp):
349
        """Handles PUT requests"""
350
        try:
351
            raw_json = req.stream.read().decode('utf-8')
352
            new_values = json.loads(raw_json)
353
        except Exception as ex:
354
            raise falcon.HTTPError(falcon.HTTP_400, title='API.EXCEPTION', description=ex)
355
356
        if not isinstance(new_values['data']['password'], str) or \
357
                len(str.strip(new_values['data']['password'])) == 0:
358
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
359
                                   description='API.INVALID_PASSWORD')
360
361
        cnx = mysql.connector.connect(**config.myems_user_db)
362
        cursor = cnx.cursor()
363
        result = dict()
364
365
        if 'name' in new_values['data']:
366
367
            if not isinstance(new_values['data']['name'], str) or \
368
                    len(str.strip(new_values['data']['name'])) == 0:
369
                raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
370
                                       description='API.INVALID_USER_NAME')
371
372
            query = (" SELECT id, name, uuid, display_name, email, salt, password, is_admin "
373
                     " FROM tbl_users "
374
                     " WHERE name = %s ")
375
            cursor.execute(query, (str.strip(new_values['data']['name']).lower(),))
376
            row = cursor.fetchone()
377
            if row is None:
378
                cursor.close()
379
                cnx.disconnect()
380
                raise falcon.HTTPError(falcon.HTTP_404, 'API.ERROR', 'API.USER_NOT_FOUND')
381
382
            result = {"id": row[0],
383
                      "name": row[1],
384
                      "uuid": row[2],
385
                      "display_name": row[3],
386
                      "email": row[4],
387
                      "salt": row[5],
388
                      "password": row[6],
389
                      "is_admin": True if row[7] else False}
390
391
        elif 'email' in new_values['data']:
392
            if not isinstance(new_values['data']['email'], str) or \
393
                    len(str.strip(new_values['data']['email'])) == 0:
394
                raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
395
                                       description='API.INVALID_EMAIL')
396
397
            query = (" SELECT id, name, uuid, display_name, email, salt, password, is_admin "
398
                     " FROM tbl_users "
399
                     " WHERE email = %s ")
400
            cursor.execute(query, (str.strip(new_values['data']['email']).lower(),))
401
            row = cursor.fetchone()
402
            if row is None:
403
                cursor.close()
404
                cnx.disconnect()
405
                raise falcon.HTTPError(falcon.HTTP_404, 'API.ERROR', 'API.USER_NOT_FOUND')
406
407
            result = {"id": row[0],
408
                      "name": row[1],
409
                      "uuid": row[2],
410
                      "display_name": row[3],
411
                      "email": row[4],
412
                      "salt": row[5],
413
                      "password": row[6],
414
                      "is_admin": True if row[7] else False}
415
        else:
416
            cursor.close()
417
            cnx.disconnect()
418
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
419
                                   description='API.INVALID_USER_NAME_OR_EMAIL')
420
421
        salt = result['salt']
422
        password = str.strip(new_values['data']['password'])
423
        hashed_password = hashlib.sha512(salt.encode() + password.encode()).hexdigest()
424
425
        if hashed_password != result['password']:
426
            cursor.close()
427
            cnx.disconnect()
428
            raise falcon.HTTPError(falcon.HTTP_400, 'API.BAD_REQUEST', 'API.INVALID_PASSWORD')
429
430
        add_session = (" INSERT INTO tbl_sessions "
431
                       "             (user_uuid, token, utc_expires) "
432
                       " VALUES (%s, %s, %s) ")
433
        user_uuid = result['uuid']
434
        token = hashlib.sha1(os.urandom(24)).hexdigest()
435
        utc_expires = datetime.utcnow() + timedelta(seconds=1000 * 60 * 60 * 8)
436
        cursor.execute(add_session, (user_uuid, token, utc_expires))
437
        cnx.commit()
438
        cursor.close()
439
        cnx.disconnect()
440
        resp.set_cookie('user_uuid', user_uuid,
441
                        domain=config.myems_api_domain, path='/', secure=False, http_only=False)
442
        resp.set_cookie('token', token,
443
                        domain=config.myems_api_domain, path='/', secure=False, http_only=False)
444
        del result['salt']
445
        del result['password']
446
        result['token'] = token
447
448
        resp.body = json.dumps(result)
449
        resp.status = falcon.HTTP_200
450
451
452
class UserLogout:
453
    @staticmethod
454
    def __init__():
455
        pass
456
457
    @staticmethod
458
    def on_options(req, resp):
459
        resp.status = falcon.HTTP_200
460
461
    @staticmethod
462
    def on_put(req, resp):
463
        """Handles PUT requests"""
464
465
        if 'USER-UUID' not in req.headers or \
466
                not isinstance(req.headers['USER-UUID'], str) or \
467
                len(str.strip(req.headers['USER-UUID'])) == 0:
468
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
469
                                   description='API.INVALID_USER_UUID')
470
        user_uuid = str.strip(req.headers['USER-UUID'])
471
472
        if 'TOKEN' not in req.headers or \
473
                not isinstance(req.headers['TOKEN'], str) or \
474
                len(str.strip(req.headers['TOKEN'])) == 0:
475
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
476
                                   description='API.INVALID_TOKEN')
477
        token = str.strip(req.headers['TOKEN'])
478
479
        cnx = mysql.connector.connect(**config.myems_user_db)
480
        cursor = cnx.cursor()
481
        query = (" DELETE FROM tbl_sessions "
482
                 " WHERE user_uuid = %s AND token = %s ")
483
        cursor.execute(query, (user_uuid, token,))
484
        rowcount = cursor.rowcount
485
        cnx.commit()
486
        cursor.close()
487
        cnx.disconnect()
488
        if rowcount is None or rowcount == 0:
489
            raise falcon.HTTPError(falcon.HTTP_404, title='API.NOT_FOUND',
490
                                   description='API.USER_SESSION_NOT_FOUND')
491
492
        resp.set_cookie('user_uuid', '',
493
                        domain=config.myems_api_domain, path='/', secure=False, http_only=False)
494
        resp.set_cookie('token', '',
495
                        domain=config.myems_api_domain, path='/', secure=False, http_only=False)
496
        resp.body = json.dumps("OK")
497
        resp.status = falcon.HTTP_200
498
499
500
class ChangePassword:
501
    @staticmethod
502
    def __init__():
503
        pass
504
505
    @staticmethod
506
    def on_options(req, resp):
507
        resp.status = falcon.HTTP_200
508
509
    @staticmethod
510
    def on_put(req, resp):
511
        """Handles PUT requests"""
512
        if 'USER-UUID' not in req.headers or \
513
                not isinstance(req.headers['USER-UUID'], str) or \
514
                len(str.strip(req.headers['USER-UUID'])) == 0:
515
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
516
                                   description='API.INVALID_USER_UUID')
517
        user_uuid = str.strip(req.headers['USER-UUID'])
518
519
        if 'TOKEN' not in req.headers or \
520
                not isinstance(req.headers['TOKEN'], str) or \
521
                len(str.strip(req.headers['TOKEN'])) == 0:
522
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
523
                                   description='API.INVALID_TOKEN')
524
        token = str.strip(req.headers['TOKEN'])
525
526
        try:
527
            raw_json = req.stream.read().decode('utf-8')
528
            new_values = json.loads(raw_json)
529
        except Exception as ex:
530
            raise falcon.HTTPError(falcon.HTTP_400, 'API.ERROR', ex.args)
531
532
        if 'old_password' not in new_values['data'] or \
533
                not isinstance(new_values['data']['old_password'], str) or \
534
                len(str.strip(new_values['data']['old_password'])) == 0:
535
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
536
                                   description='API.INVALID_OLD_PASSWORD')
537
        old_password = str.strip(new_values['data']['old_password'])
538
539
        if 'new_password' not in new_values['data'] or \
540
                not isinstance(new_values['data']['new_password'], str) or \
541
                len(str.strip(new_values['data']['new_password'])) == 0:
542
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
543
                                   description='API.INVALID_NEW_PASSWORD')
544
        new_password = str.strip(new_values['data']['new_password'])
545
546
        # Verify User Session
547
548
        cnx = mysql.connector.connect(**config.myems_user_db)
549
        cursor = cnx.cursor()
550
        query = (" SELECT utc_expires "
551
                 " FROM tbl_sessions "
552
                 " WHERE user_uuid = %s AND token = %s")
553
        cursor.execute(query, (user_uuid, token,))
554
        row = cursor.fetchone()
555
556 View Code Duplication
        if row is None:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
557
            cursor.close()
558
            cnx.disconnect()
559
            raise falcon.HTTPError(falcon.HTTP_404, title='API.NOT_FOUND',
560
                                   description='API.USER_SESSION_NOT_FOUND')
561
        else:
562
            utc_expires = row[0]
563
            if datetime.utcnow() > utc_expires:
564
                cursor.close()
565
                cnx.disconnect()
566
                raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
567
                                       description='API.USER_SESSION_TIMEOUT')
568
569
        query = (" SELECT salt, password "
570
                 " FROM tbl_users "
571
                 " WHERE uuid = %s ")
572
        cursor.execute(query, (user_uuid,))
573
        row = cursor.fetchone()
574
        if row is None:
575
            cursor.close()
576
            cnx.disconnect()
577
            raise falcon.HTTPError(falcon.HTTP_404, 'API.NOT_FOUND', 'API.USER_NOT_FOUND')
578
579
        result = {'salt': row[0], 'password': row[1]}
580
581
        # verify old password
582
        salt = result['salt']
583
        hashed_password = hashlib.sha512(salt.encode() + old_password.encode()).hexdigest()
584
585
        if hashed_password != result['password']:
586
            cursor.close()
587
            cnx.disconnect()
588
            raise falcon.HTTPError(falcon.HTTP_400, 'API.BAD_REQUEST', 'API.INVALID_OLD_PASSWORD')
589
590
        # Update User password
591
        salt = uuid.uuid4().hex
592
        hashed_password = hashlib.sha512(salt.encode() + new_password.encode()).hexdigest()
593
594
        update_user = (" UPDATE tbl_users "
595
                       " SET salt = %s, password = %s "
596
                       " WHERE uuid = %s ")
597
        cursor.execute(update_user, (salt, hashed_password, user_uuid,))
598
        cnx.commit()
599
600
        # Refresh User session
601
        update_session = (" UPDATE tbl_sessions "
602
                          " SET utc_expires = %s "
603
                          " WHERE user_uuid = %s AND token = %s ")
604
        utc_expires = datetime.utcnow() + timedelta(seconds=1000 * 60 * 60 * 8)
605
        cursor.execute(update_session, (utc_expires, user_uuid, token, ))
606
        cnx.commit()
607
608
        cursor.close()
609
        cnx.disconnect()
610
        resp.body = json.dumps("OK")
611
        resp.status = falcon.HTTP_200
612
613
614
class ResetPassword:
615
    @staticmethod
616
    def __init__():
617
        pass
618
619
    @staticmethod
620
    def on_options(req, resp):
621
        resp.status = falcon.HTTP_200
622
623
    @staticmethod
624
    def on_put(req, resp):
625
        """Handles PUT requests"""
626
        if 'USER-UUID' not in req.headers or \
627
                not isinstance(req.headers['USER-UUID'], str) or \
628
                len(str.strip(req.headers['USER-UUID'])) == 0:
629
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
630
                                   description='API.INVALID_USER_UUID')
631
        admin_user_uuid = str.strip(req.headers['USER-UUID'])
632
633
        if 'TOKEN' not in req.headers or \
634
                not isinstance(req.headers['TOKEN'], str) or \
635
                len(str.strip(req.headers['TOKEN'])) == 0:
636
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
637
                                   description='API.INVALID_TOKEN')
638
        admin_token = str.strip(req.headers['TOKEN'])
639
640
        try:
641
            raw_json = req.stream.read().decode('utf-8')
642
            new_values = json.loads(raw_json)
643
        except Exception as ex:
644
            raise falcon.HTTPError(falcon.HTTP_400, 'API.ERROR', ex.args)
645
646
        if 'name' not in new_values['data'] or \
647
                not isinstance(new_values['data']['name'], str) or \
648
                len(str.strip(new_values['data']['name'])) == 0:
649
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
650
                                   description='API.INVALID_USER_NAME')
651
        user_name = str.strip(new_values['data']['name'])
652
653
        if 'password' not in new_values['data'] or \
654
                not isinstance(new_values['data']['password'], str) or \
655
                len(str.strip(new_values['data']['password'])) == 0:
656
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
657
                                   description='API.INVALID_PASSWORD')
658
        new_password = str.strip(new_values['data']['password'])
659
660
        # Verify Administrator
661
        cnx = mysql.connector.connect(**config.myems_user_db)
662
        cursor = cnx.cursor()
663
        query = (" SELECT utc_expires "
664
                 " FROM tbl_sessions "
665
                 " WHERE user_uuid = %s AND token = %s")
666
        cursor.execute(query, (admin_user_uuid, admin_token,))
667
        row = cursor.fetchone()
668
669 View Code Duplication
        if row is None:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
670
            cursor.close()
671
            cnx.disconnect()
672
            raise falcon.HTTPError(falcon.HTTP_404, title='API.NOT_FOUND',
673
                                   description='API.ADMINISTRATOR_SESSION_NOT_FOUND')
674
        else:
675
            utc_expires = row[0]
676
            if datetime.utcnow() > utc_expires:
677
                cursor.close()
678
                cnx.disconnect()
679
                raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
680
                                       description='API.ADMINISTRATOR_SESSION_TIMEOUT')
681
682
        query = (" SELECT name "
683
                 " FROM tbl_users "
684
                 " WHERE uuid = %s AND is_admin = true ")
685
        cursor.execute(query, (admin_user_uuid,))
686
        row = cursor.fetchone()
687
        if row is None:
688
            cursor.close()
689
            cnx.disconnect()
690
            raise falcon.HTTPError(falcon.HTTP_400, 'API.BAD_REQUEST', 'API.INVALID_PRIVILEGE')
691
692
        salt = uuid.uuid4().hex
693
        hashed_password = hashlib.sha512(salt.encode() + new_password.encode()).hexdigest()
694
695
        update_user = (" UPDATE tbl_users "
696
                       " SET salt = %s, password = %s "
697
                       " WHERE name = %s ")
698
        cursor.execute(update_user, (salt, hashed_password, user_name,))
699
        cnx.commit()
700
701
        # Refresh administrator session
702
        update_session = (" UPDATE tbl_sessions "
703
                          " SET utc_expires = %s "
704
                          " WHERE user_uuid = %s and token = %s ")
705
        utc_expires = datetime.utcnow() + timedelta(seconds=1000 * 60 * 60 * 8)
706
        cursor.execute(update_session, (utc_expires, admin_user_uuid, admin_token, ))
707
        cnx.commit()
708
709
        cursor.close()
710
        cnx.disconnect()
711
        resp.body = json.dumps("OK")
712
        resp.status = falcon.HTTP_200
713