Skip to content
This repository was archived by the owner on Jan 30, 2025. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
"typescript": "^4.6.3"
},
"dependencies": {
"@babel/runtime": "^7.17.9"
"@babel/runtime": "^7.17.9",
"matrix-widget-api": "^1.1.1"
}
}
62 changes: 62 additions & 0 deletions src/RuntimeModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ limitations under the License.
*/

import { EventEmitter } from "events";
import { Capability, Widget } from "matrix-widget-api";

import { ModuleApi } from "./ModuleApi";
import { PlainSubstitution } from "./types/translations";
Expand All @@ -41,4 +42,65 @@ export abstract class RuntimeModule extends EventEmitter {
protected t(s: string, variables?: Record<string, PlainSubstitution>): string {
return this.moduleApi.translateString(s, variables);
}

/**
* Gets widget permissions behaviour to preapprove permissions.
* @returns instance of IWidgetPermissions with custom behaviour or undefined for default
*/
public getWidgetPermissions(): WidgetPermissions | undefined {
return undefined;
}
}

/**
* Represents widget permissions behaviour to preapprove permissions that can be customized by module.
*/
export interface WidgetPermissions {
/**
* Approves the widget embedding.
* This will be used to embed certain widgets without prompting the user.
* @param {Widget} widget The widget to approve embedding for.
* @returns {boolean} true if embedding is preapproved, false otherwise
*/
isEmbeddingPreapproved(widget: Widget): boolean;

/**
* Approves the widget for identity token.
* This will be used to give certain widgets an identity token without having to
* prompt the user to approve it.
* @param {Widget} widget The widget to approve identity request for.
* @returns {boolean} Resolves to true if identity request is preapproved, false otherwise
*/
isIdentityRequestPreapproved(widget: Widget): Promise<boolean>;

/**
* Approves the widget for capabilities that it requested, if any can be
* approved. Typically this will be used to give certain widgets capabilities
* without having to prompt the user to approve them. This cannot reject
* capabilities that Element will be automatically granting, such as the
* ability for Jitsi widgets to stay on screen - those will be approved
* regardless.
* @param {Widget} widget The widget to approve capabilities for.
* @param {Set<Capability>} requestedCapabilities The capabilities the widget requested.
* @returns {Set<Capability>} Resolves to the capabilities that are approved for use
* by the widget. If none are approved, this should return an empty Set.
*/
preapproveCapabilities(widget: Widget, requestedCapabilities: Set<Capability>): Promise<Set<Capability>>;
}

/**
* Defines a default widget permissions behaviour. Can be extended to customize.
*/
export class DefaultWidgetPermissions implements WidgetPermissions {
isEmbeddingPreapproved(widget: Widget): boolean {
return false;
}

async isIdentityRequestPreapproved(widget: Widget): Promise<boolean> {
return false;
}

async preapproveCapabilities(widget: Widget, requestedCapabilities: Set<Capability>): Promise<Set<Capability>> {
return new Set();
}
}
62 changes: 62 additions & 0 deletions test/RuntimeModule.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
Copyright 2023 Mikhail Aheichyk
Copyright 2023 Nordeck IT + Consulting GmbH.

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 {Capability, Widget, MatrixWidgetType} from "matrix-widget-api";

import {DefaultWidgetPermissions} from "../src/RuntimeModule";

describe("RuntimeModule", () => {
describe("WidgetPermissions", () => {
const mockWidget = new Widget({
id: "widget-id",
creatorUserId: "@user-id",
type: MatrixWidgetType.Custom,
url: "https://example.com",
});

const defaultWidgetPermissions = new DefaultWidgetPermissions();

const customWidgetPermissions = new class extends DefaultWidgetPermissions {
isEmbeddingPreapproved(widget: Widget): boolean {
return true;
}

isIdentityRequestPreapproved(widget: Widget): Promise<boolean> {
return Promise.resolve(true);
}

preapproveCapabilities(widget: Widget, requestedCapabilities: Set<Capability>): Promise<Set<Capability>> {
return Promise.resolve(requestedCapabilities);
}
}();

it("default permissions", async () => {
expect(defaultWidgetPermissions.isEmbeddingPreapproved(mockWidget)).toBe(false);
await expect(defaultWidgetPermissions.isIdentityRequestPreapproved(mockWidget)).resolves.toBe(false);
await expect(
defaultWidgetPermissions.preapproveCapabilities(mockWidget, new Set(["org.matrix.msc2931.navigate"])),
).resolves.toEqual(new Set());
});

it("custom permissions", async () => {
expect(customWidgetPermissions.isEmbeddingPreapproved(mockWidget)).toBe(true);
await expect(customWidgetPermissions.isIdentityRequestPreapproved(mockWidget)).resolves.toBe(true);
await expect(
customWidgetPermissions.preapproveCapabilities(mockWidget, new Set(["org.matrix.msc2931.navigate"])),
).resolves.toEqual(new Set(["org.matrix.msc2931.navigate"]));
});
});
});