<?php
declare(strict_types=1);
function out($code,$body=''){http_response_code($code);if($body!==''){header('Content-Type: text/plain; charset=utf-8');echo $body;}exit;}
$cf=__DIR__.'/config.php';if(!is_file($cf))out(503,'Relay not configured');$c=require $cf;if(!is_array($c))out(500,'Invalid config');
if($_SERVER['REQUEST_METHOD']==='GET'){$mode=(string)($_GET['hub_mode']??$_GET['hub.mode']??'');$token=(string)($_GET['hub_verify_token']??$_GET['hub.verify_token']??'');$challenge=(string)($_GET['hub_challenge']??$_GET['hub.challenge']??'');if($mode==='subscribe'&&$token!==''&&hash_equals((string)($c['whatsapp_verify_token']??''),$token))out(200,$challenge);out(403,'Verification failed');}
if($_SERVER['REQUEST_METHOD']!=='POST')out(405,'POST required');
$raw=file_get_contents('php://input');if(!is_string($raw)||$raw==='')out(200,'OK');$secret=(string)($c['whatsapp_app_secret']??'');if($secret==='')out(503,'Meta App Secret required');$got=(string)($_SERVER['HTTP_X_HUB_SIGNATURE_256']??'');$want='sha256='.hash_hmac('sha256',$raw,$secret);if($got===''||!hash_equals($want,$got))out(403,'Invalid Meta signature');
function wa_media_node($raw){$j=json_decode($raw,true);if(!is_array($j))return null;foreach((array)($j['entry']??[]) as $e)foreach((array)($e['changes']??[]) as $ch)foreach((array)(($ch['value']??[])['messages']??[]) as $m){$t=(string)($m['type']??'');if(in_array($t,['image','audio','video','document'],true)&&!empty($m[$t]['id']))return ['id'=>(string)$m[$t]['id'],'type'=>$t,'name'=>(string)($m[$t]['filename']??('whatsapp-'.$t)),'mime'=>(string)($m[$t]['mime_type']??'application/octet-stream')];}return null;}
function wa_get($c,$url){$ch=curl_init($url);curl_setopt_array($ch,[CURLOPT_RETURNTRANSFER=>true,CURLOPT_CONNECTTIMEOUT=>8,CURLOPT_TIMEOUT=>25,CURLOPT_IPRESOLVE=>CURL_IPRESOLVE_V4,CURLOPT_HTTP_VERSION=>CURL_HTTP_VERSION_1_1,CURLOPT_HTTPHEADER=>['Authorization: Bearer '.(string)$c['whatsapp_access_token']]]);$body=curl_exec($ch);$err=curl_error($ch);$code=(int)curl_getinfo($ch,CURLINFO_HTTP_CODE);curl_close($ch);return [$body,$err,$code];}
function download_media($c,$d){$ver=(string)($c['whatsapp_graph_version']??'v26.0');[$meta,$err,$code]=wa_get($c,'https://graph.facebook.com/'.$ver.'/'.rawurlencode($d['id']));$j=is_string($meta)?json_decode($meta,true):null;if($err!==''||$code<200||$code>=300||!is_array($j)||empty($j['url']))return null;if((int)($j['file_size']??0)>8*1024*1024)return null;[$bytes,$err,$code]=wa_get($c,(string)$j['url']);if($err!==''||$code!==200||!is_string($bytes)||strlen($bytes)>8*1024*1024)return null;return [$bytes,$d['name'],$d['mime']?:($j['mime_type']??'application/octet-stream')];}
function mp_body($raw,$media,&$ctype){$b='----MesoraWA'.bin2hex(random_bytes(12));$e="\r\n";$name=preg_replace('/[^A-Za-z0-9._-]/','_',basename($media[1]));$body='--'.$b.$e.'Content-Disposition: form-data; name="update_json"; filename="update.json"'.$e.'Content-Type: application/json'.$e.$e.$raw.$e.'--'.$b.$e.'Content-Disposition: form-data; name="media"; filename="'.$name.'"'.$e.'Content-Type: '.$media[2].$e.$e.$media[0].$e.'--'.$b.'--'.$e;$ctype='multipart/form-data; boundary='.$b;return $body;}
$d=wa_media_node($raw);$media=$d?download_media($c,$d):null;$ts=(string)time();$headers=['X-Mesora-Provider: whatsapp','X-Mesora-Site: '.(string)$c['site_id'],'X-Mesora-Timestamp: '.$ts,'Expect:'];if($media){$sig=hash_hmac('sha256',$ts.'.WHATSAPP.MEDIA.'.hash('sha256',$raw).'.'.hash('sha256',$media[0]),(string)$c['shared_secret']);$ctype='';$post=mp_body($raw,$media,$ctype);$headers[]='X-Mesora-Media: 1';$headers[]='Content-Type: '.$ctype;}else{$sig=hash_hmac('sha256',$ts.'.WHATSAPP.'.$raw,(string)$c['shared_secret']);$post=$raw;$headers[]='Content-Type: application/json';}$headers[]='X-Mesora-Signature: '.$sig;$url=(string)($c['whatsapp_wordpress_url']??'');if($url==='')out(503,'WordPress WhatsApp URL missing');$ch=curl_init($url);curl_setopt_array($ch,[CURLOPT_POST=>true,CURLOPT_POSTFIELDS=>$post,CURLOPT_RETURNTRANSFER=>true,CURLOPT_CONNECTTIMEOUT=>8,CURLOPT_TIMEOUT=>25,CURLOPT_HTTPHEADER=>$headers,CURLOPT_IPRESOLVE=>CURL_IPRESOLVE_V4,CURLOPT_HTTP_VERSION=>CURL_HTTP_VERSION_1_1]);$body=curl_exec($ch);$err=curl_error($ch);$code=(int)curl_getinfo($ch,CURLINFO_HTTP_CODE);curl_close($ch);if($err!==''||$code<200||$code>=300)out(502,'WordPress forward failed');out(200,'OK');
