Restructure repository: organize tools by purpose, create what search tool

- Move single-file tools to tools/ organized by category (security, forensics, data, etc.)
- Move multi-file projects to projects/ (go-tools, puzzlebox, timesketch, rust-tools)
- Move system scripts to scripts/ (proxy, display, setup, windows)
- Organize config files in config/ (shell, visidata, applications)
- Move experimental tools to archive/experimental
- Create 'what' fuzzy search tool with progressive enhancement (ollama->fzf->grep)
- Add initial metadata database for intelligent tool discovery
- Preserve git history using 'git mv' commands
This commit is contained in:
tobias
2025-08-24 19:50:00 +02:00
parent 9518290544
commit 619b0bc432
124 changed files with 1063 additions and 0 deletions

51
tools/system/backup_docker.sh Executable file
View File

@@ -0,0 +1,51 @@
#!/bin/bash
# Check if the Docker Compose file was provided
if [ $# -eq 0 ]; then
echo "No Docker Compose file provided"
exit 1
fi
COMPOSE_FILE=$1
DIR=$(dirname "${COMPOSE_FILE}")
BASE_DIR_NAME=$(basename "${DIR}")
BACKUP_DIR=/mnt/backups/$BASE_DIR_NAME
TIMESTAMP=$(date +"%Y%m%d%H%M%S")
# Create a new backup directory for this stack if it doesn't already exist
mkdir -p $BACKUP_DIR
# Stop the Docker Compose stack
docker-compose -f $COMPOSE_FILE down
# Tarball the Docker Compose directory
CONFIG_BACKUP_FILE="files_${DIR##*/}"_$TIMESTAMP.tar.gz
tar -czvf $BACKUP_DIR/$CONFIG_BACKUP_FILE -C / $DIR
# Identify and save each Docker image used by the stack
IMAGES=$(docker-compose -f $COMPOSE_FILE config | awk '{if ($1 == "image:") print $2;}')
BACKUP_FILE=$BACKUP_DIR/"backup_${BASE_DIR_NAME}_${TIMESTAMP}.txt"
# Clear the backup list file
echo "${COMPOSE_FILE}" > $BACKUP_FILE
# Write config backup file name to the backup list file
echo $CONFIG_BACKUP_FILE >> $BACKUP_FILE
for IMAGE in $IMAGES; do
# Get image id (strip off "sha256:" prefix)
IMAGE_ID=$(docker inspect --format="{{.Id}}" $IMAGE | sed 's/sha256://')
# Check if the image backup file already exists
IMAGE_BACKUP_FILE="image_${IMAGE//[:\/]/_}_${IMAGE_ID}.tar.gz"
IMAGE_BACKUP=$BACKUP_DIR/$IMAGE_BACKUP_FILE
if [ ! -f $IMAGE_BACKUP ]; then
docker save $IMAGE | gzip > $IMAGE_BACKUP
fi
# Write image backup file name to the backup list file
echo $IMAGE_BACKUP_FILE >> $BACKUP_FILE
done
# Restart the Docker Compose stack
docker-compose -f $COMPOSE_FILE up -d

65
tools/system/ltop.py Executable file
View File

@@ -0,0 +1,65 @@
#!/usr/bin/env python3
import sys
import curses
from operator import itemgetter
import time
# Number of top items to be displayed
N = 10
def gen_output(item_dict, N=10):
"""
Generate a formatted output string for the top N items in item_dict.
:param item_dict: A dictionary containing items and their counts
:param N: The number of top items to be displayed
:return: A generator yielding formatted strings for each of the top N items
"""
top_items = dict(sorted(item_dict.items(), key=itemgetter(1), reverse=True)[:N])
count_length = len(str(max(top_items.values())))
for i, key in enumerate(top_items):
yield i, f'{i + 1:3} : [{top_items[key]:{count_length}}] {key}'
def main(screen):
"""
Main function to read input lines, maintain a count of each unique line, and
periodically display the top N lines with the highest counts using curses.
:param screen: A curses window object
"""
if not sys.stdin.isatty(): # Check if the input comes from a pipe
# Initialize an empty dictionary to store unique input lines and their counts
toplist = {}
# Set the next screen update time
t_update = time.time() + 1
for line in sys.stdin:
line = line.strip()
# Increment the count for each unique input line
if line in toplist:
toplist[line] += 1
else:
toplist[line] = 1
# Periodically update the screen with the top N lines
if time.time() > t_update:
for idx, line in gen_output(toplist):
screen.addstr(idx, 0, line)
screen.refresh()
t_update = time.time() + 1
# Clean up the curses environment and print the final top N lines
curses.endwin()
for idx, line in gen_output(toplist):
print(line)
else:
print("Usage: cat input_file.txt | ./top_lines.py")
print("Or: ./top_lines.py < input_file.txt")
# Initialize the curses library, run the main function, and restore the terminal state
curses.wrapper(main)

View File

@@ -0,0 +1,57 @@
#!/bin/bash
# Specify your backup directory
BACKUP_DIR=/mnt/backups
# List available stacks for backup
echo "Available stacks for recovery:"
STACKS=($(ls $BACKUP_DIR))
select STACK_NAME in "${STACKS[@]}"; do
# Verify stack backup directory exists
STACK_BACKUP_DIR=$BACKUP_DIR/$STACK_NAME
if [ -d $STACK_BACKUP_DIR ]; then
break
else
echo "Invalid selection"
fi
done
# List available backups for the stack
echo "Available backups for stack $STACK_NAME:"
BACKUPS=($(ls $STACK_BACKUP_DIR/backup_*.txt))
# Display only the timestamps
TIMESTAMPS=("${BACKUPS[@]##*_}")
select CHOICE in "${TIMESTAMPS[@]}"; do
# Get the full filename of the chosen backup
BACKUP_FILE=$(echo "${BACKUPS[@]}" | tr ' ' '\n' | grep $CHOICE)
if [ -f $BACKUP_FILE ]; then
break
else
echo "Invalid selection"
fi
done
# Extract original Docker Compose file path
COMPOSE_FILE=$(head -n 1 $BACKUP_FILE)
DIR=$(dirname "${COMPOSE_FILE}")
# Check if stack is running and stop it
docker-compose -f $COMPOSE_FILE down
# Rename existing Docker Compose directory
mv $DIR $DIR.recovery_$(date +"%Y%m%d%H%M%S")
# Restore files from backup
tar -xzvf $STACK_BACKUP_DIR/$(sed '2q;d' $BACKUP_FILE) -C /
# Load Docker images from backup
tail -n +3 $BACKUP_FILE | while read IMAGE_FILE; do
docker load < $STACK_BACKUP_DIR/$IMAGE_FILE
done
# Change to the Docker Compose directory and restart the Docker Compose stack
cd $DIR
docker-compose up -d

22
tools/system/watchgrowth.sh Executable file
View File

@@ -0,0 +1,22 @@
#!/bin/bash
old_size=$(du -b "${1}" | cut -f1)
while true; do
sleep 1
new_size=$(du -b "${1}" | cut -f1)
size_diff=$(( ${new_size} - ${old_size} ))
old_size=${new_size}
#speed=$(( ${size_diff} / (1024*1024) ))
progress=""
if [[ $# -eq 3 ]] ; then
total=${2}
progress_p=$(echo "2 k ${new_size} ${total} 100 / / p" | dc)
progress="${progress_p} %"
fi
speed=$(echo "2 k ${size_diff} 1024 1024 * / p" | dc)
echo "${progress} - ${speed} MB/s"
done

101
tools/system/wipe.sh Normal file
View File

@@ -0,0 +1,101 @@
#!/bin/bash
#disabling Kernellogging to Console
echo '2 4 1 7' > /proc/sys/kernel/printk
#rechnet die eine centrierierte fensterposition aus anhand von bildschirm- & fenstergröße
# 'mitte 50'
function mitte(){
cols=$(tput cols)
mitte=$(echo $(( $cols / 2 - $1 / 2 )) )
echo $mitte
}
#zeigt eine infomeldung für x-Sekunden an
# 'info text 5'
function info(){
text=${1}
text_len=$(( ${#1} + 4 ))
timeout=${2}
dialog --backtitle "CERTBw - Zero-Wipe" --infobox "$text" 3 $text_len; sleep $timeout
}
#zeigt überischt von datenträgern an und fragt ab welcher gewipet werden soll
function ask_4_device(){
[ -e /tmp/devicelist ] || rm /tmp/devicelist
lsblk -o NAME,SIZE,TYPE,FSTYPE | tail -n+2 | tr -cd ',.\n [:alnum:]' | awk '{printf "%-5s%6s %s (%s) \n" , $1,$2,$3,$4}' | sed -e "s/()//g" >/tmp/devicelist
devlines=$(( $(cat /tmp/devicelist | wc -l) + 2 ))
dialog --backtitle "CERTBw - Zero-Wipe" --begin 2 $(mitte 30) --title "Available Devices" --progressbox $devlines 30 --and-widget --stdout --inputbox 'Welche Platte soll gewipet werden?' 7 60 '/dev/sda' < /tmp/devicelist
result=${?}
return $result
}
#prüft den rückgabewert des vorangegangenen 'dialog' fensters auf abbruch und startet das menu neu
function check_result(){
result=${?}
if ([ $result = 1 ] || [ $result = 255 ]); then
info 'CANCELED' 1
menu
exit 0
fi
}
#kopiert Nullen auf das Angegebene Gerät und zeitg den Fortschritt mit 'dialog' an
function wipe(){
#anlegen von named pipes für den Datenstrom und Statusmeldungen
mkfifo data
mkfifo status
size_512=$(blockdev --getsz $1)
size=$((512 * ${size_512}))
echo "wiping Disk $1:"
(while read -r line
do
#Zusammenfassen von Informationen für das Dialogfenster in ein 'dialog' kompatibles Format
split=$(echo $line | tr -d "%[]=<>" | xargs)
space=$(echo "$split" | cut -f1 -d" ")
time=$(echo "$split" | cut -f2 -d" ")
rate=$(echo "$split" | cut -f3 -d" ")
prozent=$(echo "$split" | cut -f4 -d" ")
eta=$(echo "$split" | cut -f6 -d" ")
echo "XXX"
echo $prozent
echo "Wiped $space in $time so far. ($rate)"
echo "ETA : $eta"
echo "XXX"
done < <(pv -f -s $size /dev/zero 1>data 2>status | dd bs=1M iflag=fullblock oflag=nocache if=data of=$1 2>/dev/null | stdbuf -oL tr "\r" "\n" <status) ) | dialog --backtitle "CERTBw - Zero-Wipe" --title "Wiping $1" --gauge "Please wait" 7 70 0
rm data
rm status
}
function menu(){
menu=$(dialog --stdout --backtitle "CERTBw - Zero-Wipe" --title "Wiping Complete" --menu "Action:" 0 0 5 1 Reboot 2 Poweroff 3 Verify 4 Re-Wipe 5 Shell)
case "$menu" in
1) info "REBOOTING" 1; reboot
exit 0
;;
2) info "SHUTTING DOWN" 1; poweroff
exit 0
;;
3) info "Verify - Not yet implemented" 3
menu
;;
4) /etc/wipe.sh
exit 0
;;
5) exit 0
;;
*) info 'CANCELED' 1
exit 0
;;
esac
}
##simpler ablauf
drive=$(ask_4_device)
check_result
wipe $drive
menu
exit 0