#!/bin/sh set -e [ -n "$DEBUG" ] && set -x OS_DIR=${OS_DIR:-$HOME/os} OS_MANIFEST=$OS_DIR/manifest target=/tmp/os/ restore= list= while getopts r:lh opt; do case "$opt" in r) restore=1 target="$OPTARG" ;; l) list=1 ;; h | ?) printf "usage: %s [options]\n" "$(basename "$0")" printf "\n" printf " -l list files that would be saved\n" printf " -r TARGET restore to TARGET (default: %s)\n" "${target}" printf "\n" exit 2 ;; esac done shift $((OPTIND - 1)) tmp_prefix=os-secret- # cleanup trap '{ rm -f "/tmp/${tmp_prefix}"*; }' EXIT handle_secret() { # NOTE: we can't print anything to stdout here, only the final encrypted file # to be included in the os archive case "$1" in encrypt) # read the first line from input and use it as path IFS=$(printf '\r') read -r filepath archive=/tmp/"$tmp_prefix"$(printf "%s" "$filepath" | md5sum | cut -d' ' -f1) # create tar archive from input, descends into directory ( printf "%s\n" "$filepath" cat - ) | doas sh -c "( tar -cz -f $archive -T - 2>/dev/null; chown 1000:1000 $archive; )" # encrypt the tarfile and amend some information that makes # reconstructing easier ( sops --config /dev/null --encrypt "$archive" 2>/dev/null | jq -r '.sops.data_extension |= "tar.gz"' ) >"${archive}.enc" printf "%s\n" "${archive}.enc" ;; decrypt) while IFS=$(printf '\r') read -r line; do # if $(jq -r '.sops.data_extension' "$line") == "tar.gz" sops --config /dev/null exec-file "$line" "tar xzf - -C $target < {}" done ;; esac } handle_rules() { while IFS=$(printf '\r') read -r line; do if printf "%s" "$line" | grep -qe '#secret$'; then printf "%s\n" "$line" | sed -e 's/\s#secret//' | handle_secret encrypt else # shellcheck disable=SC2086 find "$(printf "%s\n" $line)" -print 2>/dev/null || true fi done } _rsync() { extra= [ -n "$list" ] && extra="--dry-run" rsync -v -hhh $extra \ --archive \ --links \ "$@" } if [ -n "$restore" ]; then printf "os-conf: restoring %s to %s\n" "${OS_DIR}" "${target}" >&2 mkdir -p "${target}" || true _rsync \ --exclude '/manifest' \ --exclude '/README.md' \ --exclude 'colors.todo' \ --exclude 'os-secret*.enc' \ "${OS_DIR}/" "${target}" find "${OS_DIR}" -type f -name 'os-secret*.enc' -print | handle_secret decrypt else printf "os-conf: saving to %s\n" "${OS_DIR}" >&2 uniq "$OS_MANIFEST" | grep -v '^$' | grep -v '^#' | handle_rules | _rsync --files-from=- "/" "${OS_DIR}/" fi