sum7
/
yaja
Archived
1
0
Fork 0

improve JID struct

This commit is contained in:
Martin/Geno 2018-02-15 22:03:49 +01:00
parent 02ee2f2087
commit 3e39507f5a
No known key found for this signature in database
GPG Key ID: F0D39A37E925E941
14 changed files with 275 additions and 95 deletions

View File

@ -61,8 +61,8 @@ func (client *Client) auth(password string) error {
cnonceStr := cnonce()
digestURI := "xmpp/" + client.JID.Domain
nonceCount := fmt.Sprintf("%08x", 1)
digest := saslDigestResponse(client.JID.Node, realm, password, nonce, cnonceStr, "AUTHENTICATE", digestURI, nonceCount)
message := "username=\"" + client.JID.Node + "\", realm=\"" + realm + "\", nonce=\"" + nonce + "\", cnonce=\"" + cnonceStr +
digest := saslDigestResponse(client.JID.Local, realm, password, nonce, cnonceStr, "AUTHENTICATE", digestURI, nonceCount)
message := "username=\"" + client.JID.Local + "\", realm=\"" + realm + "\", nonce=\"" + nonce + "\", cnonce=\"" + cnonceStr +
"\", nc=" + nonceCount + ", qop=" + qop + ", digest-uri=\"" + digestURI + "\", response=" + digest + ", charset=" + charset
response.Body = base64.StdEncoding.EncodeToString([]byte(message))
@ -72,7 +72,7 @@ func (client *Client) auth(password string) error {
if m == "PLAIN" {
mechanism = m
// 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)))
base64.StdEncoding.Encode(enc, []byte(raw))
client.Send(&xmpp.SASLAuth{

View File

@ -120,7 +120,7 @@ func (client *Client) connect(password string) error {
if bind == nil {
return errors.New("bind is 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.Resource = bind.JID.Resource
client.Logging.Infof("set jid by server bind '%s'", bind.JID.Full())

View File

@ -110,21 +110,22 @@ func (t *Tester) StartBot(status *Status) {
first := true
allAdmins := ""
isAdmin := false
fromBare := msg.From
for _, jid := range botAllowed(t.Admins, status.account.Admins) {
if first {
first = false
allAdmins += jid.Bare()
} else {
allAdmins += ", " + jid.Bare()
allAdmins += ", "
}
if jid.Bare() == msg.From.Bare() {
allAdmins += jid.Bare().String()
if jid.Bare().IsEqual(fromBare) {
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 {
status.Disconnect(fmt.Sprintf("disconnect by admin '%s'", msg.From.Bare()))
status.Disconnect(fmt.Sprintf("disconnect by admin '%s'", fromBare.String()))
return
}
status.client.Send(xmpp.MessageClient{Type: msg.Type, To: msg.From, Body: "not allowed, ask " + allAdmins})

View File

@ -57,17 +57,17 @@ func (t *Tester) Output() *Output {
toJID := xmppbase.NewJID(to)
link := &Link{
Source: status.JID.Domain,
SourceJID: status.JID.Bare(),
SourceJID: status.JID.Bare().String(),
Target: toJID.Domain,
TargetJID: toJID.Bare(),
TargetJID: toJID.Bare().String(),
FromSource: linkOK,
FromTarget: false,
}
if switchSourceTarget {
link.Source = toJID.Domain
link.SourceJID = toJID.Bare()
link.SourceJID = toJID.Bare().String()
link.Target = status.JID.Domain
link.TargetJID = status.JID.Bare()
link.TargetJID = status.JID.Bare().String()
link.FromSource = false
link.FromTarget = linkOK
}

View File

@ -59,7 +59,7 @@ func (s *Status) Update(timeout time.Duration) {
}
c := &client.Client{
JID: xmppbase.NewJID(s.account.JID.Bare()),
JID: s.account.JID.Bare(),
Protocol: "tcp4",
Logging: s.client.Logging,
Timeout: timeout / 2,
@ -72,7 +72,7 @@ func (s *Status) Update(timeout time.Duration) {
s.IPv4 = false
}
c.JID = xmppbase.NewJID(s.account.JID.Bare())
c.JID = s.account.JID.Bare()
c.Protocol = "tcp6"
if err := c.Connect(s.account.Password); err == nil {

View File

@ -44,7 +44,7 @@ func (t *Tester) Start(mainClient *client.Client, password string) {
t.mux.Lock()
defer t.mux.Unlock()
t.Status[mainClient.JID.Bare()] = status
t.Status[mainClient.JID.Bare().String()] = status
go t.StartBot(status)
for _, acc := range t.Accounts {
@ -58,11 +58,12 @@ func (t *Tester) Close() {
}
func (t *Tester) Connect(acc *Account) {
logCTX := log.WithField("jid", acc.JID.Full())
status, ok := t.Status[acc.JID.Bare()]
logCTX := log.WithField("jid", acc.JID.Full().String())
bare := acc.JID.Bare().String()
status, ok := t.Status[bare]
if !ok {
status = NewStatus(t.mainClient, acc)
t.Status[acc.JID.Bare()] = status
t.Status[bare] = status
} else if status.JID == nil {
status.JID = acc.JID
}
@ -99,19 +100,20 @@ func (t *Tester) UpdateConnectionStatus(from, to *xmppbase.JID, recvmsg string)
t.mux.Lock()
defer t.mux.Unlock()
status, ok := t.Status[from.Bare()]
status, ok := t.Status[from.Bare().String()]
if !ok {
logCTX.Warn("recv msg without receiver")
return
}
msg, ok := status.MessageForConnection[to.Bare()]
toBare := to.Bare().String()
msg, ok := status.MessageForConnection[toBare]
logCTX = logCTX.WithField("msg-send", msg)
if !ok || msg != recvmsg || msg == "" || recvmsg == "" {
logCTX.Warn("recv wrong msg")
return
}
delete(status.MessageForConnection, to.Bare())
status.Connections[to.Bare()] = true
delete(status.MessageForConnection, toBare)
status.Connections[toBare] = true
logCTX.Info("recv msg")
}
@ -163,7 +165,7 @@ func (t *Tester) CheckStatus() {
Type: xmpp.MessageTypeChat,
To: s.JID,
})
own.MessageForConnection[s.JID.Bare()] = msg
own.MessageForConnection[s.JID.Bare().String()] = msg
logCTXTo.Debug("test send")
send++
}

View File

@ -16,7 +16,7 @@ type State struct {
}
func (s *State) AddAccount(a *model.Account) error {
if a.Node == "" {
if a.Local == "" {
return errors.New("No localpart exists in account")
}
if d := a.Domain; d != nil {
@ -39,11 +39,11 @@ func (s *State) AddAccount(a *model.Account) error {
if domain.Accounts == nil {
domain.Accounts = make(map[string]*model.Account)
}
_, ok = domain.Accounts[a.Node]
_, ok = domain.Accounts[a.Local]
if ok {
return errors.New("exists already")
}
domain.Accounts[a.Node] = a
domain.Accounts[a.Local] = a
a.Domain = d
return nil
}
@ -54,7 +54,7 @@ func (s *State) Authenticate(jid *xmppbase.JID, password string) (bool, error) {
logger := log.WithField("database", "auth")
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) {
return true, nil
} else {
@ -73,7 +73,7 @@ func (s *State) GetAccount(jid *xmppbase.JID) *model.Account {
logger := log.WithField("database", "get")
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
} else {
logger.Debug("account not found")

View File

@ -20,18 +20,18 @@ func (d *Domain) GetJID() *xmppbase.JID {
}
func (d *Domain) UpdateAccount(a *Account) error {
if a.Node == "" {
if a.Local == "" {
return errors.New("No localpart exists in account")
}
d.Lock()
d.Accounts[a.Node] = a
d.Accounts[a.Local] = a
d.Unlock()
a.Domain = d
return nil
}
type Account struct {
Node string `json:"-"`
Local string `json:"-"`
Domain *Domain `json:"-"`
Password string `json:"password"`
Roster map[string]*Buddy `json:"roster"`
@ -43,7 +43,7 @@ func NewAccount(jid *xmppbase.JID, password string) *Account {
return nil
}
return &Account{
Node: jid.Node,
Local: jid.Local,
Domain: &Domain{
FQDN: jid.Domain,
},
@ -54,7 +54,7 @@ func NewAccount(jid *xmppbase.JID, password string) *Account {
func (a *Account) GetJID() *xmppbase.JID {
return &xmppbase.JID{
Domain: a.Domain.FQDN,
Node: a.Node,
Local: a.Local,
}
}

View File

@ -76,7 +76,7 @@ func (state *TLSStream) Process() state.State {
</mechanisms>
</stream:features>`,
xmpp.CreateCookie(), xmpp.NSClient, xmpp.NSStream,
xmpp.NSSASL, xmppiq.NSFeaturesIQRegister)
xmpp.NSSASL, xmppiq.NSFeatureRegister)
} else {
fmt.Fprintf(state.Client.Conn, `<?xml version='1.0'?>
<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")
// 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())
success, err := state.database.Authenticate(state.Client.JID, info[2])
if err != nil {

View File

@ -44,7 +44,7 @@ func (state *RegisterFormRequest) Process() state.State {
return state
}
if msg.PrivateRegister == nil {
if msg.Register == nil {
state.Client.Log.Warn("is no iq register")
return nil
}
@ -53,7 +53,7 @@ func (state *RegisterFormRequest) Process() state.State {
To: state.Client.JID,
From: xmppbase.NewJID(state.Client.JID.Domain),
ID: msg.ID,
PrivateRegister: &xmppiq.IQPrivateRegister{
Register: &xmppiq.Register{
Instructions: "Choose a username and password for use with this service.",
Username: "",
Password: "",
@ -98,22 +98,22 @@ func (state *RegisterRequest) Process() state.State {
state.Client.Log.Warn("iq with error: ", msg.Error.Code)
return state
}
if msg.PrivateRegister == nil {
if msg.Register == nil {
state.Client.Log.Warn("is no iq register: ", err)
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())
account := model.NewAccount(state.Client.JID, msg.PrivateRegister.Password)
account := model.NewAccount(state.Client.JID, msg.Register.Password)
err = state.database.AddAccount(account)
if err != nil {
state.Client.Out.Encode(&xmpp.IQClient{
Type: xmpp.IQTypeResult,
To: state.Client.JID,
From: xmppbase.NewJID(state.Client.JID.Domain),
ID: msg.ID,
PrivateRegister: msg.PrivateRegister,
Type: xmpp.IQTypeResult,
To: state.Client.JID,
From: xmppbase.NewJID(state.Client.JID.Domain),
ID: msg.ID,
Register: msg.Register,
Error: &xmpp.ErrorClient{
Code: "409",
Type: "cancel",

View File

@ -11,9 +11,9 @@ func init() {
jidRegex = regexp.MustCompile(`^(?:([^@/<>'\" ]+)@)?([^@/<>'\"]+)(?:/([^<>'\" ][^<>'\"]*))?$`)
}
// JID struct
// JID implements RFC6122: XMPP - Address Format
type JID struct {
Node string
Local string
Domain string
Resource string
}
@ -28,49 +28,57 @@ func NewJID(jidString string) *JID {
jidSplit := jidSplitTmp[0]
return &JID{
Node: jidSplit[1],
Local: jidSplit[1],
Domain: jidSplit[2],
Resource: jidSplit[3],
}
}
// Bare get the "bare" jid
func (jid *JID) Bare() string {
if jid == nil {
return ""
// Clone JID struct address/pointer
func (jid *JID) Clone() *JID {
if jid != nil {
return &JID{
Local: jid.Local,
Domain: jid.Domain,
Resource: jid.Resource,
}
}
if jid.Node != "" {
return jid.Node + "@" + jid.Domain
}
return jid.Domain
}
// 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 == ""
return nil
}
// 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 {
return ""
}
if jid.Resource != "" {
return jid.Bare() + "/" + jid.Resource
str := jid.Domain
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
func (jid JID) MarshalText() ([]byte, error) {
return []byte(jid.Full()), nil
return []byte(jid.String()), nil
}
// UnmarshalText from bytearray
@ -79,7 +87,7 @@ func (jid *JID) UnmarshalText(data []byte) (err error) {
if newJID == nil {
return errors.New("not a valid jid")
}
jid.Node = newJID.Node
jid.Local = newJID.Local
jid.Domain = newJID.Domain
jid.Resource = newJID.Resource
return nil

24
xmpp/base/jid_is.go Normal file
View File

@ -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
}

123
xmpp/base/jid_is_test.go Normal file
View File

@ -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))
}

View File

@ -13,57 +13,57 @@ func TestNewJID(t *testing.T) {
checkList := map[string]*JID{
"juliet@example.com": {
Node: "juliet",
Local: "juliet",
Domain: "example.com",
},
"juliet@example.com/foo": {
Node: "juliet",
Local: "juliet",
Domain: "example.com",
Resource: "foo",
},
"juliet@example.com/foo bar": {
Node: "juliet",
Local: "juliet",
Domain: "example.com",
Resource: "foo bar",
},
"juliet@example.com/foo@bar": {
Node: "juliet",
Local: "juliet",
Domain: "example.com",
Resource: "foo@bar",
},
"foo\\20bar@example.com": {
Node: "foo\\20bar",
Local: "foo\\20bar",
Domain: "example.com",
},
"fussball@example.com": {
Node: "fussball",
Local: "fussball",
Domain: "example.com",
},
"fu&#xDF;ball@example.com": {
Node: "fu&#xDF;ball",
Local: "fu&#xDF;ball",
Domain: "example.com",
},
"&#x3C0;@example.com": {
Node: "&#x3C0;",
Local: "&#x3C0;",
Domain: "example.com",
},
"&#x3A3;@example.com/foo": {
Node: "&#x3A3;",
Local: "&#x3A3;",
Domain: "example.com",
Resource: "foo",
},
"&#x3C3;@example.com/foo": {
Node: "&#x3C3;",
Local: "&#x3C3;",
Domain: "example.com",
Resource: "foo",
},
"&#x3C2;@example.com/foo": {
Node: "&#x3C2;",
Local: "&#x3C2;",
Domain: "example.com",
Resource: "foo",
},
"king@example.com/&#x265A;": {
Node: "king",
Local: "king",
Domain: "example.com",
Resource: "&#x265A;",
},
@ -97,10 +97,10 @@ func TestNewJID(t *testing.T) {
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.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 {
assert.Nil(jid, "this should not be a valid JID:"+jidString)
}
@ -113,11 +113,11 @@ func TestJIDBare(t *testing.T) {
checkList := map[string]*JID{
"aaa@example.com": {
Node: "aaa",
Local: "aaa",
Domain: "example.com",
},
"aab@example.com": {
Node: "aab",
Local: "aab",
Domain: "example.com",
Resource: "foo",
},
@ -127,10 +127,32 @@ func TestJIDBare(t *testing.T) {
},
}
for jidValid, jid := range checkList {
jidBase := jid.Bare()
jidBase := jid.Bare().String()
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) {
@ -140,7 +162,7 @@ func TestMarshal(t *testing.T) {
err := jid.UnmarshalText([]byte("juliet@example.com/foo"))
assert.NoError(err)
assert.Equal(jid.Node, "juliet")
assert.Equal(jid.Local, "juliet")
assert.Equal(jid.Domain, "example.com")
assert.Equal(jid.Resource, "foo")
@ -149,7 +171,7 @@ func TestMarshal(t *testing.T) {
assert.Error(err)
jid = &JID{
Node: "romeo",
Local: "romeo",
Domain: "example.com",
Resource: "bar",
}