diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index f063332bb8..67acd6b889 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -18,6 +18,7 @@ alreadyinstalled AMap Amd amrutha +amsi ansistring APARTMENTTHREADED apfn @@ -209,6 +210,8 @@ gwgso gwgus gwgv Hackathon +HAMSICONTEXT +HAMSISESSION hashtables helplib helplibrary diff --git a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj index 043eab3f5a..19ae2652ce 100644 --- a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj +++ b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj @@ -506,6 +506,9 @@ true + + true + true diff --git a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters index a24784a802..13cbc13fb2 100644 --- a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters +++ b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters @@ -633,6 +633,9 @@ TestData + + TestData + TestData diff --git a/src/AppInstallerCLITests/Archive.cpp b/src/AppInstallerCLITests/Archive.cpp index 4d415761f1..238d640d87 100644 --- a/src/AppInstallerCLITests/Archive.cpp +++ b/src/AppInstallerCLITests/Archive.cpp @@ -1,34 +1,82 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. -#include "pch.h" -#include "TestCommon.h" -#include - -using namespace AppInstaller::Archive; -using namespace TestCommon; - -constexpr std::string_view s_ZipFile = "TestZip.zip"; - -TEST_CASE("Extract_ZipArchive", "[archive]") -{ - TestCommon::TempDirectory tempDirectory("TempDirectory"); - TestDataFile testZip(s_ZipFile); - - const auto& testZipPath = testZip.GetPath(); - const auto& tempDirectoryPath = tempDirectory.GetPath(); - - HRESULT hr = TryExtractArchive(testZipPath, tempDirectoryPath); - - std::filesystem::path expectedPath = tempDirectoryPath / "test.txt"; - REQUIRE(SUCCEEDED(hr)); - REQUIRE(std::filesystem::exists(expectedPath)); -} - -TEST_CASE("Scan_ZipArchive", "[archive]") -{ - TestDataFile testZip(s_ZipFile); - - const auto& testZipPath = testZip.GetPath(); - bool result = ScanZipFile(testZipPath); - REQUIRE(result); -} +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#include "pch.h" +#include "TestCommon.h" +#include "WorkflowCommon.h" +#include +#include + +using namespace AppInstaller::Archive; +using namespace AppInstaller::CLI::Workflow; +using namespace AppInstaller::Settings; +using namespace TestCommon; + +constexpr std::string_view s_ZipFile = "TestZip.zip"; +constexpr std::string_view s_TarGzFile = "TestTarGz.tar.gz"; +constexpr std::string_view s_Large7zFile = "TestLarge7z.7z"; + +TEST_CASE("Extract_ZipArchive", "[archive]") +{ + TestCommon::TempDirectory tempDirectory("TempDirectory"); + TestDataFile testZip(s_ZipFile); + + const auto& testZipPath = testZip.GetPath(); + const auto& tempDirectoryPath = tempDirectory.GetPath(); + + HRESULT hr = TryExtractArchive(testZipPath, tempDirectoryPath); + + std::filesystem::path expectedPath = tempDirectoryPath / "test.txt"; + REQUIRE(SUCCEEDED(hr)); + REQUIRE(std::filesystem::exists(expectedPath)); +} + +TEST_CASE("Scan_ZipArchive", "[archive]") +{ + TestDataFile testZip(s_ZipFile); + + const auto& testZipPath = testZip.GetPath(); + bool result = ScanZipFile(testZipPath); + REQUIRE(result); +} + +TEST_CASE("Extract_TarGzArchive", "[archive]") +{ + TestCommon::TempDirectory tempDirectory("TempDirectory"); + TestDataFile testTarGz(s_TarGzFile); + + TestCommon::TestUserSettings testSettings; + testSettings.Set(AppInstaller::Archive::ExtractionMethod::Tar); + + const auto& testTarGzPath = testTarGz.GetPath(); + const auto& tempDirectoryPath = tempDirectory.GetPath(); + + ShellExecuteExtractArchive(testTarGzPath, tempDirectoryPath); + + std::ostringstream extractOutput; + TestContext context{ extractOutput, std::cin }; + context << ShellExecuteExtractArchive(testTarGzPath, tempDirectoryPath); + + std::filesystem::path expectedPath = tempDirectoryPath / "test.txt"; + REQUIRE(SUCCEEDED(context.GetTerminationHR())); + REQUIRE(std::filesystem::exists(expectedPath)); + INFO(extractOutput.str()); +} + +TEST_CASE("Scan_TarGzArchive", "[archive]") +{ + TestDataFile testTarGz(s_TarGzFile); + + const auto& testTarGzPath = testTarGz.GetPath(); + bool result = ScanZipFile(testTarGzPath); + REQUIRE(result); +} + +//TEST_CASE("Scan_Large7zArchive", "[archive]") +//{ +// TestDataFile testLarge7z(s_Large7zFile); +// +// const auto& testTarGzPath = testLarge7z.GetPath(); +// bool result = ScanZipFile(testTarGzPath); +// REQUIRE(result); +//} + diff --git a/src/AppInstallerCLITests/TestData/TestTarGz.tar.gz b/src/AppInstallerCLITests/TestData/TestTarGz.tar.gz new file mode 100644 index 0000000000..0a127aac9b Binary files /dev/null and b/src/AppInstallerCLITests/TestData/TestTarGz.tar.gz differ diff --git a/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj b/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj index d57fcfc5e6..75676ded8f 100644 --- a/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj +++ b/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj @@ -274,6 +274,21 @@ Windows Windows + + amsi.lib;%(AdditionalDependencies) + + + amsi.lib;%(AdditionalDependencies) + + + amsi.lib;%(AdditionalDependencies) + + + amsi.lib;%(AdditionalDependencies) + + + amsi.lib;%(AdditionalDependencies) + @@ -287,6 +302,9 @@ Windows + + amsi.lib;%(AdditionalDependencies) + @@ -324,6 +342,18 @@ Windows Windows + + amsi.lib;%(AdditionalDependencies) + + + amsi.lib;%(AdditionalDependencies) + + + amsi.lib;%(AdditionalDependencies) + + + amsi.lib;%(AdditionalDependencies) + @@ -365,6 +395,18 @@ Windows Windows + + amsi.lib;%(AdditionalDependencies) + + + amsi.lib;%(AdditionalDependencies) + + + amsi.lib;%(AdditionalDependencies) + + + amsi.lib;%(AdditionalDependencies) + @@ -385,6 +427,12 @@ false Windows + + amsi.lib;%(AdditionalDependencies) + + + amsi.lib;%(AdditionalDependencies) + diff --git a/src/AppInstallerCommonCore/Archive.cpp b/src/AppInstallerCommonCore/Archive.cpp index 95766519e9..af1a432d0d 100644 --- a/src/AppInstallerCommonCore/Archive.cpp +++ b/src/AppInstallerCommonCore/Archive.cpp @@ -1,79 +1,93 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. -#include "pch.h" -#include "Public/winget/Archive.h" - -// TODO: Move include statement to pch.h and resolve build errors -#pragma warning( push ) -#pragma warning ( disable : 4189 4244 26451 ) -#include -#pragma warning ( pop ) - -namespace AppInstaller::Archive -{ - using unique_pidlist_absolute = wil::unique_any; - using unique_lpitemidlist = wil::unique_any; - - HRESULT TryExtractArchive(const std::filesystem::path& archivePath, const std::filesystem::path& destPath) - { - wil::com_ptr pFileOperation; - RETURN_IF_FAILED(CoCreateInstance(CLSID_FileOperation, NULL, CLSCTX_ALL, IID_PPV_ARGS(&pFileOperation))); - RETURN_IF_FAILED(pFileOperation->SetOperationFlags(FOF_NO_UI)); - - wil::com_ptr pShellItemTo; - RETURN_IF_FAILED(SHCreateItemFromParsingName(destPath.c_str(), NULL, IID_PPV_ARGS(&pShellItemTo))); - - unique_pidlist_absolute pidlFull; - RETURN_IF_FAILED(SHParseDisplayName(archivePath.c_str(), NULL, &pidlFull, 0, NULL)); - - wil::com_ptr pArchiveShellFolder; - RETURN_IF_FAILED(SHBindToObject(NULL, pidlFull.get(), NULL, IID_PPV_ARGS(&pArchiveShellFolder))); - - wil::com_ptr pEnumIdList; - RETURN_IF_FAILED(pArchiveShellFolder->EnumObjects(nullptr, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &pEnumIdList)); - - unique_lpitemidlist pidlChild; - ULONG nFetched; - while (pEnumIdList->Next(1, wil::out_param_ptr(pidlChild), &nFetched) == S_OK && nFetched == 1) - { - wil::com_ptr pShellItemFrom; - STRRET strFolderName; - WCHAR szFolderName[MAX_PATH]; - RETURN_IF_FAILED(pArchiveShellFolder->GetDisplayNameOf(pidlChild.get(), SHGDN_INFOLDER | SHGDN_FORPARSING, &strFolderName)); - RETURN_IF_FAILED(StrRetToBuf(&strFolderName, pidlChild.get(), szFolderName, MAX_PATH)); - RETURN_IF_FAILED(SHCreateItemWithParent(pidlFull.get(), pArchiveShellFolder.get(), pidlChild.get(), IID_PPV_ARGS(&pShellItemFrom))); - RETURN_IF_FAILED(pFileOperation->CopyItem(pShellItemFrom.get(), pShellItemTo.get(), NULL, NULL)); - } - - RETURN_IF_FAILED(pFileOperation->PerformOperations()); - return S_OK; - } - -#ifndef AICLI_DISABLE_TEST_HOOKS - static bool* s_ScanArchiveResult_TestHook_Override = nullptr; - - void TestHook_SetScanArchiveResult_Override(bool* status) - { - s_ScanArchiveResult_TestHook_Override = status; - } -#endif - - bool ScanZipFile(const std::filesystem::path& zipPath) - { -#ifndef AICLI_DISABLE_TEST_HOOKS - if (s_ScanArchiveResult_TestHook_Override) - { - return *s_ScanArchiveResult_TestHook_Override; - } -#endif - - std::ifstream instream{ zipPath, std::ios::in | std::ios::binary }; - std::vector data{ { std::istreambuf_iterator{ instream } }, std::istreambuf_iterator{} }; - - uint8_t* buffer = &data[0]; - uint64_t flag = 0; - int scanResult = pure_zip(buffer, data.size(), flag); - - return scanResult == 0; - } -} +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#include "pch.h" +#include "Public/winget/Archive.h" + +namespace AppInstaller::Archive +{ + using unique_pidlist_absolute = wil::unique_any; + using unique_lpitemidlist = wil::unique_any; + + HRESULT TryExtractArchive(const std::filesystem::path& archivePath, const std::filesystem::path& destPath) + { + wil::com_ptr pFileOperation; + RETURN_IF_FAILED(CoCreateInstance(CLSID_FileOperation, NULL, CLSCTX_ALL, IID_PPV_ARGS(&pFileOperation))); + RETURN_IF_FAILED(pFileOperation->SetOperationFlags(FOF_NO_UI)); + + wil::com_ptr pShellItemTo; + RETURN_IF_FAILED(SHCreateItemFromParsingName(destPath.c_str(), NULL, IID_PPV_ARGS(&pShellItemTo))); + + unique_pidlist_absolute pidlFull; + RETURN_IF_FAILED(SHParseDisplayName(archivePath.c_str(), NULL, &pidlFull, 0, NULL)); + + wil::com_ptr pArchiveShellFolder; + RETURN_IF_FAILED(SHBindToObject(NULL, pidlFull.get(), NULL, IID_PPV_ARGS(&pArchiveShellFolder))); + + wil::com_ptr pEnumIdList; + RETURN_IF_FAILED(pArchiveShellFolder->EnumObjects(nullptr, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &pEnumIdList)); + + unique_lpitemidlist pidlChild; + ULONG nFetched; + while (pEnumIdList->Next(1, wil::out_param_ptr(pidlChild), &nFetched) == S_OK && nFetched == 1) + { + wil::com_ptr pShellItemFrom; + STRRET strFolderName; + WCHAR szFolderName[MAX_PATH]; + RETURN_IF_FAILED(pArchiveShellFolder->GetDisplayNameOf(pidlChild.get(), SHGDN_INFOLDER | SHGDN_FORPARSING, &strFolderName)); + RETURN_IF_FAILED(StrRetToBuf(&strFolderName, pidlChild.get(), szFolderName, MAX_PATH)); + RETURN_IF_FAILED(SHCreateItemWithParent(pidlFull.get(), pArchiveShellFolder.get(), pidlChild.get(), IID_PPV_ARGS(&pShellItemFrom))); + RETURN_IF_FAILED(pFileOperation->CopyItem(pShellItemFrom.get(), pShellItemTo.get(), NULL, NULL)); + } + + RETURN_IF_FAILED(pFileOperation->PerformOperations()); + return S_OK; + } + +#ifndef AICLI_DISABLE_TEST_HOOKS + static bool* s_ScanArchiveResult_TestHook_Override = nullptr; + + void TestHook_SetScanArchiveResult_Override(bool* status) + { + s_ScanArchiveResult_TestHook_Override = status; + } +#endif + + bool ScanZipFile(const std::filesystem::path& zipPath) + { +#ifndef AICLI_DISABLE_TEST_HOOKS + if (s_ScanArchiveResult_TestHook_Override) + { + return *s_ScanArchiveResult_TestHook_Override; + } +#endif + + HRESULT hr = S_OK; + HAMSICONTEXT amsiContext; + HAMSISESSION amsiSession; + + hr = AmsiInitialize(L"WinGet", &amsiContext); + if (FAILED(hr)) + { + return false; + } + + hr = AmsiOpenSession(amsiContext, &amsiSession); + if (FAILED(hr)) + { + AmsiUninitialize(amsiContext); + return false; + } + + std::ifstream instream{ zipPath, std::ios::in | std::ios::binary }; + std::vector data{ { std::istreambuf_iterator{ instream } }, std::istreambuf_iterator{} }; + + AMSI_RESULT result = AMSI_RESULT_CLEAN; + hr = AmsiScanBuffer(amsiContext, data.data(), static_cast(data.size()), zipPath.filename().c_str(), amsiSession, &result); + + AmsiCloseSession(amsiContext, amsiSession); + AmsiUninitialize(amsiContext); + + return SUCCEEDED(hr) && (result == AMSI_RESULT_CLEAN || result == AMSI_RESULT_NOT_DETECTED); + } +} + diff --git a/src/AppInstallerCommonCore/pch.h b/src/AppInstallerCommonCore/pch.h index 2825b5ff5c..e75482a35e 100644 --- a/src/AppInstallerCommonCore/pch.h +++ b/src/AppInstallerCommonCore/pch.h @@ -18,6 +18,7 @@ #include #include #include +#include #include "TraceLogging.h"