More tests
This commit is contained in:
		
							parent
							
								
									a2e474c375
								
							
						
					
					
						commit
						f79348817f
					
				
					 5 changed files with 65 additions and 33 deletions
				
			
		|  | @ -36,13 +36,15 @@ import ( | |||
| 
 | ||||
| /* | ||||
| 	TODO | ||||
| 		limits: | ||||
| 			message cache duration | ||||
| 			Keep 10000 messages or keep X days? | ||||
| 			Attachment expiration based on plan | ||||
| 		database migration | ||||
| 		reserve topics | ||||
| 		purge accounts that were not logged into in X | ||||
| 		reset daily limits for users | ||||
| 		Account usage not updated "in real time" | ||||
| 		Attachment expiration based on plan | ||||
| 		Plan: Keep 10000 messages or keep X days? | ||||
| 		Sync: | ||||
| 			- "mute" setting | ||||
| 			- figure out what settings are "web" or "phone" | ||||
|  |  | |||
|  | @ -159,7 +159,7 @@ func (s *Server) handleAccountTokenIssue(w http.ResponseWriter, r *http.Request, | |||
| 	w.Header().Set("Access-Control-Allow-Origin", "*") // FIXME remove this | ||||
| 	response := &apiAccountTokenResponse{ | ||||
| 		Token:   token.Value, | ||||
| 		Expires: token.Expires, | ||||
| 		Expires: token.Expires.Unix(), | ||||
| 	} | ||||
| 	if err := json.NewEncoder(w).Encode(response); err != nil { | ||||
| 		return err | ||||
|  | @ -182,7 +182,7 @@ func (s *Server) handleAccountTokenExtend(w http.ResponseWriter, r *http.Request | |||
| 	w.Header().Set("Access-Control-Allow-Origin", "*") // FIXME remove this | ||||
| 	response := &apiAccountTokenResponse{ | ||||
| 		Token:   token.Value, | ||||
| 		Expires: token.Expires, | ||||
| 		Expires: token.Expires.Unix(), | ||||
| 	} | ||||
| 	if err := json.NewEncoder(w).Encode(response); err != nil { | ||||
| 		return err | ||||
|  |  | |||
|  | @ -188,6 +188,9 @@ func (a *Manager) Authenticate(username, password string) (*User, error) { | |||
| // AuthenticateToken checks if the token exists and returns the associated User if it does. | ||||
| // The method sets the User.Token value to the token that was used for authentication. | ||||
| func (a *Manager) AuthenticateToken(token string) (*User, error) { | ||||
| 	if len(token) != tokenLength { | ||||
| 		return nil, ErrUnauthenticated | ||||
| 	} | ||||
| 	user, err := a.userByToken(token) | ||||
| 	if err != nil { | ||||
| 		return nil, ErrUnauthenticated | ||||
|  | @ -205,7 +208,7 @@ func (a *Manager) CreateToken(user *User) (*Token, error) { | |||
| 	} | ||||
| 	return &Token{ | ||||
| 		Value:   token, | ||||
| 		Expires: expires.Unix(), | ||||
| 		Expires: expires, | ||||
| 	}, nil | ||||
| } | ||||
| 
 | ||||
|  | @ -217,7 +220,7 @@ func (a *Manager) ExtendToken(user *User) (*Token, error) { | |||
| 	} | ||||
| 	return &Token{ | ||||
| 		Value:   user.Token, | ||||
| 		Expires: newExpires.Unix(), | ||||
| 		Expires: newExpires, | ||||
| 	}, nil | ||||
| } | ||||
| 
 | ||||
|  | @ -390,17 +393,6 @@ func (a *Manager) Users() ([]*User, error) { | |||
| 		} | ||||
| 		users = append(users, user) | ||||
| 	} | ||||
| 	/*sort.Slice(users, func(i, j int) bool { | ||||
| 		if users[i].Role != users[j].Role { | ||||
| 			return true | ||||
| 		} | ||||
| 		if users[i].Name == Everyone || users[j].Name == Everyone { | ||||
| 			return users[i].Name != Everyone | ||||
| 		} else if string(users[i].Role) < string(users[j].Role) { | ||||
| 			return true | ||||
| 		} | ||||
| 		return users[i].Name < users[j].Name | ||||
| 	})*/ | ||||
| 	return users, nil | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -11,8 +11,8 @@ import ( | |||
| 
 | ||||
| const minBcryptTimingMillis = int64(50) // Ideally should be >100ms, but this should also run on a Raspberry Pi without massive resources | ||||
| 
 | ||||
| func TestSQLiteAuth_FullScenario_Default_DenyAll(t *testing.T) { | ||||
| 	a := newTestAuth(t, false, false) | ||||
| func TestManager_FullScenario_Default_DenyAll(t *testing.T) { | ||||
| 	a := newTestManager(t, false, false) | ||||
| 	require.Nil(t, a.AddUser("phil", "phil", user.RoleAdmin)) | ||||
| 	require.Nil(t, a.AddUser("ben", "ben", user.RoleUser)) | ||||
| 	require.Nil(t, a.AllowAccess("ben", "mytopic", true, true)) | ||||
|  | @ -84,21 +84,21 @@ func TestSQLiteAuth_FullScenario_Default_DenyAll(t *testing.T) { | |||
| 	require.Nil(t, a.Authorize(nil, "up5678", user.PermissionWrite)) | ||||
| } | ||||
| 
 | ||||
| func TestSQLiteAuth_AddUser_Invalid(t *testing.T) { | ||||
| 	a := newTestAuth(t, false, false) | ||||
| func TestManager_AddUser_Invalid(t *testing.T) { | ||||
| 	a := newTestManager(t, false, false) | ||||
| 	require.Equal(t, user.ErrInvalidArgument, a.AddUser("  invalid  ", "pass", user.RoleAdmin)) | ||||
| 	require.Equal(t, user.ErrInvalidArgument, a.AddUser("validuser", "pass", "invalid-role")) | ||||
| } | ||||
| 
 | ||||
| func TestSQLiteAuth_AddUser_Timing(t *testing.T) { | ||||
| 	a := newTestAuth(t, false, false) | ||||
| func TestManager_AddUser_Timing(t *testing.T) { | ||||
| 	a := newTestManager(t, false, false) | ||||
| 	start := time.Now().UnixMilli() | ||||
| 	require.Nil(t, a.AddUser("user", "pass", user.RoleAdmin)) | ||||
| 	require.GreaterOrEqual(t, time.Now().UnixMilli()-start, minBcryptTimingMillis) | ||||
| } | ||||
| 
 | ||||
| func TestSQLiteAuth_Authenticate_Timing(t *testing.T) { | ||||
| 	a := newTestAuth(t, false, false) | ||||
| func TestManager_Authenticate_Timing(t *testing.T) { | ||||
| 	a := newTestManager(t, false, false) | ||||
| 	require.Nil(t, a.AddUser("user", "pass", user.RoleAdmin)) | ||||
| 
 | ||||
| 	// Timing a correct attempt | ||||
|  | @ -120,8 +120,8 @@ func TestSQLiteAuth_Authenticate_Timing(t *testing.T) { | |||
| 	require.GreaterOrEqual(t, time.Now().UnixMilli()-start, minBcryptTimingMillis) | ||||
| } | ||||
| 
 | ||||
| func TestSQLiteAuth_UserManagement(t *testing.T) { | ||||
| 	a := newTestAuth(t, false, false) | ||||
| func TestManager_UserManagement(t *testing.T) { | ||||
| 	a := newTestManager(t, false, false) | ||||
| 	require.Nil(t, a.AddUser("phil", "phil", user.RoleAdmin)) | ||||
| 	require.Nil(t, a.AddUser("ben", "ben", user.RoleUser)) | ||||
| 	require.Nil(t, a.AllowAccess("ben", "mytopic", true, true)) | ||||
|  | @ -202,8 +202,8 @@ func TestSQLiteAuth_UserManagement(t *testing.T) { | |||
| 	require.Equal(t, "*", users[1].Name) | ||||
| } | ||||
| 
 | ||||
| func TestSQLiteAuth_ChangePassword(t *testing.T) { | ||||
| 	a := newTestAuth(t, false, false) | ||||
| func TestManager_ChangePassword(t *testing.T) { | ||||
| 	a := newTestManager(t, false, false) | ||||
| 	require.Nil(t, a.AddUser("phil", "phil", user.RoleAdmin)) | ||||
| 
 | ||||
| 	_, err := a.Authenticate("phil", "phil") | ||||
|  | @ -216,8 +216,8 @@ func TestSQLiteAuth_ChangePassword(t *testing.T) { | |||
| 	require.Nil(t, err) | ||||
| } | ||||
| 
 | ||||
| func TestSQLiteAuth_ChangeRole(t *testing.T) { | ||||
| 	a := newTestAuth(t, false, false) | ||||
| func TestManager_ChangeRole(t *testing.T) { | ||||
| 	a := newTestManager(t, false, false) | ||||
| 	require.Nil(t, a.AddUser("ben", "ben", user.RoleUser)) | ||||
| 	require.Nil(t, a.AllowAccess("ben", "mytopic", true, true)) | ||||
| 	require.Nil(t, a.AllowAccess("ben", "readme", true, false)) | ||||
|  | @ -235,7 +235,44 @@ func TestSQLiteAuth_ChangeRole(t *testing.T) { | |||
| 	require.Equal(t, 0, len(ben.Grants)) | ||||
| } | ||||
| 
 | ||||
| func newTestAuth(t *testing.T, defaultRead, defaultWrite bool) *user.Manager { | ||||
| func TestManager_Token_Valid(t *testing.T) { | ||||
| 	a := newTestManager(t, false, false) | ||||
| 	require.Nil(t, a.AddUser("ben", "ben", user.RoleUser)) | ||||
| 
 | ||||
| 	u, err := a.User("ben") | ||||
| 	require.Nil(t, err) | ||||
| 
 | ||||
| 	// Create token for user | ||||
| 	token, err := a.CreateToken(u) | ||||
| 	require.NotEmpty(t, token.Value) | ||||
| 	require.True(t, time.Now().Add(71*time.Hour).Unix() < token.Expires.Unix()) | ||||
| 
 | ||||
| 	u2, err := a.AuthenticateToken(token.Value) | ||||
| 	require.Nil(t, err) | ||||
| 	require.Equal(t, u.Name, u2.Name) | ||||
| 	require.Equal(t, token.Value, u2.Token) | ||||
| 
 | ||||
| 	// Remove token and auth again | ||||
| 	require.Nil(t, a.RemoveToken(u2)) | ||||
| 	u3, err := a.AuthenticateToken(token.Value) | ||||
| 	require.Equal(t, user.ErrUnauthenticated, err) | ||||
| 	require.Nil(t, u3) | ||||
| } | ||||
| 
 | ||||
| func TestManager_Token_Invalid(t *testing.T) { | ||||
| 	a := newTestManager(t, false, false) | ||||
| 	require.Nil(t, a.AddUser("ben", "ben", user.RoleUser)) | ||||
| 
 | ||||
| 	u, err := a.AuthenticateToken(strings.Repeat("x", 32)) // 32 == token length | ||||
| 	require.Nil(t, u) | ||||
| 	require.Equal(t, user.ErrUnauthenticated, err) | ||||
| 
 | ||||
| 	u, err = a.AuthenticateToken("not long enough anyway") | ||||
| 	require.Nil(t, u) | ||||
| 	require.Equal(t, user.ErrUnauthenticated, err) | ||||
| } | ||||
| 
 | ||||
| func newTestManager(t *testing.T, defaultRead, defaultWrite bool) *user.Manager { | ||||
| 	filename := filepath.Join(t.TempDir(), "user.db") | ||||
| 	a, err := user.NewManager(filename, defaultRead, defaultWrite) | ||||
| 	require.Nil(t, err) | ||||
|  |  | |||
|  | @ -4,6 +4,7 @@ package user | |||
| import ( | ||||
| 	"errors" | ||||
| 	"regexp" | ||||
| 	"time" | ||||
| ) | ||||
| 
 | ||||
| type Auther interface { | ||||
|  | @ -31,7 +32,7 @@ type User struct { | |||
| 
 | ||||
| type Token struct { | ||||
| 	Value   string | ||||
| 	Expires int64 | ||||
| 	Expires time.Time | ||||
| } | ||||
| 
 | ||||
| type Prefs struct { | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue