orderBy('created_at', 'asc')->first(); if ($existing && !$this->option('force')) { $this->line('Active PBX API credentials already exist (ID: ' . $existing->id . ', client_id: ' . $existing->api_user . ').'); $this->line('Use --force to regenerate.'); return 0; } // Deactivate old credentials and remove their FreePBX entries when forcing if ($existing && $this->option('force')) { $this->line('Deactivating existing credentials...'); $oldIds = PBXApiCredential::where('is_active', true)->pluck('api_user'); PBXApiCredential::where('is_active', true)->update(['is_active' => false]); foreach ($oldIds as $oldClientId) { try { DB::table('asterisk.api_applications')->where('client_id', $oldClientId)->delete(); } catch (\Exception $e) { // best-effort cleanup } } } $name = $this->option('name') ?? 'Laravel CCS API'; $apiUrl = config('pbx.api_url', 'http://127.0.0.1'); // FreePBX uses bin2hex(random_bytes(N)) format for its own generated IDs $clientId = bin2hex(random_bytes(16)); // 32-char hex, fits varchar(128) $clientSecret = bin2hex(random_bytes(32)); // 64-char hex — raw value stored in Laravel $hashedSecret = hash('sha256', $clientSecret); // stored in FreePBX // Step 1 — Register with FreePBX via direct DB insert into asterisk.api_applications. // This must succeed before we store anything in Laravel, so we fail fast on error. try { DB::table('asterisk.api_applications')->insert([ 'owner' => null, 'name' => substr($name, 0, 50), // varchar(50) limit 'description' => 'Laravel CCS System', 'grant_type' => 'client_credentials', 'client_id' => $clientId, 'client_secret' => $hashedSecret, 'redirect_uri' => null, 'website' => null, 'algo' => 'sha256', // null = no scope restriction → FreePBX defaults to full gql + rest access 'allowed_scopes' => null, ]); } catch (\Exception $e) { $this->error('Failed to register credentials in FreePBX (asterisk.api_applications): ' . $e->getMessage()); \Log::error('pbx:generate-credentials failed to insert into api_applications', ['error' => $e->getMessage()]); return 1; } // Step 2 — Persist encrypted credentials in the Laravel database try { $credential = PBXApiCredential::create([ 'name' => $name, 'api_user' => $clientId, 'api_secret' => $clientSecret, // encrypted by model mutator 'api_url' => $apiUrl, 'is_active' => true, ]); } catch (\Exception $e) { // Roll back the FreePBX entry so state stays consistent DB::table('asterisk.api_applications')->where('client_id', $clientId)->delete(); $this->error('Failed to store credentials in Laravel database: ' . $e->getMessage()); \Log::error('pbx:generate-credentials failed to create PBXApiCredential', ['error' => $e->getMessage()]); return 1; } $this->line('PBX API credentials generated successfully.'); $this->line(' DB ID : ' . $credential->id); $this->line(' Client ID : ' . $clientId); $this->line(' API URL : ' . $apiUrl); $this->line(' FreePBX : registered in asterisk.api_applications'); \Log::info('pbx:generate-credentials completed', [ 'credential_id' => $credential->id, 'client_id' => $clientId, ]); return 0; } }