Skip to content

Commit 2694886

Browse files
committed
Add basic sanitation
1 parent 291ac20 commit 2694886

5 files changed

Lines changed: 80 additions & 32 deletions

File tree

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using System.Collections.Generic;
2+
using System.Text.RegularExpressions;
3+
4+
namespace SSR.Net.Extensions
5+
{
6+
public static class StringExtensions
7+
{
8+
static readonly Regex ToEscape = new Regex("<|>", RegexOptions.Compiled);
9+
public static string SanitizeInitScript(this string script)
10+
{
11+
var replacements = new Dictionary<string, string>
12+
{
13+
{ "<", "\\u003c" },
14+
{ ">", "\\u003e" }
15+
};
16+
return ToEscape.Replace(script, match => replacements[match.Value]);
17+
}
18+
}
19+
}

src/SSR.Net/Services/React17Renderer.cs

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using SSR.Net.Exceptions;
2+
using SSR.Net.Extensions;
23
using SSR.Net.Models;
34
using System;
45

@@ -20,48 +21,54 @@ public React17Renderer(IJavaScriptEnginePool javaScriptEnginePool) =>
2021
public RenderedComponent RenderComponent(string componentName,
2122
string propsAsJson,
2223
int waitForEngineTimeoutMs = 50,
23-
bool fallbackToClientSideRender = true)
24+
bool fallbackToClientSideRender = true,
25+
bool sanitize = true)
2426
{
2527
var result = new RenderedComponent();
2628
var id = CreateId();
2729
var script = string.Format(SSREngineScript, componentName, propsAsJson);
2830
string html;
29-
try
30-
{
31+
try {
3132
html = _javaScriptEnginePool.EvaluateJs(script, waitForEngineTimeoutMs);
3233
}
3334
catch (Exception ex) {
3435
if (!fallbackToClientSideRender)
3536
throw ex;
36-
return FallbackToCSRWithException(componentName, propsAsJson, ex);
37+
return FallbackToCSRWithException(componentName, propsAsJson, ex, sanitize);
3738
}
3839
if (html is null)
39-
return RenderComponentCSR(componentName, propsAsJson);
40+
return RenderComponentCSR(componentName, propsAsJson, sanitize);
4041
result.Html = string.Format(SSRHtml, id, html);
4142
result.InitScript = string.Format(ClientHydrateScript, componentName, propsAsJson, id);
43+
if (sanitize)
44+
result.InitScript = result.InitScript.SanitizeInitScript();
4245
return result;
4346
}
4447

45-
private RenderedComponent FallbackToCSRWithException(string componentName, string propsAsJson, Exception ex) {
46-
var result = RenderComponentCSR(componentName, propsAsJson);
48+
private RenderedComponent FallbackToCSRWithException(string componentName, string propsAsJson, Exception ex, bool sanitize)
49+
{
50+
var result = RenderComponentCSR(componentName, propsAsJson, sanitize);
4751
if (ex is AcquireJavaScriptEngineTimeoutException timeoutException)
4852
result.TimeoutException = timeoutException;
4953
else
5054
result.RenderException = ex;
5155
return result;
5256
}
5357

54-
private static string CreateId() =>
58+
private static string CreateId() =>
5559
"react_" + Guid.NewGuid().ToString().Replace("-", "");
5660

57-
public RenderedComponent RenderComponentCSR(string componentName, string propsAsJson)
61+
public RenderedComponent RenderComponentCSR(string componentName, string propsAsJson, bool sanitize = true)
5862
{
5963
var id = CreateId();
60-
return new RenderedComponent
64+
var result = new RenderedComponent
6165
{
6266
Html = string.Format(CSRHtml, id),
6367
InitScript = string.Format(ClientRenderScript, componentName, propsAsJson, id)
6468
};
69+
if (sanitize)
70+
result.InitScript = result.InitScript.SanitizeInitScript();
71+
return result;
6572
}
6673
}
6774
}

src/SSR.Net/Services/React18Renderer.cs

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using SSR.Net.Exceptions;
2+
using SSR.Net.Extensions;
23
using SSR.Net.Models;
34
using System;
45

@@ -20,45 +21,51 @@ public React18Renderer(IJavaScriptEnginePool javaScriptEnginePool) =>
2021
public RenderedComponent RenderComponent(string componentName,
2122
string propsAsJson,
2223
int waitForEngineTimeoutMs = 50,
23-
bool fallbackToClientSideRender = true)
24+
bool fallbackToClientSideRender = true,
25+
bool sanitize = true)
2426
{
2527
var result = new RenderedComponent();
2628
var id = CreateId();
2729
var script = string.Format(SSREngineScript, componentName, propsAsJson);
2830
string html = null;
29-
try
30-
{
31+
try {
3132
html = _javaScriptEnginePool.EvaluateJs(script, waitForEngineTimeoutMs);
3233
}
3334
catch (Exception ex) {
3435
if (!fallbackToClientSideRender)
3536
throw ex;
36-
return FallbackToCSRWithException(componentName, propsAsJson, ex);
37+
return FallbackToCSRWithException(componentName, propsAsJson, ex, sanitize);
3738
}
3839
if (html is null)
39-
return RenderComponentCSR(componentName, propsAsJson);
40+
return RenderComponentCSR(componentName, propsAsJson, sanitize);
4041
result.Html = string.Format(SSRHtml, id, html);
4142
result.InitScript = string.Format(ClientHydrateScript, id, componentName, propsAsJson);
43+
if (sanitize)
44+
result.InitScript = result.InitScript.SanitizeInitScript();
4245
return result;
4346
}
4447

45-
private RenderedComponent FallbackToCSRWithException(string componentName, string propsAsJson, Exception ex) {
46-
var result = RenderComponentCSR(componentName, propsAsJson);
48+
private RenderedComponent FallbackToCSRWithException(string componentName, string propsAsJson, Exception ex, bool sanitize)
49+
{
50+
var result = RenderComponentCSR(componentName, propsAsJson, sanitize);
4751
if (ex is AcquireJavaScriptEngineTimeoutException timeoutException)
4852
result.TimeoutException = timeoutException;
4953
else
5054
result.RenderException = ex;
5155
return result;
5256
}
5357

54-
public RenderedComponent RenderComponentCSR(string componentName, string propsAsJson)
58+
public RenderedComponent RenderComponentCSR(string componentName, string propsAsJson, bool sanitize = true)
5559
{
5660
var id = CreateId();
57-
return new RenderedComponent
61+
var result = new RenderedComponent
5862
{
5963
Html = string.Format(CSRHtml, id),
6064
InitScript = string.Format(ClientRenderScript, id, componentName, propsAsJson)
6165
};
66+
if (sanitize)
67+
result.InitScript = result.InitScript.SanitizeInitScript();
68+
return result;
6269
}
6370

6471
private static string CreateId() =>

src/SSR.Net/Services/React19Renderer.cs

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using SSR.Net.Exceptions;
2+
using SSR.Net.Extensions;
23
using SSR.Net.Models;
34
using System;
45

@@ -20,45 +21,51 @@ public React19Renderer(IJavaScriptEnginePool javaScriptEnginePool) =>
2021
public RenderedComponent RenderComponent(string componentName,
2122
string propsAsJson,
2223
int waitForEngineTimeoutMs = 50,
23-
bool fallbackToClientSideRender = true)
24+
bool fallbackToClientSideRender = true,
25+
bool sanitize = true)
2426
{
2527
var result = new RenderedComponent();
2628
var id = CreateId();
2729
var script = string.Format(SSREngineScript, componentName, propsAsJson);
2830
string html = null;
29-
try
30-
{
31+
try {
3132
html = _javaScriptEnginePool.EvaluateJs(script, waitForEngineTimeoutMs);
3233
}
3334
catch (Exception ex) {
3435
if (!fallbackToClientSideRender)
3536
throw ex;
36-
return FallbackToCSRWithException(componentName, propsAsJson, ex);
37+
return FallbackToCSRWithException(componentName, propsAsJson, ex, sanitize);
3738
}
3839
if (html is null)
39-
return RenderComponentCSR(componentName, propsAsJson);
40+
return RenderComponentCSR(componentName, propsAsJson, sanitize);
4041
result.Html = string.Format(SSRHtml, id, html);
4142
result.InitScript = string.Format(ClientHydrateScript, id, componentName, propsAsJson);
43+
if (sanitize)
44+
result.InitScript = result.InitScript.SanitizeInitScript();
4245
return result;
4346
}
4447

45-
private RenderedComponent FallbackToCSRWithException(string componentName, string propsAsJson, Exception ex) {
46-
var result = RenderComponentCSR(componentName, propsAsJson);
48+
private RenderedComponent FallbackToCSRWithException(string componentName, string propsAsJson, Exception ex, bool sanitize)
49+
{
50+
var result = RenderComponentCSR(componentName, propsAsJson, sanitize);
4751
if (ex is AcquireJavaScriptEngineTimeoutException timeoutException)
4852
result.TimeoutException = timeoutException;
4953
else
5054
result.RenderException = ex;
5155
return result;
5256
}
5357

54-
public RenderedComponent RenderComponentCSR(string componentName, string propsAsJson)
58+
public RenderedComponent RenderComponentCSR(string componentName, string propsAsJson, bool sanitize = true)
5559
{
5660
var id = CreateId();
57-
return new RenderedComponent
61+
var result = new RenderedComponent
5862
{
5963
Html = string.Format(CSRHtml, id),
6064
InitScript = string.Format(ClientRenderScript, id, componentName, propsAsJson)
6165
};
66+
if (sanitize)
67+
result.InitScript = result.InitScript.SanitizeInitScript();
68+
return result;
6269
}
6370

6471
private static string CreateId() =>

src/SSR.Net/Services/Vue3Renderer.cs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using SSR.Net.Exceptions;
2+
using SSR.Net.Extensions;
23
using SSR.Net.Models;
34
using System;
45
using System.Threading.Tasks;
@@ -25,7 +26,8 @@ public async Task<RenderedComponent> RenderComponentAsync(string componentName,
2526
string propsAsJson,
2627
int waitForEngineTimeoutMs = 50,
2728
bool fallbackToClientSideRender = true,
28-
int asyncTimeoutMs = 200)
29+
int asyncTimeoutMs = 200,
30+
bool sanitize = true)
2931
{
3032
var result = new RenderedComponent();
3133
var id = CreateExecutionId();
@@ -44,10 +46,13 @@ public async Task<RenderedComponent> RenderComponentAsync(string componentName,
4446
return RenderComponentCSR(componentName, propsAsJson);
4547
result.Html = html;
4648
result.InitScript = string.Format(ClientHydrateScript, componentName, propsAsJson, id);
49+
if (sanitize)
50+
result.InitScript = result.InitScript.SanitizeInitScript();
4751
return result;
4852
}
4953

50-
private RenderedComponent FallbackToCSRWithException(string componentName, string propsAsJson, Exception ex) {
54+
private RenderedComponent FallbackToCSRWithException(string componentName, string propsAsJson, Exception ex)
55+
{
5156
var result = RenderComponentCSR(componentName, propsAsJson);
5257
if (ex is AcquireJavaScriptEngineTimeoutException timeoutException)
5358
result.TimeoutException = timeoutException;
@@ -59,14 +64,17 @@ private RenderedComponent FallbackToCSRWithException(string componentName, strin
5964
private static string CreateExecutionId() =>
6065
"vue_" + Guid.NewGuid().ToString().Replace("-", "");
6166

62-
public RenderedComponent RenderComponentCSR(string componentName, string propsAsJson)
67+
public RenderedComponent RenderComponentCSR(string componentName, string propsAsJson, bool sanitize = true)
6368
{
6469
var id = CreateExecutionId();
65-
return new RenderedComponent
70+
var result = new RenderedComponent
6671
{
6772
Html = string.Format(CSRHtml, id),
6873
InitScript = string.Format(ClientRenderScript, componentName, propsAsJson, id)
6974
};
75+
if (sanitize)
76+
result.InitScript = result.InitScript.SanitizeInitScript();
77+
return result;
7078
}
7179
}
7280
}

0 commit comments

Comments
 (0)