forked from mystiq/hydrogen-web
pass history visibility to device tracker
and delegate adding and removing members to share keys with to it
This commit is contained in:
parent
17f42f523a
commit
a23df8a545
1 changed files with 41 additions and 33 deletions
|
@ -28,14 +28,6 @@ const ROOM_HISTORY_VISIBILITY_TYPE = "m.room.history_visibility";
|
||||||
// note that encrypt could still create a new session
|
// note that encrypt could still create a new session
|
||||||
const MIN_PRESHARE_INTERVAL = 60 * 1000; // 1min
|
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
|
// 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 {
|
export class RoomEncryption {
|
||||||
constructor({room, deviceTracker, olmEncryption, megolmEncryption, megolmDecryption, encryptionParams, storage, keyBackup, notifyMissingMegolmSession, clock}) {
|
constructor({room, deviceTracker, olmEncryption, megolmEncryption, megolmDecryption, encryptionParams, storage, keyBackup, notifyMissingMegolmSession, clock}) {
|
||||||
|
@ -89,37 +81,49 @@ export class RoomEncryption {
|
||||||
}
|
}
|
||||||
|
|
||||||
async writeSync(roomResponse, memberChanges, txn, log) {
|
async writeSync(roomResponse, memberChanges, txn, log) {
|
||||||
let historyVisibility = this._historyVisibility;
|
let historyVisibility = await this._loadHistoryVisibilityIfNeeded(this._historyVisibility, txn);
|
||||||
iterateResponseStateEvents(roomResponse, event => {
|
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) {
|
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;
|
// process member changes
|
||||||
const memberChangesArray = Array.from(memberChanges.values());
|
if (memberChanges.size) {
|
||||||
// this also clears our session if we leave the room ourselves
|
const result = await this._deviceTracker.writeMemberChanges(
|
||||||
if (memberChangesArray.some(m => m.hasLeft)) {
|
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({
|
log.log({
|
||||||
l: "discardOutboundSession",
|
l: "discardOutboundSession",
|
||||||
leftUsers: memberChangesArray.filter(m => m.hasLeft).map(m => m.userId),
|
leftUsers: removedMembers,
|
||||||
});
|
});
|
||||||
this._megolmEncryption.discardOutboundSession(this._room.id, txn);
|
this._megolmEncryption.discardOutboundSession(this._room.id, txn);
|
||||||
}
|
}
|
||||||
if (memberChangesArray.some(m => m.hasJoined)) {
|
let shouldFlush = false;
|
||||||
const userIds = memberChangesArray.filter(m => m.hasJoined).map(m => m.userId);
|
// add room to userIdentities if needed, and share the current key with them
|
||||||
shouldFlush = await this._addShareRoomKeyOperationForMembers(userIds, txn, log)
|
if (addedMembers.length) {
|
||||||
|| shouldFlush;
|
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};
|
return {shouldFlush, historyVisibility};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,8 +131,11 @@ export class RoomEncryption {
|
||||||
this._historyVisibility = historyVisibility;
|
this._historyVisibility = historyVisibility;
|
||||||
}
|
}
|
||||||
|
|
||||||
async _loadHistoryVisibilityIfNeeded(historyVisibility, txn) {
|
async _loadHistoryVisibilityIfNeeded(historyVisibility, txn = undefined) {
|
||||||
if (!historyVisibility) {
|
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, "");
|
const visibilityEntry = await txn.roomState.get(this.id, ROOM_HISTORY_VISIBILITY_TYPE, "");
|
||||||
if (visibilityEntry) {
|
if (visibilityEntry) {
|
||||||
return event?.content?.history_visibility;
|
return event?.content?.history_visibility;
|
||||||
|
@ -316,6 +323,7 @@ export class RoomEncryption {
|
||||||
}
|
}
|
||||||
|
|
||||||
async _shareNewRoomKey(roomKeyMessage, hsApi, log) {
|
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 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()));
|
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) {
|
async _processShareRoomKeyOperation(operation, hsApi, log) {
|
||||||
log.set("id", operation.id);
|
log.set("id", operation.id);
|
||||||
|
this._historyVisibility = await this._loadHistoryVisibilityIfNeeded(this._historyVisibility);
|
||||||
await this._deviceTracker.trackRoom(this._room, log);
|
await this._deviceTracker.trackRoom(this._room, this._historyVisibility, log);
|
||||||
const devices = await this._deviceTracker.devicesForRoomMembers(this._room.id, operation.userIds, hsApi, 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(
|
const messages = await log.wrap("olm encrypt", log => this._olmEncryption.encrypt(
|
||||||
"m.room_key", operation.roomKeyMessage, devices, hsApi, log));
|
"m.room_key", operation.roomKeyMessage, devices, hsApi, log));
|
||||||
|
|
Loading…
Reference in a new issue