diff --git a/src/Umbraco.Core/Packaging/PackageBinaryInspector.cs b/src/Umbraco.Core/Packaging/PackageBinaryInspector.cs index faff225c8a..6eed83b7af 100644 --- a/src/Umbraco.Core/Packaging/PackageBinaryInspector.cs +++ b/src/Umbraco.Core/Packaging/PackageBinaryInspector.cs @@ -3,46 +3,48 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; +using System.Security; +using System.Security.Permissions; using System.Text; using System.Threading.Tasks; +using System.Web; namespace Umbraco.Core.Packaging { - internal class PackageBinaryInspector + internal class PackageBinaryInspector : MarshalByRefObject { - - public static IEnumerable BinariesContainInstanceOf(string dllPath) + public IEnumerable PerformScan(string dllPath, out string[] errorReport) { - var result = new List(); - if (Directory.Exists(dllPath) == false) { throw new DirectoryNotFoundException("Could not find directory " + dllPath); } + var files = Directory.GetFiles(dllPath, "*.dll"); - + var dllsWithReference = new List(); + var errors = new List(); + var assembliesWithErrors = new List(); + //we need this handler to resolve assembly dependencies below AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += (s, e) => { - var ass = Assembly.ReflectionOnlyLoad(e.Name); - if (ass == null) - { - throw new TypeLoadException("Could not load assembly " + e.Name); - } - return ass; + var a = Assembly.ReflectionOnlyLoad(e.Name); + if (a == null) throw new TypeLoadException("Could not load assembly " + e.Name); + return a; }; - //First load each dll file into the context - foreach (var f in files) - { - if (File.Exists(f) == false) - { - throw new FileNotFoundException("Could not find file " + f); - } - Assembly.ReflectionOnlyLoadFrom(f); - } + //First load each dll file into the context + foreach (var f in files) Assembly.ReflectionOnlyLoadFrom(f); - var toIgnore = new List(); + ////before we try to load these assemblies into context, ensure we haven't done that already + //var alreadyLoaded = AppDomain.CurrentDomain.ReflectionOnlyGetAssemblies(); + ////First load each dll file into the context + //foreach (var f in files.Where(a => !IsAlreadyLoaded(a, alreadyLoaded))) + //{ + // //NOTE: if you're loading an already loaded assembly from a new location + // // you will get a FileLoadException here. + // Assembly.ReflectionOnlyLoadFrom(f); + //} //Then load each referenced assembly into the context foreach (var f in files) @@ -54,27 +56,81 @@ namespace Umbraco.Core.Packaging { Assembly.ReflectionOnlyLoad(assemblyName.FullName); } - catch (Exception) + catch (FileNotFoundException) { - //if an exception occurs it means that a referenced assembly could not be found - unless something else strange is going on. - //we'll log an error for this to return in our report - result.Add("This package references an assembly that was not found (" + assemblyName.FullName + "), this package may have problems running"); - toIgnore.Add(f); + //if an exception occurs it means that a referenced assembly could not be found + errors.Add( + string.Concat("This package references the assembly '", + assemblyName.Name, + "' which was not found, this package may have problems running")); + assembliesWithErrors.Add(f); } } } //now that we have all referenced types into the context we can look up stuff - foreach (var f in files.Except(toIgnore)) + foreach (var f in files.Except(assembliesWithErrors)) { //now we need to see if they contain any type 'T' var reflectedAssembly = Assembly.ReflectionOnlyLoadFrom(f); - var found = reflectedAssembly.GetExportedTypes().Where(TypeHelper.IsTypeAssignableFrom).ToArray(); - result.AddRange(found.Select(x => x.FullName)); + var found = reflectedAssembly.GetExportedTypes().Where(TypeHelper.IsTypeAssignableFrom); + if (found.Any()) + { + dllsWithReference.Add(reflectedAssembly.FullName); + } } + errorReport = errors.ToArray(); + return dllsWithReference; + } + + public static IEnumerable ScanAssembliesForTypeReference(string dllPath, out string[] errorReport) + { + var appDomain = GetTempAppDomain(); + var type = typeof(PackageBinaryInspector); + var value = (PackageBinaryInspector) appDomain.CreateInstanceAndUnwrap( + type.Assembly.FullName, + type.FullName); + var result = value.PerformScan(dllPath, out errorReport); + AppDomain.Unload(appDomain); return result; } + private static AppDomain GetTempAppDomain() + { + //copy the current app domain setup but don't shadow copy files + var appName = "TempDomain" + Guid.NewGuid(); + var domainSetup = new AppDomainSetup + { + ApplicationName = appName, + ShadowCopyFiles = "false", + ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase, + ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile, + DynamicBase = AppDomain.CurrentDomain.SetupInformation.DynamicBase, + LicenseFile = AppDomain.CurrentDomain.SetupInformation.LicenseFile, + LoaderOptimization = AppDomain.CurrentDomain.SetupInformation.LoaderOptimization, + PrivateBinPath = AppDomain.CurrentDomain.SetupInformation.PrivateBinPath, + PrivateBinPathProbe = AppDomain.CurrentDomain.SetupInformation.PrivateBinPathProbe + }; + + //create new domain with full trust + return AppDomain.CreateDomain( + appName, + AppDomain.CurrentDomain.Evidence, + domainSetup, + new PermissionSet(PermissionState.Unrestricted)); + } + + //private static bool IsAlreadyLoaded(string assemblyFile, IEnumerable alreadyLoaded) + //{ + // return alreadyLoaded.Any(assembly => GetAssemblyLocation(assembly) == assemblyFile); + //} + + //private static string GetAssemblyLocation(Assembly assembly) + //{ + // var uri = new Uri(assembly.CodeBase); + // return uri.LocalPath; + //} + } } diff --git a/src/Umbraco.Core/Security/UmbracoBackOfficeIdentity.cs b/src/Umbraco.Core/Security/UmbracoBackOfficeIdentity.cs index 36b4b2a370..40a5764abf 100644 --- a/src/Umbraco.Core/Security/UmbracoBackOfficeIdentity.cs +++ b/src/Umbraco.Core/Security/UmbracoBackOfficeIdentity.cs @@ -1,4 +1,5 @@ using System; +using System.Runtime.Serialization; using System.Web; using System.Web.Security; using Newtonsoft.Json; @@ -11,6 +12,7 @@ namespace Umbraco.Core.Security /// /// All values are lazy loaded for performance reasons as the constructor is called for every single request /// + [Serializable] public class UmbracoBackOfficeIdentity : FormsIdentity { public UmbracoBackOfficeIdentity(FormsAuthenticationTicket ticket) @@ -104,5 +106,6 @@ namespace Umbraco.Core.Security HttpContext.Current.Items[typeof (UmbracoBackOfficeIdentity)] = DeserializedData; } } + } } \ No newline at end of file diff --git a/src/Umbraco.Core/Security/UserData.cs b/src/Umbraco.Core/Security/UserData.cs index 5f96143fe4..903d85851f 100644 --- a/src/Umbraco.Core/Security/UserData.cs +++ b/src/Umbraco.Core/Security/UserData.cs @@ -1,4 +1,5 @@ -using System.Runtime.Serialization; +using System; +using System.Runtime.Serialization; namespace Umbraco.Core.Security { @@ -6,6 +7,7 @@ namespace Umbraco.Core.Security /// Data structure used to store information in the authentication cookie /// [DataContract(Name = "userData", Namespace = "")] + [Serializable] internal class UserData { public UserData() diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/installer.aspx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/installer.aspx.cs index db918593bd..e18d46c625 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/installer.aspx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/installer.aspx.cs @@ -157,6 +157,11 @@ namespace umbraco.presentation.developer.packages } } + if (_installer.ContainsLegacyPropertyEditors) + { + LegacyPropertyEditorPanel.Visible = true; + } + if (_installer.ContainsBinaryFileErrors) { BinaryFileErrorsPanel.Visible = true; diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/installer.aspx.designer.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/installer.aspx.designer.cs index 6b97d11913..abe1f67506 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/installer.aspx.designer.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Packages/installer.aspx.designer.cs @@ -301,6 +301,7 @@ namespace umbraco.presentation.developer.packages { protected global::umbraco.uicontrols.PropertyPanel pp_templateConflicts; protected global::umbraco.uicontrols.PropertyPanel BinaryFileErrorsPanel; + protected global::umbraco.uicontrols.PropertyPanel LegacyPropertyEditorPanel; protected global::System.Web.UI.WebControls.Literal BinaryFileErrorReport; /// diff --git a/src/umbraco.cms/businesslogic/Packager/Installer.cs b/src/umbraco.cms/businesslogic/Packager/Installer.cs index 314d4a5804..01dc2522bf 100644 --- a/src/umbraco.cms/businesslogic/Packager/Installer.cs +++ b/src/umbraco.cms/businesslogic/Packager/Installer.cs @@ -63,15 +63,20 @@ namespace umbraco.cms.businesslogic.packager public IDictionary ConflictingTemplateAliases { get { return _conflictingTemplateAliases; } } /// - /// Indicates that the package contains legacy property editors that are not compatible with this version (v7) + /// Indicates that the package contains assembly reference errors /// public bool ContainsBinaryFileErrors { get; private set; } /// - /// List each property editor that is not compatible + /// List each assembly reference error /// public List BinaryFileErrors { get { return _binaryFileErrors; } } + /// + /// Indicates that the package contains legacy property editors + /// + public bool ContainsLegacyPropertyEditors { get; private set; } + public bool ContainsStyleSheeConflicts { get; private set; } public IDictionary ConflictingStyleSheetNames { get { return _conflictingStyleSheetNames; } } @@ -597,11 +602,16 @@ namespace umbraco.cms.businesslogic.packager if (ContainsUnsecureFiles) { //Now we want to see if the DLLs contain any legacy data types since we want to warn people about that - var binaryFileErrors = PackageBinaryInspector.BinariesContainInstanceOf(tempDir).ToArray(); - if (binaryFileErrors.Any()) + string[] assemblyErrors; + var assembliesWithReferences = PackageBinaryInspector.ScanAssembliesForTypeReference(tempDir, out assemblyErrors).ToArray(); + if (assemblyErrors.Any()) { ContainsBinaryFileErrors = true; - BinaryFileErrors.AddRange(binaryFileErrors); + BinaryFileErrors.AddRange(assemblyErrors); + } + if (assembliesWithReferences.Any()) + { + ContainsLegacyPropertyEditors = true; } } @@ -741,8 +751,18 @@ namespace umbraco.cms.businesslogic.packager private static string UnPack(string zipName) { // Unzip - string tempDir = IOHelper.MapPath(SystemDirectories.Data) + Path.DirectorySeparatorChar + Guid.NewGuid().ToString(); - Directory.CreateDirectory(tempDir); + + //the temp directory will be the package GUID - this keeps it consistent! + //the zipName is always the package Guid.umb + + var packageFileName = Path.GetFileNameWithoutExtension(zipName); + var packageId = Guid.NewGuid(); + Guid.TryParse(packageFileName, out packageId); + + string tempDir = IOHelper.MapPath(SystemDirectories.Data) + Path.DirectorySeparatorChar + packageId.ToString(); + //clear the directory if it exists + if (Directory.Exists(tempDir)) Directory.Delete(tempDir, true); + Directory.CreateDirectory(tempDir); var s = new ZipInputStream(File.OpenRead(zipName));