Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/070 user signup email verification #73

Closed
wants to merge 23 commits into from
Closed
Changes from 1 commit
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
f16c573
updated user login function to use secrets instead if random and hash…
abbastoof Aug 16, 2024
f67d545
added check_secret 'X-SERVICE-SECRET' to token-service, commented log…
abbastoof Aug 16, 2024
7e6d7bf
Merge branch 'fix/071-fix-security-issue-in-backend' of github.com:ab…
abbastoof Aug 16, 2024
a44eba3
changed otp to char field in userprofilemodel, added three functions …
abbastoof Aug 16, 2024
b5fb47d
changed email field to onetoonefield and created a confiremail model,…
abbastoof Aug 17, 2024
8c6b3f6
handled email_obj verify_status in user registration views functions,…
abbastoof Aug 17, 2024
8406505
updated readme with 2fa urls and instructions
abbastoof Aug 17, 2024
30a73ef
removed rabbitmq from backend
mtoof Aug 17, 2024
cc6a5e9
updated readme line 48 changed put to patch
mtoof Aug 17, 2024
5042002
Added available_username_email to views.py and handled error handling…
abbastoof Aug 18, 2024
a49e73b
removed models related to chat and notifications
abbastoof Aug 18, 2024
ca75223
Delete Backend/user_service/user_service/user_app/PersonalChatConsume…
abbastoof Aug 18, 2024
828e297
Delete Backend/user_service/user_service/user_app/NotificationConsume…
abbastoof Aug 18, 2024
0093fb6
updated readme and fixed typo error 'user/login/verifyotp/' in line 75
mtoof Aug 19, 2024
d1ad5c1
fixed first condition of available_username_email funtion from "and" …
Aug 20, 2024
6ac3e01
added specific response messages for username and email in lines 275-280
mtoof Aug 20, 2024
10cfcd7
added test_user_register and test_users_list to the test_user_service.py
abbastoof Aug 21, 2024
1070616
added handle_email to user_update and delete the prev email after upd…
Aug 21, 2024
0890e1a
fixed all tests for user-service
Aug 22, 2024
934c203
feat(token_service): add user ID validation and token refresh logic
Aug 22, 2024
82eecc6
modified validate_token_for_user in token-sevice to receive token fro…
Aug 23, 2024
0019584
changed status_code in lines 170,174,213, 215 to 200_OK
Aug 23, 2024
5a88255
updated readme for verify-token and refresh-token
Aug 23, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
handled email_obj verify_status in user registration views functions,…
… modified email related name in models,fixed user-login and verify otp in user_session_views.py
  • Loading branch information
abbastoof committed Aug 17, 2024
commit 8c6b3f60f2f8399af5e5bd8e4a7ffe32ac2330bb
2 changes: 1 addition & 1 deletion Backend/user_service/user_service/user_app/models.py
Original file line number Diff line number Diff line change
@@ -28,7 +28,7 @@ class UserProfileModel(AbstractUser):

Email: The email field is required for the user model.
"""
email = models.OneToOneField(ConfirmEmail, related_name='user_profile', on_delete=models.CASCADE)
email = models.OneToOneField(ConfirmEmail, related_name='user_profile_email', on_delete=models.CASCADE)
avatar = models.ImageField(upload_to=user_directory_path, null=True, blank=True, default='default.jpg')
friends = models.ManyToManyField("self", blank=True, symmetrical=True)
online_status = models.BooleanField(default=False)
113 changes: 63 additions & 50 deletions Backend/user_service/user_service/user_app/user_session_views.py
Original file line number Diff line number Diff line change
@@ -33,19 +33,16 @@ def generate_secret():
class UserLoginView(viewsets.ViewSet):
permission_classes = [AllowAny]

def send_email(self, user):
def send_email(self, email, otp):
send_mail(
'Verification Code',
f'Your verification code is: {user.otp}',
f'Your verification code is: {otp}',
settings.EMAIL_HOST_USER,
[user.email],
[email],
fail_silently=False,
)

def authenticate_user(self, request):
username = request.data.get("username")
password = request.data.get("password")

def authenticate_user(self, request, username, password):
if username and password:
user = authenticate(username=username, password=password)
if user is not None:
@@ -56,33 +53,39 @@ def login(self, request):
status_code = status.HTTP_200_OK
response = {}
response_message = {}
user = self.authenticate_user(request)
if user is not None:
if user.is_active:
serializer = UserSerializer(user)
# send post request to token-service
if user.otp_status:
otp = generate_secret()
user.otp = make_password(otp)
user.otp_expiry_time = now() + timedelta(minutes=1)
user.save()
self.send_email(user)
response_message = {"detail":"Verification password sent to your email"}
status_code = status.HTTP_200_OK
username = request.data.get("username")
password = request.data.get("password")
if username and password:
user = self.authenticate_user(request, username, password)
if user is not None:
if user.is_active:
serializer = UserSerializer(user)
if user.otp_status:
otp = generate_secret()
user.otp = make_password(str(otp))
user.otp_expiry_time = now() + timedelta(minutes=3)
user.save()
logger.info('user email = %s', serializer.data["email"])
self.send_email(serializer.data["email"], otp)
response_message = {"detail":"Verification password sent to your email"}
status_code = status.HTTP_200_OK
else:
data = {"id": serializer.data["id"], "username": serializer.data["username"]}
response = requests.post(f"{TOEKNSERVICE}/auth/token/gen-tokens/", data=data, headers=headers)
if response.status_code == 201:
response_message = response.json()
# logger.info('user_data = %s', response.json())
if "error" in response_message:
status_code = response_message.get("status_code")
response_message = response.json()
else:
data = {"id": serializer.data["id"], "username": serializer.data["username"]}
response = requests.post(f"{TOEKNSERVICE}/auth/token/gen-tokens/", data=data, headers=headers)
if response.status_code == 201:
response_message = response.json()
# logger.info('user_data = %s', response.json())
if "error" in response_message:
status_code = response_message.get("status_code")
response_message = response.json()
response_message = {"error": "User is Inactive"}
status_code = status.HTTP_401_UNAUTHORIZED
else:
response_message = {"detail": "User is Inactive"}
status_code = status.HTTP_401_UNAUTHORIZED
response_message = {"error": "Invalid username or password"}
status_code = status.HTTP_400_BAD_REQUEST
else:
response_message = {"detail": "Invalid username or password"}
response_message = {"error": "username and password fields are required"}
status_code = status.HTTP_400_BAD_REQUEST
return Response(response_message, status=status_code)

@@ -91,31 +94,41 @@ def verify_otp(self, request):
status_code = status.HTTP_200_OK
response = {}
response_message = {}
user = self.authenticate_user(request)
if user is not None:
if user.otp_status:
if user.otp == otp:
if user.otp_expiry_time > now():
data = {"id": user.id, "username": username}
response = requests.post(f'{TOEKNSERVICE}/auth/token/gen-tokens/', data=data, headers=headers)
user.otp = None
user.otp_expiry_time = None
if response.status_code == 201:
response_message = response.json()
# logger.info('user_data = %s', response_message)
if "error" in response_message:
status_code = response_message.get("status_code")
username = request.data.get("username")
password = request.data.get("password")
otp = request.data.get("otp")
if username and password and otp:
user = self.authenticate_user(request, username, password)
if user is not None:
if user.otp_status:
if check_password(str(otp), user.otp):
if user.otp_expiry_time > now():
data = {"id": user.id, "username": username}
response = requests.post(f'{TOEKNSERVICE}/auth/token/gen-tokens/', data=data, headers=headers)
if response.status_code == 201:
response_message = response.json()
user.otp = None
user.otp_expiry_time = None
# logger.info('user_data = %s', response_message)
if "error" in response_message:
status_code = response_message.get("status_code")
else:
status_code = status.HTTP_200_OK
else:
status_code = status.HTTP_200_OK
response_message = {"error":"expired code"}
status_code = status.HTTP_401_UNAUTHORIZED
else:
response_message = {"error":"expired password"}
response_message = {"error":"Invalid code"}
status_code = status.HTTP_401_UNAUTHORIZED
else:
response_message = {"error":"Invalid password"}
status_code = status.HTTP_401_UNAUTHORIZED
response_message = {"error":"You have not enable 2FA yet!"}
status_code = status.HTTP_400_BAD_REQUEST
else:
response_message = {"error":"You have not enable 2FA yet!"}
response_message = {"error": "Invalid username or password"}
status_code = status.HTTP_400_BAD_REQUEST
else:
response_message = {"error": "username, password and otp fields are required"}
status_code = status.HTTP_400_BAD_REQUEST
return Response(response_message, status=status_code)

class UserLogoutView(viewsets.ViewSet):
42 changes: 26 additions & 16 deletions Backend/user_service/user_service/user_app/views.py
Original file line number Diff line number Diff line change
@@ -201,12 +201,16 @@ def send_email_otp(self, request) -> Response:
if email is not None:
try:
email_obj, create = ConfirmEmail.objects.get_or_create(user_email=email)
otp = generate_secret()
email_obj.otp = make_password(str(otp))
email_obj.otp_expiry_time = now() + timedelta(minutes=1)
email_obj.save()
self.send_email(email_obj.user_email, otp)
response_message = {"detail":"Email verification code sent to your email"}
if email_obj.verify_status == False:
otp = generate_secret()
email_obj.otp = make_password(str(otp))
email_obj.otp_expiry_time = now() + timedelta(minutes=3)
email_obj.save()
self.send_email(email_obj.user_email, otp)
response_message = {"detail":"Email verification code sent to your email"}
else:
response_message = {"error": "This email already verified."}
status_code = status.HTTP_401_UNAUTHORIZED
except Exception as err:
response_message = {"error": str(err)}
status_code = status.HTTP_400_BAD_REQUEST
@@ -228,6 +232,7 @@ def verify_email_otp(self, request) -> Response:
response_message = {"detail":"Email verified"}
email_obj.otp = None
email_obj.otp_expiry_time = None
email_obj.verify_status = True
email_obj.save()
else:
response_message = {"error":"otp expired"}
@@ -260,16 +265,21 @@ def create_user(self, request) -> Response:
email = request.data.get("email")
email_obj = get_object_or_404(ConfirmEmail, user_email = email)
if email_obj is not None:
serializer = UserSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
response_message = serializer.data
if serializer.errors:
data = serializer.errors
if "email" in data:
data["email"] = ["A user with that email already exists."]
response_message = {"error":data},
status_code=status.HTTP_400_BAD_REQUEST
if email_obj.verify_status:
serializer = UserSerializer(data=request.data)
if serializer.is_valid():
serializer.validated_data["email"] = email_obj
serializer.save()
response_message = serializer.data
if serializer.errors:
data = serializer.errors
if "email" in data:
data["email"] = ["A user with that email already exists."]
response_message = {"error":data},
status_code=status.HTTP_400_BAD_REQUEST
else:
response_message = {"error": "You have not confirmed your email yet!"},
status_code=status.HTTP_401_UNAUTHORIZED
except Http404:
response_message = {"error": "You have not verified your email yet!"}
status_code = status.HTTP_401_UNAUTHORIZED
Loading