Improve JID parsing

Clean up tests
Fix #1
This commit is contained in:
Mickael Remond 2019-06-05 10:02:24 +02:00
parent 80d8d6d231
commit b93a3a2550
No known key found for this signature in database
GPG key ID: E6F6045D79965AA3
2 changed files with 67 additions and 32 deletions

51
jid.go
View file

@ -3,6 +3,7 @@ package xmpp // import "gosrc.io/xmpp"
import ( import (
"errors" "errors"
"strings" "strings"
"unicode"
) )
type Jid struct { type Jid struct {
@ -11,24 +12,52 @@ type Jid struct {
resource string resource string
} }
func NewJid(sjid string) (jid *Jid, err error) { func NewJid(sjid string) (*Jid, error) {
s1 := strings.Split(sjid, "@") s1 := strings.SplitN(sjid, "@", 2)
if len(s1) != 2 { if len(s1) != 2 {
err = errors.New("invalid JID: " + sjid) return nil, errors.New("invalid JID, missing domain: " + sjid)
return
} }
jid = new(Jid) jid := new(Jid)
jid.username = s1[0] jid.username = s1[0]
if !isUsernameValid(jid.username) {
s2 := strings.Split(s1[1], "/") return jid, errors.New("invalid domain: " + jid.username)
if len(s2) > 2 {
err = errors.New("invalid JID: " + sjid)
return
} }
s2 := strings.SplitN(s1[1], "/", 2)
jid.domain = s2[0] jid.domain = s2[0]
if !isDomainValid(jid.domain) {
return jid, errors.New("invalid domain: " + jid.domain)
}
if len(s2) == 2 { if len(s2) == 2 {
jid.resource = s2[1] jid.resource = s2[1]
} }
return return jid, nil
}
func isUsernameValid(username string) bool {
invalidRunes := []rune{'@', '/', '\'', '"', ':', '<', '>'}
return strings.IndexFunc(username, isInvalid(invalidRunes)) < 0
}
func isDomainValid(domain string) bool {
invalidRunes := []rune{'@', '/'}
return strings.IndexFunc(domain, isInvalid(invalidRunes)) < 0
}
func isInvalid(invalidRunes []rune) func(c rune) bool {
isInvalid := func(c rune) bool {
if unicode.IsSpace(c) {
return true
}
for _, r := range invalidRunes {
if c == r {
return true
}
}
return false
}
return isInvalid
} }

View file

@ -5,43 +5,49 @@ import (
) )
func TestValidJids(t *testing.T) { func TestValidJids(t *testing.T) {
var jid *Jid tests := []struct {
var err error jidstr string
expected Jid
}{
{jidstr: "test@domain.com", expected: Jid{"test", "domain.com", ""}},
{jidstr: "test@domain.com/resource", expected: Jid{"test", "domain.com", "resource"}},
// resource can contain '/' or '@'
{jidstr: "test@domain.com/a/b", expected: Jid{"test", "domain.com", "a/b"}},
{jidstr: "test@domain.com/a@b", expected: Jid{"test", "domain.com", "a@b"}},
}
goodJids := []string{"test@domain.com", "test@domain.com/resource"} for _, tt := range tests {
jid, err := NewJid(tt.jidstr)
for i, sjid := range goodJids { if err != nil {
if jid, err = NewJid(sjid); err != nil { t.Errorf("could not parse correct jid: %s", tt.jidstr)
t.Error("could not parse correct jid") continue
return
} }
if jid == nil { if jid == nil {
t.Error("jid should not be nil") t.Error("jid should not be nil")
} }
if jid.username != "test" { if jid.username != tt.expected.username {
t.Error("incorrect jid username") t.Errorf("incorrect jid username (%s): %s", tt.expected.username, jid.username)
} }
if jid.domain != "domain.com" { if jid.username != tt.expected.username {
t.Error("incorrect jid domain") t.Errorf("incorrect jid domain (%s): %s", tt.expected.domain, jid.domain)
} }
if i == 0 && jid.resource != "" { if jid.resource != tt.expected.resource {
t.Error("bare jid resource should be empty") t.Errorf("incorrect jid resource (%s): %s", tt.expected.resource, jid.resource)
}
if i == 1 && jid.resource != "resource" {
t.Error("incorrect full jid resource")
} }
} }
} }
// TODO: Check if resource cannot contain a /
func TestIncorrectJids(t *testing.T) { func TestIncorrectJids(t *testing.T) {
badJids := []string{"test@domain.com@otherdomain.com", badJids := []string{
"test@domain.com/test/test"} "user:name@domain.com",
"user<name@domain.com",
"test@domain.com@otherdomain.com",
"test@domain com/resource",
}
for _, sjid := range badJids { for _, sjid := range badJids {
if _, err := NewJid(sjid); err == nil { if _, err := NewJid(sjid); err == nil {