From a064f5b46189cbe01b545cc72f38b5e615354afc Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 18 May 2026 23:39:43 +0000 Subject: [PATCH 1/9] Initial plan From 03e73754253d9e13740d24440b55a156262b46fd Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 18 May 2026 23:50:48 +0000 Subject: [PATCH 2/9] fix(security): add OAuth state validation and CSRF protection across POST forms Agent-Logs-Url: https://github.com/marpisco/ClassLink/sessions/915c369e-d638-4384-89f9-6bf45604b511 Co-authored-by: marpisco <162377105+marpisco@users.noreply.github.com> --- admin/index.php | 34 ++++++++++++++++++++++++++++++++++ admin/relatorios.php | 6 ++++++ login/index.php | 40 +++++++++++++++++++++++++++++++++------- reservar/index.php | 7 +++++++ reservar/manage.php | 8 +++++++- src/db.php | 6 ++++-- 6 files changed, 91 insertions(+), 10 deletions(-) diff --git a/admin/index.php b/admin/index.php index 9474fbc..3aa85da 100644 --- a/admin/index.php +++ b/admin/index.php @@ -13,6 +13,7 @@ Pedido inválido. Atualize a página e tente novamente."); + } + } ?>
"; + $csrfTokenForJs = json_encode(generate_csrf_token()); + echo ""; + ?> "; + echo csrf_token_field(); foreach ($inputs as $input) { $id_safe = htmlspecialchars($input['id'], ENT_QUOTES, 'UTF-8'); $value_safe = htmlspecialchars($input['value'], ENT_QUOTES, 'UTF-8'); diff --git a/admin/relatorios.php b/admin/relatorios.php index 3f1c9e8..4258cf8 100644 --- a/admin/relatorios.php +++ b/admin/relatorios.php @@ -1,11 +1,16 @@ Pedido inválido. Atualize a página e tente novamente.
"); + } if (!$_SESSION['admin']) { http_response_code(403); die("
Não tem permissão para entrar no painel administrativo. Voltar para a página inicial
"); @@ -161,6 +166,7 @@ public function Footer() {

Gere um relatório em PDF da utilização de salas para um dia específico.

+
diff --git a/login/index.php b/login/index.php index 660b013..1f8f614 100644 --- a/login/index.php +++ b/login/index.php @@ -1,8 +1,13 @@ ⚠️ MODO DE DESENVOLVIMENTO - Dados de teste | Base de dados de desenvolvimento
' : ''; - $content = $devModeBanner . '

Verificação de Segurança

Introduza o código do seu autenticador para prosseguir.

' . (!empty($localAuthError) ? '
' . htmlspecialchars($localAuthError) . '
' : '') . '
'; + $content = $devModeBanner . '

Verificação de Segurança

Introduza o código do seu autenticador para prosseguir.

' . (!empty($localAuthError) ? '
' . htmlspecialchars($localAuthError) . '
' : '') . '
' . $csrfTokenField . '
'; render_login_template('Verificação de Segurança', $content); die(); } @@ -354,6 +367,7 @@ function start_authenticated_session($userId, $userName, $userEmail, $isAdmin) { $content .= '

Por favor, introduza o seu nome completo.

'; if (!empty($localAuthError)) { $content .= '
' . htmlspecialchars($localAuthError) . '
'; } $content .= '
'; + $content .= $csrfTokenField; $content .= ''; $content .= '
'; $content .= ''; @@ -396,6 +410,7 @@ function start_authenticated_session($userId, $userName, $userEmail, $isAdmin) { $content .= '
QR Code
'; $content .= '
Código manual:
' . htmlspecialchars($secret) . '
'; $content .= ''; + $content .= $csrfTokenField; $content .= ''; $content .= '
'; $content .= ''; @@ -451,6 +466,7 @@ function start_authenticated_session($userId, $userName, $userEmail, $isAdmin) {

Iniciar Sessão no ClassLink

+
@@ -483,6 +500,7 @@ function start_authenticated_session($userId, $userName, $userEmail, $isAdmin) {
+
@@ -536,7 +554,15 @@ function start_authenticated_session($userId, $userName, $userEmail, $isAdmin) { } else if (isset($_GET['error'])) { ?> getAccessToken('authorization_code', [ 'code' => $_GET['code'] ]); diff --git a/reservar/index.php b/reservar/index.php index 595b61c..737536e 100644 --- a/reservar/index.php +++ b/reservar/index.php @@ -1,11 +1,16 @@ @@ -120,6 +125,7 @@ function clearBulkUserSelection() {

Reservar uma Sala

+
diff --git a/src/db.php b/src/db.php index c3b0a4a..fad1dd0 100644 --- a/src/db.php +++ b/src/db.php @@ -18,7 +18,9 @@ $db = new mysqli($db['servidor'], $db['user'], $db['password'], $dbName, $db['porta']); if ($db->connect_error) { - die("Ligação ao servidor falhou: " . $db->connect_error); + error_log("ClassLink DB connection failed: " . $db->connect_error); + http_response_code(500); + die("Ligação ao servidor falhou."); } $db->set_charset("utf8mb4"); @@ -112,4 +114,4 @@ // Constant for pre-registered user ID prefix define('PRE_REGISTERED_PREFIX', 'pre_'); -?> \ No newline at end of file +?> From 41d27498efcf16172ac8435d1bacb48a508922ff Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 18 May 2026 23:52:28 +0000 Subject: [PATCH 3/9] fix(security): harden admin API path check and log OAuth state failures Agent-Logs-Url: https://github.com/marpisco/ClassLink/sessions/915c369e-d638-4384-89f9-6bf45604b511 Co-authored-by: marpisco <162377105+marpisco@users.noreply.github.com> --- admin/index.php | 12 +++++++++--- login/index.php | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/admin/index.php b/admin/index.php index 3aa85da..32237e5 100644 --- a/admin/index.php +++ b/admin/index.php @@ -40,7 +40,10 @@ } } - if ($_SERVER['REQUEST_METHOD'] === 'POST') { + $requestPath = parse_url($_SERVER['REQUEST_URI'] ?? '', PHP_URL_PATH) ?? ''; + $requestPath = '/' . ltrim($requestPath, '/'); + $isAdminApiRequest = str_starts_with($requestPath, '/admin/api/'); + if ($_SERVER['REQUEST_METHOD'] === 'POST' && !$isAdminApiRequest) { $csrfToken = $_POST['csrf_token'] ?? ''; if (!verify_csrf_token($csrfToken)) { http_response_code(403); @@ -186,13 +189,16 @@ function sidebarDropdownLink($url, $nome) { // Fechar Navbar no HTML, e passar o conteúdo para baixo echo "
"; - $csrfTokenForJs = json_encode(generate_csrf_token()); + $csrfTokenHtml = htmlspecialchars(generate_csrf_token(), ENT_QUOTES, 'UTF-8'); + echo ""; echo "