<?php
/**
 * Tokens de compartición: AES-256-GCM, clave en disco (no en el cliente).
 */

if (!defined('GRID_ROOT')) {
    define('GRID_ROOT', dirname(__DIR__));
}

require_once __DIR__ . '/path_security.php';

/**
 * @return string 32 bytes
 */
function grid_share_secret_key() {
    $path = GRID_ROOT . '/media/.share_secret.key';
    if (!is_file($path)) {
        if (!is_dir(dirname($path))) {
            @mkdir(dirname($path), 0755, true);
        }
        $k = random_bytes(32);
        @file_put_contents($path, $k);
        @chmod($path, 0600);
    }
    $k = @file_get_contents($path);
    if ($k === false || strlen($k) < 32) {
        $k = hash('sha256', 'grid_share_fallback_' . GRID_ROOT, true);
    }
    if (strlen($k) > 32) {
        $k = substr($k, 0, 32);
    }
    if (strlen($k) < 32) {
        $k = str_pad($k, 32, "\0");
    }
    return $k;
}

/**
 * @param array $payload Debe incluir exp (unix), kind file|folder, y rutas bajo media/
 * @return string token url-safe
 */
function grid_share_pack_token(array $payload) {
    $key = grid_share_secret_key();
    $iv = random_bytes(12);
    $plain = json_encode($payload, JSON_UNESCAPED_UNICODE);
    if ($plain === false) {
        return '';
    }
    $tag = '';
    $cipher = openssl_encrypt($plain, 'aes-256-gcm', $key, OPENSSL_RAW_DATA, $iv, $tag, '', 16);
    if ($cipher === false) {
        return '';
    }
    $bin = $iv . $tag . $cipher;
    return rtrim(strtr(base64_encode($bin), '+/', '-_'), '=');
}

/**
 * @return array|null payload o null
 */
function grid_share_unpack_token($token) {
    $token = trim((string)$token);
    if ($token === '') {
        return null;
    }
    $b64 = strtr($token, '-_', '+/');
    $pad = strlen($b64) % 4;
    if ($pad) {
        $b64 .= str_repeat('=', 4 - $pad);
    }
    $bin = base64_decode($b64, true);
    if ($bin === false || strlen($bin) < 12 + 16) {
        return null;
    }
    $iv = substr($bin, 0, 12);
    $tag = substr($bin, 12, 16);
    $cipher = substr($bin, 28);
    $key = grid_share_secret_key();
    $plain = openssl_decrypt($cipher, 'aes-256-gcm', $key, OPENSSL_RAW_DATA, $iv, $tag);
    if ($plain === false) {
        return null;
    }
    $data = json_decode($plain, true);
    if (!is_array($data)) {
        return null;
    }
    if (!isset($data['exp']) || (int)$data['exp'] < time()) {
        return null;
    }
    return $data;
}

/**
 * Normaliza ruta relativa tipo media/explorer/...
 */
function grid_share_normalize_media_rel($rel) {
    $rel = str_replace(["\0", '\\'], ['', '/'], (string)$rel);
    $rel = ltrim($rel, '/');
    if (strpos($rel, '..') !== false) {
        return '';
    }
    $parts = array_values(array_filter(explode('/', $rel), function ($p) {
        return $p !== '' && $p !== '.' && $p !== '..';
    }));
    return implode('/', $parts);
}

/**
 * @return string|false realpath del archivo bajo media/ o false
 */
function grid_share_resolve_under_media($mediaRel) {
    $mediaRel = grid_share_normalize_media_rel($mediaRel);
    if ($mediaRel === '' || stripos($mediaRel, 'media/') !== 0) {
        return false;
    }
    $root = defined('GRID_ROOT') ? GRID_ROOT : dirname(__DIR__);
    $full = $root . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $mediaRel);
    $real = realpath($full);
    if ($real === false) {
        return false;
    }
    $chk = validarRutaSegura($real);
    return $chk['ok'] ? $chk['real'] : false;
}

/**
 * Comprueba que $fileReal (archivo) está dentro de $folderReal (directorio).
 */
function grid_share_file_under_folder($folderReal, $fileReal) {
    $fold = realpath($folderReal);
    $file = realpath($fileReal);
    if ($fold === false || $file === false || !is_dir($fold) || !is_file($file)) {
        return false;
    }
    return grid_path_resolved_under_parent($file, $fold);
}
