fix(blueprint): Review fixes — API key lookup, tier enforcement, safety

Fixes 10 issues from Blueprint extension code review:
- CurseForge API key now reads via Blueprint dbGet() matching admin save
- PRO-tier fields (webhook, interval) enforced server-side, not just UI
- json_decode results validated before accessing parsed data
- Null user guard on getStatus() endpoint
- 429 response uses consistent error key format
- Modrinth slug derivation strips special chars, documented as fallback
- Check interval dropdown reflects saved value
- API key input changed to password type
- TypeScript error typing narrowed from any to unknown
- Removed unused DB import from ModpackApiService

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Claude (Chronicler #83 - The Compiler)
2026-04-12 13:53:37 -05:00
parent 3457b87aef
commit b0aa52c2c8
5 changed files with 32 additions and 19 deletions

View File

@@ -72,7 +72,7 @@ class ModpackAPIController extends Controller
$seconds = RateLimiter::availableIn($limitKey);
return response()->json([
'success' => false,
'message' => "Too many requests. Please wait {$seconds} seconds before checking again."
'error' => "Too many requests. Please wait {$seconds} seconds before checking again.",
], 429);
}
RateLimiter::hit($limitKey, 60);
@@ -161,7 +161,7 @@ class ModpackAPIController extends Controller
$manifest = $this->readServerFile($server, 'manifest.json');
if ($manifest) {
$data = json_decode($manifest, true);
if (isset($data['manifestType']) && $data['manifestType'] === 'minecraftModpack') {
if (is_array($data) && isset($data['manifestType']) && $data['manifestType'] === 'minecraftModpack') {
return [
'platform' => 'curseforge',
'modpack_id' => $data['projectID'] ?? null,
@@ -175,10 +175,12 @@ class ModpackAPIController extends Controller
$modrinthIndex = $this->readServerFile($server, 'modrinth.index.json');
if ($modrinthIndex) {
$data = json_decode($modrinthIndex, true);
if (isset($data['formatVersion'])) {
// Use the pack name as the Modrinth project slug for API lookups.
if (is_array($data) && isset($data['formatVersion'])) {
// Best-effort slug derivation from pack name for API lookups.
// dependencies.minecraft is a MC version (e.g. "1.20.1"), NOT a project ID.
$slug = isset($data['name']) ? strtolower(str_replace(' ', '-', $data['name'])) : null;
// NOTE: This may not match the actual Modrinth slug if the project name
// differs from its URL slug. Set MODPACK_ID egg variable for reliability.
$slug = isset($data['name']) ? preg_replace('/[^a-z0-9-]/', '', strtolower(str_replace(' ', '-', $data['name']))) : null;
return [
'platform' => 'modrinth',
'modpack_id' => $slug,
@@ -225,7 +227,10 @@ class ModpackAPIController extends Controller
public function getStatus(Request $request): JsonResponse
{
$user = $request->user();
if (!$user) {
return response()->json([], 401);
}
// Get all server UUIDs the user has access to
$serverUuids = $user->accessibleServers()->pluck('uuid')->toArray();