diff --git a/verify.go b/verify.go index 63cb7a5..c1d42f7 100644 --- a/verify.go +++ b/verify.go @@ -3,12 +3,20 @@ package vonage import ( "context" "encoding/json" + "fmt" "io/ioutil" "github.com/antihax/optional" "github.com/vonage/vonage-go-sdk/internal/verify" ) +const ( + verifyPinExpiryMax = 3600 + verifyPinExpiryMin = 60 + verifyNextEventWaitMax = 900 + verifyNextEventWaitMin = 60 +) + // VerifyClient for working with the Verify API type VerifyClient struct { Config *verify.Configuration @@ -75,6 +83,48 @@ func (client *VerifyClient) Request(number string, brand string, opts VerifyOpts verifyOpts.SenderId = optional.NewString(opts.SenderID) } + if opts.PinExpiry != 0 { + if opts.PinExpiry < verifyPinExpiryMin || opts.PinExpiry > verifyPinExpiryMax { + err := fmt.Errorf( + "bad option value: PinExpiry must be between %d and %d, but %d was given", + verifyPinExpiryMin, + verifyPinExpiryMax, + opts.PinExpiry, + ) + return VerifyRequestResponse{}, VerifyErrorResponse{}, err + } + if opts.NextEventWait != 0 { + m := opts.PinExpiry % opts.NextEventWait + if m != 0 { + err := fmt.Errorf( + "bad option value: PinExpiry must be an integer multiple of NextEventWait, but PinExpiry = %d, NextEventWait = %d", + opts.PinExpiry, + opts.NextEventWait, + ) + return VerifyRequestResponse{}, VerifyErrorResponse{}, err + } + } + verifyOpts.PinExpiry = optional.NewInt32(opts.PinExpiry) + } + + if opts.NextEventWait != 0 { + if opts.NextEventWait < verifyNextEventWaitMin || opts.NextEventWait > verifyNextEventWaitMax { + err := fmt.Errorf( + "bad option value: NextEventWait must be between %d and %d, but %d was given", + verifyNextEventWaitMin, + verifyNextEventWaitMax, + opts.NextEventWait, + ) + return VerifyRequestResponse{}, VerifyErrorResponse{}, err + } + verifyOpts.NextEventWait = optional.NewInt32(opts.NextEventWait) + if opts.PinExpiry == 0 { + // when NextEventWait is specified and PinExpiry is not, + // PinExpiry is defaulted to equal NextEventWait. + verifyOpts.PinExpiry = optional.NewInt32(opts.NextEventWait) + } + } + ctx := context.Background() result, resp, err := verifyClient.DefaultApi.VerifyRequest(ctx, "json", client.apiKey, client.apiSecret, number, brand, &verifyOpts) diff --git a/verify_test.go b/verify_test.go index 6ccc81f..257884f 100644 --- a/verify_test.go +++ b/verify_test.go @@ -441,3 +441,51 @@ func TestVerifyPsd2Request(t *testing.T) { t.Errorf("Verify request failed") } } + +func TestVerifyRequestPinExpiryFail(t *testing.T) { + httpmock.Activate() + defer httpmock.DeactivateAndReset() + + httpmock.RegisterResponder("POST", "https://api.nexmo.com/verify/json", + func(req *http.Request) (*http.Response, error) { + resp := httpmock.NewStringResponse(200, ` + { + "request_id": "abcdef0123456789abcdef0123456789", + "status": "0" + } + `, + ) + + resp.Header.Add("Content-Type", "application/json") + return resp, nil + }, + ) + + auth := CreateAuthFromKeySecret("12345678", "456") + client := NewVerifyClient(auth) + tests := []struct { + name string + expiry int32 + next int32 + wantError bool + }{ + {"success", verifyPinExpiryMax, 0, false}, + {"success", verifyPinExpiryMin, 0, false}, + {"success", 2 * verifyNextEventWaitMax, verifyNextEventWaitMax, false}, + {"expiry is too big", verifyPinExpiryMax + 1, 0, true}, + {"expiry is too small", verifyPinExpiryMin - 1, 0, true}, + {"expiry is not an integer multiple of nextEventWait", 2*verifyNextEventWaitMax - 1, verifyNextEventWaitMax, true}, + {"success", 0, verifyNextEventWaitMax, false}, + {"success", 0, verifyNextEventWaitMin, false}, + {"nextEventWait it too big", 0, verifyNextEventWaitMax + 1, true}, + {"nextEventWait is too small", 0, verifyNextEventWaitMin - 1, true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + _, _, err := client.Request("44777000777", "VonageGoTest", VerifyOpts{PinExpiry: tt.expiry, NextEventWait: tt.next}) + if (err != nil) != tt.wantError { + t.Errorf("%s: %s", tt.name, err) + } + }) + } +}