Merge remote-tracking branch 'upstream/clearnet' into fix-explicit-updates-not-yet-sending

pull/1468/head
Audric Ackermann 4 years ago
commit fb9f615a11
No known key found for this signature in database
GPG Key ID: 999F434D76324AD4

@ -106,8 +106,6 @@
window.document.title = window.getTitle();
// start a background worker for ecc
textsecure.startWorker('js/libsignal-protocol-worker.js');
let messageReceiver;
Whisper.events = _.clone(Backbone.Events);
Whisper.events.isListenedTo = eventName =>

@ -1360,7 +1360,11 @@
let title = i18n('delete');
let message = i18n('deleteContactConfirmation');
if (this.isGroup()) {
if (
this.isGroup() &&
!this.get('left') &&
!this.get('isKickedFromGroup')
) {
title = i18n('leaveGroup');
message = i18n('leaveGroupConfirmation');
}

@ -25316,77 +25316,6 @@
})();
; (function () {
'use strict';
// I am the...workee?
var origCurve25519 = Internal.curve25519_async;
Internal.startWorker = function (url) {
Internal.stopWorker(); // there can be only one
Internal.curve25519_async = new Curve25519Worker(url);
Internal.Curve.async = Internal.wrapCurve25519(Internal.curve25519_async);
libsignal.Curve.async = Internal.wrapCurve(Internal.Curve.async);
};
Internal.stopWorker = function () {
if (Internal.curve25519_async instanceof Curve25519Worker) {
var worker = Internal.curve25519_async.worker;
Internal.curve25519_async = origCurve25519;
Internal.Curve.async = Internal.wrapCurve25519(Internal.curve25519_async);
libsignal.Curve.async = Internal.wrapCurve(Internal.Curve.async);
worker.terminate();
}
};
libsignal.worker = {
startWorker: Internal.startWorker,
stopWorker: Internal.stopWorker,
};
function Curve25519Worker(url) {
this.jobs = {};
this.jobId = 0;
this.worker = new Worker(url);
this.worker.onmessage = function (e) {
var job = this.jobs[e.data.id];
if (e.data.error && typeof job.onerror === 'function') {
job.onerror(new Error(e.data.error));
} else if (typeof job.onsuccess === 'function') {
job.onsuccess(e.data.result);
}
delete this.jobs[e.data.id];
}.bind(this);
}
Curve25519Worker.prototype = {
constructor: Curve25519Worker,
postMessage: function (methodName, args, onsuccess, onerror) {
return new Promise(function (resolve, reject) {
this.jobs[this.jobId] = { onsuccess: resolve, onerror: reject };
this.worker.postMessage({ id: this.jobId, methodName: methodName, args: args });
this.jobId++;
}.bind(this));
},
keyPair: function (privKey) {
return this.postMessage('keyPair', [privKey]);
},
sharedSecret: function (pubKey, privKey) {
return this.postMessage('sharedSecret', [pubKey, privKey]);
},
sign: function (privKey, message) {
return this.postMessage('sign', [privKey, message]);
},
verify: function (pubKey, message, sig) {
return this.postMessage('verify', [pubKey, message, sig]);
}
};
})();
/*
Copyright 2013 Daniel Wirtz <dcode@dcode.io>

@ -1,11 +1,8 @@
/* global window, textsecure, SignalProtocolStore, libsignal */
/* global window, textsecure, SignalProtocolStore */
// eslint-disable-next-line func-names
(function() {
window.textsecure = window.textsecure || {};
window.textsecure.storage = window.textsecure.storage || {};
textsecure.storage.protocol = new SignalProtocolStore();
textsecure.startWorker = libsignal.worker.startWorker;
textsecure.stopWorker = libsignal.worker.stopWorker;
})();

@ -165,6 +165,7 @@ export class SessionCompositionBox extends React.Component<Props, State> {
this.onChooseAttachment = this.onChooseAttachment.bind(this);
this.onClickAttachment = this.onClickAttachment.bind(this);
this.renderCaptionEditor = this.renderCaptionEditor.bind(this);
this.abortLinkPreviewFetch = this.abortLinkPreviewFetch.bind(this);
// On Sending
this.onSendMessage = this.onSendMessage.bind(this);
@ -183,7 +184,7 @@ export class SessionCompositionBox extends React.Component<Props, State> {
}
public componentWillUnmount() {
this.linkPreviewAbortController?.abort();
this.abortLinkPreviewFetch();
this.linkPreviewAbortController = undefined;
}
public componentDidUpdate(prevProps: Props, _prevState: State) {
@ -566,7 +567,7 @@ export class SessionCompositionBox extends React.Component<Props, State> {
},
});
const abortController = new AbortController();
this.linkPreviewAbortController?.abort();
this.abortLinkPreviewFetch();
this.linkPreviewAbortController = abortController;
setTimeout(() => {
abortController.abort();
@ -590,31 +591,64 @@ export class SessionCompositionBox extends React.Component<Props, State> {
}
}
}
this.setState({
stagedLinkPreview: {
isLoaded: true,
title: ret?.title || null,
description: ret?.description || '',
url: ret?.url || null,
domain:
(ret?.url && window.Signal.LinkPreviews.getDomain(ret.url)) || '',
image,
},
});
// we finished loading the preview, and checking the abortConrtoller, we are still not aborted.
// => update the staged preview
if (
this.linkPreviewAbortController &&
!this.linkPreviewAbortController.signal.aborted
) {
this.setState({
stagedLinkPreview: {
isLoaded: true,
title: ret?.title || null,
description: ret?.description || '',
url: ret?.url || null,
domain:
(ret?.url && window.Signal.LinkPreviews.getDomain(ret.url)) ||
'',
image,
},
});
} else if (this.linkPreviewAbortController) {
this.setState({
stagedLinkPreview: {
isLoaded: false,
title: null,
description: null,
url: null,
domain: null,
image: undefined,
},
});
this.linkPreviewAbortController = undefined;
}
})
.catch(err => {
window.log.warn('fetch link preview: ', err);
abortController.abort();
this.setState({
stagedLinkPreview: {
isLoaded: true,
title: null,
domain: null,
description: null,
url: firstLink,
image: undefined,
},
});
const aborted = this.linkPreviewAbortController?.signal.aborted;
this.linkPreviewAbortController = undefined;
// if we were aborted, it either means the UI was unmount, or more probably,
// than the message was sent without the link preview.
// So be sure to reset the staged link preview so it is not sent with the next message.
// if we were not aborted, it's probably just an error on the fetch. Nothing to do excpet mark the fetch as done (with errors)
if (aborted) {
this.setState({
stagedLinkPreview: undefined,
});
} else {
this.setState({
stagedLinkPreview: {
isLoaded: true,
title: null,
description: null,
url: firstLink,
domain: null,
image: undefined,
},
});
}
});
}
@ -751,6 +785,8 @@ export class SessionCompositionBox extends React.Component<Props, State> {
// tslint:disable-next-line: cyclomatic-complexity
private async onSendMessage() {
this.abortLinkPreviewFetch();
// this is dirty but we have to replace all @(xxx) by @xxx manually here
const cleanMentions = (text: string): string => {
const matches = text.match(this.mentionsRegex);
@ -835,10 +871,13 @@ export class SessionCompositionBox extends React.Component<Props, State> {
'attachments'
);
// we consider that a link previews without a title at least is not a preview
const linkPreviews =
(stagedLinkPreview && [
_.pick(stagedLinkPreview, 'url', 'image', 'title'),
]) ||
(stagedLinkPreview &&
stagedLinkPreview.isLoaded &&
stagedLinkPreview.title?.length && [
_.pick(stagedLinkPreview, 'url', 'image', 'title'),
]) ||
[];
try {
@ -854,20 +893,15 @@ export class SessionCompositionBox extends React.Component<Props, State> {
// Message sending sucess
this.props.onMessageSuccess();
this.props.clearAttachments();
// Empty composition box
// Empty composition box and stagedAttachments
this.setState({
message: '',
showEmojiPanel: false,
stagedLinkPreview: undefined,
ignoredLink: undefined,
});
// Empty stagedAttachments
this.props.clearAttachments();
if (stagedLinkPreview && stagedLinkPreview.url) {
this.setState({
stagedLinkPreview: undefined,
ignoredLink: undefined,
});
}
} catch (e) {
// Message sending failed
window.log.error(e);
@ -983,4 +1017,8 @@ export class SessionCompositionBox extends React.Component<Props, State> {
// Focus the textarea when user clicks anywhere in the composition box
this.textarea.current?.focus();
}
private abortLinkPreviewFetch() {
this.linkPreviewAbortController?.abort();
}
}

@ -125,6 +125,8 @@ export const ConversationHeaderMenu = (props: PropsConversationHeaderMenu) => {
isMe,
isGroup,
isPublic,
left,
isKickedFromGroup,
onDeleteContact,
window.i18n
)}

@ -92,6 +92,8 @@ export const ConversationListItemContextMenu = (
isMe,
type === 'group',
isPublic,
left,
isKickedFromGroup,
onDeleteContact,
window.i18n
)}

@ -39,9 +39,12 @@ function showCopyId(isPublic: boolean, isGroup: boolean): boolean {
function showDeleteContact(
isMe: boolean,
isGroup: boolean,
isPublic: boolean
isPublic: boolean,
isGroupLeft: boolean,
isKickedFromGroup: boolean
): boolean {
return !isMe && Boolean(!isGroup || isPublic);
// you need to have left a closed group first to be able to delete it completely.
return (!isMe && !isGroup) || (isGroup && (isGroupLeft || isKickedFromGroup));
}
function showAddModerators(
@ -97,10 +100,20 @@ export function getDeleteContactMenuItem(
isMe: boolean | undefined,
isGroup: boolean | undefined,
isPublic: boolean | undefined,
isLeft: boolean | undefined,
isKickedFromGroup: boolean | undefined,
action: any,
i18n: LocalizerType
): JSX.Element | null {
if (showDeleteContact(Boolean(isMe), Boolean(isGroup), Boolean(isPublic))) {
if (
showDeleteContact(
Boolean(isMe),
Boolean(isGroup),
Boolean(isPublic),
Boolean(isLeft),
Boolean(isKickedFromGroup)
)
) {
if (isPublic) {
return <Item onClick={action}>{i18n('leaveGroup')}</Item>;
}

@ -131,3 +131,11 @@ export async function timeout<T>(
return Promise.race([timeoutPromise, promise]);
}
export async function delay(timeoutMs: number = 2000): Promise<Boolean> {
return new Promise(resolve => {
setTimeout(() => {
resolve(true);
}, timeoutMs);
});
}

@ -9,6 +9,7 @@ import {
IMAGE_WEBP,
MIMEType,
} from '../types/MIME';
import { PromiseUtils } from '../session/utils';
const MAX_REQUEST_COUNT_WITH_REDIRECTS = 20;
// tslint:disable: prefer-for-of

@ -64,7 +64,6 @@ const excludedFiles = [
'^test/test.js',
// From libsignal-protocol-javascript project
'^js/libsignal-protocol-worker.js',
'^libtextsecure/libsignal-protocol.js',
// Test files

Loading…
Cancel
Save