# Multiplatform Path Validation

Important Questions

These questions drive this research:

1. Is there a third party NuGet we can use to perform these validations? **R\ We have not found any yet, and it seems unlikely given there is not a standard way of solving this problem, according to multiple discussions in the Internet.**
2. Is there a better way to perform the validations? **R\\** **It seems there is not a better way when it comes to checking the Write and Read permissions.**
3. Can we refactor this code to make it better? **R\ We intend to move this component to Generic.Utils and change the FileSystemValidator into an abstract class. We also intend to change the current validation flow in order to replace the multiple calls from the UI with a single class for each case (output path validation and input path validation).**

There are also questions related to the refactoring of the code:

1. Can we check this with a single call? **R\ Yes. A call for the input path and a call for the output path will be enough.**
2. There are validations in the UI: can we move them to the controller? **R\\** **Yes, we can. However, it is not necessarily the better option.**
3. How many validations are we going to make. **R\\** **Currently we want all validations always.**

These questions are better answered in the **Current Validation Flow** section and the **Proposed Validation Flow** section.&#x20;

## Current Validation Flow

In the main process of the UI (Electron/Node), there are multiple handlers reacting to events that can be sent from the renderer process (Angular/Typescript):

```
this.ipcMainHandler.registerHandler(Messages.Validation.InputFilesExtensions,
        this.validateInputFilesExtensions.bind(this));
this.ipcMainHandler.registerHandler(Messages.Validation.InputFileExtension,
        this.validateInputFileExtension.bind(this));
this.ipcMainHandler.registerHandler(Messages.Validation.FolderWritePermissions,
        this.validateFolderWritePermissions.bind(this));
this.ipcMainHandler.registerHandler(Messages.Validation.FolderReadPermissions, 
        this.validateFolderReadPermissions.bind(this));
this.ipcMainHandler.registerHandler(Messages.Validation.EmptyFolder,
        this.validateEmptyOutputFolder.bind(this));
```

Each of these handlers will send a request to the controller process (C#). Below, an example is presented:

```
async validateFolderReadPermissions(event: string, args: any[]) {
    const result = await this.connection.sendRequest(
        Messages.Validation.FolderReadPermissions, args);
    return result;
}
```

The other handlers are identical to the one above, except for the name of the method and the message that is sent.&#x20;

The C# process is subscribed to these events and reacts to each of them, calling the FileSystemValidator from the Controller.

### Validations made in the front-end for input and output paths

* Paths are non-empty
* Input and output paths are different
* Paths are not network paths
* Paths have the correct syntax (different regular expression for Windows and Unix)
* Existing path **(input only)**
* Path length is less than 260 characters

{% hint style="info" %}
Maximum path length is **not** 260 characters in Unix
{% endhint %}

## Proposed Validation Flow

The proposal is to validate the input and output paths with a single call to the Controller, instead of having multiple validations, some in the front-end and some in the back-end. This single call should also return a FileSystemValidationStatus object which will provide the necessary information for the UI to react.&#x20;

**Maybe some validations should be performed in the front-end for performance reasons. However, right now it does not seem like any of the validations fall in this category.**&#x20;

### **Validations**

#### **Moved from the UI to the Controller**

* Paths are non-empty (**repeat just before starting the execution?**)
* Input and output paths are different (**in the Generic UI?**)
* Paths are not network paths (**should we allow network paths?**) \[[Useful link](https://stackoverflow.com/questions/354477/method-to-determine-if-path-string-is-local-or-remote-machine)]
* Paths have the correct syntax

#### Originally in the Controller

* Read Permission
* Write Permission
* Invalid Extensions (**should we keep this?**)
* Directory exists
* Directory is not empty

#### Removed from the UI

* Path length (duplicated in the Controller)
* Existing path (duplicated in the Controller)

The **Supported Extensions Validation (?): should this validation be done every time the path is modified?**

### Proposed Sequence

The next sequence diagram explains four events:

* Initialization
* Set Input Folder
* Set Output Folder
* Execute: It is important to validate at some moment

{% tabs %}
{% tab title="Sequence Diagram" %}
![](https://3734728532-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MPGL5qkm8R6ZRVzFLyt%2F-MSYO6SthgSNHlm-H-9L%2F-MSYh5-0aqbV-XQH4W0b%2FSeqDiagram.png?alt=media\&token=7a41c518-b2e9-4cd5-af6c-13aed1f6b313)
{% endtab %}

{% tab title="Code for the Diagram" %}
{% hint style="info" %}
If you are looking for the diagram, it is included in the Sequence Diagram tab.
{% endhint %}

This code can be used in the [Sequence Diagram Tool](https://sequencediagram.org/) to replicate the Sequence Diagram in the other tab:

```
title Validations Sequence Diagram

 

participant User
participant UI
participant Controller
participant Validator
participant CodeProcessor

 

note over User,CodeProcessor#lightgreen: Initialize
Controller->Controller: Set Validator

 

note over User,CodeProcessor#lightblue: Set Input Folder
User->UI: Set InputFolder
UI->Controller: ValidateInputFolder
Controller->Validator: ValidateInputFolder
Controller<--Validator: ValidationResult
UI<--Controller: ValidationResult
User<--UI: Validation UX

 

note over User,CodeProcessor#lightblue: Set Output Folder
User->UI: Set OutputFolder
UI->Controller: ValidateOutputFolder
Controller->Validator: ValidateOutputFolder
Controller<--Validator: ValidationResult
UI<--Controller: ValidationResult
User<--UI: Validation UX

 

note over User,CodeProcessor#lightblue: Execute
User->UI: Execution Request
UI->UI: Validate Input & \nOutput Folders Not Empty
UI->Controller: ValidateParameters \n& GetCodeDescriptor
Controller->Controller: Controller Validations
Controller->CodeProcessor: ValidateParameters \n& GetCodeDescriptor
Controller<--CodeProcessor: Validation & CodeDescriptor
UI<--Controller: Validation & CodeDescriptor
User<--UI: Validation or Progress UX
```

{% endtab %}
{% endtabs %}

## Proposed Changes related to the FileSystemValidator

### Moving this logic to Generic.Utils

This problem seems generic enough to be included in the **Generic.Utils** repo instead of being handled in the **Common.Runner/Controller**. The proposal is to create the necessary code in the **Generic.Utils** and including the module in the **Controller**.

### Having an implementation for every supported platform

In order to separate the logic needed for every supported platform, it would be useful to have an **Abstract Class** which defines common methods that should be implemented/overriden in **Concrete Classes**: one for every platform. This would result in

* FileSystemValidator (**Abstract**)&#x20;
* WindowsFileSystemValidator (**Concrete**)
* UnixFileSystemValidator (**Concrete**)

There should also be a class which is responsible for the instantiation of the appropriate class (FileSystemValidatorFactory or similar) depending on the operating system.

![](https://3734728532-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MPGL5qkm8R6ZRVzFLyt%2F-MSYhmToPpyKj1EjDmhd%2F-MSYjyapD5hA04_BxBLT%2FClassDiagram.PNG?alt=media\&token=f6804fda-a514-4890-9dbc-11e80bb7fc64)

### ~~Using fs from Node.js~~

{% hint style="info" %}
This approach would probably only be effective for the Common.Runner/Controller because of its ability to communicate with a Node process.\
**As of now, this approach has been discarded**.
{% endhint %}

It is possible to use the **fs** module for node and make the validations in the node process instead of in the controller, altough this would probably be more complicated.

#### Related Links

* [**Check files permissions with fs**](https://medium.com/better-programming/node-js-fs-module-check-file-accessibility-appending-data-and-changing-permissions-dbce0f2b373c)
* [**Node.js checking permissions of a file**](https://riptutorial.com/node-js/example/5637/check-permissions-of-a-file-or-directory)

## Solutions for each Platform

{% tabs %}
{% tab title="Windows " %}
{% hint style="info" %}
We must consider both .Net Core and .Net Framework
{% endhint %}

Currently, the validation for the **Write** permission is checked by writing a file and then deleting it.

The validation for the **Read** permission is computed using a mechanism similar to the one described in the first link. However, there is no current validation for the **Allow** **Read** access, the code is only checking if there is no **Deny Read** access that applies.

#### Edge Cases

* A subfolder has **Deny Read**
* **Path.GetFullPath** has different behavior in **.Net Core** and **.Net Framework**

#### **Related Links**

* [**Check permissions discussion**](https://groups.google.com/g/microsoft.public.dotnet.languages.csharp/c/71zq9ygnxp0/m/O96imapHgyAJ?pli=1)
* [**Stack Overflow Discussion**](https://stackoverflow.com/questions/1281620/checking-for-directory-and-file-write-permissions-in-net)
* [**Another Stack Overflow Discussion**](https://stackoverflow.com/questions/57458934/checking-if-a-directory-has-read-and-write-permissions-using-net-core)
* [**.Net documentation for System.Security.Permissions.FileIOPermission**](https://docs.microsoft.com/en-us/dotnet/api/system.security.permissions.fileiopermission?view=dotnet-plat-ext-5.0)
  {% endtab %}

{% tab title="Unix" %}
The method **UnixDirectoryInfo.CanAccess** is currently used to check the **Write** and **Read** permissions.

**Related Links:**&#x20;

* [**Stack Overflow Discussion (this one was actually started by Alberto)**](https://stackoverflow.com/questions/63024370/how-to-manage-folders-permissions-on-mac-os-with-acl-in-net-core-3-1-0)
* [**Another Stack Overflow Discussion**](https://stackoverflow.com/questions/45132081/file-permissions-on-linux-unix-with-net-core)
  {% endtab %}
  {% endtabs %}
