diff --git a/app.py b/app.py index db1c926..e2d60b0 100644 --- a/app.py +++ b/app.py @@ -2302,12 +2302,22 @@ def parse_script_metadata(filepath): "name": os.path.basename(filepath).replace(".sh", "").replace("_", " ").title(), "desc": "", "tag": "", + "url": "", "path": filepath, } try: with open(filepath, "r", encoding="utf-8", errors="replace") as f: for line in f: line = line.strip() + if line.startswith("# name:"): + metadata["name"] = line[7:].strip() + elif line.startswith("# desc:"): + metadata["desc"] = line[7:].strip() + elif line.startswith("# tag:"): + metadata["tag"] = line[6:].strip() + elif line.startswith("# url:"): + metadata["url"] = line[6:].strip() + elif not line.startswith("#") and line: if line.startswith('# name:'): name_val = line[7:].strip() if name_val: diff --git a/favorites.json b/favorites.json index f161a82..6237732 100644 --- a/favorites.json +++ b/favorites.json @@ -1 +1 @@ -["docker/list_containers.sh", "linux/test123.sh"] \ No newline at end of file +["docker/list_containers.sh", "linux/test123.sh", "devops-tools/docker_status.sh"] \ No newline at end of file diff --git a/scripts/dev-tools/base64_tool.sh b/scripts/dev-tools/base64_tool.sh new file mode 100644 index 0000000..8e4ebdd --- /dev/null +++ b/scripts/dev-tools/base64_tool.sh @@ -0,0 +1,29 @@ +#!/bin/bash +# name: Base64 Utility +# desc: Quick base64 encoder and decoder. +# tag: dev-tools + +GREEN='\033[0;32m' +BLUE='\033[0;34m' +YELLOW='\033[1;33m' +NC='\033[0m' + +echo -e "${BLUE}====================================================${NC}" +echo -e "${GREEN} BASE64 UTILITY ${NC}" +echo -e "${BLUE}====================================================${NC}" + +echo -e "Select action:" +echo -e "1) ${YELLOW}Encode${NC} text to Base64" +echo -e "2) ${YELLOW}Decode${NC} Base64 to text" +read -p "Enter Choice (1 or 2): " CHOICE + +if [ "${CHOICE}" = "1" ]; then + read -p "Enter text to encode: " PLAIN_TEXT + echo -n "${PLAIN_TEXT}" | base64 +elif [ "${CHOICE}" = "2" ]; then + read -p "Enter base64 string to decode: " B64_TEXT + echo -n "${B64_TEXT}" | base64 --decode + echo "" +else + echo "Invalid option selected." +fi diff --git a/scripts/devops-tools/docker_status.sh b/scripts/devops-tools/docker_status.sh new file mode 100644 index 0000000..1a6d4a1 --- /dev/null +++ b/scripts/devops-tools/docker_status.sh @@ -0,0 +1,36 @@ +#!/bin/bash +# name: Docker Status +# desc: Checks docker service status and lists containers and images. +# tag: devops-tools + +GREEN='\033[0;32m' +BLUE='\033[0;34m' +YELLOW='\033[1;33m' +RED='\033[0;31m' +NC='\033[0m' + +echo -e "${BLUE}====================================================${NC}" +echo -e "${GREEN} DOCKER STATUS REPORT ${NC}" +echo -e "${BLUE}====================================================${NC}" + +if ! command -v docker &> /dev/null; then + echo -e "${RED}Error: Docker CLI is not installed on this machine.${NC}" + exit 1 +fi + +echo -e "\n${YELLOW}[Docker Daemon Health]${NC}" +if docker info &> /dev/null; then + echo -e "${GREEN}Docker daemon is running perfectly.${NC}" +else + echo -e "${RED}Docker daemon is not running or accessible without root.${NC}" + exit 1 +fi + +echo -e "\n${YELLOW}[Running Containers]${NC}" +docker ps --format "table {{.ID}}\t{{.Names}}\t{{.Status}}\t{{.Ports}}" + +echo -e "\n${YELLOW}[Resource Usage Summary]${NC}" +docker stats --no-stream --format "table {{.Container}}\t{{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}" 2>/dev/null || echo "Stats unavailable" + +echo -e "\n${YELLOW}[Active Images]${NC}" +docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}" | head -n 10 diff --git a/scripts/devops-tools/resource_monitor.sh b/scripts/devops-tools/resource_monitor.sh new file mode 100644 index 0000000..f7399db --- /dev/null +++ b/scripts/devops-tools/resource_monitor.sh @@ -0,0 +1,60 @@ +#!/bin/bash +# name: Resource Alarm Monitor +# desc: Continuously checks CPU, Memory, and Disk, throwing colorful alerts when thresholds are breached. +# tag: devops-tools + +GREEN='\033[0;32m' +BLUE='\033[0;34m' +YELLOW='\033[1;33m' +RED='\033[0;31m' +NC='\033[0m' + +CPU_THRESHOLD=80 +MEM_THRESHOLD=85 +DISK_THRESHOLD=90 + +echo -e "${BLUE}====================================================${NC}" +echo -e "${GREEN} RESOURCE ALARM MONITOR ${NC}" +echo -e "${BLUE}====================================================${NC}" + +echo -e "CPU Alert Limit: ${YELLOW}${CPU_THRESHOLD}%${NC}" +echo -e "RAM Alert Limit: ${YELLOW}${MEM_THRESHOLD}%${NC}" +echo -e "Disk Alert Limit: ${YELLOW}${DISK_THRESHOLD}%${NC}\n" + +DISK_USAGE=$(df -h / | tail -1 | awk '{print $5}' | sed 's/%//') +if [ "${DISK_USAGE}" -gt "${DISK_THRESHOLD}" ]; then + echo -e "${RED}[ALERT] Disk usage is critically high: ${DISK_USAGE}%${NC}" +else + echo -e "${GREEN}[OK] Disk Usage: ${DISK_USAGE}%${NC}" +fi + +if [ "$(uname)" = "Darwin" ]; then + MEM_USAGE=$(memory_pressure | grep "System-wide memory free percentage" | awk '{print 100 - $5}') + if [ -z "${MEM_USAGE}" ]; then + MEM_USAGE=$(vm_stat | awk '/free/ {free=$3} /active/ {active=$3} /inactive/ {inactive=$3} END {total=free+active+inactive; print (active+inactive)/total*100}' | cut -d. -f1) + fi +else + MEM_USAGE=$(free | grep Mem | awk '{print int($3/$2 * 100)}') +fi + +if [ -n "${MEM_USAGE}" ]; then + if [ "${MEM_USAGE}" -gt "${MEM_THRESHOLD}" ]; then + echo -e "${RED}[ALERT] Memory usage is critically high: ${MEM_USAGE}%${NC}" + else + echo -e "${GREEN}[OK] Memory Usage: ${MEM_USAGE}%${NC}" + fi +fi + +if [ "$(uname)" = "Darwin" ]; then + CPU_USAGE=$(ps -A -o %cpu | awk '{s+=$1} END {print int(s)}') +else + CPU_USAGE=$(top -bn1 | grep "Cpu(s)" | sed "s/.*, *\([0-9.]*\)%* id.*/\1/" | awk '{print int(100 - $1)}') +fi + +if [ -n "${CPU_USAGE}" ]; then + if [ "${CPU_USAGE}" -gt "${CPU_THRESHOLD}" ]; then + echo -e "${RED}[ALERT] CPU load is high: ${CPU_USAGE}%${NC}" + else + echo -e "${GREEN}[OK] CPU Load: ${CPU_USAGE}%${NC}" + fi +fi diff --git a/scripts/devops-tools/ssl_expiry.sh b/scripts/devops-tools/ssl_expiry.sh new file mode 100644 index 0000000..b8c298e --- /dev/null +++ b/scripts/devops-tools/ssl_expiry.sh @@ -0,0 +1,23 @@ +#!/bin/bash +# name: SSL Expiry Checker +# desc: Check and verify SSL/TLS certificate validity and expiration for any web host. +# tag: devops-tools, ssl +# url: https://www.ssllabs.com/ssltest/ + +echo "=== SSL Expiry Checker ===" +read -p "Enter domain (e.g. google.com): " domain +if [ -z "$domain" ]; then + domain="google.com" +fi +echo "Connecting to $domain:443..." +echo "" +if ! command -v openssl >/dev/null 2>&1; then + echo "Error: openssl utility is not installed." + exit 1 +fi +res=$(echo | openssl s_client -servername "$domain" -connect "$domain":443 2>/dev/null | openssl x509 -noout -dates -issuer) +if [ -z "$res" ]; then + echo "Failed to retrieve SSL certificate details." +else + echo "$res" +fi diff --git a/ui/app.js b/ui/app.js index a4b7f5a..e4ccd0c 100644 --- a/ui/app.js +++ b/ui/app.js @@ -3467,6 +3467,33 @@ function bindEvents() { document.getElementById('btn-add-script').addEventListener('click', () => openModal('new')); document.getElementById('btn-refresh').addEventListener('click', () => loadScripts()); + // Predefined Tools Dropdown toggle + const btnToolsDropdown = document.getElementById('btn-tools-dropdown'); + const toolsDropdownMenu = document.getElementById('tools-dropdown-menu'); + if (btnToolsDropdown && toolsDropdownMenu) { + btnToolsDropdown.addEventListener('click', (e) => { + e.stopPropagation(); + toolsDropdownMenu.classList.toggle('active'); + }); + + // Hide dropdown when clicking outside + document.addEventListener('click', (e) => { + if (!toolsDropdownMenu.contains(e.target) && e.target !== btnToolsDropdown) { + toolsDropdownMenu.classList.remove('active'); + } + }); + + // Event delegation for dropdown items + toolsDropdownMenu.querySelectorAll('.dropdown-item').forEach(item => { + item.addEventListener('click', (e) => { + e.stopPropagation(); + toolsDropdownMenu.classList.remove('active'); + const toolKey = item.getAttribute('data-tool'); + loadPredefinedScript(toolKey); + }); + }); + } + // Script Details Actions const btnRun = document.getElementById('btn-run'); if (btnRun) { @@ -4863,3 +4890,364 @@ if (!window.hasRegisteredLifecycleCleanup) { } }); } + +// ─── Predefined Dev & DevOps Tools Templates ──────────────── +const PREDEFINED_TOOLS = { + sys_info: { + name: "System Info Dashboard", + category: "dev-tools", + filename: "system_info.sh", + url: "https://explainshell.com", + content: `#!/bin/bash +# name: System Info Dashboard +# desc: Detailed system diagnostic displaying CPU load, Memory stats, Disk status, and network details. +# tag: dev-tools, system +# url: https://explainshell.com + +echo "=== System Info Dashboard ===" +echo "Date: $(date)" +echo "OS: $(uname -a)" +echo "" +echo "--- CPU LOAD ---" +uptime +echo "" +echo "--- MEMORY USAGE ---" +if [[ "$OSTYPE" == "darwin"* ]]; then + vm_stat | perl -ne '/page size of (\\d+) bytes/ && ($s=$1); /Pages free:\\s+(\\d+)/ && ($f=$1); /Pages active:\\s+(\\d+)/ && ($a=$1); /Pages inactive:\\s+(\\d+)/ && ($i=$1); /Pages speculative:\\s+(\\d+)/ && ($sp=$1); /Pages wired down:\\s+(\\d+)/ && ($w=$1); END { printf "Active: %.2fMB\\nInactive: %.2fMB\\nSpeculative: %.2fMB\\nWired: %.2fMB\\nFree: %.2fMB\\n", ($a*$s)/1048576, ($i*$s)/1048576, ($sp*$s)/1048576, ($w*$s)/1048576, ($f*$s)/1048576 }' +else + free -m +fi +echo "" +echo "--- DISK SPACE ---" +df -h | grep -E '^/dev/' || df -h +echo "" +echo "--- NETWORK DEVICES ---" +ifconfig -a || ip a +` + }, + port_scanner: { + name: "Process Port Lister", + category: "dev-tools", + filename: "process_port_lister.sh", + url: "https://portchecktool.com", + content: `#!/bin/bash +# name: Process Port Lister +# desc: Scan and list all active listening ports and the respective processes bound to them. +# tag: dev-tools, network +# url: https://portchecktool.com + +echo "=== Process Port Lister ===" +echo "Scanning for active listening sockets..." +echo "" +if command -v lsof >/dev/null 2>&1; then + lsof -i -P -n | grep LISTEN || echo "No listening ports found via lsof." +elif command -v netstat >/dev/null 2>&1; then + netstat -antp | grep LISTEN || netstat -an | grep LISTEN || echo "No listening ports found via netstat." +elif command -v ss >/dev/null 2>&1; then + ss -lntp || ss -ln || echo "No listening ports found via ss." +else + echo "Error: Neither lsof, netstat, nor ss found on this system." +fi +` + }, + find_large_files: { + name: "Find Large Files (>100MB)", + category: "dev-tools", + filename: "find_large_files.sh", + url: "https://tldr.sh", + content: `#!/bin/bash +# name: Find Large Files (>100MB) +# desc: Search the current directory recursively and list all files larger than 100MB. +# tag: dev-tools, search +# url: https://tldr.sh + +TARGET_DIR="." +echo "=== Find Large Files (>100MB) ===" +echo "Searching in: $TARGET_DIR" +echo "This might take a moment..." +echo "" +find "$TARGET_DIR" -type f -size +100M -exec du -h {} + 2>/dev/null | sort -rh || find "$TARGET_DIR" -type f -size +100000k -exec du -h {} + 2>/dev/null | sort -rh +echo "" +echo "Search complete." +` + }, + json_formatter: { + name: "JSON Formatter/Validator", + category: "dev-tools", + filename: "json_formatter.sh", + url: "https://jsonformatter.org", + content: `#!/bin/bash +# name: JSON Formatter/Validator +# desc: Pipe JSON input directly into Python's json.tool for format-indenting and validity checking. +# tag: dev-tools, json +# url: https://jsonformatter.org + +echo "=== JSON Formatter/Validator ===" +echo "Enter/Paste your raw JSON content below, then press Ctrl+D to format:" +echo "" +TMP_FILE=$(mktemp) +cat > "$TMP_FILE" +echo "" +echo "--- Formatted Output ---" +if command -v python3 >/dev/null 2>&1; then + python3 -m json.tool "$TMP_FILE" +elif command -v python >/dev/null 2>&1; then + python -m json.tool "$TMP_FILE" +elif command -v jq >/dev/null 2>&1; then + jq . "$TMP_FILE" +else + echo "Error: Neither python3, python, nor jq found to parse JSON." + cat "$TMP_FILE" +fi +rm -f "$TMP_FILE" +` + }, + base64_util: { + name: "Base64 Encode/Decode", + category: "dev-tools", + filename: "base64_util.sh", + url: "https://www.base64decode.org", + content: `#!/bin/bash +# name: Base64 Encode/Decode +# desc: Easily encode regular text or decode encoded Base64 strings. +# tag: dev-tools, utility +# url: https://www.base64decode.org + +echo "=== Base64 Utility ===" +echo "1) Encode Text to Base64" +echo "2) Decode Base64 to Text" +read -p "Select option (1 or 2): " choice +echo "" +if [ "$choice" = "1" ]; then + read -p "Enter text to encode: " txt + echo -n "$txt" | base64 +elif [ "$choice" = "2" ]; then + read -p "Enter Base64 string to decode: " b64 + echo -n "$b64" | base64 --decode || echo -n "$b64" | base64 -d +else + echo "Invalid choice." +fi +echo "" +` + }, + docker_status: { + name: "Docker Container Status", + category: "devops-tools", + filename: "docker_status.sh", + url: "https://hub.docker.com", + content: `#!/bin/bash +# name: Docker Container Status +# desc: Check if docker daemon is running, inspect CPU/memory stats, and list active containers. +# tag: devops-tools, docker +# url: https://hub.docker.com + +echo "=== Docker Container Status ===" +if ! command -v docker >/dev/null 2>&1; then + echo "Error: docker command line tool is not installed." + exit 1 +fi +echo "--- Docker System Info ---" +docker info --format 'Containers: {{.Containers}}, Running: {{.ContainersRunning}}, Paused: {{.ContainersPaused}}, Stopped: {{.ContainersStopped}}' || echo "Error connecting to Docker Daemon." +echo "" +echo "--- Container Resource Stats ---" +docker stats --no-stream --format "table {{.Name}}\\t{{.CPUPerc}}\\t{{.MemUsage}}\\t{{.NetIO}}" 2>/dev/null || echo "No running containers or stats unavailable." +echo "" +echo "--- All Containers ---" +docker ps -a --format "table {{.Names}}\\t{{.Image}}\\t{{.Status}}\\t{{.Ports}}" +` + }, + ssl_expiry: { + name: "SSL Expiry Checker", + category: "devops-tools", + filename: "ssl_expiry.sh", + url: "https://www.ssllabs.com/ssltest/", + content: `#!/bin/bash +# name: SSL Expiry Checker +# desc: Check and verify SSL/TLS certificate validity and expiration for any web host. +# tag: devops-tools, ssl +# url: https://www.ssllabs.com/ssltest/ + +echo "=== SSL Expiry Checker ===" +read -p "Enter domain (e.g. google.com): " domain +if [ -z "$domain" ]; then + domain="google.com" +fi +echo "Connecting to $domain:443..." +echo "" +if ! command -v openssl >/dev/null 2>&1; then + echo "Error: openssl utility is not installed." + exit 1 +fi +res=$(echo | openssl s_client -servername "$domain" -connect "$domain":443 2>/dev/null | openssl x509 -noout -dates -issuer) +if [ -z "$res" ]; then + echo "Failed to retrieve SSL certificate details." +else + echo "$res" +fi +` + }, + git_diagnostics: { + name: "Git Repo Diagnostics", + category: "devops-tools", + filename: "git_diagnostics.sh", + url: "https://github.com", + content: `#!/bin/bash +# name: Git Repo Diagnostics +# desc: Run a detailed diagnostics audit on the local Git repository branches, statuses, and remotes. +# tag: devops-tools, git +# url: https://github.com + +echo "=== Git Repo Diagnostics ===" +if ! command -v git >/dev/null 2>&1; then + echo "Error: git is not installed." + exit 1 +fi +if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then + echo "Error: Current directory is not a Git repository." + exit 1 +fi +echo "Current Branch: $(git branch --show-current)" +echo "Git Root: $(git rev-parse --show-toplevel)" +echo "" +echo "--- Git Status ---" +git status -s +echo "" +echo "--- Recent Commits ---" +git log -n 5 --oneline +echo "" +echo "--- Configured Remotes ---" +git remote -v +` + }, + resource_alarm: { + name: "Resource Alarm Monitor", + category: "devops-tools", + filename: "resource_alarm.sh", + url: "https://grafana.com", + content: `#!/bin/bash +# name: Resource Alarm Monitor +# desc: Continuously monitor host disk and memory usage, triggering high usage console alerts. +# tag: devops-tools, monitoring +# url: https://grafana.com + +DISK_THRESHOLD=80 +MEM_THRESHOLD=85 + +echo "=== Resource Alarm Monitor ===" +echo "Disk Warning Limit: $DISK_THRESHOLD%" +echo "Memory Warning Limit: $MEM_THRESHOLD%" +echo "" + +# Disk Check +disk_val=$(df / | tail -1 | awk '{print $5}' | sed 's/%//') +if [ "$disk_val" -gt "$DISK_THRESHOLD" ]; then + echo "⚠️ ALARM: Disk usage on root / is at \${disk_val}%!" +else + echo "Disk usage is normal: \${disk_val}%" +fi + +# Memory Check +if [[ "$OSTYPE" == "darwin"* ]]; then + # MacOS memory approximation + free_pages=$(vm_stat | grep "Pages free" | awk '{print $3}' | sed 's/\\.//') + active_pages=$(vm_stat | grep "Pages active" | awk '{print $3}' | sed 's/\\.//') + spec_pages=$(vm_stat | grep "Pages speculative" | awk '{print $3}' | sed 's/\\.//') + wire_pages=$(vm_stat | grep "Pages wired" | awk '{print $3}' | sed 's/\\.//') + used_pages=$((active_pages + wire_pages + spec_pages)) + total_pages=$((used_pages + free_pages)) + mem_val=$((used_pages * 100 / total_pages)) +else + mem_val=$(free | grep Mem | awk '{print int($3/$2 * 100)}') +fi + +if [ "$mem_val" -gt "$MEM_THRESHOLD" ]; then + echo "⚠️ ALARM: Memory usage is at \${mem_val}%!" +else + echo "Memory usage is normal: \${mem_val}%" +fi +` + }, + k8s_pods: { + name: "Kubernetes Pod Status", + category: "devops-tools", + filename: "k8s_pods.sh", + url: "https://kubernetes.io/docs/", + content: `#!/bin/bash +# name: Kubernetes Pod Status +# desc: Connect to configured cluster, check node connectivity, list pods across namespaces. +# tag: devops-tools, kubernetes +# url: https://kubernetes.io/docs/ + +echo "=== Kubernetes Pod Status ===" +if ! command -v kubectl >/dev/null 2>&1; then + echo "Error: kubectl command-line tool is not installed." + exit 1 +fi +echo "--- Cluster Info ---" +kubectl cluster-info || echo "Error connecting to Kubernetes Cluster." +echo "" +echo "--- Nodes Status ---" +kubectl get nodes 2>/dev/null || echo "No nodes found or connection failed." +echo "" +echo "--- Pods (All Namespaces) ---" +kubectl get pods --all-namespaces +` + }, + nginx_tester: { + name: "Nginx Config Integrity", + category: "devops-tools", + filename: "nginx_tester.sh", + url: "https://nginx.org/en/docs/", + content: `#!/bin/bash +# name: Nginx Config Integrity +# desc: Validate host Nginx configuration syntax and test responsiveness of localhost. +# tag: devops-tools, nginx +# url: https://nginx.org/en/docs/ + +echo "=== Nginx Config Integrity ===" +if ! command -v nginx >/dev/null 2>&1; then + echo "Error: nginx command is not installed or not in PATH." + exit 1 +fi +echo "--- Testing Configuration Syntax ---" +nginx -t 2>&1 || sudo nginx -t 2>&1 +echo "" +echo "--- Nginx System Process Status ---" +if command -v systemctl >/dev/null 2>&1; then + systemctl status nginx --no-pager || echo "systemctl failed to get status." +else + ps aux | grep nginx | grep -v grep +fi +` + } +}; + +async function loadPredefinedScript(key) { + const template = PREDEFINED_TOOLS[key]; + if (!template) return; + + try { + notify(`Linking ${template.name}...`, 'info'); + const res = await fetch(API.save, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + category: template.category, + filename: template.filename, + content: template.content, + password: getUnlockPassword(`${template.category}/${template.filename}`) + }) + }); + const data = await res.json(); + if (data.success) { + await loadScripts(); + await selectScript(data.path); + notify(`${template.name} has been linked and is ready to run!`, 'success'); + } else { + notify(`Failed to link script: ${data.error || 'unknown error'}`, 'error'); + } + } catch (err) { + console.error('Failed to link predefined script:', err); + notify(`Failed to link script: ${err.message}`, 'error'); + } +} diff --git a/ui/index.html b/ui/index.html index 66e5a01..29166b2 100644 --- a/ui/index.html +++ b/ui/index.html @@ -12,6 +12,7 @@ + @@ -81,6 +82,15 @@