diff --git a/frontend/iframe/platform/HomeserverApi.ts b/frontend/iframe/platform/HomeserverApi.ts deleted file mode 100644 index bf8692a6..00000000 --- a/frontend/iframe/platform/HomeserverApi.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { HomeServerApi as BaseHomeserverApi } from "hydrogen-web/src/matrix/net/HomeServerApi"; -import { RequestFunction } from "hydrogen-web/src/platform/types/types"; - -type Options = { - homeserver: string; - request: RequestFunction; -}; - -export class HomeserverApi extends BaseHomeserverApi{ - constructor(options: Options) { - super({ - ...options, - // @ts-ignore - reconnector: null, - }); - } - - async resolveRoomAlias(idOrAlias: string): Promise { - // If idOrAlias is an id, there's nothing for us to do. - if (idOrAlias.startsWith("!")) { - return idOrAlias; - } - - // @ts-ignore - const url = this._url("/directory/room/" + encodeURIComponent(idOrAlias)); - - // @ts-ignore - const request = this._unauthedRequest("GET", url); - - const data = await request.response(); - return data["room_id"]; - } -} diff --git a/frontend/iframe/platform/Navigation.ts b/frontend/iframe/platform/Navigation.ts index bb70bc0a..80ba12e5 100644 --- a/frontend/iframe/platform/Navigation.ts +++ b/frontend/iframe/platform/Navigation.ts @@ -9,6 +9,7 @@ export enum Section { SessionLoading = "loading", Session = "session", Error = "error", + UnknownRoom = "unknown-room", Redirecting = "redirecting", } diff --git a/frontend/iframe/platform/Platform.ts b/frontend/iframe/platform/Platform.ts index 542f19ac..9dbe0464 100644 --- a/frontend/iframe/platform/Platform.ts +++ b/frontend/iframe/platform/Platform.ts @@ -51,6 +51,10 @@ export class Platform extends BasePlatform { return super.config; } + get reconnector(): any { + return super.reconnector; + } + get settingsStorage(): SettingsStorage { return super.settingsStorage; } diff --git a/frontend/iframe/viewmodels/RootViewModel.ts b/frontend/iframe/viewmodels/RootViewModel.ts index 624446cb..52488ff1 100644 --- a/frontend/iframe/viewmodels/RootViewModel.ts +++ b/frontend/iframe/viewmodels/RootViewModel.ts @@ -4,10 +4,12 @@ import { LogoutViewModel } from "hydrogen-web/src/domain/LogoutViewModel"; import { SegmentType } from "hydrogen-web/src/domain/navigation"; import { SessionLoadViewModel } from "hydrogen-web/src/domain/SessionLoadViewModel"; import { SessionPickerViewModel } from "hydrogen-web/src/domain/SessionPickerViewModel"; +import { UnknownRoomViewModel } from "hydrogen-web/src/domain/session/room/UnknownRoomViewModel"; import { Options as BaseOptions, ViewModel } from "hydrogen-web/src/domain/ViewModel"; import { Client } from "hydrogen-web/src/matrix/Client.js"; -import { HomeserverApi } from "../platform/HomeserverApi"; +import { HomeServerApi } from "hydrogen-web/src/matrix/net/HomeServerApi"; import { allSections, Section } from "../platform/Navigation"; +import { lookupHomeserver } from "hydrogen-web/src/matrix/well-known"; import { Platform } from "../platform/Platform"; import { SessionViewModel } from "./SessionViewModel"; @@ -21,6 +23,7 @@ export class RootViewModel extends ViewModel { private _sessionPickerViewModel: SessionPickerViewModel | undefined; private _sessionLoadViewModel: SessionLoadViewModel | undefined; private _sessionViewModel: SessionViewModel | undefined; + private _unknownRoomViewModel: UnknownRoomViewModel | undefined; private _pendingClient: Client; private readonly _singleRoomIdOrAlias: string | undefined; private _resolvedSingleRoomId: string | undefined; @@ -45,6 +48,8 @@ export class RootViewModel extends ViewModel { return Section.SessionLoading; } else if (this._sessionViewModel) { return Section.Session; + } else if (this._unknownRoomViewModel) { + return Section.UnknownRoom; } else { return Section.Redirecting; } @@ -70,6 +75,10 @@ export class RootViewModel extends ViewModel { return this._sessionLoadViewModel; } + public get unknownRoomViewModel(): UnknownRoomViewModel | undefined { + return this._unknownRoomViewModel; + } + public get sessionViewModel(): SessionViewModel | undefined { return this._sessionViewModel; } @@ -100,6 +109,17 @@ export class RootViewModel extends ViewModel { const sessionId = this.navigation.path.get("session")?.value; const loginToken = this.navigation.path.get("sso")?.value; + if (this._singleRoomIdOrAlias && !this._resolvedSingleRoomId) { + try { + this._resolvedSingleRoomId = await this.resolveRoomAlias(this._singleRoomIdOrAlias); + } catch (error) { + // Something went wrong when navigating to the room. + // We swallow the error and fallback to non-single-room mode. + console.warn(error); + this._resolvedSingleRoomId = undefined; + } + } + if (isLogin) { if (this.activeSection !== Section.Login) { this._showLogin(undefined); @@ -117,21 +137,7 @@ export class RootViewModel extends ViewModel { void this._showPicker(); } } else if (sessionId) { - if (this._singleRoomIdOrAlias && !this._resolvedSingleRoomId) { - // We're in single-room mode but haven't resolved the room alias yet. - try { - this._resolvedSingleRoomId = await this.resolveRoomAlias(sessionId, this._singleRoomIdOrAlias); - } catch (error) { - // Something went wrong when navigating to the room. - // We swallow the error and fallback to non-single-room mode. - console.warn(error); - this._resolvedSingleRoomId = undefined; - this.emitChange("singleRoomMode"); - } - } - if (this._resolvedSingleRoomId) { - this.emitChange("singleRoomMode"); this.navigation.push("room", this._resolvedSingleRoomId); } @@ -161,6 +167,10 @@ export class RootViewModel extends ViewModel { if (this.singleRoomMode || !(shouldRestoreLastUrl && this.urlRouter.tryRestoreLastUrl())) { const sessionInfos = await this.platform.sessionInfoStorage.getAll(); if (sessionInfos.length === 0) { + if (this._resolvedSingleRoomId) { + await this._showUnknownRoom(this._resolvedSingleRoomId); + return; + } this.navigation.push(Section.Login); } else if (sessionInfos.length === 1) { this.navigation.push(Section.Session, sessionInfos[0].id); @@ -169,23 +179,63 @@ export class RootViewModel extends ViewModel { } } } catch (err) { + console.error(err); this._setSection(() => this._error = err); } } } - private async resolveRoomAlias(sessionId: string, roomIdOrAlias: string): Promise { + private async resolveRoomAlias(roomIdOrAlias: string, sessionId?: string): Promise { + if (roomIdOrAlias.startsWith('!')) { + return roomIdOrAlias; + } + + let sessionInfo; + if (sessionId) { + sessionInfo = await this.platform.sessionInfoStorage.get(sessionId); + } + let homeserver: string; + let accessToken: string; + if (sessionInfo) { + homeserver = sessionInfo.homeserver; + accessToken = sessionInfo.accessToken; + } else { + homeserver = await lookupHomeserver(roomIdOrAlias.split(':')[1], this.platform.request); + accessToken = ''; + } + + const homeserverApi = new HomeServerApi({ + homeserver: homeserver, + request: this.platform.request, + accessToken: accessToken, + reconnector: this.platform.reconnector, + }); + + let response = await homeserverApi.resolveRoomAlias(roomIdOrAlias).response(); + return response.room_id; + } + + private async isWorldReadableRoom(roomId: string, sessionId: string): Promise { const sessionInfo = await this.platform.sessionInfoStorage.get(sessionId); if (!sessionInfo) { - throw new Error(`Could not find session for id ${sessionId}`); + console.error(`Could not find session for id ${sessionId}`); + return false; } - const homeserverApi = new HomeserverApi({ - homeserver: sessionInfo.homeserver, - request: this.platform.request + const homeserver = await lookupHomeserver(roomId.split(':')[1], this.platform.request); + const homeserverApi = new HomeServerApi({ + homeserver: homeserver, + request: this.platform.request, + accessToken: sessionInfo.accessToken, + reconnector: this.platform.reconnector, }); - return await homeserverApi.resolveRoomAlias(roomIdOrAlias); + return homeserverApi.state(roomId, 'm.room.history_visibility', '').response().then( + response => response.history_visibility === 'world_readable' + ).catch(err => { + console.error(err); + return false; + }); } private _showLogin(loginToken: string | undefined) { @@ -255,6 +305,29 @@ export class RootViewModel extends ViewModel { }); } + private async _showUnknownRoom(roomId: string) { + const client = new Client(this.platform); + let chosenSession; + + let sessionInfos = await this.platform.sessionInfoStorage.getAll(); + if (sessionInfos.length === 0) { + const homeserver = await lookupHomeserver(roomId.split(':')[1], this.platform.request); + await client.doGuestLogin(homeserver); + } else { + await client.startWithExistingSession(chosenSession.id); + } + + this._setSection(() => { + this._unknownRoomViewModel = new UnknownRoomViewModel(this.childOptions({ + roomIdOrAlias: roomId, + session: client.session, + isWorldReadablePromise: this.isWorldReadableRoom(roomId, client.sessionId), + })); + }); + + this.navigation.push("session", client.sessionId); + } + private _setSection(setter: Function) { // Clear all members the activeSection depends on. this._error = undefined; diff --git a/frontend/iframe/views/RootView.ts b/frontend/iframe/views/RootView.ts index 053c5398..571cb613 100644 --- a/frontend/iframe/views/RootView.ts +++ b/frontend/iframe/views/RootView.ts @@ -4,6 +4,7 @@ import { TemplateView } from "hydrogen-web/src/platform/web/ui/general/TemplateV import { LoginView } from "hydrogen-web/src/platform/web/ui/login/LoginView"; import { SessionLoadView } from "hydrogen-web/src/platform/web/ui/login/SessionLoadView"; import { SessionPickerView } from "hydrogen-web/src/platform/web/ui/login/SessionPickerView"; +import { UnknownRoomView } from "hydrogen-web/src/platform/web/ui/session/room/UnknownRoomView"; import { LogoutView } from "hydrogen-web/src/platform/web/ui/LogoutView"; import { Section } from "../platform/Navigation"; import { RootViewModel } from "../viewmodels/RootViewModel"; @@ -36,6 +37,8 @@ export class RootView extends TemplateView { return new StaticView(t => t.p("Redirecting...")); case Section.SessionLoading: return new SessionLoadView(vm.sessionLoadViewModel); + case Section.UnknownRoom: + return new UnknownRoomView(vm.unknownRoomViewModel); case Section.Error: return new StaticView(t => { return t.div({ className: "StatusView" }, [ diff --git a/frontend/iframe/views/SessionView.ts b/frontend/iframe/views/SessionView.ts index 74b7229e..163a39c1 100644 --- a/frontend/iframe/views/SessionView.ts +++ b/frontend/iframe/views/SessionView.ts @@ -14,6 +14,7 @@ import { SessionView as BaseSessionView } from "hydrogen-web/src/platform/web/ui import { SettingsView } from "hydrogen-web/src/platform/web/ui/session/settings/SettingsView"; import { SessionViewModel } from "../viewmodels/SessionViewModel"; import { RoomView } from "./RoomView"; +import { WorldReadableRoomView } from "hydrogen-web/src/platform/web/ui/session/room/WorldReadableRoomView"; export class SessionView extends BaseSessionView { constructor(value?: SessionViewModel) { @@ -46,6 +47,8 @@ export class SessionView extends BaseSessionView { return new RoomView(vm.currentRoomViewModel, viewClassForTile); } else if (vm.currentRoomViewModel.kind === "roomBeingCreated") { return new RoomBeingCreatedView(vm.currentRoomViewModel); + } else if (vm.currentRoomViewModel.kind === "preview") { + return new WorldReadableRoomView(vm.currentRoomViewModel); } else { return new UnknownRoomView(vm.currentRoomViewModel); } diff --git a/package.json b/package.json index d3de4feb..62287d36 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ "dependencies": { "@wordpress/compose": "^5.17.0", "bs58": "^5.0.0", - "hydrogen-web": "vector-im/hydrogen-web#v0.3.8", + "hydrogen-web": "Automattic/hydrogen-web#chatrix-0.7.0", "node-html-parser": "^4.0.0" }, "resolutions": { diff --git a/yarn.lock b/yarn.lock index db4d344e..9d37852d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3801,11 +3801,16 @@ core-js-pure@^3.25.1, core-js-pure@^3.8.1: resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.25.3.tgz#66ac5bfa5754b47fdfd14f3841c5ed21c46db608" integrity sha512-T/7qvgv70MEvRkZ8p6BasLZmOVYKzOaWNBEHAU8FmveCJkl4nko2quqPQOmy6AJIp5MBanhz9no3A94NoRb0XA== -core-js@^3.19.1, core-js@^3.6.5: +core-js@^3.19.1: version "3.25.3" resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.25.3.tgz#cbc2be50b5ddfa7981837bd8c41639f27b166593" integrity sha512-y1hvKXmPHvm5B7w4ln1S4uc9eV/O5+iFExSRUimnvIph11uaizFR8LFMdONN8hG3P2pipUfX4Y/fR8rAEtcHcQ== +core-js@^3.6.5: + version "3.29.0" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.29.0.tgz#0273e142b67761058bcde5615c503c7406b572d6" + integrity sha512-VG23vuEisJNkGl6XQmFJd3rEG/so/CNatqeE+7uZAwTSwFeB/qaO0be8xZYUNWprJ/GIwL8aMt9cj1kvbpTZhg== + core-util-is@~1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" @@ -4243,9 +4248,9 @@ domhandler@^5.0.1, domhandler@^5.0.2, domhandler@^5.0.3: domelementtype "^2.3.0" dompurify@^2.3.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.4.0.tgz#c9c88390f024c2823332615c9e20a453cf3825dd" - integrity sha512-Be9tbQMZds4a3C6xTmz68NlMfeONA//4dOavl/1rNw50E+/QO0KVpbcU0PcaW0nsQxurXls9ZocqFxk8R2mWEA== + version "2.4.5" + resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.4.5.tgz#0e89a27601f0bad978f9a924e7a05d5d2cccdd87" + integrity sha512-jggCCd+8Iqp4Tsz0nIvpcb22InKEBrGz5dw3EQJMs8HPJDsKbFIO3STYtAvCfDx26Muevn1MHVI0XxjgFfmiSA== domutils@^2.8.0: version "2.8.0" @@ -5715,9 +5720,9 @@ human-signals@^2.1.0: resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== -hydrogen-web@vector-im/hydrogen-web#v0.3.8: +hydrogen-web@Automattic/hydrogen-web#chatrix-0.7.0: version "0.3.8" - resolved "https://codeload.github.com/vector-im/hydrogen-web/tar.gz/8c74e54f9d644a6de47b4a7927396911510df80e" + resolved "https://codeload.github.com/Automattic/hydrogen-web/tar.gz/c50ff3faca14628b98457b91f3b8be133d28c761" dependencies: "@matrix-org/olm" "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.8.tgz" another-json "^0.2.0"