Skip to content

Commit

Permalink
Merge branch 'develop' into johannes/fix-node-example
Browse files Browse the repository at this point in the history
  • Loading branch information
Johennes authored Sep 13, 2024
2 parents 397f73c + 8cf5df7 commit 7508b6a
Show file tree
Hide file tree
Showing 18 changed files with 175 additions and 73 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/downstream-end-to-end-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@ concurrency:
jobs:
playwright:
name: Playwright
uses: matrix-org/matrix-react-sdk/.github/workflows/end-to-end-tests.yaml@develop
uses: element-hq/matrix-react-sdk/.github/workflows/end-to-end-tests.yaml@develop
permissions:
actions: read
issues: read
pull-requests: read
with:
matrix-js-sdk-sha: ${{ github.sha }}
react-sdk-repository: matrix-org/matrix-react-sdk
react-sdk-repository: element-hq/matrix-react-sdk
# We only want to run the playwright tests on merge queue to prevent regressions
# from creeping in. They take a long time to run and consume multiple concurrent runners.
skip: ${{ github.event_name != 'merge_group' }}
2 changes: 1 addition & 1 deletion .github/workflows/notify-downstream.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
include:
- repo: element-hq/element-web
event: element-web-notify
- repo: matrix-org/matrix-react-sdk
- repo: element-hq/matrix-react-sdk
event: upstream-sdk-notify

runs-on: ubuntu-latest
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
with:
final: ${{ inputs.mode == 'final' }}
npm: ${{ inputs.npm }}
downstreams: '["matrix-org/matrix-react-sdk", "element-hq/element-web"]'
downstreams: '["element-hq/matrix-react-sdk", "element-hq/element-web"]'

docs:
name: Publish Documentation
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ jobs:
matrix-react-sdk:
name: Downstream test matrix-react-sdk
if: github.event_name == 'merge_group'
uses: matrix-org/matrix-react-sdk/.github/workflows/tests.yml@develop
uses: element-hq/matrix-react-sdk/.github/workflows/tests.yml@develop
with:
disable_coverage: true
matrix-js-sdk-sha: ${{ github.sha }}
Expand Down
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
Changes in [34.5.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v34.5.0) (2024-09-10)
==================================================================================================
## 🦖 Deprecations

* Deprecate unused callback hooks `CryptoCallbacks.onSecretRequested` and `CryptoCallbacks.getDehydrationKey` ([#4376](https://github.com/matrix-org/matrix-js-sdk/pull/4376)). Contributed by @richvdh.


Changes in [34.4.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v34.4.0) (2024-08-27)
==================================================================================================
## ✨ Features
Expand Down
7 changes: 3 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "matrix-js-sdk",
"version": "34.4.0",
"version": "34.5.0",
"description": "Matrix Client-Server SDK for Javascript",
"engines": {
"node": ">=20.0.0"
Expand Down Expand Up @@ -50,7 +50,7 @@
],
"dependencies": {
"@babel/runtime": "^7.12.5",
"@matrix-org/matrix-sdk-crypto-wasm": "^7.0.0",
"@matrix-org/matrix-sdk-crypto-wasm": "^8.0.0",
"@matrix-org/olm": "3.2.15",
"another-json": "^0.2.0",
"bs58": "^6.0.0",
Expand Down Expand Up @@ -127,6 +127,5 @@
"outputDirectory": "coverage",
"outputName": "jest-sonar-report.xml",
"relativePaths": true
},
"typings": "./lib/index.d.ts"
}
}
44 changes: 44 additions & 0 deletions spec/unit/crypto-api/recovery-key.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright 2024 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { decodeRecoveryKey, encodeRecoveryKey } from "../../../src/crypto-api";

describe("recovery key", () => {
describe("decodeRecoveryKey", () => {
it("should thrown an incorrect length error", () => {
const key = [0, 1];
const encodedKey = encodeRecoveryKey(key)!;

expect(() => decodeRecoveryKey(encodedKey)).toThrow("Incorrect length");
});

it("should thrown an incorrect parity", () => {
const key = Array.from({ length: 32 }, (_, i) => i);
let encodedKey = encodeRecoveryKey(key)!;
// Mutate the encoded key to have incorrect parity
encodedKey = encodedKey.replace("EsSz", "EsSZ");

expect(() => decodeRecoveryKey(encodedKey!)).toThrow("Incorrect parity");
});

it("should decode a valid encoded key", () => {
const key = Array.from({ length: 32 }, (_, i) => i);
const encodedKey = encodeRecoveryKey(key)!;

expect(decodeRecoveryKey(encodedKey)).toEqual(new Uint8Array(key));
});
});
});
16 changes: 14 additions & 2 deletions src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@ import {
isCryptoAvailable,
} from "./crypto/index.ts";
import { DeviceInfo } from "./crypto/deviceinfo.ts";
import { decodeRecoveryKey } from "./crypto/recoverykey.ts";
import { keyFromAuthData } from "./crypto/key_passphrase.ts";
import { User, UserEvent, UserEventHandlerMap } from "./models/user.ts";
import { getHttpUriForMxc } from "./content-repo.ts";
Expand Down Expand Up @@ -223,7 +222,13 @@ import { LocalNotificationSettings } from "./@types/local_notifications.ts";
import { buildFeatureSupportMap, Feature, ServerSupport } from "./feature.ts";
import { BackupDecryptor, CryptoBackend } from "./common-crypto/CryptoBackend.ts";
import { RUST_SDK_STORE_PREFIX } from "./rust-crypto/constants.ts";
import { BootstrapCrossSigningOpts, CrossSigningKeyInfo, CryptoApi, ImportRoomKeysOpts } from "./crypto-api/index.ts";
import {
BootstrapCrossSigningOpts,
CrossSigningKeyInfo,
CryptoApi,
decodeRecoveryKey,
ImportRoomKeysOpts,
} from "./crypto-api/index.ts";
import { DeviceInfoMap } from "./crypto/DeviceList.ts";
import {
AddSecretStorageKeyOpts,
Expand Down Expand Up @@ -3627,6 +3632,12 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
return this.crypto.backupManager.flagAllGroupSessionsForBackup();
}

/**
* Return true if recovery key is valid.
* Try to decode the recovery key and check if it's successful.
* @param recoveryKey
* @deprecated Use {@link decodeRecoveryKey} directly
*/
public isValidRecoveryKey(recoveryKey: string): boolean {
try {
decodeRecoveryKey(recoveryKey);
Expand Down Expand Up @@ -3658,6 +3669,7 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
*
* @param recoveryKey - The recovery key
* @returns key backup key
* @deprecated Use {@link decodeRecoveryKey} directly
*/
public keyBackupKeyFromRecoveryKey(recoveryKey: string): Uint8Array {
return decodeRecoveryKey(recoveryKey);
Expand Down
1 change: 1 addition & 0 deletions src/crypto-api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -967,3 +967,4 @@ export interface OwnDeviceKeys {

export * from "./verification.ts";
export * from "./keybackup.ts";
export * from "./recovery-key.ts";
69 changes: 69 additions & 0 deletions src/crypto-api/recovery-key.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* Copyright 2024 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import bs58 from "bs58";

// picked arbitrarily but to try & avoid clashing with any bitcoin ones
// (which are also base58 encoded, but bitcoin's involve a lot more hashing)
const OLM_RECOVERY_KEY_PREFIX = [0x8b, 0x01];
const KEY_SIZE = 32;

/**
* Encode a recovery key using the Matrix {@link https://spec.matrix.org/v1.11/appendices/#cryptographic-key-representation | Cryptographic key representation}
* @param key
*/
export function encodeRecoveryKey(key: ArrayLike<number>): string | undefined {
const buf = Buffer.alloc(OLM_RECOVERY_KEY_PREFIX.length + key.length + 1);
buf.set(OLM_RECOVERY_KEY_PREFIX, 0);
buf.set(key, OLM_RECOVERY_KEY_PREFIX.length);

let parity = 0;
for (let i = 0; i < buf.length - 1; ++i) {
parity ^= buf[i];
}
buf[buf.length - 1] = parity;
const base58key = bs58.encode(buf);

return base58key.match(/.{1,4}/g)?.join(" ");
}

/**
* Decode a recovery key encoded with the Matrix {@link https://spec.matrix.org/v1.11/appendices/#cryptographic-key-representation | Cryptographic key representation} encoding.
* @param recoveryKey
*/
export function decodeRecoveryKey(recoveryKey: string): Uint8Array {
const result = bs58.decode(recoveryKey.replace(/ /g, ""));

let parity = 0;
for (const b of result) {
parity ^= b;
}
if (parity !== 0) {
throw new Error("Incorrect parity");
}

for (let i = 0; i < OLM_RECOVERY_KEY_PREFIX.length; ++i) {
if (result[i] !== OLM_RECOVERY_KEY_PREFIX[i]) {
throw new Error("Incorrect prefix");
}
}

if (result.length !== OLM_RECOVERY_KEY_PREFIX.length + KEY_SIZE + 1) {
throw new Error("Incorrect length");
}

return Uint8Array.from(result.slice(OLM_RECOVERY_KEY_PREFIX.length, OLM_RECOVERY_KEY_PREFIX.length + KEY_SIZE));
}
23 changes: 15 additions & 8 deletions src/crypto/aes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,17 @@ export interface IEncryptedPayload {
}

/**
* encrypt a string
* Encrypt a string using AES-CTR.
*
* @param data - the plaintext to encrypt
* @param key - the encryption key to use
* @param name - the name of the secret
* @param ivStr - the initialization vector to use
* @param key - the encryption key to use as an input to the HKDF function which is used to derive the AES key for
* encryption. Obviously, the same key must be provided when decrypting.
* @param name - the name of the secret. Used as an input to the HKDF operation which is used to derive the AES key,
* so again the same value must be provided when decrypting.
* @param ivStr - the base64-encoded initialization vector to use. If not supplied, a random one will be generated.
*
* @returns The encrypted result, including the ciphertext itself, the initialization vector (as supplied in `ivStr`,
* or generated), and an HMAC on the ciphertext — all base64-encoded.
*/
export async function encryptAES(
data: string,
Expand Down Expand Up @@ -79,11 +84,13 @@ export async function encryptAES(
}

/**
* decrypt a string
* Decrypt an AES-encrypted string.
*
* @param data - the encrypted data
* @param key - the encryption key to use
* @param name - the name of the secret
* @param data - the encrypted data, returned by {@link encryptAES}.
* @param key - the encryption key to use as an input to the HKDF function which is used to derive the AES key. Must
* be the same as provided to {@link encryptAES}.
* @param name - the name of the secret. Also used as an input to the HKDF operation which is used to derive the AES
* key, so again must be the same as provided to {@link encryptAES}.
*/
export async function decryptAES(data: IEncryptedPayload, key: Uint8Array, name: string): Promise<string> {
const [aesKey, hmacKey] = await deriveKeys(key, name);
Expand Down
2 changes: 1 addition & 1 deletion src/crypto/backup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import { DeviceTrustLevel } from "./CrossSigning.ts";
import { keyFromPassphrase } from "./key_passphrase.ts";
import { encodeUri, safeSet, sleep } from "../utils.ts";
import { IndexedDBCryptoStore } from "./store/indexeddb-crypto-store.ts";
import { encodeRecoveryKey } from "./recoverykey.ts";
import { calculateKeyCheck, decryptAES, encryptAES, IEncryptedPayload } from "./aes.ts";
import {
Curve25519SessionData,
Expand All @@ -41,6 +40,7 @@ import { CryptoEvent } from "./index.ts";
import { ClientPrefix, HTTPError, MatrixError, Method } from "../http-api/index.ts";
import { BackupTrustInfo } from "../crypto-api/keybackup.ts";
import { BackupDecryptor } from "../common-crypto/CryptoBackend.ts";
import { encodeRecoveryKey } from "../crypto-api/index.ts";

const KEY_BACKUP_KEYS_PER_REQUEST = 200;
const KEY_BACKUP_CHECK_RATE_LIMIT = 5000; // ms
Expand Down
3 changes: 2 additions & 1 deletion src/crypto/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ import { VerificationBase } from "./verification/Base.ts";
import { ReciprocateQRCode, SCAN_QR_CODE_METHOD, SHOW_QR_CODE_METHOD } from "./verification/QRCode.ts";
import { SAS as SASVerification } from "./verification/SAS.ts";
import { keyFromPassphrase } from "./key_passphrase.ts";
import { decodeRecoveryKey, encodeRecoveryKey } from "./recoverykey.ts";
import { VerificationRequest } from "./verification/request/VerificationRequest.ts";
import { InRoomChannel, InRoomRequests } from "./verification/request/InRoomChannel.ts";
import { Request, ToDeviceChannel, ToDeviceRequests } from "./verification/request/ToDeviceChannel.ts";
Expand Down Expand Up @@ -89,8 +88,10 @@ import {
BootstrapCrossSigningOpts,
CrossSigningKeyInfo,
CrossSigningStatus,
decodeRecoveryKey,
DecryptionFailureCode,
DeviceVerificationStatus,
encodeRecoveryKey,
EventEncryptionInfo,
EventShieldColour,
EventShieldReason,
Expand Down
47 changes: 2 additions & 45 deletions src/crypto/recoverykey.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,48 +14,5 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

import bs58 from "bs58";

// picked arbitrarily but to try & avoid clashing with any bitcoin ones
// (which are also base58 encoded, but bitcoin's involve a lot more hashing)
const OLM_RECOVERY_KEY_PREFIX = [0x8b, 0x01];
const KEY_SIZE = 32;

export function encodeRecoveryKey(key: ArrayLike<number>): string | undefined {
const buf = Buffer.alloc(OLM_RECOVERY_KEY_PREFIX.length + key.length + 1);
buf.set(OLM_RECOVERY_KEY_PREFIX, 0);
buf.set(key, OLM_RECOVERY_KEY_PREFIX.length);

let parity = 0;
for (let i = 0; i < buf.length - 1; ++i) {
parity ^= buf[i];
}
buf[buf.length - 1] = parity;
const base58key = bs58.encode(buf);

return base58key.match(/.{1,4}/g)?.join(" ");
}

export function decodeRecoveryKey(recoveryKey: string): Uint8Array {
const result = bs58.decode(recoveryKey.replace(/ /g, ""));

let parity = 0;
for (const b of result) {
parity ^= b;
}
if (parity !== 0) {
throw new Error("Incorrect parity");
}

for (let i = 0; i < OLM_RECOVERY_KEY_PREFIX.length; ++i) {
if (result[i] !== OLM_RECOVERY_KEY_PREFIX[i]) {
throw new Error("Incorrect prefix");
}
}

if (result.length !== OLM_RECOVERY_KEY_PREFIX.length + KEY_SIZE + 1) {
throw new Error("Incorrect length");
}

return Uint8Array.from(result.slice(OLM_RECOVERY_KEY_PREFIX.length, OLM_RECOVERY_KEY_PREFIX.length + KEY_SIZE));
}
// Re-export to avoid breaking changes
export * from "../crypto-api/recovery-key.ts";
4 changes: 4 additions & 0 deletions src/matrixrtc/CallMembership.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,10 @@ export class CallMembership {
return this.parentEvent.getSender();
}

public get eventId(): string | undefined {
return this.parentEvent.getId();
}

public get callId(): string {
return this.membershipData.call_id;
}
Expand Down
4 changes: 2 additions & 2 deletions src/rust-crypto/RoomEncryptor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -254,9 +254,9 @@ export class RoomEncryptor {
// When this.room.getBlacklistUnverifiedDevices() === null, the global settings should be used
// See Room#getBlacklistUnverifiedDevices
if (this.room.getBlacklistUnverifiedDevices() ?? globalBlacklistUnverifiedDevices) {
rustEncryptionSettings.sharingStrategy = CollectStrategy.DeviceBasedStrategyOnlyTrustedDevices;
rustEncryptionSettings.sharingStrategy = CollectStrategy.deviceBasedStrategy(true, false);
} else {
rustEncryptionSettings.sharingStrategy = CollectStrategy.DeviceBasedStrategyAllDevices;
rustEncryptionSettings.sharingStrategy = CollectStrategy.deviceBasedStrategy(false, false);
}

await logDuration(this.prefixedLogger, "shareRoomKey", async () => {
Expand Down
Loading

0 comments on commit 7508b6a

Please sign in to comment.