fix
This commit is contained in:
parent
fbd572b83a
commit
7f23ee7f09
534
firewall2.sh
534
firewall2.sh
@ -1,534 +0,0 @@
|
||||
#!/bin/bash
|
||||
MY_IP="47.5.115.173"
|
||||
ATTACK_THRESHOLD="50"
|
||||
SERVER_IP='192.168.0.55'
|
||||
NGINX_ACCESS="/tmp/access.log"
|
||||
#Firewall Port Configuration
|
||||
#
|
||||
declare -A portConfig
|
||||
portConfig["https"]="443"
|
||||
portConfig["http"]="80"
|
||||
portConfig["cups"]="631"
|
||||
portConfig["WireGuard"]="57692"
|
||||
portConfig["AdGuard-1"]="3000"
|
||||
portConfig["AdGuard-2"]="8082"
|
||||
portConfig["AdGuard-3"]="853"
|
||||
portConfig["Uptime"]="4001"
|
||||
portConfig["DNS-1"]="53"
|
||||
portConfig["DNS-2"]="67"
|
||||
portConfig["DNS-3"]="68"
|
||||
portConfig["CUPS-1"]="631"
|
||||
portConfig["CUPS-2"]="5353"
|
||||
#portConfig["Bitcoin-1"]="8333"
|
||||
#portConfig["Bitcoin-2"]="8332"
|
||||
#portConfig["Bitcoin-3"]="8333"
|
||||
#portConfig["Bitcoin-4"]="4050"
|
||||
#portConfig["KDE-Connect"]="1714-1764"
|
||||
#portConfig["Lightning-1"]="10009"
|
||||
#portConfig["Lightning-1"]="9735"
|
||||
#portConfig["Lightning-2"]="8080"
|
||||
#portConfig["Lightning-3"]="28334"
|
||||
#portConfig["Lightning-4"]="28333"
|
||||
#portConfig["Lightning-5"]="19998"
|
||||
#portConfig["Lightning-6"]="29000"
|
||||
portConfig["SyncThing-1"]="22000"
|
||||
portConfig["SyncThing-2"]="8384"
|
||||
portConfig["SyncThing-3"]="21027"
|
||||
#portConfig["NFS-1"]="2049"
|
||||
#portConfig["NFS-2"]="111"
|
||||
portConfig["Jellyfin-1"]="8096"
|
||||
portConfig["Jellyfin-1"]="7359"
|
||||
portConfig["SSH"]="22"
|
||||
MACHINES=(127.0.0.1)
|
||||
VIRT_BRIDGE="virbr0"
|
||||
#### NFT CONFIG ####
|
||||
#
|
||||
NFT='/usr/bin/nft'
|
||||
NFT_CACHE='/tmp/nft.cache'
|
||||
TMP_BLOCK='/tmp/tmp-blocked.txt'
|
||||
#Log Files
|
||||
#
|
||||
SAVED_BOTS='/opt/firewall/bots.txt'
|
||||
CRAWLER_DB='/opt/firewall/crawlers.txt'
|
||||
SAFE_TRAFFIC='/opt/firewall/safe.txt'
|
||||
PEDO_DB='/opt/firewall/pedo.txt'
|
||||
PEDO_LOG='/opt/firewall/pedo-log.txt'
|
||||
BOT_ACCOUNT="blockbot@detroitriotcity.com"
|
||||
CRAWLER_TMP='/tmp/crawlers.txt'
|
||||
RULE_SET='/opt/firewall/nft.rules'
|
||||
MENU_TOP="=============================FireWall================================="
|
||||
MENU_BOTTOM="====================================================================="
|
||||
|
||||
#Cache the Date and Current Firewall Rules at every launch
|
||||
DATE="$(date +%d/%b/%Y:%H:%M -d '1 minute ago')"
|
||||
nft list table filter >$NFT_CACHE
|
||||
|
||||
#Countries to Block
|
||||
COUNTRY=(
|
||||
https://www.ipdeny.com/ipblocks/data/countries/il.zone
|
||||
https://www.ipdeny.com/ipblocks/data/countries/cn.zone
|
||||
)
|
||||
|
||||
ipBlockParser(){
|
||||
if [[ "$1" == *":"* ]]; then
|
||||
$NFT insert rule ip6 filter input position 0 ip6 saddr $1 drop
|
||||
else
|
||||
$NFT insert rule ip filter input position 0 ip saddr "$1" drop
|
||||
fi
|
||||
}
|
||||
|
||||
portOpenParser(){
|
||||
if [[ "$1" == "443" || "$1" == "80" ]]; then
|
||||
$NFT add rule ip filter input ct state new tcp dport $1 update @http_ratelimit { ip saddr limit rate 10/second } accept
|
||||
$NFT add rule ip6 filter input ct state new tcp dport $1 update @http_ratelimit { ip6 saddr limit rate 10/second } accept
|
||||
else
|
||||
$NFT add rule ip filter input position 0 tcp dport $1 accept
|
||||
$NFT add rule ip filter input position 0 udp dport $1 accept
|
||||
$NFT add rule ip6 filter input position 0 tcp dport $1 accept
|
||||
$NFT add rule ip6 filter input position 0 udp dport $1 accept
|
||||
fi
|
||||
}
|
||||
|
||||
ipDeleteParser(){
|
||||
if [[ "$1" == *":"* ]]; then
|
||||
$NFT delete rule ip6 filter input handle $HANDLE
|
||||
else
|
||||
$NFT delete rule ip filter input handle $HANDLE
|
||||
fi
|
||||
}
|
||||
|
||||
blockCountry() {
|
||||
for i in "${COUNTRY[@]}"; do
|
||||
echo
|
||||
echo "Blocking $i"
|
||||
DB=($(curl $i))
|
||||
for j in "${DB[@]}"; do
|
||||
ipBlockParser $j
|
||||
done
|
||||
done
|
||||
|
||||
}
|
||||
|
||||
wireguard-networking() {
|
||||
$NFT add table nat
|
||||
$NFT add chain nat postrouting
|
||||
$NFT add rule nat postrouting oif wg0 iif enp11s0
|
||||
$NFT add rule nat postrouting oif enp11s0 iif wg0
|
||||
$NFT add rule nat postrouting masquerade
|
||||
$NFT add rule filter forward iifname wg0 oif enp11s0 accept
|
||||
$NFT add rule filter forward iifname enp11s0 oif wg0 accept
|
||||
$NFT add rule ip filter input ip saddr 192.168.5.0/24 accept
|
||||
}
|
||||
|
||||
attacker-protection() {
|
||||
watch
|
||||
module-nostr
|
||||
bot-search
|
||||
}
|
||||
|
||||
bot-search() {
|
||||
CRAWLERS=($(grep $DATE $NGINX_ACCESS | grep -vi $MY_IP | grep -Evi 'Guro|spank|report|rape|block' | grep -Ei -f $CRAWLER_DB | grep -Evi -f $SAFE_TRAFFIC | cut -d "-" -f1 | sort -u))
|
||||
|
||||
echo
|
||||
echo "Processing Web Crawler list into NFT....."
|
||||
echo
|
||||
for i in "${CRAWLERS[@]}"; do
|
||||
CHECK=$(cat $NFT_CACHE | grep $i)
|
||||
if [ "$CHECK" = "" ]; then
|
||||
ipBlockParser $i
|
||||
echo $i >>$SAVED_BOTS
|
||||
else
|
||||
echo
|
||||
echo "Skipping Duplicate IP $i"
|
||||
echo
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
drc-alert() {
|
||||
toot activate $BOT_ACCOUNT
|
||||
toot post ":emergency: :hacker_p: :hacker_e: :hacker_d: :hacker_o: :trans: :hacker_a: :hacker_l: :hacker_e: :hacker_r: :hacker_t: :emergency2: $1" -m /root/detroit/akkoma/blockbot/pedo.png
|
||||
}
|
||||
|
||||
pedo-search() {
|
||||
echo
|
||||
PEDO_SEARCH=$(grep $DATE $NGINX_ACCESS | grep -vi $MY_IP | grep -Ei 'tag|search' | grep -Evi -f $CRAWLER_DB | grep -Ei -f $PEDO_DB | head -1)
|
||||
echo $PEDO_SEARCH
|
||||
if [ "$PEDO_SEARCH" ]; then
|
||||
echo "Pedo Found!"
|
||||
echo "Processing Pedo Searches into NFT....."
|
||||
IP=$(echo $PEDO_SEARCH | cut -d ' ' -f1)
|
||||
ipBlockParser $IP
|
||||
message "[Pedo Alert] $PEDO_SEARCH"
|
||||
#drc-alert "$PEDO_SEARCH"
|
||||
echo $IP >> $PEDO_LOG
|
||||
else
|
||||
echo
|
||||
echo "No Pedos Found"
|
||||
echo
|
||||
fi
|
||||
}
|
||||
|
||||
basic-security() {
|
||||
$NFT flush ruleset
|
||||
$NFT -f /opt/firewall/ipv4-filter.nft
|
||||
$NFT -f /opt/firewall/ipv6-filter.nft
|
||||
$NFT add rule filter input icmp type echo-request drop
|
||||
$NFT rule filter output accept
|
||||
$NFT rule filter forward accept
|
||||
$NFT insert rule filter input ct state established accept
|
||||
$NFT insert rule filter input iif lo accept
|
||||
|
||||
for i in "${!portConfig[@]}"; do
|
||||
echo "Enabling Port for: $i"
|
||||
portOpenParser "${portConfig[$i]}"
|
||||
|
||||
done
|
||||
|
||||
$NFT add rule filter input drop
|
||||
$NFT add rule ip6 filter input drop
|
||||
}
|
||||
|
||||
virtualization() {
|
||||
ip link del virbr0
|
||||
killall dnsmasq
|
||||
/usr/bin/systemctl restart libvirtd
|
||||
/usr/bin/virsh net-start default
|
||||
/usr/bin/systemctl restart pleroma
|
||||
$NFT insert rule filter input iif $VIRT_BRIDGE accept
|
||||
}
|
||||
|
||||
trust() {
|
||||
for i in "${MACHINES[@]}"; do
|
||||
$NFT add rule filter input ip saddr $i accept
|
||||
done
|
||||
}
|
||||
|
||||
import-saved() {
|
||||
|
||||
STATS=($(cat $SAVED_BOTS | sort -u))
|
||||
for i in "${STATS[@]}"; do
|
||||
ipBlockParser $i
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
start() {
|
||||
basic-security
|
||||
|
||||
if [[ $HOSTNAME == *"nas"* ]]; then
|
||||
sysctl -w net.ipv4.conf.all.forwarding=1
|
||||
import-saved
|
||||
blockCountry
|
||||
wireguard-networking
|
||||
docker restart uptime-kuma
|
||||
|
||||
#Docker
|
||||
$NFT insert rule filter input iif docker0 accept
|
||||
else
|
||||
virtualization
|
||||
fi
|
||||
}
|
||||
|
||||
research() {
|
||||
STATS=($(cat $TMP_BLOCK | sort -u))
|
||||
for i in "${STATS[@]}"; do
|
||||
echo $MENU_TOP
|
||||
echo " [Researching $i] "
|
||||
echo
|
||||
DATA=$(grep $i $NGINX_LOG | grep -Evi -f $SAFE_TRAFFIC)
|
||||
echo "$DATA"
|
||||
echo
|
||||
echo $MENU_BOTTOM
|
||||
echo
|
||||
read -p 'Press Enter to Continue ' -e
|
||||
done
|
||||
}
|
||||
|
||||
automaticStatus() {
|
||||
status
|
||||
sleep 30
|
||||
automaticStatus
|
||||
}
|
||||
|
||||
status() {
|
||||
clear
|
||||
STATS=$(grep $DATE $NGINX_ACCESS | grep -vi $MY_IP | wc -l)
|
||||
GET=$(grep $DATE $NGINX_ACCESS | grep -vi $MY_IP | grep GET | wc -l)
|
||||
POST=$(grep $DATE $NGINX_ACCESS | grep -vi $MY_IP | grep POST | wc -l)
|
||||
PUT=$(grep $DATE $NGINX_ACCESS | grep -vi $MY_IP | grep -i PUT | wc -l)
|
||||
NOT_FOUND=$(grep $DATE $NGINX_ACCESS | grep -vi $MY_IP | grep 404 | wc -l)
|
||||
GATEWAY=$(grep $DATE $NGINX_ACCESS | grep -vi $MY_IP | grep 502 | wc -l)
|
||||
SUCCESS=$(grep $DATE $NGINX_ACCESS | grep -vi $MY_IP | grep 200 | wc -l)
|
||||
CRAWL=$(grep $DATE $NGINX_ACCESS | grep -vi $MY_IP | grep -Ei -f $CRAWLER_DB | wc -l)
|
||||
echo $MENU_TOP
|
||||
echo "Attack Threshold: $ATTACK_THRESHOLD"
|
||||
echo "Firewall Rules: $($NFT list table filter | wc -l)"
|
||||
echo
|
||||
echo "Traffic Last Minute: $STATS"
|
||||
echo " GET: $GET"
|
||||
echo " PUT: $PUT"
|
||||
echo " POST: $POST"
|
||||
echo " Crawlers: $CRAWL"
|
||||
echo
|
||||
echo "Query Stats:: "
|
||||
echo " 200: $SUCCESS"
|
||||
echo " 404: $NOT_FOUND"
|
||||
echo " 502: $GATEWAY"
|
||||
echo
|
||||
#echo "Dropped Traffic: $($NFT list table filter | grep -Ei 'log counter packets' | cut -d ' ' -f6)"
|
||||
echo
|
||||
echo "Rate-limited IP's:"
|
||||
cat $TMP_BLOCK | sort -u
|
||||
echo $MENU_BOTTOM
|
||||
}
|
||||
|
||||
stop() {
|
||||
#forgive
|
||||
$NFT -s list ruleset | tee $RULE_SET
|
||||
$NFT flush ruleset
|
||||
$NFT -f /usr/share/nftables/ipv4-filter.nft
|
||||
$NFT add rule filter input icmp type echo-request accept
|
||||
$NFT rule filter input accept
|
||||
$NFT rule filter output accept
|
||||
$NFT rule filter forward accept
|
||||
$NFT insert rule filter input ct state established accept
|
||||
$NFT insert rule filter input iif lo accept
|
||||
|
||||
$NFT -f /opt/firewall/ipv6-filter.nft
|
||||
# $NFT add rule ip6 filter input icmpv6 type nd-neighbor-solicit accept
|
||||
# $NFT add rule ip6 filter input icmpv6 type nd-router-advert accept
|
||||
message "Stopping Firewall"
|
||||
}
|
||||
|
||||
forgive() {
|
||||
IP=($(grep -vi $MY_IP $TMP_BLOCK | sort -u))
|
||||
echo $IP
|
||||
for i in "${IP[@]}"; do
|
||||
HANDLE=$(nft -n -a list ruleset | grep $i | grep handle | cut -d '#' -f2 | cut -d ' ' -f3)
|
||||
echo "Removing: $i Handle: $HANDLE"
|
||||
echo $NFT delete rule ip filter input handle $HANDLE
|
||||
ipDeleteParser $HANDLE
|
||||
done
|
||||
|
||||
echo "Clearing old $TMP_BLOCK"
|
||||
echo >$TMP_BLOCK
|
||||
}
|
||||
|
||||
module-go() {
|
||||
GO_SPAM=$(grep $2 $NGINX_ACCESS | grep -E "Go-http-client" | wc -l)
|
||||
if [[ "$GO_SPAM" -gt 10 ]]; then
|
||||
ipBlockParser "$1"
|
||||
echo $1 >>$TMP_BLOCK
|
||||
message "Go Spam Attack!"
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
module-akkoma() {
|
||||
SEARCH_SPAM=$(grep $2 $NGINX_ACCESS | grep -E "api/v1/instance|api/v1/notifications|api/v1/accounts|api/v2/search|timelines/public|timelines/home|/api/v1/accounts" | grep $1 | wc -l)
|
||||
CHECK=$(cat $NFT_CACHE | sort -u | grep $i)
|
||||
if [[ "$SEARCH_SPAM" -gt 30 ]]; then
|
||||
echo "$IP $CHECK $COUNT"
|
||||
if [ "$CHECK" = "" ]; then
|
||||
ipBlockParser "$1"
|
||||
echo $1 >>$TMP_BLOCK
|
||||
message "module-akkoma: Spam Attack! $i"
|
||||
echo "module-akkoma: Spam $1"
|
||||
else
|
||||
echo "module-akkoma: Ignoring Duplicate IP: $i"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
module-get-spam() {
|
||||
GET_SPAM=$(grep $2 $NGINX_ACCESS | grep -E "GET / HTTP" | wc -l)
|
||||
if [[ "$GET_SPAM" -gt 5 ]]; then
|
||||
ipBlockParser "$1"
|
||||
echo $1 >>$TMP_BLOCK
|
||||
message "GET Spam Attack! $1"
|
||||
fi
|
||||
}
|
||||
|
||||
module-php() {
|
||||
PHP_SPAM=$(grep $2 $NGINX_ACCESS | grep -E ".php|cgi-bin|wp-content|wp-admin|wp-includes" | wc -l)
|
||||
if [[ "$PHP_SPAM" -gt 1 ]]; then
|
||||
ipBlockParser "$1"
|
||||
echo $1 >>$TMP_BLOCK
|
||||
message "PHP Attack!"
|
||||
fi
|
||||
}
|
||||
|
||||
module-lightning() {
|
||||
LN_SPAM=$(grep $2 $NGINX_ACCESS | grep "lnurlp/verita84" | wc -l)
|
||||
if [[ "$LN_SPAM" -gt 5 ]]; then
|
||||
ipBlockParser "$1"
|
||||
message "Lightning Spam Attack!"
|
||||
echo $1 >>$TMP_BLOCK
|
||||
fi
|
||||
}
|
||||
|
||||
message() {
|
||||
BOT_ACCOUNT="blockbot@detroitriotcity.com"
|
||||
echo "$1" | /root/go/bin/algia dm-post -u 33c74427f3b2b73d5e38f3e6c991c122a55d204072356f71da49a0e209fb6940 --stdin
|
||||
}
|
||||
|
||||
watch() {
|
||||
echo "Scanning $DATE"
|
||||
echo
|
||||
IP=($(grep $DATE $NGINX_ACCESS | grep -Evi -f $SAFE_TRAFFIC | grep -Evi -f $CRAWLER_DB | grep -Evi -f $SAVED_BOTS |grep -vi $MY_IP | grep -vi '127.0.0.1' | cut -d ' ' -f1 | sort -u))
|
||||
|
||||
for i in "${IP[@]}"; do
|
||||
module-akkoma "$i" "$DATE"
|
||||
module-lightning "$i" "$DATE"
|
||||
module-php "$i" "$DATE"
|
||||
module-go "$i" "$DATE"
|
||||
module-get-spam "$i" "$DATE"
|
||||
|
||||
COUNT=$(grep $DATE $NGINX_ACCESS | grep $i | grep -Evi -f $SAFE_TRAFFIC | grep -Evi -f $SAVED_BOTS | wc -l)
|
||||
|
||||
CHECK=$(cat $NFT_CACHE | sort -u | grep $i)
|
||||
if [[ "$COUNT" -gt $ATTACK_THRESHOLD ]]; then
|
||||
if [ "$CHECK" = "" ]; then
|
||||
echo "Danger! Blocking IP: $i Count: $COUNT"
|
||||
logger "Blocking IP: $i with a count of: $COUNT"
|
||||
echo $i >>$TMP_BLOCK
|
||||
ipBlockParser $i
|
||||
message "Blocking IP: $i with a count of: $COUNT"
|
||||
else
|
||||
echo
|
||||
echo "Skipping Duplicate IP"
|
||||
echo
|
||||
|
||||
fi
|
||||
else
|
||||
echo
|
||||
echo "$i count: $COUNT below Threshhold: $ATTACK_THRESHOLD"
|
||||
echo
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
module-nostr(){
|
||||
IP=($(grep $DATE $NGINX_ACCESS | grep "/block=" | cut -d '=' -f2| cut -d ' ' -f1 | sed 's/"//'))
|
||||
for i in "${IP[@]}"; do
|
||||
echo $i
|
||||
if [[ "$i" == *"npub"* ]]; then
|
||||
bash /opt/strfry-policies/block.sh $i
|
||||
else
|
||||
echo "No Npubs to block"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
test-bots() {
|
||||
TEST=($(cat $SAVED_BOTS))
|
||||
for i in "${TEST[@]}"; do
|
||||
DATA=$(grep $i $NGINX_ACCESS | grep -Evi -f $CRAWLER_DB)
|
||||
if [ "$DATA" = "" ]; then
|
||||
echo "No Data. Probably OK"
|
||||
else
|
||||
echo $DATA
|
||||
echo
|
||||
read -p 'Press Enter to Continue ' -e
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
research-ip() {
|
||||
echo "Enter an IP Address to search"
|
||||
read -p 'IP Address: ' -e IP
|
||||
cat $NGINX_ACCESS | grep $IP
|
||||
echo
|
||||
read -p 'Press Enter to Continue ' -e
|
||||
}
|
||||
|
||||
menu() {
|
||||
clear
|
||||
echo
|
||||
echo $MENU_TOP
|
||||
echo "1. Start"
|
||||
echo "2. Stop"
|
||||
echo "3. Reseearch"
|
||||
echo "4. Forgive"
|
||||
echo "5. Status"
|
||||
echo "6. Live Traffic"
|
||||
echo "7. Test Bot Search Rules"
|
||||
echo "8. Research IP"
|
||||
echo "9. View Current Rule Set"
|
||||
echo "0. Quit"
|
||||
echo $MENU_BOTTOM
|
||||
echo
|
||||
read -p 'Choice: ' CHOICE
|
||||
echo
|
||||
if [ "$CHOICE" = "1" ]; then
|
||||
echo
|
||||
echo "Starting Firewall"
|
||||
start
|
||||
read -p 'Press Enter to Continue ' -e-
|
||||
elif [ "$CHOICE" = "2" ]; then
|
||||
echo
|
||||
echo "Stopping Firewall"
|
||||
stop
|
||||
read -p 'Press Enter to Continue ' -e
|
||||
elif [ "$CHOICE" = "3" ]; then
|
||||
research
|
||||
read -p 'Press Enter to Continue ' -e
|
||||
elif [ "$CHOICE" = "4" ]; then
|
||||
forgive
|
||||
elif [ "$CHOICE" = "55" ]; then
|
||||
automaticStatus
|
||||
elif [ "$CHOICE" = "5" ]; then
|
||||
status
|
||||
read -p 'Press Enter to Continue ' -e
|
||||
elif [ "$CHOICE" = "6" ]; then
|
||||
tail -f $NGINX_ACCESS | grep -Evi -f $SAFE_TRAFFIC | grep -Evi -f $CRAWLER_DB
|
||||
read -p 'Press Enter to Continue ' -e
|
||||
elif [ "$CHOICE" = "7" ]; then
|
||||
test-bots
|
||||
read -p 'Press Enter to Continue ' -e
|
||||
elif [ "$CHOICE" = "8" ]; then
|
||||
research-ip
|
||||
read -p 'Press Enter to Continue ' -e
|
||||
elif [ "$CHOICE" = "9" ]; then
|
||||
nft -s list ruleset | less
|
||||
elif [ "$CHOICE" = "0" ]; then
|
||||
exit
|
||||
fi
|
||||
echo
|
||||
menu
|
||||
}
|
||||
|
||||
if [ "$1" = "start" ]; then
|
||||
start
|
||||
elif [ "$1" = "virt" ]; then
|
||||
virtualization
|
||||
elif [ "$1" = "bot-search" ]; then
|
||||
bot-search
|
||||
elif [ "$1" = "attacker-protection" ]; then
|
||||
attacker-protection
|
||||
elif [ "$1" = "country" ]; then
|
||||
blockCountry
|
||||
elif [ "$1" = "status" ]; then
|
||||
automaticStatus
|
||||
elif [ "$1" = "forgive" ]; then
|
||||
forgive
|
||||
elif [ "$1" = "watch" ]; then
|
||||
watch
|
||||
elif [ "$1" = "research" ]; then
|
||||
research
|
||||
elif [ "$1" = "stop" ]; then
|
||||
stop
|
||||
elif [ "$1" = "message" ]; then
|
||||
message $2
|
||||
elif [ "$1" = "test" ]; then
|
||||
test-bots
|
||||
elif [ "$1" = "nostr" ]; then
|
||||
module-nostr
|
||||
elif [ "$1" = "import" ]; then
|
||||
import-saved
|
||||
elif [ "$1" = "saved" ]; then
|
||||
saved-bots
|
||||
else
|
||||
menu
|
||||
fi
|
Loading…
Reference in New Issue
Block a user