use decryption result to show message verification status in timeline

This commit is contained in:
Bruno Windels 2020-09-08 10:50:39 +02:00
parent 9137d5dcbb
commit c32ac2c764
11 changed files with 56 additions and 0 deletions

View file

@ -71,6 +71,10 @@ export class MessageTile extends SimpleTile {
return this._isContinuation; return this._isContinuation;
} }
get isUnverified() {
return this._entry.isUnverified;
}
_getContent() { _getContent() {
return this._entry.content; return this._entry.content;
} }

View file

@ -135,6 +135,7 @@ export class Sync {
storeNames.userIdentities, storeNames.userIdentities,
storeNames.inboundGroupSessions, storeNames.inboundGroupSessions,
storeNames.groupSessionDecryptions, storeNames.groupSessionDecryptions,
storeNames.deviceIdentities,
]); ]);
const roomChanges = []; const roomChanges = [];
let sessionChanges; let sessionChanges;

View file

@ -270,4 +270,8 @@ export class DeviceTracker {
}); });
return devices; return devices;
} }
async getDeviceByCurve25519Key(curve25519Key, txn) {
return await txn.deviceIdentities.getByCurve25519Key(curve25519Key);
}
} }

View file

@ -34,12 +34,14 @@ export class RoomEncryption {
this._megolmSyncCache = this._megolmDecryption.createSessionCache(); this._megolmSyncCache = this._megolmDecryption.createSessionCache();
// not `event_id`, but an internal event id passed in to the decrypt methods // not `event_id`, but an internal event id passed in to the decrypt methods
this._eventIdsByMissingSession = new Map(); this._eventIdsByMissingSession = new Map();
this._senderDeviceCache = new Map();
} }
notifyTimelineClosed() { notifyTimelineClosed() {
// empty the backfill cache when closing the timeline // empty the backfill cache when closing the timeline
this._megolmBackfillCache.dispose(); this._megolmBackfillCache.dispose();
this._megolmBackfillCache = this._megolmDecryption.createSessionCache(); this._megolmBackfillCache = this._megolmDecryption.createSessionCache();
this._senderDeviceCache = new Map(); // purge the sender device cache
} }
async writeMemberChanges(memberChanges, txn) { async writeMemberChanges(memberChanges, txn) {
@ -56,9 +58,25 @@ export class RoomEncryption {
if (!result) { if (!result) {
this._addMissingSessionEvent(event, isSync, retryData); this._addMissingSessionEvent(event, isSync, retryData);
} }
if (result && isTimelineOpen) {
await this._verifyDecryptionResult(result, txn);
}
return result; return result;
} }
async _verifyDecryptionResult(result, txn) {
let device = this._senderDeviceCache.get(result.senderCurve25519Key);
if (!device) {
device = await this._deviceTracker.getDeviceByCurve25519Key(result.senderCurve25519Key, txn);
this._senderDeviceCache.set(result.senderCurve25519Key, device);
}
if (device) {
result.setDevice(device);
} else if (!this._room.isTrackingMembers) {
result.setRoomNotTrackedYet();
}
}
_addMissingSessionEvent(event, isSync, data) { _addMissingSessionEvent(event, isSync, data) {
const senderKey = event.content?.["sender_key"]; const senderKey = event.content?.["sender_key"];
const sessionId = event.content?.["session_id"]; const sessionId = event.content?.["session_id"];

View file

@ -57,6 +57,7 @@ export class Room extends EventEmitter {
this._storage.storeNames.timelineEvents, this._storage.storeNames.timelineEvents,
this._storage.storeNames.inboundGroupSessions, this._storage.storeNames.inboundGroupSessions,
this._storage.storeNames.groupSessionDecryptions, this._storage.storeNames.groupSessionDecryptions,
this._storage.storeNames.deviceIdentities,
]); ]);
try { try {
for (const retryEntry of retryEntries) { for (const retryEntry of retryEntries) {
@ -280,6 +281,7 @@ export class Room extends EventEmitter {
stores = stores.concat([ stores = stores.concat([
this._storage.storeNames.inboundGroupSessions, this._storage.storeNames.inboundGroupSessions,
this._storage.storeNames.groupSessionDecryptions, this._storage.storeNames.groupSessionDecryptions,
this._storage.storeNames.deviceIdentities,
]); ]);
} }
const txn = await this._storage.readWriteTxn(stores); const txn = await this._storage.readWriteTxn(stores);

View file

@ -78,6 +78,16 @@ export class EventEntry extends BaseEntry {
this._decryptionResult = result; this._decryptionResult = result;
} }
get isEncrypted() {
return this._eventEntry.event.type === "m.room.encrypted";
}
get isVerified() {
return this.isEncrypted && this._decryptionResult?.isVerified;
}
get isUnverified() {
return this.isEncrypted && this._decryptionResult?.isUnverified;
} }
setDecryptionError(err) { setDecryptionError(err) {

View file

@ -38,6 +38,7 @@ export class TimelineReader {
this._storage.storeNames.timelineFragments, this._storage.storeNames.timelineFragments,
this._storage.storeNames.inboundGroupSessions, this._storage.storeNames.inboundGroupSessions,
this._storage.storeNames.groupSessionDecryptions, this._storage.storeNames.groupSessionDecryptions,
this._storage.storeNames.deviceIdentities,
]); ]);
} else { } else {

View file

@ -14,6 +14,7 @@ export const schema = [
createInboundGroupSessionsStore, createInboundGroupSessionsStore,
createOutboundGroupSessionsStore, createOutboundGroupSessionsStore,
createGroupSessionDecryptions, createGroupSessionDecryptions,
addSenderKeyIndexToDeviceStore
]; ];
// TODO: how to deal with git merge conflicts of this array? // TODO: how to deal with git merge conflicts of this array?
@ -94,3 +95,9 @@ function createOutboundGroupSessionsStore(db) {
function createGroupSessionDecryptions(db) { function createGroupSessionDecryptions(db) {
db.createObjectStore("groupSessionDecryptions", {keyPath: "key"}); db.createObjectStore("groupSessionDecryptions", {keyPath: "key"});
} }
//v9
function addSenderKeyIndexToDeviceStore(db, txn) {
const deviceIdentities = txn.objectStore("deviceIdentities");
deviceIdentities.createIndex("byCurve25519Key", "curve25519Key", {unique: true});
}

View file

@ -38,4 +38,8 @@ export class DeviceIdentityStore {
deviceIdentity.key = encodeKey(deviceIdentity.userId, deviceIdentity.deviceId); deviceIdentity.key = encodeKey(deviceIdentity.userId, deviceIdentity.deviceId);
return this._store.put(deviceIdentity); return this._store.put(deviceIdentity);
} }
getByCurve25519Key(curve25519Key) {
return this._store.index("byCurve25519Key").get(curve25519Key);
}
} }

View file

@ -373,6 +373,10 @@ ul.Timeline > li.continuation time {
color: #ccc; color: #ccc;
} }
.TextMessageView.unverified .message-container {
color: #ff4b55;
}
.message-container p { .message-container p {
margin: 3px 0; margin: 3px 0;
line-height: 2.2rem; line-height: 2.2rem;

View file

@ -22,6 +22,7 @@ export function renderMessage(t, vm, children) {
"TextMessageView": true, "TextMessageView": true,
own: vm.isOwn, own: vm.isOwn,
pending: vm.isPending, pending: vm.isPending,
unverified: vm.isUnverified,
continuation: vm => vm.isContinuation, continuation: vm => vm.isContinuation,
}; };