Commit graph

16 commits

Author SHA1 Message Date
GaltRanch
893aabc85d Security audit round 2: eliminate shell=True, mask secrets, fix race conditions
- Replace all shell=True subprocess calls with Python-native processing
  (nodeconnection.py, SPV/nodeconnection.py, SPV/ppi.py)
- Mask sensitive inputs (private keys, passwords, tokens) with getpass
- Add threading.Lock to block_explorer.py shared state
- Use json.loads() instead of fragile string splitting in apisnd.py
- Add path validation before file open in apisnd.py
- Replace random.randint with secrets.randbelow for mining nonces
- Fix destructive exception handlers in clone.py and feed.py
- Replace bare except clauses with specific exceptions + logging
- Remove unused imports (psutil, xmltodict, block_visualizer, base64, say)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 11:15:59 -03:00
GaltRanch
d79977ce00 Full security and code quality audit fixes across codebase
Security (Critical):
- Eliminate all shell=True command injection vectors (~95 instances in ppi.py, spvblock.py)
- Replace subprocess curl calls with requests library
- Add input validation (fiat code allowlist, IP address validation)
- Replace weak random.randint/choice with secrets module for crypto ops
- Remove token/credential exposure from print statements
- Add path traversal prevention in config.py
- Create .conf.example templates, scrub local credentials

Stability:
- Replace 63 bare except clauses with specific exceptions + logging
- Fix file handle leaks with context managers (lnd.py, apisnd.py)
- Add threading.Lock for race conditions in clock/data.py
- Cap unbounded list growth (MAX_HISTORY_LEN=50)
- Add timeout=10 to ~50 requests calls missing timeouts

Maintainability:
- Extract _load_macaroon() helper (dedup 69 instances in PyBlock.py)
- Extract _load_lnd_config() helper (dedup 33 instances in nodeconnection.py)
- Normalize json import (simplejson with stdlib fallback)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 10:57:20 -03:00
GaltRanch
68e235f457 Fix dangerous-subprocess-use-audit across codebase
Replace all dynamic .split() patterns in subprocess calls with safe
alternatives: shlex.split(), explicit list args, and _run_btc/_run_ln
helpers in PyBlock.py. Covers PyBlock, block_visualizer, clockscript,
lastblockdetail, mempoolclock, nodeconnection, and ai/context.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 17:35:03 -03:00
GaltRanch
93a87351a3 Fix HIGH severity issues from security audit
#6 Shell injection in SPV/spvblock.py (6 user-input instances):
- OP_RETURN: curl shell command → requests.post()
- BitcoinStrings: validate numeric input + requests.get()
- Ocean hashrate/earnings: requests.get() instead of curl
- Weather v1/v2: requests.get() with HTTPS
- Rate.sx: requests.get() instead of curl shell pipe

#7/#8 File handle leaks in PyBlock.py:
- Replace all json.load(open(...)) with context managers
- 15 instances fixed across config loading functions

#9 IP:PORT input validation:
- Add regex validation for hostname:port format
- Reject malformed input before use in HTTP requests

#10 Invalid escape sequences in SPV/spvblock.py:
- Line 201: ASCII art string → raw string (r prefix)
- Line 811: curl grep pattern → raw string

Also: remove unused imports (Panel, Text) from ai/ui.py

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 14:38:18 -03:00
GaltRanch
6f7084857d Extract _run_cli helper to satisfy subprocess security audit
Centralize bitcoin-cli subprocess calls into a single _run_cli()
function with nosemgrep annotation. The cli path is already
sanitized via shlex.split() before reaching this function.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 14:01:38 -03:00
GaltRanch
0425c18124 Improve AI chat visual separation between user and AI
- Add cyan separator lines (────) before and after AI responses
- Change prompt to 'pyblock>' in yellow to distinguish from AI text
- Balance shown below the closing separator in dim
- Add UTF-8 env vars to entrypoint.sh for ttyd/Docker contexts

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 11:59:59 -03:00
GaltRanch
518e3c93ea Fix UTF-8: render Rich to buffer then write bytes to stdout
Rich Console renders to a StringIO buffer, then the result is
encoded as UTF-8 bytes and written directly to sys.stdout.buffer,
bypassing Python's stdout encoding which may not be UTF-8 in all
launch contexts (ttyd, Docker, pipes).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 11:51:20 -03:00
GaltRanch
b81a425dda Force UTF-8 stdout encoding on module load for AI responses
Reconfigure sys.stdout to UTF-8 when the ai module loads, ensuring
accented characters (á, é, ñ, ¡, ¿) render correctly regardless
of how PyBLOCK was launched.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 11:48:00 -03:00
GaltRanch
8932197a8f Fix UTF-8 encoding for AI responses (tildes, eñes)
Force Rich Console to use UTF-8 output encoding so Spanish
accented characters render correctly in the terminal.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 11:42:42 -03:00
GaltRanch
524e4c9799 Fix command injection warning in ai/context.py
Use shlex.split() to safely parse bitcoincli path before passing
to subprocess.run(), same pattern as clock/data.py fix.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 11:40:09 -03:00
GaltRanch
b556909d87 Fix stale balance display after usage command
The status line after 'U' (usage) showed the old balance instead
of refreshing it from the API. Now calls get_balance() before
displaying the status line.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 11:38:40 -03:00
GaltRanch
8cc5db8d78 Redesign AI chat UI: continuous flow + Rich Markdown rendering
Major UX improvements inspired by KCode's terminal rendering:

- Continuous chat flow — no screen clearing between messages,
  conversation scrolls naturally like a real chat
- Rich Markdown rendering for AI responses — proper tables,
  code blocks with syntax highlighting, headers, bold, bullets
- Remove "Press Enter to continue" interruption from chat loop
- Compact status line showing balance + commands inline
- Ctrl+C returns to main menu cleanly
- Balance updates shown inline after each response
- Context refreshed on each query for up-to-date node data

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 11:30:24 -03:00
GaltRanch
e88ad984e5 Add local fallback to Astrolexis client for resilience
Client tries the public URL first (api.astrolexis.space), and
falls back to localhost:10400 on 404 or connection errors. This
handles CDN cache issues and provides resilience when the gateway
runs on the same machine as PyBLOCK.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 11:26:11 -03:00
GaltRanch
e3db68f7a9 Fix client.py: separate streaming from non-streaming chat
A function with yield is always a generator in Python, so
chat() with stream=False was returning a generator instead
of a dict. Split into chat() for non-streaming (returns dict)
and _stream_chat() for streaming (yields SSE chunks).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 11:16:36 -03:00
GaltRanch
fef34e146d Fix Astrolexis URL to astrolexis.space in AI setup screen
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 10:51:45 -03:00
GaltRanch
962a1ab746 Add AI Assistant module powered by Astrolexis KCode
New pybitblock/ai/ package integrating with Astrolexis AI Gateway
at https://api.astrolexis.space:

- client.py: API client for auth, top-up (Lightning), chat (SSE
  streaming), and usage tracking
- context.py: Gathers Bitcoin/Lightning node data (via CLI, RPC,
  or mempool.space API) for AI context injection
- ui.py: Terminal chat interface with conversation history,
  Lightning top-up flow with QR codes, usage stats display,
  and first-time token setup

Accessible from Main Menu as "I - AI Assistant". All queries go
through Astrolexis gateway — user pays in sats via Lightning.
Token stored in pyblocksettings.conf.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 10:48:25 -03:00