seedproject-web/api/app/Helpers/Auth.php
Carlos Arias 1559ce017d chore: scaffold SeedProject base (Phase 1)
Clean-room copy of the reusable engines from comiida, with all
instance data, secrets, dependencies, and build output excluded:
- app/         Astro theme skeleton (no comiida blog posts; hero image -> placeholder)
- api/         SeedProject PHP framework (no vendor/.env/config.php)
- content-pipeline/  engine only (scripts/admin/prompts; empty runtime state)
- astroagent.config.json + app/.astroagent/skills

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SYHWLHihq3v9nxNwoPCKSn
2026-07-04 22:53:10 +00:00

119 lines
4.3 KiB
PHP

<?php
class Auth {
// ─── API Authentication ───────────────────────────────────────────────────
public static function API() {
header('Access-Control-Allow-Origin: *');
// Ajax requests from inside the server pass through
if (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
return null;
}
// External requests require API key
if ($_SERVER['REMOTE_ADDR'] != $_SERVER['SERVER_ADDR']) {
if (SECUREAPI) {
$headers = apache_request_headers();
if ($headers['X-Authorization'] != AUTHORIZATION) die('Access Denied');
}
$ApiKey = $_REQUEST['apikey'];
$ApiUser = \Db::getRow("SELECT * FROM sp_users_api WHERE apikey = '{$ApiKey}'");
if (!$ApiUser) {
Logger::Entry([
'userid' => 0,
'trigval' => 'security.api_auth_failed',
'msgval' => 'Invalid API key presented',
'status' => 1,
]);
$Return = ['code' => '401', 'msg' => 'Unauthorized: Api Invalid'];
header('Content-Type: application/json;charset=UTF-8');
echo json_encode($Return);
exit();
}
$Return['code'] = '1';
$Return['userid'] = $ApiUser['userid'];
return $Return;
}
}
// ─── Session Login Check ──────────────────────────────────────────────────
public static function handleLogin() {
$logged = $_SESSION['login'];
if ($logged == false) {
session_destroy();
header('location: /login');
exit;
}
return $logged;
}
// ─── Load Permissions into Session ───────────────────────────────────────
// Call this once after successful login.
public static function loadPermissions(int $roleId): void {
$rows = \Db::select("
SELECT p.perm_controller, p.perm_action
FROM sp_role_perm rp
JOIN sp_permissions p ON rp.perm_id = p.perm_id
WHERE rp.role_id = ?
", [$roleId]);
$permissions = [];
foreach ($rows as $row) {
$permissions[] = $row['perm_controller'] . '.' . $row['perm_action'];
}
$_SESSION['permissions'] = $permissions;
}
// ─── Permission Checks ────────────────────────────────────────────────────
/**
* Returns true if the current user has the given permission.
* Permission format: 'controller.action' e.g. 'users.create'
*/
public static function can(string $permission): bool {
$permissions = $_SESSION['permissions'] ?? [];
return in_array($permission, $permissions);
}
/**
* Halts execution with a 403 JSON response if the user lacks the permission.
* Use in API controllers.
*/
public static function requirePermission(string $permission): void {
if (!self::can($permission)) {
Logger::Entry([
'userid' => $_SESSION['login']['userid'] ?? 0,
'trigval' => 'security.permission_denied',
'msgval' => 'Permission denied: ' . $permission,
'status' => 1,
]);
http_response_code(403);
header('Content-Type: application/json');
echo json_encode(['success' => false, 'error' => 'Permission denied']);
exit;
}
}
/**
* Returns all permissions for the current user as an array.
*/
public static function getPermissions(): array {
return $_SESSION['permissions'] ?? [];
}
/**
* Returns a JS-safe array of the current user's permissions.
* Use in header partial to inject into window.AppUser.
*/
public static function getPermissionsJson(): string {
return json_encode(self::getPermissions());
}
}