Fix Bulk registration invalid MXID in requests, fixes #30 (#33)

* Fix Bulk registration invalid MXID in requests

* update readme
This commit is contained in:
Aine 2024-09-17 14:02:41 +03:00 committed by GitHub
parent 66c706532a
commit 6957cb1f7d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 35 additions and 10 deletions

View file

@ -37,6 +37,7 @@ The following changes are already implemented:
* [Federation page improvements](https://github.com/Awesome-Technologies/synapse-admin/pull/583) (using theme colors) * [Federation page improvements](https://github.com/Awesome-Technologies/synapse-admin/pull/583) (using theme colors)
* [Add UI option to block deleted rooms from being rejoined](https://github.com/etkecc/synapse-admin/pull/26) * [Add UI option to block deleted rooms from being rejoined](https://github.com/etkecc/synapse-admin/pull/26)
* [Fix required fields check on Bulk registration CSV upload](https://github.com/etkecc/synapse-admin/pull/32) * [Fix required fields check on Bulk registration CSV upload](https://github.com/etkecc/synapse-admin/pull/32)
* [Fix requests with invalid MXIDs on Bulk registration](https://github.com/etkecc/synapse-admin/pull/33)
_the list will be updated as new changes are added_ _the list will be updated as new changes are added_

View file

@ -15,7 +15,7 @@ import {
import { DataProvider, useTranslate } from "ra-core"; import { DataProvider, useTranslate } from "ra-core";
import { useDataProvider, useNotify, RaRecord, Title } from "react-admin"; import { useDataProvider, useNotify, RaRecord, Title } from "react-admin";
import { generateRandomMxId, generateRandomPassword } from "../synapse/synapse"; import { generateRandomMxId, generateRandomPassword, returnMXID } from "../synapse/synapse";
const LOGGING = true; const LOGGING = true;
@ -74,7 +74,7 @@ const FilePicker = () => {
const [conflictMode, setConflictMode] = useState("stop"); const [conflictMode, setConflictMode] = useState("stop");
const [passwordMode, setPasswordMode] = useState(true); const [passwordMode, setPasswordMode] = useState(true);
const [useridMode, setUseridMode] = useState("ignore"); const [useridMode, setUseridMode] = useState("update");
const translate = useTranslate(); const translate = useTranslate();
const notify = useNotify(); const notify = useNotify();
@ -266,12 +266,15 @@ const FilePicker = () => {
const userRecord = { ...entry }; const userRecord = { ...entry };
// No need to do a bunch of cryptographic random number getting if // No need to do a bunch of cryptographic random number getting if
// we are using neither a generated password nor a generated user id. // we are using neither a generated password nor a generated user id.
if (useridMode === "ignore" || userRecord.id === undefined) { if (useridMode === "ignore" || userRecord.id === undefined || userRecord.id === "") {
userRecord.id = generateRandomMxId(); userRecord.id = generateRandomMxId();
} }
if (passwordMode === false || entry.password === undefined) { if (passwordMode === false || entry.password === undefined || entry.password === "") {
userRecord.password = generateRandomPassword(); userRecord.password = generateRandomPassword();
} }
// we want to ensure that the ID is always full MXID, otherwise randomly-generated MXIDs will be in the full
// form, but the ones from the CSV will be localpart-only.
userRecord.id = returnMXID(userRecord.id);
/* TODO record update stats (especially admin no -> yes, deactivated x -> !x, ... */ /* TODO record update stats (especially admin no -> yes, deactivated x -> !x, ... */
/* For these modes we will consider the ID that's in the record. /* For these modes we will consider the ID that's in the record.

View file

@ -3,6 +3,7 @@ import { stringify } from "query-string";
import { DataProvider, DeleteParams, HttpError, Identifier, Options, RaRecord, fetchUtils } from "react-admin"; import { DataProvider, DeleteParams, HttpError, Identifier, Options, RaRecord, fetchUtils } from "react-admin";
import storage from "../storage"; import storage from "../storage";
import { returnMXID } from "./synapse.ts"
import { MatrixError, displayError } from "../components/error"; import { MatrixError, displayError } from "../components/error";
// Adds the access token to all requests // Adds the access token to all requests
@ -234,7 +235,7 @@ const resourceMap = {
path: "/_synapse/admin/v2/users", path: "/_synapse/admin/v2/users",
map: (u: User) => ({ map: (u: User) => ({
...u, ...u,
id: u.name, id: returnMXID(u.name),
avatar_src: u.avatar_url ? mxcUrlToHttp(u.avatar_url) : undefined, avatar_src: u.avatar_url ? mxcUrlToHttp(u.avatar_url) : undefined,
is_guest: !!u.is_guest, is_guest: !!u.is_guest,
admin: !!u.admin, admin: !!u.admin,
@ -245,12 +246,12 @@ const resourceMap = {
data: "users", data: "users",
total: json => json.total, total: json => json.total,
create: (data: RaRecord) => ({ create: (data: RaRecord) => ({
endpoint: `/_synapse/admin/v2/users/@${encodeURIComponent(data.id)}:${storage.getItem("home_server")}`, endpoint: `/_synapse/admin/v2/users/${encodeURIComponent(returnMXID(data.id))}`,
body: data, body: data,
method: "PUT", method: "PUT",
}), }),
delete: (params: DeleteParams) => ({ delete: (params: DeleteParams) => ({
endpoint: `/_synapse/admin/v1/deactivate/${encodeURIComponent(params.id)}`, endpoint: `/_synapse/admin/v1/deactivate/${encodeURIComponent(returnMXID(params.id))}`,
body: { erase: true }, body: { erase: true },
method: "POST", method: "POST",
}), }),
@ -349,7 +350,7 @@ const resourceMap = {
id: um.media_id, id: um.media_id,
}), }),
reference: (id: Identifier) => ({ reference: (id: Identifier) => ({
endpoint: `/_synapse/admin/v1/users/${encodeURIComponent(id)}/media`, endpoint: `/_synapse/admin/v1/users/${encodeURIComponent(returnMXID(id))}/media`,
}), }),
data: "media", data: "media",
total: json => json.total, total: json => json.total,
@ -384,7 +385,7 @@ const resourceMap = {
create: (data: RaServerNotice) => ({ create: (data: RaServerNotice) => ({
endpoint: "/_synapse/admin/v1/send_server_notice", endpoint: "/_synapse/admin/v1/send_server_notice",
body: { body: {
user_id: data.id, user_id: returnMXID(data.id),
content: { content: {
msgtype: "m.text", msgtype: "m.text",
body: data.body, body: data.body,
@ -397,7 +398,7 @@ const resourceMap = {
path: "/_synapse/admin/v1/statistics/users/media", path: "/_synapse/admin/v1/statistics/users/media",
map: (usms: UserMediaStatistic) => ({ map: (usms: UserMediaStatistic) => ({
...usms, ...usms,
id: usms.user_id, id: returnMXID(usms.user_id),
}), }),
data: "users", data: "users",
total: json => json.total, total: json => json.total,

View file

@ -72,6 +72,26 @@ export function generateRandomMxId(): string {
return `@${localpart}:${homeserver}`; return `@${localpart}:${homeserver}`;
} }
/**
* Return the full MXID from an arbitrary input
* @param input the input string
* @returns full MXID as string
*/
export function returnMXID(input: string): string {
const homeserver = storage.getItem("home_server");
// Check if the input already looks like a valid MXID (i.e., starts with "@" and contains ":")
const mxidPattern = /^@[^@:]+:[^@:]+$/;
if (mxidPattern.test(input)) {
return input; // Already a valid MXID
}
// If input is not a valid MXID, assume it's a localpart and construct the MXID
const localpart = input.startsWith('@') ? input.slice(1) : input;
return `@${localpart}:${homeserver}`;
}
/** /**
* Generate a random user password * Generate a random user password
* @returns a new random password as string * @returns a new random password as string