Skip to content

Commit

Permalink
Merge branch 'main' into release/4.1
Browse files Browse the repository at this point in the history
  • Loading branch information
tomasherceg committed Jan 17, 2023
2 parents 6c3947e + bcc3c9a commit 1a8edbc
Show file tree
Hide file tree
Showing 10 changed files with 129 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ public MarkupDirectiveCompilerPipeline(IAbstractTreeBuilder treeBuilder, IContro

public MarkupPageMetadata Compile(DothtmlRootNode dothtmlRoot, string fileName)
{
var directivesByName = dothtmlRoot.Directives.GroupBy(d => d.Name, StringComparer.OrdinalIgnoreCase).ToDictionary(d => d.Key, d => (IReadOnlyList<DothtmlDirectiveNode>)d.ToList());
var directivesByName = dothtmlRoot.Directives
.GroupBy(d => d.Name, StringComparer.OrdinalIgnoreCase)
.ToDictionary(d => d.Key, d => (IReadOnlyList<DothtmlDirectiveNode>)d.ToList(), StringComparer.OrdinalIgnoreCase);

var resolvedDirectives = new Dictionary<string, IReadOnlyList<IAbstractDirective>>();

Expand Down
20 changes: 15 additions & 5 deletions src/Framework/Framework/Hosting/DotvvmPresenter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -477,9 +477,15 @@ async Task ValidateSecFetchHeaders(IDotvvmRequestContext context)
else
{
if (site == "same-origin")
await context.RejectRequest($"Same site iframe are disabled in this application. If you are the developer, you can enable iframes by setting DotvvmConfiguration.Security.FrameOptionsSameOrigin.EnableForRoute(\"{route}\")");
await context.RejectRequest($"""
Same site iframe are disabled in this application.
If you are the developer, you can enable iframes by setting DotvvmConfiguration.Security.FrameOptionsSameOrigin.EnableForRoute("{route}")
""");
else
await context.RejectRequest($"Cross site iframe are disabled in this application. If you are the developer, you can enable cross-site iframes by setting DotvvmConfiguration.Security.FrameOptionsCrossOrigin.EnableForRoute(\"{route}\"). Note that it's not recommended to enable cross-site iframes for sites / pages where security is important (due to Clickjacking)");
await context.RejectRequest($"""
Cross site iframe are disabled in this application.
If you are the developer, you can enable cross-site iframes by setting DotvvmConfiguration.Security.FrameOptionsCrossOrigin.EnableForRoute("{route}"). Note that it's not recommended to enable cross-site iframes for sites / pages where security is important (due to Clickjacking)
""");
}
}

Expand All @@ -491,7 +497,7 @@ async Task ValidateSecFetchHeaders(IDotvvmRequestContext context)
if (site != "same-origin")
await context.RejectRequest($"Cross site postbacks are disabled.");
if (dest != "empty")
await context.RejectRequest($"postbacks must have Sec-Fetch-Dest: empty");
await context.RejectRequest($"Postbacks must have Sec-Fetch-Dest: empty");
}
else
{
Expand All @@ -505,12 +511,16 @@ async Task ValidateSecFetchHeaders(IDotvvmRequestContext context)
else if (dest is "empty")
{
if (!DetermineSpaRequest(context.HttpContext))
await context.RejectRequest($"Pages can not be loaded using Javascript for security reasons. If you are the developer, you can disable this check by setting DotvvmConfiguration.Security.VerifySecFetchForPages.DisableForRoute(\"{route}\"). [dest: {dest}, site: {site}]");
await context.RejectRequest($"""
Pages can not be loaded using Javascript for security reasons.
Try refreshing the page to get rid of the error.
If you are the developer, you can disable this check by setting DotvvmConfiguration.Security.VerifySecFetchForPages.DisableForRoute("{route}"). [dest: {dest}, site: {site}]
""");
if (site != "same-origin")
await context.RejectRequest($"Cross site SPA requests are disabled.");
}
else
await context.RejectRequest("Can not load a DotVVM page with this Sec-Fetch-Dest.");
await context.RejectRequest($"Cannot load a DotVVM page with Sec-Fetch-Dest: {dest}.");
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,10 @@ private async Task ValidateSecFetch(IDotvvmRequestContext c)
// the user may have control over contents of the file and it may served from a trusted domain.
// if you don't like this behavior, you can return the file from your own middleware,
// we'll not add an option to disable this check.
if (site == "cross-site" || dest != "document")

// in addition to navigation, we also allow usage from JS, since it simplifies service worker implementation
// and there probably isn't a way to do harm (we need to prevent the files getting into script tags, styles, ...)
if (!(site != "cross-site" && dest is "document" or "empty"))
await c.RejectRequest("Returned file can only be used from same-site navigation.");
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,15 @@ public bool Contains(KeyValuePair<string, string[]> item)

public void CopyTo(KeyValuePair<string, string[]>[] array, int arrayIndex)
{
throw new NotImplementedException();
if (array.Length - arrayIndex < OriginalHeaders.Count)
throw new ArgumentException("Insufficient array size");

foreach (var (key, values) in OriginalHeaders)
{
var valuesCopy = (values.Count > 0) ? new string[values.Count] : Array.Empty<string>();
Array.Copy(values, valuesCopy, values.Count);
array[arrayIndex++] = new KeyValuePair<string, string[]>(key: key, value: valuesCopy);
}
}

public bool Remove(KeyValuePair<string, string[]> item)
Expand Down
1 change: 1 addition & 0 deletions src/Samples/Common/DotVVM.Samples.Common.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
<None Remove="Views\FeatureSamples\Api\ApiInSpa_PageA.dothtml" />
<None Remove="Views\FeatureSamples\Api\ApiInSpa_PageB.dothtml" />
<None Remove="Views\FeatureSamples\Api\ApiRefresh.dothtml" />
<None Remove="Views\FeatureSamples\Api\CollectionOddEvenWithRestApi.dothtml" />
<None Remove="Views\FeatureSamples\Attribute\ToStringConversion.dothtml" />
<None Remove="Views\FeatureSamples\AutoUI\AutoEditor.dothtml" />
<None Remove="Views\FeatureSamples\AutoUI\AutoForm.dothtml" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DotVVM.Framework.ViewModel;
using DotVVM.Samples.BasicSamples.Api.Common.Model;
using DotVVM.Samples.Common.Api.Owin;

namespace DotVVM.Samples.Common.ViewModels.FeatureSamples.Api
{
public class CollectionOddEvenWithRestApiViewModel : DotvvmViewModelBase
{
private readonly ResetClient owinResetApi;

public ICollection<Company<string>> Companies { get; set; }
public int Value { get; set; }

public CollectionOddEvenWithRestApiViewModel(ResetClient owinResetApi)
{
this.owinResetApi = owinResetApi;
}

public override Task Init()
{
owinResetApi.ResetData();
return base.Init();
}
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
@viewModel DotVVM.Samples.Common.ViewModels.FeatureSamples.Api.CollectionOddEvenWithRestApiViewModel, DotVVM.Samples.Common

<!DOCTYPE html>

<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title></title>
<style>
.even {
background-color: yellow;
}
.odd {
background-color: lime;
}
</style>
</head>
<body>

<dot:Button Text="Refresh" Click="{staticCommand: Value = Value + 1}" />

<dot:Repeater DataSource="{value: Companies = _api.RefreshOnChange(_apiOwin.Companies.Get(), Value)}"
data-ui="repeater">
<div class-even="{value: _collection.IsEven}"
class-odd="{value: _collection.IsOdd}">
{{value: Id}}: {{value: Name}}
</div>
</dot:Repeater>


</body>
</html>


3 changes: 2 additions & 1 deletion src/Samples/Tests/Abstractions/SamplesRouteUrls.designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 19 additions & 0 deletions src/Samples/Tests/Tests/Feature/ApiTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,25 @@ void CheckRequests(params string[] expected)
});
}

[Fact]
[Trait("Category", "owin-only")]
public void Feature_Api_CollectionOddEvenWithRestApi()
{
RunInAllBrowsers(browser => {
browser.NavigateToUrl(SamplesRouteUrls.FeatureSamples_Api_CollectionOddEvenWithRestApi);

// make sure that the collection is
var rows = browser
.Single("repeater", SelectByDataUi)
.FindElements("div")
.ThrowIfDifferentCountThan(35);
for (var i = 0; i < rows.Count; i++)
{
AssertUI.HasClass(rows[i], i % 2 == 0 ? "even" : "odd");
}
});
}

public ApiTests(ITestOutputHelper output) : base(output)
{
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,5 +88,16 @@ public void ResolvedTree_ViewModel_TypeFromGlobalImportedNamespace()
Assert.IsFalse(root.Directives.Any(d => d.Value.Any(dd => dd.DothtmlNode.HasNodeErrors)));
Assert.AreEqual(typeof(TestViewModel), root.DataContextTypeStack.DataContextType);
}

[TestMethod]
[DataRow("@viewModel")]
[DataRow("@viewmodel")]
public void ResolvedTree_ViewModel_DirectiveIdentifier_CaseInsensitivity(string directive)
{
var root = ParseSource($"{directive} System.String");

Assert.IsFalse(root.Directives.Any(d => d.Value.Any(dd => dd.DothtmlNode.HasNodeErrors)));
Assert.AreEqual(typeof(string), root.DataContextTypeStack.DataContextType);
}
}
}

0 comments on commit 1a8edbc

Please sign in to comment.