fix: tokens de arcos
This commit is contained in:
parent
50e028827f
commit
9bd301b55d
@ -1,6 +1,9 @@
|
||||
APP_NAME="Arcos"
|
||||
APP_ENV=local
|
||||
APP_KEY=base64:2qBv3agj3nPac2/LlDEAiQBE3vV7ycffh4lhc0ksfGM=
|
||||
# Clave dedicada para tokens de arcos RFID (NO CAMBIAR DESPUÉS DE GENERARLA)
|
||||
# Generar con: php -r "echo 'base64:' . base64_encode(random_bytes(32)) . PHP_EOL;"
|
||||
ARCO_TOKEN_ENCRYPTION_KEY=
|
||||
APP_DEBUG=true
|
||||
APP_TIMEZONE=America/Mexico_City
|
||||
APP_URL=http://localhost:8080
|
||||
@ -55,7 +58,7 @@ CACHE_PREFIX=
|
||||
MEMCACHED_HOST=127.0.0.1
|
||||
|
||||
REDIS_CLIENT=phpredis
|
||||
REDIS_HOST=127.0.0.1
|
||||
REDIS_HOST=redis
|
||||
REDIS_PASSWORD=null
|
||||
REDIS_PORT=6379
|
||||
|
||||
|
||||
@ -1,68 +1,10 @@
|
||||
<?php
|
||||
namespace App\Helpers;
|
||||
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Illuminate\Contracts\Encryption\DecryptException;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class EncryptionHelper
|
||||
{
|
||||
/**
|
||||
* Encrypt the given data (arrays/objects).
|
||||
*/
|
||||
public static function encryptData($data)
|
||||
{
|
||||
try {
|
||||
return Crypt::encryptString(json_encode($data));
|
||||
} catch (\Exception $e) {
|
||||
throw new \RuntimeException("Error al encriptar los datos: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypt the given data (arrays/objects).
|
||||
*/
|
||||
public static function decryptData($encryptedData)
|
||||
{
|
||||
try {
|
||||
$decrypted = Crypt::decryptString($encryptedData);
|
||||
return json_decode($decrypted, true);
|
||||
} catch (DecryptException $e) {
|
||||
Log::error('Error al desencriptar los datos: ' . $e->getMessage());
|
||||
return null;
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Error inesperado al desencriptar los datos: ' . $e->getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypt a simple string (for tokens, passwords, etc.)
|
||||
*/
|
||||
public static function encryptString(string $string): string
|
||||
{
|
||||
try {
|
||||
return Crypt::encryptString($string);
|
||||
} catch (\Exception $e) {
|
||||
throw new \RuntimeException("Error al encriptar el string: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypt a simple string
|
||||
*/
|
||||
public static function decryptString(string $encryptedString): ?string
|
||||
{
|
||||
try {
|
||||
return Crypt::decryptString($encryptedString);
|
||||
} catch (DecryptException $e) {
|
||||
Log::error('Error al desencriptar el string: ' . $e->getMessage());
|
||||
return null;
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Error inesperado al desencriptar el string: ' . $e->getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypt using a custom key (independent of APP_KEY)
|
||||
@ -133,50 +75,4 @@ public static function verifyWithCustomKey(string $plainValue, string $encrypted
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a hash for searchable encrypted data
|
||||
*/
|
||||
public static function hash(string $data, string $algorithm = 'sha256'): string
|
||||
{
|
||||
return hash($algorithm, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypt multiple fields in an array
|
||||
*/
|
||||
public static function encryptFields(array $data, array $fields): array
|
||||
{
|
||||
foreach ($fields as $field) {
|
||||
if (isset($data[$field])) {
|
||||
$data[$field] = self::encryptData($data[$field]);
|
||||
}
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypt multiple fields in an array
|
||||
*/
|
||||
public static function decryptFields(array $data, array $fields): array
|
||||
{
|
||||
foreach ($fields as $field) {
|
||||
if (isset($data[$field])) {
|
||||
$data[$field] = self::decryptData($data[$field]);
|
||||
}
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify if a plain value matches an encrypted value
|
||||
*/
|
||||
public static function verifyEncrypted(string $plainValue, string $encryptedValue): bool
|
||||
{
|
||||
try {
|
||||
$decrypted = self::decryptString($encryptedValue);
|
||||
return $decrypted === $plainValue;
|
||||
} catch (\Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
0
app/Helpers/arco.php
Normal file
0
app/Helpers/arco.php
Normal file
@ -23,7 +23,7 @@ public function handle(Request $request, Closure $next): Response
|
||||
]);
|
||||
}
|
||||
|
||||
// Buscar arco por token plano (el método desencripta internamente)
|
||||
// Buscar arco por token plano
|
||||
$arco = Arco::buscarPorToken($tokenPlano);
|
||||
|
||||
if (!$arco) {
|
||||
@ -39,18 +39,23 @@ public function handle(Request $request, Closure $next): Response
|
||||
}
|
||||
|
||||
// Validación de IP deshabilitada para desarrollo
|
||||
// TODO: Habilitar en producción o configurar nginx para enviar X-Forwarded-For
|
||||
// $requestIp = $request->ip();
|
||||
// if ($arco->ip_address !== $requestIp) {
|
||||
// return ApiResponse::FORBIDDEN->response([
|
||||
// 'message' => 'Token no autorizado para esta IP',
|
||||
// 'detail' => [
|
||||
// 'ip_registrada_arco' => $arco->ip_address,
|
||||
// 'ip_del_request' => $requestIp,
|
||||
// 'arco_nombre' => $arco->nombre
|
||||
// ]
|
||||
// ]);
|
||||
// }
|
||||
// PROBLEMA: En Docker, $request->ip() retorna la IP del gateway (172.x.x.x), no la IP real del cliente
|
||||
// SOLUCIÓN PRODUCCIÓN: Usar un proxy inverso externo (nginx/traefik) que pase X-Forwarded-For correctamente
|
||||
// Para desarrollo, la validación de token es suficiente
|
||||
/*
|
||||
$requestIp = $request->ip();
|
||||
if ($arco->ip_address !== $requestIp) {
|
||||
return ApiResponse::FORBIDDEN->response([
|
||||
'message' => 'Token no autorizado para esta IP',
|
||||
'detail' => [
|
||||
'ip_registrada_arco' => $arco->ip_address,
|
||||
'ip_del_request' => $requestIp,
|
||||
'arco_nombre' => $arco->nombre
|
||||
]
|
||||
]);
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
// Agregar el arco al request para uso posterior
|
||||
$request->merge(['arco_autenticado' => $arco]);
|
||||
|
||||
@ -49,11 +49,33 @@ protected static function boot()
|
||||
static::creating(function ($arco) {
|
||||
if (!$arco->api_token) {
|
||||
$plainToken = Str::random(64);
|
||||
$arco->api_token = EncryptionHelper::encryptString($plainToken);
|
||||
$arco->api_token = EncryptionHelper::encryptWithCustomKey(
|
||||
$plainToken,
|
||||
self::getEncryptionKey()
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtener la clave de encriptación personalizada para tokens de arcos
|
||||
*/
|
||||
private static function getEncryptionKey(): string
|
||||
{
|
||||
$key = config('app.arco_token_encryption_key');
|
||||
|
||||
if (empty($key)) {
|
||||
throw new \RuntimeException('ARCO_TOKEN_ENCRYPTION_KEY no está configurada en .env');
|
||||
}
|
||||
|
||||
// Si la clave está en formato base64:xxxx, decodificarla
|
||||
if (str_starts_with($key, 'base64:')) {
|
||||
return base64_decode(substr($key, 7));
|
||||
}
|
||||
|
||||
return $key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Relación con detecciones
|
||||
*/
|
||||
@ -87,7 +109,7 @@ public static function buscarPorToken(string $tokenPlano): ?self
|
||||
|
||||
foreach ($arcos as $arco) {
|
||||
// Desencriptar el token de la BD y comparar con el token plano recibido
|
||||
if (EncryptionHelper::verifyEncrypted($tokenPlano, $arco->api_token)) {
|
||||
if (EncryptionHelper::verifyWithCustomKey($tokenPlano, $arco->api_token, self::getEncryptionKey())) {
|
||||
return $arco;
|
||||
}
|
||||
}
|
||||
@ -101,7 +123,10 @@ public static function buscarPorToken(string $tokenPlano): ?self
|
||||
public function regenerarToken(): string
|
||||
{
|
||||
$plainToken = Str::random(64);
|
||||
$this->api_token = EncryptionHelper::encryptString($plainToken);
|
||||
$this->api_token = EncryptionHelper::encryptWithCustomKey(
|
||||
$plainToken,
|
||||
self::getEncryptionKey()
|
||||
);
|
||||
$this->save();
|
||||
|
||||
return $plainToken;
|
||||
@ -112,6 +137,6 @@ public function regenerarToken(): string
|
||||
*/
|
||||
public function obtenerTokenDesencriptado(): ?string
|
||||
{
|
||||
return EncryptionHelper::decryptString($this->api_token);
|
||||
return EncryptionHelper::decryptWithCustomKey($this->api_token, self::getEncryptionKey());
|
||||
}
|
||||
}
|
||||
|
||||
@ -104,6 +104,19 @@
|
||||
|
||||
'key' => env('APP_KEY'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Arco Token Encryption Key
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This key is used to encrypt the API tokens for RFID arcos. Unlike APP_KEY,
|
||||
| this key should NEVER change once set, as changing it will invalidate all
|
||||
| existing arco tokens. Store this key securely and back it up.
|
||||
|
|
||||
*/
|
||||
|
||||
'arco_token_encryption_key' => env('ARCO_TOKEN_ENCRYPTION_KEY'),
|
||||
|
||||
'previous_keys' => [
|
||||
...array_filter(
|
||||
explode(',', env('APP_PREVIOUS_KEYS', ''))
|
||||
|
||||
@ -3,6 +3,9 @@ services:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: dockerfile
|
||||
args:
|
||||
USER_ID: 1000
|
||||
GROUP_ID: 1000
|
||||
working_dir: /var/www/arcos-backend
|
||||
environment:
|
||||
- DB_HOST=mysql
|
||||
|
||||
10
dockerfile
10
dockerfile
@ -15,6 +15,7 @@ RUN apk add --no-cache \
|
||||
openssl \
|
||||
bash \
|
||||
mysql-client \
|
||||
su-exec \
|
||||
&& docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd zip
|
||||
|
||||
# Instalar extensión de Redis
|
||||
@ -33,10 +34,11 @@ COPY . .
|
||||
COPY entrypoint-dev.sh /usr/local/bin/entrypoint-dev.sh
|
||||
RUN chmod +x /usr/local/bin/entrypoint-dev.sh
|
||||
|
||||
RUN mkdir -p storage/app/keys storage/logs bootstrap/cache
|
||||
|
||||
RUN chown -R www-data:www-data /var/www/arcos-backend/storage /var/www/arcos-backend/bootstrap/cache
|
||||
RUN chmod -R 775 /var/www/arcos-backend/storage /var/www/arcos-backend/bootstrap/cache
|
||||
ARG USER_ID=1000
|
||||
ARG GROUP_ID=1000
|
||||
RUN apk add --no-cache shadow && \
|
||||
usermod -u ${USER_ID} www-data && \
|
||||
groupmod -g ${GROUP_ID} www-data
|
||||
|
||||
EXPOSE 9000
|
||||
|
||||
|
||||
@ -1,10 +1,16 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
git config --global --add safe.directory /var/www/repuve-v1
|
||||
# Configurar Git sin necesidad de permisos globales
|
||||
export GIT_CONFIG_GLOBAL=/tmp/.gitconfig
|
||||
git config --global --add safe.directory /var/www/pdv.backend
|
||||
|
||||
echo "=== Iniciando entrypoint DESARROLLO ==="
|
||||
|
||||
# Asegurar permisos correctos para directorios críticos
|
||||
echo "Verificando permisos de directorios..."
|
||||
chown -R www-data:www-data /var/www/arcos-backend/vendor /var/www/arcos-backend/storage /var/www/arcos-backend/bootstrap/cache 2>/dev/null || true
|
||||
|
||||
# Variables desde Docker environment
|
||||
DB_HOST=${DB_HOST:-mysql}
|
||||
DB_USERNAME=${DB_USERNAME:-root}
|
||||
@ -79,7 +85,6 @@ fi
|
||||
# Establecer permisos correctos para las claves
|
||||
chmod 600 storage/app/keys/oauth-private.key
|
||||
chmod 644 storage/app/keys/oauth-public.key
|
||||
chown www-data:www-data storage/app/keys/oauth-*.key
|
||||
|
||||
echo "✓ Claves de Passport verificadas"
|
||||
|
||||
@ -111,5 +116,5 @@ echo "✓ Configuración de desarrollo completada"
|
||||
|
||||
echo "=== Iniciando PHP-FPM DESARROLLO ==="
|
||||
|
||||
# Iniciar PHP-FPM
|
||||
exec "$@"
|
||||
# Iniciar PHP-FPM como usuario www-data
|
||||
exec su-exec www-data "$@"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user