square-authentication 1.0.0__py3-none-any.whl → 2.0.0__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.
@@ -6,11 +6,11 @@ from square_logger.main import SquareLogger
6
6
 
7
7
  try:
8
8
  config_file_path = (
9
- os.path.dirname(os.path.abspath(__file__))
10
- + os.sep
11
- + "data"
12
- + os.sep
13
- + "config.ini"
9
+ os.path.dirname(os.path.abspath(__file__))
10
+ + os.sep
11
+ + "data"
12
+ + os.sep
13
+ + "config.ini"
14
14
  )
15
15
  ldict_configuration = ConfigReader(config_file_path).read_configuration()
16
16
 
@@ -3,6 +3,7 @@ import os.path
3
3
  from fastapi import FastAPI, status
4
4
  from fastapi.middleware.cors import CORSMiddleware
5
5
  from fastapi.responses import JSONResponse
6
+ from square_commons import get_api_output_in_standard_format
6
7
  from uvicorn import run
7
8
 
8
9
  from square_authentication.configuration import (
@@ -31,15 +32,14 @@ app.include_router(utility.router)
31
32
  @app.get("/")
32
33
  @global_object_square_logger.async_auto_logger
33
34
  async def root():
34
- return JSONResponse(
35
- status_code=status.HTTP_200_OK, content={"text": config_str_module_name}
36
- )
35
+ output_content = get_api_output_in_standard_format(log=config_str_module_name)
36
+ return JSONResponse(status_code=status.HTTP_200_OK, content=output_content)
37
37
 
38
38
 
39
39
  if __name__ == "__main__":
40
40
  try:
41
41
  if os.path.exists(config_str_ssl_key_file_path) and os.path.exists(
42
- config_str_ssl_crt_file_path
42
+ config_str_ssl_crt_file_path
43
43
  ):
44
44
  run(
45
45
  app,
@@ -0,0 +1,16 @@
1
+ messages = {
2
+ "REGISTRATION_SUCCESSFUL": "registration was successful. welcome aboard!",
3
+ "LOGIN_SUCCESSFUL": "you have logged in successfully.",
4
+ "LOGOUT_SUCCESSFUL": "you have logged out successfully.",
5
+ "INCORRECT_USERNAME": "the username you entered does not exist.",
6
+ "INCORRECT_PASSWORD": "the password you entered is incorrect. please try again.",
7
+ "INCORRECT_USER_ID": "the user ID you provided does not exist or is invalid.",
8
+ "USERNAME_ALREADY_EXISTS": "the username you entered is already taken. please choose a different one.",
9
+ "INCORRECT_ACCESS_TOKEN": "the access token provided is invalid or expired.",
10
+ "INCORRECT_REFRESH_TOKEN": "the refresh token provided is invalid or expired.",
11
+ "GENERIC_READ_SUCCESSFUL": "data retrieved successfully.",
12
+ "GENERIC_CREATION_SUCCESSFUL": "records created successfully.",
13
+ "GENERIC_UPDATE_SUCCESSFUL": "your information has been updated successfully.",
14
+ "GENERIC_400": "the request is invalid or cannot be processed.",
15
+ "GENERIC_500": "an internal server error occurred. please try again later.",
16
+ }
@@ -1,22 +1,29 @@
1
1
  from datetime import datetime, timedelta, timezone
2
- from typing import Annotated, Union
2
+ from typing import Annotated, List
3
+ from uuid import UUID
3
4
 
4
5
  import bcrypt
5
6
  import jwt
6
- from fastapi import APIRouter, status, Header
7
+ from fastapi import APIRouter, status, Header, HTTPException
7
8
  from fastapi.responses import JSONResponse
8
- from requests.exceptions import HTTPError
9
+ from square_commons import get_api_output_in_standard_format
10
+ from square_database.pydantic_models.pydantic_models import (
11
+ FiltersV0,
12
+ FilterConditionsV0,
13
+ )
9
14
  from square_database_helper.main import SquareDatabaseHelper
10
- from square_database_structure.square.authentication.enums import UserLogEventEnum
15
+ from square_database_structure.square import global_string_database_name
16
+ from square_database_structure.square.authentication import global_string_schema_name
11
17
  from square_database_structure.square.authentication.tables import (
12
- local_string_database_name,
13
- local_string_schema_name,
14
18
  User,
15
- UserLog,
16
19
  UserCredential,
17
- UserProfile,
18
20
  UserSession,
21
+ UserApp,
22
+ )
23
+ from square_database_structure.square.public import (
24
+ global_string_schema_name as global_string_public_schema_name,
19
25
  )
26
+ from square_database_structure.square.public.tables import App
20
27
 
21
28
  from square_authentication.configuration import (
22
29
  global_object_square_logger,
@@ -28,6 +35,7 @@ from square_authentication.configuration import (
28
35
  config_int_square_database_port,
29
36
  config_str_square_database_protocol,
30
37
  )
38
+ from square_authentication.messages import messages
31
39
  from square_authentication.utils.token import get_jwt_payload
32
40
 
33
41
  router = APIRouter(
@@ -41,66 +49,441 @@ global_object_square_database_helper = SquareDatabaseHelper(
41
49
  )
42
50
 
43
51
 
44
- @router.get("/register_username/")
52
+ @router.post("/register_username/v0")
45
53
  @global_object_square_logger.async_auto_logger
46
- async def register_username(username: str, password: str):
54
+ async def register_username_v0(username: str, password: str):
47
55
  local_str_user_id = None
56
+ username = username.lower()
48
57
  try:
49
- # ======================================================================================
58
+ """
59
+ validation
60
+ """
61
+
62
+ # validation for username
63
+ local_list_response_user_creds = global_object_square_database_helper.get_rows_v0(
64
+ database_name=global_string_database_name,
65
+ schema_name=global_string_schema_name,
66
+ table_name=UserCredential.__tablename__,
67
+ filters=FiltersV0(
68
+ {
69
+ UserCredential.user_credential_username.name: FilterConditionsV0(
70
+ eq=username
71
+ )
72
+ }
73
+ ),
74
+ )[
75
+ "data"
76
+ ][
77
+ "main"
78
+ ]
79
+ if len(local_list_response_user_creds) > 0:
80
+ output_content = get_api_output_in_standard_format(
81
+ message=messages["USERNAME_ALREADY_EXISTS"],
82
+ log=f"an account with the username {username} already exists.",
83
+ )
84
+ raise HTTPException(
85
+ status_code=status.HTTP_409_CONFLICT,
86
+ detail=output_content,
87
+ )
88
+
89
+ """
90
+ main process
91
+ """
50
92
  # entry in user table
51
- local_list_response_user = global_object_square_database_helper.insert_rows(
93
+ local_list_response_user = global_object_square_database_helper.insert_rows_v0(
52
94
  data=[{}],
53
- database_name=local_string_database_name,
54
- schema_name=local_string_schema_name,
95
+ database_name=global_string_database_name,
96
+ schema_name=global_string_schema_name,
55
97
  table_name=User.__tablename__,
56
- )
98
+ )["data"]["main"]
57
99
  local_str_user_id = local_list_response_user[0][User.user_id.name]
58
- # ======================================================================================
59
100
 
60
- # ======================================================================================
61
- # entry in user log
62
- local_list_response_user_log = global_object_square_database_helper.insert_rows(
101
+ # entry in credential table
102
+
103
+ # hash password
104
+ local_str_hashed_password = bcrypt.hashpw(
105
+ password.encode("utf-8"), bcrypt.gensalt()
106
+ ).decode("utf-8")
107
+
108
+ global_object_square_database_helper.insert_rows_v0(
63
109
  data=[
64
110
  {
65
- UserLog.user_id.name: local_str_user_id,
66
- UserLog.user_log_event.name: UserLogEventEnum.CREATED.value,
111
+ UserCredential.user_id.name: local_str_user_id,
112
+ UserCredential.user_credential_username.name: username,
113
+ UserCredential.user_credential_hashed_password.name: local_str_hashed_password,
67
114
  }
68
115
  ],
69
- database_name=local_string_database_name,
70
- schema_name=local_string_schema_name,
71
- table_name=UserLog.__tablename__,
116
+ database_name=global_string_database_name,
117
+ schema_name=global_string_schema_name,
118
+ table_name=UserCredential.__tablename__,
72
119
  )
73
- # ======================================================================================
74
120
 
75
- # ======================================================================================
76
- # entry in user profile
77
- local_list_response_user_profile = (
78
- global_object_square_database_helper.insert_rows(
79
- data=[{UserProfile.user_id.name: local_str_user_id}],
80
- database_name=local_string_database_name,
81
- schema_name=local_string_schema_name,
82
- table_name=UserProfile.__tablename__,
121
+ """
122
+ return value
123
+ """
124
+ output_content = get_api_output_in_standard_format(
125
+ message=messages["REGISTRATION_SUCCESSFUL"],
126
+ data={"main": {"user_id": local_str_user_id, "username": username}},
127
+ )
128
+ return JSONResponse(
129
+ status_code=status.HTTP_201_CREATED,
130
+ content=output_content,
131
+ )
132
+ except HTTPException as http_exception:
133
+ return JSONResponse(
134
+ status_code=http_exception.status_code, content=http_exception.detail
135
+ )
136
+ except Exception as e:
137
+ global_object_square_logger.logger.error(e, exc_info=True)
138
+ """
139
+ rollback logic
140
+ """
141
+ if local_str_user_id:
142
+ global_object_square_database_helper.delete_rows_v0(
143
+ database_name=global_string_database_name,
144
+ schema_name=global_string_schema_name,
145
+ table_name=User.__tablename__,
146
+ filters=FiltersV0(
147
+ {User.user_id.name: FilterConditionsV0(eq=local_str_user_id)}
148
+ ),
83
149
  )
150
+ output_content = get_api_output_in_standard_format(
151
+ message=messages["GENERIC_500"],
152
+ log=str(e),
153
+ )
154
+ return JSONResponse(
155
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=output_content
84
156
  )
85
157
 
86
- # ======================================================================================
87
158
 
88
- # ======================================================================================
89
- # entry in credential table
159
+ @router.get("/get_user_app_ids/v0")
160
+ @global_object_square_logger.async_auto_logger
161
+ async def get_user_app_ids_v0(user_id: UUID):
162
+ try:
163
+ local_string_user_id = str(user_id)
164
+ """
165
+ validation
166
+ """
167
+
168
+ local_list_response_user = global_object_square_database_helper.get_rows_v0(
169
+ database_name=global_string_database_name,
170
+ schema_name=global_string_schema_name,
171
+ table_name=User.__tablename__,
172
+ filters=FiltersV0(
173
+ {User.user_id.name: FilterConditionsV0(eq=local_string_user_id)}
174
+ ),
175
+ )["data"]["main"]
176
+ if len(local_list_response_user) != 1:
177
+ output_content = get_api_output_in_standard_format(
178
+ message=messages["INCORRECT_USER_ID"],
179
+ log=f"invalid user_id: {local_string_user_id}",
180
+ )
181
+ raise HTTPException(
182
+ status_code=status.HTTP_404_NOT_FOUND,
183
+ detail=output_content,
184
+ )
185
+ """
186
+ main process
187
+ """
188
+ local_list_response_user_app = global_object_square_database_helper.get_rows_v0(
189
+ database_name=global_string_database_name,
190
+ schema_name=global_string_schema_name,
191
+ table_name=UserApp.__tablename__,
192
+ filters=FiltersV0(
193
+ {UserApp.user_id.name: FilterConditionsV0(eq=local_string_user_id)}
194
+ ),
195
+ )["data"]["main"]
196
+ """
197
+ return value
198
+ """
199
+ output_content = get_api_output_in_standard_format(
200
+ message=messages["GENERIC_READ_SUCCESSFUL"],
201
+ data={
202
+ "main": [x[UserApp.app_id.name] for x in local_list_response_user_app]
203
+ },
204
+ )
205
+ return JSONResponse(
206
+ status_code=status.HTTP_200_OK,
207
+ content=output_content,
208
+ )
209
+ except HTTPException as http_exception:
210
+ return JSONResponse(
211
+ status_code=http_exception.status_code, content=http_exception.detail
212
+ )
213
+ except Exception as e:
214
+ """
215
+ rollback logic
216
+ """
217
+ global_object_square_logger.logger.error(e, exc_info=True)
218
+ output_content = get_api_output_in_standard_format(
219
+ message=messages["GENERIC_500"],
220
+ log=str(e),
221
+ )
222
+ return JSONResponse(
223
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
224
+ content=output_content,
225
+ )
226
+
227
+
228
+ @router.patch("/update_user_app_ids/v0")
229
+ @global_object_square_logger.async_auto_logger
230
+ async def update_user_app_ids_v0(
231
+ user_id: UUID,
232
+ app_ids_to_add: List[int],
233
+ app_ids_to_remove: List[int],
234
+ ):
235
+ try:
236
+ local_string_user_id = str(user_id)
237
+ """
238
+ validation
239
+ """
240
+
241
+ app_ids_to_add = list(set(app_ids_to_add))
242
+ app_ids_to_remove = list(set(app_ids_to_remove))
243
+
244
+ # check if app_ids_to_add and app_ids_to_remove don't have common ids.
245
+ local_list_common_app_ids = set(app_ids_to_add) & set(app_ids_to_remove)
246
+ if len(local_list_common_app_ids) > 0:
247
+ output_content = get_api_output_in_standard_format(
248
+ message=messages["GENERIC_400"],
249
+ log=f"invalid app_ids: {list(local_list_common_app_ids)}, present in both add list and remove list.",
250
+ )
251
+ raise HTTPException(
252
+ status_code=status.HTTP_400_BAD_REQUEST,
253
+ detail=output_content,
254
+ )
255
+ # validate access token
256
+ # TBD
257
+
258
+ # check if user id is in user table
259
+ local_list_response_user = global_object_square_database_helper.get_rows_v0(
260
+ database_name=global_string_database_name,
261
+ schema_name=global_string_schema_name,
262
+ table_name=User.__tablename__,
263
+ filters=FiltersV0(
264
+ {User.user_id.name: FilterConditionsV0(eq=local_string_user_id)}
265
+ ),
266
+ )["data"]["main"]
267
+ if len(local_list_response_user) != 1:
268
+ output_content = get_api_output_in_standard_format(
269
+ message=messages["INCORRECT_USER_ID"],
270
+ log=f"invalid user_id: {local_string_user_id}",
271
+ )
272
+ raise HTTPException(
273
+ status_code=status.HTTP_404_NOT_FOUND,
274
+ detail=output_content,
275
+ )
276
+
277
+ # check if all app_ids are valid
278
+ local_list_all_app_ids = [*app_ids_to_add, *app_ids_to_remove]
279
+ local_list_response_app = global_object_square_database_helper.get_rows_v0(
280
+ database_name=global_string_database_name,
281
+ schema_name=global_string_public_schema_name,
282
+ table_name=App.__tablename__,
283
+ apply_filters=False,
284
+ filters=FiltersV0({}),
285
+ )["data"]["main"]
286
+ local_list_invalid_ids = [
287
+ x
288
+ for x in local_list_all_app_ids
289
+ if x not in [y[App.app_id.name] for y in local_list_response_app]
290
+ ]
291
+ if len(local_list_invalid_ids) > 0:
292
+ output_content = get_api_output_in_standard_format(
293
+ message=messages["GENERIC_400"],
294
+ log=f"invalid app_ids: {local_list_invalid_ids}.",
295
+ )
296
+ raise HTTPException(
297
+ status_code=status.HTTP_400_BAD_REQUEST,
298
+ detail=output_content,
299
+ )
300
+ """
301
+ main process
302
+ """
303
+ # logic for adding new app_ids
304
+ local_list_response_user_app = global_object_square_database_helper.get_rows_v0(
305
+ database_name=global_string_database_name,
306
+ schema_name=global_string_schema_name,
307
+ table_name=UserApp.__tablename__,
308
+ filters=FiltersV0(
309
+ {UserApp.user_id.name: FilterConditionsV0(eq=local_string_user_id)}
310
+ ),
311
+ )["data"]["main"]
312
+ local_list_new_app_ids = [
313
+ {
314
+ UserApp.user_id.name: local_string_user_id,
315
+ UserApp.app_id.name: x,
316
+ }
317
+ for x in app_ids_to_add
318
+ if x not in [y[UserApp.app_id.name] for y in local_list_response_user_app]
319
+ ]
320
+ if len(local_list_new_app_ids) > 0:
321
+ global_object_square_database_helper.insert_rows_v0(
322
+ database_name=global_string_database_name,
323
+ schema_name=global_string_schema_name,
324
+ table_name=UserApp.__tablename__,
325
+ data=local_list_new_app_ids,
326
+ )
327
+
328
+ # logic for removing app_ids
329
+ for app_id in app_ids_to_remove:
330
+ global_object_square_database_helper.delete_rows_v0(
331
+ database_name=global_string_database_name,
332
+ schema_name=global_string_schema_name,
333
+ table_name=UserApp.__tablename__,
334
+ filters=FiltersV0(
335
+ {
336
+ UserApp.user_id.name: FilterConditionsV0(
337
+ eq=local_string_user_id
338
+ ),
339
+ UserApp.app_id.name: FilterConditionsV0(eq=app_id),
340
+ }
341
+ ),
342
+ )
343
+ global_object_square_database_helper.delete_rows_v0(
344
+ database_name=global_string_database_name,
345
+ schema_name=global_string_schema_name,
346
+ table_name=UserSession.__tablename__,
347
+ filters=FiltersV0(
348
+ {
349
+ UserSession.user_id.name: FilterConditionsV0(
350
+ eq=local_string_user_id
351
+ ),
352
+ UserSession.app_id.name: FilterConditionsV0(eq=app_id),
353
+ }
354
+ ),
355
+ )
356
+
357
+ """
358
+ return value
359
+ """
360
+ # get latest app ids
361
+ local_list_response_user_app = global_object_square_database_helper.get_rows_v0(
362
+ database_name=global_string_database_name,
363
+ schema_name=global_string_schema_name,
364
+ table_name=UserApp.__tablename__,
365
+ filters=FiltersV0(
366
+ {UserApp.user_id.name: FilterConditionsV0(eq=local_string_user_id)}
367
+ ),
368
+ )["data"]["main"]
369
+ output_content = get_api_output_in_standard_format(
370
+ message=messages["GENERIC_UPDATE_SUCCESSFUL"],
371
+ data={
372
+ "main": [x[UserApp.app_id.name] for x in local_list_response_user_app]
373
+ },
374
+ )
375
+ return JSONResponse(
376
+ status_code=status.HTTP_200_OK,
377
+ content=output_content,
378
+ )
379
+ except HTTPException as http_exception:
380
+ return JSONResponse(
381
+ status_code=http_exception.status_code, content=http_exception.detail
382
+ )
383
+ except Exception as e:
384
+ """
385
+ rollback logic
386
+ """
387
+ global_object_square_logger.logger.error(e, exc_info=True)
388
+ output_content = get_api_output_in_standard_format(
389
+ message=messages["GENERIC_500"],
390
+ log=str(e),
391
+ )
392
+ return JSONResponse(
393
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
394
+ content=output_content,
395
+ )
90
396
 
91
- # hash password
92
- local_str_hashed_password = bcrypt.hashpw(
93
- password.encode("utf-8"), bcrypt.gensalt()
94
- ).decode("utf-8")
397
+
398
+ @router.get("/login_username/v0")
399
+ @global_object_square_logger.async_auto_logger
400
+ async def login_username_v0(username: str, password: str, app_id: int):
401
+ username = username.lower()
402
+ try:
403
+ """
404
+ validation
405
+ """
406
+ # validation for username
407
+ local_list_authentication_user_response = global_object_square_database_helper.get_rows_v0(
408
+ database_name=global_string_database_name,
409
+ schema_name=global_string_schema_name,
410
+ table_name=UserCredential.__tablename__,
411
+ filters=FiltersV0(
412
+ {
413
+ UserCredential.user_credential_username.name: FilterConditionsV0(
414
+ eq=username
415
+ )
416
+ }
417
+ ),
418
+ )[
419
+ "data"
420
+ ][
421
+ "main"
422
+ ]
423
+ if len(local_list_authentication_user_response) != 1:
424
+ output_content = get_api_output_in_standard_format(
425
+ message=messages["INCORRECT_USERNAME"],
426
+ log=f"incorrect username {username}",
427
+ )
428
+ return JSONResponse(
429
+ status_code=status.HTTP_400_BAD_REQUEST, content=output_content
430
+ )
431
+ # validate if app_id is assigned to user
432
+ # this will also validate if app_id is valid
433
+ local_dict_user = local_list_authentication_user_response[0]
434
+ local_str_user_id = local_dict_user[UserCredential.user_id.name]
435
+ local_list_user_app_response = global_object_square_database_helper.get_rows_v0(
436
+ database_name=global_string_database_name,
437
+ schema_name=global_string_schema_name,
438
+ table_name=UserApp.__tablename__,
439
+ filters=FiltersV0(
440
+ {
441
+ UserApp.user_id.name: FilterConditionsV0(eq=local_str_user_id),
442
+ UserApp.app_id.name: FilterConditionsV0(eq=app_id),
443
+ }
444
+ ),
445
+ )["data"]["main"]
446
+ if len(local_list_user_app_response) != 1:
447
+ output_content = get_api_output_in_standard_format(
448
+ message=messages["GENERIC_400"],
449
+ log=f"user_id {local_str_user_id}({username}) not assigned to app {app_id}.",
450
+ )
451
+ return JSONResponse(
452
+ status_code=status.HTTP_400_BAD_REQUEST, content=output_content
453
+ )
454
+
455
+ # validate password
456
+ if not (
457
+ bcrypt.checkpw(
458
+ password.encode("utf-8"),
459
+ local_dict_user[
460
+ UserCredential.user_credential_hashed_password.name
461
+ ].encode("utf-8"),
462
+ )
463
+ ):
464
+ output_content = get_api_output_in_standard_format(
465
+ message=messages["INCORRECT_PASSWORD"],
466
+ log=f"incorrect password for user_id {local_str_user_id}({username}).",
467
+ )
468
+ return JSONResponse(
469
+ status_code=status.HTTP_400_BAD_REQUEST,
470
+ content=output_content,
471
+ )
472
+ """
473
+ main process
474
+ """
475
+ # return new access token and refresh token
95
476
 
96
477
  # create access token
97
478
  local_dict_access_token_payload = {
479
+ "app_id": app_id,
98
480
  "user_id": local_str_user_id,
99
481
  "exp": datetime.now(timezone.utc)
100
- + timedelta(minutes=config_int_access_token_valid_minutes),
482
+ + timedelta(minutes=config_int_access_token_valid_minutes),
101
483
  }
102
484
  local_str_access_token = jwt.encode(
103
- local_dict_access_token_payload, config_str_secret_key_for_access_token
485
+ local_dict_access_token_payload,
486
+ config_str_secret_key_for_access_token,
104
487
  )
105
488
 
106
489
  # create refresh token
@@ -109,222 +492,141 @@ async def register_username(username: str, password: str):
109
492
  )
110
493
 
111
494
  local_dict_refresh_token_payload = {
495
+ "app_id": app_id,
112
496
  "user_id": local_str_user_id,
113
497
  "exp": local_object_refresh_token_expiry_time,
114
498
  }
115
499
  local_str_refresh_token = jwt.encode(
116
- local_dict_refresh_token_payload, config_str_secret_key_for_refresh_token
500
+ local_dict_refresh_token_payload,
501
+ config_str_secret_key_for_refresh_token,
117
502
  )
118
- try:
119
- local_list_response_authentication_username = global_object_square_database_helper.insert_rows(
120
- data=[
121
- {
122
- UserCredential.user_id.name: local_str_user_id,
123
- UserCredential.user_credential_username.name: username,
124
- UserCredential.user_credential_hashed_password.name: local_str_hashed_password,
125
- }
126
- ],
127
- database_name=local_string_database_name,
128
- schema_name=local_string_schema_name,
129
- table_name=UserCredential.__tablename__,
130
- )
131
- except HTTPError as http_error:
132
- if http_error.response.status_code == 400:
133
- return JSONResponse(
134
- status_code=status.HTTP_409_CONFLICT,
135
- content=f"an account with the username {username} already exists.",
136
- )
137
- else:
138
- raise http_error
139
- # ======================================================================================
140
-
141
- # ======================================================================================
142
503
  # entry in user session table
143
- local_list_response_user_session = global_object_square_database_helper.insert_rows(
504
+ global_object_square_database_helper.insert_rows_v0(
144
505
  data=[
145
506
  {
146
507
  UserSession.user_id.name: local_str_user_id,
508
+ UserSession.app_id.name: app_id,
147
509
  UserSession.user_session_refresh_token.name: local_str_refresh_token,
148
510
  UserSession.user_session_expiry_time.name: local_object_refresh_token_expiry_time.strftime(
149
511
  "%Y-%m-%d %H:%M:%S.%f+00"
150
512
  ),
151
513
  }
152
514
  ],
153
- database_name=local_string_database_name,
154
- schema_name=local_string_schema_name,
515
+ database_name=global_string_database_name,
516
+ schema_name=global_string_schema_name,
155
517
  table_name=UserSession.__tablename__,
156
518
  )
157
- # ======================================================================================
158
- return JSONResponse(
159
- status_code=status.HTTP_200_OK,
160
- content={
161
- "user_id": local_str_user_id,
162
- "access_token": local_str_access_token,
163
- "refresh_token": local_str_refresh_token,
519
+ """
520
+ return value
521
+ """
522
+ output_content = get_api_output_in_standard_format(
523
+ data={
524
+ "main": {
525
+ "user_id": local_str_user_id,
526
+ "access_token": local_str_access_token,
527
+ "refresh_token": local_str_refresh_token,
528
+ }
164
529
  },
530
+ message=messages["LOGIN_SUCCESSFUL"],
165
531
  )
166
- except Exception as e:
167
- global_object_square_logger.logger.error(e, exc_info=True)
168
- if local_str_user_id:
169
- global_object_square_database_helper.delete_rows(
170
- database_name=local_string_database_name,
171
- schema_name=local_string_schema_name,
172
- table_name=User.__tablename__,
173
- filters={User.user_id.name: local_str_user_id},
174
- )
175
532
  return JSONResponse(
176
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=str(e)
533
+ status_code=status.HTTP_200_OK,
534
+ content=output_content,
177
535
  )
178
-
179
-
180
- @router.get("/login_username/")
181
- @global_object_square_logger.async_auto_logger
182
- async def login_username(username: str, password: str):
183
- try:
184
- # ======================================================================================
185
- # get entry from authentication_username table
186
- local_list_authentication_user_response = (
187
- global_object_square_database_helper.get_rows(
188
- database_name=local_string_database_name,
189
- schema_name=local_string_schema_name,
190
- table_name=UserCredential.__tablename__,
191
- filters={UserCredential.user_credential_username.name: username},
192
- )
536
+ except HTTPException as http_exception:
537
+ return JSONResponse(
538
+ status_code=http_exception.status_code, content=http_exception.detail
193
539
  )
194
- # ======================================================================================
195
-
196
- # ======================================================================================
197
- # validate username
198
- # ======================================================================================
199
- if len(local_list_authentication_user_response) != 1:
200
- return JSONResponse(
201
- status_code=status.HTTP_400_BAD_REQUEST, content="incorrect username."
202
- )
203
- # ======================================================================================
204
- # validate password
205
- # ======================================================================================
206
- else:
207
- if not (
208
- bcrypt.checkpw(
209
- password.encode("utf-8"),
210
- local_list_authentication_user_response[0][
211
- UserCredential.user_credential_hashed_password.name
212
- ].encode("utf-8"),
213
- )
214
- ):
215
- return JSONResponse(
216
- status_code=status.HTTP_400_BAD_REQUEST,
217
- content="incorrect password.",
218
- )
219
-
220
- # ======================================================================================
221
- # return new access token and refresh token
222
- # ======================================================================================
223
- else:
224
- local_str_user_id = local_list_authentication_user_response[0][
225
- UserCredential.user_id.name
226
- ]
227
- # create access token
228
- local_dict_access_token_payload = {
229
- "user_id": local_str_user_id,
230
- "exp": datetime.now(timezone.utc)
231
- + timedelta(minutes=config_int_access_token_valid_minutes),
232
- }
233
- local_str_access_token = jwt.encode(
234
- local_dict_access_token_payload,
235
- config_str_secret_key_for_access_token,
236
- )
237
-
238
- # create refresh token
239
- local_object_refresh_token_expiry_time = datetime.now(
240
- timezone.utc
241
- ) + timedelta(minutes=config_int_refresh_token_valid_minutes)
242
-
243
- local_dict_refresh_token_payload = {
244
- "user_id": local_str_user_id,
245
- "exp": local_object_refresh_token_expiry_time,
246
- }
247
- local_str_refresh_token = jwt.encode(
248
- local_dict_refresh_token_payload,
249
- config_str_secret_key_for_refresh_token,
250
- )
251
- # ======================================================================================
252
- # entry in user session table
253
- local_list_response_user_session = global_object_square_database_helper.insert_rows(
254
- data=[
255
- {
256
- UserSession.user_id.name: local_str_user_id,
257
- UserSession.user_session_refresh_token.name: local_str_refresh_token,
258
- UserSession.user_session_expiry_time.name: local_object_refresh_token_expiry_time.strftime(
259
- "%Y-%m-%d %H:%M:%S.%f+00"
260
- ),
261
- }
262
- ],
263
- database_name=local_string_database_name,
264
- schema_name=local_string_schema_name,
265
- table_name=UserSession.__tablename__,
266
- )
267
- # ======================================================================================
268
- return JSONResponse(
269
- status_code=status.HTTP_200_OK,
270
- content={
271
- "user_id": local_str_user_id,
272
- "access_token": local_str_access_token,
273
- "refresh_token": local_str_refresh_token,
274
- },
275
- )
276
- # ======================================================================================
277
-
278
540
  except Exception as e:
541
+ """
542
+ rollback logic
543
+ """
279
544
  global_object_square_logger.logger.error(e, exc_info=True)
545
+ output_content = get_api_output_in_standard_format(
546
+ message=messages["GENERIC_500"],
547
+ log=str(e),
548
+ )
280
549
  return JSONResponse(
281
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=str(e)
550
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=output_content
282
551
  )
283
552
 
284
553
 
285
- @router.get("/generate_access_token/")
554
+ @router.get("/generate_access_token/v0")
286
555
  @global_object_square_logger.async_auto_logger
287
- async def generate_access_token(
288
- user_id: str, refresh_token: Annotated[Union[str, None], Header()]
556
+ async def generate_access_token_v0(
557
+ user_id: str, app_id: int, refresh_token: Annotated[str, Header()]
289
558
  ):
290
559
  try:
291
- # ======================================================================================
560
+ """
561
+ validation
562
+ """
292
563
  # validate user_id
293
- local_list_user_response = global_object_square_database_helper.get_rows(
294
- database_name=local_string_database_name,
295
- schema_name=local_string_schema_name,
564
+ local_list_user_response = global_object_square_database_helper.get_rows_v0(
565
+ database_name=global_string_database_name,
566
+ schema_name=global_string_schema_name,
296
567
  table_name=User.__tablename__,
297
- filters={User.user_id.name: user_id},
298
- )
568
+ filters=FiltersV0({User.user_id.name: FilterConditionsV0(eq=user_id)}),
569
+ )["data"]["main"]
299
570
 
300
571
  if len(local_list_user_response) != 1:
572
+ output_content = get_api_output_in_standard_format(
573
+ message=messages["INCORRECT_USER_ID"],
574
+ log=f"incorrect user_id: {user_id}.",
575
+ )
301
576
  return JSONResponse(
302
577
  status_code=status.HTTP_400_BAD_REQUEST,
303
- content=f"incorrect user_id: {user_id}.",
578
+ content=output_content,
579
+ )
580
+ # validate if app_id is assigned to user
581
+ # this will also validate if app_id is valid
582
+ local_dict_user = local_list_user_response[0]
583
+ local_str_user_id = local_dict_user[User.user_id.name]
584
+ local_list_user_app_response = global_object_square_database_helper.get_rows_v0(
585
+ database_name=global_string_database_name,
586
+ schema_name=global_string_schema_name,
587
+ table_name=UserApp.__tablename__,
588
+ filters=FiltersV0(
589
+ {
590
+ UserApp.user_id.name: FilterConditionsV0(eq=local_str_user_id),
591
+ UserApp.app_id.name: FilterConditionsV0(eq=app_id),
592
+ }
593
+ ),
594
+ )["data"]["main"]
595
+ if len(local_list_user_app_response) != 1:
596
+ output_content = get_api_output_in_standard_format(
597
+ message=messages["GENERIC_400"],
598
+ log=f"user_id {local_str_user_id} not assigned to app {app_id}.",
599
+ )
600
+ return JSONResponse(
601
+ status_code=status.HTTP_400_BAD_REQUEST, content=output_content
304
602
  )
305
- # ======================================================================================
306
-
307
- # ======================================================================================
308
603
  # validate refresh token
309
-
310
- # validating if a session refresh token exists in the database.
604
+ # validating if a session refresh token exists in the database for provided app id.
311
605
  local_list_user_session_response = (
312
- global_object_square_database_helper.get_rows(
313
- database_name=local_string_database_name,
314
- schema_name=local_string_schema_name,
606
+ global_object_square_database_helper.get_rows_v0(
607
+ database_name=global_string_database_name,
608
+ schema_name=global_string_schema_name,
315
609
  table_name=UserSession.__tablename__,
316
- filters={
317
- UserSession.user_id.name: user_id,
318
- UserSession.user_session_refresh_token.name: refresh_token,
319
- },
320
- )
610
+ filters=FiltersV0(
611
+ {
612
+ UserSession.user_id.name: FilterConditionsV0(eq=user_id),
613
+ UserSession.user_session_refresh_token.name: FilterConditionsV0(
614
+ eq=refresh_token
615
+ ),
616
+ UserSession.app_id.name: FilterConditionsV0(eq=app_id),
617
+ }
618
+ ),
619
+ )["data"]["main"]
321
620
  )
322
621
 
323
622
  if len(local_list_user_session_response) != 1:
623
+ output_content = get_api_output_in_standard_format(
624
+ message=messages["INCORRECT_REFRESH_TOKEN"],
625
+ log=f"incorrect refresh token: {refresh_token} for user_id: {user_id} for app_id: {app_id}.",
626
+ )
324
627
  return JSONResponse(
325
628
  status_code=status.HTTP_400_BAD_REQUEST,
326
- content=f"incorrect refresh token: {refresh_token} for user_id: {user_id}."
327
- f"for user_id: {user_id}.",
629
+ content=output_content,
328
630
  )
329
631
  # validating if the refresh token is valid, active and of the same user.
330
632
  try:
@@ -332,133 +634,238 @@ async def generate_access_token(
332
634
  refresh_token, config_str_secret_key_for_refresh_token
333
635
  )
334
636
  except Exception as error:
637
+ output_content = get_api_output_in_standard_format(
638
+ message=messages["INCORRECT_REFRESH_TOKEN"], log=str(error)
639
+ )
335
640
  return JSONResponse(
336
641
  status_code=status.HTTP_400_BAD_REQUEST,
337
- content=str(error),
642
+ content=output_content,
338
643
  )
339
644
 
340
645
  if local_dict_refresh_token_payload["user_id"] != user_id:
646
+ output_content = get_api_output_in_standard_format(
647
+ message=messages["INCORRECT_REFRESH_TOKEN"],
648
+ log=f"refresh token and user_id mismatch.",
649
+ )
341
650
  return JSONResponse(
342
651
  status_code=status.HTTP_400_BAD_REQUEST,
343
- content=f"refresh token and user_id mismatch.",
652
+ content=output_content,
344
653
  )
345
-
346
- # ======================================================================================
347
- # ======================================================================================
654
+ if local_dict_refresh_token_payload["app_id"] != app_id:
655
+ output_content = get_api_output_in_standard_format(
656
+ message=messages["INCORRECT_REFRESH_TOKEN"],
657
+ log=f"refresh token and app_id mismatch.",
658
+ )
659
+ return JSONResponse(
660
+ status_code=status.HTTP_400_BAD_REQUEST,
661
+ content=output_content,
662
+ )
663
+ """
664
+ main process
665
+ """
348
666
  # create and send access token
349
667
  local_dict_access_token_payload = {
668
+ "app_id": app_id,
350
669
  "user_id": user_id,
351
670
  "exp": datetime.now(timezone.utc)
352
- + timedelta(minutes=config_int_access_token_valid_minutes),
671
+ + timedelta(minutes=config_int_access_token_valid_minutes),
353
672
  }
354
673
  local_str_access_token = jwt.encode(
355
674
  local_dict_access_token_payload, config_str_secret_key_for_access_token
356
675
  )
357
-
676
+ """
677
+ return value
678
+ """
679
+ output_content = get_api_output_in_standard_format(
680
+ data={"main": {"access_token": local_str_access_token}},
681
+ message=messages["GENERIC_CREATION_SUCCESSFUL"],
682
+ )
358
683
  return JSONResponse(
359
684
  status_code=status.HTTP_200_OK,
360
- content={"access_token": local_str_access_token},
685
+ content=output_content,
686
+ )
687
+ except HTTPException as http_exception:
688
+ return JSONResponse(
689
+ status_code=http_exception.status_code, content=http_exception.detail
361
690
  )
362
- # ======================================================================================
363
-
364
691
  except Exception as e:
692
+ """
693
+ rollback logic
694
+ """
365
695
  global_object_square_logger.logger.error(e, exc_info=True)
696
+ output_content = get_api_output_in_standard_format(
697
+ message=messages["GENERIC_500"],
698
+ log=str(e),
699
+ )
366
700
  return JSONResponse(
367
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=str(e)
701
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=output_content
368
702
  )
369
703
 
370
704
 
371
- @router.delete("/logout/")
705
+ @router.delete("/logout/v0")
372
706
  @global_object_square_logger.async_auto_logger
373
- async def logout(
374
- user_id: str,
375
- access_token: Annotated[Union[str, None], Header()],
376
- refresh_token: Annotated[Union[str, None], Header()],
707
+ async def logout_v0(
708
+ user_id: str,
709
+ app_id: int,
710
+ access_token: Annotated[str, Header()],
711
+ refresh_token: Annotated[str, Header()],
377
712
  ):
378
713
  try:
379
- # ======================================================================================
714
+ """
715
+ validation
716
+ """
380
717
  # validate user_id
381
- local_list_user_response = global_object_square_database_helper.get_rows(
382
- database_name=local_string_database_name,
383
- schema_name=local_string_schema_name,
718
+ local_list_user_response = global_object_square_database_helper.get_rows_v0(
719
+ database_name=global_string_database_name,
720
+ schema_name=global_string_schema_name,
384
721
  table_name=User.__tablename__,
385
- filters={User.user_id.name: user_id},
386
- )
722
+ filters=FiltersV0(
723
+ {
724
+ User.user_id.name: FilterConditionsV0(eq=user_id),
725
+ }
726
+ ),
727
+ )["data"]["main"]
387
728
 
388
729
  if len(local_list_user_response) != 1:
730
+ output_content = get_api_output_in_standard_format(
731
+ message=messages["INCORRECT_USER_ID"],
732
+ log=f"incorrect user_id: {user_id}.",
733
+ )
389
734
  return JSONResponse(
390
735
  status_code=status.HTTP_400_BAD_REQUEST,
391
- content=f"incorrect user_id: {user_id}.",
736
+ content=output_content,
392
737
  )
393
- # ======================================================================================
394
738
 
395
- # ======================================================================================
396
- # validate refresh token
739
+ # validate if app_id is assigned to user
740
+ # this will also validate if app_id is valid
741
+ local_dict_user = local_list_user_response[0]
742
+ local_str_user_id = local_dict_user[User.user_id.name]
743
+ local_list_user_app_response = global_object_square_database_helper.get_rows_v0(
744
+ database_name=global_string_database_name,
745
+ schema_name=global_string_schema_name,
746
+ table_name=UserApp.__tablename__,
747
+ filters=FiltersV0(
748
+ {
749
+ UserApp.user_id.name: FilterConditionsV0(eq=local_str_user_id),
750
+ UserApp.app_id.name: FilterConditionsV0(eq=app_id),
751
+ }
752
+ ),
753
+ )["data"]["main"]
754
+ if len(local_list_user_app_response) != 1:
755
+ output_content = get_api_output_in_standard_format(
756
+ message=messages["GENERIC_400"],
757
+ log=f"user_id {local_str_user_id} not assigned to app {app_id}.",
758
+ )
759
+ return JSONResponse(
760
+ status_code=status.HTTP_400_BAD_REQUEST, content=output_content
761
+ )
397
762
 
763
+ # validate refresh token
398
764
  # validating if a session refresh token exists in the database.
399
765
  local_list_user_session_response = (
400
- global_object_square_database_helper.get_rows(
401
- database_name=local_string_database_name,
402
- schema_name=local_string_schema_name,
766
+ global_object_square_database_helper.get_rows_v0(
767
+ database_name=global_string_database_name,
768
+ schema_name=global_string_schema_name,
403
769
  table_name=UserSession.__tablename__,
404
- filters={
405
- UserSession.user_id.name: user_id,
406
- UserSession.user_session_refresh_token.name: refresh_token,
407
- },
408
- )
770
+ filters=FiltersV0(
771
+ {
772
+ UserSession.user_id.name: FilterConditionsV0(eq=user_id),
773
+ UserSession.user_session_refresh_token.name: FilterConditionsV0(
774
+ eq=refresh_token
775
+ ),
776
+ UserSession.app_id.name: FilterConditionsV0(eq=app_id),
777
+ }
778
+ ),
779
+ )["data"]["main"]
409
780
  )
410
781
 
411
782
  if len(local_list_user_session_response) != 1:
783
+ output_content = get_api_output_in_standard_format(
784
+ message=messages["INCORRECT_REFRESH_TOKEN"],
785
+ log=f"incorrect refresh token: {refresh_token} for user_id: {user_id} for app_id: {app_id}.",
786
+ )
412
787
  return JSONResponse(
413
788
  status_code=status.HTTP_400_BAD_REQUEST,
414
- content=f"incorrect refresh token: {refresh_token} for user_id: {user_id}."
415
- f"for user_id: {user_id}.",
789
+ content=output_content,
416
790
  )
417
- # not validating if the refresh token is valid, active and of the same user.
418
- # ======================================================================================
791
+ # **not validating if the refresh token is valid, active, of the same user and of the provided app id.**
419
792
 
420
- # ======================================================================================
421
793
  # validate access token
422
- # validating if the access token is valid, active and of the same user.
794
+ # validating if the access token is valid, active, of the same user and of the provided app.
423
795
  try:
424
796
  local_dict_access_token_payload = get_jwt_payload(
425
797
  access_token, config_str_secret_key_for_access_token
426
798
  )
427
799
  except Exception as error:
800
+ output_content = get_api_output_in_standard_format(
801
+ message=messages["INCORRECT_ACCESS_TOKEN"], log=str(error)
802
+ )
428
803
  return JSONResponse(
429
804
  status_code=status.HTTP_400_BAD_REQUEST,
430
- content=str(error),
805
+ content=output_content,
431
806
  )
432
807
  if local_dict_access_token_payload["user_id"] != user_id:
808
+ output_content = get_api_output_in_standard_format(
809
+ message=messages["INCORRECT_ACCESS_TOKEN"],
810
+ log=f"access token and user_id mismatch.",
811
+ )
433
812
  return JSONResponse(
434
813
  status_code=status.HTTP_400_BAD_REQUEST,
435
- content=f"access token and user_id mismatch.",
814
+ content=output_content,
815
+ )
816
+ if local_dict_access_token_payload["app_id"] != app_id:
817
+ output_content = get_api_output_in_standard_format(
818
+ message=messages["INCORRECT_ACCESS_TOKEN"],
819
+ log=f"access token and app_id mismatch.",
820
+ )
821
+ return JSONResponse(
822
+ status_code=status.HTTP_400_BAD_REQUEST,
823
+ content=output_content,
436
824
  )
437
-
438
825
  # ======================================================================================
439
826
 
440
827
  # NOTE: if both access token and refresh token have expired for a user,
441
828
  # it can be assumed that user session only needs to be removed from the front end.
442
829
 
443
830
  # ======================================================================================
831
+ """
832
+ main process
833
+ """
444
834
  # delete session for user
445
- global_object_square_database_helper.delete_rows(
446
- database_name=local_string_database_name,
447
- schema_name=local_string_schema_name,
835
+ global_object_square_database_helper.delete_rows_v0(
836
+ database_name=global_string_database_name,
837
+ schema_name=global_string_schema_name,
448
838
  table_name=UserSession.__tablename__,
449
- filters={
450
- UserSession.user_id.name: user_id,
451
- UserSession.user_session_refresh_token.name: refresh_token,
452
- },
839
+ filters=FiltersV0(
840
+ {
841
+ UserSession.user_id.name: FilterConditionsV0(eq=user_id),
842
+ UserSession.user_session_refresh_token.name: FilterConditionsV0(
843
+ eq=refresh_token
844
+ ),
845
+ UserSession.app_id.name: FilterConditionsV0(eq=app_id),
846
+ }
847
+ ),
453
848
  )
454
-
849
+ """
850
+ return value
851
+ """
852
+ output_content = get_api_output_in_standard_format(
853
+ message=messages["LOGOUT_SUCCESSFUL"],
854
+ )
855
+ return JSONResponse(status_code=status.HTTP_200_OK, content=output_content)
856
+ except HTTPException as http_exception:
455
857
  return JSONResponse(
456
- status_code=status.HTTP_200_OK, content="Log out successful."
858
+ status_code=http_exception.status_code, content=http_exception.detail
457
859
  )
458
- # ======================================================================================
459
-
460
860
  except Exception as e:
861
+ """
862
+ rollback logic
863
+ """
461
864
  global_object_square_logger.logger.error(e, exc_info=True)
865
+ output_content = get_api_output_in_standard_format(
866
+ message=messages["GENERIC_500"],
867
+ log=str(e),
868
+ )
462
869
  return JSONResponse(
463
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=str(e)
870
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=output_content
464
871
  )
@@ -1,3 +1,5 @@
1
1
  from fastapi import APIRouter
2
2
 
3
- router = APIRouter(tags=["utility"], )
3
+ router = APIRouter(
4
+ tags=["utility"],
5
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: square-authentication
3
- Version: 1.0.0
3
+ Version: 2.0.0
4
4
  Summary: authentication layer for my personal server.
5
5
  Home-page: https://github.com/thepmsquare/square_authentication
6
6
  Author: thePmSquare
@@ -20,10 +20,10 @@ Requires-Dist: bcrypt>=4.1.2
20
20
  Requires-Dist: pyjwt>=2.8.0
21
21
  Requires-Dist: requests>=2.32.3
22
22
  Requires-Dist: cryptography>=42.0.7
23
- Requires-Dist: square-commons>=0.0.1
23
+ Requires-Dist: square-commons>=1.0.0
24
24
  Requires-Dist: square-logger>=1.0.0
25
- Requires-Dist: square-database-helper>=0.0.5
26
- Requires-Dist: square-database-structure>=0.0.11
25
+ Requires-Dist: square-database-helper>=2.0.0
26
+ Requires-Dist: square-database-structure>=1.0.0
27
27
 
28
28
  # square_authentication
29
29
 
@@ -43,6 +43,21 @@ pip install square_authentication
43
43
 
44
44
  ## changelog
45
45
 
46
+ ### v2.0.0
47
+
48
+ - authentication module needs to be used across applications so
49
+ - register_username: will not create sessions and therefore will not auto login.
50
+ - login: added validation if app is assigned to user before assigning it and added app_id in session row.
51
+ - logout: added app_id as new parameter and validation for that.
52
+ - generate_access_token: added app_id as new parameter and validation for that.
53
+ - added 2 new endpoints
54
+ - get user app ids: **access token validation pending**.
55
+ - change user app ids: **access token validation pending**.
56
+ - add versions for all endpoint paths.
57
+ - make it compatible with square_database_helper 2.x.
58
+ - username in database will always be lowercase.
59
+ - standardise output formats for all api.
60
+
46
61
  ### v1.0.0
47
62
 
48
63
  - initial implementation.
@@ -0,0 +1,15 @@
1
+ square_authentication/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ square_authentication/configuration.py,sha256=i0uNtNSQd-n1rBxFM6jsIz1Wy3d090RcdTViSqHKc7Y,2973
3
+ square_authentication/main.py,sha256=JK9KBmN73KL8EpKrXrjrwwf37bmC4AXrFHtfl2roYwQ,1636
4
+ square_authentication/messages.py,sha256=NHJLnaB-qj69VJrMkmbMXDHJUnakQLht14ZBrw4dGgg,1094
5
+ square_authentication/data/config.ini,sha256=_740RvKpL5W2bUDGwZ7ePwuP-mAasr5cXXB81yq_Jv8,906
6
+ square_authentication/routes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
+ square_authentication/routes/core.py,sha256=gwfNQcMvT5DdbZQBotLPwy1Actr7SBSgrimfHfMviYs,33617
8
+ square_authentication/routes/utility.py,sha256=Kx4S4tZ1GKsPoC8CoZ4fkLEebvr02KeFEPePtTHtpnQ,75
9
+ square_authentication/utils/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
10
+ square_authentication/utils/encryption.py,sha256=T6BShoUr_xeGpbfPgTK-GxTlXPwcjwU4c4KW7KPzrF8,1865
11
+ square_authentication/utils/token.py,sha256=Y_arg5LegX-aprMj9YweUK8jjNZLGDjLUGgxbUA12w4,560
12
+ square_authentication-2.0.0.dist-info/METADATA,sha256=BrxsipcwD1dQNTUeM7pXXtAOZMPXBO1i4n7tRRbXx7s,1966
13
+ square_authentication-2.0.0.dist-info/WHEEL,sha256=eOLhNAGa2EW3wWl_TU484h7q1UNgy0JXjjoqKoxAAQc,92
14
+ square_authentication-2.0.0.dist-info/top_level.txt,sha256=wDssVJIl9KIEJPj5rR3rv4uRI7yCndMBrvHd_6BGXQA,22
15
+ square_authentication-2.0.0.dist-info/RECORD,,
@@ -1,14 +0,0 @@
1
- square_authentication/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- square_authentication/configuration.py,sha256=9rRznQcfsUd_o-OnYjdBJSiLa30_5o5BXJjzhZPLUqc,2993
3
- square_authentication/main.py,sha256=01bu19koJNkJoz2VadPiV9M6TaIRoFEs5UabJfD6Tjo,1528
4
- square_authentication/data/config.ini,sha256=_740RvKpL5W2bUDGwZ7ePwuP-mAasr5cXXB81yq_Jv8,906
5
- square_authentication/routes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- square_authentication/routes/core.py,sha256=cZduu9VUMrrkrBYsR9elorQ6aPqpVAkV2f_4P8tKEto,20210
7
- square_authentication/routes/utility.py,sha256=qFvXfmWqBhUAEQQq9StmY9tERVUoVE7Fe07dhVPZPoU,70
8
- square_authentication/utils/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
9
- square_authentication/utils/encryption.py,sha256=T6BShoUr_xeGpbfPgTK-GxTlXPwcjwU4c4KW7KPzrF8,1865
10
- square_authentication/utils/token.py,sha256=Y_arg5LegX-aprMj9YweUK8jjNZLGDjLUGgxbUA12w4,560
11
- square_authentication-1.0.0.dist-info/METADATA,sha256=vBdyC4c-vg7SWkg4GnxnAOtoRVPmAGzNBa4nD8LU60U,1209
12
- square_authentication-1.0.0.dist-info/WHEEL,sha256=eOLhNAGa2EW3wWl_TU484h7q1UNgy0JXjjoqKoxAAQc,92
13
- square_authentication-1.0.0.dist-info/top_level.txt,sha256=wDssVJIl9KIEJPj5rR3rv4uRI7yCndMBrvHd_6BGXQA,22
14
- square_authentication-1.0.0.dist-info/RECORD,,