forgot_password.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. import base64
  2. import secrets
  3. from flask import request
  4. from flask_restful import Resource, reqparse # type: ignore
  5. from constants.languages import languages
  6. from controllers.console import api
  7. from controllers.console.auth.error import EmailCodeError, InvalidEmailError, InvalidTokenError, PasswordMismatchError
  8. from controllers.console.error import AccountInFreezeError, AccountNotFound, EmailSendIpLimitError
  9. from controllers.console.wraps import setup_required
  10. from events.tenant_event import tenant_was_created
  11. from extensions.ext_database import db
  12. from libs.helper import email, extract_remote_ip
  13. from libs.password import hash_password, valid_password
  14. from models.account import Account
  15. from services.account_service import AccountService, TenantService
  16. from services.errors.account import AccountRegisterError
  17. from services.errors.workspace import WorkSpaceNotAllowedCreateError
  18. from services.feature_service import FeatureService
  19. class ForgotPasswordSendEmailApi(Resource):
  20. @setup_required
  21. def post(self):
  22. parser = reqparse.RequestParser()
  23. parser.add_argument("email", type=email, required=True, location="json")
  24. parser.add_argument("language", type=str, required=False, location="json")
  25. args = parser.parse_args()
  26. ip_address = extract_remote_ip(request)
  27. if AccountService.is_email_send_ip_limit(ip_address):
  28. raise EmailSendIpLimitError()
  29. if args["language"] is not None and args["language"] == "zh-Hans":
  30. language = "zh-Hans"
  31. else:
  32. language = "en-US"
  33. account = Account.query.filter_by(email=args["email"]).first()
  34. token = None
  35. if account is None:
  36. if FeatureService.get_system_features().is_allow_register:
  37. token = AccountService.send_reset_password_email(email=args["email"], language=language)
  38. return {"result": "fail", "data": token, "code": "account_not_found"}
  39. else:
  40. raise AccountNotFound()
  41. else:
  42. token = AccountService.send_reset_password_email(account=account, email=args["email"], language=language)
  43. return {"result": "success", "data": token}
  44. class ForgotPasswordCheckApi(Resource):
  45. @setup_required
  46. def post(self):
  47. parser = reqparse.RequestParser()
  48. parser.add_argument("email", type=str, required=True, location="json")
  49. parser.add_argument("code", type=str, required=True, location="json")
  50. parser.add_argument("token", type=str, required=True, nullable=False, location="json")
  51. args = parser.parse_args()
  52. user_email = args["email"]
  53. token_data = AccountService.get_reset_password_data(args["token"])
  54. if token_data is None:
  55. raise InvalidTokenError()
  56. if user_email != token_data.get("email"):
  57. raise InvalidEmailError()
  58. if args["code"] != token_data.get("code"):
  59. raise EmailCodeError()
  60. return {"is_valid": True, "email": token_data.get("email")}
  61. class ForgotPasswordResetApi(Resource):
  62. @setup_required
  63. def post(self):
  64. parser = reqparse.RequestParser()
  65. parser.add_argument("token", type=str, required=True, nullable=False, location="json")
  66. parser.add_argument("new_password", type=valid_password, required=True, nullable=False, location="json")
  67. parser.add_argument("password_confirm", type=valid_password, required=True, nullable=False, location="json")
  68. args = parser.parse_args()
  69. new_password = args["new_password"]
  70. password_confirm = args["password_confirm"]
  71. if str(new_password).strip() != str(password_confirm).strip():
  72. raise PasswordMismatchError()
  73. token = args["token"]
  74. reset_data = AccountService.get_reset_password_data(token)
  75. if reset_data is None:
  76. raise InvalidTokenError()
  77. AccountService.revoke_reset_password_token(token)
  78. salt = secrets.token_bytes(16)
  79. base64_salt = base64.b64encode(salt).decode()
  80. password_hashed = hash_password(new_password, salt)
  81. base64_password_hashed = base64.b64encode(password_hashed).decode()
  82. account = Account.query.filter_by(email=reset_data.get("email")).first()
  83. if account:
  84. account.password = base64_password_hashed
  85. account.password_salt = base64_salt
  86. db.session.commit()
  87. tenant = TenantService.get_join_tenants(account)
  88. if not tenant and not FeatureService.get_system_features().is_allow_create_workspace:
  89. tenant = TenantService.create_tenant(f"{account.name}'s Workspace")
  90. TenantService.create_tenant_member(tenant, account, role="owner")
  91. account.current_tenant = tenant
  92. tenant_was_created.send(tenant)
  93. else:
  94. try:
  95. account = AccountService.create_account_and_tenant(
  96. email=reset_data.get("email", ""),
  97. name=reset_data.get("email", ""),
  98. password=password_confirm,
  99. interface_language=languages[0],
  100. )
  101. except WorkSpaceNotAllowedCreateError:
  102. pass
  103. except AccountRegisterError as are:
  104. raise AccountInFreezeError()
  105. return {"result": "success"}
  106. api.add_resource(ForgotPasswordSendEmailApi, "/forgot-password")
  107. api.add_resource(ForgotPasswordCheckApi, "/forgot-password/validity")
  108. api.add_resource(ForgotPasswordResetApi, "/forgot-password/resets")