From 88282fb9c4fe4134b04803a10a0fcdf72f466696 Mon Sep 17 00:00:00 2001 From: Adrian Stevens Date: Tue, 30 Apr 2024 15:29:54 -0700 Subject: [PATCH 1/2] Fix file and folder sanitization for file-related commands --- .../Commands/Current/App/AppTools.cs | 25 ++++++++++------- .../Current/File/FileDeleteCommand.cs | 27 +++++++------------ .../Current/File/FileInitialCommand.cs | 2 +- .../Commands/Current/File/FileListCommand.cs | 2 +- .../Commands/Current/File/FileReadCommand.cs | 10 ++++++- .../Commands/Current/File/FileWriteCommand.cs | 19 ++++++++++--- .../Meadow.Cli/Properties/launchSettings.json | 12 +++++++-- 7 files changed, 60 insertions(+), 37 deletions(-) diff --git a/Source/v2/Meadow.CLI/Commands/Current/App/AppTools.cs b/Source/v2/Meadow.CLI/Commands/Current/App/AppTools.cs index e989a618..aa8a681d 100644 --- a/Source/v2/Meadow.CLI/Commands/Current/App/AppTools.cs +++ b/Source/v2/Meadow.CLI/Commands/Current/App/AppTools.cs @@ -98,26 +98,31 @@ internal static async Task TrimApplication(string path, return true; } - internal static string SanitiseMeadowFilename(string fileName) + internal static string SanitizeMeadowFolderName(string fileName) { + return SanitizeMeadowFilename(fileName) + '/'; + } + + internal static string SanitizeMeadowFilename(string fileName) + { + fileName = fileName.Replace('\\', Path.DirectorySeparatorChar); + fileName = fileName.Replace('/', Path.DirectorySeparatorChar); + var folder = Path.GetDirectoryName(fileName); + if (string.IsNullOrWhiteSpace(folder)) { - folder = MeadowRootFolder; + folder = Path.DirectorySeparatorChar + MeadowRootFolder; } else { - if (folder.EndsWith('/') == false) - { - folder += "/"; - } - if (folder.StartsWith('/') == false) + if (!folder.StartsWith(Path.DirectorySeparatorChar)) { - folder = $"/{folder}"; + folder = $"{Path.DirectorySeparatorChar}{folder}"; } - if (folder.Contains(MeadowRootFolder) == false) + if (!folder.Contains(MeadowRootFolder)) { - folder = $"/{MeadowRootFolder}{folder}"; + folder = $"{Path.DirectorySeparatorChar}{MeadowRootFolder}{folder}"; } } diff --git a/Source/v2/Meadow.Cli/Commands/Current/File/FileDeleteCommand.cs b/Source/v2/Meadow.Cli/Commands/Current/File/FileDeleteCommand.cs index 18b79987..7382e528 100644 --- a/Source/v2/Meadow.Cli/Commands/Current/File/FileDeleteCommand.cs +++ b/Source/v2/Meadow.Cli/Commands/Current/File/FileDeleteCommand.cs @@ -27,12 +27,9 @@ protected override async ValueTask ExecuteCommand() await device.RuntimeDisable(CancellationToken); } - // get a list of files in the target folder - var folder = Path.GetDirectoryName(MeadowFile)!.Replace(Path.DirectorySeparatorChar, '/'); - if (string.IsNullOrWhiteSpace(folder)) - { - folder = $"/{AppTools.MeadowRootFolder}/"; - } + Logger?.LogInformation($"Looking for file {MeadowFile}..."); + + var folder = AppTools.SanitizeMeadowFolderName(Path.GetDirectoryName(MeadowFile)!); var fileList = await connection.GetFileList($"{folder}", false, CancellationToken); @@ -55,29 +52,23 @@ protected override async ValueTask ExecuteCommand() var exists = fileList?.Any(f => Path.GetFileName(f.Name) == requested) ?? false; + var file = AppTools.SanitizeMeadowFilename(MeadowFile); + if (!exists) { - Logger?.LogError($"File '{MeadowFile}' not found on device."); + Logger?.LogError($"File '{file}' not found on device"); } else { - var wasRuntimeEnabled = await device.IsRuntimeEnabled(CancellationToken); - - if (wasRuntimeEnabled) - { - Logger?.LogError($"The runtime must be disabled before doing any file management. Use 'meadow runtime disable' first."); - return; - } - - Logger?.LogInformation($"Deleting file '{MeadowFile}' from device..."); - await device.DeleteFile(AppTools.SanitiseMeadowFilename(MeadowFile), CancellationToken); + Logger?.LogInformation($"Deleting file '{file}' from device..."); + await device.DeleteFile(file, CancellationToken); } } } private async Task DeleteFileRecursive(IMeadowDevice device, string directoryname, MeadowFileInfo fileInfo, CancellationToken cancellationToken) { - var meadowFile = AppTools.SanitiseMeadowFilename(Path.Combine(directoryname, fileInfo.Name)); + var meadowFile = AppTools.SanitizeMeadowFilename(Path.Combine(directoryname, fileInfo.Name)); if (fileInfo.IsDirectory) { // Add a backslash as we're a directory and not a file diff --git a/Source/v2/Meadow.Cli/Commands/Current/File/FileInitialCommand.cs b/Source/v2/Meadow.Cli/Commands/Current/File/FileInitialCommand.cs index c7d959b7..22277c0f 100644 --- a/Source/v2/Meadow.Cli/Commands/Current/File/FileInitialCommand.cs +++ b/Source/v2/Meadow.Cli/Commands/Current/File/FileInitialCommand.cs @@ -19,7 +19,7 @@ protected override async ValueTask ExecuteCommand() Logger?.LogInformation($"Reading file '{MeadowFile}' from device...\n"); - var data = await device.ReadFileString(AppTools.SanitiseMeadowFilename(MeadowFile), CancellationToken); + var data = await device.ReadFileString(AppTools.SanitizeMeadowFilename(MeadowFile), CancellationToken); if (data == null) { diff --git a/Source/v2/Meadow.Cli/Commands/Current/File/FileListCommand.cs b/Source/v2/Meadow.Cli/Commands/Current/File/FileListCommand.cs index a8e910b7..876b9c3d 100644 --- a/Source/v2/Meadow.Cli/Commands/Current/File/FileListCommand.cs +++ b/Source/v2/Meadow.Cli/Commands/Current/File/FileListCommand.cs @@ -26,7 +26,7 @@ protected override async ValueTask ExecuteCommand() if (Folder != null) { - Folder = AppTools.SanitiseMeadowFilename(Folder); + Folder = AppTools.SanitizeMeadowFolderName(Folder); Logger?.LogInformation($"Getting file list from '{Folder}'..."); } diff --git a/Source/v2/Meadow.Cli/Commands/Current/File/FileReadCommand.cs b/Source/v2/Meadow.Cli/Commands/Current/File/FileReadCommand.cs index 7ad1ecde..3bd63c2e 100644 --- a/Source/v2/Meadow.Cli/Commands/Current/File/FileReadCommand.cs +++ b/Source/v2/Meadow.Cli/Commands/Current/File/FileReadCommand.cs @@ -21,6 +21,14 @@ protected override async ValueTask ExecuteCommand() var device = await GetCurrentDevice(); var connection = await GetCurrentConnection(); + var state = await device.IsRuntimeEnabled(CancellationToken); + + if (state == true) + { + Logger?.LogInformation($"{Strings.DisablingRuntime}..."); + await device.RuntimeDisable(CancellationToken); + } + var received = 0; connection.FileBytesReceived += (s, count) => @@ -43,7 +51,7 @@ protected override async ValueTask ExecuteCommand() await device.RuntimeDisable(); } - var success = await device.ReadFile(AppTools.SanitiseMeadowFilename(MeadowFile), LocalFile, CancellationToken); + var success = await device.ReadFile(AppTools.SanitizeMeadowFilename(MeadowFile), LocalFile, CancellationToken); if (success) { diff --git a/Source/v2/Meadow.Cli/Commands/Current/File/FileWriteCommand.cs b/Source/v2/Meadow.Cli/Commands/Current/File/FileWriteCommand.cs index 9a85124b..196bd2c0 100644 --- a/Source/v2/Meadow.Cli/Commands/Current/File/FileWriteCommand.cs +++ b/Source/v2/Meadow.Cli/Commands/Current/File/FileWriteCommand.cs @@ -29,6 +29,14 @@ protected override async ValueTask ExecuteCommand() var connection = await GetCurrentConnection(); var device = await GetCurrentDevice(); + var state = await device.IsRuntimeEnabled(CancellationToken); + + if (state == true) + { + Logger?.LogInformation($"{Strings.DisablingRuntime}..."); + await device.RuntimeDisable(CancellationToken); + } + if (TargetFileNames.Any() && Files.Count != TargetFileNames.Count) { Logger?.LogError($"Number of files to write ({Files.Count}) does not match the number of target file names ({TargetFileNames.Count})."); @@ -40,8 +48,11 @@ protected override async ValueTask ExecuteCommand() { var p = e.completed / (double)e.total * 100d; - // Console instead of Logger due to line breaking for progress bar - Console?.Output.Write($"Writing {e.fileName}: {p:0}% \r"); + if (!double.IsNaN(p)) + { + // Console instead of Logger due to line breaking for progress bar + Console?.Output.Write($"Writing {e.fileName}: {p:0}% \r"); + } }; Logger?.LogInformation($"Writing {Files.Count} file{(Files.Count > 1 ? "s" : "")} to device..."); @@ -54,7 +65,7 @@ protected override async ValueTask ExecuteCommand() } else { - var targetFileName = AppTools.SanitiseMeadowFilename(GetTargetFileName(i)); + var targetFileName = AppTools.SanitizeMeadowFilename(GetTargetFileName(i)); Logger?.LogInformation( $"Writing '{Files[i]}' as '{targetFileName}' to device"); @@ -85,4 +96,4 @@ private string GetTargetFileName(int i) return new FileInfo(Files[i]).Name; } -} +} \ No newline at end of file diff --git a/Source/v2/Meadow.Cli/Properties/launchSettings.json b/Source/v2/Meadow.Cli/Properties/launchSettings.json index c9a7e2fd..e6bb0322 100644 --- a/Source/v2/Meadow.Cli/Properties/launchSettings.json +++ b/Source/v2/Meadow.Cli/Properties/launchSettings.json @@ -83,13 +83,21 @@ "commandName": "Project", "commandLineArgs": "file list" }, + "File List folder": { + "commandName": "Project", + "commandLineArgs": "file list Temp" + }, "File List verbose": { "commandName": "Project", "commandLineArgs": "file list --verbose" }, "File Delete": { "commandName": "Project", - "commandLineArgs": "file delete Juego.pdb" + "commandLineArgs": "file delete /yo2.txt" + }, + "File Delete folder": { + "commandName": "Project", + "commandLineArgs": "file delete /Temp/yo3.txt" }, "File Delete All": { "commandName": "Project", @@ -105,7 +113,7 @@ }, "File Write": { "commandName": "Project", - "commandLineArgs": "file write -f \"f:\\temp\\test.txt\"" + "commandLineArgs": "file write -f .\\yo2.txt" }, "Firmware List": { "commandName": "Project", From 24424b0e196ab7c96ec6c7afff882c258daff82f Mon Sep 17 00:00:00 2001 From: Adrian Stevens Date: Tue, 30 Apr 2024 15:50:05 -0700 Subject: [PATCH 2/2] Improved folder sanitization --- .../v2/Meadow.CLI/Commands/Current/App/AppTools.cs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Source/v2/Meadow.CLI/Commands/Current/App/AppTools.cs b/Source/v2/Meadow.CLI/Commands/Current/App/AppTools.cs index aa8a681d..78abd6c0 100644 --- a/Source/v2/Meadow.CLI/Commands/Current/App/AppTools.cs +++ b/Source/v2/Meadow.CLI/Commands/Current/App/AppTools.cs @@ -118,11 +118,14 @@ internal static string SanitizeMeadowFilename(string fileName) { if (!folder.StartsWith(Path.DirectorySeparatorChar)) { - folder = $"{Path.DirectorySeparatorChar}{folder}"; - } - if (!folder.Contains(MeadowRootFolder)) - { - folder = $"{Path.DirectorySeparatorChar}{MeadowRootFolder}{folder}"; + if (!folder.StartsWith($"{MeadowRootFolder}")) + { + folder = $"{Path.DirectorySeparatorChar}{MeadowRootFolder}{Path.DirectorySeparatorChar}{folder}"; + } + else + { + folder = $"{Path.DirectorySeparatorChar}{folder}"; + } } }