OSDN Git Service

GUI: Hide the options for "legacy" compatibility mode by default + some improvements...
authorLoRd_MuldeR <mulder2@gmx.de>
Wed, 12 Jun 2024 15:41:53 +0000 (17:41 +0200)
committerLoRd_MuldeR <mulder2@gmx.de>
Thu, 13 Jun 2024 20:12:23 +0000 (22:12 +0200)
README.md
gui/App.config
gui/Process/SlunkCryptRunner.cs
gui/SlunkCryptGUI.csproj
gui/SlunkCryptGUI.xaml.cs
gui/Utilities/ApplicationConfig.cs
gui/Utilities/DictionaryHelper.cs [new file with mode: 0644]

index 9da1274..c1c8e8f 100644 (file)
--- a/README.md
+++ b/README.md
@@ -63,6 +63,9 @@ The following settings can be adjusted in the `slunkcrypt-gui.exe.config` config
 - **`KeepIncompleteFiles`:**  
   If set to `true`, incomplete or corrupted output files will *not* be deleted &mdash; default value: `false`.
 
+- **`LegacyCompat`:**  
+  If set to `1`, show options to enable “legacy” compatibility-mode in the GUI; if set to `2`, select “legacy” compatibility-mode by default &mdash; default value: `0`.
+
 Command-line Usage
 ==================
 
@@ -132,7 +135,7 @@ The following environment variables may be used:
   Specifies the number of worker threads to use. By default, SlunkCrypt detects the number of available processors and creates one thread for each processor.
 
 - **`SLUNK_LEGACY_COMPAT`**:  
-  If set to a *non-zero* value, enables "legacy" compatibility-mode, required to decrypt files encrypted with SlunkCrypt version 1.2.x or older.
+  If set to a *non-zero* value, enables “legacy” compatibility-mode, required to decrypt files encrypted with SlunkCrypt version 1.2.x or older.
 
 - **`SLUNK_DEBUG_LOGGING`**:  
   If set to a *non-zero* value, enables additional logging output to the syslog (Unix-like) or to the debugger (Windows). This is intended for debugging purposes only!
index 1ede395..0dbe71c 100644 (file)
@@ -7,6 +7,6 @@
         <add key="DisableBusyIndicator" value="false"/>
         <add key="ThreadCount" value="0"/>
         <add key="KeepIncompleteFiles" value="false"/>
-        <add key="LegacyCompat" value="false"/>
+        <add key="LegacyCompat" value="0"/>
     </appSettings>
 </configuration>
index fe4ddc5..c6ca8fb 100644 (file)
@@ -19,6 +19,8 @@ namespace com.muldersoft.slunkcrypt.gui.process
     {
         public enum Mode { Encrypt, Decrypt }
 
+        public enum Error { Checksum, Password }
+
         public struct SlunkOptions
         {
             public SlunkOptions(bool keepIncompleteFiles, int threadCount, bool enableLegacyCompat)
@@ -40,7 +42,14 @@ namespace com.muldersoft.slunkcrypt.gui.process
         private const bool ENABLE_DEBUG_LOGGING = false;
 #endif
 
-        private static readonly Regex RX_PROGRESS = new Regex(@"(\d+)\.(\d)%", RegexOptions.Compiled);
+        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;
 
@@ -63,12 +72,15 @@ namespace com.muldersoft.slunkcrypt.gui.process
             {
                 throw new ArgumentException("Invalid SlunkCrypt parameters!");
             }
-            Dictionary<string, string> environmentVariables = new Dictionary<string, string>();
-            environmentVariables.Add("SLUNK_PASSPHRASE", password);
-            environmentVariables.Add("SLUNK_KEEP_INCOMPLETE", Convert.ToString(Convert.ToInt32(options.HasValue ? options.Value.keepIncompleteFiles : false)));
-            environmentVariables.Add("SLUNK_THREADS", Convert.ToString(Math.Max(0, Math.Min(32, options.HasValue ? options.Value.threadCount : 0))));
-            environmentVariables.Add("SLUNK_LEGACY_COMPAT", Convert.ToString(Convert.ToInt32(options.HasValue ? options.Value.enableLegacyCompat : false)));
-            environmentVariables.Add("SLUNK_DEBUG_LOGGING", Convert.ToString(Convert.ToInt32(ENABLE_DEBUG_LOGGING)));
+            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);
         }
 
@@ -82,23 +94,34 @@ namespace com.muldersoft.slunkcrypt.gui.process
             catch { }
         }
 
+        public Error? ErrorState { get; private set; } = null;
+
         // =============================================================================
         // Internal methods
         // =============================================================================
 
         protected override double ParseProgressString(ref string currentLine, bool stream)
         {
-            double temp, result = double.NaN;
             int index = int.MaxValue;
-            Match match = RX_PROGRESS.Match(currentLine);
-            while (match.Success)
+            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 = temp;
+                    result = double.IsNaN(result) ? temp : Math.Max(result, temp);
                 }
                 index = Math.Min(index, match.Index);
-                match = RX_PROGRESS.Match(currentLine, match.Index + match.Length);
             }
             if (index != int.MaxValue)
             {
index 75d4819..08d3e98 100644 (file)
@@ -82,6 +82,7 @@
       <DependentUpon>PasswordToggleBox.xaml</DependentUpon>
     </Compile>
     <Compile Include="Properties\_Version.cs" />
+    <Compile Include="Utilities\DictionaryHelper.cs" />
     <Compile Include="Utilities\EnumHelper.cs" />
     <Compile Include="Process\ExecutableHelper.cs" />
     <Compile Include="Utilities\ApplicationConfig.cs" />
index e35406e..a848242 100644 (file)
@@ -49,7 +49,7 @@ namespace com.muldersoft.slunkcrypt.gui
 
         private volatile int m_isInitialized = 0;
         private volatile ModeOfOperation m_modeOfOperation = (ModeOfOperation)(-1);
-        private volatile bool m_busyFlag = false, m_checksumError = false, m_processReceived = false, m_disableAnimation = false;
+        private volatile bool m_busyFlag = false, m_processReceived = false, m_disableAnimation = false;
         private volatile SlunkCryptRunner m_processRunner = null;
         private uint? m_menuId_disableAnimation = null, m_menuId_enableExpertMode = null;
 
@@ -68,6 +68,10 @@ namespace com.muldersoft.slunkcrypt.gui
             m_dispatcherTimer.Interval = TimeSpan.FromMilliseconds(331);
             m_logFileReadOnly = new ReadOnlyObservableCollection<string>(m_logFile);
             m_disableAnimation = m_config.DisableBusyIndicator;
+            if (m_config.LegacyCompat < 1)
+            {
+                Checkbox_Encrypt_LegacyCompat.Visibility = Checkbox_Decrypt_LegacyCompat.Visibility = Visibility.Collapsed;
+            }
         }
 
         // =============================================================================
@@ -125,7 +129,7 @@ namespace com.muldersoft.slunkcrypt.gui
                 {
                     Hint_SoftwareRendering.Visibility = Visibility.Visible;
                 }
-                if (m_config.LegacyCompat)
+                if (m_config.LegacyCompat > 1)
                 {
                     Checkbox_Encrypt_LegacyCompat.IsChecked = Checkbox_Decrypt_LegacyCompat.IsChecked = true;
                 }
@@ -273,10 +277,6 @@ namespace com.muldersoft.slunkcrypt.gui
         private void Process_OutputAvailable(string line, bool stderr)
         {
             AppendLogFile(line);
-            if (line.IndexOf("Checksum mismatch detected!", StringComparison.OrdinalIgnoreCase) >= 0)
-            {
-                m_checksumError = true;
-            }
         }
 
         private void Porcess_ProgressChanged(double progress)
@@ -522,7 +522,7 @@ namespace com.muldersoft.slunkcrypt.gui
 
         private async Task ValidatePassword(string inputFilePath, string outputFilePath, PasswordToggleBox passwordEdit, CheckBox legacyCheckBox, SlunkProcessor processor, bool checkStrongPasswd)
         {
-            bool enableLegacyCompat = legacyCheckBox.IsChecked.GetValueOrDefault();
+            bool enableLegacyCompat = (m_config.LegacyCompat > 0) && legacyCheckBox.IsChecked.GetValueOrDefault(m_config.LegacyCompat > 1);
             string passwordStr;
             if (string.IsNullOrEmpty(passwordStr = passwordEdit.Password) || (passwordStr.Length < MIN_PASSWD_LENGTH))
             {
@@ -548,7 +548,7 @@ namespace com.muldersoft.slunkcrypt.gui
                         return;
                     }
                 }
-                if (enableLegacyCompat && (!m_config.LegacyCompat))
+                if (enableLegacyCompat && (m_config.LegacyCompat < 2))
                 {
                     if (MessageBox.Show(this, "Legacy compat-mode should not be used to encrypt new files!", "Legacy Compatibility", MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel) != MessageBoxResult.OK)
                     {
@@ -567,7 +567,7 @@ namespace com.muldersoft.slunkcrypt.gui
                 ResetKeyboardFocus(this);
                 SetProgress(double.PositiveInfinity);
                 ClearLogFile();
-                Button_Decrypt_Toggle.IsChecked = Button_Encrypt_Toggle.IsChecked = m_checksumError = m_processReceived = false;
+                Button_Decrypt_Toggle.IsChecked = Button_Encrypt_Toggle.IsChecked = m_processReceived = false;
                 if (!await processor(inputFile, outputFile, password, enableLegacyCompat))
                 {
                     if (!m_config.KeepIncompleteFiles)
@@ -583,10 +583,10 @@ namespace com.muldersoft.slunkcrypt.gui
         private async Task<bool> Encrypt(string inputFile, string outputFile, string password, bool enableLegacyCompat)
         {
             SetStatus("Please wait while the encryption process is initializing...");
-            int? exitCode = await RunProcess(SlunkCryptRunner.Mode.Encrypt, inputFile, outputFile, password, enableLegacyCompat);
-            if (exitCode.HasValue)
+            Tuple<int, SlunkCryptRunner.Error?> result = await RunProcess(SlunkCryptRunner.Mode.Encrypt, inputFile, outputFile, password, enableLegacyCompat);
+            if (!ReferenceEquals(result, null))
             {
-                if (exitCode.Value == 0)
+                if (result.Item1 == 0)
                 {
                     SetProgress(1);
                     SetStatus("Completed: The file has been encrypted successfully.", Status.Success);
@@ -594,8 +594,16 @@ namespace com.muldersoft.slunkcrypt.gui
                 }
                 else
                 {
+                    switch (result.Item2)
+                    {
+                        case SlunkCryptRunner.Error.Password:
+                            SetStatus("Error: The specified passphrase is forbidden! (contained in OWASP database)", Status.Failure);
+                            break;
+                        default:
+                            SetStatus("Error: Failed to enecrypt the file. Please see the log file for details!", Status.Failure);
+                            break;
+                    }
                     SetProgress(1, true);
-                    SetStatus("Error: Failed to enecrypt the file. Please see the log file for details!", Status.Failure);
                     SystemSounds.Hand.Play();
                 }
                 return true;
@@ -606,10 +614,10 @@ namespace com.muldersoft.slunkcrypt.gui
         private async Task<bool> Decrypt(string inputFile, string outputFile, string password, bool enableLegacyCompat)
         {
             SetStatus("Please wait while the decryption process is initializing...");
-            int? exitCode = await RunProcess(SlunkCryptRunner.Mode.Decrypt, inputFile, outputFile, password, enableLegacyCompat);
-            if (exitCode.HasValue)
+            Tuple<int, SlunkCryptRunner.Error?> result = await RunProcess(SlunkCryptRunner.Mode.Decrypt, inputFile, outputFile, password, enableLegacyCompat);
+            if (!ReferenceEquals(result, null))
             {
-                if (exitCode.Value == 0)
+                if (result.Item1 == 0)
                 {
                     SetStatus("Completed: The file has been decrypted successfully (checksum is correct).", Status.Success);
                     SetProgress(1);
@@ -617,13 +625,14 @@ namespace com.muldersoft.slunkcrypt.gui
                 }
                 else
                 {
-                    if (m_checksumError)
-                    {
-                        SetStatus("Error: Checksum mismatch detected! Wrong passphrase or corrupted file?", Status.Failure);
-                    }
-                    else
+                    switch (result.Item2)
                     {
-                        SetStatus("Error: Failed to decrypt the file. Please see the log file for details!", Status.Failure);
+                        case SlunkCryptRunner.Error.Checksum:
+                            SetStatus("Error: Checksum mismatch detected! Wrong passphrase or corrupted file?", Status.Failure);
+                            break;
+                        default:
+                            SetStatus("Error: Failed to decrypt the file. Please see the log file for details!", Status.Failure);
+                            break;
                     }
                     SetProgress(1, true);
                     SystemSounds.Hand.Play();
@@ -633,7 +642,7 @@ namespace com.muldersoft.slunkcrypt.gui
             return false;
         }
 
-        private async Task<int?> RunProcess(SlunkCryptRunner.Mode mode, string inputFile, string outputFile, string password, bool enableLegacyCompat)
+        private async Task<Tuple<int, SlunkCryptRunner.Error?>> RunProcess(SlunkCryptRunner.Mode mode, string inputFile, string outputFile, string password, bool enableLegacyCompat)
         {
             if (!ReferenceEquals(m_processRunner, null))
             {
@@ -647,7 +656,8 @@ namespace com.muldersoft.slunkcrypt.gui
                     m_processRunner.OutputAvailable += Process_OutputAvailable;
                     m_processRunner.ProgressChanged += Porcess_ProgressChanged;
                     SetProcessPriority(ProcessPriorityClass.AboveNormal);
-                    return await m_processRunner.ExecuteAsync(mode, inputFile, outputFile, password, options);
+                    int exitCode = await m_processRunner.ExecuteAsync(mode, inputFile, outputFile, password, options);
+                    return Tuple.Create(exitCode, m_processRunner.ErrorState);
                 }
             }
             catch (ProcessRunner.ProcessStartException err)
index c725a09..65d53f5 100644 (file)
@@ -34,15 +34,15 @@ namespace com.muldersoft.slunkcrypt.gui.utils
         {
             get
             {
-                return ComputeIfAbsent("ThreadCount", (key) => AppConfHelper.GetConfigValueAsInt32(key).GetValueOrDefault(0));
+                return ComputeIfAbsent("ThreadCount", (key) => Clamp(0, AppConfHelper.GetConfigValueAsInt32(key).GetValueOrDefault(0), 32));
             }
         }
 
-        public bool LegacyCompat
+        public int LegacyCompat
         {
             get
             {
-                return ComputeIfAbsent("LegacyCompat", (key) => AppConfHelper.GetConfigValueAsBool(key).GetValueOrDefault(false));
+                return ComputeIfAbsent("LegacyCompat", (key) => Clamp(0, AppConfHelper.GetConfigValueAsInt32(key).GetValueOrDefault(0), 2));
             }
         }
 
@@ -60,6 +60,11 @@ namespace com.muldersoft.slunkcrypt.gui.utils
             return Convert.ToBoolean(m_cache.GetOrAdd(name, (key) => Convert.ToInt32(valueFactory(key))));
         }
 
+        protected static int Clamp(int min, int value, int max)
+        {
+            return (value < min) ? min : ((value > max) ? max : value);
+        }
+
         // =============================================================================
         // Helper class
         // =============================================================================
@@ -116,6 +121,14 @@ namespace com.muldersoft.slunkcrypt.gui.utils
                     {
                         return result;
                     }
+                    else
+                    {
+                        bool boolean;
+                        if (bool.TryParse(value.Trim(), out boolean))
+                        {
+                            return Convert.ToInt32(boolean);
+                        }
+                    }
                 }
                 return null;
             }
diff --git a/gui/Utilities/DictionaryHelper.cs b/gui/Utilities/DictionaryHelper.cs
new file mode 100644 (file)
index 0000000..6ca35e1
--- /dev/null
@@ -0,0 +1,18 @@
+/******************************************************************************/
+/* SlunkCrypt, by LoRd_MuldeR <MuldeR2@GMX.de>                                */
+/* This work has been released under the CC0 1.0 Universal license!           */
+/******************************************************************************/
+
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+
+namespace com.muldersoft.slunkcrypt.gui.utils
+{
+    public static class DictionaryHelper
+    {
+        public static IReadOnlyDictionary<K, V> ToReadOnlyDictionary<K, V>(this IDictionary<K, V> dict)
+        {
+            return (dict is ReadOnlyDictionary<K, V>) ? ((ReadOnlyDictionary<K, V>)dict) : new ReadOnlyDictionary<K, V>(dict);
+        }
+    }
+}