This commit is contained in:
Bruno Windels 2021-10-27 10:26:36 +02:00
parent faf4ea6434
commit 718b410253
5 changed files with 51 additions and 42 deletions

View File

@ -24,6 +24,7 @@ import { ObservableMap } from "../observable/index.js";
import {User} from "./User.js"; import {User} from "./User.js";
import {DeviceMessageHandler} from "./DeviceMessageHandler.js"; import {DeviceMessageHandler} from "./DeviceMessageHandler.js";
import {Account as E2EEAccount} from "./e2ee/Account.js"; import {Account as E2EEAccount} from "./e2ee/Account.js";
import {uploadAccountAsDehydratedDevice} from "./e2ee/Dehydration.js";
import {Decryption as OlmDecryption} from "./e2ee/olm/Decryption.js"; import {Decryption as OlmDecryption} from "./e2ee/olm/Decryption.js";
import {Encryption as OlmEncryption} from "./e2ee/olm/Encryption.js"; import {Encryption as OlmEncryption} from "./e2ee/olm/Encryption.js";
import {Decryption as MegOlmDecryption} from "./e2ee/megolm/Decryption"; import {Decryption as MegOlmDecryption} from "./e2ee/megolm/Decryption";
@ -284,8 +285,8 @@ export class Session {
pickleKey: PICKLE_KEY, pickleKey: PICKLE_KEY,
userId: this._sessionInfo.userId, userId: this._sessionInfo.userId,
olmWorker: this._olmWorker, olmWorker: this._olmWorker,
deviceId, deviceId: this.deviceId,
storage, storage: this._storage,
}); });
log.set("keys", this._e2eeAccount.identityKeys); log.set("keys", this._e2eeAccount.identityKeys);
this._setupEncryption(); this._setupEncryption();

View File

@ -29,6 +29,7 @@ import {Session} from "./Session.js";
import {PasswordLoginMethod} from "./login/PasswordLoginMethod.js"; import {PasswordLoginMethod} from "./login/PasswordLoginMethod.js";
import {TokenLoginMethod} from "./login/TokenLoginMethod.js"; import {TokenLoginMethod} from "./login/TokenLoginMethod.js";
import {SSOLoginHelper} from "./login/SSOLoginHelper.js"; import {SSOLoginHelper} from "./login/SSOLoginHelper.js";
import {getDehydratedDevice} from "./e2ee/Dehydration.js";
export const LoadStatus = createEnum( export const LoadStatus = createEnum(
"NotLoading", "NotLoading",
@ -38,7 +39,7 @@ export const LoadStatus = createEnum(
"SetupAccount", // asked to restore from dehydrated device if present, call sc.accountSetup.finish() to progress to the next stage "SetupAccount", // asked to restore from dehydrated device if present, call sc.accountSetup.finish() to progress to the next stage
"Loading", "Loading",
"SessionSetup", // upload e2ee keys, ... "SessionSetup", // upload e2ee keys, ...
"Migrating", //not used atm, but would fit here "Migrating", // not used atm, but would fit here
"FirstSync", "FirstSync",
"Error", "Error",
"Ready", "Ready",
@ -174,7 +175,7 @@ export class SessionContainer {
} }
return; return;
} }
const dehydratedDevice = await this._inspectAccountAfterLogin(sessionInfo); const dehydratedDevice = await this._inspectAccountAfterLogin(sessionInfo, log);
if (dehydratedDevice) { if (dehydratedDevice) {
sessionInfo.deviceId = dehydratedDevice.deviceId; sessionInfo.deviceId = dehydratedDevice.deviceId;
} }
@ -240,7 +241,7 @@ export class SessionContainer {
}); });
await this._session.load(log); await this._session.load(log);
if (dehydratedDevice) { if (dehydratedDevice) {
await log.wrap("dehydrateIdentity", log => await this._session.dehydrateIdentity(dehydratedDevice, log)); await log.wrap("dehydrateIdentity", log => this._session.dehydrateIdentity(dehydratedDevice, log));
} else if (!this._session.hasIdentity) { } else if (!this._session.hasIdentity) {
this._status.set(LoadStatus.SessionSetup); this._status.set(LoadStatus.SessionSetup);
await log.wrap("createIdentity", log => this._session.createIdentity(log)); await log.wrap("createIdentity", log => this._session.createIdentity(log));
@ -308,25 +309,27 @@ export class SessionContainer {
} }
} }
async _inspectAccountAfterLogin(sessionInfo) { _inspectAccountAfterLogin(sessionInfo, log) {
this._status.set(LoadStatus.QueryAccount); return log.wrap("inspectAccount", async log => {
const hsApi = new HomeServerApi({ this._status.set(LoadStatus.QueryAccount);
homeserver: sessionInfo.homeServer, const hsApi = new HomeServerApi({
accessToken: sessionInfo.accessToken, homeserver: sessionInfo.homeServer,
request: this._platform.request, accessToken: sessionInfo.accessToken,
request: this._platform.request,
});
const olm = await this._olmPromise;
const encryptedDehydratedDevice = await getDehydratedDevice(hsApi, olm, log);
if (encryptedDehydratedDevice) {
let resolveStageFinish;
const promiseStageFinish = new Promise(r => resolveStageFinish = r);
this._accountSetup = new AccountSetup(encryptedDehydratedDevice, resolveStageFinish);
this._status.set(LoadStatus.SetupAccount);
await promiseStageFinish;
const dehydratedDevice = this._accountSetup?._dehydratedDevice;
this._accountSetup = null;
return dehydratedDevice;
}
}); });
const olm = await this._olmPromise;
const encryptedDehydratedDevice = await getDehydratedDevice(hsApi, olm);
if (encryptedDehydratedDevice) {
let resolveStageFinish;
const promiseStageFinish = new Promise(r => resolveStageFinish = r);
this._accountSetup = new AccountSetup(encryptedDehydratedDevice, resolveStageFinish);
this._status.set(LoadStatus.SetupAccount);
await promiseStageFinish;
const dehydratedDevice = this._accountSetup?._dehydratedDevice;
this._accountSetup = null;
return dehydratedDevice;
}
} }
get accountSetup() { get accountSetup() {

View File

@ -55,11 +55,11 @@ export class Account {
static async adoptDehydratedDevice({olm, dehydratedDevice, pickleKey, hsApi, userId, olmWorker, storage}) { static async adoptDehydratedDevice({olm, dehydratedDevice, pickleKey, hsApi, userId, olmWorker, storage}) {
const account = dehydratedDevice.adoptUnpickledOlmAccount(); const account = dehydratedDevice.adoptUnpickledOlmAccount();
const areDeviceKeysUploaded = true; const oneTimeKeys = JSON.parse(account.one_time_keys());
const oneTimeKeys = JSON.parse(this._account.one_time_keys());
// only one algorithm supported by olm atm, so hardcode its name // only one algorithm supported by olm atm, so hardcode its name
const oneTimeKeysEntries = Object.entries(oneTimeKeys.curve25519); const oneTimeKeysEntries = Object.entries(oneTimeKeys.curve25519);
const serverOTKCount = oneTimeKeysEntries.length; const serverOTKCount = oneTimeKeysEntries.length;
const areDeviceKeysUploaded = true;
await initiallyStoreAccount(account, pickleKey, areDeviceKeysUploaded, serverOTKCount, storage); await initiallyStoreAccount(account, pickleKey, areDeviceKeysUploaded, serverOTKCount, storage);
return new Account({ return new Account({
pickleKey, hsApi, account, userId, pickleKey, hsApi, account, userId,
@ -76,11 +76,13 @@ export class Account {
account.create(); account.create();
account.generate_one_time_keys(account.max_number_of_one_time_keys()); account.generate_one_time_keys(account.max_number_of_one_time_keys());
} }
const areDeviceKeysUploaded = false;
const serverOTKCount = 0;
if (storage) { if (storage) {
await initiallyStoreAccount(account, pickleKey, false, 0, storage); await initiallyStoreAccount(account, pickleKey, areDeviceKeysUploaded, serverOTKCount, storage);
} }
return new Account({pickleKey, hsApi, account, userId, return new Account({pickleKey, hsApi, account, userId,
deviceId, areDeviceKeysUploaded, serverOTKCount: 0, olm, olmWorker}); deviceId, areDeviceKeysUploaded, serverOTKCount, olm, olmWorker});
} }
constructor({pickleKey, hsApi, account, userId, deviceId, areDeviceKeysUploaded, serverOTKCount, olm, olmWorker}) { constructor({pickleKey, hsApi, account, userId, deviceId, areDeviceKeysUploaded, serverOTKCount, olm, olmWorker}) {

View File

@ -14,20 +14,23 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
export const DEHYDRATION_LIBOLM_PICKLE_ALGORITHM = "org.matrix.msc2697.v1.olm.libolm_pickle"; const DEHYDRATION_LIBOLM_PICKLE_ALGORITHM = "org.matrix.msc2697.v1.olm.libolm_pickle";
async function getDehydratedDevice(hsApi, olm) { export async function getDehydratedDevice(hsApi, olm, log) {
const response = await hsApi.getDehydratedDevice().response(); try {
if (response.device_data.algorithm === DEHYDRATION_LIBOLM_PICKLE_ALGORITHM) { const response = await hsApi.getDehydratedDevice({log}).response();
return new DehydratedDevice(response, olm); if (response.device_data.algorithm === DEHYDRATION_LIBOLM_PICKLE_ALGORITHM) {
return new EncryptedDehydratedDevice(response, olm);
}
} catch (err) {
if (err.name !== "HomeServerError") {
log.error = err;
}
return undefined;
} }
} }
async function hasRemainingDevice(ownUserId, ownDeviceId, storage) { export async function uploadAccountAsDehydratedDevice(account, hsApi, key, deviceDisplayName, log) {
}
async function uploadAccountAsDehydratedDevice(account, hsApi, key, deviceDisplayName, log) {
const response = await hsApi.createDehydratedDevice({ const response = await hsApi.createDehydratedDevice({
device_data: { device_data: {
algorithm: DEHYDRATION_LIBOLM_PICKLE_ALGORITHM, algorithm: DEHYDRATION_LIBOLM_PICKLE_ALGORITHM,
@ -66,7 +69,7 @@ class DehydratedDevice {
this._account = account; this._account = account;
} }
claim(hsApi, log) { async claim(hsApi, log) {
try { try {
const response = await hsApi.claimDehydratedDevice(this.deviceId, {log}).response(); const response = await hsApi.claimDehydratedDevice(this.deviceId, {log}).response();
return response.success; return response.success;
@ -83,6 +86,6 @@ class DehydratedDevice {
} }
get deviceId() { get deviceId() {
this._dehydratedDevice.device_id; return this._dehydratedDevice.device_id;
} }
} }

View File

@ -242,12 +242,12 @@ export class HomeServerApi {
return this._get(`/dehydrated_device`, null, null, options); return this._get(`/dehydrated_device`, null, null, options);
} }
createDehydratedDevice(payload, options = null) { createDehydratedDevice(payload, options = {}) {
options.prefix = DEHYDRATION_PREFIX; options.prefix = DEHYDRATION_PREFIX;
return this._put(`/dehydrated_device`, null, payload, options); return this._put(`/dehydrated_device`, null, payload, options);
} }
claimDehydratedDevice(deviceId) { claimDehydratedDevice(deviceId, options = {}) {
options.prefix = DEHYDRATION_PREFIX; options.prefix = DEHYDRATION_PREFIX;
return this._post(`/dehydrated_device/claim`, null, {device_id: deviceId}, options); return this._post(`/dehydrated_device/claim`, null, {device_id: deviceId}, options);
} }