Skip to content

Commit 128ea3f

Browse files
authored
Merge pull request #1576 from johnhenley/issues/fix-html-encoding-part-2-1385
FIX: Additional work on XML/HTML encoding for content display of code blocks
2 parents 483299a + e8de7bb commit 128ea3f

File tree

10 files changed

+152
-16
lines changed

10 files changed

+152
-16
lines changed

Dnn.CommunityForums/Entities/ReplyInfo.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -401,11 +401,11 @@ public string GetProperty(string propertyName, string format, System.Globalizati
401401
}
402402

403403
case "summary":
404-
return PropertyAccess.FormatString(Utilities.EncodeBrackets(System.Web.HttpUtility.HtmlEncode(length > 0 && this.Summary.Length > length ? this.Summary.Substring(0, length) : this.Summary)), format);
404+
return PropertyAccess.FormatString(Utilities.EncodeBrackets(length > 0 && this.Summary.Length > length ? this.Summary.Substring(0, length) : this.Summary), format);
405405
case "body":
406-
return PropertyAccess.FormatString(Utilities.EncodeBrackets(System.Web.HttpUtility.HtmlEncode(length > 0 && this.Content.Body.Length > length ? this.Content.Body.Substring(0, length) : this.Content.Body)), format);
406+
return PropertyAccess.FormatString(Utilities.EncodeBrackets(Utilities.EncodeCodeBlocks(length > 0 && this.Content.Body.Length > length ? this.Content.Body.Substring(0, length) : this.Content.Body)), format);
407407
case "bodytitle":
408-
return PropertyAccess.FormatString(Utilities.EncodeBrackets(System.Web.HttpUtility.HtmlEncode(GetTopicTitle(this.Content.Body))), format);
408+
return PropertyAccess.FormatString(Utilities.EncodeBrackets(GetTopicTitle(this.Content.Body)), format);
409409
case "link":
410410
{
411411
string sTopicURL = new ControlUtils().BuildUrl(this.Forum.PortalSettings.PortalId, this.GetTabId(), this.Forum.ModuleId, this.Forum.ForumGroup.PrefixURL, this.Forum.PrefixURL, this.Forum.ForumGroupId, this.Forum.ForumID, this.TopicId, this.Topic.TopicUrl, -1, -1, string.Empty, 1, this.ContentId, this.Forum.SocialGroupId);

Dnn.CommunityForums/Entities/TopicInfo.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -736,15 +736,15 @@ public string GetProperty(string propertyName, string format, System.Globalizati
736736

737737
return string.Empty;
738738
case "bodytitle":
739-
return PropertyAccess.FormatString(Utilities.EncodeBrackets(System.Web.HttpUtility.HtmlEncode(GetTopicTitle(this.Content.Body))), format);
739+
return PropertyAccess.FormatString(Utilities.EncodeBrackets(GetTopicTitle(this.Content.Body)), format);
740740
case "summary":
741741
return PropertyAccess.FormatString(
742-
Utilities.EncodeBrackets(System.Web.HttpUtility.HtmlEncode(
742+
Utilities.EncodeBrackets(
743743
!string.IsNullOrEmpty(this.Summary)
744744
? length > 0 && this.Summary.Length > length ? this.Summary.Substring(0, length) : this.Summary
745-
: length > 0 && this.Content.Body.Length > length ? this.Content.Body.Substring(0, length) : this.Content.Body)), format);
745+
: length > 0 && this.Content.Body.Length > length ? this.Content.Body.Substring(0, length) : this.Content.Body), format);
746746
case "body":
747-
return PropertyAccess.FormatString(Utilities.EncodeBrackets(System.Web.HttpUtility.HtmlEncode(length > 0 && this.Content.Body.Length > length ? this.Content.Body.Substring(0, length) : this.Content.Body)), format);
747+
return PropertyAccess.FormatString(Utilities.EncodeBrackets(Utilities.EncodeCodeBlocks(length > 0 && this.Content.Body.Length > length ? this.Content.Body.Substring(0, length) : this.Content.Body)), format);
748748
case "lastreplyid":
749749
return PropertyAccess.FormatString(this.LastReplyId.ToString(), format);
750750
case "replycount":

Dnn.CommunityForums/class/CodeParser.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ namespace DotNetNuke.Modules.ActiveForums
2222
{
2323
using System.Text.RegularExpressions;
2424

25-
public class CodeParser
25+
public static class CodeParser
2626
{
2727
public static string ParseCode(string sCode)
2828
{
@@ -83,5 +83,12 @@ private static string HandleBrackets(string sCode)
8383

8484
return sCode;
8585
}
86+
87+
internal static string ConvertCodeBrackets(string text)
88+
{
89+
text = Regex.Replace(text, "\\[CODE\\]", "<pre><code>", RegexOptions.IgnoreCase);
90+
text = Regex.Replace(text, "\\[\\/CODE\\]", "</code></pre>", RegexOptions.IgnoreCase);
91+
return text;
92+
}
8693
}
8794
}

Dnn.CommunityForums/class/TemplateUtils.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -595,7 +595,6 @@ private static string ParsePreview(int portalId, string template, string message
595595
}
596596
}
597597

598-
var objCode = new CodeParser();
599598
template = CodeParser.ParseCode(System.Net.WebUtility.HtmlDecode(template));
600599
}
601600

Dnn.CommunityForums/class/Utilities.cs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -520,7 +520,7 @@ private static string CleanTextBox(int portalId, string text, bool allowHTML, bo
520520
strMessage = DotNetNuke.Modules.ActiveForums.Controllers.FilterController.RemoveFilterWords(portalId, moduleId, themePath, strMessage, processEmoticons, false, HttpContext.Current.Request.Url);
521521
}
522522

523-
strMessage = System.Net.WebUtility.HtmlEncode(strMessage);
523+
//strMessage = System.Net.WebUtility.HtmlEncode(strMessage);
524524
strMessage = ReplaceNewLineWithHtmlBreakTag(strMessage);
525525

526526
i = 0;
@@ -546,7 +546,22 @@ private static string CleanTextBox(int portalId, string text, bool allowHTML, bo
546546
strMessage = ReplaceNewLineWithHtmlBreakTag(strMessage);
547547
}
548548

549-
strMessage = EncodeBrackets(strMessage);
549+
//strMessage = EncodeBrackets(strMessage);
550+
}
551+
552+
return strMessage;
553+
}
554+
555+
internal static string EncodeCodeBlocks(string text)
556+
{
557+
string strMessage = text;
558+
if (!String.IsNullOrEmpty(strMessage) && (strMessage.ToUpperInvariant().Contains("[CODE]") || strMessage.ToUpperInvariant().Contains("<CODE")))
559+
{
560+
var pattern = @"[\[<]code[\]>](?<codeblock>(?s:.)*?)[\[<]\/code[\]>]";
561+
foreach (Match m in RegexUtils.GetCachedRegex(pattern, RegexOptions.Compiled & RegexOptions.IgnoreCase).Matches(strMessage))
562+
{
563+
strMessage = strMessage.Replace(m.Value, System.Web.HttpUtility.HtmlEncode(m.Value));
564+
}
550565
}
551566

552567
return strMessage;

Dnn.CommunityForums/controls/af_post.ascx.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -620,7 +620,8 @@ private void PrepareReply()
620620
{
621621
if (body.ToUpperInvariant().Contains("<CODE") || body.ToUpperInvariant().Contains("[CODE]"))
622622
{
623-
body = CodeParser.ParseCode(System.Net.WebUtility.HtmlDecode(body));
623+
//body = CodeParser.ParseCode(System.Net.WebUtility.HtmlDecode(body));
624+
body = Utilities.EncodeCodeBlocks(body);
624625
}
625626
}
626627
else

Dnn.CommunityForums/controls/af_quickreply.ascx.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ private void SaveQuickReply()
308308
this.AllowHTML = this.IsHtmlPermitted(this.ForumInfo.FeatureSettings.EditorPermittedUsers, this.IsTrusted, DotNetNuke.Modules.ActiveForums.Controllers.PermissionController.HasRequiredPerm(this.ForumInfo.Security.ModerateRoleIds, this.ForumUser.UserRoleIds));
309309
}
310310

311-
sBody = Utilities.CleanString(this.PortalId, this.Request.Form["txtBody"], this.AllowHTML, EditorTypes.TEXTBOX, this.UseFilter, this.AllowScripts, this.ForumModuleId, this.ThemePath, this.ForumInfo.FeatureSettings.AllowEmoticons);
311+
sBody = Utilities.CleanString(this.PortalId, CodeParser.ConvertCodeBrackets(this.Request.Form["txtBody"]), this.AllowHTML, EditorTypes.TEXTBOX, this.UseFilter, this.AllowScripts, this.ForumModuleId, this.ThemePath, this.ForumInfo.FeatureSettings.AllowEmoticons);
312312
ri.Content.AuthorId = this.UserId;
313313
ri.Content.AuthorName = sUsername;
314314
ri.Content.Body = sBody;

Dnn.CommunityForumsTests/Services/Tokens/TokenReplacerTests.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,9 @@ public void ReplaceForumTokensTest2()
380380
ForumGroup = new DotNetNuke.Modules.ActiveForums.Entities.ForumGroupInfo
381381
{
382382
GroupName = "Test Forum Group",
383+
PortalSettings = DotNetNuke.Entities.Portals.PortalController.Instance.GetCurrentPortalSettings(),
384+
FeatureSettings = new DotNetNuke.Modules.ActiveForums.Entities.FeatureSettings(featureSettings),
385+
Security = mockPermissions.Object,
383386
},
384387
FeatureSettings = new DotNetNuke.Modules.ActiveForums.Entities.FeatureSettings(featureSettings),
385388
},
@@ -424,7 +427,7 @@ public void ReplaceForumTokensTest2()
424427
// Assert
425428
Assert.That(actualResult, Is.EqualTo(expectedResult));
426429
}
427-
430+
428431
[Test]
429432
public void RemovePrefixedToken1()
430433
{
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// Copyright (c) by DNN Community
2+
//
3+
// DNN Community licenses this file to you under the MIT license.
4+
//
5+
// See the LICENSE file in the project root for more information.
6+
//
7+
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
8+
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
9+
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
10+
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
11+
//
12+
// The above copyright notice and this permission notice shall be included in all copies or substantial portions
13+
// of the Software.
14+
//
15+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
16+
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17+
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
18+
// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19+
// DEALINGS IN THE SOFTWARE.
20+
21+
namespace DotNetNuke.Modules.ActiveForumsTests
22+
{
23+
using System.Reflection;
24+
25+
using DotNetNuke.Modules.ActiveForums;
26+
using NUnit.Framework;
27+
28+
[TestFixture]
29+
public partial class CodeParserTests : DotNetNuke.Modules.ActiveForumsTests.TestBase
30+
{
31+
[TestCase("[CODE]test[/CODE]", "<div class=\"afcodeblock\"><pre><code>test</code></pre></div>")]
32+
[TestCase("No code here", "No code here")]
33+
public void ParseCode_ReturnsExpectedHtml(string input, string expected)
34+
{
35+
var result = CodeParser.ParseCode(input);
36+
Assert.That(result, Does.Contain(expected));
37+
}
38+
39+
[TestCase("[CODE]test[/CODE]", "<pre><code>test</code></pre>")]
40+
[TestCase("[/CODE]", "</code></pre>")]
41+
public void ConvertCodeBrackets_ConvertsBrackets(string input, string expected)
42+
{
43+
var result = CodeParser.ConvertCodeBrackets(input);
44+
Assert.That(result, Does.Contain(expected));
45+
}
46+
47+
[TestCase("&#91;CODE&#93;", "[CODE]")]
48+
[TestCase("&amp;#91;CODE&amp;#93;", "[CODE]")]
49+
[TestCase("&#93;", "]")]
50+
[TestCase("&amp;#93;", "]")]
51+
public void HandleBrackets_ReplacesEntities(string input, string expected)
52+
{
53+
var method = typeof(CodeParser).GetMethod("HandleBrackets", BindingFlags.NonPublic | BindingFlags.Static);
54+
var result = method.Invoke(null, new object[] { input }) as string;
55+
Assert.That(result, Is.EqualTo(expected));
56+
}
57+
}
58+
}

Dnn.CommunityForumsTests/class/UtilitiesTests.cs

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,10 @@
1818
// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
1919
// DEALINGS IN THE SOFTWARE.
2020

21-
using System.Collections;
22-
2321
namespace DotNetNuke.Modules.ActiveForumsTests
2422
{
2523
using System;
24+
using System.Collections;
2625
using System.Globalization;
2726

2827
using DotNetNuke.Modules.ActiveForums;
@@ -459,5 +458,59 @@ public void GetSha256HashTest()
459458
// Assert
460459
Assert.That(actualResult, Is.EqualTo(expectedResult));
461460
}
461+
462+
[Test]
463+
public void EncodeCodeBlocks_NullOrEmpty_ReturnsInput()
464+
{
465+
Assert.Multiple(() =>
466+
{
467+
Assert.That(Utilities.EncodeCodeBlocks(null), Is.Null);
468+
Assert.That(Utilities.EncodeCodeBlocks(string.Empty), Is.Empty);
469+
});
470+
}
471+
472+
[Test]
473+
public void EncodeCodeBlocks_NoCodeTags_ReturnsInput()
474+
{
475+
var input = "This is a test without code tags.";
476+
var result = Utilities.EncodeCodeBlocks(input);
477+
Assert.That(result, Is.EqualTo(input));
478+
}
479+
480+
[Test]
481+
public void EncodeCodeBlocks_WithCodeTags_EncodesBlock()
482+
{
483+
var input = "Some text [code]int x = 1;[/code] more text";
484+
var expectedEncoded = System.Net.WebUtility.HtmlEncode("[code]int x = 1;[/code]");
485+
var result = Utilities.EncodeCodeBlocks(input);
486+
Assert.That(result.Contains(expectedEncoded), Is.True);
487+
}
488+
489+
[Test]
490+
public void EncodeCodeBlocks_WithAngleCodeTags_EncodesBlock()
491+
{
492+
var input = "Some text <code>int y = 2;</code> more text";
493+
var expectedEncoded = System.Net.WebUtility.HtmlEncode("<code>int y = 2;</code>");
494+
var result = Utilities.EncodeCodeBlocks(input);
495+
Assert.Multiple(() =>
496+
{
497+
Assert.That(result.Contains(expectedEncoded), Is.True);
498+
Assert.That(result.Contains("<code>int y = 2;</code>"), Is.False);
499+
});
500+
}
501+
502+
[Test]
503+
public void EncodeCodeBlocks_MultipleCodeBlocks_EncodesAll()
504+
{
505+
var input = "[code]a[/code] and <code>b</code>";
506+
var expected1 = System.Net.WebUtility.HtmlEncode("[code]a[/code]");
507+
var expected2 = System.Net.WebUtility.HtmlEncode("<code>b</code>");
508+
var result = Utilities.EncodeCodeBlocks(input);
509+
Assert.Multiple(() =>
510+
{
511+
Assert.That(result.Contains(expected1), Is.True);
512+
Assert.That(result.Contains(expected2), Is.True);
513+
});
514+
}
462515
}
463516
}

0 commit comments

Comments
 (0)