You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			213 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			JavaScript
		
	
			
		
		
	
	
			213 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			JavaScript
		
	
function SignalProtocolStore() {
 | 
						|
  this.store = {};
 | 
						|
}
 | 
						|
 | 
						|
SignalProtocolStore.prototype = {
 | 
						|
  Direction: { SENDING: 1, RECEIVING: 2 },
 | 
						|
  getIdentityKeyPair() {
 | 
						|
    return Promise.resolve(this.get('identityKey'));
 | 
						|
  },
 | 
						|
  getLocalRegistrationId() {
 | 
						|
    return Promise.resolve(this.get('registrationId'));
 | 
						|
  },
 | 
						|
  put(key, value) {
 | 
						|
    if (
 | 
						|
      key === undefined ||
 | 
						|
      value === undefined ||
 | 
						|
      key === null ||
 | 
						|
      value === null
 | 
						|
    ) {
 | 
						|
      throw new Error('Tried to store undefined/null');
 | 
						|
    }
 | 
						|
    this.store[key] = value;
 | 
						|
  },
 | 
						|
  get(key, defaultValue) {
 | 
						|
    if (key === null || key === undefined) {
 | 
						|
      throw new Error('Tried to get value for undefined/null key');
 | 
						|
    }
 | 
						|
    if (key in this.store) {
 | 
						|
      return this.store[key];
 | 
						|
    }
 | 
						|
    return defaultValue;
 | 
						|
  },
 | 
						|
  remove(key) {
 | 
						|
    if (key === null || key === undefined) {
 | 
						|
      throw new Error('Tried to remove value for undefined/null key');
 | 
						|
    }
 | 
						|
    delete this.store[key];
 | 
						|
  },
 | 
						|
 | 
						|
  isTrustedIdentity(identifier, identityKey) {
 | 
						|
    if (identifier === null || identifier === undefined) {
 | 
						|
      throw new Error('tried to check identity key for undefined/null key');
 | 
						|
    }
 | 
						|
    if (!(identityKey instanceof ArrayBuffer)) {
 | 
						|
      throw new Error('Expected identityKey to be an ArrayBuffer');
 | 
						|
    }
 | 
						|
    const trusted = this.get(`identityKey${identifier}`);
 | 
						|
    if (trusted === undefined) {
 | 
						|
      return Promise.resolve(true);
 | 
						|
    }
 | 
						|
    return Promise.resolve(identityKey === trusted);
 | 
						|
  },
 | 
						|
  loadIdentityKey(identifier) {
 | 
						|
    if (identifier === null || identifier === undefined) {
 | 
						|
      throw new Error('Tried to get identity key for undefined/null key');
 | 
						|
    }
 | 
						|
    return new Promise(resolve => {
 | 
						|
      resolve(this.get(`identityKey${identifier}`));
 | 
						|
    });
 | 
						|
  },
 | 
						|
  saveIdentity(identifier, identityKey) {
 | 
						|
    if (identifier === null || identifier === undefined) {
 | 
						|
      throw new Error('Tried to put identity key for undefined/null key');
 | 
						|
    }
 | 
						|
    return new Promise(resolve => {
 | 
						|
      const existing = this.get(`identityKey${identifier}`);
 | 
						|
      this.put(`identityKey${identifier}`, identityKey);
 | 
						|
      if (existing && existing !== identityKey) {
 | 
						|
        resolve(true);
 | 
						|
      } else {
 | 
						|
        resolve(false);
 | 
						|
      }
 | 
						|
    });
 | 
						|
  },
 | 
						|
 | 
						|
  /* Returns a prekeypair object or undefined */
 | 
						|
  loadPreKey(keyId) {
 | 
						|
    return new Promise(resolve => {
 | 
						|
      const res = this.get(`25519KeypreKey${keyId}`);
 | 
						|
      resolve(res);
 | 
						|
    });
 | 
						|
  },
 | 
						|
  storePreKey(keyId, keyPair, contactPubKey = null) {
 | 
						|
    if (contactPubKey) {
 | 
						|
      const data = {
 | 
						|
        id: keyId,
 | 
						|
        publicKey: keyPair.pubKey,
 | 
						|
        privateKey: keyPair.privKey,
 | 
						|
        recipient: contactPubKey,
 | 
						|
      };
 | 
						|
      return new Promise(resolve => {
 | 
						|
        resolve(this.put(`25519KeypreKey${contactPubKey}`, data));
 | 
						|
      });
 | 
						|
    }
 | 
						|
    return new Promise(resolve => {
 | 
						|
      resolve(this.put(`25519KeypreKey${keyId}`, keyPair));
 | 
						|
    });
 | 
						|
  },
 | 
						|
  removePreKey(keyId) {
 | 
						|
    return new Promise(resolve => {
 | 
						|
      resolve(this.remove(`25519KeypreKey${keyId}`));
 | 
						|
    });
 | 
						|
  },
 | 
						|
 | 
						|
  /* Returns a signed keypair object or undefined */
 | 
						|
  loadSignedPreKey(keyId) {
 | 
						|
    return new Promise(resolve => {
 | 
						|
      const res = this.get(`25519KeysignedKey${keyId}`);
 | 
						|
      resolve(res);
 | 
						|
    });
 | 
						|
  },
 | 
						|
  loadSignedPreKeys() {
 | 
						|
    return new Promise(resolve => {
 | 
						|
      const res = [];
 | 
						|
      const keys = Object.keys(this.store);
 | 
						|
      for (let i = 0, max = keys.length; i < max; i += 1) {
 | 
						|
        const key = keys[i];
 | 
						|
        if (key.startsWith('25519KeysignedKey')) {
 | 
						|
          res.push(this.store[key]);
 | 
						|
        }
 | 
						|
      }
 | 
						|
      resolve(res);
 | 
						|
    });
 | 
						|
  },
 | 
						|
  storeSignedPreKey(keyId, keyPair) {
 | 
						|
    return new Promise(resolve => {
 | 
						|
      resolve(this.put(`25519KeysignedKey${keyId}`, keyPair));
 | 
						|
    });
 | 
						|
  },
 | 
						|
  removeSignedPreKey(keyId) {
 | 
						|
    return new Promise(resolve => {
 | 
						|
      resolve(this.remove(`25519KeysignedKey${keyId}`));
 | 
						|
    });
 | 
						|
  },
 | 
						|
 | 
						|
  loadSession(identifier) {
 | 
						|
    return new Promise(resolve => {
 | 
						|
      resolve(this.get(`session${identifier}`));
 | 
						|
    });
 | 
						|
  },
 | 
						|
  storeSession(identifier, record) {
 | 
						|
    return new Promise(resolve => {
 | 
						|
      resolve(this.put(`session${identifier}`, record));
 | 
						|
    });
 | 
						|
  },
 | 
						|
  removeAllSessions(identifier) {
 | 
						|
    return new Promise(resolve => {
 | 
						|
      const keys = Object.keys(this.store);
 | 
						|
      for (let i = 0, max = keys.length; i < max; i += 1) {
 | 
						|
        const key = keys[i];
 | 
						|
        if (key.match(RegExp(`^session${identifier.replace('+', '\\+')}.+`))) {
 | 
						|
          delete this.store[key];
 | 
						|
        }
 | 
						|
      }
 | 
						|
      resolve();
 | 
						|
    });
 | 
						|
  },
 | 
						|
  getDeviceIds(identifier) {
 | 
						|
    return new Promise(resolve => {
 | 
						|
      const deviceIds = [];
 | 
						|
      const keys = Object.keys(this.store);
 | 
						|
      for (let i = 0, max = keys.length; i < max; i += 1) {
 | 
						|
        const key = keys[i];
 | 
						|
        if (key.match(RegExp(`^session${identifier.replace('+', '\\+')}.+`))) {
 | 
						|
          deviceIds.push(parseInt(key.split('.')[1], 10));
 | 
						|
        }
 | 
						|
      }
 | 
						|
      resolve(deviceIds);
 | 
						|
    });
 | 
						|
  },
 | 
						|
  async loadPreKeyForContact(contactPubKey) {
 | 
						|
    return new Promise(resolve => {
 | 
						|
      const key = this.get(`25519KeypreKey${contactPubKey}`);
 | 
						|
      if (!key) {
 | 
						|
        resolve(undefined);
 | 
						|
      }
 | 
						|
      resolve({
 | 
						|
        pubKey: key.publicKey,
 | 
						|
        privKey: key.privateKey,
 | 
						|
        keyId: key.id,
 | 
						|
        recipient: key.recipient,
 | 
						|
      });
 | 
						|
    });
 | 
						|
  },
 | 
						|
  async storeContactSignedPreKey(pubKey, signedPreKey) {
 | 
						|
    const key = {
 | 
						|
      identityKeyString: pubKey,
 | 
						|
      keyId: signedPreKey.keyId,
 | 
						|
      publicKey: signedPreKey.publicKey,
 | 
						|
      signature: signedPreKey.signature,
 | 
						|
      created_at: Date.now(),
 | 
						|
      confirmed: false,
 | 
						|
    };
 | 
						|
    this.put(`contactSignedPreKey${pubKey}`, key);
 | 
						|
  },
 | 
						|
  async loadContactSignedPreKey(pubKey) {
 | 
						|
    const preKey = this.get(`contactSignedPreKey${pubKey}`);
 | 
						|
    if (preKey) {
 | 
						|
      return {
 | 
						|
        id: preKey.id,
 | 
						|
        identityKeyString: preKey.identityKeyString,
 | 
						|
        publicKey: preKey.publicKey,
 | 
						|
        signature: preKey.signature,
 | 
						|
        created_at: preKey.created_at,
 | 
						|
        keyId: preKey.keyId,
 | 
						|
        confirmed: preKey.confirmed,
 | 
						|
      };
 | 
						|
    }
 | 
						|
    window.log.warn('Failed to fetch contact signed prekey:', pubKey);
 | 
						|
    return undefined;
 | 
						|
  },
 | 
						|
};
 |