Use central defintion of storage system

Change-Id: Ibf31c650b08920bf82827607c3421556ac90ae61
This commit is contained in:
Manuel Stahl 2024-08-16 20:58:26 +02:00
parent 035baa786a
commit dbcb4f92dc
9 changed files with 66 additions and 53 deletions

View file

@ -34,6 +34,7 @@ import { Link } from "react-router-dom";
import { dateParser } from "./date";
import { DeleteMediaParams, SynapseDataProvider } from "../synapse/dataProvider";
import { getMediaUrl } from "../synapse/synapse";
import storage from "../storage";
const DeleteMediaDialog = ({ open, onClose, onSubmit }) => {
const translate = useTranslate();
@ -339,7 +340,7 @@ export const ViewMediaButton = ({ media_id, label }) => {
};
export const MediaIDField = ({ source }) => {
const homeserver = localStorage.getItem("home_server");
const homeserver = storage.getItem("home_server");
const record = useRecordContext();
if (!record) return null;

View file

@ -27,6 +27,7 @@ import {
isValidBaseUrl,
splitMxid,
} from "../synapse/synapse";
import storage from "../storage";
const FormBox = styled(Box)(({ theme }) => ({
display: "flex",
@ -94,7 +95,7 @@ const LoginPage = () => {
const [locale, setLocale] = useLocaleState();
const locales = useLocales();
const translate = useTranslate();
const base_url = allowSingleBaseUrl ? restrictBaseUrl : localStorage.getItem("base_url");
const base_url = allowSingleBaseUrl ? restrictBaseUrl : storage.getItem("base_url");
const [ssoBaseUrl, setSSOBaseUrl] = useState("");
const loginToken = /\?loginToken=([a-zA-Z0-9_-]+)/.exec(window.location.href);
@ -103,8 +104,8 @@ const LoginPage = () => {
console.log("SSO token is", ssoToken);
// Prevent further requests
window.history.replaceState({}, "", window.location.href.replace(loginToken[0], "#").split("#")[0]);
const baseUrl = localStorage.getItem("sso_base_url");
localStorage.removeItem("sso_base_url");
const baseUrl = storage.getItem("sso_base_url");
storage.removeItem("sso_base_url");
if (baseUrl) {
const auth = {
base_url: baseUrl,
@ -154,7 +155,7 @@ const LoginPage = () => {
};
const handleSSO = () => {
localStorage.setItem("sso_base_url", ssoBaseUrl);
storage.setItem("sso_base_url", ssoBaseUrl);
const ssoFullUrl = `${ssoBaseUrl}/_matrix/client/r0/login/sso/redirect?redirectUrl=${encodeURIComponent(
window.location.href
)}`;

View file

@ -128,8 +128,8 @@ export const UserList = (props: ListProps) => (
// https://matrix.org/docs/spec/appendices#user-identifiers
// here only local part of user_id
// maxLength = 255 - "@" - ":" - localStorage.getItem("home_server").length
// localStorage.getItem("home_server").length is not valid here
// maxLength = 255 - "@" - ":" - storage.getItem("home_server").length
// storage.getItem("home_server").length is not valid here
const validateUser = [required(), maxLength(253), regex(/^[a-z0-9._=\-/]+$/, "synapseadmin.users.invalid_user_id")];
const validateAddress = [required(), maxLength(255)];

3
src/storage.ts Normal file
View file

@ -0,0 +1,3 @@
const storage = localStorage;
export default storage;

View file

@ -1,13 +1,14 @@
import fetchMock from "jest-fetch-mock";
import authProvider from "./authProvider";
import storage from "../storage";
fetchMock.enableMocks();
describe("authProvider", () => {
beforeEach(() => {
fetchMock.resetMocks();
localStorage.clear();
storage.clear();
});
describe("login", () => {
@ -36,10 +37,10 @@ describe("authProvider", () => {
}),
method: "POST",
});
expect(localStorage.getItem("base_url")).toEqual("http://example.com");
expect(localStorage.getItem("user_id")).toEqual("@user:example.com");
expect(localStorage.getItem("access_token")).toEqual("foobar");
expect(localStorage.getItem("device_id")).toEqual("some_device");
expect(storage.getItem("base_url")).toEqual("http://example.com");
expect(storage.getItem("user_id")).toEqual("@user:example.com");
expect(storage.getItem("access_token")).toEqual("foobar");
expect(storage.getItem("device_id")).toEqual("some_device");
});
});
@ -67,16 +68,16 @@ describe("authProvider", () => {
}),
method: "POST",
});
expect(localStorage.getItem("base_url")).toEqual("https://example.com");
expect(localStorage.getItem("user_id")).toEqual("@user:example.com");
expect(localStorage.getItem("access_token")).toEqual("foobar");
expect(localStorage.getItem("device_id")).toEqual("some_device");
expect(storage.getItem("base_url")).toEqual("https://example.com");
expect(storage.getItem("user_id")).toEqual("@user:example.com");
expect(storage.getItem("access_token")).toEqual("foobar");
expect(storage.getItem("device_id")).toEqual("some_device");
});
describe("logout", () => {
it("should remove the access_token from localStorage", async () => {
localStorage.setItem("base_url", "example.com");
localStorage.setItem("access_token", "foo");
it("should remove the access_token from storage", async () => {
storage.setItem("base_url", "example.com");
storage.setItem("access_token", "foo");
fetchMock.mockResponse(JSON.stringify({}));
await authProvider.logout(null);
@ -89,7 +90,7 @@ describe("authProvider", () => {
method: "POST",
user: { authenticated: true, token: "Bearer foo" },
});
expect(localStorage.getItem("access_token")).toBeNull();
expect(storage.getItem("access_token")).toBeNull();
});
});
@ -113,7 +114,7 @@ describe("authProvider", () => {
});
it("should resolve when logged in", async () => {
localStorage.setItem("access_token", "foobar");
storage.setItem("access_token", "foobar");
await expect(authProvider.checkAuth({})).resolves.toBeUndefined();
});

View file

@ -1,5 +1,7 @@
import { AuthProvider, Options, fetchUtils } from "react-admin";
import storage from "../storage";
const authProvider: AuthProvider = {
// called when the user attempts to log in
login: async ({
@ -19,7 +21,7 @@ const authProvider: AuthProvider = {
body: JSON.stringify(
Object.assign(
{
device_id: localStorage.getItem("device_id"),
device_id: storage.getItem("device_id"),
initial_device_display_name: "Synapse Admin",
},
loginToken
@ -40,23 +42,23 @@ const authProvider: AuthProvider = {
// server, since the admin might want to access the admin API via some
// private address
base_url = base_url.replace(/\/+$/g, "");
localStorage.setItem("base_url", base_url);
storage.setItem("base_url", base_url);
const decoded_base_url = window.decodeURIComponent(base_url);
const login_api_url = decoded_base_url + "/_matrix/client/r0/login";
const { json } = await fetchUtils.fetchJson(login_api_url, options);
localStorage.setItem("home_server", json.home_server);
localStorage.setItem("user_id", json.user_id);
localStorage.setItem("access_token", json.access_token);
localStorage.setItem("device_id", json.device_id);
storage.setItem("home_server", json.home_server);
storage.setItem("user_id", json.user_id);
storage.setItem("access_token", json.access_token);
storage.setItem("device_id", json.device_id);
},
// called when the user clicks on the logout button
logout: async () => {
console.log("logout");
const logout_api_url = localStorage.getItem("base_url") + "/_matrix/client/r0/logout";
const access_token = localStorage.getItem("access_token");
const logout_api_url = storage.getItem("base_url") + "/_matrix/client/r0/logout";
const access_token = storage.getItem("access_token");
const options: Options = {
method: "POST",
@ -68,7 +70,7 @@ const authProvider: AuthProvider = {
if (typeof access_token === "string") {
await fetchUtils.fetchJson(logout_api_url, options);
localStorage.removeItem("access_token");
storage.removeItem("access_token");
}
},
// called when the API returns an error
@ -81,7 +83,7 @@ const authProvider: AuthProvider = {
},
// called when the user navigates to a new location, to check for authentication
checkAuth: () => {
const access_token = localStorage.getItem("access_token");
const access_token = storage.getItem("access_token");
console.log("checkAuth " + access_token);
return typeof access_token === "string" ? Promise.resolve() : Promise.reject();
},

View file

@ -1,6 +1,7 @@
import fetchMock from "jest-fetch-mock";
import dataProvider from "./dataProvider";
import storage from "../storage";
fetchMock.enableMocks();
@ -9,8 +10,8 @@ beforeEach(() => {
});
describe("dataProvider", () => {
localStorage.setItem("base_url", "http://localhost");
localStorage.setItem("access_token", "access_token");
storage.setItem("base_url", "http://localhost");
storage.setItem("access_token", "access_token");
it("fetches all users", async () => {
fetchMock.mockResponseOnce(

View file

@ -2,9 +2,11 @@ import { stringify } from "query-string";
import { DataProvider, DeleteParams, Identifier, Options, RaRecord, fetchUtils } from "react-admin";
import storage from "../storage";
// Adds the access token to all requests
const jsonClient = (url: string, options: Options = {}) => {
const token = localStorage.getItem("access_token");
const token = storage.getItem("access_token");
console.log("httpClient " + url);
if (token != null) {
options.user = {
@ -16,7 +18,7 @@ const jsonClient = (url: string, options: Options = {}) => {
};
const mxcUrlToHttp = (mxcUrl: string) => {
const homeserver = localStorage.getItem("base_url");
const homeserver = storage.getItem("base_url");
const re = /^mxc:\/\/([^/]+)\/(\w+)/;
const ret = re.exec(mxcUrl);
console.log("mxcClient " + ret);
@ -232,7 +234,7 @@ const resourceMap = {
data: "users",
total: json => json.total,
create: (data: RaRecord) => ({
endpoint: `/_synapse/admin/v2/users/@${encodeURIComponent(data.id)}:${localStorage.getItem("home_server")}`,
endpoint: `/_synapse/admin/v2/users/@${encodeURIComponent(data.id)}:${storage.getItem("home_server")}`,
body: data,
method: "PUT",
}),
@ -341,7 +343,7 @@ const resourceMap = {
data: "media",
total: json => json.total,
delete: (params: DeleteParams) => ({
endpoint: `/_synapse/admin/v1/media/${localStorage.getItem("home_server")}/${params.id}`,
endpoint: `/_synapse/admin/v1/media/${storage.getItem("home_server")}/${params.id}`,
}),
},
protect_media: {
@ -358,11 +360,11 @@ const resourceMap = {
quarantine_media: {
map: (qm: UserMedia) => ({ id: qm.media_id }),
create: (params: UserMedia) => ({
endpoint: `/_synapse/admin/v1/media/quarantine/${localStorage.getItem("home_server")}/${params.media_id}`,
endpoint: `/_synapse/admin/v1/media/quarantine/${storage.getItem("home_server")}/${params.media_id}`,
method: "POST",
}),
delete: (params: DeleteParams) => ({
endpoint: `/_synapse/admin/v1/media/unquarantine/${localStorage.getItem("home_server")}/${params.id}`,
endpoint: `/_synapse/admin/v1/media/unquarantine/${storage.getItem("home_server")}/${params.id}`,
method: "POST",
}),
},
@ -506,7 +508,7 @@ const dataProvider: SynapseDataProvider = {
order_by: field,
dir: getSearchOrder(order),
};
const homeserver = localStorage.getItem("base_url");
const homeserver = storage.getItem("base_url");
if (!homeserver || !(resource in resourceMap)) throw Error("Homeserver not set");
const res = resourceMap[resource];
@ -523,7 +525,7 @@ const dataProvider: SynapseDataProvider = {
getOne: async (resource, params) => {
console.log("getOne " + resource);
const homeserver = localStorage.getItem("base_url");
const homeserver = storage.getItem("base_url");
if (!homeserver || !(resource in resourceMap)) throw Error("Homeserver not set");
const res = resourceMap[resource];
@ -535,7 +537,7 @@ const dataProvider: SynapseDataProvider = {
getMany: async (resource, params) => {
console.log("getMany " + resource);
const homeserver = localStorage.getItem("base_url");
const homeserver = storage.getItem("base_url");
if (!homeserver || !(resource in resourceMap)) throw Error("Homerserver not set");
const res = resourceMap[resource];
@ -560,7 +562,7 @@ const dataProvider: SynapseDataProvider = {
dir: getSearchOrder(order),
};
const homeserver = localStorage.getItem("base_url");
const homeserver = storage.getItem("base_url");
if (!homeserver || !(resource in resourceMap)) throw Error("Homeserver not set");
const res = resourceMap[resource];
@ -577,7 +579,7 @@ const dataProvider: SynapseDataProvider = {
update: async (resource, params) => {
console.log("update " + resource);
const homeserver = localStorage.getItem("base_url");
const homeserver = storage.getItem("base_url");
if (!homeserver || !(resource in resourceMap)) throw Error("Homeserver not set");
const res = resourceMap[resource];
@ -592,7 +594,7 @@ const dataProvider: SynapseDataProvider = {
updateMany: async (resource, params) => {
console.log("updateMany " + resource);
const homeserver = localStorage.getItem("base_url");
const homeserver = storage.getItem("base_url");
if (!homeserver || !(resource in resourceMap)) throw Error("Homeserver not set");
const res = resourceMap[resource];
@ -609,7 +611,7 @@ const dataProvider: SynapseDataProvider = {
create: async (resource, params) => {
console.log("create " + resource);
const homeserver = localStorage.getItem("base_url");
const homeserver = storage.getItem("base_url");
if (!homeserver || !(resource in resourceMap)) throw Error("Homeserver not set");
const res = resourceMap[resource];
@ -626,7 +628,7 @@ const dataProvider: SynapseDataProvider = {
createMany: async (resource: string, params: { ids: Identifier[]; data: RaRecord }) => {
console.log("createMany " + resource);
const homeserver = localStorage.getItem("base_url");
const homeserver = storage.getItem("base_url");
if (!homeserver || !(resource in resourceMap)) throw Error("Homeserver not set");
const res = resourceMap[resource];
@ -648,7 +650,7 @@ const dataProvider: SynapseDataProvider = {
delete: async (resource, params) => {
console.log("delete " + resource);
const homeserver = localStorage.getItem("base_url");
const homeserver = storage.getItem("base_url");
if (!homeserver || !(resource in resourceMap)) throw Error("Homeserver not set");
const res = resourceMap[resource];
@ -673,7 +675,7 @@ const dataProvider: SynapseDataProvider = {
deleteMany: async (resource, params) => {
console.log("deleteMany " + resource);
const homeserver = localStorage.getItem("base_url");
const homeserver = storage.getItem("base_url");
if (!homeserver || !(resource in resourceMap)) throw Error("Homeserver not set");
const res = resourceMap[resource];
@ -719,10 +721,10 @@ const dataProvider: SynapseDataProvider = {
* @returns
*/
deleteMedia: async ({ before_ts, size_gt = 0, keep_profiles = true }) => {
const homeserver = localStorage.getItem("home_server"); // TODO only required for synapse < 1.78.0
const homeserver = storage.getItem("home_server"); // TODO only required for synapse < 1.78.0
const endpoint = `/_synapse/admin/v1/media/${homeserver}/delete?before_ts=${before_ts}&size_gt=${size_gt}&keep_profiles=${keep_profiles}`;
const base_url = localStorage.getItem("base_url");
const base_url = storage.getItem("base_url");
const endpoint_url = base_url + endpoint;
const { json } = await jsonClient(endpoint_url, { method: "POST" });
return json as DeleteMediaResult;

View file

@ -1,5 +1,7 @@
import { fetchUtils } from "react-admin";
import storage from "../storage";
export const splitMxid = mxid => {
const re = /^@(?<name>[a-zA-Z0-9._=\-/]+):(?<domain>[a-zA-Z0-9\-.]+\.[a-zA-Z]+)$/;
return re.exec(mxid)?.groups;
@ -53,7 +55,7 @@ export const getSupportedLoginFlows = async baseUrl => {
};
export const getMediaUrl = media_id => {
const baseUrl = localStorage.getItem("base_url");
const baseUrl = storage.getItem("base_url");
return `${baseUrl}/_matrix/media/v1/download/${media_id}?allow_redirect=true`;
};
@ -62,7 +64,7 @@ export const getMediaUrl = media_id => {
* @returns full MXID as string
*/
export function generateRandomMxId(): string {
const homeserver = localStorage.getItem("home_server");
const homeserver = storage.getItem("home_server");
const characters = "0123456789abcdefghijklmnopqrstuvwxyz";
const localpart = Array.from(crypto.getRandomValues(new Uint32Array(8)))
.map(x => characters[x % characters.length])