Update files
This commit is contained in:
parent
85bc6a1ad9
commit
37cb69c69f
|
|
@ -141,9 +141,30 @@ function validateTelegramOAuth(authData, botToken) {
|
|||
// Авторизация через Telegram OAuth (Login Widget)
|
||||
router.post('/oauth', strictAuthLimiter, async (req, res) => {
|
||||
try {
|
||||
const { user: telegramUser, auth_date, hash } = req.body;
|
||||
// Telegram Login Widget может отправлять данные в двух форматах:
|
||||
// 1. { user: {...}, auth_date, hash }
|
||||
// 2. { id, first_name, last_name, username, photo_url, auth_date, hash }
|
||||
let telegramUser, auth_date, hash;
|
||||
|
||||
if (!telegramUser || !auth_date || !hash) {
|
||||
if (req.body.user) {
|
||||
// Формат 1
|
||||
telegramUser = req.body.user;
|
||||
auth_date = req.body.auth_date;
|
||||
hash = req.body.hash;
|
||||
} else {
|
||||
// Формат 2 - данные напрямую в body
|
||||
telegramUser = {
|
||||
id: req.body.id,
|
||||
first_name: req.body.first_name,
|
||||
last_name: req.body.last_name,
|
||||
username: req.body.username,
|
||||
photo_url: req.body.photo_url
|
||||
};
|
||||
auth_date = req.body.auth_date;
|
||||
hash = req.body.hash;
|
||||
}
|
||||
|
||||
if (!telegramUser || !telegramUser.id || !auth_date || !hash) {
|
||||
logSecurityEvent('INVALID_OAUTH_DATA', req);
|
||||
return res.status(400).json({ error: 'Неверные данные авторизации' });
|
||||
}
|
||||
|
|
@ -276,6 +297,27 @@ router.post('/oauth', strictAuthLimiter, async (req, res) => {
|
|||
|
||||
const settings = normalizeUserSettings(populatedUser.settings);
|
||||
|
||||
// Генерируем JWT токены для web-сессии
|
||||
const { signAccessToken, signRefreshToken, ACCESS_COOKIE, REFRESH_COOKIE } = require('../utils/tokens');
|
||||
|
||||
const accessToken = signAccessToken(populatedUser._id.toString());
|
||||
const refreshToken = signRefreshToken(populatedUser._id.toString());
|
||||
|
||||
// Устанавливаем cookies
|
||||
res.cookie(ACCESS_COOKIE, accessToken, {
|
||||
httpOnly: true,
|
||||
secure: process.env.NODE_ENV === 'production',
|
||||
sameSite: 'lax',
|
||||
maxAge: 5 * 60 * 1000 // 5 минут
|
||||
});
|
||||
|
||||
res.cookie(REFRESH_COOKIE, refreshToken, {
|
||||
httpOnly: true,
|
||||
secure: process.env.NODE_ENV === 'production',
|
||||
sameSite: 'lax',
|
||||
maxAge: 7 * 24 * 60 * 60 * 1000 // 7 дней
|
||||
});
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
user: {
|
||||
|
|
@ -491,7 +533,7 @@ router.post('/magic-link/set-password', async (req, res) => {
|
|||
}
|
||||
|
||||
// Хешируем пароль
|
||||
const bcrypt = require('bcrypt');
|
||||
const bcrypt = require('bcryptjs');
|
||||
const passwordHash = await bcrypt.hash(password, 10);
|
||||
|
||||
// Обновляем пользователя
|
||||
|
|
@ -568,7 +610,7 @@ router.post('/login-email', strictAuthLimiter, async (req, res) => {
|
|||
}
|
||||
|
||||
// Проверить пароль
|
||||
const bcrypt = require('bcrypt');
|
||||
const bcrypt = require('bcryptjs');
|
||||
const isPasswordValid = await bcrypt.compare(password, user.passwordHash);
|
||||
|
||||
if (!isPasswordValid) {
|
||||
|
|
@ -721,7 +763,7 @@ router.post('/link-email', authenticate, async (req, res) => {
|
|||
}
|
||||
|
||||
// Хешируем пароль
|
||||
const bcrypt = require('bcrypt');
|
||||
const bcrypt = require('bcryptjs');
|
||||
const passwordHash = await bcrypt.hash(password, 10);
|
||||
|
||||
// Привязываем email и пароль
|
||||
|
|
|
|||
|
|
@ -257,3 +257,14 @@
|
|||
background: var(--bg-secondary);
|
||||
}
|
||||
|
||||
|
||||
/* Telegram OAuth Widget */
|
||||
.telegram-widget-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.telegram-widget-container iframe {
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { useState } from 'react'
|
||||
import { useState, useEffect, useRef } from 'react'
|
||||
import { X, Send } from 'lucide-react'
|
||||
import { sendMagicLink } from '../utils/api'
|
||||
import './AuthModal.css'
|
||||
|
|
@ -8,6 +8,86 @@ export default function AuthModal({ reason, onClose, onAuth }) {
|
|||
const [loading, setLoading] = useState(false)
|
||||
const [sent, setSent] = useState(false)
|
||||
const [error, setError] = useState('')
|
||||
const telegramWidgetRef = useRef(null)
|
||||
const [botUsername, setBotUsername] = useState('NakamaSpaceBot') // Дефолтное значение
|
||||
|
||||
useEffect(() => {
|
||||
// Получить bot username из API или использовать дефолтное
|
||||
const fetchBotUsername = async () => {
|
||||
try {
|
||||
// Можно получить через API или использовать переменную окружения
|
||||
// Пока используем дефолтное значение
|
||||
setBotUsername('NakamaSpaceBot')
|
||||
} catch (error) {
|
||||
console.error('Ошибка получения bot username:', error)
|
||||
}
|
||||
}
|
||||
|
||||
fetchBotUsername()
|
||||
initTelegramWidget()
|
||||
}, [])
|
||||
|
||||
const initTelegramWidget = () => {
|
||||
if (!telegramWidgetRef.current) return
|
||||
|
||||
// Проверить не загружен ли уже виджет
|
||||
if (document.querySelector('script[src*="telegram-widget"]')) {
|
||||
return
|
||||
}
|
||||
|
||||
// Очистить контейнер
|
||||
telegramWidgetRef.current.innerHTML = ''
|
||||
|
||||
const script = document.createElement('script')
|
||||
script.async = true
|
||||
script.src = 'https://telegram.org/js/telegram-widget.js?22'
|
||||
script.setAttribute('data-telegram-login', botUsername)
|
||||
script.setAttribute('data-size', 'large')
|
||||
script.setAttribute('data-request-access', 'write')
|
||||
script.setAttribute('data-onauth', 'onTelegramAuth')
|
||||
script.setAttribute('data-radius', '10')
|
||||
const authUrl = `${window.location.origin}/api/auth/oauth`
|
||||
script.setAttribute('data-auth-url', authUrl)
|
||||
|
||||
// Глобальная функция для обработки авторизации
|
||||
window.onTelegramAuth = async (userData) => {
|
||||
console.log('[Telegram Widget] Данные от виджета:', userData)
|
||||
|
||||
try {
|
||||
setLoading(true)
|
||||
setError('')
|
||||
|
||||
// Telegram Login Widget отправляет данные напрямую
|
||||
const response = await fetch('/api/auth/oauth', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
credentials: 'include',
|
||||
body: JSON.stringify(userData)
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json()
|
||||
throw new Error(errorData.error || 'Ошибка авторизации')
|
||||
}
|
||||
|
||||
const result = await response.json()
|
||||
console.log('[Telegram Widget] Авторизация успешна:', result)
|
||||
|
||||
// Вызываем callback и закрываем модалку
|
||||
if (onAuth) {
|
||||
onAuth(result)
|
||||
}
|
||||
onClose()
|
||||
} catch (error) {
|
||||
console.error('Ошибка авторизации через Telegram:', error)
|
||||
setError(error.message || 'Ошибка авторизации')
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
telegramWidgetRef.current.appendChild(script)
|
||||
}
|
||||
|
||||
const handleSendMagicLink = async () => {
|
||||
if (!email.trim() || !email.includes('@')) {
|
||||
|
|
@ -28,11 +108,6 @@ export default function AuthModal({ reason, onClose, onAuth }) {
|
|||
}
|
||||
}
|
||||
|
||||
const handleTelegramAuth = () => {
|
||||
// Открываем Telegram бота для авторизации
|
||||
window.open('https://t.me/YOUR_BOT_USERNAME', '_blank')
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="auth-modal-overlay" onClick={onClose}>
|
||||
<div className="auth-modal-content" onClick={e => e.stopPropagation()}>
|
||||
|
|
@ -46,16 +121,8 @@ export default function AuthModal({ reason, onClose, onAuth }) {
|
|||
|
||||
{!sent ? (
|
||||
<>
|
||||
{/* Telegram авторизация */}
|
||||
<button
|
||||
className="auth-btn telegram"
|
||||
onClick={handleTelegramAuth}
|
||||
>
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm4.64 6.8c-.15 1.58-.8 5.42-1.13 7.19-.14.75-.42 1-.68 1.03-.58.05-1.02-.38-1.58-.75-.88-.58-1.38-.94-2.23-1.5-.99-.65-.35-1.01.22-1.59.15-.15 2.71-2.48 2.76-2.69a.2.2 0 00-.05-.18c-.06-.05-.14-.03-.21-.02-.09.02-1.49.95-4.22 2.79-.4.27-.76.41-1.08.4-.36-.01-1.04-.2-1.55-.37-.63-.2-1.12-.31-1.08-.66.02-.18.27-.36.74-.55 2.92-1.27 4.86-2.11 5.83-2.51 2.78-1.16 3.35-1.36 3.73-1.36.08 0 .27.02.39.12.1.08.13.19.14.27-.01.06.01.24 0 .38z"/>
|
||||
</svg>
|
||||
Войти через Telegram
|
||||
</button>
|
||||
{/* Telegram авторизация через OAuth Widget */}
|
||||
<div ref={telegramWidgetRef} className="telegram-widget-container"></div>
|
||||
|
||||
<div className="auth-divider">
|
||||
<span>или</span>
|
||||
|
|
@ -92,7 +159,7 @@ export default function AuthModal({ reason, onClose, onAuth }) {
|
|||
</div>
|
||||
|
||||
<p className="auth-hint">
|
||||
Отправим ссылку для входа на email. Регистрация не требуется.
|
||||
Отправим ссылку для регистрации на email.
|
||||
</p>
|
||||
</>
|
||||
) : (
|
||||
|
|
|
|||
Loading…
Reference in New Issue