From e579dd596cee09d809aaf087e5f30abc6317d0fe Mon Sep 17 00:00:00 2001 From: Thanakorn Date: Thu, 24 Sep 2026 14:30:22 +0700 Subject: [PATCH] Start every session through session.php; idle timeout, app access and auth status codes --- app/ac_dashboard/api/engine/by_source.php | 2 +- app/ac_dashboard/api/engine/journals.php | 2 +- app/ac_dashboard/api/engine/pl.php | 2 +- .../api/engine/posting_window.php | 2 +- app/ac_dashboard/api/engine/recent.php | 2 +- app/ac_dashboard/api/engine/trend.php | 2 +- app/ac_dashboard/index.php | 2 +- app/accounting/account_formulas.php | 2 +- app/accounting/api/engine/account.php | 2 +- app/accounting/api/engine/account_formula.php | 2 +- app/accounting/api/engine/account_stats.php | 2 +- app/accounting/api/engine/acquire_op_lock.php | 2 +- app/accounting/api/engine/department.php | 2 +- .../api/engine/department_stats.php | 2 +- .../api/engine/get_balance_sheet.php | 2 +- .../api/engine/get_gl_by_source.php | 2 +- .../api/engine/get_gl_documents.php | 2 +- app/accounting/api/engine/get_gl_movement.php | 2 +- .../api/engine/get_journal_detail.php | 2 +- .../api/engine/get_journal_listing.php | 2 +- .../api/engine/get_pl_statement.php | 2 +- .../api/engine/get_trial_balance.php | 2 +- app/accounting/api/engine/get_vat_report.php | 2 +- .../api/engine/log_batch_action.php | 2 +- app/accounting/api/engine/manage_account.php | 2 +- .../api/engine/manage_department.php | 2 +- app/accounting/api/engine/post_gl_entry.php | 2 +- app/accounting/api/engine/posting_window.php | 2 +- .../api/engine/product_account_mapping.php | 2 +- app/accounting/api/engine/release_op_lock.php | 2 +- app/accounting/api/engine/remove_account.php | 2 +- .../api/engine/remove_department.php | 2 +- .../api/engine/retrieve_account.php | 2 +- .../api/engine/retrieve_department.php | 2 +- .../api/engine/save_manual_journal.php | 2 +- app/accounting/balance_sheet.php | 2 +- app/accounting/chart_of_accounts.php | 2 +- app/accounting/departments.php | 2 +- app/accounting/gl_entries.php | 2 +- app/accounting/gl_movement.php | 2 +- app/accounting/journal_listing.php | 2 +- app/accounting/manage_account.php | 2 +- app/accounting/manage_department.php | 2 +- app/accounting/pl_statement.php | 2 +- app/accounting/posting_window.php | 2 +- app/accounting/trial_balance.php | 2 +- app/accounting/vat_report.php | 2 +- app/assets/js/custom.js | 11 ++++ app/assets/utils/app_access.php | 37 ++++++++++++++ app/assets/utils/db_auth.php | 34 +++++++++++-- app/contact/api/engine/contact.php | 2 +- app/contact/api/engine/contact_stats.php | 2 +- app/contact/api/engine/contact_type.php | 2 +- app/contact/api/engine/manage_contact.php | 2 +- .../api/engine/manage_contact_type.php | 2 +- app/contact/api/engine/remove_contact.php | 2 +- .../api/engine/remove_contact_type.php | 2 +- app/contact/api/engine/retrieve_contact.php | 2 +- .../api/engine/retrieve_contact_type.php | 2 +- app/contact/contact.php | 2 +- app/contact/manage_contact.php | 2 +- app/contact/manage_contact_type.php | 2 +- app/dashboard/api/engine_report/low_stock.php | 2 +- .../api/engine_report/reports_stats.php | 2 +- app/dashboard/index.php | 2 +- app/dashboard/low_stock_products.php | 2 +- .../api/engine/convert_purchase_request.php | 2 +- .../engine/delete_supplier_credit_note.php | 2 +- .../api/engine/manage_purchase_request.php | 2 +- .../engine/manage_supplier_credit_note.php | 2 +- .../api/engine/retrieve_purchase_request.php | 2 +- .../engine/update_purchase_request_status.php | 2 +- app/expense/manage_purchase_invoice.php | 2 +- app/expense/manage_purchase_order.php | 2 +- app/expense/manage_purchase_request.php | 2 +- app/expense/manage_supplier_credit_note.php | 2 +- app/expense/purchase_invoice.php | 2 +- app/expense/purchase_order.php | 2 +- app/expense/purchase_request.php | 2 +- app/finance/api/engine/delete_payment.php | 2 +- .../api/engine/delete_payment_billing.php | 2 +- app/finance/api/engine/delete_receipt.php | 2 +- .../api/engine/delete_receipt_billing.php | 2 +- app/finance/api/engine/manage_payment.php | 2 +- .../api/engine/manage_payment_billing.php | 2 +- app/finance/api/engine/manage_receipt.php | 2 +- .../api/engine/manage_receipt_billing.php | 2 +- app/finance/manage_payment.php | 2 +- app/finance/manage_payment_billing.php | 2 +- app/finance/manage_receipt.php | 2 +- app/finance/manage_receipt_billing.php | 2 +- app/finance/payment.php | 2 +- app/finance/payment_billing.php | 2 +- app/finance/receipt.php | 2 +- app/finance/receipt_billing.php | 2 +- app/ics/api/engine/approve_stock.php | 2 +- app/ics/api/engine/barcode_lookup.php | 2 +- app/ics/api/engine/contact_search.php | 2 +- app/ics/api/engine/delete_stock_in.php | 2 +- app/ics/api/engine/delete_stock_out.php | 2 +- app/ics/api/engine/delete_stock_transfer.php | 2 +- app/ics/api/engine/location_barcode_label.php | 2 +- app/ics/api/engine/manage_stock_in.php | 2 +- app/ics/api/engine/manage_stock_out.php | 2 +- app/ics/api/engine/manage_stock_transfer.php | 2 +- app/ics/api/engine/product_search.php | 2 +- app/ics/api/engine/retrieve_active_lot.php | 2 +- app/ics/api/engine/retrieve_active_serial.php | 2 +- app/ics/api/engine/retrieve_aisle.php | 2 +- app/ics/api/engine/retrieve_bin.php | 2 +- app/ics/api/engine/retrieve_bin_stock.php | 2 +- app/ics/api/engine/retrieve_lot.php | 2 +- .../api/engine/retrieve_stock_by_source.php | 2 +- app/ics/api/engine/retrieve_stock_in.php | 2 +- app/ics/api/engine/retrieve_stock_out.php | 2 +- .../api/engine/retrieve_stock_transfer.php | 2 +- app/ics/api/engine/retrieve_warehouse.php | 2 +- app/ics/api/engine/retrieve_zone.php | 2 +- app/ics/api/engine/sku_barcode_label.php | 2 +- app/ics/api/engine/sku_label_lots.php | 2 +- app/ics/api/engine/sku_label_products.php | 2 +- app/ics/api/engine/stock_in.php | 2 +- app/ics/api/engine/stock_out.php | 2 +- app/ics/api/engine/stock_transfer.php | 2 +- app/ics/api/engine/validate_scan_location.php | 2 +- app/ics/api/engine_report/product_stats.php | 2 +- app/ics/api/engine_report/stock_activity.php | 2 +- app/ics/api/engine_report/stock_movement.php | 2 +- app/ics/api/engine_report/stock_trend.php | 2 +- .../api/engine_report/warehouse_balance.php | 2 +- .../api/engine_report/warehouse_overview.php | 2 +- app/ics/api/engine_report/warehouse_stats.php | 2 +- app/ics/location_barcode_label.php | 2 +- app/ics/manage_stock_in.php | 2 +- app/ics/manage_stock_out.php | 2 +- app/ics/manage_stock_transfer.php | 2 +- app/ics/sku_barcode_label.php | 2 +- app/ics/stock_in.php | 2 +- app/ics/stock_out.php | 2 +- app/ics/stock_overview.php | 2 +- app/ics/stock_transfer.php | 2 +- app/include_topbar.php | 13 +++++ app/inventory/api/engine/manage_category.php | 2 +- app/inventory/api/engine/manage_product.php | 2 +- app/inventory/api/engine/manage_storage.php | 2 +- app/inventory/api/engine/manage_warehouse.php | 2 +- app/inventory/api/engine/manager.php | 2 +- app/inventory/api/engine/product.php | 2 +- app/inventory/api/engine/product_category.php | 2 +- app/inventory/api/engine/product_stats.php | 2 +- app/inventory/api/engine/remove_category.php | 2 +- app/inventory/api/engine/remove_product.php | 2 +- app/inventory/api/engine/remove_storage.php | 2 +- app/inventory/api/engine/remove_warehouse.php | 2 +- .../api/engine/retrieve_category.php | 2 +- app/inventory/api/engine/retrieve_product.php | 2 +- app/inventory/api/engine/retrieve_storage.php | 2 +- .../api/engine/retrieve_warehouse.php | 2 +- app/inventory/api/engine/storage.php | 2 +- app/inventory/api/engine/warehouse.php | 2 +- app/inventory/api/engine/warehouse_stats.php | 2 +- app/inventory/manage_category.php | 2 +- app/inventory/manage_product.php | 2 +- app/inventory/manage_storage.php | 2 +- app/inventory/manage_warehouse.php | 2 +- app/inventory/product.php | 2 +- app/inventory/warehouse.php | 2 +- app/journal/index.php | 2 +- app/journal/new.php | 2 +- app/login/api/engine/back.php | 3 +- app/order/api/engine/cancel_order.php | 2 +- app/order/api/engine/cancel_return.php | 2 +- app/order/api/engine/confirm_order.php | 2 +- app/order/api/engine/confirm_return.php | 2 +- app/order/api/engine/delete_invoice.php | 2 +- app/order/api/engine/delete_order.php | 2 +- app/order/api/engine/delete_return.php | 2 +- app/order/api/engine/issue_invoice.php | 2 +- app/order/api/engine/manage_invoice.php | 2 +- app/order/api/engine/manage_order.php | 2 +- app/order/api/engine/manage_return.php | 2 +- .../api/engine/proceed_to_credit_note.php | 2 +- app/order/api/engine/proceed_to_invoice.php | 2 +- app/order/api/engine/retrieve_invoice.php | 2 +- app/order/api/engine/retrieve_order.php | 2 +- app/order/api/engine/retrieve_return.php | 2 +- .../api/engine/update_invoice_status.php | 2 +- app/order/api/engine/update_order_status.php | 2 +- app/order/api/engine/void_invoice.php | 2 +- app/order/invoice.php | 2 +- app/order/manage_invoice.php | 2 +- app/order/manage_order.php | 2 +- app/order/manage_return.php | 2 +- app/order/order.php | 2 +- app/order/print_invoice.php | 2 +- app/order/return.php | 2 +- app/po/api/engine/cancel_po.php | 2 +- app/po/api/engine/cancel_supplier_return.php | 2 +- app/po/api/engine/close_po.php | 2 +- app/po/api/engine/confirm_po.php | 2 +- app/po/api/engine/confirm_supplier_return.php | 2 +- app/po/api/engine/delete_po.php | 2 +- app/po/api/engine/delete_purchase_request.php | 2 +- app/po/api/engine/delete_supplier_return.php | 2 +- app/po/api/engine/manage_po.php | 2 +- app/po/api/engine/manage_supplier_return.php | 2 +- .../engine/proceed_to_purchase_invoice.php | 2 +- .../proceed_to_supplier_credit_note.php | 2 +- app/po/api/engine/receive_po.php | 2 +- app/po/api/engine/retrieve_po.php | 2 +- .../api/engine/retrieve_supplier_return.php | 2 +- app/po/api/engine/update_po_payment.php | 2 +- app/po/invoice.php | 2 +- app/po/manage_po.php | 2 +- app/po/manage_purchase_invoice.php | 2 +- app/po/manage_supplier_return.php | 2 +- app/po/po.php | 2 +- app/po/supplier_returns.php | 2 +- app/reports/api/engine_report/bin_log.php | 2 +- .../api/engine_report/bin_occupancy.php | 2 +- .../api/engine_report/expired_stock.php | 2 +- .../api/engine_report/lot_stock_log.php | 2 +- app/reports/api/engine_report/product_lot.php | 2 +- .../api/engine_report/stock_movement.php | 2 +- .../api/engine_report/stock_movement_sku.php | 2 +- app/reports/expired_stock.php | 2 +- app/reports/occupy_rack.php | 2 +- app/reports/product_lot.php | 2 +- app/reports/stock_movement.php | 2 +- app/revenue/api/engine/convert_quotation.php | 2 +- app/revenue/api/engine/delete_credit_note.php | 2 +- app/revenue/api/engine/delete_quotation.php | 2 +- app/revenue/api/engine/manage_credit_note.php | 2 +- app/revenue/api/engine/manage_order.php | 2 +- app/revenue/api/engine/manage_quotation.php | 2 +- app/revenue/api/engine/proceed_to_invoice.php | 2 +- app/revenue/api/engine/quotation_stats.php | 2 +- app/revenue/api/engine/retrieve_quotation.php | 2 +- .../api/engine/update_quotation_status.php | 2 +- app/revenue/invoice.php | 2 +- app/revenue/manage_credit_note.php | 2 +- app/revenue/manage_invoice.php | 2 +- app/revenue/manage_order.php | 2 +- app/revenue/manage_quotation.php | 2 +- app/revenue/order.php | 2 +- app/revenue/quotation.php | 2 +- app/session.php | 51 ++++++++++++++++++- app/setting/api/engine/change_password.php | 2 +- app/setting/api/engine/company_setting.php | 2 +- app/setting/api/engine/document_types.php | 2 +- app/setting/api/engine/gl_maintenance.php | 2 +- app/setting/api/engine/manage_company.php | 2 +- app/setting/api/engine/manage_profile.php | 2 +- app/setting/api/engine/manage_smtp.php | 2 +- app/setting/api/engine/manage_users.php | 2 +- app/setting/api/engine/request_reset_otp.php | 2 +- app/setting/api/engine/reset_password_otp.php | 2 +- app/setting/api/engine/retrieve_company.php | 2 +- app/setting/api/engine/retrieve_profile.php | 2 +- app/setting/api/engine/retrieve_smtp.php | 2 +- app/setting/api/engine/retrieve_users.php | 2 +- app/setting/api/engine/search_users.php | 2 +- app/setting/api/engine/stock_maintenance.php | 2 +- app/setting/api/engine/switch_branch.php | 2 +- app/setting/api/engine/test_smtp.php | 2 +- app/setting/company.php | 2 +- app/setting/document_types.php | 2 +- app/setting/gl_maintenance.php | 2 +- app/setting/profile.php | 2 +- app/setting/smtp.php | 2 +- app/setting/stock_maintenance.php | 2 +- app/setting/system_config.php | 2 +- app/setting/users.php | 2 +- 273 files changed, 409 insertions(+), 274 deletions(-) create mode 100644 app/assets/utils/app_access.php diff --git a/app/ac_dashboard/api/engine/by_source.php b/app/ac_dashboard/api/engine/by_source.php index b721ba3..edcbd83 100644 --- a/app/ac_dashboard/api/engine/by_source.php +++ b/app/ac_dashboard/api/engine/by_source.php @@ -1,5 +1,5 @@ diff --git a/app/accounting/account_formulas.php b/app/accounting/account_formulas.php index fb270db..1e7ab14 100644 --- a/app/accounting/account_formulas.php +++ b/app/accounting/account_formulas.php @@ -1,5 +1,5 @@ diff --git a/app/accounting/api/engine/account.php b/app/accounting/api/engine/account.php index dc93c73..3c3eec0 100644 --- a/app/accounting/api/engine/account.php +++ b/app/accounting/api/engine/account.php @@ -1,5 +1,5 @@ diff --git a/app/accounting/chart_of_accounts.php b/app/accounting/chart_of_accounts.php index 7f170b8..345924a 100644 --- a/app/accounting/chart_of_accounts.php +++ b/app/accounting/chart_of_accounts.php @@ -1,5 +1,5 @@ diff --git a/app/accounting/departments.php b/app/accounting/departments.php index 033fd47..0d23598 100644 --- a/app/accounting/departments.php +++ b/app/accounting/departments.php @@ -1,5 +1,5 @@ diff --git a/app/accounting/gl_entries.php b/app/accounting/gl_entries.php index c970b77..82756f2 100644 --- a/app/accounting/gl_entries.php +++ b/app/accounting/gl_entries.php @@ -1,5 +1,5 @@ diff --git a/app/accounting/gl_movement.php b/app/accounting/gl_movement.php index ae8a269..bd56062 100644 --- a/app/accounting/gl_movement.php +++ b/app/accounting/gl_movement.php @@ -1,5 +1,5 @@ diff --git a/app/accounting/journal_listing.php b/app/accounting/journal_listing.php index efed99a..0fb24a3 100644 --- a/app/accounting/journal_listing.php +++ b/app/accounting/journal_listing.php @@ -1,5 +1,5 @@ diff --git a/app/accounting/manage_account.php b/app/accounting/manage_account.php index f5da6c1..eefa1a0 100644 --- a/app/accounting/manage_account.php +++ b/app/accounting/manage_account.php @@ -1,5 +1,5 @@ diff --git a/app/accounting/manage_department.php b/app/accounting/manage_department.php index f17f99f..ee938d4 100644 --- a/app/accounting/manage_department.php +++ b/app/accounting/manage_department.php @@ -1,5 +1,5 @@ diff --git a/app/accounting/pl_statement.php b/app/accounting/pl_statement.php index 3e5907f..f7f3d99 100644 --- a/app/accounting/pl_statement.php +++ b/app/accounting/pl_statement.php @@ -1,5 +1,5 @@ diff --git a/app/accounting/posting_window.php b/app/accounting/posting_window.php index ed4b4c9..a86cee2 100644 --- a/app/accounting/posting_window.php +++ b/app/accounting/posting_window.php @@ -1,5 +1,5 @@ diff --git a/app/accounting/trial_balance.php b/app/accounting/trial_balance.php index 9ca2e24..315c3a2 100644 --- a/app/accounting/trial_balance.php +++ b/app/accounting/trial_balance.php @@ -1,5 +1,5 @@ diff --git a/app/accounting/vat_report.php b/app/accounting/vat_report.php index 1aadad4..66b44fe 100644 --- a/app/accounting/vat_report.php +++ b/app/accounting/vat_report.php @@ -1,5 +1,5 @@ diff --git a/app/assets/js/custom.js b/app/assets/js/custom.js index fe9c47e..63c1fa7 100644 --- a/app/assets/js/custom.js +++ b/app/assets/js/custom.js @@ -905,6 +905,17 @@ function ajax_request(options) { return; } + // Session ended on the server (idle timeout, not signed in, password changed): + // drop per-tab data and go back to the sign-in form. + const endedCodes = ['session_expired', 'auth_required', 'password_changed']; + if (xhr?.status === 401 && endedCodes.includes(xhr?.responseJSON?.code)) { + try { sessionStorage.clear(); } catch (e) {} + bootbox.alert(escape_html(xhr.responseJSON.message || 'Please sign in again.'), function() { + window.location.href = server_url + 'login/index.php'; + }); + return; + } + // File / payload too large (nginx 413) if (xhr?.status === 413) { bootbox.alert('The file you selected is too large. Please use an image under 2 MB and try again.'); diff --git a/app/assets/utils/app_access.php b/app/assets/utils/app_access.php new file mode 100644 index 0000000..f4036fb --- /dev/null +++ b/app/assets/utils/app_access.php @@ -0,0 +1,37 @@ + "Invalid request"])); } } // validate otp - $sql = "SELECT `password` + $sql = "SELECT `password`, license, app_access FROM user WHERE user_id = :company_id"; $sth = $pdo1->prepare($sql); @@ -68,7 +69,8 @@ if(!empty($_SESSION["login_company_id"])){ ":company_id" => $_SESSION["login_user_id"] ]); db_check($sth, $answer); - $password = $sth->fetchColumn(); + $user_row = $sth->fetch(PDO::FETCH_ASSOC) ?: []; + $password = $user_row['password'] ?? ''; /** Generate OTP */ function generateOTP($sercet_key, $time_step = 180, $length = 6){ $counter = floor($_SESSION["otpTime"] / $time_step); @@ -83,7 +85,9 @@ if(!empty($_SESSION["login_company_id"])){ $otp = generateOTP($password); if( $_SESSION["otp"]!=$otp ){ + http_response_code(401); $answer["message"] = "Your password has been reset, Please logout and login again."; + $answer["code"] = "password_changed"; exit(json_encode($answer)); } @@ -98,13 +102,29 @@ if(!empty($_SESSION["login_company_id"])){ $map = $sth->fetchAll(PDO::FETCH_ASSOC); if( count($map)==0 ){ + http_response_code(403); $answer["message"] = "Your accessibility to this company has been removed."; + $answer["code"] = "access_removed"; exit(json_encode($answer)); } $user_role = $map[0]['role'] ?? 'viewer'; $_SESSION['login_role'] = $user_role; + // App access (WMS / Accounting), re-read on every request so a change made in + // Setting → Users applies at once. Owners hold it on their own user row; + // invited users per company (same rule as login_confirm.php). + $app_access = (($user_row['license'] ?? 'owner') === 'owner') + ? ($user_row['app_access'] ?? 'wms') + : ($map[0]['app_access'] ?? 'wms'); + $_SESSION['login_app_access'] = $app_access; + + $required_app = app_access_app_for($_SERVER['SCRIPT_NAME'] ?? ''); + if ($required_app !== null && !app_access_allows($app_access, $required_app)) { + http_response_code(403); + exit(json_encode(['success' => 0, 'message' => 'Your account does not have access to this module.'])); + } + // Single-session enforcement: if a session_token was issued at login, verify // it still matches the DB. A mismatch means a newer login has taken over. if (!empty($_SESSION['session_token'])) { @@ -132,7 +152,12 @@ if(!empty($_SESSION["login_company_id"])){ // unless the engine explicitly declared itself a pre-auth route. if (empty($_SESSION['login_company_id']) && !defined('UNAUTHENTICATED_ROUTE')) { http_response_code(401); - exit(json_encode(['success' => 0, 'message' => 'Authentication required.'])); + $expired = !empty($_SESSION['_idle_expired']); + exit(json_encode([ + 'success' => 0, + 'message' => $expired ? 'Your session has expired. Please sign in again.' : 'Authentication required.', + 'code' => $expired ? 'session_expired' : 'auth_required', + ])); } // set up ANSWER @@ -153,6 +178,7 @@ if (!is_array($data)) { $data = $_POST; } else { // Truly no data received + http_response_code(400); $answer["message"] = "Request denied: No valid JSON payload or Form Data detected."; exit(json_encode($answer)); } diff --git a/app/contact/api/engine/contact.php b/app/contact/api/engine/contact.php index 7caa1a2..b359be5 100644 --- a/app/contact/api/engine/contact.php +++ b/app/contact/api/engine/contact.php @@ -1,5 +1,5 @@ diff --git a/app/contact/manage_contact.php b/app/contact/manage_contact.php index 1a50311..c33e43c 100644 --- a/app/contact/manage_contact.php +++ b/app/contact/manage_contact.php @@ -1,5 +1,5 @@ diff --git a/app/dashboard/low_stock_products.php b/app/dashboard/low_stock_products.php index b7b580b..1f52e68 100644 --- a/app/dashboard/low_stock_products.php +++ b/app/dashboard/low_stock_products.php @@ -1,5 +1,5 @@ diff --git a/app/expense/api/engine/convert_purchase_request.php b/app/expense/api/engine/convert_purchase_request.php index b225d69..010e0bd 100644 --- a/app/expense/api/engine/convert_purchase_request.php +++ b/app/expense/api/engine/convert_purchase_request.php @@ -1,5 +1,5 @@ diff --git a/app/expense/purchase_order.php b/app/expense/purchase_order.php index 6f1a71c..7904ecd 100644 --- a/app/expense/purchase_order.php +++ b/app/expense/purchase_order.php @@ -1,5 +1,5 @@ diff --git a/app/expense/purchase_request.php b/app/expense/purchase_request.php index f5a3c39..b9d16b0 100644 --- a/app/expense/purchase_request.php +++ b/app/expense/purchase_request.php @@ -1,5 +1,5 @@ diff --git a/app/finance/api/engine/delete_payment.php b/app/finance/api/engine/delete_payment.php index db37bd6..8785ed1 100644 --- a/app/finance/api/engine/delete_payment.php +++ b/app/finance/api/engine/delete_payment.php @@ -1,5 +1,5 @@ diff --git a/app/finance/receipt.php b/app/finance/receipt.php index 49c6abd..34b2d4b 100644 --- a/app/finance/receipt.php +++ b/app/finance/receipt.php @@ -1,5 +1,5 @@ diff --git a/app/ics/api/engine/approve_stock.php b/app/ics/api/engine/approve_stock.php index eb209bf..2190c1f 100644 --- a/app/ics/api/engine/approve_stock.php +++ b/app/ics/api/engine/approve_stock.php @@ -11,7 +11,7 @@ * warehouse int warehouse_id (to resolve the dynamic table) * type string 'in' | 'out' | 'transfer' */ -session_start(); +require_once __DIR__ . '/../../../session.php'; require_once '../../../assets/utils/db_auth.php'; require_once '../../../assets/utils/classes/StockManager.php'; require_once '../../../assets/utils/classes/WarehouseManager.php'; diff --git a/app/ics/api/engine/barcode_lookup.php b/app/ics/api/engine/barcode_lookup.php index 6db0793..d6edb5a 100644 --- a/app/ics/api/engine/barcode_lookup.php +++ b/app/ics/api/engine/barcode_lookup.php @@ -1,5 +1,5 @@ diff --git a/app/ics/stock_transfer.php b/app/ics/stock_transfer.php index 6c66970..625ce21 100644 --- a/app/ics/stock_transfer.php +++ b/app/ics/stock_transfer.php @@ -1,5 +1,5 @@ 0) { + ob_end_clean(); + } + header('Location: '.$server_url.'dashboard/index.php'); + exit; +} // ── User display data from session ──────────────────────────────────────────── $topbar_name = htmlspecialchars(trim(($_SESSION['login_name'] ?? '') . ' ' . ($_SESSION['login_surname'] ?? '')), ENT_QUOTES, 'UTF-8'); @@ -367,6 +379,7 @@ function log_out() { checkRequired: 0, action: 'read', onSuccess: function(res) { + try { sessionStorage.clear(); } catch (e) {} window.location.href = server_url + 'index.php'; } }); diff --git a/app/inventory/api/engine/manage_category.php b/app/inventory/api/engine/manage_category.php index 21380d0..76c21da 100644 --- a/app/inventory/api/engine/manage_category.php +++ b/app/inventory/api/engine/manage_category.php @@ -1,5 +1,5 @@ diff --git a/app/inventory/warehouse.php b/app/inventory/warehouse.php index 90307f8..c0f3e43 100644 --- a/app/inventory/warehouse.php +++ b/app/inventory/warehouse.php @@ -1,5 +1,5 @@ diff --git a/app/journal/new.php b/app/journal/new.php index 9a67953..e498b43 100644 --- a/app/journal/new.php +++ b/app/journal/new.php @@ -1,5 +1,5 @@ diff --git a/app/login/api/engine/back.php b/app/login/api/engine/back.php index 9b5daac..cf48fbd 100644 --- a/app/login/api/engine/back.php +++ b/app/login/api/engine/back.php @@ -34,7 +34,8 @@ if (!empty($_SESSION['login_user_id'])) { // Intentional 1-second delay — prevents timing attacks on session enumeration sleep(1); -session_destroy(); +// Clears the session data, deletes the session file and expires the cookie. +session_end_completely(); $answer["success"] = 1; exit(json_encode($answer)); \ No newline at end of file diff --git a/app/order/api/engine/cancel_order.php b/app/order/api/engine/cancel_order.php index 3a63187..be6f23f 100644 --- a/app/order/api/engine/cancel_order.php +++ b/app/order/api/engine/cancel_order.php @@ -1,5 +1,5 @@ diff --git a/app/order/manage_invoice.php b/app/order/manage_invoice.php index 54f4f69..5edae95 100644 --- a/app/order/manage_invoice.php +++ b/app/order/manage_invoice.php @@ -1,5 +1,5 @@ diff --git a/app/order/print_invoice.php b/app/order/print_invoice.php index 5746221..f91acb1 100644 --- a/app/order/print_invoice.php +++ b/app/order/print_invoice.php @@ -1,5 +1,5 @@ diff --git a/app/po/api/engine/cancel_po.php b/app/po/api/engine/cancel_po.php index 6d308e4..85bdc3e 100644 --- a/app/po/api/engine/cancel_po.php +++ b/app/po/api/engine/cancel_po.php @@ -1,5 +1,5 @@ diff --git a/app/po/manage_po.php b/app/po/manage_po.php index aa75577..283626c 100644 --- a/app/po/manage_po.php +++ b/app/po/manage_po.php @@ -1,5 +1,5 @@ diff --git a/app/po/supplier_returns.php b/app/po/supplier_returns.php index 911a6f5..3eaed25 100644 --- a/app/po/supplier_returns.php +++ b/app/po/supplier_returns.php @@ -1,5 +1,5 @@ diff --git a/app/reports/api/engine_report/bin_log.php b/app/reports/api/engine_report/bin_log.php index 297bb13..f54a251 100644 --- a/app/reports/api/engine_report/bin_log.php +++ b/app/reports/api/engine_report/bin_log.php @@ -1,5 +1,5 @@ diff --git a/app/reports/occupy_rack.php b/app/reports/occupy_rack.php index 908745b..b699413 100644 --- a/app/reports/occupy_rack.php +++ b/app/reports/occupy_rack.php @@ -1,5 +1,5 @@ diff --git a/app/reports/product_lot.php b/app/reports/product_lot.php index bccb40c..7503783 100644 --- a/app/reports/product_lot.php +++ b/app/reports/product_lot.php @@ -1,5 +1,5 @@ diff --git a/app/reports/stock_movement.php b/app/reports/stock_movement.php index a2f4874..a5ee3b2 100644 --- a/app/reports/stock_movement.php +++ b/app/reports/stock_movement.php @@ -1,5 +1,5 @@ diff --git a/app/revenue/api/engine/convert_quotation.php b/app/revenue/api/engine/convert_quotation.php index 5ad14ad..1451111 100644 --- a/app/revenue/api/engine/convert_quotation.php +++ b/app/revenue/api/engine/convert_quotation.php @@ -1,5 +1,5 @@ diff --git a/app/revenue/manage_credit_note.php b/app/revenue/manage_credit_note.php index a290f8e..4ba61d1 100644 --- a/app/revenue/manage_credit_note.php +++ b/app/revenue/manage_credit_note.php @@ -1,5 +1,5 @@ diff --git a/app/revenue/quotation.php b/app/revenue/quotation.php index 27b1fcf..776005a 100644 --- a/app/revenue/quotation.php +++ b/app/revenue/quotation.php @@ -1,5 +1,5 @@ diff --git a/app/session.php b/app/session.php index 3651670..b9766e2 100644 --- a/app/session.php +++ b/app/session.php @@ -1,5 +1,7 @@ 0, 'path' => $repo_name, 'domain' => '', - 'secure' => isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on', + 'secure' => $is_https, 'httponly' => true, 'samesite' => 'Lax', ]); session_start(); -} \ No newline at end of file + + // Idle timeout: a signed-in session untouched for SESSION_IDLE_SECONDS is + // cleared here, so pages redirect to the login form and API engines answer + // 401 (db_auth.php) exactly as for a visitor who never signed in. + if (!empty($_SESSION['login_company_id'])) { + $last = (int)($_SESSION['_last_activity'] ?? 0); + if ($last > 0 && (time() - $last) > SESSION_IDLE_SECONDS) { + $_SESSION = []; + session_regenerate_id(true); + $_SESSION['_idle_expired'] = true; + } else { + $_SESSION['_last_activity'] = time(); + } + } +} + +/** + * End the current session completely: server data, the session file and the + * browser cookie. Used by logout and by any flow that must force a new sign-in. + */ +if (!function_exists('session_end_completely')) { + function session_end_completely(): void { + if (session_status() !== PHP_SESSION_ACTIVE) return; + $_SESSION = []; + $p = session_get_cookie_params(); + setcookie(session_name(), '', [ + 'expires' => time() - 42000, + 'path' => $p['path'], + 'domain' => $p['domain'], + 'secure' => $p['secure'], + 'httponly' => $p['httponly'], + 'samesite' => $p['samesite'] ?? 'Lax', + ]); + session_destroy(); + } +} diff --git a/app/setting/api/engine/change_password.php b/app/setting/api/engine/change_password.php index 363dea0..4b6dcc2 100644 --- a/app/setting/api/engine/change_password.php +++ b/app/setting/api/engine/change_password.php @@ -1,5 +1,5 @@ diff --git a/app/setting/document_types.php b/app/setting/document_types.php index 0a6b4df..ff5a0f9 100644 --- a/app/setting/document_types.php +++ b/app/setting/document_types.php @@ -1,5 +1,5 @@ diff --git a/app/setting/gl_maintenance.php b/app/setting/gl_maintenance.php index 011cffb..79c470a 100644 --- a/app/setting/gl_maintenance.php +++ b/app/setting/gl_maintenance.php @@ -1,5 +1,5 @@ diff --git a/app/setting/profile.php b/app/setting/profile.php index 269fe6c..a5eaa1e 100644 --- a/app/setting/profile.php +++ b/app/setting/profile.php @@ -1,5 +1,5 @@ diff --git a/app/setting/smtp.php b/app/setting/smtp.php index 5ce9851..4d99154 100644 --- a/app/setting/smtp.php +++ b/app/setting/smtp.php @@ -1,5 +1,5 @@ diff --git a/app/setting/stock_maintenance.php b/app/setting/stock_maintenance.php index d0ea5e1..809b844 100644 --- a/app/setting/stock_maintenance.php +++ b/app/setting/stock_maintenance.php @@ -1,5 +1,5 @@ diff --git a/app/setting/system_config.php b/app/setting/system_config.php index 22a4f73..f5e7bcd 100644 --- a/app/setting/system_config.php +++ b/app/setting/system_config.php @@ -1,5 +1,5 @@ diff --git a/app/setting/users.php b/app/setting/users.php index 9b394bd..f130a69 100644 --- a/app/setting/users.php +++ b/app/setting/users.php @@ -1,5 +1,5 @@