2021-05-31 17:22:03 +05:30
|
|
|
/*
|
|
|
|
Copyright 2021 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.
|
|
|
|
*/
|
|
|
|
|
2021-08-04 13:34:35 +05:30
|
|
|
export const EVENT_TYPE = "m.room.power_levels";
|
|
|
|
|
2021-05-31 17:22:03 +05:30
|
|
|
export class PowerLevels {
|
2021-06-24 17:54:22 +05:30
|
|
|
constructor({powerLevelEvent, createEvent, ownUserId, membership}) {
|
2021-05-31 17:22:03 +05:30
|
|
|
this._plEvent = powerLevelEvent;
|
|
|
|
this._createEvent = createEvent;
|
|
|
|
this._ownUserId = ownUserId;
|
2021-06-24 17:54:22 +05:30
|
|
|
this._membership = membership;
|
2021-05-31 17:22:03 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
canRedactFromSender(userId) {
|
2021-06-24 17:54:22 +05:30
|
|
|
if (userId === this._ownUserId && this._membership === "join") {
|
2021-05-31 17:22:03 +05:30
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return this.canRedact;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-17 13:11:25 +05:30
|
|
|
canSendType(eventType) {
|
|
|
|
return this._myLevel >= this._getEventTypeLevel(eventType);
|
|
|
|
}
|
|
|
|
|
2021-05-31 17:22:03 +05:30
|
|
|
get canRedact() {
|
2021-06-17 13:11:25 +05:30
|
|
|
return this._myLevel >= this._getActionLevel("redact");
|
|
|
|
}
|
|
|
|
|
|
|
|
get _myLevel() {
|
2021-06-24 17:54:22 +05:30
|
|
|
if (this._membership !== "join") {
|
|
|
|
return Number.MIN_SAFE_INTEGER;
|
|
|
|
}
|
2021-06-18 13:13:19 +05:30
|
|
|
return this.getUserLevel(this._ownUserId);
|
2021-05-31 17:22:03 +05:30
|
|
|
}
|
|
|
|
|
2021-06-18 13:13:19 +05:30
|
|
|
getUserLevel(userId) {
|
2021-05-31 17:22:03 +05:30
|
|
|
if (this._plEvent) {
|
|
|
|
let userLevel = this._plEvent.content?.users?.[userId];
|
|
|
|
if (typeof userLevel !== "number") {
|
|
|
|
userLevel = this._plEvent.content?.users_default;
|
|
|
|
}
|
|
|
|
if (typeof userLevel === "number") {
|
|
|
|
return userLevel;
|
|
|
|
}
|
|
|
|
} else if (this._createEvent) {
|
|
|
|
if (userId === this._createEvent.content?.creator) {
|
|
|
|
return 100;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** @param {string} action either "invite", "kick", "ban" or "redact". */
|
|
|
|
_getActionLevel(action) {
|
|
|
|
const level = this._plEvent?.content[action];
|
|
|
|
if (typeof level === "number") {
|
|
|
|
return level;
|
|
|
|
} else {
|
|
|
|
return 50;
|
|
|
|
}
|
|
|
|
}
|
2021-06-17 13:11:25 +05:30
|
|
|
|
|
|
|
_getEventTypeLevel(eventType) {
|
|
|
|
const level = this._plEvent?.content.events?.[eventType];
|
|
|
|
if (typeof level === "number") {
|
|
|
|
return level;
|
|
|
|
} else {
|
|
|
|
const level = this._plEvent?.content.events_default;
|
|
|
|
if (typeof level === "number") {
|
|
|
|
return level;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-05-31 17:22:03 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
export function tests() {
|
|
|
|
const alice = "@alice:hs.tld";
|
|
|
|
const bob = "@bob:hs.tld";
|
2021-06-17 13:11:25 +05:30
|
|
|
const charly = "@charly:hs.tld";
|
2021-05-31 17:22:03 +05:30
|
|
|
const createEvent = {content: {creator: alice}};
|
2021-06-17 13:11:25 +05:30
|
|
|
const redactPowerLevelEvent = {content: {
|
2021-05-31 17:22:03 +05:30
|
|
|
redact: 50,
|
|
|
|
users: {
|
|
|
|
[alice]: 50
|
|
|
|
},
|
|
|
|
users_default: 0
|
|
|
|
}};
|
2021-06-17 13:11:25 +05:30
|
|
|
const eventsPowerLevelEvent = {content: {
|
|
|
|
events_default: 5,
|
|
|
|
events: {
|
2021-06-17 13:29:24 +05:30
|
|
|
"m.room.message": 45,
|
|
|
|
"m.room.topic": 50,
|
2021-06-17 13:11:25 +05:30
|
|
|
},
|
|
|
|
users: {
|
|
|
|
[alice]: 50,
|
|
|
|
[bob]: 10
|
|
|
|
},
|
|
|
|
users_default: 0
|
|
|
|
}};
|
2021-05-31 17:22:03 +05:30
|
|
|
|
|
|
|
return {
|
|
|
|
"redact somebody else event with power level event": assert => {
|
2021-06-24 17:58:10 +05:30
|
|
|
const pl1 = new PowerLevels({powerLevelEvent: redactPowerLevelEvent, ownUserId: alice, membership: "join"});
|
2021-05-31 17:22:03 +05:30
|
|
|
assert.equal(pl1.canRedact, true);
|
2021-06-24 17:58:10 +05:30
|
|
|
const pl2 = new PowerLevels({powerLevelEvent: redactPowerLevelEvent, ownUserId: bob, membership: "join"});
|
2021-05-31 17:22:03 +05:30
|
|
|
assert.equal(pl2.canRedact, false);
|
|
|
|
},
|
|
|
|
"redact somebody else event with create event": assert => {
|
2021-06-24 17:58:10 +05:30
|
|
|
const pl1 = new PowerLevels({createEvent, ownUserId: alice, membership: "join"});
|
2021-05-31 17:22:03 +05:30
|
|
|
assert.equal(pl1.canRedact, true);
|
2021-06-24 17:58:10 +05:30
|
|
|
const pl2 = new PowerLevels({createEvent, ownUserId: bob, membership: "join"});
|
2021-05-31 17:22:03 +05:30
|
|
|
assert.equal(pl2.canRedact, false);
|
|
|
|
},
|
|
|
|
"redact own event": assert => {
|
2021-06-24 17:58:10 +05:30
|
|
|
const pl = new PowerLevels({ownUserId: alice, membership: "join"});
|
2021-05-31 17:22:03 +05:30
|
|
|
assert.equal(pl.canRedactFromSender(alice), true);
|
|
|
|
assert.equal(pl.canRedactFromSender(bob), false);
|
|
|
|
},
|
2021-06-17 13:11:25 +05:30
|
|
|
"can send event without power levels": assert => {
|
2021-06-24 17:58:10 +05:30
|
|
|
const pl = new PowerLevels({createEvent, ownUserId: charly, membership: "join"});
|
2021-06-17 13:11:25 +05:30
|
|
|
assert.equal(pl.canSendType("m.room.message"), true);
|
|
|
|
},
|
|
|
|
"can't send any event below events_default": assert => {
|
2021-06-24 17:58:10 +05:30
|
|
|
const pl = new PowerLevels({powerLevelEvent: eventsPowerLevelEvent, ownUserId: charly, membership: "join"});
|
2021-06-17 13:11:25 +05:30
|
|
|
assert.equal(pl.canSendType("m.foo"), false);
|
|
|
|
},
|
|
|
|
"can't send event below events[type]": assert => {
|
2021-06-24 17:58:10 +05:30
|
|
|
const pl = new PowerLevels({powerLevelEvent: eventsPowerLevelEvent, ownUserId: bob, membership: "join"});
|
2021-06-17 13:11:25 +05:30
|
|
|
assert.equal(pl.canSendType("m.foo"), true);
|
|
|
|
assert.equal(pl.canSendType("m.room.message"), false);
|
|
|
|
},
|
2021-06-17 13:29:24 +05:30
|
|
|
"can send event above or at events[type]": assert => {
|
2021-06-24 17:58:10 +05:30
|
|
|
const pl = new PowerLevels({powerLevelEvent: eventsPowerLevelEvent, ownUserId: alice, membership: "join"});
|
2021-06-17 13:11:25 +05:30
|
|
|
assert.equal(pl.canSendType("m.room.message"), true);
|
2021-06-17 13:29:24 +05:30
|
|
|
assert.equal(pl.canSendType("m.room.topic"), true);
|
2021-06-17 13:11:25 +05:30
|
|
|
},
|
2021-06-24 17:58:10 +05:30
|
|
|
"can't redact or send in non-joined room'": assert => {
|
|
|
|
const pl = new PowerLevels({createEvent, ownUserId: alice, membership: "leave"});
|
|
|
|
assert.equal(pl.canRedact, false);
|
|
|
|
assert.equal(pl.canRedactFromSender(alice), false);
|
|
|
|
assert.equal(pl.canSendType("m.room.message"), false);
|
|
|
|
},
|
2021-05-31 17:22:03 +05:30
|
|
|
}
|
2021-06-17 13:11:25 +05:30
|
|
|
}
|