mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
fix: email validation (#4707)
* fix: email validation on complete login or sign up functionality * dev: add try catch block * dev: split up code * dev: empty return
This commit is contained in:
parent
52d8d6e7ce
commit
249e71e424
@ -4,6 +4,8 @@ import uuid
|
|||||||
|
|
||||||
# Django imports
|
# Django imports
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
from django.core.validators import validate_email
|
||||||
|
from django.core.exceptions import ValidationError
|
||||||
|
|
||||||
# Third party imports
|
# Third party imports
|
||||||
from zxcvbn import zxcvbn
|
from zxcvbn import zxcvbn
|
||||||
@ -46,68 +48,71 @@ class Adapter:
|
|||||||
def authenticate(self):
|
def authenticate(self):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def complete_login_or_signup(self):
|
def sanitize_email(self, email):
|
||||||
email = self.user_data.get("email")
|
# Check if email is present
|
||||||
user = User.objects.filter(email=email).first()
|
if not email:
|
||||||
# Check if sign up case or login
|
|
||||||
is_signup = bool(user)
|
|
||||||
if not user:
|
|
||||||
# New user
|
|
||||||
(ENABLE_SIGNUP,) = get_configuration_value(
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"key": "ENABLE_SIGNUP",
|
|
||||||
"default": os.environ.get("ENABLE_SIGNUP", "1"),
|
|
||||||
},
|
|
||||||
]
|
|
||||||
)
|
|
||||||
if (
|
|
||||||
ENABLE_SIGNUP == "0"
|
|
||||||
and not WorkspaceMemberInvite.objects.filter(
|
|
||||||
email=email,
|
|
||||||
).exists()
|
|
||||||
):
|
|
||||||
raise AuthenticationException(
|
|
||||||
error_code=AUTHENTICATION_ERROR_CODES["SIGNUP_DISABLED"],
|
|
||||||
error_message="SIGNUP_DISABLED",
|
|
||||||
payload={"email": email},
|
|
||||||
)
|
|
||||||
user = User(email=email, username=uuid.uuid4().hex)
|
|
||||||
|
|
||||||
if self.user_data.get("user").get("is_password_autoset"):
|
|
||||||
user.set_password(uuid.uuid4().hex)
|
|
||||||
user.is_password_autoset = True
|
|
||||||
user.is_email_verified = True
|
|
||||||
else:
|
|
||||||
# Validate password
|
|
||||||
results = zxcvbn(self.code)
|
|
||||||
if results["score"] < 3:
|
|
||||||
raise AuthenticationException(
|
|
||||||
error_code=AUTHENTICATION_ERROR_CODES[
|
|
||||||
"INVALID_PASSWORD"
|
|
||||||
],
|
|
||||||
error_message="INVALID_PASSWORD",
|
|
||||||
payload={"email": email},
|
|
||||||
)
|
|
||||||
|
|
||||||
user.set_password(self.code)
|
|
||||||
user.is_password_autoset = False
|
|
||||||
|
|
||||||
avatar = self.user_data.get("user", {}).get("avatar", "")
|
|
||||||
first_name = self.user_data.get("user", {}).get("first_name", "")
|
|
||||||
last_name = self.user_data.get("user", {}).get("last_name", "")
|
|
||||||
user.avatar = avatar if avatar else ""
|
|
||||||
user.first_name = first_name if first_name else ""
|
|
||||||
user.last_name = last_name if last_name else ""
|
|
||||||
user.save()
|
|
||||||
Profile.objects.create(user=user)
|
|
||||||
|
|
||||||
if not user.is_active:
|
|
||||||
raise AuthenticationException(
|
raise AuthenticationException(
|
||||||
AUTHENTICATION_ERROR_CODES["USER_ACCOUNT_DEACTIVATED"],
|
error_code=AUTHENTICATION_ERROR_CODES["INVALID_EMAIL"],
|
||||||
error_message="USER_ACCOUNT_DEACTIVATED",
|
error_message="INVALID_EMAIL",
|
||||||
|
payload={"email": email},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Sanitize email
|
||||||
|
email = str(email).lower().strip()
|
||||||
|
|
||||||
|
# validate email
|
||||||
|
try:
|
||||||
|
validate_email(email)
|
||||||
|
except ValidationError:
|
||||||
|
raise AuthenticationException(
|
||||||
|
error_code=AUTHENTICATION_ERROR_CODES["INVALID_EMAIL"],
|
||||||
|
error_message="INVALID_EMAIL",
|
||||||
|
payload={"email": email},
|
||||||
|
)
|
||||||
|
# Return email
|
||||||
|
return email
|
||||||
|
|
||||||
|
def validate_password(self, email):
|
||||||
|
"""Validate password strength"""
|
||||||
|
results = zxcvbn(self.code)
|
||||||
|
if results["score"] < 3:
|
||||||
|
raise AuthenticationException(
|
||||||
|
error_code=AUTHENTICATION_ERROR_CODES["INVALID_PASSWORD"],
|
||||||
|
error_message="INVALID_PASSWORD",
|
||||||
|
payload={"email": email},
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
def __check_signup(self, email):
|
||||||
|
"""Check if sign up is enabled or not and raise exception if not enabled"""
|
||||||
|
|
||||||
|
# Get configuration value
|
||||||
|
(ENABLE_SIGNUP,) = get_configuration_value(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"key": "ENABLE_SIGNUP",
|
||||||
|
"default": os.environ.get("ENABLE_SIGNUP", "1"),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
# Check if sign up is disabled and invite is present or not
|
||||||
|
if (
|
||||||
|
ENABLE_SIGNUP == "0"
|
||||||
|
and not WorkspaceMemberInvite.objects.filter(
|
||||||
|
email=email,
|
||||||
|
).exists()
|
||||||
|
):
|
||||||
|
# Raise exception
|
||||||
|
raise AuthenticationException(
|
||||||
|
error_code=AUTHENTICATION_ERROR_CODES["SIGNUP_DISABLED"],
|
||||||
|
error_message="SIGNUP_DISABLED",
|
||||||
|
payload={"email": email},
|
||||||
|
)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def save_user_data(self, user):
|
||||||
# Update user details
|
# Update user details
|
||||||
user.last_login_medium = self.provider
|
user.last_login_medium = self.provider
|
||||||
user.last_active = timezone.now()
|
user.last_active = timezone.now()
|
||||||
@ -116,7 +121,63 @@ class Adapter:
|
|||||||
user.last_login_uagent = self.request.META.get("HTTP_USER_AGENT")
|
user.last_login_uagent = self.request.META.get("HTTP_USER_AGENT")
|
||||||
user.token_updated_at = timezone.now()
|
user.token_updated_at = timezone.now()
|
||||||
user.save()
|
user.save()
|
||||||
|
return user
|
||||||
|
|
||||||
|
def complete_login_or_signup(self):
|
||||||
|
# Get email
|
||||||
|
email = self.user_data.get("email")
|
||||||
|
|
||||||
|
# Sanitize email
|
||||||
|
email = self.sanitize_email(email)
|
||||||
|
|
||||||
|
# Check if the user is present
|
||||||
|
user = User.objects.filter(email=email).first()
|
||||||
|
# Check if sign up case or login
|
||||||
|
is_signup = bool(user)
|
||||||
|
# If user is not present, create a new user
|
||||||
|
if not user:
|
||||||
|
# New user
|
||||||
|
self.__check_signup(email)
|
||||||
|
|
||||||
|
# Initialize user
|
||||||
|
user = User(email=email, username=uuid.uuid4().hex)
|
||||||
|
|
||||||
|
# Check if password is autoset
|
||||||
|
if self.user_data.get("user").get("is_password_autoset"):
|
||||||
|
user.set_password(uuid.uuid4().hex)
|
||||||
|
user.is_password_autoset = True
|
||||||
|
user.is_email_verified = True
|
||||||
|
|
||||||
|
# Validate password
|
||||||
|
else:
|
||||||
|
# Validate password
|
||||||
|
self.validate_password(email)
|
||||||
|
# Set password
|
||||||
|
user.set_password(self.code)
|
||||||
|
user.is_password_autoset = False
|
||||||
|
|
||||||
|
# Set user details
|
||||||
|
avatar = self.user_data.get("user", {}).get("avatar", "")
|
||||||
|
first_name = self.user_data.get("user", {}).get("first_name", "")
|
||||||
|
last_name = self.user_data.get("user", {}).get("last_name", "")
|
||||||
|
user.avatar = avatar if avatar else ""
|
||||||
|
user.first_name = first_name if first_name else ""
|
||||||
|
user.last_name = last_name if last_name else ""
|
||||||
|
user.save()
|
||||||
|
|
||||||
|
# Create profile
|
||||||
|
Profile.objects.create(user=user)
|
||||||
|
|
||||||
|
if not user.is_active:
|
||||||
|
raise AuthenticationException(
|
||||||
|
AUTHENTICATION_ERROR_CODES["USER_ACCOUNT_DEACTIVATED"],
|
||||||
|
error_message="USER_ACCOUNT_DEACTIVATED",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Save user data
|
||||||
|
user = self.save_user_data(user=user)
|
||||||
|
|
||||||
|
# Call callback if present
|
||||||
if self.callback:
|
if self.callback:
|
||||||
self.callback(
|
self.callback(
|
||||||
user,
|
user,
|
||||||
@ -124,7 +185,9 @@ class Adapter:
|
|||||||
self.request,
|
self.request,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Create or update account if token data is present
|
||||||
if self.token_data:
|
if self.token_data:
|
||||||
self.create_update_account(user=user)
|
self.create_update_account(user=user)
|
||||||
|
|
||||||
|
# Return user
|
||||||
return user
|
return user
|
||||||
|
@ -58,6 +58,8 @@ AUTHENTICATION_ERROR_CODES = {
|
|||||||
"ADMIN_USER_DEACTIVATED": 5190,
|
"ADMIN_USER_DEACTIVATED": 5190,
|
||||||
# Rate limit
|
# Rate limit
|
||||||
"RATE_LIMIT_EXCEEDED": 5900,
|
"RATE_LIMIT_EXCEEDED": 5900,
|
||||||
|
# Unknown
|
||||||
|
"AUTHENTICATION_FAILED": 5999,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -81,11 +81,11 @@ class OauthAdapter(Adapter):
|
|||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
return response.json()
|
return response.json()
|
||||||
except requests.RequestException:
|
except requests.RequestException:
|
||||||
code = (
|
if self.provider == "google":
|
||||||
"GOOGLE_OAUTH_PROVIDER_ERROR"
|
code = "GOOGLE_OAUTH_PROVIDER_ERROR"
|
||||||
if self.provider == "google"
|
if self.provider == "github":
|
||||||
else "GITHUB_OAUTH_PROVIDER_ERROR"
|
code = "GITHUB_OAUTH_PROVIDER_ERROR"
|
||||||
)
|
|
||||||
raise AuthenticationException(
|
raise AuthenticationException(
|
||||||
error_code=AUTHENTICATION_ERROR_CODES[code],
|
error_code=AUTHENTICATION_ERROR_CODES[code],
|
||||||
error_message=str(code),
|
error_message=str(code),
|
||||||
|
Loading…
Reference in New Issue
Block a user