From 64aa6695f5cd135ca2eb21455588e3e3d39ccd08 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Mon, 30 Sep 2019 12:16:46 -0600 Subject: [PATCH 01/21] Move matrix-to.js to utils/permalinks/RoomPermalinkCreator Just a little bit of refactoring to make the feature of custom prefixes a bit easier. --- src/autocomplete/CommunityProvider.js | 2 +- src/autocomplete/RoomProvider.js | 2 +- src/autocomplete/UserProvider.js | 2 +- src/components/structures/GroupView.js | 2 +- src/components/structures/RoomView.js | 2 +- src/components/views/dialogs/ShareDialog.js | 2 +- src/components/views/elements/ReplyThread.js | 2 +- src/components/views/messages/RoomCreate.js | 2 +- src/components/views/messages/TextualBody.js | 2 +- src/components/views/rooms/MessageComposer.js | 2 +- src/components/views/rooms/MessageComposerInput.js | 2 +- src/components/views/rooms/ReplyPreview.js | 2 +- src/components/views/rooms/SlateMessageComposer.js | 2 +- src/linkify-matrix.js | 2 +- .../permalinks/RoomPermalinkCreator.js} | 2 +- .../permalinks/RoomPermalinkCreator-test.js} | 8 ++++---- 16 files changed, 19 insertions(+), 19 deletions(-) rename src/{matrix-to.js => utils/permalinks/RoomPermalinkCreator.js} (99%) rename test/{matrix-to-test.js => utils/permalinks/RoomPermalinkCreator-test.js} (98%) diff --git a/src/autocomplete/CommunityProvider.js b/src/autocomplete/CommunityProvider.js index ffce1e71cf..14c0116604 100644 --- a/src/autocomplete/CommunityProvider.js +++ b/src/autocomplete/CommunityProvider.js @@ -23,7 +23,7 @@ import QueryMatcher from './QueryMatcher'; import {PillCompletion} from './Components'; import sdk from '../index'; import _sortBy from 'lodash/sortBy'; -import {makeGroupPermalink} from "../matrix-to"; +import {makeGroupPermalink} from "../utils/permalinks/RoomPermalinkCreator"; import type {Completion, SelectionRange} from "./Autocompleter"; import FlairStore from "../stores/FlairStore"; diff --git a/src/autocomplete/RoomProvider.js b/src/autocomplete/RoomProvider.js index b94edf590c..062fb5a5c5 100644 --- a/src/autocomplete/RoomProvider.js +++ b/src/autocomplete/RoomProvider.js @@ -26,7 +26,7 @@ import {PillCompletion} from './Components'; import {getDisplayAliasForRoom} from '../Rooms'; import sdk from '../index'; import _sortBy from 'lodash/sortBy'; -import {makeRoomPermalink} from "../matrix-to"; +import {makeRoomPermalink} from "../utils/permalinks/RoomPermalinkCreator"; import type {Completion, SelectionRange} from "./Autocompleter"; const ROOM_REGEX = /\B#\S*/g; diff --git a/src/autocomplete/UserProvider.js b/src/autocomplete/UserProvider.js index 62ae5d4970..d154e02a9d 100644 --- a/src/autocomplete/UserProvider.js +++ b/src/autocomplete/UserProvider.js @@ -28,7 +28,7 @@ import _sortBy from 'lodash/sortBy'; import MatrixClientPeg from '../MatrixClientPeg'; import type {MatrixEvent, Room, RoomMember, RoomState} from 'matrix-js-sdk'; -import {makeUserPermalink} from "../matrix-to"; +import {makeUserPermalink} from "../utils/permalinks/RoomPermalinkCreator"; import type {Completion, SelectionRange} from "./Autocompleter"; const USER_REGEX = /\B@\S*/g; diff --git a/src/components/structures/GroupView.js b/src/components/structures/GroupView.js index 70d8b2e298..6c96dec04f 100644 --- a/src/components/structures/GroupView.js +++ b/src/components/structures/GroupView.js @@ -36,7 +36,7 @@ import classnames from 'classnames'; import GroupStore from '../../stores/GroupStore'; import FlairStore from '../../stores/FlairStore'; import { showGroupAddRoomDialog } from '../../GroupAddressPicker'; -import {makeGroupPermalink, makeUserPermalink} from "../../matrix-to"; +import {makeGroupPermalink, makeUserPermalink} from "../../utils/permalinks/RoomPermalinkCreator"; import {Group} from "matrix-js-sdk"; const LONG_DESC_PLACEHOLDER = _td( diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index 3446901331..057b1f2d80 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -31,7 +31,7 @@ import Promise from 'bluebird'; import classNames from 'classnames'; import {Room} from "matrix-js-sdk"; import { _t } from '../../languageHandler'; -import {RoomPermalinkCreator} from '../../matrix-to'; +import {RoomPermalinkCreator} from '../../utils/permalinks/RoomPermalinkCreator'; import MatrixClientPeg from '../../MatrixClientPeg'; import ContentMessages from '../../ContentMessages'; diff --git a/src/components/views/dialogs/ShareDialog.js b/src/components/views/dialogs/ShareDialog.js index bd6746a1e5..ae43ee2ae5 100644 --- a/src/components/views/dialogs/ShareDialog.js +++ b/src/components/views/dialogs/ShareDialog.js @@ -20,7 +20,7 @@ import {Room, User, Group, RoomMember, MatrixEvent} from 'matrix-js-sdk'; import sdk from '../../../index'; import { _t } from '../../../languageHandler'; import QRCode from 'qrcode-react'; -import {RoomPermalinkCreator, makeGroupPermalink, makeUserPermalink} from "../../../matrix-to"; +import {RoomPermalinkCreator, makeGroupPermalink, makeUserPermalink} from "../../../utils/permalinks/RoomPermalinkCreator"; import * as ContextualMenu from "../../structures/ContextualMenu"; const socials = [ diff --git a/src/components/views/elements/ReplyThread.js b/src/components/views/elements/ReplyThread.js index 08630a16a5..5c1d6a3ef4 100644 --- a/src/components/views/elements/ReplyThread.js +++ b/src/components/views/elements/ReplyThread.js @@ -21,7 +21,7 @@ import PropTypes from 'prop-types'; import dis from '../../../dispatcher'; import {wantsDateSeparator} from '../../../DateUtils'; import {MatrixEvent, MatrixClient} from 'matrix-js-sdk'; -import {makeUserPermalink, RoomPermalinkCreator} from "../../../matrix-to"; +import {makeUserPermalink, RoomPermalinkCreator} from "../../../utils/permalinks/RoomPermalinkCreator"; import SettingsStore from "../../../settings/SettingsStore"; // This component does no cycle detection, simply because the only way to make such a cycle would be to diff --git a/src/components/views/messages/RoomCreate.js b/src/components/views/messages/RoomCreate.js index bf0ef32460..282ba28b8a 100644 --- a/src/components/views/messages/RoomCreate.js +++ b/src/components/views/messages/RoomCreate.js @@ -19,7 +19,7 @@ import PropTypes from 'prop-types'; import createReactClass from 'create-react-class'; import dis from '../../../dispatcher'; -import { RoomPermalinkCreator } from '../../../matrix-to'; +import { RoomPermalinkCreator } from '../../../utils/permalinks/RoomPermalinkCreator'; import { _t } from '../../../languageHandler'; import MatrixClientPeg from '../../../MatrixClientPeg'; diff --git a/src/components/views/messages/TextualBody.js b/src/components/views/messages/TextualBody.js index 7143d02e74..ebcf4857c4 100644 --- a/src/components/views/messages/TextualBody.js +++ b/src/components/views/messages/TextualBody.js @@ -30,7 +30,7 @@ import { _t } from '../../../languageHandler'; import * as ContextualMenu from '../../structures/ContextualMenu'; import SettingsStore from "../../../settings/SettingsStore"; import ReplyThread from "../elements/ReplyThread"; -import {host as matrixtoHost} from '../../../matrix-to'; +import {host as matrixtoHost} from '../../../utils/permalinks/RoomPermalinkCreator'; import {pillifyLinks} from '../../../utils/pillify'; import {IntegrationManagers} from "../../../integrations/IntegrationManagers"; diff --git a/src/components/views/rooms/MessageComposer.js b/src/components/views/rooms/MessageComposer.js index 022d45e60e..4e7f8825ad 100644 --- a/src/components/views/rooms/MessageComposer.js +++ b/src/components/views/rooms/MessageComposer.js @@ -23,7 +23,7 @@ import sdk from '../../../index'; import dis from '../../../dispatcher'; import RoomViewStore from '../../../stores/RoomViewStore'; import Stickerpicker from './Stickerpicker'; -import { makeRoomPermalink } from '../../../matrix-to'; +import { makeRoomPermalink } from '../../../utils/permalinks/RoomPermalinkCreator'; import ContentMessages from '../../../ContentMessages'; import classNames from 'classnames'; import E2EIcon from './E2EIcon'; diff --git a/src/components/views/rooms/MessageComposerInput.js b/src/components/views/rooms/MessageComposerInput.js index df7ba27493..917465aaaa 100644 --- a/src/components/views/rooms/MessageComposerInput.js +++ b/src/components/views/rooms/MessageComposerInput.js @@ -54,7 +54,7 @@ import EMOJIBASE from 'emojibase-data/en/compact.json'; import EMOTICON_REGEX from 'emojibase-regex/emoticon'; import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore"; -import {makeUserPermalink} from "../../../matrix-to"; +import {makeUserPermalink} from "../../../utils/permalinks/RoomPermalinkCreator"; import ReplyPreview from "./ReplyPreview"; import RoomViewStore from '../../../stores/RoomViewStore'; import ReplyThread from "../elements/ReplyThread"; diff --git a/src/components/views/rooms/ReplyPreview.js b/src/components/views/rooms/ReplyPreview.js index 58e7237801..97b29dddee 100644 --- a/src/components/views/rooms/ReplyPreview.js +++ b/src/components/views/rooms/ReplyPreview.js @@ -21,7 +21,7 @@ import { _t } from '../../../languageHandler'; import RoomViewStore from '../../../stores/RoomViewStore'; import SettingsStore from "../../../settings/SettingsStore"; import PropTypes from "prop-types"; -import {RoomPermalinkCreator} from "../../../matrix-to"; +import {RoomPermalinkCreator} from "../../../utils/permalinks/RoomPermalinkCreator"; function cancelQuoting() { dis.dispatch({ diff --git a/src/components/views/rooms/SlateMessageComposer.js b/src/components/views/rooms/SlateMessageComposer.js index d7aa745753..8b51f8266f 100644 --- a/src/components/views/rooms/SlateMessageComposer.js +++ b/src/components/views/rooms/SlateMessageComposer.js @@ -25,7 +25,7 @@ import dis from '../../../dispatcher'; import RoomViewStore from '../../../stores/RoomViewStore'; import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore"; import Stickerpicker from './Stickerpicker'; -import { makeRoomPermalink } from '../../../matrix-to'; +import { makeRoomPermalink } from '../../../utils/permalinks/RoomPermalinkCreator'; import ContentMessages from '../../../ContentMessages'; import classNames from 'classnames'; diff --git a/src/linkify-matrix.js b/src/linkify-matrix.js index a9e894d582..1c8c27fc42 100644 --- a/src/linkify-matrix.js +++ b/src/linkify-matrix.js @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {baseUrl} from "./matrix-to"; +import {baseUrl} from "./utils/permalinks/RoomPermalinkCreator"; function matrixLinkify(linkify) { // Text tokens diff --git a/src/matrix-to.js b/src/utils/permalinks/RoomPermalinkCreator.js similarity index 99% rename from src/matrix-to.js rename to src/utils/permalinks/RoomPermalinkCreator.js index 14467cb4c5..3cc8169434 100644 --- a/src/matrix-to.js +++ b/src/utils/permalinks/RoomPermalinkCreator.js @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import MatrixClientPeg from "./MatrixClientPeg"; +import MatrixClientPeg from "../../MatrixClientPeg"; import isIp from "is-ip"; import utils from 'matrix-js-sdk/lib/utils'; diff --git a/test/matrix-to-test.js b/test/utils/permalinks/RoomPermalinkCreator-test.js similarity index 98% rename from test/matrix-to-test.js rename to test/utils/permalinks/RoomPermalinkCreator-test.js index 23434a57e2..09bfaa3974 100644 --- a/test/matrix-to-test.js +++ b/test/utils/permalinks/RoomPermalinkCreator-test.js @@ -11,15 +11,15 @@ See the License for the specific language governing permissions and limitations under the License. */ -import expect from 'expect'; -import peg from '../src/MatrixClientPeg'; +import expect from 'expect/build/index'; +import peg from '../../../src/MatrixClientPeg'; import { makeGroupPermalink, makeRoomPermalink, makeUserPermalink, RoomPermalinkCreator, -} from "../src/matrix-to"; -import * as testUtils from "./test-utils"; +} from "../../../src/utils/permalinks/RoomPermalinkCreator"; +import * as testUtils from "../../test-utils"; function mockRoom(roomId, members, serverACL) { members.forEach(m => m.membership = "join"); From f9d5e89017fbc663556567d2079894daf35c69cf Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Mon, 30 Sep 2019 12:37:13 -0600 Subject: [PATCH 02/21] Move early parts of matrix.to bits into its own class --- src/components/views/messages/TextualBody.js | 7 +++-- src/linkify-matrix.js | 2 +- src/utils/permalinks/RoomPermalinkCreator.js | 18 +++++++------ src/utils/permalinks/SpecPermalinks.js | 28 ++++++++++++++++++++ 4 files changed, 44 insertions(+), 11 deletions(-) create mode 100644 src/utils/permalinks/SpecPermalinks.js diff --git a/src/components/views/messages/TextualBody.js b/src/components/views/messages/TextualBody.js index ebcf4857c4..3277f215bf 100644 --- a/src/components/views/messages/TextualBody.js +++ b/src/components/views/messages/TextualBody.js @@ -30,9 +30,9 @@ import { _t } from '../../../languageHandler'; import * as ContextualMenu from '../../structures/ContextualMenu'; import SettingsStore from "../../../settings/SettingsStore"; import ReplyThread from "../elements/ReplyThread"; -import {host as matrixtoHost} from '../../../utils/permalinks/RoomPermalinkCreator'; import {pillifyLinks} from '../../../utils/pillify'; import {IntegrationManagers} from "../../../integrations/IntegrationManagers"; +import {RoomPermalinkCreator} from "../../../utils/permalinks/RoomPermalinkCreator"; module.exports = createReactClass({ displayName: 'TextualBody', @@ -251,7 +251,10 @@ module.exports = createReactClass({ // never preview matrix.to links (if anything we should give a smart // preview of the room/user they point to: nobody needs to be reminded // what the matrix.to site looks like). - if (host === matrixtoHost) return false; + if (this.props.mxEvent && this.props.mxEvent.getRoom()) { + const permalinks = new RoomPermalinkCreator(this.props.mxEvent.getRoom()); + if (permalinks.isPermalinkHost(host)) return false; + } if (node.textContent.toLowerCase().trim().startsWith(host.toLowerCase())) { // it's a "foo.pl" style link diff --git a/src/linkify-matrix.js b/src/linkify-matrix.js index 1c8c27fc42..e823e507c4 100644 --- a/src/linkify-matrix.js +++ b/src/linkify-matrix.js @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {baseUrl} from "./utils/permalinks/RoomPermalinkCreator"; +import {baseUrl} from "./utils/permalinks/SpecPermalinks"; function matrixLinkify(linkify) { // Text tokens diff --git a/src/utils/permalinks/RoomPermalinkCreator.js b/src/utils/permalinks/RoomPermalinkCreator.js index 3cc8169434..bd2e0b72fc 100644 --- a/src/utils/permalinks/RoomPermalinkCreator.js +++ b/src/utils/permalinks/RoomPermalinkCreator.js @@ -17,9 +17,7 @@ limitations under the License. import MatrixClientPeg from "../../MatrixClientPeg"; import isIp from "is-ip"; import utils from 'matrix-js-sdk/lib/utils'; - -export const host = "matrix.to"; -export const baseUrl = `https://${host}`; +import {host as matrixtoHost, baseUrl as matrixtoBaseUrl} from "SpecPermalinks"; // The maximum number of servers to pick when working out which servers // to add to permalinks. The servers are appended as ?via=example.org @@ -123,15 +121,19 @@ export class RoomPermalinkCreator { return this._started; } + isPermalinkHost(host: string): boolean { + return host === matrixtoHost; + } + forEvent(eventId) { const roomId = this._roomId; - const permalinkBase = `${baseUrl}/#/${roomId}/${eventId}`; + const permalinkBase = `${matrixtoBaseUrl}/#/${roomId}/${eventId}`; return `${permalinkBase}${encodeServerCandidates(this._serverCandidates)}`; } forRoom() { const roomId = this._roomId; - const permalinkBase = `${baseUrl}/#/${roomId}`; + const permalinkBase = `${matrixtoBaseUrl}/#/${roomId}`; return `${permalinkBase}${encodeServerCandidates(this._serverCandidates)}`; } @@ -255,11 +257,11 @@ export class RoomPermalinkCreator { } export function makeUserPermalink(userId) { - return `${baseUrl}/#/${userId}`; + return `${matrixtoBaseUrl}/#/${userId}`; } export function makeRoomPermalink(roomId) { - const permalinkBase = `${baseUrl}/#/${roomId}`; + const permalinkBase = `${matrixtoBaseUrl}/#/${roomId}`; if (!roomId) { throw new Error("can't permalink a falsey roomId"); @@ -280,7 +282,7 @@ export function makeRoomPermalink(roomId) { } export function makeGroupPermalink(groupId) { - return `${baseUrl}/#/${groupId}`; + return `${matrixtoBaseUrl}/#/${groupId}`; } export function encodeServerCandidates(candidates) { diff --git a/src/utils/permalinks/SpecPermalinks.js b/src/utils/permalinks/SpecPermalinks.js new file mode 100644 index 0000000000..461696bfea --- /dev/null +++ b/src/utils/permalinks/SpecPermalinks.js @@ -0,0 +1,28 @@ +/* +Copyright 2019 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +export const host = "matrix.to"; +export const baseUrl = `https://${host}`; + +/** + * Generates matrix.to permalinks + */ +export default class SpecPermalinks { + constructor() { + } + + // TODO: The class +} From 926e1146f94eff20605150eb28ef27729baa10cd Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Mon, 30 Sep 2019 12:51:17 -0600 Subject: [PATCH 03/21] Move spec permalinks into their own class This allows for Riot permalinks to be introduced without if-else ladders everywhere. --- src/linkify-matrix.js | 2 +- ...cPermalinks.js => PermalinkConstructor.js} | 23 ++++++--- src/utils/permalinks/RoomPermalinkCreator.js | 49 +++++++++--------- .../permalinks/SpecPermalinkConstructor.js | 50 +++++++++++++++++++ 4 files changed, 93 insertions(+), 31 deletions(-) rename src/utils/permalinks/{SpecPermalinks.js => PermalinkConstructor.js} (50%) create mode 100644 src/utils/permalinks/SpecPermalinkConstructor.js diff --git a/src/linkify-matrix.js b/src/linkify-matrix.js index e823e507c4..2d72b7fb41 100644 --- a/src/linkify-matrix.js +++ b/src/linkify-matrix.js @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import {baseUrl} from "./utils/permalinks/SpecPermalinks"; +import {baseUrl} from "./utils/permalinks/SpecPermalinkConstructor"; function matrixLinkify(linkify) { // Text tokens diff --git a/src/utils/permalinks/SpecPermalinks.js b/src/utils/permalinks/PermalinkConstructor.js similarity index 50% rename from src/utils/permalinks/SpecPermalinks.js rename to src/utils/permalinks/PermalinkConstructor.js index 461696bfea..014bf3e225 100644 --- a/src/utils/permalinks/SpecPermalinks.js +++ b/src/utils/permalinks/PermalinkConstructor.js @@ -14,15 +14,24 @@ See the License for the specific language governing permissions and limitations under the License. */ -export const host = "matrix.to"; -export const baseUrl = `https://${host}`; - /** - * Generates matrix.to permalinks + * Interface for classes that actually produce permalinks (strings). + * TODO: Convert this to a real TypeScript interface */ -export default class SpecPermalinks { - constructor() { +export default class PermalinkConstructor { + forEvent(roomId: string, eventId: string, serverCandidates: string[]): string { + throw new Error("Not implemented"); } - // TODO: The class + forRoom(roomIdOrAlias: string, serverCandidates: string[]): string { + throw new Error("Not implemented"); + } + + forGroup(groupId: string): string { + throw new Error("Not implemented"); + } + + forUser(userId: string): string { + throw new Error("Not implemented"); + } } diff --git a/src/utils/permalinks/RoomPermalinkCreator.js b/src/utils/permalinks/RoomPermalinkCreator.js index bd2e0b72fc..984b4233ba 100644 --- a/src/utils/permalinks/RoomPermalinkCreator.js +++ b/src/utils/permalinks/RoomPermalinkCreator.js @@ -17,7 +17,13 @@ limitations under the License. import MatrixClientPeg from "../../MatrixClientPeg"; import isIp from "is-ip"; import utils from 'matrix-js-sdk/lib/utils'; -import {host as matrixtoHost, baseUrl as matrixtoBaseUrl} from "SpecPermalinks"; +import SpecPermalinkConstructor, { + baseUrl as matrixtoBaseUrl, + host as matrixtoHost +} from "./SpecPermalinkConstructor"; +import PermalinkConstructor from "./PermalinkConstructor"; + +const SdkConfig = require("../../SdkConfig"); // The maximum number of servers to pick when working out which servers // to add to permalinks. The servers are appended as ?via=example.org @@ -71,7 +77,7 @@ export class RoomPermalinkCreator { // We support being given a roomId as a fallback in the event the `room` object // doesn't exist or is not healthy for us to rely on. For example, loading a // permalink to a room which the MatrixClient doesn't know about. - constructor(room, roomId=null) { + constructor(room, roomId = null) { this._room = room; this._roomId = room ? room.roomId : roomId; this._highestPlUserId = null; @@ -126,15 +132,11 @@ export class RoomPermalinkCreator { } forEvent(eventId) { - const roomId = this._roomId; - const permalinkBase = `${matrixtoBaseUrl}/#/${roomId}/${eventId}`; - return `${permalinkBase}${encodeServerCandidates(this._serverCandidates)}`; + return getPermalinkConstructor().forEvent(this._roomId, eventId, this._serverCandidates); } forRoom() { - const roomId = this._roomId; - const permalinkBase = `${matrixtoBaseUrl}/#/${roomId}`; - return `${permalinkBase}${encodeServerCandidates(this._serverCandidates)}`; + return getPermalinkConstructor().forRoom(this._roomId, this._serverCandidates); } onRoomState(event) { @@ -184,8 +186,8 @@ export class RoomPermalinkCreator { } const serverName = getServerName(userId); return !isHostnameIpAddress(serverName) && - !isHostInRegex(serverName, this._bannedHostsRegexps) && - isHostInRegex(serverName, this._allowedHostsRegexps); + !isHostInRegex(serverName, this._bannedHostsRegexps) && + isHostInRegex(serverName, this._allowedHostsRegexps); }); const maxEntry = allowedEntries.reduce((max, entry) => { return (entry[1] > max[1]) ? entry : max; @@ -223,7 +225,7 @@ export class RoomPermalinkCreator { } _updatePopulationMap() { - const populationMap: {[server:string]:number} = {}; + const populationMap: { [server: string]: number } = {}; for (const member of this._room.getJoinedMembers()) { const serverName = getServerName(member.userId); if (!populationMap[serverName]) { @@ -244,9 +246,9 @@ export class RoomPermalinkCreator { .sort((a, b) => this._populationMap[b] - this._populationMap[a]) .filter(a => { return !candidates.includes(a) && - !isHostnameIpAddress(a) && - !isHostInRegex(a, this._bannedHostsRegexps) && - isHostInRegex(a, this._allowedHostsRegexps); + !isHostnameIpAddress(a) && + !isHostInRegex(a, this._bannedHostsRegexps) && + isHostInRegex(a, this._allowedHostsRegexps); }); const remainingServers = serversByPopulation.slice(0, MAX_SERVER_CANDIDATES - candidates.length); @@ -257,24 +259,22 @@ export class RoomPermalinkCreator { } export function makeUserPermalink(userId) { - return `${matrixtoBaseUrl}/#/${userId}`; + return getPermalinkConstructor().forUser(userId); } export function makeRoomPermalink(roomId) { - const permalinkBase = `${matrixtoBaseUrl}/#/${roomId}`; - if (!roomId) { throw new Error("can't permalink a falsey roomId"); } // If the roomId isn't actually a room ID, don't try to list the servers. // Aliases are already routable, and don't need extra information. - if (roomId[0] !== '!') return permalinkBase; + if (roomId[0] !== '!') return getPermalinkConstructor().forRoom(roomId, []); const client = MatrixClientPeg.get(); const room = client.getRoom(roomId); if (!room) { - return permalinkBase; + return getPermalinkConstructor().forRoom(roomId, []); } const permalinkCreator = new RoomPermalinkCreator(room); permalinkCreator.load(); @@ -282,12 +282,15 @@ export function makeRoomPermalink(roomId) { } export function makeGroupPermalink(groupId) { - return `${matrixtoBaseUrl}/#/${groupId}`; + return getPermalinkConstructor().forGroup(groupId); } -export function encodeServerCandidates(candidates) { - if (!candidates || candidates.length === 0) return ''; - return `?via=${candidates.map(c => encodeURIComponent(c)).join("&via=")}`; +function getPermalinkConstructor(): PermalinkConstructor { + if (SdkConfig.get()['useRiotToCreatePermalinks']) { + // TODO: Return a RiotPermalinkConstructor + } + + return new SpecPermalinkConstructor(); } function getServerName(userId) { diff --git a/src/utils/permalinks/SpecPermalinkConstructor.js b/src/utils/permalinks/SpecPermalinkConstructor.js new file mode 100644 index 0000000000..6c53bfc5f2 --- /dev/null +++ b/src/utils/permalinks/SpecPermalinkConstructor.js @@ -0,0 +1,50 @@ +/* +Copyright 2019 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import PermalinkConstructor from "./PermalinkConstructor"; + +export const host = "matrix.to"; +export const baseUrl = `https://${host}`; + +/** + * Generates matrix.to permalinks + */ +export default class SpecPermalinkConstructor extends PermalinkConstructor { + constructor() { + super(); + } + + forEvent(roomId: string, eventId: string, serverCandidates: string[]): string { + return `${baseUrl}/#/${roomId}/${eventId}${this.encodeServerCandidates(serverCandidates)}`; + } + + forRoom(roomIdOrAlias: string, serverCandidates: string[]): string { + return `${baseUrl}/#/${roomIdOrAlias}${this.encodeServerCandidates(serverCandidates)}`; + } + + forUser(userId: string): string { + return `${baseUrl}/#/${userId}`; + } + + forGroup(groupId: string): string { + return `${baseUrl}/#/${groupId}`; + } + + encodeServerCandidates(candidates: string[]) { + if (!candidates || candidates.length === 0) return ''; + return `?via=${candidates.map(c => encodeURIComponent(c)).join("&via=")}`; + } +} From f879185aef3ed3f1849ea011219baf58a306d9cc Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Mon, 30 Sep 2019 12:53:45 -0600 Subject: [PATCH 04/21] Move permalink host check into permalink constructors Without the requirement for a room to work --- src/components/views/messages/TextualBody.js | 7 ++----- src/utils/permalinks/PermalinkConstructor.js | 4 ++++ src/utils/permalinks/RoomPermalinkCreator.js | 13 +++++-------- src/utils/permalinks/SpecPermalinkConstructor.js | 4 ++++ 4 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/components/views/messages/TextualBody.js b/src/components/views/messages/TextualBody.js index 3277f215bf..d3c53c8a33 100644 --- a/src/components/views/messages/TextualBody.js +++ b/src/components/views/messages/TextualBody.js @@ -32,7 +32,7 @@ import SettingsStore from "../../../settings/SettingsStore"; import ReplyThread from "../elements/ReplyThread"; import {pillifyLinks} from '../../../utils/pillify'; import {IntegrationManagers} from "../../../integrations/IntegrationManagers"; -import {RoomPermalinkCreator} from "../../../utils/permalinks/RoomPermalinkCreator"; +import {isPermalinkHost} from "../../../utils/permalinks/RoomPermalinkCreator"; module.exports = createReactClass({ displayName: 'TextualBody', @@ -251,10 +251,7 @@ module.exports = createReactClass({ // never preview matrix.to links (if anything we should give a smart // preview of the room/user they point to: nobody needs to be reminded // what the matrix.to site looks like). - if (this.props.mxEvent && this.props.mxEvent.getRoom()) { - const permalinks = new RoomPermalinkCreator(this.props.mxEvent.getRoom()); - if (permalinks.isPermalinkHost(host)) return false; - } + if (isPermalinkHost(host)) return false; if (node.textContent.toLowerCase().trim().startsWith(host.toLowerCase())) { // it's a "foo.pl" style link diff --git a/src/utils/permalinks/PermalinkConstructor.js b/src/utils/permalinks/PermalinkConstructor.js index 014bf3e225..47d813390f 100644 --- a/src/utils/permalinks/PermalinkConstructor.js +++ b/src/utils/permalinks/PermalinkConstructor.js @@ -34,4 +34,8 @@ export default class PermalinkConstructor { forUser(userId: string): string { throw new Error("Not implemented"); } + + isPermalinkHost(host: string): boolean { + throw new Error("Not implemented"); + } } diff --git a/src/utils/permalinks/RoomPermalinkCreator.js b/src/utils/permalinks/RoomPermalinkCreator.js index 984b4233ba..7394854c18 100644 --- a/src/utils/permalinks/RoomPermalinkCreator.js +++ b/src/utils/permalinks/RoomPermalinkCreator.js @@ -17,10 +17,7 @@ limitations under the License. import MatrixClientPeg from "../../MatrixClientPeg"; import isIp from "is-ip"; import utils from 'matrix-js-sdk/lib/utils'; -import SpecPermalinkConstructor, { - baseUrl as matrixtoBaseUrl, - host as matrixtoHost -} from "./SpecPermalinkConstructor"; +import SpecPermalinkConstructor from "./SpecPermalinkConstructor"; import PermalinkConstructor from "./PermalinkConstructor"; const SdkConfig = require("../../SdkConfig"); @@ -127,10 +124,6 @@ export class RoomPermalinkCreator { return this._started; } - isPermalinkHost(host: string): boolean { - return host === matrixtoHost; - } - forEvent(eventId) { return getPermalinkConstructor().forEvent(this._roomId, eventId, this._serverCandidates); } @@ -285,6 +278,10 @@ export function makeGroupPermalink(groupId) { return getPermalinkConstructor().forGroup(groupId); } +export function isPermalinkHost(host: string): boolean { + return getPermalinkConstructor().isPermalinkHost(host); +} + function getPermalinkConstructor(): PermalinkConstructor { if (SdkConfig.get()['useRiotToCreatePermalinks']) { // TODO: Return a RiotPermalinkConstructor diff --git a/src/utils/permalinks/SpecPermalinkConstructor.js b/src/utils/permalinks/SpecPermalinkConstructor.js index 6c53bfc5f2..5dd4a5a24e 100644 --- a/src/utils/permalinks/SpecPermalinkConstructor.js +++ b/src/utils/permalinks/SpecPermalinkConstructor.js @@ -43,6 +43,10 @@ export default class SpecPermalinkConstructor extends PermalinkConstructor { return `${baseUrl}/#/${groupId}`; } + isPermalinkHost(testHost: string): boolean { + return testHost === host; + } + encodeServerCandidates(candidates: string[]) { if (!candidates || candidates.length === 0) return ''; return `?via=${candidates.map(c => encodeURIComponent(c)).join("&via=")}`; From f183e96d66bd6f48fa8b765bfc5412a11b927cc8 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Mon, 30 Sep 2019 13:04:20 -0600 Subject: [PATCH 05/21] Introduce a RiotPermalinkConstructor and fix the setting name Originally we were planning on using the current location as the permalink prefix, but that doesn't work if the user is a desktop user. --- .../permalinks/RiotPermalinkConstructor.js | 60 +++++++++++++++++++ src/utils/permalinks/RoomPermalinkCreator.js | 7 ++- 2 files changed, 64 insertions(+), 3 deletions(-) create mode 100644 src/utils/permalinks/RiotPermalinkConstructor.js diff --git a/src/utils/permalinks/RiotPermalinkConstructor.js b/src/utils/permalinks/RiotPermalinkConstructor.js new file mode 100644 index 0000000000..87d8d058f9 --- /dev/null +++ b/src/utils/permalinks/RiotPermalinkConstructor.js @@ -0,0 +1,60 @@ +/* +Copyright 2019 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import PermalinkConstructor from "./PermalinkConstructor"; + +/** + * Generates permalinks that self-reference the running webapp + */ +export default class RiotPermalinkConstructor extends PermalinkConstructor { + + _riotUrl: string; + + constructor(riotUrl: string) { + super(); + this._riotUrl = riotUrl; + } + + forEvent(roomId: string, eventId: string, serverCandidates: string[]): string { + // TODO: Fix URL + return `${this._riotUrl}/#/${roomId}/${eventId}${this.encodeServerCandidates(serverCandidates)}`; + } + + forRoom(roomIdOrAlias: string, serverCandidates: string[]): string { + // TODO: Fix URL + return `${this._riotUrl}/#/${roomIdOrAlias}${this.encodeServerCandidates(serverCandidates)}`; + } + + forUser(userId: string): string { + // TODO: Fix URL + return `${this._riotUrl}/#/${userId}`; + } + + forGroup(groupId: string): string { + // TODO: Fix URL + return `${this._riotUrl}/#/${groupId}`; + } + + isPermalinkHost(testHost: string): boolean { + // TODO: Actual check + return testHost === this._riotUrl; + } + + encodeServerCandidates(candidates: string[]) { + if (!candidates || candidates.length === 0) return ''; + return `?via=${candidates.map(c => encodeURIComponent(c)).join("&via=")}`; + } +} diff --git a/src/utils/permalinks/RoomPermalinkCreator.js b/src/utils/permalinks/RoomPermalinkCreator.js index 7394854c18..aeb7d3b72c 100644 --- a/src/utils/permalinks/RoomPermalinkCreator.js +++ b/src/utils/permalinks/RoomPermalinkCreator.js @@ -17,8 +17,9 @@ limitations under the License. import MatrixClientPeg from "../../MatrixClientPeg"; import isIp from "is-ip"; import utils from 'matrix-js-sdk/lib/utils'; -import SpecPermalinkConstructor from "./SpecPermalinkConstructor"; +import SpecPermalinkConstructor, {baseUrl as matrixtoBaseUrl} from "./SpecPermalinkConstructor"; import PermalinkConstructor from "./PermalinkConstructor"; +import RiotPermalinkConstructor from "./RiotPermalinkConstructor"; const SdkConfig = require("../../SdkConfig"); @@ -283,8 +284,8 @@ export function isPermalinkHost(host: string): boolean { } function getPermalinkConstructor(): PermalinkConstructor { - if (SdkConfig.get()['useRiotToCreatePermalinks']) { - // TODO: Return a RiotPermalinkConstructor + if (SdkConfig.get()['permalinkPrefix'] && SdkConfig.get()['permalinkPrefix'] !== matrixtoBaseUrl) { + return new RiotPermalinkConstructor(SdkConfig.get()['permalinkPrefix']); } return new SpecPermalinkConstructor(); From baf78da79179812155355e3c053b06f7263879cc Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Mon, 30 Sep 2019 16:03:24 -0600 Subject: [PATCH 06/21] Support spec-level permalink parsing --- src/utils/permalinks/PermalinkConstructor.js | 38 +++++++++++++++++++ .../permalinks/SpecPermalinkConstructor.js | 38 ++++++++++++++++++- 2 files changed, 75 insertions(+), 1 deletion(-) diff --git a/src/utils/permalinks/PermalinkConstructor.js b/src/utils/permalinks/PermalinkConstructor.js index 47d813390f..507f16f795 100644 --- a/src/utils/permalinks/PermalinkConstructor.js +++ b/src/utils/permalinks/PermalinkConstructor.js @@ -38,4 +38,42 @@ export default class PermalinkConstructor { isPermalinkHost(host: string): boolean { throw new Error("Not implemented"); } + + parsePermalink(fullUrl: string): PermalinkParts { + throw new Error("Not implemented"); + } +} + +// Inspired by/Borrowed with permission from the matrix-bot-sdk: +// https://github.com/turt2live/matrix-js-bot-sdk/blob/7c4665c9a25c2c8e0fe4e509f2616505b5b66a1c/src/Permalinks.ts#L1-L6 +export class PermalinkParts { + roomIdOrAlias: string; + eventId: string; + userId: string; + groupId: string; + viaServers: string[]; + + constructor(roomIdOrAlias: string, eventId: string, userId: string, groupId: string, viaServers: string[]) { + this.roomIdOrAlias = roomIdOrAlias; + this.eventId = eventId; + this.groupId = groupId; + this.userId = userId; + this.viaServers = viaServers; + } + + static forUser(userId: string): PermalinkParts { + return new PermalinkParts(null, null, userId, null, null); + } + + static forGroup(groupId: string): PermalinkParts { + return new PermalinkParts(null, null, null, groupId, null); + } + + static forRoom(roomIdOrAlias: string, viaServers: string[]): PermalinkParts { + return new PermalinkParts(roomIdOrAlias, null, null, null, viaServers || []); + } + + static forEvent(roomId: string, eventId: string, viaServers: string[]): PermalinkParts { + return new PermalinkParts(roomId, eventId, null, null, viaServers || []); + } } diff --git a/src/utils/permalinks/SpecPermalinkConstructor.js b/src/utils/permalinks/SpecPermalinkConstructor.js index 5dd4a5a24e..e4cff798a7 100644 --- a/src/utils/permalinks/SpecPermalinkConstructor.js +++ b/src/utils/permalinks/SpecPermalinkConstructor.js @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import PermalinkConstructor from "./PermalinkConstructor"; +import PermalinkConstructor, {PermalinkParts} from "./PermalinkConstructor"; export const host = "matrix.to"; export const baseUrl = `https://${host}`; @@ -51,4 +51,40 @@ export default class SpecPermalinkConstructor extends PermalinkConstructor { if (!candidates || candidates.length === 0) return ''; return `?via=${candidates.map(c => encodeURIComponent(c)).join("&via=")}`; } + + // Heavily inspired by/borrowed from the matrix-bot-sdk (with permission): + // https://github.com/turt2live/matrix-js-bot-sdk/blob/7c4665c9a25c2c8e0fe4e509f2616505b5b66a1c/src/Permalinks.ts#L33-L61 + parsePermalink(fullUrl: string): PermalinkParts { + if (!fullUrl || !fullUrl.startsWith(baseUrl)) { + throw new Error("Does not appear to be a permalink"); + } + + const parts = fullUrl.substring(`${baseUrl}/#/`.length).split("/"); + + const entity = parts[0]; + if (entity[0] === '@') { + // Probably a user, no further parsing needed. + return PermalinkParts.forUser(entity); + } else if (entity[0] === '+') { + // Probably a group, no further parsing needed. + return PermalinkParts.forGroup(entity); + } else if (entity[0] === '#' || entity[0] === '!') { + if (parts.length === 1) { + return PermalinkParts.forRoom(entity, []); + } + + // rejoin the rest because v3 events can have slashes (annoyingly) + const eventIdAndQuery = parts.length > 1 ? parts.slice(1).join('/') : ""; + const secondaryParts = eventIdAndQuery.split("?"); + + const eventId = secondaryParts[0]; + const query = secondaryParts.length > 1 ? secondaryParts[1] : ""; + + const via = query.split("via=").filter(p => !!p); + + return PermalinkParts.forEvent(entity, eventId, via); + } else { + throw new Error("Unknown entity type in permalink"); + } + } } From 9bb1ebb89db0f94c5056f2bd2fec3f07be1fd3a4 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Mon, 30 Sep 2019 16:03:52 -0600 Subject: [PATCH 07/21] Support riot-level permalink parsing --- .../permalinks/RiotPermalinkConstructor.js | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/utils/permalinks/RiotPermalinkConstructor.js b/src/utils/permalinks/RiotPermalinkConstructor.js index 87d8d058f9..207e181a15 100644 --- a/src/utils/permalinks/RiotPermalinkConstructor.js +++ b/src/utils/permalinks/RiotPermalinkConstructor.js @@ -57,4 +57,46 @@ export default class RiotPermalinkConstructor extends PermalinkConstructor { if (!candidates || candidates.length === 0) return ''; return `?via=${candidates.map(c => encodeURIComponent(c)).join("&via=")}`; } + + // Heavily inspired by/borrowed from the matrix-bot-sdk (with permission): + // https://github.com/turt2live/matrix-js-bot-sdk/blob/7c4665c9a25c2c8e0fe4e509f2616505b5b66a1c/src/Permalinks.ts#L33-L61 + // Adapted for Riot's URL format + parsePermalink(fullUrl: string): PermalinkParts { + if (!fullUrl || !fullUrl.startsWith(this._riotUrl)) { + throw new Error("Does not appear to be a permalink"); + } + + const parts = fullUrl.substring(`${this._riotUrl}/#/`.length).split("/"); + if (parts.length < 2) { // we're expecting an entity and an ID of some kind at least + throw new Error("URL is missing parts"); + } + + const entityType = parts[0]; + const entity = parts[1]; + if (entityType === 'user') { + // Probably a user, no further parsing needed. + return PermalinkParts.forUser(entity); + } else if (entityType === 'group') { + // Probably a group, no further parsing needed. + return PermalinkParts.forGroup(entity); + } else if (entityType === 'room') { + if (parts.length === 2) { + return PermalinkParts.forRoom(entity, []); + } + + // rejoin the rest because v3 events can have slashes (annoyingly) + const eventIdAndQuery = parts.length > 2 ? parts.slice(2).join('/') : ""; + const secondaryParts = eventIdAndQuery.split("?"); + + const eventId = secondaryParts[0]; + const query = secondaryParts.length > 1 ? secondaryParts[1] : ""; + + // TODO: Verify Riot works with via args + const via = query.split("via=").filter(p => !!p); + + return PermalinkParts.forEvent(entity, eventId, via); + } else { + throw new Error("Unknown entity type in permalink"); + } + } } From 3e5a39d646f521f0be37c91aaebcdbb38ed34d51 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Mon, 30 Sep 2019 16:04:10 -0600 Subject: [PATCH 08/21] Add utility function for permalink parsing --- src/utils/permalinks/RoomPermalinkCreator.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/utils/permalinks/RoomPermalinkCreator.js b/src/utils/permalinks/RoomPermalinkCreator.js index aeb7d3b72c..88bcd5768a 100644 --- a/src/utils/permalinks/RoomPermalinkCreator.js +++ b/src/utils/permalinks/RoomPermalinkCreator.js @@ -18,7 +18,7 @@ import MatrixClientPeg from "../../MatrixClientPeg"; import isIp from "is-ip"; import utils from 'matrix-js-sdk/lib/utils'; import SpecPermalinkConstructor, {baseUrl as matrixtoBaseUrl} from "./SpecPermalinkConstructor"; -import PermalinkConstructor from "./PermalinkConstructor"; +import PermalinkConstructor, {PermalinkParts} from "./PermalinkConstructor"; import RiotPermalinkConstructor from "./RiotPermalinkConstructor"; const SdkConfig = require("../../SdkConfig"); @@ -291,6 +291,17 @@ function getPermalinkConstructor(): PermalinkConstructor { return new SpecPermalinkConstructor(); } +export function parsePermalink(fullUrl: string): PermalinkParts { + const riotPrefix = SdkConfig.get()['permalinkPrefix']; + if (fullUrl.startsWith(matrixtoBaseUrl)) { + return new SpecPermalinkConstructor().parsePermalink(fullUrl); + } else if (riotPrefix && fullUrl.startsWith(riotPrefix)) { + return new RiotPermalinkConstructor(riotPrefix).parsePermalink(fullUrl); + } + + return null; // not a permalink we can handle +} + function getServerName(userId) { return userId.split(":").splice(1).join(":"); } From 199dfa7bf91a00c2668e1209a84bd6d4b9f1300e Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Mon, 30 Sep 2019 16:04:49 -0600 Subject: [PATCH 09/21] Always check if the permalink is a spec permalink See code for rationale --- src/utils/permalinks/RoomPermalinkCreator.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/utils/permalinks/RoomPermalinkCreator.js b/src/utils/permalinks/RoomPermalinkCreator.js index 88bcd5768a..7df204a17b 100644 --- a/src/utils/permalinks/RoomPermalinkCreator.js +++ b/src/utils/permalinks/RoomPermalinkCreator.js @@ -280,6 +280,9 @@ export function makeGroupPermalink(groupId) { } export function isPermalinkHost(host: string): boolean { + // Always check if the permalink is a spec permalink (callers are likely to call + // parsePermalink after this function). + if (new SpecPermalinkConstructor().isPermalinkHost(host)) return true; return getPermalinkConstructor().isPermalinkHost(host); } From 8acaa3ce95e03df9a8996112df81c9e67ad36033 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Mon, 30 Sep 2019 16:05:28 -0600 Subject: [PATCH 10/21] Update generated Riot permalinks Also adds some safety around the Riot URL to ensure it mostly looks like a URL --- .../permalinks/RiotPermalinkConstructor.js | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/utils/permalinks/RiotPermalinkConstructor.js b/src/utils/permalinks/RiotPermalinkConstructor.js index 207e181a15..1b985e8190 100644 --- a/src/utils/permalinks/RiotPermalinkConstructor.js +++ b/src/utils/permalinks/RiotPermalinkConstructor.js @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import PermalinkConstructor from "./PermalinkConstructor"; +import PermalinkConstructor, {PermalinkParts} from "./PermalinkConstructor"; /** * Generates permalinks that self-reference the running webapp @@ -26,31 +26,31 @@ export default class RiotPermalinkConstructor extends PermalinkConstructor { constructor(riotUrl: string) { super(); this._riotUrl = riotUrl; + + if (!this._riotUrl.startsWith("http:") && !this._riotUrl.startsWith("https:")) { + throw new Error("Riot prefix URL does not appear to be an HTTP(S) URL"); + } } forEvent(roomId: string, eventId: string, serverCandidates: string[]): string { - // TODO: Fix URL - return `${this._riotUrl}/#/${roomId}/${eventId}${this.encodeServerCandidates(serverCandidates)}`; + return `${this._riotUrl}/#/room/${roomId}/${eventId}${this.encodeServerCandidates(serverCandidates)}`; } forRoom(roomIdOrAlias: string, serverCandidates: string[]): string { - // TODO: Fix URL - return `${this._riotUrl}/#/${roomIdOrAlias}${this.encodeServerCandidates(serverCandidates)}`; + return `${this._riotUrl}/#/room/${roomIdOrAlias}${this.encodeServerCandidates(serverCandidates)}`; } forUser(userId: string): string { - // TODO: Fix URL - return `${this._riotUrl}/#/${userId}`; + return `${this._riotUrl}/#/user/${userId}`; } forGroup(groupId: string): string { - // TODO: Fix URL - return `${this._riotUrl}/#/${groupId}`; + return `${this._riotUrl}/#/group/${groupId}`; } isPermalinkHost(testHost: string): boolean { - // TODO: Actual check - return testHost === this._riotUrl; + const parsedUrl = new URL(this._riotUrl); + return testHost === (parsedUrl.host || parsedUrl.hostname); // one of the hosts should match } encodeServerCandidates(candidates: string[]) { From 6656ef112f250df0c5c9ff9ab6d2fa73509baa31 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Mon, 30 Sep 2019 16:06:00 -0600 Subject: [PATCH 11/21] Rework /join to parse permalinks more safely They might not be matrix.to anymore, so parse them more correctly. --- src/SlashCommands.js | 49 +++++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/src/SlashCommands.js b/src/SlashCommands.js index 21c837030b..6a329761c8 100644 --- a/src/SlashCommands.js +++ b/src/SlashCommands.js @@ -23,8 +23,6 @@ import dis from './dispatcher'; import sdk from './index'; import {_t, _td} from './languageHandler'; import Modal from './Modal'; -import {MATRIXTO_URL_PATTERN} from "./linkify-matrix"; -import * as querystring from "querystring"; import MultiInviter from './utils/MultiInviter'; import { linkifyAndSanitizeHtml } from './HtmlUtils'; import QuestionDialog from "./components/views/dialogs/QuestionDialog"; @@ -34,6 +32,7 @@ import Promise from "bluebird"; import { getAddressType } from './UserAddress'; import { abbreviateUrl } from './utils/UrlUtils'; import { getDefaultIdentityServerUrl, useDefaultIdentityServer } from './utils/IdentityServerUtils'; +import {isPermalinkHost, parsePermalink} from "./utils/permalinks/RoomPermalinkCreator"; const singleMxcUpload = async () => { return new Promise((resolve) => { @@ -441,7 +440,19 @@ export const CommandMap = { const params = args.split(' '); if (params.length < 1) return reject(this.getUsage()); - const matrixToMatches = params[0].match(MATRIXTO_URL_PATTERN); + let isPermalink = false; + if (params[0].startsWith("http:") || params[0].startsWith("https:")) { + // It's at least a URL - try and pull out a hostname to check against the + // permalink handler + const parsedUrl = new URL(params[0]); + const hostname = parsedUrl.host || parsedUrl.hostname; // takes first non-falsey value + + // if we're using a Riot permalink handler, this will catch it before we get much further. + // see below where we make assumptions about parsing the URL. + if (isPermalinkHost(hostname)) { + isPermalink = true; + } + } if (params[0][0] === '#') { let roomAlias = params[0]; if (!roomAlias.includes(':')) { @@ -469,29 +480,25 @@ export const CommandMap = { auto_join: true, }); return success(); - } else if (matrixToMatches) { - let entity = matrixToMatches[1]; - let eventId = null; - let viaServers = []; + } else if (isPermalink) { + const permalinkParts = parsePermalink(params[0]); - if (entity[0] !== '!' && entity[0] !== '#') return reject(this.getUsage()); - - if (entity.indexOf('?') !== -1) { - const parts = entity.split('?'); - entity = parts[0]; - - const parsed = querystring.parse(parts[1]); - viaServers = parsed["via"]; - if (typeof viaServers === 'string') viaServers = [viaServers]; + // This check technically isn't needed because we already did our + // safety checks up above. However, for good measure, let's be sure. + if (!permalinkParts) { + return reject(this.getUsage()); } - // We quietly support event ID permalinks too - if (entity.indexOf('/$') !== -1) { - const parts = entity.split("/$"); - entity = parts[0]; - eventId = `$${parts[1]}`; + // If for some reason someone wanted to join a group or user, we should + // stop them now. + if (!permalinkParts.roomIdOrAlias) { + return reject(this.getUsage()); } + const entity = permalinkParts.roomIdOrAlias; + const viaServers = permalinkParts.viaServers; + const eventId = permalinkParts.eventId; + const dispatch = { action: 'view_room', auto_join: true, From ff4eee5239a31908e78b33e88810a659aa924c6c Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Mon, 30 Sep 2019 16:09:19 -0600 Subject: [PATCH 12/21] Minor cleanup of getPermalinkConstructor --- src/utils/permalinks/RoomPermalinkCreator.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/utils/permalinks/RoomPermalinkCreator.js b/src/utils/permalinks/RoomPermalinkCreator.js index 7df204a17b..82f92c80c9 100644 --- a/src/utils/permalinks/RoomPermalinkCreator.js +++ b/src/utils/permalinks/RoomPermalinkCreator.js @@ -287,8 +287,9 @@ export function isPermalinkHost(host: string): boolean { } function getPermalinkConstructor(): PermalinkConstructor { - if (SdkConfig.get()['permalinkPrefix'] && SdkConfig.get()['permalinkPrefix'] !== matrixtoBaseUrl) { - return new RiotPermalinkConstructor(SdkConfig.get()['permalinkPrefix']); + const riotPrefix = SdkConfig.get()['permalinkPrefix']; + if (riotPrefix && riotPrefix !== matrixtoBaseUrl) { + return new RiotPermalinkConstructor(riotPrefix); } return new SpecPermalinkConstructor(); From 2cb0b4903a1001dde8c85db908efec2440ab4870 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Mon, 30 Sep 2019 20:17:54 -0600 Subject: [PATCH 13/21] Converge on permalink processing for HtmlUtils and linkify-matrix --- src/HtmlUtils.js | 28 +++------------- src/linkify-matrix.js | 20 +++-------- src/utils/permalinks/RoomPermalinkCreator.js | 35 ++++++++++++++++++++ 3 files changed, 45 insertions(+), 38 deletions(-) diff --git a/src/HtmlUtils.js b/src/HtmlUtils.js index 6ede36ee81..7fc6908caf 100644 --- a/src/HtmlUtils.js +++ b/src/HtmlUtils.js @@ -2,6 +2,7 @@ Copyright 2015, 2016 OpenMarket Ltd Copyright 2017, 2018 New Vector Ltd Copyright 2019 Michael Telatynski <7t3chguy@gmail.com> +Copyright 2019 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -33,6 +34,7 @@ import url from 'url'; import EMOJIBASE from 'emojibase-data/en/compact.json'; import EMOJIBASE_REGEX from 'emojibase-regex'; +import {tryTransformPermalinkToLocalHref} from "./utils/permalinks/RoomPermalinkCreator"; linkifyMatrix(linkify); @@ -158,30 +160,10 @@ const transformTags = { // custom to matrix if (attribs.href) { attribs.target = '_blank'; // by default - let m; - // FIXME: horrible duplication with linkify-matrix - m = attribs.href.match(linkifyMatrix.VECTOR_URL_PATTERN); - if (m) { - attribs.href = m[1]; + const transformed = tryTransformPermalinkToLocalHref(attribs.href); + if (transformed !== attribs.href || attribs.href.match(linkifyMatrix.VECTOR_URL_PATTERN)) { + attribs.href = transformed; delete attribs.target; - } else { - m = attribs.href.match(linkifyMatrix.MATRIXTO_URL_PATTERN); - if (m) { - const entity = m[1]; - switch (entity[0]) { - case '@': - attribs.href = '#/user/' + entity; - break; - case '+': - attribs.href = '#/group/' + entity; - break; - case '#': - case '!': - attribs.href = '#/room/' + entity; - break; - } - delete attribs.target; - } } } attribs.rel = 'noopener'; // https://mathiasbynens.github.io/rel-noopener/ diff --git a/src/linkify-matrix.js b/src/linkify-matrix.js index 2d72b7fb41..0bed83ce84 100644 --- a/src/linkify-matrix.js +++ b/src/linkify-matrix.js @@ -1,5 +1,6 @@ /* Copyright 2015, 2016 OpenMarket Ltd +Copyright 2019 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -15,6 +16,7 @@ limitations under the License. */ import {baseUrl} from "./utils/permalinks/SpecPermalinkConstructor"; +import {tryTransformPermalinkToLocalHref} from "./utils/permalinks/RoomPermalinkCreator"; function matrixLinkify(linkify) { // Text tokens @@ -225,20 +227,8 @@ matrixLinkify.options = { case 'roomalias': case 'userid': case 'groupid': - return matrixLinkify.MATRIXTO_BASE_URL + '/#/' + href; default: { - // FIXME: horrible duplication with HtmlUtils' transform tags - let m = href.match(matrixLinkify.VECTOR_URL_PATTERN); - if (m) { - return m[1]; - } - m = href.match(matrixLinkify.MATRIXTO_URL_PATTERN); - if (m) { - const entity = m[1]; - if (matrixToEntityMap[entity[0]]) return matrixToEntityMap[entity[0]] + entity; - } - - return href; + return tryTransformPermalinkToLocalHref(href); } } }, @@ -249,8 +239,8 @@ matrixLinkify.options = { target: function(href, type) { if (type === 'url') { - if (href.match(matrixLinkify.VECTOR_URL_PATTERN) || - href.match(matrixLinkify.MATRIXTO_URL_PATTERN)) { + const transformed = tryTransformPermalinkToLocalHref(href); + if (transformed !== href || href.match(matrixLinkify.VECTOR_URL_PATTERN)) { return null; } else { return '_blank'; diff --git a/src/utils/permalinks/RoomPermalinkCreator.js b/src/utils/permalinks/RoomPermalinkCreator.js index 82f92c80c9..489a6c8b82 100644 --- a/src/utils/permalinks/RoomPermalinkCreator.js +++ b/src/utils/permalinks/RoomPermalinkCreator.js @@ -20,6 +20,7 @@ import utils from 'matrix-js-sdk/lib/utils'; import SpecPermalinkConstructor, {baseUrl as matrixtoBaseUrl} from "./SpecPermalinkConstructor"; import PermalinkConstructor, {PermalinkParts} from "./PermalinkConstructor"; import RiotPermalinkConstructor from "./RiotPermalinkConstructor"; +import * as matrixLinkify from "../../linkify-matrix"; const SdkConfig = require("../../SdkConfig"); @@ -286,6 +287,40 @@ export function isPermalinkHost(host: string): boolean { return getPermalinkConstructor().isPermalinkHost(host); } +/** + * Transforms a permalink (or possible permalink) into a local URL if possible. If + * the given permalink is found to not be a permalink, it'll be returned unaltered. + */ +export function tryTransformPermalinkToLocalHref(permalink: string): string { + if (!permalink.startsWith("http:") && !permalink.startsWith("https:")) { + return permalink; + } + + let m = permalink.match(matrixLinkify.VECTOR_URL_PATTERN); + if (m) { + return m[1]; + } + + // A bit of a hack to convert permalinks of unknown origin to Riot links + try { + const permalinkParts = parsePermalink(permalink); + if (permalinkParts) { + if (permalinkParts.roomIdOrAlias) { + const eventIdPart = permalinkParts.eventId ? `/${permalinkParts.eventId}` : ''; + permalink = `#/room/${permalinkParts.roomIdOrAlias}${eventIdPart}`; + } else if (permalinkParts.groupId) { + permalink = `#/group/${permalinkParts.groupId}`; + } else if (permalinkParts.userId) { + permalink = `#/user/${permalinkParts.userId}`; + } // else not a valid permalink for our purposes - do not handle + } + } catch (e) { + // Not an href we need to care about + } + + return permalink; +} + function getPermalinkConstructor(): PermalinkConstructor { const riotPrefix = SdkConfig.get()['permalinkPrefix']; if (riotPrefix && riotPrefix !== matrixtoBaseUrl) { From 2824f468d98c34b1304e5e294ea546253bff13c4 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Mon, 30 Sep 2019 20:27:51 -0600 Subject: [PATCH 14/21] Update pill processing to handle better permalinks --- src/components/views/elements/Pill.js | 32 +++++++++---------- .../views/rooms/MessageComposerInput.js | 13 +++----- src/utils/permalinks/RoomPermalinkCreator.js | 26 +++++++++++++++ 3 files changed, 45 insertions(+), 26 deletions(-) diff --git a/src/components/views/elements/Pill.js b/src/components/views/elements/Pill.js index 4c987a0095..abe570cdcd 100644 --- a/src/components/views/elements/Pill.js +++ b/src/components/views/elements/Pill.js @@ -1,6 +1,7 @@ /* Copyright 2017 Vector Creations Ltd Copyright 2018 New Vector Ltd +Copyright 2019 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -22,23 +23,21 @@ import classNames from 'classnames'; import { Room, RoomMember, MatrixClient } from 'matrix-js-sdk'; import PropTypes from 'prop-types'; import MatrixClientPeg from '../../../MatrixClientPeg'; -import { MATRIXTO_URL_PATTERN } from '../../../linkify-matrix'; import { getDisplayAliasForRoom } from '../../../Rooms'; import FlairStore from "../../../stores/FlairStore"; - -const REGEX_MATRIXTO = new RegExp(MATRIXTO_URL_PATTERN); +import {getPrimaryPermalinkEntity} from "../../../utils/permalinks/RoomPermalinkCreator"; // For URLs of matrix.to links in the timeline which have been reformatted by // HttpUtils transformTags to relative links. This excludes event URLs (with `[^\/]*`) -const REGEX_LOCAL_MATRIXTO = /^#\/(?:user|room|group)\/(([#!@+])[^/]*)$/; +const REGEX_LOCAL_PERMALINK = /^#\/(?:user|room|group)\/(([#!@+])[^/]*)$/; const Pill = createReactClass({ statics: { isPillUrl: (url) => { - return !!REGEX_MATRIXTO.exec(url); + return !!getPrimaryPermalinkEntity(url); }, isMessagePillUrl: (url) => { - return !!REGEX_LOCAL_MATRIXTO.exec(url); + return !!REGEX_LOCAL_PERMALINK.exec(url); }, roomNotifPos: (text) => { return text.indexOf("@room"); @@ -95,22 +94,21 @@ const Pill = createReactClass({ }, async componentWillReceiveProps(nextProps) { - let regex = REGEX_MATRIXTO; - if (nextProps.inMessage) { - regex = REGEX_LOCAL_MATRIXTO; - } - - let matrixToMatch; let resourceId; let prefix; if (nextProps.url) { - // Default to the empty array if no match for simplicity - // resource and prefix will be undefined instead of throwing - matrixToMatch = regex.exec(nextProps.url) || []; + if (nextProps.inMessage) { + // Default to the empty array if no match for simplicity + // resource and prefix will be undefined instead of throwing + const matrixToMatch = REGEX_LOCAL_PERMALINK.exec(nextProps.url) || []; - resourceId = matrixToMatch[1]; // The room/user ID - prefix = matrixToMatch[2]; // The first character of prefix + resourceId = matrixToMatch[1]; // The room/user ID + prefix = matrixToMatch[2]; // The first character of prefix + } else { + resourceId = getPrimaryPermalinkEntity(nextProps.url); + prefix = resourceId ? resourceId[0] : undefined; + } } const pillType = this.props.type || { diff --git a/src/components/views/rooms/MessageComposerInput.js b/src/components/views/rooms/MessageComposerInput.js index 917465aaaa..6696a91483 100644 --- a/src/components/views/rooms/MessageComposerInput.js +++ b/src/components/views/rooms/MessageComposerInput.js @@ -48,13 +48,11 @@ import Markdown from '../../../Markdown'; import MessageComposerStore from '../../../stores/MessageComposerStore'; import ContentMessages from '../../../ContentMessages'; -import {MATRIXTO_URL_PATTERN} from '../../../linkify-matrix'; - import EMOJIBASE from 'emojibase-data/en/compact.json'; import EMOTICON_REGEX from 'emojibase-regex/emoticon'; import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore"; -import {makeUserPermalink} from "../../../utils/permalinks/RoomPermalinkCreator"; +import {getPrimaryPermalinkEntity, makeUserPermalink} from "../../../utils/permalinks/RoomPermalinkCreator"; import ReplyPreview from "./ReplyPreview"; import RoomViewStore from '../../../stores/RoomViewStore'; import ReplyThread from "../elements/ReplyThread"; @@ -224,18 +222,15 @@ export default class MessageComposerInput extends React.Component { // special case links if (tag === 'a') { const href = el.getAttribute('href'); - let m; - if (href) { - m = href.match(MATRIXTO_URL_PATTERN); - } - if (m) { + const permalinkEntity = getPrimaryPermalinkEntity(href); + if (permalinkEntity) { return { object: 'inline', type: 'pill', data: { href, completion: el.innerText, - completionId: m[1], + completionId: permalinkEntity, }, }; } else { diff --git a/src/utils/permalinks/RoomPermalinkCreator.js b/src/utils/permalinks/RoomPermalinkCreator.js index 489a6c8b82..666729bacd 100644 --- a/src/utils/permalinks/RoomPermalinkCreator.js +++ b/src/utils/permalinks/RoomPermalinkCreator.js @@ -321,6 +321,32 @@ export function tryTransformPermalinkToLocalHref(permalink: string): string { return permalink; } +export function getPrimaryPermalinkEntity(permalink: string): string { + try { + let permalinkParts = parsePermalink(permalink); + + // If not a permalink, try the vector patterns. + if (!permalinkParts) { + let m = permalink.match(matrixLinkify.VECTOR_URL_PATTERN); + if (m) { + // A bit of a hack, but it gets the job done + const handler = new RiotPermalinkConstructor("http://localhost"); + const entityInfo = m[1].split('#').slice(1).join('#'); + permalinkParts = handler.parsePermalink(`http://localhost/#${entityInfo}`); + } + } + + if (!permalinkParts) return null; // not processable + if (permalinkParts.userId) return permalinkParts.userId; + if (permalinkParts.groupId) return permalinkParts.groupId; + if (permalinkParts.roomIdOrAlias) return permalinkParts.roomIdOrAlias; + } catch (e) { + // no entity - not a permalink + } + + return null; +} + function getPermalinkConstructor(): PermalinkConstructor { const riotPrefix = SdkConfig.get()['permalinkPrefix']; if (riotPrefix && riotPrefix !== matrixtoBaseUrl) { From ce0a534db1ed14565eee9d690c52098433671dc4 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Mon, 30 Sep 2019 20:37:24 -0600 Subject: [PATCH 15/21] Fix pills for CIDER too --- src/editor/deserialize.js | 9 +++------ src/editor/serialize.js | 3 ++- src/utils/permalinks/PermalinkConstructor.js | 4 ++++ src/utils/permalinks/RiotPermalinkConstructor.js | 10 ++++++++++ src/utils/permalinks/RoomPermalinkCreator.js | 4 ++++ src/utils/permalinks/SpecPermalinkConstructor.js | 4 ++++ 6 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/editor/deserialize.js b/src/editor/deserialize.js index 04edd4541c..2d725af4ac 100644 --- a/src/editor/deserialize.js +++ b/src/editor/deserialize.js @@ -15,11 +15,9 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { MATRIXTO_URL_PATTERN } from '../linkify-matrix'; import { walkDOMDepthFirst } from "./dom"; import { checkBlockNode } from "../HtmlUtils"; - -const REGEX_MATRIXTO = new RegExp(MATRIXTO_URL_PATTERN); +import {getPrimaryPermalinkEntity} from "../utils/permalinks/RoomPermalinkCreator"; function parseAtRoomMentions(text, partCreator) { const ATROOM = "@room"; @@ -41,9 +39,8 @@ function parseAtRoomMentions(text, partCreator) { function parseLink(a, partCreator) { const {href} = a; - const pillMatch = REGEX_MATRIXTO.exec(href) || []; - const resourceId = pillMatch[1]; // The room/user ID - const prefix = pillMatch[2]; // The first character of prefix + const resourceId = getPrimaryPermalinkEntity(href); // The room/user ID + const prefix = resourceId ? resourceId[0] : undefined; // First character of ID switch (prefix) { case "@": return partCreator.userPill(a.textContent, resourceId); diff --git a/src/editor/serialize.js b/src/editor/serialize.js index 07a1ad908e..734e2ba030 100644 --- a/src/editor/serialize.js +++ b/src/editor/serialize.js @@ -16,6 +16,7 @@ limitations under the License. */ import Markdown from '../Markdown'; +import {makeGenericPermalink} from "../utils/permalinks/RoomPermalinkCreator"; export function mdSerialize(model) { return model.parts.reduce((html, part) => { @@ -29,7 +30,7 @@ export function mdSerialize(model) { return html + part.text; case "room-pill": case "user-pill": - return html + `[${part.text}](https://matrix.to/#/${part.resourceId})`; + return html + `[${part.text}](${makeGenericPermalink(part.resourceId)})`; } }, ""); } diff --git a/src/utils/permalinks/PermalinkConstructor.js b/src/utils/permalinks/PermalinkConstructor.js index 507f16f795..f74c432bf0 100644 --- a/src/utils/permalinks/PermalinkConstructor.js +++ b/src/utils/permalinks/PermalinkConstructor.js @@ -35,6 +35,10 @@ export default class PermalinkConstructor { throw new Error("Not implemented"); } + forEntity(entityId: string): string { + throw new Error("Not implemented"); + } + isPermalinkHost(host: string): boolean { throw new Error("Not implemented"); } diff --git a/src/utils/permalinks/RiotPermalinkConstructor.js b/src/utils/permalinks/RiotPermalinkConstructor.js index 1b985e8190..f8c4cb361e 100644 --- a/src/utils/permalinks/RiotPermalinkConstructor.js +++ b/src/utils/permalinks/RiotPermalinkConstructor.js @@ -48,6 +48,16 @@ export default class RiotPermalinkConstructor extends PermalinkConstructor { return `${this._riotUrl}/#/group/${groupId}`; } + forEntity(entityId: string): string { + if (entityId[0] === '!' || entityId[0] === '#') { + return this.forRoom(entityId); + } else if (entityId[0] === '@') { + return this.forUser(entityId); + } else if (entityId[0] === '+') { + return this.forGroup(entityId); + } else throw new Error("Unrecognized entity"); + } + isPermalinkHost(testHost: string): boolean { const parsedUrl = new URL(this._riotUrl); return testHost === (parsedUrl.host || parsedUrl.hostname); // one of the hosts should match diff --git a/src/utils/permalinks/RoomPermalinkCreator.js b/src/utils/permalinks/RoomPermalinkCreator.js index 666729bacd..4cac095ca0 100644 --- a/src/utils/permalinks/RoomPermalinkCreator.js +++ b/src/utils/permalinks/RoomPermalinkCreator.js @@ -253,6 +253,10 @@ export class RoomPermalinkCreator { } } +export function makeGenericPermalink(entityId: string): string { + return getPermalinkConstructor().forEntity(entityId); +} + export function makeUserPermalink(userId) { return getPermalinkConstructor().forUser(userId); } diff --git a/src/utils/permalinks/SpecPermalinkConstructor.js b/src/utils/permalinks/SpecPermalinkConstructor.js index e4cff798a7..1c80ff8975 100644 --- a/src/utils/permalinks/SpecPermalinkConstructor.js +++ b/src/utils/permalinks/SpecPermalinkConstructor.js @@ -43,6 +43,10 @@ export default class SpecPermalinkConstructor extends PermalinkConstructor { return `${baseUrl}/#/${groupId}`; } + forEntity(entityId: string): string { + return `${baseUrl}/#/${entityId}`; + } + isPermalinkHost(testHost: string): boolean { return testHost === host; } From 6e6f8a13e10aa8b8eaa18f382e99f157fd36908d Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Mon, 30 Sep 2019 20:37:50 -0600 Subject: [PATCH 16/21] Handle BigEmoji permalinks better Now that permalinks could be not-matrix.to we should be safer in what we'll allow. --- src/HtmlUtils.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/HtmlUtils.js b/src/HtmlUtils.js index 7fc6908caf..3620eb2973 100644 --- a/src/HtmlUtils.js +++ b/src/HtmlUtils.js @@ -447,10 +447,12 @@ export function bodyToHtml(content, highlights, opts={}) { const match = BIGEMOJI_REGEX.exec(contentBodyTrimmed); emojiBody = match && match[0] && match[0].length === contentBodyTrimmed.length && // Prevent user pills expanding for users with only emoji in - // their username + // their username. Permalinks (links in pills) can be any URL + // now, so we just check for an HTTP-looking thing. ( content.formatted_body == undefined || - !content.formatted_body.includes("https://matrix.to/") + !content.formatted_body.includes("http:") || + !content.formatted_body.includes("https:") ); } From 6f5ccd4c12c366d73c43193e27cef916e7dea3e0 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Mon, 30 Sep 2019 20:38:03 -0600 Subject: [PATCH 17/21] Minor comment updates --- src/components/views/messages/TextualBody.js | 2 +- src/components/views/rooms/MessageComposerInput.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/views/messages/TextualBody.js b/src/components/views/messages/TextualBody.js index d3c53c8a33..5b5de531de 100644 --- a/src/components/views/messages/TextualBody.js +++ b/src/components/views/messages/TextualBody.js @@ -248,7 +248,7 @@ module.exports = createReactClass({ const url = node.getAttribute("href"); const host = url.match(/^https?:\/\/(.*?)(\/|$)/)[1]; - // never preview matrix.to links (if anything we should give a smart + // never preview permalinks (if anything we should give a smart // preview of the room/user they point to: nobody needs to be reminded // what the matrix.to site looks like). if (isPermalinkHost(host)) return false; diff --git a/src/components/views/rooms/MessageComposerInput.js b/src/components/views/rooms/MessageComposerInput.js index 6696a91483..3a51ac19e8 100644 --- a/src/components/views/rooms/MessageComposerInput.js +++ b/src/components/views/rooms/MessageComposerInput.js @@ -536,7 +536,7 @@ export default class MessageComposerInput extends React.Component { const textWithMdPills = this.plainWithMdPills.serialize(editorState); const markdown = new Markdown(textWithMdPills); - // HTML deserialize has custom rules to turn matrix.to links into pill objects. + // HTML deserialize has custom rules to turn permalinks into pill objects. return this.html.deserialize(markdown.toHTML()); } From fc66e69c02f6eccb97fe27dbcdc19170e2be447a Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Mon, 30 Sep 2019 20:39:58 -0600 Subject: [PATCH 18/21] Rename RoomPermalinkCreator -> Permalinks due to scope The file handles more than just a RoomPermalinkCreator, so we should name it accordingly. --- src/HtmlUtils.js | 2 +- src/SlashCommands.js | 2 +- src/autocomplete/CommunityProvider.js | 2 +- src/autocomplete/RoomProvider.js | 2 +- src/autocomplete/UserProvider.js | 2 +- src/components/structures/GroupView.js | 2 +- src/components/structures/RoomView.js | 2 +- src/components/views/dialogs/ShareDialog.js | 2 +- src/components/views/elements/Pill.js | 2 +- src/components/views/elements/ReplyThread.js | 2 +- src/components/views/messages/RoomCreate.js | 2 +- src/components/views/messages/TextualBody.js | 2 +- src/components/views/rooms/MessageComposer.js | 2 +- src/components/views/rooms/MessageComposerInput.js | 2 +- src/components/views/rooms/ReplyPreview.js | 2 +- src/components/views/rooms/SlateMessageComposer.js | 2 +- src/editor/deserialize.js | 2 +- src/editor/serialize.js | 2 +- src/linkify-matrix.js | 2 +- src/utils/permalinks/{RoomPermalinkCreator.js => Permalinks.js} | 0 test/utils/permalinks/RoomPermalinkCreator-test.js | 2 +- 21 files changed, 20 insertions(+), 20 deletions(-) rename src/utils/permalinks/{RoomPermalinkCreator.js => Permalinks.js} (100%) diff --git a/src/HtmlUtils.js b/src/HtmlUtils.js index 3620eb2973..e1bd85a7bb 100644 --- a/src/HtmlUtils.js +++ b/src/HtmlUtils.js @@ -34,7 +34,7 @@ import url from 'url'; import EMOJIBASE from 'emojibase-data/en/compact.json'; import EMOJIBASE_REGEX from 'emojibase-regex'; -import {tryTransformPermalinkToLocalHref} from "./utils/permalinks/RoomPermalinkCreator"; +import {tryTransformPermalinkToLocalHref} from "./utils/permalinks/Permalinks"; linkifyMatrix(linkify); diff --git a/src/SlashCommands.js b/src/SlashCommands.js index 6a329761c8..d9fe28cc6d 100644 --- a/src/SlashCommands.js +++ b/src/SlashCommands.js @@ -32,7 +32,7 @@ import Promise from "bluebird"; import { getAddressType } from './UserAddress'; import { abbreviateUrl } from './utils/UrlUtils'; import { getDefaultIdentityServerUrl, useDefaultIdentityServer } from './utils/IdentityServerUtils'; -import {isPermalinkHost, parsePermalink} from "./utils/permalinks/RoomPermalinkCreator"; +import {isPermalinkHost, parsePermalink} from "./utils/permalinks/Permalinks"; const singleMxcUpload = async () => { return new Promise((resolve) => { diff --git a/src/autocomplete/CommunityProvider.js b/src/autocomplete/CommunityProvider.js index 14c0116604..7358fdb8a9 100644 --- a/src/autocomplete/CommunityProvider.js +++ b/src/autocomplete/CommunityProvider.js @@ -23,7 +23,7 @@ import QueryMatcher from './QueryMatcher'; import {PillCompletion} from './Components'; import sdk from '../index'; import _sortBy from 'lodash/sortBy'; -import {makeGroupPermalink} from "../utils/permalinks/RoomPermalinkCreator"; +import {makeGroupPermalink} from "../utils/permalinks/Permalinks"; import type {Completion, SelectionRange} from "./Autocompleter"; import FlairStore from "../stores/FlairStore"; diff --git a/src/autocomplete/RoomProvider.js b/src/autocomplete/RoomProvider.js index 062fb5a5c5..3e87545b70 100644 --- a/src/autocomplete/RoomProvider.js +++ b/src/autocomplete/RoomProvider.js @@ -26,7 +26,7 @@ import {PillCompletion} from './Components'; import {getDisplayAliasForRoom} from '../Rooms'; import sdk from '../index'; import _sortBy from 'lodash/sortBy'; -import {makeRoomPermalink} from "../utils/permalinks/RoomPermalinkCreator"; +import {makeRoomPermalink} from "../utils/permalinks/Permalinks"; import type {Completion, SelectionRange} from "./Autocompleter"; const ROOM_REGEX = /\B#\S*/g; diff --git a/src/autocomplete/UserProvider.js b/src/autocomplete/UserProvider.js index d154e02a9d..6f3eb3e6b8 100644 --- a/src/autocomplete/UserProvider.js +++ b/src/autocomplete/UserProvider.js @@ -28,7 +28,7 @@ import _sortBy from 'lodash/sortBy'; import MatrixClientPeg from '../MatrixClientPeg'; import type {MatrixEvent, Room, RoomMember, RoomState} from 'matrix-js-sdk'; -import {makeUserPermalink} from "../utils/permalinks/RoomPermalinkCreator"; +import {makeUserPermalink} from "../utils/permalinks/Permalinks"; import type {Completion, SelectionRange} from "./Autocompleter"; const USER_REGEX = /\B@\S*/g; diff --git a/src/components/structures/GroupView.js b/src/components/structures/GroupView.js index 6c96dec04f..dd520bb7d4 100644 --- a/src/components/structures/GroupView.js +++ b/src/components/structures/GroupView.js @@ -36,7 +36,7 @@ import classnames from 'classnames'; import GroupStore from '../../stores/GroupStore'; import FlairStore from '../../stores/FlairStore'; import { showGroupAddRoomDialog } from '../../GroupAddressPicker'; -import {makeGroupPermalink, makeUserPermalink} from "../../utils/permalinks/RoomPermalinkCreator"; +import {makeGroupPermalink, makeUserPermalink} from "../../utils/permalinks/Permalinks"; import {Group} from "matrix-js-sdk"; const LONG_DESC_PLACEHOLDER = _td( diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index 057b1f2d80..4d52158dae 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -31,7 +31,7 @@ import Promise from 'bluebird'; import classNames from 'classnames'; import {Room} from "matrix-js-sdk"; import { _t } from '../../languageHandler'; -import {RoomPermalinkCreator} from '../../utils/permalinks/RoomPermalinkCreator'; +import {RoomPermalinkCreator} from '../../utils/permalinks/Permalinks'; import MatrixClientPeg from '../../MatrixClientPeg'; import ContentMessages from '../../ContentMessages'; diff --git a/src/components/views/dialogs/ShareDialog.js b/src/components/views/dialogs/ShareDialog.js index ae43ee2ae5..f6d5b65fd6 100644 --- a/src/components/views/dialogs/ShareDialog.js +++ b/src/components/views/dialogs/ShareDialog.js @@ -20,7 +20,7 @@ import {Room, User, Group, RoomMember, MatrixEvent} from 'matrix-js-sdk'; import sdk from '../../../index'; import { _t } from '../../../languageHandler'; import QRCode from 'qrcode-react'; -import {RoomPermalinkCreator, makeGroupPermalink, makeUserPermalink} from "../../../utils/permalinks/RoomPermalinkCreator"; +import {RoomPermalinkCreator, makeGroupPermalink, makeUserPermalink} from "../../../utils/permalinks/Permalinks"; import * as ContextualMenu from "../../structures/ContextualMenu"; const socials = [ diff --git a/src/components/views/elements/Pill.js b/src/components/views/elements/Pill.js index abe570cdcd..12830488b1 100644 --- a/src/components/views/elements/Pill.js +++ b/src/components/views/elements/Pill.js @@ -25,7 +25,7 @@ import PropTypes from 'prop-types'; import MatrixClientPeg from '../../../MatrixClientPeg'; import { getDisplayAliasForRoom } from '../../../Rooms'; import FlairStore from "../../../stores/FlairStore"; -import {getPrimaryPermalinkEntity} from "../../../utils/permalinks/RoomPermalinkCreator"; +import {getPrimaryPermalinkEntity} from "../../../utils/permalinks/Permalinks"; // For URLs of matrix.to links in the timeline which have been reformatted by // HttpUtils transformTags to relative links. This excludes event URLs (with `[^\/]*`) diff --git a/src/components/views/elements/ReplyThread.js b/src/components/views/elements/ReplyThread.js index 5c1d6a3ef4..fac0a71617 100644 --- a/src/components/views/elements/ReplyThread.js +++ b/src/components/views/elements/ReplyThread.js @@ -21,7 +21,7 @@ import PropTypes from 'prop-types'; import dis from '../../../dispatcher'; import {wantsDateSeparator} from '../../../DateUtils'; import {MatrixEvent, MatrixClient} from 'matrix-js-sdk'; -import {makeUserPermalink, RoomPermalinkCreator} from "../../../utils/permalinks/RoomPermalinkCreator"; +import {makeUserPermalink, RoomPermalinkCreator} from "../../../utils/permalinks/Permalinks"; import SettingsStore from "../../../settings/SettingsStore"; // This component does no cycle detection, simply because the only way to make such a cycle would be to diff --git a/src/components/views/messages/RoomCreate.js b/src/components/views/messages/RoomCreate.js index 282ba28b8a..9bb6fcc0d8 100644 --- a/src/components/views/messages/RoomCreate.js +++ b/src/components/views/messages/RoomCreate.js @@ -19,7 +19,7 @@ import PropTypes from 'prop-types'; import createReactClass from 'create-react-class'; import dis from '../../../dispatcher'; -import { RoomPermalinkCreator } from '../../../utils/permalinks/RoomPermalinkCreator'; +import { RoomPermalinkCreator } from '../../../utils/permalinks/Permalinks'; import { _t } from '../../../languageHandler'; import MatrixClientPeg from '../../../MatrixClientPeg'; diff --git a/src/components/views/messages/TextualBody.js b/src/components/views/messages/TextualBody.js index 5b5de531de..a9e0da143e 100644 --- a/src/components/views/messages/TextualBody.js +++ b/src/components/views/messages/TextualBody.js @@ -32,7 +32,7 @@ import SettingsStore from "../../../settings/SettingsStore"; import ReplyThread from "../elements/ReplyThread"; import {pillifyLinks} from '../../../utils/pillify'; import {IntegrationManagers} from "../../../integrations/IntegrationManagers"; -import {isPermalinkHost} from "../../../utils/permalinks/RoomPermalinkCreator"; +import {isPermalinkHost} from "../../../utils/permalinks/Permalinks"; module.exports = createReactClass({ displayName: 'TextualBody', diff --git a/src/components/views/rooms/MessageComposer.js b/src/components/views/rooms/MessageComposer.js index 4e7f8825ad..632ca53f82 100644 --- a/src/components/views/rooms/MessageComposer.js +++ b/src/components/views/rooms/MessageComposer.js @@ -23,7 +23,7 @@ import sdk from '../../../index'; import dis from '../../../dispatcher'; import RoomViewStore from '../../../stores/RoomViewStore'; import Stickerpicker from './Stickerpicker'; -import { makeRoomPermalink } from '../../../utils/permalinks/RoomPermalinkCreator'; +import { makeRoomPermalink } from '../../../utils/permalinks/Permalinks'; import ContentMessages from '../../../ContentMessages'; import classNames from 'classnames'; import E2EIcon from './E2EIcon'; diff --git a/src/components/views/rooms/MessageComposerInput.js b/src/components/views/rooms/MessageComposerInput.js index 3a51ac19e8..cc92f7c750 100644 --- a/src/components/views/rooms/MessageComposerInput.js +++ b/src/components/views/rooms/MessageComposerInput.js @@ -52,7 +52,7 @@ import EMOJIBASE from 'emojibase-data/en/compact.json'; import EMOTICON_REGEX from 'emojibase-regex/emoticon'; import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore"; -import {getPrimaryPermalinkEntity, makeUserPermalink} from "../../../utils/permalinks/RoomPermalinkCreator"; +import {getPrimaryPermalinkEntity, makeUserPermalink} from "../../../utils/permalinks/Permalinks"; import ReplyPreview from "./ReplyPreview"; import RoomViewStore from '../../../stores/RoomViewStore'; import ReplyThread from "../elements/ReplyThread"; diff --git a/src/components/views/rooms/ReplyPreview.js b/src/components/views/rooms/ReplyPreview.js index 97b29dddee..caf8feeea2 100644 --- a/src/components/views/rooms/ReplyPreview.js +++ b/src/components/views/rooms/ReplyPreview.js @@ -21,7 +21,7 @@ import { _t } from '../../../languageHandler'; import RoomViewStore from '../../../stores/RoomViewStore'; import SettingsStore from "../../../settings/SettingsStore"; import PropTypes from "prop-types"; -import {RoomPermalinkCreator} from "../../../utils/permalinks/RoomPermalinkCreator"; +import {RoomPermalinkCreator} from "../../../utils/permalinks/Permalinks"; function cancelQuoting() { dis.dispatch({ diff --git a/src/components/views/rooms/SlateMessageComposer.js b/src/components/views/rooms/SlateMessageComposer.js index 8b51f8266f..4bb2f29e61 100644 --- a/src/components/views/rooms/SlateMessageComposer.js +++ b/src/components/views/rooms/SlateMessageComposer.js @@ -25,7 +25,7 @@ import dis from '../../../dispatcher'; import RoomViewStore from '../../../stores/RoomViewStore'; import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore"; import Stickerpicker from './Stickerpicker'; -import { makeRoomPermalink } from '../../../utils/permalinks/RoomPermalinkCreator'; +import { makeRoomPermalink } from '../../../utils/permalinks/Permalinks'; import ContentMessages from '../../../ContentMessages'; import classNames from 'classnames'; diff --git a/src/editor/deserialize.js b/src/editor/deserialize.js index 2d725af4ac..d41e413dbc 100644 --- a/src/editor/deserialize.js +++ b/src/editor/deserialize.js @@ -17,7 +17,7 @@ limitations under the License. import { walkDOMDepthFirst } from "./dom"; import { checkBlockNode } from "../HtmlUtils"; -import {getPrimaryPermalinkEntity} from "../utils/permalinks/RoomPermalinkCreator"; +import {getPrimaryPermalinkEntity} from "../utils/permalinks/Permalinks"; function parseAtRoomMentions(text, partCreator) { const ATROOM = "@room"; diff --git a/src/editor/serialize.js b/src/editor/serialize.js index 734e2ba030..a55eed97da 100644 --- a/src/editor/serialize.js +++ b/src/editor/serialize.js @@ -16,7 +16,7 @@ limitations under the License. */ import Markdown from '../Markdown'; -import {makeGenericPermalink} from "../utils/permalinks/RoomPermalinkCreator"; +import {makeGenericPermalink} from "../utils/permalinks/Permalinks"; export function mdSerialize(model) { return model.parts.reduce((html, part) => { diff --git a/src/linkify-matrix.js b/src/linkify-matrix.js index 0bed83ce84..1ec2434bf0 100644 --- a/src/linkify-matrix.js +++ b/src/linkify-matrix.js @@ -16,7 +16,7 @@ limitations under the License. */ import {baseUrl} from "./utils/permalinks/SpecPermalinkConstructor"; -import {tryTransformPermalinkToLocalHref} from "./utils/permalinks/RoomPermalinkCreator"; +import {tryTransformPermalinkToLocalHref} from "./utils/permalinks/Permalinks"; function matrixLinkify(linkify) { // Text tokens diff --git a/src/utils/permalinks/RoomPermalinkCreator.js b/src/utils/permalinks/Permalinks.js similarity index 100% rename from src/utils/permalinks/RoomPermalinkCreator.js rename to src/utils/permalinks/Permalinks.js diff --git a/test/utils/permalinks/RoomPermalinkCreator-test.js b/test/utils/permalinks/RoomPermalinkCreator-test.js index 09bfaa3974..9b4afcfc05 100644 --- a/test/utils/permalinks/RoomPermalinkCreator-test.js +++ b/test/utils/permalinks/RoomPermalinkCreator-test.js @@ -18,7 +18,7 @@ import { makeRoomPermalink, makeUserPermalink, RoomPermalinkCreator, -} from "../../../src/utils/permalinks/RoomPermalinkCreator"; +} from "../../../src/utils/permalinks/Permalinks"; import * as testUtils from "../../test-utils"; function mockRoom(roomId, members, serverACL) { From 6b09c3e9e6db7ceaf1c5c2ebf3ba8d5c63dbfe87 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Mon, 30 Sep 2019 21:03:16 -0600 Subject: [PATCH 19/21] Appease the linter --- src/linkify-matrix.js | 7 ------- src/utils/permalinks/Permalinks.js | 6 ++++-- src/utils/permalinks/RiotPermalinkConstructor.js | 1 - 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/src/linkify-matrix.js b/src/linkify-matrix.js index 1ec2434bf0..fabd9d15ad 100644 --- a/src/linkify-matrix.js +++ b/src/linkify-matrix.js @@ -191,13 +191,6 @@ matrixLinkify.MATRIXTO_MD_LINK_PATTERN = '\\[([^\\]]*)\\]\\((?:https?://)?(?:www\\.)?matrix\\.to/#/([#@!+][^\\)]*)\\)'; matrixLinkify.MATRIXTO_BASE_URL= baseUrl; -const matrixToEntityMap = { - '@': '#/user/', - '#': '#/room/', - '!': '#/room/', - '+': '#/group/', -}; - matrixLinkify.options = { events: function(href, type) { switch (type) { diff --git a/src/utils/permalinks/Permalinks.js b/src/utils/permalinks/Permalinks.js index 4cac095ca0..19dcbd062a 100644 --- a/src/utils/permalinks/Permalinks.js +++ b/src/utils/permalinks/Permalinks.js @@ -294,13 +294,15 @@ export function isPermalinkHost(host: string): boolean { /** * Transforms a permalink (or possible permalink) into a local URL if possible. If * the given permalink is found to not be a permalink, it'll be returned unaltered. + * @param {string} permalink The permalink to try and transform. + * @returns {string} The transformed permalink or original URL if unable. */ export function tryTransformPermalinkToLocalHref(permalink: string): string { if (!permalink.startsWith("http:") && !permalink.startsWith("https:")) { return permalink; } - let m = permalink.match(matrixLinkify.VECTOR_URL_PATTERN); + const m = permalink.match(matrixLinkify.VECTOR_URL_PATTERN); if (m) { return m[1]; } @@ -331,7 +333,7 @@ export function getPrimaryPermalinkEntity(permalink: string): string { // If not a permalink, try the vector patterns. if (!permalinkParts) { - let m = permalink.match(matrixLinkify.VECTOR_URL_PATTERN); + const m = permalink.match(matrixLinkify.VECTOR_URL_PATTERN); if (m) { // A bit of a hack, but it gets the job done const handler = new RiotPermalinkConstructor("http://localhost"); diff --git a/src/utils/permalinks/RiotPermalinkConstructor.js b/src/utils/permalinks/RiotPermalinkConstructor.js index f8c4cb361e..176100aa8b 100644 --- a/src/utils/permalinks/RiotPermalinkConstructor.js +++ b/src/utils/permalinks/RiotPermalinkConstructor.js @@ -20,7 +20,6 @@ import PermalinkConstructor, {PermalinkParts} from "./PermalinkConstructor"; * Generates permalinks that self-reference the running webapp */ export default class RiotPermalinkConstructor extends PermalinkConstructor { - _riotUrl: string; constructor(riotUrl: string) { From f903f431ed63d8af01114f12b4ad93d65045ea7d Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Mon, 30 Sep 2019 21:08:34 -0600 Subject: [PATCH 20/21] Fix BigEmoji handling for permalinks OR doesn't give us the right thing, but AND does. --- src/HtmlUtils.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/HtmlUtils.js b/src/HtmlUtils.js index e1bd85a7bb..7a212b2497 100644 --- a/src/HtmlUtils.js +++ b/src/HtmlUtils.js @@ -451,8 +451,8 @@ export function bodyToHtml(content, highlights, opts={}) { // now, so we just check for an HTTP-looking thing. ( content.formatted_body == undefined || - !content.formatted_body.includes("http:") || - !content.formatted_body.includes("https:") + (!content.formatted_body.includes("http:") && + !content.formatted_body.includes("https:")) ); } From 0862ad029da494554caba4ab6f1a5f870199340a Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Mon, 30 Sep 2019 21:15:31 -0600 Subject: [PATCH 21/21] Fix permalinks test --- .../{RoomPermalinkCreator-test.js => Permalinks-test.js} | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) rename test/utils/permalinks/{RoomPermalinkCreator-test.js => Permalinks-test.js} (99%) diff --git a/test/utils/permalinks/RoomPermalinkCreator-test.js b/test/utils/permalinks/Permalinks-test.js similarity index 99% rename from test/utils/permalinks/RoomPermalinkCreator-test.js rename to test/utils/permalinks/Permalinks-test.js index 9b4afcfc05..27f06b44cb 100644 --- a/test/utils/permalinks/RoomPermalinkCreator-test.js +++ b/test/utils/permalinks/Permalinks-test.js @@ -1,5 +1,7 @@ /* Copyright 2018 New Vector Ltd +Copyright 2019 The Matrix.org Foundation C.I.C. + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at @@ -11,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import expect from 'expect/build/index'; +import expect from 'expect'; import peg from '../../../src/MatrixClientPeg'; import { makeGroupPermalink, @@ -62,7 +64,7 @@ function mockRoom(roomId, members, serverACL) { }; } -describe('matrix-to', function() { +describe('Permalinks', function() { let sandbox; beforeEach(function() {