Skip to content

Commit cdcf09f

Browse files
committed
Minor improvements and fixes
1 parent 9a6f35f commit cdcf09f

File tree

7 files changed

+68
-28
lines changed

7 files changed

+68
-28
lines changed

src/BlazorFrame.Tests/Services/MessageValidationServiceTests.cs

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,8 @@ public void ValidateMessage_WithStrictValidationAndTooDeepNesting_ReturnsInvalid
187187
result.IsValid.Should().BeFalse();
188188

189189
// The error message can be either our custom message or the JSON parser's depth limit message
190-
(result.ValidationError.Contains("JSON structure is too complex or deeply nested") ||
190+
result.ValidationError.Should().NotBeNull();
191+
(result.ValidationError!.Contains("JSON structure is too complex or deeply nested") ||
191192
(result.ValidationError.Contains("Invalid JSON format") && result.ValidationError.Contains("maximum configured depth")))
192193
.Should().BeTrue("because deep nesting should be detected and reported");
193194
}
@@ -293,10 +294,6 @@ public void ValidateMessage_WithCustomValidatorThrowingException_ReturnsInvalidM
293294
[InlineData("vbscript:MsgBox('xss')")]
294295
[InlineData("onload=alert('xss')")]
295296
[InlineData("onerror=alert('xss')")]
296-
[InlineData("eval(maliciousCode)")]
297-
[InlineData("Function('return evil')()")]
298-
[InlineData("setTimeout(hack, 1000)")]
299-
[InlineData("setInterval(malware, 100)")]
300297
public void ValidateMessage_WithSuspiciousPatterns_ReturnsInvalidMessage(string suspiciousContent)
301298
{
302299
// Arrange
@@ -355,11 +352,11 @@ public void ExtractOrigin_WithSpecialSchemes_ReturnsSchemePrefix(string url, str
355352
[InlineData("invalid-url")]
356353
[InlineData("ftp://unsupported.com")]
357354
[InlineData("file:///local/file")]
358-
public void ExtractOrigin_WithInvalidUrl_ReturnsNull(string url)
355+
public void ExtractOrigin_WithInvalidUrl_ReturnsNull(string? url)
359356
{
360357
// Arrange
361358
// Act
362-
var result = _validationService.ExtractOrigin(url);
359+
var result = _validationService.ExtractOrigin(url!);
363360

364361
// Assert
365362
result.Should().BeNull();
@@ -391,13 +388,13 @@ public void ValidateUrl_WithValidUrl_ReturnsValid(string url)
391388
[Theory]
392389
[InlineData(null)]
393390
[InlineData("")]
394-
public void ValidateUrl_WithNullOrEmptyUrl_ReturnsInvalid(string url)
391+
public void ValidateUrl_WithNullOrEmptyUrl_ReturnsInvalid(string? url)
395392
{
396393
// Arrange
397394
var options = new MessageSecurityOptions();
398395

399396
// Act
400-
var (isValid, errorMessage) = _validationService.ValidateUrl(url, options);
397+
var (isValid, errorMessage) = _validationService.ValidateUrl(url!, options);
401398

402399
// Assert
403400
isValid.Should().BeFalse();

src/BlazorFrame/BlazorFrame.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@
2525
</ItemGroup>
2626

2727
<ItemGroup>
28-
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="8.0.16" />
29-
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.16" />
28+
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="8.0.24" />
29+
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.3" />
3030
</ItemGroup>
3131

3232
<ItemGroup>

src/BlazorFrame/BlazorFrame.razor.cs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,7 @@ protected override void OnParametersSet()
370370
UpdateAllowedOrigins();
371371
ValidateConfiguration();
372372
ValidateSrcUrl();
373+
ValidateResizeOptions();
373374
}
374375

375376
private void ValidateConfiguration()
@@ -405,7 +406,7 @@ private void ValidateConfiguration()
405406
MessageType = "configuration-validation"
406407
};
407408

408-
_ = Task.Run(async () =>
409+
_ = InvokeAsync(async () =>
409410
{
410411
try
411412
{
@@ -444,7 +445,7 @@ private void ValidateSrcUrl()
444445
MessageType = "url-validation"
445446
};
446447

447-
_ = Task.Run(async () =>
448+
_ = InvokeAsync(async () =>
448449
{
449450
try
450451
{
@@ -458,6 +459,18 @@ private void ValidateSrcUrl()
458459
}
459460
}
460461

462+
private void ValidateResizeOptions()
463+
{
464+
if (ResizeOptions == null)
465+
return;
466+
467+
var errors = ResizeOptions.Validate();
468+
foreach (var error in errors)
469+
{
470+
Logger?.LogError("BlazorFrame ResizeOptions validation error: {Error}", error);
471+
}
472+
}
473+
461474
protected override async Task OnAfterRenderAsync(bool firstRender)
462475
{
463476
if (isInitialized) return;
@@ -725,5 +738,7 @@ public async ValueTask DisposeAsync()
725738
objRef?.Dispose();
726739
isInitialized = false;
727740
}
741+
742+
GC.SuppressFinalize(this);
728743
}
729744
}

src/BlazorFrame/Messages/MessageSecurityOptions.cs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,6 @@
55
/// </summary>
66
public class MessageSecurityOptions
77
{
8-
/// <summary>
9-
/// List of allowed origins. If null or empty, will auto-derive from Src URL.
10-
/// </summary>
11-
public List<string>? AllowedOrigins { get; set; }
12-
138
/// <summary>
149
/// Whether to perform strict message format validation
1510
/// </summary>

src/BlazorFrame/Models/ResizeOptions.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,4 +53,30 @@ public class ResizeOptions
5353
PollingInterval = 250,
5454
DebounceMs = 50
5555
};
56+
57+
/// <summary>
58+
/// Validates the resize options and returns any errors
59+
/// </summary>
60+
/// <returns>List of validation error messages, empty if valid</returns>
61+
public List<string> Validate()
62+
{
63+
var errors = new List<string>();
64+
65+
if (MinHeight < 0)
66+
errors.Add("MinHeight must be >= 0.");
67+
68+
if (MaxHeight <= 0)
69+
errors.Add("MaxHeight must be > 0.");
70+
71+
if (MinHeight >= MaxHeight)
72+
errors.Add($"MinHeight ({MinHeight}) must be less than MaxHeight ({MaxHeight}).");
73+
74+
if (PollingInterval <= 0)
75+
errors.Add("PollingInterval must be > 0.");
76+
77+
if (DebounceMs < 0)
78+
errors.Add("DebounceMs must be >= 0.");
79+
80+
return errors;
81+
}
5682
}

src/BlazorFrame/Models/SandboxOptions.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ public enum SandboxPreset
2323
Permissive,
2424

2525
/// <summary>
26-
/// Strict sandbox: allow-scripts allow-same-origin (no forms, no popups)
27-
/// Suitable for display-only content with limited interaction
26+
/// Strict sandbox: allow-scripts allow-same-origin allow-top-navigation-by-user-activation
27+
/// Suitable for display-only content with limited interaction and user-initiated navigation
2828
/// </summary>
2929
Strict,
3030

@@ -52,7 +52,7 @@ public static class SandboxHelper
5252
SandboxPreset.None => null,
5353
SandboxPreset.Basic => "allow-scripts allow-same-origin",
5454
SandboxPreset.Permissive => "allow-scripts allow-same-origin allow-forms allow-popups",
55-
SandboxPreset.Strict => "allow-scripts allow-same-origin",
55+
SandboxPreset.Strict => "allow-scripts allow-same-origin allow-top-navigation-by-user-activation",
5656
SandboxPreset.Paranoid => "allow-scripts",
5757
_ => null
5858
};

src/BlazorFrame/Services/MessageValidationService.cs

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -299,20 +299,27 @@ private static bool ContainsSuspiciousContent(string messageJson)
299299
{
300300
var cleanJson = JsonCommentRegex.Replace(messageJson, "");
301301

302-
var suspiciousPatterns = new[]
302+
// HTML injection patterns - these are dangerous in any context
303+
var htmlPatterns = new[]
303304
{
304305
"<script",
305306
"javascript:",
306307
"vbscript:",
308+
};
309+
310+
// HTML event handler patterns - look for attribute-style injection
311+
var eventHandlerPatterns = new[]
312+
{
307313
"onload=",
308314
"onerror=",
309-
"eval(",
310-
"Function(",
311-
"setTimeout(",
312-
"setInterval("
315+
"onclick=",
316+
"onmouseover=",
317+
"onfocus=",
313318
};
314319

315-
return suspiciousPatterns.Any(pattern =>
320+
return htmlPatterns.Any(pattern =>
321+
cleanJson.Contains(pattern, StringComparison.OrdinalIgnoreCase))
322+
|| eventHandlerPatterns.Any(pattern =>
316323
cleanJson.Contains(pattern, StringComparison.OrdinalIgnoreCase));
317324
}
318325

@@ -327,7 +334,7 @@ private static bool IsValidMessageType(string messageType)
327334
return messageType.All(c => char.IsLetterOrDigit(c) || c == '-' || c == '_' || c == '.');
328335
}
329336

330-
private static IframeMessage CreateInvalidMessage(string origin, string messageJson, string error)
337+
private static IframeMessage CreateInvalidMessage(string origin, string messageJson, string? error)
331338
{
332339
return new IframeMessage
333340
{

0 commit comments

Comments
 (0)