Browse Source

Merge pull request #175 from qor5/login-more-hooky

Login more hooky
xuxinx 1 year ago
parent
commit
08921dc77b
2 changed files with 64 additions and 61 deletions
  1. 50 57
      login/builder.go
  2. 14 4
      login/example/main.go

+ 50 - 57
login/builder.go

@@ -36,9 +36,7 @@ var (
 )
 
 type HomeURLFunc func(r *http.Request, user interface{}) string
-type NotifyUserOfResetPasswordLinkFunc func(user interface{}, resetLink string) error
-type PasswordValidationFunc func(password string) (message string, ok bool)
-type HookFunc func(r *http.Request, user interface{}, vals ...interface{}) error
+type HookFunc func(r *http.Request, user interface{}, extraVals ...interface{}) error
 
 type void struct{}
 
@@ -109,19 +107,18 @@ type Builder struct {
 	totpSetupPageFunc             web.PageFunc
 	totpValidatePageFunc          web.PageFunc
 
-	notifyUserOfResetPasswordLinkFunc NotifyUserOfResetPasswordLinkFunc
-	passwordValidationFunc            PasswordValidationFunc
+	beforeSetPasswordHook HookFunc
 
-	afterLoginHook                 HookFunc
-	afterFailedToLoginHook         HookFunc
-	afterUserLockedHook            HookFunc
-	afterLogoutHook                HookFunc
-	afterSendResetPasswordLinkHook HookFunc
-	afterResetPasswordHook         HookFunc
-	afterChangePasswordHook        HookFunc
-	afterExtendSessionHook         HookFunc
-	afterTOTPCodeReusedHook        HookFunc
-	afterOAuthCompleteHook         HookFunc
+	afterLoginHook                        HookFunc
+	afterFailedToLoginHook                HookFunc
+	afterUserLockedHook                   HookFunc
+	afterLogoutHook                       HookFunc
+	afterConfirmSendResetPasswordLinkHook HookFunc
+	afterResetPasswordHook                HookFunc
+	afterChangePasswordHook               HookFunc
+	afterExtendSessionHook                HookFunc
+	afterTOTPCodeReusedHook               HookFunc
+	afterOAuthCompleteHook                HookFunc
 
 	db                   *gorm.DB
 	userModel            interface{}
@@ -293,29 +290,26 @@ func (b *Builder) TOTPValidatePageFunc(v web.PageFunc) (r *Builder) {
 	return b
 }
 
-func (b *Builder) NotifyUserOfResetPasswordLinkFunc(v NotifyUserOfResetPasswordLinkFunc) (r *Builder) {
-	b.notifyUserOfResetPasswordLinkFunc = v
-	return b
-}
-
-func (b *Builder) PasswordValidationFunc(v PasswordValidationFunc) (r *Builder) {
-	b.passwordValidationFunc = v
-	return b
-}
-
 func (b *Builder) wrapHook(v HookFunc) HookFunc {
 	if v == nil {
 		return nil
 	}
 
-	return func(r *http.Request, user interface{}, vals ...interface{}) error {
+	return func(r *http.Request, user interface{}, extraVals ...interface{}) error {
 		if GetCurrentUser(r) == nil {
 			r = r.WithContext(context.WithValue(r.Context(), UserKey, user))
 		}
-		return v(r, user, vals...)
+		return v(r, user, extraVals...)
 	}
 }
 
+// extra vals:
+// - password
+func (b *Builder) BeforeSetPassword(v HookFunc) (r *Builder) {
+	b.beforeSetPasswordHook = b.wrapHook(v)
+	return b
+}
+
 func (b *Builder) AfterLogin(v HookFunc) (r *Builder) {
 	b.afterLoginHook = b.wrapHook(v)
 	return b
@@ -336,8 +330,10 @@ func (b *Builder) AfterLogout(v HookFunc) (r *Builder) {
 	return b
 }
 
-func (b *Builder) AfterSendResetPasswordLink(v HookFunc) (r *Builder) {
-	b.afterSendResetPasswordLinkHook = b.wrapHook(v)
+// extra vals:
+// - reset link
+func (b *Builder) AfterConfirmSendResetPasswordLink(v HookFunc) (r *Builder) {
+	b.afterConfirmSendResetPasswordLinkHook = b.wrapHook(v)
 	return b
 }
 
@@ -351,7 +347,7 @@ func (b *Builder) AfterChangePassword(v HookFunc) (r *Builder) {
 	return b
 }
 
-// vals:
+// extra vals:
 // - old session token
 func (b *Builder) AfterExtendSession(v HookFunc) (r *Builder) {
 	b.afterExtendSessionHook = b.wrapHook(v)
@@ -1006,17 +1002,8 @@ func (b *Builder) sendResetPasswordLink(w http.ResponseWriter, r *http.Request)
 	if doTOTP {
 		link = MustSetQuery(link, "totp", "1")
 	}
-	if err = b.notifyUserOfResetPasswordLinkFunc(u, link); err != nil {
-		setFailCodeFlash(w, FailCodeSystemError)
-		setWrongForgetPasswordInputFlash(w, WrongForgetPasswordInputFlash{
-			Account: account,
-		})
-		http.Redirect(w, r, failRedirectURL, http.StatusFound)
-		return
-	}
-
-	if b.afterSendResetPasswordLinkHook != nil {
-		if herr := b.afterSendResetPasswordLinkHook(r, u); herr != nil {
+	if b.afterConfirmSendResetPasswordLinkHook != nil {
+		if herr := b.afterConfirmSendResetPasswordLinkHook(r, u, link); herr != nil {
 			setFailCodeFlash(w, FailCodeSystemError)
 			http.Redirect(w, r, failRedirectURL, http.StatusFound)
 			return
@@ -1069,18 +1056,6 @@ func (b *Builder) doResetPassword(w http.ResponseWriter, r *http.Request) {
 		http.Redirect(w, r, failRedirectURL, http.StatusFound)
 		return
 	}
-	if b.passwordValidationFunc != nil {
-		msg, ok := b.passwordValidationFunc(password)
-		if !ok {
-			setCustomErrorMessageFlash(w, msg)
-			setWrongResetPasswordInputFlash(w, WrongResetPasswordInputFlash{
-				Password:        password,
-				ConfirmPassword: confirmPassword,
-			})
-			http.Redirect(w, r, failRedirectURL, http.StatusFound)
-			return
-		}
-	}
 
 	u, err := b.findUserByID(userID)
 	if err != nil {
@@ -1105,6 +1080,24 @@ func (b *Builder) doResetPassword(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
+	if b.beforeSetPasswordHook != nil {
+		if herr := b.beforeSetPasswordHook(r, u, password); herr != nil {
+			verr, ok := herr.(*ValidationError)
+			if !ok {
+				setFailCodeFlash(w, FailCodeSystemError)
+				http.Redirect(w, r, failRedirectURL, http.StatusFound)
+				return
+			}
+			setCustomErrorMessageFlash(w, verr.Msg)
+			setWrongResetPasswordInputFlash(w, WrongResetPasswordInputFlash{
+				Password:        password,
+				ConfirmPassword: confirmPassword,
+			})
+			http.Redirect(w, r, failRedirectURL, http.StatusFound)
+			return
+		}
+	}
+
 	if u.(UserPasser).GetIsTOTPSetup() {
 		if !doTOTP {
 			setWrongResetPasswordInputFlash(w, WrongResetPasswordInputFlash{
@@ -1189,10 +1182,10 @@ func (b *Builder) ChangePassword(
 	if confirmPassword != password {
 		return ErrPasswordNotMatch
 	}
-	if b.passwordValidationFunc != nil {
-		msg, ok := b.passwordValidationFunc(password)
-		if !ok {
-			return &ValidationError{Msg: msg}
+
+	if b.beforeSetPasswordHook != nil {
+		if herr := b.beforeSetPasswordHook(r, user, password); herr != nil {
+			return herr
 		}
 	}
 

+ 14 - 4
login/example/main.go

@@ -6,10 +6,10 @@ import (
 	"net/http"
 	"os"
 
-	"github.com/qor5/x/i18n"
-	"github.com/qor5/x/login"
 	"github.com/markbates/goth/providers/google"
 	"github.com/markbates/goth/providers/twitter"
+	"github.com/qor5/x/i18n"
+	"github.com/qor5/x/login"
 	. "github.com/theplant/htmlgo"
 	"github.com/theplant/testingutils"
 	"golang.org/x/text/language"
@@ -67,9 +67,19 @@ func main() {
 		HomeURLFunc(func(r *http.Request, user interface{}) string {
 			return "/admin"
 		}).
-		NotifyUserOfResetPasswordLinkFunc(func(user interface{}, resetLink string) error {
+		BeforeSetPassword(func(r *http.Request, user interface{}, extraVals ...interface{}) error {
+			password := extraVals[0].(string)
+			if len(password) <= 2 {
+				return &login.ValidationError{
+					Msg: "password length cannot be less than 2",
+				}
+			}
+			return nil
+		}).
+		AfterConfirmSendResetPasswordLink(func(r *http.Request, user interface{}, extraVals ...interface{}) error {
+			link := extraVals[0]
 			fmt.Println("#########################################start")
-			testingutils.PrintlnJson(resetLink)
+			testingutils.PrintlnJson(link)
 			fmt.Println("#########################################end")
 			return nil
 		})