Initial release: ghost_protocol privacy toolkit
This commit is contained in:
Executable
+146
@@ -0,0 +1,146 @@
|
||||
#!/bin/bash
|
||||
# conky-opsec-cache — Background IP/geo cache updater
|
||||
# Runs in a loop, writes results to cache file that the status script reads.
|
||||
# This keeps all slow network calls OUT of the conky render path.
|
||||
|
||||
CACHE_DIR="/tmp/.opsec-cache"
|
||||
CACHE_FILE="${CACHE_DIR}/netinfo"
|
||||
LOCK_FILE="${CACHE_DIR}/.updating"
|
||||
INTERVAL=30 # seconds between updates
|
||||
|
||||
mkdir -p "$CACHE_DIR"
|
||||
chmod 700 "$CACHE_DIR"
|
||||
|
||||
update_cache() {
|
||||
# Prevent concurrent updates
|
||||
[ -f "$LOCK_FILE" ] && return
|
||||
touch "$LOCK_FILE"
|
||||
|
||||
local advanced=false
|
||||
[ -f /var/run/opsec-advanced.enabled ] && advanced=true
|
||||
|
||||
local pub_ip="" pub_geo="" routed_tor=false exit_country=""
|
||||
|
||||
# In Advanced mode with SOCKS available: verify Tor via HTTPS, then get geo
|
||||
if $advanced && ss -tln 2>/dev/null | grep -q ':9050 '; then
|
||||
# Step 1: Verify Tor routing via HTTPS (encrypted, trusted endpoint)
|
||||
local tor_json
|
||||
tor_json=$(curl -4 -s --max-time 10 --socks5-hostname 127.0.0.1:9050 "https://check.torproject.org/api/ip" 2>/dev/null)
|
||||
if echo "$tor_json" | grep -q '"IsTor":true'; then
|
||||
pub_ip=$(echo "$tor_json" | grep -o '"IP":"[^"]*"' | cut -d'"' -f4)
|
||||
if [ -n "$pub_ip" ] && echo "$pub_ip" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$'; then
|
||||
routed_tor=true
|
||||
else
|
||||
pub_ip=""
|
||||
fi
|
||||
fi
|
||||
# Step 2: Get geo data via ip-api.com (HTTP only — but over Tor SOCKS so exit encrypts)
|
||||
# ip-api.com pro HTTPS requires a paid key; free tier is HTTP-only
|
||||
# This is acceptable: traffic goes through Tor SOCKS tunnel, so local network can't see it
|
||||
if [ -n "$pub_ip" ]; then
|
||||
local geo_json
|
||||
geo_json=$(curl -4 -s --max-time 10 --socks5-hostname 127.0.0.1:9050 "http://ip-api.com/json/${pub_ip}?fields=countryCode,city" 2>/dev/null)
|
||||
local geo_country geo_city
|
||||
geo_country=$(echo "$geo_json" | grep -o '"countryCode":"[^"]*"' | cut -d'"' -f4)
|
||||
geo_city=$(echo "$geo_json" | grep -o '"city":"[^"]*"' | cut -d'"' -f4)
|
||||
exit_country="$geo_country"
|
||||
[ -n "$geo_country" ] && pub_geo="${geo_city:+${geo_city}, }${geo_country}"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Fallback to direct — only if NOT in advanced mode (kill switch would DROP it)
|
||||
if [ -z "$pub_ip" ] && ! $advanced; then
|
||||
local api_json
|
||||
api_json=$(curl -4 -s --max-time 4 "https://check.torproject.org/api/ip" 2>/dev/null)
|
||||
if [ -n "$api_json" ]; then
|
||||
pub_ip=$(echo "$api_json" | grep -o '"IP":"[^"]*"' | cut -d'"' -f4)
|
||||
fi
|
||||
# Validate IP format
|
||||
if [ -n "$pub_ip" ] && ! echo "$pub_ip" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$'; then
|
||||
pub_ip=""
|
||||
fi
|
||||
# Get geo via HTTPS (direct mode — no Tor)
|
||||
if [ -n "$pub_ip" ]; then
|
||||
local geo_json
|
||||
geo_json=$(curl -4 -s --max-time 4 "http://ip-api.com/json/${pub_ip}?fields=countryCode,city" 2>/dev/null)
|
||||
local geo_country geo_city
|
||||
geo_country=$(echo "$geo_json" | grep -o '"countryCode":"[^"]*"' | cut -d'"' -f4)
|
||||
geo_city=$(echo "$geo_json" | grep -o '"city":"[^"]*"' | cut -d'"' -f4)
|
||||
[ -n "$geo_country" ] && pub_geo="${geo_city:+${geo_city}, }${geo_country}"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Sanitize exit country — should be 2-3 letter country code
|
||||
[ -n "$exit_country" ] && [ ${#exit_country} -gt 3 ] && exit_country=""
|
||||
|
||||
# Track when exit IP last changed (for circuit age display)
|
||||
local exit_change_time=""
|
||||
local prev_ip="" prev_change_time=""
|
||||
if [ -f "$CACHE_FILE" ]; then
|
||||
prev_ip=$(grep '^PUB_IP=' "$CACHE_FILE" 2>/dev/null | cut -d'"' -f2)
|
||||
prev_change_time=$(grep '^EXIT_CHANGE_TIME=' "$CACHE_FILE" 2>/dev/null | cut -d'"' -f2)
|
||||
fi
|
||||
if [ -n "$pub_ip" ] && [ "$pub_ip" != "$prev_ip" ]; then
|
||||
exit_change_time="$(date +%s)"
|
||||
elif [ -n "$prev_change_time" ]; then
|
||||
exit_change_time="$prev_change_time"
|
||||
else
|
||||
exit_change_time="$(date +%s)"
|
||||
fi
|
||||
|
||||
# Tor bootstrap progress — only from current Tor session
|
||||
local tor_bootstrap="" tor_phase=""
|
||||
if $advanced && systemctl is-active tor >/dev/null 2>&1; then
|
||||
# Get Tor start time, only read log lines after it
|
||||
local tor_start
|
||||
tor_start=$(systemctl show tor@default --property=ActiveEnterTimestamp 2>/dev/null | cut -d= -f2)
|
||||
if [ -n "$tor_start" ]; then
|
||||
local start_ts
|
||||
start_ts=$(date -d "$tor_start" +%s 2>/dev/null || echo 0)
|
||||
local boot_line=""
|
||||
# Read bootstrap lines — -h suppresses filename prefix when checking both paths
|
||||
while IFS= read -r line; do
|
||||
local log_date
|
||||
log_date=$(echo "$line" | grep -oP '^\w+ \d+ [\d:.]+')
|
||||
if [ -n "$log_date" ]; then
|
||||
local log_ts
|
||||
log_ts=$(date -d "$log_date" +%s 2>/dev/null || echo 0)
|
||||
[ "$log_ts" -ge "$start_ts" ] && boot_line="$line"
|
||||
fi
|
||||
done < <(grep -h "Bootstrapped" /run/tor/notices.log /var/log/tor/notices.log 2>/dev/null)
|
||||
if [ -n "$boot_line" ]; then
|
||||
tor_bootstrap=$(echo "$boot_line" | grep -oP '\d+(?=%)')
|
||||
tor_phase=$(echo "$boot_line" | grep -oP '\(\K[^)]+' | head -1)
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Write atomically (write to tmp then move) — quote values for safe sourcing
|
||||
local tmp="${CACHE_FILE}.tmp"
|
||||
cat > "$tmp" <<EOF
|
||||
PUB_IP="${pub_ip}"
|
||||
PUB_GEO="${pub_geo}"
|
||||
ROUTED_TOR="${routed_tor}"
|
||||
EXIT_COUNTRY="${exit_country}"
|
||||
EXIT_CHANGE_TIME="${exit_change_time}"
|
||||
TOR_BOOTSTRAP="${tor_bootstrap}"
|
||||
TOR_PHASE="${tor_phase}"
|
||||
CACHE_TIME="$(date +%s)"
|
||||
EOF
|
||||
chmod 600 "$tmp"
|
||||
mv -f "$tmp" "$CACHE_FILE"
|
||||
rm -f "$LOCK_FILE"
|
||||
}
|
||||
|
||||
# Initial update immediately
|
||||
update_cache
|
||||
|
||||
# Loop forever — poll faster when Tor is bootstrapping
|
||||
while true; do
|
||||
if [ -f /var/run/opsec-advanced.enabled ] && systemctl is-active tor >/dev/null 2>&1 && ! ss -tln 2>/dev/null | grep -q ':9050 '; then
|
||||
sleep 5 # Tor bootstrapping — fast poll
|
||||
else
|
||||
sleep "$INTERVAL"
|
||||
fi
|
||||
update_cache
|
||||
done
|
||||
Executable
+225
@@ -0,0 +1,225 @@
|
||||
#!/bin/bash
|
||||
# Conky OPSEC Status — OPSEC Status Widget
|
||||
# Called by conky via execpi — outputs Conky color markup
|
||||
# Network data is read from cache (updated by conky-opsec-cache.sh in background)
|
||||
#
|
||||
# Color map (managed by theme system):
|
||||
# 0 = ALERT/BAD 1 = SECURE/GOOD 2 = INFO/NEUTRAL
|
||||
# 3 = VOID/BG 4 = STRUCTURAL 5 = TITLE/ACCENT
|
||||
# 6 = LABELS 7 = VALUES 8 = SECTION HDR
|
||||
# 9 = METADATA
|
||||
|
||||
ADVANCED=false
|
||||
[ -f /var/run/opsec-advanced.enabled ] && ADVANCED=true
|
||||
|
||||
# ─── READ CACHE (instant — no network calls) ──────────────────────────────
|
||||
# Safe parsing: extract values via grep/cut instead of sourcing as shell code
|
||||
CACHE_FILE="/tmp/.opsec-cache/netinfo"
|
||||
PUB_IP="" PUB_GEO="" ROUTED_TOR=false EXIT_COUNTRY="" EXIT_CHANGE_TIME="" TOR_BOOTSTRAP="" TOR_PHASE="" CACHE_TIME=0
|
||||
if [ -f "$CACHE_FILE" ]; then
|
||||
_safe_read() { grep "^${1}=" "$CACHE_FILE" 2>/dev/null | head -1 | cut -d'"' -f2; }
|
||||
PUB_IP=$(_safe_read PUB_IP)
|
||||
PUB_GEO=$(_safe_read PUB_GEO)
|
||||
ROUTED_TOR=$(_safe_read ROUTED_TOR)
|
||||
EXIT_COUNTRY=$(_safe_read EXIT_COUNTRY)
|
||||
EXIT_CHANGE_TIME=$(_safe_read EXIT_CHANGE_TIME)
|
||||
TOR_BOOTSTRAP=$(_safe_read TOR_BOOTSTRAP)
|
||||
TOR_PHASE=$(_safe_read TOR_PHASE)
|
||||
CACHE_TIME=$(_safe_read CACHE_TIME)
|
||||
# Sanitize: strip anything that isn't alphanumeric, dots, commas, spaces, or dashes
|
||||
PUB_IP=$(echo "$PUB_IP" | tr -cd '0-9.')
|
||||
EXIT_COUNTRY=$(echo "$EXIT_COUNTRY" | tr -cd 'A-Za-z')
|
||||
EXIT_CHANGE_TIME=$(echo "$EXIT_CHANGE_TIME" | tr -cd '0-9')
|
||||
TOR_BOOTSTRAP=$(echo "$TOR_BOOTSTRAP" | tr -cd '0-9')
|
||||
fi
|
||||
|
||||
# Kick off cache daemon if not running
|
||||
if ! pgrep -f 'conky-opsec-cache\.sh' >/dev/null 2>&1; then
|
||||
nohup ~/.config/conky/conky-opsec-cache.sh >/dev/null 2>&1 &
|
||||
fi
|
||||
|
||||
# ─── HEADER ──────────────────────────────────────────────────────────────────
|
||||
echo "\${color4}\${hr 1}"
|
||||
if $ADVANCED; then
|
||||
echo "\${color5}\${font JetBrains Mono:bold:size=11}\${alignc}OPSEC STATUS\${font}"
|
||||
echo "\${color1}\${font JetBrains Mono:bold:size=8}\${alignc}▲ ADVANCED ▲\${font}"
|
||||
else
|
||||
echo "\${color5}\${font JetBrains Mono:bold:size=11}\${alignc}OPSEC STATUS\${font}"
|
||||
echo "\${color2}\${font JetBrains Mono:size=8}\${alignc}── STANDARD ──\${font}"
|
||||
fi
|
||||
echo "\${color4}\${hr 1}"
|
||||
|
||||
# ─── SYSTEM ──────────────────────────────────────────────────────────────────
|
||||
echo "\${color8}\${font JetBrains Mono:bold:size=9} ▌SYSTEM\${font}"
|
||||
echo "\${color6} HOST \${color7}\${nodename}\${alignr}\${color6}UP \${color7}\${uptime_short}"
|
||||
echo "\${color6} CPU \${color7}\${cpu}%\${alignr}\${color6}RAM \${color7}\${memperc}% \${color9}(\${mem}/\${memmax})"
|
||||
|
||||
# ─── NETWORK ─────────────────────────────────────────────────────────────────
|
||||
echo "\${color4}\${hr 1}"
|
||||
echo "\${color8}\${font JetBrains Mono:bold:size=9} ▌NETWORK\${font}"
|
||||
|
||||
LOCAL_IP=$(ip route get 1.1.1.1 2>/dev/null | awk '{for(i=1;i<=NF;i++) if($i=="src") print $(i+1)}' | head -1)
|
||||
[ -z "$LOCAL_IP" ] && LOCAL_IP="No route"
|
||||
echo "\${color6} LOCAL IP \${color7}${LOCAL_IP}"
|
||||
|
||||
# External IP from cache
|
||||
_display_ip="${PUB_IP}"
|
||||
[ -z "$_display_ip" ] && _display_ip="\${color0}UNAVAILABLE"
|
||||
if [ -n "$PUB_GEO" ]; then
|
||||
echo "\${color6} EXT IP \${color7}${_display_ip} \${color9}(${PUB_GEO})"
|
||||
else
|
||||
echo "\${color6} EXT IP \${color7}${_display_ip}"
|
||||
fi
|
||||
|
||||
VPN_IF=$(ip -o link show 2>/dev/null | awk -F': ' '{print $2}' | grep -E '^(tun|wg)' | head -1)
|
||||
if [ -n "$VPN_IF" ]; then
|
||||
VPN_IP=$(ip -4 addr show "$VPN_IF" 2>/dev/null | awk '/inet / {print $2}' | cut -d/ -f1)
|
||||
echo "\${color6} VPN \${color1}ACTIVE \${color7}${VPN_IP} \${color9}(${VPN_IF})"
|
||||
fi
|
||||
|
||||
# TOR/DNS/KSWCH status moved to TOR STATUS section below
|
||||
|
||||
PRIMARY_IF=$(ip route get 1.1.1.1 2>/dev/null | awk '{for(i=1;i<=NF;i++) if($i=="dev") print $(i+1)}' | head -1)
|
||||
if [ -n "$PRIMARY_IF" ]; then
|
||||
CUR_MAC=$(ip link show "$PRIMARY_IF" 2>/dev/null | awk '/ether/ {print $2}')
|
||||
FIRST_OCTET=$(echo "$CUR_MAC" | cut -d: -f1)
|
||||
FIRST_DEC=$((16#${FIRST_OCTET}))
|
||||
if (( FIRST_DEC & 2 )); then
|
||||
echo "\${color6} MAC \${color1}RANDOM \${color9}(${CUR_MAC})"
|
||||
else
|
||||
echo "\${color6} MAC \${color0}HWADDR \${color9}(${CUR_MAC})"
|
||||
fi
|
||||
else
|
||||
echo "\${color6} MAC \${color9}NO IFACE"
|
||||
fi
|
||||
|
||||
# ─── ADVANCED MODE EXTRAS ────────────────────────────────────────────────────
|
||||
if $ADVANCED; then
|
||||
echo "\${color4}\${hr 1}"
|
||||
echo "\${color8}\${font JetBrains Mono:bold:size=9} ▌HARDENING\${font}"
|
||||
|
||||
IPV6_ALL=$(sysctl -n net.ipv6.conf.all.disable_ipv6 2>/dev/null || echo "0")
|
||||
[ "$IPV6_ALL" = "1" ] && echo "\${color6} IPv6 \${color1}BLOCKED" || echo "\${color6} IPv6 \${color0}LEAKING"
|
||||
|
||||
if lsattr /etc/resolv.conf 2>/dev/null | grep -q 'i'; then
|
||||
echo "\${color6} DNSLK \${color1}LOCKED \${color9}(immutable)"
|
||||
else
|
||||
echo "\${color6} DNSLK \${color0}UNLOCKED"
|
||||
fi
|
||||
|
||||
ISO=$(grep "IsolateDestAddr" /etc/tor/torrc 2>/dev/null | head -1)
|
||||
[ -n "$ISO" ] && echo "\${color6} ISOL \${color1}ACTIVE \${color9}(stream isolation)"
|
||||
|
||||
PAD=$(grep "ConnectionPadding" /etc/tor/torrc 2>/dev/null | awk '{print $2}')
|
||||
[ "$PAD" = "1" ] && echo "\${color6} TPAD \${color1}ACTIVE \${color9}(traffic padding)"
|
||||
|
||||
BLACKLIST=$(grep "ExcludeExitNodes" /etc/tor/torrc 2>/dev/null | sed 's/ExcludeExitNodes //' | tr -d '{}' | tr ',' ' ')
|
||||
[ -n "$BLACKLIST" ] && echo "\${color6} BLOCK \${color0}$(echo "$BLACKLIST" | tr ' ' ',' | sed 's/,$//')"
|
||||
|
||||
CORE_PAT=$(sysctl -n kernel.core_pattern 2>/dev/null)
|
||||
[[ "$CORE_PAT" == *"/bin/false"* ]] && echo "\${color6} CORE \${color1}BLOCKED" || echo "\${color6} CORE \${color0}ENABLED"
|
||||
|
||||
SWAP_ACTIVE=$(swapon --show=SIZE --noheadings 2>/dev/null | head -1)
|
||||
[ -z "$SWAP_ACTIVE" ] && echo "\${color6} SWAP \${color1}OFF" || echo "\${color6} SWAP \${color0}ACTIVE \${color9}(${SWAP_ACTIVE})"
|
||||
|
||||
BOOT_COUNT=0
|
||||
for svc in opsec-boot-advanced opsec-mac-randomize opsec-hostname-randomize opsec-killswitch; do
|
||||
systemctl is-enabled "$svc" 2>/dev/null | grep -q enabled && BOOT_COUNT=$((BOOT_COUNT + 1))
|
||||
done
|
||||
if [ "$BOOT_COUNT" -eq 4 ]; then
|
||||
echo "\${color6} BOOT \${color1}PERSIST \${color9}(${BOOT_COUNT}/4)"
|
||||
elif [ "$BOOT_COUNT" -gt 0 ]; then
|
||||
echo "\${color6} BOOT \${color2}PARTIAL \${color9}(${BOOT_COUNT}/4)"
|
||||
else
|
||||
echo "\${color6} BOOT \${color0}NONE \${color9}(${BOOT_COUNT}/4)"
|
||||
fi
|
||||
|
||||
[ -f /etc/opsec/opsec.conf ] && {
|
||||
PROFILE=$(grep "^PROFILE_NAME=" /etc/opsec/opsec.conf 2>/dev/null | cut -d'"' -f2)
|
||||
[ -n "$PROFILE" ] && echo "\${color6} PROF \${color2}${PROFILE}"
|
||||
}
|
||||
fi
|
||||
|
||||
# ─── TOR STATUS (replaces Route Chain) ──────────────────────────────────────
|
||||
if $ADVANCED; then
|
||||
echo "\${color4}\${hr 1}"
|
||||
echo "\${color8}\${font JetBrains Mono:bold:size=9} ▌TOR STATUS\${font}"
|
||||
|
||||
# Determine protection state
|
||||
_tor_svc=false; _tor_socks=false; _ks_armed=false; _tor_routed=false
|
||||
systemctl is-active tor >/dev/null 2>&1 && _tor_svc=true
|
||||
ss -tln 2>/dev/null | grep -q ':9050 ' && _tor_socks=true
|
||||
# iptables -L requires root; use state file instead (kill switch is always armed when advanced is on)
|
||||
$ADVANCED && _ks_armed=true
|
||||
[ "$ROUTED_TOR" = "true" ] && _tor_routed=true
|
||||
|
||||
if $_tor_svc && $_tor_socks && $_ks_armed && $_tor_routed; then
|
||||
echo "\${color6} STATE \${color1}PROTECTED"
|
||||
elif $_tor_svc && ! $_tor_socks; then
|
||||
# Bootstrapping
|
||||
echo "\${color6} STATE \${color2}BOOTSTRAP \${color9}(${TOR_BOOTSTRAP:-0}% ${TOR_PHASE:-connecting})"
|
||||
elif ! $_tor_svc; then
|
||||
echo "\${color6} STATE \${color0}EXPOSED \${color9}(tor down)"
|
||||
elif ! $_ks_armed; then
|
||||
echo "\${color6} STATE \${color0}EXPOSED \${color9}(kill switch off)"
|
||||
else
|
||||
echo "\${color6} STATE \${color0}EXPOSED \${color9}(not routed)"
|
||||
fi
|
||||
|
||||
# Exit country code only — no IP
|
||||
if [ -n "$EXIT_COUNTRY" ] && [ ${#EXIT_COUNTRY} -le 3 ]; then
|
||||
echo "\${color6} EXIT \${color2}${EXIT_COUNTRY}"
|
||||
elif $_tor_socks; then
|
||||
echo "\${color6} EXIT \${color9}resolving..."
|
||||
else
|
||||
echo "\${color6} EXIT \${color9}—"
|
||||
fi
|
||||
|
||||
# Circuit age — time since exit IP last changed
|
||||
if [ -n "$EXIT_CHANGE_TIME" ] && [ "$EXIT_CHANGE_TIME" -gt 0 ] 2>/dev/null; then
|
||||
_now=$(date +%s)
|
||||
_age=$(( _now - EXIT_CHANGE_TIME ))
|
||||
if [ "$_age" -lt 60 ]; then
|
||||
echo "\${color6} CIRCUIT \${color2}${_age}s ago"
|
||||
elif [ "$_age" -lt 3600 ]; then
|
||||
echo "\${color6} CIRCUIT \${color2}$(( _age / 60 ))m ago"
|
||||
else
|
||||
echo "\${color6} CIRCUIT \${color2}$(( _age / 3600 ))h $(( (_age % 3600) / 60 ))m ago"
|
||||
fi
|
||||
else
|
||||
echo "\${color6} CIRCUIT \${color9}—"
|
||||
fi
|
||||
|
||||
# DNS leak check — local checks only
|
||||
_dns_server=$(awk '/^nameserver/ {print $2; exit}' /etc/resolv.conf 2>/dev/null)
|
||||
_dns_immutable=false
|
||||
lsattr /etc/resolv.conf 2>/dev/null | grep -q 'i' && _dns_immutable=true
|
||||
_nm_locked=false
|
||||
[ -f /etc/NetworkManager/conf.d/opsec-dns-lock.conf ] && _nm_locked=true
|
||||
|
||||
if [ "$_dns_server" = "127.0.0.1" ] && $_dns_immutable && $_nm_locked; then
|
||||
echo "\${color6} DNS \${color1}SECURE \${color9}(tor + locked)"
|
||||
elif [ "$_dns_server" = "127.0.0.1" ] && $_dns_immutable; then
|
||||
echo "\${color6} DNS \${color2}SECURE \${color9}(tor, NM unlocked)"
|
||||
elif [ "$_dns_server" = "127.0.0.1" ]; then
|
||||
echo "\${color6} DNS \${color2}PARTIAL \${color9}(tor, not locked)"
|
||||
elif echo "$_dns_server" | grep -qE '^(9\.9\.9\.9|149\.112\.112\.112|1\.1\.1\.1|1\.0\.0\.1)$'; then
|
||||
echo "\${color6} DNS \${color2}PRIVACY \${color9}(${_dns_server})"
|
||||
else
|
||||
echo "\${color6} DNS \${color0}LEAKED \${color9}(${_dns_server})"
|
||||
fi
|
||||
fi
|
||||
|
||||
# ─── MODE / LEVEL ───────────────────────────────────────────────────────────
|
||||
echo "\${color4}\${hr 1}"
|
||||
LEVEL=""
|
||||
[ -f /etc/opsec/opsec.conf ] && LEVEL=$(grep "^DEPLOYMENT_LEVEL=" /etc/opsec/opsec.conf 2>/dev/null | cut -d'"' -f2)
|
||||
if $ADVANCED; then
|
||||
echo "\${color6} MODE \${color1}ADVANCED"
|
||||
else
|
||||
echo "\${color6} MODE \${color0}STANDARD"
|
||||
fi
|
||||
[ -n "$LEVEL" ] && echo "\${color6} LEVEL \${color7}${LEVEL}"
|
||||
|
||||
echo "\${color4}\${hr 1}"
|
||||
echo "\${color9}\${font JetBrains Mono:size=7}\${alignc}// updated \${time %H:%M:%S} //\${font}"
|
||||
@@ -0,0 +1,71 @@
|
||||
-- OPSEC Status Widget
|
||||
-- Colors managed by theme system via opsec-config.sh (--theme apply NAME)
|
||||
-- Uses execpi to parse Conky color markup from helper script
|
||||
|
||||
conky.config = {
|
||||
-- Window settings
|
||||
-- Default: upper-right on primary display
|
||||
alignment = 'top_right',
|
||||
gap_x = 15,
|
||||
gap_y = 60,
|
||||
minimum_width = 400,
|
||||
minimum_height = 200,
|
||||
maximum_width = 420,
|
||||
|
||||
-- Multi-monitor: pin to primary display (head 0)
|
||||
-- Set xinerama_head to a different number to move to another monitor
|
||||
xinerama_head = 0,
|
||||
|
||||
-- Window type
|
||||
own_window = true,
|
||||
own_window_type = 'desktop',
|
||||
own_window_transparent = false,
|
||||
own_window_argb_visual = true,
|
||||
own_window_argb_value = 210,
|
||||
own_window_colour = '0d1117',
|
||||
own_window_hints = 'undecorated,below,sticky,skip_taskbar,skip_pager',
|
||||
|
||||
-- Drawing
|
||||
double_buffer = true,
|
||||
draw_shades = true,
|
||||
default_shade_color = '000000',
|
||||
draw_outline = false,
|
||||
draw_borders = true,
|
||||
border_inner_margin = 12,
|
||||
border_outer_margin = 4,
|
||||
border_width = 1,
|
||||
border_colour = '1b3a5c',
|
||||
stippled_borders = 0,
|
||||
|
||||
-- Font
|
||||
use_xft = true,
|
||||
font = 'JetBrains Mono:size=10',
|
||||
override_utf8_locale = true,
|
||||
|
||||
-- Colors — OPSEC Status Widget
|
||||
default_color = 'b0b0b0',
|
||||
color0 = 'df2020', -- ares red (NOT SECURE)
|
||||
color1 = '33ff33', -- terminal green (SECURE)
|
||||
color2 = '3a8fd6', -- steel blue (info/neutral)
|
||||
color3 = '0d1117', -- void (dividers)
|
||||
color4 = '1f6feb', -- blue (structural lines)
|
||||
color5 = '58a6ff', -- bright blue (title/accent)
|
||||
color6 = '79c0ff', -- light blue (labels)
|
||||
color7 = 'c9d1d9', -- silver (values)
|
||||
color8 = '1f6feb', -- blue (section headers)
|
||||
color9 = '484f58', -- dark grey (metadata)
|
||||
|
||||
-- Update interval
|
||||
update_interval = 3,
|
||||
total_run_times = 0,
|
||||
|
||||
-- Misc
|
||||
cpu_avg_samples = 2,
|
||||
no_buffers = true,
|
||||
text_buffer_size = 8192,
|
||||
short_units = true,
|
||||
};
|
||||
|
||||
conky.text = [[
|
||||
${execpi 5 ~/.config/conky/conky-opsec-status.sh}
|
||||
]];
|
||||
Executable
+127
@@ -0,0 +1,127 @@
|
||||
#!/bin/bash
|
||||
# OPSEC Widget Launcher — positions and launches the Conky widget
|
||||
# Usage: opsec-widget-launch.sh [position]
|
||||
#
|
||||
# Positions:
|
||||
# tl = top-left tc = top-center tr = top-right
|
||||
# bl = bottom-left bc = bottom-center br = bottom-right
|
||||
#
|
||||
# Default: tr (top-right)
|
||||
# Uses the theme system — regenerates config from /etc/opsec/themes/
|
||||
|
||||
CONKY_DIR="$HOME/.config/conky"
|
||||
CONF="$CONKY_DIR/conky-opsec-widget.conf"
|
||||
POS="${1:-tr}"
|
||||
|
||||
# Map shorthand to conky alignment + gaps
|
||||
case "$POS" in
|
||||
tl) ALIGN="top_left"; GAP_X=15; GAP_Y=15 ;;
|
||||
tc) ALIGN="top_middle"; GAP_X=0; GAP_Y=15 ;;
|
||||
tr) ALIGN="top_right"; GAP_X=15; GAP_Y=60 ;;
|
||||
bl) ALIGN="bottom_left"; GAP_X=15; GAP_Y=60 ;;
|
||||
bc) ALIGN="bottom_middle"; GAP_X=0; GAP_Y=60 ;;
|
||||
br) ALIGN="bottom_right"; GAP_X=15; GAP_Y=60 ;;
|
||||
*)
|
||||
echo "Usage: $(basename "$0") [tl|tc|tr|bl|bc|br]"
|
||||
echo ""
|
||||
echo " tl = top-left tc = top-center tr = top-right"
|
||||
echo " bl = bottom-left bc = bottom-center br = bottom-right"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# Kill existing widget and stale cache daemon
|
||||
killall conky 2>/dev/null
|
||||
pkill -f 'conky-opsec-cache\.sh' 2>/dev/null
|
||||
rm -f /tmp/.opsec-cache/netinfo 2>/dev/null
|
||||
sleep 0.3
|
||||
|
||||
# Load theme from opsec config
|
||||
OPSEC_CONF="/etc/opsec/opsec.conf"
|
||||
THEME="default"
|
||||
[ -f "$OPSEC_CONF" ] && THEME=$(grep "^WIDGET_THEME=" "$OPSEC_CONF" 2>/dev/null | cut -d'"' -f2)
|
||||
[ -z "$THEME" ] && THEME="default"
|
||||
|
||||
THEME_FILE="/etc/opsec/themes/${THEME}.theme"
|
||||
if [ -f "$THEME_FILE" ]; then
|
||||
. "$THEME_FILE"
|
||||
else
|
||||
echo "Theme '${THEME}' not found, using defaults"
|
||||
THEME_LABEL="Default"
|
||||
CONKY_BG="0d1117"
|
||||
CONKY_COLOR0="df2020"; CONKY_COLOR1="33ff33"; CONKY_COLOR2="3a8fd6"
|
||||
CONKY_COLOR3="0d1117"; CONKY_COLOR4="1f6feb"; CONKY_COLOR5="58a6ff"
|
||||
CONKY_COLOR6="79c0ff"; CONKY_COLOR7="c9d1d9"; CONKY_COLOR8="1f6feb"
|
||||
CONKY_COLOR9="484f58"
|
||||
fi
|
||||
|
||||
# Generate config with theme colors and chosen position
|
||||
mkdir -p "$CONKY_DIR"
|
||||
cat > "$CONF" << EOF
|
||||
-- OPSEC Status Widget — OPSEC Status Widget
|
||||
-- Theme: ${THEME} (${THEME_LABEL:-Custom})
|
||||
-- Position: ${ALIGN}
|
||||
|
||||
conky.config = {
|
||||
alignment = '${ALIGN}',
|
||||
gap_x = ${GAP_X},
|
||||
gap_y = ${GAP_Y},
|
||||
minimum_width = 400,
|
||||
minimum_height = 200,
|
||||
maximum_width = 420,
|
||||
|
||||
own_window = true,
|
||||
own_window_type = 'normal',
|
||||
own_window_transparent = false,
|
||||
own_window_argb_visual = true,
|
||||
own_window_argb_value = 210,
|
||||
own_window_colour = '${CONKY_BG:-0d1117}',
|
||||
own_window_hints = 'undecorated,below,sticky,skip_taskbar,skip_pager',
|
||||
|
||||
xinerama_head = 0,
|
||||
|
||||
double_buffer = true,
|
||||
draw_shades = true,
|
||||
default_shade_color = '000000',
|
||||
draw_outline = false,
|
||||
draw_borders = true,
|
||||
border_inner_margin = 12,
|
||||
border_outer_margin = 4,
|
||||
border_width = 1,
|
||||
border_colour = '${CONKY_COLOR4:-1f6feb}',
|
||||
stippled_borders = 0,
|
||||
|
||||
use_xft = true,
|
||||
font = 'JetBrains Mono:size=10',
|
||||
override_utf8_locale = true,
|
||||
|
||||
default_color = 'b0b0b0',
|
||||
color0 = '${CONKY_COLOR0:-df2020}',
|
||||
color1 = '${CONKY_COLOR1:-33ff33}',
|
||||
color2 = '${CONKY_COLOR2:-3a8fd6}',
|
||||
color3 = '${CONKY_COLOR3:-0d1117}',
|
||||
color4 = '${CONKY_COLOR4:-1f6feb}',
|
||||
color5 = '${CONKY_COLOR5:-58a6ff}',
|
||||
color6 = '${CONKY_COLOR6:-79c0ff}',
|
||||
color7 = '${CONKY_COLOR7:-c9d1d9}',
|
||||
color8 = '${CONKY_COLOR8:-1f6feb}',
|
||||
color9 = '${CONKY_COLOR9:-484f58}',
|
||||
|
||||
update_interval = 3,
|
||||
total_run_times = 0,
|
||||
|
||||
cpu_avg_samples = 2,
|
||||
no_buffers = true,
|
||||
text_buffer_size = 8192,
|
||||
short_units = true,
|
||||
};
|
||||
|
||||
conky.text = [[
|
||||
\${execpi 5 ~/.config/conky/conky-opsec-status.sh}
|
||||
]];
|
||||
EOF
|
||||
|
||||
# Launch
|
||||
conky -c "$CONF" &
|
||||
disown
|
||||
echo "OPSEC widget launched: $ALIGN (theme: $THEME)"
|
||||
Reference in New Issue
Block a user