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 {DeviceMessageHandler} from "./DeviceMessageHandler.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 {Encryption as OlmEncryption} from "./e2ee/olm/Encryption.js";
import {Decryption as MegOlmDecryption} from "./e2ee/megolm/Decryption";
@ -284,8 +285,8 @@ export class Session {
pickleKey: PICKLE_KEY,
userId: this._sessionInfo.userId,
olmWorker: this._olmWorker,
deviceId,
storage,
deviceId: this.deviceId,
storage: this._storage,
});
log.set("keys", this._e2eeAccount.identityKeys);
this._setupEncryption();

View file

@ -29,6 +29,7 @@ import {Session} from "./Session.js";
import {PasswordLoginMethod} from "./login/PasswordLoginMethod.js";
import {TokenLoginMethod} from "./login/TokenLoginMethod.js";
import {SSOLoginHelper} from "./login/SSOLoginHelper.js";
import {getDehydratedDevice} from "./e2ee/Dehydration.js";
export const LoadStatus = createEnum(
"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
"Loading",
"SessionSetup", // upload e2ee keys, ...
"Migrating", //not used atm, but would fit here
"Migrating", // not used atm, but would fit here
"FirstSync",
"Error",
"Ready",
@ -174,7 +175,7 @@ export class SessionContainer {
}
return;
}
const dehydratedDevice = await this._inspectAccountAfterLogin(sessionInfo);
const dehydratedDevice = await this._inspectAccountAfterLogin(sessionInfo, log);
if (dehydratedDevice) {
sessionInfo.deviceId = dehydratedDevice.deviceId;
}
@ -240,7 +241,7 @@ export class SessionContainer {
});
await this._session.load(log);
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) {
this._status.set(LoadStatus.SessionSetup);
await log.wrap("createIdentity", log => this._session.createIdentity(log));
@ -308,25 +309,27 @@ export class SessionContainer {
}
}
async _inspectAccountAfterLogin(sessionInfo) {
this._status.set(LoadStatus.QueryAccount);
const hsApi = new HomeServerApi({
homeserver: sessionInfo.homeServer,
accessToken: sessionInfo.accessToken,
request: this._platform.request,
_inspectAccountAfterLogin(sessionInfo, log) {
return log.wrap("inspectAccount", async log => {
this._status.set(LoadStatus.QueryAccount);
const hsApi = new HomeServerApi({
homeserver: sessionInfo.homeServer,
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() {

View file

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

View file

@ -14,20 +14,23 @@ See the License for the specific language governing permissions and
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) {
const response = await hsApi.getDehydratedDevice().response();
if (response.device_data.algorithm === DEHYDRATION_LIBOLM_PICKLE_ALGORITHM) {
return new DehydratedDevice(response, olm);
export async function getDehydratedDevice(hsApi, olm, log) {
try {
const response = await hsApi.getDehydratedDevice({log}).response();
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) {
}
async function uploadAccountAsDehydratedDevice(account, hsApi, key, deviceDisplayName, log) {
export async function uploadAccountAsDehydratedDevice(account, hsApi, key, deviceDisplayName, log) {
const response = await hsApi.createDehydratedDevice({
device_data: {
algorithm: DEHYDRATION_LIBOLM_PICKLE_ALGORITHM,
@ -66,7 +69,7 @@ class DehydratedDevice {
this._account = account;
}
claim(hsApi, log) {
async claim(hsApi, log) {
try {
const response = await hsApi.claimDehydratedDevice(this.deviceId, {log}).response();
return response.success;
@ -83,6 +86,6 @@ class DehydratedDevice {
}
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);
}
createDehydratedDevice(payload, options = null) {
createDehydratedDevice(payload, options = {}) {
options.prefix = DEHYDRATION_PREFIX;
return this._put(`/dehydrated_device`, null, payload, options);
}
claimDehydratedDevice(deviceId) {
claimDehydratedDevice(deviceId, options = {}) {
options.prefix = DEHYDRATION_PREFIX;
return this._post(`/dehydrated_device/claim`, null, {device_id: deviceId}, options);
}