sandboxes.am 10 KB

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