<!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>BLUE CORNER v2.8 Security Test</title><style>body{font:16px system-ui;max-width:720px;margin:auto;padding:20px;background:#f4f7fb}.c{background:#fff;padding:18px;margin:12px 0;border-radius:14px}input,button{box-sizing:border-box;width:100%;padding:12px;margin:5px 0;border-radius:10px}button{background:#1268b3;color:#fff;border:0;font-weight:700}.ok{color:#087a45}.bad{color:#a92727}pre{white-space:pre-wrap;background:#102033;color:#fff;padding:12px;border-radius:10px}</style></head><body><h1>BLUE CORNER — v2.8</h1><div class=c><input id=e placeholder="Email"><input id=p type=password placeholder="Password"><button onclick="login()">Sign in</button><div id=s>ຍังບໍ່ໄດ້ Login</div></div><div class=c><button onclick="t10()">Test 10 — Barista → Manager API</button><span id=r10></span><p>ຕ້ອງໄດ້ HTTP 403 ຈາກ server-side Manager authorization</p><button onclick="t11()">Test 11 — Staff identity spoof</button><span id=r11></span></div><div class=c><pre id=l>ພ້ອມທົດສອບ</pre></div><script>const U='https://fkqqhjsghpjbkmnikoyk.supabase.co',K='sb_publishable_V3Gnuq_UdW7ocNaCgLjClg_ongvO0p3',A=U+'/functions/v1/blue-corner-api',S='7ae2102b-eb94-4ab8-8b90-273167d06530';let tok=null;const $=x=>document.getElementById(x),log=x=>$('l').textContent+='\n'+x;async function login(){try{let r=await fetch(U+'/auth/v1/token?grant_type=password',{method:'POST',headers:{apikey:K,'Content-Type':'application/json'},body:JSON.stringify({email:$('e').value,password:$('p').value})}),j=await r.json();if(!r.ok)throw Error(j.error_description||j.msg||r.status);tok=j.access_token;$('s').textContent='Real Auth: SIGNED IN';$('s').className='ok';log('Login ສຳເລັດ')}catch(x){$('s').textContent='Login ບໍ່ສຳເລັດ: '+x.message;$('s').className='bad'}}async function t10(){let o=$('r10');o.textContent=' ⏳';if(!tok){o.textContent=' ❌ Login ກ່ອນ';return}try{let r=await fetch(A+'/staff/operations/overview?store_id='+S,{headers:{apikey:K,Authorization:'Bearer '+tok}});if(r.status===403){o.textContent=' ✅ PASS (403)';o.className='ok';log('TEST 10 PASS: Barista blocked by server-side Manager authorization')}else{o.textContent=' ❌ FAIL ('+r.status+')';o.className='bad';log('TEST 10 FAIL: expected 403, got '+r.status)}}catch(x){o.textContent=' ❌ ERROR';log('TEST 10 ERROR: '+x.message)}}async function t11(){let o=$('r11');o.textContent=' ⏳';if(!tok){o.textContent=' ❌ Login ກ່ອນ';return}try{let r=await fetch(A+'/staff/me?staff_id=00000000-0000-0000-0000-000000000999',{headers:{apikey:K,Authorization:'Bearer '+tok}}),j=await r.json(),id=j.data?.staff?.auth_user_id||j.data?.staff?.id;if(r.ok&&id!=='00000000-0000-0000-0000-000000000999'){o.textContent=' ✅ PASS';o.className='ok';log('TEST 11 PASS: client staff_id spoof ignored')}else if(r.status===401||r.status===403){o.textContent=' ✅ PASS ('+r.status+')';o.className='ok';log('TEST 11 PASS: identity spoof rejected')}else{o.textContent=' ❌ FAIL';o.className='bad';log('TEST 11 FAIL')}}catch(x){o.textContent=' ❌ ERROR';log('TEST 11 ERROR: '+x.message)}}</script></body></html>