From 70474a40cc82af756e37d4876271bd0df07292eb Mon Sep 17 00:00:00 2001 From: Rahil Bhimjiani Date: Mon, 1 Jan 2024 10:24:52 +0530 Subject: [PATCH 1/8] app-crypt/lego: ACME client alternative to certbot/acme.sh written in Go which offers many built-in DNS plugins Signed-off-by: Rahil Bhimjiani --- app-crypt/lego/Manifest | 3 ++ app-crypt/lego/lego-4.14.2.ebuild | 82 +++++++++++++++++++++++++++++++ app-crypt/lego/lego-9999.ebuild | 82 +++++++++++++++++++++++++++++++ app-crypt/lego/metadata.xml | 13 +++++ 4 files changed, 180 insertions(+) create mode 100644 app-crypt/lego/Manifest create mode 100644 app-crypt/lego/lego-4.14.2.ebuild create mode 100644 app-crypt/lego/lego-9999.ebuild create mode 100644 app-crypt/lego/metadata.xml diff --git a/app-crypt/lego/Manifest b/app-crypt/lego/Manifest new file mode 100644 index 0000000000..6a66b1065e --- /dev/null +++ b/app-crypt/lego/Manifest @@ -0,0 +1,3 @@ +DIST lego-4.14.2-deps.tar.xz 204384528 BLAKE2B 5db3b7b6c194b4042b4c81a490c99f79339c9c0c4571bf31061a352626f08afcf8508edaf104af784243476264edd03c3e992aef711d05f26f5270f27b98e7bd SHA512 a07c5bf3fa0b99e3b2af06141b1049ff030b7d74c2a38fbe7c15fc46a622d4cc02c2e563e03eb5aede1ef8dc0ea3d16b775f2381a41caafbe3c6e45831d56544 +DIST lego-4.14.2-docs.tar.gz 3639965 BLAKE2B deb991244c93cd317a8e3acb90acc5f6712d5f5a1cf65ce615a13830e5a91fb35070b1eb9ce808322fa1e6e3cc9a6ee4253b488c1c8cbef0d7899b000a00d45f SHA512 13ea06e72581aee038d8cc4906b357d506b1dd20f1c8bd32a1c3fcfa364bdac2ccb76416bf6328f07e8feabc934329358ab75b0a440ede859caf350febac69fd +DIST lego-4.14.2.tar.gz 672197 BLAKE2B b633d6ed12fd7d38c35db392a58785fd32c3475961a49c5dbb3fe4986ca17c322a39ff604e73688928db1fa26eee70c8d9774fb560f96c5e017b680e2f89dbf2 SHA512 089788d1df077bdf8731250664628c9dbf44c8db7f2755242029c69b450eb892845b4c0b549a7affe80e351a29a6cc9d07514df3d0b7d1d17b42e20d1c85eca1 diff --git a/app-crypt/lego/lego-4.14.2.ebuild b/app-crypt/lego/lego-4.14.2.ebuild new file mode 100644 index 0000000000..2e16460056 --- /dev/null +++ b/app-crypt/lego/lego-4.14.2.ebuild @@ -0,0 +1,82 @@ +# Copyright 1999-2023 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +EAPI=8 + +inherit go-module + +DESCRIPTION="Let's Encrypt/ACME client (like certbot or acme.sh) and library written in Go" +HOMEPAGE="https://github.com/go-acme/lego/" + +DOCUMENTATION_COMMIT=e28a6ff22f2b7f75b8aaae5012672cfcca2be690 + +if [[ ${PV} == 9999* ]]; then + inherit git-r3 + EGIT_REPO_URI="https://github.com/go-acme/lego.git" +else + SRC_URI=" + https://github.com/go-acme/lego/archive/v${PV}.tar.gz -> ${P}.tar.gz + https://github.com/rahilarious/gentoo-distfiles/releases/download/${P}/deps.tar.xz -> ${P}-deps.tar.xz + doc? ( https://github.com/go-acme/lego/archive/${DOCUMENTATION_COMMIT}.tar.gz -> ${P}-docs.tar.gz ) +" + KEYWORDS="~amd64" +fi + +# main +LICENSE="MIT" +# deps +LICENSE+=" Apache-2.0 BSD-2 BSD ISC MPL-2.0" +SLOT="0" +IUSE="doc" + +# some tests require network access otherwise get following error +# expected: "zoneee: unexpected status code: [status code: 401] body: Unauthorized" +# actual : "zoneee: could not find zone for domain \"prefix.example.com\" (_acme-challenge.prefix.example.com.): could not find the start of authority for _acme-challenge.prefix.example.com.: read udp 10.0.0.1:54729->10.0.0.1:53: read: connection refused" +PROPERTIES="test_network" +RESTRICT="test" + +src_unpack() { + if [[ ${PV} == 9999* ]]; then + git-r3_src_unpack + go-module_live_vendor + if use doc; then + EGIT_BRANCH="gh-pages" + EGIT_CHECKOUT_DIR="${WORKDIR}/${P}-doc" + git-r3_src_unpack + fi + else + go-module_src_unpack + fi +} + +src_compile() { + export CGO_ENABLED=0 + + local VERSION + if [[ ${PV} == 9999* ]]; then + VERSION="$(git rev-parse HEAD)" || die + else + VERSION="${PV}" + fi + + ego build -trimpath -ldflags "-X main.version=${VERSION}" -o dist/"${PN}" ./cmd/lego/ +} + +src_test() { + ego test -v -cover ./... +} + +src_install() { + # primary program + dobin dist/"${PN}" + + # docs + einstalldocs + if use doc; then + if [[ ${PV} == 9999* ]]; then + dodoc -r ../"${P}"-doc/* + else + dodoc -r ../"${PN}"-"${DOCUMENTATION_COMMIT}"/* + fi + fi +} diff --git a/app-crypt/lego/lego-9999.ebuild b/app-crypt/lego/lego-9999.ebuild new file mode 100644 index 0000000000..2e16460056 --- /dev/null +++ b/app-crypt/lego/lego-9999.ebuild @@ -0,0 +1,82 @@ +# Copyright 1999-2023 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +EAPI=8 + +inherit go-module + +DESCRIPTION="Let's Encrypt/ACME client (like certbot or acme.sh) and library written in Go" +HOMEPAGE="https://github.com/go-acme/lego/" + +DOCUMENTATION_COMMIT=e28a6ff22f2b7f75b8aaae5012672cfcca2be690 + +if [[ ${PV} == 9999* ]]; then + inherit git-r3 + EGIT_REPO_URI="https://github.com/go-acme/lego.git" +else + SRC_URI=" + https://github.com/go-acme/lego/archive/v${PV}.tar.gz -> ${P}.tar.gz + https://github.com/rahilarious/gentoo-distfiles/releases/download/${P}/deps.tar.xz -> ${P}-deps.tar.xz + doc? ( https://github.com/go-acme/lego/archive/${DOCUMENTATION_COMMIT}.tar.gz -> ${P}-docs.tar.gz ) +" + KEYWORDS="~amd64" +fi + +# main +LICENSE="MIT" +# deps +LICENSE+=" Apache-2.0 BSD-2 BSD ISC MPL-2.0" +SLOT="0" +IUSE="doc" + +# some tests require network access otherwise get following error +# expected: "zoneee: unexpected status code: [status code: 401] body: Unauthorized" +# actual : "zoneee: could not find zone for domain \"prefix.example.com\" (_acme-challenge.prefix.example.com.): could not find the start of authority for _acme-challenge.prefix.example.com.: read udp 10.0.0.1:54729->10.0.0.1:53: read: connection refused" +PROPERTIES="test_network" +RESTRICT="test" + +src_unpack() { + if [[ ${PV} == 9999* ]]; then + git-r3_src_unpack + go-module_live_vendor + if use doc; then + EGIT_BRANCH="gh-pages" + EGIT_CHECKOUT_DIR="${WORKDIR}/${P}-doc" + git-r3_src_unpack + fi + else + go-module_src_unpack + fi +} + +src_compile() { + export CGO_ENABLED=0 + + local VERSION + if [[ ${PV} == 9999* ]]; then + VERSION="$(git rev-parse HEAD)" || die + else + VERSION="${PV}" + fi + + ego build -trimpath -ldflags "-X main.version=${VERSION}" -o dist/"${PN}" ./cmd/lego/ +} + +src_test() { + ego test -v -cover ./... +} + +src_install() { + # primary program + dobin dist/"${PN}" + + # docs + einstalldocs + if use doc; then + if [[ ${PV} == 9999* ]]; then + dodoc -r ../"${P}"-doc/* + else + dodoc -r ../"${PN}"-"${DOCUMENTATION_COMMIT}"/* + fi + fi +} diff --git a/app-crypt/lego/metadata.xml b/app-crypt/lego/metadata.xml new file mode 100644 index 0000000000..9fbd01cd7f --- /dev/null +++ b/app-crypt/lego/metadata.xml @@ -0,0 +1,13 @@ + + + + + me@rahil.rocks + Rahil Bhimjiani + + + go-acme/lego + https://github.com/go-acme/lego/issues + https://go-acme.github.io/lego/ + + From 455aae69ed201dcef931219a5b17cf3a82d5c01b Mon Sep 17 00:00:00 2001 From: Rahil Bhimjiani Date: Mon, 1 Jan 2024 10:50:55 +0530 Subject: [PATCH 2/8] net-dns/AdGuardHome: Pi-Hole alternative written in Go offers following features which lack in Pi-hole * Encrypted DNS upstream servers (DNS-over-HTTPS, DNS-over-TLS, DNSCrypt) * Running as a DNS-over-HTTPS or DNS-over-TLS server Signed-off-by: Rahil Bhimjiani --- .../AdGuardHome/AdGuardHome-0.107.43.ebuild | 106 ++++++++++++++++++ net-dns/AdGuardHome/Manifest | 3 + .../files/AdGuardHome-0.107.43.service | 22 ++++ net-dns/AdGuardHome/metadata.xml | 13 +++ 4 files changed, 144 insertions(+) create mode 100644 net-dns/AdGuardHome/AdGuardHome-0.107.43.ebuild create mode 100644 net-dns/AdGuardHome/Manifest create mode 100644 net-dns/AdGuardHome/files/AdGuardHome-0.107.43.service create mode 100644 net-dns/AdGuardHome/metadata.xml diff --git a/net-dns/AdGuardHome/AdGuardHome-0.107.43.ebuild b/net-dns/AdGuardHome/AdGuardHome-0.107.43.ebuild new file mode 100644 index 0000000000..c1a9f54336 --- /dev/null +++ b/net-dns/AdGuardHome/AdGuardHome-0.107.43.ebuild @@ -0,0 +1,106 @@ +# Copyright 1999-2024 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +EAPI=8 + +inherit fcaps go-module systemd + +DESCRIPTION="Network-wide ads & trackers blocking DNS server like Pi-Hole with web ui" +HOMEPAGE="https://github.com/AdguardTeam/AdGuardHome/" + +SRC_URI=" + https://github.com/AdguardTeam/${PN}/archive/refs/tags/v${PV}.tar.gz -> ${P}.tar.gz + https://github.com/AdguardTeam/${PN}/releases/download/v${PV}/AdGuardHome_frontend.tar.gz -> ${P}-frontend.tar.gz + https://github.com/rahilarious/gentoo-distfiles/releases/download/${P}/deps.tar.xz -> ${P}-deps.tar.xz +" + +# main +LICENSE="GPL-3" +# deps +LICENSE+=" Apache-2.0 BSD BSD-2 MIT ZLIB" + +SLOT="0" +KEYWORDS="~amd64" + +FILECAPS=( + -m 755 'cap_net_bind_service=+eip cap_net_raw=+eip' usr/bin/${PN} +) + +src_prepare() { + default + # move frontend to project directory + rm build/gitkeep && mv ../build ./ || die +} + +src_compile() { + # mimicking https://github.com/AdguardTeam/AdGuardHome/blob/master/scripts/make/go-build.sh + + local MY_LDFLAGS="-s -w" + MY_LDFLAGS+=" -X github.com/AdguardTeam/AdGuardHome/internal/version.version=${PV}" + MY_LDFLAGS+=" -X github.com/AdguardTeam/AdGuardHome/internal/version.channel=release" + MY_LDFLAGS+=" -X github.com/AdguardTeam/AdGuardHome/internal/version.committime=$(date +%s)" + if [ "$(go env GOARM)" != '' ] + then + MY_LDFLAGS+=" -X github.com/AdguardTeam/AdGuardHome/internal/version.goarm=$(go env GOARM)" + elif [ "$(go env GOMIPS)" != '' ] + then + MY_LDFLAGS+=" -X github.com/AdguardTeam/AdGuardHome/internal/version.gomips=$(go env GOMIPS)" + fi + + ego build -ldflags "${MY_LDFLAGS}" -trimpath +} + +src_test() { + + # mimicking https://github.com/AdguardTeam/AdGuardHome/blob/master/scripts/make/go-test.sh + count_flags='--count=1' + cover_flags='--coverprofile=./coverage.txt' + shuffle_flags='--shuffle=on' + timeout_flags="--timeout=30s" + fuzztime_flags="--fuzztime=20s" + readonly count_flags cover_flags shuffle_flags timeout_flags fuzztime_flags + + # race only works when pie is disabled + export GOFLAGS="${GOFLAGS/-buildmode=pie/}" + + # following test is failing without giving any reason. Tried disabling internal/updater internal/whois tests toggling race, but still failing. + # ego test\ + # "$count_flags"\ + # "$cover_flags"\ + # "$shuffle_flags"\ + # --race=1\ + # "$timeout_flags"\ + # ./... + + # mimicking https://github.com/AdguardTeam/AdGuardHome/blob/master/scripts/make/go-bench.sh + ego test\ + "$count_flags"\ + "$shuffle_flags"\ + --race=0\ + "$timeout_flags"\ + --bench='.'\ + --benchmem\ + --benchtime=1s\ + --run='^$'\ + ./... + + # mimicking https://github.com/AdguardTeam/AdGuardHome/blob/master/scripts/make/go-fuzz.sh + ego test\ + "$count_flags"\ + "$shuffle_flags"\ + --race=0\ + "$timeout_flags"\ + "$fuzztime_flags"\ + --fuzz='.'\ + --run='^$'\ + ./internal/filtering/rulelist/\ + ; + +} + +src_install() { + dobin "${PN}" + einstalldocs + + systemd_newunit "${FILESDIR}"/AdGuardHome-0.107.43.service "${PN}".service +} diff --git a/net-dns/AdGuardHome/Manifest b/net-dns/AdGuardHome/Manifest new file mode 100644 index 0000000000..ced137539c --- /dev/null +++ b/net-dns/AdGuardHome/Manifest @@ -0,0 +1,3 @@ +DIST AdGuardHome-0.107.43-deps.tar.xz 104529544 BLAKE2B 4fde3b1e2f85cf85209eb2149c40a5478e4d55cbae90847fafdb5f056b7af2a8234a5880fac6bbed1b62e64d7e849162abbc9e5fef3b262ecea8760fcb21c21c SHA512 44458c3d1d46c7ccf50308227ff765927e1b6d4876065af13004bd0ec2c82c7727e76a81bfc52cf920ea2dee361e5c761db73ed610d04b23568c6e7611301348 +DIST AdGuardHome-0.107.43-frontend.tar.gz 2781809 BLAKE2B 72d42f40a5f671f5dab72a7fcbd77fdfbd58126b67c73fd6e1dbec5f956c017ff64c01cb8c89ec5c72ef2058640e7cea5b93fe1b3c2c7b76edc6de32ab7f4801 SHA512 1c1fd527638c3e35fa21b5738868dae04b41a0bbb04942c94cc36d1dc7f6961bd202c7862fdfffe3ed52039c75b3f358e399c17ccd121e78432ec58fa837f4a0 +DIST AdGuardHome-0.107.43.tar.gz 2227903 BLAKE2B a4811969b2e156a33d6267edeca4be3535e095e8133c6c8d761e132e5f95d21403df37f8ac5567d85994b89ff8912f1799f21f648d6a26a6bf7971d02bd11ffd SHA512 cc9f7602ada6e40ff7c8449bfc1c40fb184c848019ff95b1db46a974f4a72606c587015d440e25094c51cc0b6d01eb68686765d0a92f01752615db63e4527803 diff --git a/net-dns/AdGuardHome/files/AdGuardHome-0.107.43.service b/net-dns/AdGuardHome/files/AdGuardHome-0.107.43.service new file mode 100644 index 0000000000..2311ee1497 --- /dev/null +++ b/net-dns/AdGuardHome/files/AdGuardHome-0.107.43.service @@ -0,0 +1,22 @@ +# This unit is inspired from +# `AdGuardHome -s install` on systemd machine and +# https://aur.archlinux.org/cgit/aur.git/tree/adguardhome.service?h=adguardhome + +[Unit] +Description=Network-wide ads & trackers blocking DNS server with WebUI +After=network-online.target +ConditionFileIsExecutable=/usr/bin/AdGuardHome + +[Service] +StartLimitInterval=5 +StartLimitBurst=10 +DynamicUser=true +StateDirectory=AdGuardHome +WorkingDirectory=/var/lib/AdGuardHome +AmbientCapabilities=CAP_NET_BIND_SERVICE CAP_NET_RAW +CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_NET_RAW +ExecStart=/usr/bin/AdGuardHome --no-check-update --work-dir /var/lib/AdGuardHome +ExecReload=/usr/bin/kill -HUP $MAINPID + +[Install] +WantedBy=multi-user.target diff --git a/net-dns/AdGuardHome/metadata.xml b/net-dns/AdGuardHome/metadata.xml new file mode 100644 index 0000000000..2aeba77180 --- /dev/null +++ b/net-dns/AdGuardHome/metadata.xml @@ -0,0 +1,13 @@ + + + + + me@rahil.rocks + Rahil Bhimjiani + + + AdguardTeam/AdGuardHome + https://github.com/AdguardTeam/AdGuardHome/issues + https://github.com/AdguardTeam/AdGuardHome/ + + From 26fd689d608e7cb99a173c645851cc22e66af2e3 Mon Sep 17 00:00:00 2001 From: Rahil Bhimjiani Date: Mon, 1 Jan 2024 11:23:54 +0530 Subject: [PATCH 3/8] net-dns/blocky: Fast and lightweight DNS proxy as ad-blocker Supports DoH, DoT and prometheus+grafana integration with very versatile cli and configuration options Signed-off-by: Rahil Bhimjiani --- acct-group/blocky/blocky-0.ebuild | 10 + acct-group/blocky/metadata.xml | 8 + acct-user/blocky/blocky-0.ebuild | 13 + acct-user/blocky/metadata.xml | 8 + net-dns/blocky/Manifest | 3 + net-dns/blocky/blocky-0.22.ebuild | 104 + net-dns/blocky/blocky-9999.ebuild | 104 + net-dns/blocky/files/blocky-0.22.service | 16 + .../files/disable-failed-tests-0.22.patch | 2272 +++++++++++++++++ net-dns/blocky/metadata.xml | 16 + 10 files changed, 2554 insertions(+) create mode 100644 acct-group/blocky/blocky-0.ebuild create mode 100644 acct-group/blocky/metadata.xml create mode 100644 acct-user/blocky/blocky-0.ebuild create mode 100644 acct-user/blocky/metadata.xml create mode 100644 net-dns/blocky/Manifest create mode 100644 net-dns/blocky/blocky-0.22.ebuild create mode 100644 net-dns/blocky/blocky-9999.ebuild create mode 100644 net-dns/blocky/files/blocky-0.22.service create mode 100644 net-dns/blocky/files/disable-failed-tests-0.22.patch create mode 100644 net-dns/blocky/metadata.xml diff --git a/acct-group/blocky/blocky-0.ebuild b/acct-group/blocky/blocky-0.ebuild new file mode 100644 index 0000000000..a85e41314e --- /dev/null +++ b/acct-group/blocky/blocky-0.ebuild @@ -0,0 +1,10 @@ +# Copyright 2019-2023 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +EAPI=8 + +inherit acct-group + +DESCRIPTION="A group for net-dns/blocky" + +ACCT_GROUP_ID="69" diff --git a/acct-group/blocky/metadata.xml b/acct-group/blocky/metadata.xml new file mode 100644 index 0000000000..3e6b5d8ad4 --- /dev/null +++ b/acct-group/blocky/metadata.xml @@ -0,0 +1,8 @@ + + + + + me@rahil.rocks + Rahil Bhimjiani + + diff --git a/acct-user/blocky/blocky-0.ebuild b/acct-user/blocky/blocky-0.ebuild new file mode 100644 index 0000000000..f941ee07e2 --- /dev/null +++ b/acct-user/blocky/blocky-0.ebuild @@ -0,0 +1,13 @@ +# Copyright 2019-2023 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +EAPI=8 + +inherit acct-user + +DESCRIPTION="A user for net-dns/blocky" + +ACCT_USER_ID="100" +ACCT_USER_GROUPS=( "blocky" ) + +acct-user_add_deps diff --git a/acct-user/blocky/metadata.xml b/acct-user/blocky/metadata.xml new file mode 100644 index 0000000000..3e6b5d8ad4 --- /dev/null +++ b/acct-user/blocky/metadata.xml @@ -0,0 +1,8 @@ + + + + + me@rahil.rocks + Rahil Bhimjiani + + diff --git a/net-dns/blocky/Manifest b/net-dns/blocky/Manifest new file mode 100644 index 0000000000..cbfdf1469a --- /dev/null +++ b/net-dns/blocky/Manifest @@ -0,0 +1,3 @@ +DIST blocky-0.22-deps.tar.xz 163869124 BLAKE2B e98614feaeb11604866d08003147871096c993cdb90c85bba46ea999a339570ca1500a80bddee202595372ec5d22baa6ec0345d8cf50ffee6d61dd8d6495d49f SHA512 883e5dd66cf974c6d8c73a94c7677d5003ceb7a3ba68001c2d9d36e1e4d1ea64f0818d30240fe77f192ad3f95ede93127bed9adc9647da07a9b9bebc958ffd33 +DIST blocky-0.22-docs.tar.gz 5639822 BLAKE2B e177790deb7493f84d8217661e4e4296004a9db7e00ff8d37dbd3c4ed8b7ba0a7cf431067c103f25784e46ca7a8bf80532cdd8f305f3e4ce119890027f0eb186 SHA512 3eed0ff726479826fbefb4140c36bb26825124134d1fbbecf74a31b2fbdde993630adc645ea2e582ce8d415736cc85b20f64a835c87da98700b715c03d368e75 +DIST blocky-0.22.tar.gz 712644 BLAKE2B d74881026421337a0fc32a6af2cf6bff736e0130ac599cd80714f0cafff1e81864e0327bc773f8377106421642cf545b76407fca94f07425c428ff8512a7113b SHA512 928ba882cb567f80b9b00c1ab74ba2fba0324b9e5fb6439789d50d8fd438a26f84772d36f91ef9c3a2351c798a399c15aa1b69927a2da11795edd576b7bae6a4 diff --git a/net-dns/blocky/blocky-0.22.ebuild b/net-dns/blocky/blocky-0.22.ebuild new file mode 100644 index 0000000000..5b601c8825 --- /dev/null +++ b/net-dns/blocky/blocky-0.22.ebuild @@ -0,0 +1,104 @@ +# Copyright 1999-2024 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +EAPI=8 + +inherit fcaps go-module systemd shell-completion + +DESCRIPTION="Fast and lightweight DNS proxy as ad-blocker with many features written in Go" +HOMEPAGE="https://github.com/0xERR0R/blocky/" + +DOCUMENTATION_COMMIT=9c6a86eb163e758686c5d6d4d5259deb086a8aa9 + +if [[ ${PV} == 9999* ]]; then + inherit git-r3 + EGIT_REPO_URI="https://github.com/0xERR0R/blocky.git" +else + SRC_URI=" + https://github.com/0xERR0R/blocky/archive/v${PV}.tar.gz -> ${P}.tar.gz + https://github.com/rahilarious/gentoo-distfiles/releases/download/${P}/deps.tar.xz -> ${P}-deps.tar.xz + doc? ( https://github.com/0xERR0R/blocky/archive/${DOCUMENTATION_COMMIT}.tar.gz -> ${P}-docs.tar.gz ) +" + KEYWORDS="~amd64" +fi + +# main +LICENSE="Apache-2.0" +# deps +LICENSE+=" AGPL-3 BSD-2 BSD ISC MIT MPL-2.0" +SLOT="0" +IUSE="doc" + +# RESTRICT="test" + +RDEPEND=" + acct-user/blocky + acct-group/blocky +" + +PATCHES=( + "${FILESDIR}"/disable-failed-tests-0.22.patch +) + +FILECAPS=( + -m 755 'cap_net_bind_service=+ep' usr/bin/"${PN}" +) + +src_unpack() { + if [[ ${PV} == 9999* ]]; then + git-r3_src_unpack + go-module_live_vendor + if use doc; then + EGIT_BRANCH="gh-pages" + EGIT_CHECKOUT_DIR="${WORKDIR}/${P}-doc" + git-r3_src_unpack + fi + else + go-module_src_unpack + fi +} + +src_compile() { + [[ ${PV} != 9999* ]] && export VERSION="${PV}" + + # mimicking project's Dockerfile + emake GO_SKIP_GENERATE=yes GO_BUILD_FLAGS="-tags static -v " build + + local shell + for shell in bash fish zsh; do + bin/"${PN}" completion "${shell}" > "${PN}"."${shell}" || die + done +} + +src_test() { + # mimcking make test + ego run github.com/onsi/ginkgo/v2/ginkgo --label-filter="!e2e" --coverprofile=coverage.txt --covermode=atomic --cover -r -p + ego tool cover -html coverage.txt -o coverage.html +} + +src_install() { + # primary program + dobin bin/"${PN}" + + # secondary supplements + insinto /etc/"${PN}" + newins docs/config.yml config.yml.sample + + newbashcomp "${PN}".bash "${PN}" + dofishcomp "${PN}".fish + newzshcomp "${PN}".zsh _"${PN}" + + # TODO openrc services + systemd_newunit "${FILESDIR}"/blocky-0.22.service "${PN}".service + + # docs + einstalldocs + + if use doc; then + if [[ ${PV} == 9999* ]]; then + dodoc -r ../"${P}"-doc/main/* + else + dodoc -r ../"${PN}"-"${DOCUMENTATION_COMMIT}"/v"${PV}"/* + fi + fi +} diff --git a/net-dns/blocky/blocky-9999.ebuild b/net-dns/blocky/blocky-9999.ebuild new file mode 100644 index 0000000000..3f5b49b9fc --- /dev/null +++ b/net-dns/blocky/blocky-9999.ebuild @@ -0,0 +1,104 @@ +# Copyright 1999-2024 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +EAPI=8 + +inherit fcaps go-module systemd shell-completion + +DESCRIPTION="Fast and lightweight DNS proxy as ad-blocker with many features written in Go" +HOMEPAGE="https://github.com/0xERR0R/blocky/" + +DOCUMENTATION_COMMIT=9c6a86eb163e758686c5d6d4d5259deb086a8aa9 + +if [[ ${PV} == 9999* ]]; then + inherit git-r3 + EGIT_REPO_URI="https://github.com/0xERR0R/blocky.git" +else + SRC_URI=" + https://github.com/0xERR0R/blocky/archive/v${PV}.tar.gz -> ${P}.tar.gz + https://github.com/rahilarious/gentoo-distfiles/releases/download/${P}/deps.tar.xz -> ${P}-deps.tar.xz + doc? ( https://github.com/0xERR0R/blocky/archive/${DOCUMENTATION_COMMIT}.tar.gz -> ${P}-docs.tar.gz ) +" + KEYWORDS="~amd64" +fi + +# main +LICENSE="Apache-2.0" +# deps +LICENSE+=" AGPL-3 BSD-2 BSD ISC MIT MPL-2.0" +SLOT="0" +IUSE="doc" + +RESTRICT="test" + +RDEPEND=" + acct-user/blocky + acct-group/blocky +" + +# PATCHES=( +# "${FILESDIR}"/disable-failed-tests-0.22.patch +# ) + +FILECAPS=( + -m 755 'cap_net_bind_service=+ep' usr/bin/"${PN}" +) + +src_unpack() { + if [[ ${PV} == 9999* ]]; then + git-r3_src_unpack + go-module_live_vendor + if use doc; then + EGIT_BRANCH="gh-pages" + EGIT_CHECKOUT_DIR="${WORKDIR}/${P}-doc" + git-r3_src_unpack + fi + else + go-module_src_unpack + fi +} + +src_compile() { + [[ ${PV} != 9999* ]] && export VERSION="${PV}" + + # mimicking project's Dockerfile + emake GO_SKIP_GENERATE=yes GO_BUILD_FLAGS="-tags static -v " build + + local shell + for shell in bash fish zsh; do + bin/"${PN}" completion "${shell}" > "${PN}"."${shell}" || die + done +} + +src_test() { + # mimcking make test + ego run github.com/onsi/ginkgo/v2/ginkgo --label-filter="!e2e" --coverprofile=coverage.txt --covermode=atomic --cover -r -p + ego tool cover -html coverage.txt -o coverage.html +} + +src_install() { + # primary program + dobin bin/"${PN}" + + # secondary supplements + insinto /etc/"${PN}" + newins docs/config.yml config.yml.sample + + newbashcomp "${PN}".bash "${PN}" + dofishcomp "${PN}".fish + newzshcomp "${PN}".zsh _"${PN}" + + # TODO openrc services + systemd_newunit "${FILESDIR}"/blocky-0.22.service "${PN}".service + + # docs + einstalldocs + + if use doc; then + if [[ ${PV} == 9999* ]]; then + dodoc -r ../"${P}"-doc/main/* + else + dodoc -r ../"${PN}"-"${DOCUMENTATION_COMMIT}"/v"${PV}"/* + fi + fi +} diff --git a/net-dns/blocky/files/blocky-0.22.service b/net-dns/blocky/files/blocky-0.22.service new file mode 100644 index 0000000000..ce40a31cee --- /dev/null +++ b/net-dns/blocky/files/blocky-0.22.service @@ -0,0 +1,16 @@ +[Unit] +Description=Fast and lightweight DNS proxy as ad-blocker +Documentation=https://0xerr0r.github.io/blocky/ +After=network-online.target +Wants=network-online.target + +[Service] +CapabilityBoundingSet=CAP_NET_BIND_SERVICE +AmbientCapabilities=CAP_NET_BIND_SERVICE +NoNewPrivileges=true +User=blocky +ExecStart=/usr/bin/blocky --config /etc/blocky/config.yml +Restart=on-failure + +[Install] +WantedBy=multi-user.target diff --git a/net-dns/blocky/files/disable-failed-tests-0.22.patch b/net-dns/blocky/files/disable-failed-tests-0.22.patch new file mode 100644 index 0000000000..98883469df --- /dev/null +++ b/net-dns/blocky/files/disable-failed-tests-0.22.patch @@ -0,0 +1,2272 @@ +diff --git a/cache/stringcache/chained_grouped_cache_test.go b/cache/stringcache/chained_grouped_cache_test.go +deleted file mode 100644 +index e83f956..0000000 +--- a/cache/stringcache/chained_grouped_cache_test.go ++++ /dev/null +@@ -1,93 +0,0 @@ +-package stringcache_test +- +-import ( +- "github.com/0xERR0R/blocky/cache/stringcache" +- . "github.com/onsi/ginkgo/v2" +- . "github.com/onsi/gomega" +-) +- +-var _ = Describe("Chained grouped cache", func() { +- Describe("Empty cache", func() { +- When("empty cache was created", func() { +- cache := stringcache.NewChainedGroupedCache() +- +- It("should have element count of 0", func() { +- Expect(cache.ElementCount("someGroup")).Should(BeNumerically("==", 0)) +- }) +- +- It("should not find any string", func() { +- Expect(cache.Contains("searchString", []string{"someGroup"})).Should(BeEmpty()) +- }) +- }) +- }) +- Describe("Delegation", func() { +- When("Chained cache contains delegates", func() { +- inMemoryCache1 := stringcache.NewInMemoryGroupedStringCache() +- inMemoryCache2 := stringcache.NewInMemoryGroupedStringCache() +- cache := stringcache.NewChainedGroupedCache(inMemoryCache1, inMemoryCache2) +- +- factory := cache.Refresh("group1") +- +- factory.AddEntry("string1") +- factory.AddEntry("string2") +- +- It("cache should still have 0 element, since finish was not executed", func() { +- Expect(cache.ElementCount("group1")).Should(BeNumerically("==", 0)) +- }) +- +- It("factory has 4 elements (both caches)", func() { +- Expect(factory.Count()).Should(BeNumerically("==", 4)) +- }) +- +- It("should have element count of 4", func() { +- factory.Finish() +- Expect(cache.ElementCount("group1")).Should(BeNumerically("==", 4)) +- }) +- +- It("should find strings", func() { +- Expect(cache.Contains("string1", []string{"group1"})).Should(ConsistOf("group1")) +- Expect(cache.Contains("string2", []string{"group1", "someOtherGroup"})).Should(ConsistOf("group1")) +- }) +- }) +- }) +- +- Describe("Cache refresh", func() { +- When("cache with 2 groups was created", func() { +- inMemoryCache1 := stringcache.NewInMemoryGroupedStringCache() +- inMemoryCache2 := stringcache.NewInMemoryGroupedStringCache() +- cache := stringcache.NewChainedGroupedCache(inMemoryCache1, inMemoryCache2) +- +- factory := cache.Refresh("group1") +- +- factory.AddEntry("g1") +- factory.AddEntry("both") +- factory.Finish() +- +- factory = cache.Refresh("group2") +- factory.AddEntry("g2") +- factory.AddEntry("both") +- factory.Finish() +- +- It("should contain 4 elements in 2 groups", func() { +- Expect(cache.ElementCount("group1")).Should(BeNumerically("==", 4)) +- Expect(cache.ElementCount("group2")).Should(BeNumerically("==", 4)) +- Expect(cache.Contains("g1", []string{"group1", "group2"})).Should(ConsistOf("group1")) +- Expect(cache.Contains("g2", []string{"group1", "group2"})).Should(ConsistOf("group2")) +- Expect(cache.Contains("both", []string{"group1", "group2"})).Should(ConsistOf("group1", "group2")) +- }) +- +- It("Should replace group content on refresh", func() { +- factory := cache.Refresh("group1") +- factory.AddEntry("newString") +- factory.Finish() +- +- Expect(cache.ElementCount("group1")).Should(BeNumerically("==", 2)) +- Expect(cache.ElementCount("group2")).Should(BeNumerically("==", 4)) +- Expect(cache.Contains("g1", []string{"group1", "group2"})).Should(BeEmpty()) +- Expect(cache.Contains("newString", []string{"group1", "group2"})).Should(ConsistOf("group1")) +- Expect(cache.Contains("g2", []string{"group1", "group2"})).Should(ConsistOf("group2")) +- Expect(cache.Contains("both", []string{"group1", "group2"})).Should(ConsistOf("group2")) +- }) +- }) +- }) +-}) +diff --git a/cache/stringcache/in_memory_grouped_cache_test.go b/cache/stringcache/in_memory_grouped_cache_test.go +deleted file mode 100644 +index 7692935..0000000 +--- a/cache/stringcache/in_memory_grouped_cache_test.go ++++ /dev/null +@@ -1,130 +0,0 @@ +-package stringcache_test +- +-import ( +- "github.com/0xERR0R/blocky/cache/stringcache" +- . "github.com/onsi/ginkgo/v2" +- . "github.com/onsi/gomega" +-) +- +-var _ = Describe("In-Memory grouped cache", func() { +- Describe("Empty cache", func() { +- When("empty cache was created", func() { +- cache := stringcache.NewInMemoryGroupedStringCache() +- +- It("should have element count of 0", func() { +- Expect(cache.ElementCount("someGroup")).Should(BeNumerically("==", 0)) +- }) +- +- It("should not find any string", func() { +- Expect(cache.Contains("searchString", []string{"someGroup"})).Should(BeEmpty()) +- }) +- }) +- When("cache with one empty group", func() { +- cache := stringcache.NewInMemoryGroupedStringCache() +- factory := cache.Refresh("group1") +- factory.Finish() +- +- It("should have element count of 0", func() { +- Expect(cache.ElementCount("group1")).Should(BeNumerically("==", 0)) +- }) +- +- It("should not find any string", func() { +- Expect(cache.Contains("searchString", []string{"group1"})).Should(BeEmpty()) +- }) +- }) +- }) +- Describe("Cache creation", func() { +- When("cache with 1 group was created", func() { +- cache := stringcache.NewInMemoryGroupedStringCache() +- +- factory := cache.Refresh("group1") +- +- factory.AddEntry("string1") +- factory.AddEntry("string2") +- +- It("cache should still have 0 element, since finish was not executed", func() { +- Expect(cache.ElementCount("group1")).Should(BeNumerically("==", 0)) +- }) +- +- It("factory has 2 elements", func() { +- Expect(factory.Count()).Should(BeNumerically("==", 2)) +- }) +- +- It("should have element count of 2", func() { +- factory.Finish() +- Expect(cache.ElementCount("group1")).Should(BeNumerically("==", 2)) +- }) +- +- It("should find strings", func() { +- Expect(cache.Contains("string1", []string{"group1"})).Should(ConsistOf("group1")) +- Expect(cache.Contains("string2", []string{"group1", "someOtherGroup"})).Should(ConsistOf("group1")) +- }) +- }) +- When("String grouped cache is used", func() { +- cache := stringcache.NewInMemoryGroupedStringCache() +- factory := cache.Refresh("group1") +- +- factory.AddEntry("string1") +- factory.AddEntry("/string2/") +- factory.Finish() +- +- It("should ignore regex", func() { +- Expect(cache.ElementCount("group1")).Should(BeNumerically("==", 1)) +- Expect(cache.Contains("string1", []string{"group1"})).Should(ConsistOf("group1")) +- }) +- }) +- When("Regex grouped cache is used", func() { +- cache := stringcache.NewInMemoryGroupedRegexCache() +- factory := cache.Refresh("group1") +- +- factory.AddEntry("string1") +- factory.AddEntry("/string2/") +- factory.Finish() +- +- It("should ignore non-regex", func() { +- Expect(cache.ElementCount("group1")).Should(BeNumerically("==", 1)) +- Expect(cache.Contains("string1", []string{"group1"})).Should(BeEmpty()) +- Expect(cache.Contains("string2", []string{"group1"})).Should(ConsistOf("group1")) +- Expect(cache.Contains("shouldalsomatchstring2", []string{"group1"})).Should(ConsistOf("group1")) +- }) +- }) +- }) +- +- Describe("Cache refresh", func() { +- When("cache with 2 groups was created", func() { +- cache := stringcache.NewInMemoryGroupedStringCache() +- +- factory := cache.Refresh("group1") +- +- factory.AddEntry("g1") +- factory.AddEntry("both") +- factory.Finish() +- +- factory = cache.Refresh("group2") +- factory.AddEntry("g2") +- factory.AddEntry("both") +- factory.Finish() +- +- It("should contain 4 elements in 2 groups", func() { +- Expect(cache.ElementCount("group1")).Should(BeNumerically("==", 2)) +- Expect(cache.ElementCount("group2")).Should(BeNumerically("==", 2)) +- Expect(cache.Contains("g1", []string{"group1", "group2"})).Should(ConsistOf("group1")) +- Expect(cache.Contains("g2", []string{"group1", "group2"})).Should(ConsistOf("group2")) +- Expect(cache.Contains("both", []string{"group1", "group2"})).Should(ConsistOf("group1", "group2")) +- }) +- +- It("Should replace group content on refresh", func() { +- factory := cache.Refresh("group1") +- factory.AddEntry("newString") +- factory.Finish() +- +- Expect(cache.ElementCount("group1")).Should(BeNumerically("==", 1)) +- Expect(cache.ElementCount("group2")).Should(BeNumerically("==", 2)) +- Expect(cache.Contains("g1", []string{"group1", "group2"})).Should(BeEmpty()) +- Expect(cache.Contains("newString", []string{"group1", "group2"})).Should(ConsistOf("group1")) +- Expect(cache.Contains("g2", []string{"group1", "group2"})).Should(ConsistOf("group2")) +- Expect(cache.Contains("both", []string{"group1", "group2"})).Should(ConsistOf("group2")) +- }) +- }) +- }) +-}) +diff --git a/lists/downloader_test.go b/lists/downloader_test.go +deleted file mode 100644 +index 5387c86..0000000 +--- a/lists/downloader_test.go ++++ /dev/null +@@ -1,218 +0,0 @@ +-package lists +- +-import ( +- "errors" +- "io" +- "net" +- "net/http" +- "net/http/httptest" +- "strings" +- "sync/atomic" +- "time" +- +- "github.com/0xERR0R/blocky/config" +- . "github.com/0xERR0R/blocky/evt" +- . "github.com/0xERR0R/blocky/helpertest" +- "github.com/0xERR0R/blocky/log" +- . "github.com/onsi/ginkgo/v2" +- . "github.com/onsi/gomega" +- "github.com/sirupsen/logrus/hooks/test" +-) +- +-var _ = Describe("Downloader", func() { +- var ( +- sutConfig config.DownloaderConfig +- sut *httpDownloader +- failedDownloadCountEvtChannel chan string +- loggerHook *test.Hook +- ) +- BeforeEach(func() { +- var err error +- +- sutConfig, err = config.WithDefaults[config.DownloaderConfig]() +- Expect(err).Should(Succeed()) +- +- failedDownloadCountEvtChannel = make(chan string, 5) +- // collect received events in the channel +- fn := func(url string) { +- failedDownloadCountEvtChannel <- url +- } +- Expect(Bus().Subscribe(CachingFailedDownloadChanged, fn)).Should(Succeed()) +- DeferCleanup(func() { +- Expect(Bus().Unsubscribe(CachingFailedDownloadChanged, fn)) +- }) +- +- loggerHook = test.NewGlobal() +- log.Log().AddHook(loggerHook) +- DeferCleanup(loggerHook.Reset) +- }) +- +- JustBeforeEach(func() { +- sut = newDownloader(sutConfig, nil) +- }) +- +- Describe("NewDownloader", func() { +- It("Should use provided parameters", func() { +- transport := &http.Transport{} +- +- sut = NewDownloader( +- config.DownloaderConfig{ +- Attempts: 5, +- Cooldown: config.Duration(2 * time.Second), +- Timeout: config.Duration(5 * time.Second), +- }, +- transport, +- ).(*httpDownloader) +- +- Expect(sut.cfg.Attempts).Should(BeNumerically("==", 5)) +- Expect(sut.cfg.Timeout).Should(BeNumerically("==", 5*time.Second)) +- Expect(sut.cfg.Cooldown).Should(BeNumerically("==", 2*time.Second)) +- Expect(sut.client.Transport).Should(BeIdenticalTo(transport)) +- }) +- }) +- +- Describe("Download of a file", func() { +- var server *httptest.Server +- When("Download was successful", func() { +- BeforeEach(func() { +- server = TestServer("line.one\nline.two") +- DeferCleanup(server.Close) +- +- sut = newDownloader(sutConfig, nil) +- }) +- It("Should return all lines from the file", func() { +- reader, err := sut.DownloadFile(server.URL) +- +- Expect(err).Should(Succeed()) +- Expect(reader).Should(Not(BeNil())) +- DeferCleanup(reader.Close) +- buf := new(strings.Builder) +- _, err = io.Copy(buf, reader) +- Expect(err).Should(Succeed()) +- Expect(buf.String()).Should(Equal("line.one\nline.two")) +- }) +- }) +- When("Server returns NOT_FOUND (404)", func() { +- BeforeEach(func() { +- server = httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { +- rw.WriteHeader(http.StatusNotFound) +- })) +- DeferCleanup(server.Close) +- +- sutConfig.Attempts = 3 +- }) +- It("Should return error", func() { +- reader, err := sut.DownloadFile(server.URL) +- +- Expect(err).Should(HaveOccurred()) +- Expect(reader).Should(BeNil()) +- Expect(err.Error()).Should(Equal("got status code 404")) +- Expect(failedDownloadCountEvtChannel).Should(HaveLen(3)) +- Expect(failedDownloadCountEvtChannel).Should(Receive(Equal(server.URL))) +- }) +- }) +- When("Wrong URL is defined", func() { +- BeforeEach(func() { +- sutConfig.Attempts = 1 +- }) +- It("Should return error", func() { +- _, err := sut.DownloadFile("somewrongurl") +- +- Expect(err).Should(HaveOccurred()) +- Expect(loggerHook.LastEntry().Message).Should(ContainSubstring("Can't download file: ")) +- // failed download event was emitted only once +- Expect(failedDownloadCountEvtChannel).Should(HaveLen(1)) +- Expect(failedDownloadCountEvtChannel).Should(Receive(Equal("somewrongurl"))) +- }) +- }) +- +- When("If timeout occurs on first request", func() { +- var attempt uint64 = 1 +- +- BeforeEach(func() { +- sutConfig = config.DownloaderConfig{ +- Timeout: config.Duration(20 * time.Millisecond), +- Attempts: 3, +- Cooldown: config.Duration(time.Millisecond), +- } +- +- // should produce a timeout on first attempt +- server = httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { +- a := atomic.LoadUint64(&attempt) +- atomic.AddUint64(&attempt, 1) +- if a == 1 { +- time.Sleep(500 * time.Millisecond) +- } else { +- _, err := rw.Write([]byte("blocked1.com")) +- Expect(err).Should(Succeed()) +- } +- })) +- DeferCleanup(server.Close) +- }) +- It("Should perform a retry and return file content", func() { +- reader, err := sut.DownloadFile(server.URL) +- Expect(err).Should(Succeed()) +- Expect(reader).Should(Not(BeNil())) +- DeferCleanup(reader.Close) +- +- buf := new(strings.Builder) +- _, err = io.Copy(buf, reader) +- Expect(err).Should(Succeed()) +- Expect(buf.String()).Should(Equal("blocked1.com")) +- +- // failed download event was emitted only once +- Expect(failedDownloadCountEvtChannel).Should(HaveLen(1)) +- Expect(failedDownloadCountEvtChannel).Should(Receive(Equal(server.URL))) +- Expect(loggerHook.LastEntry().Message).Should(ContainSubstring("Temporary network err / Timeout occurred: ")) +- }) +- }) +- When("If timeout occurs on all request", func() { +- BeforeEach(func() { +- sutConfig = config.DownloaderConfig{ +- Timeout: config.Duration(10 * time.Millisecond), +- Attempts: 3, +- Cooldown: config.Duration(time.Millisecond), +- } +- +- // should always produce a timeout +- server = httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { +- time.Sleep(20 * time.Millisecond) +- })) +- DeferCleanup(server.Close) +- }) +- It("Should perform a retry until max retry attempt count is reached and return TransientError", func() { +- reader, err := sut.DownloadFile(server.URL) +- Expect(err).Should(HaveOccurred()) +- Expect(errors.As(err, new(*TransientError))).Should(BeTrue()) +- Expect(err.Error()).Should(ContainSubstring("Timeout")) +- Expect(reader).Should(BeNil()) +- +- // failed download event was emitted 3 times +- Expect(failedDownloadCountEvtChannel).Should(HaveLen(3)) +- Expect(failedDownloadCountEvtChannel).Should(Receive(Equal(server.URL))) +- }) +- }) +- When("DNS resolution of passed URL fails", func() { +- BeforeEach(func() { +- sutConfig = config.DownloaderConfig{ +- Timeout: config.Duration(500 * time.Millisecond), +- Attempts: 3, +- Cooldown: 200 * config.Duration(time.Millisecond), +- } +- }) +- It("Should perform a retry until max retry attempt count is reached and return DNSError", func() { +- reader, err := sut.DownloadFile("http://some.domain.which.does.not.exist") +- Expect(err).Should(HaveOccurred()) +- +- var dnsError *net.DNSError +- Expect(errors.As(err, &dnsError)).Should(BeTrue(), "received error %w", err) +- Expect(reader).Should(BeNil()) +- +- // failed download event was emitted 3 times +- Expect(failedDownloadCountEvtChannel).Should(HaveLen(3)) +- Expect(failedDownloadCountEvtChannel).Should(Receive(Equal("http://some.domain.which.does.not.exist"))) +- Expect(loggerHook.LastEntry().Message).Should(ContainSubstring("Name resolution err: ")) +- }) +- }) +- }) +-}) +diff --git a/lists/list_cache_benchmark_test.go b/lists/list_cache_benchmark_test.go +deleted file mode 100644 +index fedf2fd..0000000 +--- a/lists/list_cache_benchmark_test.go ++++ /dev/null +@@ -1,29 +0,0 @@ +-package lists +- +-import ( +- "testing" +- +- "github.com/0xERR0R/blocky/config" +-) +- +-func BenchmarkRefresh(b *testing.B) { +- file1, _ := createTestListFile(b.TempDir(), 100000) +- file2, _ := createTestListFile(b.TempDir(), 150000) +- file3, _ := createTestListFile(b.TempDir(), 130000) +- lists := map[string][]config.BytesSource{ +- "gr1": config.NewBytesSources(file1, file2, file3), +- } +- +- cfg := config.SourceLoadingConfig{ +- Concurrency: 5, +- RefreshPeriod: config.Duration(-1), +- } +- downloader := NewDownloader(config.DownloaderConfig{}, nil) +- cache, _ := NewListCache(ListCacheTypeBlacklist, cfg, lists, downloader) +- +- b.ReportAllocs() +- +- for n := 0; n < b.N; n++ { +- cache.Refresh() +- } +-} +diff --git a/lists/list_cache_test.go b/lists/list_cache_test.go +deleted file mode 100644 +index 2d08cfb..0000000 +--- a/lists/list_cache_test.go ++++ /dev/null +@@ -1,496 +0,0 @@ +-package lists +- +-import ( +- "bufio" +- "context" +- "errors" +- "fmt" +- "io" +- "math/rand" +- "net/http/httptest" +- "os" +- "strings" +- +- "github.com/0xERR0R/blocky/config" +- . "github.com/0xERR0R/blocky/evt" +- "github.com/0xERR0R/blocky/lists/parsers" +- "github.com/0xERR0R/blocky/log" +- "github.com/0xERR0R/blocky/util" +- "github.com/sirupsen/logrus" +- +- . "github.com/0xERR0R/blocky/helpertest" +- . "github.com/onsi/ginkgo/v2" +- . "github.com/onsi/gomega" +-) +- +-var _ = Describe("ListCache", func() { +- var ( +- tmpDir *TmpFolder +- emptyFile, file1, file2, file3 *TmpFile +- server1, server2, server3 *httptest.Server +- +- sut *ListCache +- sutConfig config.SourceLoadingConfig +- +- listCacheType ListCacheType +- lists map[string][]config.BytesSource +- downloader FileDownloader +- mockDownloader *MockDownloader +- ) +- +- BeforeEach(func() { +- var err error +- +- listCacheType = ListCacheTypeBlacklist +- +- sutConfig, err = config.WithDefaults[config.SourceLoadingConfig]() +- Expect(err).Should(Succeed()) +- +- sutConfig.RefreshPeriod = -1 +- +- downloader = NewDownloader(config.DownloaderConfig{}, nil) +- mockDownloader = nil +- +- server1 = TestServer("blocked1.com\nblocked1a.com\n192.168.178.55") +- DeferCleanup(server1.Close) +- server2 = TestServer("blocked2.com") +- DeferCleanup(server2.Close) +- server3 = TestServer("blocked3.com\nblocked1a.com") +- DeferCleanup(server3.Close) +- +- tmpDir = NewTmpFolder("ListCache") +- Expect(tmpDir.Error).Should(Succeed()) +- DeferCleanup(tmpDir.Clean) +- +- emptyFile = tmpDir.CreateStringFile("empty", "#empty file") +- Expect(emptyFile.Error).Should(Succeed()) +- +- emptyFile = tmpDir.CreateStringFile("empty", "#empty file") +- Expect(emptyFile.Error).Should(Succeed()) +- file1 = tmpDir.CreateStringFile("file1", "blocked1.com", "blocked1a.com") +- Expect(file1.Error).Should(Succeed()) +- file2 = tmpDir.CreateStringFile("file2", "blocked2.com") +- Expect(file2.Error).Should(Succeed()) +- file3 = tmpDir.CreateStringFile("file3", "blocked3.com", "blocked1a.com") +- Expect(file3.Error).Should(Succeed()) +- }) +- +- JustBeforeEach(func() { +- var err error +- +- Expect(lists).ShouldNot(BeNil(), "bad test: forgot to set `lists`") +- +- if mockDownloader != nil { +- downloader = mockDownloader +- } +- +- sut, err = NewListCache(listCacheType, sutConfig, lists, downloader) +- Expect(err).Should(Succeed()) +- }) +- +- Describe("List cache and matching", func() { +- When("List is empty", func() { +- BeforeEach(func() { +- lists = map[string][]config.BytesSource{ +- "gr0": config.NewBytesSources(emptyFile.Path), +- } +- }) +- +- When("Query with empty", func() { +- It("should not panic", func() { +- group := sut.Match("", []string{"gr0"}) +- Expect(group).Should(BeEmpty()) +- }) +- }) +- +- It("should not match anything", func() { +- group := sut.Match("google.com", []string{"gr1"}) +- Expect(group).Should(BeEmpty()) +- }) +- }) +- When("List becomes empty on refresh", func() { +- BeforeEach(func() { +- mockDownloader = newMockDownloader(func(res chan<- string, err chan<- error) { +- res <- "blocked1.com" +- res <- "# nothing" +- }) +- +- lists = map[string][]config.BytesSource{ +- "gr1": {mockDownloader.ListSource()}, +- } +- }) +- +- It("should delete existing elements from group cache", func(ctx context.Context) { +- group := sut.Match("blocked1.com", []string{"gr1"}) +- Expect(group).Should(ContainElement("gr1")) +- +- err := sut.refresh(ctx) +- Expect(err).Should(Succeed()) +- +- group = sut.Match("blocked1.com", []string{"gr1"}) +- Expect(group).Should(BeEmpty()) +- }) +- }) +- When("List has invalid lines", func() { +- BeforeEach(func() { +- lists = map[string][]config.BytesSource{ +- "gr1": { +- config.TextBytesSource( +- "inlinedomain1.com", +- "invaliddomain!", +- "inlinedomain2.com", +- ), +- }, +- } +- }) +- +- It("should still other domains", func() { +- group := sut.Match("inlinedomain1.com", []string{"gr1"}) +- Expect(group).Should(ContainElement("gr1")) +- +- group = sut.Match("inlinedomain2.com", []string{"gr1"}) +- Expect(group).Should(ContainElement("gr1")) +- }) +- }) +- When("a temporary/transient err occurs on download", func() { +- BeforeEach(func() { +- // should produce a transient error on second and third attempt +- mockDownloader = newMockDownloader(func(res chan<- string, err chan<- error) { +- res <- "blocked1.com\nblocked2.com\n" +- err <- &TransientError{inner: errors.New("boom")} +- err <- &TransientError{inner: errors.New("boom")} +- }) +- +- lists = map[string][]config.BytesSource{ +- "gr1": {mockDownloader.ListSource()}, +- } +- }) +- +- It("should not delete existing elements from group cache", func(ctx context.Context) { +- By("Lists loaded without timeout", func() { +- Eventually(func(g Gomega) { +- group := sut.Match("blocked1.com", []string{"gr1"}) +- g.Expect(group).Should(ContainElement("gr1")) +- }, "1s").Should(Succeed()) +- }) +- +- Expect(sut.refresh(ctx)).Should(HaveOccurred()) +- +- By("List couldn't be loaded due to timeout", func() { +- group := sut.Match("blocked1.com", []string{"gr1"}) +- Expect(group).Should(ContainElement("gr1")) +- }) +- +- sut.Refresh() +- +- By("List couldn't be loaded due to timeout", func() { +- group := sut.Match("blocked1.com", []string{"gr1"}) +- Expect(group).Should(ContainElement("gr1")) +- }) +- }) +- }) +- When("non transient err occurs on download", func() { +- BeforeEach(func() { +- // should produce a non transient error on second attempt +- mockDownloader = newMockDownloader(func(res chan<- string, err chan<- error) { +- res <- "blocked1.com" +- err <- errors.New("boom") +- }) +- +- lists = map[string][]config.BytesSource{ +- "gr1": {mockDownloader.ListSource()}, +- } +- }) +- +- It("should keep existing elements from group cache", func(ctx context.Context) { +- By("Lists loaded without err", func() { +- group := sut.Match("blocked1.com", []string{"gr1"}) +- Expect(group).Should(ContainElement("gr1")) +- }) +- +- Expect(sut.refresh(ctx)).Should(HaveOccurred()) +- +- By("Lists from first load is kept", func() { +- group := sut.Match("blocked1.com", []string{"gr1"}) +- Expect(group).Should(ContainElement("gr1")) +- }) +- }) +- }) +- When("Configuration has 3 external working urls", func() { +- BeforeEach(func() { +- lists = map[string][]config.BytesSource{ +- "gr1": config.NewBytesSources(server1.URL, server2.URL), +- "gr2": config.NewBytesSources(server3.URL), +- } +- }) +- +- It("should download the list and match against", func() { +- group := sut.Match("blocked1.com", []string{"gr1", "gr2"}) +- Expect(group).Should(ContainElement("gr1")) +- +- group = sut.Match("blocked1a.com", []string{"gr1", "gr2"}) +- Expect(group).Should(ContainElement("gr1")) +- +- group = sut.Match("blocked1a.com", []string{"gr2"}) +- Expect(group).Should(ContainElement("gr2")) +- }) +- }) +- When("Configuration has some faulty urls", func() { +- BeforeEach(func() { +- lists = map[string][]config.BytesSource{ +- "gr1": config.NewBytesSources(server1.URL, server2.URL, "doesnotexist"), +- "gr2": config.NewBytesSources(server3.URL, "someotherfile"), +- } +- }) +- +- It("should download the list and match against", func() { +- group := sut.Match("blocked1.com", []string{"gr1", "gr2"}) +- Expect(group).Should(ContainElement("gr1")) +- +- group = sut.Match("blocked1a.com", []string{"gr1", "gr2"}) +- Expect(group).Should(ContainElements("gr1", "gr2")) +- +- group = sut.Match("blocked1a.com", []string{"gr2"}) +- Expect(group).Should(ContainElement("gr2")) +- }) +- }) +- When("List will be updated", func() { +- resultCnt := 0 +- +- BeforeEach(func() { +- lists = map[string][]config.BytesSource{ +- "gr1": config.NewBytesSources(server1.URL), +- } +- +- _ = Bus().SubscribeOnce(BlockingCacheGroupChanged, func(listType ListCacheType, group string, cnt int) { +- resultCnt = cnt +- }) +- }) +- +- It("event should be fired and contain count of elements in downloaded lists", func() { +- group := sut.Match("blocked1.com", []string{}) +- Expect(group).Should(BeEmpty()) +- Expect(resultCnt).Should(Equal(3)) +- }) +- }) +- When("multiple groups are passed", func() { +- BeforeEach(func() { +- lists = map[string][]config.BytesSource{ +- "gr1": config.NewBytesSources(file1.Path, file2.Path), +- "gr2": config.NewBytesSources("file://" + file3.Path), +- } +- }) +- +- It("should match", func() { +- Expect(sut.groupedCache.ElementCount("gr1")).Should(Equal(3)) +- Expect(sut.groupedCache.ElementCount("gr2")).Should(Equal(2)) +- +- group := sut.Match("blocked1.com", []string{"gr1", "gr2"}) +- Expect(group).Should(ContainElement("gr1")) +- +- group = sut.Match("blocked1a.com", []string{"gr1", "gr2"}) +- Expect(group).Should(ContainElement("gr1")) +- +- group = sut.Match("blocked1a.com", []string{"gr2"}) +- Expect(group).Should(ContainElement("gr2")) +- }) +- }) +- When("group with bigger files", func() { +- It("should match", func() { +- file1, lines1 := createTestListFile(GinkgoT().TempDir(), 10000) +- file2, lines2 := createTestListFile(GinkgoT().TempDir(), 15000) +- file3, lines3 := createTestListFile(GinkgoT().TempDir(), 13000) +- lists := map[string][]config.BytesSource{ +- "gr1": config.NewBytesSources(file1, file2, file3), +- } +- +- sut, err := NewListCache(ListCacheTypeBlacklist, sutConfig, lists, downloader) +- Expect(err).Should(Succeed()) +- +- Expect(sut.groupedCache.ElementCount("gr1")).Should(Equal(lines1 + lines2 + lines3)) +- }) +- }) +- When("inline list content is defined", func() { +- BeforeEach(func() { +- lists = map[string][]config.BytesSource{ +- "gr1": {config.TextBytesSource( +- "inlinedomain1.com", +- "#some comment", +- "inlinedomain2.com", +- )}, +- } +- }) +- +- It("should match", func() { +- Expect(sut.groupedCache.ElementCount("gr1")).Should(Equal(2)) +- group := sut.Match("inlinedomain1.com", []string{"gr1"}) +- Expect(group).Should(ContainElement("gr1")) +- +- group = sut.Match("inlinedomain2.com", []string{"gr1"}) +- Expect(group).Should(ContainElement("gr1")) +- }) +- }) +- When("Text file can't be parsed", func() { +- BeforeEach(func() { +- lists = map[string][]config.BytesSource{ +- "gr1": { +- config.TextBytesSource( +- "inlinedomain1.com", +- "lineTooLong"+strings.Repeat("x", bufio.MaxScanTokenSize), // too long +- ), +- }, +- } +- }) +- +- It("should still match already imported strings", func() { +- group := sut.Match("inlinedomain1.com", []string{"gr1"}) +- Expect(group).Should(ContainElement("gr1")) +- }) +- }) +- When("Text file has too many errors", func() { +- BeforeEach(func() { +- sutConfig.MaxErrorsPerSource = 0 +- sutConfig.Strategy = config.StartStrategyTypeFailOnError +- }) +- It("should fail parsing", func() { +- lists := map[string][]config.BytesSource{ +- "gr1": { +- config.TextBytesSource("invaliddomain!"), // too many errors since `maxErrorsPerSource` is 0 +- }, +- } +- +- _, err := NewListCache(ListCacheTypeBlacklist, sutConfig, lists, downloader) +- Expect(err).ShouldNot(Succeed()) +- Expect(err).Should(MatchError(parsers.ErrTooManyErrors)) +- }) +- }) +- When("file has end of line comment", func() { +- BeforeEach(func() { +- lists = map[string][]config.BytesSource{ +- "gr1": {config.TextBytesSource("inlinedomain1.com#a comment")}, +- } +- }) +- +- It("should still parse the domain", func() { +- group := sut.Match("inlinedomain1.com", []string{"gr1"}) +- Expect(group).Should(ContainElement("gr1")) +- }) +- }) +- When("inline regex content is defined", func() { +- BeforeEach(func() { +- lists = map[string][]config.BytesSource{ +- "gr1": {config.TextBytesSource("/^apple\\.(de|com)$/")}, +- } +- }) +- +- It("should match", func() { +- group := sut.Match("apple.com", []string{"gr1"}) +- Expect(group).Should(ContainElement("gr1")) +- +- group = sut.Match("apple.de", []string{"gr1"}) +- Expect(group).Should(ContainElement("gr1")) +- }) +- }) +- }) +- Describe("LogConfig", func() { +- var ( +- logger *logrus.Entry +- hook *log.MockLoggerHook +- ) +- +- BeforeEach(func() { +- logger, hook = log.NewMockEntry() +- }) +- +- It("should print list configuration", func() { +- lists := map[string][]config.BytesSource{ +- "gr1": config.NewBytesSources(server1.URL, server2.URL), +- "gr2": {config.TextBytesSource("inline", "definition")}, +- } +- +- sut, err := NewListCache(ListCacheTypeBlacklist, sutConfig, lists, downloader) +- Expect(err).Should(Succeed()) +- +- sut.LogConfig(logger) +- Expect(hook.Calls).ShouldNot(BeEmpty()) +- Expect(hook.Messages).Should(ContainElement(ContainSubstring("gr1:"))) +- Expect(hook.Messages).Should(ContainElement(ContainSubstring("gr2:"))) +- Expect(hook.Messages).Should(ContainElement(ContainSubstring("TOTAL:"))) +- }) +- }) +- +- Describe("StartStrategy", func() { +- When("async load is enabled", func() { +- BeforeEach(func() { +- sutConfig.Strategy = config.StartStrategyTypeFast +- }) +- +- It("should never return an error", func() { +- lists := map[string][]config.BytesSource{ +- "gr1": config.NewBytesSources("doesnotexist"), +- } +- +- _, err := NewListCache(ListCacheTypeBlacklist, sutConfig, lists, downloader) +- Expect(err).Should(Succeed()) +- }) +- }) +- }) +-}) +- +-type MockDownloader struct { +- util.MockCallSequence[string] +-} +- +-func newMockDownloader(driver func(res chan<- string, err chan<- error)) *MockDownloader { +- return &MockDownloader{util.NewMockCallSequence(driver)} +-} +- +-func (m *MockDownloader) DownloadFile(_ string) (io.ReadCloser, error) { +- str, err := m.Call() +- if err != nil { +- return nil, err +- } +- +- return io.NopCloser(strings.NewReader(str)), nil +-} +- +-func (m *MockDownloader) ListSource() config.BytesSource { +- return config.BytesSource{ +- Type: config.BytesSourceTypeHttp, +- From: "http://mock-downloader", +- } +-} +- +-func createTestListFile(dir string, totalLines int) (string, int) { +- file, err := os.CreateTemp(dir, "blocky") +- if err != nil { +- log.Log().Fatal(err) +- } +- +- w := bufio.NewWriter(file) +- for i := 0; i < totalLines; i++ { +- fmt.Fprintln(w, RandStringBytes(8+rand.Intn(10))+".com") +- } +- w.Flush() +- +- return file.Name(), totalLines +-} +- +-const ( +- initCharpool = "abcdefghijklmnopqrstuvwxyz" +- contCharpool = initCharpool + "0123456789-" +-) +- +-func RandStringBytes(n int) string { +- b := make([]byte, n) +- +- pool := initCharpool +- +- for i := range b { +- b[i] = pool[rand.Intn(len(pool))] +- +- pool = contCharpool +- } +- +- return string(b) +-} +diff --git a/server/server_test.go b/server/server_test.go +deleted file mode 100644 +index 65b30bc..0000000 +--- a/server/server_test.go ++++ /dev/null +@@ -1,888 +0,0 @@ +-package server +- +-import ( +- "bytes" +- "encoding/base64" +- "encoding/json" +- "io" +- "net" +- "net/http" +- "strings" +- "sync/atomic" +- "time" +- +- "github.com/0xERR0R/blocky/api" +- "github.com/0xERR0R/blocky/config" +- . "github.com/0xERR0R/blocky/helpertest" +- . "github.com/0xERR0R/blocky/log" +- "github.com/0xERR0R/blocky/model" +- "github.com/0xERR0R/blocky/resolver" +- "github.com/0xERR0R/blocky/util" +- "github.com/creasty/defaults" +- . "github.com/onsi/ginkgo/v2" +- . "github.com/onsi/gomega" +- +- "github.com/miekg/dns" +-) +- +-var ( +- mockClientName atomic.Value +- sut *Server +- err error +-) +- +-var _ = BeforeSuite(func() { +- var upstreamGoogle, upstreamFritzbox, upstreamClient config.Upstream +- googleMockUpstream := resolver.NewMockUDPUpstreamServer().WithAnswerFn(func(request *dns.Msg) (response *dns.Msg) { +- if request.Question[0].Name == "error." { +- return nil +- } +- response, err := util.NewMsgWithAnswer( +- util.ExtractDomain(request.Question[0]), 123, A, "123.124.122.122", +- ) +- +- Expect(err).Should(Succeed()) +- +- return response +- }) +- DeferCleanup(googleMockUpstream.Close) +- +- fritzboxMockUpstream := resolver.NewMockUDPUpstreamServer().WithAnswerFn(func(request *dns.Msg) (response *dns.Msg) { +- response, err := util.NewMsgWithAnswer( +- util.ExtractDomain(request.Question[0]), 3600, A, "192.168.178.2", +- ) +- +- Expect(err).Should(Succeed()) +- +- return response +- }) +- DeferCleanup(fritzboxMockUpstream.Close) +- +- clientMockUpstream := resolver.NewMockUDPUpstreamServer().WithAnswerFn(func(request *dns.Msg) (response *dns.Msg) { +- var clientName string +- client := mockClientName.Load() +- +- if client != nil { +- clientName = mockClientName.Load().(string) +- } +- +- response, err := util.NewMsgWithAnswer( +- util.ExtractDomain(request.Question[0]), 3600, dns.Type(dns.TypePTR), clientName, +- ) +- +- Expect(err).Should(Succeed()) +- +- return response +- }) +- DeferCleanup(clientMockUpstream.Close) +- +- upstreamClient = clientMockUpstream.Start() +- upstreamFritzbox = fritzboxMockUpstream.Start() +- upstreamGoogle = googleMockUpstream.Start() +- +- tmpDir := NewTmpFolder("server") +- Expect(tmpDir.Error).Should(Succeed()) +- DeferCleanup(tmpDir.Clean) +- +- certPem := writeCertPem(tmpDir) +- Expect(certPem.Error).Should(Succeed()) +- +- keyPem := writeKeyPem(tmpDir) +- Expect(keyPem.Error).Should(Succeed()) +- +- doubleclickFile := tmpDir.CreateStringFile("doubleclick.net.txt", "doubleclick.net", "doubleclick.net.cn") +- Expect(doubleclickFile.Error).Should(Succeed()) +- +- bildFile := tmpDir.CreateStringFile("www.bild.de.txt", "www.bild.de") +- Expect(bildFile.Error).Should(Succeed()) +- +- heiseFile := tmpDir.CreateStringFile("heise.de.txt", "heise.de") +- Expect(heiseFile.Error).Should(Succeed()) +- +- youtubeFile := tmpDir.CreateStringFile("youtube.com.txt", "youtube.com") +- Expect(youtubeFile.Error).Should(Succeed()) +- +- // create server +- sut, err = NewServer(&config.Config{ +- CustomDNS: config.CustomDNSConfig{ +- CustomTTL: config.Duration(3600 * time.Second), +- Mapping: config.CustomDNSMapping{ +- HostIPs: map[string][]net.IP{ +- "custom.lan": {net.ParseIP("192.168.178.55")}, +- "lan.home": {net.ParseIP("192.168.178.56")}, +- }, +- }, +- }, +- Conditional: config.ConditionalUpstreamConfig{ +- Mapping: config.ConditionalUpstreamMapping{ +- Upstreams: map[string][]config.Upstream{ +- "net.cn": {upstreamClient}, +- "fritz.box": {upstreamFritzbox}, +- }, +- }, +- }, +- Blocking: config.BlockingConfig{ +- BlackLists: map[string][]config.BytesSource{ +- "ads": config.NewBytesSources( +- doubleclickFile.Path, +- bildFile.Path, +- heiseFile.Path, +- ), +- "youtube": config.NewBytesSources(youtubeFile.Path), +- }, +- WhiteLists: map[string][]config.BytesSource{ +- "ads": config.NewBytesSources(heiseFile.Path), +- "whitelist": config.NewBytesSources(heiseFile.Path), +- }, +- ClientGroupsBlock: map[string][]string{ +- "default": {"ads"}, +- "clWhitelistOnly": {"whitelist"}, +- "clAdsAndYoutube": {"ads", "youtube"}, +- "clYoutubeOnly": {"youtube"}, +- }, +- BlockType: "zeroIp", +- BlockTTL: config.Duration(6 * time.Hour), +- }, +- Upstreams: config.UpstreamsConfig{ +- Groups: map[string][]config.Upstream{"default": {upstreamGoogle}}, +- }, +- ClientLookup: config.ClientLookupConfig{ +- Upstream: upstreamClient, +- }, +- +- Ports: config.PortsConfig{ +- DNS: config.ListenConfig{"55555"}, +- TLS: config.ListenConfig{"8853"}, +- HTTP: config.ListenConfig{"4000"}, +- HTTPS: config.ListenConfig{"4443"}, +- }, +- CertFile: certPem.Path, +- KeyFile: keyPem.Path, +- Prometheus: config.MetricsConfig{ +- Enable: true, +- Path: "/metrics", +- }, +- }) +- +- Expect(err).Should(Succeed()) +- +- errChan := make(chan error, 10) +- +- // start server +- go func() { +- sut.Start(errChan) +- }() +- DeferCleanup(sut.Stop) +- +- Consistently(errChan, "1s").ShouldNot(Receive()) +-}) +- +-var _ = Describe("Running DNS server", func() { +- Describe("performing DNS request with running server", func() { +- BeforeEach(func() { +- mockClientName.Store("") +- // reset client cache +- res := sut.queryResolver +- for res != nil { +- if t, ok := res.(*resolver.ClientNamesResolver); ok { +- t.FlushCache() +- +- break +- } +- if c, ok := res.(resolver.ChainedResolver); ok { +- res = c.GetNext() +- } else { +- break +- } +- } +- }) +- +- Context("DNS query is resolvable via external DNS", func() { +- It("should return valid answer", func() { +- Expect(requestServer(util.NewMsgWithQuestion("google.de.", A))). +- Should( +- SatisfyAll( +- BeDNSRecord("google.de.", A, "123.124.122.122"), +- HaveTTL(BeNumerically("==", 123)), +- )) +- }) +- }) +- Context("Custom DNS entry with exact match", func() { +- It("should return valid answer", func() { +- Expect(requestServer(util.NewMsgWithQuestion("custom.lan.", A))). +- Should( +- SatisfyAll( +- BeDNSRecord("custom.lan.", A, "192.168.178.55"), +- HaveTTL(BeNumerically("==", 3600)), +- )) +- }) +- }) +- Context("Custom DNS entry with sub domain", func() { +- It("should return valid answer", func() { +- Expect(requestServer(util.NewMsgWithQuestion("host.lan.home.", A))). +- Should( +- SatisfyAll( +- BeDNSRecord("host.lan.home.", A, "192.168.178.56"), +- HaveTTL(BeNumerically("==", 3600)), +- )) +- }) +- }) +- Context("Conditional upstream", func() { +- It("should resolve query via conditional upstream resolver", func() { +- Expect(requestServer(util.NewMsgWithQuestion("host.fritz.box.", A))). +- Should( +- SatisfyAll( +- BeDNSRecord("host.fritz.box.", A, "192.168.178.2"), +- HaveTTL(BeNumerically("==", 3600)), +- )) +- }) +- }) +- Context("Conditional upstream blocking", func() { +- It("Query should be blocked, domain is in default group", func() { +- Expect(requestServer(util.NewMsgWithQuestion("doubleclick.net.cn.", A))). +- Should( +- SatisfyAll( +- BeDNSRecord("doubleclick.net.cn.", A, "0.0.0.0"), +- HaveTTL(BeNumerically("==", 21600)), +- )) +- }) +- }) +- Context("Blocking default group", func() { +- It("Query should be blocked, domain is in default group", func() { +- Expect(requestServer(util.NewMsgWithQuestion("doubleclick.net.", A))). +- Should( +- SatisfyAll( +- BeDNSRecord("doubleclick.net.", A, "0.0.0.0"), +- HaveTTL(BeNumerically("==", 21600)), +- )) +- }) +- }) +- Context("Blocking default group with sub domain", func() { +- It("Query with subdomain should be blocked, domain is in default group", func() { +- Expect(requestServer(util.NewMsgWithQuestion("www.bild.de.", A))). +- Should( +- SatisfyAll( +- BeDNSRecord("www.bild.de.", A, "0.0.0.0"), +- HaveTTL(BeNumerically("==", 21600)), +- )) +- }) +- }) +- Context("no blocking default group with sub domain", func() { +- It("Query with should not be blocked, sub domain is not in blacklist", func() { +- Expect(requestServer(util.NewMsgWithQuestion("bild.de.", A))). +- Should( +- SatisfyAll( +- BeDNSRecord("bild.de.", A, "123.124.122.122"), +- HaveTTL(BeNumerically("<=", 123)), +- )) +- }) +- }) +- Context("domain is on white and blacklist default group", func() { +- It("Query with should not be blocked, domain is on white and blacklist", func() { +- Expect(requestServer(util.NewMsgWithQuestion("heise.de.", A))). +- Should( +- SatisfyAll( +- BeDNSRecord("heise.de.", A, "123.124.122.122"), +- HaveTTL(BeNumerically("<=", 123)), +- )) +- }) +- }) +- Context("domain is on client specific white list", func() { +- It("Query with should not be blocked, domain is on client's white list", func() { +- mockClientName.Store("clWhitelistOnly") +- Expect(requestServer(util.NewMsgWithQuestion("heise.de.", A))). +- Should( +- SatisfyAll( +- BeDNSRecord("heise.de.", A, "123.124.122.122"), +- HaveTTL(BeNumerically("<=", 123)), +- )) +- }) +- }) +- Context("block client whitelist only", func() { +- It("Query with should be blocked, client has only whitelist, domain is not on client's white list", func() { +- mockClientName.Store("clWhitelistOnly") +- Expect(requestServer(util.NewMsgWithQuestion("google.de.", A))). +- Should( +- SatisfyAll( +- BeDNSRecord("google.de.", A, "0.0.0.0"), +- HaveTTL(BeNumerically("==", 21600)), +- )) +- }) +- }) +- Context("block client with 2 groups", func() { +- It("Query with should be blocked, domain is on black list", func() { +- mockClientName.Store("clAdsAndYoutube") +- +- Expect(requestServer(util.NewMsgWithQuestion("www.bild.de.", A))). +- Should( +- SatisfyAll( +- BeDNSRecord("www.bild.de.", A, "0.0.0.0"), +- HaveTTL(BeNumerically("==", 21600)), +- )) +- +- Expect(requestServer(util.NewMsgWithQuestion("youtube.com.", A))). +- Should( +- SatisfyAll( +- BeDNSRecord("youtube.com.", A, "0.0.0.0"), +- HaveTTL(BeNumerically("==", 21600)), +- )) +- }) +- }) +- Context("client with 1 group: no block if domain in other group", func() { +- It("Query with should not be blocked, domain is on black list in another group", func() { +- mockClientName.Store("clYoutubeOnly") +- +- Expect(requestServer(util.NewMsgWithQuestion("www.bild.de.", A))). +- Should( +- SatisfyAll( +- BeDNSRecord("www.bild.de.", A, "123.124.122.122"), +- HaveTTL(BeNumerically("<=", 123)), +- )) +- }) +- }) +- Context("block client with 1 group", func() { +- It("Query with should not blocked, domain is on black list in client's group", func() { +- mockClientName.Store("clYoutubeOnly") +- +- Expect(requestServer(util.NewMsgWithQuestion("youtube.com.", A))). +- Should( +- SatisfyAll( +- BeDNSRecord("youtube.com.", A, "0.0.0.0"), +- HaveTTL(BeNumerically("==", 21600)), +- )) +- }) +- }) +- Context("health check", func() { +- It("Should always return dummy response", func() { +- resp := requestServer(util.NewMsgWithQuestion("healthcheck.blocky.", A)) +- +- Expect(resp.Answer).Should(BeEmpty()) +- }) +- }) +- }) +- +- Describe("Prometheus endpoint", func() { +- When("Prometheus URL is called", func() { +- It("should return prometheus data", func() { +- resp, err := http.Get("http://localhost:4000/metrics") +- Expect(err).Should(Succeed()) +- Expect(resp).Should(HaveHTTPStatus(http.StatusOK)) +- }) +- }) +- }) +- Describe("Root endpoint", func() { +- When("Root URL is called", func() { +- It("should return root page", func() { +- resp, err := http.Get("http://localhost:4000/") +- Expect(err).Should(Succeed()) +- Expect(resp).Should( +- SatisfyAll( +- HaveHTTPStatus(http.StatusOK), +- HaveHTTPHeaderWithValue("Content-type", "text/html; charset=UTF-8"), +- )) +- }) +- }) +- }) +- +- Describe("Query Rest API", func() { +- When("Query API is called", func() { +- It("Should process the query", func() { +- req := api.QueryRequest{ +- Query: "google.de", +- Type: "A", +- } +- jsonValue, err := json.Marshal(req) +- Expect(err).Should(Succeed()) +- +- resp, err := http.Post("http://localhost:4000/api/query", "application/json", bytes.NewBuffer(jsonValue)) +- +- Expect(err).Should(Succeed()) +- defer resp.Body.Close() +- +- Expect(resp).Should( +- SatisfyAll( +- HaveHTTPStatus(http.StatusOK), +- HaveHTTPHeaderWithValue("Content-type", "application/json"), +- )) +- +- var result api.QueryResult +- err = json.NewDecoder(resp.Body).Decode(&result) +- Expect(err).Should(Succeed()) +- Expect(result.Response).Should(Equal("A (123.124.122.122)")) +- }) +- }) +- When("Wrong request type is used", func() { +- It("Should return internal error", func() { +- req := api.QueryRequest{ +- Query: "google.de", +- Type: "WrongType", +- } +- jsonValue, err := json.Marshal(req) +- Expect(err).Should(Succeed()) +- +- resp, err := http.Post("http://localhost:4000/api/query", "application/json", bytes.NewBuffer(jsonValue)) +- +- Expect(err).Should(Succeed()) +- DeferCleanup(resp.Body.Close) +- +- Expect(resp.StatusCode).Should(Equal(http.StatusInternalServerError)) +- }) +- }) +- When("Internal error occurs", func() { +- It("Should return internal error", func() { +- req := api.QueryRequest{ +- Query: "error.", +- Type: "A", +- } +- jsonValue, err := json.Marshal(req) +- Expect(err).Should(Succeed()) +- +- resp, err := http.Post("http://localhost:4000/api/query", "application/json", bytes.NewBuffer(jsonValue)) +- Expect(err).Should(Succeed()) +- DeferCleanup(resp.Body.Close) +- Expect(resp.StatusCode).Should(Equal(http.StatusInternalServerError)) +- }) +- }) +- When("Request is malformed", func() { +- It("Should return internal error", func() { +- jsonValue := []byte("") +- +- resp, err := http.Post("http://localhost:4000/api/query", "application/json", bytes.NewBuffer(jsonValue)) +- +- Expect(err).Should(Succeed()) +- DeferCleanup(resp.Body.Close) +- +- Expect(resp.StatusCode).Should(Equal(http.StatusInternalServerError)) +- }) +- }) +- }) +- +- Describe("DOH endpoint", func() { +- Context("DOH over GET (RFC 8484)", func() { +- When("DOH get request with 'example.com' is performed", func() { +- It("should get a valid response", func() { +- resp, err := http.Get("http://localhost:4000/dns-query?dns=AAABAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB") +- Expect(err).Should(Succeed()) +- DeferCleanup(resp.Body.Close) +- +- Expect(resp).Should(HaveHTTPStatus(http.StatusOK)) +- Expect(resp).Should(HaveHTTPHeaderWithValue("Content-type", "application/dns-message")) +- +- rawMsg, err := io.ReadAll(resp.Body) +- Expect(err).Should(Succeed()) +- +- msg := new(dns.Msg) +- err = msg.Unpack(rawMsg) +- Expect(err).Should(Succeed()) +- +- Expect(msg.Answer).Should(BeDNSRecord("www.example.com.", A, "123.124.122.122")) +- }) +- }) +- When("Request does not contain a valid DNS message", func() { +- It("should return 'Bad Request'", func() { +- resp, err := http.Get("http://localhost:4000/dns-query?dns=xxxx") +- Expect(err).Should(Succeed()) +- DeferCleanup(resp.Body.Close) +- +- Expect(resp).Should(HaveHTTPStatus(http.StatusBadRequest)) +- }) +- }) +- When("Request's parameter does not contain a valid base64'", func() { +- It("should return 'Bad Request'", func() { +- resp, err := http.Get("http://localhost:4000/dns-query?dns=äöä") +- Expect(err).Should(Succeed()) +- DeferCleanup(resp.Body.Close) +- +- Expect(resp).Should(HaveHTTPStatus(http.StatusBadRequest)) +- }) +- }) +- When("Request does not contain a dns parameter", func() { +- It("should return 'Bad Request'", func() { +- resp, err := http.Get("http://localhost:4000/dns-query?test") +- Expect(err).Should(Succeed()) +- DeferCleanup(resp.Body.Close) +- +- Expect(resp).Should(HaveHTTPStatus(http.StatusBadRequest)) +- }) +- }) +- When("Request's dns parameter is too long'", func() { +- It("should return 'URI Too Long'", func() { +- longBase64msg := base64.StdEncoding.EncodeToString([]byte(strings.Repeat("t", 513))) +- +- resp, err := http.Get("http://localhost:4000/dns-query?dns=" + longBase64msg) +- Expect(err).Should(Succeed()) +- DeferCleanup(resp.Body.Close) +- +- Expect(resp).Should(HaveHTTPStatus(http.StatusRequestURITooLong)) +- }) +- }) +- }) +- Context("DOH over POST (RFC 8484)", func() { +- When("DOH post request with 'example.com' is performed", func() { +- It("should get a valid response", func() { +- msg := util.NewMsgWithQuestion("www.example.com.", A) +- rawDNSMessage, err := msg.Pack() +- Expect(err).Should(Succeed()) +- +- resp, err := http.Post("http://localhost:4000/dns-query", +- "application/dns-message", bytes.NewReader(rawDNSMessage)) +- Expect(err).Should(Succeed()) +- DeferCleanup(resp.Body.Close) +- +- Expect(resp).Should( +- SatisfyAll( +- HaveHTTPStatus(http.StatusOK), +- HaveHTTPHeaderWithValue("Content-type", "application/dns-message"), +- )) +- +- rawMsg, err := io.ReadAll(resp.Body) +- Expect(err).Should(Succeed()) +- +- msg = new(dns.Msg) +- err = msg.Unpack(rawMsg) +- Expect(err).Should(Succeed()) +- +- Expect(msg.Answer).Should(BeDNSRecord("www.example.com.", A, "123.124.122.122")) +- }) +- It("should get a valid response, clientId is passed", func() { +- msg := util.NewMsgWithQuestion("www.example.com.", A) +- rawDNSMessage, err := msg.Pack() +- Expect(err).Should(Succeed()) +- +- resp, err := http.Post("http://localhost:4000/dns-query/client123", +- "application/dns-message", bytes.NewReader(rawDNSMessage)) +- Expect(err).Should(Succeed()) +- DeferCleanup(resp.Body.Close) +- +- Expect(resp).Should( +- SatisfyAll( +- HaveHTTPStatus(http.StatusOK), +- HaveHTTPHeaderWithValue("Content-type", "application/dns-message"), +- )) +- rawMsg, err := io.ReadAll(resp.Body) +- Expect(err).Should(Succeed()) +- +- msg = new(dns.Msg) +- err = msg.Unpack(rawMsg) +- Expect(err).Should(Succeed()) +- +- Expect(msg.Answer).Should(BeDNSRecord("www.example.com.", A, "123.124.122.122")) +- }) +- }) +- When("POST payload exceeds 512 bytes", func() { +- It("should return 'Payload Too Large'", func() { +- largeMessage := []byte(strings.Repeat("t", 513)) +- +- resp, err := http.Post("http://localhost:4000/dns-query", "application/dns-message", bytes.NewReader(largeMessage)) +- Expect(err).Should(Succeed()) +- DeferCleanup(resp.Body.Close) +- +- Expect(resp).Should(HaveHTTPStatus(http.StatusRequestEntityTooLarge)) +- }) +- }) +- When("Request has wrong type", func() { +- It("should return 'Unsupported Media Type'", func() { +- resp, err := http.Post("http://localhost:4000/dns-query", "application/text", bytes.NewReader([]byte("a"))) +- Expect(err).Should(Succeed()) +- DeferCleanup(resp.Body.Close) +- +- Expect(resp).Should(HaveHTTPStatus(http.StatusUnsupportedMediaType)) +- }) +- }) +- When("Internal error occurs", func() { +- It("should return 'Internal server error'", func() { +- msg := util.NewMsgWithQuestion("error.", A) +- rawDNSMessage, err := msg.Pack() +- Expect(err).Should(Succeed()) +- +- resp, err := http.Post("http://localhost:4000/dns-query", +- "application/dns-message", bytes.NewReader(rawDNSMessage)) +- Expect(err).Should(Succeed()) +- DeferCleanup(resp.Body.Close) +- +- Expect(resp).Should(HaveHTTPStatus(http.StatusInternalServerError)) +- }) +- }) +- }) +- }) +- +- Describe("Server create", func() { +- var ( +- cfg config.Config +- cErr error +- ) +- BeforeEach(func() { +- cErr = defaults.Set(&cfg) +- +- Expect(cErr).Should(Succeed()) +- +- cfg.Upstreams.Groups = map[string][]config.Upstream{ +- "default": {config.Upstream{Net: config.NetProtocolTcpUdp, Host: "1.1.1.1", Port: 53}}, +- } +- +- cfg.Redis.Address = "test-fail" +- }) +- When("Server is created", func() { +- It("is created without redis connection", func() { +- _, err := NewServer(&cfg) +- +- Expect(err).Should(Succeed()) +- }) +- It("can't be created if redis server is unavailable", func() { +- cfg.Redis.Required = true +- +- _, err := NewServer(&cfg) +- +- Expect(err).ShouldNot(Succeed()) +- }) +- }) +- }) +- +- Describe("Server start", Label("XX"), func() { +- When("Server start is called", func() { +- It("start was called 2 times, start should fail", func() { +- // create server +- server, err := NewServer(&config.Config{ +- Upstreams: config.UpstreamsConfig{ +- Groups: map[string][]config.Upstream{ +- "default": {config.Upstream{Net: config.NetProtocolTcpUdp, Host: "4.4.4.4", Port: 53}}, +- }, +- }, +- CustomDNS: config.CustomDNSConfig{ +- Mapping: config.CustomDNSMapping{ +- HostIPs: map[string][]net.IP{ +- "custom.lan": {net.ParseIP("192.168.178.55")}, +- "lan.home": {net.ParseIP("192.168.178.56")}, +- }, +- }, +- }, +- Blocking: config.BlockingConfig{BlockType: "zeroIp"}, +- Ports: config.PortsConfig{ +- DNS: config.ListenConfig{":55556"}, +- }, +- }) +- +- Expect(err).Should(Succeed()) +- +- errChan := make(chan error, 10) +- +- // start server +- go server.Start(errChan) +- +- DeferCleanup(server.Stop) +- +- Consistently(errChan, "1s").ShouldNot(Receive()) +- +- // start again -> should fail +- server.Start(errChan) +- +- Eventually(errChan).Should(Receive()) +- }) +- }) +- }) +- Describe("Server stop", func() { +- When("Stop is called", func() { +- It("stop was called 2 times, start should fail", func() { +- // create server +- server, err := NewServer(&config.Config{ +- Upstreams: config.UpstreamsConfig{ +- Groups: map[string][]config.Upstream{ +- "default": {config.Upstream{Net: config.NetProtocolTcpUdp, Host: "4.4.4.4", Port: 53}}, +- }, +- }, +- CustomDNS: config.CustomDNSConfig{ +- Mapping: config.CustomDNSMapping{ +- HostIPs: map[string][]net.IP{ +- "custom.lan": {net.ParseIP("192.168.178.55")}, +- "lan.home": {net.ParseIP("192.168.178.56")}, +- }, +- }, +- }, +- Blocking: config.BlockingConfig{BlockType: "zeroIp"}, +- Ports: config.PortsConfig{ +- DNS: config.ListenConfig{"127.0.0.1:55557"}, +- }, +- }) +- +- Expect(err).Should(Succeed()) +- +- errChan := make(chan error, 10) +- +- // start server +- go func() { +- server.Start(errChan) +- }() +- +- time.Sleep(100 * time.Millisecond) +- +- err = server.Stop() +- +- // stop server, should be ok +- Expect(err).Should(Succeed()) +- +- // stop again, should raise error +- err = server.Stop() +- +- Expect(err).Should(HaveOccurred()) +- }) +- }) +- }) +- +- Describe("NewServer with strict upstream strategy", func() { +- It("successfully returns upstream branches", func() { +- branches, err := createUpstreamBranches(&config.Config{ +- Upstreams: config.UpstreamsConfig{ +- Strategy: config.UpstreamStrategyStrict, +- Groups: config.UpstreamGroups{ +- "default": {{Host: "0.0.0.0"}}, +- }, +- }, +- }, +- nil) +- +- Expect(err).ToNot(HaveOccurred()) +- Expect(branches).ToNot(BeNil()) +- Expect(branches).To(HaveLen(1)) +- _ = branches["default"].(*resolver.StrictResolver) +- }) +- }) +- +- Describe("create query resolver", func() { +- When("some upstream returns error", func() { +- It("create query resolver should return error", func() { +- r, err := createQueryResolver(&config.Config{ +- StartVerifyUpstream: true, +- Upstreams: config.UpstreamsConfig{ +- Groups: config.UpstreamGroups{ +- "default": {{Host: "0.0.0.0"}}, +- }, +- }, +- }, +- nil, nil) +- +- Expect(err).To(HaveOccurred()) +- Expect(err).To(MatchError(ContainSubstring("creation of upstream branches failed: "))) +- Expect(r).To(BeNil()) +- }) +- }) +- }) +- +- Describe("resolve client IP", func() { +- Context("UDP address", func() { +- It("should correct resolve client IP", func() { +- ip, protocol := resolveClientIPAndProtocol(&net.UDPAddr{IP: net.ParseIP("192.168.178.88")}) +- Expect(ip).Should(Equal(net.ParseIP("192.168.178.88"))) +- Expect(protocol).Should(Equal(model.RequestProtocolUDP)) +- }) +- }) +- Context("TCP address", func() { +- It("should correct resolve client IP", func() { +- ip, protocol := resolveClientIPAndProtocol(&net.TCPAddr{IP: net.ParseIP("192.168.178.88")}) +- Expect(ip).Should(Equal(net.ParseIP("192.168.178.88"))) +- Expect(protocol).Should(Equal(model.RequestProtocolTCP)) +- }) +- }) +- }) +- +- Describe("self-signed certificate creation", func() { +- var ( +- cfg config.Config +- cErr error +- ) +- BeforeEach(func() { +- cErr = defaults.Set(&cfg) +- +- Expect(cErr).Should(Succeed()) +- +- cfg.Upstreams.Groups = map[string][]config.Upstream{ +- "default": {config.Upstream{Net: config.NetProtocolTcpUdp, Host: "1.1.1.1", Port: 53}}, +- } +- }) +- +- It("should create self-signed certificate if key/cert files are not provided", func() { +- cfg.KeyFile = "" +- cfg.CertFile = "" +- cfg.Ports = config.PortsConfig{ +- HTTPS: []string{":14443"}, +- } +- +- sut, err := NewServer(&cfg) +- Expect(err).Should(Succeed()) +- Expect(sut.cert.Certificate).ShouldNot(BeNil()) +- }) +- }) +-}) +- +-func requestServer(request *dns.Msg) *dns.Msg { +- conn, err := net.Dial("udp", ":55555") +- if err != nil { +- Log().Fatal("could not connect to server: ", err) +- } +- defer conn.Close() +- +- msg, err := request.Pack() +- if err != nil { +- Log().Fatal("can't pack request: ", err) +- } +- +- _, err = conn.Write(msg) +- if err != nil { +- Log().Fatal("can't send request to server: ", err) +- } +- +- out := make([]byte, 1024) +- +- if _, err := conn.Read(out); err == nil { +- response := new(dns.Msg) +- +- err = response.Unpack(out) +- +- if err != nil { +- Log().Fatal("can't unpack response: ", err) +- } +- +- return response +- } +- +- Log().Fatal("could not read from connection", err) +- +- return nil +-} +- +-func writeCertPem(tmpDir *TmpFolder) *TmpFile { +- return tmpDir.CreateStringFile("cert.pem", +- "-----BEGIN CERTIFICATE-----", +- "MIICMzCCAZygAwIBAgIRAJCCrDTGEtZfRpxDY1KAoswwDQYJKoZIhvcNAQELBQAw", +- "EjEQMA4GA1UEChMHQWNtZSBDbzAgFw03MDAxMDEwMDAwMDBaGA8yMDg0MDEyOTE2", +- "MDAwMFowEjEQMA4GA1UEChMHQWNtZSBDbzCBnzANBgkqhkiG9w0BAQEFAAOBjQAw", +- "gYkCgYEA4mEaF5yWYYrTfMgRXdBpgGnqsHIADQWlw7BIJWD/gNp+fgp4TUZ/7ggV", +- "rrvRORvRFjw14avd9L9EFP7XLi8ViU3uoE1UWI32MlrKqLbGNCXyUIApIoqlbRg6", +- "iErxIk5+ChzFuysQOx01S2yv/ML6dx7NOGHs1S38MUzRZtcXBH8CAwEAAaOBhjCB", +- "gzAOBgNVHQ8BAf8EBAMCAqQwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDwYDVR0TAQH/", +- "BAUwAwEB/zAdBgNVHQ4EFgQUslNI6tYIv909RttHaZVMS/u/VYYwLAYDVR0RBCUw", +- "I4IJbG9jYWxob3N0hwR/AAABhxAAAAAAAAAAAAAAAAAAAAABMA0GCSqGSIb3DQEB", +- "CwUAA4GBAJ2gRpQHr5Qj7dt26bYVMdN4JGXTsvjbVrJfKI0VfPGJ+SUY/uTVBUeX", +- "+Cwv4DFEPBlNx/lzuUkwmRaExC4/w81LWwxe5KltYsjyJuYowiUbLZ6tzLaQ9Bcx", +- "jxClAVvgj90TGYOwsv6ESOX7GWteN1FlD3+jk7vefjFagaKKFYR9", +- "-----END CERTIFICATE-----") +-} +- +-func writeKeyPem(tmpDir *TmpFolder) *TmpFile { +- return tmpDir.CreateStringFile("key.pem", +- "-----BEGIN PRIVATE KEY-----", +- "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAOJhGheclmGK03zI", +- "EV3QaYBp6rByAA0FpcOwSCVg/4Dafn4KeE1Gf+4IFa670Tkb0RY8NeGr3fS/RBT+", +- "1y4vFYlN7qBNVFiN9jJayqi2xjQl8lCAKSKKpW0YOohK8SJOfgocxbsrEDsdNUts", +- "r/zC+ncezThh7NUt/DFM0WbXFwR/AgMBAAECgYEA1exixstPhI+2+OTrHFc1S4dL", +- "oz+ncqbSlZEBLGl0KWTQQfVM5+FmRR7Yto1/0lLKDBQL6t0J2x3fjWOhHmCaHKZA", +- "VAvZ8+OKxwofih3hlO0tGCB8szUJygp2FAmd0rOUqvPQ+PTohZEUXyDaB8MOIbX+", +- "qoo7g19+VlbyKqmM8HkCQQDs4GQJwEn7GXKllSMyOfiYnjQM2pwsqO0GivXkH+p3", +- "+h5KDp4g3O4EbmbrvZyZB2euVsBjW3pFMu+xPXuOXf91AkEA9KfC7LGLD2OtLmrM", +- "iCZAqHlame+uEEDduDmqjTPnNKUWVeRtYKMF5Hltbeo1jMXMSbVZ+fRWKfQ+HAhQ", +- "xjFJowJAV6U7PqRoe0FSO1QwXrA2fHnk9nCY4qlqckZObyckAVqJhIteFPjKFNeo", +- "u0dAPxsPUOGGc/zwA9Sx/ZmrMuUy1QJBALl7bqawO/Ng6G0mfwZBqgeQaYYHVnnw", +- "E6iV353J2eHpvzNDSUFYlyEOhk4soIindSf0m9CK08Be8a+jBkocF+0CQQC+Hi7L", +- "kZV1slpW82BxYIhs9Gb0OQgK8SsI4aQPTFGUarQXXAm4eRqBO0kaG+jGX6TtW353", +- "EHK784GIxwVXKej/", +- "-----END PRIVATE KEY-----") +-} +diff --git a/resolver/hosts_file_resolver_test.go b/resolver/hosts_file_resolver_test.go +deleted file mode 100644 +index eef4591..0000000 +--- a/resolver/hosts_file_resolver_test.go ++++ /dev/null +@@ -1,376 +0,0 @@ +-package resolver +- +-import ( +- "context" +- "time" +- +- "github.com/0xERR0R/blocky/config" +- . "github.com/0xERR0R/blocky/helpertest" +- "github.com/0xERR0R/blocky/log" +- . "github.com/0xERR0R/blocky/model" +- "github.com/miekg/dns" +- . "github.com/onsi/ginkgo/v2" +- . "github.com/onsi/gomega" +- "github.com/stretchr/testify/mock" +-) +- +-var _ = Describe("HostsFileResolver", func() { +- var ( +- TTL = uint32(time.Now().Second()) +- +- sut *HostsFileResolver +- sutConfig config.HostsFileConfig +- m *mockResolver +- tmpDir *TmpFolder +- tmpFile *TmpFile +- ) +- +- Describe("Type", func() { +- It("follows conventions", func() { +- expectValidResolverType(sut) +- }) +- }) +- +- BeforeEach(func() { +- tmpDir = NewTmpFolder("HostsFileResolver") +- Expect(tmpDir.Error).Should(Succeed()) +- DeferCleanup(tmpDir.Clean) +- +- tmpFile = writeHostFile(tmpDir) +- Expect(tmpFile.Error).Should(Succeed()) +- +- sutConfig = config.HostsFileConfig{ +- Sources: config.NewBytesSources(tmpFile.Path), +- HostsTTL: config.Duration(time.Duration(TTL) * time.Second), +- FilterLoopback: true, +- Loading: config.SourceLoadingConfig{ +- RefreshPeriod: -1, +- MaxErrorsPerSource: 5, +- }, +- } +- }) +- +- JustBeforeEach(func() { +- var err error +- +- sut, err = NewHostsFileResolver(sutConfig, systemResolverBootstrap) +- Expect(err).Should(Succeed()) +- +- m = &mockResolver{} +- m.On("Resolve", mock.Anything).Return(&Response{Res: new(dns.Msg)}, nil) +- sut.Next(m) +- }) +- +- Describe("IsEnabled", func() { +- It("is true", func() { +- Expect(sut.IsEnabled()).Should(BeTrue()) +- }) +- }) +- +- Describe("LogConfig", func() { +- It("should log something", func() { +- logger, hook := log.NewMockEntry() +- +- sut.LogConfig(logger) +- +- Expect(hook.Calls).ShouldNot(BeEmpty()) +- }) +- }) +- +- Describe("Using hosts file", func() { +- When("Hosts file cannot be located", func() { +- BeforeEach(func() { +- sutConfig = config.HostsFileConfig{ +- Sources: config.NewBytesSources("/this/file/does/not/exist"), +- HostsTTL: config.Duration(time.Duration(TTL) * time.Second), +- } +- }) +- It("should not parse any hosts", func() { +- Expect(sut.cfg.Sources).ShouldNot(BeEmpty()) +- Expect(sut.hosts.v4.hosts).Should(BeEmpty()) +- Expect(sut.hosts.v6.hosts).Should(BeEmpty()) +- Expect(sut.hosts.v4.aliases).Should(BeEmpty()) +- Expect(sut.hosts.v6.aliases).Should(BeEmpty()) +- Expect(sut.hosts.isEmpty()).Should(BeTrue()) +- }) +- It("should go to next resolver on query", func() { +- Expect(sut.Resolve(newRequest("example.com.", A))). +- Should( +- SatisfyAll( +- HaveResponseType(ResponseTypeRESOLVED), +- HaveReturnCode(dns.RcodeSuccess), +- )) +- m.AssertExpectations(GinkgoT()) +- }) +- }) +- +- When("Hosts file is not set", func() { +- BeforeEach(func() { +- sutConfig.Deprecated.Filepath = new(config.BytesSource) +- sutConfig.Sources = nil +- +- m = &mockResolver{} +- m.On("Resolve", mock.Anything).Return(&Response{Res: new(dns.Msg)}, nil) +- sut.Next(m) +- }) +- It("should not return an error", func() { +- err := sut.loadSources(context.Background()) +- Expect(err).Should(Succeed()) +- }) +- It("should go to next resolver on query", func() { +- Expect(sut.Resolve(newRequest("example.com.", A))). +- Should( +- SatisfyAll( +- HaveResponseType(ResponseTypeRESOLVED), +- HaveReturnCode(dns.RcodeSuccess), +- )) +- m.AssertExpectations(GinkgoT()) +- }) +- }) +- +- When("Hosts file can be located", func() { +- It("should parse it successfully", func() { +- Expect(sut).ShouldNot(BeNil()) +- Expect(sut.hosts.v4.hosts).Should(HaveLen(5)) +- Expect(sut.hosts.v6.hosts).Should(HaveLen(2)) +- Expect(sut.hosts.v4.aliases).Should(HaveLen(4)) +- Expect(sut.hosts.v6.aliases).Should(HaveLen(2)) +- }) +- +- When("filterLoopback is false", func() { +- BeforeEach(func() { +- sutConfig.FilterLoopback = false +- }) +- +- It("should parse it successfully", func() { +- Expect(sut).ShouldNot(BeNil()) +- Expect(sut.hosts.v4.hosts).Should(HaveLen(7)) +- Expect(sut.hosts.v6.hosts).Should(HaveLen(3)) +- Expect(sut.hosts.v4.aliases).Should(HaveLen(5)) +- Expect(sut.hosts.v6.aliases).Should(HaveLen(2)) +- }) +- }) +- }) +- +- When("Hosts file has too many errors", func() { +- BeforeEach(func() { +- tmpFile = tmpDir.CreateStringFile("hosts-too-many-errors.txt", +- "invalidip localhost", +- "127.0.0.1 localhost", // ok +- "127.0.0.1 # no host", +- "127.0.0.1 invalidhost!", +- "a.b.c.d localhost", +- "127.0.0.x localhost", +- "256.0.0.1 localhost", +- ) +- Expect(tmpFile.Error).Should(Succeed()) +- +- sutConfig.Sources = config.NewBytesSources(tmpFile.Path) +- }) +- +- It("should not be used", func() { +- Expect(sut).ShouldNot(BeNil()) +- Expect(sut.cfg.Sources).ShouldNot(BeEmpty()) +- Expect(sut.hosts.v4.hosts).Should(BeEmpty()) +- Expect(sut.hosts.v6.hosts).Should(BeEmpty()) +- Expect(sut.hosts.v4.aliases).Should(BeEmpty()) +- Expect(sut.hosts.v6.aliases).Should(BeEmpty()) +- }) +- }) +- +- When("IPv4 mapping is defined for a host", func() { +- It("defined ipv4 query should be resolved", func() { +- Expect(sut.Resolve(newRequest("ipv4host.", A))). +- Should( +- SatisfyAll( +- HaveResponseType(ResponseTypeHOSTSFILE), +- HaveReturnCode(dns.RcodeSuccess), +- BeDNSRecord("ipv4host.", A, "192.168.2.1"), +- HaveTTL(BeNumerically("==", TTL)), +- )) +- }) +- It("defined ipv4 query for alias should be resolved", func() { +- Expect(sut.Resolve(newRequest("router2.", A))). +- Should( +- SatisfyAll( +- HaveResponseType(ResponseTypeHOSTSFILE), +- HaveReturnCode(dns.RcodeSuccess), +- BeDNSRecord("router2.", A, "10.0.0.1"), +- HaveTTL(BeNumerically("==", TTL)), +- )) +- }) +- It("ipv4 query should return NOERROR and empty result", func() { +- Expect(sut.Resolve(newRequest("does.not.exist.", A))). +- Should( +- SatisfyAll( +- HaveNoAnswer(), +- HaveReturnCode(dns.RcodeSuccess), +- HaveResponseType(ResponseTypeRESOLVED), +- )) +- }) +- }) +- +- When("IPv6 mapping is defined for a host", func() { +- It("defined ipv6 query should be resolved", func() { +- Expect(sut.Resolve(newRequest("ipv6host.", AAAA))). +- Should( +- SatisfyAll( +- HaveResponseType(ResponseTypeHOSTSFILE), +- HaveReturnCode(dns.RcodeSuccess), +- BeDNSRecord("ipv6host.", AAAA, "faaf:faaf:faaf:faaf::1"), +- HaveTTL(BeNumerically("==", TTL)), +- )) +- }) +- It("ipv6 query should return NOERROR and empty result", func() { +- Expect(sut.Resolve(newRequest("does.not.exist.", AAAA))). +- Should( +- SatisfyAll( +- HaveNoAnswer(), +- HaveReturnCode(dns.RcodeSuccess), +- HaveResponseType(ResponseTypeRESOLVED), +- )) +- }) +- }) +- +- When("the domain is not known", func() { +- It("calls the next resolver", func() { +- resp, err := sut.Resolve(newRequest("not-in-hostsfile.tld.", A)) +- Expect(err).Should(Succeed()) +- Expect(resp).ShouldNot(HaveResponseType(ResponseTypeHOSTSFILE)) +- m.AssertExpectations(GinkgoT()) +- }) +- }) +- +- When("the question type is not handled", func() { +- It("calls the next resolver", func() { +- resp, err := sut.Resolve(newRequest("localhost.", MX)) +- Expect(err).Should(Succeed()) +- Expect(resp).ShouldNot(HaveResponseType(ResponseTypeHOSTSFILE)) +- m.AssertExpectations(GinkgoT()) +- }) +- }) +- +- When("Reverse DNS request is received", func() { +- It("should resolve the defined domain name", func() { +- By("ipv4 with one hostname", func() { +- Expect(sut.Resolve(newRequest("2.0.0.10.in-addr.arpa.", PTR))). +- Should( +- SatisfyAll( +- HaveResponseType(ResponseTypeHOSTSFILE), +- HaveReturnCode(dns.RcodeSuccess), +- BeDNSRecord("2.0.0.10.in-addr.arpa.", PTR, "router3."), +- HaveTTL(BeNumerically("==", TTL)), +- )) +- }) +- By("ipv4 with aliases", func() { +- Expect(sut.Resolve(newRequest("1.0.0.10.in-addr.arpa.", PTR))). +- Should( +- SatisfyAll( +- HaveResponseType(ResponseTypeHOSTSFILE), +- HaveReturnCode(dns.RcodeSuccess), +- WithTransform(ToAnswer, ContainElements( +- BeDNSRecord("1.0.0.10.in-addr.arpa.", PTR, "router0."), +- BeDNSRecord("1.0.0.10.in-addr.arpa.", PTR, "router1."), +- BeDNSRecord("1.0.0.10.in-addr.arpa.", PTR, "router2."), +- )), +- )) +- }) +- By("ipv6", func() { +- Expect(sut.Resolve(newRequest("1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.f.a.a.f.f.a.a.f.f.a.a.f.f.a.a.f.ip6.arpa.", PTR))). +- Should( +- SatisfyAll( +- HaveResponseType(ResponseTypeHOSTSFILE), +- HaveReturnCode(dns.RcodeSuccess), +- WithTransform(ToAnswer, ContainElements( +- BeDNSRecord("1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.f.a.a.f.f.a.a.f.f.a.a.f.f.a.a.f.ip6.arpa.", +- PTR, "ipv6host."), +- BeDNSRecord("1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.f.a.a.f.f.a.a.f.f.a.a.f.f.a.a.f.ip6.arpa.", +- PTR, "ipv6host.local.lan."), +- )), +- )) +- }) +- }) +- +- It("should ignore invalid PTR", func() { +- resp, err := sut.Resolve(newRequest("2.0.0.10.in-addr.fail.arpa.", PTR)) +- Expect(err).Should(Succeed()) +- Expect(resp).ShouldNot(HaveResponseType(ResponseTypeHOSTSFILE)) +- m.AssertExpectations(GinkgoT()) +- }) +- +- When("filterLoopback is true", func() { +- It("calls the next resolver", func() { +- resp, err := sut.Resolve(newRequest("1.0.0.127.in-addr.arpa.", PTR)) +- Expect(err).Should(Succeed()) +- Expect(resp).ShouldNot(HaveResponseType(ResponseTypeHOSTSFILE)) +- m.AssertExpectations(GinkgoT()) +- }) +- }) +- +- When("the IP is not known", func() { +- It("calls the next resolver", func() { +- resp, err := sut.Resolve(newRequest("255.255.255.255.in-addr.arpa.", PTR)) +- Expect(err).Should(Succeed()) +- Expect(resp).ShouldNot(HaveResponseType(ResponseTypeHOSTSFILE)) +- m.AssertExpectations(GinkgoT()) +- }) +- }) +- +- When("filterLoopback is false", func() { +- BeforeEach(func() { +- sutConfig.FilterLoopback = false +- }) +- +- It("resolve the defined domain name", func() { +- Expect(sut.Resolve(newRequest("1.1.0.127.in-addr.arpa.", PTR))). +- Should( +- SatisfyAll( +- HaveResponseType(ResponseTypeHOSTSFILE), +- HaveReturnCode(dns.RcodeSuccess), +- WithTransform(ToAnswer, ContainElements( +- BeDNSRecord("1.1.0.127.in-addr.arpa.", PTR, "localhost2."), +- BeDNSRecord("1.1.0.127.in-addr.arpa.", PTR, "localhost2.local.lan."), +- )), +- )) +- }) +- }) +- }) +- }) +- +- Describe("Delegating to next resolver", func() { +- When("no hosts file is provided", func() { +- It("should delegate to next resolver", func() { +- _, err := sut.Resolve(newRequest("example.com.", A)) +- Expect(err).Should(Succeed()) +- // delegate was executed +- m.AssertExpectations(GinkgoT()) +- }) +- }) +- }) +-}) +- +-func writeHostFile(tmpDir *TmpFolder) *TmpFile { +- return tmpDir.CreateStringFile("hosts.txt", +- "# Random comment", +- "127.0.0.1 localhost", +- "127.0.1.1 localhost2 localhost2.local.lan", +- "::1 localhost", +- "# Two empty lines to follow", +- "", +- "", +- "faaf:faaf:faaf:faaf::1 ipv6host ipv6host.local.lan", +- "192.168.2.1 ipv4host ipv4host.local.lan", +- "faaf:faaf:faaf:faaf::2 dualhost dualhost.local.lan", +- "192.168.2.2 dualhost dualhost.local.lan", +- "10.0.0.1 router0 router1 router2", +- "10.0.0.2 router3 # Another comment", +- "10.0.0.3 router4#comment without a space", +- "10.0.0.4 # Invalid entry", +- "300.300.300.300 invalid4 # Invalid IPv4", +- "abcd:efgh:ijkl::1 invalid6 # Invalid IPv6", +- "1.2.3.4 localhost", // localhost name but not localhost IP +- +- // from https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts +- "fe80::1%lo0 localhost", // interface name +- ) +-} diff --git a/net-dns/blocky/metadata.xml b/net-dns/blocky/metadata.xml new file mode 100644 index 0000000000..e8b50d9eb3 --- /dev/null +++ b/net-dns/blocky/metadata.xml @@ -0,0 +1,16 @@ + + + + + me@rahil.rocks + Rahil Bhimjiani + + + Blocky is a DNS proxy and ad-blocker alternative to Pi-Hole and AdGuard Home written in Go with support for DNSSEC, DNS over HTTPS (DoH), DNS over TLS (DoT), metrics via prometheus-grafana, REST api, per client per group blacklists and whitelists, custom domains, conditional forwarding and simple YAML config. + + + 0xERR0R/blocky + https://github.com/0xERR0R/blocky/issues + https://0xerr0r.github.io/blocky/ + + From 231822dc2b2d1576e68aaeb14ed9c973f6c9f374 Mon Sep 17 00:00:00 2001 From: Andrey Syutkin Date: Mon, 1 Jan 2024 13:45:03 +0300 Subject: [PATCH 4/8] app-misc/far2l: version bump to 2.5.3_beta Drop python plugins support for now Signed-off-by: Andrey Syutkin --- app-misc/far2l/Manifest | 3 +- app-misc/far2l/far2l-2.3.2_alpha.ebuild | 92 ------------------- ....0_beta.ebuild => far2l-2.5.3_beta.ebuild} | 26 ++---- app-misc/far2l/far2l-9999.ebuild | 26 ++---- app-misc/far2l/metadata.xml | 3 +- 5 files changed, 18 insertions(+), 132 deletions(-) delete mode 100644 app-misc/far2l/far2l-2.3.2_alpha.ebuild rename app-misc/far2l/{far2l-2.4.0_beta.ebuild => far2l-2.5.3_beta.ebuild} (64%) diff --git a/app-misc/far2l/Manifest b/app-misc/far2l/Manifest index 7e9fdc0d6d..51138987f7 100644 --- a/app-misc/far2l/Manifest +++ b/app-misc/far2l/Manifest @@ -1,2 +1 @@ -DIST v_2.3.2.tar.gz 6232935 BLAKE2B ea146088c518bfeb0d935313a07f00a37fd2b6998388060514d144494946565661d3554e8ffb63b4bed8b9f1c3cea2ba4ec4c0787b0fa89df7f8d39720606b03 SHA512 e610a2b92ab3e7896f3aa5a59872cf273ab1c60ff6aac8e71d1d7152c2e8cb36fb8552167e13c8a4bcec9138052a3397c202cfa4b57cddf2053508421eb66799 -DIST v_2.4.0.tar.gz 6223889 BLAKE2B 25c13233dc53b4be7ba97eb20c6455cda2d1ffd332ece0c6869cd88f7af16b052fab13968a20bf12d6549e17b46fc894503d59f58a893e550808759fde974279 SHA512 096f7a755f71be2b5f80ad091ed4f796e064af6f91d7313bb3c898ea65cb743e406963df3c8b1a263df0d3b2a628f2f47653a14b8fe78a32ee9379ff424f9594 +DIST v_2.5.3.tar.gz 6529657 BLAKE2B fe0a1fad689594c1f472301b1f39e813fc7a5d949a99db38120f4beb4d703854ce0e6fc844e881623cf3a255357ec3680a9efbc78090a800c4c6d3455d6eafea SHA512 a4569511428f7d1465554e9c8075b9481be73f5383831b46e1c5e6ab25e5672585dbbe96bbf22c6dd5115c38e62916f0eef8206718374110b78389fde54086bd diff --git a/app-misc/far2l/far2l-2.3.2_alpha.ebuild b/app-misc/far2l/far2l-2.3.2_alpha.ebuild deleted file mode 100644 index f0d8a1521f..0000000000 --- a/app-misc/far2l/far2l-2.3.2_alpha.ebuild +++ /dev/null @@ -1,92 +0,0 @@ -# Copyright 1999-2021 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI=7 - -PYTHON_COMPAT=( python3_10 ) - -WX_GTK_VER="3.0-gtk3" - -inherit cmake xdg wxwidgets python-r1 - -DESCRIPTION="Linux port of FAR Manager v2" -HOMEPAGE="https://github.com/elfmz/far2l" - -if [[ "${PV}" == "9999" ]] ; then - inherit git-r3 - SRC_URI="" - EGIT_REPO_URI="https://github.com/elfmz/far2l" - EGIT_BRANCH="master" -else - MY_PV="v_${PV/_alpha/}" - MY_P="${PN}-${MY_PV}" - S="${WORKDIR}/${MY_P}" - SRC_URI="https://github.com/elfmz/far2l/archive/${MY_PV}.tar.gz" - KEYWORDS="~amd64" -fi - -LICENSE="GPL-2" -SLOT="0" -IUSE="+ssl sftp samba nfs webdav +archive +wxwidgets python" -REQUIRED_USE="python? ( ${PYTHON_REQUIRED_USE} )" -RESTRICT="mirror" - -BDEPEND="sys-devel/m4" - -RDEPEND="dev-libs/xerces-c - dev-libs/spdlog - app-i18n/uchardet - wxwidgets? ( x11-libs/wxGTK:${WX_GTK_VER} ) - ssl? ( dev-libs/openssl ) - sftp? ( net-libs/libssh[sftp] ) - samba? ( net-fs/samba ) - nfs? ( net-fs/libnfs ) - webdav? ( net-libs/neon ) - archive? ( - dev-libs/libpcre2 - app-arch/libarchive ) - python? ( - ${PYTHON_DEPS} - virtual/python-cffi - dev-python/debugpy - )" - -DEPEND="${RDEPEND}" - -DOCS=( README.md ) - -pkg_setup() { - if use wxwidgets; then - setup-wxwidgets - fi -} - -src_prepare() { - sed -e "s:execute_process(COMMAND ln -sf \../../bin/far2l \${CMAKE_INSTALL_PREFIX}/lib/far2l/far2l_askpass)::" -i "${S}"/CMakeLists.txt || die - sed -e "s:execute_process(COMMAND ln -sf \../../bin/far2l \${CMAKE_INSTALL_PREFIX}/lib/far2l/far2l_sudoapp)::" -i "${S}"/CMakeLists.txt || die - sed -e "s:execute_process(COMMAND rm -f \${CMAKE_INSTALL_PREFIX}/lib/far2l/Plugins/objinfo/plug/objinfo.far-plug-mb)::" -i "${S}"/CMakeLists.txt || die - sed -e "s:execute_process(COMMAND rm -f \${CMAKE_INSTALL_PREFIX}/lib/far2l/Plugins/farftp/plug/farftp.far-plug-mb && echo Removed existing farftp plugin)::" -i "${S}"/CMakeLists.txt || die - sed -e "s:execute_process(COMMAND rm -f \${CMAKE_INSTALL_PREFIX}/lib/far2l/Plugins/python/plug/python.far-plug-wide && echo Removed existing python plugin)::" -i "${S}"/CMakeLists.txt || die - sed -e "s:execute_process(COMMAND echo Python\: prepaing virtual environment)::" -i "${S}"/CMakeLists.txt || die - sed -e "s:execute_process(COMMAND \${PYTHON3} -m venv --system-site-packages \${CMAKE_INSTALL_PREFIX}/lib/far2l/Plugins/python/plug/python)::" -i "${S}"/CMakeLists.txt || die - sed -e "s:execute_process(COMMAND echo Python\: installing packages)::" -i "${S}"/CMakeLists.txt || die - sed -e "s:execute_process(COMMAND \${CMAKE_INSTALL_PREFIX}/lib/far2l/Plugins/python/plug/python/bin/python -m pip install cffi debugpy)::" -i "${S}"/CMakeLists.txt || die - cmake_src_prepare -} - -src_configure() { - local mycmakeargs=( - -DUSEWX="$(usex wxwidgets)" - -DPYTHON="$(usex python)" - -DBUILD_SHARED_LIBS=OFF - ) - - cmake_src_configure -} - -src_install(){ - cmake_src_install - einstalldocs - dosym "../../bin/far2l" "usr/lib/far2l/far2l_askpass" - dosym "../../bin/far2l" "usr/lib/far2l/far2l_sudoapp" -} diff --git a/app-misc/far2l/far2l-2.4.0_beta.ebuild b/app-misc/far2l/far2l-2.5.3_beta.ebuild similarity index 64% rename from app-misc/far2l/far2l-2.4.0_beta.ebuild rename to app-misc/far2l/far2l-2.5.3_beta.ebuild index 4742dd5ce4..7f902db401 100644 --- a/app-misc/far2l/far2l-2.4.0_beta.ebuild +++ b/app-misc/far2l/far2l-2.5.3_beta.ebuild @@ -1,20 +1,17 @@ -# Copyright 1999-2022 Gentoo Authors +# Copyright 1999-2024 Gentoo Authors # Distributed under the terms of the GNU General Public License v2 -EAPI=7 - -PYTHON_COMPAT=( python3_10 ) +EAPI=8 WX_GTK_VER="3.0-gtk3" -inherit cmake xdg wxwidgets python-r1 +inherit cmake xdg wxwidgets DESCRIPTION="Linux port of FAR Manager v2" HOMEPAGE="https://github.com/elfmz/far2l" if [[ "${PV}" == "9999" ]] ; then inherit git-r3 - SRC_URI="" EGIT_REPO_URI="https://github.com/elfmz/far2l" EGIT_BRANCH="master" else @@ -27,8 +24,7 @@ fi LICENSE="GPL-2" SLOT="0" -IUSE="+ssl sftp samba nfs webdav +archive +wxwidgets python" -REQUIRED_USE="python? ( ${PYTHON_REQUIRED_USE} )" +IUSE="+ssl sftp samba nfs webdav +archive +wxwidgets" RESTRICT="mirror" BDEPEND="sys-devel/m4" @@ -44,11 +40,7 @@ RDEPEND="dev-libs/xerces-c webdav? ( net-libs/neon ) archive? ( dev-libs/libpcre2 - app-arch/libarchive ) - python? ( - ${PYTHON_DEPS} - virtual/python-cffi - dev-python/debugpy + app-arch/libarchive )" DEPEND="${RDEPEND}" @@ -65,17 +57,15 @@ src_prepare() { sed -e "s:execute_process(COMMAND ln -sf \../../bin/far2l \${CMAKE_INSTALL_PREFIX}/lib/far2l/far2l_askpass)::" -i "${S}"/CMakeLists.txt || die sed -e "s:execute_process(COMMAND ln -sf \../../bin/far2l \${CMAKE_INSTALL_PREFIX}/lib/far2l/far2l_sudoapp)::" -i "${S}"/CMakeLists.txt || die sed -e "s:execute_process(COMMAND rm -f \${CMAKE_INSTALL_PREFIX}/lib/far2l/Plugins/.*::" -i "${S}"/CMakeLists.txt || die - sed -e "s:execute_process(COMMAND echo Python\: prepaing virtual environment)::" -i "${S}"/CMakeLists.txt || die - sed -e "s:execute_process(COMMAND \${PYTHON3} -m venv --system-site-packages \${CMAKE_INSTALL_PREFIX}/lib/far2l/Plugins/python/plug/python)::" -i "${S}"/CMakeLists.txt || die - sed -e "s:execute_process(COMMAND echo Python\: installing packages)::" -i "${S}"/CMakeLists.txt || die - sed -e "s:execute_process(COMMAND \${CMAKE_INSTALL_PREFIX}/lib/far2l/Plugins/python/plug/python/bin/python -m pip install cffi debugpy)::" -i "${S}"/CMakeLists.txt || die cmake_src_prepare } src_configure() { local mycmakeargs=( -DUSEWX="$(usex wxwidgets)" - -DPYTHON="$(usex python)" +# FIXME: add python plugins support +# We need pcpp for this +# -DPYTHON="$(usex python)" -DBUILD_SHARED_LIBS=OFF ) diff --git a/app-misc/far2l/far2l-9999.ebuild b/app-misc/far2l/far2l-9999.ebuild index 4742dd5ce4..7f902db401 100644 --- a/app-misc/far2l/far2l-9999.ebuild +++ b/app-misc/far2l/far2l-9999.ebuild @@ -1,20 +1,17 @@ -# Copyright 1999-2022 Gentoo Authors +# Copyright 1999-2024 Gentoo Authors # Distributed under the terms of the GNU General Public License v2 -EAPI=7 - -PYTHON_COMPAT=( python3_10 ) +EAPI=8 WX_GTK_VER="3.0-gtk3" -inherit cmake xdg wxwidgets python-r1 +inherit cmake xdg wxwidgets DESCRIPTION="Linux port of FAR Manager v2" HOMEPAGE="https://github.com/elfmz/far2l" if [[ "${PV}" == "9999" ]] ; then inherit git-r3 - SRC_URI="" EGIT_REPO_URI="https://github.com/elfmz/far2l" EGIT_BRANCH="master" else @@ -27,8 +24,7 @@ fi LICENSE="GPL-2" SLOT="0" -IUSE="+ssl sftp samba nfs webdav +archive +wxwidgets python" -REQUIRED_USE="python? ( ${PYTHON_REQUIRED_USE} )" +IUSE="+ssl sftp samba nfs webdav +archive +wxwidgets" RESTRICT="mirror" BDEPEND="sys-devel/m4" @@ -44,11 +40,7 @@ RDEPEND="dev-libs/xerces-c webdav? ( net-libs/neon ) archive? ( dev-libs/libpcre2 - app-arch/libarchive ) - python? ( - ${PYTHON_DEPS} - virtual/python-cffi - dev-python/debugpy + app-arch/libarchive )" DEPEND="${RDEPEND}" @@ -65,17 +57,15 @@ src_prepare() { sed -e "s:execute_process(COMMAND ln -sf \../../bin/far2l \${CMAKE_INSTALL_PREFIX}/lib/far2l/far2l_askpass)::" -i "${S}"/CMakeLists.txt || die sed -e "s:execute_process(COMMAND ln -sf \../../bin/far2l \${CMAKE_INSTALL_PREFIX}/lib/far2l/far2l_sudoapp)::" -i "${S}"/CMakeLists.txt || die sed -e "s:execute_process(COMMAND rm -f \${CMAKE_INSTALL_PREFIX}/lib/far2l/Plugins/.*::" -i "${S}"/CMakeLists.txt || die - sed -e "s:execute_process(COMMAND echo Python\: prepaing virtual environment)::" -i "${S}"/CMakeLists.txt || die - sed -e "s:execute_process(COMMAND \${PYTHON3} -m venv --system-site-packages \${CMAKE_INSTALL_PREFIX}/lib/far2l/Plugins/python/plug/python)::" -i "${S}"/CMakeLists.txt || die - sed -e "s:execute_process(COMMAND echo Python\: installing packages)::" -i "${S}"/CMakeLists.txt || die - sed -e "s:execute_process(COMMAND \${CMAKE_INSTALL_PREFIX}/lib/far2l/Plugins/python/plug/python/bin/python -m pip install cffi debugpy)::" -i "${S}"/CMakeLists.txt || die cmake_src_prepare } src_configure() { local mycmakeargs=( -DUSEWX="$(usex wxwidgets)" - -DPYTHON="$(usex python)" +# FIXME: add python plugins support +# We need pcpp for this +# -DPYTHON="$(usex python)" -DBUILD_SHARED_LIBS=OFF ) diff --git a/app-misc/far2l/metadata.xml b/app-misc/far2l/metadata.xml index 231e890f0f..5995d0e6f7 100644 --- a/app-misc/far2l/metadata.xml +++ b/app-misc/far2l/metadata.xml @@ -1,5 +1,5 @@ - + syutkin@gmail.com @@ -11,7 +11,6 @@ Multiarc extended archives support NFS support in NetRocks - Python scripting support SMB support in NetRocks SFTP support in NetRocks FTPS support in NetRocks From c0e466a9fee41408c85478a2cd967fa7904bbbc0 Mon Sep 17 00:00:00 2001 From: Moritz Brunner Date: Sun, 31 Dec 2023 21:25:27 +0100 Subject: [PATCH 5/8] dev-python/PyPubSub: Change working directory for test runner The default pytest test runner doesn't find the test cases unless it is run in the correct directory. Closes: https://bugs.gentoo.org/916697 Signed-off-by: Moritz Brunner --- dev-python/PyPubSub/PyPubSub-4.0.3.ebuild | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/dev-python/PyPubSub/PyPubSub-4.0.3.ebuild b/dev-python/PyPubSub/PyPubSub-4.0.3.ebuild index 0b0e1876e4..c65dc950f9 100644 --- a/dev-python/PyPubSub/PyPubSub-4.0.3.ebuild +++ b/dev-python/PyPubSub/PyPubSub-4.0.3.ebuild @@ -28,8 +28,9 @@ BDEPEND=" dev-python/pytest[${PYTHON_USEDEP}] )" -python_test() { - py.test -v -v || die -} - distutils_enable_tests pytest + +python_test() { + cd tests/suite + distutils-r1_python_test +} From ad6bd68959de396ae567a41116f5d32613cf2486 Mon Sep 17 00:00:00 2001 From: Moritz Brunner Date: Sun, 31 Dec 2023 21:27:38 +0100 Subject: [PATCH 6/8] dev-python/PyPubSub: bump to 4.0.3-r1, destabilize ~amd64, ~arm, ~arm64, ~x86 Change all keywords to ~ARCH in accordance with GURU regulations. Signed-off-by: Moritz Brunner --- .../{PyPubSub-4.0.3.ebuild => PyPubSub-4.0.3-r1.ebuild} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename dev-python/PyPubSub/{PyPubSub-4.0.3.ebuild => PyPubSub-4.0.3-r1.ebuild} (96%) diff --git a/dev-python/PyPubSub/PyPubSub-4.0.3.ebuild b/dev-python/PyPubSub/PyPubSub-4.0.3-r1.ebuild similarity index 96% rename from dev-python/PyPubSub/PyPubSub-4.0.3.ebuild rename to dev-python/PyPubSub/PyPubSub-4.0.3-r1.ebuild index c65dc950f9..541fbda263 100644 --- a/dev-python/PyPubSub/PyPubSub-4.0.3.ebuild +++ b/dev-python/PyPubSub/PyPubSub-4.0.3-r1.ebuild @@ -16,7 +16,7 @@ S="${WORKDIR}/${MY_PN}-${PV}" LICENSE="BSD" SLOT="0" -KEYWORDS="amd64 arm arm64 x86" +KEYWORDS="~amd64 ~arm ~arm64 ~x86" IUSE="test" RESTRICT="!test? ( test )" From da7a78856fc2610be0d91b616b603fe2bc014e68 Mon Sep 17 00:00:00 2001 From: Moritz Brunner Date: Mon, 1 Jan 2024 13:28:02 +0100 Subject: [PATCH 7/8] .gitignore: Add tags file generated by ctags Signed-off-by: Moritz Brunner --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 8fbf55708d..655146b1cf 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ /metadata/md5-cache /packages/ /profiles/use.local.desc +/tags From a59fc15fc951059c3adcc39f7a69482f307bd103 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Mon, 1 Jan 2024 15:29:17 +0100 Subject: [PATCH 8/8] app-office/drawio-desktop-bin: treeclean, now in ::gentoo Signed-off-by: Florian Schmaus --- app-office/drawio-desktop-bin/Manifest | 3 -- .../drawio-desktop-bin-21.6.5.ebuild | 26 ---------- .../drawio-desktop-bin-22.1.15.ebuild | 51 ------------------- app-office/drawio-desktop-bin/metadata.xml | 12 ----- 4 files changed, 92 deletions(-) delete mode 100644 app-office/drawio-desktop-bin/Manifest delete mode 100644 app-office/drawio-desktop-bin/drawio-desktop-bin-21.6.5.ebuild delete mode 100644 app-office/drawio-desktop-bin/drawio-desktop-bin-22.1.15.ebuild delete mode 100644 app-office/drawio-desktop-bin/metadata.xml diff --git a/app-office/drawio-desktop-bin/Manifest b/app-office/drawio-desktop-bin/Manifest deleted file mode 100644 index 6076dd18fd..0000000000 --- a/app-office/drawio-desktop-bin/Manifest +++ /dev/null @@ -1,3 +0,0 @@ -DIST drawio-desktop-bin-22.1.15.tar.gz 454755 BLAKE2B 3fcdb54bd397919f21145d6912091d84baa5d55731babcc70a3d9a7a7c4db67eed2ff7fd62660e1915721e856d09244ef05bf6135bb00039f8b998f94986ae75 SHA512 164d18b723c65aa095dc71dab75b886cf99ef6a462dce1440c8547063658c3063cc0951dad6552fd01edaa3c1a41002b184d4e2fe7ec87f0c31dfc6fd25643c9 -DIST drawio-x86_64-21.6.5.AppImage 163718032 BLAKE2B 04a9a0b0a19442110eecf199bb92d3f4f98d218abc6873c59fa2539c3c661de1e78137edab614a198d36f93e4f09ba47c185e8bb3b859d1d37f71f9cdefb2048 SHA512 eb3e998d7ef430fd38d9f6aaa3c625766637615bec5f735e2e9740c16dcbbcd6d671c619f7dac8ae5cd2ee9a4618c23d00bdf34c6d8a21b463c4fdcb95b5b7f2 -DIST drawio-x86_64-22.1.15.AppImage 199610803 BLAKE2B aa443e2177c7230d322f9db50a2e5315ae43ae4f44fd5e9bbcfd372288276716222fc24e2f513cbbc9180d44871c654dd75016672ef64e602ecfbfc1c5d0865a SHA512 2ee285ad6ac6295f319b8dc5503610a6965a230d5f8d7348811b1d81319fdc784db974d31ccb4253061ba9474659ac1fb6a39f6e6784dc58bb4908027b329c8f diff --git a/app-office/drawio-desktop-bin/drawio-desktop-bin-21.6.5.ebuild b/app-office/drawio-desktop-bin/drawio-desktop-bin-21.6.5.ebuild deleted file mode 100644 index 23c5fff5dd..0000000000 --- a/app-office/drawio-desktop-bin/drawio-desktop-bin-21.6.5.ebuild +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright 1999-2023 Gentoo Foundation -# Distributed under the terms of the GNU General Public License v2 - -EAPI=8 - -MY_PN="${PN/-bin/}" - -DESCRIPTION="Diagram drawing application built on web technologies" -HOMEPAGE="https://github.com/jgraph/drawio-desktop" - -SRC_URI="https://github.com/jgraph/${MY_PN}/releases/download/v${PV}/drawio-x86_64-${PV}.AppImage" -KEYWORDS="~amd64" - -LICENSE="Apache-2.0" -SLOT="0" -RESTRICT="strip" - -RDEPEND="sys-fs/fuse:0" - -S="${WORKDIR}" - -QA_PREBUILT="*" - -src_install() { - newbin "${DISTDIR}/drawio-x86_64-21.6.5.AppImage" drawio-appimage -} diff --git a/app-office/drawio-desktop-bin/drawio-desktop-bin-22.1.15.ebuild b/app-office/drawio-desktop-bin/drawio-desktop-bin-22.1.15.ebuild deleted file mode 100644 index aee43d3bd6..0000000000 --- a/app-office/drawio-desktop-bin/drawio-desktop-bin-22.1.15.ebuild +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright 1999-2023 Gentoo Foundation -# Distributed under the terms of the GNU General Public License v2 - -EAPI=8 - -inherit desktop - -MY_PN="${PN/-bin/}" - -DESCRIPTION="Diagram drawing application built on web technologies" -HOMEPAGE="https://github.com/jgraph/drawio-desktop" - -SRC_URI=" - https://github.com/jgraph/${MY_PN}/releases/download/v${PV}/drawio-x86_64-${PV}.AppImage - https://github.com/jgraph/drawio-desktop/archive/v${PV}.tar.gz -> ${P}.tar.gz -" -KEYWORDS="-* ~amd64" - -LICENSE="Apache-2.0" -SLOT="0" -RESTRICT="strip" - -RDEPEND="sys-fs/fuse:0" - -S="${WORKDIR}" - -QA_PREBUILT="*" - -src_install() { - newbin "${DISTDIR}/drawio-x86_64-${PV}.AppImage" drawio-appimage - - pushd "${MY_PN}-${PV}/build" || die - for f in *x*.png; do - case "${f}" in - # not all icon sizes are supported - 720x720.png) - continue - ;; - *) - newicon -s "${f%.png}" "${f}" "drawio.png" - ;; - esac - done - popd || die - - make_desktop_entry \ - "/usr/bin/drawio-appimage" \ - "draw.io" \ - "drawio" \ - "Graphics;Office" -} diff --git a/app-office/drawio-desktop-bin/metadata.xml b/app-office/drawio-desktop-bin/metadata.xml deleted file mode 100644 index 033e236961..0000000000 --- a/app-office/drawio-desktop-bin/metadata.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - Vitaly Zdanevich - zdanevich.vitaly@ya.ru - - - jgraph/drawio-desktop - https://github.com/jgraph/drawio-desktop/issues - -