adds option to whitelist image domains

This commit is contained in:
Ariel Fuggini 2020-08-27 18:05:12 -05:00 committed by JC Brand
parent f88960c561
commit 6adec9a8d2
4 changed files with 46 additions and 21 deletions

View File

@ -1692,6 +1692,9 @@ show_images_inline
If set to ``false``, images won't be rendered in chats, instead only their links will be shown.
It also accepts an array strings of whitelisted domain names to only render images that belong to those domains.
E.g. ``['imgur.com', 'imgbb.com']``
show_retraction_warning
-----------------------

View File

@ -974,6 +974,7 @@ describe("A Chat Message", function () {
expect(msg.textContent.trim()).toEqual('hello world');
expect(msg.querySelectorAll('img').length).toEqual(2);
// @XXX This test isn't really testing anything - needs revisiting
// Non-https images aren't rendered
message = base_url+"/logo/conversejs-filled.svg";
expect(view.content.querySelectorAll('img').length).toBe(4);
@ -985,7 +986,31 @@ describe("A Chat Message", function () {
message = 'http://imgur.com/xxxxxxx';
mock.sendMessage(view, message);
await u.waitUntil(() => view.el.querySelectorAll('.chat-content .chat-image').length === 5, 1000);
expect(view.content.querySelectorAll('img').length).toBe(5);
expect(view.content.querySelectorAll('.chat-content .chat-image').length).toBe(5);
done();
}));
it("will render images from approved URLs only",
mock.initConverse(
['rosterGroupsFetched', 'chatBoxesFetched'], {},
async function (done, _converse) {
await mock.waitForRoster(_converse, 'current');
const base_url = 'https://conversejs.org';
let message = 'http://wrongdomain.com/xxxxxxx.png';
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
await mock.openChatBoxFor(_converse, contact_jid);
_converse.api.settings.set('show_images_inline', ['conversejs.org']);
const view = _converse.api.chatviews.get(contact_jid);
spyOn(view.model, 'sendMessage').and.callThrough();
mock.sendMessage(view, message);
message = base_url+"/logo/conversejs-filled.svg";
mock.sendMessage(view, message);
await u.waitUntil(() => view.el.querySelectorAll('.chat-content .chat-msg').length === 2, 1000);
await u.waitUntil(() => view.el.querySelectorAll('.chat-content .chat-image').length === 1, 1000)
expect(view.content.querySelectorAll('.chat-content .chat-image').length).toBe(1);
done();
}));

View File

@ -120,9 +120,9 @@ function addHyperlinks (text, onImgLoad, onImgClick) {
text.addTemplateResult(
url_obj.start,
url_obj.end,
show_images && u.isImageURL(url_text) ?
u.convertToImageTag(url_text, onImgLoad, onImgClick) :
u.convertUrlToHyperlink(url_text),
show_images && u.isImageURL(url_text) && u.isImageDomainAllowed(url_text)
? u.convertToImageTag(url_text, onImgLoad, onImgClick)
: u.convertUrlToHyperlink(url_text)
);
});
}

View File

@ -82,6 +82,18 @@ u.isImageURL = url => {
? regex.test(url)
: checkFileTypes(['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.tiff', '.svg'], url);
}
u.isImageDomainAllowed = url => {
try {
const show_images_inline = api.settings.get('show_images_inline');
const is_domains_array = Array.isArray(show_images_inline);
if (!is_domains_array) return true;
const image_domain = getURI(url).domain();
return show_images_inline.includes(image_domain);
} catch (error) {
log.debug(error);
return true;
}
}
function getFileName (uri) {
try {
@ -294,24 +306,9 @@ u.escapeHTML = function (string) {
.replace(/"/g, """);
};
u.convertToImageTag = function (url, onLoad, onClick) {
const uri = getURI(url);
const img_url_without_ext = ['imgur.com', 'pbs.twimg.com'].includes(uri.hostname());
if (u.isImageURL(url) || img_url_without_ext) {
if (img_url_without_ext) {
const format = (uri.hostname() === 'pbs.twimg.com') ? uri.search(true).format : 'png';
return tpl_image({
onClick,
onLoad,
'url': uri.removeSearch(/.*/).toString() + `.${format}`
});
} else {
return tpl_image({url, onClick, onLoad});
}
}
}
return tpl_image({url, onClick, onLoad});
};
u.convertURIoHyperlink = function (uri, urlAsTyped) {
let normalized_url = uri.normalize()._string;