Skip to content

Commit cba204d

Browse files
Using the language package
1 parent b2268e1 commit cba204d

File tree

4 files changed

+122
-15
lines changed

4 files changed

+122
-15
lines changed

go.mod

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ require (
66
buf.build/go/protoyaml v0.6.0
77
github.com/benbjohnson/clock v1.3.5
88
github.com/dennwc/iters v1.1.0
9-
github.com/flaticols/countrycodes v0.0.2
109
github.com/frostbyte73/core v0.1.1
1110
github.com/fsnotify/fsnotify v1.9.0
1211
github.com/gammazero/deque v1.1.0
@@ -40,6 +39,7 @@ require (
4039
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b
4140
golang.org/x/mod v0.25.0
4241
golang.org/x/sys v0.34.0
42+
golang.org/x/text v0.27.0
4343
google.golang.org/genproto/googleapis/rpc v0.0.0-20250721164621-a45f3dfb1074
4444
google.golang.org/grpc v1.74.2
4545
google.golang.org/protobuf v1.36.6
@@ -88,7 +88,6 @@ require (
8888
golang.org/x/crypto v0.40.0 // indirect
8989
golang.org/x/net v0.42.0 // indirect
9090
golang.org/x/sync v0.16.0 // indirect
91-
golang.org/x/text v0.27.0 // indirect
9291
golang.org/x/tools v0.34.0 // indirect
9392
google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 // indirect
9493
)

go.sum

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,6 @@ github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4
4747
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
4848
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
4949
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
50-
github.com/flaticols/countrycodes v0.0.2 h1:vedxSqHwG3r7lwUK2bfGFWkVcFv7QuSCKFMkywI/rIE=
51-
github.com/flaticols/countrycodes v0.0.2/go.mod h1:HCwEez5Z+nf062EOWMPqEh1uLb5QdZSTQmTrq4avBOA=
5250
github.com/frostbyte73/core v0.1.1 h1:ChhJOR7bAKOCPbA+lqDLE2cGKlCG5JXsDvvQr4YaJIA=
5351
github.com/frostbyte73/core v0.1.1/go.mod h1:mhfOtR+xWAvwXiwor7jnqPMnu4fxbv1F2MwZ0BEpzZo=
5452
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=

livekit/sip.go

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ import (
1111
"google.golang.org/grpc/codes"
1212
"google.golang.org/grpc/status"
1313

14-
"github.com/flaticols/countrycodes"
1514
"github.com/livekit/protocol/utils/xtwirp"
15+
"golang.org/x/text/language"
1616
)
1717

1818
var (
@@ -687,25 +687,45 @@ func (p *CreateSIPParticipantRequest) Validate() error {
687687
}
688688

689689
// Validate destination if provided
690-
if p.Destination != nil {
691-
if err := p.Destination.Validate(); err != nil {
692-
return err
693-
}
694-
}
690+
p.Destination.Validate()
695691

696692
return nil
697693
}
698694

699695
func (d *Destination) Validate() error {
696+
if d == nil {
697+
return nil
698+
}
699+
700700
// Rule 1: If city is specified, country must be specified
701-
if d.City != "" && d.Country == "" {
702-
return errors.New("if city is specified, country must also be specified")
701+
if d.City != "" && d.Country == "" && d.Region == "" {
702+
return errors.New("if city is specified, country or region must also be specified")
703703
}
704704

705-
// Rule 2: If country is specified, it must be a valid ISO 3166-1 alpha-2 code
705+
// Rule 2: If country is specified, it must be a valid ISO 3166-1 alpha-2 code (2-letter only)
706706
if d.Country != "" {
707-
if !countrycodes.IsValidAlpha2(d.Country) {
708-
return errors.New("country must be a valid ISO 3166-1 alpha-2 code (e.g., 'US', 'IN', 'UK')")
707+
// First check: must be exactly 2 characters
708+
if len(d.Country) != 2 {
709+
return errors.New("country must be a valid ISO 3166-1 alpha-2 code (2-letter like 'US', 'IN', 'UK')")
710+
}
711+
712+
// Use golang.org/x/text/language to validate 2-letter country codes
713+
region, err := language.ParseRegion(d.Country)
714+
if err != nil {
715+
return errors.New("country must be a valid ISO 3166-1 alpha-2 code (2-letter like 'US', 'IN', 'UK')")
716+
}
717+
718+
// Check if the parsed region is actually a valid country
719+
// This is the most direct way to validate - region.IsCountry() returns true
720+
// only for actual valid countries, false for invalid codes like "XX"
721+
if !region.IsCountry() {
722+
return errors.New("country must be a valid ISO 3166-1 alpha-2 code (2-letter like 'US', 'IN', 'UK')")
723+
}
724+
725+
// Additional check: ensure the parsed region matches our input
726+
// This prevents 3-letter codes like "USA" from being converted to "US"
727+
if region.String() != d.Country {
728+
return errors.New("country must be a valid ISO 3166-1 alpha-2 code (2-letter like 'US', 'IN', 'UK')")
709729
}
710730
}
711731

livekit/sip_test.go

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -704,3 +704,93 @@ func TestDispatchRuleUpdate(t *testing.T) {
704704
require.True(t, r2 != out)
705705
require.True(t, proto.Equal(r2, out))
706706
}
707+
708+
func TestDestinationValidation(t *testing.T) {
709+
tests := []struct {
710+
name string
711+
destination *Destination
712+
expectError bool
713+
errorMsg string
714+
}{
715+
{
716+
name: "nil destination should pass",
717+
destination: nil,
718+
expectError: false,
719+
},
720+
{
721+
name: "empty destination should pass",
722+
destination: &Destination{},
723+
expectError: false,
724+
},
725+
{
726+
name: "valid country only",
727+
destination: &Destination{
728+
Country: "US",
729+
},
730+
expectError: false,
731+
},
732+
{
733+
name: "valid country and city",
734+
destination: &Destination{
735+
Country: "US",
736+
City: "New York",
737+
},
738+
expectError: false,
739+
},
740+
{
741+
name: "valid country and region",
742+
destination: &Destination{
743+
Country: "US",
744+
Region: "us-east-1",
745+
},
746+
expectError: false,
747+
},
748+
{
749+
name: "city without country or region should fail",
750+
destination: &Destination{
751+
City: "New York",
752+
},
753+
expectError: true,
754+
errorMsg: "if city is specified, country or region must also be specified",
755+
},
756+
{
757+
name: "invalid country code - 3 letters",
758+
destination: &Destination{
759+
Country: "USA",
760+
},
761+
expectError: true,
762+
errorMsg: "country must be a valid ISO 3166-1 alpha-2 code",
763+
},
764+
{
765+
name: "invalid country code - 1 letter",
766+
destination: &Destination{
767+
Country: "U",
768+
},
769+
expectError: true,
770+
errorMsg: "country must be a valid ISO 3166-1 alpha-2 code",
771+
},
772+
{
773+
name: "invalid country code - XX (should fail with IsCountry check)",
774+
destination: &Destination{
775+
Country: "XX",
776+
},
777+
expectError: true,
778+
errorMsg: "country must be a valid ISO 3166-1 alpha-2 code",
779+
},
780+
}
781+
782+
for _, tt := range tests {
783+
t.Run(tt.name, func(t *testing.T) {
784+
err := tt.destination.Validate()
785+
786+
if tt.expectError {
787+
require.Error(t, err)
788+
if tt.errorMsg != "" {
789+
require.Contains(t, err.Error(), tt.errorMsg)
790+
}
791+
} else {
792+
require.NoError(t, err)
793+
}
794+
})
795+
}
796+
}

0 commit comments

Comments
 (0)