Skip to content
This repository was archived by the owner on Jan 30, 2025. It is now read-only.

Commit 6bb3980

Browse files
authored
Add extension mechanism, and extension points to replace deprecated Security customisations. (#31)
1 parent 92305c9 commit 6bb3980

File tree

6 files changed

+425
-1
lines changed

6 files changed

+425
-1
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@matrix-org/react-sdk-module-api",
3-
"version": "2.3.0",
3+
"version": "2.4.0",
44
"description": "Module API surface for matrix-react-sdk",
55
"main": "lib/index.js",
66
"types": "lib/index.d.ts",

src/RuntimeModule.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { EventEmitter } from "events";
1818

1919
import { ModuleApi } from "./ModuleApi";
2020
import { PlainSubstitution } from "./types/translations";
21+
import { AllExtensions } from "./types/extensions";
2122

2223
// TODO: Type the event emitter with AnyLifecycle (extract TypedEventEmitter from js-sdk somehow?)
2324
// See https://github.com/matrix-org/matrix-react-sdk-module-api/issues/4
@@ -27,6 +28,9 @@ import { PlainSubstitution } from "./types/translations";
2728
* will be provided information about the application state and can react to it.
2829
*/
2930
export abstract class RuntimeModule extends EventEmitter {
31+
public extensions?: AllExtensions;
32+
public moduleName: string = RuntimeModule.name;
33+
3034
protected constructor(protected readonly moduleApi: ModuleApi) {
3135
super();
3236
}
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
/*
2+
Copyright 2023 Verji Tech AS
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
7+
http://www.apache.org/licenses/LICENSE-2.0
8+
9+
Unless required by applicable law or agreed to in writing, software
10+
distributed under the License is distributed on an "AS IS" BASIS,
11+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
See the License for the specific language governing permissions and
13+
limitations under the License.
14+
*/
15+
16+
/*
17+
* Types copied (and renamed) from matrix-js-sdk
18+
*/
19+
20+
/**
21+
* Copied from https://github.com/matrix-org/matrix-js-sdk/blob/2337d5a7af6265bbcabbd42c1594cd8b1829b00b/src/secret-storage.ts#L39-L50
22+
*/
23+
export interface SecretStorageKeyDescriptionCommon {
24+
/** A human-readable name for this key. */
25+
// XXX: according to the spec, this is optional
26+
name: string;
27+
28+
/** The encryption algorithm used with this key. */
29+
algorithm: string;
30+
31+
/** Information for deriving this key from a passphrase. */
32+
// XXX: according to the spec, this is optional
33+
passphrase: PassphraseInfo;
34+
}
35+
36+
/**
37+
* Copied from https://github.com/matrix-org/matrix-js-sdk/blob/2337d5a7af6265bbcabbd42c1594cd8b1829b00b/src/secret-storage.ts#L59-L71
38+
*/
39+
export interface SecretStorageKeyDescriptionAesV1 extends SecretStorageKeyDescriptionCommon {
40+
// XXX: strictly speaking, we should be able to enforce the algorithm here. But
41+
// this interface ends up being incorrectly used where other algorithms are in use (notably
42+
// in device-dehydration support), and unpicking that is too much like hard work
43+
// at the moment.
44+
// algorithm: "m.secret_storage.v1.aes-hmac-sha2";
45+
46+
/** The 16-byte AES initialization vector, encoded as base64. */
47+
iv: string;
48+
49+
/** The MAC of the result of encrypting 32 bytes of 0, encoded as base64. */
50+
mac: string;
51+
}
52+
53+
/**
54+
* Copied from https://github.com/matrix-org/matrix-js-sdk/blob/2337d5a7af6265bbcabbd42c1594cd8b1829b00b/src/secret-storage.ts#L78
55+
*/
56+
export type SecretStorageKeyDescription = SecretStorageKeyDescriptionAesV1;
57+
58+
/**
59+
* Copied from https://github.com/matrix-org/matrix-js-sdk/blob/2337d5a7af6265bbcabbd42c1594cd8b1829b00b/src/secret-storage.ts#L85-L97
60+
*/
61+
export interface PassphraseInfo {
62+
/** The algorithm to be used to derive the key. */
63+
algorithm: "m.pbkdf2";
64+
65+
/** The number of PBKDF2 iterations to use. */
66+
iterations: number;
67+
68+
/** The salt to be used for PBKDF2. */
69+
salt: string;
70+
71+
/** The number of bits to generate. Defaults to 256. */
72+
bits?: number;
73+
}
74+
75+
/*
76+
* Copied from https://github.com/matrix-org/matrix-react-sdk/blob/11096b207a1510569f5c54182e328f6148a6475c/src/MatrixClientPeg.ts#L57-L67
77+
*/
78+
export interface ExamineLoginResponseCreds {
79+
homeserverUrl: string;
80+
identityServerUrl?: string;
81+
userId: string;
82+
deviceId?: string;
83+
accessToken: string;
84+
refreshToken?: string;
85+
guest?: boolean;
86+
pickleKey?: string;
87+
freshLogin?: boolean;
88+
}
89+
90+
/**
91+
* Copied from https://github.com/matrix-org/matrix-react-sdk/blob/11096b207a1510569f5c54182e328f6148a6475c/src/toasts/SetupEncryptionToast.ts#L71-L75
92+
*/
93+
export enum SetupEncryptionKind {
94+
SetUpEncryption = "set_up_encryption",
95+
UpgradeEncryption = "upgrade_encryption",
96+
VerifyThisSessions = "verify_this_session",
97+
}
98+
99+
export interface ExtendedMatrixClientCreds extends ExamineLoginResponseCreds {
100+
secureBackupKey?: string;
101+
}
102+
103+
export interface ProvideCryptoSetupStore {
104+
getInstance: () => SetupEncryptionStoreProjection;
105+
}
106+
107+
export interface SetupEncryptionStoreProjection {
108+
usePassPhrase(): Promise<void>;
109+
}
110+
111+
export interface ProvideCryptoSetupExtensions {
112+
examineLoginResponse(response: any, credentials: ExtendedMatrixClientCreds): void;
113+
persistCredentials(credentials: ExtendedMatrixClientCreds): void;
114+
getSecretStorageKey(): Uint8Array | null;
115+
createSecretStorageKey(): Uint8Array | null;
116+
catchAccessSecretStorageError(e: Error): void;
117+
setupEncryptionNeeded: (args: CryptoSetupArgs) => boolean;
118+
getDehydrationKeyCallback():
119+
| ((keyInfo: SecretStorageKeyDescription, checkFunc: (key: Uint8Array) => void) => Promise<Uint8Array>)
120+
| null;
121+
SHOW_ENCRYPTION_SETUP_UI: boolean;
122+
}
123+
124+
export abstract class CryptoSetupExtensionsBase implements ProvideCryptoSetupExtensions {
125+
public abstract examineLoginResponse(response: any, credentials: ExtendedMatrixClientCreds): void;
126+
public abstract persistCredentials(credentials: ExtendedMatrixClientCreds): void;
127+
public abstract getSecretStorageKey(): Uint8Array | null;
128+
public abstract createSecretStorageKey(): Uint8Array | null;
129+
public abstract catchAccessSecretStorageError(e: Error): void;
130+
public abstract setupEncryptionNeeded(args: CryptoSetupArgs): boolean;
131+
public abstract getDehydrationKeyCallback():
132+
| ((keyInfo: SecretStorageKeyDescription, checkFunc: (key: Uint8Array) => void) => Promise<Uint8Array>)
133+
| null;
134+
public abstract SHOW_ENCRYPTION_SETUP_UI: boolean;
135+
}
136+
137+
/* Define an interface for setupEncryptionNeeded to help enforce mandatory arguments */
138+
export interface CryptoSetupArgs {
139+
kind: SetupEncryptionKind;
140+
storeProvider: ProvideCryptoSetupStore;
141+
}
142+
143+
/**
144+
*
145+
* The default/empty crypto-extensions
146+
* Can (and will) be used if none of the modules has an implementaion of IProvideCryptoSetupExtensions
147+
*
148+
* */
149+
export class DefaultCryptoSetupExtensions extends CryptoSetupExtensionsBase {
150+
public SHOW_ENCRYPTION_SETUP_UI = true;
151+
152+
public examineLoginResponse(response: any, credentials: ExtendedMatrixClientCreds): void {
153+
console.log("Default empty examineLoginResponse() => void");
154+
}
155+
public persistCredentials(credentials: ExtendedMatrixClientCreds): void {
156+
console.log("Default empty persistCredentials() => void");
157+
}
158+
159+
public getSecretStorageKey(): Uint8Array | null {
160+
console.log("Default empty getSecretStorageKey() => null");
161+
return null;
162+
}
163+
164+
public createSecretStorageKey(): Uint8Array | null {
165+
console.log("Default empty createSecretStorageKey() => null");
166+
return null;
167+
}
168+
169+
public catchAccessSecretStorageError(e: Error): void {
170+
console.log("Default catchAccessSecretStorageError() => void");
171+
}
172+
173+
public setupEncryptionNeeded(args: CryptoSetupArgs): boolean {
174+
console.log("Default setupEncryptionNeeded() => false");
175+
return false;
176+
}
177+
178+
public getDehydrationKeyCallback():
179+
| ((keyInfo: SecretStorageKeyDescription, checkFunc: (key: Uint8Array) => void) => Promise<Uint8Array>)
180+
| null {
181+
console.log("Default empty getDehydrationKeyCallback() => null");
182+
return null;
183+
}
184+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
Copyright 2023 Verji Tech AS
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
7+
http://www.apache.org/licenses/LICENSE-2.0
8+
9+
Unless required by applicable law or agreed to in writing, software
10+
distributed under the License is distributed on an "AS IS" BASIS,
11+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
See the License for the specific language governing permissions and
13+
limitations under the License.
14+
*/
15+
16+
/**
17+
* Mostly for test. To ensure we handle more than one module having extensions
18+
* Can possibly also be useful for PoC development
19+
*/
20+
export interface ProvideExperimentalExtensions {
21+
experimentalMethod(args?: any): any;
22+
}
23+
24+
export abstract class ExperimentalExtensionsBase implements ProvideExperimentalExtensions {
25+
public abstract experimentalMethod(args?: any): any;
26+
}
27+
28+
export class DefaultExperimentalExtensions extends ExperimentalExtensionsBase {
29+
public experimentalMethod(args?: any): any {
30+
return null;
31+
}
32+
}

src/types/extensions.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
Copyright 2023 Verji Tech AS
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
7+
http://www.apache.org/licenses/LICENSE-2.0
8+
9+
Unless required by applicable law or agreed to in writing, software
10+
distributed under the License is distributed on an "AS IS" BASIS,
11+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
See the License for the specific language governing permissions and
13+
limitations under the License.
14+
*/
15+
16+
import { ProvideCryptoSetupExtensions } from "../lifecycles/CryptoSetupExtensions";
17+
import { ProvideExperimentalExtensions } from "../lifecycles/ExperimentalExtensions";
18+
19+
export type AllExtensions = {
20+
cryptoSetup?: ProvideCryptoSetupExtensions;
21+
experimental?: ProvideExperimentalExtensions;
22+
};

0 commit comments

Comments
 (0)