70 lines
2.2 KiB
Go
70 lines
2.2 KiB
Go
package onboarding
|
|||
|
|
|
||
|
|
import (
|
||
|
|
"testing"
|
||
|
|
|
||
|
|
"github.com/google/uuid"
|
||
|
|
)
|
||
|
|
|
||
|
|
func TestSMSLoginSelectsRegistrationOrExistingAccountTemplate(t *testing.T) {
|
||
|
|
for _, registered := range []bool{false, true} {
|
||
|
|
name := "register"
|
||
|
|
if registered {
|
||
|
|
name = "login"
|
||
|
|
}
|
||
|
|
t.Run(name, func(t *testing.T) {
|
||
|
|
f := newLoginFixture(t)
|
||
|
|
if registered {
|
||
|
|
_, err := f.s.pool.Exec(f.ctx, `INSERT INTO customer_phone_credential(phone_digest,phone_masked,issuer,subject) VALUES($1,$2,$3,$4)`, domainMAC(f.s.crypt.hashKey, "PHONE1\n"+f.phone), "+86138****0000", f.user.Issuer, f.user.Subject)
|
||
|
|
must(t, err)
|
||
|
|
}
|
||
|
|
f.send()
|
||
|
|
want := SMSPurposeRegister
|
||
|
|
if registered {
|
||
|
|
want = SMSPurposeLogin
|
||
|
|
}
|
||
|
|
if f.sender.purpose != want {
|
||
|
|
t.Fatalf("expected %s, got %s", want, f.sender.purpose)
|
||
|
|
}
|
||
|
|
})
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestSMSPasswordPurposeAndIdempotencyAreBoundTogether(t *testing.T) {
|
||
|
|
f := newLoginFixture(t)
|
||
|
|
in := f.smsInput()
|
||
|
|
in.Purpose = SMSPurposeChangePassword
|
||
|
|
id := uuid.NewString()
|
||
|
|
w, first := f.request("POST", "/api/v1/web/login/sms/send", in, f.cookie, f.csrf, id)
|
||
|
|
if w.Code != 200 || f.sender.purpose != SMSPurposeChangePassword {
|
||
|
|
t.Fatal("wrong password template", w.Body.String())
|
||
|
|
}
|
||
|
|
w, again := f.request("POST", "/api/v1/web/login/sms/send", in, f.cookie, f.csrf, id)
|
||
|
|
if w.Code != 200 || first["sms_challenge_id"] != again["sms_challenge_id"] || f.sender.calls != 1 {
|
||
|
|
t.Fatal("replay sent a second message", w.Body.String())
|
||
|
|
}
|
||
|
|
in.Purpose = SMSPurposeLogin
|
||
|
|
w, _ = f.request("POST", "/api/v1/web/login/sms/send", in, f.cookie, f.csrf, id)
|
||
|
|
if w.Code != 409 || f.sender.calls != 1 {
|
||
|
|
t.Fatal("request ID reused across purposes", w.Body.String())
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestSMSLoginRejectsPhoneChangePurpose(t *testing.T) {
|
||
|
|
f := newLoginFixture(t)
|
||
|
|
in := f.smsInput()
|
||
|
|
in.Purpose = SMSPurposeChangePhone
|
||
|
|
w, _ := f.request("POST", "/api/v1/web/login/sms/send", in, f.cookie, f.csrf, "")
|
||
|
|
if w.Code != 400 || f.sender.calls != 0 {
|
||
|
|
t.Fatal("phone change accepted by login", w.Body.String())
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestSMSOperatorAlwaysUsesLoginTemplate(t *testing.T) {
|
||
|
|
f := newOperatorLoginFixture(t)
|
||
|
|
f.send()
|
||
|
|
if f.sender.purpose != SMSPurposeLogin {
|
||
|
|
t.Fatal("unprovisioned operator received a registration message")
|
||
|
|
}
|
||
|
|
}
|