diff --git a/_contentTemplates/upload/notes.md b/_contentTemplates/upload/notes.md index 0d5e9f049f..2dc6c44bf5 100644 --- a/_contentTemplates/upload/notes.md +++ b/_contentTemplates/upload/notes.md @@ -1,12 +1,12 @@ #server-security-note ->warning File upload and remove controllers can create application vulnerabilities. Learn about all possible security risks and how to avoid them. Do not trust any part of the upload or remove request and implement server-side validation. +>warning File handling, saving and deletion can create application vulnerabilities. This includes any related controller methods. Learn about all possible security risks and how to avoid them. Do not trust the user files or requests, and implement server-side validation. > -* [ASP.NET Core Secuirty Considerations](https://docs.microsoft.com/en-us/aspnet/core/mvc/models/file-uploads?view=aspnetcore-6.0#security-considerations) +* [ASP.NET Core Secuirty Considerations](https://learn.microsoft.com/en-us/aspnet/core/mvc/models/file-uploads) * [File Upload Security Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html) * [Upload Path Traversal](https://security.stackexchange.com/questions/177307/path-traversal-via-filename) > -The controller methods in this documentation do not implement security measures for simplicity and brevity. +The code examples in this documentation do not implement security measures for simplicity and brevity. #end diff --git a/components/fileselect/events.md b/components/fileselect/events.md index 0d096e583c..6d27083083 100644 --- a/components/fileselect/events.md +++ b/components/fileselect/events.md @@ -39,21 +39,25 @@ Property | Type | Description ## OnSelect -The `OnSelect` fires when one or more files have been selected. The selection of files is achieved either through the **Select Files** button or by dropping the files anywhere in the component. +The `OnSelect` event fires each time when the user selects file(s) through the **Select Files** button or by drag and drop anywhere in the component. -The event handler receives a [`FileSelectEventArgs` object](#fileselectfileinfo). If you set its `IsCancelled` property to `true`, the component will ignore the user action and the selected files will not appear in the component file list. +The event handler receives a [`FileSelectEventArgs` object](#fileselectfileinfo). If you set its `IsCancelled` property to `true`, the component ignores the user action and all newly selected files do not appear in the component file list. + +`OnSelect` fires for both valid and invalid files. You can verify if the file is valid by checking the validation-related properties of each [`FileSelectFileInfo`](slug:fileselect-events#fileselectfileinfo) object. If necessary, the application can still handle invalid files, for example, read their content. See the [example below](#example). ## OnRemove -The `OnRemove` fires when a file has been removed from the list of selected files either by clicking the **x** icon or by pressing the `Del` key. +The `OnRemove` event fires when the user deletes a file from the list by clicking the **x** icon or by pressing the `Del` key. + +The event handler receives a [`FileSelectEventArgs` object](#fileselectfileinfo). The `Files` collection in the event argument always contains a single `FileSelectFileInfo` object. This is unlike the `OnSelect` event where `Files` can include one or more files. -The event handler receives a [`FileSelectEventArgs` object](#fileselectfileinfo). The `Files` collection in the event argument always contains a single `FileSelectFileInfo` object. This is unlike the `OnSelect` event where `Files` may include one or more files. +`OnRemove` fires for both valid and invalid files. ## Example ->caption Handling the `OnSelect` and `OnRemove` events of the FileSelect +>caption Handle the FileSelect `OnSelect` and `OnRemove` events ````RAZOR @using System.Threading @@ -66,35 +70,44 @@ The event handler receives a [`FileSelectEventArgs` object](#fileselectfileinfo) @using IONS = System.IO -
- Expected files: @string.Join(", ", AllowedExtensions) -
- + OnRemove="@OnFileRemove" + OnSelect="@OnFileSelect"> +
+ Expected files:   @string.Join(", ", AllowedExtensions) +
+ @code { - private readonly List AllowedExtensions = new() { ".jpg", ".png", ".gif" }; + private readonly List AllowedExtensions = new() { ".gif", ".jpg", ".jpeg", ".png", ".svg" }; private Dictionary Tokens { get; set; } = new(); - private async Task HandleFiles(FileSelectEventArgs args) + private async Task OnFileSelect(FileSelectEventArgs args) { foreach (var file in args.Files) { - if (!file.InvalidExtension) + if (file.InvalidExtension || file.InvalidMaxFileSize || file.InvalidMinFileSize) { - // Read file in-memory. - await ReadFile(file); + // Skip invalid files. + continue; // OR - // Save to local file system. - // This works only in server apps and the Upload component may be a better choice. - //await UploadFile(file); + // Cancel all files, but refactor the handler to iterate and validate all files before reading any of them. + //args.IsCancelled = true; + //return; } + + // Read file in-memory. + await ReadFile(file); + + // OR + + // Save to local file system. + // This works only in server apps and the Upload component may be a better choice. + //await UploadFile(file); } } @@ -117,7 +130,7 @@ The event handler receives a [`FileSelectEventArgs` object](#fileselectfileinfo) //await file.Stream.CopyToAsync(fs, Tokens[file.Id].Token); } - private async Task RemoveFiles(FileSelectEventArgs args) + private async Task OnFileRemove(FileSelectEventArgs args) { foreach (var file in args.Files) { diff --git a/components/fileselect/validation.md b/components/fileselect/validation.md index 63391155f2..6bfa4220c0 100644 --- a/components/fileselect/validation.md +++ b/components/fileselect/validation.md @@ -8,43 +8,68 @@ published: true position: 10 --- -# FileSelect - Selected Files Validation +# FileSelect File Validation If you want to validate the selected files, you should implement the validation in two parts: -* client validation - performed by the Telerik FileSelect component -* server validation - must be implemented in the application endpoints +* Client validation—performed by the Telerik FileSelect component +* Server validation—must be implemented in the application backend or endpoints -The Telerik FileSelect component offers parameters to validate the file selection on the client: +## Parameters -* `Accept` - `string` - not validation per se, but this parameter can [instruct the browser what file types to allow users to select](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/accept). -* `AllowedExtensions` - `List` - a list of valid file extensions. Choosing other file types will mark them as invalid in the UI. The default value is `null`, which allows all extensions. -* `MinFileSize`- `int?` - the minimum size of a file in bytes. Files with a smaller size will be marked as invalid in the UI. -* `MaxFileSize`- `int?` - the maximum size of a file in bytes. Files with a larger size will be marked as invalid in the UI. +The Telerik [FileSelect component offers parameters](slug:Telerik.Blazor.Components.TelerikFileSelect) to validate the file selection on the client: ->caption Client validation in the Telerik FileSelect component +* `AllowedExtensions` +* `MinFileSize` +* `MaxFileSize` -For brevity, this sample does not showcase actual upload of the files. You can find an example in the [FileSelect Events article](slug:fileselect-events). +Selected files that don't meet the defined criteria are marked as invalid in the component UI. + +The FileSelect also provides an `Accept` parameter. It does not enforce validation, but [instructs the browser what file types to allow users to select](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/accept). This can also help users find the correct files more easily. + +## Events + +The [FileSelect fires its `OnSelect` and `OnRemove` events](slug:fileselect-events) for both valid and invalid files. The application can confirm file validity through the [event argument properties](slug:fileselect-events#fileselectfileinfo) and decide how to proceed. + +## Example + +For brevity, the code below does not handle the selected file. See a full example in the [FileSelect Events article](slug:fileselect-events#example). + +>caption Telerik FileSelect file validation ````RAZOR -@* Some images are only allowed, min size 1KB, max size 4MB *@ - -
- - -
- Expected files: JPG, PNG, JPEG between 1KB and 4MB. -
+ + + +
+ Expected files: JPG, PNG, SVG between 1 KB and 4 MB.
@code { - public List AllowedExtensions { get; set; } = new List() { ".jpg", ".png", ".jpeg" }; + private readonly List AllowedExtensions = new List() { ".jpg", ".jpeg", ".png", ".svg" }; + + private const int MinSize = 1024; + + private const int MaxSize = 4 * 1024 * 1024; + + private void OnFileSelect(FileSelectEventArgs args) + { + FileSelectFileInfo file = args.Files.First(); - public int MinSize { get; set; } = 1024; + if (file.InvalidExtension || file.InvalidMaxFileSize || file.InvalidMinFileSize) + { + // Optionally, ignore the user action completely. + // The selected file(s) will not appear in the file list. + //args.IsCancelled = true; + return; + } - public int MaxSize { get; set; } = 4 * 1024 * 1024; + // Handle selected valid file... + } } ````