From be9217d4c8c5a30f9c50a49fc41f7cdc44703be8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Wed, 24 Jul 2013 00:54:18 +0200 Subject: [PATCH] add server-side filesize check on uploads --- .../discourse/components/utilities.js | 71 +++++++++---------- .../discourse/views/composer_view.js | 9 +-- app/controllers/uploads_controller.rb | 15 ++-- app/models/upload.rb | 4 +- config/locales/client.cs.yml | 2 +- config/locales/client.de.yml | 2 +- config/locales/client.en.yml | 3 +- config/locales/client.fr.yml | 3 +- config/locales/client.it.yml | 2 +- config/locales/client.ko.yml | 2 +- config/locales/client.nb_NO.yml | 2 +- config/locales/client.nl.yml | 2 +- config/locales/client.pseudo.yml | 2 +- config/locales/client.pt_BR.yml | 2 +- config/locales/client.ru.yml | 2 +- config/locales/client.sv.yml | 2 +- config/locales/client.zh_CN.yml | 2 +- config/locales/client.zh_TW.yml | 2 +- config/locales/server.cs.yml | 2 +- config/locales/server.de.yml | 2 +- config/locales/server.en.yml | 5 +- config/locales/server.fr.yml | 5 +- config/locales/server.it.yml | 2 +- config/locales/server.ko.yml | 2 +- config/locales/server.nl.yml | 2 +- config/locales/server.pseudo.yml | 2 +- config/locales/server.pt_BR.yml | 2 +- config/locales/server.ru.yml | 2 +- config/locales/server.zh_CN.yml | 2 +- config/locales/server.zh_TW.yml | 2 +- spec/controllers/uploads_controller_spec.rb | 20 +++++- spec/models/upload_spec.rb | 13 ++-- test/javascripts/components/utilities_test.js | 17 +---- .../fixtures/site_settings_fixtures.js | 2 +- 34 files changed, 114 insertions(+), 97 deletions(-) diff --git a/app/assets/javascripts/discourse/components/utilities.js b/app/assets/javascripts/discourse/components/utilities.js index f4f70f5c8..ce3bf0af6 100644 --- a/app/assets/javascripts/discourse/components/utilities.js +++ b/app/assets/javascripts/discourse/components/utilities.js @@ -163,41 +163,55 @@ Discourse.Utilities = { /** Validate a list of files to be uploaded - @method validateFilesForUpload + @method validateUploadedFiles @param {Array} files The list of files we want to upload **/ - validateFilesForUpload: function(files) { + validateUploadedFiles: function(files) { if (!files || files.length === 0) { return false; } + // can only upload one file at a time if (files.length > 1) { bootbox.alert(I18n.t('post.errors.too_many_uploads')); return false; } + var upload = files[0]; - // ensures that new users can upload image/attachment - if (Discourse.Utilities.isUploadForbidden(upload.name)) { - if (Discourse.Utilities.isAnImage(upload.name)) { - bootbox.alert(I18n.t('post.errors.image_upload_not_allowed_for_new_user')); - } else { - bootbox.alert(I18n.t('post.errors.attachment_upload_not_allowed_for_new_user')); - } - return false; - } - // if the image was pasted, sets its name to a default one + + // CHROME ONLY: if the image was pasted, sets its name to a default one if (upload instanceof Blob && !(upload instanceof File) && upload.type === "image/png") { upload.name = "blob.png"; } + + return Discourse.Utilities.validateUploadedFile(upload, Discourse.Utilities.isAnImage(upload.name) ? 'image' : 'attachment'); + }, + + /** + Validate a file to be uploaded + + @method validateUploadedFile + @param {File} file The file to be uploaded + @param {string} type The type of the file + **/ + validateUploadedFile: function(file, type) { // check that the uploaded file is authorized - if (!Discourse.Utilities.isAuthorizedUpload(upload)) { + if (!Discourse.Utilities.isAuthorizedUpload(file)) { var extensions = Discourse.SiteSettings.authorized_extensions.replace(/\|/g, ", "); bootbox.alert(I18n.t('post.errors.upload_not_authorized', { authorized_extensions: extensions })); return false; } - // check file size - var fileSizeKB = upload.size / 1024; - var maxSizeKB = Discourse.Utilities.maxUploadSizeInKB(upload.name); - if (fileSizeKB > maxSizeKB) { - bootbox.alert(I18n.t('post.errors.upload_too_large', { max_size_kb: maxSizeKB })); + + // ensures that new users can upload a file + if (Discourse.User.current('trust_level') === 0 && Discourse.SiteSettings['newuser_max_' + type + 's'] === 0) { + bootbox.alert(I18n.t('post.errors.' + type + '_upload_not_allowed_for_new_user')); return false; } + + // check file size + var fileSizeKB = file.size / 1024; + var maxSizeKB = Discourse.SiteSettings['max_' + type + '_size_kb']; + if (fileSizeKB > maxSizeKB) { + bootbox.alert(I18n.t('post.errors.' + type + '_too_large', { max_size_kb: maxSizeKB })); + return false; + } + // everything went fine return true; }, @@ -238,27 +252,6 @@ Discourse.Utilities = { return path && path.match(/\.(png|jpg|jpeg|gif|bmp|tif|tiff)$/i); }, - /** - Retrieve max upload size in KB depending on the file is an image or not - - @method maxUploadSizeInKB - @param {String} path The path - **/ - maxUploadSizeInKB: function(path) { - return Discourse.Utilities.isAnImage(path) ? Discourse.SiteSettings.max_image_size_kb : Discourse.SiteSettings.max_attachment_size_kb; - }, - - /** - Test whether an upload is forbidden or not - - @method isUploadForbidden - @param {String} path The path - **/ - isUploadForbidden: function(path) { - if (Discourse.User.current('trust_level') > 0) { return false; } - return Discourse.Utilities.isAnImage(path) ? Discourse.SiteSettings.newuser_max_images === 0 : Discourse.SiteSettings.newuser_max_attachments === 0; - }, - /** Determines whether we allow attachments or not diff --git a/app/assets/javascripts/discourse/views/composer_view.js b/app/assets/javascripts/discourse/views/composer_view.js index 66d46ec4a..ed365503a 100644 --- a/app/assets/javascripts/discourse/views/composer_view.js +++ b/app/assets/javascripts/discourse/views/composer_view.js @@ -252,7 +252,7 @@ Discourse.ComposerView = Discourse.View.extend({ // submit - this event is triggered for each upload $uploadTarget.on('fileuploadsubmit', function (e, data) { - var result = Discourse.Utilities.validateFilesForUpload(data.files); + var result = Discourse.Utilities.validateUploadedFiles(data.files); // reset upload status when everything is ok if (result) composerView.setProperties({ uploadProgress: 0, isUploading: true }); return result; @@ -300,10 +300,11 @@ Discourse.ComposerView = Discourse.View.extend({ switch (data.jqXHR.status) { // 0 == cancel from the user case 0: return; - // 413 == entity too large, returned usually from nginx + // 413 == entity too large, usually returned from the web server case 413: - var maxSizeKB = Discourse.Utilities.maxUploadSizeInKB(data.files[0].name); - bootbox.alert(I18n.t('post.errors.upload_too_large', { max_size_kb: maxSizeKB })); + var type = Discourse.Utilities.isAnImage(data.files[0].name) ? "image" : "attachment"; + var maxSizeKB = Discourse.SiteSettings['max_' + type + '_size_kb']; + bootbox.alert(I18n.t('post.errors.' + type + '_too_large', { max_size_kb: maxSizeKB })); return; // 415 == media type not authorized case 415: diff --git a/app/controllers/uploads_controller.rb b/app/controllers/uploads_controller.rb index a928c9e5e..11710d71a 100644 --- a/app/controllers/uploads_controller.rb +++ b/app/controllers/uploads_controller.rb @@ -4,21 +4,28 @@ class UploadsController < ApplicationController def create file = params[:file] || params[:files].first + # check if the extension is allowed unless SiteSetting.authorized_upload?(file) text = I18n.t("upload.unauthorized", authorized_extensions: SiteSetting.authorized_extensions.gsub("|", ", ")) return render status: 415, text: text end - upload = Upload.create_for(current_user.id, file) + # check the file size (note: this might also be done in the web server) + filesize = File.size(file.tempfile) + type = SiteSetting.authorized_image?(file) ? "image" : "attachment" + max_size_kb = SiteSetting.send("max_#{type}_size_kb") * 1024 + return render status: 413, text: I18n.t("upload.#{type}s.too_large", max_size_kb: max_size_kb) if filesize > max_size_kb + + upload = Upload.create_for(current_user.id, file, filesize) render_serialized(upload, UploadSerializer, root: false) rescue FastImage::ImageFetchFailure - render status: 422, text: I18n.t("upload.image.fetch_failure") + render status: 422, text: I18n.t("upload.images.fetch_failure") rescue FastImage::UnknownImageType - render status: 422, text: I18n.t("upload.image.unknown_image_type") + render status: 422, text: I18n.t("upload.images.unknown_image_type") rescue FastImage::SizeNotFound - render status: 422, text: I18n.t("upload.image.size_not_found") + render status: 422, text: I18n.t("upload.images.size_not_found") end end diff --git a/app/models/upload.rb b/app/models/upload.rb index a6d2d865b..180681131 100644 --- a/app/models/upload.rb +++ b/app/models/upload.rb @@ -43,7 +43,7 @@ class Upload < ActiveRecord::Base end end - def self.create_for(user_id, file) + def self.create_for(user_id, file, filesize) # compute the sha sha1 = Digest::SHA1.file(file.tempfile).hexdigest # check if the file has already been uploaded @@ -61,7 +61,7 @@ class Upload < ActiveRecord::Base upload = Upload.create!({ user_id: user_id, original_filename: file.original_filename, - filesize: File.size(file.tempfile), + filesize: filesize, sha1: sha1, url: "", width: width, diff --git a/config/locales/client.cs.yml b/config/locales/client.cs.yml index cbea8ff81..64ff9392d 100644 --- a/config/locales/client.cs.yml +++ b/config/locales/client.cs.yml @@ -788,7 +788,7 @@ cs: create: "Bohužel nastala chyba při vytváření příspěvku. Prosím zkuste to znovu." edit: "Bohužel nastala chyba při editaci příspěvku. Prosím zkuste to znovu." upload: "Bohužel nastala chyba při nahrávání příspěvku. Prosím zkuste to znovu." - upload_too_large: "Soubor, který se snažíte nahrát je bohužel příliš velký (maximální velikost je {{max_size_kb}}kb). Prosím zmenšete ho zkuste to znovu." + image_too_large: "Soubor, který se snažíte nahrát je bohužel příliš velký (maximální velikost je {{max_size_kb}}kb). Prosím zmenšete ho zkuste to znovu." too_many_uploads: "Bohužel, najednou smíte nahrát jen jeden soubor." upload_not_authorized: "Bohužel, soubor, který se snažíte nahrát, není povolený (povolené přípony: {{authorized_extensions}})." upload_not_allowed_for_new_user: "Bohužel, noví uživatelé nemohou nahrávat obrázky." diff --git a/config/locales/client.de.yml b/config/locales/client.de.yml index ea831d32b..63ea308e9 100644 --- a/config/locales/client.de.yml +++ b/config/locales/client.de.yml @@ -762,7 +762,7 @@ de: create: "Entschuldige, es gab einen Fehler beim Anlegen des Beitrags. Bitte versuche es noch einmal." edit: "Entschuldige, es gab einen Fehler beim Bearbeiten des Beitrags. Bitte versuche es noch einmal." upload: "Entschuldige, es gab einen Fehler beim Hochladen der Datei. Bitte versuche es noch einmal." - upload_too_large: "Entschuldige, die Datei die du hochladen wolltest ist zu groß (Maximalgröße {{max_size_kb}}kb), bitte reduziere die Dateigröße und versuche es nochmal." + image_too_large: "Entschuldige, die Datei die du hochladen wolltest ist zu groß (Maximalgröße {{max_size_kb}}kb), bitte reduziere die Dateigröße und versuche es nochmal." abandon: "Willst Du diesen Beitrag wirklich verwerfen?" diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 2094705f4..b15d6c38e 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -762,7 +762,8 @@ en: create: "Sorry, there was an error creating your post. Please try again." edit: "Sorry, there was an error editing your post. Please try again." upload: "Sorry, there was an error uploading that file. Please try again." - upload_too_large: "Sorry, the file you are trying to upload is too big (maximum size is {{max_size_kb}}kb), please resize it and try again." + attachment_too_large: "Sorry, the file you are trying to upload is too big (maximum size is {{max_size_kb}}kb)." + image_too_large: "Sorry, the image you are trying to upload is too big (maximum size is {{max_size_kb}}kb), please resize it and try again." too_many_uploads: "Sorry, you can only upload one file at a time." upload_not_authorized: "Sorry, the file you are trying to upload is not authorized (authorized extension: {{authorized_extensions}})." image_upload_not_allowed_for_new_user: "Sorry, new users can not upload images." diff --git a/config/locales/client.fr.yml b/config/locales/client.fr.yml index be33a22e5..c2e45e938 100644 --- a/config/locales/client.fr.yml +++ b/config/locales/client.fr.yml @@ -743,7 +743,8 @@ fr: create: "Désolé, il y a eu une erreur lors de la publication de votre message. Merci de réessayer." edit: "Désolé, il y a eu une erreur lors de l'édition de votre message. Merci de réessayer." upload: "Désolé, il y a eu une erreur lors de l'envoi du fichier. Merci de réessayer." - upload_too_large: "Désolé, le fichier que vous êtes en train d'envoyer est trop grand (maximum {{max_size_kb}}Kb). Merci de le redimensionner et de réessayer." + image_too_large: "Désolé, l'image que vous êtes en train d'envoyer est trop grande (taille maximum de {{max_size_kb}} Ko). Merci de le redimensionner et de réessayer." + attachment_too_large: "Désolé, le fichier que vous êtes en train d'envoyer est trop grand (taille maximum de {{max_size_kb}} Ko)." too_many_uploads: "Désolé, vous ne pouvez envoyer qu'un seul fichier à la fois." upload_not_authorized: "Désole, le fichier que vous êtes en train d'uploader n'est pas autorisé (extensions autorisées : {{authorized_extensions}})." image_upload_not_allowed_for_new_user: "Désolé, les nouveaux utilisateurs ne peuvent pas uploader d'image." diff --git a/config/locales/client.it.yml b/config/locales/client.it.yml index fc8a7ef8f..3a8ddc7ec 100644 --- a/config/locales/client.it.yml +++ b/config/locales/client.it.yml @@ -660,7 +660,7 @@ it: create: "Spiacenti, si è verificato un errore durante la creazione del tuo post. Per favore, prova di nuovo." edit: "Spiacenti, si è verificato un errore durante la modifica del tuo post. Per favore, prova di nuovo." upload: "Spiacenti, si è verificato un errore durante il caricamento del file. Per favore, prova di nuovo." - upload_too_large: "Spiacenti, il file che stai cercando di caricare è troppo grande (la dimensione massima è {{max_size_kb}}kb), per favore ridimensionalo e prova di nuovo." + image_too_large: "Spiacenti, il file che stai cercando di caricare è troppo grande (la dimensione massima è {{max_size_kb}}kb), per favore ridimensionalo e prova di nuovo." too_many_uploads: "Spiacenti, puoi caricare un'immagine per volta." abandon: "Sei sicuro di voler abbandonare il tuo post?" diff --git a/config/locales/client.ko.yml b/config/locales/client.ko.yml index 12adf7f0f..6012a0977 100644 --- a/config/locales/client.ko.yml +++ b/config/locales/client.ko.yml @@ -610,7 +610,7 @@ ko: create: "죄송합니다, 귀하의 게시물을 만드는 동안 오류가 발생했습니다. 다시 시도하십시오." edit: "죄송합니다, 귀하의 게시물을 수정하는 중에 오류가 발생했습니다. 다시 시도하십시오." upload: "죄송합니다, 오류가 업로드하는 파일이 있었다. 다시 시도하십시오." - upload_too_large: "죄송합니다, 당신이 업로드하려는 파일이 너무 큽니다. (최대 크기는 {{max_size_kb}}kb), 사이즈를 조정하고 다시 시도해보세요" + image_too_large: "죄송합니다, 당신이 업로드하려는 파일이 너무 큽니다. (최대 크기는 {{max_size_kb}}kb), 사이즈를 조정하고 다시 시도해보세요" upload_too_many_images: "죄송합니다, 당신은 한 번에 하나의 이미지를 업로드 할 수 있습니다." only_images_are_supported: "죄송합니다, 당신은 한 번에 하나의 이미지를 업로드 할 수 있습니다." diff --git a/config/locales/client.nb_NO.yml b/config/locales/client.nb_NO.yml index 041bba36d..1125b1bf6 100644 --- a/config/locales/client.nb_NO.yml +++ b/config/locales/client.nb_NO.yml @@ -680,7 +680,7 @@ nb_NO: create: "Beklager, det oppstod en feil ved å publisere ditt innlegg. Vennligst prøv igjen." edit: "Beklager, det oppstod en feil ved redigeringen av ditt innlegg. Vennligst prøv igjen." upload: "Sorry, there was an error uploading that file. Please try again." - upload_too_large: "Beklager, filen du prøve å laste opp er for stor (maks størrelse er {{max_size_kb}}kb), vennligst reduser størrelsen og prøv igjen." + image_too_large: "Beklager, filen du prøve å laste opp er for stor (maks størrelse er {{max_size_kb}}kb), vennligst reduser størrelsen og prøv igjen." too_many_uploads: "Beklager, du kan bare laste opp ett bilde om gangen." abandon: "Er du sikker på at du vil forlate innlegget ditt?" diff --git a/config/locales/client.nl.yml b/config/locales/client.nl.yml index 113fc09db..024e07385 100644 --- a/config/locales/client.nl.yml +++ b/config/locales/client.nl.yml @@ -757,7 +757,7 @@ nl: create: "Sorry, er is iets misgegaan bij het plaatsen van je bericht. Probeer het nog eens." edit: "Sorry, er is iets misgegaan bij het bewerken van je bericht. Probeer het nog eens." upload: "Sorry, er is iets misgegaan bij het uploaden van je bestand. Probeer het nog eens." - upload_too_large: "Sorry, het bestand dat je wil uploaden is te groot (maximum grootte is {{max_size_kb}}kb), verklein het bestand en probeer het opnieuw." + image_too_large: "Sorry, het bestand dat je wil uploaden is te groot (maximum grootte is {{max_size_kb}}kb), verklein het bestand en probeer het opnieuw." too_many_uploads: "Sorry, je kan maar één afbeelding tegelijk uploaden." upload_not_authorized: "Sorry, je mag dat type bestand niet uploaden (toegestane extensies: {{authorized_extensions}})." upload_not_allowed_for_new_user: "Sorry, nieuwe gebruikers mogen nog geen afbeeldingen uploaden." diff --git a/config/locales/client.pseudo.yml b/config/locales/client.pseudo.yml index 728361f5f..308b86597 100644 --- a/config/locales/client.pseudo.yml +++ b/config/locales/client.pseudo.yml @@ -731,7 +731,7 @@ pseudo: edit: '[[ Šóřřý, ťĥéřé ŵáš áɳ éřřóř éďíťíɳǧ ýóůř ƿóšť. Рłéášé ťřý áǧáíɳ. ]]' upload: '[[ Šóřřý, ťĥéřé ŵáš áɳ éřřóř ůƿłóáďíɳǧ ťĥáť ƒíłé. Рłéášé ťřý áǧáíɳ. ]]' - upload_too_large: '[[ Šóřřý, ťĥé ƒíłé ýóů ářé ťřýíɳǧ ťó ůƿłóáď íš ťóó ƀíǧ + image_too_large: '[[ Šóřřý, ťĥé ƒíłé ýóů ářé ťřýíɳǧ ťó ůƿłóáď íš ťóó ƀíǧ (ɱáхíɱůɱ šížé íš {{max_size_kb}}ǩƀ), ƿłéášé řéšížé íť áɳď ťřý áǧáíɳ. ]]' too_many_uploads: '[[ Šóřřý, ýóů čáɳ óɳłý ůƿłóáď óɳé ƒíłé áť á ťíɱé. ]]' upload_not_authorized: '[[ Šóřřý, ťĥé ƒíłé ýóů ářé ťřýíɳǧ ťó ůƿłóáď íš ɳóť diff --git a/config/locales/client.pt_BR.yml b/config/locales/client.pt_BR.yml index 2fd3c56e2..1d47a8ccf 100644 --- a/config/locales/client.pt_BR.yml +++ b/config/locales/client.pt_BR.yml @@ -656,7 +656,7 @@ pt_BR: create: "Desculpe, houve um erro ao criar o seu post. Por favor tenta outra vez." edit: "Desculpe, houve um erro ao editar o seu post. Por favor tenta outra vez." upload: "Desculpe, houve um erro ao enviar esse ficheiro. Por favor tenta otura vez." - upload_too_large: "Desculpe, o arquivo que você está tentando enviar é muito grande (o tamanho máximo é {{max_size_kb}}kb), por favor diminua-o e tente novamente." + image_too_large: "Desculpe, o arquivo que você está tentando enviar é muito grande (o tamanho máximo é {{max_size_kb}}kb), por favor diminua-o e tente novamente." too_many_uploads: "Desculpe, você pode enviar apenas um arquivos por vez." upload_not_authorized: "Desculpe, o tipo de arquivo que você está tentando enviar não está autorizado (extensões autorizadas: {{authorized_extensions}})." upload_not_allowed_for_new_user: "Desculpe, novos usuários não podem enviar imagens." diff --git a/config/locales/client.ru.yml b/config/locales/client.ru.yml index 1df75111c..e4a0efa13 100644 --- a/config/locales/client.ru.yml +++ b/config/locales/client.ru.yml @@ -735,7 +735,7 @@ ru: create: К сожалению, не удалось создать сообщение. Попробуйте еще раз. edit: К сожалению, не удалось изменить сообщение. Попробуйте еще раз. upload: К сожалению, не удалось загрузить файл. Попробуйте еще раз. - upload_too_large: 'Превышен допустимый размер ({{max_size_kb}}kb) файла. Уменьшите размер изображения и повторите попытку.' + image_too_large: 'Превышен допустимый размер ({{max_size_kb}}kb) файла. Уменьшите размер изображения и повторите попытку.' too_many_uploads: К сожалению, за один раз можно загрузить только одно изображение. upload_not_authorized: 'К сожалению, вы не можете загрузить файл данного типа (список разрешенных типов файлов: {{authorized_extensions}}).' upload_not_allowed_for_new_user: К сожалению, загрузка изображений недоступна новым пользователям. diff --git a/config/locales/client.sv.yml b/config/locales/client.sv.yml index 689a7675d..84e2c6ca0 100644 --- a/config/locales/client.sv.yml +++ b/config/locales/client.sv.yml @@ -578,7 +578,7 @@ sv: create: "Tyvärr, det uppstod ett fel under skapandet av ditt inlägg. Var god försök igen." edit: "Tyvärr, det uppstod ett fel under ändringen av ditt inlägg. Var god försök igen." upload: "Tyvärr, det uppstod ett fel under uppladdandet av den filen. Vad god försök igen." - upload_too_large: "Tyvärr, filen som du försöker ladda upp är för stor (maxstorlek är {{max_size_kb}}kb), var god ändra storlek och försök igen." + image_too_large: "Tyvärr, filen som du försöker ladda upp är för stor (maxstorlek är {{max_size_kb}}kb), var god ändra storlek och försök igen." too_many_uploads: "Tyvärr, du kan bara ladda upp en bild i taget." abandon: "Är du säker på att du vill överge ditt inlägg?" diff --git a/config/locales/client.zh_CN.yml b/config/locales/client.zh_CN.yml index d0aee4fa5..6055b09c3 100644 --- a/config/locales/client.zh_CN.yml +++ b/config/locales/client.zh_CN.yml @@ -765,7 +765,7 @@ zh_CN: create: "抱歉,在创建你的帖子时发生了错误。请重试。" edit: "抱歉,在编辑你的帖子时发生了错误。请重试。" upload: "抱歉,在上传文件时发生了错误。请重试。" - upload_too_large: "抱歉,你上传的文件太大了(最大不能超过 {{max_size_kb}}kb),请调整文件大小后重新上传。" + image_too_large: "抱歉,你上传的文件太大了(最大不能超过 {{max_size_kb}}kb),请调整文件大小后重新上传。" too_many_uploads: "抱歉, 你只能一次上传一张图片。" upload_not_authorized: "抱歉, 你不能上传此类型文件(可上传的文件类型有: {{authorized_extensions}})。" upload_not_allowed_for_new_user: "抱歉,新用户不能上传图片。" diff --git a/config/locales/client.zh_TW.yml b/config/locales/client.zh_TW.yml index 25b188647..53aba3030 100644 --- a/config/locales/client.zh_TW.yml +++ b/config/locales/client.zh_TW.yml @@ -660,7 +660,7 @@ zh_TW: create: "抱歉,在創建你的帖子時發生了錯誤。請重試。" edit: "抱歉,在編輯你的帖子時發生了錯誤。請重試。" upload: "抱歉,在上傳文件時發生了錯誤。請重試。" - upload_too_large: "抱歉,你上傳的文件太大了(最大不能超過 {{max_size_kb}}kb),請調整文件大小後重新上傳。" + image_too_large: "抱歉,你上傳的文件太大了(最大不能超過 {{max_size_kb}}kb),請調整文件大小後重新上傳。" too_many_uploads: "抱歉, 你只能一次上傳一張圖片。" abandon: "你確定要丟棄你的帖子嗎?" diff --git a/config/locales/server.cs.yml b/config/locales/server.cs.yml index caf79aa62..3e40a2374 100644 --- a/config/locales/server.cs.yml +++ b/config/locales/server.cs.yml @@ -1100,7 +1100,7 @@ cs: upload: pasted_image_filename: "" - image: + images: fetch_failure: "Bohužel, nastala chybí při získávání obrázku." unknown_image_type: "Bohužel, soubor, který se snažíte nahrát, zřejmě není obrázek." size_not_found: "Bohužel se nepodařilo zjistit velikost obrázku. Není soubor s obrázkem poškozený?" diff --git a/config/locales/server.de.yml b/config/locales/server.de.yml index c377df314..c470072dc 100644 --- a/config/locales/server.de.yml +++ b/config/locales/server.de.yml @@ -1004,7 +1004,7 @@ de: upload: pasted_image_filename: "" - image: + images: fetch_failure: "Entschuldige, beim Laden des Bildes ist ein Fehler aufgetreten." unknown_image_type: "Entschuldige, aber die Datei die Du hochladen möchtest schein kein Bild zu sein." size_not_found: "Entschuldige, aber wir konnten die Grösse des Bildes nicht feststellen. Vielleicht ist das Bild defekt?" diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index 6554f2007..9c40f254b 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -1090,7 +1090,10 @@ en: upload: unauthorized: "Sorry, the file you are trying to upload is not authorized (authorized extensions: %{authorized_extensions})." pasted_image_filename: "Pasted image" - image: + attachments: + too_large: "Sorry, the file you are trying to upload is too big (maximum size is %{max_size_kb}%kb)." + images: + too_large: "Sorry, the image you are trying to upload is too big (maximum size is %{max_size_kb}%kb), please resize it and try again." fetch_failure: "Sorry, there has been an error while fetching the image." unknown_image_type: "Sorry, but the file you tried to upload doesn't appear to be an image." size_not_found: "Sorry, but we couldn't determine the size of the image. Maybe your image is corrupted?" diff --git a/config/locales/server.fr.yml b/config/locales/server.fr.yml index bfd6fe54d..f0f3ece74 100644 --- a/config/locales/server.fr.yml +++ b/config/locales/server.fr.yml @@ -962,7 +962,10 @@ fr: upload: pasted_image_filename: "Image collée" - image: + attachments: + too_large: "Désolé, le fichier que vous êtes en train d'uploader est trop grand (la taille maximum est %{max_size_kb}% ko)." + images: + too_large: "Désolé, l'image que vous êtes en train d'uploader est trop grande (la taille maximum est %{max_size_kb}% ko)." fetch_failure: "Désolé, une erreur s'est produite lorsque nous avons essayé de récupérer l'image." unknown_image_type: "Désolé, mais le fichier que vous essayez d'envoyer ne semble pas être une image." size_not_found: "Désolé, mais nous n'avons pas réussit à déterminer la taille de l'image. Peut-être que l'image est corrompue ?" diff --git a/config/locales/server.it.yml b/config/locales/server.it.yml index 5eeb2b9bc..128033b80 100644 --- a/config/locales/server.it.yml +++ b/config/locales/server.it.yml @@ -917,7 +917,7 @@ it: upload: pasted_image_filename: "" - image: + images: fetch_failure: "Spiacente, si è verificato un errore nel recupero dell'immagine." unknown_image_type: "Spiacente, ma il file che hai provato a caricare non sembra un'immagine." size_not_found: "Spiacente, ma non riusciamo a determinare la dimensione dell'immagine. Probabilmente l'immagine è corrotta?" diff --git a/config/locales/server.ko.yml b/config/locales/server.ko.yml index e9602bc03..25ade8a28 100644 --- a/config/locales/server.ko.yml +++ b/config/locales/server.ko.yml @@ -932,7 +932,7 @@ ko: deleted: 'deleted' upload: - image: + images: fetch_failure: "Sorry, there has been an error while fetching the image." unknown_image_type: "Sorry, but the file you tried to upload doesn't appear to be an image." size_not_found: "Sorry, but we couldn't determine the size of the image. Maybe your image is corrupted?" diff --git a/config/locales/server.nl.yml b/config/locales/server.nl.yml index 5ac66ed33..af73040ee 100644 --- a/config/locales/server.nl.yml +++ b/config/locales/server.nl.yml @@ -1075,7 +1075,7 @@ nl: upload: pasted_image_filename: "Geplakte afbeelding" - image: + images: fetch_failure: "Er ging iets mis bij het opvragen van de afbeelding." unknown_image_type: "Het bestand dat je wil uploaden is geen afbeelding." size_not_found: "Het is niet gelukt de afmetingen van de afbeelding te bepalen. Misschien is het bestand corrupt?" diff --git a/config/locales/server.pseudo.yml b/config/locales/server.pseudo.yml index 3bdaea76d..29915fa65 100644 --- a/config/locales/server.pseudo.yml +++ b/config/locales/server.pseudo.yml @@ -1273,7 +1273,7 @@ pseudo: deleted: '[[ ďéłéťéď ]]' upload: pasted_image_filename: '[[ Рášťéď íɱáǧé ]]' - image: + images: fetch_failure: '[[ Šóřřý, ťĥéřé ĥáš ƀééɳ áɳ éřřóř ŵĥíłé ƒéťčĥíɳǧ ťĥé íɱáǧé. ]]' unknown_image_type: '[[ Šóřřý, ƀůť ťĥé ƒíłé ýóů ťříéď ťó ůƿłóáď ďóéšɳ''ť áƿƿéář diff --git a/config/locales/server.pt_BR.yml b/config/locales/server.pt_BR.yml index e412cd8db..cb27e2563 100644 --- a/config/locales/server.pt_BR.yml +++ b/config/locales/server.pt_BR.yml @@ -955,7 +955,7 @@ pt_BR: upload: unauthorized: "Desculpe-nos, o arquivo que você está tentando enviar não é autorizado (extensões autorizadas: %{authorized_extensions})." pasted_image_filename: "Imagem colada" - image: + images: fetch_failure: "Desculpe, houve um erro ao transferir a imagem." unknown_image_type: "Desculpe, mas o arquivo que você tentou enviar não parece ser uma imagem." size_not_found: "Desculpe, mas não conseguimos determinar o tamanho da imagem. É possível que seu arquivo de imagem esteja corrompido?" diff --git a/config/locales/server.ru.yml b/config/locales/server.ru.yml index 3a9cdb736..7ffd7cd2e 100644 --- a/config/locales/server.ru.yml +++ b/config/locales/server.ru.yml @@ -1073,7 +1073,7 @@ ru: upload: unauthorized: 'К сожалению, вы не можете загрузить файл данного типа (список разрешенных типов файлов: %{authorized_extensions}).' pasted_image_filename: Имя файла изображения - image: + images: fetch_failure: Извините, во время извлечения изображения произошла ошибка. unknown_image_type: Файл, который вы загружаете, не является изображением. size_not_found: Извините, мы не можем определить размер изображения. Возможно, изображение повреждено? diff --git a/config/locales/server.zh_CN.yml b/config/locales/server.zh_CN.yml index 462f3a90c..7f8153bdd 100644 --- a/config/locales/server.zh_CN.yml +++ b/config/locales/server.zh_CN.yml @@ -934,7 +934,7 @@ zh_CN: upload: pasted_image_filename: "" - image: + images: fetch_failure: "抱歉,获取图片時发生错误。" unknown_image_type: "抱歉,你上传的文件似乎不是一张图片。" size_not_found: "抱歉,我们无法获取图片大小,请检查你的图片是否已损坏。" diff --git a/config/locales/server.zh_TW.yml b/config/locales/server.zh_TW.yml index d0b41e44a..b959bf449 100644 --- a/config/locales/server.zh_TW.yml +++ b/config/locales/server.zh_TW.yml @@ -917,7 +917,7 @@ zh_TW: upload: pasted_image_filename: "" - image: + images: fetch_failure: "抱歉,獲取圖片時發生錯誤。" unknown_image_type: "抱歉,你上傳的文件似乎不是一張圖片。" size_not_found: "抱歉,我們無法獲取圖片大小,請檢查你的圖片是否已損壞。" diff --git a/spec/controllers/uploads_controller_spec.rb b/spec/controllers/uploads_controller_spec.rb index 0b0c56a55..4f6f27151 100644 --- a/spec/controllers/uploads_controller_spec.rb +++ b/spec/controllers/uploads_controller_spec.rb @@ -41,13 +41,29 @@ describe UploadsController do context 'when authorized' do - before { SiteSetting.stubs(:authorized_extensions).returns(".txt") } + before { SiteSetting.stubs(:authorized_extensions).returns(".png|.txt") } - it 'is successful' do + it 'is successful with an image' do + xhr :post, :create, file: logo + response.status.should eq 200 + end + + it 'is successful with an attachment' do xhr :post, :create, file: text_file response.status.should eq 200 end + context 'with a big file' do + + before { SiteSetting.stubs(:max_attachment_size_kb).returns(1) } + + it 'rejects the upload' do + xhr :post, :create, file: text_file + response.status.should eq 413 + end + + end + end context 'when not authorized' do diff --git a/spec/models/upload_spec.rb b/spec/models/upload_spec.rb index 2dd3f42cf..12de3eb20 100644 --- a/spec/models/upload_spec.rb +++ b/spec/models/upload_spec.rb @@ -27,6 +27,7 @@ describe Upload do end let(:image_sha1) { Digest::SHA1.file(image.tempfile).hexdigest } + let(:image_filesize) { File.size(image.tempfile) } let(:attachment) do ActionDispatch::Http::UploadedFile.new({ @@ -35,6 +36,8 @@ describe Upload do }) end + let(:attachment_filesize) { File.size(attachment.tempfile) } + context ".create_thumbnail!" do it "does not create a thumbnail when disabled" do @@ -77,7 +80,7 @@ describe Upload do it "does not create another upload if it already exists" do Upload.expects(:where).with(sha1: image_sha1).returns([upload]) Upload.expects(:create!).never - Upload.create_for(user_id, image).should == upload + Upload.create_for(user_id, image, image_filesize).should == upload end it "computes width & height for images" do @@ -85,24 +88,24 @@ describe Upload do FastImage.any_instance.expects(:size).returns([100, 200]) ImageSizer.expects(:resize) ActionDispatch::Http::UploadedFile.any_instance.expects(:rewind) - Upload.create_for(user_id, image) + Upload.create_for(user_id, image, image_filesize) end it "does not create an upload when there is an error with FastImage" do SiteSetting.expects(:authorized_image?).returns(true) Upload.expects(:create!).never - expect { Upload.create_for(user_id, attachment) }.to raise_error(FastImage::UnknownImageType) + expect { Upload.create_for(user_id, attachment, attachment_filesize) }.to raise_error(FastImage::UnknownImageType) end it "does not compute width & height for non-image" do SiteSetting.expects(:authorized_image?).returns(false) FastImage.any_instance.expects(:size).never - Upload.create_for(user_id, image) + Upload.create_for(user_id, image, image_filesize) end it "saves proper information" do Upload.expects(:store_file).returns(url) - upload = Upload.create_for(user_id, image) + upload = Upload.create_for(user_id, image, image_filesize) upload.user_id.should == user_id upload.original_filename.should == image.original_filename upload.filesize.should == File.size(image.tempfile) diff --git a/test/javascripts/components/utilities_test.js b/test/javascripts/components/utilities_test.js index 40329feb6..36a40be7a 100644 --- a/test/javascripts/components/utilities_test.js +++ b/test/javascripts/components/utilities_test.js @@ -7,9 +7,9 @@ test("emailValid", function() { ok(utils.emailValid('bob@EXAMPLE.com'), "allows upper case in the email domain"); }); -var validUpload = utils.validateFilesForUpload; +var validUpload = utils.validateUploadedFiles; -test("validateFilesForUpload", function() { +test("validateUploadedFiles", function() { ok(!validUpload(null), "no files are invalid"); ok(!validUpload(undefined), "undefined files are invalid"); ok(!validUpload([]), "empty array of files is invalid"); @@ -55,7 +55,7 @@ test("prevents files that are too big from being uploaded", function() { this.stub(bootbox, "alert"); ok(!validUpload([image])); - ok(bootbox.alert.calledWith(I18n.t('post.errors.upload_too_large', { max_size_kb: 5 }))); + ok(bootbox.alert.calledWith(I18n.t('post.errors.image_too_large', { max_size_kb: 5 }))); }); var dummyBlob = function() { @@ -83,17 +83,6 @@ test("allows valid uploads to go through", function() { ok(!bootbox.alert.calledOnce); }); -var isAuthorized = function (filename) { - return utils.isAuthorizedUpload({ name: filename }); -}; - -test("isAuthorizedUpload", function() { - ok(isAuthorized("image.png")); - ok(isAuthorized("image.jpg")); - ok(!isAuthorized("image.txt")); - ok(!isAuthorized("")); -}); - var getUploadMarkdown = function(filename) { return utils.getUploadMarkdown({ original_filename: filename, diff --git a/test/javascripts/fixtures/site_settings_fixtures.js b/test/javascripts/fixtures/site_settings_fixtures.js index 2c8540884..f8e1e1e4b 100644 --- a/test/javascripts/fixtures/site_settings_fixtures.js +++ b/test/javascripts/fixtures/site_settings_fixtures.js @@ -1,3 +1,3 @@ /*jshint maxlen:10000000 */ -Discourse.SiteSettingsOriginal = {"title":"Discourse Meta","logo_url":"/assets/logo.png","logo_small_url":"/assets/logo-single.png","traditional_markdown_linebreaks":false,"top_menu":"latest|new|unread|read|favorited|categories","post_menu":"like|edit|flag|delete|share|bookmark|reply","share_links":"twitter|facebook|google+|email","track_external_right_clicks":false,"must_approve_users":false,"ga_tracking_code":"UA-33736483-2","ga_domain_name":"","enable_long_polling":true,"polling_interval":3000,"anon_polling_interval":30000,"min_post_length":20,"max_post_length":16000,"min_topic_title_length":15,"max_topic_title_length":255,"min_private_message_title_length":2,"allow_uncategorized_topics":true,"min_search_term_length":3,"flush_timings_secs":5,"suppress_reply_directly_below":true,"email_domains_blacklist":"mailinator.com","email_domains_whitelist":null,"version_checks":true,"min_title_similar_length":10,"min_body_similar_length":15,"category_colors":"BF1E2E|F1592A|F7941D|9EB83B|3AB54A|12A89D|25AAE2|0E76BD|652D90|92278F|ED207B|8C6238|231F20|808281|B3B5B4|283890","max_upload_size_kb":1024,"category_featured_topics":6,"favicon_url":"/assets/favicon.ico","dynamic_favicon":false,"uncategorized_name":"uncategorized","uncategorized_color":"AB9364","uncategorized_text_color":"FFFFFF","invite_only":false,"login_required":false,"enable_local_logins":true,"enable_local_account_create":true,"enable_google_logins":true,"enable_yahoo_logins":true,"enable_twitter_logins":true,"enable_facebook_logins":true,"enable_cas_logins":false,"enable_github_logins":true,"enable_persona_logins":true,"educate_until_posts":2,"topic_views_heat_low":1000,"topic_views_heat_medium":2000,"topic_views_heat_high":5000,"min_private_message_post_length":5,"faq_url":"","tos_url":"","privacy_policy_url":"","authorized_extensions":".jpg|.jpeg|.png|.gif","relative_date_duration":14}; +Discourse.SiteSettingsOriginal = {"title":"Discourse Meta","logo_url":"/assets/logo.png","logo_small_url":"/assets/logo-single.png","traditional_markdown_linebreaks":false,"top_menu":"latest|new|unread|read|favorited|categories","post_menu":"like|edit|flag|delete|share|bookmark|reply","share_links":"twitter|facebook|google+|email","track_external_right_clicks":false,"must_approve_users":false,"ga_tracking_code":"UA-33736483-2","ga_domain_name":"","enable_long_polling":true,"polling_interval":3000,"anon_polling_interval":30000,"min_post_length":20,"max_post_length":16000,"min_topic_title_length":15,"max_topic_title_length":255,"min_private_message_title_length":2,"allow_uncategorized_topics":true,"min_search_term_length":3,"flush_timings_secs":5,"suppress_reply_directly_below":true,"email_domains_blacklist":"mailinator.com","email_domains_whitelist":null,"version_checks":true,"min_title_similar_length":10,"min_body_similar_length":15,"category_colors":"BF1E2E|F1592A|F7941D|9EB83B|3AB54A|12A89D|25AAE2|0E76BD|652D90|92278F|ED207B|8C6238|231F20|808281|B3B5B4|283890","max_upload_size_kb":1024,"category_featured_topics":6,"favicon_url":"/assets/favicon.ico","dynamic_favicon":false,"uncategorized_name":"uncategorized","uncategorized_color":"AB9364","uncategorized_text_color":"FFFFFF","invite_only":false,"login_required":false,"enable_local_logins":true,"enable_local_account_create":true,"enable_google_logins":true,"enable_yahoo_logins":true,"enable_twitter_logins":true,"enable_facebook_logins":true,"enable_cas_logins":false,"enable_github_logins":true,"enable_persona_logins":true,"educate_until_posts":2,"topic_views_heat_low":1000,"topic_views_heat_medium":2000,"topic_views_heat_high":5000,"min_private_message_post_length":5,"faq_url":"","tos_url":"","privacy_policy_url":"","authorized_extensions":".jpg|.jpeg|.png|.gif|.txt","relative_date_duration":14}; Discourse.SiteSettings = jQuery.extend(true, {}, Discourse.SiteSettingsOriginal);