Skip to content

Commit 6561938

Browse files
authored
Fix script hashing to use full application startup path and add logging (#480)
* #479 fix script hashing to use full application startup path and add logging * #479 small refactor to use TryGetValue to get the expected hash
1 parent 4b45edd commit 6561938

File tree

2 files changed

+81
-25
lines changed

2 files changed

+81
-25
lines changed

sqlnexus/ScriptIntegrity.cs

Lines changed: 65 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,78 @@
1-
using System;
1+
using NexusInterfaces;
2+
using System;
23
using System.Collections.Generic;
34
using System.IO;
5+
using System.Windows.Forms;
46
using System.Security.Cryptography;
57

68
namespace sqlnexus
79
{
810
public static class ScriptIntegrityChecker
911
{
12+
13+
public static ILogger Logger { get; set; }
14+
15+
// Central logging helper – falls back to Trace / Console if no logger yet
16+
private static void Log(string msg, bool verbose = false)
17+
{
18+
// Use local Logger if set, else Util.Logger
19+
var lg = Logger ?? Util.Logger;
20+
if (lg != null)
21+
{
22+
// Use Silent so it goes only to file (not status bar / dialogs)
23+
lg.LogMessage("[ScriptIntegrity] " + msg, verbose ? MessageOptions.Silent : MessageOptions.Silent);
24+
}
25+
else
26+
{
27+
System.Diagnostics.Trace.WriteLine(msg);
28+
}
29+
}
30+
1031
// Store expected hashes for each allowed script
1132

1233
private static readonly Dictionary<string, string> ScriptHashes = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase) {
13-
{ "PerfStatsAnalysis.sql", "37111E6F2052A2A7B15E26329475738B4E543FE66AFB7BA426639C062D9E81A1" },
14-
{ "ReadTracePostProcessing.sql", "770DE7883BEFFA30C81C5BF45433EFF4C121EF92796047C49AC459103517BB68" },
15-
{ "ReadTraceReportValidate.sql", "92A575503905D2CABEE18D1804D1DCDCACD12FACD912B16E1040C923AB168E02" },
16-
{ "SQLNexus_PostProcessing.sql", "D6B0081152C262BFF6CBD0F04FC01B990E619DDD10FEDB8470438D0514E815FA" },
17-
{ "SQLNexus_PreProcessing.sql", "81465871D11C26E93329C5F60CBACED1311E97205B29CD8E5526273018168FF6" },
18-
{ "PostBuild.cmd", "741ABE8E8750EE4F010268B29C08B645EAB3EAE4E805D46CD5CA100926E00A48" },
19-
{ "PostProcess.cmd", "814ABCA4622978440172394F24AD6C81535D0C78E53D4356642704A95CD38C7F" },
20-
{ "PreBuild.cmd", "9C706DD338C5A3743C176E43F2C35FE765CF4719FBF33AF6FDAA811418B01187" },
21-
};
34+
{ Application.StartupPath + "\\" + "PerfStatsAnalysis.sql", "37111E6F2052A2A7B15E26329475738B4E543FE66AFB7BA426639C062D9E81A1" },
35+
{ Application.StartupPath + "\\" + "ReadTracePostProcessing.sql", "770DE7883BEFFA30C81C5BF45433EFF4C121EF92796047C49AC459103517BB68" },
36+
{ Application.StartupPath + "\\" + "ReadTraceReportValidate.sql", "92A575503905D2CABEE18D1804D1DCDCACD12FACD912B16E1040C923AB168E02" },
37+
{ Application.StartupPath + "\\" + "SQLNexus_PostProcessing.sql", "BA659CE90DD602AD16C5A8F131D95C1A7D86AA00D764C68C3DE176C5AD0A4139" },
38+
{ Application.StartupPath + "\\" + "SQLNexus_PreProcessing.sql", "81465871D11C26E93329C5F60CBACED1311E97205B29CD8E5526273018168FF6" },
39+
{ Application.StartupPath + "\\" + "PostBuild.cmd", "741ABE8E8750EE4F010268B29C08B645EAB3EAE4E805D46CD5CA100926E00A48" },
40+
{ Application.StartupPath + "\\" + "PostProcess.cmd", "814ABCA4622978440172394F24AD6C81535D0C78E53D4356642704A95CD38C7F" },
41+
{ Application.StartupPath + "\\" + "PreBuild.cmd", "9C706DD338C5A3743C176E43F2C35FE765CF4719FBF33AF6FDAA811418B01187" }
42+
};
43+
44+
2245
// Returns true only if the file is listed and the hash matches
2346
public static bool VerifyScript(string filePath)
2447
{
25-
string fileName = Path.GetFileName(filePath);
26-
if (!ScriptHashes.ContainsKey(fileName))
48+
49+
Log($"Computing hash for file: {filePath}");
50+
51+
// Check if file is in the allowed list and get expected hash
52+
if (!ScriptHashes.TryGetValue(filePath, out string expectedHash))
53+
{
54+
Log($"Script '{filePath}' not in the allowed list. Blocked.");
2755
return false;
56+
}
2857

29-
string expectedHash = ScriptHashes[fileName];
58+
// Compute actual hash
3059
string actualHash = ComputeFileHash(filePath);
3160

32-
return string.Equals(expectedHash, actualHash, StringComparison.OrdinalIgnoreCase);
61+
62+
if (actualHash == null)
63+
{
64+
Log($"Failed to compute hash for '{filePath}'.");
65+
return false;
66+
}
67+
68+
if (!string.Equals(expectedHash, actualHash, StringComparison.OrdinalIgnoreCase))
69+
{
70+
Log($"Hash mismatch for '{filePath}'. Expected={expectedHash} Actual={actualHash}");
71+
return false;
72+
}
73+
74+
Log($"Script '{filePath}' integrity OK.");
75+
return true;
3376
}
3477

3578
// Returns true only if the file is listed in the dictionary
@@ -44,14 +87,18 @@ private static string ComputeFileHash(string filePath)
4487
try
4588
{
4689
using (var stream = File.OpenRead(filePath))
47-
using (var sha = SHA256.Create())
4890
{
49-
byte[] hash = sha.ComputeHash(stream);
50-
return BitConverter.ToString(hash).Replace("-", "");
91+
using (var sha = SHA256.Create())
92+
{
93+
byte[] hash = sha.ComputeHash(stream);
94+
return BitConverter.ToString(hash).Replace("-", "");
95+
}
5196
}
97+
5298
}
53-
catch (Exception)
99+
catch (Exception ex)
54100
{
101+
Log($"Error computing hash for '{filePath}': {ex.Message}");
55102
return null;
56103
}
57104
}

sqlnexus/fmImport.cs

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1219,7 +1219,10 @@ private void RunPostProcessing(string sourcePath)
12191219
psi.Arguments = string.Format("\"{0}\" \"{1}\" \"{2}\"", Globals.credentialMgr.Server, Globals.credentialMgr.Database, sourcePath);
12201220

12211221
MainForm.LogMessage("Executing: PostProcess.cmd " + psi.Arguments);
1222-
psi.FileName = "PostProcess.cmd";
1222+
psi.FileName = Application.StartupPath + "\\PostProcess.cmd";
1223+
1224+
//print psi filename full path
1225+
MainForm.LogMessage("PostProcess.cmd full path: " + Path.GetFullPath(psi.FileName));
12231226

12241227
// do a script validation before executing
12251228
if (!ScriptIntegrityChecker.VerifyScript(psi.FileName))
@@ -1370,15 +1373,10 @@ private void RunScript(string scriptname)
13701373
if (string.IsNullOrEmpty(scriptname))
13711374
return;
13721375

1373-
if (!ScriptIntegrityChecker.VerifyScript(scriptname))
1374-
{
1375-
MainForm.LogMessage("Script is not allowed or has been tampered with: '" + scriptname + "'", MessageOptions.All, TraceEventType.Error, "Script integrity");
1376-
return;
1377-
}
1378-
13791376

13801377
Cursor saveCur = this.Cursor;
13811378
string FullScriptName;
1379+
13821380
try
13831381
{
13841382
this.Cursor = Cursors.WaitCursor;
@@ -1394,6 +1392,7 @@ private void RunScript(string scriptname)
13941392
if (-1 == scriptname.IndexOf('\\'))
13951393
{
13961394
FullScriptName = Application.StartupPath + "\\" + scriptname;
1395+
13971396
if (!File.Exists(FullScriptName))
13981397
{
13991398
FullScriptName = Application.StartupPath + @"\Reports\" + scriptname;
@@ -1415,7 +1414,17 @@ private void RunScript(string scriptname)
14151414
{
14161415
MainForm.LogMessage("Script '" + FullScriptName + "' doesn't exist", MessageOptions.All);
14171416
return;
1417+
}
1418+
1419+
//print full path to the script
1420+
MainForm.LogMessage("Full path to script: " + Path.GetFullPath(FullScriptName));
14181421

1422+
// do a script validation before executing
1423+
1424+
if (!ScriptIntegrityChecker.VerifyScript(FullScriptName))
1425+
{
1426+
MainForm.LogMessage("Script is not allowed or has been tampered with: '" + scriptname + "'", MessageOptions.All, TraceEventType.Error, "Script integrity");
1427+
return;
14191428
}
14201429

14211430
//db.ExecuteNonQuery(File.ReadAllText(FullScriptName), Microsoft.SqlServer.Management.Common.ExecutionTypes.ContinueOnError);

0 commit comments

Comments
 (0)