fix: tokens de arcos
This commit is contained in:
parent
50e028827f
commit
9bd301b55d
@ -1,6 +1,9 @@
|
|||||||
APP_NAME="Arcos"
|
APP_NAME="Arcos"
|
||||||
APP_ENV=local
|
APP_ENV=local
|
||||||
APP_KEY=base64:2qBv3agj3nPac2/LlDEAiQBE3vV7ycffh4lhc0ksfGM=
|
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_DEBUG=true
|
||||||
APP_TIMEZONE=America/Mexico_City
|
APP_TIMEZONE=America/Mexico_City
|
||||||
APP_URL=http://localhost:8080
|
APP_URL=http://localhost:8080
|
||||||
@ -55,7 +58,7 @@ CACHE_PREFIX=
|
|||||||
MEMCACHED_HOST=127.0.0.1
|
MEMCACHED_HOST=127.0.0.1
|
||||||
|
|
||||||
REDIS_CLIENT=phpredis
|
REDIS_CLIENT=phpredis
|
||||||
REDIS_HOST=127.0.0.1
|
REDIS_HOST=redis
|
||||||
REDIS_PASSWORD=null
|
REDIS_PASSWORD=null
|
||||||
REDIS_PORT=6379
|
REDIS_PORT=6379
|
||||||
|
|
||||||
|
|||||||
@ -1,68 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace App\Helpers;
|
namespace App\Helpers;
|
||||||
|
|
||||||
use Illuminate\Support\Facades\Crypt;
|
|
||||||
use Illuminate\Contracts\Encryption\DecryptException;
|
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
class EncryptionHelper
|
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)
|
* 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);
|
$arco = Arco::buscarPorToken($tokenPlano);
|
||||||
|
|
||||||
if (!$arco) {
|
if (!$arco) {
|
||||||
@ -39,18 +39,23 @@ public function handle(Request $request, Closure $next): Response
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Validación de IP deshabilitada para desarrollo
|
// Validación de IP deshabilitada para desarrollo
|
||||||
// TODO: Habilitar en producción o configurar nginx para enviar X-Forwarded-For
|
// PROBLEMA: En Docker, $request->ip() retorna la IP del gateway (172.x.x.x), no la IP real del cliente
|
||||||
// $requestIp = $request->ip();
|
// SOLUCIÓN PRODUCCIÓN: Usar un proxy inverso externo (nginx/traefik) que pase X-Forwarded-For correctamente
|
||||||
// if ($arco->ip_address !== $requestIp) {
|
// Para desarrollo, la validación de token es suficiente
|
||||||
// return ApiResponse::FORBIDDEN->response([
|
/*
|
||||||
// 'message' => 'Token no autorizado para esta IP',
|
$requestIp = $request->ip();
|
||||||
// 'detail' => [
|
if ($arco->ip_address !== $requestIp) {
|
||||||
// 'ip_registrada_arco' => $arco->ip_address,
|
return ApiResponse::FORBIDDEN->response([
|
||||||
// 'ip_del_request' => $requestIp,
|
'message' => 'Token no autorizado para esta IP',
|
||||||
// 'arco_nombre' => $arco->nombre
|
'detail' => [
|
||||||
// ]
|
'ip_registrada_arco' => $arco->ip_address,
|
||||||
// ]);
|
'ip_del_request' => $requestIp,
|
||||||
// }
|
'arco_nombre' => $arco->nombre
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
// Agregar el arco al request para uso posterior
|
// Agregar el arco al request para uso posterior
|
||||||
$request->merge(['arco_autenticado' => $arco]);
|
$request->merge(['arco_autenticado' => $arco]);
|
||||||
|
|||||||
@ -49,11 +49,33 @@ protected static function boot()
|
|||||||
static::creating(function ($arco) {
|
static::creating(function ($arco) {
|
||||||
if (!$arco->api_token) {
|
if (!$arco->api_token) {
|
||||||
$plainToken = Str::random(64);
|
$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
|
* Relación con detecciones
|
||||||
*/
|
*/
|
||||||
@ -87,7 +109,7 @@ public static function buscarPorToken(string $tokenPlano): ?self
|
|||||||
|
|
||||||
foreach ($arcos as $arco) {
|
foreach ($arcos as $arco) {
|
||||||
// Desencriptar el token de la BD y comparar con el token plano recibido
|
// 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;
|
return $arco;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -101,7 +123,10 @@ public static function buscarPorToken(string $tokenPlano): ?self
|
|||||||
public function regenerarToken(): string
|
public function regenerarToken(): string
|
||||||
{
|
{
|
||||||
$plainToken = Str::random(64);
|
$plainToken = Str::random(64);
|
||||||
$this->api_token = EncryptionHelper::encryptString($plainToken);
|
$this->api_token = EncryptionHelper::encryptWithCustomKey(
|
||||||
|
$plainToken,
|
||||||
|
self::getEncryptionKey()
|
||||||
|
);
|
||||||
$this->save();
|
$this->save();
|
||||||
|
|
||||||
return $plainToken;
|
return $plainToken;
|
||||||
@ -112,6 +137,6 @@ public function regenerarToken(): string
|
|||||||
*/
|
*/
|
||||||
public function obtenerTokenDesencriptado(): ?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'),
|
'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' => [
|
'previous_keys' => [
|
||||||
...array_filter(
|
...array_filter(
|
||||||
explode(',', env('APP_PREVIOUS_KEYS', ''))
|
explode(',', env('APP_PREVIOUS_KEYS', ''))
|
||||||
|
|||||||
@ -3,6 +3,9 @@ services:
|
|||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: dockerfile
|
dockerfile: dockerfile
|
||||||
|
args:
|
||||||
|
USER_ID: 1000
|
||||||
|
GROUP_ID: 1000
|
||||||
working_dir: /var/www/arcos-backend
|
working_dir: /var/www/arcos-backend
|
||||||
environment:
|
environment:
|
||||||
- DB_HOST=mysql
|
- DB_HOST=mysql
|
||||||
|
|||||||
10
dockerfile
10
dockerfile
@ -15,6 +15,7 @@ RUN apk add --no-cache \
|
|||||||
openssl \
|
openssl \
|
||||||
bash \
|
bash \
|
||||||
mysql-client \
|
mysql-client \
|
||||||
|
su-exec \
|
||||||
&& docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd zip
|
&& docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd zip
|
||||||
|
|
||||||
# Instalar extensión de Redis
|
# Instalar extensión de Redis
|
||||||
@ -33,10 +34,11 @@ COPY . .
|
|||||||
COPY entrypoint-dev.sh /usr/local/bin/entrypoint-dev.sh
|
COPY entrypoint-dev.sh /usr/local/bin/entrypoint-dev.sh
|
||||||
RUN chmod +x /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
|
ARG USER_ID=1000
|
||||||
|
ARG GROUP_ID=1000
|
||||||
RUN chown -R www-data:www-data /var/www/arcos-backend/storage /var/www/arcos-backend/bootstrap/cache
|
RUN apk add --no-cache shadow && \
|
||||||
RUN chmod -R 775 /var/www/arcos-backend/storage /var/www/arcos-backend/bootstrap/cache
|
usermod -u ${USER_ID} www-data && \
|
||||||
|
groupmod -g ${GROUP_ID} www-data
|
||||||
|
|
||||||
EXPOSE 9000
|
EXPOSE 9000
|
||||||
|
|
||||||
|
|||||||
@ -1,10 +1,16 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
set -e
|
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 ==="
|
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
|
# Variables desde Docker environment
|
||||||
DB_HOST=${DB_HOST:-mysql}
|
DB_HOST=${DB_HOST:-mysql}
|
||||||
DB_USERNAME=${DB_USERNAME:-root}
|
DB_USERNAME=${DB_USERNAME:-root}
|
||||||
@ -79,7 +85,6 @@ fi
|
|||||||
# Establecer permisos correctos para las claves
|
# Establecer permisos correctos para las claves
|
||||||
chmod 600 storage/app/keys/oauth-private.key
|
chmod 600 storage/app/keys/oauth-private.key
|
||||||
chmod 644 storage/app/keys/oauth-public.key
|
chmod 644 storage/app/keys/oauth-public.key
|
||||||
chown www-data:www-data storage/app/keys/oauth-*.key
|
|
||||||
|
|
||||||
echo "✓ Claves de Passport verificadas"
|
echo "✓ Claves de Passport verificadas"
|
||||||
|
|
||||||
@ -111,5 +116,5 @@ echo "✓ Configuración de desarrollo completada"
|
|||||||
|
|
||||||
echo "=== Iniciando PHP-FPM DESARROLLO ==="
|
echo "=== Iniciando PHP-FPM DESARROLLO ==="
|
||||||
|
|
||||||
# Iniciar PHP-FPM
|
# Iniciar PHP-FPM como usuario www-data
|
||||||
exec "$@"
|
exec su-exec www-data "$@"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user