Version 1.0.4 terminalphone.sh
This commit is contained in:
parent
ca94542464
commit
616768a364
1 changed files with 200 additions and 3 deletions
203
terminalphone.sh
203
terminalphone.sh
|
|
@ -9,7 +9,7 @@ set -euo pipefail
|
||||||
# CONFIGURATION
|
# CONFIGURATION
|
||||||
#=============================================================================
|
#=============================================================================
|
||||||
APP_NAME="TerminalPhone"
|
APP_NAME="TerminalPhone"
|
||||||
VERSION="1.0.3"
|
VERSION="1.0.4"
|
||||||
BASE_DIR="$(dirname "$(readlink -f "$0")")"
|
BASE_DIR="$(dirname "$(readlink -f "$0")")"
|
||||||
DATA_DIR="$BASE_DIR/.terminalphone"
|
DATA_DIR="$BASE_DIR/.terminalphone"
|
||||||
TOR_DIR="$DATA_DIR/tor_data"
|
TOR_DIR="$DATA_DIR/tor_data"
|
||||||
|
|
@ -25,6 +25,7 @@ RECV_PIPE="$DATA_DIR/run/recv_$$"
|
||||||
SEND_PIPE="$DATA_DIR/run/send_$$"
|
SEND_PIPE="$DATA_DIR/run/send_$$"
|
||||||
CIPHER_RUNTIME_FILE="$DATA_DIR/run/cipher_$$"
|
CIPHER_RUNTIME_FILE="$DATA_DIR/run/cipher_$$"
|
||||||
|
|
||||||
|
|
||||||
# Defaults
|
# Defaults
|
||||||
LISTEN_PORT=7777
|
LISTEN_PORT=7777
|
||||||
TOR_SOCKS_PORT=9050
|
TOR_SOCKS_PORT=9050
|
||||||
|
|
@ -34,6 +35,7 @@ SAMPLE_RATE=8000 # Hz
|
||||||
PTT_KEY=" " # spacebar
|
PTT_KEY=" " # spacebar
|
||||||
CHUNK_DURATION=1 # seconds per audio chunk
|
CHUNK_DURATION=1 # seconds per audio chunk
|
||||||
CIPHER="aes-256-cbc" # OpenSSL cipher for encryption
|
CIPHER="aes-256-cbc" # OpenSSL cipher for encryption
|
||||||
|
SNOWFLAKE_ENABLED=0 # Snowflake bridge (off by default)
|
||||||
|
|
||||||
# ANSI Colors
|
# ANSI Colors
|
||||||
RED='\033[0;31m'
|
RED='\033[0;31m'
|
||||||
|
|
@ -59,6 +61,7 @@ fi
|
||||||
|
|
||||||
# State
|
# State
|
||||||
TOR_PID=""
|
TOR_PID=""
|
||||||
|
|
||||||
CALL_ACTIVE=0
|
CALL_ACTIVE=0
|
||||||
ORIGINAL_STTY=""
|
ORIGINAL_STTY=""
|
||||||
|
|
||||||
|
|
@ -107,6 +110,7 @@ kill_bg_processes() {
|
||||||
if [ -n "$TOR_PID" ] && kill -0 "$TOR_PID" 2>/dev/null; then
|
if [ -n "$TOR_PID" ] && kill -0 "$TOR_PID" 2>/dev/null; then
|
||||||
kill "$TOR_PID" 2>/dev/null || true
|
kill "$TOR_PID" 2>/dev/null || true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
save_pid() {
|
save_pid() {
|
||||||
|
|
@ -155,6 +159,7 @@ OPUS_BITRATE=$OPUS_BITRATE
|
||||||
OPUS_FRAMESIZE=$OPUS_FRAMESIZE
|
OPUS_FRAMESIZE=$OPUS_FRAMESIZE
|
||||||
PTT_KEY="$PTT_KEY"
|
PTT_KEY="$PTT_KEY"
|
||||||
CIPHER="$CIPHER"
|
CIPHER="$CIPHER"
|
||||||
|
SNOWFLAKE_ENABLED=$SNOWFLAKE_ENABLED
|
||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -269,15 +274,71 @@ HiddenServiceDir $TOR_DIR/hidden_service
|
||||||
HiddenServicePort $LISTEN_PORT 127.0.0.1:$LISTEN_PORT
|
HiddenServicePort $LISTEN_PORT 127.0.0.1:$LISTEN_PORT
|
||||||
Log notice file $TOR_DIR/tor.log
|
Log notice file $TOR_DIR/tor.log
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
# Append snowflake bridge config if enabled
|
||||||
|
if [ "$SNOWFLAKE_ENABLED" -eq 1 ] && check_dep snowflake-client; then
|
||||||
|
local sf_bin
|
||||||
|
sf_bin=$(command -v snowflake-client)
|
||||||
|
cat >> "$TOR_CONF" << EOF
|
||||||
|
|
||||||
|
UseBridges 1
|
||||||
|
ClientTransportPlugin snowflake exec $sf_bin
|
||||||
|
Bridge snowflake 192.0.2.3:80 2B280B23E1107BB62ABFC40DDCC8824814F80A72 fingerprint=2B280B23E1107BB62ABFC40DDCC8824814F80A72 url=https://snowflake-broker.torproject.net/ ice=stun:stun.l.google.com:19302,stun:stun.voip.blackberry.com:3478
|
||||||
|
EOF
|
||||||
|
log_info "Snowflake bridge enabled in torrc"
|
||||||
|
elif [ "$SNOWFLAKE_ENABLED" -eq 1 ]; then
|
||||||
|
log_warn "Snowflake enabled but snowflake-client not found — skipping bridge"
|
||||||
|
fi
|
||||||
|
|
||||||
chmod 600 "$TOR_CONF"
|
chmod 600 "$TOR_CONF"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
install_snowflake() {
|
||||||
|
if check_dep snowflake-client; then
|
||||||
|
log_ok "snowflake-client already installed"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_info "Installing snowflake-client..."
|
||||||
|
|
||||||
|
local SUDO="sudo"
|
||||||
|
if [ $IS_TERMUX -eq 1 ]; then
|
||||||
|
SUDO=""
|
||||||
|
elif ! check_dep sudo; then
|
||||||
|
SUDO=""
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $IS_TERMUX -eq 1 ]; then
|
||||||
|
pkg install -y snowflake-client
|
||||||
|
elif check_dep apt-get; then
|
||||||
|
$SUDO apt-get update -qq
|
||||||
|
$SUDO apt-get install -y snowflake-client
|
||||||
|
elif check_dep dnf; then
|
||||||
|
$SUDO dnf install -y snowflake-client
|
||||||
|
elif check_dep pacman; then
|
||||||
|
$SUDO pacman -S --noconfirm snowflake-pt-client
|
||||||
|
else
|
||||||
|
log_err "No supported package manager found. Install snowflake-client manually."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if check_dep snowflake-client; then
|
||||||
|
log_ok "snowflake-client installed successfully"
|
||||||
|
else
|
||||||
|
log_err "snowflake-client installation failed"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
start_tor() {
|
start_tor() {
|
||||||
if [ -n "$TOR_PID" ] && kill -0 "$TOR_PID" 2>/dev/null; then
|
if [ -n "$TOR_PID" ] && kill -0 "$TOR_PID" 2>/dev/null; then
|
||||||
log_info "Tor is already running (PID $TOR_PID)"
|
log_info "Tor is already running (PID $TOR_PID)"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
setup_tor
|
setup_tor
|
||||||
|
|
||||||
# Clear old log so we only see fresh output
|
# Clear old log so we only see fresh output
|
||||||
|
|
@ -285,6 +346,9 @@ start_tor() {
|
||||||
> "$tor_log"
|
> "$tor_log"
|
||||||
|
|
||||||
log_info "Starting Tor..."
|
log_info "Starting Tor..."
|
||||||
|
if [ "$SNOWFLAKE_ENABLED" -eq 1 ]; then
|
||||||
|
echo -e " ${DIM}Snowflake bridge enabled — this may take longer than usual, please be patient.${NC}"
|
||||||
|
fi
|
||||||
tor -f "$TOR_CONF" &>/dev/null &
|
tor -f "$TOR_CONF" &>/dev/null &
|
||||||
TOR_PID=$!
|
TOR_PID=$!
|
||||||
save_pid "tor" "$TOR_PID"
|
save_pid "tor" "$TOR_PID"
|
||||||
|
|
@ -361,6 +425,7 @@ stop_tor() {
|
||||||
TOR_PID=""
|
TOR_PID=""
|
||||||
log_ok "Tor stopped"
|
log_ok "Tor stopped"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get_onion() {
|
get_onion() {
|
||||||
|
|
@ -766,6 +831,42 @@ draw_call_header() {
|
||||||
echo -e " ${GREEN}●${NC} Local cipher: ${WHITE}${cipher_upper}${NC}" >&2
|
echo -e " ${GREEN}●${NC} Local cipher: ${WHITE}${cipher_upper}${NC}" >&2
|
||||||
echo -e " ${DIM}●${NC} Remote cipher: ${DIM}waiting...${NC}" >&2
|
echo -e " ${DIM}●${NC} Remote cipher: ${DIM}waiting...${NC}" >&2
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Show Snowflake bridge info if enabled
|
||||||
|
if [ "$SNOWFLAKE_ENABLED" -eq 1 ]; then
|
||||||
|
local tor_log="$TOR_DIR/tor.log"
|
||||||
|
echo "" >&2
|
||||||
|
echo -e " ${TOR_PURPLE}●${NC} ${BOLD}Snowflake bridge${NC}" >&2
|
||||||
|
if [ -f "$tor_log" ]; then
|
||||||
|
# Parse bridge descriptor: "new bridge descriptor 'NAME' (fresh): $FINGERPRINT"
|
||||||
|
local bridge_line=""
|
||||||
|
bridge_line=$(grep "new bridge descriptor" "$tor_log" 2>/dev/null | tail -1 || true)
|
||||||
|
if [ -n "$bridge_line" ]; then
|
||||||
|
local bridge_name=""
|
||||||
|
bridge_name=$(echo "$bridge_line" | sed -n "s/.*new bridge descriptor '\([^']*\)'.*/\1/p" || true)
|
||||||
|
local bridge_fp=""
|
||||||
|
bridge_fp=$(echo "$bridge_line" | sed -n 's/.*(\(fresh\|stale\)): \(.*\)/\2/p' || true)
|
||||||
|
if [ -n "$bridge_name" ]; then
|
||||||
|
# Truncate fingerprint to fit terminal
|
||||||
|
local fp_display="$bridge_fp"
|
||||||
|
if [ ${#fp_display} -gt 40 ]; then
|
||||||
|
fp_display="${fp_display:0:40}..."
|
||||||
|
fi
|
||||||
|
echo -e " ${DIM}descriptor:${NC} ${WHITE}${bridge_name}${NC} ${DIM}— ${fp_display}${NC}" >&2
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
# Show managed proxy status
|
||||||
|
local proxy_line=""
|
||||||
|
proxy_line=$(grep 'Managed proxy.*snowflake' "$tor_log" 2>/dev/null | tail -1 || true)
|
||||||
|
if [ -n "$proxy_line" ]; then
|
||||||
|
if echo "$proxy_line" | grep -q "connected"; then
|
||||||
|
echo -e " ${DIM}transport:${NC} ${GREEN}connected${NC}" >&2
|
||||||
|
else
|
||||||
|
echo -e " ${DIM}transport:${NC} ${YELLOW}connecting...${NC}" >&2
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
echo "" >&2
|
echo "" >&2
|
||||||
|
|
||||||
echo -e " ${BOLD}Controls:${NC}" >&2
|
echo -e " ${BOLD}Controls:${NC}" >&2
|
||||||
|
|
@ -1181,6 +1282,17 @@ show_status() {
|
||||||
echo -e " ${RED}●${NC} Audio dependencies missing"
|
echo -e " ${RED}●${NC} Audio dependencies missing"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Snowflake
|
||||||
|
if [ "$SNOWFLAKE_ENABLED" -eq 1 ]; then
|
||||||
|
if check_dep snowflake-client; then
|
||||||
|
echo -e " ${GREEN}●${NC} Snowflake bridge enabled"
|
||||||
|
else
|
||||||
|
echo -e " ${YELLOW}●${NC} Snowflake enabled (client not installed)"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo -e " ${DIM}●${NC} Snowflake bridge disabled"
|
||||||
|
fi
|
||||||
|
|
||||||
# Config
|
# Config
|
||||||
echo -e "\n ${DIM}Listen port: $LISTEN_PORT${NC}"
|
echo -e "\n ${DIM}Listen port: $LISTEN_PORT${NC}"
|
||||||
echo -e " ${DIM}SOCKS port: $TOR_SOCKS_PORT${NC}"
|
echo -e " ${DIM}SOCKS port: $TOR_SOCKS_PORT${NC}"
|
||||||
|
|
@ -1201,10 +1313,17 @@ settings_menu() {
|
||||||
echo -e "\n${BOLD}${CYAN}═══ Settings ═══${NC}\n"
|
echo -e "\n${BOLD}${CYAN}═══ Settings ═══${NC}\n"
|
||||||
echo -e " ${DIM}Current cipher: ${NC}${WHITE}${CIPHER}${NC}"
|
echo -e " ${DIM}Current cipher: ${NC}${WHITE}${CIPHER}${NC}"
|
||||||
echo -e " ${DIM}Current Opus bitrate: ${NC}${WHITE}${OPUS_BITRATE} kbps${NC}"
|
echo -e " ${DIM}Current Opus bitrate: ${NC}${WHITE}${OPUS_BITRATE} kbps${NC}"
|
||||||
echo -e " ${DIM}Current Opus frame: ${NC}${WHITE}${OPUS_FRAMESIZE} ms${NC}\n"
|
echo -e " ${DIM}Current Opus frame: ${NC}${WHITE}${OPUS_FRAMESIZE} ms${NC}"
|
||||||
|
|
||||||
|
local sf_label="${RED}disabled${NC}"
|
||||||
|
if [ "$SNOWFLAKE_ENABLED" -eq 1 ]; then
|
||||||
|
sf_label="${GREEN}enabled${NC}"
|
||||||
|
fi
|
||||||
|
echo -e " ${DIM}Snowflake bridge: ${NC}${sf_label}\n"
|
||||||
|
|
||||||
echo -e " ${BOLD}${WHITE}1${NC} ${CYAN}│${NC} Change encryption cipher"
|
echo -e " ${BOLD}${WHITE}1${NC} ${CYAN}│${NC} Change encryption cipher"
|
||||||
echo -e " ${BOLD}${WHITE}2${NC} ${CYAN}│${NC} Change Opus encoding quality"
|
echo -e " ${BOLD}${WHITE}2${NC} ${CYAN}│${NC} Change Opus encoding quality"
|
||||||
|
echo -e " ${BOLD}${WHITE}3${NC} ${CYAN}│${NC} Snowflake bridge (censorship circumvention)"
|
||||||
echo -e " ${BOLD}${WHITE}0${NC} ${CYAN}│${NC} ${DIM}Back to main menu${NC}"
|
echo -e " ${BOLD}${WHITE}0${NC} ${CYAN}│${NC} ${DIM}Back to main menu${NC}"
|
||||||
echo ""
|
echo ""
|
||||||
echo -ne " ${BOLD}Select: ${NC}"
|
echo -ne " ${BOLD}Select: ${NC}"
|
||||||
|
|
@ -1213,6 +1332,7 @@ settings_menu() {
|
||||||
case "$schoice" in
|
case "$schoice" in
|
||||||
1) settings_cipher ;;
|
1) settings_cipher ;;
|
||||||
2) settings_opus ;;
|
2) settings_opus ;;
|
||||||
|
3) settings_snowflake ;;
|
||||||
0|q|Q) return ;;
|
0|q|Q) return ;;
|
||||||
*)
|
*)
|
||||||
echo -e "\n ${RED}Invalid choice${NC}"
|
echo -e "\n ${RED}Invalid choice${NC}"
|
||||||
|
|
@ -1384,6 +1504,79 @@ settings_opus() {
|
||||||
read -r
|
read -r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
settings_snowflake() {
|
||||||
|
clear
|
||||||
|
echo -e "\n${BOLD}${CYAN}═══ Snowflake Bridge ═══${NC}\n"
|
||||||
|
echo -e " ${DIM}Snowflake uses WebRTC proxies to help bypass Tor censorship.${NC}"
|
||||||
|
echo -e " ${DIM}Enable this if Tor is blocked in your region.${NC}\n"
|
||||||
|
|
||||||
|
if [ "$SNOWFLAKE_ENABLED" -eq 1 ]; then
|
||||||
|
echo -e " Status: ${GREEN}${BOLD}ENABLED${NC}"
|
||||||
|
else
|
||||||
|
echo -e " Status: ${RED}${BOLD}DISABLED${NC}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if check_dep snowflake-client; then
|
||||||
|
echo -e " Binary: ${GREEN}●${NC} snowflake-client installed"
|
||||||
|
else
|
||||||
|
echo -e " Binary: ${RED}●${NC} snowflake-client not installed"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e " ${DIM}Tor manages snowflake-client as a pluggable transport.${NC}"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
if [ "$SNOWFLAKE_ENABLED" -eq 1 ]; then
|
||||||
|
echo -e " ${BOLD}${WHITE}1${NC} ${CYAN}│${NC} Disable Snowflake"
|
||||||
|
else
|
||||||
|
echo -e " ${BOLD}${WHITE}1${NC} ${CYAN}│${NC} Enable Snowflake"
|
||||||
|
fi
|
||||||
|
echo -e " ${BOLD}${WHITE}0${NC} ${CYAN}│${NC} ${DIM}Back${NC}"
|
||||||
|
echo ""
|
||||||
|
echo -ne " ${BOLD}Select: ${NC}"
|
||||||
|
read -r sf_choice
|
||||||
|
|
||||||
|
case "$sf_choice" in
|
||||||
|
1)
|
||||||
|
if [ "$SNOWFLAKE_ENABLED" -eq 1 ]; then
|
||||||
|
SNOWFLAKE_ENABLED=0
|
||||||
|
save_config
|
||||||
|
|
||||||
|
echo -e "\n ${YELLOW}${BOLD}✓${NC} Snowflake disabled"
|
||||||
|
echo -e " ${DIM}Restart Tor for changes to take effect.${NC}"
|
||||||
|
else
|
||||||
|
# Install if not present
|
||||||
|
if ! check_dep snowflake-client; then
|
||||||
|
echo ""
|
||||||
|
echo -ne " ${BOLD}snowflake-client not installed. Install now? [Y/n]: ${NC}"
|
||||||
|
read -r install_confirm
|
||||||
|
if [ "$install_confirm" != "n" ] && [ "$install_confirm" != "N" ]; then
|
||||||
|
install_snowflake || {
|
||||||
|
echo -ne " ${DIM}Press Enter to continue...${NC}"
|
||||||
|
read -r
|
||||||
|
return
|
||||||
|
}
|
||||||
|
else
|
||||||
|
echo -e "\n ${YELLOW}Snowflake not enabled (client not installed)${NC}"
|
||||||
|
echo -ne " ${DIM}Press Enter to continue...${NC}"
|
||||||
|
read -r
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
SNOWFLAKE_ENABLED=1
|
||||||
|
save_config
|
||||||
|
echo -e "\n ${GREEN}${BOLD}✓${NC} Snowflake enabled"
|
||||||
|
echo -e " ${DIM}Restart Tor for changes to take effect.${NC}"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
0|q|Q) return ;;
|
||||||
|
*)
|
||||||
|
echo -e "\n ${RED}Invalid choice${NC}"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
echo -ne " ${DIM}Press Enter to continue...${NC}"
|
||||||
|
read -r
|
||||||
|
}
|
||||||
|
|
||||||
#=============================================================================
|
#=============================================================================
|
||||||
# MAIN MENU
|
# MAIN MENU
|
||||||
#=============================================================================
|
#=============================================================================
|
||||||
|
|
@ -1415,8 +1608,12 @@ main_menu() {
|
||||||
if [ -n "$SHARED_SECRET" ]; then
|
if [ -n "$SHARED_SECRET" ]; then
|
||||||
secret_status="${GREEN}●${NC}"
|
secret_status="${GREEN}●${NC}"
|
||||||
fi
|
fi
|
||||||
|
local sf_status="${RED}●${NC}"
|
||||||
|
if [ "$SNOWFLAKE_ENABLED" -eq 1 ]; then
|
||||||
|
sf_status="${GREEN}●${NC}"
|
||||||
|
fi
|
||||||
|
|
||||||
echo -e " ${DIM}Tor:${NC} $tor_status ${DIM}Secret:${NC} $secret_status ${DIM}PTT:${NC} ${GREEN}[SPACE]${NC}\n"
|
echo -e " ${DIM}Tor:${NC} $tor_status ${DIM}Secret:${NC} $secret_status ${DIM}SF:${NC} $sf_status ${DIM}PTT:${NC} ${GREEN}[SPACE]${NC}\n"
|
||||||
|
|
||||||
echo -e " ${BOLD}${WHITE}1${NC} ${CYAN}│${NC} Listen for calls"
|
echo -e " ${BOLD}${WHITE}1${NC} ${CYAN}│${NC} Listen for calls"
|
||||||
echo -e " ${BOLD}${WHITE}2${NC} ${CYAN}│${NC} Call an onion address"
|
echo -e " ${BOLD}${WHITE}2${NC} ${CYAN}│${NC} Call an onion address"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue