diff --git a/.travis.yml b/.travis.yml
index fdb7a5b..801ca94 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,5 +1,7 @@
-language: bash
+language: rust
before_install:
- wget -c https://goo.gl/ZzKHFv -O - | tar -xvJ -C /tmp/
- PATH="/tmp/shellcheck-latest:$PATH"
-script: shellcheck $(grep -rl '^#!.*[ /]bash$' .)
+script: |
+ shellcheck $(grep -rl '^#!.*[ /]bash$' .)
+ (cd trust-check && cargo test)
diff --git a/README.md b/README.md
index 5ac733f..a31eec0 100644
--- a/README.md
+++ b/README.md
@@ -7,6 +7,8 @@ An Arch Linux AUR tool for managing an auto-updating local 'aurto' package repos
- Automatic on startup & hourly update of aur packages in the ***aurto*** repo.
- Automatic daily update of `*-git` packages in the ***aurto*** repo.
- Uses _makechrootpkg_ to build packages isolated from the main system.
+- Automatic removal of packages no longer in the AUR from the ***aurto*** repo.
+- Automatic removal of packages with unknown/distrusted maintainers from the ***aurto*** repo.
# Install
From a plain Arch install, first install **aurutils** from the aur (skip if already installed).
@@ -55,14 +57,38 @@ Add a directory full of built packages to the ***aurto*** repo
aurto addpkg $(find /path/to/packages/*pkg.tar*)
```
+Show repo-less installed packages, these may have not been added to ***aurto*** yet or may have been automatically dropped from ***aurto*** because of maintainer change or removal from the AUR.
+```sh
+pacman -Qm
+```
+
Rebuild all orphans packages into the ***aurto*** repo
```sh
aurto add $(pacman -Qqm)
```
+# Maintainer Trust
+**aurto** uses a system of maintainer trust for limited security. On adding packages with unknown maintainers you'll be asked whether you want to trust these maintainers.
+```
+$ aurto add spotify
+aurto: Trust maintainer(s): AWhetter? [y/N]
+```
+If not the package will _not_ be added to the ***aurto*** repo.
+
+If any ***aurto*** repo packages changes maintainer to an unknown maintainer they will be removed from the ***aurto*** repo on the next _update-aurto_ run. A warning will appear in the _update-aurto_ logs
+```
+WARNING: Packages with unknown maintainers removed from aurto, ...
+```
+If desired such packages can be re-added and the new maintainer added to the local trusted users.
+
+Local trusted users are stored in `/etc/aurto/trusted-users` initially populated with the [Arch Linux Trusted Users](https://wiki.archlinux.org/index.php/Trusted_Users#Active_Trusted_Users) & me.
+
+Clear `/etc/aurto/trusted-users` to trust no-one.
+Remove `/etc/aurto/trusted-users` to trust everyone.
+
# Limitations & Security
-aurto automatically builds and regularly re-builds updated remote code from the aur.
+**aurto** automatically builds and regularly re-builds updated remote code from the aur.
Code is _built_ in a clean chroot, but presumably will eventually be installed to your system.
-Only add aur packages from maintainers you trust.
+Take care trusting maintainers.
-aurto is for simple folk's simple needs. If it can't do what you want uninstall & use [aurutils](https://github.com/AladW/aurutils) directly.
+If aurto can't do what you want use [aurutils](https://github.com/AladW/aurutils) directly.
diff --git a/bin/aurto b/bin/aurto
index bcebfcc..d43dd07 100755
--- a/bin/aurto
+++ b/bin/aurto
@@ -19,19 +19,63 @@ source "$lib_dir/shared-functions"
function aurto_sync { sudo pacsync aurto >/dev/null; }
+function check_new_package_trust {
+ local mistrust
+ local not_in_aur
+ local mistrusted_users
+
+ if [ -f /etc/aurto/trusted-users ]; then
+ echo "aurto: Checking maintainer trust..." >&2
+ else
+ echo "aurto: Checking maintainer trust... $(dim disabled)" >&2
+ fi
+
+ mistrust=$("$lib_dir"/trust-check "${@:1}")
+ if [ -z "$mistrust" ]; then
+ if [ -f /etc/aurto/trusted-users ]; then
+ rm_last_print
+ echo "aurto: Checking maintainer trust... $(green ✓)" >&2
+ fi
+ else
+ not_in_aur=$(not_in_aur_packages "$mistrust")
+ if [ ! -z "$not_in_aur" ]; then
+ rm_last_print
+ echo "aurto: Package not in AUR: $(yellow "$not_in_aur")" >&2
+ exit 1
+ fi
+
+ mistrusted_users=$(new_line_to_space_separated_unique "$(echo "$mistrust" | cut -d: -f2)")
+ rm_last_print
+ echo -n "aurto: Trust maintainer(s): $(bold "$mistrusted_users")? [y/N] " >&2
+ read -n 1 -r
+ echo
+ if [[ $REPLY =~ ^[Yy]$ ]]; then
+ echo "aurto: Adding $(bold "$mistrusted_users") >> /etc/aurto/trusted-users" >&2
+ # shellcheck disable=SC2001
+ echo "$mistrusted_users" | sed -e 's/ /\n/g' >> /etc/aurto/trusted-users
+ else
+ exit 1
+ fi
+ fi
+}
+
if [ "$command" == "add" ] && [ -n "$arg1" ]; then
+ check_new_package_trust "${@:2}"
aurto_sync
echo "aurto: Running: $(dim aursync --no-view --no-confirm --chroot --repo=aurto) $(cyan "${*:2}")" >&2
"$lib_dir"/summerize-build aursync --no-view --no-confirm --chroot --repo=aurto "${@:2}"
aurto_sync
echo -e "aurto: To install run: $(green pacman -Syu) $(cyan "${*:2}")" >&2
+
elif [ "$command" == "addpkg" ] && [ -n "$arg1" ]; then
+ check_new_package_trust "${@:2}"
echo "aurto: Running: $(dim repo-add /var/cache/pacman/aurto/aurto.db.tar) $(cyan "${*:2}")" >&2
- repo-add /var/cache/pacman/aurto/aurto.db.tar "${@:2}"
+ "$lib_dir"/summerize-build repo-add /var/cache/pacman/aurto/aurto.db.tar "${@:2}"
for pkg in "${@:2}"; do
cp "$pkg" /var/cache/pacman/aurto/
done
aurto_sync
+
elif [ "$command" == "remove" ] && [ -n "$arg1" ]; then
removed=""
for pkg in "${@:2}"; do
@@ -47,6 +91,7 @@ elif [ "$command" == "remove" ] && [ -n "$arg1" ]; then
echo -e "aurto: Removed $(cyan "$removed")" >&2
aurto_sync
fi
+
else
echo "$(bold aurto) v$version: simple management tool for the 'aurto' repository"
echo " Usage: $(green aurto add)|$(green addpkg)|$(green remove) $(cyan PACKAGES...)"
diff --git a/lib/aurto/default-trusted-users.txt b/lib/aurto/default-trusted-users.txt
new file mode 100644
index 0000000..d8ade2e
--- /dev/null
+++ b/lib/aurto/default-trusted-users.txt
@@ -0,0 +1,49 @@
+alad
+alexheretic
+alucryd
+Ambrevar
+anatolik
+andrewSC
+anthraxx
+arcanis
+arojas
+Barthalion
+BlackIkeEagle
+Bluewind
+City-busz
+coderobe
+ConnorBehan
+lfleischer
+eworm
+Dragonlord
+dvzrv
+eschwartz
+escondida
+farseerfc
+felixonmars
+Foxboron
+foxxx0
+giniu
+grazzolini
+heftig
+jelly
+jleclanche
+jsteel
+keenerd
+Kyrias
+Lordheavy
+mtorromeo
+Muflone
+NicoHood
+schivmeister
+schuay
+seblu
+sergej
+shibumi
+stativ
+svenstaro
+tensor5
+wild
+Xyne
+xyproto
+zorun
diff --git a/lib/aurto/shared-functions b/lib/aurto/shared-functions
index 59a528b..1b2a1e6 100644
--- a/lib/aurto/shared-functions
+++ b/lib/aurto/shared-functions
@@ -4,6 +4,7 @@ if test -t 1; then
function green { echo -e "\\e[32m$*\\e[39m"; }
function cyan { echo -e "\\e[36m$*\\e[39m"; }
function red { echo -e "\\e[31m$*\\e[39m"; }
+ function yellow { echo -e "\\e[33m$*\\e[39m"; }
function dim { echo -e "\\e[2m$*\\e[22m"; }
function rm_last_print {
printf "\\033[1A" # move cursor one line up
@@ -14,6 +15,7 @@ else
function green { bold "$@"; }
function cyan { bold "$@"; }
function red { bold "$@"; }
+ function yellow { bold "$@"; }
function dim { bold "$@"; }
function rm_last_print { return; }
fi
@@ -22,3 +24,29 @@ fi
function last_pkg_modify {
stat /var/cache/pacman/aurto/*.pkg.tar* -c '%Y' 2>/dev/null | sort | tail -n1 | tr -d '\n'
}
+
+## Takes '\n' separated things and returns a ' ' separated unique sequence (no empties)
+function new_line_to_space_separated_unique {
+ local space_sep=""
+
+ while read -r line; do
+ if [ ! -z "$line" ] && [[ $space_sep != *" $line "* ]]; then
+ space_sep="$space_sep $line "
+ fi
+ done <<< "$1"
+
+ echo "$space_sep" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' | tr -s ' '
+}
+
+## Works on trust-check output returning packages that are not/no longer in AUR
+function not_in_aur_packages {
+ local packages=""
+
+ while read -r line; do
+ if [ ! -z "$line" ] && [[ $line = *"::not-in-aur"* ]]; then
+ packages="$packages $(echo "$line" | cut -d':' -f1)"
+ fi
+ done <<< "$1"
+
+ echo "$packages" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' | tr -s ' '
+}
diff --git a/lib/aurto/update-aurto b/lib/aurto/update-aurto
index 20d74de..54db641 100755
--- a/lib/aurto/update-aurto
+++ b/lib/aurto/update-aurto
@@ -20,6 +20,39 @@ fi
pacsync aurto >/dev/null || true
+## Check trust
+## - remove packages no longer in the AUR
+## - remove packages with maintainers lacking trust
+if [ -f /etc/aurto/trusted-users ]; then
+ echo "aurto: Checking maintainer trust..." >&2
+else
+ echo "aurto: Checking maintainer trust... $(dim disabled)" >&2
+fi
+# shellcheck disable=SC2046
+mistrust=$("$lib_dir"/trust-check $(pacman -Slq aurto))
+if [ -z "$mistrust" ]; then
+ if [ -f /etc/aurto/trusted-users ]; then
+ rm_last_print
+ echo "Checking maintainer trust... $(green ✓)" >&2
+ fi
+else
+ not_in_aur=$(not_in_aur_packages "$mistrust")
+ mistrusted_pkgs=$(new_line_to_space_separated_unique "$(echo "$mistrust" | grep -v '::' | cut -d: -f1)")
+
+ if [ ! -z "$not_in_aur" ]; then
+ rm_last_print
+ # shellcheck disable=SC2086
+ aurto remove $not_in_aur
+ echo "$(yellow WARNING:) Packages no longer in AUR removed from aurto: $(yellow "$not_in_aur")" >&2
+ fi
+ if [ ! -z "$mistrusted_pkgs" ]; then
+ # shellcheck disable=SC2086
+ aurto remove $mistrusted_pkgs
+ echo -n "$(yellow WARNING:) Packages with unknown maintainers removed from aurto, " >&2
+ echo "re-add with: $(green aurto add) $(cyan "$mistrusted_pkgs")" >&2
+ fi
+fi
+
modify=$(last_pkg_modify)
echo "Running: aursync --no-view --no-confirm --repo aurto --chroot --update" >&2
diff --git a/makefile b/makefile
index 5f064c2..e91214b 100644
--- a/makefile
+++ b/makefile
@@ -3,12 +3,15 @@ PREFIX = /usr
all:
@rm -rf target
+ @(cd trust-check && cargo build --release && strip target/release/trust-check)
+
@install -D conf/aurto.pacman.conf target/etc/pacman.d/aurto
@install -Dm440 conf/50_aurto_passwordless -t target/etc/sudoers.d
@chmod 750 target/etc/sudoers.d
@install -D bin/* -t target$(PREFIX)/bin
@install -D lib/aurto/* -t target$(PREFIX)/lib/aurto
+ @install trust-check/target/release/trust-check -t target$(PREFIX)/lib/aurto
@install -D timer/* -t target$(PREFIX)/lib/systemd/system
@install -D completion/bash/aurto target$(PREFIX)/share/bash-completion/completions/aurto
diff --git a/makelocalaur b/makelocalaur
index 1cf5cda..8204e9a 100755
--- a/makelocalaur
+++ b/makelocalaur
@@ -2,8 +2,10 @@
set -eu
script_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+rm -rf "$script_dir"/*-999-*pkg*
+
cd "$script_dir"/..
-tar zcf aurto-git.tar.gz -C "$script_dir" .
+tar zcf aurto-git.tar.gz --exclude='./target' --exclude='./trust-check/target' -C "$script_dir" .
mv aurto-git.tar.gz "$script_dir"/aur
cd "$script_dir"/aur
diff --git a/makelocalaur.PKGBUILD b/makelocalaur.PKGBUILD
index aca8abb..22943bb 100644
--- a/makelocalaur.PKGBUILD
+++ b/makelocalaur.PKGBUILD
@@ -11,9 +11,10 @@ depends=('aurutils<1.6.0'
'devtools'
'systemd'
'pacutils'
- 'pacman-contrib')
+ 'pacman-contrib'
+ 'curl')
optdepends=()
-makedepends=()
+makedepends=('cargo')
install="aurto.install"
source=("aurto-git.tar.gz")
sha256sums=('eb94c0a2920ddea570621da7326f3d60c30401e8c42073b5b3ed3b1216c1ce4b')
diff --git a/trust-check/.gitignore b/trust-check/.gitignore
new file mode 100644
index 0000000..eccd7b4
--- /dev/null
+++ b/trust-check/.gitignore
@@ -0,0 +1,2 @@
+/target/
+**/*.rs.bk
diff --git a/trust-check/Cargo.lock b/trust-check/Cargo.lock
new file mode 100644
index 0000000..97fdd3e
--- /dev/null
+++ b/trust-check/Cargo.lock
@@ -0,0 +1,177 @@
+[[package]]
+name = "cc"
+version = "1.0.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "cfg-if"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "curl"
+version = "0.4.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "curl-sys 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)",
+ "openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "openssl-sys 0.9.31 (registry+https://github.com/rust-lang/crates.io-index)",
+ "schannel 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "socket2 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "curl-sys"
+version = "0.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cc 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libz-sys 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
+ "openssl-sys 0.9.31 (registry+https://github.com/rust-lang/crates.io-index)",
+ "pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "vcpkg 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "json"
+version = "0.11.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "kernel32-sys"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "libc"
+version = "0.2.41"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "libz-sys"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cc 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)",
+ "pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "vcpkg 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "openssl-probe"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "openssl-sys"
+version = "0.9.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cc 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)",
+ "pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "vcpkg 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "pkg-config"
+version = "0.3.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "schannel"
+version = "0.1.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "socket2"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "trust-check"
+version = "0.1.0"
+dependencies = [
+ "curl 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "json 0.11.13 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "vcpkg"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "winapi"
+version = "0.2.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "winapi"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "winapi-build"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[metadata]
+"checksum cc 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "49ec142f5768efb5b7622aebc3fdbdbb8950a4b9ba996393cb76ef7466e8747d"
+"checksum cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "405216fd8fe65f718daa7102ea808a946b6ce40c742998fbfd3463645552de18"
+"checksum curl 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "aaf20bbe084f285f215eef2165feed70d6b75ba29cad24469badb853a4a287d0"
+"checksum curl-sys 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "71c63a540a9ee4e15e56c3ed9b11a2f121239b9f6d7b7fe30f616e048148df9a"
+"checksum json 0.11.13 (registry+https://github.com/rust-lang/crates.io-index)" = "9ad0485404155f45cce53a40d4b2d6ac356418300daed05273d9e26f91c390be"
+"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
+"checksum lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e6412c5e2ad9584b0b8e979393122026cdd6d2a80b933f890dcd694ddbe73739"
+"checksum libc 0.2.41 (registry+https://github.com/rust-lang/crates.io-index)" = "ac8ebf8343a981e2fa97042b14768f02ed3e1d602eac06cae6166df3c8ced206"
+"checksum libz-sys 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "87f737ad6cc6fd6eefe3d9dc5412f1573865bded441300904d2f42269e140f16"
+"checksum openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de"
+"checksum openssl-sys 0.9.31 (registry+https://github.com/rust-lang/crates.io-index)" = "a4d6a27d108b29befe1822d40e2e22f85518dac59acbf7f30fdc532f48fd0a77"
+"checksum pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "110d5ee3593dbb73f56294327fe5668bcc997897097cbc76b51e7aed3f52452f"
+"checksum schannel 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "85fd9df495640643ad2d00443b3d78aae69802ad488debab4f1dd52fc1806ade"
+"checksum socket2 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ff606e0486e88f5fc6cfeb3966e434fb409abbc7a3ab495238f70a1ca97f789d"
+"checksum vcpkg 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7ed0f6789c8a85ca41bbc1c9d175422116a9869bd1cf31bb08e1493ecce60380"
+"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
+"checksum winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "04e3bd221fcbe8a271359c04f21a76db7d0c6028862d1bb5512d85e1e2eb5bb3"
+"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
+"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
diff --git a/trust-check/Cargo.toml b/trust-check/Cargo.toml
new file mode 100644
index 0000000..dc1ca55
--- /dev/null
+++ b/trust-check/Cargo.toml
@@ -0,0 +1,11 @@
+[package]
+name = "trust-check"
+version = "0.1.0"
+authors = ["Alex Butler "]
+
+[dependencies]
+curl = "0.4"
+json = "0.11"
+
+[profile.release]
+lto = true
diff --git a/trust-check/src/main.rs b/trust-check/src/main.rs
new file mode 100644
index 0000000..1a196c1
--- /dev/null
+++ b/trust-check/src/main.rs
@@ -0,0 +1,178 @@
+//! Arch Linux binary to return input aur packages along with their
+//! mistrusted maintainers. Local trusted users are stored in
+//! /etc/aurto/trusted-users.
+//!
+//! Will output a line per package in PACKAGE_NAME:USERNAME format
+//! for each mistrusted package.
+//!
+//! If package is not found in the AUR will output PACKAGE_NAME::not-in-aur
+
+extern crate curl;
+extern crate json;
+
+use std::collections::HashSet;
+use std::error::Error;
+use std::path::Path;
+use std::{env, fs, str};
+
+type Res = Result>;
+
+const AURWEB_INFO: &str = "https://aur.archlinux.org/rpc/?v=5&type=info";
+const LOCAL_TRUST_PATH: &str = "/etc/aurto/trusted-users";
+
+fn main() -> Res<()> {
+ let mut packages = vec![];
+ for arg in env::args().skip(1) {
+ packages.push(translate_full_package(arg)?);
+ }
+
+ if packages.is_empty() || packages.iter().any(|p| p.starts_with('-')) {
+ return print_help();
+ }
+
+ let trust_everyone = !Path::new(LOCAL_TRUST_PATH).is_file();
+
+ let trusted = if trust_everyone {
+ HashSet::new()
+ } else {
+ local_trusted_users()?
+ };
+
+ let (pkg_maintainers, not_in_aur) = package_maintainers(&packages)?;
+
+ if !trust_everyone {
+ for pkg in pkg_maintainers
+ .into_iter()
+ .filter(|pkg| !trusted.contains(&pkg.maintainer.to_lowercase()))
+ {
+ println!("{}:{}", pkg.name, pkg.maintainer);
+ }
+ }
+
+ for pkg in not_in_aur {
+ println!("{}::not-in-aur", pkg);
+ }
+
+ Ok(())
+}
+
+/// normalises package names & full package archive names -> package names
+fn translate_full_package(arg: String) -> Result {
+ if arg.contains(".pkg.") {
+ let archive_name = Path::new(&arg)
+ .file_name()
+ .and_then(|f| f.to_str())
+ .ok_or_else(|| format!("Can't handle arg `{}`", arg))?;
+ let mut name_bits: Vec<_> = archive_name.split('-').rev().skip(3).collect();
+ name_bits.reverse();
+ Ok(name_bits.join("-"))
+ }
+ else {
+ Ok(arg)
+ }
+}
+
+fn local_trusted_users() -> Res> {
+ Ok(fs::read_to_string(LOCAL_TRUST_PATH)?
+ .split('\n')
+ .map(|user| user.trim().to_lowercase())
+ .filter(|user| !user.is_empty())
+ .collect())
+}
+
+#[derive(Debug)]
+struct MaintainedPackage {
+ name: String,
+ maintainer: String,
+}
+
+fn package_maintainers>(
+ packages: &[T],
+) -> Res<(Vec, Vec)> {
+ let url = {
+ let mut url = AURWEB_INFO.to_owned();
+ for pkg in packages {
+ url = url + "&arg[]=" + valid_arch_package_name(pkg.as_ref())?;
+ }
+ url
+ };
+
+ let mut buf = Vec::new();
+ {
+ let mut handle = curl::easy::Easy::new();
+ handle.url(&url)?;
+ let mut transfer = handle.transfer();
+ transfer.write_function(|data| {
+ buf.extend_from_slice(data);
+ Ok(data.len())
+ })?;
+ transfer.perform()?;
+ }
+
+ let mut json = json::parse(str::from_utf8(&buf)?)?;
+
+ let not_in_aur: Vec<_> = {
+ let in_aur: HashSet<_> = json["results"]
+ .members()
+ .filter_map(|info| info["Name"].as_str().map(|s| s.to_lowercase()))
+ .collect();
+ packages
+ .iter()
+ .map(|p| p.as_ref().to_lowercase())
+ .filter(|pkg| !in_aur.contains(pkg))
+ .collect()
+ };
+
+ let mut maintained_pkgs = vec![];
+ for info in json["results"].members_mut() {
+ let name = info["Name"].take_string();
+ let maintainer = info["Maintainer"].take_string();
+ if let (Some(name), Some(maintainer)) = (name, maintainer) {
+ maintained_pkgs.push(MaintainedPackage { name, maintainer });
+ }
+ }
+
+ Ok((maintained_pkgs, not_in_aur))
+}
+
+fn valid_arch_package_name(name: &str) -> Result<&str, String> {
+ fn valid_char(c: char) -> bool {
+ // https://wiki.archlinux.org/index.php/Arch_packaging_standards#Package_naming
+ // enforced to ensure a valid url request later
+ c.is_alphanumeric() || c == '@' || c == '.' || c == '_' || c == '+' || c == '-'
+ }
+
+ if !name.is_empty() && name.chars().all(valid_char) {
+ Ok(name)
+ }
+ else {
+ Err(format!("package name `{}` is invalid", name))
+ }
+}
+
+fn print_help() -> Result<(), Box> {
+ eprintln!("trust-check: output aurto-untrusted package:maintainer");
+ eprintln!(" Usage: trust-check PACKAGES...");
+ Ok(())
+}
+
+#[test]
+fn translate_full_package_for_package_name() {
+ assert_eq!(translate_full_package("aurto".into()), Ok("aurto".into()));
+ assert_eq!(
+ translate_full_package("gnome-shell-extension-arch-update".into()),
+ Ok("gnome-shell-extension-arch-update".into()),
+ );
+}
+
+#[test]
+fn translate_full_package_for_archive_name() {
+ assert_eq!(
+ translate_full_package("/home/alex/tmp/aurto-0.6.7-2-any.pkg.tar.gz".into()),
+ Ok("aurto".into()),
+ );
+ assert_eq!(
+ translate_full_package("../gnome-shell-extension-arch-update-26-1-any.pkg.tar.gz".into()),
+ Ok("gnome-shell-extension-arch-update".into()),
+ );
+}