Skip to content

Commit

Permalink
Merge pull request #651 from vector-im/bwindels/write-session-backup
Browse files Browse the repository at this point in the history
Session backup writing
  • Loading branch information
bwindels authored Feb 1, 2022
2 parents 3043884 + f4fa013 commit 247d13f
Show file tree
Hide file tree
Showing 39 changed files with 953 additions and 311 deletions.
4 changes: 2 additions & 2 deletions src/domain/AccountSetupViewModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ limitations under the License.

import {ViewModel} from "./ViewModel.js";
import {KeyType} from "../matrix/ssss/index";
import {Status} from "./session/settings/SessionBackupViewModel.js";
import {Status} from "./session/settings/KeyBackupViewModel.js";

export class AccountSetupViewModel extends ViewModel {
constructor(accountSetup) {
Expand Down Expand Up @@ -50,7 +50,7 @@ export class AccountSetupViewModel extends ViewModel {
}
}

// this vm adopts the same shape as SessionBackupViewModel so the same view can be reused.
// this vm adopts the same shape as KeyBackupViewModel so the same view can be reused.
class DecryptDehydratedDeviceViewModel extends ViewModel {
constructor(accountSetupViewModel, decryptedCallback) {
super();
Expand Down
14 changes: 7 additions & 7 deletions src/domain/session/SessionStatusViewModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,25 +36,25 @@ export class SessionStatusViewModel extends ViewModel {
this._reconnector = reconnector;
this._status = this._calculateState(reconnector.connectionStatus.get(), sync.status.get());
this._session = session;
this._setupSessionBackupUrl = this.urlCreator.urlForSegment("settings");
this._setupKeyBackupUrl = this.urlCreator.urlForSegment("settings");
this._dismissSecretStorage = false;
}

start() {
const update = () => this._updateStatus();
this.track(this._sync.status.subscribe(update));
this.track(this._reconnector.connectionStatus.subscribe(update));
this.track(this._session.needsSessionBackup.subscribe(() => {
this.track(this._session.needsKeyBackup.subscribe(() => {
this.emitChange();
}));
}

get setupSessionBackupUrl () {
return this._setupSessionBackupUrl;
get setupKeyBackupUrl () {
return this._setupKeyBackupUrl;
}

get isShown() {
return (this._session.needsSessionBackup.get() && !this._dismissSecretStorage) || this._status !== SessionStatus.Syncing;
return (this._session.needsKeyBackup.get() && !this._dismissSecretStorage) || this._status !== SessionStatus.Syncing;
}

get statusLabel() {
Expand All @@ -70,7 +70,7 @@ export class SessionStatusViewModel extends ViewModel {
case SessionStatus.SyncError:
return this.i18n`Sync failed because of ${this._sync.error}`;
}
if (this._session.needsSessionBackup.get()) {
if (this._session.needsKeyBackup.get()) {
return this.i18n`Set up session backup to decrypt older messages.`;
}
return "";
Expand Down Expand Up @@ -135,7 +135,7 @@ export class SessionStatusViewModel extends ViewModel {

get isSecretStorageShown() {
// TODO: we need a model here where we can have multiple messages queued up and their buttons don't bleed into each other.
return this._status === SessionStatus.Syncing && this._session.needsSessionBackup.get() && !this._dismissSecretStorage;
return this._status === SessionStatus.Syncing && this._session.needsKeyBackup.get() && !this._dismissSecretStorage;
}

get canDismiss() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,27 @@ import {ViewModel} from "../../ViewModel.js";
import {KeyType} from "../../../matrix/ssss/index";
import {createEnum} from "../../../utils/enum";

export const Status = createEnum("Enabled", "SetupKey", "SetupPhrase", "Pending");
export const Status = createEnum("Enabled", "SetupKey", "SetupPhrase", "Pending", "NewVersionAvailable");
export const BackupWriteStatus = createEnum("Writing", "Stopped", "Done", "Pending");

export class SessionBackupViewModel extends ViewModel {
export class KeyBackupViewModel extends ViewModel {
constructor(options) {
super(options);
this._session = options.session;
this._error = null;
this._isBusy = false;
this._dehydratedDeviceId = undefined;
this._status = undefined;
this._backupOperation = this._session.keyBackup.flatMap(keyBackup => keyBackup.operationInProgress);
this._progress = this._backupOperation.flatMap(op => op.progress);
this.track(this._backupOperation.subscribe(() => {
// see if needsNewKey might be set
this._reevaluateStatus();
this.emitChange("isBackingUp");
}));
this.track(this._progress.subscribe(() => this.emitChange("backupPercentage")));
this._reevaluateStatus();
this.track(this._session.hasSecretStorageKey.subscribe(() => {
this.track(this._session.keyBackup.subscribe(() => {
if (this._reevaluateStatus()) {
this.emitChange("status");
}
Expand All @@ -41,11 +50,11 @@ export class SessionBackupViewModel extends ViewModel {
return false;
}
let status;
const hasSecretStorageKey = this._session.hasSecretStorageKey.get();
if (hasSecretStorageKey === true) {
status = this._session.sessionBackup ? Status.Enabled : Status.SetupKey;
} else if (hasSecretStorageKey === false) {
status = Status.SetupKey;
const keyBackup = this._session.keyBackup.get();
if (keyBackup) {
status = keyBackup.needsNewKey ? Status.NewVersionAvailable : Status.Enabled;
} else if (keyBackup === null) {
status = this.showPhraseSetup() ? Status.SetupPhrase : Status.SetupKey;
} else {
status = Status.Pending;
}
Expand All @@ -59,7 +68,7 @@ export class SessionBackupViewModel extends ViewModel {
}

get purpose() {
return this.i18n`set up session backup`;
return this.i18n`set up key backup`;
}

offerDehydratedDeviceSetup() {
Expand All @@ -75,7 +84,28 @@ export class SessionBackupViewModel extends ViewModel {
}

get backupVersion() {
return this._session.sessionBackup?.version;
return this._session.keyBackup.get()?.version;
}

get backupWriteStatus() {
const keyBackup = this._session.keyBackup.get();
if (!keyBackup) {
return BackupWriteStatus.Pending;
} else if (keyBackup.hasStopped) {
return BackupWriteStatus.Stopped;
}
const operation = keyBackup.operationInProgress.get();
if (operation) {
return BackupWriteStatus.Writing;
} else if (keyBackup.hasBackedUpAllKeys) {
return BackupWriteStatus.Done;
} else {
return BackupWriteStatus.Pending;
}
}

get backupError() {
return this._session.keyBackup.get()?.error?.message;
}

get status() {
Expand Down Expand Up @@ -144,4 +174,33 @@ export class SessionBackupViewModel extends ViewModel {
this.emitChange("");
}
}

get isBackingUp() {
return !!this._backupOperation.get();
}

get backupPercentage() {
const progress = this._progress.get();
if (progress) {
return Math.round((progress.finished / progress.total) * 100);
}
return 0;
}

get backupInProgressLabel() {
const progress = this._progress.get();
if (progress) {
return this.i18n`${progress.finished} of ${progress.total}`;
}
return this.i18n`…`;
}

cancelBackup() {
this._backupOperation.get()?.abort();
}

startBackup() {
this._session.keyBackup.get()?.flush();
}
}

8 changes: 4 additions & 4 deletions src/domain/session/settings/SettingsViewModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ limitations under the License.
*/

import {ViewModel} from "../../ViewModel.js";
import {SessionBackupViewModel} from "./SessionBackupViewModel.js";
import {KeyBackupViewModel} from "./KeyBackupViewModel.js";

class PushNotificationStatus {
constructor() {
Expand Down Expand Up @@ -43,7 +43,7 @@ export class SettingsViewModel extends ViewModel {
this._updateService = options.updateService;
const {client} = options;
this._client = client;
this._sessionBackupViewModel = this.track(new SessionBackupViewModel(this.childOptions({session: this._session})));
this._keyBackupViewModel = this.track(new KeyBackupViewModel(this.childOptions({session: this._session})));
this._closeUrl = this.urlCreator.urlUntilSegment("session");
this._estimate = null;
this.sentImageSizeLimit = null;
Expand Down Expand Up @@ -115,8 +115,8 @@ export class SettingsViewModel extends ViewModel {
return !!this.platform.updateService;
}

get sessionBackupViewModel() {
return this._sessionBackupViewModel;
get keyBackupViewModel() {
return this._keyBackupViewModel;
}

get storageQuota() {
Expand Down
3 changes: 2 additions & 1 deletion src/matrix/DeviceMessageHandler.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ export class DeviceMessageHandler {
async writeSync(prep, txn) {
// write olm changes
prep.olmDecryptChanges.write(txn);
await Promise.all(prep.newRoomKeys.map(key => this._megolmDecryption.writeRoomKey(key, txn)));
const didWriteValues = await Promise.all(prep.newRoomKeys.map(key => this._megolmDecryption.writeRoomKey(key, txn)));
return didWriteValues.some(didWrite => !!didWrite);
}
}

Expand Down
Loading

0 comments on commit 247d13f

Please sign in to comment.