Skip to content

Commit f9bcf8d

Browse files
committed
Validate phone numbers
1 parent 9bd5598 commit f9bcf8d

15 files changed

Lines changed: 89 additions & 47 deletions

api/go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ require (
1313
github.com/gofiber/swagger v0.0.1
1414
github.com/google/uuid v1.3.0
1515
github.com/joho/godotenv v1.4.0
16+
github.com/nyaruka/phonenumbers v1.1.0
1617
github.com/palantir/stacktrace v0.0.0-20161112013806-78658fd2d177
1718
github.com/rs/zerolog v1.26.1
1819
github.com/swaggo/swag v1.8.2

api/go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,8 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN
368368
github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8=
369369
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
370370
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
371+
github.com/nyaruka/phonenumbers v1.1.0 h1:OvNAOAl4A9a2kNpzziITbUVH4bBBeKHkHl0llPmkxaA=
372+
github.com/nyaruka/phonenumbers v1.1.0/go.mod h1:cGaEsOrLjIL0iKGqJR5Rfywy86dSkbApEpXuM9KySNA=
371373
github.com/otiai10/copy v1.7.0/go.mod h1:rmRl6QPdJj6EiUqXQ/4Nn2lLXoNQjFCQbbNrxgc/t3U=
372374
github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=
373375
github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs=

api/pkg/requests/message_receive_request.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,36 @@ package requests
33
import (
44
"time"
55

6+
"github.com/nyaruka/phonenumbers"
7+
68
"github.com/NdoleStudio/http-sms-manager/pkg/services"
79
)
810

911
// MessageReceive is the payload for sending and SMS message
1012
type MessageReceive struct {
13+
request
1114
From string `json:"from" example:"+18005550199"`
1215
To string `json:"to" example:"+18005550100"`
1316
Content string `json:"content" example:"This is a sample text message received on a phone"`
1417
// Timestamp is the time when the event was emitted, Please send the timestamp in UTC with as much precision as possible
1518
Timestamp time.Time `json:"timestamp" example:"2022-06-05T14:26:09.527976+03:00"`
1619
}
1720

21+
// Sanitize sets defaults to MessageReceive
22+
func (input *MessageReceive) Sanitize() MessageReceive {
23+
input.To = input.sanitizeAddress(input.To)
24+
input.From = input.sanitizeAddress(input.From)
25+
return *input
26+
}
27+
1828
// ToMessageReceiveParams converts MessageReceive to services.MessageReceiveParams
1929
func (input MessageReceive) ToMessageReceiveParams(source string) services.MessageReceiveParams {
30+
phone, _ := phonenumbers.Parse(input.To, phonenumbers.UNKNOWN_REGION)
2031
return services.MessageReceiveParams{
2132
Source: source,
2233
Contact: input.From,
2334
Timestamp: input.Timestamp,
24-
Owner: input.To,
35+
Owner: *phone,
2536
Content: input.Content,
2637
}
2738
}

api/pkg/requests/message_send_request.go

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,36 @@ package requests
33
import (
44
"time"
55

6+
"github.com/nyaruka/phonenumbers"
7+
68
"github.com/NdoleStudio/http-sms-manager/pkg/services"
79
)
810

911
// MessageSend is the payload for sending and SMS message
1012
type MessageSend struct {
13+
request
1114
From string `json:"from" example:"+18005550199"`
1215
To string `json:"to" example:"+18005550100"`
1316
Content string `json:"content" example:"This is a sample text message"`
1417
}
1518

19+
// Sanitize sets defaults to MessageReceive
20+
func (input *MessageSend) Sanitize() MessageSend {
21+
input.To = input.sanitizeAddress(input.To)
22+
input.From = input.sanitizeAddress(input.From)
23+
return *input
24+
}
25+
1626
// ToMessageSendParams converts MessageSend to services.MessageSendParams
1727
func (input MessageSend) ToMessageSendParams(source string) services.MessageSendParams {
28+
from, _ := phonenumbers.Parse(input.From, phonenumbers.UNKNOWN_REGION)
29+
to, _ := phonenumbers.Parse(input.From, phonenumbers.UNKNOWN_REGION)
30+
1831
return services.MessageSendParams{
1932
Source: source,
20-
Owner: input.From,
33+
Owner: *from,
2134
RequestReceivedAt: time.Now().UTC(),
22-
Contact: input.To,
35+
Contact: *to,
2336
Content: input.Content,
2437
}
2538
}

api/pkg/requests/phone_update_request.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package requests
33
import (
44
"strings"
55

6+
"github.com/nyaruka/phonenumbers"
7+
68
"github.com/NdoleStudio/http-sms-manager/pkg/entities"
79
"github.com/NdoleStudio/http-sms-manager/pkg/services"
810
)
@@ -17,14 +19,15 @@ type PhoneUpsert struct {
1719
// Sanitize sets defaults to MessageOutstanding
1820
func (input *PhoneUpsert) Sanitize() PhoneUpsert {
1921
input.FcmToken = strings.TrimSpace(input.FcmToken)
20-
input.PhoneNumber = strings.TrimSpace(input.PhoneNumber)
22+
input.PhoneNumber = input.sanitizeAddress(input.PhoneNumber)
2123
return *input
2224
}
2325

2426
// ToUpsertParams converts PhoneUpsert to services.PhoneUpsertParams
2527
func (input *PhoneUpsert) ToUpsertParams(user entities.AuthUser) services.PhoneUpsertParams {
28+
phone, _ := phonenumbers.Parse(input.PhoneNumber, phonenumbers.UNKNOWN_REGION)
2629
return services.PhoneUpsertParams{
27-
PhoneNumber: input.PhoneNumber,
30+
PhoneNumber: *phone,
2831
FcmToken: input.FcmToken,
2932
UserID: user.ID,
3033
}

api/pkg/requests/request.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package requests
33
import (
44
"strconv"
55
"strings"
6+
7+
"github.com/nyaruka/phonenumbers"
68
)
79

810
type request struct{}
@@ -13,6 +15,11 @@ func (input *request) sanitizeAddress(value string) string {
1315
if len(value) > 0 && value[0] == ' ' {
1416
value = strings.Replace(value, " ", "+", 1)
1517
}
18+
19+
if number, err := phonenumbers.Parse(value, phonenumbers.UNKNOWN_REGION); err == nil {
20+
value = phonenumbers.Format(number, phonenumbers.E164)
21+
}
22+
1623
return value
1724
}
1825

api/pkg/services/message_service.go

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import (
66
"sync"
77
"time"
88

9+
"github.com/nyaruka/phonenumbers"
10+
911
"github.com/NdoleStudio/http-sms-manager/pkg/events"
1012
"github.com/NdoleStudio/http-sms-manager/pkg/repositories"
1113
cloudevents "github.com/cloudevents/sdk-go/v2"
@@ -142,7 +144,7 @@ func (service *MessageService) StoreEvent(ctx context.Context, message *entities
142144
// MessageReceiveParams parameters registering a message event
143145
type MessageReceiveParams struct {
144146
Contact string
145-
Owner string
147+
Owner phonenumbers.PhoneNumber
146148
Content string
147149
Timestamp time.Time
148150
Source string
@@ -157,7 +159,7 @@ func (service *MessageService) ReceiveMessage(ctx context.Context, params Messag
157159

158160
eventPayload := events.MessagePhoneReceivedPayload{
159161
ID: uuid.New(),
160-
Owner: params.Owner,
162+
Owner: phonenumbers.Format(&params.Owner, phonenumbers.E164),
161163
Contact: params.Contact,
162164
Timestamp: params.Timestamp,
163165
Content: params.Content,
@@ -340,8 +342,8 @@ func (service *MessageService) handleOutstandingMessages(ctx context.Context, so
340342

341343
// MessageSendParams parameters for sending a new message
342344
type MessageSendParams struct {
343-
Owner string
344-
Contact string
345+
Owner phonenumbers.PhoneNumber
346+
Contact phonenumbers.PhoneNumber
345347
Content string
346348
Source string
347349
RequestReceivedAt time.Time
@@ -356,8 +358,8 @@ func (service *MessageService) SendMessage(ctx context.Context, params MessageSe
356358

357359
eventPayload := events.MessageAPISentPayload{
358360
ID: uuid.New(),
359-
Owner: params.Owner,
360-
Contact: params.Contact,
361+
Owner: phonenumbers.Format(&params.Owner, phonenumbers.E164),
362+
Contact: phonenumbers.Format(&params.Contact, phonenumbers.E164),
361363
RequestReceivedAt: params.RequestReceivedAt,
362364
Content: params.Content,
363365
}

api/pkg/services/phone_service.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import (
55
"fmt"
66
"time"
77

8+
"github.com/nyaruka/phonenumbers"
9+
810
"github.com/google/uuid"
911

1012
"github.com/NdoleStudio/http-sms-manager/pkg/repositories"
@@ -53,7 +55,7 @@ func (service *PhoneService) Index(ctx context.Context, authUser entities.AuthUs
5355

5456
// PhoneUpsertParams are parameters for creating a new entities.Phone
5557
type PhoneUpsertParams struct {
56-
PhoneNumber string
58+
PhoneNumber phonenumbers.PhoneNumber
5759
FcmToken string
5860
UserID entities.UserID
5961
}
@@ -69,7 +71,7 @@ func (service *PhoneService) Upsert(ctx context.Context, params PhoneUpsertParam
6971
ID: uuid.New(),
7072
UserID: params.UserID,
7173
FcmToken: &params.FcmToken,
72-
PhoneNumber: params.PhoneNumber,
74+
PhoneNumber: phonenumbers.Format(&params.PhoneNumber, phonenumbers.E164),
7375
CreatedAt: time.Now().UTC(),
7476
UpdatedAt: time.Now().UTC(),
7577
}

api/pkg/validators/heartbeat_handler_validator.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212

1313
// HeartbeatHandlerValidator validates models used in handlers.HeartbeatHandler
1414
type HeartbeatHandlerValidator struct {
15+
validator
1516
logger telemetry.Logger
1617
tracer telemetry.Tracer
1718
}
@@ -51,11 +52,6 @@ func (validator *HeartbeatHandlerValidator) ValidateIndex(_ context.Context, req
5152
phoneNumberRule,
5253
},
5354
},
54-
Messages: map[string][]string{
55-
"to": {
56-
"regex:The 'to' field must be a valid E.164 phone number: https://en.wikipedia.org/wiki/E.164",
57-
},
58-
},
5955
})
6056
return v.ValidateStruct()
6157
}

api/pkg/validators/message_handler_validator.go

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,12 @@ import (
1414
)
1515

1616
const (
17-
phoneNumberRule = "regex:^\\+[1-9]\\d{1,14}$"
17+
phoneNumberRule = "phoneNumber"
1818
)
1919

2020
// MessageHandlerValidator validates models used in handlers.MessageHandler
2121
type MessageHandlerValidator struct {
22+
validator
2223
logger telemetry.Logger
2324
tracer telemetry.Tracer
2425
}
@@ -52,11 +53,6 @@ func (validator MessageHandlerValidator) ValidateMessageReceive(_ context.Contex
5253
"max:500",
5354
},
5455
},
55-
Messages: map[string][]string{
56-
"to": {
57-
"regex: The 'to' field must be a valid E.164 phone number: https://en.wikipedia.org/wiki/E.164",
58-
},
59-
},
6056
})
6157

6258
return v.ValidateStruct()
@@ -81,14 +77,6 @@ func (validator MessageHandlerValidator) ValidateMessageSend(_ context.Context,
8177
"max:500",
8278
},
8379
},
84-
Messages: map[string][]string{
85-
"to": {
86-
"regex: The 'to' field must be a valid E.164 phone number: https://en.wikipedia.org/wiki/E.164",
87-
},
88-
"from": {
89-
"regex: The 'from' field must be a valid E.164 phone number: https://en.wikipedia.org/wiki/E.164",
90-
},
91-
},
9280
})
9381

9482
return v.ValidateStruct()
@@ -138,11 +126,6 @@ func (validator MessageHandlerValidator) ValidateMessageIndex(_ context.Context,
138126
phoneNumberRule,
139127
},
140128
},
141-
Messages: map[string][]string{
142-
"to": {
143-
"regex:The 'to' field must be a valid E.164 phone number: https://en.wikipedia.org/wiki/E.164",
144-
},
145-
},
146129
})
147130
return v.ValidateStruct()
148131
}

0 commit comments

Comments
 (0)