Skip to content

Commit c453b57

Browse files
committed
refactor: simplify user parsing
1 parent 4546122 commit c453b57

7 files changed

Lines changed: 59 additions & 61 deletions

File tree

internal/bootstrap/router_bootstrap.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package bootstrap
22

33
import (
44
"fmt"
5-
"strings"
65

76
"github.com/steveiliop56/tinyauth/internal/controller"
87
"github.com/steveiliop56/tinyauth/internal/middleware"
@@ -15,7 +14,7 @@ func (app *BootstrapApp) setupRouter() (*gin.Engine, error) {
1514
engine.Use(gin.Recovery())
1615

1716
if len(app.config.Server.TrustedProxies) > 0 {
18-
err := engine.SetTrustedProxies(strings.Split(app.config.Server.TrustedProxies, ","))
17+
err := engine.SetTrustedProxies(app.config.Server.TrustedProxies)
1918

2019
if err != nil {
2120
return nil, fmt.Errorf("failed to set trusted proxies: %w", err)

internal/config/config.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,15 @@ type Config struct {
3333
}
3434

3535
type ServerConfig struct {
36-
Port int `description:"The port on which the server listens." yaml:"port"`
37-
Address string `description:"The address on which the server listens." yaml:"address"`
38-
SocketPath string `description:"The path to the Unix socket." yaml:"socketPath"`
39-
TrustedProxies string `description:"Comma-separated list of trusted proxy addresses." yaml:"trustedProxies"`
36+
Port int `description:"The port on which the server listens." yaml:"port"`
37+
Address string `description:"The address on which the server listens." yaml:"address"`
38+
SocketPath string `description:"The path to the Unix socket." yaml:"socketPath"`
39+
TrustedProxies []string `description:"Comma-separated list of trusted proxy addresses." yaml:"trustedProxies"`
4040
}
4141

4242
type AuthConfig struct {
4343
IP IPConfig `description:"IP whitelisting config options." yaml:"ip"`
44-
Users string `description:"Comma-separated list of users (username:hashed_password)." yaml:"users"`
44+
Users []string `description:"Comma-separated list of users (username:hashed_password)." yaml:"users"`
4545
UsersFile string `description:"Path to the users file." yaml:"usersFile"`
4646
SecureCookie bool `description:"Enable secure cookies." yaml:"secureCookie"`
4747
SessionExpiry int `description:"Session expiry time in seconds." yaml:"sessionExpiry"`
@@ -56,7 +56,7 @@ type IPConfig struct {
5656
}
5757

5858
type OAuthConfig struct {
59-
Whitelist string `description:"Comma-separated list of allowed OAuth domains." yaml:"whitelist"`
59+
Whitelist []string `description:"Comma-separated list of allowed OAuth domains." yaml:"whitelist"`
6060
AutoRedirect string `description:"The OAuth provider to use for automatic redirection." yaml:"autoRedirect"`
6161
Providers map[string]OAuthServiceConfig `description:"OAuth providers configuration." yaml:"providers"`
6262
}

internal/controller/proxy_controller_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ func setupProxyController(t *testing.T, middlewares *[]gin.HandlerFunc) (*gin.En
5757
Password: "$2a$10$ne6z693sTgzT3ePoQ05PgOecUHnBjM7sSNj6M.l5CLUP.f6NyCnt.", // test
5858
},
5959
},
60-
OauthWhitelist: "",
60+
OauthWhitelist: []string{},
6161
SessionExpiry: 3600,
6262
SessionMaxLifetime: 0,
6363
SecureCookie: false,

internal/controller/user_controller_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ func setupUserController(t *testing.T, middlewares *[]gin.HandlerFunc) (*gin.Eng
6060
TotpSecret: totpSecret,
6161
},
6262
},
63-
OauthWhitelist: "",
63+
OauthWhitelist: []string{},
6464
SessionExpiry: 3600,
6565
SessionMaxLifetime: 0,
6666
SecureCookie: false,

internal/service/auth_service.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ type LoginAttempt struct {
2727

2828
type AuthServiceConfig struct {
2929
Users []config.User
30-
OauthWhitelist string
30+
OauthWhitelist []string
3131
SessionExpiry int
3232
SessionMaxLifetime int
3333
SecureCookie bool
@@ -187,7 +187,7 @@ func (auth *AuthService) RecordLoginAttempt(identifier string, success bool) {
187187
}
188188

189189
func (auth *AuthService) IsEmailWhitelisted(email string) bool {
190-
return utils.CheckFilter(auth.config.OauthWhitelist, email)
190+
return utils.CheckFilter(strings.Join(auth.config.OauthWhitelist, ","), email)
191191
}
192192

193193
func (auth *AuthService) CreateSessionCookie(c *gin.Context, data *config.SessionCookie) error {

internal/utils/user_utils.go

Lines changed: 41 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -7,87 +7,86 @@ import (
77
"github.com/steveiliop56/tinyauth/internal/config"
88
)
99

10-
func ParseUsers(users string) ([]config.User, error) {
11-
var usersParsed []config.User
10+
func ParseUsers(usersStr []string) ([]config.User, error) {
11+
var users []config.User
1212

13-
users = strings.TrimSpace(users)
14-
15-
if users == "" {
13+
if len(usersStr) == 0 {
1614
return []config.User{}, nil
1715
}
1816

19-
userList := strings.Split(users, ",")
20-
21-
if len(userList) == 0 {
22-
return []config.User{}, errors.New("invalid user format")
23-
}
24-
25-
for _, user := range userList {
17+
for _, user := range usersStr {
2618
if strings.TrimSpace(user) == "" {
2719
continue
2820
}
2921
parsed, err := ParseUser(strings.TrimSpace(user))
3022
if err != nil {
3123
return []config.User{}, err
3224
}
33-
usersParsed = append(usersParsed, parsed)
25+
users = append(users, parsed)
3426
}
3527

36-
return usersParsed, nil
28+
return users, nil
3729
}
3830

39-
func GetUsers(conf string, file string) ([]config.User, error) {
40-
var users string
31+
func GetUsers(usersCfg []string, usersPath string) ([]config.User, error) {
32+
var usersStr []string
4133

42-
if conf == "" && file == "" {
34+
if len(usersCfg) == 0 && usersPath == "" {
4335
return []config.User{}, nil
4436
}
4537

46-
if conf != "" {
47-
users += conf
38+
if len(usersCfg) > 0 {
39+
usersStr = append(usersStr, usersCfg...)
4840
}
4941

50-
if file != "" {
51-
contents, err := ReadFile(file)
42+
if usersPath != "" {
43+
contents, err := ReadFile(usersPath)
44+
5245
if err != nil {
5346
return []config.User{}, err
5447
}
55-
if users != "" {
56-
users += ","
48+
49+
lines := strings.SplitSeq(contents, "\n")
50+
51+
for line := range lines {
52+
lineTrimmed := strings.TrimSpace(line)
53+
if lineTrimmed == "" {
54+
continue
55+
}
56+
usersStr = append(usersStr, lineTrimmed)
5757
}
58-
users += ParseFileToLine(contents)
5958
}
6059

61-
return ParseUsers(users)
60+
return ParseUsers(usersStr)
6261
}
6362

64-
func ParseUser(user string) (config.User, error) {
65-
if strings.Contains(user, "$$") {
66-
user = strings.ReplaceAll(user, "$$", "$")
63+
func ParseUser(userStr string) (config.User, error) {
64+
if strings.Contains(userStr, "$$") {
65+
userStr = strings.ReplaceAll(userStr, "$$", "$")
6766
}
6867

69-
userSplit := strings.Split(user, ":")
68+
parts := strings.SplitN(userStr, ":", 4)
7069

71-
if len(userSplit) < 2 || len(userSplit) > 3 {
70+
if len(parts) < 2 || len(parts) > 3 {
7271
return config.User{}, errors.New("invalid user format")
7372
}
7473

75-
for _, userPart := range userSplit {
76-
if strings.TrimSpace(userPart) == "" {
74+
for i, part := range parts {
75+
trimmed := strings.TrimSpace(part)
76+
if trimmed == "" {
7777
return config.User{}, errors.New("invalid user format")
7878
}
79+
parts[i] = trimmed
80+
}
81+
82+
user := config.User{
83+
Username: parts[0],
84+
Password: parts[1],
7985
}
8086

81-
if len(userSplit) == 2 {
82-
return config.User{
83-
Username: strings.TrimSpace(userSplit[0]),
84-
Password: strings.TrimSpace(userSplit[1]),
85-
}, nil
87+
if len(parts) == 3 {
88+
user.TotpSecret = parts[2]
8689
}
8790

88-
return config.User{
89-
Username: strings.TrimSpace(userSplit[0]),
90-
Password: strings.TrimSpace(userSplit[1]),
91-
TotpSecret: strings.TrimSpace(userSplit[2]),
92-
}, nil
91+
return user, nil
9392
}

internal/utils/user_utils_test.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ func TestGetUsers(t *testing.T) {
2222
defer os.Remove("/tmp/tinyauth_users_test.txt")
2323

2424
// Test file
25-
users, err := utils.GetUsers("", "/tmp/tinyauth_users_test.txt")
25+
users, err := utils.GetUsers([]string{}, "/tmp/tinyauth_users_test.txt")
2626

2727
assert.NilError(t, err)
2828

@@ -34,7 +34,7 @@ func TestGetUsers(t *testing.T) {
3434
assert.Equal(t, "$2a$10$Mz5xhkfSJUtPWkzCd/TdaePh9CaXc5QcGII5wIMPLSR46eTwma30G", users[1].Password)
3535

3636
// Test config
37-
users, err = utils.GetUsers("user3:$2a$10$Mz5xhkfSJUtPWkzCd/TdaePh9CaXc5QcGII5wIMPLSR46eTwma30G,user4:$2a$10$Mz5xhkfSJUtPWkzCd/TdaePh9CaXc5QcGII5wIMPLSR46eTwma30G", "")
37+
users, err = utils.GetUsers([]string{"user3:$2a$10$Mz5xhkfSJUtPWkzCd/TdaePh9CaXc5QcGII5wIMPLSR46eTwma30G", "user4:$2a$10$Mz5xhkfSJUtPWkzCd/TdaePh9CaXc5QcGII5wIMPLSR46eTwma30G"}, "")
3838

3939
assert.NilError(t, err)
4040

@@ -46,7 +46,7 @@ func TestGetUsers(t *testing.T) {
4646
assert.Equal(t, "$2a$10$Mz5xhkfSJUtPWkzCd/TdaePh9CaXc5QcGII5wIMPLSR46eTwma30G", users[1].Password)
4747

4848
// Test both
49-
users, err = utils.GetUsers("user5:$2a$10$Mz5xhkfSJUtPWkzCd/TdaePh9CaXc5QcGII5wIMPLSR46eTwma30G", "/tmp/tinyauth_users_test.txt")
49+
users, err = utils.GetUsers([]string{"user5:$2a$10$Mz5xhkfSJUtPWkzCd/TdaePh9CaXc5QcGII5wIMPLSR46eTwma30G"}, "/tmp/tinyauth_users_test.txt")
5050

5151
assert.NilError(t, err)
5252

@@ -60,14 +60,14 @@ func TestGetUsers(t *testing.T) {
6060
assert.Equal(t, "$2a$10$Mz5xhkfSJUtPWkzCd/TdaePh9CaXc5QcGII5wIMPLSR46eTwma30G", users[2].Password)
6161

6262
// Test empty
63-
users, err = utils.GetUsers("", "")
63+
users, err = utils.GetUsers([]string{}, "")
6464

6565
assert.NilError(t, err)
6666

6767
assert.Equal(t, 0, len(users))
6868

6969
// Test non-existent file
70-
users, err = utils.GetUsers("", "/tmp/non_existent_file.txt")
70+
users, err = utils.GetUsers([]string{}, "/tmp/non_existent_file.txt")
7171

7272
assert.ErrorContains(t, err, "no such file or directory")
7373

@@ -76,7 +76,7 @@ func TestGetUsers(t *testing.T) {
7676

7777
func TestParseUsers(t *testing.T) {
7878
// Valid users
79-
users, err := utils.ParseUsers("user1:$2a$10$Mz5xhkfSJUtPWkzCd/TdaePh9CaXc5QcGII5wIMPLSR46eTwma30G,user2:$2a$10$Mz5xhkfSJUtPWkzCd/TdaePh9CaXc5QcGII5wIMPLSR46eTwma30G:ABCDEF") // user2 has TOTP
79+
users, err := utils.ParseUsers([]string{"user1:$2a$10$Mz5xhkfSJUtPWkzCd/TdaePh9CaXc5QcGII5wIMPLSR46eTwma30G", "user2:$2a$10$Mz5xhkfSJUtPWkzCd/TdaePh9CaXc5QcGII5wIMPLSR46eTwma30G:ABCDEF"}) // user2 has TOTP
8080

8181
assert.NilError(t, err)
8282

@@ -90,7 +90,7 @@ func TestParseUsers(t *testing.T) {
9090
assert.Equal(t, "ABCDEF", users[1].TotpSecret)
9191

9292
// Valid weirdly spaced users
93-
users, err = utils.ParseUsers(" user1:$2a$10$Mz5xhkfSJUtPWkzCd/TdaePh9CaXc5QcGII5wIMPLSR46eTwma30G , user2:$2a$10$Mz5xhkfSJUtPWkzCd/TdaePh9CaXc5QcGII5wIMPLSR46eTwma30G:ABCDEF ") // Spacing is on purpose
93+
users, err = utils.ParseUsers([]string{" user1:$2a$10$Mz5xhkfSJUtPWkzCd/TdaePh9CaXc5QcGII5wIMPLSR46eTwma30G ", " user2:$2a$10$Mz5xhkfSJUtPWkzCd/TdaePh9CaXc5QcGII5wIMPLSR46eTwma30G:ABCDEF "}) // Spacing is on purpose
9494
assert.NilError(t, err)
9595

9696
assert.Equal(t, 2, len(users))

0 commit comments

Comments
 (0)