Skip to content

Instantly share code, notes, and snippets.

@kriswebdev
Last active April 17, 2016 10:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kriswebdev/de1fc97a508d04563d7a to your computer and use it in GitHub Desktop.
Save kriswebdev/de1fc97a508d04563d7a to your computer and use it in GitHub Desktop.
Vuze Private Profile
#!/bin/bash
# === INFO ===
# Vuze Private Profile (LINUX)
# Author: KrisWebDev
# Version: 1.1.1
# Description: Switch Vuze to a private profile, where downloaded files and settings are stored in a password-protected encrypted directory.
# Warnings: This app only provides PARTIAL LOCAL security, and DOESN'T provide anonymity over the network! It does NOT replace a proxy/VPN/ToR!
# Encrypted filesystem (encfs) is easy to use but it DOESN'T provide "plausible deniability".
# It is recommended to manually disable Vuze UPnP plugin in the private profile.
# Requirements: Linux (only tested on Ubuntu with bash)
# encfs (sudo apt-get install encfs)
# Vuze 5.7.1.0 and above (bugfix to open .torrent files)
# Uninstall Vuze
# Reinstall Vuze manually:
# https://wiki.vuze.com/w/Initial_Setup_Guide#Manual_install_from_Vuze_website
# Then go in Vuze > Help > "Join Beta Program" then "Check for Updates"
# Additional Requirements for hidden mode:
# screen, mkpasswd (sudo apt-get install screen whois)
# Vuze must be able to find log4j.jar & commons-cli.jar. For manual install, put these in Azureus2.jar folder: http://svn.vuze.com/public/client/trunk/uis/lib/
# === LICENSE ===
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# === CONFIGURATION ===
# Crypted dir (download content, torrent files and private settings):
CRYPTED_DIR=$(xdg-user-dir DOWNLOAD)"/vuze-crypt"
# Virtual mount point (unencrypted view of crypted dir):
# Note: It is recommended to use a leading dot for the mount name,
# to consider it as hidden by the system.
# Don't change this after initial run! If you do, use a new empty CRYPTED_DIR or manually change all Vuze Options > Files > * path.
MOUNT_DIR=$(xdg-user-dir DOWNLOAD)"/.vuze-private"
# Optional *SUB*directory for the complete files, with trailing slash.
MOUNT_COMPLETE_SUBDIR="/complete"
# Where is your Vuze startup script?
# It's the "azureus" or "vuze" executable file, the *REAL* one with java or run_java statement inside, not a redirect
VUZE_STARTUP_SCRIPT="/usr/bin/azureus"
# Accelerate Vuze damn slow UI (true/false)
OPENGL_ACCELERATION=true
# Advanced configuration, avoid changing this.
# Path to existing Vuze public configuration:
VUZE_PUBLIC_CONF=~/".azureus"
# If anything ain't working, enable this
DEBUG=false
# === CODE ===
me=`basename "$0"`
# DON'T move it outside $MOUNT_DIR !
VUZE_PRIVATE_CONF="$MOUNT_DIR/.azureus-private"
VUZE_X_JAVA_ARGS=""
VUZE_X_JAVA_ARGS_COMP=""
RUN_VUZE_BACKGROUND=true
start_vuze_private() {
if [ "$OPENGL_ACCELERATION" = true ]; then
VUZE_X_JAVA_ARGS="-Dsun.java2d.opengl=true"
fi
# As the startup script pass arguments to Vuze and not Java, we need to rewrite it
launcher_script_public=$(< "$VUZE_STARTUP_SCRIPT")
cd "$(dirname "$VUZE_STARTUP_SCRIPT")"
# Script is maybe a redirect. Let's try to find the real vuze launch script
if [[ "$launcher_script_public" != *"-Dazureus.install.path"* ]]; then
real_script_path=$(sed -n -e 's/^\s*["'\'']\?\(.\+\(vuze\|azureus\)\)["'\'']\?\s*"\?\$@\?"\?\s*$/\1/p' -e '//q' "$VUZE_STARTUP_SCRIPT")
if [ -z "$real_script_path" ]; then
real_script_path=$(sed -n -e 's/^\s*["'\'']\?\(.\+\(vuze\|azureus\)\)["'\'']\?\s*"\?\$@\?"\?\s*$/\1/p' -e '//q' /usr/bin/vuze)
VUZE_STARTUP_SCRIPT="/usr/bin/vuze"
fi
if [ -z "$real_script_path" ]; then
real_script_path=$(sed -n -e 's/^\s*["'\'']\?\(.\+\(vuze\|azureus\)\)["'\'']\?\s*"\?\$@\?"\?\s*$/\1/p' -e '//q' /usr/bin/azureus)
VUZE_STARTUP_SCRIPT="/usr/bin/azureus"
fi
if [ ! -z "$real_script_path" ]; then
# Unescape
real_script_path=$(echo "$real_script_path" | sed -r 's/\\(.)/\1/g')
echo "VUZE_STARTUP_SCRIPT (${VUZE_STARTUP_SCRIPT}) is a redirect."
echo "Real Vuze launch script found at: \"${real_script_path}\""
launcher_script_public=$(< "${real_script_path}")
cd "$(dirname "${real_script_path}")"
fi
fi
if [[ "$launcher_script_public" == *"-Dazureus.install.path"* ]]; then
# Append java args
launcher_script_private=${launcher_script_public//-Dazureus.install.path/-Dazureus.config.path=\"\$\{VUZE_PRIVATE_CONF\}\" "\$VUZE_X_JAVA_ARGS" "\$VUZE_X_JAVA_ARGS_COMP" -Dazureus.install.path}
if [[ "$@" == *"--ui=console"* ]]; then
echo "Using console UI in foreground."
launcher_script_private=${launcher_script_private//org.gudy.azureus2.ui.swt.Main/org.gudy.azureus2.ui.common.Main}
eval "$launcher_script_private"
fusermount -u "$MOUNT_DIR" # Soft unmount after Vuze closure
else
# Debug:
# eval "$launcher_script_private" &
if [ "$RUN_VUZE_BACKGROUND" = true ]; then
if [ "$DEBUG" = false ]; then
eval "$launcher_script_private" > /dev/null 2>&1 &
else
eval "$launcher_script_private" &
fi
else # Avoid closing the screen until Vuze has closed
if [ "$DEBUG" = false ]; then
eval "$launcher_script_private" > /dev/null 2>&1
else
eval "$launcher_script_private"
fi
# TODO: Auto-close the mount when Vuze closes ("start" mode)
fi
fi
sleep 2
else
echo "ERROR: You need to properly reference the configuration variable VUZE_STARTUP_SCRIPT. Aborting."
sleep 20
exit 1
fi
}
# close_app GREP_STATEMENT SIGNAL
# GREP_STATEMENT must not match itself!
close_app() {
APP_PID=$(ps -x | grep "$1" | grep -oP '^\s*\K[0-9]+' --color=never)
if [ ! -z "$APP_PID" ]; then
echo "Vuze (PID $APP_PID) is open. Trying to close Vuze (SIGNAL $2). Max $3sec."
kill $2 "$APP_PID"
WAIT_LOOP=0
while ps -p "$APP_PID" > /dev/null 2>&1; do
sleep 1
WAIT_LOOP=$((WAIT_LOOP+1))
if [ "$WAIT_LOOP" = "$3" ]; then
break
fi
done
fi
APP_PID=$(ps -x | grep "$1" | grep -oP '^\s*\K[0-9]+' --color=never)
if [ -z "$APP_PID" ]; then return 0; else return 1; fi
}
close_vuze() {
close_app "java .*[A]zureus2.jar" "-HUP" "60"
close_app "java .*[A]zureus2.jar" "-TERM" "60"
close_app "java .*[A]zureus2.jar" "-SIGINT" "60"
close_app "java .*[A]zureus2.jar" "-KILL" "60"
return $?
}
find_screen() {
if screen -ls "$1" | grep -o "^\s*[0-9]*\.$1[ "$'\t'"](" --color=NEVER -m 1 | grep -oh "[0-9]*\.$1" --color=NEVER -m 1 -q >/dev/null; then
screen -ls "$1" | grep -o "^\s*[0-9]*\.$1[ "$'\t'"](" --color=NEVER -m 1 | grep -oh "[0-9]*\.$1" --color=NEVER -m 1 2>/dev/null
return 0
else
echo "$1"
return 1
fi
}
unmount_encfs() {
ENCFS_MOUNTED=$(mount -l | grep "encfs" | grep "$MOUNT_DIR")
if [ ! -z "$ENCFS_MOUNTED" ]; then
echo "Unmounting encfs gracefully"
fusermount -u "$MOUNT_DIR"
else
echo "INFO: No encfs mount to unmount."
fi
ENCFS_MOUNTED=$(mount -l | grep "encfs" | grep "$MOUNT_DIR")
if [ ! -z "$ENCFS_MOUNTED" ]; then
echo "Failed. Forcing encfs unmount (fusermount -z)"
fusermount -u -z "$MOUNT_DIR"
sleep 3
if ! find "$MOUNT_DIR" -maxdepth 0 -empty | read v; then
echo -e "\e[31m\e[1mBROKEN: Virtual mount point \"$MOUNT_DIR\" may be in a broken state. Please empty it manually.\e[0m"
sleep 3
fi
fi
}
concat_n_escape() { printf "%q"" " "$@"; }
# === START ====
# Mount encfs crypted dir to clear view.
# Load a private Vuze profile
if [ "$1" = "start" ] || [ "$1" = "start-screened" ]; then
if [ "$1" = "start-screened" ]; then
# Unmount encfs... TODO test if necessary (not already mounted properly) and fail condition
#sudo fusermount -u "$MOUNT_DIR"
# Preparing to make mount private
RUN_VUZE_BACKGROUND=false
echo "Hi, you're in the screen matrix, or not."
fi
ENCFS_MOUNTED=$(mount -l | grep "encfs" | grep "$MOUNT_DIR")
if [ -z "$ENCFS_MOUNTED" ]; then
if [ -d "$VUZE_PRIVATE_CONF" ]; then
echo "Resuming from crash. Trying to empty $MOUNT_DIR."
rm -f -R "$VUZE_PRIVATE_CONF"
fi
echo "Mouting decrypted EncFS view:"
encfs "$CRYPTED_DIR" "$MOUNT_DIR"
ENCFS_RETURN=$?
else
echo "EncFS directory already mounted"
fi
ENCFS_MOUNTED=$(mount -l | grep "encfs" | grep "$MOUNT_DIR")
# Encfs mounted
if [ ! -z "$ENCFS_MOUNTED" ]; then
echo "Encfs mount point ready."
# Private profile doesn't exist in crypted dir
if [ ! -d "$VUZE_PRIVATE_CONF" ]; then
echo "Private Vuze conf not found (first start ever?)."
echo "Copying current Vuze conf to crypted private conf, without torrents."
cp -R "$VUZE_PUBLIC_CONF" "$VUZE_PRIVATE_CONF"
rm -R -f "$VUZE_PRIVATE_CONF/active"
mkdir -p "$VUZE_PRIVATE_CONF/active"
rm -f "$VUZE_PRIVATE_CONF/downloads.config"
rm -f "$VUZE_PRIVATE_CONF/downloads.config.bak"
echo "Adapting private settings: Download directories will point to mount dir."
echo "Please check that everyting's OK on your Vuze settings > Files."
mkdir -p "$VUZE_PRIVATE_CONF/custom"
/bin/cat >"$VUZE_PRIVATE_CONF/custom/private.config" <<EOF
Default\ save\ path=string:${MOUNT_DIR}/incomplete
Completed\ Files\ Directory=string:${MOUNT_DIR}${MOUNT_COMPLETE_SUBDIR}
General_sDefaultTorrent_Directory=string:${MOUNT_DIR}/incomplete
Move\ Completed\ When\ Done=bool:true
Move\ Torrent\ When\ Done=bool:true
File.move.download.removed.enabled=bool:false
EOF
fi
echo "Starting Vuze with private conf."
start_vuze_args=2
count_java_args=0
for arg in "${@:2}"; do
if [[ "$arg" == "-D"* ]]; then
start_vuze_args=$(( $start_vuze_args + 1 ))
count_java_args=$(( $count_java_args + 1 ))
else
break
fi
done
echo "start_vuze_args=$start_vuze_args "
VUZE_X_JAVA_ARGS_COMP="${@:2:$count_java_args}"
start_vuze_private "${@:$start_vuze_args}"
else
echo "ERROR: EncFS mounting failed. Aborting."
echo "Possible causes: Encfs not installed, bad password or need to manually empty $VUZE_PRIVATE_CONF"
exit 1
fi
# === START IN HIDDEN MODE ====
# Same as start but inside a different Linux namespace
# Vuze will be started in a password-protected GNU screen
# Encfs mount will be visible only to Vuze (so you can download/upload but not view files)
elif [ "$1" = "hidden" ]; then
# Prefer RAM to store the temporary screen conf file containing the encrypted screen password
if [ -d "/run/shm" ]; then
tmpscreendir="/run/shm"
else
tmpscreendir="/tmp"
fi
if find_screen "VZX" >/dev/null; then
echo "Screen already exist. Reattaching screen."
target_screen=$(find_screen "VZX")
screen -d -r "$target_screen"
else
echo "Creating password-protected screen and namespace."
echo -e "(Screen can be detached with \e[1mCtrl+A, D\e[0m and reattached with \e[1m$0 hidden\e[0m)"
tmpscreenfile="$(mktemp "$tmpscreendir"/.screenrc-XXXXXX)"
echo -e "Define password to protect the screen session (enter to skip):"
read -s -p "Screen password: " SCREEN_PWD
echo
if [ ! -z "$SCREEN_PWD" ]; then
(echo -n "password "; mkpasswd -m des -S SO "$SCREEN_PWD") >> "$tmpscreenfile"
fi
unset SCREEN_PWD
RUN_CMD="mount --bind \"$MOUNT_DIR\" \"$MOUNT_DIR\"; \
mount --make-private \"$MOUNT_DIR\";\
sudo -u \"#\$SUDO_UID\" -g \"#\$SUDO_GID\" bash -c \"sudo -K; rm \"$tmpscreenfile\"; "`concat_n_escape "$0"`" \\\"\\\$@\\\"; "`concat_n_escape "$0"`" stop\" - \"\$@\"; \
umount \"$MOUNT_DIR\""
# Unfortunately, encfs can't be mounted inside non-sudoed "unshare -m -r"
# due to permissions issues to access /etc/fuse.conf
# However, it runs well in "unshare -m" even after root permissions removal.
# Permissions are removed through "sudo -K" in RUN_CMD before running Vuze
echo "Script will ask for temporary root permissions to hide the mount."
sleep 3
# Make the virtual mount point invisible to processes from other namespaces, by using unshare, in a password-protected screen
screen -mS "VZX" -c "$tmpscreenfile" \
sudo unshare -m \
bash -c \
"$RUN_CMD" "$0" "start-screened" "${@:2}"
rm "$tmpscreenfile" 2>/dev/null
fi
exit 0
# === STOP ====
# Restore usual ("public") Vuze settings.
# Unmount encfs clear view.
elif [ "$1" = "stop" ]; then
close_vuze
VUZE_PID=$(ps -x | grep "java .*[A]zureus2.jar" | grep -oP '^\s*\K[0-9]+' --color=never)
if [ -n "$VUZE_PID" ]; then
echo "VUZE_PID = $VUZE_PID"
echo -e "\e[31m\e[1mBROKEN: Vuze is immortal."
echo -e "Unmounting encfs may screw up your Vuze public settings directory."
echo -e "Please close Vuze yourself and try again."
echo -e "Aborting in a dirty state.\e[0m"
exit 1
fi
unmount_encfs
echo -e "\nStatus:"
echo -n "Vuze closed ? "
if [ -z "$VUZE_PID" ]; then echo "Yes, OK."; else echo "No, FAILED!"; fi
echo -n "Encfs unmounted ? "
ENCFS_MOUNTED=$(mount -l | grep "encfs" | grep "$MOUNT_DIR")
if [ -z "$ENCFS_MOUNTED" ]; then echo "Yes, OK."; else echo "No, FAILED!"; fi
# === VIEW ====
# Just mount encfs clear view.
elif [ "$1" = "view" ]; then
ENCFS_MOUNTED=$(mount -l | grep "encfs" | grep "$MOUNT_DIR")
if [ -z "$ENCFS_MOUNTED" ]; then
echo "Mouting EncFS directory"
encfs "$CRYPTED_DIR" "$MOUNT_DIR"
else
echo "EncFS directory already mounted"
fi
ENCFS_MOUNTED=$(mount -l | grep "encfs" | grep "$MOUNT_DIR")
# Encfs mounted
if [ -z "$ENCFS_MOUNTED" ]; then
echo "ERROR: EncFS mounting failed. Aborting."
exit 1
fi
echo "Opening File Explorer."
xdg-open "$MOUNT_DIR" > /dev/null 2>&1 &
exit 0
else
echo "Usage:"
echo "$me start [-DJAVA ARGUMENTS] [VUZE ARGUMENTS] [TORRENT FILE]"
echo -e "\tMount crypted dir and change Vuze configuration"
echo -e "\tto the encrypted \"private\" profile."
echo "$me hidden [-DJAVA ARGUMENTS] [VUZE ARGUMENTS] [TORRENT FILE]"
echo -e "\tSame as start but inside a different Linux namespace."
echo -e "\tVuze will be started in a password-protected GNU screen."
echo -e "\tEncfs mount will be visible only to Vuze and programs opened through Vuze."
echo -e "\tOnly really useful with the --ui=console argument (you can't hide the GUI)."
echo "$me stop"
echo -e "\tUnmount crypted dir and restore Vuze configuration"
echo -e "\tto the unencrypted \"public\" profile."
echo "$me view"
echo -e "\tMount & browse encfs clear view directory."
fi
echo
echo "NOTE: Check your security settings after swaping profiles"
echo " (proxy, ToR, forced interface bindings...)"
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment