Skip to content

Commit

Permalink
Merge pull request #1125 from sundowndev/fix/numverify-scanner
Browse files Browse the repository at this point in the history
Fix numverify scanner
  • Loading branch information
sundowndev authored Sep 5, 2022
2 parents f336b2c + c18a461 commit 6be6afb
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 98 deletions.
8 changes: 6 additions & 2 deletions docs/getting-started/scanners.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,17 @@ The local scan is probably the simplest scan of PhoneInfoga. By default, the too

Numverify provide standard but useful information such as country code, location, line type and carrier. This scanners requires an API-key which you can get on their website after creating an account. You can use a free API key as long as you don't exceed the monthly quota.

[Read documentation](https://apilayer.com/marketplace/number_verification-api#details-tab)

??? info "Configuration"

1. Go to the [Api layer website](https://apilayer.com/) and create an account
2. Go to "Number Verification API" in the marketplace, click on "Subscribe for free", then choose whatever plan you want
3. Copy the new API token and use it as an environment variable

| Environment variable | Default | Description |
|----------------------|---------|------------------------------------------------------------------------|
| NUMVERIFY_API_KEY | | API key to authenticate to the Numverify API. |
| NUMVERIFY_ENABLE_SSL | false | Whether to use HTTPS or plain HTTP for requests to the Numverify API. |

??? example "Output example"

Expand All @@ -60,7 +65,6 @@ Numverify provide standard but useful information such as country code, location
Country prefix: +41
Country code: CH
Country name: Switzerland (Confederation of)
Location:
Carrier: Sunrise Communications AG
Line type: mobile
```
Expand Down
18 changes: 9 additions & 9 deletions lib/remote/numverify_scanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ type numverifyScanner struct {

type NumverifyScannerResponse struct {
Valid bool `json:"valid" console:"Valid"`
Number string `json:"number" console:"Number"`
LocalFormat string `json:"local_format" console:"Local format"`
InternationalFormat string `json:"international_format" console:"International format"`
CountryPrefix string `json:"country_prefix" console:"Country prefix"`
CountryCode string `json:"country_code" console:"Country code"`
CountryName string `json:"country_name" console:"Country name"`
Location string `json:"location" console:"Location"`
Carrier string `json:"carrier" console:"Carrier"`
LineType string `json:"line_type" console:"Line type"`
Number string `json:"number" console:"Number,omitempty"`
LocalFormat string `json:"local_format" console:"Local format,omitempty"`
InternationalFormat string `json:"international_format" console:"International format,omitempty"`
CountryPrefix string `json:"country_prefix" console:"Country prefix,omitempty"`
CountryCode string `json:"country_code" console:"Country code,omitempty"`
CountryName string `json:"country_name" console:"Country name,omitempty"`
Location string `json:"location" console:"Location,omitempty"`
Carrier string `json:"carrier" console:"Carrier,omitempty"`
LineType string `json:"line_type" console:"Line type,omitempty"`
}

func NewNumverifyScanner(s suppliers.NumverifySupplierInterface) Scanner {
Expand Down
53 changes: 23 additions & 30 deletions lib/remote/suppliers/numverify.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,35 +15,31 @@ type NumverifySupplierInterface interface {
Validate(string) (*NumverifyValidateResponse, error)
}

type numverifyError struct {
Code int `json:"code"`
Info string `json:"info"`
type NumverifyErrorResponse struct {
Message string `json:"message"`
}

// NumverifyValidateResponse REST API response
type NumverifyValidateResponse struct {
Valid bool `json:"valid"`
Number string `json:"number"`
LocalFormat string `json:"local_format"`
InternationalFormat string `json:"international_format"`
CountryPrefix string `json:"country_prefix"`
CountryCode string `json:"country_code"`
CountryName string `json:"country_name"`
Location string `json:"location"`
Carrier string `json:"carrier"`
LineType string `json:"line_type"`
Error numverifyError `json:"error"`
Valid bool `json:"valid"`
Number string `json:"number"`
LocalFormat string `json:"local_format"`
InternationalFormat string `json:"international_format"`
CountryPrefix string `json:"country_prefix"`
CountryCode string `json:"country_code"`
CountryName string `json:"country_name"`
Location string `json:"location"`
Carrier string `json:"carrier"`
LineType string `json:"line_type"`
}

type NumverifySupplier struct {
ApiKey string
EnableSSL string
ApiKey string
}

func NewNumverifySupplier() *NumverifySupplier {
return &NumverifySupplier{
ApiKey: os.Getenv("NUMVERIFY_API_KEY"),
EnableSSL: os.Getenv("NUMVERIFY_ENABLE_SSL"),
ApiKey: os.Getenv("NUMVERIFY_API_KEY"),
}
}

Expand All @@ -52,18 +48,11 @@ func (s *NumverifySupplier) IsAvailable() bool {
}

func (s *NumverifySupplier) Validate(internationalNumber string) (res *NumverifyValidateResponse, err error) {
scheme := "http"

if s.EnableSSL != "" {
scheme = "https"
}

logrus.
WithField("number", internationalNumber).
WithField("scheme", scheme).
Debug("Running validate operation through Numverify API")

url := fmt.Sprintf("%s://api.apilayer.com/number_verification/validate?number=%s", scheme, internationalNumber)
url := fmt.Sprintf("https://api.apilayer.com/number_verification/validate?number=%s", internationalNumber)

// Build the request
client := &http.Client{}
Expand All @@ -80,15 +69,19 @@ func (s *NumverifySupplier) Validate(internationalNumber string) (res *Numverify
// Fill the response with the data from the JSON
var result NumverifyValidateResponse

if response.StatusCode >= 400 {
errorResponse := NumverifyErrorResponse{}
if err := json.NewDecoder(response.Body).Decode(&errorResponse); err != nil {
return nil, err
}
return nil, errors.New(errorResponse.Message)
}

// Use json.Decode for reading streams of JSON data
if err := json.NewDecoder(response.Body).Decode(&result); err != nil {
return nil, err
}

if len(result.Error.Info) > 0 {
return nil, errors.New(result.Error.Info)
}

res = &NumverifyValidateResponse{
Valid: result.Valid,
Number: result.Number,
Expand Down
62 changes: 8 additions & 54 deletions lib/remote/suppliers/numverify_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@ func TestNumverifySupplierSuccess(t *testing.T) {
number := "11115551212"

_ = os.Setenv("NUMVERIFY_API_KEY", "5ad5554ac240e4d3d31107941b35a5eb")
_ = os.Setenv("NUMVERIFY_ENABLE_SSL", "1")
defer os.Setenv("NUMVERIFY_API_KEY", "")
defer os.Setenv("NUMVERIFY_ENABLE_SSL", "")
defer os.Clearenv()

expectedResult := &NumverifyValidateResponse{
Valid: true,
Expand Down Expand Up @@ -49,65 +47,23 @@ func TestNumverifySupplierSuccess(t *testing.T) {
assert.Equal(t, expectedResult, got)
}

func TestNumverifySupplierWithoutSSL(t *testing.T) {
defer gock.Off() // Flush pending mocks after test execution

number := "11115551212"

_ = os.Setenv("NUMVERIFY_API_KEY", "5ad5554ac240e4d3d31107941b35a5eb")
defer os.Setenv("NUMVERIFY_API_KEY", "")

expectedResult := &NumverifyValidateResponse{
Valid: true,
Number: "79516566591",
LocalFormat: "9516566591",
InternationalFormat: "+79516566591",
CountryPrefix: "+7",
CountryCode: "RU",
CountryName: "Russian Federation",
Location: "Saint Petersburg and Leningrad Oblast",
Carrier: "OJSC St. Petersburg Telecom (OJSC Tele2-Saint-Petersburg)",
LineType: "mobile",
}

gock.New("http://api.apilayer.com").
Get("/number_verification/validate").
MatchHeader("Apikey", "5ad5554ac240e4d3d31107941b35a5eb").
MatchParam("number", number).
Reply(200).
JSON(expectedResult)

s := NewNumverifySupplier()

assert.True(t, s.IsAvailable())

got, err := s.Validate(number)
assert.Nil(t, err)

assert.Equal(t, expectedResult, got)
}

func TestNumverifySupplierError(t *testing.T) {
defer gock.Off() // Flush pending mocks after test execution

number := "11115551212"

_ = os.Setenv("NUMVERIFY_API_KEY", "5ad5554ac240e4d3d31107941b35a5eb")
defer os.Setenv("NUMVERIFY_API_KEY", "")
defer os.Clearenv()

expectedResult := &NumverifyValidateResponse{
Valid: false,
Error: numverifyError{
Code: 100,
Info: "Access Restricted - Your current Subscription Plan does not support HTTPS Encryption.",
},
expectedResult := &NumverifyErrorResponse{
Message: "You have exceeded your daily\\/monthly API rate limit. Please review and upgrade your subscription plan at https:\\/\\/apilayer.com\\/subscriptions to continue.",
}

gock.New("http://api.apilayer.com").
gock.New("https://api.apilayer.com").
Get("/number_verification/validate").
MatchHeader("Apikey", "5ad5554ac240e4d3d31107941b35a5eb").
MatchParam("number", number).
Reply(400).
Reply(429).
JSON(expectedResult)

s := NewNumverifySupplier()
Expand All @@ -116,7 +72,7 @@ func TestNumverifySupplierError(t *testing.T) {

got, err := s.Validate(number)
assert.Nil(t, got)
assert.Equal(t, errors.New("Access Restricted - Your current Subscription Plan does not support HTTPS Encryption."), err)
assert.Equal(t, errors.New("You have exceeded your daily\\/monthly API rate limit. Please review and upgrade your subscription plan at https:\\/\\/apilayer.com\\/subscriptions to continue."), err)
}

func TestNumverifySupplierHTTPError(t *testing.T) {
Expand All @@ -125,9 +81,7 @@ func TestNumverifySupplierHTTPError(t *testing.T) {
number := "11115551212"

_ = os.Setenv("NUMVERIFY_API_KEY", "5ad5554ac240e4d3d31107941b35a5eb")
_ = os.Setenv("NUMVERIFY_ENABLE_SSL", "1")
defer os.Setenv("NUMVERIFY_API_KEY", "")
defer os.Setenv("NUMVERIFY_ENABLE_SSL", "")
defer os.Clearenv()

dummyError := errors.New("test")

Expand Down
36 changes: 33 additions & 3 deletions web/server_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package web

import (
"github.com/sundowndev/phoneinfoga/v2/lib/remote"
"github.com/sundowndev/phoneinfoga/v2/lib/remote/suppliers"
"io/ioutil"
"net/http"
Expand Down Expand Up @@ -128,7 +127,7 @@ func TestApi(t *testing.T) {

number := "79516566591"

expectedResult := remote.NumverifyScannerResponse{
expectedResult := suppliers.NumverifyValidateResponse{
Valid: true,
Number: "79516566591",
LocalFormat: "9516566591",
Expand All @@ -141,7 +140,7 @@ func TestApi(t *testing.T) {
LineType: "mobile",
}

gock.New("http://api.apilayer.com").
gock.New("https://api.apilayer.com").
Get("/number_verification/validate").
MatchHeader("Apikey", "5ad5554ac240e4d3d31107941b35a5eb").
MatchParam("number", number).
Expand All @@ -159,6 +158,37 @@ func TestApi(t *testing.T) {

assert.Equal(t, gock.IsDone(), true, "there should have no pending mocks")
})

t.Run("should handle error", func(t *testing.T) {
defer gock.Off() // Flush pending mocks after test execution

_ = os.Setenv("NUMVERIFY_API_KEY", "5ad5554ac240e4d3d31107941b35a5eb")
defer os.Unsetenv("NUMVERIFY_API_KEY")

number := "79516566591"

expectedResult := &suppliers.NumverifyErrorResponse{
Message: "You have exceeded your daily\\/monthly API rate limit. Please review and upgrade your subscription plan at https:\\/\\/apilayer.com\\/subscriptions to continue.",
}

gock.New("https://api.apilayer.com").
Get("/number_verification/validate").
MatchHeader("Apikey", "5ad5554ac240e4d3d31107941b35a5eb").
MatchParam("number", number).
Reply(429).
JSON(expectedResult)

res, err := performRequest(r, http.MethodGet, "/api/numbers/79516566591/scan/numverify")
assert.Equal(t, nil, err)

body, err := ioutil.ReadAll(res.Body)

assert.Equal(t, nil, err)
assert.Equal(t, 500, res.Result().StatusCode)
assert.Equal(t, `{"success":false,"error":"You have exceeded your daily\\/monthly API rate limit. Please review and upgrade your subscription plan at https:\\/\\/apilayer.com\\/subscriptions to continue."}`, string(body))

assert.Equal(t, gock.IsDone(), true, "there should have no pending mocks")
})
})

t.Run("googleSearchScan - /api/numbers/:number/scan/googlesearch", func(t *testing.T) {
Expand Down

0 comments on commit 6be6afb

Please sign in to comment.