Files
atakanozbancom/Models/classes/DescriptionFormatter.cs
Atakan Doğan ÖzbanandCursor fc45c35dbe Add support page, admin features, and auth hardening.
Rename public affiliate route to /support with localized nav labels, and include affiliate/social/wallpaper admin, 2FA login, and related site updates.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-29 20:25:55 +02:00

48 lines
1.9 KiB
C#

using System.Text.RegularExpressions;
using System.Web;
namespace atakanozbancom.Models.classes
{
/// <summary>
/// Renders user-entered project/affiliate descriptions as safe HTML.
/// The whole input is HTML-encoded first (so no raw tags/scripts can ever
/// survive), then a very small Markdown-style link syntax is turned into
/// real anchor tags: [Link text](https://example.com)
/// Only http:// and https:// URLs are accepted; anything else is left as
/// plain (encoded) text.
/// </summary>
public static class DescriptionFormatter
{
// [label](https://url) - label can't contain "]", url must be http(s) and can't contain whitespace or ")"
private static readonly Regex LinkPattern = new Regex(
@"\[([^\]\r\n]{1,200})\]\((https?://[^\s)]{1,2000})\)",
RegexOptions.Compiled | RegexOptions.IgnoreCase);
public static string ToSafeHtml(string raw)
{
if (string.IsNullOrWhiteSpace(raw))
return string.Empty;
// 1) Neutralize everything (script/tags/attributes) up front.
var encoded = HttpUtility.HtmlEncode(raw);
// 2) Re-introduce ONLY safe <a> links for the [text](url) syntax.
// Both groups are already HTML-encoded, so this can't break out
// of the href attribute or inject new tags/attributes.
var withLinks = LinkPattern.Replace(encoded, m =>
{
var label = m.Groups[1].Value;
var url = m.Groups[2].Value;
return $"<a href=\"{url}\" class=\"text-secondary text-decoration-none\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">{label}</a>";
});
// 3) Preserve line breaks the admin typed in the textarea.
var withBreaks = withLinks
.Replace("\r\n", "\n")
.Replace("\n", "<br />");
return withBreaks;
}
}
}