From bc039efdaf69ce514bcc03b499b9783e7e212a12 Mon Sep 17 00:00:00 2001 From: ytqh Date: Sun, 2 Feb 2025 16:37:56 +0800 Subject: [PATCH] remove unused method in user login --- api/controllers/service_api/__init__.py | 2 +- api/controllers/service_api/auth/activate.py | 77 --------- .../service_api/auth/forgot_password.py | 132 --------------- api/controllers/service_api/auth/login.py | 150 ------------------ api/controllers/service_api/auth/signup.py | 122 -------------- 5 files changed, 1 insertion(+), 482 deletions(-) delete mode 100644 api/controllers/service_api/auth/activate.py delete mode 100644 api/controllers/service_api/auth/forgot_password.py delete mode 100644 api/controllers/service_api/auth/signup.py diff --git a/api/controllers/service_api/__init__.py b/api/controllers/service_api/__init__.py index 8f98abaf44..face70687a 100644 --- a/api/controllers/service_api/__init__.py +++ b/api/controllers/service_api/__init__.py @@ -8,4 +8,4 @@ api = ExternalApi(bp) from . import index from .app import app, audio, completion, conversation, file, message, workflow from .dataset import dataset, document, hit_testing, segment, upload_file -from .auth import activate, forgot_password, login, signup \ No newline at end of file +from .auth import login \ No newline at end of file diff --git a/api/controllers/service_api/auth/activate.py b/api/controllers/service_api/auth/activate.py deleted file mode 100644 index f3f7049e5f..0000000000 --- a/api/controllers/service_api/auth/activate.py +++ /dev/null @@ -1,77 +0,0 @@ -import datetime - -from flask import request -from flask_restful import Resource, reqparse # type: ignore - -from constants.languages import supported_language -from controllers.service_api import api -from controllers.service_api.error import AlreadyActivateError -from extensions.ext_database import db -from libs.helper import StrLen, email, extract_remote_ip, timezone -from models.account import AccountStatus -from services.account_service import AccountService, RegisterService - - -class ActivateCheckApi(Resource): - def get(self): - parser = reqparse.RequestParser() - parser.add_argument("workspace_id", type=str, required=False, nullable=True, location="args") - parser.add_argument("email", type=email, required=False, nullable=True, location="args") - parser.add_argument("token", type=str, required=True, nullable=False, location="args") - args = parser.parse_args() - - workspaceId = args["workspace_id"] - reg_email = args["email"] - token = args["token"] - - invitation = RegisterService.get_invitation_if_token_valid(workspaceId, reg_email, token) - if invitation: - data = invitation.get("data", {}) - tenant = invitation.get("tenant", None) - workspace_name = tenant.name if tenant else None - workspace_id = tenant.id if tenant else None - invitee_email = data.get("email") if data else None - return { - "is_valid": invitation is not None, - "data": {"workspace_name": workspace_name, "workspace_id": workspace_id, "email": invitee_email}, - } - else: - return {"is_valid": False} - - -class ActivateApi(Resource): - def post(self): - parser = reqparse.RequestParser() - parser.add_argument("workspace_id", type=str, required=False, nullable=True, location="json") - parser.add_argument("email", type=email, required=False, nullable=True, location="json") - parser.add_argument("token", type=str, required=True, nullable=False, location="json") - parser.add_argument("name", type=StrLen(30), required=True, nullable=False, location="json") - parser.add_argument( - "interface_language", type=supported_language, required=True, nullable=False, location="json" - ) - parser.add_argument("timezone", type=timezone, required=True, nullable=False, location="json") - args = parser.parse_args() - - invitation = RegisterService.get_invitation_if_token_valid(args["workspace_id"], args["email"], args["token"]) - if invitation is None: - raise AlreadyActivateError() - - RegisterService.revoke_token(args["workspace_id"], args["email"], args["token"]) - - account = invitation["account"] - account.name = args["name"] - - account.interface_language = args["interface_language"] - account.timezone = args["timezone"] - account.interface_theme = "light" - account.status = AccountStatus.ACTIVE.value - account.initialized_at = datetime.datetime.now(datetime.UTC).replace(tzinfo=None) - db.session.commit() - - token_pair = AccountService.login(account, ip_address=extract_remote_ip(request)) - - return {"result": "success", "data": token_pair.model_dump()} - - -api.add_resource(ActivateCheckApi, "/activate/check") -api.add_resource(ActivateApi, "/activate") diff --git a/api/controllers/service_api/auth/forgot_password.py b/api/controllers/service_api/auth/forgot_password.py deleted file mode 100644 index 6a49e41f1e..0000000000 --- a/api/controllers/service_api/auth/forgot_password.py +++ /dev/null @@ -1,132 +0,0 @@ -import base64 -import secrets - -from flask import request -from flask_restful import Resource, reqparse # type: ignore - -from constants.languages import languages -from controllers.service_api import api -from controllers.service_api.auth.error import EmailCodeError, InvalidEmailError, InvalidTokenError, PasswordMismatchError -from controllers.service_api.error import AccountInFreezeError, AccountNotFound, EmailSendIpLimitError -from events.tenant_event import tenant_was_created -from extensions.ext_database import db -from libs.helper import email, extract_remote_ip -from libs.password import hash_password, valid_password -from models.account import Account -from services.account_service import AccountService, TenantService -from services.errors.account import AccountRegisterError -from services.errors.workspace import WorkSpaceNotAllowedCreateError -from services.feature_service import FeatureService - - -class ForgotPasswordSendEmailApi(Resource): - def post(self): - parser = reqparse.RequestParser() - parser.add_argument("email", type=email, required=True, location="json") - parser.add_argument("language", type=str, required=False, location="json") - args = parser.parse_args() - - ip_address = extract_remote_ip(request) - if AccountService.is_email_send_ip_limit(ip_address): - raise EmailSendIpLimitError() - - if args["language"] is not None and args["language"] == "zh-Hans": - language = "zh-Hans" - else: - language = "en-US" - - account = Account.query.filter_by(email=args["email"]).first() - token = None - if account is None: - if FeatureService.get_system_features().is_allow_register: - token = AccountService.send_reset_password_email(email=args["email"], language=language) - return {"result": "fail", "data": token, "code": "account_not_found"} - else: - raise AccountNotFound() - else: - token = AccountService.send_reset_password_email(account=account, email=args["email"], language=language) - - return {"result": "success", "data": token} - - -class ForgotPasswordCheckApi(Resource): - def post(self): - parser = reqparse.RequestParser() - parser.add_argument("email", type=str, required=True, location="json") - parser.add_argument("code", type=str, required=True, location="json") - parser.add_argument("token", type=str, required=True, nullable=False, location="json") - args = parser.parse_args() - - user_email = args["email"] - - token_data = AccountService.get_reset_password_data(args["token"]) - if token_data is None: - raise InvalidTokenError() - - if user_email != token_data.get("email"): - raise InvalidEmailError() - - if args["code"] != token_data.get("code"): - raise EmailCodeError() - - return {"is_valid": True, "email": token_data.get("email")} - - -class ForgotPasswordResetApi(Resource): - def post(self): - parser = reqparse.RequestParser() - parser.add_argument("token", type=str, required=True, nullable=False, location="json") - parser.add_argument("new_password", type=valid_password, required=True, nullable=False, location="json") - parser.add_argument("password_confirm", type=valid_password, required=True, nullable=False, location="json") - args = parser.parse_args() - - new_password = args["new_password"] - password_confirm = args["password_confirm"] - - if str(new_password).strip() != str(password_confirm).strip(): - raise PasswordMismatchError() - - token = args["token"] - reset_data = AccountService.get_reset_password_data(token) - - if reset_data is None: - raise InvalidTokenError() - - AccountService.revoke_reset_password_token(token) - - salt = secrets.token_bytes(16) - base64_salt = base64.b64encode(salt).decode() - - password_hashed = hash_password(new_password, salt) - base64_password_hashed = base64.b64encode(password_hashed).decode() - - account = Account.query.filter_by(email=reset_data.get("email")).first() - if account: - account.password = base64_password_hashed - account.password_salt = base64_salt - db.session.commit() - tenant = TenantService.get_join_tenants(account) - if not tenant and not FeatureService.get_system_features().is_allow_create_workspace: - tenant = TenantService.create_tenant(f"{account.name}'s Workspace") - TenantService.create_tenant_member(tenant, account, role="owner") - account.current_tenant = tenant - tenant_was_created.send(tenant) - else: - try: - account = AccountService.create_account_and_tenant( - email=reset_data.get("email", ""), - name=reset_data.get("email", ""), - password=password_confirm, - interface_language=languages[0], - ) - except WorkSpaceNotAllowedCreateError: - pass - except AccountRegisterError as are: - raise AccountInFreezeError() - - return {"result": "success"} - - -api.add_resource(ForgotPasswordSendEmailApi, "/forgot-password") -api.add_resource(ForgotPasswordCheckApi, "/forgot-password/validity") -api.add_resource(ForgotPasswordResetApi, "/forgot-password/resets") diff --git a/api/controllers/service_api/auth/login.py b/api/controllers/service_api/auth/login.py index ea981e0153..9ac6bf9e69 100644 --- a/api/controllers/service_api/auth/login.py +++ b/api/controllers/service_api/auth/login.py @@ -10,13 +10,10 @@ from constants.languages import languages from controllers.service_api import api from controllers.service_api.auth.error import ( EmailCodeError, - EmailOrPasswordMismatchError, - EmailPasswordLoginLimitError, InvalidEmailError, InvalidTokenError, ) from controllers.service_api.error import ( - AccountBannedError, AccountInFreezeError, AccountNotFound, EmailSendIpLimitError, @@ -33,104 +30,6 @@ from services.errors.workspace import WorkSpaceNotAllowedCreateError from services.feature_service import FeatureService -# TODO: copy as a separate auth service api -class LoginApi(Resource): - """Resource for user login.""" - - def post(self): - """Authenticate user and login. - --- - summary: User Login - description: Authenticate user with the provided email, password and optional invite token. - parameters: - - in: body - name: email - required: true - type: string - description: The user's email. - - in: body - name: password - required: true - type: string - description: The user's password. - - in: body - name: remember_me - required: false - type: boolean - description: Flag to indicate persistent login. - - in: body - name: invite_token - required: false - type: string - description: Invitation token if available. - - in: body - name: language - required: false - type: string - description: Interface language for response. - responses: - 200: - description: Success, returns token pair data. - 401: - description: Login failed due to invalid credentials or rate limits. - """ - parser = reqparse.RequestParser() - parser.add_argument("email", type=email, required=True, location="json") - parser.add_argument("password", type=valid_password, required=True, location="json") - parser.add_argument("remember_me", type=bool, required=False, default=False, location="json") - parser.add_argument("invite_token", type=str, required=False, default=None, location="json") - parser.add_argument("language", type=str, required=False, default="en-US", location="json") - args = parser.parse_args() - - if dify_config.BILLING_ENABLED and BillingService.is_email_in_freeze(args["email"]): - raise AccountInFreezeError() - - is_login_error_rate_limit = AccountService.is_login_error_rate_limit(args["email"]) - if is_login_error_rate_limit: - raise EmailPasswordLoginLimitError() - - invitation = args["invite_token"] - if invitation: - invitation = RegisterService.get_invitation_if_token_valid(None, args["email"], invitation) - - if args["language"] is not None and args["language"] == "zh-Hans": - language = "zh-Hans" - else: - language = "en-US" - - try: - if invitation: - data = invitation.get("data", {}) - invitee_email = data.get("email") if data else None - if invitee_email != args["email"]: - raise InvalidEmailError() - account = AccountService.authenticate(args["email"], args["password"], args["invite_token"]) - else: - account = AccountService.authenticate(args["email"], args["password"]) - except services.errors.account.AccountLoginError: - raise AccountBannedError() - except services.errors.account.AccountPasswordError: - AccountService.add_login_error_rate_limit(args["email"]) - raise EmailOrPasswordMismatchError() - except services.errors.account.AccountNotFoundError: - if FeatureService.get_system_features().is_allow_register: - token = AccountService.send_reset_password_email(email=args["email"], language=language) - return {"result": "fail", "data": token, "code": "account_not_found"} - else: - raise AccountNotFound() - # SELF_HOSTED only have one workspace - tenants = TenantService.get_join_tenants(account) - if len(tenants) == 0: - return { - "result": "fail", - "data": "workspace not found, please contact system admin to invite you to join in a workspace", - } - - token_pair = AccountService.login(account=account, ip_address=extract_remote_ip(request)) - AccountService.reset_login_error_rate_limit(args["email"]) - return {"result": "success", "data": token_pair.model_dump()} - - class LogoutApi(Resource): def get(self): """Logout user. @@ -149,53 +48,6 @@ class LogoutApi(Resource): return {"result": "success"} -class ResetPasswordSendEmailApi(Resource): - def post(self): - """Send reset password email. - --- - summary: Send Reset Password Email - description: Sends a reset password email to the provided email address. - parameters: - - in: body - name: email - required: true - type: string - description: The user's email. - - in: body - name: language - required: false - type: string - description: Preferred language for the email. - responses: - 200: - description: Successfully sent the reset email with token data. - 404: - description: Account not found. - """ - parser = reqparse.RequestParser() - parser.add_argument("email", type=email, required=True, location="json") - parser.add_argument("language", type=str, required=False, location="json") - args = parser.parse_args() - - if args["language"] is not None and args["language"] == "zh-Hans": - language = "zh-Hans" - else: - language = "en-US" - try: - account = AccountService.get_user_through_email(args["email"]) - except AccountRegisterError as are: - raise AccountInFreezeError() - if account is None: - if FeatureService.get_system_features().is_allow_register: - token = AccountService.send_reset_password_email(email=args["email"], language=language) - else: - raise AccountNotFound() - else: - token = AccountService.send_reset_password_email(account=account, language=language) - - return {"result": "success", "data": token} - - class EmailCodeLoginSendEmailApi(Resource): def post(self): """Send email code for login. @@ -355,9 +207,7 @@ class RefreshTokenApi(Resource): return {"result": "fail", "data": str(e)}, 401 -api.add_resource(LoginApi, "/login") api.add_resource(LogoutApi, "/logout") api.add_resource(EmailCodeLoginSendEmailApi, "/email-code-login") api.add_resource(EmailCodeLoginApi, "/email-code-login/validity") -api.add_resource(ResetPasswordSendEmailApi, "/reset-password") api.add_resource(RefreshTokenApi, "/refresh-token") diff --git a/api/controllers/service_api/auth/signup.py b/api/controllers/service_api/auth/signup.py deleted file mode 100644 index 75fafc3dd0..0000000000 --- a/api/controllers/service_api/auth/signup.py +++ /dev/null @@ -1,122 +0,0 @@ -from flask import request -from flask_restful import Resource, reqparse # type: ignore - -from configs import dify_config -from constants.languages import languages -from controllers.service_api import api -from controllers.service_api.error import ( - AccountBannedError, - AccountInFreezeError, - EmailSendIpLimitError, - NotAllowedCreateWorkspace, -) -from events.tenant_event import tenant_was_created -from libs.helper import email, extract_remote_ip -from libs.password import valid_password -from services.account_service import AccountService, TenantService -from services.billing_service import BillingService -from services.errors.account import AccountRegisterError -from services.errors.workspace import WorkSpaceNotAllowedCreateError -from services.feature_service import FeatureService - - -class SignupApi(Resource): - def post(self): - """User Signup API endpoint - This endpoint handles new user registration. - --- - parameters: - - name: body - in: body - required: true - schema: - $ref: '#/definitions/SignupRequest' - definitions: - SignupRequest: - type: object - required: - - email - - password - - name - properties: - email: - type: string - format: email - example: user@example.com - password: - type: string - format: password - example: StrongP@ssw0rd - name: - type: string - example: John Doe - language: - type: string - default: en-US - example: en-US - TokenPair: - type: object - properties: - access_token: - type: string - refresh_token: - type: string - responses: - 200: - description: Successfully registered and logged in - schema: - type: object - properties: - result: - type: string - example: success - data: - $ref: '#/definitions/TokenPair' - 400: - description: Registration failed due to validation errors - 403: - description: Registration not allowed or account banned - """ - parser = reqparse.RequestParser() - parser.add_argument("email", type=email, required=True, location="json") - parser.add_argument("password", type=valid_password, required=True, location="json") - parser.add_argument("name", type=str, required=True, location="json") - parser.add_argument("language", type=str, required=False, default="en-US", location="json") - args = parser.parse_args() - - if dify_config.BILLING_ENABLED and BillingService.is_email_in_freeze(args["email"]): - raise AccountInFreezeError() - - if not FeatureService.get_system_features().is_allow_register: - raise NotAllowedCreateWorkspace() - - ip_address = extract_remote_ip(request) - if AccountService.is_email_send_ip_limit(ip_address): - raise EmailSendIpLimitError() - - try: - # Create account and tenant - account = AccountService.create_account_and_tenant( - email=args["email"], - name=args["name"], - password=args["password"], - interface_language=args["language"] if args["language"] in languages else languages[0] - ) - - # Create default tenant - tenant = TenantService.create_tenant(f"{account.name}'s Workspace") - TenantService.create_tenant_member(tenant, account, role="owner") - account.current_tenant = tenant - tenant_was_created.send(tenant) - - # Login the user - token_pair = AccountService.login(account=account, ip_address=ip_address) - return {"result": "success", "data": token_pair.model_dump()} - - except WorkSpaceNotAllowedCreateError: - raise NotAllowedCreateWorkspace() - except AccountRegisterError: - raise AccountBannedError() - - -api.add_resource(SignupApi, "/signup") \ No newline at end of file