<?php
// =============================================================================
// VPNLink VPN 암호 저장 암호화 헬퍼 (VPN 서버 배포용, 단독 동작)
// -----------------------------------------------------------------------------
// - 샵 서버 mylib/ikev2_provision.lib.php 의 VLSEC1: 정책과 동일 포맷.
//   포맷: "VLSEC1:" . base64(iv) . ":" . base64(AES-256-CBC ciphertext)
//   키  : sha256(공유시크릿, raw)  ← 시크릿은 DB 외부(파일/환경변수)에만 보관
// - 접두어 없는 레거시 평문은 reveal 시 그대로 통과(하위호환), protect 는 멱등.
// - 배포 위치 제안: /var/www/html/mylib4ikev2svr/vpnlink_pwd_vault.lib.php
// =============================================================================

if (!defined('VPNLINK_PWD_ENC_PREFIX')) {
    define('VPNLINK_PWD_ENC_PREFIX', 'VLSEC1:');
}

if (!function_exists('vpnlink_vault_secret')) {
    // 공유 시크릿 해석 (우선순위: 환경변수 → mylib4ikev2svr/ikev2_secret.php → /var/www/html/.env)
    // ※ 반드시 샵 서버와 "같은 값"일 필요는 없으나(서버별 at-rest 암호화),
    //   운영 단순화를 위해 IKEV2_PROVISION_SHARED_SECRET 공유값 사용을 권장.
    function vpnlink_vault_secret()
    {
        static $cached = null;
        if ($cached !== null) {
            return $cached;
        }

        $candidates = array();

        foreach (array('IKEV2_PROVISION_SHARED_SECRET', 'IKEV2_SHOP_SYNC_SHARED_SECRET') as $envKey) {
            if (isset($_SERVER[$envKey]) && trim((string)$_SERVER[$envKey]) !== '') {
                $candidates[] = trim((string)$_SERVER[$envKey]);
            }
            if (isset($_ENV[$envKey]) && trim((string)$_ENV[$envKey]) !== '') {
                $candidates[] = trim((string)$_ENV[$envKey]);
            }
            $v = getenv($envKey);
            if (is_string($v) && trim($v) !== '') {
                $candidates[] = trim($v);
            }
        }

        // 샵 서버와 동일 규칙의 시크릿 PHP 파일
        $secretPhp = __DIR__ . '/ikev2_secret.php';
        if (is_file($secretPhp) && is_readable($secretPhp)) {
            $loaded = @include $secretPhp;
            if (is_array($loaded) && isset($loaded['IKEV2_PROVISION_SHARED_SECRET'])) {
                $candidates[] = trim((string)$loaded['IKEV2_PROVISION_SHARED_SECRET']);
            } elseif (is_string($loaded) && trim($loaded) !== '') {
                $candidates[] = trim($loaded);
            }
        }

        // .env 파일 (IKEv2SellerOffice4U/config.php 의 vpn_env_get 과 동일 소스)
        foreach (array('/var/www/html/.env', dirname(__DIR__) . '/.env') as $envFile) {
            if (!is_file($envFile) || !is_readable($envFile)) {
                continue;
            }
            $lines = @file($envFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
            if (!is_array($lines)) {
                continue;
            }
            foreach ($lines as $line) {
                if (preg_match('/^\s*(IKEV2_PROVISION_SHARED_SECRET|IKEV2_SHOP_SYNC_SHARED_SECRET)\s*=\s*(.+)\s*$/', $line, $m)) {
                    $candidates[] = trim(trim($m[2]), "\"'");
                }
            }
        }

        foreach ($candidates as $c) {
            if (is_string($c) && strlen($c) >= 32 && stripos($c, 'CHANGE_THIS') === false) {
                $cached = $c;
                return $cached;
            }
        }

        $cached = '';
        return $cached;
    }
}

if (!function_exists('vpnlink_vpn_pwd_is_protected')) {
    function vpnlink_vpn_pwd_is_protected($value)
    {
        return is_string($value) && strpos($value, VPNLINK_PWD_ENC_PREFIX) === 0;
    }
}

if (!function_exists('vpnlink_vpn_pwd_protect')) {
    function vpnlink_vpn_pwd_protect($plain)
    {
        $plain = (string)$plain;
        if ($plain === '' || vpnlink_vpn_pwd_is_protected($plain)) {
            return $plain;
        }

        $secret = vpnlink_vault_secret();
        if ($secret === '') {
            error_log('[vpnlink_pwd_vault] protect skipped: shared secret not found');
            return $plain;
        }

        $key = hash('sha256', $secret, true);
        $iv = random_bytes(16);
        $cipher = openssl_encrypt($plain, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
        if ($cipher === false) {
            error_log('[vpnlink_pwd_vault] protect skipped: openssl encrypt failed');
            return $plain;
        }

        return VPNLINK_PWD_ENC_PREFIX . base64_encode($iv) . ':' . base64_encode($cipher);
    }
}

if (!function_exists('vpnlink_vpn_pwd_reveal')) {
    function vpnlink_vpn_pwd_reveal($value)
    {
        $value = (string)$value;
        if ($value === '' || !vpnlink_vpn_pwd_is_protected($value)) {
            return $value;
        }

        $secret = vpnlink_vault_secret();
        $parts = explode(':', substr($value, strlen(VPNLINK_PWD_ENC_PREFIX)), 2);
        if ($secret === '' || count($parts) !== 2) {
            error_log('[vpnlink_pwd_vault] reveal failed: secret missing or malformed value');
            return '';
        }

        $iv = base64_decode($parts[0], true);
        $cipherRaw = base64_decode($parts[1], true);
        if ($iv === false || $cipherRaw === false || strlen($iv) !== 16) {
            error_log('[vpnlink_pwd_vault] reveal failed: base64/iv error');
            return '';
        }

        $key = hash('sha256', $secret, true);
        $plain = openssl_decrypt($cipherRaw, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
        if ($plain === false) {
            error_log('[vpnlink_pwd_vault] reveal failed: decrypt error (시크릿 불일치 또는 손상)');
            return '';
        }

        return (string)$plain;
    }
}
