From b4564fa5bb1404d00c2fa05f02dce067cd7a31a9 Mon Sep 17 00:00:00 2001 From: Toni Date: Sat, 14 Feb 2026 14:00:07 +0100 Subject: [PATCH] verify checksums --- .clang-tidy | 2 +- .gitignore | 5 ++-- CMakeLists.txt | 25 ++++++++++++++++- packages/emacs.shrap | 11 ++++++++ packages/libffi.shrap | 10 +++++++ packages/libgmp.shrap | 11 ++++++++ packages/libgnutls.shrap | 12 +++++++++ packages/libncurses.shrap | 4 +-- packages/libnettle.shrap | 12 +++++++++ packages/libp11-kit.shrap | 12 +++++++++ packages/m4.shrap | 10 +++++++ packages/pkg-config.shrap | 11 ++++++++ packages/vim.shrap | 2 +- packages/xz.shrap | 11 ++++++++ src/main.cc | 57 +++++++++++++++++++++++++++++---------- src/util.h | 32 ++++++++++++++++++++++ 16 files changed, 206 insertions(+), 21 deletions(-) create mode 100644 packages/emacs.shrap create mode 100644 packages/libffi.shrap create mode 100644 packages/libgmp.shrap create mode 100644 packages/libgnutls.shrap create mode 100644 packages/libnettle.shrap create mode 100644 packages/libp11-kit.shrap create mode 100644 packages/m4.shrap create mode 100644 packages/pkg-config.shrap create mode 100644 packages/xz.shrap diff --git a/.clang-tidy b/.clang-tidy index d07254d..8413fef 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1 +1 @@ -Checks: '*,clang-analyzer-*,-llvmlibc-*,-fuchsia-*,-altera-*,-abseil-*,-android-*,-modernize-use-trailing-return-type,-readability-identifier-length,-*-readability-todo,-*-magic-numbers,-readability-function-cognitive-complexity,-*-easily-swappable-parameters,-*-non-private-member-variables-in-classes,-*-no-recursion,-concurrency-mt-unsafe' \ No newline at end of file +Checks: '*,clang-analyzer-*,-llvmlibc-*,-fuchsia-*,-altera-*,-abseil-*,-android-*,-modernize-use-trailing-return-type,-readability-identifier-length,-*-readability-todo,-*-magic-numbers,-readability-function-cognitive-complexity,-*-easily-swappable-parameters,-*-non-private-member-variables-in-classes,-*-no-recursion,-concurrency-mt-unsafe,-*-runtime-int,-*-non-const-global-variables' \ No newline at end of file diff --git a/.gitignore b/.gitignore index 9b83346..0704fda 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /.cache /build -hash.py -docker.sh \ No newline at end of file +/*.py +docker.sh +/curl \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index dc51742..7dc8a47 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,9 +1,32 @@ cmake_minimum_required(VERSION 3.16) project(shrap) +include(FetchContent) set(CMAKE_CXX_STANDARD 20) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +FetchContent_Declare( + blake3 + GIT_REPOSITORY https://github.com/BLAKE3-team/BLAKE3.git + GIT_TAG 1.8.3 +) +FetchContent_MakeAvailable(blake3) + +add_library(blake3_lib STATIC + ${blake3_SOURCE_DIR}/c/blake3.c + ${blake3_SOURCE_DIR}/c/blake3_dispatch.c + ${blake3_SOURCE_DIR}/c/blake3_portable.c +) +target_compile_definitions(blake3_lib PRIVATE + BLAKE3_NO_SSE2 + BLAKE3_NO_SSE41 + BLAKE3_NO_AVX2 + BLAKE3_NO_AVX512 +) +target_include_directories(blake3_lib PUBLIC ${blake3_SOURCE_DIR}/c) + add_executable(${PROJECT_NAME} src/main.cc) -target_link_libraries(${PROJECT_NAME} PRIVATE -static) +target_link_libraries(${PROJECT_NAME} PRIVATE blake3_lib) + +set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "-static") \ No newline at end of file diff --git a/packages/emacs.shrap b/packages/emacs.shrap new file mode 100644 index 0000000..60ace80 --- /dev/null +++ b/packages/emacs.shrap @@ -0,0 +1,11 @@ +(package + (name "emacs") + (version "30.2") + (homepage "https://www.gnu.org/software/emacs/") + (dependencies "libncurses" "libgnutls") + (src (tar + (url "https://mirror.netcologne.de/gnu/emacs/emacs-30.2.tar.gz") + (dir "emacs-30.2") + (blake3 "31dab4d0c43d7494eb347787147a0572d470767e8b066625d9e99c43fc970d47"))) + (build + (configure_make))) diff --git a/packages/libffi.shrap b/packages/libffi.shrap new file mode 100644 index 0000000..aa101d8 --- /dev/null +++ b/packages/libffi.shrap @@ -0,0 +1,10 @@ +(package + (name "libffi") + (version "3.4.5") + (homepage "https://sourceware.org/libffi/") + (src (tar + (url "https://github.com/libffi/libffi/releases/download/v3.4.5/libffi-3.4.5.tar.gz") + (dir "libffi-3.4.5") + (blake3 "f9a2cfe1d2ac8d211c18c99f9cfafe5537925101bfb92c2d44d844680dd82264"))) + (build + (configure_make))) diff --git a/packages/libgmp.shrap b/packages/libgmp.shrap new file mode 100644 index 0000000..baa69e8 --- /dev/null +++ b/packages/libgmp.shrap @@ -0,0 +1,11 @@ +(package + (name "libgmp") + (version "6.3.0") + (homepage "https://gmplib.org/") + (dependencies "xz" "m4") + (src (tar + (url "https://gmplib.org/download/gmp/gmp-6.3.0.tar.xz") + (dir "gmp-6.3.0") + (blake3 "fffe4996713928ae19331c8ef39129e46d3bf5b7182820656fd4639435cd83a4"))) + (build + (configure_make))) diff --git a/packages/libgnutls.shrap b/packages/libgnutls.shrap new file mode 100644 index 0000000..65d9fa8 --- /dev/null +++ b/packages/libgnutls.shrap @@ -0,0 +1,12 @@ +(package + (name "libgnutls") + (version "3.8.12") + (homepage "https://gnutls.org/") + (dependencies "xz" "pkg-config" "libnettle" "libp11-kit") + (src (tar + (url "https://www.gnupg.org/ftp/gcrypt/gnutls/v3.8/gnutls-3.8.12.tar.xz") + (dir "gnutls-3.8.12") + (blake3 "d60d32619210c02b3b280a79e32c8323a7fd556ae77e1b461d69744bc93f05d5"))) + (build + (configure_make + (configure_flags "--with-included-libtasn1 --with-included-unistring --disable-doc --disable-tests --disable-tools")))) diff --git a/packages/libncurses.shrap b/packages/libncurses.shrap index d428bd9..62e21be 100644 --- a/packages/libncurses.shrap +++ b/packages/libncurses.shrap @@ -1,11 +1,11 @@ (package - (name "ncurses") + (name "libncurses") (version "6.6") (homepage "https://invisible-island.net/ncurses/") (src (tar (url "https://invisible-mirror.net/archives/ncurses/ncurses-6.6.tar.gz") (dir "ncurses-6.6") - (blake3 ""))) + (blake3 "fbec55697a01f99b9cc3f25be55e73ae7091f4c53e5d81a1ea15734c4e5b7238"))) (build (configure_make (configure_flags "--disable-widec --without-tests --without-progs --without-manpages")))) diff --git a/packages/libnettle.shrap b/packages/libnettle.shrap new file mode 100644 index 0000000..e2d9a60 --- /dev/null +++ b/packages/libnettle.shrap @@ -0,0 +1,12 @@ +(package + (name "libnettle") + (version "3.10") + (homepage "https://www.lysator.liu.se/~nisse/nettle/") + (dependencies "libgmp") + (src (tar + (url "https://ftp.gnu.org/gnu/nettle/nettle-3.10.tar.gz") + (dir "nettle-3.10") + (blake3 "c2b37a2c9500b6eea1b186ccd525c7c7f82abb2039bd0ff6ba1c0232329832d0"))) + (build + (configure_make + (configure_flags "--libdir=/usr/lib")))) diff --git a/packages/libp11-kit.shrap b/packages/libp11-kit.shrap new file mode 100644 index 0000000..d7cfc41 --- /dev/null +++ b/packages/libp11-kit.shrap @@ -0,0 +1,12 @@ +(package + (name "libp11-kit") + (version "0.26.2") + (homepage "https://p11-glue.github.io/p11-glue/p11-kit.html") + (dependencies "xz" "libffi") + (src (tar + (url "https://github.com/p11-glue/p11-kit/releases/download/0.26.2/p11-kit-0.26.2.tar.xz") + (dir "p11-kit-0.26.2") + (blake3 "93de717427982d3904905b0ea2997345c06dd35456c281ef3aa7bae2fd9242ed"))) + (build + (configure_make + (configure_flags "--without-libtasn1")))) diff --git a/packages/m4.shrap b/packages/m4.shrap new file mode 100644 index 0000000..27d1182 --- /dev/null +++ b/packages/m4.shrap @@ -0,0 +1,10 @@ +(package + (name "m4") + (version "1.4.21") + (homepage "https://www.gnu.org/software/m4/") + (src (tar + (url "https://ftp.gnu.org/gnu/m4/m4-1.4.21.tar.gz") + (dir "m4-1.4.21") + (blake3 "9dcdc6d7bcdd49d6d10431cca2e8f763012741b187fbaef4eff43bae12a51063"))) + (build + (configure_make))) diff --git a/packages/pkg-config.shrap b/packages/pkg-config.shrap new file mode 100644 index 0000000..66053f0 --- /dev/null +++ b/packages/pkg-config.shrap @@ -0,0 +1,11 @@ +(package + (name "pkg-config") + (version "0.29") + (homepage "www.freedesktop.org/wiki/Software/pkg-config/") + (src (tar + (url "https://pkgconfig.freedesktop.org/releases/pkg-config-0.29.tar.gz") + (dir "pkg-config-0.29") + (blake3 "16d375630d2b8f41086e9d00cd207ec9e2a74d7bfc57510ea088071840522f06"))) + (build + (configure_make + (configure_flags "CFLAGS=-Wno-format-nonliteral --with-internal-glib")))) diff --git a/packages/vim.shrap b/packages/vim.shrap index cd8207f..9212ca3 100644 --- a/packages/vim.shrap +++ b/packages/vim.shrap @@ -6,6 +6,6 @@ (src (tar (url "https://github.com/vim/vim/archive/refs/tags/v9.1.2148.tar.gz") (dir "vim-9.1.2148") - (blake3 ""))) + (blake3 "1bc0bbf9da0fa156df66aeb716cfa1310101bdb0cca9aa60f241351fc8d13d8e"))) (build (configure_make))) diff --git a/packages/xz.shrap b/packages/xz.shrap new file mode 100644 index 0000000..bd73bca --- /dev/null +++ b/packages/xz.shrap @@ -0,0 +1,11 @@ +(package + (name "xz") + (version "5.8.2") + (homepage "https://tukaani.org/xz/") + (src (tar + (url "https://github.com/tukaani-project/xz/releases/download/v5.8.2/xz-5.8.2.tar.gz") + (dir "xz-5.8.2") + (blake3 "e63d8cbda1ba9e21d36c951a6c67a81cadadfdf4e9a1895c1f278265e8d6f8ad"))) + (build + (configure_make + (configure_flags "--disable-shared --disable-doc --disable-nls")))) diff --git a/src/main.cc b/src/main.cc index 5f40aa0..0bf1d37 100644 --- a/src/main.cc +++ b/src/main.cc @@ -1,13 +1,15 @@ #include "parser.h" #include "util.h" -#include -#include #include -#include #include #include +static bool flag_raw = false; + void install_package(const std::string &name) { + // TODO: get this by the name field not filename + // TODO: actually resolve dependency tree + // TODO: track installed packages std::ifstream file("packages/" + name + ".shrap"); if (!file) { std::cerr << "Package " << name << "not found.\n"; @@ -16,11 +18,13 @@ void install_package(const std::string &name) { Expr pkg = Expr::parse(file); - try { - for (const auto &dep : pkg.get("dependencies").children) { - install_package(dep.value); + if (!flag_raw) { + try { + for (const auto &dep : pkg.get("dependencies").children) { + install_package(dep.value); + } + } catch (std::out_of_range &) { } - } catch (std::out_of_range &) { } Expr src = pkg.get("src").children[0]; @@ -31,10 +35,18 @@ void install_package(const std::string &name) { if (src_type == "tar") { std::string archive_path = "/tmp/shrap/" + Util::basename(src_url); - // TODO: replace wget with a library for zero runtime dependencies - Util::shell_command("wget -O " + archive_path + " " + src_url); + // TODO: ship ca certificates + Util::shell_command("./curl -k -L -o " + archive_path + " " + src_url); - // TODO: check archive hash from src.get("blake3").children[0].value + std::string expected_hash = src.get("blake3").children[0].value; + std::string hash = Util::hash_file(archive_path); + + if (expected_hash != hash) { + std::cerr << "Checksum check failed.\n"; + std::cerr << "Expected: " << expected_hash << "\n"; + std::cerr << "Got: " << hash << "\n"; + std::exit(1); + } Util::shell_command("tar xf " + archive_path + " -C /tmp/shrap/"); } else { @@ -72,10 +84,27 @@ int main(int argc, char **argv) { } Util::shell_command("mkdir -p /tmp/shrap"); - try { - install_package(args[1]); - } catch (std::exception &e) { - std::cerr << "ERROR: " << e.what() << std::endl; + std::vector packages; + for (size_t i = 1; i < args.size(); ++i) { + std::string arg = args[i]; + if (arg == "-r") { + flag_raw = true; + } else { + packages.push_back(arg); + } + } + + if (packages.empty()) { + std::cerr << "Usage: " << args[0] << " [-r] package1 [package2 ...]\n"; return 1; } + + for (const auto &pkg : packages) { + try { + install_package(pkg); + } catch (std::exception &e) { + std::cerr << "ERROR: " << e.what() << std::endl; + return 1; + } + } } diff --git a/src/util.h b/src/util.h index 6e93d43..0d50607 100644 --- a/src/util.h +++ b/src/util.h @@ -1,9 +1,15 @@ #pragma once +#include "blake3.h" +#include +#include +#include #include +#include #include #include #include +#include namespace Util { @@ -47,4 +53,30 @@ static std::string basename(const std::string &path) { return path.substr(pos + 1); } +static std::string hash_file(const std::string &path) { + blake3_hasher hasher; + blake3_hasher_init(&hasher); + + std::ifstream file(path, std::ios::binary); + if (!file) { + throw std::runtime_error("failed to open file"); + } + + std::vector buffer(65536); + while (file.read(buffer.data(), static_cast(buffer.size())) || + file.gcount() > 0) { + blake3_hasher_update(&hasher, buffer.data(), file.gcount()); + } + + std::array output{}; + blake3_hasher_finalize(&hasher, output.data(), BLAKE3_OUT_LEN); + + std::stringstream ss; + ss << std::hex << std::setfill('0'); + for (const auto &byte : output) { + ss << std::setw(2) << static_cast(byte); + } + return ss.str(); +} + }; // namespace Util \ No newline at end of file