diff --git a/app/assets/javascripts/discourse/components/avatar-uploader.js.es6 b/app/assets/javascripts/discourse/components/avatar-uploader.js.es6
index 539171bc9a1..fd5bac3c0e0 100644
--- a/app/assets/javascripts/discourse/components/avatar-uploader.js.es6
+++ b/app/assets/javascripts/discourse/components/avatar-uploader.js.es6
@@ -11,6 +11,10 @@ export default Em.Component.extend(UploadMixin, {
return uploading ? I18n.t("uploading") : I18n.t("user.change_avatar.upload_picture");
},
+ validateUploadedFilesOptions() {
+ return { imagesOnly: true };
+ },
+
uploadDone(upload) {
this.setProperties({
imageIsNotASquare: upload.width !== upload.height,
diff --git a/app/assets/javascripts/discourse/components/emoji-uploader.js.es6 b/app/assets/javascripts/discourse/components/emoji-uploader.js.es6
index b43bea04103..0afeb1a239c 100644
--- a/app/assets/javascripts/discourse/components/emoji-uploader.js.es6
+++ b/app/assets/javascripts/discourse/components/emoji-uploader.js.es6
@@ -11,6 +11,10 @@ export default Em.Component.extend(UploadMixin, {
return Ember.isBlank(this.get("name")) ? {} : { name: this.get("name") };
}.property("name"),
+ validateUploadedFilesOptions() {
+ return { imagesOnly: true };
+ },
+
uploadDone(upload) {
this.set("name", null);
this.sendAction("done", upload);
diff --git a/app/assets/javascripts/discourse/components/image-uploader.js.es6 b/app/assets/javascripts/discourse/components/image-uploader.js.es6
index afa00fcfb30..642ba03b3e8 100644
--- a/app/assets/javascripts/discourse/components/image-uploader.js.es6
+++ b/app/assets/javascripts/discourse/components/image-uploader.js.es6
@@ -10,6 +10,10 @@ export default Em.Component.extend(UploadMixin, {
return `background-image: url(${imageUrl})`.htmlSafe();
},
+ validateUploadedFilesOptions() {
+ return { imagesOnly: true };
+ },
+
uploadDone(upload) {
this.set("imageUrl", upload.url);
this.set("imageId", upload.id);
diff --git a/app/assets/javascripts/discourse/lib/utilities.js.es6 b/app/assets/javascripts/discourse/lib/utilities.js.es6
index 27b55bbdd74..154f92553b5 100644
--- a/app/assets/javascripts/discourse/lib/utilities.js.es6
+++ b/app/assets/javascripts/discourse/lib/utilities.js.es6
@@ -158,7 +158,7 @@ export function setCaretPosition(ctrl, pos) {
}
}
-export function validateUploadedFiles(files, bypassNewUserRestriction) {
+export function validateUploadedFiles(files, opts) {
if (!files || files.length === 0) { return false; }
if (files.length > 1) {
@@ -166,29 +166,43 @@ export function validateUploadedFiles(files, bypassNewUserRestriction) {
return false;
}
- var upload = files[0];
+ const upload = files[0];
// CHROME ONLY: if the image was pasted, sets its name to a default one
if (typeof Blob !== "undefined" && typeof File !== "undefined") {
if (upload instanceof Blob && !(upload instanceof File) && upload.type === "image/png") { upload.name = "blob.png"; }
}
- var type = uploadTypeFromFileName(upload.name);
+ opts = opts || {};
+ opts["type"] = uploadTypeFromFileName(upload.name);
- return validateUploadedFile(upload, type, bypassNewUserRestriction);
+ return validateUploadedFile(upload, opts);
}
-export function validateUploadedFile(file, type, bypassNewUserRestriction) {
+export function validateUploadedFile(file, opts) {
+ opts = opts || {};
+
+ const name = file && file.name;
+
+ if (!name) { return false; }
+
// check that the uploaded file is authorized
- if (!authorizesAllExtensions() && !isAuthorizedUpload(file)) {
- bootbox.alert(I18n.t('post.errors.upload_not_authorized', { authorized_extensions: authorizedExtensions() }));
- return false;
+ if (opts["imagesOnly"]) {
+ if (!isAnImage(name) && !isAuthorizedImage(name)) {
+ bootbox.alert(I18n.t('post.errors.upload_not_authorized', { authorized_extensions: authorizedImagesExtensions() }));
+ return false;
+ }
+ } else {
+ if (!authorizesAllExtensions() && !isAuthorizedFile(name)) {
+ bootbox.alert(I18n.t('post.errors.upload_not_authorized', { authorized_extensions: authorizedExtensions() }));
+ return false;
+ }
}
- if (!bypassNewUserRestriction) {
+ if (!opts["bypassNewUserRestriction"]) {
// ensures that new users can upload a file
- if (!Discourse.User.current().isAllowedToUploadAFile(type)) {
- bootbox.alert(I18n.t('post.errors.' + type + '_upload_not_allowed_for_new_user'));
+ if (!Discourse.User.current().isAllowedToUploadAFile(opts["type"])) {
+ bootbox.alert(I18n.t(`post.errors.${opts["type"]}_upload_not_allowed_for_new_user`));
return false;
}
}
@@ -197,13 +211,7 @@ export function validateUploadedFile(file, type, bypassNewUserRestriction) {
return true;
}
-export function uploadTypeFromFileName(fileName) {
- return isAnImage(fileName) ? 'image' : 'attachment';
-}
-
-export function authorizesAllExtensions() {
- return Discourse.SiteSettings.authorized_extensions.indexOf("*") >= 0;
-}
+const IMAGES_EXTENSIONS_REGEX = /(png|jpe?g|gif|bmp|tiff?|svg|webp|ico)/i;
function extensions() {
return Discourse.SiteSettings.authorized_extensions
@@ -213,16 +221,52 @@ function extensions() {
.filter(ext => ext.indexOf("*") === -1);
}
+function imagesExtensions() {
+ return extensions().filter(ext => IMAGES_EXTENSIONS_REGEX.test(ext));
+}
+
function extensionsRegex() {
return new RegExp("\\.(" + extensions().join("|") + ")$", "i");
}
-export function isAuthorizedUpload(file) {
- return file && file.name && extensionsRegex().test(file.name);
+function imagesExtensionsRegex() {
+ return new RegExp("\\.(" + imagesExtensions().join("|") + ")$", "i");
+}
+
+function isAuthorizedFile(fileName) {
+ return extensionsRegex().test(fileName);
+}
+
+function isAuthorizedImage(fileName){
+ return imagesExtensionsRegex().test(fileName);
}
export function authorizedExtensions() {
- return extensions().join(", ");
+ return authorizesAllExtensions() ? "*" : extensions().join(", ");
+}
+
+export function authorizedImagesExtensions() {
+ return authorizesAllExtensions() ? "png, jpg, jpeg, gif, bmp, tiff, svg, webp, ico" : imagesExtensions().join(", ");
+}
+
+export function authorizesAllExtensions() {
+ return Discourse.SiteSettings.authorized_extensions.indexOf("*") >= 0;
+}
+
+export function isAnImage(path) {
+ return (/\.(png|jpe?g|gif|bmp|tiff?|svg|webp|ico)$/i).test(path);
+}
+
+function uploadTypeFromFileName(fileName) {
+ return isAnImage(fileName) ? 'image' : 'attachment';
+}
+
+export function allowsImages() {
+ return authorizesAllExtensions() || IMAGES_EXTENSIONS_REGEX.test(authorizedExtensions());
+}
+
+export function allowsAttachments() {
+ return authorizesAllExtensions() || extensions().length > imagesExtensions().length;
}
export function uploadLocation(url) {
@@ -243,27 +287,12 @@ export function getUploadMarkdown(upload) {
if (isAnImage(upload.original_filename)) {
return '';
} else if (!Discourse.SiteSettings.prevent_anons_from_downloading_files && (/\.(mov|mp4|webm|ogv|mp3|ogg|wav|m4a)$/i).test(upload.original_filename)) {
- // is Audio/Video
return uploadLocation(upload.url);
} else {
return '' + upload.original_filename + ' (' + I18n.toHumanSize(upload.filesize) + ')\n';
}
}
-export function isAnImage(path) {
- return (/\.(png|jpe?g|gif|bmp|tiff?|svg|webp|ico)$/i).test(path);
-}
-
-export function allowsImages() {
- return authorizesAllExtensions() ||
- (/(png|jpe?g|gif|bmp|tiff?|svg|webp|ico)/i).test(authorizedExtensions());
-}
-
-export function allowsAttachments() {
- return authorizesAllExtensions() ||
- !/^((png|jpe?g|gif|bmp|tiff?|svg|webp|ico)(,\s)?)+$/i.test(authorizedExtensions());
-}
-
export function displayErrorForUpload(data) {
// deal with meaningful errors first
if (data.jqXHR) {
diff --git a/app/assets/javascripts/discourse/mixins/upload.js.es6 b/app/assets/javascripts/discourse/mixins/upload.js.es6
index 648d18dfd98..ec76aa1e660 100644
--- a/app/assets/javascripts/discourse/mixins/upload.js.es6
+++ b/app/assets/javascripts/discourse/mixins/upload.js.es6
@@ -8,6 +8,10 @@ export default Em.Mixin.create({
Em.warn("You should implement `uploadDone`");
},
+ validateUploadedFilesOptions() {
+ return {};
+ },
+
_initialize: function() {
const $upload = this.$(),
csrf = Discourse.Session.currentProp("csrfToken"),
@@ -40,7 +44,8 @@ export default Em.Mixin.create({
});
$upload.on("fileuploadsubmit", (e, data) => {
- const isValid = validateUploadedFiles(data.files, true);
+ const opts = _.merge({ bypassNewUserRestriction: true }, this.validateUploadedFilesOptions());
+ const isValid = validateUploadedFiles(data.files, opts);
let form = { type: this.get("type") };
if (this.get("data")) { form = $.extend(form, this.get("data")); }
data.formData = form;
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index 811a806778c..70d62b11e97 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -1737,7 +1737,7 @@ en:
file_too_large: "Sorry, that file is too big (maximum size is {{max_size_kb}}kb). Why not upload your large file to a cloud sharing service, then share the link?"
too_many_uploads: "Sorry, you can only upload one file at a time."
too_many_dragged_and_dropped_files: "Sorry, you can only upload 10 files at a time."
- upload_not_authorized: "Sorry, the file you are trying to upload is not authorized (authorized extension: {{authorized_extensions}})."
+ upload_not_authorized: "Sorry, the file you are trying to upload is not authorized (authorized extensions: {{authorized_extensions}})."
image_upload_not_allowed_for_new_user: "Sorry, new users can not upload images."
attachment_upload_not_allowed_for_new_user: "Sorry, new users can not upload attachments."
attachment_download_requires_login: "Sorry, you need to be logged in to download attachments."