#!/usr/bin/bash set -Eeuo pipefail set +x umask 077 ulimit -c 0 readonly SWR_WINDOWS_UUID='4EA0196C0C5FA27E' readonly SWR_KDBX_RELATIVE='HyeonworksRecovery/vault/hyeonworks-recovery.kdbx' readonly SWR_ENTRY_GROUP='/Platform/Observability/Slack' readonly SWR_ENTRY_TITLE='Alertmanager webhook - desktop-infra-전체' readonly SWR_WORKSPACE_NAME='desktop-infra' readonly SWR_CHANNEL_NAME='desktop-infra-전체' readonly SWR_ALLOWED_SHELLOPTS="${SHELLOPTS}" _SWR_VAULT_CLIENT_SOCKET='' _SWR_VAULT_CLIENT_READ_FD='' _SWR_VAULT_CLIENT_WRITE_FD='' _SWR_VAULT_CLIENT_PID='' SWR_RECOVERY_DISK_BY_ID='' SWR_RECOVERY_PARTITION_BY_ID='' SWR_RECOVERY_FS_UUID='' SWR_RECOVERY_PARTUUID='' SWR_RECOVERY_MODEL='' SWR_RECOVERY_SERIAL='' SWR_RECOVERY_WWN='' SWR_K3S_DISK_BY_ID='' SWR_K3S_PARTITION_BY_ID='' SWR_RECOVERY_DEVICE='' SWR_TRANSACTION_STATE='' SWR_PENDING_SIGNAL=0 plain_fail() { builtin printf 'ERROR: %s\n' "$1" >&2 return 1 } _swr_has_imported_function_overrides() { local exported_line while IFS= read -r exported_line; do [[ -z "$exported_line" ]] && continue return 0 done < <(builtin declare -Fx) return 1 } _swr_shellopts_are_safe() { local shellopts="${1-}" shellopts_declaration [[ "$shellopts" == "$SWR_ALLOWED_SHELLOPTS" ]] || return 1 shellopts_declaration="$(builtin declare -p SHELLOPTS 2>/dev/null)" || return 1 [[ "$shellopts_declaration" == 'declare -r SHELLOPTS='* ]] } _swr_initial_guard() { local effective_uid="${1-}" bash_env_value="${2-}" env_value="${3-}" shellopts_value="${4-}" script_path="${5-}" [[ "$effective_uid" =~ ^[0-9]+$ && "$effective_uid" != 0 ]] || return 1 [[ -z "$bash_env_value" && -z "$env_value" ]] || return 1 _swr_shellopts_are_safe "$shellopts_value" || return 1 [[ -z "${CDPATH:-}" ]] || return 1 ! _swr_has_imported_function_overrides || return 1 [[ "$script_path" == /* ]] || return 1 [[ "$script_path" == */scripts/bootstrap/backup-slack-webhook-recovery.sh ]] || return 1 [[ -f "$script_path" && ! -L "$script_path" ]] || return 1 } _swr_output_name_is_safe() { local destination_name="${1-}" required_prefix="${2-}" [[ "$destination_name" =~ ^[A-Za-z_][A-Za-z0-9_]*$ ]] || return 1 [[ "$destination_name" == "${required_prefix}"* ]] || return 1 } _swr_parse_cli() { local mode_name="${1-}" path_name="${2-}" mode='DRY_RUN' webhook_path='' shift 2 || return 1 _swr_output_name_is_safe "$mode_name" _swr_ || return 1 _swr_output_name_is_safe "$path_name" _swr_ || return 1 case "$#" in 0) ;; 3) [[ "$1" == --execute && "$2" == --slack-webhook-file ]] || return 1 [[ "$3" == /* ]] || return 1 mode='EXECUTE' webhook_path="$3" ;; *) return 1 ;; esac builtin printf -v "$mode_name" '%s' "$mode" builtin printf -v "$path_name" '%s' "$webhook_path" } _swr_print_contract() { builtin printf '%s\n' \ 'SLACK_KEEPASS_RECOVERY_MODE=DRY_RUN' \ "WINDOWS_SSD_UUID=${SWR_WINDOWS_UUID}" \ "KDBX_RELATIVE_PATH=${SWR_KDBX_RELATIVE}" \ 'MUTATION=NOT_REQUESTED' \ 'OFF_HOST_RECOVERY_SATISFIED=NO' } _swr_require_execute_tty() { local tty_fd [[ -t 0 ]] || return 1 exec {tty_fd}<>/dev/tty || return 1 [[ -t "$tty_fd" ]] || { exec {tty_fd}>&- return 1 } exec {tty_fd}>&- } _swr_validate_runtime() { local mode="${1-}" script_path="${2-}" _swr_initial_guard "${EUID:-}" "${BASH_ENV-}" "${ENV-}" "${SHELLOPTS-}" "$script_path" || return 1 case "$mode" in DRY_RUN) return 0 ;; EXECUTE) _swr_require_execute_tty ;; *) return 1 ;; esac } _swr_command() { command "$@" } _swr_capture_command() { local output_name="${1-}" framed='' captured='' rc_text rc local frame_prefix=$'\036SWR_CAPTURE_RC=' frame_suffix shift || return 1 _swr_output_name_is_safe "$output_name" _swr_ || return 1 framed="$( set +e _swr_command "$@" 2>/dev/null _swr_framed_rc=$? builtin printf '\036SWR_CAPTURE_RC=%03d\037' "$_swr_framed_rc" )" || return 1 local LC_ALL=C (( ${#framed} >= ${#frame_prefix} + 4 )) || return 1 frame_suffix="${framed: -(${#frame_prefix} + 4)}" [[ "${frame_suffix:0:${#frame_prefix}}" == "$frame_prefix" && "${frame_suffix: -1}" == $'\037' ]] || return 1 rc_text="${frame_suffix:${#frame_prefix}:3}" [[ "$rc_text" =~ ^[0-9]{3}$ ]] || return 1 rc=$((10#$rc_text)) (( rc >= 0 && rc <= 255 )) || return 1 captured="${framed:0:${#framed}-${#frame_suffix}}" if (( ${#captured} > 16384 )); then builtin printf -v "$output_name" '%s' '' return 90 fi builtin printf -v "$output_name" '%s' "$captured" return "$rc" } _swr_load_recovery_contract() { local contract_path="${1-}" line index local -a actual=() expected=( 'K3SLR_SCHEMA_VERSION=1' 'K3SLR_RECOVERY_DISK_BY_ID=/dev/disk/by-id/wwn-0x500a0751e6aa6254' 'K3SLR_RECOVERY_PARTITION_BY_ID=/dev/disk/by-id/wwn-0x500a0751e6aa6254-part3' 'K3SLR_RECOVERY_FS_UUID=4EA0196C0C5FA27E' 'K3SLR_RECOVERY_PARTUUID=4670aa9f-9045-4bce-930d-9e84dfec9f38' 'K3SLR_RECOVERY_MODEL=CT1000MX500SSD1' 'K3SLR_RECOVERY_SERIAL=2306E6AA6254' 'K3SLR_RECOVERY_WWN=0x500a0751e6aa6254' 'K3SLR_K3S_DISK_BY_ID=/dev/disk/by-id/wwn-0x500a07512df28bd1' 'K3SLR_K3S_PARTITION_BY_ID=/dev/disk/by-id/wwn-0x500a07512df28bd1-part1' 'K3SLR_K3S_FS_UUID=b86086ef-2b3c-4638-abcf-fc7f137dcb97' 'K3SLR_K3S_PARTUUID=b081b955-d6bc-442c-ac0f-db76560a5245' 'K3SLR_K3S_MODEL=CT250MX500SSD1' 'K3SLR_K3S_SERIAL=21132DF28BD1' 'K3SLR_K3S_WWN=0x500a07512df28bd1' 'K3SLR_OWNER_UID=1000' 'K3SLR_OWNER_GID=1000' 'K3SLR_OUTER_MOUNT=/mnt/k3s-recovery-ssd' 'K3SLR_INNER_MOUNT=/srv/recovery/k3s' 'K3SLR_ROOT_RELATIVE=HyeonworksRecovery' 'K3SLR_DATABASE_RELATIVE=HyeonworksRecovery/vault/hyeonworks-recovery.kdbx' 'K3SLR_CONTAINER_RELATIVE=HyeonworksRecovery/containers/k3s-recovery.luks' 'K3SLR_RUNTIME_METADATA_RELATIVE=HyeonworksRecovery/volume.env' 'K3SLR_MAPPING_NAME=k3s-recovery' 'K3SLR_PROOF_MAPPING_NAME=k3s-recovery-proof' 'K3SLR_INNER_LABEL=K3S_RECOVERY' 'K3SLR_CONTAINER_SIZE_BYTES=34359738368' 'K3SLR_MINIMUM_FREE_BYTES=10737418240' 'K3SLR_OUTER_MIN_REMAINING_PERCENT=20' ) [[ $# -eq 1 && "$contract_path" == /* && -f "$contract_path" && ! -L "$contract_path" ]] || return 1 while IFS= builtin read -r line; do actual+=("$line") (( ${#actual[@]} <= ${#expected[@]} )) || return 1 done <"$contract_path" (( ${#actual[@]} == ${#expected[@]} )) || return 1 for index in "${!expected[@]}"; do [[ "${actual[index]}" == "${expected[index]}" ]] || return 1 done SWR_RECOVERY_DISK_BY_ID='/dev/disk/by-id/wwn-0x500a0751e6aa6254' SWR_RECOVERY_PARTITION_BY_ID='/dev/disk/by-id/wwn-0x500a0751e6aa6254-part3' SWR_RECOVERY_FS_UUID='4EA0196C0C5FA27E' SWR_RECOVERY_PARTUUID='4670aa9f-9045-4bce-930d-9e84dfec9f38' SWR_RECOVERY_MODEL='CT1000MX500SSD1' SWR_RECOVERY_SERIAL='2306E6AA6254' SWR_RECOVERY_WWN='0x500a0751e6aa6254' SWR_K3S_DISK_BY_ID='/dev/disk/by-id/wwn-0x500a07512df28bd1' SWR_K3S_PARTITION_BY_ID='/dev/disk/by-id/wwn-0x500a07512df28bd1-part1' } _swr_capture_single_line() { local output_name="${1-}" captured='' shift || return 1 _swr_capture_command "$output_name" "$@" || return 1 captured="${!output_name}" [[ "$captured" == *$'\n' ]] || return 1 captured="${captured%$'\n'}" [[ -n "$captured" && "$captured" != *$'\n'* && "$captured" != *$'\r'* ]] || return 1 builtin printf -v "$output_name" '%s' "$captured" } _swr_resolve_device() { local output_name="${1-}" local _swr_recovery_disk='' _swr_recovery_partition='' local _swr_k3s_disk='' _swr_k3s_partition='' local _swr_recovery_parent='' _swr_k3s_parent='' local _swr_uuid='' _swr_partuuid='' _swr_type='' local _swr_model='' _swr_serial='' _swr_wwn='' [[ $# -eq 1 ]] || return 1 _swr_output_name_is_safe "$output_name" _swr_ || return 1 [[ -n "$SWR_RECOVERY_DISK_BY_ID" && -n "$SWR_K3S_DISK_BY_ID" ]] || return 1 _swr_capture_single_line _swr_recovery_disk /usr/bin/readlink -e -- "$SWR_RECOVERY_DISK_BY_ID" || return 1 _swr_capture_single_line _swr_recovery_partition /usr/bin/readlink -e -- "$SWR_RECOVERY_PARTITION_BY_ID" || return 1 _swr_capture_single_line _swr_k3s_disk /usr/bin/readlink -e -- "$SWR_K3S_DISK_BY_ID" || return 1 _swr_capture_single_line _swr_k3s_partition /usr/bin/readlink -e -- "$SWR_K3S_PARTITION_BY_ID" || return 1 [[ "$_swr_recovery_disk" == /* && "$_swr_recovery_partition" == /* && "$_swr_k3s_disk" == /* && "$_swr_k3s_partition" == /* ]] || return 1 [[ "$_swr_recovery_disk" != "$_swr_recovery_partition" && "$_swr_recovery_disk" != "$_swr_k3s_disk" ]] || return 1 _swr_capture_single_line _swr_recovery_parent /usr/bin/lsblk --noheadings --raw --paths --output PKNAME -- "$_swr_recovery_partition" || return 1 _swr_capture_single_line _swr_k3s_parent /usr/bin/lsblk --noheadings --raw --paths --output PKNAME -- "$_swr_k3s_partition" || return 1 [[ "$_swr_recovery_parent" == "$_swr_recovery_disk" && "$_swr_k3s_parent" == "$_swr_k3s_disk" && "$_swr_recovery_parent" != "$_swr_k3s_parent" ]] || return 1 _swr_capture_single_line _swr_uuid /usr/sbin/blkid --output value --match-tag UUID -- "$_swr_recovery_partition" || return 1 _swr_capture_single_line _swr_partuuid /usr/sbin/blkid --output value --match-tag PARTUUID -- "$_swr_recovery_partition" || return 1 _swr_capture_single_line _swr_type /usr/sbin/blkid --output value --match-tag TYPE -- "$_swr_recovery_partition" || return 1 [[ "$_swr_uuid" == "$SWR_RECOVERY_FS_UUID" && "$_swr_partuuid" == "$SWR_RECOVERY_PARTUUID" && "$_swr_type" == ntfs ]] || return 1 _swr_capture_single_line _swr_model /usr/bin/lsblk --noheadings --raw --paths --nodeps --output MODEL -- "$_swr_recovery_disk" || return 1 _swr_capture_single_line _swr_serial /usr/bin/lsblk --noheadings --raw --paths --nodeps --output SERIAL -- "$_swr_recovery_disk" || return 1 _swr_capture_single_line _swr_wwn /usr/bin/lsblk --noheadings --raw --paths --nodeps --output WWN -- "$_swr_recovery_disk" || return 1 [[ "$_swr_model" == "$SWR_RECOVERY_MODEL" && "$_swr_serial" == "$SWR_RECOVERY_SERIAL" && "$_swr_wwn" == "$SWR_RECOVERY_WWN" ]] || return 1 SWR_RECOVERY_DEVICE="$_swr_recovery_partition" builtin printf -v "$output_name" '%s' "$_swr_recovery_partition" } _swr_findmnt_capture() { local output_name="${1-}" selector="${2-}" value="${3-}" _swr_findmnt_raw='' rc [[ $# -eq 3 ]] || return 2 _swr_output_name_is_safe "$output_name" _swr_ || return 2 case "$selector" in --source|--mountpoint) ;; *) return 2 ;; esac if _swr_capture_command _swr_findmnt_raw /usr/bin/findmnt --json "$selector" "$value" \ --output SOURCE,TARGET,FSTYPE,VFS-OPTIONS,FS-OPTIONS; then rc=0 else rc=$? fi builtin printf -v "$output_name" '%s' "$_swr_findmnt_raw" return "$rc" } _swr_require_unmounted() { local device="${1-}" _swr_findmnt_output='' rc [[ $# -eq 1 && "$device" == /* ]] || return 1 if _swr_findmnt_capture _swr_findmnt_output --source "$device"; then return 1 else rc=$? fi [[ "$rc" == 1 && -z "$_swr_findmnt_output" ]] } _swr_require_mountpoint_unused() { local mountpoint="${1-}" _swr_findmnt_output='' rc [[ $# -eq 1 && "$mountpoint" == /* ]] || return 1 if _swr_findmnt_capture _swr_findmnt_output --mountpoint "$mountpoint"; then return 1 else rc=$? fi [[ "$rc" == 1 && -z "$_swr_findmnt_output" ]] } _swr_runtime_root() { local _swr_canonical='' _swr_capture_single_line _swr_canonical /usr/bin/readlink -e -- /run/user/1000 || return 1 [[ "$_swr_canonical" == /run/user/1000 ]] || return 1 builtin printf '%s\n' "$_swr_canonical" } _swr_mountpoint_is_safe() { local mountpoint="${1-}" runtime_root metadata='' [[ $# -eq 1 ]] || return 1 runtime_root="$(_swr_runtime_root)" || return 1 [[ "$runtime_root" == /* && -d "$runtime_root" && ! -L "$runtime_root" && -O "$runtime_root" ]] || return 1 [[ "$mountpoint" == "$runtime_root/slack-webhook-recovery."* && -d "$mountpoint" && ! -L "$mountpoint" && -O "$mountpoint" ]] || return 1 _swr_capture_single_line _swr_metadata /usr/bin/stat --format=%u:%g:%a -- "$mountpoint" || return 1 metadata="$_swr_metadata" [[ "$metadata" == 1000:1000:700 ]] } _swr_create_mountpoint() { local output_name="${1-}" runtime_root _swr_mount_created='' [[ $# -eq 1 ]] || return 1 _swr_output_name_is_safe "$output_name" _swr_ || return 1 runtime_root="$(_swr_runtime_root)" || return 1 [[ "$runtime_root" == /* && -d "$runtime_root" && ! -L "$runtime_root" && -O "$runtime_root" ]] || return 1 _swr_capture_single_line _swr_mount_created /usr/bin/mktemp -d -- "$runtime_root/slack-webhook-recovery.XXXXXXXX" || return 1 [[ "$_swr_mount_created" == "$runtime_root/slack-webhook-recovery."* ]] || return 1 builtin printf -v "$output_name" '%s' "$_swr_mount_created" _swr_command /usr/bin/chmod 0700 -- "$_swr_mount_created" || return 1 _swr_mountpoint_is_safe "$_swr_mount_created" || return 1 } _swr_remove_mountpoint() { local mountpoint="${1-}" [[ $# -eq 1 ]] || return 1 _swr_mountpoint_is_safe "$mountpoint" || return 1 _swr_command /usr/bin/rmdir -- "$mountpoint" } _swr_probe_rw() { local device="${1-}" [[ $# -eq 1 && "$device" == /* ]] || return 1 _swr_command /usr/bin/sudo -n /usr/bin/timeout --signal=TERM --kill-after=5s 20s \ /usr/bin/ntfs-3g.probe --readwrite "$device" } _swr_mount_volume_command() { local device="${1-}" mountpoint="${2-}" phase="${3-}" options [[ $# -eq 3 && -n "$SWR_RECOVERY_DEVICE" && "$device" == "$SWR_RECOVERY_DEVICE" ]] || return 1 case "$phase" in ro|rw) ;; *) return 1 ;; esac _swr_mountpoint_is_safe "$mountpoint" || return 1 options="norecover,no_def_opts,allow_other,nodev,nosuid,noexec,uid=1000,gid=1000,fmask=0177,dmask=0077,${phase}" _swr_command /usr/bin/sudo -n /usr/bin/timeout --signal=TERM --kill-after=10s 45s \ /usr/bin/ntfs-3g -o "$options" "$device" "$mountpoint" } _swr_mount_volume() { local device="${1-}" mountpoint="${2-}" phase="${3-}" [[ $# -eq 3 ]] || return 1 _swr_mountpoint_is_safe "$mountpoint" || return 1 _swr_mount_volume_command "$device" "$mountpoint" "$phase" } _swr_parse_findmnt_json() { local json="${1-}" source_name="${2-}" target_name="${3-}" local fstype_name="${4-}" vfs_name="${5-}" fs_name="${6-}" parsed encoded decoded rc index local frame_marker=$'\036' LC_ALL=C local -a encoded_fields=() fields=() [[ $# -eq 6 && ${#json} -le 16384 ]] || return 1 _swr_output_name_is_safe "$source_name" _swr_ || return 1 _swr_output_name_is_safe "$target_name" _swr_ || return 1 _swr_output_name_is_safe "$fstype_name" _swr_ || return 1 _swr_output_name_is_safe "$vfs_name" _swr_ || return 1 _swr_output_name_is_safe "$fs_name" _swr_ || return 1 if parsed="$(builtin printf '%s' "$json" | _swr_command /usr/bin/jq -er ' if (type == "object" and (.filesystems | type) == "array" and (.filesystems | length) == 1) then .filesystems[0] | if (type == "object" and (.source | type) == "string" and (.target | type) == "string" and (.fstype | type) == "string" and (."vfs-options" | type) == "string" and (."fs-options" | type) == "string") then [.source, .target, .fstype, ."vfs-options", ."fs-options"] else error("invalid findmnt record") end else error("ambiguous findmnt record") end | if all(.[]; length > 0 and (test("[\\x00-\\x20\\x7f]") | not)) then .[] | @base64 else error("unsafe findmnt field") end ' 2>/dev/null)"; then (( ${#parsed} <= 16384 )) || return 1 else return 1 fi mapfile -t encoded_fields <<<"$parsed" (( ${#encoded_fields[@]} == 5 )) || return 1 for index in "${!encoded_fields[@]}"; do encoded="${encoded_fields[index]}" [[ -n "$encoded" && "$encoded" =~ ^[A-Za-z0-9+/]*={0,2}$ ]] || return 1 decoded="$({ set +e builtin printf '%s' "$encoded" | _swr_command /usr/bin/base64 --decode rc=$? builtin printf '%s' "$frame_marker" exit "$rc" })" || return 1 [[ "$decoded" == *"$frame_marker" ]] || return 1 decoded="${decoded%"$frame_marker"}" [[ -n "$decoded" && "$decoded" != *[$' \t\r\n\v\f']* && "$decoded" != *$'\177'* ]] || return 1 fields+=("$decoded") done [[ -n "${fields[0]}" && -n "${fields[1]}" && -n "${fields[2]}" ]] || return 1 builtin printf -v "$source_name" '%s' "${fields[0]}" builtin printf -v "$target_name" '%s' "${fields[1]}" builtin printf -v "$fstype_name" '%s' "${fields[2]}" builtin printf -v "$vfs_name" '%s' "${fields[3]}" builtin printf -v "$fs_name" '%s' "${fields[4]}" } _swr_option_present() { local options="${1-}" expected="${2-}" [[ ",$options," == *",$expected,"* ]] } _swr_mount_options_are_safe() { local phase="${1-}" vfs_options="${2-}" fs_options="${3-}" token local vfs_phase=0 vfs_opposite=0 vfs_nosuid=0 vfs_nodev=0 vfs_noexec=0 local vfs_relatime=0 local fs_phase=0 fs_opposite=0 fs_allow_other=0 fs_default_permissions=0 local fs_user_id=0 fs_group_id=0 fs_blksize=0 local -a tokens=() [[ $# -eq 3 ]] || return 1 case "$phase" in ro|rw) ;; *) return 1 ;; esac [[ -n "$vfs_options" && "$vfs_options" != ,* && "$vfs_options" != *, && "$vfs_options" != *,,* && "$vfs_options" != *[$' \t\r\n\v\f']* && "$vfs_options" != *$'\177'* ]] || return 1 IFS=, read -r -a tokens <<<"$vfs_options" for token in "${tokens[@]}"; do [[ -n "$token" && "$token" != *[$'\t\r\n ']* ]] || return 1 case "$token" in "$phase") vfs_phase=$((vfs_phase + 1)) ;; ro|rw) vfs_opposite=$((vfs_opposite + 1)) ;; nosuid) vfs_nosuid=$((vfs_nosuid + 1)) ;; nodev) vfs_nodev=$((vfs_nodev + 1)) ;; noexec) vfs_noexec=$((vfs_noexec + 1)) ;; relatime) vfs_relatime=$((vfs_relatime + 1)) ;; suid|dev|exec) return 1 ;; uid=*|gid=*|fmask=*|dmask=*|umask|umask=*|mask|mask=*) return 1 ;; *) return 1 ;; esac done (( vfs_phase == 1 && vfs_opposite == 0 && vfs_nosuid == 1 && vfs_nodev == 1 && vfs_noexec == 1 && vfs_relatime == 1 )) || return 1 tokens=() [[ -n "$fs_options" && "$fs_options" != ,* && "$fs_options" != *, && "$fs_options" != *,,* && "$fs_options" != *[$' \t\r\n\v\f']* && "$fs_options" != *$'\177'* ]] || return 1 IFS=, read -r -a tokens <<<"$fs_options" for token in "${tokens[@]}"; do [[ -n "$token" && "$token" != *[$'\t\r\n ']* ]] || return 1 case "$token" in "$phase") fs_phase=$((fs_phase + 1)) ;; ro|rw) fs_opposite=$((fs_opposite + 1)) ;; allow_other) fs_allow_other=$((fs_allow_other + 1)) ;; default_permissions) fs_default_permissions=$((fs_default_permissions + 1)) ;; user_id=*) fs_user_id=$((fs_user_id + 1)); [[ "$token" == user_id=0 ]] || return 1 ;; group_id=*) fs_group_id=$((fs_group_id + 1)); [[ "$token" == group_id=0 ]] || return 1 ;; blksize=*) fs_blksize=$((fs_blksize + 1)); [[ "$token" == blksize=4096 ]] || return 1 ;; uid=*|gid=*|fmask=*|dmask=*) return 1 ;; umask|umask=*|mask|mask=*) return 1 ;; suid|dev|exec) return 1 ;; *) return 1 ;; esac done (( fs_phase == 1 && fs_opposite == 0 && fs_allow_other == 1 && fs_default_permissions == 1 && fs_user_id == 1 && fs_group_id == 1 && fs_blksize == 1 )) } _swr_validate_mount() { local device="${1-}" mountpoint="${2-}" phase="${3-}" local _swr_findmnt_output='' _swr_source='' _swr_target='' local _swr_fstype='' _swr_vfs='' _swr_fs='' _swr_metadata='' [[ $# -eq 3 && "$device" == /* ]] || return 1 case "$phase" in ro|rw) ;; *) return 1 ;; esac _swr_mountpoint_is_safe "$mountpoint" || return 1 _swr_findmnt_capture _swr_findmnt_output --mountpoint "$mountpoint" || return 1 _swr_parse_findmnt_json "$_swr_findmnt_output" _swr_source _swr_target \ _swr_fstype _swr_vfs _swr_fs || return 1 [[ "$_swr_source" == "$device" && "$_swr_target" == "$mountpoint" && "$_swr_fstype" == fuseblk ]] || return 1 _swr_mount_options_are_safe "$phase" "$_swr_vfs" "$_swr_fs" || return 1 _swr_capture_single_line _swr_metadata /usr/bin/stat --format=%u:%g:%a -- "$mountpoint" || return 1 [[ "$_swr_metadata" == 1000:1000:700 ]] } _swr_stably_unmounted() { local device="${1-}" _swr_require_unmounted "$device" || return 1 _swr_require_unmounted "$device" } _swr_unmount_volume() { local device="${1-}" mountpoint="${2-}" unmount_rc=0 [[ $# -eq 2 && "$device" == /* && "$mountpoint" == /* ]] || return 1 _swr_command /usr/bin/sudo -n /usr/bin/timeout --signal=TERM --kill-after=10s 45s \ /usr/bin/umount -- "$mountpoint" >/dev/null 2>&1 || unmount_rc=$? if _swr_stably_unmounted "$device"; then return 0 fi plain_fail "manual recovery required: mount state is present or ambiguous after unmount status ${unmount_rc}" } _swr_volume_action() { local result_name="${1-}" [[ $# -eq 3 ]] || return 1 _swr_output_name_is_safe "$result_name" _swr_ || return 1 plain_fail 'encrypted database snapshot boundary is unavailable' } _swr_restore_trap() { local saved="${1-}" signal_name="${2-}" if [[ -n "$saved" ]]; then builtin eval "$saved" else builtin trap - "$signal_name" fi } _swr_run_volume_cycle() { local device="${1-}" mountpoint="${2-}" result_name="${3-}" local _swr_phase_result='' phase action_rc=0 cleanup_rc=0 mount_rc=0 final_rc=0 local _swr_cycle_signal=0 mounted=0 attempted=0 local old_hup old_int old_term [[ $# -eq 2 || $# -eq 3 ]] || return 1 [[ -z "$result_name" ]] || _swr_output_name_is_safe "$result_name" _swr_ || return 1 old_hup="$(builtin trap -p HUP)" old_int="$(builtin trap -p INT)" old_term="$(builtin trap -p TERM)" builtin trap '_swr_cycle_signal=129' HUP builtin trap '_swr_cycle_signal=130' INT builtin trap '_swr_cycle_signal=143' TERM if ! _swr_require_mountpoint_unused "$mountpoint"; then final_rc=1 elif ! _swr_mountpoint_is_safe "$mountpoint"; then final_rc=1 elif ! _swr_probe_rw "$device"; then final_rc=1 else for phase in ro rw; do if [[ "$phase" == rw ]]; then [[ "$_swr_phase_result" == mutation ]] || break if ! _swr_mountpoint_is_safe "$mountpoint"; then final_rc=1 break elif ! _swr_probe_rw "$device"; then final_rc=1 break fi fi attempted=1 if _swr_mount_volume_command "$device" "$mountpoint" "$phase"; then mounted=1 else mount_rc=$? _swr_unmount_volume "$device" "$mountpoint" || cleanup_rc=$? final_rc="$mount_rc" (( cleanup_rc == 0 )) || final_rc="$cleanup_rc" break fi if (( _swr_cycle_signal != 0 )); then action_rc="$_swr_cycle_signal" elif ! _swr_validate_mount "$device" "$mountpoint" "$phase"; then action_rc=1 elif ! _swr_volume_action _swr_phase_result "$phase" "$mountpoint"; then action_rc=$? (( action_rc == 0 )) && action_rc=1 fi _swr_unmount_volume "$device" "$mountpoint" || cleanup_rc=$? mounted=0 if (( cleanup_rc != 0 )); then final_rc="$cleanup_rc" break fi if (( _swr_cycle_signal != 0 )); then final_rc="$_swr_cycle_signal" break fi if (( action_rc != 0 )); then final_rc="$action_rc" break fi case "$phase:$_swr_phase_result" in ro:exact-noop) break ;; ro:mutation) ;; rw:complete) break ;; *) final_rc=1; break ;; esac done fi if (( mounted != 0 )); then _swr_unmount_volume "$device" "$mountpoint" || cleanup_rc=$? (( cleanup_rc == 0 )) || final_rc="$cleanup_rc" fi _swr_restore_trap "$old_hup" HUP _swr_restore_trap "$old_int" INT _swr_restore_trap "$old_term" TERM if (( final_rc == 0 )) && [[ -n "$result_name" ]]; then builtin printf -v "$result_name" '%s' "$_swr_phase_result" fi return "$final_rc" } _swr_open_recovery_boundary() { local result_name="${1-}" contract_path="${2-}" local _swr_device='' _swr_mountpoint='' _swr_boundary_result='' rc=0 [[ $# -eq 2 ]] || return 1 _swr_output_name_is_safe "$result_name" _swr_ || return 1 _swr_load_recovery_contract "$contract_path" || return 1 _swr_resolve_device _swr_device || return 1 _swr_require_unmounted "$_swr_device" || return 1 _swr_runtime_root >/dev/null || return 1 _swr_create_mountpoint _swr_mountpoint || return 1 _swr_require_mountpoint_unused "$_swr_mountpoint" || return 1 if ! _swr_command /usr/bin/sudo -v; then _swr_require_mountpoint_unused "$_swr_mountpoint" && _swr_remove_mountpoint "$_swr_mountpoint" >/dev/null 2>&1 || true return 1 fi if ! _swr_mountpoint_is_safe "$_swr_mountpoint" || ! _swr_require_mountpoint_unused "$_swr_mountpoint"; then _swr_require_mountpoint_unused "$_swr_mountpoint" && _swr_remove_mountpoint "$_swr_mountpoint" >/dev/null 2>&1 || true return 1 fi if ! _swr_run_volume_cycle "$_swr_device" "$_swr_mountpoint" _swr_boundary_result; then rc=$? (( rc == 0 )) && rc=1 fi if _swr_require_unmounted "$_swr_device" && _swr_require_mountpoint_unused "$_swr_mountpoint"; then _swr_remove_mountpoint "$_swr_mountpoint" || rc=1 else rc=1 fi if (( rc == 0 )); then builtin printf -v "$result_name" '%s' "$_swr_boundary_result" fi return "$rc" } _swr_terminate_vault_child() { local child_pid="${1-}" requested_signal="${2-TERM}" [[ ( $# -eq 1 || $# -eq 2 ) && "$child_pid" =~ ^[1-9][0-9]*$ ]] || return 1 case "$requested_signal" in HUP|INT|TERM) ;; *) return 1 ;; esac kill -"$requested_signal" "$child_pid" 2>/dev/null || true if ! /usr/bin/timeout --signal=TERM --kill-after=0.1s 1s \ /usr/bin/tail --pid="$child_pid" -f /dev/null >/dev/null 2>&1; then kill -KILL "$child_pid" 2>/dev/null || true fi wait "$child_pid" 2>/dev/null || true ! kill -0 "$child_pid" 2>/dev/null } _swr_wait_vault_ready() { local socket_path="${1-}" child_pid="${2-}" attempts="${3-}" attempt [[ $# -eq 3 && "$socket_path" == /* && "$child_pid" =~ ^[1-9][0-9]*$ && "$attempts" =~ ^[1-9][0-9]*$ ]] || return 1 for (( attempt = 0; attempt < attempts; attempt++ )); do (( SWR_PENDING_SIGNAL == 0 )) || return 2 if [[ -S "$socket_path" && ! -L "$socket_path" ]]; then return 0 fi [[ ! -e "$socket_path" && ! -L "$socket_path" ]] || return 1 if ! kill -0 "$child_pid" 2>/dev/null; then return 1 fi /usr/bin/sleep 0.05 done return 1 } _swr_start_vault() { local pid_name="${1-}" socket_name="${2-}" runtime_root="${3-}" webhook_file="${4-}" local repository_root="${SWR_REPOSITORY_ROOT-}" helper socket_path child_pid readiness_rc=0 [[ $# -eq 4 ]] || return 1 _swr_output_name_is_safe "$pid_name" _swr_ || return 1 _swr_output_name_is_safe "$socket_name" _swr_ || return 1 [[ "$repository_root" == /* && "$runtime_root" == /* && "$webhook_file" == /* ]] || return 1 helper="${repository_root}/scripts/libexec/slack-webhook-recovery-vault.py" socket_path="${runtime_root}/vault.sock" [[ -f "$helper" && ! -L "$helper" ]] || return 1 [[ -d "$runtime_root" && ! -L "$runtime_root" ]] || return 1 [[ ! -e "$socket_path" && ! -L "$socket_path" ]] || return 1 /usr/bin/env -i HOME=/nonexistent LC_ALL=C.UTF-8 PATH=/usr/bin:/bin \ /usr/bin/python3 "$helper" --serve --runtime-root "$runtime_root" \ --webhook-file "$webhook_file" & child_pid=$! _swr_wait_vault_ready "$socket_path" "$child_pid" 18000 || readiness_rc=$? if (( readiness_rc != 0 || SWR_PENDING_SIGNAL != 0 )); then case "$SWR_PENDING_SIGNAL" in 129) _swr_terminate_vault_child "$child_pid" HUP || true ;; 130) _swr_terminate_vault_child "$child_pid" INT || true ;; 143) _swr_terminate_vault_child "$child_pid" TERM || true ;; *) _swr_terminate_vault_child "$child_pid" TERM || true ;; esac return 1 fi builtin printf -v "$pid_name" '%s' "$child_pid" builtin printf -v "$socket_name" '%s' "$socket_path" return 0 } _swr_vault_request() { local result_name="${1-}" socket_path="${2-}" command="${3-}" reply [[ $# -eq 3 ]] || return 1 _swr_output_name_is_safe "$result_name" _swr_ || return 1 [[ "$socket_path" == /* && -S "$socket_path" && ! -L "$socket_path" ]] || return 1 case "$command" in PREPARE|'BUILD ADD'|'BUILD UPDATE'|VERIFY_CANDIDATE|SHUTDOWN) ;; 'VERIFY_COMMITTED '/*) [[ "${command#VERIFY_COMMITTED }" != *' '* ]] || return 1 ;; *) return 1 ;; esac if [[ -z "$_SWR_VAULT_CLIENT_SOCKET" ]]; then coproc SWR_VAULT_CLIENT { /usr/bin/timeout --signal=TERM --kill-after=1s 900s \ /usr/bin/socat - "UNIX-CONNECT:${socket_path}" 2>/dev/null } _SWR_VAULT_CLIENT_PID="$SWR_VAULT_CLIENT_PID" exec {_SWR_VAULT_CLIENT_READ_FD}<&"${SWR_VAULT_CLIENT[0]}" || return 1 exec {_SWR_VAULT_CLIENT_WRITE_FD}>&"${SWR_VAULT_CLIENT[1]}" || return 1 _SWR_VAULT_CLIENT_SOCKET="$socket_path" fi [[ "$_SWR_VAULT_CLIENT_SOCKET" == "$socket_path" ]] || return 1 builtin printf '%s\n' "$command" >&"$_SWR_VAULT_CLIENT_WRITE_FD" || return 1 IFS= builtin read -r -t 20 -u "$_SWR_VAULT_CLIENT_READ_FD" reply || return 1 case "$reply" in absent|exact-noop|mismatch|ambiguous|failed|candidate-ready|verified|stopped) builtin printf -v "$result_name" '%s' "$reply" ;; *) return 1 ;; esac } _swr_stop_vault() { local socket_path="${1-}" child_pid="${2-}" _swr_stop_reply='' local shutdown_ok=1 [[ $# -eq 2 && "$child_pid" =~ ^[1-9][0-9]*$ ]] || return 1 if [[ -S "$socket_path" && ! -L "$socket_path" ]]; then _swr_vault_request _swr_stop_reply "$socket_path" SHUTDOWN || shutdown_ok=0 [[ "$_swr_stop_reply" == stopped ]] || shutdown_ok=0 fi if [[ -n "$_SWR_VAULT_CLIENT_WRITE_FD" ]]; then exec {_SWR_VAULT_CLIENT_WRITE_FD}>&- fi if [[ -n "$_SWR_VAULT_CLIENT_READ_FD" ]]; then exec {_SWR_VAULT_CLIENT_READ_FD}<&- fi if [[ -n "$_SWR_VAULT_CLIENT_PID" ]]; then (( shutdown_ok != 0 )) || kill -TERM "$_SWR_VAULT_CLIENT_PID" 2>/dev/null || true wait "$_SWR_VAULT_CLIENT_PID" 2>/dev/null || true fi _SWR_VAULT_CLIENT_SOCKET='' _SWR_VAULT_CLIENT_READ_FD='' _SWR_VAULT_CLIENT_WRITE_FD='' _SWR_VAULT_CLIENT_PID='' if (( shutdown_ok == 0 )); then kill -TERM "$child_pid" 2>/dev/null || true wait "$child_pid" 2>/dev/null || true return 1 fi /usr/bin/timeout --signal=TERM --kill-after=1s 10s \ /usr/bin/tail --pid="$child_pid" -f /dev/null >/dev/null 2>&1 || { kill -TERM "$child_pid" 2>/dev/null || true wait "$child_pid" 2>/dev/null || true return 1 } wait "$child_pid" } defer_signal() { case "${1-}" in HUP) SWR_PENDING_SIGNAL=129 ;; INT) SWR_PENDING_SIGNAL=130 ;; TERM) SWR_PENDING_SIGNAL=143 ;; *) return 1 ;; esac } _swr_work_root_is_safe() { local work_root="${1-}" _swr_metadata='' _swr_filesystem='' [[ $# -eq 1 && "$work_root" == /run/user/1000/platform-slack-keepass.* && -d "$work_root" && ! -L "$work_root" && -O "$work_root" ]] || return 1 _swr_capture_single_line _swr_metadata /usr/bin/stat --format=%u:%g:%a -- "$work_root" || return 1 _swr_capture_single_line _swr_filesystem /usr/bin/stat --file-system --format=%T -- "$work_root" || return 1 [[ "$_swr_metadata" == 1000:1000:700 && "$_swr_filesystem" == tmpfs ]] } _swr_prepare_transaction() { local work_name="${1-}" device_name="${2-}" mount_name="${3-}" local webhook_file="${4-}" contract_path="${5-}" local _swr_prepared_device='' _swr_prepared_work_root='' _swr_prepared_mountpoint='' local _swr_runtime_metadata='' _swr_runtime_filesystem='' [[ $# -eq 5 && "$webhook_file" == /* && "$contract_path" == /* ]] || return 1 _swr_output_name_is_safe "$work_name" _swr_ || return 1 _swr_output_name_is_safe "$device_name" _swr_ || return 1 _swr_output_name_is_safe "$mount_name" _swr_ || return 1 _swr_load_recovery_contract "$contract_path" || return 1 _swr_resolve_device _swr_prepared_device || return 1 builtin printf -v "$device_name" '%s' "$_swr_prepared_device" _swr_require_unmounted "$_swr_prepared_device" || return 1 [[ "$(_swr_runtime_root)" == /run/user/1000 ]] || return 1 _swr_capture_single_line _swr_runtime_metadata /usr/bin/stat --format=%u:%g:%a -- /run/user/1000 || return 1 _swr_capture_single_line _swr_runtime_filesystem /usr/bin/stat --file-system --format=%T -- /run/user/1000 || return 1 [[ "$_swr_runtime_metadata" == 1000:1000:700 && "$_swr_runtime_filesystem" == tmpfs ]] || return 1 _swr_capture_single_line _swr_prepared_work_root /usr/bin/mktemp -d --tmpdir=/run/user/1000 \ platform-slack-keepass.XXXXXXXX || return 1 builtin printf -v "$work_name" '%s' "$_swr_prepared_work_root" if ! _swr_command /usr/bin/chmod 0700 -- "$_swr_prepared_work_root" || ! _swr_work_root_is_safe "$_swr_prepared_work_root"; then return 1 fi if _swr_create_mountpoint _swr_prepared_mountpoint; then builtin printf -v "$mount_name" '%s' "$_swr_prepared_mountpoint" else builtin printf -v "$mount_name" '%s' "$_swr_prepared_mountpoint" return 1 fi _swr_require_mountpoint_unused "$_swr_prepared_mountpoint" || return 1 } _swr_refresh_sudo() { _swr_command /usr/bin/sudo -v } _swr_dirfd_helper() { local repository_root="${SWR_REPOSITORY_ROOT-}" helper helper="${repository_root}/scripts/libexec/slack-webhook-recovery-dirfd.py" [[ "$repository_root" == /* && -f "$helper" && ! -L "$helper" ]] || return 1 _swr_command /usr/bin/env -i LC_ALL=C.UTF-8 PATH=/usr/bin:/bin \ /usr/bin/python3 "$helper" "$@" } _swr_dirfd_snapshot() { local mountpoint="${1-}" work_root="${2-}" [[ $# -eq 2 ]] || return 1 _swr_dirfd_helper snapshot --mount-root "$mountpoint" \ --destination "$work_root/baseline.kdbx" --result "$work_root/baseline.json" } _swr_audit_runtime_processes() { local work_root="${1-}" [[ $# -eq 1 && "$work_root" == /* ]] || return 1 _swr_dirfd_helper audit-processes --runtime-root "$work_root" } _swr_dirfd_snapshot_current() { local mountpoint="${1-}" work_root="${2-}" [[ $# -eq 2 ]] || return 1 _swr_dirfd_helper snapshot-current --mount-root "$mountpoint" \ --candidate "$work_root/candidate.kdbx" --destination "$work_root/current.kdbx" \ --result "$work_root/current.json" } _swr_dirfd_commit() { local result_name="${1-}" mountpoint="${2-}" work_root="${3-}" local backup_name="${4-}" _swr_fs_status='' command_rc=0 [[ $# -eq 4 ]] || return 1 _swr_output_name_is_safe "$result_name" _swr_ || return 1 if _swr_dirfd_helper commit --mount-root "$mountpoint" \ --baseline "$work_root/baseline.json" --candidate "$work_root/candidate.kdbx" \ --backup-name "$backup_name" --result "$work_root/commit.json"; then command_rc=0 else command_rc=$? fi if _swr_fs_status="$(_swr_dirfd_helper status --result "$work_root/commit.json")"; then [[ -n "$_swr_fs_status" && "$_swr_fs_status" != *$'\n'* && "$_swr_fs_status" != *$'\r'* ]] || return 1 case "$_swr_fs_status" in precommit-failure|rename-attempted|verified-commit|committed-but-uncertain) ;; *) return 1 ;; esac builtin printf -v "$result_name" '%s' "$_swr_fs_status" else builtin printf -v "$result_name" '%s' missing fi [[ "$_swr_fs_status" == verified-commit ]] && command_rc=0 return "$command_rc" } _swr_confirm_token() { local expected="${1-}" prompt tty_fd reply='' case "$expected" in UPDATE) prompt='Type UPDATE SLACK KDBX default: ' ;; WRITE) prompt='Type WRITE SLACK KDBX default: ' ;; *) return 1 ;; esac exec {tty_fd}<>/dev/tty || return 1 builtin printf '%s' "$prompt" >&"$tty_fd" IFS= builtin read -r -u "$tty_fd" reply || { exec {tty_fd}>&- return 1 } exec {tty_fd}>&- [[ "$reply" == "$expected SLACK KDBX default" ]] } _swr_inventory_directory() { local output_name="${1-}" directory="${2-}" inventory_fd inventory_pid local original_read_fd original_write_fd record='' producer_rc=0 framing_rc=0 local record_bytes=0 total_bytes=0 next_total=0 LC_ALL=C local -n output_ref="$output_name" [[ $# -eq 2 && "$directory" == /* ]] || return 1 _swr_output_name_is_safe "$output_name" _swr_ || return 1 output_ref=() coproc SWR_INVENTORY_PROCESS { _swr_command /usr/bin/find "$directory" -mindepth 1 -maxdepth 1 -printf '%f\0' } inventory_pid="$SWR_INVENTORY_PROCESS_PID" original_read_fd="${SWR_INVENTORY_PROCESS[0]}" original_write_fd="${SWR_INVENTORY_PROCESS[1]}" if ! exec {inventory_fd}<&"$original_read_fd"; then kill -TERM "$inventory_pid" 2>/dev/null || true wait "$inventory_pid" 2>/dev/null || true unset SWR_INVENTORY_PROCESS SWR_INVENTORY_PROCESS_PID return 1 fi exec {original_read_fd}<&- exec {original_write_fd}>&- while true; do record='' if IFS= builtin read -r -d '' -n 256 -u "$inventory_fd" record; then record_bytes=${#record} next_total=$((total_bytes + record_bytes)) if (( record_bytes < 1 || record_bytes > 255 || next_total > 4096 || ${#output_ref[@]} >= 16 )) || [[ "$record" == */* || "$record" == . || "$record" == .. ]]; then framing_rc=1 break fi output_ref+=("$record") total_bytes=$next_total else if [[ -n "$record" ]]; then framing_rc=1 fi break fi done exec {inventory_fd}<&- if (( framing_rc != 0 )); then kill -TERM "$inventory_pid" 2>/dev/null || true fi if wait "$inventory_pid"; then producer_rc=0 else producer_rc=$? fi unset SWR_INVENTORY_PROCESS SWR_INVENTORY_PROCESS_PID (( producer_rc == 0 && framing_rc == 0 )) } _swr_remove_work_root() { local work_root="${1-}" path name _swr_metadata='' local -a _swr_inventory=() local -a owned_files=( baseline.kdbx baseline.json candidate.kdbx current.kdbx current.json commit.json ) [[ $# -eq 1 ]] || return 1 _swr_work_root_is_safe "$work_root" || return 1 [[ ! -e "$work_root/vault.sock" && ! -L "$work_root/vault.sock" ]] || return 1 local -A expected=() for name in "${owned_files[@]}"; do expected["$name"]=1; done _swr_inventory_directory _swr_inventory "$work_root" || return 1 for name in "${_swr_inventory[@]}"; do [[ -n "${expected[$name]+x}" ]] || return 1 done for name in "${owned_files[@]}"; do path="$work_root/$name" [[ -e "$path" || -L "$path" ]] || continue [[ -f "$path" && ! -L "$path" && -O "$path" ]] || return 1 _swr_capture_single_line _swr_metadata /usr/bin/stat --format=%u:%g:%a:%h -- "$path" || return 1 [[ "$_swr_metadata" == 1000:1000:600:1 ]] || return 1 done for path in "${owned_files[@]}"; do path="$work_root/$path" [[ -e "$path" || -L "$path" ]] || continue [[ -f "$path" && ! -L "$path" && -O "$path" ]] || return 1 _swr_capture_single_line _swr_metadata /usr/bin/stat --format=%u:%g:%a:%h -- "$path" || return 1 [[ "$_swr_metadata" == 1000:1000:600:1 ]] || return 1 _swr_command /usr/bin/rm -f -- "$path" || return 1 done _swr_command /usr/bin/rmdir -- "$work_root" } cleanup_transaction() { local work_root="${1-}" device="${2-}" mountpoint="${3-}" local socket_path="${4-}" child_pid="${5-}" rc=0 unmounted=0 [[ $# -eq 5 ]] || return 1 if [[ -n "$child_pid" ]]; then _swr_stop_vault "$socket_path" "$child_pid" || rc=1 fi if [[ -n "$work_root" ]]; then _swr_audit_runtime_processes "$work_root" || rc=1 fi if [[ -n "$device" ]] && _swr_stably_unmounted "$device"; then unmounted=1 elif [[ -n "$device" ]]; then rc=1 fi if (( unmounted != 0 )) && [[ -n "$mountpoint" && -d "$mountpoint" ]]; then _swr_require_mountpoint_unused "$mountpoint" && _swr_remove_mountpoint "$mountpoint" || rc=1 fi if (( unmounted != 0 )) && [[ -n "$work_root" ]]; then _swr_remove_work_root "$work_root" || rc=1 fi return "$rc" } _swr_restore_transaction_traps() { _swr_restore_trap "$1" HUP _swr_restore_trap "$2" INT _swr_restore_trap "$3" TERM } _swr_unmount_transaction_once() { local mounted_name="${1-}" device="${2-}" mountpoint="${3-}" [[ $# -eq 3 && "$mounted_name" == mounted ]] || return 1 # Prearm the no-retry state before the potentially ambiguous unmount call. builtin printf -v "$mounted_name" '%s' 0 _swr_unmount_volume "$device" "$mountpoint" } execute_transaction() { local webhook_file="${1-}" contract_path="${2-}" local _swr_work_root='' _swr_device='' _swr_mountpoint='' local _swr_vault_pid='' _swr_vault_socket='' _swr_reply='' _swr_fs_commit='' local backup_name='' mounted=0 cleanup_rc=0 final_rc=1 TZ=UTC0 local old_hup old_int old_term [[ $# -eq 2 && "$webhook_file" == /* && "$contract_path" == /* ]] || return 1 SWR_TRANSACTION_STATE=PRECOMMIT_FAILURE SWR_PENDING_SIGNAL=0 old_hup="$(builtin trap -p HUP)" old_int="$(builtin trap -p INT)" old_term="$(builtin trap -p TERM)" builtin trap 'defer_signal HUP' HUP builtin trap 'defer_signal INT' INT builtin trap 'defer_signal TERM' TERM if _swr_prepare_transaction _swr_work_root _swr_device _swr_mountpoint \ "$webhook_file" "$contract_path" && (( SWR_PENDING_SIGNAL == 0 )) && _swr_start_vault _swr_vault_pid _swr_vault_socket "$_swr_work_root" "$webhook_file" && (( SWR_PENDING_SIGNAL == 0 )) && _swr_refresh_sudo && (( SWR_PENDING_SIGNAL == 0 )) && _swr_probe_rw "$_swr_device" && (( SWR_PENDING_SIGNAL == 0 )); then mounted=1 if _swr_mount_volume_command "$_swr_device" "$_swr_mountpoint" ro && (( SWR_PENDING_SIGNAL == 0 )) && _swr_validate_mount "$_swr_device" "$_swr_mountpoint" ro && (( SWR_PENDING_SIGNAL == 0 )) && _swr_dirfd_snapshot "$_swr_mountpoint" "$_swr_work_root" && (( SWR_PENDING_SIGNAL == 0 )) && _swr_unmount_transaction_once mounted "$_swr_device" "$_swr_mountpoint" && (( SWR_PENDING_SIGNAL == 0 )); then if _swr_vault_request _swr_reply "$_swr_vault_socket" PREPARE; then (( SWR_PENDING_SIGNAL == 0 )) || _swr_reply=signal-pending case "$_swr_reply" in exact-noop) if (( SWR_PENDING_SIGNAL == 0 )); then SWR_TRANSACTION_STATE=NOOP final_rc=0 fi ;; absent|mismatch) if [[ "$_swr_reply" == mismatch ]] && ! _swr_confirm_token UPDATE; then final_rc=1 elif (( SWR_PENDING_SIGNAL == 0 )) && _swr_vault_request _swr_reply "$_swr_vault_socket" \ "BUILD $([[ "$_swr_reply" == absent ]] && builtin printf ADD || builtin printf UPDATE)" && [[ "$_swr_reply" == candidate-ready ]] && (( SWR_PENDING_SIGNAL == 0 )) && _swr_vault_request _swr_reply "$_swr_vault_socket" VERIFY_CANDIDATE && [[ "$_swr_reply" == verified ]] && (( SWR_PENDING_SIGNAL == 0 )) && _swr_confirm_token WRITE && (( SWR_PENDING_SIGNAL == 0 )) && _swr_probe_rw "$_swr_device" && (( SWR_PENDING_SIGNAL == 0 )); then mounted=1 if _swr_mount_volume_command "$_swr_device" "$_swr_mountpoint" rw && (( SWR_PENDING_SIGNAL == 0 )) && _swr_validate_mount "$_swr_device" "$_swr_mountpoint" rw && (( SWR_PENDING_SIGNAL == 0 )); then builtin printf -v backup_name 'hyeonworks-recovery.pre-slack-%(%Y%m%dT%H%M%SZ)T.kdbx' -1 if _swr_dirfd_commit _swr_fs_commit "$_swr_mountpoint" "$_swr_work_root" "$backup_name"; then if [[ "$_swr_fs_commit" == verified-commit ]]; then if (( SWR_PENDING_SIGNAL != 0 )); then SWR_TRANSACTION_STATE=COMMITTED_BUT_UNCERTAIN elif _swr_dirfd_snapshot_current "$_swr_mountpoint" "$_swr_work_root" && _swr_vault_request _swr_reply "$_swr_vault_socket" \ "VERIFY_COMMITTED $_swr_work_root/current.kdbx" && [[ "$_swr_reply" == verified ]] && (( SWR_PENDING_SIGNAL == 0 )); then SWR_TRANSACTION_STATE=VERIFIED_COMMIT else SWR_TRANSACTION_STATE=COMMITTED_BUT_UNCERTAIN fi else SWR_TRANSACTION_STATE=COMMITTED_BUT_UNCERTAIN fi else case "$_swr_fs_commit" in precommit-failure) SWR_TRANSACTION_STATE=PRECOMMIT_FAILURE ;; rename-attempted|committed-but-uncertain|missing) SWR_TRANSACTION_STATE=COMMITTED_BUT_UNCERTAIN ;; *) SWR_TRANSACTION_STATE=COMMITTED_BUT_UNCERTAIN ;; esac fi if _swr_unmount_transaction_once mounted "$_swr_device" "$_swr_mountpoint"; then [[ "$SWR_TRANSACTION_STATE" == VERIFIED_COMMIT ]] && final_rc=0 || final_rc=1 else SWR_TRANSACTION_STATE=MANUAL_RECOVERY_REQUIRED final_rc=1 fi fi fi ;; ambiguous|failed) final_rc=1 ;; signal-pending) final_rc=1 ;; *) final_rc=1 ;; esac fi fi fi if (( mounted != 0 )); then if _swr_unmount_volume "$_swr_device" "$_swr_mountpoint"; then mounted=0 else SWR_TRANSACTION_STATE=MANUAL_RECOVERY_REQUIRED fi fi cleanup_transaction "$_swr_work_root" "$_swr_device" "$_swr_mountpoint" \ "$_swr_vault_socket" "$_swr_vault_pid" || cleanup_rc=$? if (( cleanup_rc != 0 )); then SWR_TRANSACTION_STATE=MANUAL_RECOVERY_REQUIRED final_rc=1 fi if (( SWR_PENDING_SIGNAL != 0 )); then final_rc="$SWR_PENDING_SIGNAL" fi case "$SWR_TRANSACTION_STATE" in NOOP) (( final_rc == 0 && SWR_PENDING_SIGNAL == 0 )) && builtin printf '%s\n' \ 'SLACK_KEEPASS_RECOVERY=NOOP' \ 'WINDOWS_SSD_UNMOUNTED=PASS' \ 'OFF_HOST_RECOVERY_SATISFIED=NO' ;; VERIFIED_COMMIT) (( final_rc == 0 && SWR_PENDING_SIGNAL == 0 )) && builtin printf '%s\n' \ 'SLACK_KEEPASS_RECOVERY=COMMITTED' \ 'KDBX_PRECHANGE_BACKUP=CREATED' \ 'WINDOWS_SSD_UNMOUNTED=PASS' \ 'OFF_HOST_RECOVERY_SATISFIED=NO' ;; COMMITTED_BUT_UNCERTAIN|MANUAL_RECOVERY_REQUIRED) builtin printf '%s\n' 'SLACK_KEEPASS_RECOVERY=MANUAL_RECOVERY_REQUIRED' final_rc=1 ;; esac (( SWR_PENDING_SIGNAL == 0 )) || final_rc="$SWR_PENDING_SIGNAL" _swr_restore_transaction_traps "$old_hup" "$old_int" "$old_term" return "$final_rc" } _swr_main() { local script_path="$0" _swr_mode _swr_webhook_path if [[ "$script_path" == 'scripts/bootstrap/backup-slack-webhook-recovery.sh' ]]; then script_path="${SWR_REPOSITORY_ROOT}/scripts/bootstrap/backup-slack-webhook-recovery.sh" fi _swr_parse_cli _swr_mode _swr_webhook_path "$@" || { plain_fail 'expected no arguments or exactly --execute --slack-webhook-file ABSOLUTE_PATH' return 1 } _swr_validate_runtime "$_swr_mode" "$script_path" || { plain_fail 'runtime guard rejected the invocation' return 1 } case "$_swr_mode" in DRY_RUN) _swr_print_contract ;; EXECUTE) [[ -n "$_swr_webhook_path" ]] || { plain_fail 'absolute webhook path is required' return 1 } execute_transaction "$_swr_webhook_path" "${SWR_RECOVERY_CONTRACT-}" ;; *) plain_fail 'unsupported mode' return 1 ;; esac } if [[ "${BASH_SOURCE[0]}" != "$0" ]]; then return 0 fi _swr_main "$@"