Files
tinker_tickets/api/revoke_api_key.php
T
jaredandClaude Opus 4.8 d11cb989bf Fix API correctness: external API stub/collision, recurring dates, CSV, audit
- create_ticket_api.php: remove the wrong CREATE TABLE stub that broke a
  fresh DB; generate collision-safe ticket_ids so a genuine id collision
  isn't misreported as a duplicate and a hw alert dropped; stop leaking
  raw DB errors; correct a reopen comment that falsely claimed refreshed
  sensor data
- manage_recurring.php: fix next-run so create/edit no longer skips the
  current period (monthly day-of-month this month, daily today if time
  not passed, correct ISO weekday, month-length clamp); only recompute
  on schedule changes to avoid double-fire
- export_tickets.php, audit_log.php: neutralize CSV formula injection
- revoke_api_key.php, generate_api_key.php: correct HTTP status codes and
  stop the catch clobbering specific 4xx codes
- health.php: stop leaking PHP version / extension names / paths to
  unauthenticated callers
- watch_ticket.php: define $data before use
- manage_templates/recurring/custom_fields: add audit logging for CRUD;
  add recurring_ticket + custom_field to the audit entity whitelist

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 12:26:39 -04:00

136 lines
3.7 KiB
PHP

<?php
// API endpoint for revoking API keys (Admin only)
error_reporting(E_ALL);
ini_set('display_errors', 0);
// Apply rate limiting
require_once dirname(__DIR__) . '/middleware/RateLimitMiddleware.php';
RateLimitMiddleware::apply('api');
ob_start();
try {
// Load config
require_once dirname(__DIR__) . '/config/config.php';
require_once dirname(__DIR__) . '/helpers/Database.php';
// Load models
require_once dirname(__DIR__) . '/models/ApiKeyModel.php';
require_once dirname(__DIR__) . '/models/AuditLogModel.php';
// Check authentication via session
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
if (!isset($_SESSION['user']) || !isset($_SESSION['user']['user_id'])) {
http_response_code(401);
throw new Exception("Authentication required");
}
// Check admin privileges
if (!isset($_SESSION['user']['is_admin']) || !$_SESSION['user']['is_admin']) {
http_response_code(403);
throw new Exception("Admin privileges required");
}
// CSRF Protection
require_once dirname(__DIR__) . '/middleware/CsrfMiddleware.php';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$csrfToken = $_SERVER['HTTP_X_CSRF_TOKEN'] ?? '';
if (!CsrfMiddleware::validateToken($csrfToken)) {
http_response_code(403);
throw new Exception("Invalid CSRF token");
}
}
// Only allow POST
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
http_response_code(405);
throw new Exception("Method not allowed");
}
// Get request data
$input = json_decode(file_get_contents('php://input'), true);
if (!$input) {
http_response_code(400);
throw new Exception("Invalid request data");
}
$keyId = (int)($input['key_id'] ?? 0);
if ($keyId <= 0) {
http_response_code(400);
throw new Exception("Valid key ID is required");
}
// Use centralized database connection
$conn = Database::getConnection();
// Get key info for audit log
$apiKeyModel = new ApiKeyModel($conn);
$keyInfo = $apiKeyModel->getKeyById($keyId);
if (!$keyInfo) {
http_response_code(404);
throw new Exception("API key not found");
}
if (!$keyInfo['is_active']) {
http_response_code(409);
throw new Exception("API key is already revoked");
}
// Revoke the key
$success = $apiKeyModel->revokeKey($keyId);
if (!$success) {
http_response_code(500);
throw new Exception("Failed to revoke API key");
}
// Log the action
$auditLog = new AuditLogModel($conn);
$auditLog->log(
$_SESSION['user']['user_id'],
'revoke',
'api_key',
$keyId,
['key_name' => $keyInfo['key_name'], 'key_prefix' => $keyInfo['key_prefix']]
);
// Clear output buffer
ob_end_clean();
// Return success
header('Content-Type: application/json');
echo json_encode([
'success' => true,
'message' => 'API key revoked successfully'
]);
} catch (Exception $e) {
ob_end_clean();
header('Content-Type: application/json');
// Preserve any specific status set before the throw (401/403/404/409/...);
// only fall back to 500 when nothing more specific was set.
$code = http_response_code();
if (!is_int($code) || $code < 400) {
$code = 500;
}
http_response_code($code);
if ($code >= 500) {
error_log("Revoke API key error: " . $e->getMessage());
echo json_encode([
'success' => false,
'error' => 'An internal error occurred'
]);
} else {
echo json_encode([
'success' => false,
'error' => $e->getMessage()
]);
}
}