Regalamiunsorriso/www/faceai_config.php
MaddoScientisto 97e53353c4 feat: Add FaceAI integration with handoff and return functionality
- Introduced a new workspace for FaceAI in package.json.
- Implemented FaceAI handoff logic in faceai_handoff.php, including identity verification and token signing.
- Created faceai_return.php to handle return requests from FaceAI, validating tokens and forwarding results.
- Developed faceai_simulator.php and faceai_simulator_view.php for simulating the FaceAI interface with demo photos.
- Enhanced rus-ecom-240621.js to support new FaceAI features, including dynamic URL building and button integration.
- Added faceai_config.php for configuration management, including environment variable handling and utility functions.
- Updated HTML structure and styles in simulator view for better user experience.
2026-04-07 19:53:40 +02:00

185 lines
5.7 KiB
PHP

<?php
function faceai_env($key, $default = null)
{
$value = getenv($key);
return $value === false ? $default : $value;
}
function faceai_config()
{
static $config = null;
if ($config !== null) {
return $config;
}
$config = array(
'frontend_url' => rtrim(faceai_env('FACEAI_FRONTEND_URL', 'http://localhost:5173'), '/'),
'backend_internal_url' => rtrim(faceai_env('FACEAI_BACKEND_INTERNAL_URL', 'http://localhost:3001'), '/'),
'shared_secret' => (string) faceai_env('FACEAI_SHARED_SECRET', 'change-me'),
'allow_dev_handoff' => faceai_env('FACEAI_ALLOW_DEV_HANDOFF', '1') === '1',
'identity_cookie' => (string) faceai_env('FACEAI_IDENTITY_COOKIE', 'rus_faceai_identity'),
'return_forward_url' => rtrim((string) faceai_env('FACEAI_RETURN_FORWARD_URL', ''), '/')
);
return $config;
}
function faceai_base64url_encode($value)
{
return rtrim(strtr(base64_encode($value), '+/', '-_'), '=');
}
function faceai_base64url_decode($value)
{
$padding = strlen($value) % 4;
if ($padding > 0) {
$value .= str_repeat('=', 4 - $padding);
}
return base64_decode(strtr($value, '-_', '+/'));
}
function faceai_sign_payload(array $payload, $secret)
{
$body = faceai_base64url_encode(json_encode($payload));
$signature = hash_hmac('sha256', $body, $secret, true);
return $body . '.' . faceai_base64url_encode($signature);
}
function faceai_verify_payload($token, $secret)
{
if (!is_string($token) || strpos($token, '.') === false) {
throw new RuntimeException('Invalid token format.');
}
list($body, $signature) = explode('.', $token, 2);
$expected = faceai_base64url_encode(hash_hmac('sha256', $body, $secret, true));
if (!hash_equals($expected, $signature)) {
throw new RuntimeException('Invalid token signature.');
}
$decoded = faceai_base64url_decode($body);
$payload = json_decode($decoded, true);
if (!is_array($payload)) {
throw new RuntimeException('Invalid token payload.');
}
if (isset($payload['expiresAt']) && (int) $payload['expiresAt'] < (int) round(microtime(true) * 1000)) {
throw new RuntimeException('Token expired.');
}
return $payload;
}
function faceai_build_url($baseUrl, array $params)
{
return $baseUrl . (strpos($baseUrl, '?') === false ? '?' : '&') . http_build_query($params);
}
function faceai_request_value($key, $default = '')
{
if (!isset($_GET[$key])) {
return $default;
}
if (is_array($_GET[$key])) {
return $default;
}
return trim((string) $_GET[$key]);
}
function faceai_html($value)
{
return htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8');
}
function faceai_resolve_identity(array $config)
{
if (!empty($_COOKIE[$config['identity_cookie']])) {
$payload = faceai_verify_payload($_COOKIE[$config['identity_cookie']], $config['shared_secret']);
if (($payload['type'] ?? '') !== 'legacy-identity') {
throw new RuntimeException('Unexpected identity cookie payload.');
}
return array(
'id' => (string) ($payload['userId'] ?? ''),
'displayName' => (string) ($payload['displayName'] ?? ''),
'email' => (string) ($payload['email'] ?? ''),
'membershipStatus' => (string) ($payload['membershipStatus'] ?? 'inactive')
);
}
if ($config['allow_dev_handoff']) {
$userId = faceai_request_value('devUserId');
if ($userId !== '') {
return array(
'id' => $userId,
'displayName' => faceai_request_value('devDisplayName', 'Local Test User'),
'email' => faceai_request_value('devEmail', 'local.test@example.invalid'),
'membershipStatus' => faceai_request_value('devMembershipStatus', 'active')
);
}
}
return null;
}
function faceai_render_message_page($title, $message, array $details = array(), $statusCode = 400)
{
http_response_code($statusCode);
header('Content-Type: text/html; charset=UTF-8');
echo '<!doctype html><html lang="it"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">';
echo '<title>' . faceai_html($title) . '</title>';
echo '<style>body{font-family:Georgia,serif;background:#f7f1e8;color:#2a231b;margin:0;padding:32px}main{max-width:900px;margin:0 auto;background:#fff;border:1px solid #ddcbb5;padding:24px}h1{margin-top:0}code{background:#f2ece2;padding:2px 5px}ul{padding-left:20px}li{margin:8px 0}</style>';
echo '</head><body><main>';
echo '<h1>' . faceai_html($title) . '</h1>';
echo '<p>' . faceai_html($message) . '</p>';
if (!empty($details)) {
echo '<ul>';
foreach ($details as $detail) {
echo '<li>' . faceai_html($detail) . '</li>';
}
echo '</ul>';
}
echo '</main></body></html>';
exit;
}
function faceai_fetch_json($url)
{
$context = stream_context_create(array(
'http' => array(
'ignore_errors' => true,
'timeout' => 10
)
));
$response = @file_get_contents($url, false, $context);
if ($response === false) {
throw new RuntimeException('Unable to fetch remote FaceAI data.');
}
$statusCode = 0;
if (!empty($http_response_header[0]) && preg_match('/\s(\d{3})\s/', $http_response_header[0], $matches)) {
$statusCode = (int) $matches[1];
}
$payload = json_decode($response, true);
if (!is_array($payload)) {
throw new RuntimeException('FaceAI returned invalid JSON.');
}
if ($statusCode >= 400) {
throw new RuntimeException($payload['error'] ?? ('FaceAI bridge request failed with status ' . $statusCode . '.'));
}
return $payload;
}