TorbatYar/scripts/fix_public_https_urls.py
Mortezakoohjani 12c8615615 Ship enterprise Accounting FE/API with CRUD parity and production wiring.
Adds accounting-service PATCH/archive, fiscal helpers, COA templates and setup status, plus SuperApp Accounting UI (DS, scoreboard, masters, vouchers, ledger, ops modules) with session refresh and HTTPS public API URLs.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-24 15:26:43 +03:30

134 lines
4.8 KiB
Python

#!/usr/bin/env python3
"""Diagnose and fix NEXT_PUBLIC_* URLs to HTTPS on production."""
from __future__ import annotations
import base64
import paramiko
APP_HOST, APP_USER, APP_PASS = "192.168.10.162", "morteza", "Moli@5404"
NGX_HOST, NGX_USER, NGX_PASS = "192.168.10.156", "torbatyaruser", "Moli@5404"
REMOTE = "/home/morteza/torbatyar"
HTTPS_KEYS = {
"NEXT_PUBLIC_BACKEND_URL": "https://api.torbatyar.ir",
"NEXT_PUBLIC_API_BASE_URL": "https://api.torbatyar.ir",
"NEXT_PUBLIC_IDENTITY_API_URL": "https://identity.torbatyar.ir",
"NEXT_PUBLIC_KEYCLOAK_URL": "https://auth.torbatyar.ir",
"NEXT_PUBLIC_ACCOUNTING_API_URL": "https://accounting.torbatyar.ir",
"KEYCLOAK_PUBLIC_URL": "https://auth.torbatyar.ir",
"FRONTEND_CALLBACK_URL": "https://torbatyar.ir/auth/callback",
}
def connect(host, user, password):
c = paramiko.SSHClient()
c.set_missing_host_key_policy(paramiko.AutoAddPolicy())
c.connect(host, username=user, password=password, timeout=30, allow_agent=False, look_for_keys=False)
return c
def run(c, cmd, password=None, timeout=600):
b64 = base64.b64encode(cmd.encode()).decode()
if password:
full = f"echo {password!r} | sudo -S -p '' bash -c 'echo {b64} | base64 -d | bash'"
else:
full = f"bash -lc 'echo {b64} | base64 -d | bash'"
print("\n>>>", cmd[:200].replace("\n", " | "))
_, out, err = c.exec_command(full, timeout=timeout, get_pty=True)
text = (out.read() + err.read()).decode("utf-8", "replace")
code = out.channel.recv_exit_status()
print(text[-5000:].encode("ascii", "replace").decode("ascii"))
return code, text
def main() -> int:
# Public smoke first
ngx = connect(NGX_HOST, NGX_USER, NGX_PASS)
try:
run(
ngx,
"""
echo === identity https ===
curl -sI https://identity.torbatyar.ir/health | head -n 12 || true
curl -s https://identity.torbatyar.ir/health || curl -sk https://identity.torbatyar.ir/health || echo FAIL
echo
echo === identity http ===
curl -sI http://identity.torbatyar.ir/health | head -n 12 || true
""",
password=NGX_PASS,
timeout=60,
)
finally:
ngx.close()
app = connect(APP_HOST, APP_USER, APP_PASS)
try:
keys_repr = repr(HTTPS_KEYS)
code, _ = run(
app,
f"""
set -e
cd {REMOTE}
echo === BEFORE ===
grep -E 'NEXT_PUBLIC_|KEYCLOAK_PUBLIC_URL|FRONTEND_CALLBACK' .env || true
python3 - <<'PY'
from pathlib import Path
p = Path('.env')
text = p.read_text(encoding='utf-8') if p.exists() else ''
keys = {keys_repr}
lines = text.splitlines()
seen = set()
out = []
for line in lines:
if not line.strip() or line.lstrip().startswith('#') or '=' not in line:
out.append(line)
continue
k = line.split('=', 1)[0].strip()
if k in keys:
out.append(f'{{k}}={{keys[k]}}')
seen.add(k)
else:
# also rewrite accidental http://*.torbatyar.ir public URLs
if k.startswith('NEXT_PUBLIC_') or k in ('KEYCLOAK_PUBLIC_URL', 'FRONTEND_CALLBACK_URL', 'CORS_ORIGINS'):
v = line.split('=', 1)[1]
v2 = v.replace('http://api.torbatyar.ir', 'https://api.torbatyar.ir') \\
.replace('http://identity.torbatyar.ir', 'https://identity.torbatyar.ir') \\
.replace('http://auth.torbatyar.ir', 'https://auth.torbatyar.ir') \\
.replace('http://torbatyar.ir', 'https://torbatyar.ir') \\
.replace('http://www.torbatyar.ir', 'https://www.torbatyar.ir') \\
.replace('http://accounting.torbatyar.ir', 'https://accounting.torbatyar.ir')
out.append(f'{{k}}={{v2}}')
seen.add(k)
continue
out.append(line)
for k, v in keys.items():
if k not in seen:
out.append(f'{{k}}={{v}}')
p.write_text('\\n'.join(out).rstrip() + '\\n', encoding='utf-8')
print('env_patched')
PY
echo === AFTER ===
grep -E 'NEXT_PUBLIC_|KEYCLOAK_PUBLIC_URL|FRONTEND_CALLBACK' .env || true
# recreate frontend so Next picks new NEXT_PUBLIC_* at process start
docker compose up -d --force-recreate frontend identity-access-service
sleep 10
docker compose exec -T frontend printenv | grep -E 'NEXT_PUBLIC_IDENTITY|NEXT_PUBLIC_BACKEND|NEXT_PUBLIC_KEYCLOAK|NEXT_PUBLIC_ACCOUNTING' || true
docker compose ps frontend identity-access-service
curl -sf http://127.0.0.1:8001/health || echo IDENTITY_LOCAL_FAIL
echo
curl -s -o /dev/null -w 'accounting_page=%{{http_code}}\\n' http://127.0.0.1:3000/accounting
""",
password=APP_PASS,
timeout=300,
)
if code != 0:
raise RuntimeError("fix failed")
finally:
app.close()
print("\n=== DONE ===")
return 0
if __name__ == "__main__":
raise SystemExit(main())