cetirizine

An experimental matrix client written in reactjs utilizing tailwind and storybook
git clone git://archive.git.mtrnord.blog/MTRNord/cetirizine.git
Log | Files | Refs | README | LICENSE

e2ee.ts (12079B)


      1 import {
      2     DeviceId,
      3     DeviceLists,
      4     KeysBackupRequest,
      5     KeysClaimRequest,
      6     KeysQueryRequest,
      7     KeysUploadRequest,
      8     OlmMachine,
      9     RequestType,
     10     RoomId,
     11     RoomMessageRequest,
     12     SignatureUploadRequest,
     13     ToDeviceRequest,
     14     UserId
     15 } from "@mtrnord/matrix-sdk-crypto-js";
     16 import { MatrixClient } from "./client";
     17 import { OwnUser } from "./ownUser";
     18 import { Room } from "./room";
     19 import { IRoomEvent } from "./api/events";
     20 import { HostnameMissingError, NotLogeedInError, OlmMachineNotSetupError, SDKError } from "./utils";
     21 
     22 export class MatrixE2EE {
     23     private olmMachine?: OlmMachine;
     24     private outgoingRequestsBeingProcessed = false;
     25     private missingSessionsBeingRequested = false;
     26 
     27     constructor(private client: MatrixClient, private user: OwnUser) { }
     28 
     29     public async decryptRoomEvent(roomID: string, event: IRoomEvent<any>): Promise<any> {
     30         return await this.olmMachine?.decryptRoomEvent(JSON.stringify(event), new RoomId(roomID));
     31     }
     32 
     33     public async receiveSyncData(
     34         to_device_events: string,
     35         changed_devices: DeviceLists,
     36         one_time_key_counts: Map<any, any>,
     37         unused_fallback_keys?: Set<any>
     38     ): Promise<any> {
     39         return await this.olmMachine?.receiveSyncChanges(
     40             to_device_events,
     41             changed_devices,
     42             one_time_key_counts,
     43             unused_fallback_keys
     44         );
     45     }
     46 
     47     public async encryptRoomEvent(roomID: RoomId, type: string, content: string): Promise<SDKError | any> {
     48         if (!this.client.isLoggedIn) {
     49             return new NotLogeedInError();
     50         }
     51         if (!this.olmMachine) {
     52             return new OlmMachineNotSetupError();
     53         }
     54         return await this.olmMachine?.encryptRoomEvent(roomID, type, content);
     55     }
     56 
     57     public async initOlmMachine(userID: UserId, deviceID: DeviceId, storePassphrase?: string): Promise<void> {
     58         this.olmMachine = await OlmMachine.initialize(userID, deviceID, "cetirizine-crypto", storePassphrase);
     59         console.warn("Init olm done")
     60     }
     61 
     62     public async updateTrackedUsers(users: any[]): Promise<void> {
     63         await this.olmMachine?.updateTrackedUsers(users);
     64     }
     65 
     66     public async sendIdentifyAndOneTimeKeys(): Promise<SDKError | void> {
     67         if (!this.client.isLoggedIn) {
     68             return new NotLogeedInError();
     69         }
     70         if (!this.user.hostname) {
     71             return new HostnameMissingError();
     72         }
     73         if (!this.olmMachine) {
     74             return new OlmMachineNotSetupError();
     75         }
     76 
     77         if (this.outgoingRequestsBeingProcessed) {
     78             return;
     79         }
     80         this.outgoingRequestsBeingProcessed = true;
     81 
     82         const outgoing_requests = await this.olmMachine.outgoingRequests();
     83 
     84         for (const request of outgoing_requests) {
     85             await this.processRequest(request);
     86         }
     87 
     88         await this.getMissingSessions();
     89         this.outgoingRequestsBeingProcessed = false;
     90     }
     91 
     92     public async shareKeysForRoom(room: Room): Promise<SDKError | void> {
     93         if (!this.client.isLoggedIn) {
     94             return new NotLogeedInError();
     95         }
     96         if (!this.user.hostname) {
     97             return new HostnameMissingError();
     98         }
     99         if (!this.olmMachine) {
    100             return new OlmMachineNotSetupError();
    101         }
    102         const encryptionSettings = room.getEncryptionSettings();
    103         if (encryptionSettings) {
    104             const requests = await this.olmMachine.shareRoomKey(new RoomId(room.roomID), room.getJoinedMemberIDs().map(id => new UserId(id)), encryptionSettings);
    105             for (const request of requests) {
    106                 await this.processRequest(request);
    107             }
    108         }
    109     }
    110 
    111     public async getMissingSessions(): Promise<SDKError | void> {
    112         if (!this.client.isLoggedIn) {
    113             return new NotLogeedInError();
    114         }
    115         if (!this.user.hostname) {
    116             return new HostnameMissingError();
    117         }
    118         if (!this.olmMachine) {
    119             return new OlmMachineNotSetupError();
    120         }
    121 
    122         if (this.missingSessionsBeingRequested) {
    123             return;
    124         }
    125         this.missingSessionsBeingRequested = true;
    126 
    127         const encryptedRooms = [...this.client.getRooms()].filter(room => room.isEncrypted());
    128         const users = encryptedRooms.map(room => room.getJoinedMemberIDs().map(id => new UserId(id))).flat();
    129         const request = await this.olmMachine?.getMissingSessions(users);
    130         if (request) {
    131             await this.processRequest(request);
    132         }
    133 
    134         this.missingSessionsBeingRequested = false;
    135     }
    136 
    137     private async processRequest(request: any): Promise<SDKError | void> {
    138         if (!this.client.isLoggedIn) {
    139             return new NotLogeedInError();
    140         }
    141         if (!this.user.hostname) {
    142             return new HostnameMissingError();
    143         }
    144         if (!this.olmMachine) {
    145             return new OlmMachineNotSetupError();
    146         }
    147         // Check which type the request is
    148         if (request.type === RequestType.KeysUpload) {
    149             // Send the key
    150             const request_typed = request as KeysUploadRequest;
    151             const response = await fetch(
    152                 `${this.user.hostname}/_matrix/client/v3/keys/upload`,
    153                 {
    154                     method: "POST",
    155                     headers: {
    156                         "Content-Type": "application/json",
    157                         "Authorization": `Bearer ${this.user.access_token}`
    158                     },
    159                     body: request_typed.body
    160                 }
    161             )
    162             if (!response.ok) {
    163                 if (response.status === 401) {
    164                     await this.client.logout();
    165                     console.error(response);
    166                 }
    167                 console.error("Failed to upload keys", response);
    168                 return;
    169             }
    170             this.olmMachine.markRequestAsSent(request_typed.id!, request_typed.type, await response.text());
    171         } else if (request.type === RequestType.KeysQuery) {
    172             const request_typed = request as KeysQueryRequest;
    173             const response = await fetch(
    174                 `${this.user.hostname}/_matrix/client/v3/keys/query`,
    175                 {
    176                     method: "POST",
    177                     headers: {
    178                         "Content-Type": "application/json",
    179                         "Authorization": `Bearer ${this.user.access_token}`
    180                     },
    181                     body: request_typed.body
    182                 }
    183             )
    184             if (!response.ok) {
    185                 if (response.status === 401) {
    186                     await this.client.logout();
    187                     console.error(response);
    188                 }
    189                 console.error("Failed to query keys", response);
    190                 return;
    191             }
    192             this.olmMachine.markRequestAsSent(request_typed.id!, request_typed.type, await response.text());
    193         } else if (request.type === RequestType.KeysClaim) {
    194             const request_typed = request as KeysClaimRequest;
    195             const response = await fetch(
    196                 `${this.user.hostname}/_matrix/client/v3/keys/claim`,
    197                 {
    198                     method: "POST",
    199                     headers: {
    200                         "Content-Type": "application/json",
    201                         "Authorization": `Bearer ${this.user.access_token}`
    202                     },
    203                     body: request_typed.body
    204                 }
    205             )
    206             if (!response.ok) {
    207                 if (response.status === 401) {
    208                     await this.client.logout();
    209                     console.error(response);
    210                 }
    211                 console.error("Failed to claim keys", response);
    212                 return;
    213             }
    214             this.olmMachine.markRequestAsSent(request_typed.id!, request_typed.type, await response.text());
    215         } else if (request.type === RequestType.ToDevice) {
    216             const request_typed = request as ToDeviceRequest;
    217             const response = await fetch(
    218                 `${this.user.hostname}/_matrix/client/v3/sendToDevice/${request_typed.event_type}/${request_typed.txn_id}`,
    219                 {
    220                     method: "PUT",
    221                     headers: {
    222                         "Content-Type": "application/json",
    223                         "Authorization": `Bearer ${this.user.access_token}`
    224                     },
    225                     body: request_typed.body
    226                 }
    227             )
    228             if (!response.ok) {
    229                 if (response.status === 401) {
    230                     await this.client.logout();
    231                     console.error(response);
    232                 }
    233                 console.error("Failed to send to device", response);
    234                 return;
    235             }
    236             this.olmMachine.markRequestAsSent(request_typed.id ?? request_typed.txn_id, request_typed.type, await response.text());
    237         } else if (request.type === RequestType.SignatureUpload) {
    238             const request_typed = request as SignatureUploadRequest;
    239             const response = await fetch(
    240                 `${this.user.hostname}/_matrix/client/v3/keys/signatures/upload`,
    241                 {
    242                     method: "POST",
    243                     headers: {
    244                         "Content-Type": "application/json",
    245                         "Authorization": `Bearer ${this.user.access_token}`
    246                     },
    247                     body: request_typed.body
    248                 }
    249             )
    250             if (!response.ok) {
    251                 if (response.status === 401) {
    252                     await this.client.logout();
    253                     console.error(response);
    254                 }
    255                 console.error("Failed to upload signatures", response);
    256                 return;
    257             }
    258             this.olmMachine.markRequestAsSent(request_typed.id!, request_typed.type, await response.text());
    259         } else if (request.type === RequestType.RoomMessage) {
    260             const request_typed = request as RoomMessageRequest;
    261             const response = await fetch(
    262                 `${this.user.hostname}/_matrix/client/v3/rooms/${request_typed.room_id}/send/${request_typed.event_type}/${request_typed.txn_id}`,
    263                 {
    264                     method: "PUT",
    265                     headers: {
    266                         "Content-Type": "application/json",
    267                         "Authorization": `Bearer ${this.user.access_token}`
    268                     },
    269                     body: request_typed.body
    270                 }
    271             )
    272             if (!response.ok) {
    273                 if (response.status === 401) {
    274                     await this.client.logout();
    275                     console.error(response);
    276                 }
    277                 console.error("Failed to send message", response);
    278                 return;
    279             }
    280             this.olmMachine.markRequestAsSent(request_typed.id!, request_typed.type, await response.text());
    281         } else if (request.type === RequestType.KeysBackup) {
    282             const request_typed = request as KeysBackupRequest;
    283             const response = await fetch(
    284                 `${this.user.hostname}/_matrix/client/v3/room_keys/keys`,
    285                 {
    286                     method: "PUT",
    287                     headers: {
    288                         "Content-Type": "application/json",
    289                         "Authorization": `Bearer ${this.user.access_token}`
    290                     },
    291                     body: request_typed.body
    292                 }
    293             )
    294             if (!response.ok) {
    295                 if (response.status === 401) {
    296                     await this.client.logout();
    297                     console.error(response);
    298                 }
    299                 console.error("Failed to backup keys", response);
    300                 return;
    301             }
    302             this.olmMachine.markRequestAsSent(request_typed.id!, request_typed.type, await response.text());
    303         }
    304     }
    305 
    306     public logoutE2ee(): void {
    307         this.missingSessionsBeingRequested = false;
    308         this.outgoingRequestsBeingProcessed = false;
    309     }
    310 }