diff --git a/src/HtmlUtils.tsx b/src/HtmlUtils.tsx index 5e83fdc2a0..a37b7f0ac9 100644 --- a/src/HtmlUtils.tsx +++ b/src/HtmlUtils.tsx @@ -25,7 +25,6 @@ import _linkifyElement from 'linkifyjs/element'; import _linkifyString from 'linkifyjs/string'; import classNames from 'classnames'; import EMOJIBASE_REGEX from 'emojibase-regex'; -import url from 'url'; import katex from 'katex'; import { AllHtmlEntities } from 'html-entities'; import { IContent } from 'matrix-js-sdk/src/models/event'; @@ -153,10 +152,8 @@ export function getHtmlText(insaneHtml: string): string { */ export function isUrlPermitted(inputUrl: string): boolean { try { - const parsed = url.parse(inputUrl); - if (!parsed.protocol) return false; // URL parser protocol includes the trailing colon - return PERMITTED_URL_SCHEMES.includes(parsed.protocol.slice(0, -1)); + return PERMITTED_URL_SCHEMES.includes(new URL(inputUrl).protocol.slice(0, -1)); } catch (e) { return false; } diff --git a/src/Lifecycle.ts b/src/Lifecycle.ts index 61ded93833..410124a637 100644 --- a/src/Lifecycle.ts +++ b/src/Lifecycle.ts @@ -21,6 +21,7 @@ import { createClient } from 'matrix-js-sdk/src/matrix'; import { InvalidStoreError } from "matrix-js-sdk/src/errors"; import { MatrixClient } from "matrix-js-sdk/src/client"; import { decryptAES, encryptAES, IEncryptedPayload } from "matrix-js-sdk/src/crypto/aes"; +import { QueryDict } from 'matrix-js-sdk/src/utils'; import { IMatrixClientCreds, MatrixClientPeg } from './MatrixClientPeg'; import SecurityCustomisations from "./customisations/Security"; @@ -65,7 +66,7 @@ interface ILoadSessionOpts { guestIsUrl?: string; ignoreGuest?: boolean; defaultDeviceDisplayName?: string; - fragmentQueryParams?: Record; + fragmentQueryParams?: QueryDict; } /** @@ -118,8 +119,8 @@ export async function loadSession(opts: ILoadSessionOpts = {}): Promise ) { console.log("Using guest access credentials"); return doSetLoggedIn({ - userId: fragmentQueryParams.guest_user_id, - accessToken: fragmentQueryParams.guest_access_token, + userId: fragmentQueryParams.guest_user_id as string, + accessToken: fragmentQueryParams.guest_access_token as string, homeserverUrl: guestHsUrl, identityServerUrl: guestIsUrl, guest: true, @@ -173,7 +174,7 @@ export async function getStoredSessionOwner(): Promise<[string, boolean]> { * login, else false */ export function attemptTokenLogin( - queryParams: Record, + queryParams: QueryDict, defaultDeviceDisplayName?: string, fragmentAfterLogin?: string, ): Promise { @@ -198,7 +199,7 @@ export function attemptTokenLogin( homeserver, identityServer, "m.login.token", { - token: queryParams.loginToken, + token: queryParams.loginToken as string, initial_device_display_name: defaultDeviceDisplayName, }, ).then(function(creds) { diff --git a/src/components/structures/MatrixChat.tsx b/src/components/structures/MatrixChat.tsx index 15536f260d..785838ffca 100644 --- a/src/components/structures/MatrixChat.tsx +++ b/src/components/structures/MatrixChat.tsx @@ -19,7 +19,7 @@ import { createClient } from "matrix-js-sdk/src/matrix"; import { InvalidStoreError } from "matrix-js-sdk/src/errors"; import { RoomMember } from "matrix-js-sdk/src/models/room-member"; import { MatrixEvent } from "matrix-js-sdk/src/models/event"; -import { sleep, defer, IDeferred } from "matrix-js-sdk/src/utils"; +import { sleep, defer, IDeferred, QueryDict } from "matrix-js-sdk/src/utils"; // focus-visible is a Polyfill for the :focus-visible CSS pseudo-attribute used by _AccessibleButton.scss import 'focus-visible'; @@ -155,7 +155,7 @@ const ONBOARDING_FLOW_STARTERS = [ interface IScreen { screen: string; - params?: object; + params?: QueryDict; } /* eslint-disable camelcase */ @@ -185,9 +185,9 @@ interface IProps { // TODO type things better onNewScreen: (screen: string, replaceLast: boolean) => void; enableGuest?: boolean; // the queryParams extracted from the [real] query-string of the URI - realQueryParams?: Record; + realQueryParams?: QueryDict; // the initial queryParams extracted from the hash-fragment of the URI - startingFragmentQueryParams?: Record; + startingFragmentQueryParams?: QueryDict; // called when we have completed a token login onTokenLoginCompleted?: () => void; // Represents the screen to display as a result of parsing the initial window.location @@ -195,7 +195,7 @@ interface IProps { // TODO type things better // displayname, if any, to set on the device when logging in/registering. defaultDeviceDisplayName?: string; // A function that makes a registration URL - makeRegistrationUrl: (object) => string; + makeRegistrationUrl: (params: QueryDict) => string; } interface IState { @@ -298,7 +298,7 @@ export default class MatrixChat extends React.PureComponent { if (this.screenAfterLogin.screen.startsWith("room/") && params['signurl'] && params['email']) { // probably a threepid invite - try to store it const roomId = this.screenAfterLogin.screen.substring("room/".length); - ThreepidInviteStore.instance.storeInvite(roomId, params as IThreepidInviteWireFormat); + ThreepidInviteStore.instance.storeInvite(roomId, params as unknown as IThreepidInviteWireFormat); } } @@ -1952,7 +1952,7 @@ export default class MatrixChat extends React.PureComponent { this.setState({ serverConfig }); }; - private makeRegistrationUrl = (params: {[key: string]: string}) => { + private makeRegistrationUrl = (params: QueryDict) => { if (this.props.startingFragmentQueryParams.referrer) { params.referrer = this.props.startingFragmentQueryParams.referrer; } @@ -2107,7 +2107,7 @@ export default class MatrixChat extends React.PureComponent { onForgotPasswordClick={showPasswordReset ? this.onForgotPasswordClick : undefined} onServerConfigChange={this.onServerConfigChange} fragmentAfterLogin={fragmentAfterLogin} - defaultUsername={this.props.startingFragmentQueryParams.defaultUsername} + defaultUsername={this.props.startingFragmentQueryParams.defaultUsername as string} {...this.getServerProperties()} /> ); diff --git a/src/utils/HostingLink.js b/src/utils/HostingLink.js index ff7b0c221c..134e045ca2 100644 --- a/src/utils/HostingLink.js +++ b/src/utils/HostingLink.js @@ -14,9 +14,6 @@ See the License for the specific language governing permissions and limitations under the License. */ -import url from 'url'; -import qs from 'qs'; - import SdkConfig from '../SdkConfig'; import { MatrixClientPeg } from '../MatrixClientPeg'; @@ -28,11 +25,8 @@ export function getHostingLink(campaign) { if (MatrixClientPeg.get().getDomain() !== 'matrix.org') return null; try { - const hostingUrl = url.parse(hostingLink); - const params = qs.parse(hostingUrl.query); - params.utm_campaign = campaign; - hostingUrl.search = undefined; - hostingUrl.query = params; + const hostingUrl = new URL(hostingLink); + hostingUrl.searchParams.set("utm_campaign", campaign); return hostingUrl.format(); } catch (e) { return hostingLink;