Skip to content

Commit b381e04

Browse files
committed
Fix a potential newline SQL injection bug
1 parent c78dcd0 commit b381e04

File tree

10 files changed

+58
-79
lines changed

10 files changed

+58
-79
lines changed
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
<?xml version="1.0" encoding="utf-8"?>
2-
<AppInstaller DisplayName="MyMoney.Net" IsBundle="true" Version="2.0.0.6" DisplayPublisher="Chris Lovett" SupportedArchitectures="neutral" OutputFolder="D:\git\clovett\MyMoney.Net\Source\WPF\MoneyPackage\AppPackages\" Description="MyMoney is a rich client .NET application for managing your personal finances. It is written entirely in C# and is designed for programmers who want easy access to their data and who want to quickly and easily add their own features. Your data will not be locked up in some proprietary format, it is yours to do with as you like." MinOS="10.0.18362.0" CertificateUri="https://lovettsoftwarestorage.blob.core.windows.net/downloads/MyMoney.Net/MoneyPackage_2.0.0.6_Test/MoneyPackage_2.0.0.6_AnyCPU.cer" PackageUri="https://lovettsoftwarestorage.blob.core.windows.net/downloads/MyMoney.Net/MoneyPackage_2.0.0.6_Test/MoneyPackage_2.0.0.6_AnyCPU.msixbundle" AppInstallerFile="https://lovettsoftwarestorage.blob.core.windows.net/downloads/MyMoney.Net/MoneyPackage.appinstaller" LogoPath="D:\git\clovett\MyMoney.Net\Source\WPF\MoneyPackage\Images\StoreLogo.png" TileColor="transparent" />
2+
<AppInstaller DisplayName="MyMoney.Net" IsBundle="true" Version="2.0.0.7" DisplayPublisher="Chris Lovett" SupportedArchitectures="neutral" OutputFolder="D:\git\clovett\MyMoney.Net\Source\WPF\MoneyPackage\AppPackages\" Description="MyMoney is a rich client .NET application for managing your personal finances. It is written entirely in C# and is designed for programmers who want easy access to their data and who want to quickly and easily add their own features. Your data will not be locked up in some proprietary format, it is yours to do with as you like." MinOS="10.0.18362.0" CertificateUri="https://lovettsoftwarestorage.blob.core.windows.net/downloads/MyMoney.Net/MoneyPackage_2.0.0.7_Test/MoneyPackage_2.0.0.7_AnyCPU.cer" PackageUri="https://lovettsoftwarestorage.blob.core.windows.net/downloads/MyMoney.Net/MoneyPackage_2.0.0.7_Test/MoneyPackage_2.0.0.7_AnyCPU.msixbundle" AppInstallerFile="https://lovettsoftwarestorage.blob.core.windows.net/downloads/MyMoney.Net/MoneyPackage.appinstaller" LogoPath="D:\git\clovett\MyMoney.Net\Source\WPF\MoneyPackage\Images\StoreLogo.png" TileColor="transparent" />
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
MainPackage=D:\git\clovett\MyMoney.Net\Source\WPF\MoneyPackage\bin\AnyCPU\Release\MoneyPackage_2.0.0.6_AnyCPU.msix
2-
SymbolPackage=D:\git\clovett\MyMoney.Net\Source\WPF\MoneyPackage\obj\Release\Symbols\MoneyPackage_2.0.0.6_AnyCPU.appxsym
1+
MainPackage=D:\git\clovett\MyMoney.Net\Source\WPF\MoneyPackage\bin\AnyCPU\Release\MoneyPackage_2.0.0.7_AnyCPU.msix
2+
SymbolPackage=D:\git\clovett\MyMoney.Net\Source\WPF\MoneyPackage\obj\Release\Symbols\MoneyPackage_2.0.0.7_AnyCPU.appxsym

Source/WPF/MoneyPackage/Package.appxmanifest

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities" IgnorableNamespaces="uap rescap">
3-
<Identity Name="43906ChrisLovett.MyMoney.Net" Publisher="CN=Chris Lovett, O=Chris Lovett, S=Washington, C=US" Version="2.0.0.6" />
3+
<Identity Name="43906ChrisLovett.MyMoney.Net" Publisher="CN=Chris Lovett, O=Chris Lovett, S=Washington, C=US" Version="2.0.0.7" />
44
<Properties>
55
<DisplayName>MyMoney.Net</DisplayName>
66
<PublisherDisplayName>Chris Lovett</PublisherDisplayName>

Source/WPF/MyMoney/Attachments/StatementManager.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ void CheckFileHashes(StatementIndex index)
369369
var dir = Path.GetDirectoryName(index.FileName);
370370
foreach(var item in index.Items)
371371
{
372-
if (string.IsNullOrEmpty(item.Hash))
372+
if (string.IsNullOrEmpty(item.Hash) && !string.IsNullOrEmpty(item.Filename))
373373
{
374374
var statementFile = Path.Combine(dir, item.Filename);
375375
item.Hash = Sha256Hash(statementFile);

Source/WPF/MyMoney/Database/SqlDatabase.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -919,7 +919,7 @@ public void AddLogin(string userName, string password)
919919
static string DBString(string s)
920920
{
921921
if (s == null) return null;
922-
return s.Replace("'", "''");
922+
return s.Replace("'", "''").Replace("\r","\\r").Replace("\n", "\\n");
923923
}
924924

925925
static string TwoDigit(int i)

Source/WPF/MyMoney/Ofx/Ofx.cs

Lines changed: 29 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1114,32 +1114,6 @@ internal XDocument SendOfxRequest(XDocument doc)
11141114
return result;
11151115
}
11161116

1117-
private int GetSignOnStatusCode(XElement ofx)
1118-
{
1119-
XElement signOnMsgResponse = ofx.Element("SIGNONMSGSRSV1");
1120-
if (signOnMsgResponse != null)
1121-
{
1122-
XElement sonOnResponse = signOnMsgResponse.Element("SONRS");
1123-
if (sonOnResponse != null)
1124-
{
1125-
XElement status = sonOnResponse.Element("STATUS");
1126-
if (status != null)
1127-
{
1128-
XElement code = sonOnResponse.Element("CODE");
1129-
if (code != null)
1130-
{
1131-
int i = 0;
1132-
if (int.TryParse(code.Value, out i))
1133-
{
1134-
return i;
1135-
}
1136-
}
1137-
}
1138-
}
1139-
}
1140-
return -1;
1141-
}
1142-
11431117
public static OFX LoadCachedProfile(MyMoney money, OnlineAccount oa)
11441118
{
11451119
string profilePath = Path.Combine(OfxLogPath, OfxRequest.GetLogfileName(money, oa) + "PROF_RS.xml");
@@ -1838,17 +1812,6 @@ public XDocument ParseOfxResponse(Stream stm, bool implementSecurity)
18381812
sgml.InputStream = new StringReader(sb.ToString());
18391813

18401814
doc = XDocument.Load(sgml);
1841-
1842-
//Trim newlines.
1843-
foreach (XNode node in doc.DescendantNodes())
1844-
{
1845-
XText text = node as XText;
1846-
if (text != null)
1847-
{
1848-
text.Value = text.Value.Trim().Replace(Environment.NewLine, " ");
1849-
}
1850-
}
1851-
18521815
sr.Close();
18531816
}
18541817
return doc;
@@ -1894,8 +1857,7 @@ public void ProcessResponse(XDocument doc, OfxDownloadData results)
18941857

18951858
XElement e = doc.SelectExpectedElement("OFX/SIGNONMSGSRSV1/SONRS/STATUS/CODE");
18961859

1897-
int statusCode = 0;
1898-
int.TryParse(e.Value.Trim(), out statusCode);
1860+
int statusCode = e.GetElementValueAsInt();
18991861
if (statusCode != 0)
19001862
{
19011863
OfxErrorCode ec = (OfxErrorCode)statusCode;
@@ -1946,7 +1908,7 @@ public void ProcessResponse(XDocument doc, OfxDownloadData results)
19461908
statusCode = 0;
19471909
if (e != null)
19481910
{
1949-
int.TryParse(e.Value.Trim(), out statusCode);
1911+
statusCode = e.GetElementValueAsInt();
19501912
}
19511913
if (statusCode != 0)
19521914
{
@@ -2004,7 +1966,7 @@ void ProcessCreditCardResponse(XElement cc, OfxDownloadData results)
20041966
{
20051967
throw new OfxException("TRNUID is missing in the response");
20061968
}
2007-
string id = idElement.Value.Trim();
1969+
string id = idElement.Value.GetNormalizedValue();
20081970

20091971
// Account can be null if we are loading a .ofx file off disk
20101972
Account a = (Account)this.truidMap[id];
@@ -2065,7 +2027,7 @@ void ProcessBankResponse(XElement br, OfxDownloadData results)
20652027
{
20662028
throw new OfxException("TRNUID is missing in the response");
20672029
}
2068-
string id = idElement.Value.Trim();
2030+
string id = idElement.Value.GetNormalizedValue();
20692031

20702032
// Account can be null if we are loading a .ofx file off disk
20712033
Account a = (Account)this.truidMap[id];
@@ -2127,7 +2089,7 @@ void ProcessInvestmentResponse(XElement ir, OfxDownloadData results)
21272089
{
21282090
throw new OfxException("TRNUID is missing in the response");
21292091
}
2130-
string id = idElement.Value.Trim();
2092+
string id = idElement.Value.GetNormalizedValue();
21312093

21322094
// Account can be null if we are loading a .ofx file off disk
21332095
Account a = (Account)this.truidMap[id];
@@ -2726,10 +2688,10 @@ private Transaction ProcessInvestmentTransaction(Account a, XElement e)
27262688
XElement invtran = e.Element("INVTRAN");
27272689
if (invtran != null)
27282690
{
2729-
t.FITID = invtran.SelectElementValue("FITID");
2691+
t.FITID = invtran.SelectElementValue("FITID").GetNormalizedValue();
27302692
t.Date = ParseOfxDate(invtran.SelectElementValue("DTTRADE"));
27312693
// todo: should use DTSETTLE for stock splits.
2732-
t.Memo = invtran.SelectElementValue("MEMO");
2694+
t.Memo = invtran.SelectElementValue("MEMO").GetNormalizedValue();
27332695
}
27342696
t.Amount = e.SelectElementValueAsDecimal("TOTAL");
27352697
return t;
@@ -2839,10 +2801,10 @@ Transaction ProcessInvestmentBankTransaction(Account a, XElement e)
28392801
XElement s = e.Element("STMTTRN");
28402802
if (s != null)
28412803
{
2842-
t.FITID = s.SelectElementValue("FITID");
2804+
t.FITID = s.SelectElementValue("FITID").GetNormalizedValue();
28432805
t.Date = ParseOfxDate(s.SelectElementValue("DTPOSTED"));
28442806
t.Amount = s.SelectElementValueAsDecimal("TRNAMT");
2845-
t.Memo = s.SelectElementValue("MEMO");
2807+
t.Memo = s.SelectElementValue("MEMO").GetNormalizedValue();
28462808

28472809
switch (s.SelectElementValue("TRNTYPE"))
28482810
{
@@ -2901,7 +2863,7 @@ Transaction ProcessMarginInterest(Account a, XElement e)
29012863
private static void ProcessCurrency(XElement currency, Transaction t)
29022864
{
29032865
if (currency == null) return;
2904-
string symbol = currency.SelectElementValue("CURSYM");
2866+
string symbol = currency.SelectElementValue("CURSYM").GetNormalizedValue();
29052867

29062868
if (symbol != "USD")
29072869
{
@@ -2912,10 +2874,10 @@ private static void ProcessCurrency(XElement currency, Transaction t)
29122874
Security ProcessSecId(XElement secId)
29132875
{
29142876
if (secId == null) return null;
2915-
string uniqueId = secId.SelectElementValue("UNIQUEID");
2877+
string uniqueId = secId.SelectElementValue("UNIQUEID").GetNormalizedValue();
29162878
if (string.IsNullOrEmpty(uniqueId)) return null;
29172879

2918-
string idType = secId.SelectElementValue("UNIQUEIDTYPE");
2880+
string idType = secId.SelectElementValue("UNIQUEIDTYPE").GetNormalizedValue();
29192881
if (string.IsNullOrEmpty(uniqueId)) idType = "CUSIP";
29202882

29212883
SecurityInfo info = null;
@@ -3021,11 +2983,11 @@ Dictionary<string, SecurityInfo> ReadSecurityInfo(XDocument doc)
30212983
XElement secInfo = e.SelectElement("SECINFO");
30222984
if (secInfo != null)
30232985
{
3024-
s.UniqueId = secInfo.SelectElementValue("SECID/UNIQUEID");
3025-
s.UniqueIdType = secInfo.SelectElementValue("SECID/UNIQUEIDTYPE");
3026-
s.Name = secInfo.SelectElementValue("SECNAME");
3027-
s.Ticker = secInfo.SelectElementValue("TICKER");
3028-
string price = secInfo.SelectElementValue("UNITPRICE");
2986+
s.UniqueId = secInfo.SelectElementValue("SECID/UNIQUEID").GetNormalizedValue();
2987+
s.UniqueIdType = secInfo.SelectElementValue("SECID/UNIQUEIDTYPE").GetNormalizedValue();
2988+
s.Name = secInfo.SelectElementValue("SECNAME").GetNormalizedValue();
2989+
s.Ticker = secInfo.SelectElementValue("TICKER").GetNormalizedValue();
2990+
string price = secInfo.SelectElementValue("UNITPRICE").GetNormalizedValue();
30292991

30302992
Security sec = null;
30312993
if (!string.IsNullOrEmpty(s.Ticker))
@@ -3132,45 +3094,44 @@ private void ProcessStatement(OfxDownloadData results, Account a, XElement srs)
31323094

31333095
foreach (XElement sr in transactionList.Elements("STMTTRN"))
31343096
{
3097+
string fitid = sr.SelectExpectedElement("FITID").Value.GetNormalizedValue();
31353098

3136-
string fitid = sr.SelectExpectedElement("FITID").Value.Trim();
3137-
3138-
DateTime dt = ParseOfxDate(sr.SelectExpectedElement("DTPOSTED").Value.Trim());
3139-
decimal amount = decimal.Parse(sr.SelectExpectedElement("TRNAMT").Value.Trim());
3099+
DateTime dt = ParseOfxDate(sr.SelectExpectedElement("DTPOSTED").Value.GetNormalizedValue());
3100+
decimal amount = decimal.Parse(sr.SelectExpectedElement("TRNAMT").Value.GetNormalizedValue());
31403101
if (amount == 0 && a.Type == AccountType.Credit)
31413102
continue; // ignore those annoying credit checks.
31423103

31433104
string number = null;
31443105

31453106
XElement e = sr.Element("CHECKNUM");
3146-
if (e != null)
3107+
if (e != null && int.TryParse(e.Value.GetNormalizedValue(), out int num))
31473108
{
3148-
number = Int32.Parse(e.Value.Trim()).ToString();
3109+
number = num.ToString();
31493110
}
31503111

31513112
string payee = null;
31523113
if ((e = sr.Element("NAME")) != null)
31533114
{
3154-
payee = e.Value.Trim();
3115+
payee = e.Value.GetNormalizedValue();
31553116
}
31563117
else if ((e = sr.Element("PAYEE")) != null)
31573118
{
3158-
payee = e.Value.Trim();
3119+
payee = e.Value.GetNormalizedValue();
31593120
}
31603121
else if ((e = sr.Element("PAYEE2")) != null)
31613122
{
3162-
payee = e.Value.Trim();
3123+
payee = e.Value.GetNormalizedValue();
31633124
}
31643125

31653126

31663127
string memo = null;
31673128
if ((e = sr.Element("MEMO")) != null)
31683129
{
3169-
memo = e.Value.Trim();
3130+
memo = e.Value.GetNormalizedValue();
31703131
}
31713132
else if ((e = sr.Element("MEMO2")) != null)
31723133
{
3173-
memo = e.Value.Trim();
3134+
memo = e.Value.GetNormalizedValue();
31743135
}
31753136

31763137
string s = "Bill Payment ";
@@ -3273,7 +3234,7 @@ private void ProcessStatement(OfxDownloadData results, Account a, XElement srs)
32733234
// process INVACCTFROM
32743235
private bool CheckAccountId(ref Account a, AccountType accountType, XElement from, OfxDownloadData results)
32753236
{
3276-
string accountid = from.SelectElementValue("ACCTID");
3237+
string accountid = from.SelectElementValue("ACCTID").GetNormalizedValue();
32773238

32783239
Account temp = new Account() { Name = accountid, AccountId = accountid, Type = accountType };
32793240

@@ -3446,7 +3407,7 @@ private Account FindAccountByOfxId(string accountId)
34463407

34473408
private static bool CheckUSD(XElement srs, OfxDownloadData results, Account a)
34483409
{
3449-
string dollar = srs.SelectElementValue("CURDEF");
3410+
string dollar = srs.SelectElementValue("CURDEF").GetNormalizedValue();
34503411

34513412
// todo: how to support multi-currency properly...
34523413
//if (dollar != "USD")

Source/WPF/MyMoney/Setup/changes.xml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
<?xml version="1.0" encoding="utf-8" ?>
22
<changes>
3-
<change version="2.0.0.6" date="5/172022">
3+
<change version="2.0.0.7" date="7/28/2022">
4+
- Fix a potential newline SQL injection bug.
5+
</change>
6+
<change version="2.0.0.6" date="5/17/2022">
47
- Fix initial setup of Attachments folder.
58
</change>
69
<change version="2.0.0.5" date="5/2/2022">

Source/WPF/MyMoney/Utilities/XmlHelpers.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,5 +116,20 @@ public static string GetRequiredAttribute(this XmlElement cdef, string name, str
116116
}
117117
return null;
118118
}
119+
120+
public static string GetNormalizedValue(this string s)
121+
{
122+
return s.Trim().Replace("\r\n", " ").Replace('\r', ' ').Replace('\n', ' ');
123+
}
124+
125+
public static int GetElementValueAsInt(this XElement e, int defaultValue = 0)
126+
{
127+
int i = 0;
128+
if (int.TryParse(e.Value.GetNormalizedValue(), out i))
129+
{
130+
return i;
131+
}
132+
return defaultValue;
133+
}
119134
}
120135
}

Source/WPF/Version/Version.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@
66
// And also sync this with the MSIX package manifest in
77
// ~\MyMoney.Net\Source\WPF\MoneyPackage\Package.appxmanifest
88

9-
[assembly: AssemblyVersion("2.0.0.6")]
10-
[assembly: AssemblyFileVersion("2.0.0.6")]
9+
[assembly: AssemblyVersion("2.0.0.7")]
10+
[assembly: AssemblyFileVersion("2.0.0.7")]

Source/WPF/Version/Version.props

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
33
<PropertyGroup>
4-
<ApplicationRevision>6</ApplicationRevision>
5-
<ApplicationVersion>2.0.0.6</ApplicationVersion>
4+
<ApplicationRevision>7</ApplicationRevision>
5+
<ApplicationVersion>2.0.0.7</ApplicationVersion>
66
</PropertyGroup>
77
</Project>

0 commit comments

Comments
 (0)