138 lines
3.9 KiB
JavaScript
138 lines
3.9 KiB
JavaScript
import { xml, jid, Client } from "@xmpp/client-core";
|
|
import _reconnect from "@xmpp/reconnect";
|
|
import _websocket from "@xmpp/websocket";
|
|
import _tcp from "@xmpp/tcp";
|
|
import _tls from "@xmpp/tls";
|
|
import _middleware from "@xmpp/middleware";
|
|
import _streamFeatures from "@xmpp/stream-features";
|
|
import _iqCaller from "@xmpp/iq/caller.js";
|
|
import _iqCallee from "@xmpp/iq/callee.js";
|
|
import _resolve from "@xmpp/resolve";
|
|
import _starttls from "@xmpp/starttls";
|
|
import _sasl2 from "@xmpp/sasl2";
|
|
import _sasl from "@xmpp/sasl";
|
|
import _resourceBinding from "@xmpp/resource-binding";
|
|
import _streamManagement from "@xmpp/stream-management";
|
|
import _bind2 from "@xmpp/client-core/src/bind2/bind2.js";
|
|
import _fast from "@xmpp/client-core/src/fast/fast.js";
|
|
import SASLFactory from "saslmechanisms";
|
|
import scramsha1 from "@xmpp/sasl-scram-sha-1";
|
|
import plain from "@xmpp/sasl-plain";
|
|
import anonymous from "@xmpp/sasl-anonymous";
|
|
import htsha256none from "@xmpp/sasl-ht-sha-256-none";
|
|
|
|
import createOnAuthenticate from "./lib/createOnAuthenticate.js";
|
|
import getDomain from "./lib/getDomain.js";
|
|
|
|
function client(options = {}) {
|
|
let { resource, credentials, username, password, userAgent, ...params } =
|
|
options;
|
|
|
|
const { domain, service } = params;
|
|
if (!domain && service) {
|
|
params.domain = getDomain(service);
|
|
}
|
|
|
|
const entity = new Client(params);
|
|
if (username && params.domain) {
|
|
entity.jid = jid(username, params.domain);
|
|
}
|
|
|
|
const reconnect = _reconnect({ entity });
|
|
const websocket = _websocket({ entity });
|
|
const tcp = setupIfAvailable(_tcp, { entity });
|
|
const tls = setupIfAvailable(_tls, { entity });
|
|
|
|
const middleware = _middleware({ entity });
|
|
const streamFeatures = _streamFeatures({ middleware });
|
|
const iqCaller = _iqCaller({ middleware, entity });
|
|
const iqCallee = _iqCallee({ middleware, entity });
|
|
const resolve = _resolve({ entity });
|
|
|
|
// SASL mechanisms - order matters and define priority
|
|
const saslFactory = new SASLFactory();
|
|
const mechanisms = Object.entries({
|
|
...(typeof scramsha1 === "function" && { scramsha1 }),
|
|
plain,
|
|
anonymous,
|
|
}).map(([k, v]) => ({ [k]: v(saslFactory) }));
|
|
|
|
// eslint-disable-next-line n/no-unsupported-features/node-builtins
|
|
userAgent ??= xml("user-agent", { id: globalThis.crypto.randomUUID() });
|
|
|
|
// Stream features - order matters and define priority
|
|
const starttls = setupIfAvailable(_starttls, { streamFeatures });
|
|
const sasl2 = _sasl2(
|
|
{ streamFeatures, saslFactory },
|
|
createOnAuthenticate(credentials ?? { username, password }, userAgent),
|
|
);
|
|
|
|
const fast = _fast({
|
|
sasl2,
|
|
entity,
|
|
});
|
|
sasl2.setup({ fast });
|
|
|
|
// SASL2 inline features
|
|
const bind2 = _bind2({ sasl2, entity }, resource);
|
|
|
|
// FAST mechanisms - order matters and define priority
|
|
htsha256none(fast.saslFactory);
|
|
|
|
// Stream features - order matters and define priority
|
|
const sasl = _sasl(
|
|
{ streamFeatures, saslFactory },
|
|
createOnAuthenticate(credentials ?? { username, password }, userAgent),
|
|
);
|
|
const streamManagement = _streamManagement({
|
|
streamFeatures,
|
|
entity,
|
|
middleware,
|
|
bind2,
|
|
sasl2,
|
|
});
|
|
const resourceBinding = _resourceBinding(
|
|
{ iqCaller, streamFeatures },
|
|
resource,
|
|
);
|
|
|
|
iqCallee?.get("urn:xmpp:ping", "ping", () => {
|
|
return {};
|
|
});
|
|
|
|
return Object.assign(entity, {
|
|
entity,
|
|
reconnect,
|
|
tcp,
|
|
websocket,
|
|
tls,
|
|
middleware,
|
|
streamFeatures,
|
|
iqCaller,
|
|
iqCallee,
|
|
resolve,
|
|
starttls,
|
|
saslFactory,
|
|
sasl2,
|
|
sasl,
|
|
resourceBinding,
|
|
streamManagement,
|
|
mechanisms,
|
|
bind2,
|
|
fast,
|
|
});
|
|
}
|
|
|
|
// In browsers and react-native some packages are excluded
|
|
// see package.json and https://metrobundler.dev/docs/configuration/#resolvermainfields
|
|
// in which case the default import returns an empty object
|
|
function setupIfAvailable(module, ...args) {
|
|
if (typeof module !== "function") {
|
|
return undefined;
|
|
}
|
|
|
|
return module(...args);
|
|
}
|
|
|
|
export { xml, jid, client };
|