@jsxc/jsxc
Version:
Real-time XMPP chat application with video calls, file transfer and encrypted communication
65 lines (49 loc) • 2.1 kB
text/typescript
import Address from '../vendor/Address';
import Store from './Store';
import BundleManager from './BundleManager';
import EncryptedDeviceMessage from '../model/EncryptedDeviceMessage';
import { SessionCipher } from '../vendor/SessionCipher';
import { SessionBuilder } from '../vendor/SessionBuilder';
import Bundle from './Bundle';
import Log from '@util/Log';
export default class Session {
private sessionCipher;
constructor(private address: Address, private store: Store, private bundleManager: BundleManager) {}
public async decrypt(ciphertext, preKey: boolean = false): Promise<ArrayBuffer> {
let sessionCipher = this.getSessionCipher();
let plaintextBuffer;
if (preKey) {
plaintextBuffer = await sessionCipher.decryptPreKeyMessage(ciphertext);
} else {
plaintextBuffer = await sessionCipher.decryptMessage(ciphertext);
}
return plaintextBuffer;
}
public async encrypt(plaintext): Promise<EncryptedDeviceMessage | null> {
try {
if (!this.store.hasSession(this.address.toString())) {
await this.establishSession();
}
let session = this.getSessionCipher();
let ciphertext = await session.encryptMessage(plaintext);
return new EncryptedDeviceMessage(this.address, ciphertext);
} catch (err) {
Log.warn('Could not encrypt data for device with id ' + this.address.getDeviceId(), err);
return null; // Otherwise Promise.all throws an error
}
}
private async establishSession() {
let bundle = await this.bundleManager.requestBundle(this.address);
await this.processPreKeyMessage(bundle);
}
private processPreKeyMessage = (bundle: Bundle): Promise<void> => {
let builder = new SessionBuilder(this.address, this.store);
return builder.processPreKey(bundle).then(() => undefined);
};
private getSessionCipher(): SessionCipher {
if (!this.sessionCipher) {
this.sessionCipher = new SessionCipher(this.address, this.store);
}
return this.sessionCipher;
}
}