Parameter starting with @ is interpreted as a response file path
My app accepts a password as a command line argument, an example...
MyApp.exe --password @123#456
Unfortunately, the @ results in failure, as the dragonfruit subsystem thinks it is a response file and tries (and fails) to locate it as a file on the filesystem.
Would it be possible to allow for the @ character to either be escaped, or handle the exception of failing to open a response file and allow the arguments to pass through to the app unaltered?
Currently the behaviors is to throw an unhandled exception and crash...
System.Security.Permissions.FileIOPermission.EmulateFileIOPermissionChecks
Found in System.CommandLine.DragonFruit v0.3.0-alpha.20158.1
Cheers Jonathan
Command line parameters should typically be treated as plain strings, but no further parsing, if you enclose them in quotes. Does the following work?
MyApp.exe --password "@123#456"
No it does not, I tried both...
MyApp.exe --password "@123#456"
and also
MyApp.exe --password @@123#456
Full exception details...
System.ArgumentException
HResult=0x80070057
Message=Illegal characters in path.
Source=mscorlib
StackTrace:
at System.Security.Permissions.FileIOPermission.EmulateFileIOPermissionChecks(String fullPath)
at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
at System.IO.StreamReader..ctor(String path, Encoding encoding, Boolean detectEncodingFromByteOrderMarks, Int32 bufferSize, Boolean checkHost)
at System.IO.StreamReader..ctor(String path, Encoding encoding)
at System.IO.File.InternalReadAllLines(String path, Encoding encoding)
at System.CommandLine.Parsing.StringExtensions.<ExpandResponseFile>d__15.MoveNext()
at System.CommandLine.Parsing.StringExtensions.<Tokenize>g__ReadResponseFile|4_2(String filePath, Int32 i, <>c__DisplayClass4_0& )
at System.CommandLine.Parsing.StringExtensions.Tokenize(IReadOnlyList`1 args, CommandLineConfiguration configuration)
at System.CommandLine.Parsing.Parser.Parse(IReadOnlyList`1 arguments, String rawInput)
at System.CommandLine.Parsing.ParserExtensions.<InvokeAsync>d__3.MoveNext()
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.CommandLine.DragonFruit.CommandLine.<InvokeMethodAsync>d__2.MoveNext()
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.CommandLine.DragonFruit.CommandLine.<ExecuteAssemblyAsync>d__0.MoveNext()
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at AutoGeneratedProgram.<Main>d__0.MoveNext() in C:\Source\coredev\applications\Deploy\Deploy\obj\Debug\net472\Deploy.Program.g.cs:line 10
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at AutoGeneratedProgram.<Main>(String[] args)
This exception was originally thrown at this call stack:
System.Security.Permissions.FileIOPermission.EmulateFileIOPermissionChecks(string)
System.IO.FileStream.Init(string, System.IO.FileMode, System.IO.FileAccess, int, bool, System.IO.FileShare, int, System.IO.FileOptions, Microsoft.Win32.Win32Native.SECURITY_ATTRIBUTES, string, bool, bool, bool)
System.IO.FileStream.FileStream(string, System.IO.FileMode, System.IO.FileAccess, System.IO.FileShare, int, System.IO.FileOptions, string, bool, bool, bool)
System.IO.StreamReader.StreamReader(string, System.Text.Encoding, bool, int, bool)
System.IO.StreamReader.StreamReader(string, System.Text.Encoding)
System.IO.File.InternalReadAllLines(string, System.Text.Encoding)
System.CommandLine.Parsing.StringExtensions.ExpandResponseFile(string, System.CommandLine.Parsing.ResponseFileHandling)
System.CommandLine.Parsing.StringExtensions.Tokenize.__ReadResponseFile|4_2(string, int, ref System.CommandLine.Parsing.StringExtensions.<>c__DisplayClass4_0)
System.CommandLine.Parsing.StringExtensions.Tokenize(System.Collections.Generic.IReadOnlyList<string>, System.CommandLine.CommandLineConfiguration)
System.CommandLine.Parsing.Parser.Parse(System.Collections.Generic.IReadOnlyList<string>, string)
...
[Call Stack Truncated]
Escaping the @ with a \ at least stops the subsystem regarding it as a response file.
However, this is not a fix but a workaround, you'll need to remove the \ from the argument in your code.
FYI many common tools use libiberty's expandargv or a compatible implementation. They check for the leading @ after all escaping/quoting is resolved and don't provide any way to prevent an argument starting with @ from being treated as a response file. They do however silently leave the original argument alone if the response file does not exist or cannot be read.
If you are passing paths and not arbitrary strings like passwords, you can "escape" them by prepending ./ when the first character is @ as such paths are always relative.