Passed
Push — master ( c34674...9ec8a0 )
by Guangyu
06:29 queued 11s
created

core.user.UserItem.on_get()   B

Complexity

Conditions 6

Size

Total Lines 38
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Importance

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