diff --git a/src/Umbraco.Core/Packaging/IConflictingPackageContentFinder.cs b/src/Umbraco.Core/Packaging/IConflictingPackageContentFinder.cs index ce528b56e3..e9690ab672 100644 --- a/src/Umbraco.Core/Packaging/IConflictingPackageContentFinder.cs +++ b/src/Umbraco.Core/Packaging/IConflictingPackageContentFinder.cs @@ -5,7 +5,6 @@ namespace Umbraco.Core.Packaging { public interface IConflictingPackageContentFinder { - IFile[] FindConflictingStylesheets(XElement stylesheetNotes); ITemplate[] FindConflictingTemplates(XElement templateNotes); IMacro[] FindConflictingMacros(XElement macroNodes); diff --git a/src/Umbraco.Core/Packaging/IPackageExtraction.cs b/src/Umbraco.Core/Packaging/IPackageExtraction.cs index efe2949356..da0e718779 100644 --- a/src/Umbraco.Core/Packaging/IPackageExtraction.cs +++ b/src/Umbraco.Core/Packaging/IPackageExtraction.cs @@ -27,7 +27,14 @@ namespace Umbraco.Core.Packaging /// filename of the file to copy /// destination path (including destination filename) /// True a file was overwritten - bool CopyFileFromArchive(string packageFilePath, string fileInPackageName, string destinationfilePath); + void CopyFileFromArchive(string packageFilePath, string fileInPackageName, string destinationfilePath); + + /// + /// Copies a file from package to given destination + /// + /// Full path to the ubraco package file + /// Key: Source file in package. Value: Destination path inclusive file name + void CopyFilesFromArchive(string packageFilePath, IEnumerable> sourceDestination); /// /// Check if given list of files can be found in the package @@ -44,5 +51,13 @@ namespace Umbraco.Core.Packaging /// Full path to the umbraco package file /// list of files that are found more than ones (accross directories) in the package IEnumerable FindDubletFileNames(string packageFilePath); + + /// + /// Reads the given files from archive and returns them as a collection of byte arrays + /// + /// + /// + /// + IEnumerable ReadFilesFromArchive(string packageFilePath, IEnumerable filesToGet); } } \ No newline at end of file diff --git a/src/Umbraco.Core/Packaging/Models/InstallationSummary.cs b/src/Umbraco.Core/Packaging/Models/InstallationSummary.cs index 198218f70a..ab501eaaf0 100644 --- a/src/Umbraco.Core/Packaging/Models/InstallationSummary.cs +++ b/src/Umbraco.Core/Packaging/Models/InstallationSummary.cs @@ -4,8 +4,6 @@ using Umbraco.Core.Models; namespace Umbraco.Core.Packaging.Models { - - [Serializable] [DataContract(IsReference = true)] internal class InstallationSummary @@ -15,29 +13,11 @@ namespace Umbraco.Core.Packaging.Models public ILanguage[] LanguagesInstalled { get; set; } public IDictionaryItem[] DictionaryItemsInstalled { get; set; } public IMacro[] MacrosInstalled { get; set; } - public Details[] FilesInstalled { get; set; } + public string[] FilesInstalled { get; set; } public ITemplate[] TemplatesInstalled { get; set; } - public IContentType[] DocumentTypesInstalled { get; set; } + public IContentType[] ContentTypesInstalled { get; set; } public IFile[] StylesheetsInstalled { get; set; } - public IContent[] DocumentsInstalled { get; set; } + public IContent[] ContentInstalled { get; set; } public PackageAction[] Actions { get; set; } } - - [Serializable] - [DataContract(IsReference = true)] - public enum InstallStatus - { - Inserted, - Overwridden - } - - - [Serializable] - [DataContract(IsReference = true)] - public class Details - { - public InstallStatus Status { get; set; } - public TItem Destination { get; set; } - public TItem Source { get; set; } - } } \ No newline at end of file diff --git a/src/Umbraco.Core/Packaging/Models/PreInstallWarnings.cs b/src/Umbraco.Core/Packaging/Models/PreInstallWarnings.cs index 5953616e20..3dbe1f3e0a 100644 --- a/src/Umbraco.Core/Packaging/Models/PreInstallWarnings.cs +++ b/src/Umbraco.Core/Packaging/Models/PreInstallWarnings.cs @@ -1,12 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; using Umbraco.Core.Models; namespace Umbraco.Core.Packaging.Models { + [Serializable] + [DataContract(IsReference = true)] public class PreInstallWarnings { - public IFileInPackageInfo[] UnsecureFiles { get; set; } + public KeyValuePair[] UnsecureFiles { get; set; } + public KeyValuePair[] FilesReplaced { get; set; } public IMacro[] ConflictingMacroAliases { get; set; } public ITemplate[] ConflictingTemplateAliases { get; set; } public IFile[] ConflictingStylesheetNames { get; set; } + public string[] AssembliesWithLegacyPropertyEditors { get; set; } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Packaging/PackageBinaryByteInspector.cs b/src/Umbraco.Core/Packaging/PackageBinaryByteInspector.cs new file mode 100644 index 0000000000..010e3a8521 --- /dev/null +++ b/src/Umbraco.Core/Packaging/PackageBinaryByteInspector.cs @@ -0,0 +1,219 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Security; +using System.Security.Permissions; +using Umbraco.Core.Logging; + +namespace Umbraco.Core.Packaging +{ + internal class PackageBinaryByteInspector : MarshalByRefObject + { + /// + /// Entry point to call from your code + /// + /// + /// + /// + /// + /// + /// Will perform the assembly scan in a separate app domain + /// + public static IEnumerable ScanAssembliesForTypeReference(IEnumerable assemblys, out string[] errorReport) + { + var appDomain = GetTempAppDomain(); + var type = typeof(PackageBinaryByteInspector); + try + { + var value = (PackageBinaryByteInspector)appDomain.CreateInstanceAndUnwrap( + type.Assembly.FullName, + type.FullName); + var result = value.PerformScan(assemblys.ToArray(), out errorReport); + return result; + } + finally + { + AppDomain.Unload(appDomain); + } + } + + /// + /// Performs the assembly scanning + /// + /// + /// + /// + /// + /// + /// This method is executed in a separate app domain + /// + internal IEnumerable PerformScan(IEnumerable assemblies, out string[] errorReport) + { + 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 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 + var loaded = assemblies.Select(Assembly.ReflectionOnlyLoad).ToList(); + + //load each of the LoadFrom assemblies into the Load context too + foreach (var a in loaded) + { + Assembly.ReflectionOnlyLoad(a.FullName); + } + + //get the list of assembly names to compare below + var loadedNames = loaded.Select(x => x.GetName().Name).ToArray(); + + //Then load each referenced assembly into the context + foreach (var a in loaded) + { + //don't load any referenced assemblies that are already found in the loaded array - this is based on name + // regardless of version. We'll assume that if the assembly found in the folder matches the assembly name + // being looked for, that is the version the user has shipped their package with and therefore it 'must' be correct + foreach (var assemblyName in a.GetReferencedAssemblies().Where(ass => loadedNames.Contains(ass.Name) == false)) + { + try + { + Assembly.ReflectionOnlyLoad(assemblyName.FullName); + } + catch (FileNotFoundException) + { + //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")); + assembliesWithErrors.Add(a); + } + catch (Exception ex) + { + //if an exception occurs it means that a referenced assembly could not be found + errors.Add( + string.Concat("This package could not be verified for compatibility. An error occurred while loading a referenced assembly '", + assemblyName.Name, + "' see error log for full details.")); + assembliesWithErrors.Add(a); + LogHelper.Error("An error occurred scanning package assemblies", ex); + } + } + } + + var contractType = GetLoadFromContractType(); + + //now that we have all referenced types into the context we can look up stuff + foreach (var a in loaded.Except(assembliesWithErrors)) + { + //now we need to see if they contain any type 'T' + var reflectedAssembly = a; + + try + { + var found = reflectedAssembly.GetExportedTypes() + .Where(contractType.IsAssignableFrom); + + if (found.Any()) + { + dllsWithReference.Add(reflectedAssembly.FullName); + } + } + catch (Exception ex) + { + //This is a hack that nobody can seem to get around, I've read everything and it seems that + // this is quite a common thing when loading types into reflection only load context, so + // we're just going to ignore this specific one for now + var typeLoadEx = ex as TypeLoadException; + if (typeLoadEx != null) + { + if (typeLoadEx.Message.InvariantContains("does not have an implementation")) + { + //ignore + continue; + } + } + else + { + errors.Add( + string.Concat("This package could not be verified for compatibility. An error occurred while scanning a packaged assembly '", + a.GetName().Name, + "' see error log for full details.")); + assembliesWithErrors.Add(a); + LogHelper.Error("An error occurred scanning package assemblies", ex); + } + } + + } + + errorReport = errors.ToArray(); + return dllsWithReference; + } + + + /// + /// In order to compare types, the types must be in the same context, this method will return the type that + /// we are checking against but from the Load context. + /// + /// + /// + private static Type GetLoadFromContractType() + { + var contractAssemblyLoadFrom =Assembly.ReflectionOnlyLoad(typeof (T).Assembly.FullName); + + var contractType = contractAssemblyLoadFrom.GetExportedTypes() + .FirstOrDefault(x => x.FullName == typeof(T).FullName && x.Assembly.FullName == typeof(T).Assembly.FullName); + + if (contractType == null) + { + throw new InvalidOperationException("Could not find type " + typeof(T) + " in the LoadFrom assemblies"); + } + return contractType; + } + + /// + /// Create an app domain + /// + /// + 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 string GetAssemblyPath(Assembly a) + { + var codeBase = a.CodeBase; + var uri = new Uri(codeBase); + return uri.LocalPath; + } + + } +} diff --git a/src/Umbraco.Core/Packaging/PackageExtraction.cs b/src/Umbraco.Core/Packaging/PackageExtraction.cs index ea59ac671f..6550fd435d 100644 --- a/src/Umbraco.Core/Packaging/PackageExtraction.cs +++ b/src/Umbraco.Core/Packaging/PackageExtraction.cs @@ -67,43 +67,41 @@ namespace Umbraco.Core.Packaging } } + - public bool CopyFileFromArchive(string packageFilePath, string fileInPackageName, string destinationfilePath) + public void CopyFileFromArchive(string packageFilePath, string fileInPackageName, string destinationfilePath) { - bool fileFoundInArchive = false; - bool fileOverwritten = false; + CopyFilesFromArchive(packageFilePath, new[]{new KeyValuePair(fileInPackageName, destinationfilePath) } ); + } + + public void CopyFilesFromArchive(string packageFilePath, IEnumerable> sourceDestination) + { + var d = sourceDestination.ToDictionary(k => k.Key.ToLower(), v => v.Value); + ReadZipfileEntries(packageFilePath, (entry, stream) => { - string fileName = Path.GetFileName(entry.Name); + string fileName = (Path.GetFileName(entry.Name) ?? string.Empty).ToLower(); + if (fileName == string.Empty) { return true; } - if (string.IsNullOrEmpty(fileName) == false && - fileName.Equals(fileInPackageName, StringComparison.InvariantCultureIgnoreCase)) + string destination; + if (string.IsNullOrEmpty(fileName) == false && d.TryGetValue(fileName, out destination)) { - fileFoundInArchive = true; - - fileOverwritten = File.Exists(destinationfilePath); - - using (var streamWriter = File.Open(destinationfilePath, FileMode.Create)) + using (var streamWriter = File.Open(destination, FileMode.Create)) { - var data = new byte[2048]; - int size; - while ((size = stream.Read(data, 0, data.Length)) > 0) - { - streamWriter.Write(data, 0, size); - } - - streamWriter.Close(); + stream.CopyTo(streamWriter); } - return false; + + d.Remove(fileName); + return d.Any(); } return true; }); - - if (fileFoundInArchive == false) throw new ArgumentException(string.Format("Could not find file: {0} in package file: {1}", fileInPackageName, packageFilePath), "fileInPackageName"); - - return fileOverwritten; + if (d.Any()) + { + throw new ArgumentException(string.Format("The following source file(s): \"{0}\" could not be found in archive: \"{1}\"", string.Join("\", \"",d.Keys), packageFilePath)); + } } public IEnumerable FindMissingFiles(string packageFilePath, IEnumerable expectedFiles) @@ -148,6 +146,39 @@ namespace Umbraco.Core.Packaging return dictionary.Values.Where(v => v.Count > 1).SelectMany(v => v); } + public IEnumerable ReadFilesFromArchive(string packageFilePath, IEnumerable filesToGet) + { + CheckPackageExists(packageFilePath); + + var files = new HashSet(filesToGet.Select(f => f.ToLower())); + + using (var fs = File.OpenRead(packageFilePath)) + { + using (var zipInputStream = new ZipInputStream(fs)) + { + ZipEntry zipEntry; + while ((zipEntry = zipInputStream.GetNextEntry()) != null) + { + + if (zipEntry.IsDirectory) continue; + + if (files.Contains(zipEntry.Name)) + { + using (var memStream = new MemoryStream()) + { + zipInputStream.CopyTo(memStream); + yield return memStream.ToArray(); + memStream.Close(); + } + } + } + + zipInputStream.Close(); + } + fs.Close(); + } + } + private void ReadZipfileEntries(string packageFilePath, Func entryFunc, bool skipsDirectories = true) { CheckPackageExists(packageFilePath); diff --git a/src/Umbraco.Core/Packaging/PackageInstallation.cs b/src/Umbraco.Core/Packaging/PackageInstallation.cs index deaf43416b..5b91e76a22 100644 --- a/src/Umbraco.Core/Packaging/PackageInstallation.cs +++ b/src/Umbraco.Core/Packaging/PackageInstallation.cs @@ -9,8 +9,10 @@ using Umbraco.Core.Configuration; using Umbraco.Core.IO; using Umbraco.Core.Models; using Umbraco.Core.Packaging.Models; -using Umbraco.Core.Services; - +using Umbraco.Core.Services; +using umbraco.interfaces; +using File = System.IO.File; + namespace Umbraco.Core.Packaging { internal class PackageInstallation : IPackageInstallation @@ -89,7 +91,7 @@ namespace Umbraco.Core.Packaging try { XElement rootElement = GetConfigXmlElement(packageFilePath); - return GetPreInstallWarnings(rootElement); + return GetPreInstallWarnings(packageFilePath, rootElement); } catch (Exception e) { @@ -150,20 +152,20 @@ namespace Umbraco.Core.Packaging var macros = EmptyArrayIfNull(macroes)?? InstallMacros(macroes, userId); installationSummary.MacrosInstalled = macros; - var keyValuePairs = EmptyArrayIfNull>(packageFile) ?? InstallFiles(packageFile, files); + var keyValuePairs = EmptyArrayIfNull(packageFile) ?? InstallFiles(packageFile, files); installationSummary.FilesInstalled = keyValuePairs; var templatesInstalled = EmptyArrayIfNull(templates) ?? InstallTemplats(templates, userId); installationSummary.TemplatesInstalled = templatesInstalled; var documentTypesInstalled = EmptyArrayIfNull(documentTypes) ?? InstallDocumentTypes(documentTypes, userId); - installationSummary.DocumentTypesInstalled =documentTypesInstalled; + installationSummary.ContentTypesInstalled =documentTypesInstalled; var stylesheetsInstalled = EmptyArrayIfNull(styleSheets) ?? InstallStylesheets(styleSheets, userId); installationSummary.StylesheetsInstalled = stylesheetsInstalled; var documentsInstalled = EmptyArrayIfNull(documentSet) ?? InstallDocuments(documentSet, userId); - installationSummary.DocumentsInstalled = documentsInstalled; + installationSummary.ContentInstalled = documentsInstalled; var packageActions = EmptyArrayIfNull(actions) ?? GetPackageActions(actions, metaData.Name); installationSummary.Actions = packageActions; @@ -228,12 +230,9 @@ namespace Umbraco.Core.Packaging XElement filesElement = rootElement.Element(Constants.Packaging.FilesNodeName); if (filesElement != null) { - IEnumerable extractFileInPackageInfos = - ExtractFileInPackageInfos(filesElement).ToArray(); + var sourceDestination = ExtractSourceDestinationFileInformation(filesElement).ToArray(); - IEnumerable missingFiles = - _packageExtraction.FindMissingFiles(packageFilePath, - extractFileInPackageInfos.Select(i => i.FileNameInPackage)).ToArray(); + var missingFiles = _packageExtraction.FindMissingFiles(packageFilePath, sourceDestination.Select(i => i.Key)).ToArray(); if (missingFiles.Any()) { @@ -241,14 +240,14 @@ namespace Umbraco.Core.Packaging string.Join(", ", missingFiles.Select( mf => { - FileInPackageInfo fileInPackageInfo = - extractFileInPackageInfos.Single(fi => fi.FileNameInPackage == mf); - return string.Format("Guid: \"{0}\" Original File: \"{1}\"", - fileInPackageInfo.FileNameInPackage, fileInPackageInfo.RelativePath); + var sd = sourceDestination.Single(fi => fi.Key == mf); + return string.Format("source: \"{0}\" destination: \"{1}\"", + sd.Key, sd.Value); }))); } IEnumerable dubletFileNames = _packageExtraction.FindDubletFileNames(packageFilePath).ToArray(); + if (dubletFileNames.Any()) { throw new Exception("The following filename(s) are found more than one time in the package, since the filename is used ad primary key, this is not allowed: " + @@ -347,21 +346,21 @@ namespace Umbraco.Core.Packaging } - private Details[] InstallFiles(string packageFilePath, XElement filesElement) + private string[] InstallFiles(string packageFilePath, XElement filesElement) { - return ExtractFileInPackageInfos(filesElement).Select(fpi => - { - bool existingOverrided = _packageExtraction.CopyFileFromArchive(packageFilePath, fpi.FileNameInPackage, - fpi.FullPath); + var sourceDestination = ExtractSourceDestinationFileInformation(filesElement); + sourceDestination = AppendRootToDestination(FullpathToRoot, sourceDestination); - return new Details() - { - Source = fpi.FileNameInPackage, - Destination = fpi.FullPath, - Status = existingOverrided ? InstallStatus.Overwridden : InstallStatus.Inserted - }; + _packageExtraction.CopyFilesFromArchive(packageFilePath, sourceDestination); + + return sourceDestination.Select(sd => sd.Value).ToArray(); + } - }).ToArray(); + private KeyValuePair[] AppendRootToDestination(string fullpathToRoot, IEnumerable> sourceDestination) + { + return + sourceDestination.Select( + sd => new KeyValuePair(sd.Key, Path.Combine(fullpathToRoot, sd.Value))).ToArray(); } private IMacro[] InstallMacros(XElement macroElements, int userId = 0) @@ -406,45 +405,70 @@ namespace Umbraco.Core.Packaging return _packagingService.ImportDataTypeDefinitions(dataTypeElements, userId).ToArray(); } - private PreInstallWarnings GetPreInstallWarnings(XElement rootElement) + private PreInstallWarnings GetPreInstallWarnings(string packagePath, XElement rootElement) { XElement files = rootElement.Element(Constants.Packaging.FilesNodeName); XElement styleSheets = rootElement.Element(Constants.Packaging.StylesheetsNodeName); XElement templates = rootElement.Element(Constants.Packaging.TemplatesNodeName); XElement alias = rootElement.Element(Constants.Packaging.MacrosNodeName); - var conflictingPackageContent = new PreInstallWarnings - { - UnsecureFiles = files == null ? new IFileInPackageInfo[0] : FindUnsecureFiles(files), - ConflictingMacroAliases = alias == null ? new IMacro[0] : ConflictingPackageContentFinder.FindConflictingMacros(alias), - ConflictingTemplateAliases = - templates == null ? new ITemplate[0] : ConflictingPackageContentFinder.FindConflictingTemplates(templates), - ConflictingStylesheetNames = - styleSheets == null ? new IFile[0] : ConflictingPackageContentFinder.FindConflictingStylesheets(styleSheets) - }; + + var sourceDestination = EmptyArrayIfNull>(files) ?? ExtractSourceDestinationFileInformation(files); - return conflictingPackageContent; + var installWarnings = new PreInstallWarnings(); + + var macroAliases = EmptyArrayIfNull(alias) ?? ConflictingPackageContentFinder.FindConflictingMacros(alias); + installWarnings.ConflictingMacroAliases = macroAliases; + + var templateAliases = EmptyArrayIfNull(templates) ?? ConflictingPackageContentFinder.FindConflictingTemplates(templates); + installWarnings.ConflictingTemplateAliases = templateAliases; + + var stylesheetNames = EmptyArrayIfNull(styleSheets) ?? ConflictingPackageContentFinder.FindConflictingStylesheets(styleSheets); + installWarnings.ConflictingStylesheetNames = stylesheetNames; + + installWarnings.UnsecureFiles = FindUnsecureFiles(sourceDestination); + installWarnings.FilesReplaced = FindFilesToBeReplaced(sourceDestination); + installWarnings.AssembliesWithLegacyPropertyEditors = FindLegacyPropertyEditors(packagePath, sourceDestination); + + return installWarnings; } - private IFileInPackageInfo[] FindUnsecureFiles(XElement fileElement) + private KeyValuePair[] FindFilesToBeReplaced(IEnumerable> sourceDestination) { - return ExtractFileInPackageInfos(fileElement) - .Where(IsFileNodeUnsecure).Cast().ToArray(); + return sourceDestination.Where(sd => File.Exists(Path.Combine(FullpathToRoot, sd.Value))).ToArray(); } - private bool IsFileNodeUnsecure(FileInPackageInfo fileInPackageInfo) + private string[] FindLegacyPropertyEditors(string packagePath, IEnumerable> sourceDestinationPair) { + var dlls = sourceDestinationPair.Where( + sd => (Path.GetExtension(sd.Value) ?? string.Empty).Equals(".dll", StringComparison.InvariantCultureIgnoreCase)).Select(sd => sd.Key).ToArray(); - // Should be done with regex :) - if (fileInPackageInfo.Directory.ToLower().Contains(IOHelper.DirSepChar + "app_code")) return true; - if (fileInPackageInfo.Directory.ToLower().Contains(IOHelper.DirSepChar + "bin")) return true; + if (dlls.Any() == false) { return new string[0]; } + + + // Now we want to see if the DLLs contain any legacy data types since we want to warn people about that + string[] assemblyErrors; + IEnumerable assemblyesToScan =_packageExtraction.ReadFilesFromArchive(packagePath, dlls); + return PackageBinaryByteInspector.ScanAssembliesForTypeReference(assemblyesToScan, out assemblyErrors).ToArray(); + + } - string extension = Path.GetExtension(fileInPackageInfo.Directory); + private KeyValuePair[] FindUnsecureFiles(IEnumerable> sourceDestinationPair) + { + return sourceDestinationPair.Where(sd => IsFileDestinationUnsecure(sd.Value)).ToArray(); + } - return extension.Equals(".dll", StringComparison.InvariantCultureIgnoreCase); + private bool IsFileDestinationUnsecure(string destination) + { + var unsecureDirNames = new[] {"bin", "app_code"}; + if(unsecureDirNames.Any(ud => destination.StartsWith(ud, StringComparison.InvariantCultureIgnoreCase))) + return true; + + string extension = Path.GetExtension(destination); + return extension != null && extension.Equals(".dll", StringComparison.InvariantCultureIgnoreCase); } - private IEnumerable ExtractFileInPackageInfos(XElement filesElement) + private KeyValuePair[] ExtractSourceDestinationFileInformation(XElement filesElement) { if (string.Equals(Constants.Packaging.FilesNodeName, filesElement.Name.LocalName) == false) { @@ -475,15 +499,13 @@ namespace Umbraco.Core.Packaging "filesElement"); } + var fileName = PrepareAsFilePathElement(orgNameElement.Value); + var relativeDir = UpdatePathPlaceholders(PrepareAsFilePathElement(orgPathElement.Value)); - return new FileInPackageInfo - { - FileNameInPackage = guidElement.Value, - FileName = PrepareAsFilePathElement(orgNameElement.Value), - RelativeDir = UpdatePathPlaceholders( - PrepareAsFilePathElement(orgPathElement.Value)), - DestinationRootDir = FullpathToRoot - }; + var relativePath = Path.Combine(relativeDir, fileName); + + + return new KeyValuePair(guidElement.Value, relativePath); }).ToArray(); } diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 8397f8a63a..64627e6a09 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -365,6 +365,7 @@ +