Skip to content

Commit 57165c0

Browse files
committed
refactor: use more Go 1.26 features
1 parent 07cc857 commit 57165c0

19 files changed

Lines changed: 161 additions & 229 deletions

cmd/uncord/main.go

Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -198,18 +198,14 @@ func run() error {
198198
defer subCancel()
199199
var wg sync.WaitGroup
200200

201-
wg.Add(1)
202-
go func() {
203-
defer wg.Done()
201+
wg.Go(func() {
204202
blocklist.Run(subCtx, cfg.DisposableEmailBlocklistRefreshInterval)
205-
}()
203+
})
206204

207205
// The purge goroutine is started below after the attachment repository is initialised, because orphan attachment
208206
// cleanup needs access to the repo and storage provider.
209207
startPurgeGoroutine := func(attachRepo *attachment.PGRepository, storage media.StorageProvider) {
210-
wg.Add(1)
211-
go func() {
212-
defer wg.Done()
208+
wg.Go(func() {
213209
purgeExpiredData(subCtx, userRepo, attachRepo, storage, cfg)
214210

215211
ticker := time.NewTicker(cfg.DataCleanupInterval)
@@ -222,16 +218,14 @@ func run() error {
222218
purgeExpiredData(subCtx, userRepo, attachRepo, storage, cfg)
223219
}
224220
}
225-
}()
221+
})
226222
}
227223

228224
// Start permission cache invalidation subscriber with reconnection.
229225
permSub := permission.NewSubscriber(permCache, rdb, log.Logger)
230-
wg.Add(1)
231-
go func() {
232-
defer wg.Done()
226+
wg.Go(func() {
233227
runWithBackoff(subCtx, "permission-cache-subscriber", permSub.Run)
234-
}()
228+
})
235229

236230
// Load external templates from DATA_DIR (nil means use compiled-in defaults).
237231
verificationTmpl, verifyPageTmpl, err := loadTemplates(cfg.DataDir)
@@ -301,11 +295,9 @@ func run() error {
301295
// Start thumbnail worker with reconnection.
302296
thumbWorker := media.NewThumbnailWorker(rdb, storage, attachmentRepo, log.Logger)
303297
thumbWorker.EnsureStream(subCtx)
304-
wg.Add(1)
305-
go func() {
306-
defer wg.Done()
298+
wg.Go(func() {
307299
runWithBackoff(subCtx, "thumbnail-worker", thumbWorker.Run)
308-
}()
300+
})
309301
authService, err := auth.NewService(userRepo, rdb, cfg, blocklist, emailSender, serverRepo, permPublisher, log.Logger)
310302
if err != nil {
311303
return fmt.Errorf("create auth service: %w", err)
@@ -329,11 +321,9 @@ func run() error {
329321
DocumentStore: documentStore,
330322
Logger: log.Logger,
331323
})
332-
wg.Add(1)
333-
go func() {
334-
defer wg.Done()
324+
wg.Go(func() {
335325
runWithBackoff(subCtx, "gateway-hub", gatewayHub.Run)
336-
}()
326+
})
337327

338328
app := newFiberApp(cfg)
339329

@@ -704,11 +694,11 @@ func newFiberApp(cfg *config.Config) *fiber.App {
704694
// (e.g. Fiber's built-in 404/405). errors.AsType is a generic helper added in Go 1.26.
705695
ErrorHandler: func(c fiber.Ctx, err error) error {
706696
status := fiber.StatusInternalServerError
707-
message := "An internal error occurred"
697+
msg := "An internal error occurred"
708698
apiCode := apierrors.InternalError
709699
if e, ok := errors.AsType[*fiber.Error](err); ok {
710700
status = e.Code
711-
message = e.Message
701+
msg = e.Message
712702
apiCode = fiberStatusToAPICode(e.Code)
713703
} else {
714704
log.Error().Err(err).
@@ -719,7 +709,7 @@ func newFiberApp(cfg *config.Config) *fiber.App {
719709
return c.Status(status).JSON(httputil.ErrorResponse{
720710
Error: httputil.ErrorBody{
721711
Code: apiCode,
722-
Message: message,
712+
Message: msg,
723713
},
724714
})
725715
},

internal/api/invite_test.go

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"encoding/json"
66
"net/http"
7+
"slices"
78
"testing"
89
"time"
910

@@ -71,10 +72,7 @@ func (r *fakeInviteRepo) List(_ context.Context, after *uuid.UUID, limit int) ([
7172
if start >= len(r.invites) {
7273
return nil, nil
7374
}
74-
end := start + limit
75-
if end > len(r.invites) {
76-
end = len(r.invites)
77-
}
75+
end := min(start+limit, len(r.invites))
7876
return r.invites[start:end], nil
7977
}
8078

@@ -198,10 +196,8 @@ func newFakeInviteMemberRepo() *fakeInviteMemberRepo {
198196
}
199197

200198
func (r *fakeInviteMemberRepo) IsBanned(_ context.Context, userID uuid.UUID) (bool, error) {
201-
for _, id := range r.bans {
202-
if id == userID {
203-
return true, nil
204-
}
199+
if slices.Contains(r.bans, userID) {
200+
return true, nil
205201
}
206202
return false, nil
207203
}

internal/api/member_test.go

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"encoding/json"
66
"net/http"
7+
"slices"
78
"strings"
89
"testing"
910
"time"
@@ -44,10 +45,7 @@ func (r *fakeMemberRepo) List(_ context.Context, after *uuid.UUID, limit int) ([
4445
if start >= len(r.members) {
4546
return nil, nil
4647
}
47-
end := start + limit
48-
if end > len(r.members) {
49-
end = len(r.members)
50-
}
48+
end := min(start+limit, len(r.members))
5149
return r.members[start:end], nil
5250
}
5351

@@ -146,10 +144,7 @@ func (r *fakeMemberRepo) ListBans(_ context.Context, after *uuid.UUID, limit int
146144
if start >= len(r.bans) {
147145
return nil, nil
148146
}
149-
end := start + limit
150-
if end > len(r.bans) {
151-
end = len(r.bans)
152-
}
147+
end := min(start+limit, len(r.bans))
153148
return r.bans[start:end], nil
154149
}
155150

@@ -163,10 +158,8 @@ func (r *fakeMemberRepo) IsBanned(_ context.Context, userID uuid.UUID) (bool, er
163158
}
164159

165160
func (r *fakeMemberRepo) AssignRole(_ context.Context, userID, roleID uuid.UUID) error {
166-
for _, id := range r.roles[userID] {
167-
if id == roleID {
168-
return member.ErrAlreadyMember
169-
}
161+
if slices.Contains(r.roles[userID], roleID) {
162+
return member.ErrAlreadyMember
170163
}
171164
r.roles[userID] = append(r.roles[userID], roleID)
172165
// Update the member's RoleIDs so the re-fetched profile reflects the change.

internal/api/message_test.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -883,19 +883,20 @@ func TestCreateMessage_TooManyAttachments(t *testing.T) {
883883
userID := uuid.New()
884884

885885
// Create 11 IDs to exceed the limit of 10.
886-
ids := "["
886+
var ids strings.Builder
887+
ids.WriteString("[")
887888
for i := range 11 {
888889
if i > 0 {
889-
ids += ","
890+
ids.WriteString(",")
890891
}
891-
ids += `"` + uuid.New().String() + `"`
892+
ids.WriteString(`"` + uuid.New().String() + `"`)
892893
}
893-
ids += "]"
894+
ids.WriteString("]")
894895

895896
app := testMessageAppWithAttachments(t, msgRepo, attRepo, allowAllResolver(), userID)
896897

897898
resp := doReq(t, app, jsonReq(http.MethodPost, "/channels/"+channelID.String()+"/messages",
898-
`{"content":"hello","attachment_ids":`+ids+`}`))
899+
`{"content":"hello","attachment_ids":`+ids.String()+`}`))
899900
body := readBody(t, resp)
900901

901902
if resp.StatusCode != fiber.StatusBadRequest {

internal/auth/mfa_crypto.go

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,7 @@ func EncryptTOTPSecret(secret, hexKey string) (string, error) {
2929
}
3030

3131
nonce := make([]byte, gcm.NonceSize())
32-
if _, err := rand.Read(nonce); err != nil {
33-
return "", fmt.Errorf("generate nonce: %w", err)
34-
}
32+
_, _ = rand.Read(nonce)
3533

3634
ciphertext := gcm.Seal(nonce, nonce, []byte(secret), nil)
3735
return base64.StdEncoding.EncodeToString(ciphertext), nil
@@ -77,17 +75,15 @@ const recoveryCodeCount = 10
7775

7876
// GenerateRecoveryCodes generates a set of recovery codes in the format "xxxx-xxxx-xxxx-xxxx-xxxx" where each group is
7977
// 4 hex characters. Each code represents 10 random bytes (80 bits of entropy).
80-
func GenerateRecoveryCodes() ([]string, error) {
78+
func GenerateRecoveryCodes() []string {
8179
codes := make([]string, recoveryCodeCount)
8280
for i := range codes {
8381
b := make([]byte, 10)
84-
if _, err := rand.Read(b); err != nil {
85-
return nil, fmt.Errorf("generate recovery code: %w", err)
86-
}
82+
_, _ = rand.Read(b)
8783
h := hex.EncodeToString(b)
8884
codes[i] = h[:4] + "-" + h[4:8] + "-" + h[8:12] + "-" + h[12:16] + "-" + h[16:]
8985
}
90-
return codes, nil
86+
return codes
9187
}
9288

9389
// HashRecoveryCode hashes a recovery code using the same Argon2id parameters as passwords. The hyphen is stripped

internal/auth/mfa_crypto_test.go

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,7 @@ func TestEncryptTOTPSecretInvalidKey(t *testing.T) {
6565
func TestGenerateRecoveryCodes(t *testing.T) {
6666
t.Parallel()
6767

68-
codes, err := GenerateRecoveryCodes()
69-
if err != nil {
70-
t.Fatalf("GenerateRecoveryCodes() error = %v", err)
71-
}
68+
codes := GenerateRecoveryCodes()
7269
if len(codes) != recoveryCodeCount {
7370
t.Fatalf("GenerateRecoveryCodes() returned %d codes, want %d", len(codes), recoveryCodeCount)
7471
}

internal/auth/mfa_pending_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ func TestResetMFASetupAttempts(t *testing.T) {
145145
ctx := context.Background()
146146
userID := uuid.New()
147147

148-
for i := 0; i < 3; i++ {
148+
for range 3 {
149149
if _, err := IncrementMFASetupAttempts(ctx, rdb, userID); err != nil {
150150
t.Fatalf("IncrementMFASetupAttempts() error = %v", err)
151151
}

internal/auth/service.go

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -166,10 +166,7 @@ func (s *Service) Register(ctx context.Context, req RegisterRequest) (*AuthResul
166166
return nil, fmt.Errorf("hash password: %w", err)
167167
}
168168

169-
verifyToken, err := generateSecureToken(verifyTokenBytes)
170-
if err != nil {
171-
return nil, fmt.Errorf("generate verification token: %w", err)
172-
}
169+
verifyToken := generateSecureToken(verifyTokenBytes)
173170

174171
userID, err := s.users.Create(ctx, user.CreateParams{
175172
Email: email,
@@ -330,10 +327,7 @@ func (s *Service) ResendVerification(ctx context.Context, userID uuid.UUID) erro
330327
return ErrEmailAlreadyVerified
331328
}
332329

333-
verifyToken, err := generateSecureToken(verifyTokenBytes)
334-
if err != nil {
335-
return fmt.Errorf("generate verification token: %w", err)
336-
}
330+
verifyToken := generateSecureToken(verifyTokenBytes)
337331

338332
err = s.users.ReplaceVerificationToken(ctx, userID, verifyToken, time.Now().Add(24*time.Hour), 60*time.Second)
339333
if err != nil {
@@ -487,10 +481,7 @@ func (s *Service) ConfirmMFASetup(ctx context.Context, userID uuid.UUID, code st
487481
return nil, ErrInvalidMFACode
488482
}
489483

490-
codes, err := GenerateRecoveryCodes()
491-
if err != nil {
492-
return nil, fmt.Errorf("generate recovery codes: %w", err)
493-
}
484+
codes := GenerateRecoveryCodes()
494485

495486
hashes := make([]string, len(codes))
496487
for i, c := range codes {
@@ -580,10 +571,7 @@ func (s *Service) RegenerateRecoveryCodes(ctx context.Context, userID uuid.UUID,
580571
return nil, ErrMFANotEnabled
581572
}
582573

583-
codes, err := GenerateRecoveryCodes()
584-
if err != nil {
585-
return nil, fmt.Errorf("generate recovery codes: %w", err)
586-
}
574+
codes := GenerateRecoveryCodes()
587575

588576
hashes := make([]string, len(codes))
589577
for i, c := range codes {
@@ -753,10 +741,8 @@ func (s *Service) recordLoginAttempt(ctx context.Context, email, ip string, succ
753741
}
754742
}
755743

756-
func generateSecureToken(n int) (string, error) {
744+
func generateSecureToken(n int) string {
757745
b := make([]byte, n)
758-
if _, err := rand.Read(b); err != nil {
759-
return "", err
760-
}
761-
return hex.EncodeToString(b), nil
746+
_, _ = rand.Read(b)
747+
return hex.EncodeToString(b)
762748
}

internal/category/category_test.go

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@ func TestValidateName(t *testing.T) {
1515
wantErr bool
1616
}{
1717
{"nil", nil, false},
18-
{"empty after trim", ptr(" "), true},
19-
{"one char", ptr("A"), false},
20-
{"100 chars", ptr(strings.Repeat("a", 100)), false},
21-
{"101 chars", ptr(strings.Repeat("a", 101)), true},
22-
{"whitespace padded valid", ptr(" hello "), false},
18+
{"empty after trim", new(" "), true},
19+
{"one char", new("A"), false},
20+
{"100 chars", new(strings.Repeat("a", 100)), false},
21+
{"101 chars", new(strings.Repeat("a", 101)), true},
22+
{"whitespace padded valid", new(" hello "), false},
2323
}
2424

2525
for _, tt := range tests {
@@ -37,7 +37,7 @@ func TestValidateName(t *testing.T) {
3737

3838
t.Run("trims whitespace in place", func(t *testing.T) {
3939
t.Parallel()
40-
name := ptr(" hello ")
40+
name := new(" hello ")
4141
if err := ValidateName(name); err != nil {
4242
t.Fatalf("unexpected error: %v", err)
4343
}
@@ -87,9 +87,9 @@ func TestValidatePosition(t *testing.T) {
8787
wantErr bool
8888
}{
8989
{"nil", nil, false},
90-
{"zero", intPtr(0), false},
91-
{"positive", intPtr(5), false},
92-
{"negative", intPtr(-1), true},
90+
{"zero", new(0), false},
91+
{"positive", new(5), false},
92+
{"negative", new(-1), true},
9393
}
9494

9595
for _, tt := range tests {
@@ -105,6 +105,3 @@ func TestValidatePosition(t *testing.T) {
105105
})
106106
}
107107
}
108-
109-
func ptr(s string) *string { return &s }
110-
func intPtr(n int) *int { return &n }

0 commit comments

Comments
 (0)