relay.ts raw
1 import {
2 CryptoHelper,
3 Relay_DECRYPTED,
4 Relay_ENCRYPTED,
5 StorageService,
6 } from '@common';
7 import { LockedVaultContext } from './identity';
8
9 export const addRelay = async function (
10 this: StorageService,
11 data: {
12 identityId: string;
13 url: string;
14 write: boolean;
15 read: boolean;
16 }
17 ): Promise<void> {
18 this.assureIsInitialized();
19
20 // Check, if a relay with the same URL already exists for the identity.
21 const existingRelay =
22 this.getBrowserSessionHandler().browserSessionData?.relays.find(
23 (x) =>
24 x.url.toLowerCase() === data.url.toLowerCase() &&
25 x.identityId === data.identityId
26 );
27 if (existingRelay) {
28 throw new Error('A relay with the same URL already exists.');
29 }
30
31 const browserSessionData = this.getBrowserSessionHandler().browserSessionData;
32 if (!browserSessionData) {
33 throw new Error('Browser session data is undefined.');
34 }
35
36 const decryptedRelay: Relay_DECRYPTED = {
37 id: CryptoHelper.v4(),
38 identityId: data.identityId,
39 url: data.url,
40 write: data.write,
41 read: data.read,
42 };
43
44 // Add the new relay to the session data.
45 browserSessionData.relays.push(decryptedRelay);
46 this.getBrowserSessionHandler().saveFullData(browserSessionData);
47
48 // Encrypt the new relay and add it to the sync data.
49 const encryptedRelay = await encryptRelay.call(this, decryptedRelay);
50 const encryptedRelays = [
51 ...(this.getBrowserSyncHandler().browserSyncData?.relays ?? []),
52 encryptedRelay,
53 ];
54 await this.getBrowserSyncHandler().saveAndSetPartialData_Relays({
55 relays: encryptedRelays,
56 });
57 };
58
59 export const deleteRelay = async function (
60 this: StorageService,
61 relayId: string
62 ): Promise<void> {
63 this.assureIsInitialized();
64
65 if (!relayId) {
66 return;
67 }
68
69 const browserSessionData = this.getBrowserSessionHandler().browserSessionData;
70 const browserSyncData = this.getBrowserSyncHandler().browserSyncData;
71 if (!browserSessionData || !browserSyncData) {
72 throw new Error('Browser session or sync data is undefined.');
73 }
74
75 browserSessionData.relays = browserSessionData.relays.filter(
76 (x) => x.id !== relayId
77 );
78 await this.getBrowserSessionHandler().saveFullData(browserSessionData);
79
80 // Handle Sync data.
81 const encryptedRelayId = await this.encrypt(relayId);
82 await this.getBrowserSyncHandler().saveAndSetPartialData_Relays({
83 relays: browserSyncData.relays.filter((x) => x.id !== encryptedRelayId),
84 });
85 };
86
87 export const updateRelay = async function (
88 this: StorageService,
89 relayClone: Relay_DECRYPTED
90 ): Promise<void> {
91 this.assureIsInitialized();
92
93 const browserSessionData = this.getBrowserSessionHandler().browserSessionData;
94 const browserSyncData = this.getBrowserSyncHandler().browserSyncData;
95 if (!browserSessionData || !browserSyncData) {
96 throw new Error('Browser session or sync data is undefined.');
97 }
98
99 const sessionRelay = browserSessionData.relays.find(
100 (x) => x.id === relayClone.id
101 );
102 const encryptedRelayId = await this.encrypt(relayClone.id);
103 const syncRelay = browserSyncData.relays.find(
104 (x) => x.id === encryptedRelayId
105 );
106 if (!sessionRelay || !syncRelay) {
107 throw new Error(
108 'Relay not found in browser session or sync data for update.'
109 );
110 }
111
112 // Handle Session update.
113 sessionRelay.read = relayClone.read;
114 sessionRelay.write = relayClone.write;
115 sessionRelay.url = relayClone.url;
116 await this.getBrowserSessionHandler().saveFullData(browserSessionData);
117
118 // Handle Sync update.
119 syncRelay.read = await this.encrypt(relayClone.read.toString());
120 syncRelay.write = await this.encrypt(relayClone.write.toString());
121 syncRelay.url = await this.encrypt(relayClone.url);
122 await this.getBrowserSyncHandler().saveAndSetPartialData_Relays({
123 relays: browserSyncData.relays,
124 });
125 };
126
127 export const decryptRelay = async function (
128 this: StorageService,
129 relay: Relay_ENCRYPTED,
130 withLockedVault: LockedVaultContext | undefined = undefined
131 ): Promise<Relay_DECRYPTED> {
132 if (typeof withLockedVault === 'undefined') {
133 const decryptedRelay: Relay_DECRYPTED = {
134 id: await this.decrypt(relay.id, 'string'),
135 identityId: await this.decrypt(relay.identityId, 'string'),
136 url: await this.decrypt(relay.url, 'string'),
137 read: await this.decrypt(relay.read, 'boolean'),
138 write: await this.decrypt(relay.write, 'boolean'),
139 };
140 return decryptedRelay;
141 }
142
143 // v2: Use pre-derived key
144 if (withLockedVault.keyBase64) {
145 const decryptedRelay: Relay_DECRYPTED = {
146 id: await this.decryptWithLockedVaultV2(
147 relay.id,
148 'string',
149 withLockedVault.iv,
150 withLockedVault.keyBase64
151 ),
152 identityId: await this.decryptWithLockedVaultV2(
153 relay.identityId,
154 'string',
155 withLockedVault.iv,
156 withLockedVault.keyBase64
157 ),
158 url: await this.decryptWithLockedVaultV2(
159 relay.url,
160 'string',
161 withLockedVault.iv,
162 withLockedVault.keyBase64
163 ),
164 read: await this.decryptWithLockedVaultV2(
165 relay.read,
166 'boolean',
167 withLockedVault.iv,
168 withLockedVault.keyBase64
169 ),
170 write: await this.decryptWithLockedVaultV2(
171 relay.write,
172 'boolean',
173 withLockedVault.iv,
174 withLockedVault.keyBase64
175 ),
176 };
177 return decryptedRelay;
178 }
179
180 // v1: Use password (PBKDF2)
181 const decryptedRelay: Relay_DECRYPTED = {
182 id: await this.decryptWithLockedVault(
183 relay.id,
184 'string',
185 withLockedVault.iv,
186 withLockedVault.password!
187 ),
188 identityId: await this.decryptWithLockedVault(
189 relay.identityId,
190 'string',
191 withLockedVault.iv,
192 withLockedVault.password!
193 ),
194 url: await this.decryptWithLockedVault(
195 relay.url,
196 'string',
197 withLockedVault.iv,
198 withLockedVault.password!
199 ),
200 read: await this.decryptWithLockedVault(
201 relay.read,
202 'boolean',
203 withLockedVault.iv,
204 withLockedVault.password!
205 ),
206 write: await this.decryptWithLockedVault(
207 relay.write,
208 'boolean',
209 withLockedVault.iv,
210 withLockedVault.password!
211 ),
212 };
213 return decryptedRelay;
214 };
215
216 export const decryptRelays = async function (
217 this: StorageService,
218 relays: Relay_ENCRYPTED[],
219 withLockedVault: LockedVaultContext | undefined = undefined
220 ): Promise<Relay_DECRYPTED[]> {
221 const decryptedRelays: Relay_DECRYPTED[] = [];
222
223 for (const relay of relays) {
224 const decryptedRelay = await decryptRelay.call(
225 this,
226 relay,
227 withLockedVault
228 );
229 decryptedRelays.push(decryptedRelay);
230 }
231
232 return decryptedRelays;
233 };
234
235 export const encryptRelay = async function (
236 this: StorageService,
237 relay: Relay_DECRYPTED
238 ): Promise<Relay_ENCRYPTED> {
239 const encryptedRelay: Relay_ENCRYPTED = {
240 id: await this.encrypt(relay.id),
241 identityId: await this.encrypt(relay.identityId),
242 url: await this.encrypt(relay.url),
243 read: await this.encrypt(relay.read.toString()),
244 write: await this.encrypt(relay.write.toString()),
245 };
246
247 return encryptedRelay;
248 };
249