mirror of
https://github.com/vector-im/hydrogen-web.git
synced 2024-11-20 03:25:52 +01:00
WIP-2
This commit is contained in:
parent
ea68e812ba
commit
cf78def1d2
@ -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);
|
||||
|
@ -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;
|
||||
});
|
||||
|
@ -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);
|
||||
|
@ -41,5 +41,6 @@ export class SecretFetcher {
|
||||
|
||||
setSecretSharing(sharing: SharedSecret) {
|
||||
this.secretSharing = sharing;
|
||||
this.secretSharing.setSecretFetcher(this);
|
||||
}
|
||||
}
|
||||
|
@ -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> {
|
||||
|
@ -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(() => {
|
||||
|
Loading…
Reference in New Issue
Block a user