diff --git a/DOC/AGENT_Context_Project.md b/DOC/AGENT_Context_Project.md index b9477d4..2968c2a 100644 --- a/DOC/AGENT_Context_Project.md +++ b/DOC/AGENT_Context_Project.md @@ -45,6 +45,7 @@ Linux_post_install/ │ ├── pos-system-firewall # Interactive UFW manager (menu-driven, 284 lines) │ ├── pos-system-backup # Encrypted folder snapshots (tar + gpg AES-256, --service) (115 lines) │ ├── pos-ssh-load-keys # Load SSH keys into ssh-agent +│ ├── pos-communication-telegram # Send Telegram messages via Bot API │ ├── pos-vbox # Disposable Docker-based "VMs" │ ├── pos-network-hotspot # Wi-Fi hotspot (create_ap + wihotspot-gui) │ ├── flag-reader # Inspect feature flags (list/status/--raw) @@ -201,6 +202,7 @@ All non-interactive `pos` commands log output to `~/.local/share/linux_post_inst | system | firewall | `pos-system-firewall` | Interactive UFW management | | system | backup | `pos-system-backup` | Encrypted folder snapshots (`tar` + gpg AES-256; `--service` picks from `/srv` and `~/srv`) | | ssh | load-keys | `pos-ssh-load-keys` | Load SSH keys into agent | +| communication | telegram | `pos-communication-telegram` | Send Telegram messages via Bot API (`--send`, `test`, `config set`); config in `~/.config/linux_post_install/telegram.env` | | vbox | create | `pos-vbox create` | Create disposable VM (asks "Enter now?") | | vbox | enter | `pos-vbox enter` | Start and exec into container | | vbox | ls | `pos-vbox ls` | List vbox-managed containers only (label-filtered) | @@ -246,7 +248,7 @@ Sourced by most scripts. Provides: source "$(dirname "$0")/../lib/common.sh" ``` -**Scripts that do NOT source common.sh** (self-contained): `bin/pos`, `pos-network-ip`, `pos-network-checkport`, `pos-network-scan`, `pos-media-mp3`, `pos-media-mp4`, `pos-ssh-load-keys`, `pos-system-firewall`. +**Scripts that do NOT source common.sh** (self-contained): `bin/pos`, `pos-network-ip`, `pos-network-checkport`, `pos-network-scan`, `pos-media-mp3`, `pos-media-mp4`, `pos-ssh-load-keys`, `pos-system-firewall`, `pos-communication-telegram`. --- @@ -444,7 +446,7 @@ Use conventional prefixes: `feat:`, `fix:`, `docs:`, `refactor:`, `chore:` | `bin/flag-set` | 21 | Set a flag (optionally with a value) | | `bin/flag-clear` | 21 | Unset a flag | | `features/autostart.sh` | 14 | Boot-time feature (moved from `bin/`, flag-gated service) | -| `bin/pos` | 146 | CLI dispatcher with smart arg matching + logging | +| `bin/pos` | 153 | CLI dispatcher with smart arg matching + logging | | `bin/pos-docker-compose` | 363 | Largest script — full compose management | | `bin/pos-system-firewall` | 284 | Interactive UFW manager | | `bin/pos-system-backup` | 115 | Encrypted folder snapshots: path mode + `--service` (`/srv`, `~/srv` picker), tar + gpg AES-256 | @@ -452,6 +454,7 @@ Use conventional prefixes: `feat:`, `fix:`, `docs:`, `refactor:`, `chore:` | `bin/pos-docker-health` | 109 | Quick health dashboard | | `bin/pos-vbox` | 156 | Docker-based disposable VMs (label-filtered, auto-enter prompt) | | `bin/pos-network-hotspot` | 91 | Wi-Fi hotspot: `create_ap` (start with background prompt/`--foreground`, stop, status) + `wihotspot-gui` | +| `bin/pos-communication-telegram` | 138 | Telegram sender via Bot API: `--send`, `test`, `config set`; token masked; config `~/.config/linux_post_install/telegram.env` | | `completions/pos.bash` | 118 | Dynamic bash completion | | `apps/install.sh` | 171 | App install/uninstall picker/orchestrator | diff --git a/DOC/POS.md b/DOC/POS.md index e2b9fd9..c49c5c5 100644 --- a/DOC/POS.md +++ b/DOC/POS.md @@ -10,6 +10,7 @@ - [media](#media) - [system](#system) - [ssh](#ssh) + - [communication](#communication) - [vbox](#vbox) - [flags](#flags) - [Legacy wrappers](#legacy-wrappers) @@ -145,6 +146,25 @@ Global config keys: |---------|------|---------|---------------| | `pos ssh load-keys` | `bin/pos-ssh-load-keys` | Load all `~/.ssh/id_*` private keys into the ssh-agent | Uses `SSH_AUTH_SOCK` (default `/run/ssh-agent/socket`, provided by `ssh-agent.service`); skips `.pub`, `known_hosts`, `authorized_keys`, `config`; validates keys before adding | +### communication + +| Command | File | Purpose | Configuration | +|---------|------|---------|---------------| +| `pos communication telegram --send "text"` | `bin/pos-communication-telegram` | Send a text message to a Telegram chat via the Bot API | Token + chat ID from `~/.config/linux_post_install/telegram.env` (`TELEGRAM_BOT_TOKEN`, `TELEGRAM_CHAT_ID`, chmod 600). Precedence: `--token`/`--chat-id` flags > env > config file | + +`pos communication telegram` in detail: + +| Command | Behavior | +|---------|----------| +| `pos communication telegram --send "text"` | POSTs `sendMessage` to the Bot API (20s timeout); prints `[+] Message sent to chat ` or fails with a nonzero exit | +| `pos communication telegram --send "text" --token --chat-id ` | One-shot override of token/chat ID | +| `pos communication telegram test` | Sends a canned test message using the current config | +| `pos communication telegram config` | Shows current config (bot token masked) | +| `pos communication telegram config set TELEGRAM_BOT_TOKEN=...` | Saves a bot token (600 perms) | +| `pos communication telegram config set TELEGRAM_CHAT_ID=...` | Saves the target chat ID | + +The bot token is a secret — it is stored only in `~/.config/linux_post_install/telegram.env` and never in the repo. Requires network access to `api.telegram.org`. + ### vbox **File:** `bin/pos-vbox` diff --git a/README.md b/README.md index d109403..1dde178 100755 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ It is a **personal toolkit** — a bootstrap script, a unified `pos` CLI for eve **What you get:** - 25+ system packages installed automatically -- The `pos` CLI: network, Docker, media, system, SSH, and vbox tools +- The `pos` CLI: network, Docker, media, system, SSH, communication (Telegram), and vbox tools - Wi-Fi hotspot tools (`create_ap`, `wihotspot-gui`) via `pos network hotspot` - 15 optional desktop apps (VS Code, Brave, OBS, Tailscale, …) — pick what you want - 119+ self-hosted services with Tailscale access (Jellyfin, Home Assistant, …) diff --git a/apps/utilities/tsui.sh b/apps/utilities/tsui.sh new file mode 100755 index 0000000..3515f40 --- /dev/null +++ b/apps/utilities/tsui.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +set -euo pipefail +source "$(dirname "$0")/../../lib/common.sh" + +install_tsui() { + command -v tsui &>/dev/null && { log "tsui already installed"; return 0; } + + spawn "Installing tsui" bash -c " + curl -fsSL https://neuralink.com/tsui/install.sh | bash + " + log "Run tsui: sudo tsui" +} + +uninstall_tsui() { + command -v tsui &>/dev/null || { log "tsui not installed"; return 0; } + spawn "Removing tsui" sudo rm -f /usr/local/bin/tsui +} + +case "${1:-}" in + uninstall) uninstall_tsui ;; + *) install_tsui ;; +esac diff --git a/bin/pos b/bin/pos index 8851e9a..ac6206f 100755 --- a/bin/pos +++ b/bin/pos @@ -42,6 +42,8 @@ CATEGORIES media mp3 | mp4 system firewall | backup ssh load-keys + communication + telegram vbox create | enter | stop | start | rm | ls EXAMPLES @@ -63,6 +65,9 @@ EXAMPLES pos ssh load-keys Load all SSH keys into agent + pos communication telegram --send "Backup done" + Send a Telegram message + pos vbox create lab1 Create disposable Docker VM pos vbox create lab1 --dir . Create VM using current directory pos vbox enter lab1 Shell into a Docker VM diff --git a/bin/pos-communication-telegram b/bin/pos-communication-telegram new file mode 100755 index 0000000..a2b369e --- /dev/null +++ b/bin/pos-communication-telegram @@ -0,0 +1,138 @@ +#!/usr/bin/env bash +set -euo pipefail + +CONFIG_DIR="$HOME/.config/linux_post_install" +CONFIG_FILE="$CONFIG_DIR/telegram.env" +API="https://api.telegram.org" + +usage() { + cat < --chat-id Override token/chat for one send + test Send a test message using the current config + config Show current config (token masked) + config set KEY=VALUE Set TELEGRAM_BOT_TOKEN or TELEGRAM_CHAT_ID + +Config file: $CONFIG_FILE +Keys: TELEGRAM_BOT_TOKEN | TELEGRAM_CHAT_ID + +Precedence: CLI flags > environment > config file. + +Examples: + pos communication telegram config set TELEGRAM_BOT_TOKEN=123456:ABC-DEF + pos communication telegram config set TELEGRAM_CHAT_ID=987654321 + pos communication telegram --send "Backup finished" + pos communication telegram test +EOF + exit 0 +} + +err() { echo "ERROR: $*" >&2; exit 1; } + +load_config() { + [ -f "$CONFIG_FILE" ] || return 0 + local k v + while IFS='=' read -r k v; do + [ -n "$k" ] || continue + case "$k" in + \#*) continue ;; + esac + v="${v%\"}"; v="${v#\"}"; v="${v%\'}"; v="${v#\'}" + if [ -z "${!k:-}" ]; then + export "$k"="$v" + fi + done < <(grep -E '^[A-Z_]+=' "$CONFIG_FILE" || true) +} + +mask_token() { + local t="$1" + [ -z "$t" ] && { echo "(not set)"; return; } + if [ "${#t}" -le 12 ]; then + echo "${t:0:4}... (${#t} chars)" + else + echo "${t:0:6}...${t: -4} (${#t} chars)" + fi +} + +cmd_send() { + local text="$1" + [ -z "${TELEGRAM_BOT_TOKEN:-}" ] && err "No bot token — run 'pos communication telegram config set TELEGRAM_BOT_TOKEN=...'" + [ -z "${TELEGRAM_CHAT_ID:-}" ] && err "No chat id — run 'pos communication telegram config set TELEGRAM_CHAT_ID=...'" + curl -fsS -m 20 -X POST "$API/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \ + --data-urlencode "chat_id=${TELEGRAM_CHAT_ID}" \ + --data-urlencode "text=${text}" >/dev/null + echo "[+] Message sent to chat ${TELEGRAM_CHAT_ID}" +} + +cmd_config() { + load_config + echo "Config: $CONFIG_FILE" + echo " TELEGRAM_BOT_TOKEN = $(mask_token "${TELEGRAM_BOT_TOKEN:-}")" + echo " TELEGRAM_CHAT_ID = ${TELEGRAM_CHAT_ID:-}" +} + +cmd_config_set() { + local kv="$1" + local key="${kv%%=*}" + local val="${kv#*=}" + case "$key" in + TELEGRAM_BOT_TOKEN|TELEGRAM_CHAT_ID) ;; + *) err "Unknown key '$key' (allowed: TELEGRAM_BOT_TOKEN, TELEGRAM_CHAT_ID)" ;; + esac + [ -z "$val" ] && err "No value given (expected $key=...)" + + mkdir -p "$CONFIG_DIR" + if [ -f "$CONFIG_FILE" ]; then + if grep -q "^${key}=" "$CONFIG_FILE"; then + sed -i "s|^${key}=.*|${key}=${val}|" "$CONFIG_FILE" + else + echo "${key}=${val}" >>"$CONFIG_FILE" + fi + else + echo "${key}=${val}" >"$CONFIG_FILE" + fi + chmod 600 "$CONFIG_FILE" + echo "[+] $key saved to $CONFIG_FILE" +} + +cmd="${1:-}" + +case "$cmd" in + -h|--help) usage ;; + --send) + shift + [ $# -ge 1 ] || usage + text="$1" + shift + while [ $# -gt 0 ]; do + case "$1" in + --token) TELEGRAM_BOT_TOKEN="$2"; shift 2 ;; + --chat-id) TELEGRAM_CHAT_ID="$2"; shift 2 ;; + *) err "Unknown option '$1'" ;; + esac + done + load_config + cmd_send "$text" + ;; + test) + load_config + cmd_send "Test message from pos $(date '+%Y-%m-%d %H:%M:%S')" + ;; + config) + shift + case "${1:-}" in + set) shift; [ $# -eq 1 ] || usage; cmd_config_set "$1" ;; + *) cmd_config ;; + esac + ;; + *) + echo "ERROR: Unknown telegram command '$cmd'" + echo "Run 'pos communication telegram --help' for usage." + exit 1 + ;; +esac