Skip to content
This repository was archived by the owner on Jul 12, 2023. It is now read-only.

Commit 7684903

Browse files
authored
Fix NPE when queue is full (#2307)
1 parent a96fbc5 commit 7684903

File tree

2 files changed

+96
-1
lines changed

2 files changed

+96
-1
lines changed

pkg/controller/issueapi/send_sms.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ func (c *Controller) SendSMS(ctx context.Context, realm *database.Realm, smsProv
7373
if err := c.doSend(ctx, realm, smsProvider, signer, keyID, request, result); err != nil {
7474
result.HTTPCode = http.StatusBadRequest
7575
if sms.IsSMSQueueFull(err) {
76-
result.ErrorReturn = result.ErrorReturn.WithCode(api.ErrSMSQueueFull)
76+
result.ErrorReturn = api.Errorf("failed to send sms: queue is full: %s", err).WithCode(api.ErrSMSQueueFull)
7777
} else {
7878
result.ErrorReturn = api.Errorf("failed to send sms: %s", err).WithCode(api.ErrSMSFailure)
7979
}

pkg/controller/issueapi/send_sms_test.go

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"fmt"
2323
"io"
2424
"net/http"
25+
"os"
2526
"strings"
2627
"testing"
2728
"time"
@@ -219,3 +220,97 @@ func TestSMS_sendSMS(t *testing.T) {
219220
t.Errorf("expected SMS failure to roll-back and delete code. got %v", err)
220221
}
221222
}
223+
224+
func TestSMS_sendSMS_integration(t *testing.T) {
225+
t.Parallel()
226+
227+
if testing.Short() {
228+
t.Skipf("🚧 Skipping twilio tests (short)!")
229+
}
230+
231+
accountSid := os.Getenv("TWILIO_ACCOUNT_SID")
232+
authToken := os.Getenv("TWILIO_AUTH_TOKEN")
233+
if accountSid == "" || authToken == "" {
234+
t.Skipf("🚧 🚧 Skipping twilio tests (missing TWILIO_ACCOUNT_SID/TWILIO_AUTH_TOKEN)")
235+
}
236+
237+
ctx := project.TestContext(t)
238+
239+
harness := envstest.NewServerConfig(t, testDatabaseInstance)
240+
db := harness.Database
241+
242+
realm, err := db.FindRealm(1)
243+
if err != nil {
244+
t.Fatal(err)
245+
}
246+
realm.AllowBulkUpload = true
247+
if err := db.SaveRealm(realm, database.SystemTest); err != nil {
248+
t.Fatalf("failed to save realm: %v", err)
249+
}
250+
251+
smsConfig := &database.SMSConfig{
252+
RealmID: realm.ID,
253+
ProviderType: sms.ProviderTypeTwilio,
254+
TwilioAccountSid: accountSid,
255+
TwilioFromNumber: "+15005550008", // magic number
256+
TwilioAuthToken: authToken,
257+
}
258+
if err := db.SaveSMSConfig(smsConfig); err != nil {
259+
t.Fatal(err)
260+
}
261+
262+
smsProvider, err := realm.SMSProvider(harness.Database)
263+
if err != nil {
264+
t.Fatal(err)
265+
}
266+
267+
membership := &database.Membership{
268+
RealmID: realm.ID,
269+
Realm: realm,
270+
Permissions: rbac.CodeBulkIssue,
271+
}
272+
273+
ctx = controller.WithMembership(ctx, membership)
274+
275+
harness.Config.SMSSigning.FailClosed = true
276+
c := issueapi.New(harness.Config, db, harness.RateLimiter, harness.KeyManager, harness.Renderer)
277+
278+
t.Run("queue_full", func(t *testing.T) {
279+
t.Parallel()
280+
281+
request := &api.IssueCodeRequest{
282+
TestType: "confirmed",
283+
SymptomDate: time.Now().UTC().Add(-48 * time.Hour).Format(project.RFC3339Date),
284+
TZOffset: 0,
285+
Phone: project.TestPhoneNumber,
286+
}
287+
result := &issueapi.IssueResult{
288+
HTTPCode: http.StatusOK,
289+
VerCode: &database.VerificationCode{
290+
RealmID: realm.ID,
291+
Code: "00000001",
292+
LongCode: "00000001ABC",
293+
Claimed: true,
294+
TestType: "confirmed",
295+
ExpiresAt: time.Now().Add(time.Hour),
296+
LongExpiresAt: time.Now().Add(time.Hour),
297+
},
298+
}
299+
if err := realm.SaveVerificationCode(db, result.VerCode); err != nil {
300+
t.Fatal(err)
301+
}
302+
// un-hmac the codes so rollback can find them.
303+
result.VerCode.Code = "00000001"
304+
result.VerCode.LongCode = "00000001ABC"
305+
306+
c.SendSMS(ctx, realm, smsProvider, nil, "", request, result)
307+
if result.ErrorReturn == nil {
308+
t.Fatal("expected failed SMS, but got no error response")
309+
} else if result.ErrorReturn.ErrorCode != api.ErrSMSQueueFull {
310+
t.Fatal("expected SMS failure code")
311+
}
312+
if _, err := realm.FindVerificationCodeByUUID(db, result.VerCode.UUID); !database.IsNotFound(err) {
313+
t.Errorf("expected SMS failure to roll-back and delete code. got %v", err)
314+
}
315+
})
316+
}

0 commit comments

Comments
 (0)