pass history visibility to device tracker

and delegate adding and removing members to share keys with to it
This commit is contained in:
Bruno Windels 2022-07-22 17:49:59 +02:00
parent 17f42f523a
commit a23df8a545
1 changed files with 41 additions and 33 deletions

View File

@ -28,14 +28,6 @@ const ROOM_HISTORY_VISIBILITY_TYPE = "m.room.history_visibility";
// note that encrypt could still create a new session
const MIN_PRESHARE_INTERVAL = 60 * 1000; // 1min
// Use enum when converting to TS
const HistoryVisibility = Object.freeze({
Joined: "joined",
Invited: "invited",
WorldReadable: "world_readable",
Shared: "shared",
});
// TODO: this class is a good candidate for splitting up into encryption and decryption, there doesn't seem to be much overlap
export class RoomEncryption {
constructor({room, deviceTracker, olmEncryption, megolmEncryption, megolmDecryption, encryptionParams, storage, keyBackup, notifyMissingMegolmSession, clock}) {
@ -89,37 +81,49 @@ export class RoomEncryption {
}
async writeSync(roomResponse, memberChanges, txn, log) {
let historyVisibility = this._historyVisibility;
iterateResponseStateEvents(roomResponse, event => {
let historyVisibility = await this._loadHistoryVisibilityIfNeeded(this._historyVisibility, txn);
const addedMembers = [];
const removedMembers = [];
// update the historyVisibility if needed
await iterateResponseStateEvents(roomResponse, event => {
// TODO: can the same state event appear twice? Hence we would be rewriting the useridentities twice...
// we'll see in the logs
if(event.state_key === "" && event.type === ROOM_HISTORY_VISIBILITY_TYPE) {
historyVisibility = event?.content?.history_visibility;
const newHistoryVisibility = event?.content?.history_visibility;
if (newHistoryVisibility !== historyVisibility) {
return log.wrap({
l: "history_visibility changed",
from: historyVisibility,
to: newHistoryVisibility
}, async log => {
historyVisibility = newHistoryVisibility;
const result = await this._deviceTracker.writeHistoryVisibility(this._room, historyVisibility, txn, log);
addedMembers.push(...result.added);
removedMembers.push(...result.removed);
});
}
}
});
let shouldFlush = false;
const memberChangesArray = Array.from(memberChanges.values());
// this also clears our session if we leave the room ourselves
if (memberChangesArray.some(m => m.hasLeft)) {
// process member changes
if (memberChanges.size) {
const result = await this._deviceTracker.writeMemberChanges(
this._room, memberChanges, historyVisibility, txn);
addedMembers.push(...result.added);
removedMembers.push(...result.removed);
}
// discard key if somebody (including ourselves) left
if (removedMembers.length) {
log.log({
l: "discardOutboundSession",
leftUsers: memberChangesArray.filter(m => m.hasLeft).map(m => m.userId),
leftUsers: removedMembers,
});
this._megolmEncryption.discardOutboundSession(this._room.id, txn);
}
if (memberChangesArray.some(m => m.hasJoined)) {
const userIds = memberChangesArray.filter(m => m.hasJoined).map(m => m.userId);
shouldFlush = await this._addShareRoomKeyOperationForMembers(userIds, txn, log)
|| shouldFlush;
let shouldFlush = false;
// add room to userIdentities if needed, and share the current key with them
if (addedMembers.length) {
shouldFlush = await this._addShareRoomKeyOperationForMembers(addedMembers, txn, log);
}
if (memberChangesArray.some(m => m.wasInvited)) {
historyVisibility = await this._loadHistoryVisibilityIfNeeded(historyVisibility, txn);
if (historyVisibility === HistoryVisibility.Invited) {
const userIds = memberChangesArray.filter(m => m.wasInvited).map(m => m.userId);
shouldFlush = await this._addShareRoomKeyOperationForMembers(userIds, txn, log)
|| shouldFlush;
}
}
await this._deviceTracker.writeMemberChanges(this._room, memberChanges, txn);
return {shouldFlush, historyVisibility};
}
@ -127,8 +131,11 @@ export class RoomEncryption {
this._historyVisibility = historyVisibility;
}
async _loadHistoryVisibilityIfNeeded(historyVisibility, txn) {
async _loadHistoryVisibilityIfNeeded(historyVisibility, txn = undefined) {
if (!historyVisibility) {
if (!txn) {
txn = await this._storage.readTxn([this._storage.storeNames.roomState]);
}
const visibilityEntry = await txn.roomState.get(this.id, ROOM_HISTORY_VISIBILITY_TYPE, "");
if (visibilityEntry) {
return event?.content?.history_visibility;
@ -316,6 +323,7 @@ export class RoomEncryption {
}
async _shareNewRoomKey(roomKeyMessage, hsApi, log) {
this._historyVisibility = await this._loadHistoryVisibilityIfNeeded(this._historyVisibility);
const devices = await this._deviceTracker.devicesForTrackedRoom(this._room.id, this._historyVisibility, hsApi, log);
const userIds = Array.from(devices.reduce((set, device) => set.add(device.userId), new Set()));
@ -386,8 +394,8 @@ export class RoomEncryption {
async _processShareRoomKeyOperation(operation, hsApi, log) {
log.set("id", operation.id);
await this._deviceTracker.trackRoom(this._room, log);
this._historyVisibility = await this._loadHistoryVisibilityIfNeeded(this._historyVisibility);
await this._deviceTracker.trackRoom(this._room, this._historyVisibility, log);
const devices = await this._deviceTracker.devicesForRoomMembers(this._room.id, operation.userIds, hsApi, log);
const messages = await log.wrap("olm encrypt", log => this._olmEncryption.encrypt(
"m.room_key", operation.roomKeyMessage, devices, hsApi, log));