square-authentication 6.2.1__py3-none-any.whl → 7.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.
@@ -1,21 +1,40 @@
1
+ import random
2
+ from datetime import timezone, datetime, timedelta
1
3
  from typing import Annotated, Optional
2
4
 
3
- from fastapi import APIRouter, HTTPException, status, Header, UploadFile
5
+ import bcrypt
6
+ from fastapi import APIRouter, Header, HTTPException, UploadFile, status
4
7
  from fastapi.responses import JSONResponse
5
8
  from square_commons import get_api_output_in_standard_format
9
+ from square_commons.email import send_email_using_mailgun
6
10
  from square_database_helper import FiltersV0
7
11
  from square_database_helper.pydantic_models import FilterConditionsV0
8
12
  from square_database_structure.square import global_string_database_name
9
13
  from square_database_structure.square.authentication import global_string_schema_name
10
- from square_database_structure.square.authentication.tables import UserProfile
14
+ from square_database_structure.square.authentication.enums import (
15
+ VerificationCodeTypeEnum,
16
+ )
17
+ from square_database_structure.square.authentication.tables import (
18
+ UserProfile,
19
+ UserVerificationCode,
20
+ )
21
+ from square_database_structure.square.email import (
22
+ global_string_schema_name as email_schema_name,
23
+ )
24
+ from square_database_structure.square.email.enums import EmailTypeEnum, EmailStatusEnum
25
+ from square_database_structure.square.email.tables import EmailLog
11
26
 
12
27
  from square_authentication.configuration import (
13
- global_object_square_logger,
14
28
  config_str_secret_key_for_access_token,
15
- global_object_square_file_store_helper,
16
29
  global_object_square_database_helper,
30
+ global_object_square_file_store_helper,
31
+ global_object_square_logger,
32
+ MAIL_GUN_API_KEY,
17
33
  )
18
34
  from square_authentication.messages import messages
35
+ from square_authentication.pydantic_models.profile import (
36
+ ValidateEmailVerificationCodeV0,
37
+ )
19
38
  from square_authentication.utils.token import get_jwt_payload
20
39
 
21
40
  router = APIRouter(
@@ -164,3 +183,428 @@ async def update_profile_photo_v0(
164
183
  return JSONResponse(
165
184
  status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=output_content
166
185
  )
186
+
187
+
188
+ @router.patch("/update_profile_details/v0")
189
+ @global_object_square_logger.auto_logger()
190
+ async def update_profile_details_v0(
191
+ access_token: Annotated[str, Header()],
192
+ first_name: Optional[str] = None,
193
+ last_name: Optional[str] = None,
194
+ email: Optional[str] = None,
195
+ phone_number_country_code: Optional[str] = None,
196
+ phone_number: Optional[str] = None,
197
+ ):
198
+ try:
199
+ """
200
+ validation
201
+ """
202
+ # validate access token
203
+ try:
204
+ local_dict_access_token_payload = get_jwt_payload(
205
+ access_token, config_str_secret_key_for_access_token
206
+ )
207
+ except Exception as error:
208
+ output_content = get_api_output_in_standard_format(
209
+ message=messages["INCORRECT_ACCESS_TOKEN"], log=str(error)
210
+ )
211
+ raise HTTPException(
212
+ status_code=status.HTTP_400_BAD_REQUEST,
213
+ detail=output_content,
214
+ )
215
+ user_id = local_dict_access_token_payload["user_id"]
216
+
217
+ # validate email format
218
+ if email and "@" not in email:
219
+ output_content = get_api_output_in_standard_format(
220
+ message=messages["INVALID_EMAIL_FORMAT"]
221
+ )
222
+ raise HTTPException(
223
+ status_code=status.HTTP_400_BAD_REQUEST,
224
+ detail=output_content,
225
+ )
226
+
227
+ # validate phone number format
228
+ if phone_number and not phone_number.isdigit():
229
+ output_content = get_api_output_in_standard_format(
230
+ message=messages["INVALID_PHONE_NUMBER_FORMAT"]
231
+ )
232
+ raise HTTPException(
233
+ status_code=status.HTTP_400_BAD_REQUEST,
234
+ detail=output_content,
235
+ )
236
+ if (phone_number and not phone_number_country_code) or (
237
+ phone_number_country_code and not phone_number
238
+ ):
239
+ output_content = get_api_output_in_standard_format(
240
+ message=messages["GENERIC_MISSING_REQUIRED_FIELD"],
241
+ log="both phone number and country code must be provided together.",
242
+ )
243
+ raise HTTPException(
244
+ status_code=status.HTTP_400_BAD_REQUEST,
245
+ detail=output_content,
246
+ )
247
+
248
+ """
249
+ main process
250
+ """
251
+ profile_update_data = {}
252
+ if first_name is not None:
253
+ profile_update_data[UserProfile.user_profile_first_name.name] = first_name
254
+ if last_name is not None:
255
+ profile_update_data[UserProfile.user_profile_last_name.name] = last_name
256
+ if email is not None:
257
+ profile_update_data[UserProfile.user_profile_email.name] = email
258
+ if phone_number is not None and phone_number_country_code is not None:
259
+ profile_update_data[UserProfile.user_profile_phone_number.name] = (
260
+ phone_number
261
+ )
262
+ profile_update_data[
263
+ UserProfile.user_profile_phone_number_country_code.name
264
+ ] = phone_number_country_code
265
+
266
+ # updating user profile
267
+ profile_update_response = global_object_square_database_helper.edit_rows_v0(
268
+ data=profile_update_data,
269
+ filters=FiltersV0(
270
+ root={UserProfile.user_id.name: FilterConditionsV0(eq=user_id)}
271
+ ),
272
+ database_name=global_string_database_name,
273
+ schema_name=global_string_schema_name,
274
+ table_name=UserProfile.__tablename__,
275
+ apply_filters=True,
276
+ )
277
+
278
+ """
279
+ return value
280
+ """
281
+ output_content = get_api_output_in_standard_format(
282
+ data=profile_update_response["data"],
283
+ message=messages["GENERIC_UPDATE_SUCCESSFUL"],
284
+ )
285
+ return JSONResponse(
286
+ status_code=status.HTTP_200_OK,
287
+ content=output_content,
288
+ )
289
+ except HTTPException as http_exception:
290
+ global_object_square_logger.logger.error(http_exception, exc_info=True)
291
+ return JSONResponse(
292
+ status_code=http_exception.status_code, content=http_exception.detail
293
+ )
294
+ except Exception as e:
295
+ """
296
+ rollback logic
297
+ """
298
+ global_object_square_logger.logger.error(e, exc_info=True)
299
+ output_content = get_api_output_in_standard_format(
300
+ message=messages["GENERIC_500"],
301
+ log=str(e),
302
+ )
303
+ return JSONResponse(
304
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=output_content
305
+ )
306
+
307
+
308
+ @router.post("/send_verification_email/v0")
309
+ @global_object_square_logger.auto_logger()
310
+ async def send_verification_email_v0(
311
+ access_token: Annotated[str, Header()],
312
+ ):
313
+ try:
314
+ """
315
+ validation
316
+ """
317
+ # validate access token
318
+ try:
319
+ local_dict_access_token_payload = get_jwt_payload(
320
+ access_token, config_str_secret_key_for_access_token
321
+ )
322
+ except Exception as error:
323
+ output_content = get_api_output_in_standard_format(
324
+ message=messages["INCORRECT_ACCESS_TOKEN"], log=str(error)
325
+ )
326
+ raise HTTPException(
327
+ status_code=status.HTTP_400_BAD_REQUEST,
328
+ detail=output_content,
329
+ )
330
+ user_id = local_dict_access_token_payload["user_id"]
331
+
332
+ # validate if user has email in profile
333
+ user_profile_response = global_object_square_database_helper.get_rows_v0(
334
+ database_name=global_string_database_name,
335
+ schema_name=global_string_schema_name,
336
+ table_name=UserProfile.__tablename__,
337
+ filters=FiltersV0(
338
+ root={UserProfile.user_id.name: FilterConditionsV0(eq=user_id)}
339
+ ),
340
+ apply_filters=True,
341
+ )
342
+ user_profile_data = user_profile_response["data"]["main"][0]
343
+ if not user_profile_data.get(UserProfile.user_profile_email.name):
344
+ output_content = get_api_output_in_standard_format(
345
+ message=messages["GENERIC_MISSING_REQUIRED_FIELD"],
346
+ log="email is required to send verification email.",
347
+ )
348
+ raise HTTPException(
349
+ status_code=status.HTTP_400_BAD_REQUEST,
350
+ detail=output_content,
351
+ )
352
+ # check if email is already verified
353
+ if user_profile_data.get(UserProfile.user_profile_email_verified.name):
354
+ output_content = get_api_output_in_standard_format(
355
+ message=messages["EMAIL_ALREADY_VERIFIED"]
356
+ )
357
+ return JSONResponse(status_code=status.HTTP_200_OK, content=output_content)
358
+
359
+ """
360
+ main process
361
+ """
362
+ # create 6 digit verification code
363
+ verification_code = random.randint(100000, 999999)
364
+ # hash the verification code
365
+ hashed_verification_code = bcrypt.hashpw(
366
+ str(verification_code).encode("utf-8"), bcrypt.gensalt()
367
+ ).decode("utf-8")
368
+ # expire the verification code after 10 minutes
369
+ expires_at = datetime.now(timezone.utc) + timedelta(minutes=10)
370
+ # add verification code to UserVerification code table
371
+ global_object_square_database_helper.insert_rows_v0(
372
+ database_name=global_string_database_name,
373
+ schema_name=global_string_schema_name,
374
+ table_name=UserVerificationCode.__tablename__,
375
+ data=[
376
+ {
377
+ UserVerificationCode.user_id.name: user_id,
378
+ UserVerificationCode.user_verification_code_type.name: VerificationCodeTypeEnum.EMAIL_VERIFICATION.value,
379
+ UserVerificationCode.user_verification_code_hash.name: hashed_verification_code,
380
+ UserVerificationCode.user_verification_code_expires_at.name: expires_at.strftime(
381
+ "%Y-%m-%d %H:%M:%S.%f+00"
382
+ ),
383
+ }
384
+ ],
385
+ )
386
+ # send verification email
387
+ if (
388
+ user_profile_data[UserProfile.user_profile_first_name.name]
389
+ and user_profile_data[UserProfile.user_profile_last_name.name]
390
+ ):
391
+ user_to_name = f"{user_profile_data[UserProfile.user_profile_first_name.name]} {user_profile_data[UserProfile.user_profile_last_name.name]}"
392
+ elif user_profile_data[UserProfile.user_profile_first_name.name]:
393
+ user_to_name = user_profile_data[UserProfile.user_profile_first_name.name]
394
+ elif user_profile_data[UserProfile.user_profile_last_name.name]:
395
+ user_to_name = user_profile_data[UserProfile.user_profile_last_name.name]
396
+ else:
397
+ user_to_name = ""
398
+
399
+ mailgun_response = send_email_using_mailgun(
400
+ from_email="auth@thepmsquare.com",
401
+ from_name="square_authentication",
402
+ to_email=user_profile_data[UserProfile.user_profile_email.name],
403
+ to_name=user_to_name,
404
+ subject="Email Verification",
405
+ body=f"Your verification code is {verification_code}. It will expire in 10 minutes.",
406
+ api_key=MAIL_GUN_API_KEY,
407
+ domain_name="thepmsquare.com",
408
+ )
409
+ # add log for email sending
410
+ global_object_square_database_helper.insert_rows_v0(
411
+ database_name=global_string_database_name,
412
+ schema_name=email_schema_name,
413
+ table_name=EmailLog.__tablename__,
414
+ data=[
415
+ {
416
+ EmailLog.user_id.name: user_id,
417
+ EmailLog.recipient_email.name: user_profile_data[
418
+ UserProfile.user_profile_email.name
419
+ ],
420
+ EmailLog.email_type.name: EmailTypeEnum.VERIFY_EMAIL.value,
421
+ EmailLog.status.name: EmailStatusEnum.SENT.value,
422
+ EmailLog.third_party_message_id.name: mailgun_response.get("id"),
423
+ }
424
+ ],
425
+ )
426
+ """
427
+ return value
428
+ """
429
+ output_content = get_api_output_in_standard_format(
430
+ data={
431
+ "expires_at": expires_at.isoformat(),
432
+ },
433
+ message=messages["GENERIC_ACTION_SUCCESSFUL"],
434
+ )
435
+ return JSONResponse(
436
+ status_code=status.HTTP_200_OK,
437
+ content=output_content,
438
+ )
439
+ except HTTPException as http_exception:
440
+ global_object_square_logger.logger.error(http_exception, exc_info=True)
441
+ return JSONResponse(
442
+ status_code=http_exception.status_code, content=http_exception.detail
443
+ )
444
+ except Exception as e:
445
+ """
446
+ rollback logic
447
+ """
448
+ global_object_square_logger.logger.error(e, exc_info=True)
449
+ output_content = get_api_output_in_standard_format(
450
+ message=messages["GENERIC_500"],
451
+ log=str(e),
452
+ )
453
+ return JSONResponse(
454
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=output_content
455
+ )
456
+
457
+
458
+ @router.post("/validate_email_verification_code/v0")
459
+ @global_object_square_logger.auto_logger()
460
+ async def validate_email_verification_code_v0(
461
+ access_token: Annotated[str, Header()],
462
+ body: ValidateEmailVerificationCodeV0,
463
+ ):
464
+ verification_code = body.verification_code
465
+ try:
466
+ """
467
+ validation
468
+ """
469
+ # validate access token
470
+ try:
471
+ local_dict_access_token_payload = get_jwt_payload(
472
+ access_token, config_str_secret_key_for_access_token
473
+ )
474
+ except Exception as error:
475
+ output_content = get_api_output_in_standard_format(
476
+ message=messages["INCORRECT_ACCESS_TOKEN"], log=str(error)
477
+ )
478
+ raise HTTPException(
479
+ status_code=status.HTTP_400_BAD_REQUEST,
480
+ detail=output_content,
481
+ )
482
+ user_id = local_dict_access_token_payload["user_id"]
483
+
484
+ # validate if user has email in profile
485
+ user_profile_response = global_object_square_database_helper.get_rows_v0(
486
+ database_name=global_string_database_name,
487
+ schema_name=global_string_schema_name,
488
+ table_name=UserProfile.__tablename__,
489
+ filters=FiltersV0(
490
+ root={UserProfile.user_id.name: FilterConditionsV0(eq=user_id)}
491
+ ),
492
+ apply_filters=True,
493
+ )
494
+ user_profile_data = user_profile_response["data"]["main"][0]
495
+ if not user_profile_data.get(UserProfile.user_profile_email.name):
496
+ output_content = get_api_output_in_standard_format(
497
+ message=messages["GENERIC_MISSING_REQUIRED_FIELD"],
498
+ log="email is required to send verification email.",
499
+ )
500
+ raise HTTPException(
501
+ status_code=status.HTTP_400_BAD_REQUEST,
502
+ detail=output_content,
503
+ )
504
+ # check if email is already verified
505
+ if user_profile_data.get(UserProfile.user_profile_email_verified.name):
506
+ output_content = get_api_output_in_standard_format(
507
+ message=messages["EMAIL_ALREADY_VERIFIED"]
508
+ )
509
+ return JSONResponse(status_code=status.HTTP_200_OK, content=output_content)
510
+ # check for verification code in UserVerificationCode table
511
+ verification_code_response = global_object_square_database_helper.get_rows_v0(
512
+ database_name=global_string_database_name,
513
+ schema_name=global_string_schema_name,
514
+ table_name=UserVerificationCode.__tablename__,
515
+ filters=FiltersV0(
516
+ root={
517
+ UserVerificationCode.user_id.name: FilterConditionsV0(eq=user_id),
518
+ UserVerificationCode.user_verification_code_type.name: FilterConditionsV0(
519
+ eq=VerificationCodeTypeEnum.EMAIL_VERIFICATION.value
520
+ ),
521
+ UserVerificationCode.user_verification_code_used_at.name: FilterConditionsV0(
522
+ is_null=True
523
+ ),
524
+ UserVerificationCode.user_verification_code_expires_at.name: FilterConditionsV0(
525
+ gte=datetime.now(timezone.utc).strftime(
526
+ "%Y-%m-%d %H:%M:%S.%f+00"
527
+ )
528
+ ),
529
+ }
530
+ ),
531
+ order_by=[
532
+ "-" + UserVerificationCode.user_verification_code_created_at.name
533
+ ],
534
+ limit=1,
535
+ apply_filters=True,
536
+ )
537
+ if len(verification_code_response["data"]["main"]) != 1:
538
+ output_content = get_api_output_in_standard_format(
539
+ message=messages["INCORRECT_VERIFICATION_CODE"]
540
+ )
541
+ raise HTTPException(
542
+ status_code=status.HTTP_400_BAD_REQUEST,
543
+ detail=output_content,
544
+ )
545
+ """
546
+ main process
547
+ """
548
+
549
+ # check if the latest verification code matches the provided code
550
+ latest_verification_code_data = verification_code_response["data"]["main"][0]
551
+ latest_verification_code_hash = latest_verification_code_data[
552
+ UserVerificationCode.user_verification_code_hash.name
553
+ ]
554
+ if not bcrypt.checkpw(
555
+ str(verification_code).encode("utf-8"),
556
+ latest_verification_code_hash.encode("utf-8"),
557
+ ):
558
+ output_content = get_api_output_in_standard_format(
559
+ message=messages["INCORRECT_VERIFICATION_CODE"]
560
+ )
561
+ raise HTTPException(
562
+ status_code=status.HTTP_400_BAD_REQUEST,
563
+ detail=output_content,
564
+ )
565
+ # update user profile to mark email as verified
566
+ email_verified_time = datetime.now(timezone.utc)
567
+ global_object_square_database_helper.edit_rows_v0(
568
+ database_name=global_string_database_name,
569
+ schema_name=global_string_schema_name,
570
+ table_name=UserProfile.__tablename__,
571
+ filters=FiltersV0(
572
+ root={UserProfile.user_id.name: FilterConditionsV0(eq=user_id)}
573
+ ),
574
+ data={
575
+ UserProfile.user_profile_email_verified.name: email_verified_time.strftime(
576
+ "%Y-%m-%d %H:%M:%S.%f+00"
577
+ ),
578
+ },
579
+ apply_filters=True,
580
+ )
581
+ """
582
+ return value
583
+ """
584
+ output_content = get_api_output_in_standard_format(
585
+ data={
586
+ UserProfile.user_profile_email_verified.name: email_verified_time.isoformat(),
587
+ },
588
+ message=messages["GENERIC_ACTION_SUCCESSFUL"],
589
+ )
590
+ return JSONResponse(
591
+ status_code=status.HTTP_200_OK,
592
+ content=output_content,
593
+ )
594
+ except HTTPException as http_exception:
595
+ global_object_square_logger.logger.error(http_exception, exc_info=True)
596
+ return JSONResponse(
597
+ status_code=http_exception.status_code, content=http_exception.detail
598
+ )
599
+ except Exception as e:
600
+ """
601
+ rollback logic
602
+ """
603
+ global_object_square_logger.logger.error(e, exc_info=True)
604
+ output_content = get_api_output_in_standard_format(
605
+ message=messages["GENERIC_500"],
606
+ log=str(e),
607
+ )
608
+ return JSONResponse(
609
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content=output_content
610
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: square_authentication
3
- Version: 6.2.1
3
+ Version: 7.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
@@ -19,7 +19,7 @@ Requires-Dist: bcrypt>=4.1.2
19
19
  Requires-Dist: pyjwt>=2.8.0
20
20
  Requires-Dist: requests>=2.32.3
21
21
  Requires-Dist: cryptography>=42.0.7
22
- Requires-Dist: square_commons>=1.0.0
22
+ Requires-Dist: square_commons>=2.1.0
23
23
  Requires-Dist: square_logger>=2.0.0
24
24
  Requires-Dist: square_database_helper>=2.0.0
25
25
  Requires-Dist: square_database_structure>=2.3.1
@@ -53,10 +53,39 @@ pip install square_authentication
53
53
 
54
54
  ## changelog
55
55
 
56
+ ### v7.0.0
57
+
58
+ - internal support for UserAuthProvider.
59
+ - internal support for username shifted from UserProfile to User.
60
+ - internal support for phone number country code in UserProfile.
61
+ - core
62
+ - register_username_v0 fixed to account for changes mentioned above and creates empty profile.
63
+ - login_username_v0 fixed to account for changes mentioned above.
64
+ - update_username_v0 fixed to account for changes mentioned above.
65
+ - **breaking change**: delete_user_v0 is now a POST method instead of DELETE.
66
+ - add generate_account_backup_codes_v0.
67
+ - add reset_password_and_login_using_backup_code_v0.
68
+ - add validation for email verification when adding email as recovery method in update_user_recovery_methods_v0.
69
+ - add send_reset_password_email_v0.
70
+ - profile
71
+ - add update_profile_details_v0.
72
+ - add send_verification_email_v0.
73
+ - add validate_email_verification_code_v0.
74
+ - tests
75
+ - add test cases and fixtures for login_username_v0.
76
+ - add test cases and fixtures for delete_user_v0.
77
+ - add test cases and fixtures for update_profile_details_v0.
78
+ - env
79
+ - add EMAIL section and MAIL_GUN_API_KEY variable.
80
+
81
+ ### v6.2.2
82
+
83
+ - remove config.ini and config.testing.ini from version control.
84
+
56
85
  ### v6.2.1
57
86
 
58
87
  - core
59
- - tweak validation for username in register_username_v0 and update_username_v0.
88
+ - tweak validation for username in register_username_v0 and update_username_v0.
60
89
 
61
90
  ### v6.2.0
62
91
 
@@ -0,0 +1,20 @@
1
+ square_authentication/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ square_authentication/configuration.py,sha256=_6T9bGdQnoBMJvVOKU_AH6bL7g057GiP-bgsqFsbv-k,4934
3
+ square_authentication/main.py,sha256=nhkv8U4E9b7VIH7Aaj8iMWIwA4VIL-vzRXjZaYEFWPw,1755
4
+ square_authentication/messages.py,sha256=H0BS84UaE7OZkufpaf0mwSX3FzXQzmGx-TrrrJmm818,2649
5
+ square_authentication/data/config.sample.ini,sha256=bkQ71kpnBpw15yxW2mAinLaVU7QUoEWCNop6hqSUGzw,1204
6
+ square_authentication/data/config.testing.sample.ini,sha256=n0lNWLY7g7iIXtnzbm2BFSAeN8i-dYtNH1zdFlhUirU,1251
7
+ square_authentication/pydantic_models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ square_authentication/pydantic_models/core.py,sha256=sy28oW71ptteX_2fuXPtCmAfSHcxE5MRYKPB_f4b7_I,825
9
+ square_authentication/pydantic_models/profile.py,sha256=tq7RJMfbMBMi7FaRQksWJR3Iucr2l8P2ziKgQvV4owg,110
10
+ square_authentication/routes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
+ square_authentication/routes/core.py,sha256=wlXIjcqjPFzNhrDjzUssr64bUz4UyshWRj5f_4deTuA,90422
12
+ square_authentication/routes/profile.py,sha256=VhdGAg5VXxbQQSvfecx3cu3gFkfTrSXPrQq-4piXWus,24208
13
+ square_authentication/routes/utility.py,sha256=KDr8KdkT0jAGPjfP-b5XXYG7p49WU7J1FiK6oSIckQI,1779
14
+ square_authentication/utils/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
15
+ square_authentication/utils/encryption.py,sha256=WakaiEAgWpTJltxBzqOtv81_DCDKfzJqt60fWSPoNvo,2027
16
+ square_authentication/utils/token.py,sha256=t-RPBY4cYyT1ro3lkLBTOy2BeRGBfluBVBivL5DLmDg,680
17
+ square_authentication-7.0.0.dist-info/METADATA,sha256=gy62vYZfS7k_NeBx6K9xL8YKINcLbQqRa77nYPR8m60,6728
18
+ square_authentication-7.0.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
19
+ square_authentication-7.0.0.dist-info/top_level.txt,sha256=wDssVJIl9KIEJPj5rR3rv4uRI7yCndMBrvHd_6BGXQA,22
20
+ square_authentication-7.0.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.8.0)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,19 +0,0 @@
1
- square_authentication/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- square_authentication/configuration.py,sha256=zdlBY7xyMoEl8fc2whpXqsILvvrNnFGC1Yry_pB6FaI,4579
3
- square_authentication/main.py,sha256=nhkv8U4E9b7VIH7Aaj8iMWIwA4VIL-vzRXjZaYEFWPw,1755
4
- square_authentication/messages.py,sha256=WVZtWBctx-YK1xGo97DFAMkSgCZpDEd9gABBSqlvd58,1575
5
- square_authentication/data/config.ini,sha256=Mayh9AhTBZd8i08Y--ClZuDEjJjfvnfKQmtqablzXOA,1154
6
- square_authentication/data/config.testing.ini,sha256=KB4PMPZ6a9yJGPXYJWwKlYcNET1Au3TQdJHQyngbZUA,1201
7
- square_authentication/pydantic_models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
- square_authentication/pydantic_models/core.py,sha256=qeNETcJv7mnRKGhATOW2bg0NlHuyzvot1dZ1b1qqhwU,610
9
- square_authentication/routes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
- square_authentication/routes/core.py,sha256=7KqTA3y6CedH7XelV2HBCkne4Bql9p31OzSeioguhE0,63838
11
- square_authentication/routes/profile.py,sha256=3b-PtMaD9cxvf112MOn9rPu5F2KG4sRxAbuPvll8dUU,6216
12
- square_authentication/routes/utility.py,sha256=KDr8KdkT0jAGPjfP-b5XXYG7p49WU7J1FiK6oSIckQI,1779
13
- square_authentication/utils/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
14
- square_authentication/utils/encryption.py,sha256=WakaiEAgWpTJltxBzqOtv81_DCDKfzJqt60fWSPoNvo,2027
15
- square_authentication/utils/token.py,sha256=t-RPBY4cYyT1ro3lkLBTOy2BeRGBfluBVBivL5DLmDg,680
16
- square_authentication-6.2.1.dist-info/METADATA,sha256=Fm26I8AcPJiMOGrzo-P3vwIbuw3W7rEsXwtqEpub5FY,5499
17
- square_authentication-6.2.1.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
18
- square_authentication-6.2.1.dist-info/top_level.txt,sha256=wDssVJIl9KIEJPj5rR3rv4uRI7yCndMBrvHd_6BGXQA,22
19
- square_authentication-6.2.1.dist-info/RECORD,,