From d8877853cd74347d121547be2dec3d75a67a4c35 Mon Sep 17 00:00:00 2001 From: Sonny Piers Date: Mon, 30 Dec 2024 12:46:36 +0100 Subject: [PATCH] much improvements --- packages/client-core/src/bind2/bind2.js | 4 +++- packages/client/index.js | 8 +------- packages/component-core/lib/Component.js | 2 +- packages/connection/index.js | 9 +++++++- packages/resource-binding/index.js | 1 + packages/sasl/test.js | 5 ++--- packages/sasl2/index.js | 8 ++++---- packages/sasl2/test.js | 26 ++++++++++++++++++------ packages/session-establishment/test.js | 7 +++---- packages/stream-features/index.js | 4 ---- packages/stream-features/route.js | 12 ----------- packages/stream-management/index.js | 10 +++------ 12 files changed, 46 insertions(+), 50 deletions(-) delete mode 100644 packages/stream-features/route.js diff --git a/packages/client-core/src/bind2/bind2.js b/packages/client-core/src/bind2/bind2.js index 4fd186bd..fa1ae5c1 100644 --- a/packages/client-core/src/bind2/bind2.js +++ b/packages/client-core/src/bind2/bind2.js @@ -2,7 +2,7 @@ import xml from "@xmpp/xml"; const NS_BIND = "urn:xmpp:bind:0"; -export default function bind2({ sasl2 }, tag) { +export default function bind2({ sasl2, entity }, tag) { const features = new Map(); sasl2.use( @@ -22,6 +22,8 @@ export default function bind2({ sasl2 }, tag) { ); }, (element) => { + if (!element.is("bound")) return; + entity._ready(false); for (const child of element.getChildElements()) { const feature = features.get(child.getNS()); feature?.[1]?.(child); diff --git a/packages/client/index.js b/packages/client/index.js index 36df03f7..0d5c1e5b 100644 --- a/packages/client/index.js +++ b/packages/client/index.js @@ -15,7 +15,6 @@ import _starttls from "@xmpp/starttls"; import _sasl2 from "@xmpp/sasl2"; import _sasl from "@xmpp/sasl"; import _resourceBinding from "@xmpp/resource-binding"; -import _sessionEstablishment from "@xmpp/session-establishment"; import _streamManagement from "@xmpp/stream-management"; import _bind2 from "@xmpp/client-core/src/bind2/bind2.js"; @@ -65,7 +64,7 @@ function client(options = {}) { ); // SASL2 inline features - const bind2 = _bind2({ sasl2 }, resource); + const bind2 = _bind2({ sasl2, entity }, resource); // Stream features - order matters and define priority const sasl = _sasl( @@ -83,10 +82,6 @@ function client(options = {}) { { iqCaller, streamFeatures }, resource, ); - const sessionEstablishment = _sessionEstablishment({ - iqCaller, - streamFeatures, - }); return Object.assign(entity, { entity, @@ -104,7 +99,6 @@ function client(options = {}) { sasl2, sasl, resourceBinding, - sessionEstablishment, streamManagement, mechanisms, bind2, diff --git a/packages/component-core/lib/Component.js b/packages/component-core/lib/Component.js index 6f3cd284..fded6354 100644 --- a/packages/component-core/lib/Component.js +++ b/packages/component-core/lib/Component.js @@ -37,7 +37,7 @@ class Component extends Connection { } this._jid(this.options.domain); - this._status("online", this.jid); + this._ready(false); } } diff --git a/packages/connection/index.js b/packages/connection/index.js index 56e1aa43..881ac528 100644 --- a/packages/connection/index.js +++ b/packages/connection/index.js @@ -22,7 +22,6 @@ class Connection extends EventEmitter { } _reset() { - this.jid = this.jid?.bare() ?? null; this.status = "offline"; this._detachSocket(); this._detachParser(); @@ -185,6 +184,14 @@ class Connection extends EventEmitter { this.emit(status, ...args); } + _ready(resumed = false) { + if (resumed) { + this.status = "online"; + } else { + this._status("online", this.jid); + } + } + async _end() { let el; try { diff --git a/packages/resource-binding/index.js b/packages/resource-binding/index.js index 5324db22..5b9352ff 100644 --- a/packages/resource-binding/index.js +++ b/packages/resource-binding/index.js @@ -15,6 +15,7 @@ async function bind(entity, iqCaller, resource) { const result = await iqCaller.set(makeBindElement(resource)); const jid = result.getChildText("jid"); entity._jid(jid); + entity._ready(false); return jid; } diff --git a/packages/sasl/test.js b/packages/sasl/test.js index 5147a99d..86513b56 100644 --- a/packages/sasl/test.js +++ b/packages/sasl/test.js @@ -43,14 +43,13 @@ test("with object credentials", async () => { ); entity.mockInput(); - - await promise(entity, "online"); }); test("with function credentials", async () => { expect.assertions(2); const mech = "PLAIN"; + let promise_authenticate; async function onAuthenticate(authenticate, mechanisms) { expect(mechanisms).toEqual([mech]); @@ -79,7 +78,7 @@ test("with function credentials", async () => { entity.mockInput(); - await promise(entity, "online"); + await promise_authenticate; }); test("Mechanism not found", async () => { diff --git a/packages/sasl2/index.js b/packages/sasl2/index.js index 29c237be..1b93b46f 100644 --- a/packages/sasl2/index.js +++ b/packages/sasl2/index.js @@ -72,9 +72,11 @@ async function authenticate({ } // https://xmpp.org/extensions/xep-0388.html#success - // this is a bare JID, unless resource binding has occurred, in which case it is a full JID. + // this is a bare JID, unless resource binding or stream resumption has occurred, in which case it is a full JID. const aid = element.getChildText("authorization-identifier"); - if (aid) entity._jid(aid); + if (aid) { + entity._jid(aid); + } for (const child of element.getChildElements()) { const feature = features.get(child.getNS()); @@ -132,8 +134,6 @@ export default function sasl2({ streamFeatures, saslFactory }, onAuthenticate) { } await onAuthenticate(done, intersection); - // Not online yet, wait for next features - return true; }, ); diff --git a/packages/sasl2/test.js b/packages/sasl2/test.js index 0a7e696c..b2042769 100644 --- a/packages/sasl2/test.js +++ b/packages/sasl2/test.js @@ -37,10 +37,17 @@ test("with object credentials", async () => { , ); - entity.mockInput(); - entity.mockInput(); + const jid = "username@localhost/example~Ln8YSSzsyK-b_3-vIFvOJNnE"; - await promise(entity, "online"); + expect(entity.jid?.toString()).not.toBe(jid); + + entity.mockInput( + + {jid} + , + ); + + expect(entity.jid.toString()).toBe(jid); }); test("with function credentials", async () => { @@ -74,10 +81,17 @@ test("with function credentials", async () => { , ); - entity.mockInput(); - entity.mockInput(); + const jid = "username@localhost/example~Ln8YSSzsyK-b_3-vIFvOJNnE"; + + expect(entity.jid?.toString()).not.toBe(jid); + + entity.mockInput( + + {jid} + , + ); - await promise(entity, "online"); + expect(entity.jid.toString()).toBe(jid); }); test("failure", async () => { diff --git a/packages/session-establishment/test.js b/packages/session-establishment/test.js index 5418ace1..5ca535f9 100644 --- a/packages/session-establishment/test.js +++ b/packages/session-establishment/test.js @@ -1,7 +1,9 @@ import { mockClient, promise, timeout } from "@xmpp/test"; +import sessionEstablishment from "./index.js"; test("mandatory", async () => { const { entity } = mockClient(); + sessionEstablishment(entity); entity.mockInput( @@ -15,12 +17,11 @@ test("mandatory", async () => { expect(child).toEqual( , ); - - await promise(entity, "online"); }); test("optional", async () => { const { entity } = mockClient(); + sessionEstablishment(entity); entity.mockInput( @@ -32,8 +33,6 @@ test("optional", async () => { const promiseSend = promise(entity, "send"); - await promise(entity, "online"); - await timeout(promiseSend, 0).catch((err) => { expect(err.name).toBe("TimeoutError"); }); diff --git a/packages/stream-features/index.js b/packages/stream-features/index.js index bf41a2db..0ffc79be 100644 --- a/packages/stream-features/index.js +++ b/packages/stream-features/index.js @@ -1,5 +1,3 @@ -import route from "./route.js"; - /** * References * https://xmpp.org/rfcs/rfc6120.html#streams-negotiation Stream Negotiation @@ -8,8 +6,6 @@ import route from "./route.js"; */ export default function streamFeatures({ middleware }) { - middleware.use(route()); - function use(name, xmlns, handler) { return middleware.use((ctx, next) => { const { stanza } = ctx; diff --git a/packages/stream-features/route.js b/packages/stream-features/route.js deleted file mode 100644 index 0aed4f5c..00000000 --- a/packages/stream-features/route.js +++ /dev/null @@ -1,12 +0,0 @@ -export default function route() { - return async ({ stanza, entity }, next) => { - if (!stanza.is("features", "http://etherx.jabber.org/streams")) - return next(); - - // FIXME: instead of this prevent mechanism - // emit online once all stream features have negotiated - // and if entity.jid is set - const prevent = await next(); - if (!prevent && entity.jid) entity._status("online", entity.jid); - }; -} diff --git a/packages/stream-management/index.js b/packages/stream-management/index.js index 1cabd870..74fb74eb 100644 --- a/packages/stream-management/index.js +++ b/packages/stream-management/index.js @@ -63,12 +63,9 @@ export default function streamManagement({ max: null, }; - let address = null; - function resumed() { sm.enabled = true; - if (address) entity.jid = address; - entity.status = "online"; + entity._ready(true); } function failed() { @@ -83,8 +80,7 @@ export default function streamManagement({ sm.max = max; } - entity.on("online", (jid) => { - address = jid; + entity.on("online", () => { sm.outbound = 0; sm.inbound = 0; }); @@ -147,7 +143,7 @@ function setupStreamFeature({ try { await resume(entity, sm); resumed(); - return true; + return; // If resumption fails, continue with session establishment } catch { failed();