Add image file size validation

This commit is contained in:
Ivan Diaz 2018-09-20 15:52:27 -03:00
parent 4df3bab1ff
commit 285b62832a
29 changed files with 74 additions and 54 deletions

View File

@ -1,17 +0,0 @@
'use strict';
var babel = require('babel-core');
module.exports = {
process: function(src, filename) {
// Ignore files other than .js, .es, .jsx or .es6
if (!babel.canCompile(filename)) {
return '';
}
// Ignore all files within node_modules
if (filename.indexOf('node_modules') === -1) {
return babel.transform(src, {filename: filename}).code;
}
return src;
}
};

View File

@ -1,13 +1,11 @@
// MOCKS
const ValidationFactoryMock = require('lib-app/__mocks__/validations/validation-factory-mock');
const TextEditorMock = require('core-components/__mocks__/text-editor-mock');
const FormField = ReactMock();
// COMPONENT
const Form = requireUnit('core-components/form', {
'lib-app/validations/validator-factory': ValidationFactoryMock,
'core-components/form-field': FormField,
'core-components/text-editor': TextEditorMock
});
describe('Form component', function () {
@ -187,18 +185,6 @@ describe('Form component', function () {
expect(form.props.onSubmit).to.not.have.been.called;
});
it('should transform TextEdit value to HTML', function () {
form.state.form.first = TextEditorMock.createEmpty();
TestUtils.Simulate.submit(ReactDOM.findDOMNode(form));
expect(TextEditorMock.getHTMLFromEditorState).to.have.been.calledWith(form.state.form.first);
expect(form.props.onSubmit).to.have.been.calledWith({
first: 'HTML_CODE',
second: 'value2',
third: 'value3'
});
});
it('should focus the first field with error', function () {
ValidationFactoryMock.validators.defaultValidatorMock.performValidation = stub().returns('MOCK_ERROR');
ValidationFactoryMock.validators.customValidatorMock.performValidation = stub().returns('MOCK_ERROR_2');

View File

@ -6,7 +6,6 @@ import {reactDFS, renderChildrenWithProps} from 'lib-core/react-dfs';
import ValidationFactory from 'lib-app/validations/validator-factory';
import FormField from 'core-components/form-field';
import TextEditor from 'core-components/text-editor';
class Form extends React.Component {

View File

@ -21,7 +21,7 @@ module.exports = [
'session-prefix': 'opensupports-z6ctpq2winvfhchX2_',
'maintenance-mode': false,
'allow-attachments': true,
'max-size': 500,
'max-size': 1,
'departments': [
{id: 1, name: 'Sales Support', owners: 2},
{id: 2, name: 'Technical Issues', owners: 5},

View File

@ -321,6 +321,7 @@ export default {
'INVALID_EMAIL_OR_TICKET_NUMBER': 'Número de e-mail ou chamado inválido',
'INVALID_FILE': 'arquivo inválido',
'ERRORS_FOUND': 'Erros encontrados',
'ERROR_IMAGE_SIZE': 'Nenhuma imagem pode ter um tamanho maior que {size} MB',
//MESSAGES
'SIGNUP_SUCCESS': 'Você se registrou com sucesso em nosso sistema de suporte.',

View File

@ -321,6 +321,7 @@ export default {
'INVALID_EMAIL_OR_TICKET_NUMBER': '電子郵件或機票號無效',
'INVALID_FILE': '無效文件',
'ERRORS_FOUND': '發現錯誤',
'ERROR_IMAGE_SIZE': '没有图像的大小可以超过{size}MB',
//MESSAGES
'SIGNUP_SUCCESS': '您已在我們的支持系統中成功註冊',

View File

@ -321,6 +321,7 @@ export default {
'INVALID_EMAIL_OR_TICKET_NUMBER': 'Ungültige E-Mail-Adresse oder Ticketnummer!',
'INVALID_FILE': 'Ungültige Datei!',
'ERRORS_FOUND': 'Fehler gefunden!',
'ERROR_IMAGE_SIZE': 'Kein Bild darf größer als {size} MB sein',
//MESSAGES
'SIGNUP_SUCCESS': 'Sie haben sich erfolgreich in unserem Support-System registriert.',

View File

@ -322,6 +322,7 @@ export default {
'INVALID_EMAIL_OR_TICKET_NUMBER': 'Invalid email or ticket number',
'INVALID_FILE': 'Invalid file',
'ERRORS_FOUND': 'Errors found',
'ERROR_IMAGE_SIZE': 'No image can have a size greater than {size} MB',
//MESSAGES
'SIGNUP_SUCCESS': 'You have registered successfully in our support system.',

View File

@ -346,6 +346,7 @@ export default {
'WILL_RECOVER_EMAIL_TEMPLATE': 'Esta plantilla de correo electrónico se recuperará a su valor predeterminado en este idioma.',
'SUCCESS_IMPORTING_CSV_DESCRIPTION': 'El archivo CSV se ha importado correctamente',
'SUCCESS_DELETING_ALL_USERS': 'Los usuarios se han eliminado correctamente',
'ERROR_IMAGE_SIZE': 'Ninguna imagen puede tener un tamaño superior a {size} MB',
'LAST_7_DAYS': 'Últimos 7 dias',
'LAST_30_DAYS': 'Últimos 30 dias',

View File

@ -321,6 +321,7 @@ export default {
'INVALID_EMAIL_OR_TICKET_NUMBER': 'Numéro de courriel ou de ticket invalide',
'INVALID_FILE': 'Fichier invalide',
'ERRORS_FOUND': 'Des erreurs sont survenues',
'ERROR_IMAGE_SIZE': 'Aucune image ne peut avoir une taille supérieure à {size} MB',
//MESSAGES
'SIGNUP_SUCCESS': 'Vous êtes inscrit avec succès dans notre système de support.',

View File

@ -322,6 +322,7 @@
'INVALID_EMAIL_OR_TICKET_NUMBER': 'Μη έγκυρη ηλεκτρονική διεύθυνση ή αριθμός εισιτηρίου',
'INVALID_FILE': 'Μη έγκυρο αρχείο',
'ERRORS_FOUND': 'Βρέθηκαν Σφάλματα',
'ERROR_IMAGE_SIZE': 'Καμία εικόνα δεν μπορεί να έχει μέγεθος μεγαλύτερο από {size} MB',
//MESSAGES
'SIGNUP_SUCCESS': 'Έχετε εγγραφεί με επιτυχία στο σύστημα υποστήριξης μας.',

View File

@ -321,6 +321,7 @@ export default {
'INVALID_EMAIL_OR_TICKET_NUMBER': 'अमान्य ईमेल या टिकट नंबर',
'INVALID_FILE': 'अवैध फाइल',
'ERRORS_FOUND': 'त्रुटियां मिलीं',
'ERROR_IMAGE_SIZE': 'कोई छवि {size} एमबी से अधिक आकार नहीं हो सकती है',
//MESSAGES
'SIGNUP_SUCCESS': 'आप हमारे समर्थन प्रणाली में सफलतापूर्वक दर्ज कर लिया है।',

View File

@ -321,6 +321,7 @@ export default {
'INVALID_EMAIL_OR_TICKET_NUMBER': 'E-mail o numero di ticket non validi',
'INVALID_FILE': 'File non valido',
'ERRORS_FOUND': 'Trovati errori',
'ERROR_IMAGE_SIZE': 'Nessuna immagine può avere una dimensione superiore a {size} MB',
//MESSAGES
'SIGNUP_SUCCESS': 'È stato registrato con successo nel nostro sistema di supporto.',

View File

@ -321,6 +321,7 @@ export default {
'INVALID_EMAIL_OR_TICKET_NUMBER': '電子メールまたはチケット番号が無効です',
'INVALID_FILE': '無効なファイル',
'ERRORS_FOUND': 'エラーが見つかりました',
'ERROR_IMAGE_SIZE': 'イメージのサイズが{size} MBを超えることはできません',
//MESSAGES
'SIGNUP_SUCCESS': 'あなたは私たちのサポートシステムに正常に登録しました。',

View File

@ -322,6 +322,7 @@ export default {
'INVALID_EMAIL_OR_TICKET_NUMBER': 'Ongeldig e-mailadres of incidentnummer',
'INVALID_FILE': 'Ongeldig bestand',
'ERRORS_FOUND': 'Er is een fout opgetreden',
'ERROR_IMAGE_SIZE': 'Geen enkele afbeelding kan groter zijn dan {size} MB',
//MESSAGES
'SIGNUP_SUCCESS': 'U hebt zich succesvol geregistreerd in ons ondersteuningssysteem.',

View File

@ -321,6 +321,7 @@ export default {
'INVALID_EMAIL_OR_TICKET_NUMBER': 'Número de e-mail ou bilhete inválido',
'INVALID_FILE': 'arquivo inválido',
'ERRORS_FOUND': 'Erros encontrados',
'ERROR_IMAGE_SIZE': 'Nenhuma imagem pode ter um tamanho maior que {size} MB',
//MESSAGES
'SIGNUP_SUCCESS': 'Você se registrou com sucesso em nosso sistema de suporte.',

View File

@ -320,6 +320,7 @@ export default {
'INVALID_EMAIL_OR_TICKET_NUMBER': 'Неправильный номер эл. Почты или номера билета.',
'INVALID_FILE': 'неверный файл',
'ERRORS_FOUND': 'Ошибки найдены',
'ERROR_IMAGE_SIZE': 'Изображение не может иметь размер больше {size} МБ',
//MESSAGES
'SIGNUP_SUCCESS': 'Вы успешно зарегистрировались в нашей системе поддержки.',

View File

@ -321,6 +321,7 @@ export default {
'INVALID_EMAIL_OR_TICKET_NUMBER': 'Geçersiz e-posta veya bilet numarası',
'INVALID_FILE': 'geçersiz dosya',
'ERRORS_FOUND': 'Hatalar bulundu',
'ERROR_IMAGE_SIZE': 'Hiçbir resmin boyutu {size} MB\'den büyük olabilir',
//MESSAGES
'SIGNUP_SUCCESS': 'Destek sistemimize başarılı bir şekilde kayıt oldunuz.',

View File

@ -61,6 +61,7 @@ class SessionStore {
this.setItem('user-system-enabled', configs['user-system-enabled']);
this.setItem('allow-attachments', configs['allow-attachments']);
this.setItem('maintenance-mode', configs['maintenance-mode']);
this.setItem('max-size', configs['max-size']);
}
getConfigs() {
@ -75,7 +76,8 @@ class SessionStore {
registration: (this.getItem('registration') * 1),
'user-system-enabled': (this.getItem('user-system-enabled') * 1),
'allow-attachments': (this.getItem('allow-attachments') * 1),
'maintenance-mode': (this.getItem('maintenance-mode') * 1)
'maintenance-mode': (this.getItem('maintenance-mode') * 1),
'max-size': this.getItem('max-size'),
};
}

View File

@ -0,0 +1,24 @@
import _ from 'lodash';
import Validator from 'lib-app/validations/validator';
import SessionStore from 'lib-app/session-store';
import Base64ImageParser from 'lib-core/base64-image-parser';
class ImageSizeValidator extends Validator {
constructor(errorKey = 'ERROR_IMAGE_SIZE', validator = null) {
super(validator);
this.maxSize = 1;
this.errorKey = errorKey;
}
validate(value = '', form = {}) {
let images = Base64ImageParser.getImagesSrc(value).map(Base64ImageParser.dataURLtoFile);
if(_.some(images, f => f.size > 1048576 * SessionStore.getItem('max-size'))) {
return this.getError(this.errorKey, {size: SessionStore.getItem('max-size')});
}
}
}
export default ImageSizeValidator;

View File

@ -1,5 +1,3 @@
import TextEditor from 'core-components/text-editor';
import Validator from 'lib-app/validations/validator';
class LengthValidator extends Validator {
@ -11,11 +9,11 @@ class LengthValidator extends Validator {
}
validate(value = '', form = {}) {
if (TextEditor.isEditorState(value)) {
value = value.getCurrentContent().getPlainText();
}
let div = document.createElement("div");
div.innerHTML = value;
let text = div.textContent || div.innerText || "";
if (value.length < this.minlength) return this.getError(this.errorKey);
if (text.length < this.minlength) return this.getError(this.errorKey);
}
}

View File

@ -3,13 +3,14 @@ import EmailValidator from 'lib-app/validations/email-validator';
import RepeatPasswordValidator from 'lib-app/validations/repeat-password-validator';
import LengthValidator from 'lib-app/validations/length-validator';
import ListValidator from 'lib-app/validations/list-validator';
import ImageSizeValidator from 'lib-app/validations/image-size-validator';
let validators = {
'DEFAULT': new Validator(),
'NAME': new LengthValidator(2, 'ERROR_NAME'),
'TITLE': new LengthValidator(1, 'ERROR_TITLE'),
'EMAIL': new EmailValidator(),
'TEXT_AREA': new LengthValidator(10, 'ERROR_CONTENT_SHORT'),
'TEXT_AREA': new ImageSizeValidator(undefined, new LengthValidator(10, 'ERROR_CONTENT_SHORT')),
'PASSWORD': new LengthValidator(6, 'ERROR_PASSWORD'),
'REPEAT_PASSWORD': new RepeatPasswordValidator(),
'URL': new LengthValidator(5, 'ERROR_URL'),

View File

@ -27,8 +27,8 @@ class Validator {
if (value.length === 0) return this.getError('ERROR_EMPTY');
}
getError(errorKey) {
return i18n(errorKey);
getError(errorKey, params) {
return i18n(errorKey, params);
}
}

View File

@ -4,6 +4,7 @@ var jsdom = require('jsdom').jsdom;
global.document = jsdom('<html><body></body></html>');
global.window = document.defaultView;
global.Node = global.window.Node;
global.navigator = {
userAgent: 'node.js'
};

View File

@ -77,7 +77,7 @@ class InitSettingsController extends Controller {
'maintenance-mode' => 0,
'layout' => 'boxed',
'allow-attachments' => !!Controller::request('allow-attachments'),
'max-size' => 1024,
'max-size' => 1,
'title' => Controller::request('title') ? Controller::request('title') : 'Support Center',
'url' => Controller::request('url') ? Controller::request('url') : ('http://' . $_SERVER['HTTP_HOST']),
'registration' => !!Controller::request('registration'),

View File

@ -109,6 +109,14 @@ abstract class Controller {
$fileUploader = FileUploader::getInstance();
$fileUploader->setMaxSize($maxSize);
$allImagesValidSize = true;
for($i=0;$i<$totalImages;$i++) {
$allImagesValidSize = $allImagesValidSize && $fileUploader->isSizeValid($_FILES["image_$i"]);
}
if(!$allImagesValidSize) throw new Exception(ERRORS::INVALID_FILE);
$imagePaths = [];
$url = Setting::getSetting('url')->getValue();
for($i=0;$i<$totalImages;$i++) {

View File

@ -1,7 +1,7 @@
<?php
class FileUploader extends FileManager {
private $maxSize = 1024;
private $maxSize = 1;
private $linearCongruentialGenerator;
private $linearCongruentialGeneratorOffset;
private $fileName;
@ -19,10 +19,14 @@ class FileUploader extends FileManager {
private function __construct() {}
public function isSizeValid($file) {
return $file['size'] <= (1048576 * $this->maxSize);
}
public function upload($file) {
$this->setNewName($file['name']);
if($file['size'] > (1024 * $this->maxSize)) {
if(!$this->isSizeValid($file)) {
return false;
}

View File

@ -10,7 +10,7 @@ describe'system/edit-settings' do
"time-zone" => -3,
"layout" => 'full-width',
"allow-attachments" => 1,
"max-size" => 2048,
"max-size" => 2,
"language" => 'en',
"no-reply-email" => 'testemail@hotmail.com'
})
@ -27,7 +27,7 @@ describe'system/edit-settings' do
(row['value']).should.equal('full-width')
row = $database.getRow('setting', 'max-size', 'name')
(row['value']).should.equal('2048')
(row['value']).should.equal('2')
row = $database.getRow('setting', 'language', 'name')
(row['value']).should.equal('en')