fix: strictly enforce IP restriction, fix empty whitelist fallback, and update SW to v2
This commit is contained in:
parent
1bd8f57371
commit
5219b8bfc6
|
|
@ -875,12 +875,17 @@ class DoctorApi extends BaseController
|
|||
if (! $this->isQueueAccessAllowed()) {
|
||||
return $this->response
|
||||
->setStatusCode(403)
|
||||
->setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0')
|
||||
->setHeader('Pragma', 'no-cache')
|
||||
->setBody($this->renderQueueAccessDeniedHtml());
|
||||
}
|
||||
|
||||
$pwaPath = FCPATH . 'App/Queue/index.html';
|
||||
if (file_exists($pwaPath)) {
|
||||
return $this->response->setBody(file_get_contents($pwaPath));
|
||||
return $this->response
|
||||
->setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0')
|
||||
->setHeader('Pragma', 'no-cache')
|
||||
->setBody(file_get_contents($pwaPath));
|
||||
}
|
||||
|
||||
return redirect()->to(base_url('app'));
|
||||
|
|
@ -894,6 +899,7 @@ class DoctorApi extends BaseController
|
|||
$swPath = FCPATH . 'App/Queue/sw.js';
|
||||
if (file_exists($swPath)) {
|
||||
return $this->response->setHeader('Content-Type', 'application/javascript')
|
||||
->setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0')
|
||||
->setHeader('Service-Worker-Allowed', '/')
|
||||
->setBody(file_get_contents($swPath));
|
||||
}
|
||||
|
|
@ -908,6 +914,7 @@ class DoctorApi extends BaseController
|
|||
$manifestPath = FCPATH . 'App/Queue/manifest.json';
|
||||
if (file_exists($manifestPath)) {
|
||||
return $this->response->setHeader('Content-Type', 'application/json')
|
||||
->setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0')
|
||||
->setBody(file_get_contents($manifestPath));
|
||||
}
|
||||
return $this->response->setStatusCode(404);
|
||||
|
|
@ -915,18 +922,10 @@ class DoctorApi extends BaseController
|
|||
|
||||
/**
|
||||
* Verifies if the incoming request is authorized to access the OPD TV Queue Display / API.
|
||||
* Access is allowed if:
|
||||
* 1. User has an active authenticated HMS session (CodeIgniter Shield / user_id)
|
||||
* 2. TV_QUEUE_IP_RESTRICTION_ENABLED setting is set to '0' (disabled)
|
||||
* 3. Request origin matches allowed IPs/subnets (TV_QUEUE_ALLOWED_IPS)
|
||||
* When TV_QUEUE_IP_RESTRICTION_ENABLED is '1', only allowed IPs/subnets can access.
|
||||
*/
|
||||
private function isQueueAccessAllowed(): bool
|
||||
{
|
||||
// 1. Logged in staff / administrator can always view
|
||||
if ((function_exists('auth') && auth()->loggedIn()) || (session()->has('user_id') && (int) session()->get('user_id') > 0)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$db = db_connect();
|
||||
$enabledRow = $db->table('hospital_setting')
|
||||
->select('s_value')
|
||||
|
|
@ -939,21 +938,26 @@ class DoctorApi extends BaseController
|
|||
return true;
|
||||
}
|
||||
|
||||
// 2. Resolve client IP
|
||||
// 1. Resolve client IP
|
||||
$clientIp = trim((string) $this->request->getIPAddress());
|
||||
if ($clientIp === '' || $clientIp === '0.0.0.0') {
|
||||
$clientIp = trim((string) ($_SERVER['REMOTE_ADDR'] ?? '127.0.0.1'));
|
||||
}
|
||||
|
||||
// 3. Fetch allowed IP rules
|
||||
// 2. Fetch allowed IP rules
|
||||
$allowedRow = $db->table('hospital_setting')
|
||||
->select('s_value')
|
||||
->where('s_name', 'TV_QUEUE_ALLOWED_IPS')
|
||||
->get(1)
|
||||
->getRowArray();
|
||||
|
||||
$defaultAllowed = "127.0.0.1\n::1\n10.*\n192.168.*\n172.16.*\n103.251.140.182";
|
||||
$allowedIpsRaw = !empty($allowedRow['s_value']) ? (string) $allowedRow['s_value'] : $defaultAllowed;
|
||||
// If setting exists in DB (even if empty because user deleted all IPs), respect it!
|
||||
// Only if setting was never saved in DB, use default list.
|
||||
if ($allowedRow !== null) {
|
||||
$allowedIpsRaw = (string) $allowedRow['s_value'];
|
||||
} else {
|
||||
$allowedIpsRaw = "127.0.0.1\n::1\n10.*\n192.168.*\n172.16.*\n103.251.140.182";
|
||||
}
|
||||
|
||||
$rules = preg_split('/[\r\n,]+/', $allowedIpsRaw, -1, PREG_SPLIT_NO_EMPTY);
|
||||
foreach ($rules as $rule) {
|
||||
|
|
|
|||
|
|
@ -509,7 +509,8 @@
|
|||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', '/api/v1/opd/queue/live', true);
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState === 4 && xhr.status === 200) {
|
||||
if (xhr.readyState === 4) {
|
||||
if (xhr.status === 200) {
|
||||
try {
|
||||
var json = JSON.parse(xhr.responseText);
|
||||
if (json.status === 1) {
|
||||
|
|
@ -545,6 +546,12 @@
|
|||
} catch (e) {
|
||||
console.log('JSON parse error');
|
||||
}
|
||||
} else if (xhr.status === 403) {
|
||||
// Access forbidden: wipe sensitive data and reload to show 403 screen
|
||||
trackersData = [];
|
||||
adsData = [];
|
||||
window.location.reload();
|
||||
}
|
||||
}
|
||||
};
|
||||
xhr.send();
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
const CACHE_NAME = 'hms-opd-queue-v1';
|
||||
const CACHE_NAME = 'hms-opd-queue-v2';
|
||||
const ASSETS_TO_CACHE = [
|
||||
'/app/queue',
|
||||
'/App/Queue/index.html',
|
||||
'/App/Queue/manifest.json',
|
||||
'/assets/img/logo.png',
|
||||
'/assets/img/pwa-icon-512.png',
|
||||
|
|
@ -35,8 +33,8 @@ self.addEventListener('activate', (event) => {
|
|||
});
|
||||
|
||||
self.addEventListener('fetch', (event) => {
|
||||
// API endpoints always fetch fresh network data
|
||||
if (event.request.url.includes('/api/v1/')) {
|
||||
// Navigation requests (HTML documents) and API endpoints must always go straight to network
|
||||
if (event.request.mode === 'navigate' || event.request.url.includes('/api/v1/') || event.request.url.includes('/app/queue')) {
|
||||
event.respondWith(fetch(event.request));
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user