Files
docker_file_analysis/scripts/fhelp
T
tobias 3a8e5d90ef Overhaul help system UX with navi, recipes, and onboarding
- Rewrite fhelp: add 'start' onboarding, recipe fallback chain
  (our files → cheat → tldr), 'workflow' dynamic loader, tier badges
- Add welcome.sh: unified English welcome for bash/zsh/fish
- Replace German README with concise English version
- Add Zsh F1/Ctrl+/ widget for inline help while typing
- Configure navi Ctrl+G widget for interactive cheatsheet browsing
- Fix dangerous 'alias help=fhelp' (was breaking bash builtin)
- Add 'h' and 'analyse' as safe aliases

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 17:38:37 +01:00

511 lines
16 KiB
Bash
Executable File

#!/bin/bash
# Enhanced File Analysis Help System
# Integrates multiple help sources: custom cheat sheets, tldr, tool database, and workflows
# Color definitions
RED='\033[0;31m'
GREEN='\033[0;32m'
BLUE='\033[0;34m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
MAGENTA='\033[0;35m'
NC='\033[0m'
# Help system paths
TOOLS_DB="/opt/remnux-docs/tools.db"
CHEAT_DIR="/opt/cheatsheets"
WORKFLOW_DIR="/opt/remnux-docs/workflows"
TLDR_CACHE="/home/remnux/.local/share/tldr"
# Resolve cheat file names from a user-provided tool name
# Tries several variants: exact, without .py, with .py, hyphen/underscore alternatives
resolve_cheat_file() {
local name="$1"
local base=$(echo "$name" | sed 's/\.[Pp][Yy]$//')
# candidates to try in order
local candidates=(
"$name"
"$base"
"${base}.py"
"${base//_/}"
"${base//-/_}"
"${base//_/-}"
)
for cand in "${candidates[@]}"; do
if [[ -f "$CHEAT_DIR/personal/$cand" ]]; then
echo "$CHEAT_DIR/personal/$cand"
return 0
fi
if [[ -f "$CHEAT_DIR/personal/${cand}.cheat" ]]; then
echo "$CHEAT_DIR/personal/${cand}.cheat"
return 0
fi
if [[ -f "$CHEAT_DIR/${cand}.cheat" ]]; then
echo "$CHEAT_DIR/${cand}.cheat"
return 0
fi
done
return 1
}
show_main_help() {
echo -e "${CYAN}REMnux Analysis Container Help System${NC}"
echo "======================================="
echo ""
echo -e "${GREEN}Getting Started:${NC}"
echo " fhelp start - Quick start guide (30 seconds)"
echo ""
echo -e "${GREEN}Find Tools:${NC}"
echo " fhelp tools <keyword> - Search by name or category"
echo " fhelp tools --interactive - Interactive browser (fzf)"
echo " Ctrl+G - Interactive cheatsheet browser (navi)"
echo ""
echo -e "${GREEN}Get Examples:${NC}"
echo " fhelp cheat <tool> - Usage examples for a specific tool"
echo " fhelp quick <command> - Quick tldr examples"
echo " F1 / Ctrl+/ - Help for command you're typing (zsh)"
echo ""
echo -e "${GREEN}Analysis Workflows:${NC}"
echo " fhelp workflow - List all 8 analysis workflows"
echo " fhelp workflow <name> - Show step-by-step workflow"
echo ""
echo -e "${GREEN}Other:${NC}"
echo " fhelp coverage - Help coverage statistics"
echo " fhelp examples - Browse all cheat sheets"
echo " fhelp --offline - Verify offline capabilities"
echo ""
echo -e "${YELLOW}Shortcuts:${NC} analyse, h, ? (all run fhelp)"
echo ""
echo -e "${YELLOW}Examples:${NC}"
echo " fhelp tools pdf # Find PDF analysis tools"
echo " fhelp cheat pdfid.py # pdfid.py usage examples"
echo " fhelp workflow static # Static analysis workflow"
}
show_start() {
echo -e "${CYAN}Quick Start Guide${NC}"
echo "================="
echo ""
# Count tools
local tool_count=0
local rich_count=0
if [[ -f "$TOOLS_DB" ]]; then
tool_count=$(wc -l < "$TOOLS_DB" 2>/dev/null || echo 0)
rich_count=$(grep -c '|rich$' "$TOOLS_DB" 2>/dev/null || echo 0)
fi
echo -e " This container has ${GREEN}${tool_count} analysis tools${NC} installed."
echo -e " ${GREEN}${rich_count}${NC} have detailed help with FOR610 lab examples."
echo ""
echo -e "${YELLOW}1. Find a tool:${NC}"
echo " fhelp tools pdf # search by keyword"
echo " fhelp tools --interactive # browse with fuzzy search"
echo ""
echo -e "${YELLOW}2. Get usage examples:${NC}"
echo " fhelp cheat pdfid.py # cheat sheet with examples"
echo " fhelp cheat oledump.py # Office document analysis"
echo " fhelp cheat capa # malware capabilities"
echo ""
echo -e "${YELLOW}3. Follow a workflow:${NC}"
echo " fhelp workflow # list all workflows"
echo " fhelp workflow static # static analysis steps"
echo " fhelp workflow document # document analysis steps"
echo ""
echo -e "${YELLOW}4. Interactive help:${NC}"
echo -e " ${GREEN}Ctrl+G${NC} # browse cheatsheets (navi)"
echo -e " ${GREEN}F1${NC} or ${GREEN}Ctrl+/${NC} # help for command you're typing (zsh)"
echo ""
echo -e "${YELLOW}5. Tool tiers:${NC}"
echo -e " ${GREEN}[FOR610]${NC} Rich help with lab examples and workflows"
echo -e " ${BLUE}[docs]${NC} Standard help from REMnux documentation"
echo -e " ${YELLOW}[basic]${NC} Minimal help (try: tool --help)"
echo ""
echo "Mount your files to /work/ and start analyzing!"
}
show_cheat() {
local tool="$1"
if [[ -z "$tool" ]]; then
echo -e "${RED}Please specify a tool name${NC}"
echo "Usage: fhelp cheat <tool>"
return 1
fi
# Check for specific workflow cheat sheets first
local cheat_file=""
case "$tool" in
"pdf"|"pdf-analysis")
cheat_file="$CHEAT_DIR/pdf-analysis.cheat"
;;
"malware"|"malware-analysis")
cheat_file="$CHEAT_DIR/malware-analysis.cheat"
;;
"system"|"system-utilities")
cheat_file="$CHEAT_DIR/system-utilities.cheat"
;;
*)
cheat_file=""
;;
esac
# If not a workflow cheat, try to resolve tool-specific cheat
if [[ -z "$cheat_file" || ! -f "$cheat_file" ]]; then
cheat_file=$(resolve_cheat_file "$tool") || cheat_file=""
fi
if [[ -n "$cheat_file" && -f "$cheat_file" ]]; then
echo -e "${CYAN}Cheat Sheet: ${YELLOW}$tool${NC}"
echo "$(printf '=%.0s' $(seq 1 $((${#tool} + 14))))"
echo ""
# Display cheat file content (skip YAML frontmatter if present)
awk '/^---$/{if(++c==2) start=1; next} start || !/^---$/ && c!=1' "$cheat_file"
elif command -v cheat >/dev/null 2>&1 && cheat "$tool" >/dev/null 2>&1; then
# Fallback: try the cheat command
echo -e "${CYAN}Cheat Sheet (cheat): ${YELLOW}$tool${NC}"
echo "$(printf '=%.0s' $(seq 1 $((${#tool} + 22))))"
echo ""
cheat "$tool"
elif command -v tldr >/dev/null 2>&1 && tldr "$tool" >/dev/null 2>&1; then
# Fallback: try tldr
echo -e "${CYAN}Quick Reference (tldr): ${YELLOW}$tool${NC}"
echo "$(printf '=%.0s' $(seq 1 $((${#tool} + 24))))"
echo ""
tldr "$tool"
else
echo -e "${YELLOW}No help found for '$tool'${NC}"
echo ""
# Suggest similar tools
if [[ -f "$TOOLS_DB" ]]; then
local matches=$(grep -i "$tool" "$TOOLS_DB" 2>/dev/null | head -5)
if [[ -n "$matches" ]]; then
echo "Did you mean one of these?"
echo "$matches" | while IFS='|' read -r name desc cat usage tier; do
local badge=""
case "$tier" in
rich) badge="${GREEN}[FOR610]${NC}" ;;
standard) badge="${BLUE}[docs]${NC}" ;;
*) badge="${YELLOW}[basic]${NC}" ;;
esac
echo -e " ${GREEN}$name${NC} $badge - $desc"
done
fi
fi
return 1
fi
}
show_quick() {
local command="$1"
if [[ -z "$command" ]]; then
echo -e "${RED}Please specify a command name${NC}"
echo "Usage: fhelp quick <command>"
return 1
fi
echo -e "${CYAN}Quick examples for: ${YELLOW}$command${NC}"
echo ""
if command -v tldr >/dev/null 2>&1; then
if ! tldr "$command" 2>/dev/null; then
echo -e "${YELLOW}No tldr page found for '$command'${NC}"
echo "Try: fhelp cheat $command"
fi
else
echo -e "${RED}tldr command not available${NC}"
return 1
fi
}
show_tools() {
local search_term="$1"
local option="$2"
case "$search_term" in
"--interactive")
if command -v find-tool >/dev/null 2>&1; then
find-tool --interactive
else
echo -e "${RED}find-tool not available${NC}"
fi
return
;;
"--list")
if command -v find-tool >/dev/null 2>&1; then
find-tool --list
else
echo -e "${RED}find-tool not available${NC}"
fi
return
;;
esac
if [[ -z "$search_term" ]]; then
echo -e "${RED}Please provide a search term${NC}"
echo "Usage: fhelp tools <search_term>"
echo " fhelp tools --interactive"
echo " fhelp tools --list"
return 1
fi
echo -e "${CYAN}Searching analysis tools for '${YELLOW}$search_term${CYAN}'...${NC}"
echo ""
if command -v find-tool >/dev/null 2>&1; then
find-tool "$search_term"
elif [[ -f "$TOOLS_DB" ]]; then
# Fallback: direct grep on tools.db
local results=$(grep -i "$search_term" "$TOOLS_DB" 2>/dev/null)
if [[ -n "$results" ]]; then
echo "$results" | while IFS='|' read -r name desc cat usage tier; do
local tier_badge=""
case "$tier" in
rich) tier_badge="${GREEN}[FOR610]${NC}" ;;
standard) tier_badge="${BLUE}[docs]${NC}" ;;
basic) tier_badge="${YELLOW}[basic]${NC}" ;;
*) tier_badge="" ;;
esac
echo -e " ${GREEN}$name${NC} $tier_badge"
echo " $desc"
echo " Usage: $usage"
echo ""
done
else
echo "No tools found matching '$search_term'"
fi
else
echo -e "${RED}No tools database available${NC}"
fi
}
show_examples() {
echo -e "${CYAN}Available Command Examples${NC}"
echo ""
if [[ -d "$CHEAT_DIR/personal" ]]; then
local count=$(ls -1 "$CHEAT_DIR/personal/"*.cheat 2>/dev/null | wc -l)
echo -e "${GREEN}Per-tool cheat sheets: $count${NC} (use: fhelp cheat <name>)"
echo ""
# Show a sample of tools grouped by first letter
ls -1 "$CHEAT_DIR/personal/"*.cheat 2>/dev/null | sed 's|.*/||; s|\.cheat$||' | head -30 | sed 's/^/ /'
if [[ $count -gt 30 ]]; then
echo " ... and $((count - 30)) more"
fi
echo ""
fi
if [[ -d "$CHEAT_DIR" ]]; then
echo -e "${GREEN}Workflow cheat sheets:${NC}"
ls -1 "$CHEAT_DIR"/*.cheat 2>/dev/null | sed 's|.*/||; s|\.cheat$||' | sed 's/^/ /'
echo ""
fi
echo -e "${GREEN}Analysis workflows:${NC} (use: fhelp workflow <name>)"
if [[ -d "$WORKFLOW_DIR" ]]; then
ls -1 "$WORKFLOW_DIR"/*.txt 2>/dev/null | sed 's|.*/||; s|\.txt$||' | grep -v index | sed 's/^/ /'
else
echo " static-analysis, behavioral-analysis, network-interception"
echo " document-analysis, javascript-deobfuscation, unpacking"
echo " code-injection, dotnet-analysis"
fi
}
show_workflow() {
local name="$1"
if [[ -z "$name" ]]; then
# Show workflow index
if [[ -f "$WORKFLOW_DIR/index.txt" ]]; then
cat "$WORKFLOW_DIR/index.txt"
else
echo -e "${CYAN}Available Analysis Workflows${NC}"
echo "=============================="
echo ""
echo " static-analysis-workflow Static Properties Analysis"
echo " behavioral-analysis-workflow Behavioral Analysis"
echo " network-interception-workflow Network Interception"
echo " document-analysis-workflow Malicious Document Analysis"
echo " javascript-deobfuscation-workflow JavaScript Deobfuscation"
echo " unpacking-workflow Unpacking Packed Executables"
echo " code-injection-workflow Code Injection Analysis"
echo " dotnet-analysis-workflow .NET Malware Analysis"
echo ""
echo "Usage: fhelp workflow <name>"
echo "Example: fhelp workflow static-analysis"
fi
return
fi
# Normalize name: allow partial matches
local wf_file=""
# Try exact match first
if [[ -f "$WORKFLOW_DIR/${name}.txt" ]]; then
wf_file="$WORKFLOW_DIR/${name}.txt"
elif [[ -f "$WORKFLOW_DIR/${name}-workflow.txt" ]]; then
wf_file="$WORKFLOW_DIR/${name}-workflow.txt"
else
# Fuzzy match: find workflow files containing the search term
if [[ -d "$WORKFLOW_DIR" ]]; then
wf_file=$(ls -1 "$WORKFLOW_DIR"/*.txt 2>/dev/null | grep -i "$name" | grep -v index | head -1)
fi
fi
if [[ -n "$wf_file" && -f "$wf_file" ]]; then
cat "$wf_file"
else
echo -e "${YELLOW}No workflow found matching '$name'${NC}"
echo ""
show_workflow # Show list
fi
}
show_coverage() {
echo -e "${CYAN}Help Coverage Statistics${NC}"
echo "========================"
echo ""
if [[ -f "$TOOLS_DB" ]]; then
local total=$(wc -l < "$TOOLS_DB" 2>/dev/null || echo 0)
local rich=$(grep -c '|rich$' "$TOOLS_DB" 2>/dev/null || echo 0)
local standard=$(grep -c '|standard$' "$TOOLS_DB" 2>/dev/null || echo 0)
local basic=$(grep -c '|basic$' "$TOOLS_DB" 2>/dev/null || echo 0)
echo -e " Tools in database: ${GREEN}$total${NC}"
echo -e " Rich help (FOR610): ${GREEN}$rich${NC}"
echo -e " Standard (docs): ${BLUE}$standard${NC}"
echo -e " Basic: ${YELLOW}$basic${NC}"
else
echo " Tools database not available"
fi
echo ""
if [[ -d "$CHEAT_DIR/personal" ]]; then
local cheats=$(ls -1 "$CHEAT_DIR/personal/"*.cheat 2>/dev/null | wc -l)
echo -e " Cheat sheets: ${GREEN}$cheats${NC}"
fi
if [[ -d "$WORKFLOW_DIR" ]]; then
local wfs=$(ls -1 "$WORKFLOW_DIR"/*.txt 2>/dev/null | grep -cv index 2>/dev/null || echo 0)
echo -e " Workflows: ${GREEN}$wfs${NC}"
fi
}
show_offline_status() {
echo -e "${CYAN}Offline Capability Check${NC}"
echo "==========================="
echo ""
echo "Documentation Tools:"
local tools=("find-tool" "cheat" "tldr")
for tool in "${tools[@]}"; do
if command -v "$tool" >/dev/null 2>&1; then
echo -e " ${GREEN}+ $tool - available${NC}"
else
echo -e " ${RED}- $tool - missing${NC}"
fi
done
echo ""
echo "Documentation Files:"
if [[ -f "$TOOLS_DB" ]]; then
local db_count=$(wc -l < "$TOOLS_DB" 2>/dev/null || echo 0)
echo -e " ${GREEN}+ tools.db - $db_count tools${NC}"
else
echo -e " ${RED}- tools.db - missing${NC}"
fi
if [[ -d "$CHEAT_DIR/personal" ]]; then
local cheat_count=$(ls -1 "$CHEAT_DIR/personal/"*.cheat 2>/dev/null | wc -l)
echo -e " ${GREEN}+ cheatsheets - $cheat_count files${NC}"
else
echo -e " ${RED}- cheatsheets - missing${NC}"
fi
if [[ -d "$WORKFLOW_DIR" ]]; then
local wf_count=$(ls -1 "$WORKFLOW_DIR"/*.txt 2>/dev/null | grep -cv index 2>/dev/null || echo 0)
echo -e " ${GREEN}+ workflows - $wf_count workflows${NC}"
else
echo -e " ${RED}- workflows - missing${NC}"
fi
echo ""
echo -e "${GREEN}Offline help system ready!${NC}"
}
show_all() {
echo -e "${CYAN}Complete Help System Overview${NC}"
echo "================================="
echo ""
show_coverage
echo ""
show_workflow
echo ""
show_offline_status
}
# Main command parsing
case "${1:-}" in
"start"|"quickstart"|"getting-started")
show_start
;;
"tools")
shift
show_tools "$@"
;;
"cheat")
shift
show_cheat "$@"
;;
"quick")
shift
show_quick "$@"
;;
"examples")
show_examples
;;
"workflow")
shift
show_workflow "$@"
;;
"pdf")
show_workflow "document-analysis"
;;
"malware")
show_workflow "static-analysis"
;;
"forensics")
show_workflow "behavioral-analysis"
;;
"coverage")
show_coverage
;;
"--offline")
show_offline_status
;;
"--all")
show_all
;;
"--help"|"-h"|"help"|"")
show_main_help
;;
*)
# Try as workflow name first, then show error
if [[ -d "$WORKFLOW_DIR" ]] && ls "$WORKFLOW_DIR"/*.txt 2>/dev/null | grep -qi "$1"; then
show_workflow "$1"
else
echo -e "${RED}Unknown option: $1${NC}"
echo ""
show_main_help
fi
;;
esac