binwiederhier 3 лет назад
Родитель
Сommit
f79348817f
5 измененных файлов с 65 добавлено и 33 удалено
  1. 4 2
      server/server.go
  2. 2 2
      server/server_account.go
  3. 5 13
      user/manager.go
  4. 52 15
      user/manager_test.go
  5. 2 1
      user/types.go

+ 4 - 2
server/server.go

@@ -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"

+ 2 - 2
server/server_account.go

@@ -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

+ 5 - 13
user/manager.go

@@ -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
 }
 

+ 52 - 15
user/manager_test.go

@@ -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)

+ 2 - 1
user/types.go

@@ -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 {