From 8b22eeb6abfa9dedf05afb9a9ae6f77c486eaaad Mon Sep 17 00:00:00 2001 From: Rob Reynolds Date: Mon, 4 May 2015 10:29:25 -0500 Subject: [PATCH] (GH-121) Specs and Files Service hardening - Rename Md5HashProvider to CryptoHashProvider and provide enumeration for HashAlgorithm Crytpo providers. - Implement adapter for HashAlgorithm. - Update specs for CryptoHashProvider - Specs for FilesService --- .../chocolatey.tests.integration.csproj | 2 +- ...derSpecs.cs => CrytpoHashProviderSpecs.cs} | 10 +- src/chocolatey.tests/chocolatey.tests.csproj | 3 +- .../services/FilesServiceSpecs.cs | 248 ++++++++++++++++++ .../cryptography/CrytpoHashProvider.cs | 109 ++++++++ .../cryptography/Md5HashProviderSpecs.cs | 65 ----- src/chocolatey/chocolatey.csproj | 5 +- .../ApplicationParameters.cs | 2 + .../registration/ContainerBinding.cs | 2 +- .../services/FilesService.cs | 9 +- .../infrastructure/adapters/HashAlgorithm.cs | 19 ++ .../infrastructure/adapters/IHashAlgorithm.cs | 11 + .../cryptography/CryptoHashProviderType.cs | 10 + .../cryptography/CrytpoHashProvider.cs | 79 ++++++ .../cryptography/Md5HashProvider.cs | 42 --- 15 files changed, 499 insertions(+), 117 deletions(-) rename src/chocolatey.tests.integration/infrastructure/cryptography/{Md5HashProviderSpecs.cs => CrytpoHashProviderSpecs.cs} (84%) create mode 100644 src/chocolatey.tests/infrastructure.app/services/FilesServiceSpecs.cs create mode 100644 src/chocolatey.tests/infrastructure/cryptography/CrytpoHashProvider.cs delete mode 100644 src/chocolatey.tests/infrastructure/cryptography/Md5HashProviderSpecs.cs create mode 100644 src/chocolatey/infrastructure/adapters/HashAlgorithm.cs create mode 100644 src/chocolatey/infrastructure/adapters/IHashAlgorithm.cs create mode 100644 src/chocolatey/infrastructure/cryptography/CryptoHashProviderType.cs create mode 100644 src/chocolatey/infrastructure/cryptography/CrytpoHashProvider.cs delete mode 100644 src/chocolatey/infrastructure/cryptography/Md5HashProvider.cs diff --git a/src/chocolatey.tests.integration/chocolatey.tests.integration.csproj b/src/chocolatey.tests.integration/chocolatey.tests.integration.csproj index 36d7ca3485..74e6aa82d5 100644 --- a/src/chocolatey.tests.integration/chocolatey.tests.integration.csproj +++ b/src/chocolatey.tests.integration/chocolatey.tests.integration.csproj @@ -76,7 +76,7 @@ - + diff --git a/src/chocolatey.tests.integration/infrastructure/cryptography/Md5HashProviderSpecs.cs b/src/chocolatey.tests.integration/infrastructure/cryptography/CrytpoHashProviderSpecs.cs similarity index 84% rename from src/chocolatey.tests.integration/infrastructure/cryptography/Md5HashProviderSpecs.cs rename to src/chocolatey.tests.integration/infrastructure/cryptography/CrytpoHashProviderSpecs.cs index ca63b1c570..20aa0947e7 100644 --- a/src/chocolatey.tests.integration/infrastructure/cryptography/Md5HashProviderSpecs.cs +++ b/src/chocolatey.tests.integration/infrastructure/cryptography/CrytpoHashProviderSpecs.cs @@ -23,23 +23,23 @@ namespace chocolatey.tests.integration.infrastructure.cryptography using chocolatey.infrastructure.cryptography; using chocolatey.infrastructure.filesystem; - public class Md5HashProviderSpecs + public class CrytpoHashProviderSpecs { - public abstract class Md5HashProviderSpecsBase : TinySpec + public abstract class CrytpoHashProviderSpecsBase : TinySpec { - protected Md5HashProvider Provider; + protected CrytpoHashProvider Provider; protected DotNetFileSystem FileSystem; protected string ContextDirectory; public override void Context() { FileSystem = new DotNetFileSystem(); - Provider = new Md5HashProvider(FileSystem); + Provider = new CrytpoHashProvider(FileSystem,CryptoHashProviderType.Md5); ContextDirectory = FileSystem.combine_paths(FileSystem.get_directory_name(Assembly.GetExecutingAssembly().CodeBase.Replace("file:///", string.Empty)), "context"); } } - public class when_Md5HashProvider_provides_a_hash : Md5HashProviderSpecsBase + public class when_HashProvider_provides_a_hash : CrytpoHashProviderSpecsBase { private string result; private string filePath; diff --git a/src/chocolatey.tests/chocolatey.tests.csproj b/src/chocolatey.tests/chocolatey.tests.csproj index 5693af63ce..411590c1d4 100644 --- a/src/chocolatey.tests/chocolatey.tests.csproj +++ b/src/chocolatey.tests/chocolatey.tests.csproj @@ -77,12 +77,13 @@ + - + diff --git a/src/chocolatey.tests/infrastructure.app/services/FilesServiceSpecs.cs b/src/chocolatey.tests/infrastructure.app/services/FilesServiceSpecs.cs new file mode 100644 index 0000000000..dd8bf96c41 --- /dev/null +++ b/src/chocolatey.tests/infrastructure.app/services/FilesServiceSpecs.cs @@ -0,0 +1,248 @@ +namespace chocolatey.tests.infrastructure.app.services +{ + using System; + using System.Collections.Generic; + using System.IO; + using Moq; + using Should; + using chocolatey.infrastructure.app; + using chocolatey.infrastructure.app.configuration; + using chocolatey.infrastructure.app.domain; + using chocolatey.infrastructure.app.services; + using chocolatey.infrastructure.cryptography; + using chocolatey.infrastructure.filesystem; + using chocolatey.infrastructure.results; + using chocolatey.infrastructure.services; + + public class FilesServiceSpecs + { + public abstract class FilesServiceSpecsBase : TinySpec + { + protected FilesService Service; + protected Mock XmlService = new Mock(); + protected Mock FileSystem = new Mock(); + protected Mock HashProvider = new Mock(); + + public override void Context() + { + XmlService.ResetCalls(); + FileSystem.ResetCalls(); + HashProvider.ResetCalls(); + Service = new FilesService(XmlService.Object,FileSystem.Object,HashProvider.Object); + } + } + + public class when_FilesService_reads_from_files : FilesServiceSpecsBase + { + private Func because; + + public override void Because() + { + because = () => Service.read_from_file("fake path"); + } + + [Fact] + public void should_deserialize_when_file_exists() + { + Context(); + FileSystem.Setup(x => x.file_exists(It.IsAny())).Returns(true); + XmlService.Setup(x => x.deserialize(It.IsAny())).Returns(new PackageFiles()); + + because(); + } + + [Fact] + public void should_not_deserialize_if_file_does_not_exist() + { + Context(); + FileSystem.Setup(x => x.file_exists(It.IsAny())).Returns(false); + + because(); + + XmlService.Verify(x => x.deserialize(It.IsAny()),Times.Never); + } + } + + public class when_FilesService_saves_files : FilesServiceSpecsBase + { + private Action because; + private PackageFiles files; + + public override void Because() + { + because = () => Service.save_to_file(files , "fake path"); + } + + [Fact] + public void should_save_if_the_snapshot_is_not_null() + { + Context(); + files = new PackageFiles(); + + because(); + + XmlService.Verify(x => x.serialize(files, It.IsAny()), Times.Once()); + } + + [Fact] + public void should_not_do_anything_if_the_snapshot_is_null() + { + Context(); + files = null; + + because(); + + XmlService.Verify(x => x.serialize(files, It.IsAny()), Times.Never); + } + } + + public class when_FilesService_captures_files_and_install_directory_reports_choco_install_location : FilesServiceSpecsBase + { + private PackageFiles result; + private PackageResult packageResult; + private readonly ChocolateyConfiguration config = new ChocolateyConfiguration(); + + public override void Context() + { + base.Context(); + packageResult = new PackageResult("bob", "1.2.3", ApplicationParameters.InstallLocation); + } + + public override void Because() + { + result = Service.capture_package_files(packageResult, config); + } + + [Fact] + public void should_not_call_get_files() + { + FileSystem.Verify(x => x.get_files(It.IsAny(), It.IsAny(), SearchOption.AllDirectories), Times.Never); + } + + [Fact] + public void should_return_a_warning_if_the_install_directory_matches_choco_install_location() + { + packageResult.Warning.ShouldBeTrue(); + } + + [Fact] + public void should_return_null() + { + result.ShouldBeNull(); + } + } + + public class when_FilesService_captures_files_and_install_directory_reports_packages_location : FilesServiceSpecsBase + { + private PackageFiles result; + private PackageResult packageResult; + private readonly ChocolateyConfiguration config = new ChocolateyConfiguration(); + + public override void Context() + { + base.Context(); + packageResult = new PackageResult("bob", "1.2.3", ApplicationParameters.PackagesLocation); + } + + public override void Because() + { + result = Service.capture_package_files(packageResult, config); + } + + [Fact] + public void should_not_call_get_files() + { + FileSystem.Verify(x => x.get_files(It.IsAny(), It.IsAny(), SearchOption.AllDirectories), Times.Never); + } + + [Fact] + public void should_return_a_warning_if_the_install_directory_matches_choco_install_location() + { + packageResult.Warning.ShouldBeTrue(); + } + + [Fact] + public void should_return_null() + { + result.ShouldBeNull(); + } + } + + public class when_FilesService_captures_files_and_package_result_is_null : FilesServiceSpecsBase + { + private PackageFiles result; + private PackageResult packageResult; + private readonly ChocolateyConfiguration config = new ChocolateyConfiguration(); + + public override void Context() + { + base.Context(); + packageResult = null; + } + + public override void Because() + { + result = Service.capture_package_files(packageResult, config); + } + + [Fact] + public void should_not_call_get_files() + { + FileSystem.Verify(x => x.get_files(It.IsAny(), It.IsAny(), SearchOption.AllDirectories), Times.Never); + } + + [Fact] + public void should_return_null() + { + result.ShouldBeNull(); + } + } + + public class when_FilesService_captures_files_happy_path : FilesServiceSpecsBase + { + private PackageFiles result; + private PackageResult packageResult; + private readonly ChocolateyConfiguration config = new ChocolateyConfiguration(); + private readonly string installDirectory = ApplicationParameters.PackagesLocation + "\\bob"; + private readonly IList files = new List { "file1", "file2" }; + + public override void Context() + { + base.Context(); + packageResult = new PackageResult("bob", "1.2.3", installDirectory); + + FileSystem.Setup(x => x.get_files(ApplicationParameters.PackagesLocation + "\\bob", It.IsAny(), SearchOption.AllDirectories)).Returns(files); + HashProvider.Setup(x => x.hash_file(It.IsAny())).Returns("yes"); + } + + public override void Because() + { + result = Service.capture_package_files(packageResult, config); + } + + [Fact] + public void should_return_a_PackageFiles_object() + { + result.ShouldNotBeNull(); + } + + [Fact] + public void should_contain_package_files() + { + result.Files.ShouldNotBeEmpty(); + } + + [Fact] + public void should_contain_the_correct_number_of_package_files() + { + result.Files.Count.ShouldEqual(files.Count); + } + + [Fact] + public void should_call_hash_provider_for_each_file() + { + HashProvider.Verify(x => x.hash_file(It.IsAny()),Times.Exactly(files.Count)); + } + } + } +} \ No newline at end of file diff --git a/src/chocolatey.tests/infrastructure/cryptography/CrytpoHashProvider.cs b/src/chocolatey.tests/infrastructure/cryptography/CrytpoHashProvider.cs new file mode 100644 index 0000000000..4222e4f970 --- /dev/null +++ b/src/chocolatey.tests/infrastructure/cryptography/CrytpoHashProvider.cs @@ -0,0 +1,109 @@ +// Copyright © 2011 - Present RealDimensions Software, LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace chocolatey.tests.infrastructure.cryptography +{ + using System; + using System.IO; + using System.Security.Cryptography; + using Moq; + using Should; + using chocolatey.infrastructure.adapters; + using chocolatey.infrastructure.app; + using chocolatey.infrastructure.cryptography; + using chocolatey.infrastructure.filesystem; + + public class CrytpoHashProviderSpecs + { + public abstract class CrytpoHashProviderSpecsBase : TinySpec + { + protected CrytpoHashProvider Provider; + protected Mock FileSystem = new Mock(); + + public override void Context() + { + Provider = new CrytpoHashProvider(FileSystem.Object, CryptoHashProviderType.Md5); + } + } + + public class when_HashProvider_provides_a_hash : CrytpoHashProviderSpecsBase + { + private string result; + private string filePath = "c:\\path\\does\\not\\matter.txt"; + private readonly byte[] byteArray = new byte[] {23, 25, 27}; + + public override void Context() + { + base.Context(); + FileSystem.Setup(x => x.file_exists(It.IsAny())).Returns(true); + FileSystem.Setup(x => x.read_file_bytes(filePath)).Returns(byteArray); + } + + public override void Because() + { + result = Provider.hash_file(filePath); + } + + [Fact] + public void should_provide_the_correct_hash_based_on_a_checksum() + { + var expected = BitConverter.ToString(MD5.Create().ComputeHash(byteArray)).Replace("-", string.Empty); + + result.ShouldEqual(expected); + } + } + + public class when_HashProvider_attempts_to_provide_a_hash_for_a_file_over_2GB : CrytpoHashProviderSpecsBase + { + private string result; + private string filePath = "c:\\path\\does\\not\\matter.txt"; + private readonly byte[] byteArray = new byte[] { 23, 25, 27 }; + private readonly Mock _hashAlgorithm = new Mock(); + + public override void Context() + { + base.Context(); + Provider = new CrytpoHashProvider(FileSystem.Object, _hashAlgorithm.Object); + + FileSystem.Setup(x => x.file_exists(It.IsAny())).Returns(true); + FileSystem.Setup(x => x.read_file_bytes(filePath)).Returns(byteArray); + _hashAlgorithm.Setup(x => x.ComputeHash(byteArray)).Throws(); //IO.IO_FileTooLong2GB (over Int32.MaxValue) + } + + public override void Because() + { + result = Provider.hash_file(filePath); + } + + [Fact] + public void should_log_a_warning() + { + MockLogger.MessagesFor(LogLevel.Warn).Count.ShouldEqual(1); + } + + [Fact] + public void should_not_throw_an_error_itself() + { + //this handles itself + } + + [Fact] + public void should_provide_an_unchanging_hash_for_a_file_too_big_to_hash() + { + result.ShouldEqual(ApplicationParameters.HashProviderFileTooBig); + } + } + } +} \ No newline at end of file diff --git a/src/chocolatey.tests/infrastructure/cryptography/Md5HashProviderSpecs.cs b/src/chocolatey.tests/infrastructure/cryptography/Md5HashProviderSpecs.cs deleted file mode 100644 index 560d47255f..0000000000 --- a/src/chocolatey.tests/infrastructure/cryptography/Md5HashProviderSpecs.cs +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright © 2011 - Present RealDimensions Software, LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace chocolatey.tests.infrastructure.cryptography -{ - using System; - using System.Security.Cryptography; - using Moq; - using Should; - using chocolatey.infrastructure.cryptography; - using chocolatey.infrastructure.filesystem; - - public class Md5HashProviderSpecs - { - public abstract class Md5HashProviderSpecsBase : TinySpec - { - protected Md5HashProvider Provider; - protected Mock FileSystem = new Mock(); - - public override void Context() - { - Provider = new Md5HashProvider(FileSystem.Object); - } - } - - public class when_Md5HashProvider_provides_a_hash : Md5HashProviderSpecsBase - { - private string result; - private string filePath = "c:\\path\\does\\not\\matter.txt"; - private readonly byte[] byteArray = new byte[] {23, 25, 27}; - - public override void Context() - { - base.Context(); - FileSystem.Setup(x => x.file_exists(It.IsAny())).Returns(true); - FileSystem.Setup(x => x.read_file_bytes(filePath)).Returns(byteArray); - } - - public override void Because() - { - result = Provider.hash_file(filePath); - } - - [Fact] - public void should_provide_the_correct_hash_based_on_a_checksum() - { - var expected = BitConverter.ToString(MD5.Create().ComputeHash(byteArray)).Replace("-", string.Empty); - - result.ShouldEqual(expected); - } - } - } -} \ No newline at end of file diff --git a/src/chocolatey/chocolatey.csproj b/src/chocolatey/chocolatey.csproj index fcb6693aec..f75bdca93a 100644 --- a/src/chocolatey/chocolatey.csproj +++ b/src/chocolatey/chocolatey.csproj @@ -166,8 +166,11 @@ + + + - + diff --git a/src/chocolatey/infrastructure.app/ApplicationParameters.cs b/src/chocolatey/infrastructure.app/ApplicationParameters.cs index a55cf8bbf7..f2a95be4d3 100644 --- a/src/chocolatey/infrastructure.app/ApplicationParameters.cs +++ b/src/chocolatey/infrastructure.app/ApplicationParameters.cs @@ -63,6 +63,8 @@ public static class ApplicationParameters public static int DefaultWaitForExitInSeconds = 2700; public static readonly string[] ConfigFileExtensions = new string[] {".autoconf",".config",".conf",".cfg",".jsc",".json",".jsonp",".ini",".xml",".yaml"}; + + public static string HashProviderFileTooBig = "UnableToDetectChanges_FileTooBig"; public static class Tools { diff --git a/src/chocolatey/infrastructure.app/registration/ContainerBinding.cs b/src/chocolatey/infrastructure.app/registration/ContainerBinding.cs index 762607914c..794b3463b5 100644 --- a/src/chocolatey/infrastructure.app/registration/ContainerBinding.cs +++ b/src/chocolatey/infrastructure.app/registration/ContainerBinding.cs @@ -56,7 +56,7 @@ public void RegisterComponents(Container container) container.Register(Lifestyle.Singleton); container.Register(Lifestyle.Singleton); container.Register(Lifestyle.Singleton); - container.Register(Lifestyle.Singleton); + container.Register(() => new CrytpoHashProvider(container.GetInstance(), CryptoHashProviderType.Md5), Lifestyle.Singleton); container.Register(Lifestyle.Singleton); container.Register(Lifestyle.Singleton); container.Register(Lifestyle.Singleton); diff --git a/src/chocolatey/infrastructure.app/services/FilesService.cs b/src/chocolatey/infrastructure.app/services/FilesService.cs index fff059df6d..2b87891b65 100644 --- a/src/chocolatey/infrastructure.app/services/FilesService.cs +++ b/src/chocolatey/infrastructure.app/services/FilesService.cs @@ -49,11 +49,15 @@ public PackageFiles read_from_file(string filePath) public void save_to_file(PackageFiles snapshot, string filePath) { + if (snapshot == null) return; + _xmlService.serialize(snapshot, filePath); } public PackageFiles capture_package_files(PackageResult packageResult, ChocolateyConfiguration config) { + if (packageResult == null) return null; + var installDirectory = packageResult.InstallLocation; if (installDirectory.is_equal_to(ApplicationParameters.InstallLocation) || installDirectory.is_equal_to(ApplicationParameters.PackagesLocation)) { @@ -65,11 +69,14 @@ public PackageFiles capture_package_files(PackageResult packageResult, Chocolate var packageFiles = new PackageFiles(); + this.Log().Debug(() => "Capturing package files in '{0}'".format_with(installDirectory)); //gather all files in the folder var files = _fileSystem.get_files(installDirectory, pattern: "*.*", option: SearchOption.AllDirectories); foreach (string file in files.or_empty_list_if_null()) { - packageFiles.Files.Add(new PackageFile { Path = file, Checksum = _hashProvider.hash_file(file)}); + var hash = _hashProvider.hash_file(file); + this.Log().Debug(() => " Found '{0}'{1} with checksum '{2}'".format_with(file, Environment.NewLine, hash)); + packageFiles.Files.Add(new PackageFile { Path = file, Checksum = hash}); } return packageFiles; diff --git a/src/chocolatey/infrastructure/adapters/HashAlgorithm.cs b/src/chocolatey/infrastructure/adapters/HashAlgorithm.cs new file mode 100644 index 0000000000..1c303a1cec --- /dev/null +++ b/src/chocolatey/infrastructure/adapters/HashAlgorithm.cs @@ -0,0 +1,19 @@ +namespace chocolatey.infrastructure.adapters +{ + using cryptography; + + public sealed class HashAlgorithm : IHashAlgorithm + { + private readonly System.Security.Cryptography.HashAlgorithm _algorithm; + + public HashAlgorithm(System.Security.Cryptography.HashAlgorithm algorithm) + { + _algorithm = algorithm; + } + + public byte[] ComputeHash(byte[] buffer) + { + return _algorithm.ComputeHash(buffer); + } + } +} \ No newline at end of file diff --git a/src/chocolatey/infrastructure/adapters/IHashAlgorithm.cs b/src/chocolatey/infrastructure/adapters/IHashAlgorithm.cs new file mode 100644 index 0000000000..5d87e8797e --- /dev/null +++ b/src/chocolatey/infrastructure/adapters/IHashAlgorithm.cs @@ -0,0 +1,11 @@ +namespace chocolatey.infrastructure.adapters +{ + // ReSharper disable InconsistentNaming + + public interface IHashAlgorithm + { + byte[] ComputeHash(byte[] buffer); + } + + // ReSharper restore InconsistentNaming +} \ No newline at end of file diff --git a/src/chocolatey/infrastructure/cryptography/CryptoHashProviderType.cs b/src/chocolatey/infrastructure/cryptography/CryptoHashProviderType.cs new file mode 100644 index 0000000000..77fe3352a9 --- /dev/null +++ b/src/chocolatey/infrastructure/cryptography/CryptoHashProviderType.cs @@ -0,0 +1,10 @@ +namespace chocolatey.infrastructure.cryptography +{ + public enum CryptoHashProviderType + { + Md5, + Sha1, + Sha256, + Sha512 + } +} \ No newline at end of file diff --git a/src/chocolatey/infrastructure/cryptography/CrytpoHashProvider.cs b/src/chocolatey/infrastructure/cryptography/CrytpoHashProvider.cs new file mode 100644 index 0000000000..95f7c4c0f2 --- /dev/null +++ b/src/chocolatey/infrastructure/cryptography/CrytpoHashProvider.cs @@ -0,0 +1,79 @@ +// Copyright © 2011 - Present RealDimensions Software, LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace chocolatey.infrastructure.cryptography +{ + using System; + using System.IO; + using System.Security.Cryptography; + using adapters; + using app; + using filesystem; + using Environment = System.Environment; + using HashAlgorithm = adapters.HashAlgorithm; + + + public sealed class CrytpoHashProvider : IHashProvider + { + private readonly IFileSystem _fileSystem; + private readonly IHashAlgorithm _hashAlgorithm; + + public CrytpoHashProvider(IFileSystem fileSystem, CryptoHashProviderType providerType) + { + _fileSystem = fileSystem; + + switch (providerType) + { + case CryptoHashProviderType.Md5: + _hashAlgorithm = new HashAlgorithm(MD5.Create()); + break; + case CryptoHashProviderType.Sha1: + _hashAlgorithm = new HashAlgorithm(SHA1.Create()); + break; + case CryptoHashProviderType.Sha256: + _hashAlgorithm = new HashAlgorithm(SHA256.Create()); + break; + case CryptoHashProviderType.Sha512: + _hashAlgorithm = new HashAlgorithm(SHA512.Create()); + break; + } + } + + public CrytpoHashProvider(IFileSystem fileSystem, IHashAlgorithm hashAlgorithm) + { + _fileSystem = fileSystem; + _hashAlgorithm = hashAlgorithm; + } + + public string hash_file(string filePath) + { + if (!_fileSystem.file_exists(filePath)) return string.Empty; + + try + { + var hash = _hashAlgorithm.ComputeHash(_fileSystem.read_file_bytes(filePath)); + + return BitConverter.ToString(hash).Replace("-", string.Empty); + } + catch (IOException ex) + { + this.Log().Warn(() => "Error computing hash for '{0}'{1} Captured error:{1} {2}".format_with(filePath, Environment.NewLine, ex.Message)); + //IO.IO_FileTooLong2GB (over Int32.MaxValue) + return ApplicationParameters.HashProviderFileTooBig; + return "UnableToDetectChanges_FileTooBig"; + } + } + } +} \ No newline at end of file diff --git a/src/chocolatey/infrastructure/cryptography/Md5HashProvider.cs b/src/chocolatey/infrastructure/cryptography/Md5HashProvider.cs deleted file mode 100644 index e15004bc57..0000000000 --- a/src/chocolatey/infrastructure/cryptography/Md5HashProvider.cs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright © 2011 - Present RealDimensions Software, LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace chocolatey.infrastructure.cryptography -{ - using System; - using System.Security.Cryptography; - using filesystem; - - public sealed class Md5HashProvider : IHashProvider - { - private readonly IFileSystem _fileSystem; - private readonly MD5 _cryptoProvider; - - public Md5HashProvider(IFileSystem fileSystem) - { - _fileSystem = fileSystem; - _cryptoProvider = MD5.Create(); - } - - public string hash_file(string filePath) - { - if (!_fileSystem.file_exists(filePath)) return string.Empty; - - var hash = _cryptoProvider.ComputeHash(_fileSystem.read_file_bytes(filePath)); - - return BitConverter.ToString(hash).Replace("-", string.Empty); - } - } -} \ No newline at end of file