diff --git a/keyserver/src/responders/website-responders.js b/keyserver/src/responders/website-responders.js --- a/keyserver/src/responders/website-responders.js +++ b/keyserver/src/responders/website-responders.js @@ -47,7 +47,7 @@ import { ServerError } from 'lib/utils/errors.js'; import { promiseAll } from 'lib/utils/promises.js'; import { defaultNotifPermissionAlertInfo } from 'lib/utils/push-alerts.js'; -import { infoFromURL } from 'lib/utils/url-utils.js'; +import { infoFromURL, urlInfoValidator } from 'lib/utils/url-utils.js'; import { tBool, tNumber, @@ -77,7 +77,7 @@ getAppURLFactsFromRequestURL, getCommAppURLFacts, } from '../utils/urls.js'; -import { validateOutput } from '../utils/validation-utils.js'; +import { validateOutput, validateInput } from '../utils/validation-utils.js'; const { renderToNodeStream } = ReactDOMServer; @@ -274,7 +274,16 @@ const initialNavInfoPromise = (async () => { try { - const urlInfo = infoFromURL(req.url); + let urlInfo = infoFromURL(decodeURI(req.url)); + + try { + urlInfo = await validateInput(viewer, urlInfoValidator, urlInfo, true); + } catch (exc) { + // We should still be able to handle older links + if (exc.message !== 'invalid_client_id_prefix') { + throw exc; + } + } let backupInfo = { now: currentDateInTimeZone(viewer.timeZone), diff --git a/keyserver/src/utils/validation-utils.js b/keyserver/src/utils/validation-utils.js --- a/keyserver/src/utils/validation-utils.js +++ b/keyserver/src/utils/validation-utils.js @@ -31,8 +31,9 @@ viewer: Viewer, inputValidator: TType, input: mixed, + ignoreViewerVersion?: boolean, ): Promise { - if (!viewer.isSocket) { + if (!ignoreViewerVersion && !viewer.isSocket) { await checkClientSupported(viewer, inputValidator, input); } const convertedInput = checkInputValidator(inputValidator, input); @@ -41,7 +42,8 @@ hasMinStateVersion(viewer.platformDetails, { native: 43, web: 3, - }) + }) || + ignoreViewerVersion ) { try { return convertClientIDsToServerIDs( diff --git a/lib/utils/url-utils.js b/lib/utils/url-utils.js --- a/lib/utils/url-utils.js +++ b/lib/utils/url-utils.js @@ -1,6 +1,8 @@ // @flow -import { idSchemaRegex } from './validation-utils.js'; +import t, { type TInterface } from 'tcomb'; + +import { idSchemaRegex, tID, tShape } from './validation-utils.js'; import { pendingThreadIDRegex } from '../shared/thread-utils.js'; export type URLInfo = { @@ -18,6 +20,20 @@ ... }; +export const urlInfoValidator: TInterface = tShape({ + year: t.maybe(t.Number), + month: t.maybe(t.Number), + verify: t.maybe(t.String), + calendar: t.maybe(t.Boolean), + chat: t.maybe(t.Boolean), + thread: t.maybe(tID), + settings: t.maybe(t.enums.of(['account', 'danger-zone'])), + threadCreation: t.maybe(t.Boolean), + selectedUserList: t.maybe(t.list(t.String)), + inviteSecret: t.maybe(t.String), + qrCode: t.maybe(t.Boolean), +}); + // We use groups to capture parts of the URL and any changes // to regexes must be reflected in infoFromURL. const yearRegex = new RegExp('(/|^)year/([0-9]+)(/|$)', 'i');