🌙
🔗 Прокси для тг
👤 Мой профиль
📱 Помощь с устройствами
📜 Пользовательское соглашение
🛡️ Политика конфиденциальности
🚪 Выйти
До конца подписки
0
📱 МОИ УСТРОЙСТВА
0
РЕФЕРАЛЫ
0
УСТРОЙСТВ
🌍 АКТИВНЫЕ СЕРВЕРА
💡 Важно: Одна ссылка = одно устройство. UUID генерируется автоматически при первом подключении.
👤
async function checkAuthStatus() { const urlParams = new URLSearchParams(window.location.search); const token = urlParams.get('token'); const userId = urlParams.get('user_id'); if (token && userId) { await processAuthToken(token, userId); window.history.replaceState({}, document.title, window.location.pathname); } } async function processAuthToken(token, userId) { try { const response = await fetch(`${API_BASE}/api/auth/telegram`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ token, user_id: parseInt(userId) }) }); const data = await response.json(); if (response.ok && data.success) { authToken = token; currentUser = { id: data.user_id, name: data.name, telegram_id: data.telegram_id, email: data.email }; isLoggedIn = true; localStorage.setItem('10vpn_user_id', data.user_id); localStorage.setItem('10vpn_user_name', data.name); localStorage.setItem('10vpn_auth_token', token); if (data.email) localStorage.setItem('10vpn_user_email', data.email); updateUIForLoggedIn(); loadUserData(data.user_id); loadDevices(data.user_id); showToast('✅ Успешный вход!'); } else { showToast('❌ Ошибка авторизации'); } } catch(e) { showToast('❌ Ошибка соединения'); } } function checkSavedUser() { const savedUserId = localStorage.getItem('10vpn_user_id'); const savedToken = localStorage.getItem('10vpn_auth_token'); if (savedUserId && savedToken) { authToken = savedToken; currentUser = { id: parseInt(savedUserId), name: localStorage.getItem('10vpn_user_name'), email: localStorage.getItem('10vpn_user_email') }; isLoggedIn = true; updateUIForLoggedIn(); loadUserData(savedUserId); loadDevices(savedUserId); return true; } return false; } function updateUIForLoggedIn() { document.getElementById('userName').innerText = currentUser.name || 'Пользователь'; document.getElementById('userAvatar').innerHTML = (currentUser.name ? currentUser.name[0] : '👤').toUpperCase(); document.getElementById('extendBtn').style.display = 'block'; document.getElementById('trialBtn').style.display = 'block'; document.getElementById('referralBtn').style.display = 'block'; document.getElementById('logoutBtn').style.display = 'block'; } function updateUIForLoggedOut() { isLoggedIn = false; currentUser = null; authToken = null; document.getElementById('userName').innerText = 'Войти'; document.getElementById('userAvatar').innerHTML = '👤'; document.getElementById('extendBtn').style.display = 'none'; document.getElementById('trialBtn').style.display = 'none'; document.getElementById('referralBtn').style.display = 'none'; document.getElementById('logoutBtn').style.display = 'none'; document.getElementById('daysLeft').innerText = '0'; document.getElementById('progressFill').style.width = '0%'; document.getElementById('referralCount').innerHTML = '0'; document.getElementById('devicesList').innerHTML = '
❌ Нет добавленных устройств
'; localStorage.removeItem('10vpn_user_id'); localStorage.removeItem('10vpn_user_name'); localStorage.removeItem('10vpn_user_email'); localStorage.removeItem('10vpn_auth_token'); } // ==================== ЗАГРУЗКА ДАННЫХ ==================== async function loadUserData(userId) { try { const response = await apiRequest(`${API_BASE}/api/user/${userId}`); if (response.ok) { const data = await response.json(); const daysLeft = data.days_left || 0; document.getElementById('daysLeft').innerText = daysLeft; document.getElementById('progressFill').style.width = Math.min(100, (daysLeft / 365) * 100) + '%'; if (data.expiry_date) document.getElementById('expiryDate').innerHTML = `📅 Действует до: ${escapeHtml(data.expiry_date)}`; document.getElementById('referralCount').innerHTML = data.referral_count || 0; document.getElementById('devicesLimitStat').innerHTML = data.devices_limit || 1; document.getElementById('devicesCountBadge').innerHTML = `${data.active_devices || 0}/${data.devices_limit || 1}`; document.getElementById('serversList').innerHTML = servers.map(s => `
${escapeHtml(s.icon)}${escapeHtml(s.name)}
● ${escapeHtml(s.status)}
`).join(''); } } catch(e) { console.error(e); } } async function loadDevices(userId) { try { const response = await apiRequest(`${API_BASE}/api/user/${userId}`); if (response.ok) { const data = await response.json(); const devices = data.devices || []; document.getElementById('devicesCountBadge').innerHTML = `${devices.length}/${data.devices_limit || 1}`; if (devices.length === 0) { document.getElementById('devicesList').innerHTML = '
❌ Нет добавленных устройств
'; } else { document.getElementById('devicesList').innerHTML = devices.map((d, i) => { const isBound = d.is_bound; const statusColor = isBound ? '#00ff88' : '#ffcc00'; return `
${i+1}. ${escapeHtml(d.name || 'Устройство')}
${escapeHtml(d.platform || 'Unknown')} • ${escapeHtml(d.model || 'Unknown')}
🕐 ${d.last_used ? d.last_used.slice(0, 16) : 'никогда не использовалось'} • 🆔 ${d.uuid ? d.uuid.slice(0, 16) + '...' : '—'}
${isBound ? `` : ''}
`; }).join(''); } } } catch(e) { console.error(e); } } // ==================== УПРАВЛЕНИЕ УСТРОЙСТВАМИ ==================== function copyDeviceLink(deviceToken) { if (!deviceToken) return; const link = `https://10-vpn.ru/device/${deviceToken}`; copyToClipboard(link, '✅ Ссылка устройства скопирована!'); } async function resetDeviceBinding(deviceToken) { if (!deviceToken) return; if (!confirm('Сбросить привязку устройства? После сброса ссылку можно будет использовать на другом устройстве.')) return; try { const response = await apiRequest('/api/device/reset', 'POST', { device_token: deviceToken }); const data = await response.json(); if (data.success) { showToast('✅ Привязка устройства сброшена!'); loadDevices(currentUser.id); } else { showToast('❌ ' + (data.message || 'Ошибка сброса')); } } catch(e) { showToast('❌ Ошибка соединения'); } } async function activateTrial() { if (!isLoggedIn) { openAuthModal(); return; } try { showToast('🔄 Активация пробного периода...'); const response = await apiRequest(`${API_BASE}/api/trial/activate`, 'POST', { user_id: currentUser.id }); const data = await response.json(); if (response.ok && data.success) { showToast('✅ Пробный период активирован на 7 дней!'); loadUserData(currentUser.id); } else { showToast('❌ ' + (data.message || 'Пробный период уже использован')); } } catch(e) { showToast('❌ Ошибка подключения'); } } function openAddDeviceModal() { if (!isLoggedIn) { openAuthModal(); return; } document.getElementById('addDeviceModal').classList.add('active'); } function closeAddDeviceModal() { document.getElementById('addDeviceModal').classList.remove('active'); document.getElementById('deviceNameInput').value = ''; } async function addDevice() { let deviceName = document.getElementById('deviceNameInput').value.trim(); if (!deviceName) deviceName = 'Мое устройство'; try { const response = await apiRequest('/api/device/add', 'POST', { user_id: currentUser.id, device_name: deviceName }); const data = await response.json(); if (data.success) { showToast('✅ Устройство добавлено!'); closeAddDeviceModal(); loadDevices(currentUser.id); } else { showToast('❌ ' + data.message); } } catch(e) { showToast('❌ Ошибка соединения'); } } async function deleteDevice(deviceToken) { if (!deviceToken) return; if (!confirm('Удалить это устройство? Ссылка перестанет работать.')) return; try { const response = await apiRequest('/api/device/delete', 'POST', { device_token: deviceToken }); const data = await response.json(); if (data.success) { showToast('✅ Устройство удалено'); loadDevices(currentUser.id); } else { showToast('❌ ' + data.message); } } catch(e) { showToast('❌ Ошибка соединения'); } } // ==================== ПРОФИЛЬ ==================== function toggleProfileMenu() { const menu = document.getElementById('profileMenu'); menu.classList.toggle('active'); document.addEventListener('click', function closeMenu(e) { if (!menu.contains(e.target) && !e.target.closest('.user-info')) { menu.classList.remove('active'); document.removeEventListener('click', closeMenu); } }); } function openProfileModal() { document.getElementById('profileModalName').value = currentUser?.name || ''; document.getElementById('profileModalTelegram').value = currentUser?.telegram_id || 'Не привязан'; document.getElementById('profileModalEmail').value = currentUser?.email || ''; document.getElementById('profileModal').classList.add('active'); document.getElementById('profileMenu').classList.remove('active'); } function closeProfileModal() { document.getElementById('profileModal').classList.remove('active'); } async function saveProfile() { const newName = document.getElementById('profileName').value; const newEmail = document.getElementById('profileEmail').value; if (!newName) { showToast('❌ Введите имя'); return; } try { const response = await apiRequest('/api/user/update', 'POST', { user_id: currentUser.id, name: newName, email: newEmail }); const data = await response.json(); if (data.success) { currentUser.name = newName; currentUser.email = newEmail; localStorage.setItem('10vpn_user_name', newName); if (newEmail) localStorage.setItem('10vpn_user_email', newEmail); document.getElementById('userName').innerText = newName; document.getElementById('userAvatar').innerHTML = newName[0].toUpperCase(); showToast('✅ Профиль обновлён'); } else { showToast('❌ ' + data.message); } } catch(e) { showToast('❌ Ошибка соединения'); } } async function saveProfileModal() { const newName = document.getElementById('profileModalName').value; const newEmail = document.getElementById('profileModalEmail').value; if (!newName) { showToast('❌ Введите имя'); return; } try { const response = await apiRequest('/api/user/update', 'POST', { user_id: currentUser.id, name: newName, email: newEmail }); const data = await response.json(); if (data.success) { currentUser.name = newName; currentUser.email = newEmail; localStorage.setItem('10vpn_user_name', newName); if (newEmail) localStorage.setItem('10vpn_user_email', newEmail); document.getElementById('userName').innerText = newName; document.getElementById('userAvatar').innerHTML = newName[0].toUpperCase(); showToast('✅ Профиль обновлён'); closeProfileModal(); } else { showToast('❌ ' + data.message); } } catch(e) { showToast('❌ Ошибка соединения'); } } async function deleteAccount() { if (!confirm('⚠️ Вы уверены? Это действие необратимо. Все данные будут удалены.')) return; try { const response = await apiRequest('/api/user/delete', 'POST', { user_id: currentUser.id, confirm: true }); const data = await response.json(); if (data.success) { showToast('🗑️ Аккаунт удалён'); updateUIForLoggedOut(); closeProfileModal(); } else { showToast('❌ ' + data.message); } } catch(e) { showToast('❌ Ошибка соединения'); } } function openDevicesHelp() { document.getElementById('profileMenu').classList.remove('active'); document.getElementById('devicesHelpModal').classList.add('active'); } function closeDevicesHelpModal() { document.getElementById('devicesHelpModal').classList.remove('active'); } function openAgreementLink() { window.open('https://telegra.ph/Polzovatelskoe-soglashenie-servisa-10VPN-03-17', '_blank'); } function openPrivacyLink() { window.open('https://telegra.ph/Politika-konfidencialnosti-servisa-10VPN-03-17', '_blank'); } function proxyMtproto() { window.open('tg://proxy?server=10-vpn.ru&port=8443&secret=ea71f09fb3d3d4ac0e1546605ba8395f', '_blank'); } function openAuthModal() { document.getElementById('authModal').classList.add('active'); } function closeAuthModal() { document.getElementById('authModal').classList.remove('active'); } function logout() { if (confirm('Вы уверены, что хотите выйти?')) updateUIForLoggedOut(); } function shareReferral() { if (!isLoggedIn) { openAuthModal(); return; } copyToClipboard(`https://t.me/${BOT_USERNAME}?start=${currentUser.id}`, '✅ Реферальная ссылка скопирована!'); } // ==================== ОПЛАТА ==================== function openPaymentModal() { if (!isLoggedIn) { openAuthModal(); return; } selectedPeriod = null; selectedDeviceCount = null; document.getElementById('pricePeriods').innerHTML = periods.map(p => `
📅 ${escapeHtml(p.name)}
`).join(''); document.getElementById('priceDevices').style.display = 'none'; document.getElementById('paymentMethods').style.display = 'none'; document.getElementById('paymentModal').classList.add('active'); } function selectPeriod(periodKey) { selectedPeriod = periodKey; document.querySelectorAll('.price-period').forEach(el => el.classList.remove('selected')); document.querySelector(`.price-period[data-period="${periodKey}"]`).classList.add('selected'); document.getElementById('priceDevices').innerHTML = devicesOptions.map(dev => { const priceKey = `${periodKey}_${dev}`; const p = prices[priceKey]; const saving = dev === 3 ? ' (экономия 20%)' : dev === 5 ? ' (экономия 30%)' : ''; return `
📱 ${dev} устройство(а)
${p.rub} ₽${saving}
`; }).join(''); document.getElementById('priceDevices').style.display = 'block'; } function selectDevice(devices) { selectedDeviceCount = devices; document.querySelectorAll('.price-device').forEach(el => el.classList.remove('selected')); document.querySelector(`.price-device[data-devices="${devices}"]`).classList.add('selected'); document.getElementById('paymentMethods').style.display = 'block'; } function closePaymentModal() { document.getElementById('paymentModal').classList.remove('active'); selectedPeriod = null; selectedDeviceCount = null; } async function payWithSBP() { if (!selectedPeriod || !selectedDeviceCount) { showToast('❌ Выберите срок и количество устройств'); return; } const priceKey = `${selectedPeriod}_${selectedDeviceCount}`; const tariff = prices[priceKey]; if (!tariff) { showToast('❌ Тариф не найден'); return; } showToast('🔄 Создание платежа...'); try { const response = await fetch('/api/payment/platega/create', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ user_id: currentUser.id, amount: tariff.rub, days: tariff.days, devices: tariff.devices, tariff_key: priceKey }) }); const data = await response.json(); if (data.success && data.payment_url) { window.open(data.payment_url, '_blank'); showToast('🏦 Открываем окно оплаты...'); closePaymentModal(); } else { showToast('❌ ' + (data.message || 'Ошибка создания платежа')); } } catch (error) { showToast('❌ Ошибка: ' + error.message); } } function payWithStars() { if (!selectedPeriod || !selectedDeviceCount) return; const priceKey = `${selectedPeriod}_${selectedDeviceCount}`; const p = prices[priceKey]; window.open(`https://t.me/${BOT_USERNAME}?start=pay_${p.days}_${p.devices}`, '_blank'); showToast('⭐️ Переходим в Telegram для оплаты Stars...'); setTimeout(() => closePaymentModal(), 1000); } function openInTelegram() { window.open(`https://t.me/${BOT_USERNAME}`, '_blank'); } function openInSupport() { window.open(`https://t.me/tenvpn_help_bot`, '_blank'); } function openInNews() { window.open(`https://t.me/news_10vpn`, '_blank'); } function onTelegramAuth(user) { fetch('/api/auth/telegram', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ id: user.id, first_name: user.first_name, username: user.username, auth_date: user.auth_date, hash: user.hash }) }) .then(res => res.json()) .then(data => { if (data.success) { localStorage.setItem('10vpn_user_id', data.user_id); localStorage.setItem('10vpn_user_name', data.name); window.location.href = '/'; } }); } // ==================== ИНИЦИАЛИЗАЦИЯ ==================== function init() { createStars(); loadTheme(); // Проверяем OIDC callback const params = new URLSearchParams(window.location.search); const code = params.get('code'); if (code) { fetch('/api/auth/telegram', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ code: code, redirect_uri: 'https://10-vpn.online/auth/telegram' }) }) .then(res => res.json()) .then(data => { if (data.success) { localStorage.setItem('10vpn_user_id', data.user_id); localStorage.setItem('10vpn_user_name', data.name); localStorage.setItem('10vpn_auth_token', data.auth_token); window.location.href = '/'; } else { showToast('❌ ' + (data.error || 'Ошибка авторизации')); } }) .catch(e => showToast('❌ Ошибка соединения')); return; } // Обычная инициализация if (!checkSavedUser()) { checkAuthStatus(); } if (isLoggedIn && currentUser) { setInterval(() => loadUserData(currentUser.id), 30000); setInterval(() => loadDevices(currentUser.id), 30000); } } // Запуск при загрузке if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); }