Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions _contentTemplates/upload/notes.md
Original file line number Diff line number Diff line change
@@ -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

Expand Down
53 changes: 33 additions & 20 deletions components/fileselect/events.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -66,35 +70,44 @@ The event handler receives a [`FileSelectEventArgs` object](#fileselectfileinfo)
@using IONS = System.IO


<div class="k-form-hint">
Expected files: <strong>@string.Join(", ", AllowedExtensions)</strong>
</div>

<TelerikFileSelect AllowedExtensions="@AllowedExtensions"
OnRemove="@RemoveFiles"
OnSelect="@HandleFiles">
OnRemove="@OnFileRemove"
OnSelect="@OnFileSelect">
</TelerikFileSelect>

<div class="k-form-hint">
Expected files: &nbsp; <strong>@string.Join(", ", AllowedExtensions)</strong>
</div>

@code {
private readonly List<string> AllowedExtensions = new() { ".jpg", ".png", ".gif" };
private readonly List<string> AllowedExtensions = new() { ".gif", ".jpg", ".jpeg", ".png", ".svg" };

private Dictionary<string, CancellationTokenSource> 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);
}
}

Expand All @@ -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)
{
Expand Down
71 changes: 48 additions & 23 deletions components/fileselect/validation.md
Original file line number Diff line number Diff line change
Expand Up @@ -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&mdash;performed by the Telerik FileSelect component
* Server validation&mdash;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<string>` - 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 *@

<div style="width:300px">
<TelerikFileSelect AllowedExtensions="@AllowedExtensions"
MinFileSize="@MinSize"
MaxFileSize="@MaxSize">
</TelerikFileSelect>
<div class="k-form-hint">
Expected files: <strong> JPG, PNG, JPEG </strong> between <strong>1KB</strong> and <strong>4MB</strong>.
</div>
<TelerikFileSelect AllowedExtensions="@AllowedExtensions"
MinFileSize="@MinSize"
MaxFileSize="@MaxSize"
Multiple="false"
OnSelect="@OnFileSelect">
</TelerikFileSelect>

<div class="k-form-hint">
Expected files: JPG, PNG, SVG between 1 KB and 4 MB.
</div>

@code {
public List<string> AllowedExtensions { get; set; } = new List<string>() { ".jpg", ".png", ".jpeg" };
private readonly List<string> AllowedExtensions = new List<string>() { ".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...
}
}
````

Expand Down