diff --git a/src/Orchard.Tests.Modules/Orchard.Tests.Modules.csproj b/src/Orchard.Tests.Modules/Orchard.Tests.Modules.csproj
index acfe2486b..8b3915057 100644
--- a/src/Orchard.Tests.Modules/Orchard.Tests.Modules.csproj
+++ b/src/Orchard.Tests.Modules/Orchard.Tests.Modules.csproj
@@ -154,6 +154,7 @@
+
diff --git a/src/Orchard.Tests.Modules/Users/Controllers/AccountControllerTests.cs b/src/Orchard.Tests.Modules/Users/Controllers/AccountControllerTests.cs
index 9e35a845a..601bbd69d 100644
--- a/src/Orchard.Tests.Modules/Users/Controllers/AccountControllerTests.cs
+++ b/src/Orchard.Tests.Modules/Users/Controllers/AccountControllerTests.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Security.Cryptography;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
@@ -26,20 +27,19 @@ using Orchard.Messaging.Events;
using Orchard.Messaging.Services;
using Orchard.Security;
using Orchard.Security.Permissions;
+using Orchard.Security.Providers;
using Orchard.Tests.Stubs;
using Orchard.UI.Notify;
using Orchard.Users.Controllers;
using Orchard.Users.Handlers;
using Orchard.Users.Models;
using Orchard.Users.Services;
-using Orchard.Users.ViewModels;
using Orchard.Settings;
using Orchard.Core.Settings.Services;
using Orchard.Tests.Messaging;
using Orchard.Environment.Configuration;
using Orchard.Core.Settings.Models;
using Orchard.Core.Settings.Handlers;
-using Orchard.Messaging.Models;
using System.Collections.Specialized;
namespace Orchard.Tests.Modules.Users.Controllers {
@@ -74,11 +74,14 @@ namespace Orchard.Tests.Modules.Users.Controllers {
builder.RegisterType().As();
builder.RegisterType().As();
builder.RegisterType().As();
+
builder.RegisterInstance(new Mock().Object);
builder.RegisterInstance(new Mock().Object);
builder.RegisterType().As();
builder.RegisterType().As();
- builder.RegisterInstance(new ShellSettings { Name = "Alpha", RequestUrlHost = "wiki.example.com", RequestUrlPrefix = "~/foo" });
+
+ builder.RegisterType().As();
+ builder.RegisterInstance(ShellSettingsUtility.CreateEncryptionEnabled());
_authorizer = new Mock();
builder.RegisterInstance(_authorizer.Object);
diff --git a/src/Orchard.Tests.Modules/Users/Controllers/AdminControllerTests.cs b/src/Orchard.Tests.Modules/Users/Controllers/AdminControllerTests.cs
index 6f6d395cb..ca2f20493 100644
--- a/src/Orchard.Tests.Modules/Users/Controllers/AdminControllerTests.cs
+++ b/src/Orchard.Tests.Modules/Users/Controllers/AdminControllerTests.cs
@@ -26,6 +26,7 @@ using Orchard.Messaging.Events;
using Orchard.Messaging.Services;
using Orchard.Security;
using Orchard.Security.Permissions;
+using Orchard.Security.Providers;
using Orchard.Tests.Stubs;
using Orchard.UI.Notify;
using Orchard.Users.Controllers;
@@ -69,7 +70,8 @@ namespace Orchard.Tests.Modules.Users.Controllers {
builder.RegisterInstance(new Mock().Object);
builder.RegisterType().As();
builder.RegisterType().As();
- builder.RegisterInstance(new ShellSettings { Name = "Alpha", RequestUrlHost = "wiki.example.com", RequestUrlPrefix = "~/foo" });
+ builder.RegisterType().As();
+ builder.RegisterInstance(ShellSettingsUtility.CreateEncryptionEnabled());
_authorizer = new Mock();
builder.RegisterInstance(_authorizer.Object);
diff --git a/src/Orchard.Tests.Modules/Users/Services/UserServiceTests.cs b/src/Orchard.Tests.Modules/Users/Services/UserServiceTests.cs
index efa354cc8..34b572dc7 100644
--- a/src/Orchard.Tests.Modules/Users/Services/UserServiceTests.cs
+++ b/src/Orchard.Tests.Modules/Users/Services/UserServiceTests.cs
@@ -1,5 +1,4 @@
using System;
-using System.Web.Security;
using System.Xml.Linq;
using Autofac;
using Moq;
@@ -21,6 +20,7 @@ using Orchard.Environment.Extensions;
using Orchard.Messaging.Events;
using Orchard.Messaging.Services;
using Orchard.Security;
+using Orchard.Security.Providers;
using Orchard.Tests.Stubs;
using Orchard.Tests.Utility;
using Orchard.Users.Handlers;
@@ -96,7 +96,9 @@ namespace Orchard.Tests.Modules.Users.Services {
builder.RegisterType().As();
builder.RegisterType().As();
builder.RegisterType().As();
- builder.RegisterInstance(new ShellSettings { Name = "Alpha", RequestUrlHost = "wiki.example.com", RequestUrlPrefix = "~/foo" });
+
+ builder.RegisterType().As();
+ builder.RegisterInstance(ShellSettingsUtility.CreateEncryptionEnabled());
_session = _sessionFactory.OpenSession();
builder.RegisterInstance(new TestSessionLocator(_session)).As();
@@ -121,25 +123,5 @@ namespace Orchard.Tests.Modules.Users.Services {
Assert.That(username, Is.EqualTo("foo"));
Assert.That(validateByUtc, Is.GreaterThan(_clock.UtcNow));
}
-
- [Test]
- public void NonceShouldNotBeUsedOnAnotherTenant() {
- var user = _membershipService.CreateUser(new CreateUserParams("foo", "66554321", "foo@bar.com", "", "", true));
- var nonce = _userService.CreateNonce(user, new TimeSpan(1, 0, 0));
-
- Assert.That(nonce, Is.Not.Empty);
-
- string username;
- DateTime validateByUtc;
-
- _container.Resolve().Name = "Beta";
-
- var result = _userService.DecryptNonce(nonce, out username, out validateByUtc);
-
- Assert.That(result, Is.False);
- Assert.That(username, Is.EqualTo("foo"));
- Assert.That(validateByUtc, Is.GreaterThan(_clock.UtcNow));
- }
-
}
}
diff --git a/src/Orchard.Tests.Modules/Users/ShellSettingsUtility.cs b/src/Orchard.Tests.Modules/Users/ShellSettingsUtility.cs
new file mode 100644
index 000000000..ff2a020be
--- /dev/null
+++ b/src/Orchard.Tests.Modules/Users/ShellSettingsUtility.cs
@@ -0,0 +1,27 @@
+using System;
+using System.Security.Cryptography;
+using Orchard.Environment.Configuration;
+using Orchard.Utility.Extensions;
+
+namespace Orchard.Tests.Modules.Users {
+ public class ShellSettingsUtility {
+ public static ShellSettings CreateEncryptionEnabled() {
+ // generate random keys for encryption
+ var key = new byte[32];
+ var iv = new byte[16];
+ using ( var random = new RNGCryptoServiceProvider() ) {
+ random.GetBytes(key);
+ random.GetBytes(iv);
+ }
+
+ return new ShellSettings {
+ Name = "Alpha",
+ RequestUrlHost = "wiki.example.com",
+ RequestUrlPrefix = "~/foo",
+ EncryptionAlgorithm = "AES",
+ EncryptionKey = key.ToHexString(),
+ EncryptionIV = iv.ToHexString()
+ };
+ }
+ }
+}
diff --git a/src/Orchard.Tests/DisplayManagement/Descriptors/ShapeTemplateBindingStrategyTests.cs b/src/Orchard.Tests/DisplayManagement/Descriptors/ShapeTemplateBindingStrategyTests.cs
index ec16aa7cb..eb35adff9 100644
--- a/src/Orchard.Tests/DisplayManagement/Descriptors/ShapeTemplateBindingStrategyTests.cs
+++ b/src/Orchard.Tests/DisplayManagement/Descriptors/ShapeTemplateBindingStrategyTests.cs
@@ -5,12 +5,14 @@ using System.Linq;
using Autofac;
using Moq;
using NUnit.Framework;
+using Orchard.Caching;
using Orchard.DisplayManagement.Descriptors;
using Orchard.DisplayManagement.Descriptors.ShapeTemplateStrategy;
using Orchard.Environment.Descriptor.Models;
using Orchard.Environment.Extensions;
using Orchard.Environment.Extensions.Models;
using Orchard.FileSystems.VirtualPath;
+using Orchard.Tests.Stubs;
namespace Orchard.Tests.DisplayManagement.Descriptors {
[TestFixture]
@@ -21,12 +23,14 @@ namespace Orchard.Tests.DisplayManagement.Descriptors {
private TestVirtualPathProvider _testVirtualPathProvider;
- protected override void Register(Autofac.ContainerBuilder builder) {
- _descriptor = new ShellDescriptor { };
+ protected override void Register(ContainerBuilder builder) {
+ _descriptor = new ShellDescriptor();
_testViewEngine = new TestViewEngine();
_testVirtualPathProvider = new TestVirtualPathProvider();
builder.Register(ctx => _descriptor);
+ builder.RegisterType().As();
+ builder.RegisterType().As();
builder.RegisterType().As();
builder.RegisterType().As();
builder.RegisterInstance(_testViewEngine).As();
diff --git a/src/Orchard.Tests/DisplayManagement/Descriptors/StylesheetBindingStrategyTests.cs b/src/Orchard.Tests/DisplayManagement/Descriptors/StylesheetBindingStrategyTests.cs
new file mode 100644
index 000000000..fa10824a2
--- /dev/null
+++ b/src/Orchard.Tests/DisplayManagement/Descriptors/StylesheetBindingStrategyTests.cs
@@ -0,0 +1,143 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using Autofac;
+using Moq;
+using NUnit.Framework;
+using Orchard.DisplayManagement.Descriptors;
+using Orchard.DisplayManagement.Descriptors.ResourceBindingStrategy;
+using Orchard.DisplayManagement.Descriptors.ShapeTemplateStrategy;
+using Orchard.Environment.Descriptor.Models;
+using Orchard.Environment.Extensions;
+using Orchard.Environment.Extensions.Models;
+using Orchard.FileSystems.VirtualPath;
+
+namespace Orchard.Tests.DisplayManagement.Descriptors {
+ [TestFixture]
+ public class StylesheetBindingStrategyTests : ContainerTestBase {
+ private ShellDescriptor _descriptor;
+ private IList _features;
+ private TestViewEngine _testViewEngine;
+ private TestVirtualPathProvider _testVirtualPathProvider;
+
+
+ protected override void Register(Autofac.ContainerBuilder builder) {
+ _descriptor = new ShellDescriptor { };
+ _testViewEngine = new TestViewEngine();
+ _testVirtualPathProvider = new TestVirtualPathProvider();
+
+ builder.Register(ctx => _descriptor);
+ builder.RegisterType().As();
+ builder.RegisterInstance(_testViewEngine).As();
+ builder.RegisterInstance(_testVirtualPathProvider).As();
+
+ var extensionManager = new Mock();
+ builder.Register(ctx => extensionManager);
+ builder.Register(ctx => extensionManager.Object);
+ }
+
+ public class TestViewEngine : Dictionary, IShapeTemplateViewEngine {
+ public IEnumerable DetectTemplateFileNames(IEnumerable fileNames) {
+ return fileNames;
+ }
+ }
+
+ public class TestVirtualPathProvider : IVirtualPathProvider {
+ public string Combine(params string[] paths) {
+ throw new NotImplementedException();
+ }
+
+ public string ToAppRelative(string virtualPath) {
+ throw new NotImplementedException();
+ }
+
+ public string MapPath(string virtualPath) {
+ throw new NotImplementedException();
+ }
+
+ public bool FileExists(string virtualPath) {
+ throw new NotImplementedException();
+ }
+
+ public Stream OpenFile(string virtualPath) {
+ throw new NotImplementedException();
+ }
+
+ public StreamWriter CreateText(string virtualPath) {
+ throw new NotImplementedException();
+ }
+
+ public Stream CreateFile(string virtualPath) {
+ throw new NotImplementedException();
+ }
+
+ public DateTime GetFileLastWriteTimeUtc(string virtualPath) {
+ throw new NotImplementedException();
+ }
+
+ public bool DirectoryExists(string virtualPath) {
+ throw new NotImplementedException();
+ }
+
+ public void CreateDirectory(string virtualPath) {
+ throw new NotImplementedException();
+ }
+
+ public string GetDirectoryName(string virtualPath) {
+ throw new NotImplementedException();
+ }
+
+ public IEnumerable ListFiles(string path) {
+ return new List {"~/Modules/Alpha/Styles/AlphaStyle.css"};
+ }
+
+ public IEnumerable ListDirectories(string path) {
+ throw new NotImplementedException();
+ }
+ }
+
+ protected override void Resolve(ILifetimeScope container) {
+ _features = new List();
+
+ container.Resolve>()
+ .Setup(em => em.AvailableFeatures())
+ .Returns(_features);
+ }
+
+ void AddFeature(string name, params string[] dependencies) {
+ var featureDescriptor = new FeatureDescriptor {
+ Id = name,
+ Dependencies = dependencies,
+ Extension = new ExtensionDescriptor {
+ Id = name,
+ Location = "~/Modules"
+ }
+ };
+ featureDescriptor.Extension.Features = new[] { featureDescriptor };
+
+ _features.Add(featureDescriptor);
+ }
+
+ void AddEnabledFeature(string name, params string[] dependencies) {
+ AddFeature(name, dependencies);
+ _descriptor.Features = _descriptor.Features.Concat(new[] { new ShellFeature { Name = name } });
+ }
+
+ [Test]
+ public void TemplateResolutionWorks() {
+ AddEnabledFeature("Alpha");
+
+ _testViewEngine.Add("~/Modules/Alpha/Styles/AlphaShape.css", null);
+ var strategy = _container.Resolve();
+
+ IList alterationBuilders = new List();
+ var builder = new ShapeTableBuilder(alterationBuilders,null);
+ strategy.Discover(builder);
+ var alterations = alterationBuilders.Select(alterationBuilder=>alterationBuilder.Build());
+
+ Assert.That(alterations.Any(alteration => alteration.ShapeType == "Style"));
+ }
+
+ }
+}
diff --git a/src/Orchard.Tests/Environment/Configuration/DefaultTenantManagerTests.cs b/src/Orchard.Tests/Environment/Configuration/DefaultTenantManagerTests.cs
index e50dd1567..6f1d02806 100644
--- a/src/Orchard.Tests/Environment/Configuration/DefaultTenantManagerTests.cs
+++ b/src/Orchard.Tests/Environment/Configuration/DefaultTenantManagerTests.cs
@@ -58,7 +58,7 @@ namespace Orchard.Tests.Environment.Configuration {
_appDataFolder.CreateFile("Sites\\Default\\Settings.txt", "Name: Default\r\nDataProvider: SqlCe\r\nDataConnectionString: something else");
IShellSettingsManager loader = new ShellSettingsManager(_appDataFolder, new Mock().Object);
- var foo = new ShellSettings { Name = "Foo", DataProvider = "Bar", DataConnectionString = "Quux" };
+ var foo = new ShellSettings {Name = "Foo", DataProvider = "Bar", DataConnectionString = "Quux"};
Assert.That(loader.LoadSettings().Count(), Is.EqualTo(1));
loader.SaveSettings(foo);
@@ -69,5 +69,19 @@ namespace Orchard.Tests.Environment.Configuration {
Assert.That(text, Is.StringContaining("Bar"));
Assert.That(text, Is.StringContaining("Quux"));
}
+
+ [Test]
+ public void EncryptionSettingsAreStoredAndReadable() {
+ IShellSettingsManager loader = new ShellSettingsManager(_appDataFolder, new Mock().Object);
+ var foo = new ShellSettings { Name = "Foo", DataProvider = "Bar", DataConnectionString = "Quux", EncryptionAlgorithm = "AES", EncryptionKey = "ABCDEFG", EncryptionIV= "HIJKL" };
+ loader.SaveSettings(foo);
+ Assert.That(loader.LoadSettings().Count(), Is.EqualTo(1));
+
+ var settings = loader.LoadSettings().First();
+
+ Assert.That(settings.EncryptionAlgorithm, Is.EqualTo("AES"));
+ Assert.That(settings.EncryptionKey, Is.EqualTo("ABCDEFG"));
+ Assert.That(settings.EncryptionIV, Is.EqualTo("HIJKL"));
+ }
}
}
diff --git a/src/Orchard.Tests/Orchard.Framework.Tests.csproj b/src/Orchard.Tests/Orchard.Framework.Tests.csproj
index 5815c2241..0fcaf7102 100644
--- a/src/Orchard.Tests/Orchard.Framework.Tests.csproj
+++ b/src/Orchard.Tests/Orchard.Framework.Tests.csproj
@@ -212,6 +212,7 @@
+
@@ -244,6 +245,7 @@
+
diff --git a/src/Orchard.Tests/Security/DefaultEncryptionServiceTests.cs b/src/Orchard.Tests/Security/DefaultEncryptionServiceTests.cs
new file mode 100644
index 000000000..37a9fbc45
--- /dev/null
+++ b/src/Orchard.Tests/Security/DefaultEncryptionServiceTests.cs
@@ -0,0 +1,53 @@
+using System.Security.Cryptography;
+using System.Text;
+using Autofac;
+using NUnit.Framework;
+using Orchard.Environment.Configuration;
+using Orchard.Security;
+using Orchard.Security.Providers;
+using Orchard.Utility.Extensions;
+
+namespace Orchard.Tests.Security {
+ [TestFixture]
+ public class DefaultEncryptionServiceTests {
+ private IContainer container;
+
+ [SetUp]
+ public void Init() {
+
+ var key = new byte[32];
+ var iv = new byte[16];
+ using ( var random = new RNGCryptoServiceProvider() ) {
+ random.GetBytes(key);
+ random.GetBytes(iv);
+ }
+
+ var shellSettings = new ShellSettings {
+ Name = "Foo",
+ DataProvider = "Bar",
+ DataConnectionString = "Quux",
+ EncryptionAlgorithm = "AES",
+ EncryptionKey = key.ToHexString(),
+ EncryptionIV = iv.ToHexString()
+ };
+
+ var builder = new ContainerBuilder();
+ builder.RegisterInstance(shellSettings);
+ builder.RegisterType().As();
+ container = builder.Build();
+ }
+
+ [Test]
+ public void CanEncodeAndDecodeData() {
+ var encryptionService = container.Resolve();
+
+ var secretData = Encoding.Unicode.GetBytes("this is secret data");
+ var encrypted = encryptionService.Encode(secretData);
+ var decrypted = encryptionService.Decode(encrypted);
+
+ Assert.That(encrypted, Is.Not.EqualTo(decrypted));
+ Assert.That(decrypted, Is.EqualTo(secretData));
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/Orchard.Web/Core/Shapes/CoreShapes.cs b/src/Orchard.Web/Core/Shapes/CoreShapes.cs
index 72efafe06..f292be49b 100644
--- a/src/Orchard.Web/Core/Shapes/CoreShapes.cs
+++ b/src/Orchard.Web/Core/Shapes/CoreShapes.cs
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
@@ -8,6 +9,8 @@ using System.Web.Mvc;
using System.Web.Mvc.Html;
using Orchard.DisplayManagement;
using Orchard.DisplayManagement.Descriptors;
+using Orchard.DisplayManagement.Descriptors.ResourceBindingStrategy;
+using Orchard.Mvc;
using Orchard.Settings;
using Orchard.UI;
using Orchard.UI.Resources;
@@ -19,11 +22,20 @@ using Orchard.Utility.Extensions;
namespace Orchard.Core.Shapes {
public class CoreShapes : IShapeTableProvider {
private readonly IWorkContextAccessor _workContextAccessor;
+ private readonly IHttpContextAccessor _httpContextAccessor;
- public CoreShapes(IWorkContextAccessor workContextAccessor) {
+ public CoreShapes(IWorkContextAccessor workContextAccessor, IHttpContextAccessor httpContextAccessor) {
// needed to get CurrentSite.
// note that injecting ISiteService here causes a stack overflow in AutoFac!
_workContextAccessor = workContextAccessor;
+ _httpContextAccessor = httpContextAccessor;
+ }
+
+ // not injected the usual way because this component is a 'static' dependency and RM is per-request
+ private IResourceManager ResourceManager {
+ get {
+ return _workContextAccessor.GetContext(_httpContextAccessor.Current()).Resolve();
+ }
}
public void Discover(ShapeTableBuilder builder) {
@@ -82,6 +94,26 @@ namespace Orchard.Core.Shapes {
list.ItemClasses = new List();
list.ItemAttributes = new Dictionary();
});
+
+ builder.Describe("Style")
+ .OnDisplaying(displaying => {
+ var resource = displaying.Shape;
+ string url = resource.Url;
+ string fileName = StylesheetBindingStrategy.GetAlternateShapeNameFromFileName(url);
+ if (!string.IsNullOrEmpty(fileName)) {
+ resource.Metadata.Alternates.Add("Style__" + fileName);
+ }
+ });
+
+ builder.Describe("Resource")
+ .OnDisplaying(displaying => {
+ var resource = displaying.Shape;
+ string url = resource.Url;
+ string fileName = StylesheetBindingStrategy.GetAlternateShapeNameFromFileName(url);
+ if (!string.IsNullOrEmpty(fileName)) {
+ resource.Metadata.Alternates.Add("Resource__" + fileName);
+ }
+ });
}
@@ -159,51 +191,58 @@ namespace Orchard.Core.Shapes {
#endregion
[Shape]
- public void HeadScripts(HtmlHelper Html, IResourceManager ResourceManager) {
- WriteResources(Html, _workContextAccessor.GetContext(Html.ViewContext).CurrentSite,
- ResourceManager, "script", ResourceLocation.Head, null);
- WriteLiteralScripts(Html, ResourceManager.GetRegisteredHeadScripts());
+ public void HeadScripts(dynamic Display, TextWriter Output) {
+ WriteResources(Display, Output, "script", ResourceLocation.Head, null);
+ WriteLiteralScripts(Output, ResourceManager.GetRegisteredHeadScripts());
}
[Shape]
- public void FootScripts(HtmlHelper Html, IResourceManager ResourceManager) {
- WriteResources(Html, _workContextAccessor.GetContext(Html.ViewContext).CurrentSite,
- ResourceManager, "script", null, ResourceLocation.Head);
- WriteLiteralScripts(Html, ResourceManager.GetRegisteredFootScripts());
+ public void FootScripts(dynamic Display, TextWriter Output) {
+ WriteResources(Display, Output, "script", null, ResourceLocation.Head);
+ WriteLiteralScripts(Output, ResourceManager.GetRegisteredFootScripts());
}
[Shape]
- public void Metas(HtmlHelper Html, IResourceManager ResourceManager) {
+ public void Metas(TextWriter Output) {
foreach (var meta in ResourceManager.GetRegisteredMetas()) {
- Html.ViewContext.Writer.WriteLine(meta.GetTag());
+ Output.WriteLine(meta.GetTag());
}
}
[Shape]
- public void HeadLinks(HtmlHelper Html, IResourceManager ResourceManager) {
+ public void HeadLinks(TextWriter Output) {
foreach (var link in ResourceManager.GetRegisteredLinks()) {
- Html.ViewContext.Writer.WriteLine(link.GetTag());
+ Output.WriteLine(link.GetTag());
}
}
[Shape]
- public void StylesheetLinks(HtmlHelper Html, IResourceManager ResourceManager) {
- WriteResources(Html, _workContextAccessor.GetContext(Html.ViewContext).CurrentSite,
- ResourceManager, "stylesheet", null, null);
+ public void StylesheetLinks(dynamic Display, TextWriter Output) {
+ WriteResources(Display, Output, "stylesheet", null, null);
}
- private static void WriteLiteralScripts(HtmlHelper html, IEnumerable scripts) {
+ [Shape]
+ public void Style(TextWriter Output, ResourceDefinition Resource, string Url, string Condition) {
+ UI.Resources.ResourceManager.WriteResource(Output, Resource, Url, Condition);
+ }
+
+ [Shape]
+ public void Resource(TextWriter Output, ResourceDefinition Resource, string Url, string Condition) {
+ UI.Resources.ResourceManager.WriteResource(Output, Resource, Url, Condition);
+ }
+
+ private static void WriteLiteralScripts(TextWriter output, IEnumerable scripts) {
if (scripts == null) {
return;
}
- var writer = html.ViewContext.Writer;
foreach (string script in scripts) {
- writer.WriteLine(script);
+ output.WriteLine(script);
}
}
- private static void WriteResources(HtmlHelper html, ISite site, IResourceManager rm, string resourceType, ResourceLocation? includeLocation, ResourceLocation? excludeLocation) {
+ private void WriteResources(dynamic Display, TextWriter Output, string resourceType, ResourceLocation? includeLocation, ResourceLocation? excludeLocation) {
bool debugMode;
+ var site = _workContextAccessor.GetContext(_httpContextAccessor.Current()).CurrentSite;
switch (site.ResourceDebugMode) {
case ResourceDebugMode.Enabled:
debugMode = true;
@@ -213,26 +252,29 @@ namespace Orchard.Core.Shapes {
break;
default:
Debug.Assert(site.ResourceDebugMode == ResourceDebugMode.FromAppSetting, "Unknown ResourceDebugMode value.");
- debugMode = html.ViewContext.HttpContext.IsDebuggingEnabled;
+ debugMode = _httpContextAccessor.Current().IsDebuggingEnabled;
break;
}
var defaultSettings = new RequireSettings {
DebugMode = debugMode,
Culture = CultureInfo.CurrentUICulture.Name,
};
- var requiredResources = rm.BuildRequiredResources(resourceType);
- var appPath = html.ViewContext.HttpContext.Request.ApplicationPath;
+ var requiredResources = ResourceManager.BuildRequiredResources(resourceType);
+ var appPath = _httpContextAccessor.Current().Request.ApplicationPath;
foreach (var context in requiredResources.Where(r =>
(includeLocation.HasValue ? r.Settings.Location == includeLocation.Value : true) &&
(excludeLocation.HasValue ? r.Settings.Location != excludeLocation.Value : true))) {
+
+ var path = context.GetResourceUrl(defaultSettings, appPath);
var condition = context.Settings.Condition;
- if (!string.IsNullOrEmpty(condition)) {
- html.ViewContext.Writer.WriteLine("");
+ else {
+ result = Display.Resource(Url: path, Condition: condition, Resource: context.Resource);
}
+ Output.Write(result);
}
}
diff --git a/src/Orchard.Web/Modules/Orchard.ContentTypes/Services/ContentDefinitionService.cs b/src/Orchard.Web/Modules/Orchard.ContentTypes/Services/ContentDefinitionService.cs
index d00d99d7b..6fdb834a1 100644
--- a/src/Orchard.Web/Modules/Orchard.ContentTypes/Services/ContentDefinitionService.cs
+++ b/src/Orchard.Web/Modules/Orchard.ContentTypes/Services/ContentDefinitionService.cs
@@ -6,10 +6,8 @@ using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers;
using Orchard.ContentManagement.MetaData;
using Orchard.ContentManagement.MetaData.Models;
-using Orchard.ContentTypes.Extensions;
using Orchard.ContentTypes.ViewModels;
using Orchard.Core.Contents.Extensions;
-using Orchard.Core.Contents.Settings;
using Orchard.Localization;
namespace Orchard.ContentTypes.Services {
diff --git a/src/Orchard.Web/Modules/Orchard.Email/Handlers/SmtpSettingsPartHandler.cs b/src/Orchard.Web/Modules/Orchard.Email/Handlers/SmtpSettingsPartHandler.cs
index dda95b909..c7a2e1e20 100644
--- a/src/Orchard.Web/Modules/Orchard.Email/Handlers/SmtpSettingsPartHandler.cs
+++ b/src/Orchard.Web/Modules/Orchard.Email/Handlers/SmtpSettingsPartHandler.cs
@@ -1,14 +1,27 @@
-using JetBrains.Annotations;
+using System;
+using System.Text;
+using JetBrains.Annotations;
using Orchard.Email.Models;
using Orchard.Data;
using Orchard.ContentManagement.Handlers;
+using Orchard.Security;
namespace Orchard.Email.Handlers {
[UsedImplicitly]
public class SmtpSettingsPartHandler : ContentHandler {
- public SmtpSettingsPartHandler(IRepository repository) {
+ private readonly IEncryptionService _encryptionService;
+
+ public SmtpSettingsPartHandler(IRepository repository, IEncryptionService encryptionService) {
+ _encryptionService = encryptionService;
Filters.Add(new ActivatingFilter("Site"));
Filters.Add(StorageFilter.For(repository));
+
+ OnLoaded(LazyLoadHandlers);
+ }
+
+ void LazyLoadHandlers(LoadContentContext context, SmtpSettingsPart part) {
+ part.PasswordField.Getter(() => String.IsNullOrWhiteSpace(part.Record.Password) ? String.Empty : Encoding.UTF8.GetString(_encryptionService.Decode(Convert.FromBase64String(part.Record.Password))));
+ part.PasswordField.Setter(value => part.Record.Password = String.IsNullOrWhiteSpace(value) ? String.Empty : Convert.ToBase64String(_encryptionService.Encode(Encoding.UTF8.GetBytes(value))));
}
}
}
\ No newline at end of file
diff --git a/src/Orchard.Web/Modules/Orchard.Email/Models/SmtpSettingsPart.cs b/src/Orchard.Web/Modules/Orchard.Email/Models/SmtpSettingsPart.cs
index 964d022df..e371459b4 100644
--- a/src/Orchard.Web/Modules/Orchard.Email/Models/SmtpSettingsPart.cs
+++ b/src/Orchard.Web/Modules/Orchard.Email/Models/SmtpSettingsPart.cs
@@ -1,14 +1,13 @@
-using System.Text;
-using System.Web.Security;
-using Orchard.ContentManagement;
+using Orchard.ContentManagement;
using System;
+using Orchard.ContentManagement.Utilities;
namespace Orchard.Email.Models {
public class SmtpSettingsPart : ContentPart {
- public bool IsValid() {
- return !String.IsNullOrWhiteSpace(Record.Host)
- && Record.Port > 0
- && !String.IsNullOrWhiteSpace(Record.Address);
+ private readonly ComputedField _password = new ComputedField();
+
+ public ComputedField PasswordField {
+ get { return _password; }
}
public string Address {
@@ -42,8 +41,14 @@ namespace Orchard.Email.Models {
}
public string Password {
- get { return String.IsNullOrWhiteSpace(Record.Password) ? String.Empty : Encoding.UTF8.GetString(MachineKey.Decode(Record.Password, MachineKeyProtection.All)); ; }
- set { Record.Password = String.IsNullOrWhiteSpace(value) ? String.Empty : MachineKey.Encode(Encoding.UTF8.GetBytes(value), MachineKeyProtection.All); }
+ get { return _password.Value; }
+ set { _password.Value = value; }
+ }
+
+ public bool IsValid() {
+ return !String.IsNullOrWhiteSpace(Record.Host)
+ && Record.Port > 0
+ && !String.IsNullOrWhiteSpace(Record.Address);
}
}
}
\ No newline at end of file
diff --git a/src/Orchard.Web/Modules/Orchard.Setup/Services/SetupService.cs b/src/Orchard.Web/Modules/Orchard.Setup/Services/SetupService.cs
index 4c68417fc..2d26c4bbb 100644
--- a/src/Orchard.Web/Modules/Orchard.Setup/Services/SetupService.cs
+++ b/src/Orchard.Web/Modules/Orchard.Setup/Services/SetupService.cs
@@ -1,6 +1,7 @@
using System;
using System.Globalization;
using System.Linq;
+using System.Security.Cryptography;
using System.Web;
using Orchard.ContentManagement;
using Orchard.ContentManagement.MetaData;
@@ -29,6 +30,7 @@ using Orchard.Settings;
using Orchard.Environment.State;
using Orchard.Data.Migration;
using Orchard.Themes.Services;
+using Orchard.Utility.Extensions;
using Orchard.Widgets.Models;
using Orchard.Widgets;
@@ -118,6 +120,21 @@ namespace Orchard.Setup.Services {
shellSettings.DataTablePrefix = context.DatabaseTablePrefix;
}
+ #region Encryption Settings
+
+ // generate random keys for encryption
+ var key = new byte[32];
+ var iv = new byte[16];
+ using ( var random = new RNGCryptoServiceProvider() ) {
+ random.GetBytes(key);
+ random.GetBytes(iv);
+ }
+
+ shellSettings.EncryptionAlgorithm = "AES";
+ shellSettings.EncryptionKey = key.ToHexString();
+ shellSettings.EncryptionIV = iv.ToHexString();
+ #endregion
+
var shellDescriptor = new ShellDescriptor {
Features = context.EnabledFeatures.Select(name => new ShellFeature { Name = name })
};
diff --git a/src/Orchard.Web/Modules/Orchard.Users/Services/UserService.cs b/src/Orchard.Web/Modules/Orchard.Users/Services/UserService.cs
index a1ed2f3fc..712936452 100644
--- a/src/Orchard.Web/Modules/Orchard.Users/Services/UserService.cs
+++ b/src/Orchard.Web/Modules/Orchard.Users/Services/UserService.cs
@@ -25,13 +25,15 @@ namespace Orchard.Users.Services {
private readonly IClock _clock;
private readonly IMessageManager _messageManager;
private readonly ShellSettings _shellSettings;
+ private readonly IEncryptionService _encryptionService;
- public UserService(IContentManager contentManager, IMembershipService membershipService, IClock clock, IMessageManager messageManager, ShellSettings shellSettings) {
+ public UserService(IContentManager contentManager, IMembershipService membershipService, IClock clock, IMessageManager messageManager, ShellSettings shellSettings, IEncryptionService encryptionService) {
_contentManager = contentManager;
_membershipService = membershipService;
_clock = clock;
_messageManager = messageManager;
_shellSettings = shellSettings;
+ _encryptionService = encryptionService;
Logger = NullLogger.Instance;
}
@@ -66,24 +68,22 @@ namespace Orchard.Users.Services {
}
public string CreateNonce(IUser user, TimeSpan delay) {
- // the tenant's name is added to the token to prevent cross-tenant requests
- var challengeToken = new XElement("n", new XAttribute("s", _shellSettings.Name), new XAttribute("un", user.UserName), new XAttribute("utc", _clock.UtcNow.ToUniversalTime().Add(delay).ToString(CultureInfo.InvariantCulture))).ToString();
- var data = Encoding.Unicode.GetBytes(challengeToken);
- return MachineKey.Encode(data, MachineKeyProtection.All);
+ var challengeToken = new XElement("n", new XAttribute("un", user.UserName), new XAttribute("utc", _clock.UtcNow.ToUniversalTime().Add(delay).ToString(CultureInfo.InvariantCulture))).ToString();
+ var data = Encoding.UTF8.GetBytes(challengeToken);
+ return Convert.ToBase64String(_encryptionService.Encode(data));
}
- public bool DecryptNonce(string challengeToken, out string username, out DateTime validateByUtc) {
+ public bool DecryptNonce(string nonce, out string username, out DateTime validateByUtc) {
username = null;
validateByUtc = _clock.UtcNow;
try {
- var data = MachineKey.Decode(challengeToken, MachineKeyProtection.All);
- var xml = Encoding.Unicode.GetString(data);
+ var data = _encryptionService.Decode(Convert.FromBase64String(nonce));
+ var xml = Encoding.UTF8.GetString(data);
var element = XElement.Parse(xml);
- var tenant = element.Attribute("s").Value;
username = element.Attribute("un").Value;
validateByUtc = DateTime.Parse(element.Attribute("utc").Value, CultureInfo.InvariantCulture);
- return String.Equals(_shellSettings.Name, tenant, StringComparison.Ordinal) && _clock.UtcNow <= validateByUtc;
+ return _clock.UtcNow <= validateByUtc;
}
catch {
return false;
diff --git a/src/Orchard/ContentManagement/Utilities/ComputedField.cs b/src/Orchard/ContentManagement/Utilities/ComputedField.cs
new file mode 100644
index 000000000..3bbd33b7a
--- /dev/null
+++ b/src/Orchard/ContentManagement/Utilities/ComputedField.cs
@@ -0,0 +1,29 @@
+using System;
+
+namespace Orchard.ContentManagement.Utilities {
+ public class ComputedField {
+ private Func _getter;
+ private Action _setter;
+
+ public T Value {
+ get { return GetValue(); }
+ set { SetValue(value); }
+ }
+
+ public void Getter(Func loader) {
+ _getter = loader;
+ }
+
+ public void Setter(Action setter) {
+ _setter = setter;
+ }
+
+ private T GetValue() {
+ return _getter();
+ }
+
+ private void SetValue(T value) {
+ _setter(value);
+ }
+ }
+}
diff --git a/src/Orchard/Data/SessionFactoryHolder.cs b/src/Orchard/Data/SessionFactoryHolder.cs
index f7ba7389a..bc39d6e2f 100644
--- a/src/Orchard/Data/SessionFactoryHolder.cs
+++ b/src/Orchard/Data/SessionFactoryHolder.cs
@@ -1,9 +1,5 @@
-using System;
-using System.IO;
-using System.Xml.Serialization;
-using NHibernate;
+using NHibernate;
using NHibernate.Cfg;
-using Orchard.Data;
using Orchard.Data.Providers;
using Orchard.Environment;
using Orchard.Environment.Configuration;
diff --git a/src/Orchard/DisplayManagement/Descriptors/ResourceBindingStrategy/StylesheetBindingStrategy.cs b/src/Orchard/DisplayManagement/Descriptors/ResourceBindingStrategy/StylesheetBindingStrategy.cs
new file mode 100644
index 000000000..910364b13
--- /dev/null
+++ b/src/Orchard/DisplayManagement/Descriptors/ResourceBindingStrategy/StylesheetBindingStrategy.cs
@@ -0,0 +1,98 @@
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text.RegularExpressions;
+using Orchard.Environment.Descriptor.Models;
+using Orchard.Environment.Extensions;
+using Orchard.Environment.Extensions.Models;
+using Orchard.FileSystems.VirtualPath;
+using Orchard.UI.Resources;
+
+namespace Orchard.DisplayManagement.Descriptors.ResourceBindingStrategy {
+ // discovers .css files and turns them into Style__ shapes.
+ public class StylesheetBindingStrategy : IShapeTableProvider {
+ private readonly IExtensionManager _extensionManager;
+ private readonly ShellDescriptor _shellDescriptor;
+ private readonly IVirtualPathProvider _virtualPathProvider;
+ private static readonly Regex _safeName = new Regex(@"[/:?#\[\]@!&'()*+,;=\s\""<>\.\-_]+", RegexOptions.Compiled);
+
+ public StylesheetBindingStrategy(IExtensionManager extensionManager, ShellDescriptor shellDescriptor, IVirtualPathProvider virtualPathProvider) {
+ _extensionManager = extensionManager;
+ _shellDescriptor = shellDescriptor;
+ _virtualPathProvider = virtualPathProvider;
+ }
+
+ private static string SafeName(string name) {
+ if (string.IsNullOrWhiteSpace(name))
+ return String.Empty;
+ return _safeName.Replace(name, String.Empty);
+ }
+
+ public static string GetAlternateShapeNameFromFileName(string fileName) {
+ if (fileName == null) {
+ throw new ArgumentNullException("fileName");
+ }
+ string shapeName;
+ if (Uri.IsWellFormedUriString(fileName, UriKind.Absolute)) {
+ var uri = new Uri(fileName);
+ shapeName = uri.Authority + "$" + uri.AbsolutePath + "$" + uri.Query;
+ }
+ else {
+ shapeName = Path.GetFileNameWithoutExtension(fileName);
+ }
+ return SafeName(shapeName);
+ }
+
+ private static IEnumerable Once(IEnumerable featureDescriptors) {
+ var once = new ConcurrentDictionary();
+ return featureDescriptors.Select(fd => fd.Extension).Where(ed => once.TryAdd(ed.Id, null)).ToList();
+ }
+
+ public void Discover(ShapeTableBuilder builder) {
+ var availableFeatures = _extensionManager.AvailableFeatures();
+ var activeFeatures = availableFeatures.Where(FeatureIsEnabled);
+ var activeExtensions = Once(activeFeatures);
+
+ var hits = activeExtensions.SelectMany(extensionDescriptor => {
+ var basePath = Path.Combine(extensionDescriptor.Location, extensionDescriptor.Id).Replace(Path.DirectorySeparatorChar, '/');
+ var virtualPath = Path.Combine(basePath, "Styles").Replace(Path.DirectorySeparatorChar, '/');
+ var shapes = _virtualPathProvider.ListFiles(virtualPath)
+ .Select(Path.GetFileName)
+ .Where(fileName => string.Equals(Path.GetExtension(fileName), ".css", System.StringComparison.OrdinalIgnoreCase))
+ .Select(cssFileName => new {
+ fileName = Path.GetFileNameWithoutExtension(cssFileName),
+ fileVirtualPath = Path.Combine(virtualPath, cssFileName).Replace(Path.DirectorySeparatorChar, '/'),
+ shapeType = "Style__" + GetAlternateShapeNameFromFileName(cssFileName),
+ extensionDescriptor
+ });
+ return shapes;
+ });
+
+ foreach (var iter in hits) {
+ var hit = iter;
+ var featureDescriptors = hit.extensionDescriptor.Features.Where(fd => fd.Id == hit.extensionDescriptor.Id);
+ foreach (var featureDescriptor in featureDescriptors) {
+ builder.Describe(iter.shapeType)
+ .From(new Feature {Descriptor = featureDescriptor})
+ .BoundAs(
+ hit.fileVirtualPath,
+ shapeDescriptor => displayContext => {
+ var shape = ((dynamic) displayContext.Value);
+ var output = displayContext.ViewContext.Writer;
+ ResourceDefinition resource = shape.Resource;
+ string condition = shape.Condition;
+ ResourceManager.WriteResource(output, resource, hit.fileVirtualPath, condition);
+ return null;
+ });
+ }
+ }
+ }
+
+ private bool FeatureIsEnabled(FeatureDescriptor fd) {
+ return (DefaultExtensionTypes.IsTheme(fd.Extension.ExtensionType) && (fd.Id == "TheAdmin" || fd.Id == "SafeMode")) ||
+ _shellDescriptor.Features.Any(sf => sf.Name == fd.Id);
+ }
+ }
+}
diff --git a/src/Orchard/DisplayManagement/Descriptors/ShapeTemplateStrategy/ShapeTemplateBindingStrategy.cs b/src/Orchard/DisplayManagement/Descriptors/ShapeTemplateStrategy/ShapeTemplateBindingStrategy.cs
index 921ffc803..f038ed61e 100644
--- a/src/Orchard/DisplayManagement/Descriptors/ShapeTemplateStrategy/ShapeTemplateBindingStrategy.cs
+++ b/src/Orchard/DisplayManagement/Descriptors/ShapeTemplateStrategy/ShapeTemplateBindingStrategy.cs
@@ -1,10 +1,12 @@
-using System.Collections.Concurrent;
+using System;
+using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Html;
+using Orchard.Caching;
using Orchard.DisplayManagement.Implementation;
using Orchard.Environment.Descriptor.Models;
using Orchard.Environment.Extensions;
@@ -15,6 +17,8 @@ namespace Orchard.DisplayManagement.Descriptors.ShapeTemplateStrategy {
public class ShapeTemplateBindingStrategy : IShapeTableProvider {
private readonly ShellDescriptor _shellDescriptor;
private readonly IExtensionManager _extensionManager;
+ private readonly ICacheManager _cacheManager;
+ private readonly IVirtualPathMonitor _virtualPathMonitor;
private readonly IVirtualPathProvider _virtualPathProvider;
private readonly IEnumerable _harvesters;
private readonly IEnumerable _shapeTemplateViewEngines;
@@ -24,11 +28,15 @@ namespace Orchard.DisplayManagement.Descriptors.ShapeTemplateStrategy {
IEnumerable harvesters,
ShellDescriptor shellDescriptor,
IExtensionManager extensionManager,
+ ICacheManager cacheManager,
+ IVirtualPathMonitor virtualPathMonitor,
IVirtualPathProvider virtualPathProvider,
IEnumerable shapeTemplateViewEngines) {
_harvesters = harvesters;
_shellDescriptor = shellDescriptor;
_extensionManager = extensionManager;
+ _cacheManager = cacheManager;
+ _virtualPathMonitor = virtualPathMonitor;
_virtualPathProvider = virtualPathProvider;
_shapeTemplateViewEngines = shapeTemplateViewEngines;
}
@@ -49,13 +57,21 @@ namespace Orchard.DisplayManagement.Descriptors.ShapeTemplateStrategy {
var pathContexts = harvesterInfos.SelectMany(harvesterInfo => harvesterInfo.subPaths.Select(subPath => {
var basePath = Path.Combine(extensionDescriptor.Location, extensionDescriptor.Id).Replace(Path.DirectorySeparatorChar, '/');
var virtualPath = Path.Combine(basePath, subPath).Replace(Path.DirectorySeparatorChar, '/');
- var fileNames = _virtualPathProvider.ListFiles(virtualPath).Select(Path.GetFileName);
+ var fileNames = _cacheManager.Get(virtualPath, ctx => {
+ ctx.Monitor(_virtualPathMonitor.WhenPathChanges(virtualPath));
+ return _virtualPathProvider.ListFiles(virtualPath).Select(Path.GetFileName);
+ });
return new { harvesterInfo.harvester, basePath, subPath, virtualPath, fileNames };
}));
var fileContexts = pathContexts.SelectMany(pathContext => _shapeTemplateViewEngines.SelectMany(ve => {
var fileNames = ve.DetectTemplateFileNames(pathContext.fileNames);
- return fileNames.Select(fileName => new { fileName = Path.GetFileNameWithoutExtension(fileName), fileVirtualPath = Path.Combine(pathContext.virtualPath, fileName).Replace(Path.DirectorySeparatorChar, '/'), pathContext });
+ return fileNames.Select(
+ fileName => new {
+ fileName = Path.GetFileNameWithoutExtension(fileName),
+ fileVirtualPath = Path.Combine(pathContext.virtualPath, fileName).Replace(Path.DirectorySeparatorChar, '/'),
+ pathContext
+ });
}));
var shapeContexts = fileContexts.SelectMany(fileContext => {
diff --git a/src/Orchard/Environment/Configuration/ShellSettings.cs b/src/Orchard/Environment/Configuration/ShellSettings.cs
index c6717938f..65795783f 100644
--- a/src/Orchard/Environment/Configuration/ShellSettings.cs
+++ b/src/Orchard/Environment/Configuration/ShellSettings.cs
@@ -16,6 +16,9 @@
DataTablePrefix = settings.DataTablePrefix;
RequestUrlHost = settings.RequestUrlHost;
RequestUrlPrefix = settings.RequestUrlPrefix;
+ EncryptionAlgorithm = settings.EncryptionAlgorithm;
+ EncryptionKey = settings.EncryptionKey;
+ EncryptionIV = settings.EncryptionIV;
State = settings.State;
}
@@ -28,6 +31,10 @@
public string RequestUrlHost { get; set; }
public string RequestUrlPrefix { get; set; }
+ public string EncryptionAlgorithm { get; set; }
+ public string EncryptionKey { get; set; }
+ public string EncryptionIV { get; set; }
+
public TenantState State { get; set; }
}
}
diff --git a/src/Orchard/Environment/Configuration/ShellSettingsManager.cs b/src/Orchard/Environment/Configuration/ShellSettingsManager.cs
index 9e819b36e..6e6d24044 100644
--- a/src/Orchard/Environment/Configuration/ShellSettingsManager.cs
+++ b/src/Orchard/Environment/Configuration/ShellSettingsManager.cs
@@ -84,6 +84,15 @@ namespace Orchard.Environment.Configuration {
case "RequestUrlPrefix":
shellSettings.RequestUrlPrefix = settingFields[1];
break;
+ case "EncryptionAlgorithm":
+ shellSettings.EncryptionAlgorithm = settingFields[1];
+ break;
+ case "EncryptionKey":
+ shellSettings.EncryptionKey = settingFields[1];
+ break;
+ case "EncryptionIV":
+ shellSettings.EncryptionIV = settingFields[1];
+ break;
}
}
}
@@ -94,14 +103,18 @@ namespace Orchard.Environment.Configuration {
if (settings == null)
return "";
- return string.Format("Name: {0}\r\nDataProvider: {1}\r\nDataConnectionString: {2}\r\nDataPrefix: {3}\r\nRequestUrlHost: {4}\r\nRequestUrlPrefix: {5}\r\nState: {6}\r\n",
+ return string.Format("Name: {0}\r\nDataProvider: {1}\r\nDataConnectionString: {2}\r\nDataPrefix: {3}\r\nRequestUrlHost: {4}\r\nRequestUrlPrefix: {5}\r\nState: {6}\r\nEncryptionAlgorithm: {7}\r\nEncryptionKey: {8}\r\nEncryptionIV: {9}\r\n",
settings.Name,
settings.DataProvider,
settings.DataConnectionString ?? "null",
settings.DataTablePrefix ?? "null",
settings.RequestUrlHost ?? "null",
settings.RequestUrlPrefix ?? "null",
- settings.State != null ? settings.State.ToString() : String.Empty);
+ settings.State != null ? settings.State.ToString() : String.Empty,
+ settings.EncryptionAlgorithm ?? "null",
+ settings.EncryptionKey ?? "null",
+ settings.EncryptionIV ?? "null"
+ );
}
}
}
diff --git a/src/Orchard/FileSystems/VirtualPath/DefaultVirtualPathMonitor.cs b/src/Orchard/FileSystems/VirtualPath/DefaultVirtualPathMonitor.cs
index 12fa9ec42..486cc4153 100644
--- a/src/Orchard/FileSystems/VirtualPath/DefaultVirtualPathMonitor.cs
+++ b/src/Orchard/FileSystems/VirtualPath/DefaultVirtualPathMonitor.cs
@@ -11,16 +11,21 @@ namespace Orchard.FileSystems.VirtualPath {
private readonly string _prefix = Guid.NewGuid().ToString("n");
private readonly IDictionary> _tokens = new Dictionary>();
private readonly IClock _clock;
+ private readonly IVirtualPathProvider _virtualPathProvider;
- public DefaultVirtualPathMonitor(IClock clock) {
+ public DefaultVirtualPathMonitor(IClock clock, IVirtualPathProvider virtualPathProvider) {
_clock = clock;
+ _virtualPathProvider = virtualPathProvider;
_thunk = new Thunk(this);
}
public IVolatileToken WhenPathChanges(string virtualPath) {
// Fix this to monitor first existing parent directory.
- var token = BindToken(virtualPath);
- BindSignal(virtualPath);
+ IVolatileToken token = new Token(virtualPath);
+ if (_virtualPathProvider.DirectoryExists(virtualPath)) {
+ token = BindToken(virtualPath);
+ BindSignal(virtualPath);
+ }
return token;
}
@@ -108,6 +113,5 @@ namespace Orchard.FileSystems.VirtualPath {
provider.Signal(key, value, reason);
}
}
-
}
}
\ No newline at end of file
diff --git a/src/Orchard/Orchard.Framework.csproj b/src/Orchard/Orchard.Framework.csproj
index 40d72d553..a8350ed09 100644
--- a/src/Orchard/Orchard.Framework.csproj
+++ b/src/Orchard/Orchard.Framework.csproj
@@ -142,6 +142,8 @@
+
+
@@ -170,7 +172,9 @@
+
+
diff --git a/src/Orchard/Security/IEncryptionService.cs b/src/Orchard/Security/IEncryptionService.cs
new file mode 100644
index 000000000..e2d0471ce
--- /dev/null
+++ b/src/Orchard/Security/IEncryptionService.cs
@@ -0,0 +1,20 @@
+namespace Orchard.Security {
+ ///
+ /// Provides encryption services adapted to securing tenant level information
+ ///
+ public interface IEncryptionService : ISingletonDependency {
+ ///
+ /// Decodes data that has been encrypted.
+ ///
+ /// The encrypted data to decrypt.
+ /// A Byte[] array that represents the decrypted data.
+ byte[] Decode(byte[] encodedData);
+
+ ///
+ /// Encrypts data.
+ ///
+ /// The data to encrypt.
+ /// The encrypted value.
+ byte[] Encode(byte[] data);
+ }
+}
diff --git a/src/Orchard/Security/Providers/DefaultEncryptionService.cs b/src/Orchard/Security/Providers/DefaultEncryptionService.cs
new file mode 100644
index 000000000..9620f4157
--- /dev/null
+++ b/src/Orchard/Security/Providers/DefaultEncryptionService.cs
@@ -0,0 +1,62 @@
+using System;
+using System.IO;
+using System.Linq;
+using System.Security.Cryptography;
+using Orchard.Environment.Configuration;
+using Orchard.Utility.Extensions;
+
+namespace Orchard.Security.Providers {
+ public class DefaultEncryptionService : IEncryptionService {
+ private readonly ShellSettings _shellSettings;
+ private const int SaltSize = 16;
+
+ public DefaultEncryptionService(ShellSettings shellSettings ) {
+ _shellSettings = shellSettings;
+ }
+
+ public byte[] Decode(byte[] encodedData) {
+ using ( var ms = new MemoryStream() ) {
+ using (var algorithm = CreateAlgorithm()) {
+ using ( var cs = new CryptoStream(ms, algorithm.CreateDecryptor(), CryptoStreamMode.Write) ) {
+ cs.Write(encodedData, 0, encodedData.Length);
+ cs.FlushFinalBlock();
+ }
+
+ // remove the salt part
+ return ms.ToArray().Skip(SaltSize).ToArray();
+ }
+ }
+ }
+
+ public byte[] Encode(byte[] data) {
+ var salt = new byte[SaltSize];
+
+ // generate a random salt to happend to encoded data
+ using ( var random = new RNGCryptoServiceProvider() ) {
+ random.GetBytes(salt);
+ }
+ using ( var ms = new MemoryStream() ) {
+ using (var algorithm = CreateAlgorithm()) {
+ using ( var cs = new CryptoStream(ms, algorithm.CreateEncryptor(), CryptoStreamMode.Write) ) {
+ // append the salt to the data and encrypt
+ var salted = salt.Concat(data).ToArray();
+ cs.Write(salted, 0, salted.Length);
+ cs.FlushFinalBlock();
+ }
+
+ return ms.ToArray();
+ }
+ }
+ }
+
+ private SymmetricAlgorithm CreateAlgorithm() {
+ var encryptionAlgorithm = SymmetricAlgorithm.Create(_shellSettings.EncryptionAlgorithm);
+
+ encryptionAlgorithm.Key = _shellSettings.EncryptionKey.ToByteArray();
+ encryptionAlgorithm.IV = _shellSettings.EncryptionIV.ToByteArray();
+
+ return encryptionAlgorithm;
+
+ }
+ }
+}
diff --git a/src/Orchard/UI/Resources/ResourceFilter.cs b/src/Orchard/UI/Resources/ResourceFilter.cs
index 990184f1b..fa291fe08 100644
--- a/src/Orchard/UI/Resources/ResourceFilter.cs
+++ b/src/Orchard/UI/Resources/ResourceFilter.cs
@@ -4,20 +4,16 @@ using Orchard.Mvc.Filters;
namespace Orchard.UI.Resources {
public class ResourceFilter : FilterProvider, IResultFilter {
- private readonly IResourceManager _resourceManager;
private readonly IWorkContextAccessor _workContextAccessor;
private readonly dynamic _shapeFactory;
public ResourceFilter(
- IResourceManager resourceManager,
IWorkContextAccessor workContextAccessor,
IShapeFactory shapeFactory) {
- _resourceManager = resourceManager;
_workContextAccessor = workContextAccessor;
_shapeFactory = shapeFactory;
}
-
public void OnResultExecuting(ResultExecutingContext filterContext) {
// should only run on a full view rendering result
if (!(filterContext.Result is ViewResult))
@@ -26,11 +22,11 @@ namespace Orchard.UI.Resources {
var ctx = _workContextAccessor.GetContext();
var head = ctx.Layout.Head;
var tail = ctx.Layout.Tail;
- head.Add(_shapeFactory.Metas().ResourceManager(_resourceManager));
- head.Add(_shapeFactory.HeadLinks().ResourceManager(_resourceManager));
- head.Add(_shapeFactory.StylesheetLinks().ResourceManager(_resourceManager));
- head.Add(_shapeFactory.HeadScripts().ResourceManager(_resourceManager));
- tail.Add(_shapeFactory.FootScripts().ResourceManager(_resourceManager));
+ head.Add(_shapeFactory.Metas());
+ head.Add(_shapeFactory.HeadLinks());
+ head.Add(_shapeFactory.StylesheetLinks());
+ head.Add(_shapeFactory.HeadScripts());
+ tail.Add(_shapeFactory.FootScripts());
}
public void OnResultExecuted(ResultExecutedContext filterContext) {
diff --git a/src/Orchard/UI/Resources/ResourceManager.cs b/src/Orchard/UI/Resources/ResourceManager.cs
index e5f36502b..429332006 100644
--- a/src/Orchard/UI/Resources/ResourceManager.cs
+++ b/src/Orchard/UI/Resources/ResourceManager.cs
@@ -3,8 +3,10 @@ using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Globalization;
+using System.IO;
using System.Linq;
using System.Web;
+using System.Web.Mvc;
using Autofac.Features.Metadata;
using Orchard.Environment.Extensions.Models;
@@ -40,6 +42,30 @@ namespace Orchard.UI.Resources {
return resourcePath;
}
+ private static TagBuilder GetTagBuilder(ResourceDefinition resource, string url) {
+ var tagBuilder = new TagBuilder(resource.TagName);
+ tagBuilder.MergeAttributes(resource.TagBuilder.Attributes);
+ if (!String.IsNullOrEmpty(resource.FilePathAttributeName)) {
+ if (!String.IsNullOrEmpty(url)) {
+ if (VirtualPathUtility.IsAppRelative(url)) {
+ url = VirtualPathUtility.ToAbsolute(url);
+ }
+ tagBuilder.MergeAttribute(resource.FilePathAttributeName, url, true);
+ }
+ }
+ return tagBuilder;
+ }
+
+ public static void WriteResource(TextWriter writer, ResourceDefinition resource, string url, string condition) {
+ if (!string.IsNullOrEmpty(condition)) {
+ writer.WriteLine("");
+ }
+ }
+
public ResourceManager(IEnumerable> resourceProviders) {
_providers = resourceProviders;
}
diff --git a/src/Orchard/UI/Resources/ResourceRequiredContext.cs b/src/Orchard/UI/Resources/ResourceRequiredContext.cs
index 1cbe31f31..8475613ad 100644
--- a/src/Orchard/UI/Resources/ResourceRequiredContext.cs
+++ b/src/Orchard/UI/Resources/ResourceRequiredContext.cs
@@ -6,11 +6,15 @@ namespace Orchard.UI.Resources {
public ResourceDefinition Resource { get; set; }
public RequireSettings Settings { get; set; }
+ public string GetResourceUrl(RequireSettings baseSettings, string appPath) {
+ return Resource.ResolveUrl(baseSettings == null ? Settings : baseSettings.Combine(Settings), appPath);
+ }
+
public TagBuilder GetTagBuilder(RequireSettings baseSettings, string appPath) {
var tagBuilder = new TagBuilder(Resource.TagName);
tagBuilder.MergeAttributes(Resource.TagBuilder.Attributes);
if (!String.IsNullOrEmpty(Resource.FilePathAttributeName)) {
- var resolvedUrl = Resource.ResolveUrl(baseSettings == null ? Settings : baseSettings.Combine(Settings), appPath);
+ var resolvedUrl = GetResourceUrl(baseSettings, appPath);
if (!String.IsNullOrEmpty(resolvedUrl)) {
tagBuilder.MergeAttribute(Resource.FilePathAttributeName, resolvedUrl, true);
}
diff --git a/src/Orchard/Utility/Extensions/StringExtensions.cs b/src/Orchard/Utility/Extensions/StringExtensions.cs
index bc1225b1e..3a11a1c65 100644
--- a/src/Orchard/Utility/Extensions/StringExtensions.cs
+++ b/src/Orchard/Utility/Extensions/StringExtensions.cs
@@ -1,4 +1,5 @@
-using System.Linq;
+using System;
+using System.Linq;
using System.Text.RegularExpressions;
using Orchard.Localization;
@@ -55,5 +56,16 @@ namespace Orchard.Utility.Extensions {
? ""
: Regex.Replace(text, @"(\r?\n)", replacement, RegexOptions.Singleline);
}
+
+ public static string ToHexString(this byte[] bytes) {
+ return BitConverter.ToString(bytes).Replace("-", "");
+ }
+
+ public static byte[] ToByteArray(this string hex) {
+ return Enumerable.Range(0, hex.Length).
+ Where(x => 0 == x % 2).
+ Select(x => Convert.ToByte(hex.Substring(x, 2), 16)).
+ ToArray();
+ }
}
}
\ No newline at end of file