The following code always shows path manipulation problem. How to resolve it ?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Text.RegularExpressions;
namespace PathManipulation
{
class Program
{
public string dir = null;
public void someFunction(string fileName)
{
// File.Delete(Regex.Replace(dir + fileName, #"\..\", String.Empty));
if (!(dir.IndexOf("//") >= 0) || !Regex.IsMatch(dir, "System32"))
{
String p = Regex.Replace(dir, #"..\", string.Empty);
DirectoryInfo di = new DirectoryInfo(p);
FileInfo[] fi = di.GetFiles();
if (fi.Length > 0)
{
for (int i = 0; i < fi.Length; i++)
{
if (fi[i].ToString().Equals(fileName))
{
Console.WriteLine(fi[i].ToString());
fi[i].Delete();
}
}
File.Delete(dir + fileName);
}
}
else
{
return;
}
}
static void Main(string[] args)
{
Program p = new Program();
p.dir = args[0];
p.someFunction(args[1]);
}
}
}
Yes, you break the flow of data so that the end user is not able to specify the file to be deleted.
For instance:
public void someFunction(int fileIndex){
...
if (fileIndex == 0){
File.Delete( "puppies.txt" );
}
else if (fileIndex == 1){
File.Delete( "kittens.txt" );
}
else {
throw new IllegalArgumentException( "Invalid delete index" );
}
}
That's an extreme way to solve the problem, but it does not allow the end user to delete ANYTHING the developer didn't intend.
Your data validation check:
if (!(dir.IndexOf("//") >= 0) || !Regex.IsMatch(dir, "System32"))
is weak. This is referred to as "blacklisting" and the attacker only has to figure out a pattern that is missed by your checks. So, #"C:\My Documents" for instance.
Instead, you should consider a "whitelisting" approach. Take a look at https://www.owasp.org/index.php/Data_Validation#Accept_known_good for a pretty thorough example. It doesn't address path injection directly. You simply have to think hard about what files/directories you expect to receive. Throw an error if the input deviates from that. With a little testing you will create a good whitelist.
Related
I have a code in String and I need to select only the method that I want, for example:
"public void GetEntities(List<PublisherBO> _publishers, WebResourceBO _webResourceBO, SqlBO _sqlBO) {
List<EntityBO> entities = new List<EntityBO>();
List<EntityMetadata> results = entityDAO.GetAllEntities();
EntitiesMetadata = results;
entities = ConvertEntities(results);
Data = entities;
}
public void ResetConnection() {
sqlOpen = false;
dynamicsOpen = false;
if (Service != null) {
if (Service.OrganizationWebProxyClient != null)
Service.OrganizationWebProxyClient.Close();
Service.Dispose();
}
}"
And I want to select only this:
"public void ResetConnection() {
sqlOpen = false;
dynamicsOpen = false;
if (Service != null) {
if (Service.OrganizationWebProxyClient != null)
Service.OrganizationWebProxyClient.Close();
Service.Dispose();
}
}"
I know that I have to use IndexOf Methods, the complicated is consider the { } because I know that I need to finish the select on code in } but how to consider the others { } inside this block of code and precisely select all method.
And a note: I cannot divide this in lines, because some codes have only 1 line (javascript)
This is a regex pattern that will work to match code blocks. It can fail if there are unclosed {} inside of strings.
(.*?){(?:[^{}]+|{(?<n>)|}(?<-n>))+(?(n)(?!))*}
Regex Storm
Here is a working example in C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace ConsoleApp1
{
class Program
{
static void Main (string[] args)
{
var text = #"public void GetEntities(List<PublisherBO> _publishers, WebResourceBO _webResourceBO, SqlBO _sqlBO) {
List<EntityBO> entities = new List<EntityBO>();
List<EntityMetadata> results = entityDAO.GetAllEntities();
EntitiesMetadata = results;
entities = ConvertEntities(results);
Data = entities;
}
public void ResetConnection() {
sqlOpen = false;
dynamicsOpen = false;
if (Service != null) {
if (Service.OrganizationWebProxyClient != null)
Service.OrganizationWebProxyClient.Close();
Service.Dispose();
}
}";
var matches = Regex.Matches(text, "(.*?){(?:[^{}]+|{(?<n>)|}(?<-n>))+(?(n)(?!))*}");
if (matches.Count > 0)
{
}
}
}
}
Here is a link to regex storm showing the original pattern matching C# code as well as JS code with various syntax
Regex Storm with C# and JS
I'm not so expert on C# but i tried to do my best ,
this is a small console application that should get 2 arg2 ( by passing args to the exe or by console input) i have 2 issue with it and i can't find any other solution
Merging the files is not in the correct order, if the files name has
letters included. ex.
(1.docx , 2.docx , 3.docx ) it work => result.docx(1,2,3)
(1test.docx , 2rice.docx , 3john.docx ) => result.docx(3,1,2)
Can't get WINWORD.exe to close after its the appliaction is
completed
PS: This exe is being called by PHP line CMD.EXE
i tried all possible commands to release com objects then close application ,
what is my mistake here? how to optimize the code correctly?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Office.Interop.Word;
using System.Reflection;
using System.Runtime.InteropServices;
using System.IO;
namespace DocEngine
{
public class Parameter
{
public string Name;
public string Value;
// Note we need to give a default constructor when override it
public Parameter()
{
}
}
class Program
{
public static void MergeDocuments(string fileName, List<string> documentFiles)
{
_Application oWord = new Microsoft.Office.Interop.Word.Application();
_Document oDoc = oWord.Documents.Add();
Selection oSelection = oWord.Selection;
foreach (string documentFile in documentFiles)
{
_Document oCurrentDocument = oWord.Documents.Add(documentFile);
CopyPageSetup(oCurrentDocument.PageSetup, oDoc.Sections.Last.PageSetup);
oCurrentDocument.Range().Copy();
oSelection.PasteAndFormat(WdRecoveryType.wdFormatOriginalFormatting);
if (!Object.ReferenceEquals(documentFile, documentFiles.Last()))
oSelection.InsertBreak(WdBreakType.wdSectionBreakNextPage);
}
oDoc.SaveAs(fileName, WdSaveFormat.wdFormatDocumentDefault);
oDoc.Close();
//TODO: release objects, close word application
//Marshal.ReleaseComObject(oSelection);
//Marshal.ReleaseComObject(oDoc);
//Marshal.ReleaseComObject(oWord);
Marshal.FinalReleaseComObject(oSelection);
Marshal.FinalReleaseComObject(oDoc);
Marshal.FinalReleaseComObject(oWord);
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(oWord);
System.Runtime.InteropServices.Marshal.ReleaseComObject(oSelection);
System.Runtime.InteropServices.Marshal.ReleaseComObject(oDoc);
System.Runtime.InteropServices.Marshal.ReleaseComObject(oWord);
oSelection = null;
oDoc = null;
oWord = null;
// A good idea depending on who you talk to...
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
}
public static void CopyPageSetup(PageSetup source, PageSetup target)
{
target.PaperSize = source.PaperSize;
//target.Orientation = source.Orientation; //not working in word 2003, so here is another way
if (!source.Orientation.Equals(target.Orientation))
target.TogglePortrait();
target.TopMargin = source.TopMargin;
target.BottomMargin = source.BottomMargin;
target.RightMargin = source.RightMargin;
target.LeftMargin = source.LeftMargin;
target.FooterDistance = source.FooterDistance;
target.HeaderDistance = source.HeaderDistance;
target.LayoutMode = source.LayoutMode;
}
static void Main(string[] args)
{
if (args == null || args.Length == 0)
{
Console.WriteLine("Enter Path:");
Parameter parameter1 = new Parameter
{
Name = "dir",
Value = Console.ReadLine()
};
Console.WriteLine("FileName without ext:");
Parameter parameter2 = new Parameter
{
Name = "fileName",
Value = Console.ReadLine()
};
Console.WriteLine("Thank you! ");
Console.WriteLine("Test parameter1: [{0}] = [{1}]", parameter1.Name, parameter1.Value);
Console.WriteLine("Test parameter2: [{0}] = [{1}]", parameter2.Name, parameter2.Value);
try
{
List<string> result = Directory.EnumerateFiles(parameter1.Value, "*.doc", SearchOption.AllDirectories).Union(Directory.EnumerateFiles(parameter1.Value, "*.docx", SearchOption.AllDirectories)).ToList();
var filename = Path.Combine(parameter1.Value, parameter2.Value);
MergeDocuments(filename, result);
}
catch (UnauthorizedAccessException UAEx)
{
Console.WriteLine(UAEx.Message);
}
catch (PathTooLongException PathEx)
{
Console.WriteLine(PathEx.Message);
}
}
else
{
//args = new string[2];
string sourceDirectory = args[0];
string filename1 = args[1];
try
{
List<string> result = Directory.EnumerateFiles(sourceDirectory, "*.doc", SearchOption.AllDirectories).Union(Directory.EnumerateFiles(sourceDirectory, "*.docx", SearchOption.AllDirectories)).ToList();
var filename = Path.Combine(sourceDirectory, filename1);
MergeDocuments(filename, result);
}
catch (UnauthorizedAccessException UAEx)
{
Console.WriteLine(UAEx.Message);
}
catch (PathTooLongException PathEx)
{
Console.WriteLine(PathEx.Message);
}
}
}
}
}
You don't need to make any of those COM calls or explicit GC calls, and you don't need to explicitly set things to null. You just need to call Application.Quit.
I am currently using Renci SSH.NET to upload files and folders to a Unix Server using SFTP, and creating directories using
sftp.CreateDirectory("//server/test/test2");
works perfectly, as long as the folder "test" already exists. If it doesn't, the CreateDirectory method fails, and this happens everytime when you try to create directories containing multiple levels.
Is there an elegant way to recursively generate all the directories in a string? I was assuming that the CreateDirectory method does that automatically.
There's no other way.
Just iterate directory levels, testing each level using SftpClient.GetAttributes and create the levels that do not exist.
static public void CreateDirectoryRecursively(this SftpClient client, string path)
{
string current = "";
if (path[0] == '/')
{
path = path.Substring(1);
}
while (!string.IsNullOrEmpty(path))
{
int p = path.IndexOf('/');
current += '/';
if (p >= 0)
{
current += path.Substring(0, p);
path = path.Substring(p + 1);
}
else
{
current += path;
path = "";
}
try
{
SftpFileAttributes attrs = client.GetAttributes(current);
if (!attrs.IsDirectory)
{
throw new Exception("not directory");
}
}
catch (SftpPathNotFoundException)
{
client.CreateDirectory(current);
}
}
}
A little improvement on the code provided by Martin Prikryl
Don't use Exceptions as a flow control mechanism. The better alternative here is to check if the current path exists first.
if (client.Exists(current))
{
SftpFileAttributes attrs = client.GetAttributes(current);
if (!attrs.IsDirectory)
{
throw new Exception("not directory");
}
}
else
{
client.CreateDirectory(current);
}
instead of the try catch construct
try
{
SftpFileAttributes attrs = client.GetAttributes(current);
if (!attrs.IsDirectory)
{
throw new Exception("not directory");
}
}
catch (SftpPathNotFoundException)
{
client.CreateDirectory(current);
}
Hi I found my answer quite straight forwared. Since I found this old post, I thought others might also stumble upon it. The accepted answer is not that good, so here is my take. It does not use any counting gimmicks, so I think it's a little more easy to understand.
public void CreateAllDirectories(SftpClient client, string path)
{
// Consistent forward slashes
path = path.Replace(#"\", "/");
foreach (string dir in path.Split('/'))
{
// Ignoring leading/ending/multiple slashes
if (!string.IsNullOrWhiteSpace(dir))
{
if(!client.Exists(dir))
{
client.CreateDirectory(dir);
}
client.ChangeDirectory(dir);
}
}
// Going back to default directory
client.ChangeDirectory("/");
}
FWIW, here's my rather simple take on it. The one requirement is that the server destination path is seperated by forward-slashes, as is the norm. I check for this before calling the function.
private void CreateServerDirectoryIfItDoesntExist(string serverDestinationPath, SftpClient sftpClient)
{
if (serverDestinationPath[0] == '/')
serverDestinationPath = serverDestinationPath.Substring(1);
string[] directories = serverDestinationPath.Split('/');
for (int i = 0; i < directories.Length; i++)
{
string dirName = string.Join("/", directories, 0, i + 1);
if (!sftpClient.Exists(dirName))
sftpClient.CreateDirectory(dirName);
}
}
HTH
A little modification on the accepted answer to use spans.
It's probably utterly pointless in this case, since the overhead of the sftp client is far greater than copying strings, but it can be useful in other similiar scenarios:
public static void EnsureDirectory(this SftpClient client, string path)
{
if (path.Length is 0)
return;
var curIndex = 0;
var todo = path.AsSpan();
if (todo[0] == '/' || todo[0] == '\\')
{
todo = todo.Slice(1);
curIndex++;
}
while (todo.Length > 0)
{
var endOfNextIndex = todo.IndexOf('/');
if (endOfNextIndex < 0)
endOfNextIndex = todo.IndexOf('\\');
string current;
if (endOfNextIndex >= 0)
{
curIndex += endOfNextIndex + 1;
current = path.Substring(0, curIndex);
todo = path.AsSpan().Slice(curIndex);
}
else
{
current = path;
todo = ReadOnlySpan<char>.Empty;
}
try
{
client.CreateDirectory(current);
}
catch (SshException ex) when (ex.Message == "Already exists.") { }
}
}
my approach is more sufficient and easier to read and maintain
public static void CreateDirectoryRecursively(this ISftpClient sftpClient, string path)
{
// Consistent forward slashes
var separators = new char[] { Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar };
string[] directories = path.Split(separators);
string currentDirectory = "";
for (int i = 1; i < directories.Length; i++)
{
currentDirectory = string.Join("/", currentDirectory, directories[i]);
if (!sftpClient.Exists(currentDirectory))
{
sftpClient.CreateDirectory(currentDirectory);
}
}
}
Hello I am having a strange error with using pipes to communicate between two process. In short everything is working fine with the program except that the client side never closes the stream, meaning the server's streamReader.readLine never returns null, causing the sever process to never terminate. I'm convinced this is a simple issue but I and struggling to find a answer. Here is some relevant code:
Server Side:
using (StreamReader sr = new StreamReader(clientServer))
{
// Display the read text to the console
string temp;
int count = 0;
while ((temp = sr.ReadLine()) != null)
{
if (count == 0)
{
Console.WriteLine("==========Parent Process found text:like==========");
}
Console.WriteLine(temp);
count++;
}
Console.WriteLine("out of while loop");
}
Client Project:
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Pipes;
class PipeClient
{
static void Main(string[] args)
{
try
{
if (args.Length < 3)
{
Console.WriteLine("Invalid number of commandline arguments");
}
else
{
List<string> inputList = new List<string>();
List<string> foundMatchList = new List<string>();
using (PipeStream pipeClientIn =
new AnonymousPipeClientStream(PipeDirection.In, args[0]))
{
using (StreamReader sr = new StreamReader(pipeClientIn))
{
// Display the read text to the console
string temp;
int count = 0;
while ((temp = sr.ReadLine()) != null)
{
if (count == 0)
{
Console.WriteLine("==========Client Process Read Text:==========");
}
Console.WriteLine(temp);
inputList.Add(temp);
count++;
}
foreach (var curtString in inputList)
{
if (curtString.Contains(args[2]))
{
foundMatchList.Add(curtString);
}
}
}
//Console.WriteLine("released sr");
}
// Console.WriteLine("released pipeClientIn");
using (PipeStream pipeClientOut =
new AnonymousPipeClientStream(PipeDirection.Out, args[1]))
{
using (StreamWriter sw = new StreamWriter(pipeClientOut))
{
sw.AutoFlush = true;
foreach (var match in foundMatchList)
{
sw.WriteLine(match);
}
}
}
//Console.WriteLine("released pipeClientOut");
}
}
catch (Exception e)
{
/* if (args.Length == 0)
Console.WriteLine("no arguments");
foreach(String s in args)
{
Console.Write("{0} ", s);
}*/
Console.WriteLine(e.Message);
}
}
}
I've tested and can confirm that the client process terminates.
I attempted to manually flush and close the Client StreamWriter but this did not work.
My overall question is: Why am I never seeing the the "out of while loop" message? And how can fix my client so that it will end the stream?
Did you call clientServer.DisposeLocalCopyOfClientHandle()?
from msdn
The DisposeLocalCopyOfClientHandle method should be called after the
client handle has been passed to the client. If this method is not
called, the AnonymousPipeServerStream object will not receive notice
when the client disposes of its PipeStream object.
hope this helps
Description
Download multiple files using webclient's DownloadFileAsync and utilizing a text file for URL input for download.
Problem
The approach that I have used won't download files at all. Just runs and does nothing. It fills the list array then quits the program without downloading a single file. I have googled for solutions but come up shorthanded. Then attempted to search for a solution in the database here with same results. Any help is appreciated.
Questions
Why does this approach not work?
What can I do to improve this and learn from this.
Code
DownloadClass.cs
using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Net;
using System.Threading;
using System.Windows.Forms;
namespace ThreadTest
{
class DownloadClass
{
public struct download
{
public static string URL { get; set; }
public static string file { get; set; }
public static string[] link;
public static int downloadcount;
}
public static List<string> list = new List<string>();
public static WebClient wc = new WebClient();
public static void Download()
{
int count = 0;
download.URL = list[0];
Uri URI = new Uri(download.URL);
UriBuilder uri = new UriBuilder(URI);
download.link = uri.Path.ToLower().Split(new char[] { '/' });
count = 0;
// Find file
foreach (string abs in download.link)
{
count++;
if (abs.ToLower().Contains(".html") || abs.ToLower().Contains(".exe") || abs.ToLower().Contains(".txt"))
{
try
{
download.file = download.link[count];
wc.Proxy = null;
wc.DownloadFileCompleted += new AsyncCompletedEventHandler(wc_DownloadFileCompleted);
wc.DownloadFileAsync(URI, Application.StartupPath + "\\" + download.file);
break;
}
catch (Exception)
{ }
}
}
}
public static void BeginDownload()
{
new Thread(Download).Start();
}
public static void wc_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
int count = 0;
download.downloadcount++;
download.URL = list[0];
Uri URI = new Uri(download.URL);
UriBuilder uri = new UriBuilder(URI);
download.link = uri.Path.ToLower().Split(new char[] { '/' });
count = 0;
// Find file
foreach (string abs in download.link)
{
count++;
if (abs.ToLower().Contains(".html") || abs.ToLower().Contains(".exe") || abs.ToLower().Contains(".txt"))
{
try
{
download.file = download.link[count];
}
catch (Exception)
{ }
}
}
list.RemoveAt(0);
if (list.Count > 0)
{
wc.DownloadFileAsync(URI, list[download.downloadcount], Application.StartupPath + "\\" + download.file);
}
else
{
Console.WriteLine("Downloading is done.");
Environment.Exit(0);
}
}
}
}
Program.cs (Main Class)
using System;
using System.IO;
using System.Collections.Generic;
using System.Windows.Forms;
namespace ThreadTest
{
class Program
{
static void Main(string[] args)
{
if (args.Length < 1)
{
Console.WriteLine("Usage: {0} <download txtfile>", Environment.GetCommandLineArgs()[0]);
Environment.Exit(0);
}
int counter = 0;
string line;
string format = string.Format("{0}\\{1}", Application.StartupPath, args[0]);
// Read the file line by line.
using(StreamReader file = new StreamReader(format))
{
while ((line = file.ReadLine())!= null)
{
// Store urls in a list.
DownloadClass.list.Add(line);
counter++;
}
}
DownloadClass.BeginDownload();
}
}
}
Besides being bad design there are lots of issues that lead to your code not (or nor correctly working).
You need to make sure that you application lives while it downloads something. Your current app quits right away (you have to wait for the downloading to complete in your main).
You application may download the same file multiple times but not download others at all (You need to completely lock object when they are used in an async=multithreading way like here when accessing static objects) BTW: Don't use static objects at all to avoid that in the first place.
Even if 2 is corrected it may still download the same file multiple times into the same filename and thus fail.
As long as you have no knowledge about multithreading I'd recommend you use the synchoneous methods to avoid all those problems.