Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update e2e doc in README.md #4503

Merged
merged 9 commits into from
Nov 12, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
161 changes: 135 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -303,44 +303,153 @@ Then visit `http://localhost:8005` to see the API docs.

# End-to-end encryption support

**This section is outdated.** Use of `libolm` is deprecated and we are replacing it with support
from the matrix-rust-sdk (https://github.com/element-hq/element-web/issues/21972).
The matrix-js-sdk uses underneath the [matrix-sdk-crypto-wasm bindings](https://github.com/matrix-org/matrix-rust-sdk-crypto-wasm) of the [matrix-rust-sdk](https://github.com/matrix-org/matrix-rust-sdk/) to provide end-to-end encryption support.
florianduros marked this conversation as resolved.
Show resolved Hide resolved

The SDK supports end-to-end encryption via the Olm and Megolm protocols, using
[libolm](https://gitlab.matrix.org/matrix-org/olm). It is left up to the
application to make libolm available, via the `Olm` global.
## Initialization

It is also necessary to call `await matrixClient.initCrypto()` after creating a new
`MatrixClient` (but **before** calling `matrixClient.startClient()`) to
initialise the crypto layer.
**Do not use `matrixClient.initCrypto()`. This method is deprecated and no longer maintained.**

If the `Olm` global is not available, the SDK will show a warning, as shown
below; `initCrypto()` will also fail.
To initialize the end-to-end encryption support in the matrix client:

```javascript
// Create a new matrix client
const matrixClient = sdk.createClient({
baseUrl: "http://localhost:8008",
accessToken: myAccessToken,
userId: myUserId,
});

// Initialize to enable end-to-end encryption support.
// This will use an in-memory store.
florianduros marked this conversation as resolved.
Show resolved Hide resolved
await matrixClient.initRustCrypto();
```

To persist the local data, you can use the indexedDB store:

```javascript
// If you not provide a storage key or a password (using a storage key is preferred), the indexedDB store will be uncrypted.
// The storage key must be a 32 bytes long Uint8Array.
await matrixClient.initRustCrypto({
useIndexedDB: true,
storageKey: my32BytesKey,
});
```
florianduros marked this conversation as resolved.
Show resolved Hide resolved

### Secret storage

If your [secret storage](https://spec.matrix.org/v1.12/client-server-api/#secret-storage) is not set up, you need to bootstrap it before using the `CryptoApi`:
florianduros marked this conversation as resolved.
Show resolved Hide resolved

```javascript
const matrixClient = sdk.createClient({
...,
cryptoCallbacks: {
getSecretStorageKey: (keys) => {
florianduros marked this conversation as resolved.
Show resolved Hide resolved
// This function should return the secret storage keys returned in `bootstrapSecretStorage#createSecretStorageKey`
florianduros marked this conversation as resolved.
Show resolved Hide resolved
return mySecretStorageKeys;
},
},
});

matrixClient.getCrypto().bootstrapSecretStorage({
// This will reset the secret storage if it is already set up.
// If you want to keep the current secret storage, you can set `setupNewSecretStorage` to `false`.
// If `setupNewSecretStorage` is `true`, you need to fill `createSecretStorageKey`
setupNewSecretStorage: true,
florianduros marked this conversation as resolved.
Show resolved Hide resolved
// This function will be called if `setupNewSecretStorage` is `true`.
florianduros marked this conversation as resolved.
Show resolved Hide resolved
// You should remember the key you return here, because you will need it to unlock the secret storage.
florianduros marked this conversation as resolved.
Show resolved Hide resolved
// This key should implement the https://matrix-org.github.io/matrix-js-sdk/interfaces/crypto_api.GeneratedSecretStorageKey.html interface.
florianduros marked this conversation as resolved.
Show resolved Hide resolved
createSecretStorageKey: () => {
florianduros marked this conversation as resolved.
Show resolved Hide resolved
return mySecretStorageKey;
},
});
```

In the example above, we are setting up a new secret storage. The secret storage data will be encrypted using the secret storage key returned in `createSecretStorageKey`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should remember this key because when access to the secret storage is needed, the crypto moduel is expecting the `getSecretStorageKey` to return this key.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should remember this key

This is a simplification. The application isn't really supposed to store the 4S key for a long period, though caching it for the duration of a call to bootsrapSecretStorage is a good idea.

Rather, getSecretStorageKey is supposed to prompt the user to re-enter the 4S key.


- [CryptoCallbacks#getSecretStorageKey](https://matrix-org.github.io/matrix-js-sdk/interfaces/crypto_api.CryptoCallbacks.html#getSecretStorageKey)
- [CryptoApi#bootstrapSecretStorage](https://matrix-org.github.io/matrix-js-sdk/interfaces/crypto_api.CryptoApi.html#bootstrapSecretStorage)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

better to add these links where the functions are first mentioned.


Also, if you don't have a [key backup](https://spec.matrix.org/v1.12/client-server-api/#server-side-key-backups) you should create one:
florianduros marked this conversation as resolved.
Show resolved Hide resolved
florianduros marked this conversation as resolved.
Show resolved Hide resolved

```javascript
matrixClient.getCrypto().bootstrapSecretStorage({
...,
setupNewKeyBackup: true,
});
```

Once the key backup and the secret storage are set up, you don't need to set them up again for all your devices.
florianduros marked this conversation as resolved.
Show resolved Hide resolved

### Verify a device and cross-signing

florianduros marked this conversation as resolved.
Show resolved Hide resolved
### Set up cross-signing
florianduros marked this conversation as resolved.
Show resolved Hide resolved

In order to use cross-signing to verify devices, you need to set up cross-signing:
florianduros marked this conversation as resolved.
Show resolved Hide resolved

```javascript
matrixClient.getCrypto().bootstrapCrossSigning({
authUploadDeviceSigningKeys: (makeRequest) => {
return makeRequest(authDict);
},
});
```
Unable to load crypto module: crypto will be disabled: Error: global.Olm is not defined

The `authUploadDeviceSigningKeys` callback is optional but strongly recommended in order to upload the device signing keys to the server.
florianduros marked this conversation as resolved.
Show resolved Hide resolved

- [AuthDict](https://matrix-org.github.io/matrix-js-sdk/types/matrix.AuthDict.html)
- [CryptoApi#bootstrapCrossSigning](https://matrix-org.github.io/matrix-js-sdk/interfaces/crypto_api.CryptoApi.html#bootstrapCrossSigning)
florianduros marked this conversation as resolved.
Show resolved Hide resolved

### Verify a device
florianduros marked this conversation as resolved.
Show resolved Hide resolved

Once the cross-signing is set up on one of your devices, you can verify another device with two methods:

1. Use `CryptoApi#bootstrapCrossSigning`
florianduros marked this conversation as resolved.
Show resolved Hide resolved

`bootstrapCrossSigning`will call the [CryptoCallbacks#getSecretStorageKey](https://matrix-org.github.io/matrix-js-sdk/interfaces/crypto_api.CryptoCallbacks.html#getSecretStorageKey) provided in [Secret storage chapter](#secret-storage). The device is verified with the private cross-signing keys fetched from the secret storage.
florianduros marked this conversation as resolved.
Show resolved Hide resolved

2. Request a verification with [CryptoApi#requestOwnUserVerification](https://matrix-org.github.io/matrix-js-sdk/interfaces/crypto_api.CryptoApi.html#requestOwnUserVerification) or [CryptoApi#requestDeviceVerification](https://matrix-org.github.io/matrix-js-sdk/interfaces/crypto_api.CryptoApi.html#requestDeviceVerification).
florianduros marked this conversation as resolved.
Show resolved Hide resolved

## Migrate from the legacy crypto to the new crypto
florianduros marked this conversation as resolved.
Show resolved Hide resolved

To migrate from the legacy crypto to the new crypto:
florianduros marked this conversation as resolved.
Show resolved Hide resolved

```javascript
// You should provide the legacy crypto store and the pickle key to the matrix client in order to migrate the data.
const matrixClient = sdk.createClient({
cryptoStore: myCryptoStore,
pickleKey: myPickleKey,
baseUrl: "http://localhost:8008",
accessToken: myAccessToken,
userId: myUserId,
});

// The migration will be done automatically when you call `initRustCrypto`.
await matrixClient.initRustCrypto();
```

If the crypto layer is not (successfully) initialised, the SDK will continue to
work for unencrypted rooms, but it will not support the E2E parts of the Matrix
specification.
To follow the migration progress, you can listen to the `CryptoEvent.LegacyCryptoStoreMigrationProgress` event:
florianduros marked this conversation as resolved.
Show resolved Hide resolved

To provide the Olm library in a browser application:
```javascript
// When progress === total === -1, the migration is finished.
matrixClient.on(CryptoEvent.LegacyCryptoStoreMigrationProgress, (progress, total) => {
...
});
```

- download the transpiled libolm (from https://packages.matrix.org/npm/olm/).
- load `olm.js` as a `<script>` _before_ `browser-matrix.js`.
After the migration is finished, you can remove the legacy crypto store and the pickle key from the matrix client creation.

florianduros marked this conversation as resolved.
Show resolved Hide resolved
florianduros marked this conversation as resolved.
Show resolved Hide resolved
To provide the Olm library in a node.js application:
## Use the `CryptoApi`

- `yarn add https://packages.matrix.org/npm/olm/olm-3.1.4.tgz`
(replace the URL with the latest version you want to use from
https://packages.matrix.org/npm/olm/)
- `global.Olm = require('olm');` _before_ loading `matrix-js-sdk`.
The `CryptoApi` is the main entry point for end-to-end encryption.

```javascript
// If the `CryptoApi` object is `undefined`, the end-to-end encryption is not enabled.
// You must call `initRustCrypto` before.
matrixClient.getCrypto();
```
florianduros marked this conversation as resolved.
Show resolved Hide resolved

If you want to package Olm as dependency for your node.js application, you can
use `yarn add https://packages.matrix.org/npm/olm/olm-3.1.4.tgz`. If your
application also works without e2e crypto enabled, add `--optional` to mark it
as an optional dependency.
The CryptoApi documentation is available [here](https://matrix-org.github.io/matrix-js-sdk/interfaces/crypto_api.CryptoApi.html).
florianduros marked this conversation as resolved.
Show resolved Hide resolved
florianduros marked this conversation as resolved.
Show resolved Hide resolved

# Contributing

Expand Down
6 changes: 6 additions & 0 deletions src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,11 @@ export interface ICreateClientOpts {
* {@link setCryptoStoreFactory} if unspecified; or if no factory has been
* specified, uses a default implementation (indexeddb in the browser,
* in-memory otherwise).
*
* This is only used for the legacy crypto implementation (as used by {@link MatrixClient#initCrypto}),
* but if you use the rust crypto implementation ({@link MatrixClient#initRustCrypto}) and the device
* previously used legacy crypto (so must be migrated), then this must still be provided, so that the
* data can be migrated from the legacy store.
florianduros marked this conversation as resolved.
Show resolved Hide resolved
*/
cryptoStore?: CryptoStore;

Expand Down Expand Up @@ -1269,6 +1274,7 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
protected isGuestAccount = false;
protected ongoingScrollbacks: { [roomId: string]: { promise?: Promise<Room>; errorTs?: number } } = {};
protected notifTimelineSet: EventTimelineSet | null = null;
/* @deprecated */
protected cryptoStore?: CryptoStore;
protected verificationMethods?: string[];
protected fallbackICEServerAllowed = false;
Expand Down