Skip to content

Commit e93c20e

Browse files
committed
Enhance proxy handling with IPv6 support and security improvements
- Update proxy regex to support IPv6 addresses in square brackets - Improve proxy parsing functions to handle IPv6 addresses correctly - Add validation to prevent localhost/loopback proxy addresses - Implement scrub_secrets function to clean sensitive data from logs - Handle proxy passwords that contain colons - Improve extraction of proxy components (username, password, host, port)
1 parent bff3ec5 commit e93c20e

File tree

2 files changed

+121
-27
lines changed

2 files changed

+121
-27
lines changed

scripts/_lib.sh

Lines changed: 89 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
set -euo pipefail
44

5-
PROXY_REGEXP='^(http(s)?://)?(([0-9a-zA-Z_-]+:[0-9a-zA-Z_-]+)@)?([0-9a-zA-Z._-]+)(:([0-9]+))?$'
5+
# Regex that handles both IPv4/hostname and IPv6 proxy formats
6+
# Matches: [protocol://][user:pass@][host|[ipv6]][:port][/path]
7+
PROXY_REGEXP='^(https?://)?(([^@/:]+:[^@/:]+)@)?((\[[0-9a-fA-F:]+\])|([0-9a-zA-Z._-]+))(:[0-9]+)?(/.*)?$'
68
WORKDIR=/run/farcaster
79
LOGDIR=/logs
810
HUB_IP_TTL=300
@@ -183,43 +185,80 @@ start_dnsmasq() {
183185
}
184186

185187
get_proxy_username() {
186-
echo "${HTTP_PROXY:-}" |
187-
sed -e 's/^"//' -e 's/"$//' |
188-
sed -r 's/^http(s)?\:\/\///' |
189-
grep '@' |
190-
sed 's/@[^@]*$//' |
191-
cut -d ':' -f 1 || echo ""
188+
local proxy="${HTTP_PROXY:-}"
189+
# Remove quotes
190+
proxy=$(echo "${proxy}" | sed -e 's/^"//' -e 's/"$//')
191+
# Remove protocol
192+
proxy=$(echo "${proxy}" | sed -r 's|^https?://||')
193+
# Check if has userinfo (contains @)
194+
if echo "${proxy}" | grep -q '@'; then
195+
# Extract userinfo part (everything before the last @)
196+
userinfo=$(echo "${proxy}" | sed 's/@[^@]*$//')
197+
# Extract username (everything before : in userinfo)
198+
echo "${userinfo}" | cut -d ':' -f 1
199+
fi
192200
}
193201

194202
get_proxy_password() {
195-
echo "${HTTP_PROXY:-}" |
196-
sed -e 's/^"//' -e 's/"$//' |
197-
sed -r 's/^http(s)?\:\/\///' |
198-
grep '@' |
199-
sed 's/@[^@]*$//' |
200-
cut -d ':' -f 2 || echo ""
203+
local proxy="${HTTP_PROXY:-}"
204+
# Remove quotes
205+
proxy=$(echo "${proxy}" | sed -e 's/^"//' -e 's/"$//')
206+
# Remove protocol
207+
proxy=$(echo "${proxy}" | sed -r 's|^https?://||')
208+
# Check if has userinfo (contains @)
209+
if echo "${proxy}" | grep -q '@'; then
210+
# Extract userinfo part (everything before the last @)
211+
userinfo=$(echo "${proxy}" | sed 's/@[^@]*$//')
212+
# Check if userinfo contains a colon (has password)
213+
if echo "${userinfo}" | grep -q ':'; then
214+
# Extract password (everything after first : in userinfo)
215+
echo "${userinfo}" | cut -d ':' -f 2-
216+
fi
217+
fi
201218
}
202219

203220
get_proxy_address() {
204-
echo "${HTTP_PROXY:-}" |
205-
sed -e 's/^"//' -e 's/"$//' |
206-
sed -r 's/^http(s)?\:\/\///' |
207-
sed -r 's/\/.*//' |
208-
sed 's/^.*@//'
221+
local proxy="${HTTP_PROXY:-}"
222+
# Remove quotes
223+
proxy=$(echo "${proxy}" | sed -e 's/^"//' -e 's/"$//')
224+
# Remove protocol
225+
proxy=$(echo "${proxy}" | sed -r 's|^https?://||')
226+
# Remove path
227+
proxy=$(echo "${proxy}" | sed -r 's|/.*$||')
228+
# Remove userinfo (everything before last @)
229+
echo "${proxy}" | sed 's|^.*@||'
209230
}
210231

211232
get_proxy_host_from_address() {
212-
echo "$1" |
213-
sed -r 's/^http(s)?\:\/\///' |
214-
cut -d ':' -f 1
233+
local address="$1"
234+
# Remove protocol if present
235+
address=$(echo "${address}" | sed -r 's|^https?://||')
236+
# IPv6 address
237+
if echo "${address}" | grep -q '^\[.*\]'; then
238+
echo "${address}" | sed -r 's|^(\[.*\]).*|\1|'
239+
else
240+
# IPv4 address or hostname
241+
echo "${address}" | cut -d ':' -f 1
242+
fi
215243
}
216244

217245
get_proxy_port() {
218-
port=$(echo "$1" | grep ':' | cut -d ':' -f 2)
219-
if [ "${port}" = "" ]; then
220-
port="8080"
221-
fi
222-
echo "${port}"
246+
local address="$1"
247+
local port=""
248+
249+
# IPv6 address
250+
if echo "${address}" | grep -q '^\[.*\]:'; then
251+
port=$(echo "${address}" | sed -r 's|^\[.*\]:||')
252+
# IPv4 address or hostname
253+
elif echo "${address}" | grep -q ':'; then
254+
port=$(echo "${address}" | sed 's|^[^:]*:||')
255+
fi
256+
257+
# Default to 8080 if no port specified
258+
if [ -z "${port}" ] || [ "${port}" = "${address}" ]; then
259+
port="8080"
260+
fi
261+
echo "${port}"
223262
}
224263

225264
start_udp_over_tcp_tunnel() {
@@ -369,6 +408,24 @@ start_userspace_agent() {
369408
${CMD}
370409
}
371410

411+
scrub_secrets() {
412+
local text="${1}"
413+
local temp_file=$(mktemp)
414+
echo "${text}" > "${temp_file}"
415+
416+
for secret in FARCASTER_AGENT_TOKEN HTTP_PROXY HTTPS_PROXY SOCKS5_PROXY; do
417+
# Word boundary: (^|[^A-Za-z0-9_])
418+
sed -i -E \
419+
-e "s/(^|[^A-Za-z0-9_])${secret}[[:space:]]*=[[:space:]]*([^[:space:]\"']+)/\1${secret}=********/g" \
420+
-e "s/(^|[^A-Za-z0-9_])${secret}[[:space:]]*=[[:space:]]*\"([^\"]*)\"/\1${secret}=\"********\"/g" \
421+
-e "s/(^|[^A-Za-z0-9_])${secret}[[:space:]]*=[[:space:]]*'([^']*)'/\1${secret}='********'/g" \
422+
"${temp_file}"
423+
done
424+
425+
cat "${temp_file}"
426+
rm -f "${temp_file}"
427+
}
428+
372429
function print_log() {
373430
set +e
374431
echo
@@ -377,7 +434,12 @@ function print_log() {
377434

378435
log_file="${1}"
379436
if ! [[ "${log_file}" =~ ^/dev/|^/proc/ ]]; then
380-
cat "${log_file}"
437+
# Clean up secrets from the log file.
438+
local content
439+
local scrubbed
440+
content=$(cat "${log_file}" 2>/dev/null)
441+
scrubbed=$(scrub_secrets "${content}" 2>/dev/null)
442+
echo "${scrubbed}" > "${log_file}"
381443
fi
382444

383445
echo

scripts/entrypoint.sh

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,26 @@
33
# Exit on error, undefined variables
44
set -eu
55

6+
extract_proxy_host() {
7+
local proxy_url="$1"
8+
# Remove quotes
9+
proxy_url=$(echo "${proxy_url}" | sed -e 's/^"//' -e 's/"$//')
10+
# Remove protocol
11+
proxy_url=$(echo "${proxy_url}" | sed -r 's|^https?://||')
12+
# Remove path
13+
proxy_url=$(echo "${proxy_url}" | sed -r 's|/.*$||')
14+
# Remove userinfo
15+
proxy_url=$(echo "${proxy_url}" | sed 's|^[^@]*@||')
16+
17+
# IPv6 address
18+
if echo "${proxy_url}" | grep -q '^\[.*\]'; then
19+
echo "${proxy_url}" | sed -r 's|^(\[.*\]).*|\1|'
20+
# IPv4 address or hostname
21+
else
22+
echo "${proxy_url}" | cut -d ':' -f 1
23+
fi
24+
}
25+
626
init_environment() {
727
echo "Starting Farcaster agent v${FARCASTER_VERSION:-dev}..." # Set in the Dockerfile
828
umask 007
@@ -36,6 +56,18 @@ setup_proxy_environment() {
3656
export HTTP_PROXY="${HTTPS_PROXY}"
3757
export http_proxy="${HTTPS_PROXY}"
3858
fi
59+
60+
# Parse the proxy values and ensure their host is not localhost and not 127.0.0.1
61+
for proxy in HTTP_PROXY HTTPS_PROXY; do
62+
if [ -n "${!proxy:-}" ]; then
63+
host=$(extract_proxy_host "${!proxy}")
64+
if [ "${host}" = "localhost" ] || [ "${host}" = "127.0.0.1" ] || [ "${host}" = "[::1]" ] || [ "${host}" = "[::ffff:127.0.0.1]" ]; then
65+
echo "${proxy} cannot be set to localhost, 127.0.0.1, or IPv6 loopback addresses."
66+
exit 1
67+
fi
68+
fi
69+
done
70+
3971
}
4072

4173
determine_run_mode() {

0 commit comments

Comments
 (0)