mirror of
https://github.com/BookStackApp/BookStack.git
synced 2024-10-01 01:36:00 -04:00
Allow uploads of files containing dots in filename. Closes BookStackApp/BookStack#2217
This commit is contained in:
parent
4d4a57d1bf
commit
745d15d200
@ -159,6 +159,6 @@ abstract class Controller extends BaseController
|
||||
*/
|
||||
protected function getImageValidationRules(): string
|
||||
{
|
||||
return 'image_extension|no_double_extension|mimes:jpeg,png,gif,webp';
|
||||
return 'image_extension|mimes:jpeg,png,gif,webp';
|
||||
}
|
||||
}
|
||||
|
@ -18,11 +18,6 @@ class CustomValidationServiceProvider extends ServiceProvider
|
||||
return in_array(strtolower($value->getClientOriginalExtension()), $validImageExtensions);
|
||||
});
|
||||
|
||||
Validator::extend('no_double_extension', function ($attribute, $value, $parameters, $validator) {
|
||||
$uploadName = $value->getClientOriginalName();
|
||||
return substr_count($uploadName, '.') < 2;
|
||||
});
|
||||
|
||||
Validator::extend('safe_url', function ($attribute, $value, $parameters, $validator) {
|
||||
$cleanLinkName = strtolower(trim($value));
|
||||
$isJs = strpos($cleanLinkName, 'javascript:') === 0;
|
||||
|
@ -60,7 +60,7 @@ class ImageService
|
||||
int $resizeHeight = null,
|
||||
bool $keepRatio = true
|
||||
) {
|
||||
$imageName = $uploadedFile->getClientOriginalName();
|
||||
$imageName = $this->sanitizeFileName($uploadedFile->getClientOriginalName());
|
||||
$imageData = file_get_contents($uploadedFile->getRealPath());
|
||||
|
||||
if ($resizeWidth !== null || $resizeHeight !== null) {
|
||||
@ -426,4 +426,15 @@ class ImageService
|
||||
$basePath = ($this->storageUrl == false) ? url('/') : $this->storageUrl;
|
||||
return rtrim($basePath, '/') . $filePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a sanitized filename with only one file extension
|
||||
*/
|
||||
private function sanitizeFileName(string $fileName): string
|
||||
{
|
||||
$parts = explode('.', $fileName);
|
||||
$extension = array_pop($parts);
|
||||
|
||||
return sprintf('%s.%s', implode('-', $parts), $extension);
|
||||
}
|
||||
}
|
||||
|
@ -78,7 +78,6 @@ return [
|
||||
'string' => 'يجب أن يكون :attribute على الأقل :min حرف / حروف.',
|
||||
'array' => 'يجب أن يحتوي :attribute على :min عنصر / عناصر كحد أدنى.',
|
||||
],
|
||||
'no_double_extension' => 'يجب أن يكون للسمة: امتداد ملف واحد فقط.',
|
||||
'not_in' => ':attribute المحدد غير صالح.',
|
||||
'not_regex' => 'صيغة السمة: غير صالحة.',
|
||||
'numeric' => 'يجب أن يكون :attribute رقم.',
|
||||
|
@ -78,7 +78,6 @@ return [
|
||||
'string' => 'The :attribute must be at least :min characters.',
|
||||
'array' => 'The :attribute must have at least :min items.',
|
||||
],
|
||||
'no_double_extension' => 'The :attribute must only have a single file extension.',
|
||||
'not_in' => 'The selected :attribute is invalid.',
|
||||
'not_regex' => 'The :attribute format is invalid.',
|
||||
'numeric' => 'The :attribute must be a number.',
|
||||
|
@ -78,7 +78,6 @@ return [
|
||||
'string' => ':attribute musí být delší než :min znaků.',
|
||||
'array' => ':attribute musí obsahovat více než :min prvků.',
|
||||
],
|
||||
'no_double_extension' => ':attribute musí obsahovat pouze jednu příponu souboru.',
|
||||
'not_in' => 'Zvolená hodnota pro :attribute je neplatná.',
|
||||
'not_regex' => ':attribute musí být regulární výraz.',
|
||||
'numeric' => ':attribute musí být číslo.',
|
||||
|
@ -78,7 +78,6 @@ return [
|
||||
'string' => ':attribute skal mindst være :min tegn.',
|
||||
'array' => ':attribute skal have mindst :min elementer.',
|
||||
],
|
||||
'no_double_extension' => ':attribute må kun indeholde én filtype.',
|
||||
'not_in' => 'Den valgte :attribute er ikke gyldig.',
|
||||
'not_regex' => ':attribute-formatet er ugyldigt.',
|
||||
'numeric' => ':attribute skal være et tal.',
|
||||
|
@ -78,7 +78,6 @@ return [
|
||||
'string' => ':attribute muss mindestens :min Zeichen lang sein.',
|
||||
'array' => ':attribute muss mindesten :min Elemente enthalten.',
|
||||
],
|
||||
'no_double_extension' => ':attribute darf nur eine gültige Dateiendung',
|
||||
'not_in' => ':attribute ist ungültig.',
|
||||
'not_regex' => ':attribute ist kein valides Format.',
|
||||
'numeric' => ':attribute muss eine Zahl sein.',
|
||||
|
@ -78,7 +78,6 @@ return [
|
||||
'string' => ':attribute muss mindestens :min Zeichen lang sein.',
|
||||
'array' => ':attribute muss mindesten :min Elemente enthalten.',
|
||||
],
|
||||
'no_double_extension' => ':attribute darf nur eine gültige Dateiendung',
|
||||
'not_in' => ':attribute ist ungültig.',
|
||||
'not_regex' => ':attribute ist kein gültiges Format.',
|
||||
'numeric' => ':attribute muss eine Zahl sein.',
|
||||
|
@ -78,7 +78,6 @@ return [
|
||||
'string' => 'The :attribute must be at least :min characters.',
|
||||
'array' => 'The :attribute must have at least :min items.',
|
||||
],
|
||||
'no_double_extension' => 'The :attribute must only have a single file extension.',
|
||||
'not_in' => 'The selected :attribute is invalid.',
|
||||
'not_regex' => 'The :attribute format is invalid.',
|
||||
'numeric' => 'The :attribute must be a number.',
|
||||
|
@ -78,7 +78,6 @@ return [
|
||||
'string' => 'El :attribute debe ser al menos :min caracteres.',
|
||||
'array' => 'El :attribute debe tener como mínimo :min items.',
|
||||
],
|
||||
'no_double_extension' => 'El :attribute solo debe tener una extensión de archivo.',
|
||||
'not_in' => 'El :attribute seleccionado es inválio.',
|
||||
'not_regex' => 'El formato de :attribute es inválido.',
|
||||
'numeric' => 'El :attribute debe ser numérico.',
|
||||
|
@ -78,7 +78,6 @@ return [
|
||||
'string' => ':attribute debe ser al menos :min caracteres.',
|
||||
'array' => ':attribute debe tener como mínimo :min items.',
|
||||
],
|
||||
'no_double_extension' => 'El :attribute debe tener una única extensión de archivo.',
|
||||
'not_in' => ':attribute seleccionado es inválido.',
|
||||
'not_regex' => 'El formato de :attribute es inválido.',
|
||||
'numeric' => ':attribute debe ser numérico.',
|
||||
|
@ -78,7 +78,6 @@ return [
|
||||
'string' => 'The :attribute must be at least :min characters.',
|
||||
'array' => 'The :attribute must have at least :min items.',
|
||||
],
|
||||
'no_double_extension' => 'The :attribute must only have a single file extension.',
|
||||
'not_in' => 'The selected :attribute is invalid.',
|
||||
'not_regex' => 'The :attribute format is invalid.',
|
||||
'numeric' => 'The :attribute must be a number.',
|
||||
|
@ -78,7 +78,6 @@ return [
|
||||
'string' => ':attribute doit contenir au moins :min caractères.',
|
||||
'array' => ':attribute doit contenir au moins :min éléments.',
|
||||
],
|
||||
'no_double_extension' => ':attribute ne doit avoir qu\'une seule extension de fichier.',
|
||||
'not_in' => 'L\'attribut sélectionné :attribute est invalide.',
|
||||
'not_regex' => ':attribute a un format invalide.',
|
||||
'numeric' => ':attribute doit être un nombre.',
|
||||
|
@ -78,7 +78,6 @@ return [
|
||||
'string' => 'שדה :attribute חייב להיות לפחות :min תווים.',
|
||||
'array' => 'שדה :attribute חייב להיות לפחות :min פריטים.',
|
||||
],
|
||||
'no_double_extension' => 'השדה :attribute חייב להיות בעל סיומת קובץ אחת בלבד.',
|
||||
'not_in' => 'בחירת ה-:attribute אינה תקפה.',
|
||||
'not_regex' => 'The :attribute format is invalid.',
|
||||
'numeric' => 'שדה :attribute חייב להיות מספר.',
|
||||
|
@ -78,7 +78,6 @@ return [
|
||||
'string' => ':attribute legalább :min karakter kell legyen.',
|
||||
'array' => ':attribute legalább :min elem kell legyen.',
|
||||
],
|
||||
'no_double_extension' => ':attribute csak egy fájlkiterjesztéssel rendelkezhet.',
|
||||
'not_in' => 'A kiválasztott :attribute érvénytelen.',
|
||||
'not_regex' => ':attribute formátuma érvénytelen.',
|
||||
'numeric' => ':attribute szám kell legyen.',
|
||||
|
@ -78,7 +78,6 @@ return [
|
||||
'string' => 'Il campo :attribute deve essere almeno :min caratteri.',
|
||||
'array' => 'Il campo :attribute deve contenere almeno :min elementi.',
|
||||
],
|
||||
'no_double_extension' => ':attribute deve avere solo un\'estensione.',
|
||||
'not_in' => 'Il :attribute selezionato non è valido.',
|
||||
'not_regex' => 'Il formato di :attribute non è valido.',
|
||||
'numeric' => ':attribute deve essere un numero.',
|
||||
|
@ -78,7 +78,6 @@ return [
|
||||
'string' => ':attributeは:min文字以上である必要があります。',
|
||||
'array' => ':attributeは:min個以上である必要があります。',
|
||||
],
|
||||
'no_double_extension' => 'The :attribute must only have a single file extension.',
|
||||
'not_in' => '選択された:attributeは不正です。',
|
||||
'not_regex' => 'The :attribute format is invalid.',
|
||||
'numeric' => ':attributeは数値である必要があります。',
|
||||
|
@ -78,7 +78,6 @@ return [
|
||||
'string' => ':attribute(을)를 적어도 :value바이트로 구성하세요.',
|
||||
'array' => ':attribute(을)를 적어도 :value개로 구성하세요..',
|
||||
],
|
||||
'no_double_extension' => ':attribute(이)가 단일한 확장자를 가져야 합니다.',
|
||||
'not_in' => '고른 :attribute(이)가 유효하지 않습니다.',
|
||||
'not_regex' => ':attribute(은)는 유효하지 않은 형식입니다.',
|
||||
'numeric' => ':attribute(을)를 숫자로만 구성하세요.',
|
||||
|
@ -78,7 +78,6 @@ return [
|
||||
'string' => ':attribute må være på minst :min tegn.',
|
||||
'array' => ':attribute må minst ha :min ting.',
|
||||
],
|
||||
'no_double_extension' => ':attribute kan bare ha en formattype spesifisert.',
|
||||
'not_in' => 'Den valgte :attribute er ugyldig.',
|
||||
'not_regex' => ':attribute format er ugyldig.',
|
||||
'numeric' => ':attribute må være et nummer.',
|
||||
|
@ -78,7 +78,6 @@ return [
|
||||
'string' => ':attribute moet minstens :min karakters bevatten.',
|
||||
'array' => ':attribute moet minstens :min items bevatten.',
|
||||
],
|
||||
'no_double_extension' => ':attribute mag maar een enkele bestandsextensie hebben.',
|
||||
'not_in' => ':attribute is ongeldig.',
|
||||
'not_regex' => ':attribute formaat is ongeldig.',
|
||||
'numeric' => ':attribute moet een getal zijn.',
|
||||
|
@ -78,7 +78,6 @@ return [
|
||||
'string' => 'Długość :attribute nie może być mniejsza niż :min znaków.',
|
||||
'array' => 'Rozmiar :attribute musi posiadać co najmniej :min elementy.',
|
||||
],
|
||||
'no_double_extension' => ':attribute może mieć tylko jedno rozszerzenie.',
|
||||
'not_in' => 'Wartość :attribute jest nieprawidłowa.',
|
||||
'not_regex' => 'Format :attribute jest nieprawidłowy.',
|
||||
'numeric' => ':attribute musi być liczbą.',
|
||||
|
@ -78,7 +78,6 @@ return [
|
||||
'string' => 'The :attribute must be at least :min characters.',
|
||||
'array' => 'The :attribute must have at least :min items.',
|
||||
],
|
||||
'no_double_extension' => 'The :attribute must only have a single file extension.',
|
||||
'not_in' => 'The selected :attribute is invalid.',
|
||||
'not_regex' => 'The :attribute format is invalid.',
|
||||
'numeric' => 'The :attribute must be a number.',
|
||||
|
@ -78,7 +78,6 @@ return [
|
||||
'string' => 'O campo :attribute não deve ter menos que :min caracteres.',
|
||||
'array' => 'O campo :attribute não deve ter menos que :min itens.',
|
||||
],
|
||||
'no_double_extension' => 'O campo :attribute deve ter apenas uma extensão de arquivo.',
|
||||
'not_in' => 'O campo selecionado :attribute é inválido.',
|
||||
'not_regex' => 'O formato do campo :attribute é inválido.',
|
||||
'numeric' => 'O campo :attribute deve ser um número.',
|
||||
|
@ -78,7 +78,6 @@ return [
|
||||
'string' => ':attribute должен быть минимум :min символов.',
|
||||
'array' => ':attribute должен содержать хотя бы :min элементов.',
|
||||
],
|
||||
'no_double_extension' => ':attribute должен иметь только одно расширение файла.',
|
||||
'not_in' => 'Выбранный :attribute некорректен.',
|
||||
'not_regex' => 'Формат :attribute некорректен.',
|
||||
'numeric' => ':attribute должен быть числом.',
|
||||
|
@ -78,7 +78,6 @@ return [
|
||||
'string' => ':attribute musí mať aspoň :min znakov.',
|
||||
'array' => ':attribute musí mať aspoň :min položiek.',
|
||||
],
|
||||
'no_double_extension' => 'The :attribute must only have a single file extension.',
|
||||
'not_in' => 'Vybraný :attribute je neplatný.',
|
||||
'not_regex' => 'The :attribute format is invalid.',
|
||||
'numeric' => ':attribute musí byť číslo.',
|
||||
|
@ -78,7 +78,6 @@ return [
|
||||
'string' => ':attribute mora biti najmanj :min znakov.',
|
||||
'array' => ':attribute mora imeti vsaj :min elementov.',
|
||||
],
|
||||
'no_double_extension' => ':attribute mora imeti samo eno razširitveno datoteko',
|
||||
'not_in' => 'Izbrani atribut je neveljaven.',
|
||||
'not_regex' => ':attribute oblika ni veljavna.',
|
||||
'numeric' => 'Atribut mora biti število.',
|
||||
|
@ -78,7 +78,6 @@ return [
|
||||
'string' => ':attribute måste vara minst :min tecken.',
|
||||
'array' => ':attribute måste ha minst :min poster.',
|
||||
],
|
||||
'no_double_extension' => ':attribute får bara ha ett filtillägg.',
|
||||
'not_in' => 'Vald :attribute är inte giltig',
|
||||
'not_regex' => 'Formatet på :attribute är ogiltigt.',
|
||||
'numeric' => ':attribute måste vara ett nummer.',
|
||||
|
@ -78,7 +78,6 @@ return [
|
||||
'string' => 'The :attribute must be at least :min characters.',
|
||||
'array' => 'The :attribute must have at least :min items.',
|
||||
],
|
||||
'no_double_extension' => 'The :attribute must only have a single file extension.',
|
||||
'not_in' => 'The selected :attribute is invalid.',
|
||||
'not_regex' => 'The :attribute format is invalid.',
|
||||
'numeric' => 'The :attribute must be a number.',
|
||||
|
@ -78,7 +78,6 @@ return [
|
||||
'string' => ':attribute, en az :min karakter içermelidir.',
|
||||
'array' => ':attribute, en az :min öge içermelidir.',
|
||||
],
|
||||
'no_double_extension' => ':attribute, sadece tek bir dosya tipinde olmalıdır.',
|
||||
'not_in' => 'Seçili :attribute geçersiz.',
|
||||
'not_regex' => ':attribute formatı geçersiz.',
|
||||
'numeric' => ':attribute, bir sayı olmalıdır.',
|
||||
|
@ -78,7 +78,6 @@ return [
|
||||
'string' => 'Текст в полі :attribute повинен містити не менше :min символів.',
|
||||
'array' => 'Поле :attribute повинне містити не менше :min елементів.',
|
||||
],
|
||||
'no_double_extension' => 'Поле :attribute повинне містити тільки одне розширення файлу.',
|
||||
'not_in' => 'Вибране для :attribute значення не коректне.',
|
||||
'not_regex' => 'Формат поля :attribute не вірний.',
|
||||
'numeric' => 'Поле :attribute повинно містити число.',
|
||||
|
@ -78,7 +78,6 @@ return [
|
||||
'string' => ':attribute phải có tối thiểu :min ký tự.',
|
||||
'array' => ':attribute phải có tối thiểu :min mục.',
|
||||
],
|
||||
'no_double_extension' => ':attribute chỉ được có một định dạng mở rộng duy nhất.',
|
||||
'not_in' => ':attribute đã chọn không hợp lệ.',
|
||||
'not_regex' => 'Định dạng của :attribute không hợp lệ.',
|
||||
'numeric' => ':attribute phải là một số.',
|
||||
|
@ -78,7 +78,6 @@ return [
|
||||
'string' => ':attribute 至少为:min个字符。',
|
||||
'array' => ':attribute 至少有:min项。',
|
||||
],
|
||||
'no_double_extension' => ':attribute 必须具有一个扩展名。',
|
||||
'not_in' => '选中的 :attribute 无效。',
|
||||
'not_regex' => ':attribute 格式错误。',
|
||||
'numeric' => ':attribute 必须是一个数。',
|
||||
|
@ -78,7 +78,6 @@ return [
|
||||
'string' => ':attribute 至少為:min個字元。',
|
||||
'array' => ':attribute 至少有:min項。',
|
||||
],
|
||||
'no_double_extension' => 'The :attribute必須僅具有一個文件擴展名。',
|
||||
'not_in' => '選中的 :attribute 無效。',
|
||||
'not_regex' => 'The :attribute格式無效。',
|
||||
'numeric' => ':attribute 必須是一個數。',
|
||||
|
@ -165,7 +165,7 @@ class ImageTest extends TestCase
|
||||
$this->assertFalse(file_exists(public_path($relPath)), 'Uploaded php file was uploaded but should have been stopped');
|
||||
}
|
||||
|
||||
public function test_files_with_double_extensions_cannot_be_uploaded()
|
||||
public function test_files_with_double_extensions_will_get_sanitized()
|
||||
{
|
||||
$page = Page::first();
|
||||
$admin = $this->getAdmin();
|
||||
@ -177,9 +177,17 @@ class ImageTest extends TestCase
|
||||
|
||||
$file = $this->newTestImageFromBase64('bad-phtml-png.base64', $fileName);
|
||||
$upload = $this->withHeader('Content-Type', 'image/png')->call('POST', '/images/gallery', ['uploaded_to' => $page->id], [], ['file' => $file], []);
|
||||
$upload->assertStatus(302);
|
||||
$upload->assertStatus(200);
|
||||
|
||||
$this->assertFalse(file_exists(public_path($relPath)), 'Uploaded double extension file was uploaded but should have been stopped');
|
||||
$lastImage = Image::query()->latest('id')->first();
|
||||
$newFileName = explode('.', basename($lastImage->path))[0];
|
||||
|
||||
$this->assertEquals($lastImage->name, 'bad-phtml.png');
|
||||
$this->assertFalse(file_exists(public_path($relPath)), 'Uploaded image file name was not stripped of dots');
|
||||
|
||||
$this->assertTrue(strlen($newFileName) > 0, 'File name was reduced to nothing');
|
||||
|
||||
$this->deleteImage($lastImage->path);
|
||||
}
|
||||
|
||||
public function test_url_entities_removed_from_filenames()
|
||||
@ -428,4 +436,4 @@ class ImageTest extends TestCase
|
||||
$this->deleteImage($relPath);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user