403Webshell
Server IP : 54.37.205.81  /  Your IP : 216.73.216.76
Web Server : nginx/1.22.1
System : Linux vps-249481fa 6.1.0-50-cloud-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.176-1 (2026-07-02) x86_64
User : debian ( 1000)
PHP Version : 8.2.32
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF  |  Sudo : ON  |  Pkexec : OFF
Directory :  /opt/ccp-ai-gateway/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /opt/ccp-ai-gateway/ots_notify_worker.py
#!/usr/bin/env python3
import json
import os
import re
import smtplib
import subprocess
import tempfile
from datetime import datetime, timezone
from email.message import EmailMessage
from pathlib import Path

BASE = Path("/opt/ccp-ai-gateway")
DATA = BASE / "data"
CERT_LOG = DATA / "cert_usage.jsonl"
USERS_FILE = DATA / "users.json"
WORKER_LOG = DATA / "ots_notify_worker.log"
OTS_BIN = os.environ.get("OTS_BIN", "/home/debian/.local/bin/ots")
ENV_FILES = [BASE / ".env", Path("/etc/ccp-ai-gateway/ccp-ai-gateway.env")]

def now_iso():
    return datetime.now(timezone.utc).isoformat()

def log(msg):
    line = f"[{now_iso()}] {msg}"
    print(line)
    try:
        with open(WORKER_LOG, "a", encoding="utf-8") as f:
            f.write(line + "\n")
    except Exception:
        pass

def load_env():
    for path in ENV_FILES:
        if not path.exists():
            continue
        try:
            for line in path.read_text(encoding="utf-8").splitlines():
                line = line.strip()
                if not line or line.startswith("#") or "=" not in line:
                    continue
                k, v = line.split("=", 1)
                if k.strip() and k.strip() not in os.environ:
                    os.environ[k.strip()] = v.strip().strip('"').strip("'")
        except Exception as e:
            log(f"env read failed {path}: {e}")

def load_users():
    try:
        data = json.loads(USERS_FILE.read_text(encoding="utf-8"))
        return {str(u.get("id", "")): u for u in data.get("users", []) if u.get("id")}
    except Exception:
        return {}

def load_rows():
    rows = []
    if not CERT_LOG.exists():
        return rows
    with open(CERT_LOG, "r", encoding="utf-8") as f:
        for line in f:
            try:
                rows.append(json.loads(line))
            except Exception:
                continue
    return rows

def save_rows(rows):
    fd, tmp = tempfile.mkstemp(prefix="cert_usage.", suffix=".jsonl", dir=str(DATA))
    os.close(fd)
    with open(tmp, "w", encoding="utf-8") as f:
        for row in rows:
            f.write(json.dumps(row, ensure_ascii=False) + "\n")
    os.replace(tmp, CERT_LOG)

def run_cmd(args, timeout=180):
    try:
        p = subprocess.run(args, capture_output=True, text=True, timeout=timeout)
        return p.returncode, (p.stdout or "") + (p.stderr or "")
    except Exception as e:
        return 1, str(e)

def parse_confirmed(output):
    txt = output or ""
    low = txt.lower()
    if "pending confirmation in bitcoin blockchain" in low:
        return False, "", None
    if "bitcoin block" not in low and "success" not in low:
        return False, "", None

    block_height = None
    for pat in [r"bitcoin block\s+(\d+)", r"block height[:\s]+(\d+)", r"block[:\s]+(\d+)"]:
        m = re.search(pat, txt, re.I)
        if m:
            try:
                block_height = int(m.group(1))
                break
            except Exception:
                pass

    txid = ""
    m = re.search(r"\b([a-fA-F0-9]{64})\b", txt)
    if m:
        txid = m.group(1)

    return True, txid, block_height

def smtp_ready():
    return all(os.environ.get(k) for k in ["SMTP_HOST", "SMTP_PORT", "SMTP_USER", "SMTP_PASSWORD", "SMTP_FROM"])

def send_email(row, user):
    if not smtp_ready():
        log(f"SMTP not configured; email skipped for {row.get('cert_id')}")
        return False

    to_email = str(user.get("email", "") or "").strip()
    if not to_email or "@" not in to_email:
        log(f"missing user email for {row.get('cert_id')}")
        return False

    cert_id = str(row.get("cert_id", "") or "").strip()
    title = str(row.get("original_filename", "") or "").strip() or cert_id
    verify_url = str(row.get("verify_url", "") or "").strip()
    confirmed_at = str(row.get("confirmed_at", "") or "").strip() or now_iso()

    msg = EmailMessage()
    msg["Subject"] = f"Aggiornamento certificato CopyrightChain {cert_id}"
    msg["From"] = os.environ["SMTP_FROM"]
    msg["To"] = to_email
    msg.set_content(f"""Gentile cliente,

il tuo certificato CopyrightChain รจ stato aggiornato.

ID certificato: {cert_id}
Opera / file: {title}
Stato: confermato
Data aggiornamento: {confirmed_at}

Verifica pubblica:
{verify_url}

La pagina di verifica pubblica mostra i riferimenti tecnici aggiornati del certificato.

CopyrightChain
Certificazione digitale verificabile
""")

    host = os.environ["SMTP_HOST"]
    port = int(os.environ.get("SMTP_PORT", "465"))
    smtp_user = os.environ["SMTP_USER"]
    smtp_pass = os.environ["SMTP_PASSWORD"]
    use_ssl = str(os.environ.get("SMTP_SSL", "")).lower() in ("1", "true", "yes", "on")

    if use_ssl:
        with smtplib.SMTP_SSL(host, port, timeout=30) as s:
            s.login(smtp_user, smtp_pass)
            s.send_message(msg)
    else:
        with smtplib.SMTP(host, port, timeout=30) as s:
            s.starttls()
            s.login(smtp_user, smtp_pass)
            s.send_message(msg)

    log(f"email sent to {to_email} for {cert_id}")
    return True

def main():
    load_env()
    users = load_users()
    rows = load_rows()
    changed = False

    for row in rows:
        if str(row.get("cert_type", "")).lower() != "blockchain":
            continue

        cert_id = str(row.get("cert_id", "") or "").strip()
        status = str(row.get("blockchain_status", "") or "").strip().lower()

        if status == "confirmed" and row.get("blockchain_email_sent_at"):
            continue

        proof = str(row.get("ots_path", "") or "").strip()
        manifest = str(row.get("ots_manifest_path", "") or "").strip()

        if not proof or not manifest or not os.path.exists(proof) or not os.path.exists(manifest):
            continue

        if status == "confirmed" and not row.get("blockchain_email_sent_at"):
            user = users.get(str(row.get("user_id", "")), {})
            if send_email(row, user):
                row["blockchain_email_sent_at"] = now_iso()
                changed = True
            continue

        log(f"checking {cert_id}")

        _, out_up = run_cmd([OTS_BIN, "upgrade", proof])
        row["ots_last_upgrade_at"] = now_iso()

        _, out_verify = run_cmd([OTS_BIN, "verify", proof, "-f", manifest])
        confirmed, txid, block_height = parse_confirmed(out_up + "\n" + out_verify)

        if not confirmed:
            log(f"{cert_id}: still pending")
            changed = True
            continue

        row["blockchain_status"] = "confirmed"
        row["confirmed_at"] = row.get("confirmed_at") or now_iso()
        row["anchored_at"] = row.get("anchored_at") or row["confirmed_at"]

        if txid:
            row["btc_txid"] = txid
        if block_height is not None:
            row["btc_block_height"] = block_height

        user = users.get(str(row.get("user_id", "")), {})
        if not row.get("blockchain_email_sent_at"):
            if send_email(row, user):
                row["blockchain_email_sent_at"] = now_iso()
            else:
                row["blockchain_email_pending"] = True

        log(f"{cert_id}: confirmed")
        changed = True

    if changed:
        save_rows(rows)
        log("cert_usage.jsonl updated")
    else:
        log("no changes")

if __name__ == "__main__":
    main()

Youez - 2016 - github.com/yon3zu
LinuXploit