Save attachments with macOS quarantine attribute

* Attachments: Always save file to downloads directory, show toast
* Add new build:dev command for casual builds
This commit is contained in:
Scott Nonnenberg 2020-01-09 11:57:43 -08:00 committed by Ken Powers
parent 65befde0fa
commit 1bf9ca7233
11 changed files with 202 additions and 52 deletions

View file

@ -119,6 +119,8 @@ function initializeMigrations({
getPath,
getStickersPath,
getTempPath,
openFileInDownloads,
writeToDownloads,
} = Attachments;
const {
getImageDimensions,
@ -187,11 +189,13 @@ function initializeMigrations({
loadPreviewData,
loadQuoteData,
loadStickerData,
openFileInDownloads,
readAttachmentData,
readDraftData,
readStickerData,
readTempData,
run,
writeToDownloads,
processNewAttachment: attachment =>
MessageType.processNewAttachment(attachment, {
writeNewAttachmentData,

View file

@ -26,8 +26,11 @@
getAbsoluteTempPath,
deleteDraftFile,
deleteTempFile,
openFileInDownloads,
readAttachmentData,
readDraftData,
writeNewDraftData,
writeToDownloads,
} = window.Signal.Migrations;
const {
getOlderMessagesByConversation,
@ -87,6 +90,44 @@
return { toastMessage: i18n('conversationReturnedToInbox') };
},
});
Whisper.FileSavedToast = Whisper.ToastView.extend({
className: 'toast toast-clickable',
initialize(options) {
if (!options.name) {
throw new Error('FileSavedToast: name option was not provided!');
}
this.name = options.name;
this.timeout = 10000;
if (window.getInteractionMode() === 'keyboard') {
setTimeout(() => {
this.$el.focus();
}, 1);
}
},
events: {
click: 'onClick',
keydown: 'onKeydown',
},
onClick() {
openFileInDownloads(this.name);
this.close();
},
onKeydown(event) {
if (event.key !== 'Enter' && event.key !== ' ') {
return;
}
event.preventDefault();
event.stopPropagation();
openFileInDownloads(this.name);
this.close();
},
render_attributes() {
return { toastMessage: i18n('attachmentSavedToDownloads', this.name) };
},
});
const MAX_MESSAGE_BODY_LENGTH = 64 * 1024;
Whisper.MessageBodyTooLongToast = Whisper.ToastView.extend({
@ -588,9 +629,16 @@
this.$('.timeline-placeholder').append(this.timelineView.el);
},
showToast(ToastView) {
const toast = new ToastView();
toast.$el.appendTo(this.$el);
showToast(ToastView, options) {
const toast = new ToastView(options);
const lightboxEl = $('.module-lightbox');
if (lightboxEl.length > 0) {
toast.$el.appendTo(lightboxEl);
} else {
toast.$el.appendTo(this.$el);
}
toast.render();
},
@ -1726,12 +1774,13 @@
const saveAttachment = async ({ attachment, message } = {}) => {
const timestamp = message.sent_at;
Signal.Types.Attachment.save({
const name = await Signal.Types.Attachment.save({
attachment,
document,
getAbsolutePath: getAbsoluteAttachmentPath,
readAttachmentData,
writeToDownloads,
timestamp,
});
this.showToast(Whisper.FileSavedToast, { name });
};
const onItemClick = async ({ message, attachment, type }) => {
@ -1916,18 +1965,19 @@
this.downloadAttachment({ attachment, timestamp, isDangerous });
},
downloadAttachment({ attachment, timestamp, isDangerous }) {
async downloadAttachment({ attachment, timestamp, isDangerous }) {
if (isDangerous) {
this.showToast(Whisper.DangerousFileTypeToast);
return;
}
Signal.Types.Attachment.save({
const name = await Signal.Types.Attachment.save({
attachment,
document,
getAbsolutePath: getAbsoluteAttachmentPath,
readAttachmentData,
writeToDownloads,
timestamp,
});
this.showToast(Whisper.FileSavedToast, { name });
},
async displayTapToViewMessage(messageId) {
@ -2124,13 +2174,14 @@
);
const onSave = async (options = {}) => {
Signal.Types.Attachment.save({
const name = await Signal.Types.Attachment.save({
attachment: options.attachment,
document,
index: options.index + 1,
getAbsolutePath: getAbsoluteAttachmentPath,
readAttachmentData,
writeToDownloads,
timestamp: options.message.get('sent_at'),
});
this.showToast(Whisper.FileSavedToast, { name });
};
const props = {

View file

@ -11,6 +11,7 @@
templateName: 'toast',
initialize() {
this.$el.hide();
this.timeout = 2000;
},
close() {
@ -24,8 +25,9 @@
_.result(this, 'render_attributes', '')
)
);
this.$el.attr('tabIndex', 0);
this.$el.show();
setTimeout(this.close.bind(this), 2000);
setTimeout(this.close.bind(this), this.timeout);
},
});