Merge pull request #2118 from famedly/krille/matrix-security-predisclosure

Krille/matrix security predisclosure
This commit is contained in:
Krille-chan 2025-08-07 09:57:58 +02:00 committed by GitHub
commit 026fd74352
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 55 additions and 3 deletions

View File

@ -1930,13 +1930,41 @@ class Room {
} }
} }
/// Returns the room version if specified in the `m.room.create` state event.
String? get roomVersion =>
getState(EventTypes.RoomCreate)?.content.tryGet<String>('room_version');
/// Returns the creator's user ID of the room by fetching the sender of the
/// `m.room.create` event.
Set<String> get creatorUserIds {
final creationEvent = getState(EventTypes.RoomCreate);
if (creationEvent == null) return {};
final additionalCreators =
creationEvent.content.tryGetList<String>('additional_creators') ?? [];
return {
creationEvent.senderId,
...additionalCreators,
};
}
/// Returns the power level of the given user ID. /// Returns the power level of the given user ID.
/// If a user_id is in the users list, then that user_id has the associated /// If a user_id is in the users list, then that user_id has the associated
/// power level. Otherwise they have the default level users_default. /// power level. Otherwise they have the default level users_default.
/// If users_default is not supplied, it is assumed to be 0. If the room /// If users_default is not supplied, it is assumed to be 0. If the room
/// contains no m.room.power_levels event, the rooms creator has a power /// contains no m.room.power_levels event, the rooms creator has a power
/// level of 100, and all other users have a power level of 0. /// level of 100, and all other users have a power level of 0.
/// For room version 12 and above the room creator always has maximum
/// power level.
int getPowerLevelByUserId(String userId) { int getPowerLevelByUserId(String userId) {
// Room creator has maximum power level:
if (creatorUserIds.contains(userId) &&
!((int.tryParse(roomVersion ?? '') ?? 0) < 12)) {
// 2^53 - 1 from https://spec.matrix.org/v1.15/appendices/#canonical-json
const maxInteger = 9007199254740991;
return maxInteger;
}
final powerLevelMap = getState(EventTypes.RoomPowerLevels)?.content; final powerLevelMap = getState(EventTypes.RoomPowerLevels)?.content;
final userSpecificPowerLevel = final userSpecificPowerLevel =

View File

@ -33,11 +33,12 @@ extension MatrixIdExtension on String {
bool get isValidMatrixId { bool get isValidMatrixId {
if (isEmpty) return false; if (isEmpty) return false;
if (length > maxLength) return false; if (length > maxLength) return false;
if (!validSigils.contains(substring(0, 1))) { final sigil = substring(0, 1);
if (!validSigils.contains(sigil)) {
return false; return false;
} }
// event IDs do not have to have a domain // event IDs and room IDs do not have to have a domain
if (substring(0, 1) == '\$') { if ({'\$', '!'}.contains(sigil)) {
return true; return true;
} }
// all other matrix IDs have to have a domain // all other matrix IDs have to have a domain

View File

@ -93,6 +93,18 @@ void main() {
}, },
); );
room.setState(
Event(
content: {'room_version': '11'},
eventId: '\$143273582443PhrSn:example.org',
originServerTs: DateTime.fromMillisecondsSinceEpoch(1432735824653),
senderId: '@example:example.org',
type: 'm.room.create',
unsigned: {'age': 1234},
stateKey: '',
room: room,
),
);
room.setState( room.setState(
Event( Event(
room: room, room: room,
@ -809,6 +821,17 @@ void main() {
expect(room.canSendEvent('m.room.message'), true); expect(room.canSendEvent('m.room.message'), true);
final resp = await room.setPower('@test:fakeServer.notExisting', 0); final resp = await room.setPower('@test:fakeServer.notExisting', 0);
expect(resp, '42'); expect(resp, '42');
// Creator has max power level from room version 12 on:
expect(room.creatorUserIds.contains('@example:example.org'), true);
expect(room.getPowerLevelByUserId('@example:example.org'), 0);
expect(room.roomVersion, '11');
room.states[EventTypes.RoomCreate]!['']!.content['room_version'] = '12';
expect(room.roomVersion, '12');
expect(
room.getPowerLevelByUserId('@example:example.org'),
9007199254740991,
);
}); });
test('invite', () async { test('invite', () async {