#!/bin/sh # @file write-as.sh # @description Server mode, one Linux user per account (S3): installed as # /opt/agenthub/libexec/write-as. The dashboard runs it AS a member through # sudo (`sudo -n -u ah- /opt/agenthub/libexec/write-as [mode]`) # for every change it makes inside that member's home — the file editor, a # `.gitignore` line, the files a pane reads (prompt, proxy settings, context # copies, drops, a session's launch file) — because the dashboard itself may # never write, chmod or delete there: the member can swap any name in their # own home, and a write by another account would follow the swap. As the # member this can only do what the member could. Content comes on stdin, # never in argv (sudo logs argv). Modes: # (none) stdin into the file in place (keeps its mode and owner) # append stdin appended # replace stdin into a new 0644 file renamed over the path (atomic) # private same, 0600 # mkdir the directory, 0755, parents included # remove the path, recursively (rm never follows a symlink it removes) # move the path to the 3rd argument (rename; never onto an existing # name — checked just before, and the dashboard checks first) # copy the path, recursively, to the 3rd argument (symlinks copied as # links, never followed; mode and times kept; never onto an # existing name) # @author Nguyễn Ngọc Trí Vĩ set -eu usage() { echo "usage: write-as [append|replace|private|mkdir|remove] | move|copy " >&2 exit 2 } case "${2:-}" in move|copy) [ $# -eq 3 ] || usage ;; *) { [ $# -ge 1 ] && [ $# -le 2 ]; } || usage ;; esac for p in "$1" "${3:-/}"; do case "$p" in /*) ;; *) echo "write-as: an absolute path is required" >&2; exit 2 ;; esac done swap() { t=$(mktemp "$1.XXXXXX") cat >"$t" && chmod "$2" "$t" && mv -f "$t" "$1" || { rm -f "$t"; exit 1; } } case "${2:-}" in "") exec cat >"$1" ;; append) exec cat >>"$1" ;; replace) swap "$1" 0644 ;; private) swap "$1" 0600 ;; mkdir) exec mkdir -p -m 0755 -- "$1" ;; remove) exec rm -rf -- "$1" ;; move) [ -e "$3" ] || [ -L "$3" ] && { echo "write-as: $3 exists" >&2; exit 1; } exec mv -T -- "$1" "$3" ;; copy) [ -e "$3" ] || [ -L "$3" ] && { echo "write-as: $3 exists" >&2; exit 1; } exec cp -R -P -T --preserve=mode,timestamps -- "$1" "$3" ;; *) echo "write-as: unknown mode: $2" >&2; exit 2 ;; esac