From 6db50f098d7d269974fb136cc6f4425092c0551f Mon Sep 17 00:00:00 2001 From: Quentin Gliech Date: Thu, 2 May 2024 16:52:24 +0200 Subject: [PATCH] Allow more characters in device IDs --- crates/data-model/src/compat/device.rs | 26 +++++++++++++++++-- frontend/src/routeTree.gen.ts | 12 ++++----- frontend/src/routes/__root.tsx | 8 +++--- .../routes/{devices.$id.tsx => devices.$.tsx} | 6 ++--- policies/authorization_grant.rego | 2 +- 5 files changed, 38 insertions(+), 16 deletions(-) rename frontend/src/routes/{devices.$id.tsx => devices.$.tsx} (94%) diff --git a/crates/data-model/src/compat/device.rs b/crates/data-model/src/compat/device.rs index 1a0bb197..a496763e 100644 --- a/crates/data-model/src/compat/device.rs +++ b/crates/data-model/src/compat/device.rs @@ -70,13 +70,35 @@ impl Device { } } +const fn valid_device_chars(c: char) -> bool { + // This matches the regex in the policy + c.is_ascii_alphanumeric() + || c == '.' + || c == '_' + || c == '~' + || c == '!' + || c == '$' + || c == '&' + || c == '\'' + || c == '(' + || c == ')' + || c == '*' + || c == '+' + || c == ',' + || c == ';' + || c == '=' + || c == ':' + || c == '@' + || c == '/' + || c == '-' +} + impl TryFrom for Device { type Error = InvalidDeviceID; /// Create a [`Device`] out of an ID, validating the ID has the right shape fn try_from(id: String) -> Result { - // This matches the regex in the policy - if !id.chars().all(|c| c.is_ascii_alphanumeric() || c == '-') { + if !id.chars().all(valid_device_chars) { return Err(InvalidDeviceID::InvalidCharacters); } diff --git a/frontend/src/routeTree.gen.ts b/frontend/src/routeTree.gen.ts index 7357818c..f54f9b3d 100644 --- a/frontend/src/routeTree.gen.ts +++ b/frontend/src/routeTree.gen.ts @@ -14,7 +14,7 @@ import { Route as rootRoute } from './routes/__root' import { Route as ResetCrossSigningImport } from './routes/reset-cross-signing' import { Route as AccountImport } from './routes/_account' import { Route as AccountIndexImport } from './routes/_account.index' -import { Route as DevicesIdImport } from './routes/devices.$id' +import { Route as DevicesSplatImport } from './routes/devices.$' import { Route as ClientsIdImport } from './routes/clients.$id' import { Route as AccountSessionsIndexImport } from './routes/_account.sessions.index' import { Route as EmailsIdVerifyImport } from './routes/emails.$id.verify' @@ -38,8 +38,8 @@ const AccountIndexRoute = AccountIndexImport.update({ getParentRoute: () => AccountRoute, } as any) -const DevicesIdRoute = DevicesIdImport.update({ - path: '/devices/$id', +const DevicesSplatRoute = DevicesSplatImport.update({ + path: '/devices/$', getParentRoute: () => rootRoute, } as any) @@ -84,8 +84,8 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof ClientsIdImport parentRoute: typeof rootRoute } - '/devices/$id': { - preLoaderRoute: typeof DevicesIdImport + '/devices/$': { + preLoaderRoute: typeof DevicesSplatImport parentRoute: typeof rootRoute } '/_account/': { @@ -122,7 +122,7 @@ export const routeTree = rootRoute.addChildren([ ]), ResetCrossSigningRoute, ClientsIdRoute, - DevicesIdRoute, + DevicesSplatRoute, EmailsIdVerifyRoute, ]) diff --git a/frontend/src/routes/__root.tsx b/frontend/src/routes/__root.tsx index 62cc7a0a..b904badd 100644 --- a/frontend/src/routes/__root.tsx +++ b/frontend/src/routes/__root.tsx @@ -71,8 +71,8 @@ export const Route = createRootRouteWithContext<{ case "org.matrix.session_view": if (search.device_id) throw redirect({ - to: "/devices/$id", - params: { id: search.device_id }, + to: "/devices/$", + params: { _splat: search.device_id }, }); throw redirect({ to: "/sessions", search: { last: PAGE_SIZE } }); @@ -80,8 +80,8 @@ export const Route = createRootRouteWithContext<{ case "org.matrix.session_end": if (search.device_id) throw redirect({ - to: "/devices/$id", - params: { id: search.device_id }, + to: "/devices/$", + params: { _splat: search.device_id }, }); throw redirect({ to: "/sessions", search: { last: PAGE_SIZE } }); diff --git a/frontend/src/routes/devices.$id.tsx b/frontend/src/routes/devices.$.tsx similarity index 94% rename from frontend/src/routes/devices.$id.tsx rename to frontend/src/routes/devices.$.tsx index 954bffd9..fec5dd24 100644 --- a/frontend/src/routes/devices.$id.tsx +++ b/frontend/src/routes/devices.$.tsx @@ -42,7 +42,7 @@ const QUERY = graphql(/* GraphQL */ ` } `); -export const Route = createFileRoute("/devices/$id")({ +export const Route = createFileRoute("/devices/$")({ async loader({ context, params, abortController: { signal } }) { const viewer = await context.client.query( CURRENT_VIEWER_QUERY, @@ -57,7 +57,7 @@ export const Route = createFileRoute("/devices/$id")({ const result = await context.client.query( QUERY, { - deviceId: params.id, + deviceId: params._splat, userId: viewer.data.viewer.id, }, { fetchOptions: { signal } }, @@ -78,7 +78,7 @@ export const Route = createFileRoute("/devices/$id")({ function NotFound(): React.ReactElement { const { t } = useTranslation(); - const { id: deviceId } = Route.useParams(); + const { _splat: deviceId } = Route.useParams(); return (