summaryrefslogtreecommitdiff
path: root/includes/external/matrix/node_modules/matrix-widget-api/src/transport
diff options
context:
space:
mode:
authorRaindropsSys <contact@minteck.org>2023-04-24 14:03:36 +0200
committerRaindropsSys <contact@minteck.org>2023-04-24 14:03:36 +0200
commit633c92eae865e957121e08de634aeee11a8b3992 (patch)
tree09d881bee1dae0b6eee49db1dfaf0f500240606c /includes/external/matrix/node_modules/matrix-widget-api/src/transport
parentc4657e4509733699c0f26a3c900bab47e915d5a0 (diff)
downloadpluralconnect-633c92eae865e957121e08de634aeee11a8b3992.tar.gz
pluralconnect-633c92eae865e957121e08de634aeee11a8b3992.tar.bz2
pluralconnect-633c92eae865e957121e08de634aeee11a8b3992.zip
Updated 18 files, added 1692 files and deleted includes/system/compare.inc (automated)
Diffstat (limited to 'includes/external/matrix/node_modules/matrix-widget-api/src/transport')
-rw-r--r--includes/external/matrix/node_modules/matrix-widget-api/src/transport/ITransport.ts104
-rw-r--r--includes/external/matrix/node_modules/matrix-widget-api/src/transport/PostmessageTransport.ts203
2 files changed, 307 insertions, 0 deletions
diff --git a/includes/external/matrix/node_modules/matrix-widget-api/src/transport/ITransport.ts b/includes/external/matrix/node_modules/matrix-widget-api/src/transport/ITransport.ts
new file mode 100644
index 0000000..b3b2e9a
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-widget-api/src/transport/ITransport.ts
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2020 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 { EventEmitter } from "events";
+import {
+ IWidgetApiAcknowledgeResponseData,
+ IWidgetApiRequest,
+ IWidgetApiRequestData,
+ IWidgetApiResponse,
+ IWidgetApiResponseData,
+ WidgetApiAction,
+} from "..";
+
+/**
+ * A transport for widget requests/responses. All actions
+ * get raised through a "message" CustomEvent with detail
+ * of the IWidgetApiRequest.
+ */
+export interface ITransport extends EventEmitter {
+ /**
+ * True if the transport is ready to start sending, false otherwise.
+ */
+ readonly ready: boolean;
+
+ /**
+ * The widget ID, if known. If not known, null.
+ */
+ readonly widgetId: string | null;
+
+ /**
+ * If true, the transport will refuse requests from origins other than the
+ * widget's current origin. This is intended to be used only by widgets which
+ * need excess security.
+ */
+ strictOriginCheck: boolean;
+
+ /**
+ * The origin the transport should be replying/sending to. If not known, leave
+ * null.
+ */
+ targetOrigin: string | null;
+
+ /**
+ * The number of seconds an outbound request is allowed to take before it
+ * times out.
+ */
+ timeoutSeconds: number;
+
+ /**
+ * Starts the transport for listening
+ */
+ start(): void;
+
+ /**
+ * Stops the transport. It cannot be re-started.
+ */
+ stop(): void;
+
+ /**
+ * Sends a request to the remote end.
+ * @param {WidgetApiAction} action The action to send.
+ * @param {IWidgetApiRequestData} data The request data.
+ * @returns {Promise<IWidgetApiResponseData>} A promise which resolves
+ * to the remote end's response, or throws with an Error if the request
+ * failed.
+ */
+ send<T extends IWidgetApiRequestData, R extends IWidgetApiResponseData = IWidgetApiAcknowledgeResponseData>(
+ action: WidgetApiAction,
+ data: T
+ ): Promise<R>;
+
+ /**
+ * Sends a request to the remote end. This is similar to the send() function
+ * however this version returns the full response rather than just the response
+ * data.
+ * @param {WidgetApiAction} action The action to send.
+ * @param {IWidgetApiRequestData} data The request data.
+ * @returns {Promise<IWidgetApiResponseData>} A promise which resolves
+ * to the remote end's response, or throws with an Error if the request
+ * failed.
+ */
+ sendComplete<T extends IWidgetApiRequestData, R extends IWidgetApiResponse>(action: WidgetApiAction, data: T)
+ : Promise<R>;
+
+ /**
+ * Replies to a request.
+ * @param {IWidgetApiRequest} request The request to reply to.
+ * @param {IWidgetApiResponseData} responseData The response data to reply with.
+ */
+ reply<T extends IWidgetApiResponseData>(request: IWidgetApiRequest, responseData: T): void;
+}
diff --git a/includes/external/matrix/node_modules/matrix-widget-api/src/transport/PostmessageTransport.ts b/includes/external/matrix/node_modules/matrix-widget-api/src/transport/PostmessageTransport.ts
new file mode 100644
index 0000000..9f86aa5
--- /dev/null
+++ b/includes/external/matrix/node_modules/matrix-widget-api/src/transport/PostmessageTransport.ts
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2020 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 { EventEmitter } from "events";
+import { ITransport } from "./ITransport";
+import {
+ invertedDirection,
+ isErrorResponse,
+ IWidgetApiErrorResponseData,
+ IWidgetApiRequest,
+ IWidgetApiRequestData,
+ IWidgetApiResponse,
+ IWidgetApiResponseData,
+ WidgetApiAction,
+ WidgetApiDirection,
+ WidgetApiToWidgetAction,
+} from "..";
+
+interface IOutboundRequest {
+ request: IWidgetApiRequest;
+ resolve: (response: IWidgetApiResponse) => void;
+ reject: (err: Error) => void;
+}
+
+/**
+ * Transport for the Widget API over postMessage.
+ */
+export class PostmessageTransport extends EventEmitter implements ITransport {
+ public strictOriginCheck = false;
+ public targetOrigin = "*";
+ public timeoutSeconds = 10;
+
+ private _ready = false;
+ private _widgetId: string | null = null;
+ private outboundRequests = new Map<string, IOutboundRequest | null>();
+ private stopController = new AbortController();
+
+ public get ready(): boolean {
+ return this._ready;
+ }
+
+ public get widgetId(): string | null {
+ return this._widgetId || null;
+ }
+
+ public constructor(
+ private sendDirection: WidgetApiDirection,
+ private initialWidgetId: string | null,
+ private transportWindow: Window,
+ private inboundWindow: Window,
+ ) {
+ super();
+ this._widgetId = initialWidgetId;
+ }
+
+ private get nextRequestId(): string {
+ const idBase = `widgetapi-${Date.now()}`;
+ let index = 0;
+ let id = idBase;
+ while (this.outboundRequests.has(id)) {
+ id = `${idBase}-${index++}`;
+ }
+
+ // reserve the ID
+ this.outboundRequests.set(id, null);
+
+ return id;
+ }
+
+ private sendInternal(message: IWidgetApiRequest | IWidgetApiResponse) {
+ console.log(`[PostmessageTransport] Sending object to ${this.targetOrigin}: `, message);
+ this.transportWindow.postMessage(message, this.targetOrigin);
+ }
+
+ public reply<T extends IWidgetApiResponseData>(request: IWidgetApiRequest, responseData: T) {
+ return this.sendInternal(<IWidgetApiResponse>{
+ ...request,
+ response: responseData,
+ });
+ }
+
+ public send<T extends IWidgetApiRequestData, R extends IWidgetApiResponseData>(
+ action: WidgetApiAction, data: T,
+ ): Promise<R> {
+ return this.sendComplete(action, data).then(r => <R>r.response);
+ }
+
+ public sendComplete<T extends IWidgetApiRequestData, R extends IWidgetApiResponse>(
+ action: WidgetApiAction, data: T,
+ ): Promise<R> {
+ if (!this.ready || !this.widgetId) {
+ return Promise.reject(new Error("Not ready or unknown widget ID"));
+ }
+ const request: IWidgetApiRequest = {
+ api: this.sendDirection,
+ widgetId: this.widgetId,
+ requestId: this.nextRequestId,
+ action: action,
+ data: data,
+ };
+ if (action === WidgetApiToWidgetAction.UpdateVisibility) {
+ request['visible'] = data['visible'];
+ }
+ return new Promise<R>((prResolve, prReject) => {
+ const resolve = (response: IWidgetApiResponse) => {
+ cleanUp();
+ prResolve(<R>response);
+ };
+ const reject = (err: Error) => {
+ cleanUp();
+ prReject(err);
+ };
+
+ const timerId = setTimeout(
+ () => reject(new Error("Request timed out")),
+ (this.timeoutSeconds || 1) * 1000,
+ );
+
+ const onStop = () => reject(new Error("Transport stopped"));
+ this.stopController.signal.addEventListener("abort", onStop);
+
+ const cleanUp = () => {
+ this.outboundRequests.delete(request.requestId);
+ clearTimeout(timerId);
+ this.stopController.signal.removeEventListener("abort", onStop);
+ };
+
+ this.outboundRequests.set(request.requestId, { request, resolve, reject });
+ this.sendInternal(request);
+ });
+ }
+
+ public start() {
+ this.inboundWindow.addEventListener("message", (ev: MessageEvent) => {
+ this.handleMessage(ev);
+ });
+ this._ready = true;
+ }
+
+ public stop() {
+ this._ready = false;
+ this.stopController.abort();
+ }
+
+ private handleMessage(ev: MessageEvent) {
+ if (this.stopController.signal.aborted) return;
+ if (!ev.data) return; // invalid event
+
+ if (this.strictOriginCheck && ev.origin !== window.origin) return; // bad origin
+
+ // treat the message as a response first, then downgrade to a request
+ const response = <IWidgetApiResponse>ev.data;
+ if (!response.action || !response.requestId || !response.widgetId) return; // invalid request/response
+
+ if (!response.response) {
+ // it's a request
+ const request = <IWidgetApiRequest>response;
+ if (request.api !== invertedDirection(this.sendDirection)) return; // wrong direction
+ this.handleRequest(request);
+ } else {
+ // it's a response
+ if (response.api !== this.sendDirection) return; // wrong direction
+ this.handleResponse(response);
+ }
+ }
+
+ private handleRequest(request: IWidgetApiRequest) {
+ if (this.widgetId) {
+ if (this.widgetId !== request.widgetId) return; // wrong widget
+ } else {
+ this._widgetId = request.widgetId;
+ }
+
+ this.emit("message", new CustomEvent("message", {detail: request}));
+ }
+
+ private handleResponse(response: IWidgetApiResponse) {
+ if (response.widgetId !== this.widgetId) return; // wrong widget
+
+ const req = this.outboundRequests.get(response.requestId);
+ if (!req) return; // response to an unknown request
+
+ if (isErrorResponse(response.response)) {
+ const err = <IWidgetApiErrorResponseData>response.response;
+ req.reject(new Error(err.error.message));
+ } else {
+ req.resolve(response);
+ }
+ }
+}