diff --git a/internal/auth/account/account_repository.go b/internal/auth/account/account_repository.go index 757c233..ee01416 100644 --- a/internal/auth/account/account_repository.go +++ b/internal/auth/account/account_repository.go @@ -178,7 +178,7 @@ func (r *AccountRepository) RedeemAccountVerificationToken(ctx context.Context, var verificationToken VerificationToken lastHour := time.Now().Add(-time.Hour) - result := tx.Preload("Account").Where("token = ? AND verified = ? AND created_at > ", token, false, lastHour).First(&verificationToken) + result := tx.Preload("Account").Where("uuid = ? AND verified = ? AND created_at > ?", token, false, lastHour).First(&verificationToken) if result.Error != nil { err := fmt.Errorf("seraching redeem account verification token %s: %w", token, result.Error) if errors.Is(result.Error, gorm.ErrRecordNotFound) { @@ -190,6 +190,11 @@ func (r *AccountRepository) RedeemAccountVerificationToken(ctx context.Context, verificationToken.Verified = true verificationToken.Account.Active = true saved := tx.Save(&verificationToken) + if saved.Error != nil { + return fmt.Errorf("deactivate token: %s: %w", token, result.Error) + } + + saved = tx.Save(verificationToken.Account) if saved.Error != nil { return fmt.Errorf("activating account by verification token %s: %w", token, result.Error) } @@ -224,7 +229,7 @@ func (r *AccountRepository) RedeemPassForgetToken(ctx context.Context, token str var verificationToken VerificationToken lastHour := time.Now().Add(-time.Hour) - result := tx.Preload("Account").Where("token = ? AND verified = ? AND created_at > ", token, false, lastHour).First(&verificationToken) + result := tx.Preload("Account").Where("uuid = ? AND verified = ? AND created_at > ?", token, false, lastHour).First(&verificationToken) if result.Error != nil { err := fmt.Errorf("seraching redeem pass forget token %s: %w", token, result.Error) if errors.Is(result.Error, gorm.ErrRecordNotFound) { diff --git a/internal/auth/account/account_service.go b/internal/auth/account/account_service.go index aa78905..0c175a3 100644 --- a/internal/auth/account/account_service.go +++ b/internal/auth/account/account_service.go @@ -16,7 +16,7 @@ import ( ) const activateAccountURLPath = "activateAccount" -const passwordForgetURLPath = "newPassword" +const passwordForgetURLPath = "forgotPassword" var ErrInvalidCredentials = errors.New("invalid credentials") var ErrAccountAlreadyExists = errors.New("account already exists") @@ -104,7 +104,8 @@ func (s *AccountService) sendVerificationMail(ctx context.Context, account *Acco return nil } - if err := s.mailSender.SendActivateAccountMail(account.User, account.Email, link); err != nil { + username, _ := instance.SplitUserId(account.User) + if err := s.mailSender.SendActivateAccountMail(username, account.Email, link); err != nil { return fmt.Errorf("sending verify email: %w", err) } @@ -137,7 +138,8 @@ func (s *AccountService) CreateForgotPasswordToken(ctx context.Context, email st link := s.instanceUrl.String() + "/" + passwordForgetURLPath + "/" + token.UUID - if err := s.mailSender.SendActivateAccountMail(account.User, account.Email, link); err != nil { + username, _ := instance.SplitUserId(account.User) + if err := s.mailSender.SendForgotPasswordMail(username, account.Email, link); err != nil { return fmt.Errorf("sending verify email for new password: %w", err) } diff --git a/internal/auth/handler/forgot_password.go b/internal/auth/handler/forgot_password.go index c31a675..d2c5435 100644 --- a/internal/auth/handler/forgot_password.go +++ b/internal/auth/handler/forgot_password.go @@ -9,7 +9,7 @@ import ( "golang.org/x/exp/slog" ) -func SendForgotPasswordEmail(accountService *account.AccountService) http.HandlerFunc { +func SendForgotPasswordMail(accountService *account.AccountService) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") @@ -20,7 +20,7 @@ func SendForgotPasswordEmail(accountService *account.AccountService) http.Handle } if err = accountService.CreateForgotPasswordToken(r.Context(), email); err != nil { - slog.Error("auth.SendForgotPasswordEmail:", "err", err) + slog.Error("auth.SendForgotPasswordMail:", "err", err) } w.WriteHeader(http.StatusCreated) diff --git a/internal/auth/router.go b/internal/auth/router.go index c35fe65..a3faf0d 100644 --- a/internal/auth/router.go +++ b/internal/auth/router.go @@ -11,7 +11,7 @@ func UseRoutes(router *mux.Router, accountService *account.AccountService) { router.HandleFunc("/authenticate", handler.Authentication(accountService)).Methods("POST") router.HandleFunc("/auth/login", handler.Login(accountService)).Methods("POST") router.HandleFunc("/auth/register", handler.Register(accountService)).Methods("POST") - router.HandleFunc("/auth/sendForgotPasswordEmail", handler.SendForgotPasswordEmail(accountService)).Methods("POST") + router.HandleFunc("/auth/sendForgotPasswordMail", handler.SendForgotPasswordMail(accountService)).Methods("POST") router.HandleFunc("/auth/updateForgotPassword", handler.UpdateForgotPassword(accountService)).Methods("PUT") router.HandleFunc("/auth/updatePassword", session.HttpMiddleware(accountService.GetConfig(), handler.UpdatePassword(accountService))).Methods("PUT") router.HandleFunc("/auth/deleteAccount", session.HttpMiddleware(accountService.GetConfig(), handler.DeleteAccount(accountService))).Methods("POST") diff --git a/internal/mail/template/forgot_password.html b/internal/mail/template/forgot_password.html index d82bc9f..a6f4b0b 100644 --- a/internal/mail/template/forgot_password.html +++ b/internal/mail/template/forgot_password.html @@ -114,7 +114,7 @@
-

Forgot Your Account Account

+

Forgot Password

Dear {{.User}}

Please click on the button below to change your password.

diff --git a/web/src/app/app-routing.module.ts b/web/src/app/app-routing.module.ts index 55c555e..f0cc4df 100644 --- a/web/src/app/app-routing.module.ts +++ b/web/src/app/app-routing.module.ts @@ -6,26 +6,31 @@ import {UserAccessGuard} from './guards/user-access-guard.service'; import {LoginComponent} from './pages/auth/login/login.component'; import {LobbyEntryComponent} from './pages/lobby-entry/lobby-entry.component'; import {AdminAccessGuard} from './guards/admin-access-guard.service'; -import {PasswordForgottenComponent} from './pages/auth/password-forgotten/password-forgotten.component'; + import {SignupComponent} from './pages/auth/signup/signup.component'; import {ActivateAccountComponent} from './pages/auth/activate-account/activate-account.component'; +import {ForgotPasswordComponent} from './pages/auth/forgot-password/forgot-password.component'; +import {ForgotPasswordMailComponent} from './pages/auth/forgot-password-mail/forgot-password-mail.component'; +import {UpdatePasswordComponent} from './pages/auth/update-password/update-password.component'; const routes: Routes = [ - {path: '', redirectTo: '/dashboard', pathMatch: 'full'}, - {path: 'dashboard', component: DashboardComponent, canActivate: [UserAccessGuard]}, - {path: 'admin/dashboard', component: AdminDashboardComponent, canActivate: [AdminAccessGuard]}, - {path: 'lobby/:spaceId/stream/:streamId', component: LobbyEntryComponent, canActivate: [UserAccessGuard]}, - {path: 'login', component: LoginComponent}, - {path: 'passwordForgotten', component: PasswordForgottenComponent}, - {path: 'signup', component: SignupComponent}, - {path: 'activateAccount/:token', component: ActivateAccountComponent} + {path: '', redirectTo: '/dashboard', pathMatch: 'full'}, + {path: 'dashboard', component: DashboardComponent, canActivate: [UserAccessGuard]}, + {path: 'admin/dashboard', component: AdminDashboardComponent, canActivate: [AdminAccessGuard]}, + {path: 'lobby/:spaceId/stream/:streamId', component: LobbyEntryComponent, canActivate: [UserAccessGuard]}, + {path: 'updatePassword', component: UpdatePasswordComponent, canActivate: [UserAccessGuard]}, + {path: 'login', component: LoginComponent}, + {path: 'forgotPasswordMail', component: ForgotPasswordMailComponent}, + {path: 'forgotPassword/:token', component: ForgotPasswordComponent}, + {path: 'signup', component: SignupComponent}, + {path: 'activateAccount/:token', component: ActivateAccountComponent} ]; @NgModule({ - imports: [ - RouterModule.forRoot(routes) - ], - exports: [RouterModule] + imports: [ + RouterModule.forRoot(routes) + ], + exports: [RouterModule] }) export class AppRoutingModule { } diff --git a/web/src/app/pages/auth/activate-account/activate-account.component.html b/web/src/app/pages/auth/activate-account/activate-account.component.html index 1c2fdba..c9a017b 100644 --- a/web/src/app/pages/auth/activate-account/activate-account.component.html +++ b/web/src/app/pages/auth/activate-account/activate-account.component.html @@ -1,6 +1,7 @@ -
- -

Activate Account!

+
+
+

Activate Account!

+

We activating your Account. Please wait a Moment!

diff --git a/web/src/app/pages/auth/activate-account/activate-account.component.scss b/web/src/app/pages/auth/activate-account/activate-account.component.scss index e69de29..8fecf4d 100644 --- a/web/src/app/pages/auth/activate-account/activate-account.component.scss +++ b/web/src/app/pages/auth/activate-account/activate-account.component.scss @@ -0,0 +1,15 @@ +* { + box-sizing: border-box; +} + +:host { + position: absolute; + left: 0; + right: 0; + margin-inline: auto; + width: fit-content; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; +} diff --git a/web/src/app/pages/auth/forgot-password/forgot-password.component.html b/web/src/app/pages/auth/forgot-password/forgot-password.component.html index 8ca24c8..a31a2c7 100644 --- a/web/src/app/pages/auth/forgot-password/forgot-password.component.html +++ b/web/src/app/pages/auth/forgot-password/forgot-password.component.html @@ -17,20 +17,19 @@

Change Password

-

At least one uppercase letter.

-

At least one lowercase letter.

-

At least one digit.

-

At least one special character.

-

At least 8 characters long.

+

At least one uppercase letter!

+

At least one lowercase letter!

+

At least one digit!

+

At least one special character!

+

At least 8 characters long!

- - +

Your original password is required!

-

Password does'nt match.

+

Password doesn't match!

diff --git a/web/src/app/pages/auth/login/login.component.html b/web/src/app/pages/auth/login/login.component.html index c878eba..d5f5748 100644 --- a/web/src/app/pages/auth/login/login.component.html +++ b/web/src/app/pages/auth/login/login.component.html @@ -26,7 +26,7 @@

Login

- You forget your Password? + You forget your Password?
diff --git a/web/src/app/pages/auth/signup/signup.component.html b/web/src/app/pages/auth/signup/signup.component.html index 1cc4316..bd58720 100644 --- a/web/src/app/pages/auth/signup/signup.component.html +++ b/web/src/app/pages/auth/signup/signup.component.html @@ -12,7 +12,7 @@

Create Account

User name is required!

-

User name must be at least 4 characters long.!

+

User name must be at least 4 characters long!

@@ -25,19 +25,19 @@

Create Account

-

At least one uppercase letter.

-

At least one lowercase letter.

-

At least one digit.

-

At least one special character.

-

At least 8 characters long.

+

At least one uppercase letter!

+

At least one lowercase letter!

+

At least one digit!

+

At least one special character!

+

At least 8 characters long!

- + -

Your original password is required!

-

Password does'nt match.

+

Password doesn't match!

diff --git a/web/src/app/pages/auth/update-password/update-password.component.html b/web/src/app/pages/auth/update-password/update-password.component.html index 56882c9..120040e 100644 --- a/web/src/app/pages/auth/update-password/update-password.component.html +++ b/web/src/app/pages/auth/update-password/update-password.component.html @@ -28,20 +28,20 @@

Change Password

-

At least one uppercase letter.

-

At least one lowercase letter.

-

At least one digit.

-

At least one special character.

-

At least 8 characters long.

+

At least one uppercase letter!

+

At least one lowercase letter!

+

At least one digit!

+

At least one special character!

+

At least 8 characters long!

- +

Your original password is required!

-

Password does'nt match.

+

Password doesn't match!

diff --git a/web/src/app/validators/password.validator.ts b/web/src/app/validators/password.validator.ts index 0101f32..0073e8c 100644 --- a/web/src/app/validators/password.validator.ts +++ b/web/src/app/validators/password.validator.ts @@ -5,7 +5,7 @@ export const PASSWORD_CONSTRAIN: RegExp = /^(?=[^A-Z]*[A-Z])(?=[^a-z]*[a-z])(?=\ const UPPERCASE_LETTER_CONSTRAIN: RegExp = /^(?=.*[A-Z])/; const LOWERCASE_LETTER_CONSTRAIN: RegExp = /(?=.*[a-z])/; const DIGIT_CONSTRAIN: RegExp = /(.*[0-9].*)/; -const SPECIAL_CHARACTER_CONSTRAIN: RegExp = /^(?=.*[!@#$%^&*])/; +const SPECIAL_CHARACTER_CONSTRAIN: RegExp = /^(?=.*[!@#$%^&*/-_:;+`´,'"(){}≠|?])/; const MIN_LENGTH_CONSTRAIN: RegExp = /.{8,}/; export class PasswordValidator { @@ -17,22 +17,22 @@ export class PasswordValidator { } public static uppercaseLetter(control: AbstractControl): ValidationErrors | null { - return !control?.value?.match(UPPERCASE_LETTER_CONSTRAIN) ? null : {uppercaseLetter: true}; + return control?.value?.match(UPPERCASE_LETTER_CONSTRAIN) ? null : {uppercaseLetter: true}; } public static lowercaseLetter(control: AbstractControl): ValidationErrors | null { - return !control?.value?.match(LOWERCASE_LETTER_CONSTRAIN) ? null : {lowercaseLetter: true}; + return control?.value?.match(LOWERCASE_LETTER_CONSTRAIN) ? null : {lowercaseLetter: true}; } public static digit(control: AbstractControl): ValidationErrors | null { - return !control?.value?.match(DIGIT_CONSTRAIN) ? null : {digit: true}; + return control?.value?.match(DIGIT_CONSTRAIN) ? null : {digit: true}; } public static specialCharacter(control: AbstractControl): ValidationErrors | null { - return !control?.value?.match(SPECIAL_CHARACTER_CONSTRAIN) ? null : {specialCharacter: true}; + return control?.value?.match(SPECIAL_CHARACTER_CONSTRAIN) ? null : {specialCharacter: true}; } public static minLength(control: AbstractControl): ValidationErrors | null { - return !control?.value?.match(MIN_LENGTH_CONSTRAIN) ? null : {minLength: true}; + return control?.value?.match(MIN_LENGTH_CONSTRAIN) ? null : {minLength: true}; } }