v2.4.0 — internationalization (EN/RU) + custom git templates

- i18n engine (lib/i18n.sh, lib/lang/en.sh, lib/lang/ru.sh)
- first-run language picker, persisted to .language + config.json
- install.sh, common.sh, backup.sh, templates_catalog.sh wired through t()/tf()
- backup.sh preserves .language marker and records language in metadata.json
- custom git template feature (first item in pro template picker)
  * validates HTTPS URLs, rejects shell metachars
  * 100MB size guard, 90s clone timeout
  * auto-detects index.html in dist/public/build/_site/site/docs/out/www
- bot v2.4.0: i18n.py + lang/{en,ru}.json, /lang command, language toggle button
- bot: custom git template via text input with waiter gating
This commit is contained in:
anten-ka
2026-04-10 11:41:23 +03:00
parent 194fb32fec
commit 3495ab5b0f

View File

@@ -886,11 +886,21 @@ def _validate_custom_git_url(url: str) -> bool:
if not url or len(url) > 512:
return False
# Block shell metacharacters explicitly
for bad in (" ", "`", "$", "(", ")", "<", ">", "|", "\\", "\t", "\n", "\r", ";", "&"):
for bad in (" ", "`", "$", "(", ")", "<", ">", "|", "\\", "\t", "\n", "\r", ";", "&", "'", '"'):
if bad in url:
return False
if not url.lower().startswith("https://"):
return False
# Reject embedded userinfo (https://user:pass@host/...) to prevent credential leakage.
# We look at the netloc — anything between https:// and the first '/'.
rest = url[len("https://"):]
netloc_end = rest.find("/")
netloc = rest if netloc_end == -1 else rest[:netloc_end]
if "@" in netloc:
return False
# Hostname sanity: no empty host, no whitespace already blocked above
if not netloc or netloc.startswith(":") or netloc.endswith(":"):
return False
return True