improve JID struct
This commit is contained in:
parent
02ee2f2087
commit
3e39507f5a
|
@ -61,8 +61,8 @@ func (client *Client) auth(password string) error {
|
||||||
cnonceStr := cnonce()
|
cnonceStr := cnonce()
|
||||||
digestURI := "xmpp/" + client.JID.Domain
|
digestURI := "xmpp/" + client.JID.Domain
|
||||||
nonceCount := fmt.Sprintf("%08x", 1)
|
nonceCount := fmt.Sprintf("%08x", 1)
|
||||||
digest := saslDigestResponse(client.JID.Node, realm, password, nonce, cnonceStr, "AUTHENTICATE", digestURI, nonceCount)
|
digest := saslDigestResponse(client.JID.Local, realm, password, nonce, cnonceStr, "AUTHENTICATE", digestURI, nonceCount)
|
||||||
message := "username=\"" + client.JID.Node + "\", realm=\"" + realm + "\", nonce=\"" + nonce + "\", cnonce=\"" + cnonceStr +
|
message := "username=\"" + client.JID.Local + "\", realm=\"" + realm + "\", nonce=\"" + nonce + "\", cnonce=\"" + cnonceStr +
|
||||||
"\", nc=" + nonceCount + ", qop=" + qop + ", digest-uri=\"" + digestURI + "\", response=" + digest + ", charset=" + charset
|
"\", nc=" + nonceCount + ", qop=" + qop + ", digest-uri=\"" + digestURI + "\", response=" + digest + ", charset=" + charset
|
||||||
|
|
||||||
response.Body = base64.StdEncoding.EncodeToString([]byte(message))
|
response.Body = base64.StdEncoding.EncodeToString([]byte(message))
|
||||||
|
@ -72,7 +72,7 @@ func (client *Client) auth(password string) error {
|
||||||
if m == "PLAIN" {
|
if m == "PLAIN" {
|
||||||
mechanism = m
|
mechanism = m
|
||||||
// Plain authentication: send base64-encoded \x00 user \x00 password.
|
// Plain authentication: send base64-encoded \x00 user \x00 password.
|
||||||
raw := "\x00" + client.JID.Node + "\x00" + password
|
raw := "\x00" + client.JID.Local + "\x00" + password
|
||||||
enc := make([]byte, base64.StdEncoding.EncodedLen(len(raw)))
|
enc := make([]byte, base64.StdEncoding.EncodedLen(len(raw)))
|
||||||
base64.StdEncoding.Encode(enc, []byte(raw))
|
base64.StdEncoding.Encode(enc, []byte(raw))
|
||||||
client.Send(&xmpp.SASLAuth{
|
client.Send(&xmpp.SASLAuth{
|
||||||
|
|
|
@ -120,7 +120,7 @@ func (client *Client) connect(password string) error {
|
||||||
if bind == nil {
|
if bind == nil {
|
||||||
return errors.New("bind is nil")
|
return errors.New("bind is nil")
|
||||||
} else if bind.JID != nil {
|
} else if bind.JID != nil {
|
||||||
client.JID.Node = bind.JID.Node
|
client.JID.Local = bind.JID.Local
|
||||||
client.JID.Domain = bind.JID.Domain
|
client.JID.Domain = bind.JID.Domain
|
||||||
client.JID.Resource = bind.JID.Resource
|
client.JID.Resource = bind.JID.Resource
|
||||||
client.Logging.Infof("set jid by server bind '%s'", bind.JID.Full())
|
client.Logging.Infof("set jid by server bind '%s'", bind.JID.Full())
|
||||||
|
|
|
@ -110,21 +110,22 @@ func (t *Tester) StartBot(status *Status) {
|
||||||
first := true
|
first := true
|
||||||
allAdmins := ""
|
allAdmins := ""
|
||||||
isAdmin := false
|
isAdmin := false
|
||||||
|
fromBare := msg.From
|
||||||
for _, jid := range botAllowed(t.Admins, status.account.Admins) {
|
for _, jid := range botAllowed(t.Admins, status.account.Admins) {
|
||||||
if first {
|
if first {
|
||||||
first = false
|
first = false
|
||||||
allAdmins += jid.Bare()
|
|
||||||
} else {
|
} else {
|
||||||
allAdmins += ", " + jid.Bare()
|
allAdmins += ", "
|
||||||
}
|
}
|
||||||
if jid.Bare() == msg.From.Bare() {
|
allAdmins += jid.Bare().String()
|
||||||
|
if jid.Bare().IsEqual(fromBare) {
|
||||||
isAdmin = true
|
isAdmin = true
|
||||||
status.client.Send(xmpp.MessageClient{Type: msg.Type, To: jid, Body: "last message, disconnect requested by " + msg.From.Bare()})
|
status.client.Send(xmpp.MessageClient{Type: msg.Type, To: jid, Body: "last message, disconnect requested by " + fromBare.String()})
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if isAdmin {
|
if isAdmin {
|
||||||
status.Disconnect(fmt.Sprintf("disconnect by admin '%s'", msg.From.Bare()))
|
status.Disconnect(fmt.Sprintf("disconnect by admin '%s'", fromBare.String()))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
status.client.Send(xmpp.MessageClient{Type: msg.Type, To: msg.From, Body: "not allowed, ask " + allAdmins})
|
status.client.Send(xmpp.MessageClient{Type: msg.Type, To: msg.From, Body: "not allowed, ask " + allAdmins})
|
||||||
|
|
|
@ -57,17 +57,17 @@ func (t *Tester) Output() *Output {
|
||||||
toJID := xmppbase.NewJID(to)
|
toJID := xmppbase.NewJID(to)
|
||||||
link := &Link{
|
link := &Link{
|
||||||
Source: status.JID.Domain,
|
Source: status.JID.Domain,
|
||||||
SourceJID: status.JID.Bare(),
|
SourceJID: status.JID.Bare().String(),
|
||||||
Target: toJID.Domain,
|
Target: toJID.Domain,
|
||||||
TargetJID: toJID.Bare(),
|
TargetJID: toJID.Bare().String(),
|
||||||
FromSource: linkOK,
|
FromSource: linkOK,
|
||||||
FromTarget: false,
|
FromTarget: false,
|
||||||
}
|
}
|
||||||
if switchSourceTarget {
|
if switchSourceTarget {
|
||||||
link.Source = toJID.Domain
|
link.Source = toJID.Domain
|
||||||
link.SourceJID = toJID.Bare()
|
link.SourceJID = toJID.Bare().String()
|
||||||
link.Target = status.JID.Domain
|
link.Target = status.JID.Domain
|
||||||
link.TargetJID = status.JID.Bare()
|
link.TargetJID = status.JID.Bare().String()
|
||||||
link.FromSource = false
|
link.FromSource = false
|
||||||
link.FromTarget = linkOK
|
link.FromTarget = linkOK
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,7 +59,7 @@ func (s *Status) Update(timeout time.Duration) {
|
||||||
}
|
}
|
||||||
|
|
||||||
c := &client.Client{
|
c := &client.Client{
|
||||||
JID: xmppbase.NewJID(s.account.JID.Bare()),
|
JID: s.account.JID.Bare(),
|
||||||
Protocol: "tcp4",
|
Protocol: "tcp4",
|
||||||
Logging: s.client.Logging,
|
Logging: s.client.Logging,
|
||||||
Timeout: timeout / 2,
|
Timeout: timeout / 2,
|
||||||
|
@ -72,7 +72,7 @@ func (s *Status) Update(timeout time.Duration) {
|
||||||
s.IPv4 = false
|
s.IPv4 = false
|
||||||
}
|
}
|
||||||
|
|
||||||
c.JID = xmppbase.NewJID(s.account.JID.Bare())
|
c.JID = s.account.JID.Bare()
|
||||||
c.Protocol = "tcp6"
|
c.Protocol = "tcp6"
|
||||||
|
|
||||||
if err := c.Connect(s.account.Password); err == nil {
|
if err := c.Connect(s.account.Password); err == nil {
|
||||||
|
|
|
@ -44,7 +44,7 @@ func (t *Tester) Start(mainClient *client.Client, password string) {
|
||||||
t.mux.Lock()
|
t.mux.Lock()
|
||||||
defer t.mux.Unlock()
|
defer t.mux.Unlock()
|
||||||
|
|
||||||
t.Status[mainClient.JID.Bare()] = status
|
t.Status[mainClient.JID.Bare().String()] = status
|
||||||
go t.StartBot(status)
|
go t.StartBot(status)
|
||||||
|
|
||||||
for _, acc := range t.Accounts {
|
for _, acc := range t.Accounts {
|
||||||
|
@ -58,11 +58,12 @@ func (t *Tester) Close() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tester) Connect(acc *Account) {
|
func (t *Tester) Connect(acc *Account) {
|
||||||
logCTX := log.WithField("jid", acc.JID.Full())
|
logCTX := log.WithField("jid", acc.JID.Full().String())
|
||||||
status, ok := t.Status[acc.JID.Bare()]
|
bare := acc.JID.Bare().String()
|
||||||
|
status, ok := t.Status[bare]
|
||||||
if !ok {
|
if !ok {
|
||||||
status = NewStatus(t.mainClient, acc)
|
status = NewStatus(t.mainClient, acc)
|
||||||
t.Status[acc.JID.Bare()] = status
|
t.Status[bare] = status
|
||||||
} else if status.JID == nil {
|
} else if status.JID == nil {
|
||||||
status.JID = acc.JID
|
status.JID = acc.JID
|
||||||
}
|
}
|
||||||
|
@ -99,19 +100,20 @@ func (t *Tester) UpdateConnectionStatus(from, to *xmppbase.JID, recvmsg string)
|
||||||
t.mux.Lock()
|
t.mux.Lock()
|
||||||
defer t.mux.Unlock()
|
defer t.mux.Unlock()
|
||||||
|
|
||||||
status, ok := t.Status[from.Bare()]
|
status, ok := t.Status[from.Bare().String()]
|
||||||
if !ok {
|
if !ok {
|
||||||
logCTX.Warn("recv msg without receiver")
|
logCTX.Warn("recv msg without receiver")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
msg, ok := status.MessageForConnection[to.Bare()]
|
toBare := to.Bare().String()
|
||||||
|
msg, ok := status.MessageForConnection[toBare]
|
||||||
logCTX = logCTX.WithField("msg-send", msg)
|
logCTX = logCTX.WithField("msg-send", msg)
|
||||||
if !ok || msg != recvmsg || msg == "" || recvmsg == "" {
|
if !ok || msg != recvmsg || msg == "" || recvmsg == "" {
|
||||||
logCTX.Warn("recv wrong msg")
|
logCTX.Warn("recv wrong msg")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
delete(status.MessageForConnection, to.Bare())
|
delete(status.MessageForConnection, toBare)
|
||||||
status.Connections[to.Bare()] = true
|
status.Connections[toBare] = true
|
||||||
logCTX.Info("recv msg")
|
logCTX.Info("recv msg")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -163,7 +165,7 @@ func (t *Tester) CheckStatus() {
|
||||||
Type: xmpp.MessageTypeChat,
|
Type: xmpp.MessageTypeChat,
|
||||||
To: s.JID,
|
To: s.JID,
|
||||||
})
|
})
|
||||||
own.MessageForConnection[s.JID.Bare()] = msg
|
own.MessageForConnection[s.JID.Bare().String()] = msg
|
||||||
logCTXTo.Debug("test send")
|
logCTXTo.Debug("test send")
|
||||||
send++
|
send++
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ type State struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *State) AddAccount(a *model.Account) error {
|
func (s *State) AddAccount(a *model.Account) error {
|
||||||
if a.Node == "" {
|
if a.Local == "" {
|
||||||
return errors.New("No localpart exists in account")
|
return errors.New("No localpart exists in account")
|
||||||
}
|
}
|
||||||
if d := a.Domain; d != nil {
|
if d := a.Domain; d != nil {
|
||||||
|
@ -39,11 +39,11 @@ func (s *State) AddAccount(a *model.Account) error {
|
||||||
if domain.Accounts == nil {
|
if domain.Accounts == nil {
|
||||||
domain.Accounts = make(map[string]*model.Account)
|
domain.Accounts = make(map[string]*model.Account)
|
||||||
}
|
}
|
||||||
_, ok = domain.Accounts[a.Node]
|
_, ok = domain.Accounts[a.Local]
|
||||||
if ok {
|
if ok {
|
||||||
return errors.New("exists already")
|
return errors.New("exists already")
|
||||||
}
|
}
|
||||||
domain.Accounts[a.Node] = a
|
domain.Accounts[a.Local] = a
|
||||||
a.Domain = d
|
a.Domain = d
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ func (s *State) Authenticate(jid *xmppbase.JID, password string) (bool, error) {
|
||||||
logger := log.WithField("database", "auth")
|
logger := log.WithField("database", "auth")
|
||||||
|
|
||||||
if domain, ok := s.Domains[jid.Domain]; ok {
|
if domain, ok := s.Domains[jid.Domain]; ok {
|
||||||
if acc, ok := domain.Accounts[jid.Node]; ok {
|
if acc, ok := domain.Accounts[jid.Local]; ok {
|
||||||
if acc.ValidatePassword(password) {
|
if acc.ValidatePassword(password) {
|
||||||
return true, nil
|
return true, nil
|
||||||
} else {
|
} else {
|
||||||
|
@ -73,7 +73,7 @@ func (s *State) GetAccount(jid *xmppbase.JID) *model.Account {
|
||||||
logger := log.WithField("database", "get")
|
logger := log.WithField("database", "get")
|
||||||
|
|
||||||
if domain, ok := s.Domains[jid.Domain]; ok {
|
if domain, ok := s.Domains[jid.Domain]; ok {
|
||||||
if acc, ok := domain.Accounts[jid.Node]; ok {
|
if acc, ok := domain.Accounts[jid.Local]; ok {
|
||||||
return acc
|
return acc
|
||||||
} else {
|
} else {
|
||||||
logger.Debug("account not found")
|
logger.Debug("account not found")
|
||||||
|
|
|
@ -20,18 +20,18 @@ func (d *Domain) GetJID() *xmppbase.JID {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Domain) UpdateAccount(a *Account) error {
|
func (d *Domain) UpdateAccount(a *Account) error {
|
||||||
if a.Node == "" {
|
if a.Local == "" {
|
||||||
return errors.New("No localpart exists in account")
|
return errors.New("No localpart exists in account")
|
||||||
}
|
}
|
||||||
d.Lock()
|
d.Lock()
|
||||||
d.Accounts[a.Node] = a
|
d.Accounts[a.Local] = a
|
||||||
d.Unlock()
|
d.Unlock()
|
||||||
a.Domain = d
|
a.Domain = d
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type Account struct {
|
type Account struct {
|
||||||
Node string `json:"-"`
|
Local string `json:"-"`
|
||||||
Domain *Domain `json:"-"`
|
Domain *Domain `json:"-"`
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
Roster map[string]*Buddy `json:"roster"`
|
Roster map[string]*Buddy `json:"roster"`
|
||||||
|
@ -43,7 +43,7 @@ func NewAccount(jid *xmppbase.JID, password string) *Account {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return &Account{
|
return &Account{
|
||||||
Node: jid.Node,
|
Local: jid.Local,
|
||||||
Domain: &Domain{
|
Domain: &Domain{
|
||||||
FQDN: jid.Domain,
|
FQDN: jid.Domain,
|
||||||
},
|
},
|
||||||
|
@ -54,7 +54,7 @@ func NewAccount(jid *xmppbase.JID, password string) *Account {
|
||||||
func (a *Account) GetJID() *xmppbase.JID {
|
func (a *Account) GetJID() *xmppbase.JID {
|
||||||
return &xmppbase.JID{
|
return &xmppbase.JID{
|
||||||
Domain: a.Domain.FQDN,
|
Domain: a.Domain.FQDN,
|
||||||
Node: a.Node,
|
Local: a.Local,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -76,7 +76,7 @@ func (state *TLSStream) Process() state.State {
|
||||||
</mechanisms>
|
</mechanisms>
|
||||||
</stream:features>`,
|
</stream:features>`,
|
||||||
xmpp.CreateCookie(), xmpp.NSClient, xmpp.NSStream,
|
xmpp.CreateCookie(), xmpp.NSClient, xmpp.NSStream,
|
||||||
xmpp.NSSASL, xmppiq.NSFeaturesIQRegister)
|
xmpp.NSSASL, xmppiq.NSFeatureRegister)
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(state.Client.Conn, `<?xml version='1.0'?>
|
fmt.Fprintf(state.Client.Conn, `<?xml version='1.0'?>
|
||||||
<stream:stream id='%x' version='1.0' xmlns='%s' xmlns:stream='%s'>
|
<stream:stream id='%x' version='1.0' xmlns='%s' xmlns:stream='%s'>
|
||||||
|
@ -134,7 +134,7 @@ func (state *SASLAuth) Process() state.State {
|
||||||
}
|
}
|
||||||
info := strings.Split(string(data), "\x00")
|
info := strings.Split(string(data), "\x00")
|
||||||
// should check that info[1] starts with state.Client.JID
|
// should check that info[1] starts with state.Client.JID
|
||||||
state.Client.JID.Node = info[1]
|
state.Client.JID.Local = info[1]
|
||||||
state.Client.Log = state.Client.Log.WithField("jid", state.Client.JID.Full())
|
state.Client.Log = state.Client.Log.WithField("jid", state.Client.JID.Full())
|
||||||
success, err := state.database.Authenticate(state.Client.JID, info[2])
|
success, err := state.database.Authenticate(state.Client.JID, info[2])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -44,7 +44,7 @@ func (state *RegisterFormRequest) Process() state.State {
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
|
|
||||||
if msg.PrivateRegister == nil {
|
if msg.Register == nil {
|
||||||
state.Client.Log.Warn("is no iq register")
|
state.Client.Log.Warn("is no iq register")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@ func (state *RegisterFormRequest) Process() state.State {
|
||||||
To: state.Client.JID,
|
To: state.Client.JID,
|
||||||
From: xmppbase.NewJID(state.Client.JID.Domain),
|
From: xmppbase.NewJID(state.Client.JID.Domain),
|
||||||
ID: msg.ID,
|
ID: msg.ID,
|
||||||
PrivateRegister: &xmppiq.IQPrivateRegister{
|
Register: &xmppiq.Register{
|
||||||
Instructions: "Choose a username and password for use with this service.",
|
Instructions: "Choose a username and password for use with this service.",
|
||||||
Username: "",
|
Username: "",
|
||||||
Password: "",
|
Password: "",
|
||||||
|
@ -98,14 +98,14 @@ func (state *RegisterRequest) Process() state.State {
|
||||||
state.Client.Log.Warn("iq with error: ", msg.Error.Code)
|
state.Client.Log.Warn("iq with error: ", msg.Error.Code)
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
if msg.PrivateRegister == nil {
|
if msg.Register == nil {
|
||||||
state.Client.Log.Warn("is no iq register: ", err)
|
state.Client.Log.Warn("is no iq register: ", err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
state.Client.JID.Node = msg.PrivateRegister.Username
|
state.Client.JID.Local = msg.Register.Username
|
||||||
state.Client.Log = state.Client.Log.WithField("jid", state.Client.JID.Full())
|
state.Client.Log = state.Client.Log.WithField("jid", state.Client.JID.Full())
|
||||||
account := model.NewAccount(state.Client.JID, msg.PrivateRegister.Password)
|
account := model.NewAccount(state.Client.JID, msg.Register.Password)
|
||||||
err = state.database.AddAccount(account)
|
err = state.database.AddAccount(account)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
state.Client.Out.Encode(&xmpp.IQClient{
|
state.Client.Out.Encode(&xmpp.IQClient{
|
||||||
|
@ -113,7 +113,7 @@ func (state *RegisterRequest) Process() state.State {
|
||||||
To: state.Client.JID,
|
To: state.Client.JID,
|
||||||
From: xmppbase.NewJID(state.Client.JID.Domain),
|
From: xmppbase.NewJID(state.Client.JID.Domain),
|
||||||
ID: msg.ID,
|
ID: msg.ID,
|
||||||
PrivateRegister: msg.PrivateRegister,
|
Register: msg.Register,
|
||||||
Error: &xmpp.ErrorClient{
|
Error: &xmpp.ErrorClient{
|
||||||
Code: "409",
|
Code: "409",
|
||||||
Type: "cancel",
|
Type: "cancel",
|
||||||
|
|
|
@ -11,9 +11,9 @@ func init() {
|
||||||
jidRegex = regexp.MustCompile(`^(?:([^@/<>'\" ]+)@)?([^@/<>'\"]+)(?:/([^<>'\" ][^<>'\"]*))?$`)
|
jidRegex = regexp.MustCompile(`^(?:([^@/<>'\" ]+)@)?([^@/<>'\"]+)(?:/([^<>'\" ][^<>'\"]*))?$`)
|
||||||
}
|
}
|
||||||
|
|
||||||
// JID struct
|
// JID implements RFC6122: XMPP - Address Format
|
||||||
type JID struct {
|
type JID struct {
|
||||||
Node string
|
Local string
|
||||||
Domain string
|
Domain string
|
||||||
Resource string
|
Resource string
|
||||||
}
|
}
|
||||||
|
@ -28,49 +28,57 @@ func NewJID(jidString string) *JID {
|
||||||
jidSplit := jidSplitTmp[0]
|
jidSplit := jidSplitTmp[0]
|
||||||
|
|
||||||
return &JID{
|
return &JID{
|
||||||
Node: jidSplit[1],
|
Local: jidSplit[1],
|
||||||
Domain: jidSplit[2],
|
Domain: jidSplit[2],
|
||||||
Resource: jidSplit[3],
|
Resource: jidSplit[3],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bare get the "bare" jid
|
// Clone JID struct address/pointer
|
||||||
func (jid *JID) Bare() string {
|
func (jid *JID) Clone() *JID {
|
||||||
if jid == nil {
|
if jid != nil {
|
||||||
return ""
|
return &JID{
|
||||||
|
Local: jid.Local,
|
||||||
|
Domain: jid.Domain,
|
||||||
|
Resource: jid.Resource,
|
||||||
}
|
}
|
||||||
if jid.Node != "" {
|
|
||||||
return jid.Node + "@" + jid.Domain
|
|
||||||
}
|
}
|
||||||
return jid.Domain
|
return nil
|
||||||
}
|
|
||||||
|
|
||||||
// IsBare checks if jid has node and domain but no resource
|
|
||||||
func (jid *JID) IsBare() bool {
|
|
||||||
return jid != nil && jid.Node != "" && jid.Domain != "" && jid.Resource == ""
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Full get the "full" jid as string
|
// Full get the "full" jid as string
|
||||||
func (jid *JID) Full() string {
|
func (jid *JID) Full() *JID {
|
||||||
|
return jid.Clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bare get the "bare" jid
|
||||||
|
func (jid *JID) Bare() *JID {
|
||||||
|
if jid != nil {
|
||||||
|
return &JID{
|
||||||
|
Local: jid.Local,
|
||||||
|
Domain: jid.Domain,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (jid *JID) String() string {
|
||||||
if jid == nil {
|
if jid == nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
if jid.Resource != "" {
|
str := jid.Domain
|
||||||
return jid.Bare() + "/" + jid.Resource
|
if jid.Local != "" {
|
||||||
|
str = jid.Local + "@" + str
|
||||||
}
|
}
|
||||||
return jid.Bare()
|
if jid.Resource != "" {
|
||||||
|
str = str + "/" + jid.Resource
|
||||||
|
}
|
||||||
|
return str
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsFull checks if jid has all three parts of a JID
|
|
||||||
func (jid *JID) IsFull() bool {
|
|
||||||
return jid != nil && jid.Node != "" && jid.Domain != "" && jid.Resource != ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (jid *JID) String() string { return jid.Bare() }
|
|
||||||
|
|
||||||
//MarshalText to bytearray
|
//MarshalText to bytearray
|
||||||
func (jid JID) MarshalText() ([]byte, error) {
|
func (jid JID) MarshalText() ([]byte, error) {
|
||||||
return []byte(jid.Full()), nil
|
return []byte(jid.String()), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalText from bytearray
|
// UnmarshalText from bytearray
|
||||||
|
@ -79,7 +87,7 @@ func (jid *JID) UnmarshalText(data []byte) (err error) {
|
||||||
if newJID == nil {
|
if newJID == nil {
|
||||||
return errors.New("not a valid jid")
|
return errors.New("not a valid jid")
|
||||||
}
|
}
|
||||||
jid.Node = newJID.Node
|
jid.Local = newJID.Local
|
||||||
jid.Domain = newJID.Domain
|
jid.Domain = newJID.Domain
|
||||||
jid.Resource = newJID.Resource
|
jid.Resource = newJID.Resource
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
package xmppbase
|
||||||
|
|
||||||
|
// IsDomain checks if jid has only domain but no local and resource
|
||||||
|
func (jid *JID) IsDomain() bool {
|
||||||
|
return jid != nil && jid.Local == "" && jid.Domain != "" && jid.Resource == ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsBare checks if jid has local and domain but no resource
|
||||||
|
func (jid *JID) IsBare() bool {
|
||||||
|
return jid != nil && jid.Local != "" && jid.Domain != "" && jid.Resource == ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsFull checks if jid has all three parts of a JID
|
||||||
|
func (jid *JID) IsFull() bool {
|
||||||
|
return jid != nil && jid.Local != "" && jid.Domain != "" && jid.Resource != ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsEqual to check if two jid has same values
|
||||||
|
func (a *JID) IsEqual(b *JID) bool {
|
||||||
|
if a == nil || b == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return a.Local == b.Local && a.Domain == b.Domain && a.Resource == b.Resource
|
||||||
|
}
|
|
@ -0,0 +1,123 @@
|
||||||
|
package xmppbase
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestJIDIsDomain(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
var jid *JID
|
||||||
|
assert.False(jid.IsDomain())
|
||||||
|
|
||||||
|
jid = &JID{}
|
||||||
|
assert.False(jid.IsDomain())
|
||||||
|
|
||||||
|
jid = &JID{Local: "a"}
|
||||||
|
assert.False(jid.IsDomain())
|
||||||
|
|
||||||
|
jid = &JID{Domain: "a"}
|
||||||
|
assert.True(jid.IsDomain())
|
||||||
|
|
||||||
|
jid = &JID{Resource: "a"}
|
||||||
|
assert.False(jid.IsDomain())
|
||||||
|
|
||||||
|
jid = &JID{Local: "a", Domain: "b"}
|
||||||
|
assert.False(jid.IsDomain())
|
||||||
|
|
||||||
|
jid = &JID{Local: "a", Resource: "b"}
|
||||||
|
assert.False(jid.IsDomain())
|
||||||
|
|
||||||
|
jid = &JID{Domain: "a", Resource: "b"}
|
||||||
|
assert.False(jid.IsDomain())
|
||||||
|
|
||||||
|
jid = &JID{Local: "a", Domain: "b", Resource: "a"}
|
||||||
|
assert.False(jid.IsDomain())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestJIDIsBare(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
var jid *JID
|
||||||
|
assert.False(jid.IsBare())
|
||||||
|
|
||||||
|
jid = &JID{}
|
||||||
|
assert.False(jid.IsBare())
|
||||||
|
|
||||||
|
jid = &JID{Local: "a"}
|
||||||
|
assert.False(jid.IsBare())
|
||||||
|
|
||||||
|
jid = &JID{Domain: "a"}
|
||||||
|
assert.False(jid.IsBare())
|
||||||
|
|
||||||
|
jid = &JID{Resource: "a"}
|
||||||
|
assert.False(jid.IsBare())
|
||||||
|
|
||||||
|
jid = &JID{Local: "a", Domain: "b"}
|
||||||
|
assert.True(jid.IsBare())
|
||||||
|
|
||||||
|
jid = &JID{Local: "a", Resource: "b"}
|
||||||
|
assert.False(jid.IsBare())
|
||||||
|
|
||||||
|
jid = &JID{Domain: "a", Resource: "b"}
|
||||||
|
assert.False(jid.IsBare())
|
||||||
|
|
||||||
|
jid = &JID{Local: "a", Domain: "b", Resource: "a"}
|
||||||
|
assert.False(jid.IsBare())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestJIDIsFull(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
var jid *JID
|
||||||
|
assert.False(jid.IsFull())
|
||||||
|
|
||||||
|
jid = &JID{}
|
||||||
|
assert.False(jid.IsFull())
|
||||||
|
|
||||||
|
jid = &JID{Local: "a"}
|
||||||
|
assert.False(jid.IsFull())
|
||||||
|
|
||||||
|
jid = &JID{Domain: "a"}
|
||||||
|
assert.False(jid.IsFull())
|
||||||
|
|
||||||
|
jid = &JID{Resource: "a"}
|
||||||
|
assert.False(jid.IsFull())
|
||||||
|
|
||||||
|
jid = &JID{Local: "a", Domain: "b"}
|
||||||
|
assert.False(jid.IsFull())
|
||||||
|
|
||||||
|
jid = &JID{Local: "a", Resource: "b"}
|
||||||
|
assert.False(jid.IsFull())
|
||||||
|
|
||||||
|
jid = &JID{Domain: "a", Resource: "b"}
|
||||||
|
assert.False(jid.IsFull())
|
||||||
|
|
||||||
|
jid = &JID{Local: "a", Domain: "b", Resource: "a"}
|
||||||
|
assert.True(jid.IsFull())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestJIDIsEqual(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
// just one null
|
||||||
|
var a *JID
|
||||||
|
b := &JID{}
|
||||||
|
assert.False(a.IsEqual(b))
|
||||||
|
|
||||||
|
a = &JID{}
|
||||||
|
// two empty JID
|
||||||
|
assert.True(a.IsEqual(b))
|
||||||
|
|
||||||
|
a.Local = "bot"
|
||||||
|
b.Local = "bot"
|
||||||
|
a.Domain = "example.org"
|
||||||
|
b.Domain = "example.org"
|
||||||
|
a.Resource = "notebook"
|
||||||
|
b.Resource = "notebook"
|
||||||
|
|
||||||
|
assert.True(a.IsEqual(b))
|
||||||
|
|
||||||
|
b.Resource = "mobile"
|
||||||
|
assert.False(a.IsEqual(b))
|
||||||
|
|
||||||
|
}
|
|
@ -13,57 +13,57 @@ func TestNewJID(t *testing.T) {
|
||||||
|
|
||||||
checkList := map[string]*JID{
|
checkList := map[string]*JID{
|
||||||
"juliet@example.com": {
|
"juliet@example.com": {
|
||||||
Node: "juliet",
|
Local: "juliet",
|
||||||
Domain: "example.com",
|
Domain: "example.com",
|
||||||
},
|
},
|
||||||
"juliet@example.com/foo": {
|
"juliet@example.com/foo": {
|
||||||
Node: "juliet",
|
Local: "juliet",
|
||||||
Domain: "example.com",
|
Domain: "example.com",
|
||||||
Resource: "foo",
|
Resource: "foo",
|
||||||
},
|
},
|
||||||
"juliet@example.com/foo bar": {
|
"juliet@example.com/foo bar": {
|
||||||
Node: "juliet",
|
Local: "juliet",
|
||||||
Domain: "example.com",
|
Domain: "example.com",
|
||||||
Resource: "foo bar",
|
Resource: "foo bar",
|
||||||
},
|
},
|
||||||
"juliet@example.com/foo@bar": {
|
"juliet@example.com/foo@bar": {
|
||||||
Node: "juliet",
|
Local: "juliet",
|
||||||
Domain: "example.com",
|
Domain: "example.com",
|
||||||
Resource: "foo@bar",
|
Resource: "foo@bar",
|
||||||
},
|
},
|
||||||
"foo\\20bar@example.com": {
|
"foo\\20bar@example.com": {
|
||||||
Node: "foo\\20bar",
|
Local: "foo\\20bar",
|
||||||
Domain: "example.com",
|
Domain: "example.com",
|
||||||
},
|
},
|
||||||
"fussball@example.com": {
|
"fussball@example.com": {
|
||||||
Node: "fussball",
|
Local: "fussball",
|
||||||
Domain: "example.com",
|
Domain: "example.com",
|
||||||
},
|
},
|
||||||
"fußball@example.com": {
|
"fußball@example.com": {
|
||||||
Node: "fußball",
|
Local: "fußball",
|
||||||
Domain: "example.com",
|
Domain: "example.com",
|
||||||
},
|
},
|
||||||
"π@example.com": {
|
"π@example.com": {
|
||||||
Node: "π",
|
Local: "π",
|
||||||
Domain: "example.com",
|
Domain: "example.com",
|
||||||
},
|
},
|
||||||
"Σ@example.com/foo": {
|
"Σ@example.com/foo": {
|
||||||
Node: "Σ",
|
Local: "Σ",
|
||||||
Domain: "example.com",
|
Domain: "example.com",
|
||||||
Resource: "foo",
|
Resource: "foo",
|
||||||
},
|
},
|
||||||
"σ@example.com/foo": {
|
"σ@example.com/foo": {
|
||||||
Node: "σ",
|
Local: "σ",
|
||||||
Domain: "example.com",
|
Domain: "example.com",
|
||||||
Resource: "foo",
|
Resource: "foo",
|
||||||
},
|
},
|
||||||
"ς@example.com/foo": {
|
"ς@example.com/foo": {
|
||||||
Node: "ς",
|
Local: "ς",
|
||||||
Domain: "example.com",
|
Domain: "example.com",
|
||||||
Resource: "foo",
|
Resource: "foo",
|
||||||
},
|
},
|
||||||
"king@example.com/♚": {
|
"king@example.com/♚": {
|
||||||
Node: "king",
|
Local: "king",
|
||||||
Domain: "example.com",
|
Domain: "example.com",
|
||||||
Resource: "♚",
|
Resource: "♚",
|
||||||
},
|
},
|
||||||
|
@ -97,10 +97,10 @@ func TestNewJID(t *testing.T) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Equal(jidValid.Node, jid.Node, "the local part was not right detectet:"+jidString)
|
assert.Equal(jidValid.Local, jid.Local, "the local part was not right detectet:"+jidString)
|
||||||
assert.Equal(jidValid.Domain, jid.Domain, "the domain part was not right detectet:"+jidString)
|
assert.Equal(jidValid.Domain, jid.Domain, "the domain part was not right detectet:"+jidString)
|
||||||
assert.Equal(jidValid.Resource, jid.Resource, "the resource part was not right detectet:"+jidString)
|
assert.Equal(jidValid.Resource, jid.Resource, "the resource part was not right detectet:"+jidString)
|
||||||
assert.Equal(jidValid.Full(), jidString, "the function full of jid did not work")
|
assert.Equal(jidValid.Full().String(), jidString, "the function full of jid did not work")
|
||||||
} else {
|
} else {
|
||||||
assert.Nil(jid, "this should not be a valid JID:"+jidString)
|
assert.Nil(jid, "this should not be a valid JID:"+jidString)
|
||||||
}
|
}
|
||||||
|
@ -113,11 +113,11 @@ func TestJIDBare(t *testing.T) {
|
||||||
|
|
||||||
checkList := map[string]*JID{
|
checkList := map[string]*JID{
|
||||||
"aaa@example.com": {
|
"aaa@example.com": {
|
||||||
Node: "aaa",
|
Local: "aaa",
|
||||||
Domain: "example.com",
|
Domain: "example.com",
|
||||||
},
|
},
|
||||||
"aab@example.com": {
|
"aab@example.com": {
|
||||||
Node: "aab",
|
Local: "aab",
|
||||||
Domain: "example.com",
|
Domain: "example.com",
|
||||||
Resource: "foo",
|
Resource: "foo",
|
||||||
},
|
},
|
||||||
|
@ -127,10 +127,32 @@ func TestJIDBare(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for jidValid, jid := range checkList {
|
for jidValid, jid := range checkList {
|
||||||
jidBase := jid.Bare()
|
jidBase := jid.Bare().String()
|
||||||
assert.Equal(jidValid, jidBase)
|
assert.Equal(jidValid, jidBase)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
// check nil value
|
||||||
|
var jid *JID
|
||||||
|
assert.Equal("", jid.Bare().String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestClone(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
var jid *JID
|
||||||
|
cloneJID := jid.Clone()
|
||||||
|
assert.Nil(jid)
|
||||||
|
assert.Nil(cloneJID)
|
||||||
|
|
||||||
|
originString := "bot@example.org"
|
||||||
|
|
||||||
|
jid = NewJID(originString)
|
||||||
|
cloneJID = jid.Clone()
|
||||||
|
cloneJID.Resource = "notebook"
|
||||||
|
|
||||||
|
assert.Equal(originString, jid.String())
|
||||||
|
assert.NotEqual(cloneJID.String(), jid.String())
|
||||||
|
assert.Equal(cloneJID.Bare().String(), jid.String())
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMarshal(t *testing.T) {
|
func TestMarshal(t *testing.T) {
|
||||||
|
@ -140,7 +162,7 @@ func TestMarshal(t *testing.T) {
|
||||||
err := jid.UnmarshalText([]byte("juliet@example.com/foo"))
|
err := jid.UnmarshalText([]byte("juliet@example.com/foo"))
|
||||||
|
|
||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
assert.Equal(jid.Node, "juliet")
|
assert.Equal(jid.Local, "juliet")
|
||||||
assert.Equal(jid.Domain, "example.com")
|
assert.Equal(jid.Domain, "example.com")
|
||||||
assert.Equal(jid.Resource, "foo")
|
assert.Equal(jid.Resource, "foo")
|
||||||
|
|
||||||
|
@ -149,7 +171,7 @@ func TestMarshal(t *testing.T) {
|
||||||
assert.Error(err)
|
assert.Error(err)
|
||||||
|
|
||||||
jid = &JID{
|
jid = &JID{
|
||||||
Node: "romeo",
|
Local: "romeo",
|
||||||
Domain: "example.com",
|
Domain: "example.com",
|
||||||
Resource: "bar",
|
Resource: "bar",
|
||||||
}
|
}
|
||||||
|
|
Reference in New Issue