SecurityElement.IsValidText returns true on "&" ... why? - c#

I have a TextBox that is eventually saved in a xml node. I am using the SecurityElement.Escape(string2Escape) to escape the invalid characters before saving the xml.
Problem: I tried using the IsValidText to test if i need to run the escape method, but it returns ''' and '&' as valid but then when you save the xml the system barfs because they are, in fact, not valid. It seems to only return false on '<' or '>'.
Simple solution, remove the check, but my question is why would this be the case?
The following is my failing code:
private string EscapeXML(string nodeText)
{
if (!SecurityElement.IsValidText(nodeText))
{
return SecurityElement.Escape(nodeText);
}
return nodeText;
}

Here's what I got from Reflector.
This can explain why it's behaving the way it's behaving. I don't see any method in SecurityElement that does what your are looking for but it is simple enough to implement one yourself, maybe as an extension method.

The SecurityElement constructor is apparently already doing some escaping on its own (including the "&" character), so the IsValidText seems to be only checking for the characters the constructor is not already taking care of.
As a consequence, it doesn't look safe to use the SecurityElement's IsValidText/Escape combo, unless you're using SecurityElement to build the whole xml.
I'll try to explain better with an example:
using System;
using System.Diagnostics;
using System.Security;
class MainClass
{
public static void Main (string[] args)
{
// the SecurityElement constructor escapes the & all by itself
var xmlRoot =
new SecurityElement("test","test &");
// the & is escaped without SecurityElement.Escape
Console.WriteLine (xmlRoot.ToString());
// this would throw an exception (the SecurityElement constructor
// apparently can't escape < or >'s
// var xmlRoot2 =
// new SecurityElement("test",#"test & > """);
// so this text needs to be escaped before construction
var xmlRoot3 =
new SecurityElement("test",EscapeXML(#"test & > """));
Console.WriteLine (xmlRoot3.ToString());
}
private static string EscapeXML(string nodeText)
{
return (SecurityElement.IsValidText(nodeText))?
nodeText :
SecurityElement.Escape(nodeText);
}
}

Related

System.CommandLine parsed values don't match input

I am trying to use System.CommandLine and I haven't been able to get my handler to see any of the values that I'm passing in. I've tried the simplest command line program just to see if any values make it through and so far I haven't been successful. I am targeting .NET 4.7.2 and I'm using System.CommandLine 2.0.0-beta1.20574.7
using System;
using System.CommandLine;
using System.CommandLine.Invocation;
static class Program
{
public static void Main(string[] args)
{
var rootCommand = new RootCommand
{
new Option("--continue", "continue option")
};
rootCommand.Description = "Testing System.CommandLine";
rootCommand.Handler = CommandHandler.Create<bool>
((willContinue) => run(willContinue));
rootCommand.Invoke(args);
}
private static void run(bool willContinue)
{
Console.WriteLine(willContinue);
}
}
No matter how I call my application, I am not seeing the value of willContinue come across as true.
myapp.exe --continue -> False
myapp.exe --cont -> Unrecognized command or argument '--cont' (my options are at least getting recognized)
myapp.exe --continue true -> Unrecognized command or argument 'true'
myapp.exe --help ->
myapp:
Testing System.CommandLine
Usage:
myapp [options]
Options:
--continue continue option
--version Show version information
-?, -h, --help Show help and usage information
You need to fix 2 things:
add the option type, which is bool
change the name of the option to match the parameter name
the following command works:
var rootCommand = new RootCommand
{
new Option<bool>("--willContinue", "continue option")
};
and call it like so
myapp.exe --willContinue true
the option name and parameter name don't always have to match-up, but in this case it doesn't work because 'continue' is a reserved word
I wanted to add an answer to be very clear about exactly what resolved my problem
using System;
using System.CommandLine;
using System.CommandLine.Invocation;
static class Program
{
public static void Main(string[] args)
{
var rootCommand = new RootCommand
{
new Option("--willContinue", "continue option")
// ^This option name
};
rootCommand.Description = "Testing System.CommandLine";
rootCommand.Handler = CommandHandler.Create<bool>
((WiLLCoNtInUe) => run(WiLLCoNtInUe));
// ^ HAS to match this parameter name where the command handler is created.
// but does not have to match case
rootCommand.Invoke(args);
}
private static void run(bool canBeSomethingElse)
// Because of how this is called ^ this does not have to match
{
Console.WriteLine(canBeSomethingElse);
}
}
Because the Argument/Option/Command/anything else that can be added to a Command object has to match the name of the parameter used when creating the CommandHandler, the names used can't have spaces, begin with numbers, or use a C# keyword (not having spaces is not a problem for most items because it would be silly/impossible to have an option --will continue, but with arguments you don't have to put the name of the argument into your command line call because it is listed in the usage as <argument name> and the argument is read in by position, so I was wanting to use an argument name like <file directory>, but that doesn't work because you can't have a variable name with spaces in it)

c# File.Exists always return false using value property

During debugging I found something annoying.
I have a file existing on my drive, I'm wondering why if I use the file exists function it always returns false, using property value. I try also in Immediate Window here are the results
ACGateLoginSystem.MAP_PATH == #"‪D:\Capture001.png" | true
?File.Exists(ACGateLoginSystem.MAP_PATH) | false
?File.Exists("D:\\Capture001.png") | true
I'm using windows 10 latest build, and visual studio 2017.
Following is working for me.
namespace ConsoleApplication1
{
class LoginSystem
{
public string MAP_PATH { get; set; }
}
class Program
{
static void Main(string[] args)
{
LoginSystem ACGateLoginSystem = new LoginSystem();
ACGateLoginSystem.MAP_PATH = #"D:\1.png";
if (File.Exists(ACGateLoginSystem.MAP_PATH))
Console.WriteLine("File Exists");
if (File.Exists("D:\\1.png"))
Console.WriteLine("File Exists - with direct path");
Console.ReadLine();
}
}
}
Output:
The backslash character \ is a special character in C# (and any C-like language). It is used in conjunction with a second one to define special character. Thus, this would work:
File.Exists("D:\\Capture001.png")
and this should work
File.Exists(#"D:\Capture001.png")
and this won't work
File.Exists("D:\Capture001.png")

Implementing a command line interpreter

In terminal or cmd, you can write commands, in which there is a main command and then sub-commands, or arguments and stuff...like this:
cd Desktop\Folder
lst
Format E: /fs:FAT32
I want to create a C# console application that could execute predefined commands like this, but which could also split up main commands and sub-commands, in which some could be optional and some not. I have tried just taking all as string and then splitting it to array and creating if(s) and switch and cases, but it looks really bad and hardly manageable. I'm sure that in the OS's terminal or cmd it's build in another way. Could you help me understand the basic structure of such an application?
Here, have a look at this concept.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SharpConsole
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Welcome to SharpConsole. Type in a command.");
while (true)
{
Console.Write("$ ");
string command = Console.ReadLine();
string command_main = command.Split(new char[] { ' ' }).First();
string[] arguments = command.Split(new char[] { ' ' }).Skip(1).ToArray();
if (lCommands.ContainsKey(command_main))
{
Action<string[]> function_to_execute = null;
lCommands.TryGetValue(command_main, out function_to_execute);
function_to_execute(arguments);
}
else
Console.WriteLine("Command '" + command_main + "' not found");
}
}
private static Dictionary<string, Action<string[]>> lCommands =
new Dictionary<string, Action<string[]>>()
{
{ "help", HelpFunc },
{ "cp" , CopyFunc }
};
private static void CopyFunc(string[] obj)
{
if (obj.Length != 2) return;
Console.WriteLine("Copying " + obj[0] + " to " + obj[1]);
}
public static void HelpFunc(string[] args)
{
Console.WriteLine("===== SOME MEANINGFULL HELP ==== ");
}
}
}
The basic idea is to generalize the idea of a command. We have a Dictionary, where the key is a string (the command's name), and the value you get from the dictionary is a function of type Action<string[]>. Any function which has the signature void Function(string[]) can be used as this type. Then, you can set up this dictionary with a bunch of commands and route them to the functions you want. Each of these functions will receive an array of optional arguments. So here, the command "help" will be routed to the HelpFunc(). And the "cp" command e.g. will receive an array of filenames. The parsing of the command is always the same. We read a line, split it a space. The first string is the program's name, command_main here. If you skip the first string, you'll get an enumeration of all the other subcommands or switches you typed in. Then, a lookup in the dictionary is being done to see if there is such a command. If yes, we get the function and execute it with the arguments. If not, you should display "command not found" or something. All in all, this exercise can be minimized to looking up a function in a dictionary of possible command strings, then executing it. So a possible output is
Welcome to SharpConsole. Type in a command.
$ help
===== SOME MEANINGFULL HELP ====
$ cp file1 otherfile2
Copying file1 to otherfile2
$ python --version
Command 'python' not found
$ ...
LXSH
It's a command interpreter similar to CMD or Bash.
We've distributed it under MIT license, a shell with some functionalities in C# (.NET Core). You can contribute if you wish on
GitHub.
To solve the problem of matching a given token (part of the command line) with a builtin or a command, we use a dictionary.
However, we don't index the programs in the path for the moment. We just combine the name of the program with all the paths in the %PATH% variable.
Capture input
Expand environment variables, expand aliases
Try to match a builtin and run it if there is a match
Try to match with a program in %PATH% / $PATH
Run the program or display error
While you are unlikely to find the internal working of CMD (because it's closed source), you can find easily unix shell (bash, sh, zsh, etc..) information.
Links:
Bash Reference
Zsh Reference
TCSH Reference

Using an alias for Environment.NewLine

Current best practice is to use Environment.NewLine in your code to, well, start a new line. I would like to be able to use an alias or overloaded operator in my code so that it is more concise.
Instead of this:
MessageBox.Show("My first line here" + Environment.NewLine + "My second line here");
I would like to have something like this:
MessageBox.Show("My first line here" + NL + "My second line here");
How can I easily set this up one time as an IDE setting, or for a whole project/namespace?
An alias or overloaded operator is that comes to mind, but not sure if there is a good way of doing a global alias that is more concise than Environment.NewLine, and I've never done an overloaded operator before, so not familiar with the ins and outs of that.
Simple shortening method. Pop this class in one of your utility assemblies:
namespace MyCompany
{
public static class E
{
public static readonly string NL = System.Environment.NewLine;
}
}
then you can happily use it as such:
using MyCompany;
MessageBox.Show("My first line here" + E.NL + "My second line here");
Might I suggest that you use an extension method instead?
public static class StringExtensions
{
public static string NextLine(this string s, string next)
{
return s + Environment.NewLine + next;
}
public static string NextLine(this string s)
{
// just add a new line with no text
return s + Environment.NewLine;
}
}
Usage:
var lines = "My first line here".NextLine("My second line here.")
.NextLine("third line").NextLine();
Of course, you can call it NL if you wish -- might not be clear, though.
use StringBuilder.AppendLine() in cases with few Environment.NewLine:
var sb = new StringBuilder();
sb.AppendLine("My first line here");
sb.AppendLine("My second line here");
MessageBox.Show(sb.ToString());
Write a class to provide the value of Environment.NewLine as a member, as Jesse C. Slicer has already suggested:
namespace MyNamespace
{
public static class Env
{
public static readonly string NL = Environment.NewLine;
}
}
Then write the following using directive:
using E = MyNamespace.Env;
You can add this using directive to your default new class template and any other templates you use (new struct, new interface, etc.).
Here's where the new class template is on my machine, as an example to get you started:
C:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\IDE\ItemTemplates\CSharp\Code\1033
Once this is done, you should be able to write E.NL in place of Environment.NewLine everywhere you want.
using static System.Environment;
Then you can just use it as NewLine
Alias won't work - you can alias a namespace or a type, but not a property of a type. So this works:
using NL = System.Environment;
class Program
{
static void Main(string[] args)
{
var s = NL.NewLine;
}
}
But this doesn't:
// returns: The type name 'NewLine' does not
// exist in the type 'System.Environment' error
using NL = System.Environment.NewLine;
Overloaded operator is an interesting idea, but then you'll have to use something other than a String. Usually people create a struct which can take a base string value and then overload the operators. Not worth the pain if all you want to do is replace the Environment.NewLine. You're better off to use a static extension as suggested by others.
Another alternative (if you're dead set on using NL) is to descend all the classes in your framework off of a common parent class which can have the following property:
public class BaseParentClass
{
public string NL
{
get { return System.Environment.NewLine; }
}
}
Then in the code for all the descendant classes, your code will look simply like:
public class ChildOfBaseParent
{
public void Show_A_Message()
{
MessageBox.Show("My first line here" + NL + "My second line here");
}
}
Of course if your classes do not descend off of a common parent, you will have to refactor the code base for this piece of convenience. You will need to create a parallel System.Windows.Forms.Form parent for winform classes to have this same behavior.
But definitely worth the pain if you have a lot of string concatenations involving NL...
Adding to #abatishchev response you can do nice things with the StringBuilder Class.
StringBuilder builder = new StringBuilder();
builder.Append("List:");
builder.AppendLine();
builder.Append("1. Boat")
builder.Append("2. Car").AppendLine();
builder.Replace("Boat", "Jet");

Is it possible to serialize a C# code block?

I'm using C# with .NET 3.5. Is it possible to serialize a block of code, transmit it somewhere, deserialize it, and then execute it?
An example usage of this would be:
Action<object> pauxPublish = delegate(object o)
{
if (!(o is string))
{
return;
}
Console.WriteLine(o.ToString());
};
Transmitter.Send(pauxPublish);
With some remote program doing:
var action = Transmitter.Recieve();
action("hello world");
My end goal is to be able to execute arbitrary code in a different process (which has no prior knowledge of the code).
YES!!!
We have done this for a very real case of performance. Doing this at runtime or using a DSL was not an option due to performance.
We compile the code into an assembly, and rip the IL out of the method. We then get all the metadata associated with this method and serialize the whole mess via XML, compress it, and put it in our database.
At re-hydration time, we re-constitute the IL with the metadata using the DynamicMethod class, and execute it.
We do this because of speed. We have thousands of little blocks of code. Unfortunately, to compile a block of code and run it on the fly takes at least 250 ms, which is way too slow for us. We took this approach, and it is working REALLY well. At run-time, it takes an unmeasurable amount of time to reconstitute the method and run it.
Only thing to keep an eye on... Signed assemblies and Unsigned assemblies cannot mix the serialized method data.
You could try to use IronPython in your project. It's trivial to do what you are asking in Python. The Python code could call your C# methods. As for security, you could execute the code in a restricted environment of some kind (one example is RestrictedPython).
Generally speaking that sounds like a really bad idea and a big security hole.
You don't want another process to execute any code. Understand what you really need another process to do and build a little DSL around it.
You could also send it as a string then use the CodeDomProvider to compile it, same result. I have an example bit of code thus:
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using Microsoft.CSharp;
namespace DynamicCodeApplication
{
class azCodeCompiler
{
private List<string> assemblies;
public azCodeCompiler()
{
assemblies = new List<string>();
scanAndCacheAssemblies();
}
public Assembly BuildAssembly(string code)
{
CodeDomProvider prov = CodeDomProvider.CreateProvider("CSharp");
string[] references = new string[] { }; // Intentionally empty, using csc.rsp
CompilerParameters cp = new CompilerParameters(references)
{
GenerateExecutable = false,
GenerateInMemory = true
};
string path = System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory();
cp.CompilerOptions = "#" + path + #"\csc.rsp";
CompilerResults cr = prov.CompileAssemblyFromSource(cp, code);
foreach (CompilerError err in cr.Errors)
{
Console.WriteLine(err.ToString());
}
return cr.CompiledAssembly;
}
public object ExecuteCode(string code,
string namespacename, string classname,
string functionname, bool isstatic, params object[] args)
{
object returnval = null;
Assembly asm = BuildAssembly(code);
object instance = null;
Type type = null;
if (isstatic)
{
type = asm.GetType(namespacename + "." + classname);
}
else
{
instance = asm.CreateInstance(namespacename + "." + classname);
type = instance.GetType();
}
MethodInfo method = type.GetMethod(functionname);
returnval = method.Invoke(instance, args);
return returnval;
}
private void scanAndCacheAssemblies()
{
/*
foreach (string str in Directory.GetFiles(#"C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727"))
{
if (str.Contains(".dll"))
{
foreach (string st in str.Split(new char[] { '\\' }))
{
if (st.Contains(".dll"))
{
assemblies.Add(st);
}
}
}
}
* */
assemblies.Add("Accessibility.dll");
assemblies.Add("AspNetMMCExt.dll");
assemblies.Add("cscompmgd.dll");
assemblies.Add("CustomMarshalers.dll");
assemblies.Add("IEExecRemote.dll");
assemblies.Add("IEHost.dll");
assemblies.Add("IIEHost.dll");
assemblies.Add("Microsoft.Build.Conversion.dll");
assemblies.Add("Microsoft.Build.Engine.dll");
assemblies.Add("Microsoft.Build.Framework.dll");
assemblies.Add("Microsoft.Build.Tasks.dll");
assemblies.Add("Microsoft.Build.Utilities.dll");
assemblies.Add("Microsoft.Build.VisualJSharp.dll");
assemblies.Add("Microsoft.CompactFramework.Build.Tasks.dll");
assemblies.Add("Microsoft.JScript.dll");
assemblies.Add("Microsoft.VisualBasic.Compatibility.Data.dll");
assemblies.Add("Microsoft.VisualBasic.Compatibility.dll");
assemblies.Add("Microsoft.VisualBasic.dll");
assemblies.Add("Microsoft.VisualBasic.Vsa.dll");
assemblies.Add("Microsoft.Vsa.dll");
assemblies.Add("Microsoft.Vsa.Vb.CodeDOMProcessor.dll");
assemblies.Add("Microsoft_VsaVb.dll");
assemblies.Add("mscorlib.dll");
assemblies.Add("sysglobl.dll");
assemblies.Add("System.configuration.dll");
assemblies.Add("System.Configuration.Install.dll");
assemblies.Add("System.Data.dll");
assemblies.Add("System.Data.OracleClient.dll");
assemblies.Add("System.Data.SqlXml.dll");
assemblies.Add("System.Deployment.dll");
assemblies.Add("System.Design.dll");
assemblies.Add("System.DirectoryServices.dll");
assemblies.Add("System.DirectoryServices.Protocols.dll");
assemblies.Add("System.dll");
assemblies.Add("System.Drawing.Design.dll");
assemblies.Add("System.Drawing.dll");
assemblies.Add("System.EnterpriseServices.dll");
assemblies.Add("System.Management.dll");
assemblies.Add("System.Messaging.dll");
assemblies.Add("System.Runtime.Remoting.dll");
assemblies.Add("System.Runtime.Serialization.Formatters.Soap.dll");
assemblies.Add("System.Security.dll");
assemblies.Add("System.ServiceProcess.dll");
assemblies.Add("System.Transactions.dll");
assemblies.Add("System.Web.dll");
assemblies.Add("System.Web.Mobile.dll");
assemblies.Add("System.Web.RegularExpressions.dll");
assemblies.Add("System.Web.Services.dll");
assemblies.Add("System.Windows.Forms.dll");
assemblies.Add("System.XML.dll");
assemblies.Add("vjscor.dll");
assemblies.Add("vjsjbc.dll");
assemblies.Add("vjslib.dll");
assemblies.Add("vjslibcw.dll");
assemblies.Add("vjssupuilib.dll");
assemblies.Add("vjsvwaux.dll");
assemblies.Add("vjswfc.dll");
assemblies.Add("VJSWfcBrowserStubLib.dll");
assemblies.Add("vjswfccw.dll");
assemblies.Add("vjswfchtml.dll");
assemblies.Add("Accessibility.dll");
assemblies.Add("AspNetMMCExt.dll");
assemblies.Add("cscompmgd.dll");
assemblies.Add("CustomMarshalers.dll");
assemblies.Add("IEExecRemote.dll");
assemblies.Add("IEHost.dll");
assemblies.Add("IIEHost.dll");
assemblies.Add("Microsoft.Build.Conversion.dll");
assemblies.Add("Microsoft.Build.Engine.dll");
assemblies.Add("Microsoft.Build.Framework.dll");
assemblies.Add("Microsoft.Build.Tasks.dll");
assemblies.Add("Microsoft.Build.Utilities.dll");
assemblies.Add("Microsoft.Build.VisualJSharp.dll");
assemblies.Add("Microsoft.CompactFramework.Build.Tasks.dll");
assemblies.Add("Microsoft.JScript.dll");
assemblies.Add("Microsoft.VisualBasic.Compatibility.Data.dll");
assemblies.Add("Microsoft.VisualBasic.Compatibility.dll");
assemblies.Add("Microsoft.VisualBasic.dll");
assemblies.Add("Microsoft.VisualBasic.Vsa.dll");
assemblies.Add("Microsoft.Vsa.dll");
assemblies.Add("Microsoft.Vsa.Vb.CodeDOMProcessor.dll");
assemblies.Add("Microsoft_VsaVb.dll");
assemblies.Add("mscorlib.dll");
assemblies.Add("sysglobl.dll");
assemblies.Add("System.configuration.dll");
assemblies.Add("System.Configuration.Install.dll");
assemblies.Add("System.Data.dll");
assemblies.Add("System.Data.OracleClient.dll");
assemblies.Add("System.Data.SqlXml.dll");
assemblies.Add("System.Deployment.dll");
assemblies.Add("System.Design.dll");
assemblies.Add("System.DirectoryServices.dll");
assemblies.Add("System.DirectoryServices.Protocols.dll");
assemblies.Add("System.dll");
assemblies.Add("System.Drawing.Design.dll");
assemblies.Add("System.Drawing.dll");
assemblies.Add("System.EnterpriseServices.dll");
assemblies.Add("System.Management.dll");
assemblies.Add("System.Messaging.dll");
assemblies.Add("System.Runtime.Remoting.dll");
assemblies.Add("System.Runtime.Serialization.Formatters.Soap.dll");
assemblies.Add("System.Security.dll");
assemblies.Add("System.ServiceProcess.dll");
assemblies.Add("System.Transactions.dll");
assemblies.Add("System.Web.dll");
assemblies.Add("System.Web.Mobile.dll");
assemblies.Add("System.Web.RegularExpressions.dll");
assemblies.Add("System.Web.Services.dll");
assemblies.Add("System.Windows.Forms.dll");
assemblies.Add("System.XML.dll");
assemblies.Add("vjscor.dll");
assemblies.Add("vjsjbc.dll");
assemblies.Add("vjslib.dll");
assemblies.Add("vjslibcw.dll");
assemblies.Add("vjssupuilib.dll");
assemblies.Add("vjsvwaux.dll");
assemblies.Add("vjswfc.dll");
assemblies.Add("VJSWfcBrowserStubLib.dll");
assemblies.Add("vjswfccw.dll");
assemblies.Add("vjswfchtml.dll");
return;
}
}
}
Compile it into a separate assembly, send the assembly, have the other process load it.
You might want to consider security implications.
Update: another idea would be to generate an expression tree and use this library to serialize it:
http://www.codeplex.com/metalinq/
It is an interesting challenge, but you should probably describe why you want to do this, since there is a lot of different approaches depending on your objective. As humpohl points out, there is also some pretty serious security issues.
"Serialized code" could just be source code or a compiled assembly, depending on your requirements. You probably don't need to use a seperate code serialization format.
If you want to generate code dynamically and pass that on, you could generate code using CodeDOM and compile it. However, you most likely dont need to generate completely arbitrary code.
Another option is using the DLR, and constraining the code to execute...

Categories