Extract functions for service worker usage, and add initial MSC3916 playwright test (when supported) (#12414)
* Send user credentials to service worker for MSC3916 authentication * appease linter * Add initial test The test fails, seemingly because the service worker isn't being installed or because the network mock can't reach that far. * Remove unsafe access token code * Split out base IDB operations to avoid importing `document` in serviceworkers * Use safe crypto access for service workers * Fix tests/unsafe access * Remove backwards compatibility layer & appease linter * Add docs * Fix tests * Appease the linter * Iterate tests * Factor out pickle key handling for service workers * Enable everything we can about service workers * Appease the linter * Add docs * Rename win32 image to linux in hopes of it just working * Use actual image * Apply suggestions from code review Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> * Improve documentation * Document `??` not working * Try to appease the tests * Add some notes --------- Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
This commit is contained in:
parent
374cee9080
commit
d25d529e86
12 changed files with 435 additions and 176 deletions
|
@ -34,10 +34,11 @@ import { CheckUpdatesPayload } from "./dispatcher/payloads/CheckUpdatesPayload";
|
|||
import { Action } from "./dispatcher/actions";
|
||||
import { hideToast as hideUpdateToast } from "./toasts/UpdateToast";
|
||||
import { MatrixClientPeg } from "./MatrixClientPeg";
|
||||
import { idbLoad, idbSave, idbDelete } from "./utils/StorageManager";
|
||||
import { idbLoad, idbSave, idbDelete } from "./utils/StorageAccess";
|
||||
import { ViewRoomPayload } from "./dispatcher/payloads/ViewRoomPayload";
|
||||
import { IConfigOptions } from "./IConfigOptions";
|
||||
import SdkConfig from "./SdkConfig";
|
||||
import { buildAndEncodePickleKey, getPickleAdditionalData } from "./utils/tokens/pickling";
|
||||
|
||||
export const SSO_HOMESERVER_URL_KEY = "mx_sso_hs_url";
|
||||
export const SSO_ID_SERVER_URL_KEY = "mx_sso_is_url";
|
||||
|
@ -352,55 +353,21 @@ export default abstract class BasePlatform {
|
|||
|
||||
/**
|
||||
* Get a previously stored pickle key. The pickle key is used for
|
||||
* encrypting libolm objects.
|
||||
* encrypting libolm objects and react-sdk-crypto data.
|
||||
* @param {string} userId the user ID for the user that the pickle key is for.
|
||||
* @param {string} userId the device ID that the pickle key is for.
|
||||
* @param {string} deviceId the device ID that the pickle key is for.
|
||||
* @returns {string|null} the previously stored pickle key, or null if no
|
||||
* pickle key has been stored.
|
||||
*/
|
||||
public async getPickleKey(userId: string, deviceId: string): Promise<string | null> {
|
||||
if (!window.crypto || !window.crypto.subtle) {
|
||||
return null;
|
||||
}
|
||||
let data;
|
||||
let data: { encrypted?: BufferSource; iv?: BufferSource; cryptoKey?: CryptoKey } | undefined;
|
||||
try {
|
||||
data = await idbLoad("pickleKey", [userId, deviceId]);
|
||||
} catch (e) {
|
||||
logger.error("idbLoad for pickleKey failed", e);
|
||||
}
|
||||
if (!data) {
|
||||
return null;
|
||||
}
|
||||
if (!data.encrypted || !data.iv || !data.cryptoKey) {
|
||||
logger.error("Badly formatted pickle key");
|
||||
return null;
|
||||
}
|
||||
|
||||
const additionalData = this.getPickleAdditionalData(userId, deviceId);
|
||||
|
||||
try {
|
||||
const key = await crypto.subtle.decrypt(
|
||||
{ name: "AES-GCM", iv: data.iv, additionalData },
|
||||
data.cryptoKey,
|
||||
data.encrypted,
|
||||
);
|
||||
return encodeUnpaddedBase64(key);
|
||||
} catch (e) {
|
||||
logger.error("Error decrypting pickle key");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private getPickleAdditionalData(userId: string, deviceId: string): Uint8Array {
|
||||
const additionalData = new Uint8Array(userId.length + deviceId.length + 1);
|
||||
for (let i = 0; i < userId.length; i++) {
|
||||
additionalData[i] = userId.charCodeAt(i);
|
||||
}
|
||||
additionalData[userId.length] = 124; // "|"
|
||||
for (let i = 0; i < deviceId.length; i++) {
|
||||
additionalData[userId.length + 1 + i] = deviceId.charCodeAt(i);
|
||||
}
|
||||
return additionalData;
|
||||
return (await buildAndEncodePickleKey(data, userId, deviceId)) ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -424,7 +391,7 @@ export default abstract class BasePlatform {
|
|||
const iv = new Uint8Array(32);
|
||||
crypto.getRandomValues(iv);
|
||||
|
||||
const additionalData = this.getPickleAdditionalData(userId, deviceId);
|
||||
const additionalData = getPickleAdditionalData(userId, deviceId);
|
||||
const encrypted = await crypto.subtle.encrypt({ name: "AES-GCM", iv, additionalData }, cryptoKey, randomArray);
|
||||
|
||||
try {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue