Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 | 7x 3x 3x 3x 3x 1x 2x 7x 14x 56x 53x 7x 39x 39x 39x 48x 39x 48x 7x 47x 47x 1x 46x 7x 6x 6x 1x 5x 7x 2x 2x 2x 1x 2x 1x 7x 1x 1x 7x 1x 1x 7x 1x 1x 7x 1x 7x 2x 7x 1x 35x 7x 1x 7x 2x 2x 2x 2x 16x 2x 5x 5x 84x | import { Options, fetchUtils } from "react-admin";
import storage from "../storage";
/** Parsed Matrix user ID parts used by login discovery and identity display. */
export interface MxidParts {
domain: string;
name: string;
}
/** Minimal shape of the Matrix client well-known response used by discovery. */
export interface MatrixClientWellKnown {
"m.homeserver"?: {
base_url?: string;
};
}
/** Matrix version payload used to display supported protocol versions on login. */
export interface MatrixFeatures {
unstable_features?: Record<string, boolean>;
versions: string[];
}
/** Matrix login flow descriptor returned by `/_matrix/client/r0/login`. */
export interface MatrixLoginFlow {
type: string;
}
/** Split an MXID into localpart and domain when the value is syntactically valid. */
export const splitMxid = (mxid: string | null | undefined): MxidParts | undefined => {
Iif (typeof mxid !== "string") {
return undefined;
}
const re = /^@(?<name>[a-zA-Z0-9._=\-/]+):(?<domain>[a-zA-Z0-9\-.]+\.[a-zA-Z]+)$/;
const groups = re.exec(mxid)?.groups;
if (!groups?.name || !groups?.domain) {
return undefined;
}
return {
name: groups.name,
domain: groups.domain,
};
};
/** Validate homeserver base URLs before discovery or login requests are issued. */
export const isValidBaseUrl = (baseUrl: unknown): baseUrl is string =>
typeof baseUrl === "string" && /^(http|https):\/\/[a-zA-Z0-9\-.]+(:\d{1,5})?$/.test(baseUrl);
/** Normalize configured homeserver URLs so providers build stable request paths. */
export const normalizeBaseUrl = (baseUrl: string): string => window.decodeURIComponent(baseUrl).replace(/\/+$/g, "");
/** Join a homeserver base URL with an API endpoint using the normalized base URL. */
export const buildUrl = (baseUrl: string, endpoint: string): string => `${normalizeBaseUrl(baseUrl)}${endpoint}`;
/** Inject the stored access token into a react-admin fetch option bag. */
const withAccessToken = (options: Options = {}): Options => {
const accessToken = storage.getItem("access_token");
Iif (!accessToken) {
return options;
}
return {
...options,
user: {
...options.user,
authenticated: true,
token: `Bearer ${accessToken}`,
},
};
};
/** Plain JSON fetch helper shared by discovery calls and provider requests. */
export const fetchJson = (url: string, options: Options = {}) => fetchUtils.fetchJson(url, options);
/** Authenticated variant of `fetchJson` that reuses the stored bearer token. */
export const fetchJsonWithAuth = (url: string, options: Options = {}) => fetchJson(url, withAccessToken(options));
/** Read the configured homeserver base URL from local storage. */
export const getStoredBaseUrl = (): string | null => storage.getItem("base_url");
/** Return the stored homeserver base URL or fail fast when bootstrap is incomplete. */
export const requireStoredBaseUrl = (): string => {
const baseUrl = getStoredBaseUrl();
if (!baseUrl) {
throw new Error("Homeserver not set");
}
return baseUrl;
};
/** Return the discovered home server name used by older Synapse admin endpoints. */
export const requireStoredHomeServer = (): string => {
const homeServer = storage.getItem("home_server");
if (!homeServer) {
throw new Error("Homeserver not set");
}
return homeServer;
};
/**
* Resolve the homeserver URL using the well-known lookup
* @param domain the domain part of an MXID
* @returns homeserver base URL
*/
export const getWellKnownUrl = async (domain: string): Promise<string> => {
const wellKnownUrl = `https://${domain}/.well-known/matrix/client`;
try {
const response = await fetchJson(wellKnownUrl, { method: "GET" });
const baseUrl = (response.json as MatrixClientWellKnown)["m.homeserver"]?.base_url;
return typeof baseUrl === "string" ? baseUrl : `https://${domain}`;
} catch {
// if there is no .well-known entry, return the domain itself
return `https://${domain}`;
}
};
/**
* Get synapse server version
* @param base_url the base URL of the homeserver
* @returns server version
*/
export const getServerVersion = async (baseUrl: string): Promise<string> => {
const response = await fetchJson(buildUrl(baseUrl, "/_synapse/admin/v1/server_version"), { method: "GET" });
return response.json.server_version as string;
};
/** Get supported Matrix features */
export const getSupportedFeatures = async (baseUrl: string): Promise<MatrixFeatures> => {
const response = await fetchJson(buildUrl(baseUrl, "/_matrix/client/versions"), { method: "GET" });
return response.json as MatrixFeatures;
};
/**
* Get supported login flows
* @param baseUrl the base URL of the homeserver
* @returns array of supported login flows
*/
export const getSupportedLoginFlows = async (baseUrl: string): Promise<MatrixLoginFlow[]> => {
const response = await fetchJson(buildUrl(baseUrl, "/_matrix/client/r0/login"), { method: "GET" });
return (response.json.flows as MatrixLoginFlow[]) ?? [];
};
/** Resolve a media download URL against the currently selected homeserver. */
export const getMediaUrl = (media_id: string): string =>
buildUrl(requireStoredBaseUrl(), `/_matrix/media/v1/download/${media_id}?allow_redirect=true`);
/** Run an authenticated request against an explicit homeserver base URL. */
export const fetchJsonFromBaseUrl = (baseUrl: string, endpoint: string, options: Options = {}) =>
fetchJsonWithAuth(buildUrl(baseUrl, endpoint), options);
/** Run an authenticated request against the homeserver stored in local storage. */
export const fetchJsonFromStoredBaseUrl = (endpoint: string, options: Options = {}) =>
fetchJsonFromBaseUrl(requireStoredBaseUrl(), endpoint, options);
/** Run an authenticated request against a fully assembled absolute URL. */
export const fetchJsonFromAbsoluteUrl = (url: string, options: Options = {}) => fetchJsonWithAuth(url, options);
/** Run an unauthenticated request against an explicit homeserver base URL. */
export const fetchJsonWithoutAuth = (baseUrl: string, endpoint: string, options: Options = {}) =>
fetchJson(buildUrl(baseUrl, endpoint), options);
/** Clear credentials that should not survive logout or failed auth recovery. */
export const clearStoredAuth = (): void => {
storage.removeItem("access_token");
};
/**
* Generate a random MXID for current homeserver
* @returns full MXID as string
*/
export function generateRandomMxId(): string {
const homeserver = storage.getItem("home_server");
const characters = "0123456789abcdefghijklmnopqrstuvwxyz";
const localpart = Array.from(crypto.getRandomValues(new Uint32Array(8)))
.map(x => characters[x % characters.length])
.join("");
return `@${localpart}:${homeserver}`;
}
/**
* Generate a random user password
* @returns a new random password as string
*/
export function generateRandomPassword(length = 20): string {
const characters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz~!@-#$";
return Array.from(crypto.getRandomValues(new Uint32Array(length)))
.map(x => characters[x % characters.length])
.join("");
}
|