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(); window.document.title = window.getTitle();
// start a background worker for ecc
textsecure.startWorker('js/libsignal-protocol-worker.js');
let messageReceiver; let messageReceiver;
Whisper.events = _.clone(Backbone.Events); Whisper.events = _.clone(Backbone.Events);
Whisper.events.isListenedTo = eventName => Whisper.events.isListenedTo = eventName =>

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

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

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

@ -39,9 +39,12 @@ function showCopyId(isPublic: boolean, isGroup: boolean): boolean {
function showDeleteContact( function showDeleteContact(
isMe: boolean, isMe: boolean,
isGroup: boolean, isGroup: boolean,
isPublic: boolean isPublic: boolean,
isGroupLeft: boolean,
isKickedFromGroup: boolean
): 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( function showAddModerators(
@ -97,10 +100,20 @@ export function getDeleteContactMenuItem(
isMe: boolean | undefined, isMe: boolean | undefined,
isGroup: boolean | undefined, isGroup: boolean | undefined,
isPublic: boolean | undefined, isPublic: boolean | undefined,
isLeft: boolean | undefined,
isKickedFromGroup: boolean | undefined,
action: any, action: any,
i18n: LocalizerType i18n: LocalizerType
): JSX.Element | null { ): 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) { if (isPublic) {
return <Item onClick={action}>{i18n('leaveGroup')}</Item>; return <Item onClick={action}>{i18n('leaveGroup')}</Item>;
} }

@ -131,3 +131,11 @@ export async function timeout<T>(
return Promise.race([timeoutPromise, promise]); 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, IMAGE_WEBP,
MIMEType, MIMEType,
} from '../types/MIME'; } from '../types/MIME';
import { PromiseUtils } from '../session/utils';
const MAX_REQUEST_COUNT_WITH_REDIRECTS = 20; const MAX_REQUEST_COUNT_WITH_REDIRECTS = 20;
// tslint:disable: prefer-for-of // tslint:disable: prefer-for-of

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

Loading…
Cancel
Save