# Python 3 receiver. Put behind your HTTPS reverse proxy; never print raw payloads. import os, json, time, hmac, hashlib, re, sqlite3 from http.server import BaseHTTPRequestHandler, HTTPServer SECRET=os.environ['TURBOPULSA_WEBHOOK_SECRET'].encode() DB=os.environ.get('TURBOPULSA_WEBHOOK_DB','turbopulsa-webhook.sqlite') with sqlite3.connect(DB) as c: c.executescript('CREATE TABLE IF NOT EXISTS events(id TEXT PRIMARY KEY); CREATE TABLE IF NOT EXISTS orders(id TEXT PRIMARY KEY, version INTEGER NOT NULL, status TEXT NOT NULL, client_reference TEXT NOT NULL);') def verify(raw, signature): m=re.fullmatch(r't=(\d+),v1=([a-f0-9]{64})',signature or '') if not m or abs(time.time()-int(m[1]))>300: return False expected=hmac.new(SECRET,m[1].encode()+b'.'+raw,hashlib.sha256).hexdigest() return hmac.compare_digest(expected,m[2]) def apply(event): d=event.get('data',{}) if event.get('type')!='order.status_changed' or not re.fullmatch(r'[-a-f0-9]{36}',event.get('id','')) or not re.fullmatch(r'[-a-f0-9]{36}',d.get('id','')) or not isinstance(d.get('version'),int) or d['version']<1: return False with sqlite3.connect(DB) as c: c.execute('BEGIN IMMEDIATE') if c.execute('SELECT id FROM events WHERE id=?',(event['id'],)).fetchone(): return True c.execute('INSERT INTO events(id) VALUES(?)',(event['id'],)) c.execute('INSERT INTO orders(id,version,status,client_reference) VALUES(?,?,?,?) ON CONFLICT(id) DO UPDATE SET version=excluded.version,status=excluded.status,client_reference=excluded.client_reference WHERE excluded.version>orders.version',(d['id'],d['version'],d['status'],d['client_reference'])) return True class Handler(BaseHTTPRequestHandler): def log_message(self,*args): pass def do_POST(self): if self.path!='/webhooks/turbopulsa': self.send_error(404); return size=int(self.headers.get('Content-Length',0)) if not 0