Skip to content

Commit

Permalink
allow folder upload and fix crash
Browse files Browse the repository at this point in the history
  • Loading branch information
trivalik committed Jan 6, 2023
1 parent 34276f6 commit 9b32ad1
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 104 deletions.
18 changes: 7 additions & 11 deletions uploader/uploader/LocalizationBase.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,8 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace uploader
namespace uploader
{
class LocalizationBase
{
public string MainForm_DragFile = "Drag file here";
public string MainForm_DragFileOrFolder = "Drag file or folder here";
public string MainForm_More = "More";

public string SettingsForm_Title = "Settings";
Expand All @@ -19,9 +12,11 @@ class LocalizationBase
public string SettingsForm_Language = "Language";
public string SettingsForm_Save = "Save";
public string SettingsForm_Open = "Open settings file";
public string SettingsForm_DirectUpload = "Direct file upload";
public string SettingsForm_DirectUpload = "Direct file or folder upload";

public string UploadForm_Info = "File information";
public string UploadForm_FileInfo = "File information";
public string UploadForm_FolderInfo = "Folder information";
public string UploadForm_Folder = "Folder:";
public string UploadForm_Upload = "Upload";
public string UploadForm_Cancel = "Cancel";
public string UploadForm_NoApiKey = "You have not entered an API key. Please go to settings and add one.";
Expand All @@ -35,5 +30,6 @@ class LocalizationBase
public string Message_NoLink = "No permalink found in response!";
public string Message_NoSettings = "No settings file exists.";
public string Message_Saved = "Settings saved.";
public string Message_FileTooBig = "File too big.";
}
}
39 changes: 17 additions & 22 deletions uploader/uploader/MainForm.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,5 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using DarkUI.Forms;

Expand All @@ -25,12 +17,12 @@ public MainForm()
private void MainForm_Load(object sender, EventArgs e)
{
// Set working directory to exe location because of language files
Directory.SetCurrentDirectory(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location));
Directory.SetCurrentDirectory(Path.GetDirectoryName(Application.ExecutablePath));
//LocalizationHelper.Export();

LocalizationHelper.Update();

dragLabel.Text = LocalizationHelper.Base.MainForm_DragFile;
dragLabel.Text = LocalizationHelper.Base.MainForm_DragFileOrFolder;
moreLabel.Text = LocalizationHelper.Base.MainForm_More;
}

Expand All @@ -52,27 +44,30 @@ private void MainForm_DragDrop(object sender, DragEventArgs e)
{
var settings = Settings.LoadSettings();

var files = (string[])e.Data.GetData(DataFormats.FileDrop);
foreach (var file in files)
{
var uploadForm = new UploadForm(this, settings, true, file);
uploadForm.Show();
this.Hide();
var filesOrFolders = (string[])e.Data.GetData(DataFormats.FileDrop);
foreach (var fileOrFolder in filesOrFolders)
{
ProcessPath(settings, fileOrFolder, true);
}
}

}

private void MainForm_Shown(object sender, EventArgs e)
{
var settings = Settings.LoadSettings();
var args = Environment.GetCommandLineArgs();

if (args.Length == 2)
{
var file = args[1]; // Second argument because .NET puts program filename to the first
var uploadForm = new UploadForm(this, settings, false, file);
uploadForm.Show();
this.Hide();
var fileOrFolder = args[1]; // Second argument because .NET puts program filename to the first
ProcessPath(settings, fileOrFolder, false);
}
}

private void ProcessPath(Settings settings, string fileOrFolder, bool reopen)
{
var uploadForm = new UploadForm(this, settings, reopen, fileOrFolder);
uploadForm.Show();
Hide();
}
}
}
148 changes: 81 additions & 67 deletions uploader/uploader/UploadForm.cs
Original file line number Diff line number Diff line change
@@ -1,34 +1,29 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using DarkUI.Forms;
using Microsoft.CSharp.RuntimeBinder;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RestSharp;

namespace uploader
{
public partial class UploadForm : DarkForm
{
private readonly bool _reopen;
private readonly string _fileName;
private readonly string _fileOrFolderName;
private readonly MainForm _mainForm;
private readonly Settings _settings;
private Thread _uploadThread;
private RestClient _client;
private string _resource;

public UploadForm(MainForm mainForm, Settings settings, bool reopen, string fileName)
public UploadForm(MainForm mainForm, Settings settings, bool reopen, string fileOrFolderName)
{
_fileName = fileName;
_fileOrFolderName = fileOrFolderName;
_mainForm = mainForm;
_settings = settings;
_reopen = reopen;
Expand All @@ -38,40 +33,24 @@ public UploadForm(MainForm mainForm, Settings settings, bool reopen, string file

private void ChangeStatus(string text)
{
if (InvokeRequired)
{
this.Invoke(new Action(() => ChangeStatus(text)));
return;
}

statusLabel.Text = text;
this.InvokeIfRequired(() => { statusLabel.Text = text; });
}

private void Finish(bool resetText)
{
if (InvokeRequired)
{
this.Invoke(new Action(() => Finish(resetText)));
return;
}

if (resetText)
{
ChangeStatus(LocalizationHelper.Base.Message_Idle);
}
this.InvokeIfRequired(() => {
if (resetText)
{
ChangeStatus(LocalizationHelper.Base.Message_Idle);
}
uploadButton.Text = LocalizationHelper.Base.UploadForm_Upload;
uploadButton.Text = LocalizationHelper.Base.UploadForm_Upload;
});
}

private void CloseWindow()
{
if (InvokeRequired)
{
this.Invoke(new Action(() => CloseWindow()));
return;
}

this.Close();
this.InvokeIfRequired(Close);
}

private void Upload()
Expand All @@ -91,64 +70,82 @@ private void Upload()
ChangeStatus(LocalizationHelper.Base.Message_Init);
_client = new RestClient("https://www.virustotal.com");

if (!File.Exists(_fileName))
string[] paths;
if (Directory.Exists(_fileOrFolderName))
{
paths = Directory.GetFiles(_fileOrFolderName);
}
else if (File.Exists(_fileOrFolderName))
{
paths = new [] { _fileOrFolderName };
}
else
{
throw new FileNotFoundException();
}

ChangeStatus(LocalizationHelper.Base.Message_Check);
var reportRequest = new RestRequest("vtapi/v2/file/report", Method.POST);
reportRequest.AddParameter("apikey", _settings.ApiKey);
reportRequest.AddParameter("resource", Utils.GetMD5(_fileName));
var result = true;
foreach (var path in paths)
{
var reportRequest = new RestRequest("vtapi/v2/file/report", Method.POST);
reportRequest.AddParameter("apikey", _settings.ApiKey);
reportRequest.AddParameter("resource", _resource);

var reportResponse = _client.Execute(reportRequest);
var reportContent = reportResponse.Content;
dynamic reportJson = JsonConvert.DeserializeObject(reportContent);
var reportResponse = _client.Execute(reportRequest);

try
{
var reportLink = reportJson.permalink.ToString();
Process.Start(reportLink);
// Here you can see quote or api key limits: var message = reportResponse.Headers.FirstOrDefault(x => x.Name == "X-Api-Message");
if (!string.IsNullOrEmpty(reportResponse.Content))
{
try
{
var reportJson = (JObject)JsonConvert.DeserializeObject(reportResponse.Content);
Process.Start(reportJson.SelectToken("permalink").Value<string>());
continue;
}
catch
{
// not yet received, but weird exceptions out there
}
}

if (_settings.DirectUpload) CloseWindow();
}
catch (RuntimeBinderException)
{
// Json does not contain permalink which means it's a new file (or the request failed)
ChangeStatus(LocalizationHelper.Base.Message_Upload);
var scanRequest = new RestRequest("vtapi/v2/file/scan", Method.POST);
scanRequest.AddParameter("apikey", _settings.ApiKey);
scanRequest.AddFile("file", _fileName);
scanRequest.AddFile("file", path);

var scanResponse = _client.Execute(scanRequest);
var scanContent = scanResponse.Content;
// TODO: check for HTML (file too large)
dynamic scanJson = JsonConvert.DeserializeObject(scanContent);

if (scanResponse.ErrorException is OutOfMemoryException || scanResponse.ErrorException is IOException && scanResponse.ErrorException?.InnerException is SocketException sEx && sEx.ErrorCode == (int)SocketError.ConnectionReset)
{
ChangeStatus(LocalizationHelper.Base.Message_FileTooBig);
result = false;
continue;
}
try
{
string scanLink = scanJson.permalink.ToString();
var scanJson = (JObject)JsonConvert.DeserializeObject(scanResponse.Content);
var scanLink = scanJson.SelectToken("permalink").Value<string>();

// An example link can look like this:
// https://www.virustotal.com/gui/file/<filehash_or_resource_id>/detection/<scanid>
// If we don't remove the the scanid, then it will fail on new files since the scan did not finish
// Removing it like this will show the analysis progress for new files
scanLink = scanLink.Remove(scanLink.IndexOf("/detection"));

Process.Start(scanLink);

if (_settings.DirectUpload) CloseWindow();
Process.Start(scanLink);
}
catch (Exception)
{
// Response does not contain permalink so it failed
ChangeStatus(LocalizationHelper.Base.Message_NoLink);
Finish(false);
return;
result = false;
}
}

Finish(true);
if (_settings.DirectUpload) CloseWindow();

Finish(result);
}

private void StartUploadThread()
Expand All @@ -161,17 +158,34 @@ private void StartUploadThread()
}
uploadButton.Text = LocalizationHelper.Base.UploadForm_Cancel;

_resource = mdTextbox.Text;
_uploadThread = new Thread(Upload);
_uploadThread.Start();
}

private void UploadForm_Load(object sender, EventArgs e)
{
mdTextbox.Text = Utils.GetMD5(_fileName);
shaTextbox.Text = Utils.GetSHA1(_fileName);
sha2Textbox.Text = Utils.GetSHA256(_fileName);
if (Directory.Exists(_fileOrFolderName))
{
mdTextbox.Text = _fileOrFolderName;
shaTextbox.Visible = false;
sha2Textbox.Visible = false;

darkLabel1.Text = LocalizationHelper.Base.UploadForm_Folder;
darkLabel2.Visible = false;
darkLabel3.Visible = false;

settingsGroup.Text = LocalizationHelper.Base.UploadForm_FolderInfo;
}
else
{
mdTextbox.Text = Utils.GetMD5(_fileOrFolderName);
shaTextbox.Text = Utils.GetSHA1(_fileOrFolderName);
sha2Textbox.Text = Utils.GetSHA256(_fileOrFolderName);

settingsGroup.Text = LocalizationHelper.Base.UploadForm_FileInfo;
}

settingsGroup.Text = LocalizationHelper.Base.UploadForm_Info;
uploadButton.Text = LocalizationHelper.Base.UploadForm_Upload;
statusLabel.Text = LocalizationHelper.Base.Message_Idle;

Expand Down
18 changes: 14 additions & 4 deletions uploader/uploader/Utils.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace uploader
{
internal class Utils
internal static class Utils
{
public static string GetMD5(string file)
{
Expand Down Expand Up @@ -46,5 +44,17 @@ public static string GetSHA1(string file)
return BitConverter.ToString(checksum).Replace("-", string.Empty);
}
}

public static void InvokeIfRequired(this Control control, MethodInvoker action)
{
if (control.InvokeRequired)
{
control.Invoke(action);
}
else
{
action();
}
}
}
}

0 comments on commit 9b32ad1

Please sign in to comment.