You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-08-07 23:02:56 +03:00
Rework to hold cross-signing keys in JS SDK as needed
This commit is contained in:
@@ -246,18 +246,11 @@ describe("Secrets", function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("bootstraps when no storage or cross-signing keys locally", async function() {
|
it("bootstraps when no storage or cross-signing keys locally", async function() {
|
||||||
let keys = {};
|
|
||||||
const bob = await makeTestClient(
|
const bob = await makeTestClient(
|
||||||
{
|
{
|
||||||
userId: "@bob:example.com",
|
userId: "@bob:example.com",
|
||||||
deviceId: "bob1",
|
deviceId: "bob1",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
cryptoCallbacks: {
|
|
||||||
getCrossSigningKey: t => keys[t],
|
|
||||||
saveCrossSigningKeys: k => keys = k,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
bob.uploadDeviceSigningKeys = async () => {};
|
bob.uploadDeviceSigningKeys = async () => {};
|
||||||
bob.uploadKeySignatures = async () => {};
|
bob.uploadKeySignatures = async () => {};
|
||||||
@@ -287,7 +280,6 @@ describe("Secrets", function() {
|
|||||||
const storagePublicKey = decryption.generate_key();
|
const storagePublicKey = decryption.generate_key();
|
||||||
const storagePrivateKey = decryption.get_private_key();
|
const storagePrivateKey = decryption.get_private_key();
|
||||||
|
|
||||||
let crossSigningKeys = {};
|
|
||||||
const bob = await makeTestClient(
|
const bob = await makeTestClient(
|
||||||
{
|
{
|
||||||
userId: "@bob:example.com",
|
userId: "@bob:example.com",
|
||||||
@@ -295,8 +287,6 @@ describe("Secrets", function() {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
cryptoCallbacks: {
|
cryptoCallbacks: {
|
||||||
getCrossSigningKey: t => crossSigningKeys[t],
|
|
||||||
saveCrossSigningKeys: k => crossSigningKeys = k,
|
|
||||||
getSecretStorageKey: request => {
|
getSecretStorageKey: request => {
|
||||||
const defaultKeyId = bob.getDefaultSecretStorageKeyId();
|
const defaultKeyId = bob.getDefaultSecretStorageKeyId();
|
||||||
expect(Object.keys(request.keys)).toEqual([defaultKeyId]);
|
expect(Object.keys(request.keys)).toEqual([defaultKeyId]);
|
||||||
@@ -318,6 +308,7 @@ describe("Secrets", function() {
|
|||||||
]);
|
]);
|
||||||
this.emit("accountData", event);
|
this.emit("accountData", event);
|
||||||
};
|
};
|
||||||
|
bob._crypto.checkKeyBackup = async () => {};
|
||||||
|
|
||||||
const crossSigning = bob._crypto._crossSigningInfo;
|
const crossSigning = bob._crypto._crossSigningInfo;
|
||||||
const secretStorage = bob._crypto._secretStorage;
|
const secretStorage = bob._crypto._secretStorage;
|
||||||
@@ -328,6 +319,10 @@ describe("Secrets", function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Clear local cross-signing keys and read from secret storage
|
// Clear local cross-signing keys and read from secret storage
|
||||||
|
bob._crypto._deviceList.storeCrossSigningForUser(
|
||||||
|
"@bob:example.com",
|
||||||
|
crossSigning.toStorage(),
|
||||||
|
);
|
||||||
crossSigning.keys = {};
|
crossSigning.keys = {};
|
||||||
await bob.bootstrapSecretStorage();
|
await bob.bootstrapSecretStorage();
|
||||||
|
|
||||||
|
@@ -181,7 +181,8 @@ function keyFromRecoverySession(session, decryptionKey) {
|
|||||||
* The cross-signing API is currently UNSTABLE and may change without notice.
|
* The cross-signing API is currently UNSTABLE and may change without notice.
|
||||||
*
|
*
|
||||||
* @param {function} [opts.cryptoCallbacks.getCrossSigningKey]
|
* @param {function} [opts.cryptoCallbacks.getCrossSigningKey]
|
||||||
* Optional (required for cross-signing). Function to call when a cross-signing private key is needed.
|
* Optional. Function to call when a cross-signing private key is needed.
|
||||||
|
* Secure Secret Storage will be used by default if this is unset.
|
||||||
* Args:
|
* Args:
|
||||||
* {string} type The type of key needed. Will be one of "master",
|
* {string} type The type of key needed. Will be one of "master",
|
||||||
* "self_signing", or "user_signing"
|
* "self_signing", or "user_signing"
|
||||||
@@ -193,8 +194,8 @@ function keyFromRecoverySession(session, decryptionKey) {
|
|||||||
* UInt8Array or rejects with an error.
|
* UInt8Array or rejects with an error.
|
||||||
*
|
*
|
||||||
* @param {function} [opts.cryptoCallbacks.saveCrossSigningKeys]
|
* @param {function} [opts.cryptoCallbacks.saveCrossSigningKeys]
|
||||||
* Optional (required for cross-signing). Called when new private keys
|
* Optional. Called when new private keys for cross-signing need to be saved.
|
||||||
* for cross-signing need to be saved.
|
* Secure Secret Storage will be used by default if this is unset.
|
||||||
* Args:
|
* Args:
|
||||||
* {object} keys the private keys to save. Map of key name to private key
|
* {object} keys the private keys to save. Map of key name to private key
|
||||||
* as a UInt8Array. The getPrivateKey callback above will be called
|
* as a UInt8Array. The getPrivateKey callback above will be called
|
||||||
@@ -298,7 +299,7 @@ function MatrixClient(opts) {
|
|||||||
this._cryptoStore = opts.cryptoStore;
|
this._cryptoStore = opts.cryptoStore;
|
||||||
this._sessionStore = opts.sessionStore;
|
this._sessionStore = opts.sessionStore;
|
||||||
this._verificationMethods = opts.verificationMethods;
|
this._verificationMethods = opts.verificationMethods;
|
||||||
this._cryptoCallbacks = opts.cryptoCallbacks;
|
this._cryptoCallbacks = opts.cryptoCallbacks || {};
|
||||||
|
|
||||||
this._forceTURN = opts.forceTURN || false;
|
this._forceTURN = opts.forceTURN || false;
|
||||||
this._fallbackICEServerAllowed = opts.fallbackICEServerAllowed || false;
|
this._fallbackICEServerAllowed = opts.fallbackICEServerAllowed || false;
|
||||||
|
@@ -115,8 +115,8 @@ export class CrossSigningInfo extends EventEmitter {
|
|||||||
*/
|
*/
|
||||||
isStoredInSecretStorage(secretStorage) {
|
isStoredInSecretStorage(secretStorage) {
|
||||||
let stored = true;
|
let stored = true;
|
||||||
for (const name of ["master", "self_signing", "user_signing"]) {
|
for (const type of ["master", "self_signing", "user_signing"]) {
|
||||||
stored &= secretStorage.isStored(`m.cross_signing.${name}`, false);
|
stored &= secretStorage.isStored(`m.cross_signing.${type}`, false);
|
||||||
}
|
}
|
||||||
return stored;
|
return stored;
|
||||||
}
|
}
|
||||||
@@ -126,13 +126,13 @@ export class CrossSigningInfo extends EventEmitter {
|
|||||||
* typically called in conjunction with the creation of new cross-signing
|
* typically called in conjunction with the creation of new cross-signing
|
||||||
* keys.
|
* keys.
|
||||||
*
|
*
|
||||||
|
* @param {object} keys The keys to store
|
||||||
* @param {SecretStorage} secretStorage The secret store using account data
|
* @param {SecretStorage} secretStorage The secret store using account data
|
||||||
*/
|
*/
|
||||||
async storeInSecretStorage(secretStorage) {
|
static async storeInSecretStorage(keys, secretStorage) {
|
||||||
const getKey = this._callbacks.getCrossSigningKey;
|
for (const type of Object.keys(keys)) {
|
||||||
for (const name of ["master", "self_signing", "user_signing"]) {
|
const encodedKey = encodeBase64(keys[type]);
|
||||||
const encodedKey = encodeBase64(await getKey(name));
|
await secretStorage.store(`m.cross_signing.${type}`, encodedKey);
|
||||||
await secretStorage.store(`m.cross_signing.${name}`, encodedKey);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,54 +140,14 @@ export class CrossSigningInfo extends EventEmitter {
|
|||||||
* Get private keys from secret storage created by some other device. This
|
* Get private keys from secret storage created by some other device. This
|
||||||
* also passes the private keys to the app-specific callback.
|
* also passes the private keys to the app-specific callback.
|
||||||
*
|
*
|
||||||
|
* @param {string} type The type of key to get. One of "master",
|
||||||
|
* "self_signing", or "user_signing".
|
||||||
* @param {SecretStorage} secretStorage The secret store using account data
|
* @param {SecretStorage} secretStorage The secret store using account data
|
||||||
|
* @return {Uint8Array} The private key
|
||||||
*/
|
*/
|
||||||
async getFromSecretStorage(secretStorage) {
|
static async getFromSecretStorage(type, secretStorage) {
|
||||||
if (!this._callbacks.saveCrossSigningKeys) {
|
const encodedKey = await secretStorage.get(`m.cross_signing.${type}`);
|
||||||
throw new Error("No saveCrossSigningKeys callback supplied");
|
return decodeBase64(encodedKey);
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve private keys from secret storage
|
|
||||||
const privateKeys = {};
|
|
||||||
for (const name of ["master", "self_signing", "user_signing"]) {
|
|
||||||
const encodedKey = await secretStorage.get(`m.cross_signing.${name}`);
|
|
||||||
privateKeys[name] = decodeBase64(encodedKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Regenerate public keys from private keys
|
|
||||||
// XXX: Do we want to _also_ download public keys from the homeserver to
|
|
||||||
// verify they agree...?
|
|
||||||
// See also https://github.com/vector-im/riot-web/issues/11558
|
|
||||||
const signings = {};
|
|
||||||
const publicKeys = {};
|
|
||||||
const keys = {};
|
|
||||||
try {
|
|
||||||
for (const name of ["master", "self_signing", "user_signing"]) {
|
|
||||||
signings[name] = new global.Olm.PkSigning();
|
|
||||||
publicKeys[name] = signings[name].init_with_seed(privateKeys[name]);
|
|
||||||
keys[name] = {
|
|
||||||
user_id: this.userId,
|
|
||||||
usage: [name],
|
|
||||||
keys: {
|
|
||||||
['ed25519:' + publicKeys[name]]: publicKeys[name],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
if (name !== "master") {
|
|
||||||
pkSign(
|
|
||||||
keys[name], signings["master"],
|
|
||||||
this.userId, publicKeys["master"],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
for (const signing of Object.values(signings)) {
|
|
||||||
signing.free();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save public keys locally and private keys via app callback
|
|
||||||
Object.assign(this.keys, keys);
|
|
||||||
this._callbacks.saveCrossSigningKeys(privateKeys);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -167,8 +167,6 @@ export default class SecretStorage extends EventEmitter {
|
|||||||
return keyInfo && keyInfo.getContent();
|
return keyInfo && keyInfo.getContent();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: need a function to get all the secret keys
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Store an encrypted secret on the server
|
* Store an encrypted secret on the server
|
||||||
*
|
*
|
||||||
|
@@ -245,13 +245,20 @@ export default function Crypto(baseApis, sessionStore, userId, deviceId,
|
|||||||
|
|
||||||
this._verificationTransactions = new Map();
|
this._verificationTransactions = new Map();
|
||||||
|
|
||||||
this._crossSigningInfo = new CrossSigningInfo(
|
const cryptoCallbacks = this._baseApis._cryptoCallbacks || {};
|
||||||
userId, this._baseApis._cryptoCallbacks,
|
|
||||||
);
|
this._crossSigningInfo = new CrossSigningInfo(userId, cryptoCallbacks);
|
||||||
|
|
||||||
this._secretStorage = new SecretStorage(
|
this._secretStorage = new SecretStorage(
|
||||||
baseApis, this._baseApis._cryptoCallbacks, this._crossSigningInfo,
|
baseApis, cryptoCallbacks, this._crossSigningInfo,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Assuming no app-supplied callback, default to getting from SSSS.
|
||||||
|
if (!cryptoCallbacks.getCrossSigningKey) {
|
||||||
|
cryptoCallbacks.getCrossSigningKey = async (type) => {
|
||||||
|
return CrossSigningInfo.getFromSecretStorage(type, this._secretStorage);
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
utils.inherits(Crypto, EventEmitter);
|
utils.inherits(Crypto, EventEmitter);
|
||||||
|
|
||||||
@@ -377,55 +384,75 @@ Crypto.prototype.bootstrapSecretStorage = async function({
|
|||||||
// key with the cross-signing master key. The cross-signing master key is also used
|
// key with the cross-signing master key. The cross-signing master key is also used
|
||||||
// to verify the signature on the SSSS default key when adding secrets, so we
|
// to verify the signature on the SSSS default key when adding secrets, so we
|
||||||
// effectively need it for both reading and writing secrets.
|
// effectively need it for both reading and writing secrets.
|
||||||
let crossSigningKeysReset = false;
|
let crossSigningPrivateKeys = {};
|
||||||
if (
|
|
||||||
!this._crossSigningInfo.getId() ||
|
// If we happen to reset cross-signing keys here, then we want access to the
|
||||||
!await this._baseApis._cryptoCallbacks.getCrossSigningKey("master")
|
// cross-signing private keys, but only for the scope of this method, so we
|
||||||
) {
|
// use temporary callbacks to weave the them through the various APIs.
|
||||||
logger.log(
|
const appCallbacks = Object.assign({}, this._baseApis._cryptoCallbacks);
|
||||||
"Cross-signing public and/or private keys not found on device, " +
|
|
||||||
"checking secret storage for private keys",
|
try {
|
||||||
);
|
if (
|
||||||
if (this._crossSigningInfo.isStoredInSecretStorage(this._secretStorage)) {
|
!this._crossSigningInfo.getId() ||
|
||||||
logger.log("Cross-signing private keys found in secret storage");
|
!this._crossSigningInfo.isStoredInSecretStorage(this._secretStorage)
|
||||||
await this._getCrossSigningKeysFromSecretStorage();
|
) {
|
||||||
} else {
|
|
||||||
logger.log(
|
logger.log(
|
||||||
"Cross-signing private keys not found in secret storage, " +
|
"Cross-signing public and/or private keys not found, " +
|
||||||
"creating new keys",
|
"checking secret storage for private keys",
|
||||||
);
|
);
|
||||||
await this.resetCrossSigningKeys(
|
if (this._crossSigningInfo.isStoredInSecretStorage(this._secretStorage)) {
|
||||||
CrossSigningLevel.MASTER,
|
logger.log("Cross-signing private keys found in secret storage");
|
||||||
{ authUploadDeviceSigningKeys },
|
await this.checkOwnCrossSigningTrust();
|
||||||
);
|
} else {
|
||||||
crossSigningKeysReset = true;
|
logger.log(
|
||||||
|
"Cross-signing private keys not found in secret storage, " +
|
||||||
|
"creating new keys",
|
||||||
|
);
|
||||||
|
this._baseApis._cryptoCallbacks.saveCrossSigningKeys =
|
||||||
|
keys => crossSigningPrivateKeys = keys;
|
||||||
|
this._baseApis._cryptoCallbacks.getCrossSigningKey =
|
||||||
|
name => crossSigningPrivateKeys[name];
|
||||||
|
await this.resetCrossSigningKeys(
|
||||||
|
CrossSigningLevel.MASTER,
|
||||||
|
{ authUploadDeviceSigningKeys },
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Check if Secure Secret Storage has a default key. If we don't have one, create the
|
// Check if Secure Secret Storage has a default key. If we don't have one, create
|
||||||
// default key (which will also be signed by the cross-signing master key).
|
// the default key (which will also be signed by the cross-signing master key).
|
||||||
if (!this.hasSecretStorageKey()) {
|
if (!this.hasSecretStorageKey()) {
|
||||||
logger.log("Secret storage default key not found, creating new key");
|
logger.log("Secret storage default key not found, creating new key");
|
||||||
const keyOptions = await createSecretStorageKey();
|
const keyOptions = await createSecretStorageKey();
|
||||||
const newKeyId = await this.addSecretStorageKey(
|
const newKeyId = await this.addSecretStorageKey(
|
||||||
SECRET_STORAGE_ALGORITHM_V1,
|
SECRET_STORAGE_ALGORITHM_V1,
|
||||||
keyOptions,
|
keyOptions,
|
||||||
);
|
);
|
||||||
await this.setDefaultSecretStorageKeyId(newKeyId);
|
await this.setDefaultSecretStorageKeyId(newKeyId);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If cross-signing keys were reset, store them in Secure Secret Storage.
|
// If cross-signing keys were reset, store them in Secure Secret Storage.
|
||||||
// This is done in a separate step so we can ensure secret storage has its
|
// This is done in a separate step so we can ensure secret storage has its
|
||||||
// own key first.
|
// own key first.
|
||||||
// XXX: We need to think about how to re-do these steps if they fail.
|
// XXX: We need to think about how to re-do these steps if they fail.
|
||||||
if (crossSigningKeysReset) {
|
// See also https://github.com/vector-im/riot-web/issues/11635
|
||||||
logger.log("Storing cross-signing private keys in secret storage");
|
if (crossSigningPrivateKeys) {
|
||||||
// SSSS expects its keys to be signed by cross-signing master key.
|
logger.log("Storing cross-signing private keys in secret storage");
|
||||||
// Since we have just reset cross-signing keys, we need to re-sign the
|
// SSSS expects its keys to be signed by cross-signing master key.
|
||||||
// SSSS default key with the new cross-signing master key so that the
|
// Since we have just reset cross-signing keys, we need to re-sign the
|
||||||
// following storage step can proceed.
|
// SSSS default key with the new cross-signing master key so that the
|
||||||
await this._secretStorage.signKey();
|
// following storage step can proceed.
|
||||||
await this._crossSigningInfo.storeInSecretStorage(this._secretStorage);
|
await this._secretStorage.signKey();
|
||||||
|
// Assuming no app-supplied callback, default to storing in SSSS.
|
||||||
|
if (!appCallbacks.saveCrossSigningKeys) {
|
||||||
|
await CrossSigningInfo.storeInSecretStorage(
|
||||||
|
crossSigningPrivateKeys,
|
||||||
|
this._secretStorage,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
this._baseApis._cryptoCallbacks = appCallbacks;
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.log("Secure Secret Storage ready");
|
logger.log("Secure Secret Storage ready");
|
||||||
@@ -559,41 +586,6 @@ Crypto.prototype.resetCrossSigningKeys = async function(level, {
|
|||||||
logger.info("Cross-signing key reset complete");
|
logger.info("Cross-signing key reset complete");
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* If cross-signing keys are known to exist in secret storage, this will get
|
|
||||||
* them and store them on this device as trusted.
|
|
||||||
*/
|
|
||||||
Crypto.prototype._getCrossSigningKeysFromSecretStorage = async function() {
|
|
||||||
logger.info("Getting cross-signing keys from secret storage");
|
|
||||||
// Copy old keys (usually empty) in case we need to revert
|
|
||||||
const oldKeys = Object.assign({}, this._crossSigningInfo.keys);
|
|
||||||
try {
|
|
||||||
await this._crossSigningInfo.getFromSecretStorage(this._secretStorage);
|
|
||||||
// XXX: Do we also need to sign the cross-signing master key with the
|
|
||||||
// device key as in `resetCrossSigningKeys`?
|
|
||||||
|
|
||||||
// write a copy locally so we know these are trusted keys
|
|
||||||
await this._cryptoStore.doTxn(
|
|
||||||
'readwrite', [IndexedDBCryptoStore.STORE_ACCOUNT],
|
|
||||||
(txn) => {
|
|
||||||
this._cryptoStore.storeCrossSigningKeys(txn, this._crossSigningInfo.keys);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
} catch (e) {
|
|
||||||
// If anything failed here, revert the keys so we know to try again from the start
|
|
||||||
// next time.
|
|
||||||
logger.error(
|
|
||||||
"Getting cross-signing keys from secret storage failed, " +
|
|
||||||
"revert to previous keys", e,
|
|
||||||
);
|
|
||||||
this._crossSigningInfo.keys = oldKeys;
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
this._baseApis.emit("crossSigning.keysChanged", {});
|
|
||||||
await this._afterCrossSigningLocalKeyChange();
|
|
||||||
logger.info("Cross-signing keys restored from secret storage");
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Run various follow-up actions after cross-signing keys have changed locally
|
* Run various follow-up actions after cross-signing keys have changed locally
|
||||||
* (either by resetting the keys for the account or bye getting them from secret
|
* (either by resetting the keys for the account or bye getting them from secret
|
||||||
@@ -817,10 +809,10 @@ Crypto.prototype.checkOwnCrossSigningTrust = async function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const seenPubkey = newCrossSigning.getId();
|
const seenPubkey = newCrossSigning.getId();
|
||||||
const changed = this._crossSigningInfo.getId() !== seenPubkey;
|
const masterChanged = this._crossSigningInfo.getId() !== seenPubkey;
|
||||||
if (changed) {
|
if (masterChanged) {
|
||||||
// try to get the private key if the master key changed
|
// try to get the private key if the master key changed
|
||||||
logger.info("Got new master key", seenPubkey);
|
logger.info("Got new master public key", seenPubkey);
|
||||||
|
|
||||||
let signing = null;
|
let signing = null;
|
||||||
try {
|
try {
|
||||||
@@ -828,6 +820,9 @@ Crypto.prototype.checkOwnCrossSigningTrust = async function() {
|
|||||||
'master', seenPubkey,
|
'master', seenPubkey,
|
||||||
);
|
);
|
||||||
signing = ret[1];
|
signing = ret[1];
|
||||||
|
if (!signing) {
|
||||||
|
throw new Error("Cross-signing master private key not available");
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
signing.free();
|
signing.free();
|
||||||
}
|
}
|
||||||
@@ -862,7 +857,7 @@ Crypto.prototype.checkOwnCrossSigningTrust = async function() {
|
|||||||
logger.info("Got new user-signing key", newCrossSigning.getId("user_signing"));
|
logger.info("Got new user-signing key", newCrossSigning.getId("user_signing"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (changed) {
|
if (masterChanged) {
|
||||||
await this._signObject(this._crossSigningInfo.keys.master);
|
await this._signObject(this._crossSigningInfo.keys.master);
|
||||||
keySignatures[this._crossSigningInfo.getId()]
|
keySignatures[this._crossSigningInfo.getId()]
|
||||||
= this._crossSigningInfo.keys.master;
|
= this._crossSigningInfo.keys.master;
|
||||||
@@ -874,6 +869,11 @@ Crypto.prototype.checkOwnCrossSigningTrust = async function() {
|
|||||||
|
|
||||||
this.emit("userTrustStatusChanged", userId, this.checkUserTrust(userId));
|
this.emit("userTrustStatusChanged", userId, this.checkUserTrust(userId));
|
||||||
|
|
||||||
|
if (masterChanged) {
|
||||||
|
this._baseApis.emit("crossSigning.keysChanged", {});
|
||||||
|
await this._afterCrossSigningLocalKeyChange();
|
||||||
|
}
|
||||||
|
|
||||||
// Now we may be able to trust our key backup
|
// Now we may be able to trust our key backup
|
||||||
await this.checkKeyBackup();
|
await this.checkKeyBackup();
|
||||||
// FIXME: if we previously trusted the backup, should we automatically sign
|
// FIXME: if we previously trusted the backup, should we automatically sign
|
||||||
|
Reference in New Issue
Block a user