<?php
namespace Daniel230\FirehouseInterface\Services;
use Carbon\Carbon;
use Composer\InstalledVersions;
use Daniel230\FirehouseInterface\Clients\SystemClient;
class RoutesService
{
protected $redis;
protected $sysClient;
public function __construct()
{
$this->redis = new RedisService();
$this->sysClient = new SystemClient();
if ($this->isLaravel()) {
$this->registerLaravelRoute();
}
// elseif ($this->isSymfony()) {
// $this->registerSymfonyRoute();
// }
}
private function isLaravel()
{
return class_exists('Illuminate\Foundation\Application');
}
private function isSymfony()
{
return class_exists('Symfony\Component\HttpKernel\Kernel');
}
private function registerLaravelRoute()
{
// Laravel-specific endpoints
if (
class_exists('Illuminate\Support\Facades\Route') &&
class_exists('Illuminate\Http\Request') &&
class_exists('Illuminate\Support\Facades\Validator')
) {
//firehouse status
\Illuminate\Support\Facades\Route::get('/firehouse-status', function () {
$systemStatus = $this->getSystemStatus();
return response()->json($systemStatus['data'], $systemStatus['status']);
});
\Illuminate\Support\Facades\Route::get('/firehouse-setup', function () {
return response()->json('Access Denied', 403);
});
//firehouse setup
\Illuminate\Support\Facades\Route::post('/firehouse-setup', function (\Illuminate\Http\Request $request) {
$requestToken = $request->get('request_token');
$hmac = $request->headers->get('x-fh-signature');
$systemUpdateStatus = [];
if (isset($requestToken)) {
$systemUpdateStatus = $this->requestCredentialsWithToken($requestToken);
return response()->json($systemUpdateStatus, $systemUpdateStatus['status']);
} else if ($hmac) {
$payload = $request->request->all();
$timestamp = $request->get('timestamp');
$updateSystem = $this->updateSystem($hmac, $payload, $timestamp, $payload['system_config']);
$systemUpdateStatus = $updateSystem;
} else {
return response()->json("Access Denied", 403);
}
return response()->json($systemUpdateStatus, $systemUpdateStatus['status']);
});
}
//CORS
if (class_exists('Illuminate\Support\Facades\Config')) {
// Append the dynamic route to CORS paths
\Illuminate\Support\Facades\Config::set('cors.paths', array_merge(
config('cors.paths', []),
['/firehouse-status', '/firehouse-setup']
));
}
}
public function registerSymfonyStatusRoute()
{
// Check if the necessary classes exist in the Symfony context
if (class_exists('Symfony\Component\HttpFoundation\JsonResponse')) {
$systemStatus = $this->getSystemStatus();
return new \Symfony\Component\HttpFoundation\JsonResponse($systemStatus['data'], $systemStatus['status']);
}
return new \Symfony\Component\HttpFoundation\JsonResponse(['error' => 'JsonResponse class not found'], 500);
}
public function registerSymfonySetupRoute(\Symfony\Component\HttpFoundation\Request $request)
{
// Check if the necessary classes exist in the Symfony context
if (class_exists('Symfony\Component\HttpFoundation\Request') && class_exists('Symfony\Component\HttpFoundation\JsonResponse')) {
$requestToken = $request->get('request_token');
$hmac = $request->headers->get('x-fh-signature');
$systemUpdateStatus = [];
if (isset($requestToken)) {
$systemUpdateStatus = $this->requestCredentialsWithToken($requestToken);
return new \Symfony\Component\HttpFoundation\JsonResponse($systemUpdateStatus, $systemUpdateStatus['status']);
} else if ($hmac) {
$payload = $request->request->all();
$timestamp = $request->get('timestamp');
$updateSystem = $this->updateSystem($hmac, $payload, $timestamp, $payload['system_config']);
$systemUpdateStatus = $updateSystem;
} else {
return new \Symfony\Component\HttpFoundation\JsonResponse("Access Denied", 403);
}
return new \Symfony\Component\HttpFoundation\JsonResponse($systemUpdateStatus, $systemUpdateStatus['status']);
}
return new \Symfony\Component\HttpFoundation\JsonResponse("request failed", 500);
}
public function requestCredentialsWithToken($requestToken)
{
$systemUpdateStatus = [];
$response = $this->sysClient->remoteSetupRequest($requestToken);
if ($response->getStatusCode() == 200) {
$systemUpdateStatus['status'] = 200;
$encryptedCredentials = json_decode($response->getResponseBody(), true);
$api_key = $encryptedCredentials["api_key"] ?? null;
$api_secret = $encryptedCredentials["api_secret"] ?? null;
if (isset($api_key) && isset($api_secret)) {
$this->redis->setData('API_KEY', $api_key);
$this->redis->setData('API_SECRET', $api_secret);
$systemUpdateStatus['status'] = 200;
$systemUpdateStatus['message'] = 'Api credentials setup succesfully';
} else {
$systemUpdateStatus['status'] = 206;
$systemUpdateStatus['message'] = 'Missing values';
}
} else {
$systemUpdateStatus['status'] = 400;
$systemUpdateStatus['message'] = 'Bad request';
}
return $systemUpdateStatus;
}
public function getSystemStatus() {
$response = $this->sysClient->verifySystem();
if ($response->getStatusCode() == 200) {
$data = json_decode($response->getResponseBody(), true);
} else {
$data["Error"] = "Invalid setup";
}
// Add the plugin version to the data
$pluginName = 'daniel-230/firehouse-interface';
if (class_exists(InstalledVersions::class) && InstalledVersions::isInstalled($pluginName)) {
$data['fh-version'] = InstalledVersions::getPrettyVersion($pluginName);
} else {
$data['fh-version'] = null;
}
return [
'status' => $response->getStatusCode(), // Assuming sysClient response has a getStatusCode method
'data' => $data,
];
}
public function updateSystem($hmac, $payload, $timestamp, $systemConfig)
{
$systemUpdateStatus = [];
$api_secret = $this->redis->getData('API_SECRET');
$currentTime = Carbon::now();
$maxAgeInSeconds = 5 * 60;
// Check if the timestamp is within the last 5 minutes
$acceptTime = $currentTime->diffInSeconds(Carbon::createFromTimestamp($timestamp)) <= $maxAgeInSeconds;
if ($api_secret && $payload) {
if ($acceptTime) {
$calculatedSignature = hash_hmac('sha256', json_encode($payload), $api_secret);
if (hash_equals($hmac, $calculatedSignature)) {
$systemUpdateStatus['status'] = 200; // System request verified successfully
// Check and handle system configuration
if (isset($systemConfig)) {
$updatedConfigs = [];
$unsupportedConfigs = [];
foreach ($systemConfig as $config) {
// Generate the class name based on the config type
$className = str_replace(" ", "", ucwords(str_replace("_", " ", $config['type'])));
$class = 'Daniel230\\FirehouseInterface\\Models\\SystemConfigs\\' . $className;
if (class_exists($class)) {
// Instantiate the configuration class and save to Redis
$configClass = new $class($config['config']);
if (method_exists($configClass, "toArray")) {
$this->redis->setData($className, json_encode($configClass->toArray()));
$updatedConfigs[] = $config['type'];
}
$systemUpdateStatus['redis_status'][$className] = $this->redis->getData($className);
$systemUpdateStatus['redis_status'][$className] = $this->redis->getData($className);
} else {
// Track unsupported configurations
$unsupportedConfigs[] = $config['type'];
}
}
$systemUpdateStatus['updated_configs'] = $updatedConfigs;
if (!empty($unsupportedConfigs)) {
if ($updatedConfigs) {
$systemUpdateStatus['status'] = 207;
} else {
$systemUpdateStatus['status'] = 400;
}
$systemUpdateStatus['unsupported_configs'] = $unsupportedConfigs; // Some configurations were unsupported
}
} else {
$systemUpdateStatus['status'] = 400;
$systemUpdateStatus['message'] = "Invalid config";
}
} else {
$systemUpdateStatus['status'] = 403;
$systemUpdateStatus['message'] = 'Access Denied';
}
} else {
$systemUpdateStatus['status'] = 403;
$systemUpdateStatus['message'] = 'request not authorized';
}
} else {
$systemUpdateStatus['status'] = 500;
$systemUpdateStatus['message'] = 'request failed';
}
return $systemUpdateStatus;
}
}