fix restoring of session after restore from seed

pull/1387/head
Audric Ackermann 5 years ago
parent 3d11271471
commit 6fd8ea20c7
No known key found for this signature in database
GPG Key ID: 999F434D76324AD4

@ -92,7 +92,7 @@ export interface ConversationModel
makeQuote: any; makeQuote: any;
unblock: any; unblock: any;
deleteContact: any; deleteContact: any;
endSession: any; endSession: () => Promise<void>;
block: any; block: any;
copyPublicKey: any; copyPublicKey: any;
getAvatar: any; getAvatar: any;

@ -1547,14 +1547,6 @@
}, },
async onSessionResetReceived() { async onSessionResetReceived() {
await this.setSessionResetStatus(SessionResetEnum.request_received); await this.setSessionResetStatus(SessionResetEnum.request_received);
// send empty message, this will trigger the new session to propagate
// to the reset initiator.
const user = new libsession.Types.PubKey(this.id);
const sessionEstablished = new window.libsession.Messages.Outgoing.SessionEstablishedMessage(
{ timestamp: Date.now() }
);
await libsession.getMessageQueue().send(user, sessionEstablished);
}, },
isSessionResetReceived() { isSessionResetReceived() {

@ -232,8 +232,7 @@
}; };
} }
window.log.error('Failed to fetch prekey:', keyId); throw new textsecure.PreKeyMissing();
return undefined;
}, },
async loadPreKeyForContact(contactPubKey) { async loadPreKeyForContact(contactPubKey) {
const key = await window.Signal.Data.getPreKeyByRecipient(contactPubKey); const key = await window.Signal.Data.getPreKeyByRecipient(contactPubKey);

@ -928,10 +928,6 @@
} }
}, },
endSession() {
this.model.endSession();
},
setDisappearingMessages(seconds) { setDisappearingMessages(seconds) {
if (seconds > 0) { if (seconds > 0) {
this.model.updateExpirationTimer(seconds); this.model.updateExpirationTimer(seconds);

@ -226,6 +226,18 @@
} }
} }
function PreKeyMissing() {
this.name = 'PreKeyMissing';
Error.call(this, this.name);
// Maintains proper stack trace, where our error was thrown (only available on V8)
// via https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error
if (Error.captureStackTrace) {
Error.captureStackTrace(this);
}
}
window.textsecure.SendMessageNetworkError = SendMessageNetworkError; window.textsecure.SendMessageNetworkError = SendMessageNetworkError;
window.textsecure.IncomingIdentityKeyError = IncomingIdentityKeyError; window.textsecure.IncomingIdentityKeyError = IncomingIdentityKeyError;
window.textsecure.OutgoingIdentityKeyError = OutgoingIdentityKeyError; window.textsecure.OutgoingIdentityKeyError = OutgoingIdentityKeyError;
@ -243,4 +255,5 @@
window.textsecure.PublicChatError = PublicChatError; window.textsecure.PublicChatError = PublicChatError;
window.textsecure.PublicTokenError = PublicTokenError; window.textsecure.PublicTokenError = PublicTokenError;
window.textsecure.SenderKeyMissing = SenderKeyMissing; window.textsecure.SenderKeyMissing = SenderKeyMissing;
window.textsecure.PreKeyMissing = PreKeyMissing;
})(); })();

@ -21,5 +21,6 @@ export interface LibTextsecure {
PublicChatError: any; PublicChatError: any;
PublicTokenError: any; PublicTokenError: any;
SenderKeyMissing: any; SenderKeyMissing: any;
PreKeyMissing: any;
createTaskWithTimeout(task: any, id: any, options?: any): Promise<any>; createTaskWithTimeout(task: any, id: any, options?: any): Promise<any>;
} }

@ -447,7 +447,7 @@ export class SessionConversation extends React.Component<Props, State> {
}, },
onDeleteContact: () => conversation.deleteContact(), onDeleteContact: () => conversation.deleteContact(),
onResetSession: () => { onResetSession: () => {
conversation.endSession(); void conversation.endSession();
}, },
onShowSafetyNumber: () => { onShowSafetyNumber: () => {

@ -6,7 +6,10 @@ import { removeFromCache, updateCache } from './cache';
import { SignalService } from '../protobuf'; import { SignalService } from '../protobuf';
import * as Lodash from 'lodash'; import * as Lodash from 'lodash';
import * as libsession from '../session'; import * as libsession from '../session';
import { handleSessionRequestMessage } from './sessionHandling'; import {
handleEndSession,
handleSessionRequestMessage,
} from './sessionHandling';
import { handlePairingAuthorisationMessage } from './multidevice'; import { handlePairingAuthorisationMessage } from './multidevice';
import { MediumGroupRequestKeysMessage } from '../session/messages/outgoing'; import { MediumGroupRequestKeysMessage } from '../session/messages/outgoing';
import { MultiDeviceProtocol, SessionProtocol } from '../session/protocols'; import { MultiDeviceProtocol, SessionProtocol } from '../session/protocols';
@ -169,16 +172,16 @@ async function decryptUnidentifiedSender(
window.log.info( window.log.info(
'Dropping blocked message with error after sealed sender decryption' 'Dropping blocked message with error after sealed sender decryption'
); );
await removeFromCache(envelope);
return null; return null;
} }
// eslint-disable-next-line no-param-reassign // eslint-disable no-param-reassign
envelope.source = source.getName(); envelope.source = source.getName();
// eslint-disable-next-line no-param-reassign
envelope.sourceDevice = source.getDeviceId(); envelope.sourceDevice = source.getDeviceId();
// eslint-disable-next-line no-param-reassign
envelope.unidentifiedDeliveryReceived = !originalSource; envelope.unidentifiedDeliveryReceived = !originalSource;
// eslint-enable no-param-reassign
await removeFromCache(envelope);
throw error; throw error;
} }
@ -257,6 +260,7 @@ async function doDecrypt(
} }
} }
// tslint:disable-next-line: max-func-body-length
async function decrypt( async function decrypt(
envelope: EnvelopePlus, envelope: EnvelopePlus,
ciphertext: ArrayBuffer ciphertext: ArrayBuffer
@ -309,6 +313,17 @@ async function decrypt(
return; return;
} }
} else if (error instanceof window.textsecure.PreKeyMissing) {
const convo = window.ConversationController.get(envelope.source);
if (!convo) {
window.console.warn(
'PreKeyMissing but convo is missing too. Dropping...'
);
return;
}
void convo.endSession();
return;
} }
let errorToThrow = error; let errorToThrow = error;

@ -286,14 +286,16 @@ export async function handleDataMessage(
return; return;
} }
// tslint:disable-next-line no-bitwise // tslint:disable no-bitwise
if ( if (
dataMessage.flags && dataMessage.flags &&
dataMessage.flags & SignalService.DataMessage.Flags.END_SESSION dataMessage.flags & SignalService.DataMessage.Flags.END_SESSION
) { ) {
await handleEndSession(envelope.source); await handleEndSession(envelope.source);
return; return removeFromCache(envelope);
} }
// tslint:enable no-bitwise
const message = await processDecrypted(envelope, dataMessage); const message = await processDecrypted(envelope, dataMessage);
const ourPubKey = window.textsecure.storage.user.getNumber(); const ourPubKey = window.textsecure.storage.user.getNumber();
const senderPubKey = envelope.senderIdentity || envelope.source; const senderPubKey = envelope.senderIdentity || envelope.source;
@ -302,7 +304,7 @@ export async function handleDataMessage(
const { UNPAIRING_REQUEST } = SignalService.DataMessage.Flags; const { UNPAIRING_REQUEST } = SignalService.DataMessage.Flags;
// eslint-disable-next-line no-bitwise // tslint:disable-next-line: no-bitwise
const isUnpairingRequest = Boolean(message.flags & UNPAIRING_REQUEST); const isUnpairingRequest = Boolean(message.flags & UNPAIRING_REQUEST);
if (isUnpairingRequest) { if (isUnpairingRequest) {

@ -14,6 +14,8 @@ export async function handleEndSession(number: string): Promise<void> {
try { try {
const conversation = ConversationController.get(number); const conversation = ConversationController.get(number);
if (conversation) { if (conversation) {
// this just marks the conversation as being waiting for a new session
// it does trigger a message to be sent. (the message is sent from handleSessionRequestMessage())
await conversation.onSessionResetReceived(); await conversation.onSessionResetReceived();
} else { } else {
throw new Error(); throw new Error();
@ -27,7 +29,7 @@ export async function handleSessionRequestMessage(
envelope: EnvelopePlus, envelope: EnvelopePlus,
preKeyBundleMessage: SignalService.IPreKeyBundleMessage preKeyBundleMessage: SignalService.IPreKeyBundleMessage
) { ) {
const { libsignal, libloki, StringView, textsecure, dcodeIO, log } = window; const { libsignal, StringView, textsecure, dcodeIO, log } = window;
window.console.log( window.console.log(
`Received SESSION_REQUEST from source: ${envelope.source}` `Received SESSION_REQUEST from source: ${envelope.source}`

@ -2,6 +2,7 @@ import { ContentMessage } from './ContentMessage';
import { SignalService } from '../../../../protobuf'; import { SignalService } from '../../../../protobuf';
import { MessageParams } from '../Message'; import { MessageParams } from '../Message';
import { Constants } from '../../..'; import { Constants } from '../../..';
import * as crypto from 'crypto';
export interface PreKeyBundleType { export interface PreKeyBundleType {
identityKey: Uint8Array; identityKey: Uint8Array;
@ -19,10 +20,19 @@ interface SessionRequestParams extends MessageParams {
export class SessionRequestMessage extends ContentMessage { export class SessionRequestMessage extends ContentMessage {
private readonly preKeyBundle: PreKeyBundleType; private readonly preKeyBundle: PreKeyBundleType;
private readonly padding: Buffer;
constructor(params: SessionRequestParams) { constructor(params: SessionRequestParams) {
super({ timestamp: params.timestamp, identifier: params.identifier }); super({ timestamp: params.timestamp, identifier: params.identifier });
this.preKeyBundle = params.preKeyBundle; this.preKeyBundle = params.preKeyBundle;
// Generate a random int from 1 and 512
const buffer = crypto.randomBytes(1);
// tslint:disable-next-line: no-bitwise
const paddingLength = (new Uint8Array(buffer)[0] & 0x1ff) + 1;
// Generate a random padding buffer of the chosen size
this.padding = crypto.randomBytes(paddingLength);
} }
public ttl(): number { public ttl(): number {
@ -36,7 +46,7 @@ export class SessionRequestMessage extends ContentMessage {
protected contentProto(): SignalService.Content { protected contentProto(): SignalService.Content {
const nullMessage = new SignalService.NullMessage({}); const nullMessage = new SignalService.NullMessage({});
const preKeyBundleMessage = this.getPreKeyBundleMessage(); const preKeyBundleMessage = this.getPreKeyBundleMessage();
nullMessage.padding = this.padding;
return new SignalService.Content({ return new SignalService.Content({
nullMessage, nullMessage,
preKeyBundleMessage, preKeyBundleMessage,

Loading…
Cancel
Save