Skip to content

Commit dd8c157

Browse files
authored
Improve fallback key behaviour (#2037)
1 parent 8bd2d64 commit dd8c157

File tree

4 files changed

+55
-10
lines changed

4 files changed

+55
-10
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@
7575
"@babel/preset-env": "^7.12.11",
7676
"@babel/preset-typescript": "^7.12.7",
7777
"@babel/register": "^7.12.10",
78-
"@matrix-org/olm": "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.3.tgz",
78+
"@matrix-org/olm": "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.7.tgz",
7979
"@types/bs58": "^4.0.1",
8080
"@types/jest": "^26.0.20",
8181
"@types/node": "12",

src/crypto/OlmDevice.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -543,13 +543,25 @@ export class OlmDevice {
543543
'readonly', [IndexedDBCryptoStore.STORE_ACCOUNT],
544544
(txn) => {
545545
this.getAccount(txn, (account: Account) => {
546-
result = JSON.parse(account.fallback_key());
546+
result = JSON.parse(account.unpublished_fallback_key());
547547
});
548548
},
549549
);
550550
return result;
551551
}
552552

553+
public async forgetOldFallbackKey(): Promise<void> {
554+
await this.cryptoStore.doTxn(
555+
'readwrite', [IndexedDBCryptoStore.STORE_ACCOUNT],
556+
(txn) => {
557+
this.getAccount(txn, (account: Account) => {
558+
account.forget_old_fallback_key();
559+
this.storeAccount(txn, account);
560+
});
561+
},
562+
);
563+
}
564+
553565
/**
554566
* Generate a new outbound session
555567
*

src/crypto/index.ts

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,7 @@ export class Crypto extends EventEmitter {
248248

249249
private oneTimeKeyCount: number;
250250
private needsNewFallback: boolean;
251+
private fallbackCleanup?: number; // setTimeout ID
251252

252253
/**
253254
* Cryptography bits
@@ -1850,8 +1851,23 @@ export class Crypto extends EventEmitter {
18501851
}
18511852

18521853
if (this.getNeedsNewFallback()) {
1853-
logger.info("generating fallback key");
1854-
await this.olmDevice.generateFallbackKey();
1854+
const fallbackKeys = await this.olmDevice.getFallbackKey();
1855+
// if fallbackKeys is non-empty, we've already generated a
1856+
// fallback key, but it hasn't been published yet, so we
1857+
// can use that instead of generating a new one
1858+
if (!fallbackKeys.curve25519 ||
1859+
Object.keys(fallbackKeys.curve25519).length == 0) {
1860+
logger.info("generating fallback key");
1861+
if (this.fallbackCleanup) {
1862+
// cancel any pending fallback cleanup because generating
1863+
// a new fallback key will already drop the old fallback
1864+
// that would have been dropped, and we don't want to kill
1865+
// the current key
1866+
clearTimeout(this.fallbackCleanup);
1867+
delete this.fallbackCleanup;
1868+
}
1869+
await this.olmDevice.generateFallbackKey();
1870+
}
18551871
}
18561872

18571873
logger.info("calling uploadOneTimeKeys");
@@ -1898,8 +1914,9 @@ export class Crypto extends EventEmitter {
18981914
private async uploadOneTimeKeys() {
18991915
const promises = [];
19001916

1901-
const fallbackJson: Record<string, IOneTimeKey> = {};
1917+
let fallbackJson: Record<string, IOneTimeKey>;
19021918
if (this.getNeedsNewFallback()) {
1919+
fallbackJson = {};
19031920
const fallbackKeys = await this.olmDevice.getFallbackKey();
19041921
for (const [keyId, key] of Object.entries(fallbackKeys.curve25519)) {
19051922
const k = { key, fallback: true };
@@ -1924,10 +1941,23 @@ export class Crypto extends EventEmitter {
19241941

19251942
await Promise.all(promises);
19261943

1927-
const res = await this.baseApis.uploadKeysRequest({
1944+
const requestBody: Record<string, any> = {
19281945
"one_time_keys": oneTimeJson,
1929-
"org.matrix.msc2732.fallback_keys": fallbackJson,
1930-
});
1946+
};
1947+
1948+
if (fallbackJson) {
1949+
requestBody["org.matrix.msc2732.fallback_keys"] = fallbackJson;
1950+
requestBody["fallback_keys"] = fallbackJson;
1951+
}
1952+
1953+
const res = await this.baseApis.uploadKeysRequest(requestBody);
1954+
1955+
if (fallbackJson) {
1956+
this.fallbackCleanup = setTimeout(() => {
1957+
delete this.fallbackCleanup;
1958+
this.olmDevice.forgetOldFallbackKey();
1959+
}, 60*60*1000);
1960+
}
19311961

19321962
await this.olmDevice.markKeysAsPublished();
19331963
return res;

src/sync.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1416,11 +1416,14 @@ export class SyncApi {
14161416
const currentCount = data.device_one_time_keys_count.signed_curve25519 || 0;
14171417
this.opts.crypto.updateOneTimeKeyCount(currentCount);
14181418
}
1419-
if (this.opts.crypto && data["org.matrix.msc2732.device_unused_fallback_key_types"]) {
1419+
if (this.opts.crypto &&
1420+
(data["device_unused_fallback_key_types"] ||
1421+
data["org.matrix.msc2732.device_unused_fallback_key_types"])) {
14201422
// The presence of device_unused_fallback_key_types indicates that the
14211423
// server supports fallback keys. If there's no unused
14221424
// signed_curve25519 fallback key we need a new one.
1423-
const unusedFallbackKeys = data["org.matrix.msc2732.device_unused_fallback_key_types"];
1425+
const unusedFallbackKeys = data["device_unused_fallback_key_types"] ||
1426+
data["org.matrix.msc2732.device_unused_fallback_key_types"];
14241427
this.opts.crypto.setNeedsNewFallback(
14251428
unusedFallbackKeys instanceof Array &&
14261429
!unusedFallbackKeys.includes("signed_curve25519"),

0 commit comments

Comments
 (0)