Commit 03447d76 authored by Mahmoud Aglan's avatar Mahmoud Aglan

security: fix CORS, input sanitization, invite auth, and move secrets to env

- Replace wildcard CORS (Access-Control-Allow-Origin: *) with domain whitelist
  across all 37 API files via shared includes/cors.php
- friends.php: sanitize PostgREST filter inputs (strip special chars from search)
- friends.php: validate UUID format for profile ID lookups
- friends.php: verify user is invite target before accept/decline (domino, ludo, chess)
- config/constants.php: read secrets from .env file or env vars (no more hardcoded keys)
- Add .env to .gitignore

Fixes WTF #5-6, #9-11
Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
parent 6f0df09e
...@@ -10,6 +10,7 @@ Thumbs.db ...@@ -10,6 +10,7 @@ Thumbs.db
# Sensitive # Sensitive
*.pem *.pem
.env
Connections and docs / Connections and docs /
# Deps (none for now, but future-proofing) # Deps (none for now, but future-proofing)
......
<?php <?php
header('Content-Type: application/json'); header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *'); require_once __DIR__ . '/../includes/cors.php';
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; } if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; }
......
<?php <?php
header('Content-Type: application/json'); header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *'); require_once __DIR__ . '/../includes/cors.php';
header('Access-Control-Allow-Methods: GET, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; } if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; }
......
<?php <?php
header('Content-Type: application/json'); header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *'); require_once __DIR__ . '/../includes/cors.php';
require_once __DIR__ . '/../includes/supabase.php'; require_once __DIR__ . '/../includes/supabase.php';
......
<?php <?php
header('Content-Type: application/json'); header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *'); require_once __DIR__ . '/../includes/cors.php';
header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; } if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; }
......
<?php <?php
header('Content-Type: application/json'); header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *'); require_once __DIR__ . '/../includes/cors.php';
header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; } if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; }
......
...@@ -15,9 +15,7 @@ set_error_handler(function($errno, $errstr, $errfile, $errline) { ...@@ -15,9 +15,7 @@ set_error_handler(function($errno, $errstr, $errfile, $errline) {
}); });
header('Content-Type: application/json'); header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *'); require_once __DIR__ . '/../includes/cors.php';
header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; } if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; }
if ($_SERVER['REQUEST_METHOD'] !== 'POST') { http_response_code(405); echo json_encode(['error' => 'Method not allowed']); exit; } if ($_SERVER['REQUEST_METHOD'] !== 'POST') { http_response_code(405); echo json_encode(['error' => 'Method not allowed']); exit; }
......
<?php <?php
header('Content-Type: application/json'); header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *'); require_once __DIR__ . '/../includes/cors.php';
header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; } if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; }
......
<?php <?php
header('Content-Type: application/json'); header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *'); require_once __DIR__ . '/../includes/cors.php';
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; } if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; }
......
<?php <?php
header('Content-Type: application/json'); header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *'); require_once __DIR__ . '/../includes/cors.php';
header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; } if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; }
......
<?php <?php
header('Content-Type: application/json'); header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *'); require_once __DIR__ . '/../includes/cors.php';
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
header('Cache-Control: no-cache, must-revalidate'); header('Cache-Control: no-cache, must-revalidate');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; } if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; }
......
<?php <?php
header('Content-Type: application/json'); header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *'); require_once __DIR__ . '/../includes/cors.php';
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; } if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; }
......
<?php <?php
header('Content-Type: application/json'); header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *'); require_once __DIR__ . '/../includes/cors.php';
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; } if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; }
......
<?php <?php
header('Content-Type: application/json'); header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *'); require_once __DIR__ . '/../includes/cors.php';
require_once __DIR__ . '/../includes/supabase.php'; require_once __DIR__ . '/../includes/supabase.php';
......
<?php <?php
header('Content-Type: application/json'); header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *'); require_once __DIR__ . '/../includes/cors.php';
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; } if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; }
......
<?php <?php
header('Content-Type: application/json'); header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *'); require_once __DIR__ . '/../includes/cors.php';
header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; } if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; }
......
<?php <?php
header('Content-Type: application/json'); header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *'); require_once __DIR__ . '/../includes/cors.php';
header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; } if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; }
......
<?php <?php
header('Content-Type: application/json'); header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *'); require_once __DIR__ . '/../includes/cors.php';
header('Access-Control-Allow-Methods: GET, POST, DELETE, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; } if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; }
...@@ -72,6 +70,10 @@ if ($method === 'GET') { ...@@ -72,6 +70,10 @@ if ($method === 'GET') {
$query = $_GET['query'] ?? ''; $query = $_GET['query'] ?? '';
if (strlen($query) < 2) jsonError('Query too short'); if (strlen($query) < 2) jsonError('Query too short');
// Sanitize PostgREST special characters to prevent filter injection
$query = preg_replace('/[^a-zA-Z0-9\x{0600}-\x{06FF}\s_.-]/u', '', $query);
if (strlen($query) < 2) jsonError('Query too short');
$results = $sdb->get('profiles', [ $results = $sdb->get('profiles', [
'or' => "(username.ilike.*{$query}*,display_name.ilike.*{$query}*)", 'or' => "(username.ilike.*{$query}*,display_name.ilike.*{$query}*)",
'id' => 'neq.' . $userId, 'id' => 'neq.' . $userId,
...@@ -85,7 +87,13 @@ if ($method === 'GET') { ...@@ -85,7 +87,13 @@ if ($method === 'GET') {
if ($action === 'profiles') { if ($action === 'profiles') {
$ids = $_GET['ids'] ?? ''; $ids = $_GET['ids'] ?? '';
if (!$ids) jsonResponse(['profiles' => []]); if (!$ids) jsonResponse(['profiles' => []]);
$idList = implode(',', array_map('trim', explode(',', $ids))); // Validate each ID is a valid UUID to prevent filter injection
$rawIds = array_map('trim', explode(',', $ids));
$validIds = array_filter($rawIds, function($id) {
return preg_match('/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i', $id);
});
if (empty($validIds)) jsonResponse(['profiles' => []]);
$idList = implode(',', $validIds);
$profiles = $sdb->get('profiles', [ $profiles = $sdb->get('profiles', [
'id' => "in.({$idList})", 'id' => "in.({$idList})",
'select' => 'id,username,display_name,avatar_url,level,is_online' 'select' => 'id,username,display_name,avatar_url,level,is_online'
...@@ -512,12 +520,17 @@ if ($method === 'POST') { ...@@ -512,12 +520,17 @@ if ($method === 'POST') {
$matches = $sdb->get('domino_matches', [ $matches = $sdb->get('domino_matches', [
'id' => 'eq.' . $matchId, 'id' => 'eq.' . $matchId,
'status' => 'eq.waiting', 'status' => 'eq.waiting',
'select' => 'id,players', 'select' => 'id,players,game_state',
'limit' => 1 'limit' => 1
]); ]);
if (!is_array($matches) || isset($matches['error']) || empty($matches)) { if (!is_array($matches) || isset($matches['error']) || empty($matches)) {
jsonError('Invite not found or expired'); jsonError('Invite not found or expired');
} }
// Verify current user is the invite target
$gs = is_array($matches[0]['game_state']) ? $matches[0]['game_state'] : json_decode($matches[0]['game_state'] ?? '{}', true);
if (($gs['invite_to'] ?? '') !== $userId) {
jsonError('Not authorized to accept this invite', 403);
}
$sdb->update('domino_matches', [ $sdb->update('domino_matches', [
'status' => 'in_progress' 'status' => 'in_progress'
], ['id' => 'eq.' . $matchId]); ], ['id' => 'eq.' . $matchId]);
...@@ -533,12 +546,17 @@ if ($method === 'POST') { ...@@ -533,12 +546,17 @@ if ($method === 'POST') {
$matches = $sdb->get('ludo_matches', [ $matches = $sdb->get('ludo_matches', [
'id' => 'eq.' . $matchId, 'id' => 'eq.' . $matchId,
'status' => 'eq.waiting', 'status' => 'eq.waiting',
'select' => 'id,players', 'select' => 'id,players,game_state',
'limit' => 1 'limit' => 1
]); ]);
if (!is_array($matches) || isset($matches['error']) || empty($matches)) { if (!is_array($matches) || isset($matches['error']) || empty($matches)) {
jsonError('Invite not found or expired'); jsonError('Invite not found or expired');
} }
// Verify current user is the invite target
$gs = is_array($matches[0]['game_state']) ? $matches[0]['game_state'] : json_decode($matches[0]['game_state'] ?? '{}', true);
if (($gs['invite_to'] ?? '') !== $userId) {
jsonError('Not authorized to accept this invite', 403);
}
$sdb->update('ludo_matches', [ $sdb->update('ludo_matches', [
'status' => 'in_progress' 'status' => 'in_progress'
], ['id' => 'eq.' . $matchId]); ], ['id' => 'eq.' . $matchId]);
...@@ -586,16 +604,55 @@ if ($method === 'POST') { ...@@ -586,16 +604,55 @@ if ($method === 'POST') {
if (!$matchId) jsonError('match_id required'); if (!$matchId) jsonError('match_id required');
if ($gameKey === 'domino') { if ($gameKey === 'domino') {
$matches = $sdb->get('domino_matches', [
'id' => 'eq.' . $matchId,
'status' => 'eq.waiting',
'select' => 'id,game_state',
'limit' => 1
]);
if (!is_array($matches) || isset($matches['error']) || empty($matches)) {
jsonError('Invite not found or expired');
}
$gs = is_array($matches[0]['game_state']) ? $matches[0]['game_state'] : json_decode($matches[0]['game_state'] ?? '{}', true);
if (($gs['invite_to'] ?? '') !== $userId) {
jsonError('Not authorized to decline this invite', 403);
}
$sdb->update('domino_matches', [ $sdb->update('domino_matches', [
'status' => 'completed', 'status' => 'completed',
'result' => 'declined' 'result' => 'declined'
], ['id' => 'eq.' . $matchId, 'status' => 'eq.waiting']); ], ['id' => 'eq.' . $matchId, 'status' => 'eq.waiting']);
} elseif ($gameKey === 'ludo') { } elseif ($gameKey === 'ludo') {
$matches = $sdb->get('ludo_matches', [
'id' => 'eq.' . $matchId,
'status' => 'eq.waiting',
'select' => 'id,game_state',
'limit' => 1
]);
if (!is_array($matches) || isset($matches['error']) || empty($matches)) {
jsonError('Invite not found or expired');
}
$gs = is_array($matches[0]['game_state']) ? $matches[0]['game_state'] : json_decode($matches[0]['game_state'] ?? '{}', true);
if (($gs['invite_to'] ?? '') !== $userId) {
jsonError('Not authorized to decline this invite', 403);
}
$sdb->update('ludo_matches', [ $sdb->update('ludo_matches', [
'status' => 'completed', 'status' => 'completed',
'result' => 'declined' 'result' => 'declined'
], ['id' => 'eq.' . $matchId, 'status' => 'eq.waiting']); ], ['id' => 'eq.' . $matchId, 'status' => 'eq.waiting']);
} else { } else {
$matches = $sdb->get('matches', [
'id' => 'eq.' . $matchId,
'status' => 'eq.waiting',
'select' => 'id,game_state',
'limit' => 1
]);
if (!is_array($matches) || isset($matches['error']) || empty($matches)) {
jsonError('Invite not found or expired');
}
$gs = is_array($matches[0]['game_state']) ? $matches[0]['game_state'] : json_decode($matches[0]['game_state'] ?? '{}', true);
if (($gs['invite_to'] ?? '') !== $userId) {
jsonError('Not authorized to decline this invite', 403);
}
$sdb->update('matches', [ $sdb->update('matches', [
'status' => 'completed', 'status' => 'completed',
'result' => 'declined' 'result' => 'declined'
......
<?php <?php
header('Content-Type: application/json'); header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *'); require_once __DIR__ . '/../includes/cors.php';
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; } if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; }
......
<?php <?php
header('Content-Type: application/json'); header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *'); require_once __DIR__ . '/../includes/cors.php';
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; } if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; }
......
<?php <?php
header('Content-Type: application/json'); header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *'); require_once __DIR__ . '/../includes/cors.php';
header('Access-Control-Allow-Methods: GET, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; } if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; }
......
<?php <?php
header('Content-Type: application/json'); header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *'); require_once __DIR__ . '/../includes/cors.php';
header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; } if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; }
......
<?php <?php
header('Content-Type: application/json'); header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *'); require_once __DIR__ . '/../includes/cors.php';
header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; } if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; }
......
...@@ -4,9 +4,7 @@ ...@@ -4,9 +4,7 @@
* Can be triggered by: admin panel load, external cron, or client on app boot. * Can be triggered by: admin panel load, external cron, or client on app boot.
*/ */
header('Content-Type: application/json'); header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *'); require_once __DIR__ . '/../includes/cors.php';
header('Access-Control-Allow-Methods: POST, GET, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; } if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; }
......
<?php <?php
header('Content-Type: application/json'); header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *'); require_once __DIR__ . '/../includes/cors.php';
header('Access-Control-Allow-Methods: GET, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; } if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; }
......
<?php <?php
header('Content-Type: application/json'); header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *'); require_once __DIR__ . '/../includes/cors.php';
header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; } if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; }
......
<?php <?php
header('Content-Type: application/json'); header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *'); require_once __DIR__ . '/../includes/cors.php';
header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; } if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; }
......
<?php <?php
header('Content-Type: application/json'); header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *'); require_once __DIR__ . '/../includes/cors.php';
header('Access-Control-Allow-Methods: GET, PATCH, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; } if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; }
......
...@@ -15,9 +15,7 @@ set_error_handler(function($errno, $errstr, $errfile, $errline) { ...@@ -15,9 +15,7 @@ set_error_handler(function($errno, $errstr, $errfile, $errline) {
}); });
header('Content-Type: application/json'); header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *'); require_once __DIR__ . '/../includes/cors.php';
header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; } if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; }
if ($_SERVER['REQUEST_METHOD'] !== 'POST') { http_response_code(405); echo json_encode(['error' => 'Method not allowed']); exit; } if ($_SERVER['REQUEST_METHOD'] !== 'POST') { http_response_code(405); echo json_encode(['error' => 'Method not allowed']); exit; }
......
<?php <?php
header('Content-Type: application/json'); header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *'); require_once __DIR__ . '/../includes/cors.php';
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; } if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; }
......
<?php <?php
header('Content-Type: application/json'); header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *'); require_once __DIR__ . '/../includes/cors.php';
header('Access-Control-Allow-Methods: GET, POST, PATCH, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; } if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; }
......
<?php <?php
header('Content-Type: application/json'); header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *'); require_once __DIR__ . '/../includes/cors.php';
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; } if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; }
......
<?php <?php
header('Content-Type: application/json'); header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *'); require_once __DIR__ . '/../includes/cors.php';
header('Access-Control-Allow-Methods: GET, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; } if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; }
......
<?php <?php
header('Content-Type: application/json'); header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *'); require_once __DIR__ . '/../includes/cors.php';
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; } if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; }
......
<?php <?php
header('Content-Type: application/json'); header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *'); require_once __DIR__ . '/../includes/cors.php';
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; } if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; }
......
<?php <?php
header('Content-Type: application/json'); header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *'); require_once __DIR__ . '/../includes/cors.php';
header('Access-Control-Allow-Methods: GET, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; } if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; }
......
<?php <?php
header('Content-Type: application/json'); header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *'); require_once __DIR__ . '/../includes/cors.php';
header('Access-Control-Allow-Methods: POST, GET, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; } if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; }
......
<?php <?php
header('Content-Type: application/json'); header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *'); require_once __DIR__ . '/../includes/cors.php';
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; } if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; }
......
<?php <?php
define('SUPABASE_URL', 'https://safe-supabase-kong.caprover.al-arcade.com'); // Load from .env file if present (not committed to git)
define('SUPABASE_ANON_KEY', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlzcyI6InN1cGFiYXNlIiwiaWF0IjoxNzM1Njg5NjAwLCJleHAiOjE4OTM0NTYwMDB9.31PF6PvP-pSrvRuQwLFptQoejR0W1A7o53lZhEbnz84'); $envFile = __DIR__ . '/../.env';
define('SUPABASE_SERVICE_KEY', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoic2VydmljZV9yb2xlIiwiaXNzIjoic3VwYWJhc2UiLCJpYXQiOjE3MzU2ODk2MDAsImV4cCI6MTg5MzQ1NjAwMH0.wNfmuJNkX-bZwD7RbjxOChlRf_3Xm4I7bswEYTcDCg4'); if (file_exists($envFile)) {
foreach (file($envFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) as $line) {
if (str_starts_with(trim($line), '#')) continue;
if (strpos($line, '=') === false) continue;
[$k, $v] = explode('=', $line, 2);
putenv(trim($k) . '=' . trim($v));
}
}
define('SUPABASE_URL', getenv('SUPABASE_URL') ?: 'https://safe-supabase-kong.caprover.al-arcade.com');
define('SUPABASE_ANON_KEY', getenv('SUPABASE_ANON_KEY') ?: '');
define('SUPABASE_SERVICE_KEY', getenv('SUPABASE_SERVICE_KEY') ?: '');
define('SUPABASE_REST', SUPABASE_URL . '/rest/v1'); define('SUPABASE_REST', SUPABASE_URL . '/rest/v1');
define('SUPABASE_AUTH', SUPABASE_URL . '/auth/v1'); define('SUPABASE_AUTH', SUPABASE_URL . '/auth/v1');
define('SUPABASE_STORAGE', SUPABASE_URL . '/storage/v1'); define('SUPABASE_STORAGE', SUPABASE_URL . '/storage/v1');
define('STOCKFISH_API', 'https://stockfishapi.caprover.al-arcade.com'); define('STOCKFISH_API', getenv('STOCKFISH_API') ?: 'https://stockfishapi.caprover.al-arcade.com');
define('SWISS_API', 'https://swissapi.caprover.al-arcade.com/api/v1'); define('SWISS_API', getenv('SWISS_API') ?: 'https://swissapi.caprover.al-arcade.com/api/v1');
<?php
$allowedOrigins = [
'https://el3ab-player.caprover.al-arcade.com',
'https://el3ab.caprover.al-arcade.com',
'http://localhost:3000',
'http://localhost:8080'
];
$origin = $_SERVER['HTTP_ORIGIN'] ?? '';
if (in_array($origin, $allowedOrigins, true)) {
header('Access-Control-Allow-Origin: ' . $origin);
} else {
header('Access-Control-Allow-Origin: https://el3ab-player.caprover.al-arcade.com');
}
header('Access-Control-Allow-Methods: GET, POST, DELETE, PUT, PATCH, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment