159 lines
6.5 KiB
C#
159 lines
6.5 KiB
C#
/******************************************************************************/
|
|
/* SlunkCrypt, by LoRd_MuldeR <MuldeR2@GMX.de> */
|
|
/* This work has been released under the CC0 1.0 Universal license! */
|
|
/******************************************************************************/
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Text.RegularExpressions;
|
|
using System.Threading.Tasks;
|
|
using System.Windows.Threading;
|
|
|
|
using com.muldersoft.slunkcrypt.gui.utils;
|
|
|
|
namespace com.muldersoft.slunkcrypt.gui.process
|
|
{
|
|
internal class SlunkCryptRunner : ProcessRunner
|
|
{
|
|
public enum Mode { Encrypt, Decrypt }
|
|
|
|
public enum Error { Checksum, Password }
|
|
|
|
public struct SlunkOptions
|
|
{
|
|
public SlunkOptions(bool keepIncompleteFiles, int threadCount, bool enableLegacyCompat)
|
|
{
|
|
this.keepIncompleteFiles = keepIncompleteFiles;
|
|
this.threadCount = threadCount;
|
|
this.enableLegacyCompat = enableLegacyCompat;
|
|
}
|
|
public readonly bool keepIncompleteFiles, enableLegacyCompat;
|
|
public readonly int threadCount;
|
|
}
|
|
|
|
private const string COMMAND_ENCRYPT = "-e";
|
|
private const string COMMAND_DECRYPT = "-d";
|
|
|
|
#if DEBUG
|
|
private const bool ENABLE_DEBUG_LOGGING = true;
|
|
#else
|
|
private const bool ENABLE_DEBUG_LOGGING = false;
|
|
#endif
|
|
|
|
private static readonly Regex RX_PROGRESS = new Regex(@"(\d+)\.(\d)%", RegexOptions.Compiled | RegexOptions.CultureInvariant);
|
|
|
|
private static readonly IReadOnlyDictionary<Error, Regex> RX_ERROR = new Dictionary<Error, Regex>
|
|
{
|
|
{ Error.Checksum, new Regex(@"\bChecksum\s+mismatch\s+detected\b", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant) },
|
|
{ Error.Password, new Regex(@"\bThe\s+given\s+passphrase\s+is\s+forbidden\s+as\s+a\s+precautionary\s+measure\b", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant) }
|
|
}
|
|
.ToReadOnlyDictionary();
|
|
|
|
private readonly FileStream m_executableFile;
|
|
|
|
// =============================================================================
|
|
// Constructor
|
|
// =============================================================================
|
|
|
|
public SlunkCryptRunner(Dispatcher dispatcher, ProcessPriorityClass? priorityClass = null) : base(dispatcher, priorityClass)
|
|
{
|
|
m_executableFile = ExecutableHelper.GetExecutableFile();
|
|
}
|
|
|
|
// =============================================================================
|
|
// Public methods
|
|
// =============================================================================
|
|
|
|
public async Task<int> ExecuteAsync(Mode mode, string inputFile, string outputFile, string password, SlunkOptions? options = null)
|
|
{
|
|
if ((!EnumHelper.IsDefined(mode)) || string.IsNullOrWhiteSpace(inputFile) || string.IsNullOrWhiteSpace(outputFile) || string.IsNullOrWhiteSpace(password))
|
|
{
|
|
throw new ArgumentException("Invalid SlunkCrypt parameters!");
|
|
}
|
|
Dictionary<string, string> environmentVariables = new Dictionary<string, string>
|
|
{
|
|
{ "SLUNK_PASSPHRASE", password },
|
|
{ "SLUNK_KEEP_INCOMPLETE", Convert.ToString(Convert.ToInt32(options.HasValue ? options.Value.keepIncompleteFiles : false)) },
|
|
{ "SLUNK_THREADS", Convert.ToString(Math.Max(0, Math.Min(32, options.HasValue ? options.Value.threadCount : 0))) },
|
|
{ "SLUNK_LEGACY_COMPAT", Convert.ToString(Convert.ToInt32(options.HasValue ? options.Value.enableLegacyCompat : false)) },
|
|
{ "SLUNK_DEBUG_LOGGING", Convert.ToString(Convert.ToInt32(ENABLE_DEBUG_LOGGING)) }
|
|
};
|
|
ErrorState = null;
|
|
return await ExecAsnyc(m_executableFile.Name, new string[] { GetCommandString(mode), inputFile, outputFile }, Path.GetDirectoryName(outputFile), environmentVariables);
|
|
}
|
|
|
|
public override void Dispose()
|
|
{
|
|
base.Dispose();
|
|
try
|
|
{
|
|
m_executableFile.Dispose();
|
|
}
|
|
catch { }
|
|
}
|
|
|
|
public Error? ErrorState { get; private set; } = null;
|
|
|
|
// =============================================================================
|
|
// Internal methods
|
|
// =============================================================================
|
|
|
|
protected override double ParseProgressString(ref string currentLine, bool stream)
|
|
{
|
|
int index = int.MaxValue;
|
|
double temp = double.NaN, result = double.NaN;
|
|
if (!ErrorState.HasValue)
|
|
{
|
|
foreach (KeyValuePair<Error, Regex> errorRegex in RX_ERROR)
|
|
{
|
|
if (errorRegex.Value.IsMatch(currentLine))
|
|
{
|
|
ErrorState = errorRegex.Key;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
for (Match match = RX_PROGRESS.Match(currentLine); match.Success; match = match.NextMatch())
|
|
{
|
|
if (TryParseProgressValue(match, out temp))
|
|
{
|
|
result = double.IsNaN(result) ? temp : Math.Max(result, temp);
|
|
}
|
|
index = Math.Min(index, match.Index);
|
|
}
|
|
if (index != int.MaxValue)
|
|
{
|
|
currentLine = (index > 0) ? currentLine.Substring(0, index - 1).TrimEnd() : string.Empty;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private static bool TryParseProgressValue(Match match, out double progress)
|
|
{
|
|
uint intPart, fractPart;
|
|
if (uint.TryParse(match.Groups[1].Value, out intPart) && uint.TryParse(match.Groups[2].Value, out fractPart))
|
|
{
|
|
progress = ((intPart * 10) + fractPart) / 1000.0;
|
|
return true;
|
|
}
|
|
progress = double.NaN;
|
|
return false;
|
|
}
|
|
|
|
private static string GetCommandString(Mode mode)
|
|
{
|
|
switch(mode)
|
|
{
|
|
case Mode.Encrypt:
|
|
return COMMAND_ENCRYPT;
|
|
case Mode.Decrypt:
|
|
return COMMAND_DECRYPT;
|
|
default:
|
|
throw new ArgumentException("Invalid mode!");
|
|
}
|
|
}
|
|
}
|
|
}
|