213 lines
7.7 KiB
TypeScript
213 lines
7.7 KiB
TypeScript
/*
|
|
Copyright 2024 New Vector Ltd.
|
|
Copyright 2019 The Matrix.org Foundation C.I.C.
|
|
|
|
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
|
|
Please see LICENSE files in the repository root for full details.
|
|
*/
|
|
|
|
import { mocked } from "jest-mock";
|
|
import fetchMock from "fetch-mock-jest";
|
|
import { MatrixClient } from "matrix-js-sdk/src/matrix";
|
|
|
|
import ScalarAuthClient from "../src/ScalarAuthClient";
|
|
import { stubClient } from "./test-utils";
|
|
import SdkConfig from "../src/SdkConfig";
|
|
import { WidgetType } from "../src/widgets/WidgetType";
|
|
|
|
describe("ScalarAuthClient", function () {
|
|
const apiUrl = "https://test.com/api";
|
|
const uiUrl = "https:/test.com/app";
|
|
const tokenObject = {
|
|
access_token: "token",
|
|
token_type: "Bearer",
|
|
matrix_server_name: "localhost",
|
|
expires_in: 999,
|
|
};
|
|
|
|
let client: MatrixClient;
|
|
beforeEach(function () {
|
|
jest.clearAllMocks();
|
|
client = stubClient();
|
|
});
|
|
|
|
it("should request a new token if the old one fails", async function () {
|
|
const sac = new ScalarAuthClient(apiUrl + 0, uiUrl);
|
|
|
|
fetchMock.get("https://test.com/api0/account?scalar_token=brokentoken&v=1.1", {
|
|
body: { message: "Invalid token" },
|
|
});
|
|
|
|
fetchMock.get("https://test.com/api0/account?scalar_token=wokentoken&v=1.1", {
|
|
body: { user_id: client.getUserId() },
|
|
});
|
|
|
|
client.getOpenIdToken = jest.fn().mockResolvedValue(tokenObject);
|
|
|
|
sac.exchangeForScalarToken = jest.fn((arg) => {
|
|
return Promise.resolve(arg === tokenObject ? "wokentoken" : "othertoken");
|
|
});
|
|
|
|
await sac.connect();
|
|
|
|
expect(sac.exchangeForScalarToken).toHaveBeenCalledWith(tokenObject);
|
|
expect(sac.hasCredentials).toBeTruthy();
|
|
// @ts-ignore private property
|
|
expect(sac.scalarToken).toEqual("wokentoken");
|
|
});
|
|
|
|
describe("exchangeForScalarToken", () => {
|
|
it("should return `scalar_token` from API /register", async () => {
|
|
const sac = new ScalarAuthClient(apiUrl + 1, uiUrl);
|
|
|
|
fetchMock.postOnce("https://test.com/api1/register?v=1.1", {
|
|
body: { scalar_token: "stoken" },
|
|
});
|
|
|
|
await expect(sac.exchangeForScalarToken(tokenObject)).resolves.toBe("stoken");
|
|
});
|
|
|
|
it("should throw upon non-20x code", async () => {
|
|
const sac = new ScalarAuthClient(apiUrl + 2, uiUrl);
|
|
|
|
fetchMock.postOnce("https://test.com/api2/register?v=1.1", {
|
|
status: 500,
|
|
});
|
|
|
|
await expect(sac.exchangeForScalarToken(tokenObject)).rejects.toThrow("Scalar request failed: 500");
|
|
});
|
|
|
|
it("should throw if scalar_token is missing in response", async () => {
|
|
const sac = new ScalarAuthClient(apiUrl + 3, uiUrl);
|
|
|
|
fetchMock.postOnce("https://test.com/api3/register?v=1.1", {
|
|
body: {},
|
|
});
|
|
|
|
await expect(sac.exchangeForScalarToken(tokenObject)).rejects.toThrow("Missing scalar_token in response");
|
|
});
|
|
});
|
|
|
|
describe("registerForToken", () => {
|
|
it("should call `termsInteractionCallback` upon M_TERMS_NOT_SIGNED error", async () => {
|
|
const sac = new ScalarAuthClient(apiUrl + 4, uiUrl);
|
|
const termsInteractionCallback = jest.fn();
|
|
sac.setTermsInteractionCallback(termsInteractionCallback);
|
|
fetchMock.get("https://test.com/api4/account?scalar_token=testtoken1&v=1.1", {
|
|
body: { errcode: "M_TERMS_NOT_SIGNED" },
|
|
});
|
|
sac.exchangeForScalarToken = jest.fn(() => Promise.resolve("testtoken1"));
|
|
mocked(client.getTerms).mockResolvedValue({ policies: [] });
|
|
|
|
await expect(sac.registerForToken()).resolves.toBe("testtoken1");
|
|
});
|
|
|
|
it("should throw upon non-20x code", async () => {
|
|
const sac = new ScalarAuthClient(apiUrl + 5, uiUrl);
|
|
fetchMock.get("https://test.com/api5/account?scalar_token=testtoken2&v=1.1", {
|
|
body: { errcode: "SERVER_IS_SAD" },
|
|
status: 500,
|
|
});
|
|
sac.exchangeForScalarToken = jest.fn(() => Promise.resolve("testtoken2"));
|
|
|
|
await expect(sac.registerForToken()).rejects.toBeTruthy();
|
|
});
|
|
|
|
it("should throw if user_id is missing from response", async () => {
|
|
const sac = new ScalarAuthClient(apiUrl + 6, uiUrl);
|
|
fetchMock.get("https://test.com/api6/account?scalar_token=testtoken3&v=1.1", {
|
|
body: {},
|
|
});
|
|
sac.exchangeForScalarToken = jest.fn(() => Promise.resolve("testtoken3"));
|
|
|
|
await expect(sac.registerForToken()).rejects.toThrow("Missing user_id in response");
|
|
});
|
|
});
|
|
|
|
describe("getScalarPageTitle", () => {
|
|
let sac: ScalarAuthClient;
|
|
|
|
beforeEach(async () => {
|
|
SdkConfig.put({
|
|
integrations_rest_url: apiUrl + 7,
|
|
integrations_ui_url: uiUrl,
|
|
});
|
|
|
|
window.localStorage.setItem("mx_scalar_token_at_https://test.com/api7", "wokentoken1");
|
|
fetchMock.get("https://test.com/api7/account?scalar_token=wokentoken1&v=1.1", {
|
|
body: { user_id: client.getUserId() },
|
|
});
|
|
|
|
sac = new ScalarAuthClient(apiUrl + 7, uiUrl);
|
|
await sac.connect();
|
|
});
|
|
|
|
it("should return `cached_title` from API /widgets/title_lookup", async () => {
|
|
const url = "google.com";
|
|
fetchMock.get("https://test.com/api7/widgets/title_lookup?scalar_token=wokentoken1&curl=" + url, {
|
|
body: {
|
|
page_title_cache_item: {
|
|
cached_title: "Google",
|
|
},
|
|
},
|
|
});
|
|
|
|
await expect(sac.getScalarPageTitle(url)).resolves.toBe("Google");
|
|
});
|
|
|
|
it("should throw upon non-20x code", async () => {
|
|
const url = "yahoo.com";
|
|
fetchMock.get("https://test.com/api7/widgets/title_lookup?scalar_token=wokentoken1&curl=" + url, {
|
|
status: 500,
|
|
});
|
|
|
|
await expect(sac.getScalarPageTitle(url)).rejects.toThrow("Scalar request failed: 500");
|
|
});
|
|
});
|
|
|
|
describe("disableWidgetAssets", () => {
|
|
let sac: ScalarAuthClient;
|
|
|
|
beforeEach(async () => {
|
|
SdkConfig.put({
|
|
integrations_rest_url: apiUrl + 8,
|
|
integrations_ui_url: uiUrl,
|
|
});
|
|
|
|
window.localStorage.setItem("mx_scalar_token_at_https://test.com/api8", "wokentoken1");
|
|
fetchMock.get("https://test.com/api8/account?scalar_token=wokentoken1&v=1.1", {
|
|
body: { user_id: client.getUserId() },
|
|
});
|
|
|
|
sac = new ScalarAuthClient(apiUrl + 8, uiUrl);
|
|
await sac.connect();
|
|
});
|
|
|
|
it("should send state=disable to API /widgets/set_assets_state", async () => {
|
|
fetchMock.get(
|
|
"https://test.com/api8/widgets/set_assets_state?scalar_token=wokentoken1" +
|
|
"&widget_type=m.custom&widget_id=id1&state=disable",
|
|
{
|
|
body: "OK",
|
|
},
|
|
);
|
|
|
|
await expect(sac.disableWidgetAssets(WidgetType.CUSTOM, "id1")).resolves.toBeUndefined();
|
|
});
|
|
|
|
it("should throw upon non-20x code", async () => {
|
|
fetchMock.get(
|
|
"https://test.com/api8/widgets/set_assets_state?scalar_token=wokentoken1" +
|
|
"&widget_type=m.custom&widget_id=id2&state=disable",
|
|
{
|
|
status: 500,
|
|
},
|
|
);
|
|
|
|
await expect(sac.disableWidgetAssets(WidgetType.CUSTOM, "id2")).rejects.toThrow(
|
|
"Scalar request failed: 500",
|
|
);
|
|
});
|
|
});
|
|
});
|