Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!


Shells Virtual Desktop
BMail.ag - Secure Email Service
Server.net
CPLicense.net
VPS Server
Buy VPN
Vultr
VMs for AI
HostDare
ReliableSite White-Label Dedicated Hosting for Resellers
InterServer VPS
BMail.ag - Secure Email Service
Best VPN
High-Performance Bare Metal Server Solutions
Karvl.com
Server Mania Cloud Hosting
DataWagon Hosting
AlphaVPS Hosting
Evoxt.com
Clouvider
VPS Hosting with NVMe
Residential IPs in the US & 4G Mobile Proxies in EU & US with Unlimited Bandwidth
ReliableSite White-Label Dedicated Hosting for Resellers
Rabisu - Hosting Solutions
Shells Virtual Desktop
New on LowEndTalk? Please Register and read our Community Rules.

All new Registrations are manually reviewed and approved, so a short delay after registration may occur before your account becomes active.

Feedback wanted for a bash script to block

gbzret4dgbzret4d Member
edited November 2025 in Help

I’ve put together a small script that updates firewall blocklists on Linux automatically. Main reason was to block risky IPs, bits,....to access my servers. The script pulls several public and a couple of commercial threat sources, filters out private or invalid ranges, and loads everything into ipset/iptables. Whitelists are applied first so you don’t lock yourself out. IPv4 and IPv6 are handled in parallel.

Technically it’s just one Bash script plus a few simple config files that contain the source URLs. API keys go into an env file that isn’t in the repo. If a download fails, it falls back to a local backup. Errors or issues get sent to me through Telegram. I run it through cron every few hours.

The repo is very minimal, basically the main script, a config folder and the README.

Would appreciate any feedback, ideas for improvements, or things I might have missed and yes, AI was involved.

Github: https://github.com/gbzret4d/firewall-blocklist-updater

    #!/bin/bash
set -euo pipefail

#################################################
# Firewall Blocklist Update Script (extended)
# - IPv4 and IPv6 support
# - Parallel source download
# - Secure API key file permissions
# - Container compatible (no sudo required)
# - Dynamic DynDNS IP whitelist management added
# Adjusted for installation in /usr/local/bin/
#################################################

# Fixed script directory since script is installed in /usr/local/bin/
SCRIPT_DIR="/usr/local/bin"

# Configuration directory to store sources and keys, adjust if needed
CONFIG_DIR="${CONFIG_DIR:-/usr/local/etc/firewall-blocklists}"

# Source files and keyfile locations in config dir
WHITELIST_SOURCES_FILE="${WHITELIST_SOURCES_FILE:-$CONFIG_DIR/whitelist.sources}"
BLOCKLIST_SOURCES_FILE="${BLOCKLIST_SOURCES_FILE:-$CONFIG_DIR/blocklist.sources}"
KEYFILE="${KEYFILE:-$CONFIG_DIR/firewall-blocklist-keys.env}"

# Ensure config directory exists
mkdir -p "$CONFIG_DIR"

# Ensure restrictive permissions for the key file
if [[ -f "$KEYFILE" ]]; then
  chmod 600 "$KEYFILE"
  # Load keys and variables from env file (ignore commented lines)
  export $(grep -v '^#' "$KEYFILE" | xargs) || true
  echo "[INFO] Loaded API keys and configuration from $KEYFILE"
else
  echo "[WARN] Key file $KEYFILE not found. API, Telegram features and DYNDNS_HOST disabled."
fi

# Color vars for logging
if [[ -t 1 ]]; then
  RED='\033[0;31m'
  YELLOW='\033[0;33m'
  GREEN='\033[0;32m'
  BLUE='\033[0;34m'
  NC='\033[0m'
else
  RED='' YELLOW='' GREEN='' BLUE='' NC=''
fi

log() {
  local lvl="$1"; shift
  local color="$RED"
  case "$lvl" in
    INFO) color="$GREEN" ;;
    WARN) color="$YELLOW" ;;
    DEBUG) color="$BLUE" ;;
  esac
  echo -e "$(date '+%Y-%m-%d %H:%M:%S') ${color}[$lvl]${NC} $*"
}

send_telegram() {
  if [[ -z "${TELEGRAM_BOT_TOKEN:-}" || -z "${TELEGRAM_CHAT_ID:-}" ]]; then
    log WARN "Telegram token or chat ID missing; skipping telegram notification."
    return
  fi
  local message="$1"
  curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \
    -d chat_id="${TELEGRAM_CHAT_ID}" \
    -d text="$message" >/dev/null 2>&1 || log WARN "Failed to send telegram notification."
}

error_handler() {
  local exit_code=$?
  if [[ $exit_code -ne 0 ]]; then
    local host
    host="$(hostname)"
    local msg="🚨 Firewall blocklist update FAILED with exit code $exit_code on $host at $(date '+%Y-%m-%d %H:%M:%S')"
    send_telegram "$msg"
  fi
  exit $exit_code
}
trap error_handler ERR SIGINT SIGTERM

# Determine package manager for dependencies (Container / Host)
install_pkg() {
  local pkg="$1"
  if command -v apk &>/dev/null; then
    apk add --no-cache "$pkg"
  elif command -v apt-get &>/dev/null; then
    apt-get update && apt-get install -y "$pkg"
  elif command -v dnf &>/dev/null; then
    dnf install -y "$pkg"
  elif command -v yum &>/dev/null; then
    yum install -y "$pkg"
  else
    log WARN "No known package manager found to install $pkg"
  fi
}

check_install() {
  local binary="$1"
  if ! command -v "$binary" &>/dev/null; then
    log WARN "Missing $binary, trying to install"
    install_pkg "$binary"
  else
    log DEBUG "$binary found"
  fi
}

for cmd in curl ipset iptables python3 jq grep comm sort dig; do
  check_install "$cmd"
done

# Variables
TMPDIR="${TMPDIR:-/tmp/firewall-blocklists}"
BACKUPDIR="$TMPDIR/backup"
mkdir -p "$TMPDIR" "$BACKUPDIR"

IPSET_WHITELIST="allowed_whitelist"
IPSET_BLOCKLIST="blocklist_all"
IPSET_WHITELIST6="allowed_whitelist_v6"
IPSET_BLOCKLIST6="blocklist_all_v6"
IPTABLES_CHAIN="INPUT"
IPTABLES_CHAIN6="INPUT"   # modify if you use ip6tables
IPSET_HASH_SIZE=2048
IPSET_MAX_ELEM=65536

# API Keys (defaults)
ABUSEIPDB_API_KEY="${ABUSEIPDB_API_KEY:-YOUR_API_KEY_HERE}"
HONEYDB_API_ID="${HONEYDB_API_ID:-}"
HONEYDB_API_KEY="${HONEYDB_API_KEY:-}"
HONEYDB_URL="https://honeydb.io/api/bad-hosts"

# --- Read sources into arrays ---
read_sources() {
  local file="$1"
  if [[ ! -f "$file" ]]; then
    log WARN "Sources file $file does not exist."
    return 1
  fi
  grep -E '^\s*[^#[:space:]]' "$file" || true
}

mapfile -t WHITELIST_SOURCES < <(read_sources "$WHITELIST_SOURCES_FILE") || true
mapfile -t BLOCKLIST_SOURCES < <(read_sources "$BLOCKLIST_SOURCES_FILE") || true

#########################################
# Download with backup fallback
download_with_backup() {
  local url="$1" output="$2" backup="$3"
  log INFO "Downloading $url"
  if curl -sfL --connect-timeout 20 -A "firewall-blocklist-updater" "$url" -o "$output"; then
    if [[ -s "$output" ]]; then
      cp "$output" "$backup"
      log INFO "Downloaded and backed up $url"
      return 0
    else
      log WARN "Downloaded file is empty: $output"
    fi
  else
    log WARN "Failed to download $url"
  fi
  # fallback to backup
  if [[ -s "$backup" ]]; then
    cp "$backup" "$output"
    log WARN "Used backup for $url"
    return 0
  fi
  log ERROR "No backup available for $url"
  return 1
}

# Parallel downloads (max 6 jobs)
download_and_merge_parallel() {
  local outfile="$1"
  shift
  local sources=("$@")
  : > "$TMPDIR/tmpmerge.lst"

  export -f download_with_backup log
  export TMPDIR BACKUPDIR

  printf '%s\n' "${sources[@]}" | xargs -P6 -I{} bash -c '
    url="{}"
    fname=$(basename "$url")
    if ! [[ "$fname" =~ \. ]]; then
      fname=$(echo "$url" | sed "s|https\?://||; s|[/:]|_|g")
    fi
    filepath="$TMPDIR/$fname"
    backup="$BACKUPDIR/$fname.bak"
    download_with_backup "$url" "$filepath" "$backup" && grep -Ev "^\s*(#|\$)" "$filepath" >> "$TMPDIR/tmpmerge.lst"
  '

  sort -u "$TMPDIR/tmpmerge.lst" > "$outfile"
  log INFO "Merged $(wc -l < "$outfile") unique entries into $outfile"
}

download_and_merge() {
  # fallback if no parallel available
  download_and_merge_parallel "$@"
}

download_abuseipdb() {
  local outfile="$1" bakfile="$2"
  if [[ "$ABUSEIPDB_API_KEY" == "YOUR_API_KEY_HERE" || -z "$ABUSEIPDB_API_KEY" ]]; then
    log WARN "AbuseIPDB API key missing or default. Skipping AbuseIPDB."
    return 0
  fi
  log INFO "Downloading AbuseIPDB blacklist"
  if curl -sfG "https://api.abuseipdb.com/api/v2/blacklist" \
    -H "Key: $ABUSEIPDB_API_KEY" -H "Accept: text/plain" \
    -A "firewall-blocklist-updater" -o "$outfile"; then
    if [[ -s "$outfile" ]]; then
      cp "$outfile" "$bakfile"
      grep -Eo '([0-9a-fA-F:.]+(/[0-9]+)?)' "$outfile" | sort -u > "${outfile}.ips"
      mv "${outfile}.ips" "$outfile"
      log INFO "AbuseIPDB blacklist downloaded and processed"
      return 0
    else
      log WARN "AbuseIPDB response empty"
    fi
  else
    log WARN "Failed to download AbuseIPDB blacklist"
  fi
  if [[ -s "$bakfile" ]]; then
    cp "$bakfile" "$outfile"
    log WARN "Using backup for AbuseIPDB blacklist"
    return 0
  fi
  log ERROR "No AbuseIPDB backup available"
  return 1
}

download_honeydb() {
  local outfile="$1" bakfile="$2"
  if [[ -z "$HONEYDB_API_ID" || -z "$HONEYDB_API_KEY" ]]; then
    log WARN "HoneyDB API ID or KEY not set. Skipping HoneyDB."
    return 0
  fi
  log INFO "Downloading HoneyDB blacklist"
  if curl -sfL "$HONEYDB_URL" \
    -H "X-HoneyDb-ApiId: $HONEYDB_API_ID" \
    -H "X-HoneyDb-ApiKey: $HONEYDB_API_KEY" \
    -A "firewall-blocklist-updater" -o "$outfile"; then
    if [[ -s "$outfile" ]]; then
      cp "$outfile" "$bakfile"
      if command -v jq &>/dev/null; then
        jq -r '.[].remote_host' "$outfile" | sort -u > "${outfile}.ips"
      else
        grep -Eo '([0-9a-fA-F:.]+)' "$outfile" | sort -u > "${outfile}.ips"
        log WARN "jq not found; fallback JSON parse used"
      fi
      mv "${outfile}.ips" "$outfile"
      log INFO "HoneyDB blacklist downloaded and processed"
      return 0
    else
      log WARN "HoneyDB response empty"
    fi
  else
    log WARN "Failed to download HoneyDB blacklist"
  fi
  if [[ -s "$bakfile" ]]; then
    cp "$bakfile" "$outfile"
    log WARN "Using backup for HoneyDB blacklist"
    return 0
  fi
  log ERROR "No HoneyDB backup available"
  return 1
}

# Filter IPv4 and IPv6 addresses with Python (exclude private, reserved)
filter_private_ips() {
  local infile="$1" outfile="$2"
  if ! command -v python3 &>/dev/null; then
    log WARN "python3 not found; skipping private IP filtering"
    cp "$infile" "$outfile"
    return 0
  fi

  python3 -c "$(cat <<EOF
import ipaddress, sys
ips = set()
for line in sys.stdin:
    line = line.strip()
    if not line or line.startswith("#"):
        continue
    try:
        ipobj = None
        if "/" in line:
            ipobj = ipaddress.ip_network(line, strict=False)
        else:
            ipobj = ipaddress.ip_address(line)
        if ipobj.version == 4:
            if not (ipobj.is_private or ipobj.is_loopback or ipobj.is_reserved or ipobj.is_multicast):
                ips.add(str(ipobj))
        elif ipobj.version == 6:
            if not (ipobj.is_private or ipobj.is_loopback or ipobj.is_reserved or ipobj.is_multicast):
                ips.add(str(ipobj))
    except:
        pass

with open('${outfile}', 'w') as f:
    for ip in sorted(ips):
        f.write(ip + "\n")
EOF
)" < "$infile"

  log INFO "Filtered private/local IPs (IPv4+IPv6): $infile -> $outfile"
}

create_or_flush_ipset() {
  local set=$1
  local type="hash:net"
  if [[ "$set" == *"_v6" ]]; then
    type="hash:net family inet6"
  fi
  if ipset list "$set" &>/dev/null; then
    ipset flush "$set"
    log INFO "Flushed ipset $set"
  else
    ipset create "$set" $type hashsize "$IPSET_HASH_SIZE" maxelem "$IPSET_MAX_ELEM"
    log INFO "Created ipset $set ($type)"
  fi
}

# Load IPv4 or IPv6 IPs into the appropriate ipset
load_ips_to_ipset() {
  local file="$1" set="$2"
  local cnt=0
  log INFO "Loading IPs from $file into $set"
  while IFS= read -r ip; do
    ip="${ip//[[:space:]]/}"
    if [[ "$ip" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}(/[0-9]+)?$ ]] && [[ "$set" != *_v6 ]]; then
      ipset add "$set" "$ip" 2>/dev/null || true
      ((cnt++))
    elif [[ "$ip" =~ ^([0-9a-fA-F:]+(/[0-9]+)?)$ ]] && [[ "$set" == *_v6 ]]; then
      ipset add "$set" "$ip" 2>/dev/null || true
      ((cnt++))
    fi
  done < <(grep -Ev '^\s*($|#)' "$file")
  log INFO "Loaded $cnt IPs into $set"
}

cleanup_old_iptables_rules() {
  local current_sets=("$IPSET_BLOCKLIST" "$IPSET_WHITELIST" "$IPSET_BLOCKLIST6" "$IPSET_WHITELIST6")
  mapfile -t rules < <(iptables -S "$IPTABLES_CHAIN" | grep -- "-m set --match-set" || true)
  for rule in "${rules[@]}"; do
    if [[ "$rule" =~ --match-set[[:space:]]+([^[:space:]]+) ]]; then
      local setname="${BASH_REMATCH[1]}"
      if ! [[ " ${current_sets[*]} " =~ " ${setname} " ]]; then
        local delrule="${rule/-A/-D}"
        iptables $delrule || true
        log INFO "Removed obsolete iptables rule referencing $setname"
      fi
    fi
  done
  # Optional: similar cleanup for ip6tables if used
}

ensure_iptables_rule() {
  if ! iptables -C "$IPTABLES_CHAIN" -m set --match-set "$IPSET_BLOCKLIST" src -j DROP &>/dev/null; then
    iptables -I "$IPTABLES_CHAIN" -m set --match-set "$IPSET_BLOCKLIST" src -j DROP
    log INFO "Added iptables rule to drop IPs in $IPSET_BLOCKLIST"
  else
    log INFO "iptables rule for $IPSET_BLOCKLIST already exists"
  fi
  # Optional: add ip6tables rule if IPv6 filtering desired
}

##############################################
# Dynamic DynDNS IP Whitelist Management (using DYNDNS_HOST from env)
##############################################

cleanup_old_dynamic_dns_ips() {
  if [[ -z "${DYNDNS_HOST:-}" ]]; then
    log WARN "DYNDNS_HOST not set. Skipping dynamic DNS whitelist cleanup."
    return 1
  fi
  local dnsname="$DYNDNS_HOST"
  local current_ip new_ips ip

  current_ip=$(dig +short "$dnsname" | head -n1 || true)
  if [[ -z "$current_ip" ]]; then
    log WARN "Failed to resolve $dnsname; skipping cleanup of old DynDNS IPs."
    return 1
  fi

  # List all IPs currently in whitelist ipset
  # Filter out the current IP (keep this one)
  mapfile -t new_ips < <(ipset list "$IPSET_WHITELIST" | awk '/^Members:$/ {flag=1;next} flag && NF {print $1}' || true)

  for ip in "${new_ips[@]}"; do
    if [[ "$ip" != "$current_ip" ]]; then
      ipset del "$IPSET_WHITELIST" "$ip" 2>/dev/null && log INFO "Removed old DynDNS IP $ip from whitelist"
    fi
  done
}

update_dynamic_dns_whitelist() {
  if [[ -z "${DYNDNS_HOST:-}" ]]; then
    log WARN "DYNDNS_HOST not set. Skipping dynamic DNS whitelist update."
    return 1
  fi
  local dnsname="$DYNDNS_HOST"
  local ip

  ip=$(dig +short "$dnsname" | head -n1 || true)

  if [[ -z "$ip" ]]; then
    log WARN "Failed to resolve $dnsname; whitelist entry unchanged."
    return 1
  fi

  if ipset test "$IPSET_WHITELIST" "$ip" &>/dev/null; then
    log INFO "Dynamic DNS IP $ip already in whitelist"
  else
    ipset add "$IPSET_WHITELIST" "$ip"
    log INFO "Added dynamic DNS IP $ip to whitelist"
  fi

  # Clean up older IPs, keep only current:
  cleanup_old_dynamic_dns_ips
}

# --- Main execution ---

log INFO "=== Starting firewall blocklist update ==="

cleanup_old_iptables_rules

update_dynamic_dns_whitelist   # <<<< Use DYNDNS_HOST from env here

wl_file="$TMPDIR/whitelist.lst"
download_and_merge_parallel "$wl_file" "${WHITELIST_SOURCES[@]}"

bl_file_raw="$TMPDIR/blocklist_raw.lst"
download_and_merge_parallel "$bl_file_raw" "${BLOCKLIST_SOURCES[@]}"

abuseipdb_file="$TMPDIR/abuseipdb.lst"
download_abuseipdb "$abuseipdb_file" "$BACKUPDIR/abuseipdb.bak"
cat "$abuseipdb_file" >> "$bl_file_raw" 2>/dev/null || true

honeydb_file="$TMPDIR/honeydb.lst"
download_honeydb "$honeydb_file" "$BACKUPDIR/honeydb.bak"
cat "$honeydb_file" >> "$bl_file_raw" 2>/dev/null || true

filter_private_ips "$bl_file_raw" "$TMPDIR/blocklist_filtered.lst"

bl_file_filtered="$TMPDIR/blocklist_filtered.lst"

bl_file_final="$TMPDIR/blocklist_final.lst"
comm -23 <(sort "$bl_file_filtered") <(sort "$wl_file") > "$bl_file_final"

log INFO "$(wc -l < "$bl_file_final") IPs remain after applying whitelist"

create_or_flush_ipset "$IPSET_WHITELIST"
load_ips_to_ipset "$wl_file" "$IPSET_WHITELIST"

create_or_flush_ipset "$IPSET_BLOCKLIST"
load_ips_to_ipset "$bl_file_final" "$IPSET_BLOCKLIST"

# IPv6 sets creation and loading (optional)
create_or_flush_ipset "$IPSET_WHITELIST6"
load_ips_to_ipset "$wl_file" "$IPSET_WHITELIST6"

create_or_flush_ipset "$IPSET_BLOCKLIST6"
load_ips_to_ipset "$bl_file_final" "$IPSET_BLOCKLIST6"

ensure_iptables_rule

count_wl=$(ipset list "$IPSET_WHITELIST" 2>/dev/null | awk '/Number of entries:/ {print $4}' || echo 0)
count_bl=$(ipset list "$IPSET_BLOCKLIST" 2>/dev/null | awk '/Number of entries:/ {print $4}' || echo 0)
log INFO "Whitelist contains: $count_wl IPs"
log INFO "Blocklist contains: $count_bl IPs"

log INFO "=== Firewall blocklist update finished ==="
exit 0

Comments

  • Why not just use crowdsec or fail2ban?

    Thanked by 2itsTomHarper tentor
  • @loay said:
    Why not just use crowdsec or fail2ban?

    To block ips accessing services im hosting publicly.

  • davidedavide Member
    edited November 2025

    Wow it's AMAZING!

    I especially love these:

    # Color vars for logging
    if [[ -t 1 ]]; then
      RED='\033[0;31m'
      YELLOW='\033[0;33m'
      GREEN='\033[0;32m'
      BLUE='\033[0;34m'
      NC='\033[0m'
    else
      RED='' YELLOW='' GREEN='' BLUE='' NC=''
    fi
    

    and

    local msg="🚨"

    But IMHO you should add more color; the more color you have, the richer the personality of your script. It's a waste that we all have these HD monitors with 32 bit color depth and no one uses them for serious work.

  • gbzret4dgbzret4d Member
    edited November 2025

    @davide said:
    Wow it's AMAZING!

    I especially love these:

    # Color vars for logging
    if [[ -t 1 ]]; then
      RED='\033[0;31m'
      YELLOW='\033[0;33m'
      GREEN='\033[0;32m'
      BLUE='\033[0;34m'
      NC='\033[0m'
    else
      RED='' YELLOW='' GREEN='' BLUE='' NC=''
    fi
    

    and

    local msg="🚨"

    But IMHO you should add more color; the more color you have, the richer the personality of your script. It's a waste that we all have these HD monitors with 32 bit color depth and no one uses them for serious work.

    Curse of the AI
    Comparable to RGB in gaming PCs, right?

  • @gbzret4d said:
    Comparable to RGB in gaming PCs, right?

    They both are AWESOME! :blush:

  • Vibe coded crapware. The rule is simple:

    If you need more then 100 lines of code in bash -> do it with python. Feed that mess to claude and ask it to convert to python.

  • @Levi said:
    Vibe coded crapware. The rule is simple:

    If you need more then 100 lines of code in bash -> do it with python. Feed that mess to claude and ask it to convert to python.

    You prefer/suggest Claude for coding related stuff?

  • @gbzret4d said:

    @Levi said:
    Vibe coded crapware. The rule is simple:

    If you need more then 100 lines of code in bash -> do it with python. Feed that mess to claude and ask it to convert to python.

    You prefer/suggest Claude for coding related stuff?

    Yes, less bullshit as it is with cgpt. Optimize code with xAI.

  • yoursunnyyoursunny Member, IPv6 Advocate
    edited November 2025

    Bad vibes detected.
    The rule is simple:

    If you need more than 69 lines of code in Python — do it with Go.
    Feed that spaghetti to intern and ask her to rewrite in Go.

  • davidedavide Member
    edited November 2025

    @yoursunny said:
    Bad vibes detected.
    The rule is simple:

    If you need more than 69 lines of code in Python — do it with Go.
    Feed that spaghetti to intern and ask her to rewrite in Go.

    My rule of thumb is about 5 lines of Python max, beyond 5 lines Python becomes abominable.

    ~~~

    But I know what you're thinking..... let's fix that rule of thumb: no more than 100 bytes of Python.

    Ah!

  • Asm is the answer.

  • @Levi said:

    @gbzret4d said:

    @Levi said:
    Vibe coded crapware. The rule is simple:

    If you need more then 100 lines of code in bash -> do it with python. Feed that mess to claude and ask it to convert to python.

    You prefer/suggest Claude for coding related stuff?

    Yes, less bullshit as it is with cgpt. Optimize code with xAI.

    You already tried gemini pro 3? I tried some small prompts and I liked the output and the explanation. Cgpt sometimes adds things I've never talked about

    Thanked by 1tux
  • ascicodeascicode Member
    edited November 2025

    @Levi said:

    @gbzret4d said:

    @Levi said:
    Vibe coded crapware. The rule is simple:

    If you need more then 100 lines of code in bash -> do it with python. Feed that mess to claude and ask it to convert to python.

    You prefer/suggest Claude for coding related stuff?

    Yes, less bullshit as it is with cgpt. Optimize code with xAI.

    Less BS, but expensive and not unlimited.

  • @gbzret4d said:

    @Levi said:

    @gbzret4d said:

    @Levi said:
    Vibe coded crapware. The rule is simple:

    If you need more then 100 lines of code in bash -> do it with python. Feed that mess to claude and ask it to convert to python.

    You prefer/suggest Claude for coding related stuff?

    Yes, less bullshit as it is with cgpt. Optimize code with xAI.

    You already tried gemini pro 3? I tried some small prompts and I liked the output and the explanation. Cgpt sometimes adds things I've never talked about

    You should try it with google new editor antigravity. It seems it is optimized to work with it.

    Thanked by 1gbzret4d
  • Or Hear me out,

    If you need more than 69 lines of code in go — do it with Rust.

  • Mixed vibes

  • @indiankesh said:
    Or Hear me out,

    If you need more than 69 lines of code in go — do it with Rust.

    Java is the way

  • davidedavide Member
    edited November 2025

    @gbzret4d said:

    @indiankesh said:
    Or Hear me out,

    If you need more than 69 lines of code in go — do it with Rust.

    Java is the way

    and it is paved with good intentions

    😈

    Thanked by 1gbzret4d
  • The vibes are so dense they make my eyes glaze over. Wow!

Sign In or Register to comment.