~samwhited/xmpp

dcc6772f31033948a00a7dfb9232a120120be5b7 — Sam Whited 22 hours ago 7fa903e main
all: add strict namespace checking to mux

Previously anything that had a local name that looked like a stanza
("message", "iq", or "presence") would be treated as such, opening us up
to potential vulnerabilities in servers that allow a
{jabber:server}message on a jabber:client stream but don't treat it as a
stanza, for example.
Being more strict about checking namespaces helps to avoid this issue,
but does require a breaking change to the mux API.

Signed-off-by: Sam Whited <sam@samwhited.com>
M CHANGELOG.md => CHANGELOG.md +1 -0
@@ 12,6 12,7 @@ All notable changes to this project will be documented in this file.

- disco: the `Feature`, `Identity`, and `Item` types have been moved to the
  `info` and `items` packages
- mux: make namespace checking stricter by adding argument to `New`
- roster: rename `version` attribute to `ver`
- roster: the `Push` callback now takes the roster version
- roster: `FetchIQ` now takes a `roster.IQ` instead of a `stanza.IQ` so that the

M blocklist/blocking_test.go => blocklist/blocking_test.go +2 -1
@@ 15,6 15,7 @@ import (

	"mellium.im/xmlstream"
	"mellium.im/xmpp/blocklist"
	"mellium.im/xmpp/internal/ns"
	"mellium.im/xmpp/internal/xmpptest"
	"mellium.im/xmpp/jid"
	"mellium.im/xmpp/mux"


@@ 111,7 112,7 @@ func TestFetch(t *testing.T) {
					}
				},
			}
			m := mux.New(blocklist.Handle(h))
			m := mux.New(ns.Client, blocklist.Handle(h))
			cs := xmpptest.NewClientServer(xmpptest.ServerHandler(m))

			err := blocklist.AddIQ(context.Background(), IQ, cs.Client, tc.items...)

M carbons/handler_test.go => carbons/handler_test.go +2 -1
@@ 11,6 11,7 @@ import (
	"testing"

	"mellium.im/xmpp/carbons"
	"mellium.im/xmpp/internal/ns"
	"mellium.im/xmpp/internal/xmpptest"
	"mellium.im/xmpp/mux"
	"mellium.im/xmpp/stanza"


@@ 34,7 35,7 @@ func TestHandler(t *testing.T) {
			return nil
		},
	}
	m := mux.New(carbons.Handle(h))
	m := mux.New(ns.Client, carbons.Handle(h))
	s := xmpptest.NewClientServer(xmpptest.ClientHandler(m))
	defer s.Close()
	const recv = `<message xmlns='jabber:client'

M disco/handler_test.go => disco/handler_test.go +3 -1
@@ 12,13 12,14 @@ import (
	"mellium.im/xmlstream"
	"mellium.im/xmpp/disco"
	"mellium.im/xmpp/disco/items"
	"mellium.im/xmpp/internal/ns"
	"mellium.im/xmpp/internal/xmpptest"
	"mellium.im/xmpp/mux"
	"mellium.im/xmpp/stanza"
)

func TestFeaturesRoundTrip(t *testing.T) {
	m := mux.New(disco.Handle())
	m := mux.New(ns.Client, disco.Handle())
	cs := xmpptest.NewClientServer(
		xmpptest.ServerHandler(m),
	)


@@ 58,6 59,7 @@ func (itemHandler) ForItems(node string, f func(items.Item) error) error {

func TestItemsRoundTrip(t *testing.T) {
	m := mux.New(
		ns.Client,
		disco.Handle(),
		mux.Handle(xml.Name{}, itemHandler{}),
	)

M examples/im/main.go => examples/im/main.go +1 -1
@@ 207,7 207,7 @@ func main() {
	}

	mucClient := &muc.Client{}
	mux := mux.New(muc.HandleClient(mucClient))
	mux := mux.New("jabber:client", muc.HandleClient(mucClient))
	go func() {
		err := session.Serve(mux)
		if err != nil {

M history/history_test.go => history/history_test.go +1 -0
@@ 27,6 27,7 @@ func TestRoundTrip(t *testing.T) {
		return nil
	}))
	m := mux.New(
		"",
		mux.IQFunc(stanza.SetIQ, xml.Name{Space: history.NS, Local: "query"}, func(iq stanza.IQ, e xmlstream.TokenReadEncoder, start *xml.StartElement) error {
			xmlstream.Copy(e, stanza.Message{}.Wrap(xmlstream.Wrap(
				nil,

M muc/integration_test.go => muc/integration_test.go +3 -2
@@ 19,6 19,7 @@ import (
	"mellium.im/xmpp/disco/items"
	"mellium.im/xmpp/internal/integration"
	"mellium.im/xmpp/internal/integration/prosody"
	"mellium.im/xmpp/internal/ns"
	"mellium.im/xmpp/jid"
	"mellium.im/xmpp/muc"
	"mellium.im/xmpp/mux"


@@ 49,7 50,7 @@ func integrationJoinRoom(ctx context.Context, t *testing.T, cmd *integration.Cmd
	}
	mucClient := &muc.Client{}
	go func() {
		m := mux.New(muc.HandleClient(mucClient))
		m := mux.New(ns.Client, muc.HandleClient(mucClient))
		err := session.Serve(m)
		if err != nil {
			t.Logf("error from serve: %v", err)


@@ 178,7 179,7 @@ func integrationJoinErr(ctx context.Context, t *testing.T, cmd *integration.Cmd)
	}
	mucClient := &muc.Client{}
	go func() {
		m := mux.New(muc.HandleClient(mucClient))
		m := mux.New(ns.Client, muc.HandleClient(mucClient))
		err := session.Serve(m)
		if err != nil {
			t.Logf("error from serve: %v", err)

M muc/muc_test.go => muc/muc_test.go +4 -3
@@ 12,6 12,7 @@ import (
	"testing"

	"mellium.im/xmlstream"
	"mellium.im/xmpp/internal/ns"
	"mellium.im/xmpp/internal/xmpptest"
	"mellium.im/xmpp/jid"
	"mellium.im/xmpp/muc"


@@ 22,7 23,7 @@ import (
func TestJoinPartMuc(t *testing.T) {
	j := jid.MustParse("room@example.net/me")
	h := &muc.Client{}
	m := mux.New(muc.HandleClient(h))
	m := mux.New(ns.Client, muc.HandleClient(h))
	s := xmpptest.NewClientServer(
		xmpptest.ClientHandler(m),
		xmpptest.ServerHandlerFunc(func(t xmlstream.TokenReadEncoder, start *xml.StartElement) error {


@@ 64,7 65,7 @@ func TestJoinPartMuc(t *testing.T) {
func TestJoinError(t *testing.T) {
	j := jid.MustParse("room@example.net/me")
	h := &muc.Client{}
	m := mux.New(muc.HandleClient(h))
	m := mux.New(ns.Client, muc.HandleClient(h))
	s := xmpptest.NewClientServer(
		xmpptest.ClientHandler(m),
		xmpptest.ServerHandlerFunc(func(t xmlstream.TokenReadEncoder, start *xml.StartElement) error {


@@ 100,7 101,7 @@ func TestJoinError(t *testing.T) {
func TestPartError(t *testing.T) {
	j := jid.MustParse("room@example.net/me")
	h := &muc.Client{}
	m := mux.New(muc.HandleClient(h))
	m := mux.New(ns.Client, muc.HandleClient(h))
	errHotelCalifornia := stanza.Error{
		Type:      stanza.Auth,
		Condition: stanza.NotAllowed,

M muc/room_integration_test.go => muc/room_integration_test.go +5 -4
@@ 17,6 17,7 @@ import (
	"mellium.im/xmpp"
	"mellium.im/xmpp/internal/integration"
	"mellium.im/xmpp/internal/integration/prosody"
	"mellium.im/xmpp/internal/ns"
	"mellium.im/xmpp/jid"
	"mellium.im/xmpp/muc"
	"mellium.im/xmpp/mux"


@@ 86,7 87,7 @@ func integrationMediatedInvite(ctx context.Context, t *testing.T, cmd *integrati

	mucClient := &muc.Client{}
	go func() {
		m := mux.New(muc.HandleClient(mucClient))
		m := mux.New(ns.Client, muc.HandleClient(mucClient))
		err := userOneSession.Serve(m)
		if err != nil {
			t.Logf("error from %s serve: %v", userOne, err)


@@ 99,7 100,7 @@ func integrationMediatedInvite(ctx context.Context, t *testing.T, cmd *integrati
				errChan <- nil
			},
		}
		m := mux.New(muc.HandleClient(inviteClient))
		m := mux.New(ns.Client, muc.HandleClient(inviteClient))
		err := userTwoSession.Serve(m)
		if err != nil {
			t.Logf("error from %s serve: %v", userTwo, err)


@@ 154,7 155,7 @@ func integrationSetAffiliation(ctx context.Context, t *testing.T, cmd *integrati

	mucClientOne := &muc.Client{}
	go func() {
		m := mux.New(muc.HandleClient(mucClientOne))
		m := mux.New(ns.Client, muc.HandleClient(mucClientOne))
		err := userOneSession.Serve(m)
		if err != nil {
			t.Logf("error from %s serve: %v", userOne, err)


@@ 168,7 169,7 @@ func integrationSetAffiliation(ctx context.Context, t *testing.T, cmd *integrati
		},
	}
	go func(itemChan chan<- muc.Item) {
		m := mux.New(muc.HandleClient(mucClientTwo))
		m := mux.New(ns.Client, muc.HandleClient(mucClientTwo))
		err := userTwoSession.Serve(m)
		if err != nil {
			t.Logf("error from %s serve: %v", userTwo, err)

M muc/room_test.go => muc/room_test.go +8 -4
@@ 12,6 12,7 @@ import (
	"testing"

	"mellium.im/xmlstream"
	"mellium.im/xmpp/internal/ns"
	"mellium.im/xmpp/internal/xmpptest"
	"mellium.im/xmpp/jid"
	"mellium.im/xmpp/muc"


@@ 23,8 24,8 @@ func TestMediatedInvite(t *testing.T) {
	j := jid.MustParse("room@example.net/me")
	h := &muc.Client{}
	inviteChan := make(chan muc.Invitation, 1)
	m := mux.New(muc.HandleClient(h))
	server := mux.New(
	m := mux.New(ns.Client, muc.HandleClient(h))
	server := mux.New(ns.Client,
		mux.PresenceFunc("", xml.Name{Local: "x"}, func(p stanza.Presence, r xmlstream.TokenReadEncoder) error {
			// Send back a self presence, indicating that the join is complete.
			p.To, p.From = p.From, p.To


@@ 73,6 74,7 @@ func TestDirectInvite(t *testing.T) {
	inviteChan := make(chan muc.Invitation, 1)
	s := xmpptest.NewClientServer(
		xmpptest.ServerHandler(mux.New(
			ns.Client,
			muc.HandleInvite(func(invite muc.Invitation) {
				inviteChan <- invite
			}),


@@ 119,8 121,9 @@ func TestSetAffiliation(t *testing.T) {
	j := jid.MustParse("room@example.net/me")
	h := &muc.Client{}
	handled := make(chan string, 1)
	m := mux.New(muc.HandleClient(h))
	m := mux.New(ns.Client, muc.HandleClient(h))
	server := mux.New(
		ns.Client,
		mux.PresenceFunc("", xml.Name{Local: "x"}, func(p stanza.Presence, r xmlstream.TokenReadEncoder) error {
			// Send back a self presence, indicating that the join is complete.
			p.To, p.From = p.From, p.To


@@ 176,8 179,9 @@ func TestSetSubject(t *testing.T) {
	j := jid.MustParse("room@example.net/me")
	h := &muc.Client{}
	handled := make(chan string, 1)
	m := mux.New(muc.HandleClient(h))
	m := mux.New(ns.Client, muc.HandleClient(h))
	server := mux.New(
		ns.Client,
		mux.PresenceFunc("", xml.Name{Local: "x"}, func(p stanza.Presence, r xmlstream.TokenReadEncoder) error {
			// Send back a self presence, indicating that the join is complete.
			p.To, p.From = p.From, p.To

M mux/mux.go => mux/mux.go +12 -9
@@ 54,11 54,12 @@ type ServeMux struct {
	iqPatterns       map[pattern]IQHandler
	msgPatterns      map[pattern]MessageHandler
	presencePatterns map[pattern]PresenceHandler
	stanzaNS         string
}

// New allocates and returns a new ServeMux.
func New(opt ...Option) *ServeMux {
	m := &ServeMux{}
func New(stanzaNS string, opt ...Option) *ServeMux {
	m := &ServeMux{stanzaNS: stanzaNS}
	for _, o := range opt {
		o(m)
	}


@@ 89,13 90,15 @@ func (m *ServeMux) Handler(name xml.Name) (h xmpp.Handler, ok bool) {
		return h, true
	}

	switch name.Local {
	case iqStanza:
		return xmpp.HandlerFunc(m.iqRouter), true
	case msgStanza:
		return xmpp.HandlerFunc(m.msgRouter), true
	case presStanza:
		return xmpp.HandlerFunc(m.presenceRouter), true
	if stanza.Is(name, m.stanzaNS) {
		switch name.Local {
		case iqStanza:
			return xmpp.HandlerFunc(m.iqRouter), true
		case msgStanza:
			return xmpp.HandlerFunc(m.msgRouter), true
		case presStanza:
			return xmpp.HandlerFunc(m.presenceRouter), true
		}
	}

	return nopHandler{}, false

M mux/mux_test.go => mux/mux_test.go +29 -10
@@ 133,6 133,7 @@ var testCases = [...]struct {
	x           string
	expectPanic bool
	err         error
	stanzaNS    string
}{
	0: {
		// Basic muxing based on localname and IQ type should work.


@@ 151,8 152,9 @@ var testCases = [...]struct {
			mux.IQ(stanza.GetIQ, xml.Name{}, failHandler{}),
			mux.Presence(stanza.AvailablePresence, xml.Name{}, failHandler{}),
		},
		x:   `<iq type="set" xmlns="jabber:server"><b/></iq>`,
		err: errPassTest,
		x:        `<iq type="set" xmlns="jabber:server"><b/></iq>`,
		err:      errPassTest,
		stanzaNS: ns.Server,
	},
	2: {
		// The message option works with a client namespace.


@@ 169,8 171,9 @@ var testCases = [...]struct {
			mux.IQ(stanza.GetIQ, xml.Name{}, failHandler{}),
			mux.MessageFunc(stanza.ChatMessage, xml.Name{}, passHandler{}.HandleMessage),
		},
		x:   `<message to="feste@example.net" from="olivia@example.net" type="chat" xmlns="jabber:server"></message>`,
		err: errPassTest,
		x:        `<message to="feste@example.net" from="olivia@example.net" type="chat" xmlns="jabber:server"></message>`,
		err:      errPassTest,
		stanzaNS: ns.Server,
	},
	4: {
		// The presence option works with a client namespace and no type attribute.


@@ 190,8 193,9 @@ var testCases = [...]struct {
			mux.IQ(stanza.GetIQ, xml.Name{}, failHandler{}),
			mux.PresenceFunc(stanza.AvailablePresence, xml.Name{}, passHandler{}.HandlePresence),
		},
		x:   `<presence type="" xmlns="jabber:server"></presence>`,
		err: errPassTest,
		x:        `<presence type="" xmlns="jabber:server"></presence>`,
		err:      errPassTest,
		stanzaNS: ns.Server,
	},
	6: {
		// Other top level elements can be routed with a wildcard namespace.


@@ 462,8 466,9 @@ var testCases = [...]struct {
			mux.Message(stanza.NormalMessage, xml.Name{Local: "test", Space: exampleNS}, multiHandler{}),
			mux.Message(stanza.NormalMessage, xml.Name{Local: "example", Space: exampleNS}, multiHandler{}),
		},
		x:   `<message type="normal" xmlns="jabber:server"><test xmlns="com.example">test</test><example xmlns="com.example">example</example></message>`,
		err: errors.New("mux_test: PASSED, mux_test: PASSED"),
		x:        `<message type="normal" xmlns="jabber:server"><test xmlns="com.example">test</test><example xmlns="com.example">example</example></message>`,
		err:      errors.New("mux_test: PASSED, mux_test: PASSED"),
		stanzaNS: ns.Server,
	},
	41: {
		m: []mux.Option{


@@ 503,7 508,11 @@ func TestMux(t *testing.T) {
					}
				}()
			}
			m := mux.New(tc.m...)
			stanzaNS := tc.stanzaNS
			if stanzaNS == "" {
				stanzaNS = ns.Client
			}
			m := mux.New(stanzaNS, tc.m...)
			d := xml.NewDecoder(strings.NewReader(tc.x))
			tok, _ := d.Token()
			start, ok := tok.(xml.StartElement)


@@ 558,7 567,7 @@ func TestFallback(t *testing.T) {
	start := tok.(xml.StartElement)
	w := s.TokenWriter()
	defer w.Close()
	err = mux.New().HandleXMPP(testEncoder{
	err = mux.New(ns.Client).HandleXMPP(testEncoder{
		TokenReader: r,
		TokenWriter: w,
	}, &start)


@@ 666,6 675,7 @@ func (presenceFeature) ForItems(node string, f func(items.Item) error) error {

func TestFeatures(t *testing.T) {
	m := mux.New(
		ns.Client,
		mux.Handle(xml.Name{}, handleFeature{}),
		mux.IQ("", xml.Name{}, iqFeature{}),
		mux.Message("", xml.Name{}, messageFeature{}),


@@ 709,6 719,7 @@ func TestFeatures(t *testing.T) {

func TestItems(t *testing.T) {
	m := mux.New(
		ns.Client,
		mux.Handle(xml.Name{}, handleFeature{}),
		mux.IQ("", xml.Name{}, iqFeature{}),
		mux.Message("", xml.Name{}, messageFeature{}),


@@ 752,6 763,7 @@ func TestItems(t *testing.T) {

func TestFeaturesHandlerErr(t *testing.T) {
	m := mux.New(
		ns.Client,
		mux.Handle(xml.Name{}, handleFeature{}),
	)
	err := m.ForFeatures("", func(i info.Feature) error {


@@ 764,6 776,7 @@ func TestFeaturesHandlerErr(t *testing.T) {

func TestFeaturesHandleIQErr(t *testing.T) {
	m := mux.New(
		ns.Client,
		mux.IQ("", xml.Name{}, iqFeature{}),
	)
	err := m.ForFeatures("", func(i info.Feature) error {


@@ 775,6 788,7 @@ func TestFeaturesHandleIQErr(t *testing.T) {
}
func TestFeaturesHandleMsgErr(t *testing.T) {
	m := mux.New(
		ns.Client,
		mux.Message("", xml.Name{}, messageFeature{}),
	)
	err := m.ForFeatures("", func(i info.Feature) error {


@@ 786,6 800,7 @@ func TestFeaturesHandleMsgErr(t *testing.T) {
}
func TestFeaturesHandlePresenceErr(t *testing.T) {
	m := mux.New(
		ns.Client,
		mux.Presence("", xml.Name{}, presenceFeature{}),
	)
	err := m.ForFeatures("", func(i info.Feature) error {


@@ 798,6 813,7 @@ func TestFeaturesHandlePresenceErr(t *testing.T) {

func TestItemsHandlerErr(t *testing.T) {
	m := mux.New(
		ns.Client,
		mux.Handle(xml.Name{}, handleFeature{}),
	)
	err := m.ForItems("", func(i items.Item) error {


@@ 809,6 825,7 @@ func TestItemsHandlerErr(t *testing.T) {
}
func TestItemsHandleIQErr(t *testing.T) {
	m := mux.New(
		ns.Client,
		mux.IQ("", xml.Name{}, iqFeature{}),
	)
	err := m.ForItems("", func(i items.Item) error {


@@ 820,6 837,7 @@ func TestItemsHandleIQErr(t *testing.T) {
}
func TestItemsHandleMsgErr(t *testing.T) {
	m := mux.New(
		ns.Client,
		mux.Message("", xml.Name{}, messageFeature{}),
	)
	err := m.ForItems("", func(i items.Item) error {


@@ 831,6 849,7 @@ func TestItemsHandleMsgErr(t *testing.T) {
}
func TestItemsHandlePresenceErr(t *testing.T) {
	m := mux.New(
		ns.Client,
		mux.Presence("", xml.Name{}, presenceFeature{}),
	)
	err := m.ForItems("", func(i items.Item) error {

M ping/integration_test.go => ping/integration_test.go +2 -1
@@ 22,6 22,7 @@ import (
	"mellium.im/xmpp/internal/integration/mcabber"
	"mellium.im/xmpp/internal/integration/prosody"
	"mellium.im/xmpp/internal/integration/sendxmpp"
	"mellium.im/xmpp/internal/ns"
	"mellium.im/xmpp/mux"
	"mellium.im/xmpp/ping"
	"mellium.im/xmpp/stanza"


@@ 57,7 58,7 @@ func integrationRecvPing(ctx context.Context, t *testing.T, cmd *integration.Cmd
		t.Fatalf("error connecting: %v", err)
	}
	go func() {
		m := mux.New(mux.IQFunc(stanza.GetIQ, xml.Name{Local: "ping", Space: ping.NS},
		m := mux.New(ns.Client, mux.IQFunc(stanza.GetIQ, xml.Name{Local: "ping", Space: ping.NS},
			func(iq stanza.IQ, t xmlstream.TokenReadEncoder, start *xml.StartElement) error {
				err := ping.Handler{}.HandleIQ(iq, t, start)
				gotPing <- struct{}{}

M ping/ping_test.go => ping/ping_test.go +5 -4
@@ 12,6 12,7 @@ import (

	"mellium.im/xmlstream"
	"mellium.im/xmpp/disco/info"
	"mellium.im/xmpp/internal/ns"
	"mellium.im/xmpp/internal/xmpptest"
	"mellium.im/xmpp/jid"
	"mellium.im/xmpp/mux"


@@ 56,7 57,7 @@ type tokenReadEncoder struct {
}

func TestRoundTrip(t *testing.T) {
	m := mux.New(ping.Handle())
	m := mux.New(ns.Client, ping.Handle())
	cs := xmpptest.NewClientServer(
		xmpptest.ServerHandler(m),
	)


@@ 74,7 75,7 @@ func TestWrongIQType(t *testing.T) {
	tok, _ := d.Token()
	start := tok.(xml.StartElement)

	m := mux.New(mux.IQ(stanza.SetIQ, xml.Name{Local: "ping", Space: ping.NS}, ping.Handler{}))
	m := mux.New(ns.Client, mux.IQ(stanza.SetIQ, xml.Name{Local: "ping", Space: ping.NS}, ping.Handler{}))
	err := m.HandleXMPP(tokenReadEncoder{
		TokenReader: d,
		Encoder:     e,


@@ 100,7 101,7 @@ func TestBadPayloadLocalname(t *testing.T) {
	tok, _ := d.Token()
	start := tok.(xml.StartElement)

	m := mux.New(mux.IQ(stanza.GetIQ, xml.Name{Local: "badlocal", Space: ping.NS}, ping.Handler{}))
	m := mux.New(ns.Client, mux.IQ(stanza.GetIQ, xml.Name{Local: "badlocal", Space: ping.NS}, ping.Handler{}))
	err := m.HandleXMPP(tokenReadEncoder{
		TokenReader: d,
		Encoder:     e,


@@ 126,7 127,7 @@ func TestBadPayloadNamespace(t *testing.T) {
	tok, _ := d.Token()
	start := tok.(xml.StartElement)

	m := mux.New(mux.IQ(stanza.GetIQ, xml.Name{Local: "ping", Space: "badnamespace"}, ping.Handler{}))
	m := mux.New(ns.Client, mux.IQ(stanza.GetIQ, xml.Name{Local: "ping", Space: "badnamespace"}, ping.Handler{}))
	err := m.HandleXMPP(tokenReadEncoder{
		TokenReader: d,
		Encoder:     e,

M receipts/receipts_test.go => receipts/receipts_test.go +1 -1
@@ 206,7 206,7 @@ func TestRoundTrip(t *testing.T) {
	var b strings.Builder
	e := xml.NewEncoder(&b)

	m := mux.New(receipts.Handle(h))
	m := mux.New(ns.Client, receipts.Handle(h))
	err = m.HandleXMPP(struct {
		xml.TokenReader
		xmlstream.Encoder

M roster/roster_test.go => roster/roster_test.go +3 -2
@@ 14,6 14,7 @@ import (
	"testing"

	"mellium.im/xmlstream"
	"mellium.im/xmpp/internal/ns"
	"mellium.im/xmpp/internal/xmpptest"
	"mellium.im/xmpp/jid"
	"mellium.im/xmpp/mux"


@@ 144,7 145,7 @@ func TestReceivePush(t *testing.T) {
		t.Errorf("unexpected error popping start token: %v", err)
	}
	start := tok.(xml.StartElement)
	m := mux.New(roster.Handle(h))
	m := mux.New(ns.Client, roster.Handle(h))
	err = m.HandleXMPP(struct {
		xml.TokenReader
		xmlstream.Encoder


@@ 190,7 191,7 @@ func TestReceivePushError(t *testing.T) {
		t.Errorf("unexpected error popping start token: %v", err)
	}
	start := tok.(xml.StartElement)
	m := mux.New(roster.Handle(h))
	m := mux.New(ns.Client, roster.Handle(h))
	err = m.HandleXMPP(struct {
		xml.TokenReader
		xmlstream.Encoder

M xtime/time_test.go => xtime/time_test.go +2 -1
@@ 11,6 11,7 @@ import (
	"time"

	"mellium.im/xmlstream"
	"mellium.im/xmpp/internal/ns"
	"mellium.im/xmpp/internal/xmpptest"
	"mellium.im/xmpp/mux"
	"mellium.im/xmpp/xtime"


@@ 33,7 34,7 @@ func TestRoundTrip(t *testing.T) {
			return serverTime
		},
	}
	m := mux.New(xtime.Handle(h))
	m := mux.New(ns.Client, xtime.Handle(h))
	cs := xmpptest.NewClientServer(
		xmpptest.ServerHandler(m),
	)