sandboxes.am
1 #!/bin/sh 2 3 ################################################################################################### 4 # THIS MODULE INCLUDES ALL ACTIONS INTENDED TO ISOLATE DOTFILES OR CONTAINERIZE INSTALLED APPIMAGES 5 ################################################################################################### 6 7 AMCLIPATH_ORIGIN="$AMCLIPATH" 8 SUDOCMD_ORIGIN="$SUDOCMD" 9 10 # Get xdg variables for _configure_dirs_access 11 for DIR in DESKTOP DOCUMENTS DOWNLOAD GAMES MUSIC PICTURES VIDEOS; do 12 eval XDG_DIR="$(xdg-user-dir $DIR 2>/dev/null)" 13 [ "$XDG_DIR" = "$HOME" ] || [ "$XDG_DIR" = "$HOME/" ] && XDG_DIR="" 14 eval $DIR="$XDG_DIR" 15 done 16 DESKTOP="$(echo "${DESKTOP:-~/Desktop}" | sed "s|$HOME|~|g")" 17 DOCUMENTS="$(echo "${DOCUMENTS:-~/Documents}" | sed "s|$HOME|~|g")" 18 DOWNLOAD="$(echo "${DOWNLOAD:-~/Downloads}" | sed "s|$HOME|~|g")" 19 GAMES="$(echo "${GAMES:-~/Games}" | sed "s|$HOME|~|g")" 20 MUSIC="$(echo "${MUSIC:-~/Music}" | sed "s|$HOME|~|g")" 21 PICTURES="$(echo "${PICTURES:-~/Pictures}" | sed "s|$HOME|~|g")" 22 VIDEOS="$(echo "${VIDEOS:-~/Videos}" | sed "s|$HOME|~|g")" 23 24 _check_appimage() { 25 _determine_args 26 TARGET="$(command -v "$1" 2>/dev/null)" 27 APPIMAGE="$(readlink "$TARGET" 2>/dev/null)" 28 APPIMAGEDIR="$(dirname "$APPIMAGE" 2>/dev/null)" 29 if grep "aisap-am" "$TARGET" >/dev/null 2>&1; then 30 echo " $1 is already sandboxed!" 31 return 1 32 elif [ ! -e "$APPIMAGE" ]; then 33 echo " ERROR: \"$1\" is not installed" 34 return 1 35 elif ! grep -Eaoq -m 1 -- '--appimage-extract' "$APPIMAGE"; then 36 echo " ERROR: \"$1\" is NOT an AppImage" 37 return 1 38 fi 39 } 40 41 _home() { 42 if [ -d "$APPIMAGE.home" ]; then 43 echo " ERROR: \"$1\" already contains a home dir" 44 return 1 45 fi 46 mkdir "$APPIMAGE.home" || return 1 47 echo " \$HOME set to \"$APPIMAGE.home\" for \"$1\"" 48 } 49 50 _config() { 51 if [ -d "$APPIMAGE.config" ]; then 52 echo " ERROR: \"$1\" already contains a config dir" 53 return 1 54 fi 55 mkdir "$APPIMAGE.config" || return 1 56 echo " \$XDG_CONFIG_HOME set to \"$APPIMAGE.config\" for \"$1\"" 57 } 58 59 _disable_sandbox() { 60 TARGET="$(command -v "$1")" 61 if ! grep "aisap-am sandboxing script" "$TARGET" >/dev/null 2>&1; then 62 echo " ERROR: Not a sandboxed AppImage, aborting" 63 return 1 64 fi 65 "$1" --disable-sandbox 66 } 67 68 _check_aisap() { 69 if [ "$1" = "aisap" ]; then 70 echo " Error: You can't sandbox aisap" 71 return 1 72 elif ! command -v aisap 1>/dev/null; then 73 printf '\n%s\n\n' " Error: You need aisap for this script work" 74 read -r -p " ◆ DO YOU WISH TO INSTALL AISAP? Install size <5 MiB? (Y/n) " yn 75 if echo "$yn" | grep -i '^n' >/dev/null 2>&1; then 76 echo " OPERATION ABORTED!" 77 return 1 78 fi 79 if [ "$CLI" = am ] && [ -f "$APPMANCONFIG"/appman-config ]; then 80 read -r -p " ◆ DO YOU WISH TO INSTALL AISAP LOCALLY? (Y/n) " yn 81 if echo "$yn" | grep -i '^n' >/dev/null 2>&1; then 82 "$AMCLIPATH_ORIGIN" -i aisap >/dev/null 2>&1 83 else 84 "$AMCLIPATH_ORIGIN" -i --user aisap >/dev/null 2>&1 85 fi 86 else 87 "$AMCLIPATH_ORIGIN" -i aisap >/dev/null 2>&1 88 fi 89 command -v aisap 1>/dev/null || return 1 90 echo " aisap installed successfully!" 91 fi 92 if [ -f "$BINDIR"/"$1" ]; then 93 SUDOCMD="" 94 fi 95 } 96 97 _generate_sandbox_script() { 98 echo "$DIVIDING_LINE" 99 printf '\n%s\n' " Making aisap sandbox script for \"$1\"..." 100 tmpscript="$(cat <<-'HEREDOC' 101 #!/bin/sh 102 # aisap-am sandboxing script, aisap: https://github.com/mgord9518/aisap 103 # Thanks a lot to mgord9518 for making aisap! 104 # Run this script with --disable-sandbox to do what the flag name implies 105 # The default location for the sandboxed home is in $HOME/.local/am-sandboxes 106 # But that location can be changed by setting the $SANDBOXDIR env variable 107 108 # Dependency check 109 if ! command -v aisap 1>/dev/null; then 110 echo "You need aisap for this to work" 111 notify-send -u critical "Sandbox error: Missing aisap dependency!" 112 exit 1 113 fi 114 # Set variables and create sandboxed dir. 115 APPEXEC=DUMMY 116 chmod a-x "$APPEXEC" # Prevents accidental launch of app outside the sandbox 117 APPNAME="$(echo "$APPEXEC" | awk -F "/" '{print $NF}')" 118 SANDBOXDIR="${SANDBOXDIR:-$HOME/.local/am-sandboxes}" 119 DATADIR="${XDG_DATA_HOME:-$HOME/.local/share}" 120 CONFIGDIR="${XDG_CONFIG_HOME:-$HOME/.config}" 121 CACHEDIR="${XDG_CACHE_HOME:-$HOME/.cache}" 122 DBUS="$(ls /tmp/dbus* 2>/dev/null | head -1)" 123 # get xdg user dirs, unset if var = $HOME 124 for DIR in DESKTOP DOCUMENTS DOWNLOAD GAMES MUSIC PICTURES VIDEOS; do 125 eval XDG_DIR="$(xdg-user-dir $DIR 2>/dev/null)" 126 [ "$XDG_DIR" = "$HOME" ] || [ "$XDG_DIR" = "$HOME/" ] && XDG_DIR="" 127 eval $DIR="$XDG_DIR" 128 done 129 # Use default location if var is not set 130 DESKTOP="${DESKTOP:-~/Desktop}" 131 DOCUMENTS="${DOCUMENTS:-~/Documents}" 132 DOWNLOAD="${DOWNLOAD:-~/Downloads}" 133 GAMES="${GAMES:-~/Games}" 134 MUSIC="${MUSIC:-~/Music}" 135 PICTURES="${PICTURES:-~/Pictures}" 136 VIDEOS="${VIDEOS:-~/Videos}" 137 # Try find the right name of the app conf/data dir 138 APPDATA=$( ls "$DATADIR" | grep -i "$APPNAME" | head -1 ) 139 APPCONF=$( ls "$CONFIGDIR" | grep -i "$APPNAME" | head -1 ) 140 # Disable sandbox 141 if [ "$1" = "--disable-sandbox" ]; then 142 APPIMAGEDIR="${APPEXEC%/*}" 143 echo "" 144 echo "✔ Giving exec permissions back to $APPEXEC..." \ 145 | fold -sw 77 | sed 's/^/ /g; s/ ✔/ ✔/g' 146 chmod a+x "$APPEXEC" || exit 1 147 echo "✔ Patching $APPIMAGEDIR/AM-updater to give permissions back..." \ 148 | fold -sw 77 | sed 's/^/ /g; s/ ✔/ ✔/g' 149 tmpsedEEE="$(sed 's|chmod a-x|chmod a+x|g' "$APPIMAGEDIR/AM-updater" 2>/dev/null)" 150 [ -n "$tmpsedEEE" ] && echo "$tmpsedEEE" > "$APPIMAGEDIR/AM-updater" || return 1 151 unset tmpsedEEE 152 THISFILE="$(realpath "$0")" 153 echo "✔ Replacing $THISFILE with a link to the AppImage..." \ 154 | fold -sw 77 | sed 's/^/ /g; s/ ✔/ ✔/g' 155 SUDO ln -sf "$APPEXEC" "$THISFILE" || exit 1 156 printf '\033[32m\n%s\n\033[0m\n' "✔ $APPEXEC successfully unsandboxed!" \ 157 | fold -sw 77 | sed 's/^/ /g; s/ ✔/ ✔/g' 158 exit 0 159 fi 160 mkdir -p "$SANDBOXDIR/$APPNAME" 161 [ -z "$APPNAME" ] && exit 1 162 # Start at sandboxed home 163 # Edit below this to add or remove access to parts of the system 164 exec aisap --trust-once --level 2 \ 165 --data-dir "$SANDBOXDIR/$APPNAME" \ 166 --add-file "$DATADIR/${APPDATA:-$APPNAME}":rw \ 167 --add-file "$DATADIR"/themes \ 168 --add-file "$DATADIR"/icons \ 169 --add-file "$CONFIGDIR/${APPCONF:-$APPNAME}":rw \ 170 --add-file "$CONFIGDIR"/dconf \ 171 --add-file "$CONFIGDIR"/gtk3.0 \ 172 --add-file "$CONFIGDIR"/gtk4.0 \ 173 --add-file "$CONFIGDIR"/kdeglobals \ 174 --add-file "$CONFIGDIR"/qt5ct \ 175 --add-file "$CONFIGDIR"/qt6ct \ 176 --add-file "$CONFIGDIR"/Kvantum \ 177 --add-file "$HOME"/.local/lib \ 178 --add-file /usr/share \ 179 --rm-file /NOPATH \ 180 --rm-file "$DESKTOP" \ 181 --rm-file "$DOCUMENTS" \ 182 --rm-file "$DOWNLOAD" \ 183 --rm-file "$GAMES" \ 184 --rm-file "$MUSIC" \ 185 --rm-file "$PICTURES" \ 186 --rm-file "$VIDEOS" \ 187 --add-file /var/lib/dbus \ 188 --add-file "${DBUS:-/tmp/dbus}" \ 189 --add-socket pulseaudio \ 190 --add-socket dbus \ 191 --add-socket network \ 192 --add-socket x11 \ 193 --add-socket wayland \ 194 --add-device dri -- \ 195 "$APPEXEC" "$@" 196 HEREDOC 197 )" 198 } 199 200 _configure_dirs_access() { 201 printf '\033[33m\n' 202 read -r -p " Do you want configure access to directories? (Y/n): " yn 203 if echo "$yn" | grep -i '^n' >/dev/null 2>&1; then 204 return 0 205 fi 206 printf '\033[36m' 207 for DIR in DESKTOP DOCUMENTS DOWNLOAD GAMES MUSIC PICTURES VIDEOS; do 208 eval XDG_DIR=\$$DIR 209 read -r -p " Allow $1 access to \"$XDG_DIR\"? (y/N) " yn 210 if echo "$yn" | grep -i '^y' >/dev/null 2>&1; then 211 tmpscript=$(echo "$tmpscript" \ 212 | sed "s#--rm-file \"\$$DIR\"#--add-file \"\$$DIR\":rw#g" ) 213 fi 214 done 215 sleep 0.5 216 printf '\033[31m' 217 read -r -p " Allow $1 access to a specific directory? (y/N) " yn 218 if echo "$yn" | grep -i '^y' >/dev/null 2>&1; then 219 echo " WARNING: Giving access to all of $HOME or / and similar is not safe" 220 echo " Also aisap might not let $1 start when such paths are given" 221 printf '\033[33m%s\n' " Type the path to the directory" 222 read -r -p " Example: /media/external-drive or ~/Backups: " NEWDIR 223 case "$NEWDIR" in 224 '$HOME'|'$HOME/'|"$HOME"|"$HOME/"|"/"|"~"|"~/"|"/home"|"/home/"|\ 225 "$DATADIR"|'$XDG_DATA_HOME'|"$CONFIGDIR"|'$XDG_CONFIG_HOME'|"$BINDIR") 226 notify-send -u critical "DO YOU WANT THE FBI TO GET YA?" 227 printf '\033[31m\n' 228 read -r -p " SPOOKY LOCATION! ARE YOU SURE? IF SO TYPE \"YES\": " YES 229 [ "$YES" != "YES" ] && echo " That's not \"YES\", aborting" && return 1 230 ;; 231 '') 232 printf '\033[31m\n%s\n\n' " No path given, aborting" 233 return 1 234 ;; 235 esac 236 echo " Giving access to \"$NEWDIR\"..." 237 tmpscript=$(echo "$tmpscript" \ 238 | sed "s#--rm-file /NOPATH#--add-file \"$NEWDIR\":rw#g") 239 fi 240 printf '\n\033[32m%s\n' " User directories access configured successfully!" 241 } 242 243 _install_sandbox_script() { 244 tmpscript=$(echo "$tmpscript" | sed "s#DUMMY#$APPIMAGE#g; s#SUDO#$SUDOCMD#g") 245 # Remove exec permission from AppImage and its updater for better safety™ 246 chmod a-x "$APPIMAGE" || return 1 247 tmpsedEEE="$(sed 's|chmod a+x|chmod a-x|g' "$APPIMAGEDIR/AM-updater" 2>/dev/null)" 248 [ -n "$tmpsedEEE" ] && echo "$tmpsedEEE" > "$APPIMAGEDIR/AM-updater" || return 1 249 unset tmpsedEEE 250 # Install the script 251 $SUDOCMD rm -f "$TARGET" || return 1 252 echo "$tmpscript" | $SUDOCMD tee "$TARGET" >/dev/null 2>&1 || return 1 253 $SUDOCMD chmod a+x "$TARGET" 254 SANDBOXDIR="${SANDBOXDIR:-$HOME/.local/am-sandboxes}" 255 printf '\033[32m\n%s\n\033[0m' " \"$1\" successfully sandboxed!" 256 printf '\n%s\n' " $1 will be sandboxed in \"$SANDBOXDIR\"" 257 printf '%s\n\n' " once launched" 258 printf '%s\n' " Set the \$SANDBOXDIR env variable to move the location" 259 printf '\n%s' ' Use ' 260 printf '\033[33m%s' '--disable-sandbox' 261 printf '\033[0m%s\033[33m\n' " to revert the changes, in this case that is:" 262 printf '\033[33m%s\033[0m' " $1 --disable-sandbox" 263 printf '%s\033[33m%s\n\033[0m\n' " or " "$AMCLI --disable-sandbox $1" 264 SUDOCMD="$SUDOCMD_ORIGIN" 265 } 266 267 # Main logic 268 [ -z "$2" ] && echo " USAGE: $AMCLI $1 [ARGUMENT]" && exit 1 269 case "$1" in 270 '--sandbox') 271 shift 272 while [ "$#" -gt 0 ]; do 273 _check_appimage "${@}" && _check_aisap "${@}" \ 274 && _generate_sandbox_script "${@}" \ 275 && _configure_dirs_access "${@}" \ 276 && _install_sandbox_script "${@}" 277 shift 278 done 279 ;; 280 281 '--disable-sandbox') 282 shift 283 while [ "$#" -gt 0 ]; do 284 echo "$DIVIDING_LINE" 285 _disable_sandbox "${@}" 286 shift 287 done 288 ;; 289 290 '-H'|'--home') 291 shift 292 while [ "$#" -gt 0 ]; do 293 _check_appimage "${@}" && _home "${@}" 294 shift 295 done 296 ;; 297 298 '-C'|'--config') 299 shift 300 while [ "$#" -gt 0 ]; do 301 _check_appimage "${@}" && _config "${@}" 302 shift 303 done 304 ;; 305 esac 306 _remove_info_files