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