mirror of
				https://github.com/volatiletech/authboss.git
				synced 2025-10-30 23:47:59 +02:00 
			
		
		
		
	
							
								
								
									
										25
									
								
								auth/auth.go
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								auth/auth.go
									
									
									
									
									
								
							| @@ -14,9 +14,6 @@ const ( | ||||
| 	methodPOST = "POST" | ||||
|  | ||||
| 	tplLogin = "login.tpl" | ||||
|  | ||||
| 	storeUsername = "username" | ||||
| 	storePassword = "password" | ||||
| ) | ||||
|  | ||||
| func init() { | ||||
| @@ -37,7 +34,7 @@ func (a *AuthModule) Initialize() (err error) { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	a.policies = authboss.FilterValidators(authboss.Cfg.Policies, "username", "password") | ||||
| 	a.policies = authboss.FilterValidators(authboss.Cfg.Policies, authboss.Cfg.PrimaryID, authboss.StorePassword) | ||||
|  | ||||
| 	a.isRememberLoaded = authboss.IsLoaded("remember") | ||||
| 	a.isRecoverLoaded = authboss.IsLoaded("recover") | ||||
| @@ -54,8 +51,8 @@ func (a *AuthModule) Routes() authboss.RouteTable { | ||||
|  | ||||
| func (a *AuthModule) Storage() authboss.StorageOptions { | ||||
| 	return authboss.StorageOptions{ | ||||
| 		storeUsername: authboss.String, | ||||
| 		storePassword: authboss.String, | ||||
| 		authboss.Cfg.PrimaryID: authboss.String, | ||||
| 		authboss.StorePassword: authboss.String, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -63,7 +60,7 @@ func (a *AuthModule) loginHandlerFunc(ctx *authboss.Context, w http.ResponseWrit | ||||
| 	switch r.Method { | ||||
| 	case methodGET: | ||||
| 		if _, ok := ctx.SessionStorer.Get(authboss.SessionKey); ok { | ||||
| 			if halfAuthed, ok := ctx.SessionStorer.Get(authboss.HalfAuthKey); !ok || halfAuthed == "false" { | ||||
| 			if halfAuthed, ok := ctx.SessionStorer.Get(authboss.SessionHalfAuthKey); !ok || halfAuthed == "false" { | ||||
| 				http.Redirect(w, r, authboss.Cfg.AuthLoginSuccessRoute, http.StatusFound) | ||||
| 			} | ||||
| 		} | ||||
| @@ -86,12 +83,12 @@ func (a *AuthModule) loginHandlerFunc(ctx *authboss.Context, w http.ResponseWrit | ||||
| 			return nil | ||||
| 		} | ||||
|  | ||||
| 		username, _ := ctx.FirstPostFormValue("username") | ||||
| 		key, _ := ctx.FirstPostFormValue(authboss.Cfg.PrimaryID) | ||||
| 		password, _ := ctx.FirstPostFormValue("password") | ||||
|  | ||||
| 		errData := authboss.NewHTMLData( | ||||
| 			"error", "invalid username and/or password", | ||||
| 			"username", username, | ||||
| 			authboss.Cfg.PrimaryID, key, | ||||
| 			"showRemember", a.isRememberLoaded, | ||||
| 			"showRecover", a.isRecoverLoaded, | ||||
| 		) | ||||
| @@ -101,12 +98,12 @@ func (a *AuthModule) loginHandlerFunc(ctx *authboss.Context, w http.ResponseWrit | ||||
| 			return a.templates.Render(ctx, w, r, tplLogin, errData) | ||||
| 		} | ||||
|  | ||||
| 		if err := validateCredentials(ctx, username, password); err != nil { | ||||
| 		if err := validateCredentials(ctx, key, password); err != nil { | ||||
| 			fmt.Fprintln(authboss.Cfg.LogWriter, "auth: failed to validate credentials:", err) | ||||
| 			return a.templates.Render(ctx, w, r, tplLogin, errData) | ||||
| 		} | ||||
|  | ||||
| 		ctx.SessionStorer.Put(authboss.SessionKey, username) | ||||
| 		ctx.SessionStorer.Put(authboss.SessionKey, key) | ||||
| 		authboss.Cfg.Callbacks.FireAfter(authboss.EventAuth, ctx) | ||||
| 		http.Redirect(w, r, authboss.Cfg.AuthLoginSuccessRoute, http.StatusFound) | ||||
| 	default: | ||||
| @@ -116,12 +113,12 @@ func (a *AuthModule) loginHandlerFunc(ctx *authboss.Context, w http.ResponseWrit | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func validateCredentials(ctx *authboss.Context, username, password string) error { | ||||
| 	if err := ctx.LoadUser(username); err != nil { | ||||
| func validateCredentials(ctx *authboss.Context, key, password string) error { | ||||
| 	if err := ctx.LoadUser(key); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	actualPassword, err := ctx.User.StringErr(storePassword) | ||||
| 	actualPassword, err := ctx.User.StringErr(authboss.StorePassword) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|   | ||||
| @@ -8,7 +8,7 @@ const ( | ||||
| 	// HalfAuthKey is used for sessions that have been authenticated by | ||||
| 	// the remember module. This serves as a way to force full authentication | ||||
| 	// by denying half-authed users acccess to sensitive areas. | ||||
| 	HalfAuthKey = "halfauth" | ||||
| 	SessionHalfAuthKey = "halfauth" | ||||
| 	// FlashSuccessKey is used for storing sucess flash messages on the session | ||||
| 	FlashSuccessKey = "flash_success" | ||||
| 	// FlashErrorKey is used for storing sucess flash messages on the session | ||||
|   | ||||
							
								
								
									
										23
									
								
								config.go
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								config.go
									
									
									
									
									
								
							| @@ -5,6 +5,7 @@ import ( | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"net/smtp" | ||||
| 	"strings" | ||||
| 	"time" | ||||
|  | ||||
| 	"golang.org/x/crypto/bcrypt" | ||||
| @@ -20,15 +21,19 @@ var Cfg *Config = NewConfig() | ||||
|  | ||||
| // Config holds all the configuration for both authboss and it's modules. | ||||
| type Config struct { | ||||
| 	// MountPath is the path to mount the router at. | ||||
| 	// MountPath is the path to mount authboss's routes at (eg /auth). | ||||
| 	MountPath string | ||||
| 	// ViewsPath is the path to overiding view template files. | ||||
| 	// ViewsPath is the path to search for overridden templates. | ||||
| 	ViewsPath string | ||||
| 	// HostName is self explanitory | ||||
| 	// HostName is the host of the web application (eg https://www.happiness.com:8080) for e-mail url generation. | ||||
| 	HostName string | ||||
| 	// BCryptPasswordCost is self explanitory. | ||||
| 	// BCryptCost is the cost of the bcrypt password hashing function. | ||||
| 	BCryptCost int | ||||
|  | ||||
| 	// PrimaryID is the primary identifier of the user. Set to one of: | ||||
| 	// authboss.StoreEmail, authboss.StoreUsername (StoreEmail is default) | ||||
| 	PrimaryID string | ||||
|  | ||||
| 	Layout          *template.Template | ||||
| 	LayoutEmail     *template.Template | ||||
| 	LayoutDataMaker ViewDataMaker | ||||
| @@ -45,7 +50,8 @@ type Config struct { | ||||
| 	Policies      []Validator | ||||
| 	ConfirmFields []string | ||||
|  | ||||
| 	ExpireAfter  time.Duration | ||||
| 	ExpireAfter time.Duration | ||||
|  | ||||
| 	LockAfter    int | ||||
| 	LockWindow   time.Duration | ||||
| 	LockDuration time.Duration | ||||
| @@ -73,6 +79,8 @@ func NewConfig() *Config { | ||||
| 		HostName:   "localhost:8080", | ||||
| 		BCryptCost: bcrypt.DefaultCost, | ||||
|  | ||||
| 		PrimaryID: StoreEmail, | ||||
|  | ||||
| 		Layout:      template.Must(template.New("").Parse(`<html><body>{{template "authboss" .}}</body></html>`)), | ||||
| 		LayoutEmail: template.Must(template.New("").Parse(`<html><body>{{template "authboss" .}}</body></html>`)), | ||||
|  | ||||
| @@ -96,7 +104,10 @@ func NewConfig() *Config { | ||||
| 				AllowWhitespace: false, | ||||
| 			}, | ||||
| 		}, | ||||
| 		ConfirmFields: []string{"username", "confirmUsername", "password", "confirmPassword"}, | ||||
| 		ConfirmFields: []string{ | ||||
| 			StoreEmail, "confirm" + strings.Title(StoreEmail), | ||||
| 			StorePassword, "confirm" + strings.Title(StorePassword), | ||||
| 		}, | ||||
|  | ||||
| 		RecoverRedirect:             "/login", | ||||
| 		RecoverInitiateSuccessFlash: "An email has been sent with further insructions on how to reset your password", | ||||
|   | ||||
| @@ -98,6 +98,7 @@ func TestConfirm_AfterRegister(t *testing.T) { | ||||
| 	log := &bytes.Buffer{} | ||||
| 	authboss.Cfg.LogWriter = log | ||||
| 	authboss.Cfg.Mailer = authboss.LogMailer(log) | ||||
| 	authboss.Cfg.PrimaryID = authboss.StoreUsername | ||||
|  | ||||
| 	sentEmail := false | ||||
|  | ||||
| @@ -110,7 +111,7 @@ func TestConfirm_AfterRegister(t *testing.T) { | ||||
| 		t.Error("Expected it to die with user error:", err) | ||||
| 	} | ||||
|  | ||||
| 	ctx.User = authboss.Attributes{authboss.StoreUsername: "uname"} | ||||
| 	ctx.User = authboss.Attributes{authboss.Cfg.PrimaryID: "username"} | ||||
| 	if err := c.AfterRegister(ctx); err == nil || err.(authboss.AttributeErr).Name != "email" { | ||||
| 		t.Error("Expected it to die with e-mail address error:", err) | ||||
| 	} | ||||
|   | ||||
| @@ -130,7 +130,7 @@ func (c *Context) SaveUser() error { | ||||
| 		return errors.New("User not initialized.") | ||||
| 	} | ||||
|  | ||||
| 	key, ok := c.User.String("username") | ||||
| 	key, ok := c.User.String(Cfg.PrimaryID) | ||||
| 	if !ok { | ||||
| 		return errors.New("User improperly initialized, primary ID missing") | ||||
| 	} | ||||
|   | ||||
| @@ -41,14 +41,14 @@ func TestContext_SaveUser(t *testing.T) { | ||||
| 	ctx := NewContext() | ||||
| 	storer := mockStorer{} | ||||
| 	Cfg.Storer = storer | ||||
| 	ctx.User = Attributes{"username": "joe", "email": "hello@joe.com", "password": "mysticalhash"} | ||||
| 	ctx.User = Attributes{StoreUsername: "joe", StoreEmail: "hello@joe.com", StorePassword: "mysticalhash"} | ||||
|  | ||||
| 	err := ctx.SaveUser() | ||||
| 	if err != nil { | ||||
| 		t.Error("Unexpected error:", err) | ||||
| 	} | ||||
|  | ||||
| 	attr, ok := storer["joe"] | ||||
| 	attr, ok := storer["hello@joe.com"] | ||||
| 	if !ok { | ||||
| 		t.Error("Could not find joe!") | ||||
| 	} | ||||
|   | ||||
| @@ -74,7 +74,7 @@ func TestExpire_Middleware(t *testing.T) { | ||||
| 	authboss.NewConfig() | ||||
| 	session := mocks.NewMockClientStorer() | ||||
| 	session.Values = map[string]string{ | ||||
| 		authboss.SessionKey: "username", | ||||
| 		authboss.SessionKey: "email@email.com", | ||||
| 	} | ||||
| 	maker := func(w http.ResponseWriter, r *http.Request) authboss.ClientStorer { return session } | ||||
|  | ||||
|   | ||||
| @@ -49,15 +49,15 @@ func TestAfterAuth(t *testing.T) { | ||||
|  | ||||
| 	storer := mocks.NewMockStorer() | ||||
| 	authboss.Cfg.Storer = storer | ||||
| 	ctx.User = authboss.Attributes{"username": "username"} | ||||
| 	ctx.User = authboss.Attributes{authboss.Cfg.PrimaryID: "john@john.com"} | ||||
|  | ||||
| 	if err := lock.AfterAuth(ctx); err != nil { | ||||
| 		t.Error(err) | ||||
| 	} | ||||
| 	if storer.Users["username"][StoreAttemptNumber].(int) != 0 { | ||||
| 	if storer.Users["john@john.com"][StoreAttemptNumber].(int) != 0 { | ||||
| 		t.Error("StoreAttemptNumber set incorrectly.") | ||||
| 	} | ||||
| 	if _, ok := storer.Users["username"][StoreAttemptTime].(time.Time); !ok { | ||||
| 	if _, ok := storer.Users["john@john.com"][StoreAttemptTime].(time.Time); !ok { | ||||
| 		t.Error("StoreAttemptTime not set.") | ||||
| 	} | ||||
| } | ||||
| @@ -74,35 +74,37 @@ func TestAfterAuthFail_Lock(t *testing.T) { | ||||
| 	authboss.Cfg.LockWindow = 30 * time.Minute | ||||
| 	authboss.Cfg.LockAfter = 3 | ||||
|  | ||||
| 	ctx.User = map[string]interface{}{"username": "username"} | ||||
| 	email := "john@john.com" | ||||
|  | ||||
| 	ctx.User = map[string]interface{}{authboss.Cfg.PrimaryID: email} | ||||
|  | ||||
| 	old = time.Now().UTC().Add(-1 * time.Hour) | ||||
|  | ||||
| 	for i := 0; i < 3; i++ { | ||||
| 		if lockedIntf, ok := storer.Users["username"][StoreLocked]; ok && lockedIntf.(bool) { | ||||
| 		if lockedIntf, ok := storer.Users["john@john.com"][StoreLocked]; ok && lockedIntf.(bool) { | ||||
| 			t.Errorf("%d: User should not be locked.", i) | ||||
| 		} | ||||
|  | ||||
| 		if err := lock.AfterAuthFail(ctx); err != nil { | ||||
| 			t.Error(err) | ||||
| 		} | ||||
| 		if val := storer.Users["username"][StoreAttemptNumber].(int); val != i+1 { | ||||
| 		if val := storer.Users[email][StoreAttemptNumber].(int); val != i+1 { | ||||
| 			t.Errorf("%d: StoreAttemptNumber set incorrectly: %v", i, val) | ||||
| 		} | ||||
| 		if current, ok = storer.Users["username"][StoreAttemptTime].(time.Time); !ok || old.After(current) { | ||||
| 		if current, ok = storer.Users[email][StoreAttemptTime].(time.Time); !ok || old.After(current) { | ||||
| 			t.Error("%d: StoreAttemptTime not set correctly: %v", i, current) | ||||
| 		} | ||||
|  | ||||
| 		current = old | ||||
| 	} | ||||
|  | ||||
| 	if !storer.Users["username"][StoreLocked].(bool) { | ||||
| 	if !storer.Users[email][StoreLocked].(bool) { | ||||
| 		t.Error("User should be locked.") | ||||
| 	} | ||||
| 	if val := storer.Users["username"][StoreAttemptNumber].(int); val != 3 { | ||||
| 	if val := storer.Users[email][StoreAttemptNumber].(int); val != 3 { | ||||
| 		t.Error("StoreAttemptNumber set incorrectly:", val) | ||||
| 	} | ||||
| 	if _, ok = storer.Users["username"][StoreAttemptTime].(time.Time); !ok { | ||||
| 	if _, ok = storer.Users[email][StoreAttemptTime].(time.Time); !ok { | ||||
| 		t.Error("StoreAttemptTime not set correctly.") | ||||
| 	} | ||||
| } | ||||
| @@ -120,21 +122,22 @@ func TestAfterAuthFail_Reset(t *testing.T) { | ||||
|  | ||||
| 	old = time.Now().UTC().Add(-time.Hour) | ||||
|  | ||||
| 	email := "john@john.com" | ||||
| 	ctx.User = map[string]interface{}{ | ||||
| 		"username":         "username", | ||||
| 		StoreAttemptNumber: 2, | ||||
| 		StoreAttemptTime:   old, | ||||
| 		StoreLocked:        false, | ||||
| 		authboss.Cfg.PrimaryID: email, | ||||
| 		StoreAttemptNumber:     2, | ||||
| 		StoreAttemptTime:       old, | ||||
| 		StoreLocked:            false, | ||||
| 	} | ||||
|  | ||||
| 	lock.AfterAuthFail(ctx) | ||||
| 	if val := storer.Users["username"][StoreAttemptNumber].(int); val != 0 { | ||||
| 	if val := storer.Users[email][StoreAttemptNumber].(int); val != 0 { | ||||
| 		t.Error("StoreAttemptNumber set incorrectly:", val) | ||||
| 	} | ||||
| 	if current, ok = storer.Users["username"][StoreAttemptTime].(time.Time); !ok || current.Before(old) { | ||||
| 	if current, ok = storer.Users[email][StoreAttemptTime].(time.Time); !ok || current.Before(old) { | ||||
| 		t.Error("StoreAttemptTime not set correctly.") | ||||
| 	} | ||||
| 	if locked := storer.Users["username"][StoreLocked].(bool); locked { | ||||
| 	if locked := storer.Users[email][StoreLocked].(bool); locked { | ||||
| 		t.Error("StoreLocked not set correctly:", locked) | ||||
| 	} | ||||
| } | ||||
| @@ -156,17 +159,18 @@ func TestLock(t *testing.T) { | ||||
| 	authboss.Cfg.Storer = storer | ||||
| 	lock := Lock{} | ||||
|  | ||||
| 	storer.Users["username"] = map[string]interface{}{ | ||||
| 		"username": "username", | ||||
| 		"password": "password", | ||||
| 	email := "john@john.com" | ||||
| 	storer.Users[email] = map[string]interface{}{ | ||||
| 		authboss.Cfg.PrimaryID: email, | ||||
| 		"password":             "password", | ||||
| 	} | ||||
|  | ||||
| 	err := lock.Lock("username") | ||||
| 	err := lock.Lock(email) | ||||
| 	if err != nil { | ||||
| 		t.Error(err) | ||||
| 	} | ||||
|  | ||||
| 	if locked := storer.Users["username"][StoreLocked].(bool); !locked { | ||||
| 	if locked := storer.Users[email][StoreLocked].(bool); !locked { | ||||
| 		t.Error("User should be locked.") | ||||
| 	} | ||||
| } | ||||
| @@ -178,25 +182,26 @@ func TestUnlock(t *testing.T) { | ||||
| 	lock := Lock{} | ||||
| 	authboss.Cfg.LockWindow = 1 * time.Hour | ||||
|  | ||||
| 	storer.Users["username"] = map[string]interface{}{ | ||||
| 		"username": "username", | ||||
| 		"password": "password", | ||||
| 		"locked":   true, | ||||
| 	email := "john@john.com" | ||||
| 	storer.Users[email] = map[string]interface{}{ | ||||
| 		authboss.Cfg.PrimaryID: email, | ||||
| 		"password":             "password", | ||||
| 		"locked":               true, | ||||
| 	} | ||||
|  | ||||
| 	err := lock.Unlock("username") | ||||
| 	err := lock.Unlock(email) | ||||
| 	if err != nil { | ||||
| 		t.Error(err) | ||||
| 	} | ||||
|  | ||||
| 	attemptTime := storer.Users["username"][StoreAttemptTime].(time.Time) | ||||
| 	attemptTime := storer.Users[email][StoreAttemptTime].(time.Time) | ||||
| 	if attemptTime.After(time.Now().UTC().Add(-authboss.Cfg.LockWindow)) { | ||||
| 		t.Error("StoreLocked not set correctly:", attemptTime) | ||||
| 	} | ||||
| 	if number := storer.Users["username"][StoreAttemptNumber].(int); number != 0 { | ||||
| 	if number := storer.Users[email][StoreAttemptNumber].(int); number != 0 { | ||||
| 		t.Error("StoreLocked not set correctly:", number) | ||||
| 	} | ||||
| 	if locked := storer.Users["username"][StoreLocked].(bool); locked { | ||||
| 	if locked := storer.Users[email][StoreLocked].(bool); locked { | ||||
| 		t.Error("User should not be locked.") | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -68,7 +68,7 @@ func (r *Remember) AfterAuth(ctx *authboss.Context) error { | ||||
| 		return errUserMissing | ||||
| 	} | ||||
|  | ||||
| 	key, err := ctx.User.StringErr("username") | ||||
| 	key, err := ctx.User.StringErr(authboss.Cfg.PrimaryID) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| @@ -140,7 +140,7 @@ func (r *Remember) Auth( | ||||
| 	} | ||||
|  | ||||
| 	// Ensure a half-auth. | ||||
| 	sstorer.Put(authboss.HalfAuthKey, "true") | ||||
| 	sstorer.Put(authboss.SessionHalfAuthKey, "true") | ||||
| 	// Log the user in. | ||||
| 	sstorer.Put(authboss.SessionKey, key) | ||||
|  | ||||
|   | ||||
| @@ -52,7 +52,7 @@ func TestAfterAuth(t *testing.T) { | ||||
|  | ||||
| 	ctx.SessionStorer = session | ||||
| 	ctx.CookieStorer = cookies | ||||
| 	ctx.User = authboss.Attributes{"username": "testuser"} | ||||
| 	ctx.User = authboss.Attributes{authboss.Cfg.PrimaryID: "test@email.com"} | ||||
|  | ||||
| 	if err := R.AfterAuth(ctx); err != nil { | ||||
| 		t.Error(err) | ||||
| @@ -109,7 +109,7 @@ func TestAuth(t *testing.T) { | ||||
| 		t.Error("Unexpected error:", err) | ||||
| 	} | ||||
|  | ||||
| 	if session.Values[authboss.HalfAuthKey] != "true" { | ||||
| 	if session.Values[authboss.SessionHalfAuthKey] != "true" { | ||||
| 		t.Error("The user should have been half-authed.") | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -14,8 +14,6 @@ const ( | ||||
| 	StoreEmail    = "email" | ||||
| 	StoreUsername = "username" | ||||
| 	StorePassword = "password" | ||||
| 	// UserKey is used to uniquely identify the user. | ||||
| 	StoreKey = StoreEmail | ||||
| ) | ||||
|  | ||||
| var ( | ||||
|   | ||||
| @@ -22,9 +22,9 @@ func TestErrorList_Map(t *testing.T) { | ||||
| 	errAsploded := "asploded" | ||||
|  | ||||
| 	errList := ErrorList{ | ||||
| 		FieldError{"username", errors.New(errNotLong)}, | ||||
| 		FieldError{"username", errors.New(errEmail)}, | ||||
| 		FieldError{"password", errors.New(errNotLong)}, | ||||
| 		FieldError{StoreUsername, errors.New(errNotLong)}, | ||||
| 		FieldError{StoreUsername, errors.New(errEmail)}, | ||||
| 		FieldError{StorePassword, errors.New(errNotLong)}, | ||||
| 		errors.New(errAsploded), | ||||
| 	} | ||||
|  | ||||
| @@ -33,7 +33,7 @@ func TestErrorList_Map(t *testing.T) { | ||||
| 		t.Error("Wrong number of fields:", len(m)) | ||||
| 	} | ||||
|  | ||||
| 	usernameErrs := m["username"] | ||||
| 	usernameErrs := m[StoreUsername] | ||||
| 	if len(usernameErrs) != 2 { | ||||
| 		t.Error("Wrong number of username errors:", len(usernameErrs)) | ||||
| 	} | ||||
| @@ -44,7 +44,7 @@ func TestErrorList_Map(t *testing.T) { | ||||
| 		t.Error("Wrong username error at 1:", usernameErrs[1]) | ||||
| 	} | ||||
|  | ||||
| 	passwordErrs := m["password"] | ||||
| 	passwordErrs := m[StorePassword] | ||||
| 	if len(passwordErrs) != 1 { | ||||
| 		t.Error("Wrong number of password errors:", len(passwordErrs)) | ||||
| 	} | ||||
| @@ -64,30 +64,30 @@ func TestErrorList_Map(t *testing.T) { | ||||
| func TestValidate(t *testing.T) { | ||||
| 	t.Parallel() | ||||
|  | ||||
| 	ctx := mockRequestContext("username", "john", "email", "john@john.com") | ||||
| 	ctx := mockRequestContext(StoreUsername, "john", StoreEmail, "john@john.com") | ||||
|  | ||||
| 	errList := ctx.Validate([]Validator{ | ||||
| 		mockValidator{ | ||||
| 			FieldName: "username", | ||||
| 			Errs:      ErrorList{FieldError{"username", errors.New("must be longer than 4")}}, | ||||
| 			FieldName: StoreUsername, | ||||
| 			Errs:      ErrorList{FieldError{StoreUsername, errors.New("must be longer than 4")}}, | ||||
| 		}, | ||||
| 		mockValidator{ | ||||
| 			FieldName: "missing_field", | ||||
| 			Errs:      ErrorList{FieldError{"missing_field", errors.New("Expected field to exist.")}}, | ||||
| 		}, | ||||
| 		mockValidator{ | ||||
| 			FieldName: "email", Errs: nil, | ||||
| 			FieldName: StoreEmail, Errs: nil, | ||||
| 		}, | ||||
| 	}) | ||||
|  | ||||
| 	errs := errList.Map() | ||||
| 	if errs["username"][0] != "must be longer than 4" { | ||||
| 		t.Error("Expected a different error for username:", errs["username"][0]) | ||||
| 	if errs[StoreUsername][0] != "must be longer than 4" { | ||||
| 		t.Error("Expected a different error for username:", errs[StoreUsername][0]) | ||||
| 	} | ||||
| 	if errs["missing_field"][0] != "Expected field to exist." { | ||||
| 		t.Error("Expected a different error for missing_field:", errs["missing_field"][0]) | ||||
| 	} | ||||
| 	if _, ok := errs["email"]; ok { | ||||
| 	if _, ok := errs[StoreEmail]; ok { | ||||
| 		t.Error("Expected no errors for email.") | ||||
| 	} | ||||
| } | ||||
| @@ -95,20 +95,20 @@ func TestValidate(t *testing.T) { | ||||
| func TestValidate_Confirm(t *testing.T) { | ||||
| 	t.Parallel() | ||||
|  | ||||
| 	ctx := mockRequestContext("username", "john", "confirmUsername", "johnny") | ||||
| 	errs := ctx.Validate(nil, "username", "confirmUsername").Map() | ||||
| 	ctx := mockRequestContext(StoreUsername, "john", "confirmUsername", "johnny") | ||||
| 	errs := ctx.Validate(nil, StoreUsername, "confirmUsername").Map() | ||||
| 	if errs["confirmUsername"][0] != "Does not match username" { | ||||
| 		t.Error("Expected a different error for confirmUsername:", errs["confirmUsername"][0]) | ||||
| 	} | ||||
|  | ||||
| 	ctx = mockRequestContext("username", "john", "confirmUsername", "john") | ||||
| 	errs = ctx.Validate(nil, "username", "confirmUsername").Map() | ||||
| 	ctx = mockRequestContext(StoreUsername, "john", "confirmUsername", "john") | ||||
| 	errs = ctx.Validate(nil, StoreUsername, "confirmUsername").Map() | ||||
| 	if len(errs) != 0 { | ||||
| 		t.Error("Expected no errors:", errs) | ||||
| 	} | ||||
|  | ||||
| 	ctx = mockRequestContext("username", "john", "confirmUsername", "john") | ||||
| 	errs = ctx.Validate(nil, "username").Map() | ||||
| 	ctx = mockRequestContext(StoreUsername, "john", "confirmUsername", "john") | ||||
| 	errs = ctx.Validate(nil, StoreUsername).Map() | ||||
| 	if len(errs) != 0 { | ||||
| 		t.Error("Expected no errors:", errs) | ||||
| 	} | ||||
| @@ -119,19 +119,19 @@ func TestFilterValidators(t *testing.T) { | ||||
|  | ||||
| 	validators := []Validator{ | ||||
| 		mockValidator{ | ||||
| 			FieldName: "username", Errs: ErrorList{FieldError{"username", errors.New("must be longer than 4")}}, | ||||
| 			FieldName: StoreUsername, Errs: ErrorList{FieldError{StoreUsername, errors.New("must be longer than 4")}}, | ||||
| 		}, | ||||
| 		mockValidator{ | ||||
| 			FieldName: "password", Errs: ErrorList{FieldError{"password", errors.New("must be longer than 4")}}, | ||||
| 			FieldName: StorePassword, Errs: ErrorList{FieldError{StorePassword, errors.New("must be longer than 4")}}, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	validators = FilterValidators(validators, "username") | ||||
| 	validators = FilterValidators(validators, StoreUsername) | ||||
|  | ||||
| 	if len(validators) != 1 { | ||||
| 		t.Error("Expected length to be 1") | ||||
| 	} | ||||
| 	if validators[0].Field() != "username" { | ||||
| 	if validators[0].Field() != StoreUsername { | ||||
| 		t.Error("Expcted validator for field username", validators[0].Field()) | ||||
| 	} | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user