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.
session-desktop/ts/receiver/sessionHandling.ts

124 lines
3.6 KiB
TypeScript

import { EnvelopePlus } from './types';
import { SignalService } from '../protobuf';
import * as libsession from './../session';
import { toNumber } from 'lodash';
import { PubKey } from '../session/types';
import { SessionEstablishedMessage } from '../session/messages/outgoing';
import { SessionProtocol } from '../session/protocols';
export async function handleEndSession(number: string): Promise<void> {
window.log.info('got end session');
const { ConversationController } = window;
try {
const conversation = ConversationController.get(number);
if (conversation) {
await conversation.onSessionResetReceived();
} else {
throw new Error();
}
} catch (e) {
window.log.error('Error getting conversation: ', number);
}
}
export async function handleSessionRequestMessage(
envelope: EnvelopePlus,
content: SignalService.Content
) {
const { libsignal, libloki, StringView, textsecure, dcodeIO, log } = window;
const { preKeyBundleMessage } = content;
window.console.log(
`Received SESSION_REQUEST from source: ${envelope.source}`
);
if (!preKeyBundleMessage) {
log.warn('No pre-key bundle found in a session request');
return;
}
const shouldProcessSessionRequest = await SessionProtocol.shouldProcessSessionRequest(
new PubKey(envelope.source),
toNumber(envelope.timestamp)
);
if (!shouldProcessSessionRequest) {
log.debug('Ignoring a session request message');
return;
}
try {
// device id are always 1 with Session
const deviceId = 1;
const pubkey = envelope.source;
const address = new libsignal.SignalProtocolAddress(
envelope.source,
deviceId
);
// we process the new prekeys and initiate a new session.
// The old sessions will get deleted once the correspondant
// has switch to the new session.
const [identityKey, preKey, signedKey, signature] = [
preKeyBundleMessage.identityKey,
preKeyBundleMessage.preKey,
preKeyBundleMessage.signedKey,
preKeyBundleMessage.signature,
].map(k => dcodeIO.ByteBuffer.wrap(k).toArrayBuffer());
const { preKeyId, signedKeyId } = preKeyBundleMessage;
if (pubkey !== StringView.arrayBufferToHex(identityKey)) {
throw new Error(
'Error in savePreKeyBundleMessage: envelope pubkey does not match pubkey in prekey bundle'
);
}
if (preKey === undefined || signedKey === undefined) {
window.console.warn(
"Couldn't process prekey bundle without preKey or signedKey"
);
return;
}
const signedPreKey = {
keyId: signedKeyId,
publicKey: signedKey,
signature,
};
const preKeyObject = {
publicKey: preKey,
keyId: preKeyId,
};
const device = {
identityKey,
deviceId,
preKey: preKeyObject,
signedPreKey,
registrationId: 0,
};
const builder = new libsignal.SessionBuilder(
textsecure.storage.protocol,
address
);
await builder.processPreKey(device);
await SessionProtocol.onSessionRequestProcessed(
new PubKey(envelope.source)
);
log.debug('sending session established to', envelope.source);
// We don't need to await the call below because we just want to send it off
const user = new PubKey(envelope.source);
const sessionEstablished = new SessionEstablishedMessage({
timestamp: Date.now(),
});
await libsession.getMessageQueue().send(user, sessionEstablished);
libloki.api.sendSessionEstablishedMessage(envelope.source);
} catch (e) {
log.warn('Failed to process session request', e);
// TODO how to handle a failed session request?
}
}