You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-11-26 17:03:12 +03:00
Add untested reciprocate function
This commit is contained in:
@@ -41,7 +41,7 @@ import {
|
|||||||
import {SECRET_STORAGE_ALGORITHM_V1, SecretStorage} from './SecretStorage';
|
import {SECRET_STORAGE_ALGORITHM_V1, SecretStorage} from './SecretStorage';
|
||||||
import {OutgoingRoomKeyRequestManager} from './OutgoingRoomKeyRequestManager';
|
import {OutgoingRoomKeyRequestManager} from './OutgoingRoomKeyRequestManager';
|
||||||
import {IndexedDBCryptoStore} from './store/indexeddb-crypto-store';
|
import {IndexedDBCryptoStore} from './store/indexeddb-crypto-store';
|
||||||
import {ScanQRCode, ShowQRCode} from './verification/QRCode';
|
import {ReciprocateQRCode, ScanQRCode, ShowQRCode} from './verification/QRCode';
|
||||||
import {SAS} from './verification/SAS';
|
import {SAS} from './verification/SAS';
|
||||||
import {keyFromPassphrase} from './key_passphrase';
|
import {keyFromPassphrase} from './key_passphrase';
|
||||||
import {encodeRecoveryKey} from './recoverykey';
|
import {encodeRecoveryKey} from './recoverykey';
|
||||||
@@ -55,6 +55,7 @@ const DeviceVerification = DeviceInfo.DeviceVerification;
|
|||||||
const defaultVerificationMethods = {
|
const defaultVerificationMethods = {
|
||||||
[ScanQRCode.NAME]: ScanQRCode,
|
[ScanQRCode.NAME]: ScanQRCode,
|
||||||
[ShowQRCode.NAME]: ShowQRCode,
|
[ShowQRCode.NAME]: ShowQRCode,
|
||||||
|
[ReciprocateQRCode.NAME]: ReciprocateQRCode,
|
||||||
[SAS.NAME]: SAS,
|
[SAS.NAME]: SAS,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -64,6 +65,7 @@ const defaultVerificationMethods = {
|
|||||||
export const verificationMethods = {
|
export const verificationMethods = {
|
||||||
QR_CODE_SCAN: ScanQRCode.NAME,
|
QR_CODE_SCAN: ScanQRCode.NAME,
|
||||||
QR_CODE_SHOW: ShowQRCode.NAME,
|
QR_CODE_SHOW: ShowQRCode.NAME,
|
||||||
|
RECIPROCATE_QR_CODE: ReciprocateQRCode.NAME,
|
||||||
SAS: SAS.NAME,
|
SAS: SAS.NAME,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ import {
|
|||||||
import * as qs from "qs";
|
import * as qs from "qs";
|
||||||
|
|
||||||
const MATRIXTO_REGEXP = /^(?:https?:\/\/)?(?:www\.)?matrix\.to\/#\/([#@!+][^?]+)\?(.+)$/;
|
const MATRIXTO_REGEXP = /^(?:https?:\/\/)?(?:www\.)?matrix\.to\/#\/([#@!+][^?]+)\?(.+)$/;
|
||||||
const KEY_REGEXP = /^key_([^:]+:.+)$/;
|
|
||||||
|
|
||||||
const newQRCodeError = errorFactory("m.qr_code.invalid", "Invalid QR code");
|
const newQRCodeError = errorFactory("m.qr_code.invalid", "Invalid QR code");
|
||||||
|
|
||||||
@@ -83,38 +82,34 @@ export class ScanQRCode extends Base {
|
|||||||
cancel: () => reject(newUserCancelledError()),
|
cancel: () => reject(newUserCancelledError()),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
const {action, secret, otherUserKey, keys, targetUserId} = ReciprocateQRCode.splitUrl(code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const match = code.match(MATRIXTO_REGEXP);
|
ScanQRCode.NAME = "m.qr_code.scan.v1";
|
||||||
let deviceId;
|
|
||||||
const keys = {};
|
/**
|
||||||
if (!match) {
|
* @class crypto/verification/QRCode/ReciprocateQRCode
|
||||||
throw newQRCodeError();
|
* @extends {module:crypto/verification/Base}
|
||||||
}
|
*/
|
||||||
const userId = match[1];
|
export class ReciprocateQRCode extends Base {
|
||||||
const params = match[2].split("&").map(
|
static factory(...args) {
|
||||||
(x) => x.split("=", 2).map(decodeURIComponent),
|
return new ReciprocateQRCode(...args);
|
||||||
);
|
|
||||||
let action;
|
|
||||||
for (const [name, value] of params) {
|
|
||||||
if (name === "device") {
|
|
||||||
deviceId = value;
|
|
||||||
} else if (name === "action") {
|
|
||||||
action = value;
|
|
||||||
} else {
|
|
||||||
const keyMatch = name.match(KEY_REGEXP);
|
|
||||||
if (keyMatch) {
|
|
||||||
keys[keyMatch[1]] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!deviceId || action !== "verify" || Object.keys(keys).length === 0) {
|
|
||||||
throw newQRCodeError();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async _doVerification() {
|
||||||
|
const code = await new Promise((resolve, reject) => {
|
||||||
|
this.emit("scan", {
|
||||||
|
done: resolve,
|
||||||
|
cancel: () => reject(newUserCancelledError()),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
const {secret, otherUserKey, keys, targetUserId} = ReciprocateQRCode.splitUrl(code);
|
||||||
|
|
||||||
if (!this.userId) {
|
if (!this.userId) {
|
||||||
await new Promise((resolve, reject) => {
|
await new Promise((resolve, reject) => {
|
||||||
this.emit("confirm_user_id", {
|
this.emit("confirm_user_id", {
|
||||||
userId: userId,
|
userId: targetUserId,
|
||||||
confirm: resolve,
|
confirm: resolve,
|
||||||
cancel: () => reject(newUserMismatchError()),
|
cancel: () => reject(newUserMismatchError()),
|
||||||
});
|
});
|
||||||
@@ -122,16 +117,64 @@ export class ScanQRCode extends Base {
|
|||||||
} else if (this.userId !== userId) {
|
} else if (this.userId !== userId) {
|
||||||
throw newUserMismatchError({
|
throw newUserMismatchError({
|
||||||
expected: this.userId,
|
expected: this.userId,
|
||||||
actual: userId,
|
actual: targetUserId,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
await this._verifyKeys(userId, keys, (keyId, device, key) => {
|
const crossSigningInfo = this._baseApis.getStoredCrossSigningInfo(targetUserId);
|
||||||
|
if (!crossSigningInfo) throw new Error("Missing cross signing info for user"); // this shouldn't happen by now
|
||||||
|
if (crossSigningInfo.getId("master") !== otherUserKey) {
|
||||||
|
throw newKeyMismatchError();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (secret !== this.request.encodedSharedSecret) {
|
||||||
|
throw newQRCodeError();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify our own keys that were sent in this code too
|
||||||
|
await this._verifyKeys(this._baseApis.getUserId(), keys, (keyId, device, key) => {
|
||||||
|
if (device.keys[keyId] !== key) {
|
||||||
|
throw newKeyMismatchError();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await this._verifyKeys(targetUserId, [otherUserKey, otherUserKey], (keyId, device, key) => {
|
||||||
if (device.keys[keyId] !== key) {
|
if (device.keys[keyId] !== key) {
|
||||||
throw newKeyMismatchError();
|
throw newKeyMismatchError();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static splitUrl(code) {
|
||||||
|
const match = code.match(MATRIXTO_REGEXP);
|
||||||
|
const keys = {};
|
||||||
|
if (!match) {
|
||||||
|
throw newQRCodeError();
|
||||||
|
}
|
||||||
|
const targetUserId = match[1];
|
||||||
|
const params = match[2].split("&").map(
|
||||||
|
(x) => x.split("=", 2).map(decodeURIComponent),
|
||||||
|
);
|
||||||
|
let action;
|
||||||
|
let otherUserKey;
|
||||||
|
let secret;
|
||||||
|
for (const [name, value] of params) {
|
||||||
|
if (name === "action") {
|
||||||
|
action = value;
|
||||||
|
} else if (name.startsWith("key_")) {
|
||||||
|
keys[name.substring("key_".length)] = value;
|
||||||
|
} else if (name === "other_user_key") {
|
||||||
|
otherUserKey = value;
|
||||||
|
} else if (name === "secret") {
|
||||||
|
secret = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!secret || !otherUserKey || action !== "verify" || Object.keys(keys).length === 0) {
|
||||||
|
throw newQRCodeError();
|
||||||
}
|
}
|
||||||
|
|
||||||
ScanQRCode.NAME = "m.qr_code.scan.v1";
|
return {action, secret, otherUserKey, keys, targetUserId};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ReciprocateQRCode.NAME = "m.reciprocate.v1";
|
||||||
|
|||||||
Reference in New Issue
Block a user