Merge pull request #48 from BeaudanBrown/cleaning

Cleaning
pull/49/head
BeaudanBrown 6 years ago committed by GitHub
commit ef44a123ed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1137,8 +1137,8 @@ async function saveMessage(data, { forceSave } = {}) {
// eslint-disable-next-line camelcase
received_at,
schemaVersion,
// eslint-disable-next-line camelcase
sent,
// eslint-disable-next-line camelcase
sent_at,
source,
sourceDevice,
@ -1423,7 +1423,7 @@ async function getMessagesBySentAt(sentAt) {
async function getSeenMessagesByHashList(hashes) {
const rows = await db.all(
`SELECT * FROM seenMessages WHERE hash IN ( ${hashes.map(() => '?').join(', ')} );`,
hashes
hashes
);
return map(rows, row => row.hash);

@ -7,12 +7,11 @@
Signal,
storage,
textsecure,
WebAPI
Whisper,
*/
// eslint-disable-next-line func-names
(async function() {
(async function () {
'use strict';
// Globally disable drag and drop
@ -325,7 +324,7 @@
// Combine the models
const messagesForCleanup = results.reduce((array, current) => array.concat(current.toArray()), []);
window.log.info(
`Cleanup: Found ${messagesForCleanup.length} messages for cleanup`
);
@ -376,7 +375,7 @@
let isMigrationWithIndexComplete = false;
window.log.info(
`Starting background data migration. Target version: ${
Message.CURRENT_SCHEMA_VERSION
Message.CURRENT_SCHEMA_VERSION
}`
);
idleDetector.on('idle', async () => {
@ -565,7 +564,7 @@
// Gets called when a user accepts or declines a friend request
Whisper.events.on('friendRequestUpdated', friendRequest => {
const { pubKey, ...message } = friendRequest;
const { pubKey, ...message } = friendRequest;
if (messageReceiver) {
messageReceiver.onFriendRequestUpdate(pubKey, message);
}
@ -577,11 +576,13 @@
}
});
Whisper.events.on('calculatingPoW', ({ pubKey, timestamp}) => {
Whisper.events.on('calculatingPoW', ({ pubKey, timestamp }) => {
try {
const conversation = ConversationController.get(pubKey);
conversation.onCalculatingPoW(pubKey, timestamp);
} catch (e) {}
} catch (e) {
window.log.error('Error showing PoW cog');
}
});
}
@ -1289,7 +1290,7 @@
} catch (error) {
window.log.error(
`Failed to send delivery receipt to ${data.source} for message ${
data.timestamp
data.timestamp
}:`,
error && error.stack ? error.stack : error
);

@ -1,8 +1,7 @@
/* global _: false */
/* global Backbone: false */
/* global libphonenumber: false */
/* global ConversationController: false */
/* global i18n: false */
/* global libsignal: false */
/* global storage: false */
/* global textsecure: false */
@ -11,7 +10,7 @@
/* eslint-disable more/no-then */
// eslint-disable-next-line func-names
(function() {
(function () {
'use strict';
window.Whisper = window.Whisper || {};
@ -129,7 +128,7 @@
setTimeout(() => {
this.setFriendRequestTimer();
}, 0);
const sealedSender = this.get('sealedSender');
if (sealedSender === undefined) {
this.set({ sealedSender: SEALED_SENDER.UNKNOWN });
@ -239,37 +238,39 @@
}
},
// This goes through all our message history and finds a friend request
// But this is not a concurrent operation and thus `updatePendingFriendRequests` is used
// But this is not a concurrent operation and thus updatePendingFriendRequests is used
async hasPendingFriendRequests() {
// Go through the messages and check for any pending friend requests
const messages = await window.Signal.Data.getMessagesByConversation(
this.id,
{
{
type: 'friend-request',
MessageCollection: Whisper.MessageCollection,
}
);
for (const message of messages.models) {
if (message.isFriendRequest() && message.attributes.friendStatus === 'pending') return true;
}
return false;
const pendingFriendRequest =
messages.models.find(message =>
message.isFriendRequest() &&
message.attributes.friendStatus === 'pending'
);
return pendingFriendRequest !== undefined;
},
async getPendingFriendRequests(direction) {
// Theoretically all ouur messages could be friend requests, thus we have to unfortunately go through each one :(
// Theoretically all our messages could be friend requests,
// thus we have to unfortunately go through each one :(
const messages = await window.Signal.Data.getMessagesByConversation(
this.id,
{
{
type: 'friend-request',
MessageCollection: Whisper.MessageCollection,
}
);
// Get the messages that are matching the direction and the friendStatus
return messages.models.filter(m => {
return (m.attributes.direction === direction && m.attributes.friendStatus === 'pending')
});
return messages.models.filter(m =>
m.attributes.direction === direction &&
m.attributes.friendStatus === 'pending'
);
},
getPropsForListItem() {
const result = {
@ -351,7 +352,7 @@
if (!this.isPrivate()) {
throw new Error(
'You cannot verify a group conversation. ' +
'You must verify individual contacts.'
'You must verify individual contacts.'
);
}
@ -469,7 +470,9 @@
},
async onFriendRequestAccepted({ updateUnread }) {
// Make sure we don't keep incrementing the unread count
const unreadCount = this.isKeyExchangeCompleted() || !updateUnread ? {} : { unreadCount: this.get('unreadCount') + 1 };
const unreadCount = !updateUnread || this.isKeyExchangeCompleted()
? {}
: { unreadCount: this.get('unreadCount') + 1 };
this.set({
friendRequestStatus: null,
keyExchangeCompleted: true,
@ -528,7 +531,7 @@
friendRequestStatus.allowSending = false;
const delayMs = 60 * 60 * 1000 * friendRequestLockDuration;
friendRequestStatus.unlockTimestamp = Date.now() + delayMs;
// Update the text input state
this.updateTextInputState();
@ -580,7 +583,7 @@
if (!this.isPrivate()) {
throw new Error(
'You cannot set a group conversation as trusted. ' +
'You must set individual contacts as trusted.'
'You must set individual contacts as trusted.'
);
}
@ -738,17 +741,16 @@
// This is to ensure that one user cannot spam us with multiple friend requests
if (_options.direction === 'incoming') {
const requests = await this.getPendingFriendRequests('incoming');
for (const request of requests) {
// Delete the old message if it's pending
await this._removeMessage(request.id);
}
// Delete the old message if it's pending
await Promise.all(requests.map(request => this._removeMessage(request.id)));
// Trigger an update if we removed messages
if (requests.length > 0)
this.trigger('change');
}
// Add the new message
// eslint-disable-next-line camelcase
const received_at = _options.received_at || Date.now();
const message = {
conversationId: this.id,
@ -770,11 +772,11 @@
Message: Whisper.Message,
});
const whisperMessage = new Whisper.Message({
const whisperMessage = new Whisper.Message({
...message,
id,
});
this.trigger('newmessage', whisperMessage);
this.notify(whisperMessage);
},
@ -978,9 +980,9 @@
fileName: fileName || null,
thumbnail: thumbnail
? {
...(await loadAttachmentData(thumbnail)),
objectUrl: getAbsoluteAttachmentPath(thumbnail.path),
}
...(await loadAttachmentData(thumbnail)),
objectUrl: getAbsoluteAttachmentPath(thumbnail.path),
}
: null,
};
})
@ -1007,7 +1009,7 @@
'with timestamp',
now
);
let messageWithSchema = null;
// If we have exchanged keys then let the user send the message normally
@ -1024,26 +1026,31 @@
recipients,
});
} else {
// We also need to make sure we don't send a new friend request if we already have an existing one
const incomingRequests = await this.getPendingFriendRequests('incoming');
if (incomingRequests.length > 0) return;
// We also need to make sure we don't send a new friend request
// if we already have an existing one
const incomingRequests = await this.getPendingFriendRequests('incoming');
if (incomingRequests.length > 0) return null;
// Otherwise check if we have sent a friend request
const outgoingRequests = await this.getPendingFriendRequests('outgoing');
if (outgoingRequests.length > 0) {
// Check if the requests have errored, if so then remove them and send the new request if possible
const friendRequestSent = false;
for (const outgoing of outgoingRequests) {
// Check if the requests have errored, if so then remove them
// and send the new request if possible
let friendRequestSent = false;
const promises = [];
outgoingRequests.forEach(outgoing => {
if (outgoing.hasErrors()) {
await this._removeMessage(outgoing.id);
promises.push(this._removeMessage(outgoing.id));
} else {
// No errors = we have sent over the friend request
friendRequestSent = true;
}
}
});
await Promise.all(promises);
// If the requests didn't error then don't add a new friend request because one of them was sent successfully
if (friendRequestSent) return;
// If the requests didn't error then don't add a new friend request
// because one of them was sent successfully
if (friendRequestSent) return null;
}
// Send the friend request!
@ -1114,8 +1121,8 @@
const options = this.getSendOptions();
// Add the message sending on another queue so that our UI doesn't get blocked
this.queueMessageSend(async () => {
return message.send(
this.queueMessageSend(async () =>
message.send(
this.wrapSend(
sendFunction(
destination,
@ -1128,8 +1135,8 @@
options
)
)
);
});
)
);
return true;
});
@ -1148,12 +1155,11 @@
this.trigger('disable:input', true);
this.trigger('change:placeholder', 'disabled');
return;
} else {
// Tell the user to introduce themselves
this.trigger('disable:input', false);
this.trigger('change:placeholder', 'friend-request');
return;
}
// Tell the user to introduce themselves
this.trigger('disable:input', false);
this.trigger('change:placeholder', 'friend-request');
return;
}
this.trigger('disable:input', false);
this.trigger('change:placeholder', 'chat');
@ -1303,8 +1309,8 @@
accessKey && sealedSender === SEALED_SENDER.ENABLED
? accessKey
: window.Signal.Crypto.arrayBufferToBase64(
window.Signal.Crypto.getRandomBytes(16)
),
window.Signal.Crypto.getRandomBytes(16)
),
},
};
},
@ -1583,7 +1589,7 @@
} else {
window.log.warn(
'Marked a message as read in the database, but ' +
'it was not in messageCollection.'
'it was not in messageCollection.'
);
}
@ -2104,8 +2110,10 @@
// Notification for friend request received
async notifyFriendRequest(source, type) {
// Data validation
if (!source) return Promise.reject('Invalid source');
if (!['accepted', 'requested'].includes(type)) return Promise.reject('Type must be accepted or requested.');
if (!source)
throw new Error('Invalid source');
if (!['accepted', 'requested'].includes(type))
throw new Error('Type must be accepted or requested.');
// Call the notification on the right conversation
let conversation = this;
@ -2115,29 +2123,33 @@
source,
'private'
);
window.log.info(`Notify called on a different conversation. expected: ${this.id}. actual: ${conversation.id}`);
window.log.info(`Notify called on a different conversation.
Expected: ${this.id}. Actual: ${conversation.id}`);
} catch (e) {
return Promise.reject('Failed to fetch conversation');
throw new Error('Failed to fetch conversation.');
}
}
const isTypeAccepted = type === 'accepted';
const title = isTypeAccepted ? 'friendRequestAcceptedNotificationTitle' : 'friendRequestNotificationTitle';
const message = isTypeAccepted ? 'friendRequestAcceptedNotificationMessage' : 'friendRequestNotificationMessage';
conversation.getNotificationIcon().then(iconUrl => {
window.log.info('Add notification for friend request updated', {
conversationId: conversation.idForLogging(),
});
Whisper.Notifications.add({
conversationId: conversation.id,
iconUrl,
isExpiringMessage: false,
message: i18n(message, conversation.getTitle()),
messageSentAt: Date.now(),
title: i18n(title),
});
});
const title = isTypeAccepted
? 'friendRequestAcceptedNotificationTitle'
: 'friendRequestNotificationTitle';
const message = isTypeAccepted
? 'friendRequestAcceptedNotificationMessage'
: 'friendRequestNotificationMessage';
const iconUrl = await conversation.getNotificationIcon();
window.log.info('Add notification for friend request updated', {
conversationId: conversation.idForLogging(),
});
Whisper.Notifications.add({
conversationId: conversation.id,
iconUrl,
isExpiringMessage: false,
message: i18n(message, conversation.getTitle()),
messageSentAt: Date.now(),
title: i18n(title),
});
},
});

@ -12,7 +12,7 @@
/* eslint-disable more/no-then */
// eslint-disable-next-line func-names
(function() {
(function () {
'use strict';
window.Whisper = window.Whisper || {};
@ -536,8 +536,8 @@
contact.number && contact.number[0] && contact.number[0].value;
const onSendMessage = firstNumber
? () => {
this.trigger('open-conversation', firstNumber);
}
this.trigger('open-conversation', firstNumber);
}
: null;
const onClick = async () => {
// First let's be sure that the signal account check is complete.
@ -576,8 +576,8 @@
!path && !objectUrl
? null
: Object.assign({}, attachment.thumbnail || {}, {
objectUrl: path || objectUrl,
});
objectUrl: path || objectUrl,
});
return Object.assign({}, attachment, {
isVoiceMessage: Signal.Types.Attachment.isVoiceMessage(attachment),
@ -644,15 +644,15 @@
url: getAbsoluteAttachmentPath(path),
screenshot: screenshot
? {
...screenshot,
url: getAbsoluteAttachmentPath(screenshot.path),
}
...screenshot,
url: getAbsoluteAttachmentPath(screenshot.path),
}
: null,
thumbnail: thumbnail
? {
...thumbnail,
url: getAbsoluteAttachmentPath(thumbnail.path),
}
...thumbnail,
url: getAbsoluteAttachmentPath(thumbnail.path),
}
: null,
};
},
@ -1393,7 +1393,7 @@
if (previousUnread !== message.get('unread')) {
window.log.warn(
'Caught race condition on new message read state! ' +
'Manually starting timers.'
'Manually starting timers.'
);
// We call markRead() even though the message is already
// marked read because we need to start expiration

@ -1,4 +1,4 @@
/* global log, dcodeIO */
/* global log, dcodeIO, window */
const fetch = require('node-fetch');
const is = require('@sindresorhus/is');

@ -1,7 +1,7 @@
/* global window, dcodeIO, textsecure, StringView */
// eslint-disable-next-line func-names
(function() {
(function () {
let server;
function stringToArrayBufferBase64(string) {
@ -41,15 +41,15 @@
};
const filterIncomingMessages = async function filterIncomingMessages(messages) {
const incomingHashes = messages.map(m => m.hash);
const dupHashes = await window.Signal.Data.getSeenMessagesByHashList(incomingHashes);
const newMessages = messages.filter(m => !dupHashes.includes(m.hash));
const newHashes = newMessages.map(m => ({
expiresAt: m.expiration,
hash: m.hash,
}));
await window.Signal.Data.saveSeenMessageHashes(newHashes);
return newMessages;
const incomingHashes = messages.map(m => m.hash);
const dupHashes = await window.Signal.Data.getSeenMessagesByHashList(incomingHashes);
const newMessages = messages.filter(m => !dupHashes.includes(m.hash));
const newHashes = newMessages.map(m => ({
expiresAt: m.expiration,
hash: m.hash,
}));
await window.Signal.Data.saveSeenMessageHashes(newHashes);
return newMessages;
};
window.HttpResource = function HttpResource(_server, opts = {}) {
@ -67,7 +67,7 @@
try {
result = await server.retrieveMessages(pubKey);
connected = true;
} catch(err) {
} catch (err) {
connected = false;
setTimeout(() => { pollServer(callBack); }, 5000);
return;

@ -1,6 +1,7 @@
/* global window: false */
/* global textsecure: false */
/* global StringView: false */
/* global libloki: false */
/* global libsignal: false */
/* global WebSocket: false */
/* global Event: false */
@ -10,8 +11,10 @@
/* global ContactBuffer: false */
/* global GroupBuffer: false */
/* global Worker: false */
/* global WebSocketResource: false */
/* eslint-disable more/no-then */
/* eslint-disable no-unreachable */
const WORKER_TIMEOUT = 60 * 1000; // one minute
@ -251,27 +254,26 @@ MessageReceiver.prototype.extend({
this.calledClose
);
// TODO: handle properly
return;
this.shutdown();
if (this.calledClose) {
return Promise.resolve();
}
if (ev.code === 3000) {
return Promise.resolve();
}
if (ev.code === 3001) {
this.onEmpty();
}
// possible 403 or network issue. Make an request to confirm
return this.server
.getDevices(this.number)
.then(this.connect.bind(this)) // No HTTP error? Reconnect
.catch(e => {
const event = new Event('error');
event.error = e;
return this.dispatchAndWait(event);
});
// this.shutdown();
// if (this.calledClose) {
// return Promise.resolve();
// }
// if (ev.code === 3000) {
// return Promise.resolve();
// }
// if (ev.code === 3001) {
// this.onEmpty();
// }
// // possible 403 or network issue. Make an request to confirm
// return this.server
// .getDevices(this.number)
// .then(this.connect.bind(this)) // No HTTP error? Reconnect
// .catch(e => {
// const event = new Event('error');
// event.error = e;
// return this.dispatchAndWait(event);
// });
},
handleRequest(request) {
this.incoming = this.incoming || [];
@ -708,7 +710,7 @@ MessageReceiver.prototype.extend({
promise = sessionCipher.decryptWhisperMessage(ciphertext)
.then(this.unpad);
break;
case textsecure.protobuf.Envelope.Type.FRIEND_REQUEST:
case textsecure.protobuf.Envelope.Type.FRIEND_REQUEST: {
window.log.info('friend-request message from ', envelope.source);
const fallBackSessionCipher = new libloki.FallBackSessionCipher(
address
@ -716,6 +718,7 @@ MessageReceiver.prototype.extend({
promise = fallBackSessionCipher.decrypt(ciphertext.toArrayBuffer())
.then(this.unpad);
break;
}
case textsecure.protobuf.Envelope.Type.PREKEY_BUNDLE:
window.log.info('prekey message from', this.getEnvelopeId(envelope));
promise = this.decryptPreKeyWhisperMessage(
@ -971,13 +974,13 @@ MessageReceiver.prototype.extend({
if (!message || !message.direction || !message.friendStatus) return;
// Update the conversation
const conversation = ConversationController.get(pubKey);
const conversation = window.ConversationController.get(pubKey);
if (conversation) {
// Update the conversation friend request indicator
conversation.updatePendingFriendRequests();
conversation.updateTextInputState();
}
// Send our own prekeys as a response
if (message.direction === 'incoming' && message.friendStatus === 'accepted') {
libloki.sendEmptyMessageWithPreKeys(pubKey);
@ -990,9 +993,9 @@ MessageReceiver.prototype.extend({
);
}
await conversation.onFriendRequestAccepted();
await conversation.onFriendRequestAccepted({ updateUnread: false });
}
console.log(`Friend request for ${pubKey} was ${message.friendStatus}`, message);
window.log.info(`Friend request for ${pubKey} was ${message.friendStatus}`, message);
},
async innerHandleContentMessage(envelope, plaintext) {
const content = textsecure.protobuf.Content.decode(plaintext);
@ -1000,15 +1003,17 @@ MessageReceiver.prototype.extend({
if (envelope.type === textsecure.protobuf.Envelope.Type.FRIEND_REQUEST) {
let conversation;
try {
conversation = ConversationController.get(envelope.source);
} catch (e) { }
conversation = window.ConversationController.get(envelope.source);
} catch (e) {
throw new Error('Error getting conversation for message.')
}
// only prompt friend request if there is no conversation yet
// only prompt friend request if there is no conversation yet
if (!conversation) {
this.promptUserToAcceptFriendRequest(
envelope,
content.dataMessage.body,
content.preKeyBundleMessage,
content.preKeyBundleMessage
);
} else {
const keyExchangeComplete = conversation.isKeyExchangeCompleted();
@ -1017,7 +1022,8 @@ MessageReceiver.prototype.extend({
// We are certain that other user accepted the friend request IF:
// - The message has a preKeyBundleMessage
// - We have an outgoing friend request that is pending
// The second check is crucial because it makes sure we don't save the preKeys of the incoming friend request (which is saved only when we press accept)
// The second check is crucial because it makes sure we don't save the preKeys of
// the incoming friend request (which is saved only when we press accept)
if (!keyExchangeComplete && content.preKeyBundleMessage) {
// Check for any outgoing friend requests
const pending = await conversation.getPendingFriendRequests('outgoing');
@ -1040,7 +1046,7 @@ MessageReceiver.prototype.extend({
}
// Exit early since the friend request reply will be a regular empty message
return;
return null;
}
if (content.syncMessage) {
@ -1054,9 +1060,7 @@ MessageReceiver.prototype.extend({
} else if (content.receiptMessage) {
return this.handleReceiptMessage(envelope, content.receiptMessage);
}
if (!content.preKeyBundleMessage) {
throw new Error('Unsupported content message');
}
throw new Error('Unsupported content message');
},
handleCallMessage(envelope) {
window.log.info('call message from', this.getEnvelopeId(envelope));
@ -1266,7 +1270,7 @@ MessageReceiver.prototype.extend({
preKeyBundleMessage.signature,
].map(k => dcodeIO.ByteBuffer.wrap(k).toArrayBuffer());
return {
return {
...preKeyBundleMessage,
identityKey,
preKey,
@ -1284,13 +1288,13 @@ MessageReceiver.prototype.extend({
signature,
} = preKeyBundleMessage;
if (pubKey != StringView.arrayBufferToHex(identityKey)) {
if (pubKey !== StringView.arrayBufferToHex(identityKey)) {
throw new Error(
'Error in handlePreKeyBundleMessage: envelope pubkey does not match pubkey in prekey bundle'
);
}
return await libloki.savePreKeyBundleForNumber({
return libloki.savePreKeyBundleForNumber({
pubKey,
preKeyId,
signedKeyId,
@ -1306,8 +1310,8 @@ MessageReceiver.prototype.extend({
return textsecure.storage.get('blocked-groups', []).indexOf(groupId) >= 0;
},
handleAttachment(attachment) {
console.log("Not handling attachments.");
return;
window.log.info('Not handling attachments.');
return Promise.reject();
// eslint-disable-next-line no-param-reassign
attachment.id = attachment.id.toString();
// eslint-disable-next-line no-param-reassign

@ -7,11 +7,10 @@
StringView,
dcodeIO,
log,
btoa,
_
*/
/* eslint-disable more/no-then */
/* eslint-disable no-unreachable */
function OutgoingMessage(
server,
@ -249,7 +248,8 @@ OutgoingMessage.prototype = {
if (accessKey && !senderCertificate) {
return Promise.reject(
new Error(
'OutgoingMessage.doSendMessage: accessKey was provided, but senderCertificate was not'
'OutgoingMessage.doSendMessage: accessKey was provided, ' +
'but senderCertificate was not'
)
);
}

Loading…
Cancel
Save