Skip to content

Commit 963b512

Browse files
committed
fix: reject malformed email whitespace
1 parent 95a5b3d commit 963b512

5 files changed

Lines changed: 59 additions & 5 deletions

File tree

apis/schemas_test.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ import (
44
"encoding/json"
55
"fmt"
66
"testing"
7+
8+
"github.com/opentreehole/go-common"
9+
10+
"auth_next/config"
711
)
812

913
type VerificationModel struct {
@@ -26,3 +30,24 @@ func TestVerificationModel(t *testing.T) {
2630
fmt.Println(model.Verification)
2731
}
2832
}
33+
34+
func TestRegisterRequestRejectsWhitespaceEmail(t *testing.T) {
35+
config.Config.EmailWhitelist = []string{"fudan.edu.cn", "m.fudan.edu.cn"}
36+
37+
for _, email := range []string{
38+
" student001@m.fudan.edu.cn",
39+
"student002 @m.fudan.edu.cn",
40+
"\tstudent003@fudan.edu.cn",
41+
} {
42+
body := RegisterRequest{
43+
LoginRequest: LoginRequest{
44+
EmailModel: EmailModel{Email: email},
45+
Password: "password123",
46+
},
47+
Verification: "000000",
48+
}
49+
if err := common.ValidateStruct(body); err == nil {
50+
t.Fatalf("expected validation error for email %q", email)
51+
}
52+
}
53+
}

apis/shamir.go

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import (
1111
"sync"
1212

1313
"github.com/ProtonMail/gopenpgp/v2/crypto"
14-
"github.com/go-playground/validator/v10"
1514
"github.com/gofiber/fiber/v2"
1615
"github.com/opentreehole/go-common"
1716
"github.com/rs/zerolog/log"
@@ -796,11 +795,10 @@ func decryptEmailWithThreshold(shares shamir.Shares, threshold int) (string, boo
796795
return "", false
797796
}
798797

799-
validate := validator.New()
800798
var result string
801799
ok := forEachShareCombination(n, threshold, func(selected []int) bool {
802800
email := shamir.Decrypt(selectedShares(shares, selected))
803-
if validate.Var(email, "required,email") == nil {
801+
if utils.ValidateEmail(email) {
804802
result = email
805803
return false
806804
}
@@ -822,15 +820,14 @@ func decryptUserEmailWithThreshold(userID int, shares shamir.Shares, identityNam
822820
return DecryptedUserEmailResponse{}, false
823821
}
824822

825-
validate := validator.New()
826823
var result DecryptedUserEmailResponse
827824
ok := forEachShareCombination(n, threshold, func(selected []int) bool {
828825
response := DecryptedUserEmailResponse{
829826
UserID: userID,
830827
UserEmail: shamir.Decrypt(selectedShares(shares, selected)),
831828
IdentityNames: selectedIdentityNames(identityNames, selected),
832829
}
833-
if validate.Struct(response) == nil {
830+
if utils.ValidateEmail(response.UserEmail) {
834831
result = response
835832
return false
836833
}

apis/shamir_test.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ import (
1818
)
1919

2020
func TestDecryptUserEmailWithThresholdSkipsBadShare(t *testing.T) {
21+
allowAnyEmailDomain(t)
22+
2123
const email = "test@example.com"
2224

2325
shares, err := shamir.Encrypt(email, 5, 4)
@@ -45,6 +47,8 @@ func TestDecryptUserEmailWithThresholdSkipsBadShare(t *testing.T) {
4547
}
4648

4749
func TestDecryptUserEmailWithThreeOfFive(t *testing.T) {
50+
allowAnyEmailDomain(t)
51+
4852
const email = "test@example.com"
4953

5054
shares, err := shamir.Encrypt(email, 5, 3)
@@ -87,15 +91,18 @@ func TestUpdateShamirPersistsFiveKeyLocalSQLite(t *testing.T) {
8791
oldDB := models.DB
8892
oldPublicKeys := models.ShamirPublicKeys
8993
oldShamirFeature := config.Config.ShamirFeature
94+
oldEmailWhitelist := config.Config.EmailWhitelist
9095
t.Cleanup(func() {
9196
models.DB = oldDB
9297
models.ShamirPublicKeys = oldPublicKeys
9398
config.Config.ShamirFeature = oldShamirFeature
99+
config.Config.EmailWhitelist = oldEmailWhitelist
94100
InitShamirStatus()
95101
})
96102

97103
models.DB = db
98104
config.Config.ShamirFeature = true
105+
config.Config.EmailWhitelist = nil
99106

100107
publicKeys, privateKeyRings := generateTestKeySet(t, 7)
101108
models.ShamirPublicKeys = publicKeys
@@ -217,15 +224,18 @@ func TestUpdateShamirInvalidShareDoesNotPanic(t *testing.T) {
217224
oldDB := models.DB
218225
oldPublicKeys := models.ShamirPublicKeys
219226
oldShamirFeature := config.Config.ShamirFeature
227+
oldEmailWhitelist := config.Config.EmailWhitelist
220228
t.Cleanup(func() {
221229
models.DB = oldDB
222230
models.ShamirPublicKeys = oldPublicKeys
223231
config.Config.ShamirFeature = oldShamirFeature
232+
config.Config.EmailWhitelist = oldEmailWhitelist
224233
InitShamirStatus()
225234
})
226235

227236
models.DB = db
228237
config.Config.ShamirFeature = true
238+
config.Config.EmailWhitelist = nil
229239

230240
publicKeys, _ := generateTestKeySet(t, 5)
231241
models.ShamirPublicKeys = publicKeys
@@ -297,15 +307,18 @@ func TestUpdateShamirPartialUpdateAllowedAtNinetyNinePercent(t *testing.T) {
297307
oldDB := models.DB
298308
oldPublicKeys := models.ShamirPublicKeys
299309
oldShamirFeature := config.Config.ShamirFeature
310+
oldEmailWhitelist := config.Config.EmailWhitelist
300311
t.Cleanup(func() {
301312
models.DB = oldDB
302313
models.ShamirPublicKeys = oldPublicKeys
303314
config.Config.ShamirFeature = oldShamirFeature
315+
config.Config.EmailWhitelist = oldEmailWhitelist
304316
InitShamirStatus()
305317
})
306318

307319
models.DB = db
308320
config.Config.ShamirFeature = true
321+
config.Config.EmailWhitelist = nil
309322

310323
publicKeys, _ := generateTestKeySet(t, 5)
311324
models.ShamirPublicKeys = publicKeys
@@ -430,6 +443,16 @@ func generateTestKeySet(t *testing.T, n int) ([]models.ShamirPublicKey, []*crypt
430443
return publicKeys, privateKeyRings
431444
}
432445

446+
func allowAnyEmailDomain(t *testing.T) {
447+
t.Helper()
448+
449+
oldEmailWhitelist := config.Config.EmailWhitelist
450+
config.Config.EmailWhitelist = nil
451+
t.Cleanup(func() {
452+
config.Config.EmailWhitelist = oldEmailWhitelist
453+
})
454+
}
455+
433456
func decryptTestShare(privateKeyRing *crypto.KeyRing, armoredPGPMessage string) (shamir.Share, error) {
434457
pgpMessage, err := crypto.NewPGPMessageFromArmored(armoredPGPMessage)
435458
if err != nil {

utils/validate.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ func init() {
2020
}
2121

2222
func ValidateEmail(email string) bool {
23+
if err := common.Validate.Var(email, "required,email"); err != nil {
24+
return false
25+
}
26+
2327
emailSplit := strings.Split(email, "@")
2428
if len(emailSplit) != 2 {
2529
return false

utils/validate_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ func TestValidateEmail(t *testing.T) {
1515
assert.Equal(t, ValidateEmail("abcd@fudan.edu.cn"), true)
1616
assert.Equal(t, ValidateEmail("abcd@qq.com"), false)
1717
assert.Equal(t, ValidateEmail("123345"), false)
18+
assert.Equal(t, ValidateEmail(" abcd@fudan.edu.cn"), false)
19+
assert.Equal(t, ValidateEmail("abcd @fudan.edu.cn"), false)
20+
assert.Equal(t, ValidateEmail("\tabcd@fudan.edu.cn"), false)
1821
}
1922

2023
func TestValidateEmailFudan(t *testing.T) {
@@ -32,4 +35,6 @@ func TestValidateAll(t *testing.T) {
3235
config.Config.EmailWhitelist = []string{"fudan.edu.cn", "m.fudan.edu.cn"}
3336
err := common.ValidateStruct(TempStruct{Email: "abcd@fudan.edu.cn"})
3437
assert.Equal(t, err, nil)
38+
err = common.ValidateStruct(TempStruct{Email: " abcd@fudan.edu.cn"})
39+
assert.NotEqual(t, err, nil)
3540
}

0 commit comments

Comments
 (0)