Skip to content

Commit

Permalink
fast: Avoid unecessary round trips when the token is invalid
Browse files Browse the repository at this point in the history
  • Loading branch information
sonnyp committed Jan 6, 2025
1 parent a29e515 commit c203c88
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 0 deletions.
22 changes: 22 additions & 0 deletions packages/client-core/src/fast/fast.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ export default function fast({ sasl2 }, { saveToken, fetchToken } = {}) {
};

Object.assign(fast, {
mechanism: null,
mechanisms: [],
async saveToken() {
try {
await saveToken();
Expand All @@ -43,6 +45,10 @@ export default function fast({ sasl2 }, { saveToken, fetchToken } = {}) {
streamFeatures,
features,
}) {
if (isTokenValid({ token, mechanisms: fast.mechanisms })) {
return false;
}

try {
await authenticate({
saslFactory: fast.saslFactory,
Expand Down Expand Up @@ -79,6 +85,7 @@ export default function fast({ sasl2 }, { saveToken, fetchToken } = {}) {

function reset() {
fast.mechanism = null;
fast.mechanisms = [];
}
reset();

Expand All @@ -93,6 +100,7 @@ export default function fast({ sasl2 }, { saveToken, fetchToken } = {}) {
const mechanism = mechanisms[0];

if (!mechanism) return reset();
fast.mechanisms = mechanisms;
fast.mechanism = mechanism;

// The rest is handled by @xmpp/sasl2
Expand All @@ -101,6 +109,8 @@ export default function fast({ sasl2 }, { saveToken, fetchToken } = {}) {
if (element.is("token", NS)) {
try {
await saveToken({
// The token is bound by the mechanism
// > Servers MUST bind tokens to the mechanism selected by the client in its original request, and reject attempts to use them with other mechanisms.
mechanism: fast.mechanism,
token: element.attrs.token,
expiry: element.attrs.expiry,
Expand All @@ -114,3 +124,15 @@ export default function fast({ sasl2 }, { saveToken, fetchToken } = {}) {

return fast;
}

export function isTokenValid({ token, mechanisms }) {
// Avoid an error round trip if the server does not support the token mechanism anymore
if (!mechanisms.includes(token.mechanism)) {
return false;
}
// Avoid an error round trip if the token is already expired
if (new Date(token.expiry) <= new Date()) {
return false;
}
return true;
}
57 changes: 57 additions & 0 deletions packages/client-core/src/fast/isTokenValid.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { isTokenValid } from "./fast.js";
// eslint-disable-next-line n/no-extraneous-import
import { datetime } from "@xmpp/time";

const tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);

const yesterday = new Date();
yesterday.setDate(yesterday.getDate() - 1);

it("returns false if the token.mechanism is not available", async () => {
expect(
isTokenValid({
mechanisms: ["foo"],
token: {
expires: datetime(tomorrow),
mechanism: "bar",
},
}),
);
});

it("returns true if the token.mechanism is available", async () => {
expect(
isTokenValid({
mechanisms: ["foo"],
token: {
expires: datetime(tomorrow),
mechanism: "foo",
},
}),
);
});

it("returns false if the token is expired", async () => {
expect(
isTokenValid({
mechanisms: ["foo"],
token: {
expires: datetime(yesterday),
mechanism: "foo",
},
}),
);
});

it("returns true if the token is not expired", async () => {
expect(
isTokenValid({
mechanisms: ["foo"],
token: {
expires: datetime(tomorrow),
mechanism: "foo",
},
}),
);
});

0 comments on commit c203c88

Please sign in to comment.