src/utils files conversion

This commit is contained in:
armiejean 2025-04-11 11:08:13 +08:00
parent 6db9461437
commit 8cce215ce4
11 changed files with 406 additions and 2 deletions

41
app/Helpers/Helper.php Normal file
View File

@ -0,0 +1,41 @@
<?php
if (!function_exists('fnQueryParams')) {
function fnQueryParams(array $params): string
{
$query = '';
foreach ($params as $key => $value) {
if ($value) {
if (is_array($value)) {
foreach ($value as $item) {
$query .= http_build_query([$key => $item]) . '&';
}
} else {
$query .= http_build_query([$key => $value]) . '&';
}
}
}
return $query ? '?' . rtrim($query, '&') : '';
}
}
if (!function_exists('isEmpty')) {
function isEmpty(array $obj): bool
{
return empty(array_filter($obj));
}
}
if (!function_exists('apiFormValidation')) {
function apiFormValidation(array $data, callable $setErrors): void
{
$errors = [];
foreach ($data as $key => $value) {
if (is_array($value) && isset($value[0])) {
$errors[$key] = $value[0];
}
}
$setErrors($errors);
}
}

View File

@ -12,6 +12,10 @@ class AppServiceProvider extends ServiceProvider
$this->app->singleton(ApiService::class, function () { $this->app->singleton(ApiService::class, function () {
return new ApiService(); return new ApiService();
}); });
$this->app->singleton(ApiService::class, fn () => new ApiService());
$this->app->singleton(NotificationApiService::class, fn () => new NotificationApiService());
$this->app->singleton(StationApiService::class, fn () => new StationApiService());
$this->app->singleton(CookieService::class, fn () => new CookieService());
} }
public function boot() public function boot()

View File

@ -70,4 +70,26 @@ class ApiService
throw new \Exception('API error: ' . ($response->body() ?: 'Unknown error')); throw new \Exception('API error: ' . ($response->body() ?: 'Unknown error'));
} }
} }
public function get($url, $params = [])
{
$token = $this->cookieService->getCookie()['token'] ?? null;
$this->defaultHeaders['Authorization'] = 'Bearer ' . $token;
return $this->makeRequest('get', $url, $params);
}
public function post($url, $params = [])
{
return $this->makeRequest('post', $url, $params);
}
public function put($url, $params = [])
{
return $this->makeRequest('put', $url, $params);
}
public function delete($url, $params = [])
{
return $this->makeRequest('delete', $url, ['params' => $params]);
}
} }

View File

@ -0,0 +1,57 @@
<?php
namespace App\Services;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\Facades\Log;
use App\Livewire\ErrorHandler;
class BaseApiService
{
protected $baseUrl;
protected $defaultHeaders = [];
public function __construct(string $baseUrl)
{
$this->baseUrl = $baseUrl;
}
protected function makeRequest($method, $url, $params = [], $headers = [])
{
try {
$fullHeaders = array_merge($this->defaultHeaders, $headers, [
'Authorization' => 'Bearer ' . Session::get('token', ''),
]);
$response = Http::withHeaders($fullHeaders)->{$method}($this->baseUrl . $url, $params);
if ($response->successful()) {
return $response->json();
} else {
$this->handleError($response);
return null;
}
} catch (\Exception $e) {
Log::error('API Request Error: ' . $e->getMessage());
Session::flash('error', 'API request failed: ' . $e->getMessage());
return null;
}
}
protected function handleError($response)
{
$status = $response->status();
if ($status === 401) {
Session::forget('token');
throw new \Exception('Session expired. Please login again.');
} elseif ($status === 422) {
throw new \Exception('Validation error: ' . ($response->body() ?: 'Unknown validation error'));
} elseif ($status === 404) {
throw new \Exception('API resource not found.');
} else {
throw new \Exception('API error: ' . ($response->body() ?: 'Unknown error'));
}
}
}

View File

@ -0,0 +1,55 @@
<?php
namespace App\Services;
use Illuminate\Support\Facades\Cookie;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\Log;
class CookieService
{
const COOKIE_NAME = 'FRONT_END_REST';
const PUBLIC_KEY = 'PUBLIC_00001';
const TIME_OUT_HOURS = 1; // 60 minutes
public function setCookie(array $params, string $name = self::COOKIE_NAME): bool
{
try {
if (!is_array($params)) {
throw new \TypeError('setCookie params should be an array.', 'CookieService.php', 20);
}
$expiration = now()->addHours(self::TIME_OUT_HOURS);
$encryptedValue = Crypt::encryptString(json_encode($params));
Cookie::queue($name, $encryptedValue, $expiration->diffInMinutes(), '/', null, false, true);
return true;
} catch (\Exception $e) {
Log::error('Cookie Set Error: ' . $e->getMessage());
return false;
}
}
public function getCookie(string $name = self::COOKIE_NAME)
{
$cookie = Cookie::get($name);
if (!$cookie) {
return null;
}
try {
return json_decode(Crypt::decryptString($cookie), true);
} catch (\Exception $e) {
Log::error('Cookie Get Error: ' . $e->getMessage());
return null;
}
}
public function removeCookie(string $name = self::COOKIE_NAME): bool
{
Cookie::queue(Cookie::forget($name));
return true;
}
}

View File

@ -0,0 +1,50 @@
<?php
namespace App\Services;
use Illuminate\Support\Facades\Session;
class EncryptionService
{
const ALGORITHM = 'aes-256-ctr';
private $password;
public function __construct()
{
$this->password = $this->getPasswordFromCookie();
}
private function getPasswordFromCookie()
{
$cookieService = app(CookieService::class);
$cookie = $cookieService->getCookie(process.env.REACT_APP_TOKEN ?? 'token');
return $cookie['token'] ?? 'default_password'; // Fallback if token not found
}
public function encrypt(string $text): string
{
$iv = random_bytes(16); // Initialization vector
$encrypted = openssl_encrypt($text, self::ALGORITHM, $this->password, 0, $iv);
return base64_encode($iv . $encrypted); // Combine IV and encrypted data
}
public function decrypt(string $text): string|bool
{
$data = base64_decode($text);
$iv = substr($data, 0, 16);
$encrypted = substr($data, 16);
$decrypted = openssl_decrypt($encrypted, self::ALGORITHM, $this->password, 0, $iv);
if ($decrypted === false) {
return false;
}
// Check if the result is hexadecimal (simulating your JS check)
if (preg_match('/^[0-9a-fA-F]+$/', $decrypted)) {
return $decrypted;
}
return false;
}
}

View File

@ -0,0 +1,21 @@
<?php
namespace App\Services;
class NotificationApiService extends BaseApiService
{
public function __construct()
{
parent::__construct(config('app.notif_api_base_url'));
}
public function getNotification($url, $params = [])
{
return $this->makeRequest('get', $url, $params);
}
public function postNotification($url, $params = [])
{
return $this->makeRequest('post', $url, $params);
}
}

View File

@ -0,0 +1,56 @@
<?php
namespace App\Services;
class StationApiService extends BaseApiService
{
public function __construct()
{
parent::__construct(config('app.station_api_base_url'));
$this->defaultHeaders = array_merge($this->defaultHeaders, [
'X-Requested-With' => 'station-locator-api',
]);
}
public function getBranch($url, $params = [])
{
return $this->makeRequest('get', $url, $params);
}
public function postBranch($url, $params = [])
{
return $this->makeRequest('post', $url, $params);
}
public function putBranch($url, $params = [])
{
return $this->makeRequest('put', $url, $params);
}
public function deleteBranch($url, $params = [])
{
return $this->makeRequest('delete', $url, ['params' => $params]);
}
public function postFuel($url, $params = [])
{
return $this->makeRequest('post', $url, $params);
}
public function putFuel($url, $params = [])
{
return $this->makeRequest('put', $url, $params);
}
public function getFuels($url, $params = [])
{
return $this->makeRequest('get', $url, $params);
}
public function getCsv($url, $params = [])
{
return Http::withHeaders(array_merge($this->defaultHeaders, [
'Authorization' => 'Bearer ' . Session::get('token', ''),
]))->get($this->baseUrl . $url, $params)->body(); // Return raw text for CSV
}
}

View File

@ -11,7 +11,8 @@
"laravel/framework": "^11.31", "laravel/framework": "^11.31",
"laravel/tinker": "^2.9", "laravel/tinker": "^2.9",
"laravel/ui": "^4.6", "laravel/ui": "^4.6",
"livewire/livewire": "^3.6" "livewire/livewire": "^3.6",
"paragonie/sodium_compat": "^2.1"
}, },
"require-dev": { "require-dev": {
"fakerphp/faker": "^1.23", "fakerphp/faker": "^1.23",
@ -24,6 +25,9 @@
"phpunit/phpunit": "^11.0.1" "phpunit/phpunit": "^11.0.1"
}, },
"autoload": { "autoload": {
"files": [
"app/Helpers/Helper.php"
],
"psr-4": { "psr-4": {
"App\\": "app/", "App\\": "app/",
"Database\\Factories\\": "database/factories/", "Database\\Factories\\": "database/factories/",

93
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "285c8ee44334e3e198f19e9bd78c85e5", "content-hash": "76604e550276fef9afccacf4143ff3aa",
"packages": [ "packages": [
{ {
"name": "brick/math", "name": "brick/math",
@ -2647,6 +2647,97 @@
], ],
"time": "2024-11-21T10:39:51+00:00" "time": "2024-11-21T10:39:51+00:00"
}, },
{
"name": "paragonie/sodium_compat",
"version": "v2.1.0",
"source": {
"type": "git",
"url": "https://github.com/paragonie/sodium_compat.git",
"reference": "a673d5f310477027cead2e2f2b6db5d8368157cb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/paragonie/sodium_compat/zipball/a673d5f310477027cead2e2f2b6db5d8368157cb",
"reference": "a673d5f310477027cead2e2f2b6db5d8368157cb",
"shasum": ""
},
"require": {
"php": "^8.1",
"php-64bit": "*"
},
"require-dev": {
"phpunit/phpunit": "^7|^8|^9",
"vimeo/psalm": "^4|^5"
},
"suggest": {
"ext-sodium": "Better performance, password hashing (Argon2i), secure memory management (memzero), and better security."
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0.x-dev"
}
},
"autoload": {
"files": [
"autoload.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"ISC"
],
"authors": [
{
"name": "Paragon Initiative Enterprises",
"email": "security@paragonie.com"
},
{
"name": "Frank Denis",
"email": "jedisct1@pureftpd.org"
}
],
"description": "Pure PHP implementation of libsodium; uses the PHP extension if it exists",
"keywords": [
"Authentication",
"BLAKE2b",
"ChaCha20",
"ChaCha20-Poly1305",
"Chapoly",
"Curve25519",
"Ed25519",
"EdDSA",
"Edwards-curve Digital Signature Algorithm",
"Elliptic Curve Diffie-Hellman",
"Poly1305",
"Pure-PHP cryptography",
"RFC 7748",
"RFC 8032",
"Salpoly",
"Salsa20",
"X25519",
"XChaCha20-Poly1305",
"XSalsa20-Poly1305",
"Xchacha20",
"Xsalsa20",
"aead",
"cryptography",
"ecdh",
"elliptic curve",
"elliptic curve cryptography",
"encryption",
"libsodium",
"php",
"public-key cryptography",
"secret-key cryptography",
"side-channel resistant"
],
"support": {
"issues": "https://github.com/paragonie/sodium_compat/issues",
"source": "https://github.com/paragonie/sodium_compat/tree/v2.1.0"
},
"time": "2024-09-04T12:51:01+00:00"
},
{ {
"name": "phpoption/phpoption", "name": "phpoption/phpoption",
"version": "1.9.3", "version": "1.9.3",

View File

@ -14,6 +14,9 @@ return [
*/ */
'name' => env('APP_NAME', 'Laravel'), 'name' => env('APP_NAME', 'Laravel'),
'api_base_url' => env('API_BASE_URL', 'https://your-backend-api.com/api'),
'notif_api_base_url' => env('NOTIF_API_BASE_URL', 'https://your-backend-api.com/notif'),
'station_api_base_url' => env('STATION_API_BASE_URL', 'https://your-backend-api.com/station'),
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------