This commit is contained in:
RMidhunSuresh 2023-06-04 19:36:34 +05:30
parent ea68e812ba
commit cf78def1d2
6 changed files with 92 additions and 17 deletions

View File

@ -81,8 +81,13 @@ export class DeviceMessageHandler extends EventEmitter{
await log.wrap("Verifying fingerprint of encrypted toDevice messages", async (log) => {
for (const result of decryptionResults) {
console.log("result", result);
const deviceId = result.event.sender_device ?? result.event.content.requesting_device_id;
const device = await deviceTracker.deviceForId(result.event.sender, deviceId, hsApi, log);
const sender = result.event.sender;
const device = await deviceTracker.deviceForCurveKey(
sender,
result.senderCurve25519Key,
hsApi,
log
);
result.setDevice(device);
if (result.isVerified) {
console.log("Received encrypted toDevice messages", decryptionResults);

View File

@ -352,7 +352,7 @@ export class Session {
if (isValid) {
this._secretStorage = secretStorage;
await this._loadSecretStorageService(log);
this.secretFetcher.secretStorage(secretStorage);
this.secretFetcher.setSecretStorage(secretStorage);
}
return isValid;
});

View File

@ -528,6 +528,21 @@ export class DeviceTracker {
/** Gets a single device */
async deviceForId(userId: string, deviceId: string, hsApi: HomeServerApi, log: ILogItem) {
/**
* 1. If the device keys are outdated, we will fetch all the keys and update them.
*/
const userIdentityTxn = await this._storage.readTxn([this._storage.storeNames.userIdentities]);
const userIdentity = await userIdentityTxn.userIdentities.get(userId);
if (userIdentity?.keysTrackingStatus !== KeysTrackingStatus.UpToDate) {
const {deviceKeys} = await this._queryKeys([userId], hsApi, log);
const keyList = deviceKeys.get(userId);
const device = keyList!.find(device => device.device_id === deviceId);
return device;
}
/**
* 2. If keys are up to date, return from storage.
*/
const txn = await this._storage.readTxn([
this._storage.storeNames.deviceKeys,
]);
@ -554,6 +569,9 @@ export class DeviceTracker {
const txn = await this._storage.readWriteTxn([
this._storage.storeNames.deviceKeys,
]);
// todo: the following comment states what the code does
// but it fails to explain why it does what it does...
// check again we don't have the device already.
// when updating all keys for a user we allow updating the
// device when the key hasn't changed so the device display name
@ -577,6 +595,22 @@ export class DeviceTracker {
return deviceKey;
}
async deviceForCurveKey(userId: string, key: string, hsApi: HomeServerApi, log: ILogItem) {
const txn = await this._storage.readTxn([
this._storage.storeNames.deviceKeys,
this._storage.storeNames.userIdentities,
]);
const userIdentity = await txn.userIdentities.get(userId);
if (userIdentity?.keysTrackingStatus !== KeysTrackingStatus.UpToDate) {
const {deviceKeys} = await this._queryKeys([userId], hsApi, log);
const keyList = deviceKeys.get(userId);
const device = keyList!.find(device => device.keys.curve25519 === key);
return device;
}
const device = await txn.deviceKeys.getByCurve25519Key(key);
return device;
}
/**
* Gets all the device identities with which keys should be shared for a set of users in a tracked room.
* If any userIdentities are outdated, it will fetch them from the homeserver.
@ -611,7 +645,7 @@ export class DeviceTracker {
/** Gets the device identites for a set of user identities that
* are known to be up to date, and a set of userIds that are known
* to be absent from our store our outdated. The outdated user ids
* to be absent from our store or are outdated. The outdated user ids
* will have their keys fetched from the homeserver. */
async _devicesForUserIdentities(upToDateIdentities: UserIdentity[], outdatedUserIds: string[], hsApi: HomeServerApi, log: ILogItem): Promise<DeviceKey[]> {
log.set("uptodate", upToDateIdentities.length);

View File

@ -41,5 +41,6 @@ export class SecretFetcher {
setSecretSharing(sharing: SharedSecret) {
this.secretSharing = sharing;
this.secretSharing.setSecretFetcher(this);
}
}

View File

@ -24,11 +24,11 @@ import type {Crypto} from "../../platform/web/dom/Crypto.js";
import type {Encoding} from "../../platform/web/utils/Encoding.js";
import type {CrossSigning} from "../verification/CrossSigning";
import type {SecretFetcher} from "./SecretFetcher";
import type {ObservableValue} from "../../observable/value";
import {makeTxnId, formatToDeviceMessagesPayload} from "../common.js";
import {Deferred} from "../../utils/Deferred";
import {StoreNames} from "../storage/common";
import {SESSION_E2EE_KEY_PREFIX} from "../e2ee/common";
import { ObservableValue } from "../../lib";
type SecretRequestResponse = {
request_id: string;
@ -105,13 +105,44 @@ export class SharedSecret {
private async _respondToRequest(request) {
await this.logger.run("SharedSecret.respondToRequest", async (log) => {
if (!this.shouldRespondToRequest(request, log)) {
return;
}
const requestContent = request.event.content;
const id = requestContent.request_id;
const deviceId = requestContent.requesting_device_id;
const name = requestContent.name;
const secret = await this.secretFetcher.getSecret(name);
if (!secret) {
// Can't share a secret that we don't know about.
log.log({ l: "Secret not available to share" });
return;
}
const content = { secret, request_id: id };
const device = await this.deviceTracker.deviceForId(this.ourUserId, deviceId, this.hsApi, log);
if (!device) {
log.log({ l: "Cannot find device", deviceId });
return;
}
const messages = await log.wrap("olm encrypt", log => this.olmEncryption.encrypt(
EVENT_TYPE.SEND, content, [device], this.hsApi, log));
console.log("messages", messages);
const payload = formatToDeviceMessagesPayload(messages);
console.log("payload", payload);
await this.hsApi.sendToDevice("m.room.encrypted", payload, makeTxnId(), {log}).response();
});
}
private async shouldRespondToRequest(request: any, log: ILogItem): Promise<boolean> {
return log.wrap("SecretSharing.shouldRespondToRequest", async () => {
const crossSigning = this.crossSigning.get();
console.log("cs", this.crossSigning);
if (!crossSigning) {
// We're not in a position to respond to this request
log.log({ crossSigningNotAvailable: true });
console.log("return here");
return;
return false;
}
const content = request.event.content;
@ -128,7 +159,7 @@ export class SharedSecret {
// 1. Ensure that the message came from the same user as us
// 2. Validate message format
// 3. Check if this is a cancellation
return;
return false;
}
// 3. Check that the device is verified
@ -137,15 +168,15 @@ export class SharedSecret {
const device = await this.deviceTracker.deviceForId(this.ourUserId, deviceId, this.hsApi, log);
if (!device) {
log.log({ l: "Device could not be acquired", deviceId });
return;
return false;
}
if (await crossSigning.isOurUserDeviceTrusted(device, log)) {
console.log("We can send the secret safely!");
if (!await crossSigning.isOurUserDeviceTrusted(device, log)) {
log.log({ l: "Device not trusted, returning" });
return false;
}
else {
console.log("Device is not trusted; cannot send secret.");
}
});
return true;
})
}
async getLocallyStoredSecret(name: string): Promise<any> {

View File

@ -98,8 +98,12 @@ export class ToDeviceChannel extends Disposables implements IChannel {
this.track(
this.deviceMessageHandler.disposableOn(
"message",
async ({ unencrypted }) =>
await this.handleDeviceMessage(unencrypted)
async ({ unencrypted }) => {
if (!unencrypted) {
return;
}
await this.handleDeviceMessage(unencrypted);
}
)
);
this.track(() => {