From 404bfc49729d2a109291036861c4a907857271e6 Mon Sep 17 00:00:00 2001 From: ht Date: Sun, 6 Sep 2026 18:25:05 +0300 Subject: [PATCH] restrict browser permissions on API responses --- docs/quality/uygulama-durumu.md | 6 ++++++ server/index.js | 1 + tests/http-state.test.mjs | 1 + 3 files changed, 8 insertions(+) diff --git a/docs/quality/uygulama-durumu.md b/docs/quality/uygulama-durumu.md index d6c1cfd..2011e32 100644 --- a/docs/quality/uygulama-durumu.md +++ b/docs/quality/uygulama-durumu.md @@ -2064,3 +2064,9 @@ Doğrulama: 289 test geçti, browser QA script sözdizimi kontrolü başarılı, Yerel sentetik QA sunucusu başlatıldı; Playwright ile giriş sayfası 200 döndü, test hesabıyla ana uygulamaya geçildi ve Giresun, Kayseri, Akdeniz, Aksaray ve Tepecik kayıtlarının tümü ekranda doğrulandı. Kanıt [`qa-browser-five-tenders-runtime.json`](evidence/qa-browser-five-tenders-runtime.json) içinde tutuluyor; resmi kabul yerine geçmez. Doğrulama: browser çalışma zamanı kontrolü başarılı, 289 otomatik test geçmiş durumda. + +### 2026-09-06 · API Permissions-Policy başlığı + +API JSON yanıtlarına kamera, mikrofon ve konum izinlerini kapatan `Permissions-Policy` başlığı eklendi; uygulamanın kullanmadığı tarayıcı yetkileri varsayılan olarak sınırlandırıldı ve HTTP testiyle doğrulandı. + +Doğrulama: 289 test geçti, üretim derlemesi başarılı. diff --git a/server/index.js b/server/index.js index 7daaf36..945de38 100644 --- a/server/index.js +++ b/server/index.js @@ -627,6 +627,7 @@ function json(res, code, body) { 'Cache-Control': 'no-store', 'X-Content-Type-Options': 'nosniff', 'Referrer-Policy': 'no-referrer', + 'Permissions-Policy': 'camera=(), microphone=(), geolocation=()', }; const origin = res.__ihaleistCorsOrigin; if (CORS_ORIGINS.length) headers.Vary = 'Origin'; diff --git a/tests/http-state.test.mjs b/tests/http-state.test.mjs index 6e62422..df67706 100644 --- a/tests/http-state.test.mjs +++ b/tests/http-state.test.mjs @@ -37,6 +37,7 @@ test('HTTP preparation requires auth, persists draft and rejects stale revisions assert.equal(unauthorized.status,401); assert.equal(unauthorized.headers.get('x-content-type-options'),'nosniff'); assert.equal(unauthorized.headers.get('referrer-policy'),'no-referrer'); + assert.equal(unauthorized.headers.get('permissions-policy'),'camera=(), microphone=(), geolocation=()'); assert.equal(unauthorized.headers.get('vary'),'Origin'); const draft={firma:{firmaUnvan:'QA Laboratuvar'},priceSchema:1,pricesBySource:{kit1:'12.50'},gecerlilikGun:'120',checks:{products:{kit1:{product:'Test kit',status:'suitable',source:'Teknik 3.2'}},documents:{doc1:{status:'verified',evidence:'Test v1'}}},manualDocuments:[{document:'Yetki',note:'7.1',mandatory:true}],analysisSource:{itemsAndSpecs:[{name:'Kit',quantity:'2 adet'}],documentChecklist:[]}}; const data={key:'2026/1582991',patch:{takipte:true,gorev:{kontrolListesi:[]},bidDraft:draft,checklist:[{key:'collect-documents',sourceSnapshot:'source-v1',done:true}]},snapshot:{id:'ilan-qa',ikn:'2026/1582991'},version:0};