Skip to content

Commit

Permalink
fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
sonnyp committed Dec 22, 2024
1 parent 5880c50 commit e560649
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 56 deletions.
2 changes: 1 addition & 1 deletion packages/client/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ function client(options = {}) {
const starttls = _starttls({ streamFeatures });
const sasl2 = _sasl2(
{ streamFeatures, saslFactory },
credentials || { username, password },
createOnAuthenticate(credentials ?? { username, password }),
{ clientId, software, device },
);
const sasl = _sasl(
Expand Down
4 changes: 2 additions & 2 deletions packages/sasl/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import xml from "@xmpp/xml";

const NS = "urn:ietf:params:xml:ns:xmpp-sasl";

function getMechanismNames(features) {
return features
function getMechanismNames(stanza) {
return stanza
.getChild("mechanisms", NS)
.getChildElements()
.map((el) => el.text());
Expand Down
58 changes: 21 additions & 37 deletions packages/sasl2/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,23 @@ import xml from "@xmpp/xml";

const NS = "urn:xmpp:sasl:2";

function getMechanismNames(stanza) {
return stanza
.getChild("authentication", NS)
.getChildren("mechanism", NS)
.map((m) => m.text());
}

async function authenticate({
saslFactory,
entity,
mechname,
mechanism,
credentials,
userAgent,
}) {
const mech = saslFactory.create([mechname]);
const mech = saslFactory.create([mechanism]);
if (!mech) {
throw new Error("No compatible mechanism");
throw new Error(`SASL: Mechanism ${mechanism} not found.`);
}

const { domain } = entity.options;
Expand Down Expand Up @@ -106,52 +113,29 @@ async function authenticate({

export default function sasl2(
{ streamFeatures, saslFactory },
credentials,
userAgent,
onAuthenticate,
// userAgent,
) {
streamFeatures.use("authentication", NS, async ({ stanza, entity }) => {
const offered = new Set(
stanza
.getChild("authentication", NS)
.getChildren("mechanism", NS)
.map((m) => m.text()),
);
const offered = getMechanismNames(stanza);
const supported = saslFactory._mechs.map(({ name }) => name);
const intersection = supported.filter((mech) => offered.includes(mech));

const intersection = supported
.map((mech) => ({
name: mech,
canOther: offered.has(mech),
}))
.filter((mech) => mech.canOther);

if (typeof credentials === "function") {
await credentials((creds, mechname) => {
authenticate({
saslFactory,
entity,
mechname,
credentials: creds,
userAgent,
});
}, intersection);
} else {
let mechname = intersection[0]?.name;
if (!credentials.username && !credentials.password) {
mechname = "ANONYMOUS";
}
if (intersection.length === 0) {
throw new SASLError("SASL: No compatible mechanism available.");
}

async function done(credentials, mechanism) {
await authenticate({
saslFactory,
entity,
mechname,
mechanism,
credentials,
userAgent,
});
}

await onAuthenticate(done, intersection);

return true; // Not online yet, wait for next features
});

return {};
}
25 changes: 9 additions & 16 deletions packages/sasl2/test.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,11 @@
import { mockClient, promise } from "@xmpp/test";
import sasl2 from "./index";

const username = "foo";
const password = "bar";
const credentials = { username, password };

function makeClient({ credentials, ...args }) {
const entity = mockClient({ credentials, ...args });
sasl2(entity, (credentials = { username, password }));
return entity;
}

test("no compatibles mechanisms", async () => {
const { entity } = makeClient({ username, password });
test("No compatible mechanism available", async () => {
const { entity } = mockClient({ username, password });

entity.mockInput(
<features xmlns="http://etherx.jabber.org/streams">
Expand All @@ -24,11 +17,11 @@ test("no compatibles mechanisms", async () => {

const error = await promise(entity, "error");
expect(error instanceof Error).toBe(true);
expect(error.message).toBe("No compatible mechanism");
expect(error.message).toBe("SASL: No compatible mechanism available.");
});

test("with object credentials", async () => {
const { entity } = makeClient({ credentials });
const { entity } = mockClient({ credentials });

entity.mockInput(
<features xmlns="http://etherx.jabber.org/streams">
Expand All @@ -54,11 +47,11 @@ test("with function credentials", async () => {
const mech = "PLAIN";

function authenticate(auth, mechanisms) {
expect(mechanisms).toEqual([{ name: mech, canOther: true }]);
expect(mechanisms).toEqual([mech]);
return auth(credentials, mech);
}

const { entity } = makeClient({ credentials: authenticate });
const { entity } = mockClient({ credentials: authenticate });

entity.mockInput(
<features xmlns="http://etherx.jabber.org/streams">
Expand All @@ -81,7 +74,7 @@ test("with function credentials", async () => {
});

test("failure", async () => {
const { entity } = makeClient({ credentials });
const { entity } = mockClient({ credentials });

entity.mockInput(
<features xmlns="http://etherx.jabber.org/streams">
Expand Down Expand Up @@ -113,7 +106,7 @@ test("failure", async () => {
});

test("prefers SCRAM-SHA-1", async () => {
const { entity } = makeClient({ credentials });
const { entity } = mockClient({ credentials });

entity.mockInput(
<features xmlns="http://etherx.jabber.org/streams">
Expand All @@ -130,7 +123,7 @@ test("prefers SCRAM-SHA-1", async () => {
});

test.skip("use ANONYMOUS if username and password are not provided", async () => {

Check warning on line 125 in packages/sasl2/test.js

View workflow job for this annotation

GitHub Actions / test (20)

Disabled test

Check warning on line 125 in packages/sasl2/test.js

View workflow job for this annotation

GitHub Actions / test (22)

Disabled test

Check warning on line 125 in packages/sasl2/test.js

View workflow job for this annotation

GitHub Actions / test (23)

Disabled test
const { entity } = makeClient();
const { entity } = mockClient();

entity.mockInput(
<features xmlns="http://etherx.jabber.org/streams">
Expand Down

0 comments on commit e560649

Please sign in to comment.