# Регистрация в Ласточке ## Обзор Ласточка поддерживает регистрацию с полной верификацией пользователя через email. **Требуемые данные при регистрации:** 1. ✅ Логин (уникальный, проверяется на дубликат) 2. ✅ Email (с верификацией кодом) 3. ✅ Телефон (обязательно, маска +7 XXX XXX-XX-XX) 4. ✅ Пароль (минимум 6 символов) 5. ✅ Подтверждение пароля 6. ⭕ Отображаемое имя (необязательно) ## Процесс регистрации ``` ┌─────────────────────┐ ┌──────────────────┐ ┌─────────────────┐ | Ввод данных | -> | Email с кодом | -> | Верификация | | (логин, email, | | отправлено | | завершена | | телефон, пароль) | | | | Вход в систему | └─────────────────────┘ └──────────────────┘ └─────────────────┘ ``` ## Форма регистрации ### Поля формы #### 1. Логин - **Обязательно:** да - **Минимальная длина:** 3 символа - **Допустимые символы:** буквы (a-z), цифры (0-9), подчёркивание (_) - **Проверка:** автоматическая проверка на уникальность (debounce 500ms) - **Пример:** `ivan_petrov`, `user123` #### 2. Email - **Обязательно:** да - **Формат:** стандартный email (example@domain.com) - **Проверка:** валидация формата + верификация кодом - **Пример:** `ivan@mail.ru` #### 3. Телефон - **Обязательно:** да - **Формат:** российский номер +7 (XXX) XXX-XX-XX - **Маска ввода:** автоматическое форматирование - **Пример:** `+7 (999) 123-45-67` #### 4. Пароль - **Обязательно:** да - **Минимальная длина:** 6 символов - **Отображение:** кнопка показать/скрыть #### 5. Подтверждение пароля - **Обязательно:** да - **Проверка:** совпадение с паролем #### 6. Отображаемое имя - **Обязательно:** нет - **По умолчанию:** используется логин - **Назначение:** отображается в списке контактов ## API ### 1. Проверка логина на доступность ```typescript import { useAuthStore } from '@/store/auth' const { checkLogin } = useAuthStore() const isAvailable = await checkLogin('username') ``` **Что происходит:** - Проверка логина в базе данных - Возвращает `true` если логин свободен ### 2. Отправка email для регистрации ```typescript const { sendRegistrationEmail } = useAuthStore() await sendRegistrationEmail( 'username', // логин 'password123', // пароль 'email@test.com',// email '79991234567', // телефон 'Имя' // отображаемое имя ) ``` **Что происходит:** - Валидация всех данных - Проверка логина на уникальность - Создание учётной записи в Tinode - Отправка email с кодом подтверждения - Переход в режим ожидания кода ### 3. Проверка email кода ```typescript const { verifyRegistrationEmail } = useAuthStore() await verifyRegistrationEmail('123456') ``` **Что происходит:** - Проверка кода подтверждения - Активация учётной записи - Автоматический вход в систему ## Компоненты ### RegisterForm.tsx Основной компонент формы регистрации. **Props:** ```typescript interface RegisterFormProps { onSuccess?: () => void // Callback после успешной регистрации } ``` **Функции:** - Валидация всех полей в реальном времени - Проверка логина на уникальность (debounced) - Проверка совпадения паролей - Валидация email и телефона - Отображение ошибок для каждого поля - Переключение видимости пароля **Состояния:** - `verificationStep: 'none'` — ввод данных - `verificationStep: 'email-sent'` — ожидание кода - `verificationStep: 'verified'` — успешно ### EmailVerification.tsx Компонент ввода кода из email. **Props:** ```typescript interface EmailVerificationProps { email: string // Email для отображения (маскированный) onComplete: (code) => void // Callback при вводе кода onBack: () => void // Callback при возврате назад isLoading: boolean // Индикатор загрузки error: string | null // Сообщение об ошибке title?: string // Заголовок description?: string // Описание } ``` **Функции:** - 6 полей для ввода кода - Автопереход между полями - Поддержка вставки из буфера обмена - Обработка Backspace - Маскирование email для отображения ### LoginScreen.tsx Главный экран с переключением между входом и регистрацией. **Режимы:** - `login` — форма входа - `register` — форма регистрации ## Валидация ### Логин ```typescript // Проверка длины if (login.length < 3) { error: 'Логин должен быть не менее 3 символов' } // Проверка символов if (!/^[a-zA-Z0-9_]+$/.test(login)) { error: 'Логин может содержать только буквы, цифры и подчёркивание' } // Проверка на дубликат (debounced 500ms) const available = await checkLogin(login) if (!available) { error: 'Этот логин уже занят' } ``` ### Email ```typescript import { isValidEmail } from '@/lib/phone-utils' if (!isValidEmail(email)) { error: 'Введите корректный email' } ``` ### Телефон ```typescript import { isValidPhoneNumber, checkPhoneAvailability } from '@/lib/phone-utils' // Валидация формата if (!isValidPhoneNumber(phone)) { error: 'Введите корректный номер телефона' } // Проверка на дубликат (debounced 500ms) const result = await checkPhoneAvailability(phone) if (!result.available) { error: 'Этот номер уже зарегистрирован' } ``` ### Пароль ```typescript if (password.length < 6) { error: 'Пароль должен быть не менее 6 символов' } if (password !== passwordConfirm) { error: 'Пароли не совпадают' } ``` ## Утилиты ### phone-utils.ts ```typescript import { formatPhoneNumber, // Форматирование: "+7 (999) 999-99-99" cleanPhoneNumber, // Очистка: "79999999999" isValidPhoneNumber, // Валидация: true/false isValidEmail, // Валидация email: true/false normalizeEmail, // Нормализация: lowercase + trim } from '@/lib/phone-utils' ``` ## Store (auth.ts) ### Состояние ```typescript interface AuthState { isAuthenticated: boolean userId: string | null displayName: string | null isLoading: boolean error: string | null // Для email-верификации emailForVerification: string | null loginForVerification: string | null passwordForVerification: string | null verificationStep: 'none' | 'email-sent' | 'verified' // Методы login: (login, password) => Promise checkLogin: (login) => Promise registerWithProfile: (login, password, email, phone, displayName) => Promise sendRegistrationEmail: (login, password, email, phone, displayName) => Promise verifyRegistrationEmail: (code) => Promise logout: () => Promise tryAutoLogin: () => Promise } ``` ## Email-провайдеры ### Настройка на сервере Для отправки email необходимо настроить SMTP на сервере Tinode. **Конфигурация SMTP:** ```yaml # Конфигурация сервера smtp: host: "smtp.mail.ru" port: 587 username: "noreply@lastochka.ru" password: "your-password" from: "Ласточка " tls: true ``` **Популярные провайдеры для РФ:** - Mail.ru (smtp.mail.ru) - Yandex (smtp.yandex.ru) - SendPulse (smtp.sendpulse.com) - Unisender (smtp.unisender.com) ### Шаблон письма **Тема:** Код подтверждения для Ласточки **Текст:** ``` Здравствуйте! Ваш код подтверждения для регистрации в мессенджере Ласточка: 123456 Код действителен в течение 10 минут. Если вы не регистрировались в Ласточке, просто проигнорируйте это письмо. --- Ласточка — Твой дом в интернете ``` ## Безопасность ### Валидация данных - Проверка уникальности логина (real-time) - Валидация формата email - Валидация российского номера телефона - Проверка сложности пароля (минимум 6 символов) - Проверка совпадения паролей ### Защита от злоупотреблений - Rate limiting на отправку email (не чаще 1 раза в минуту) - Максимум 3 попытки ввода кода - Блокировка при множественных неудачных попытках - CSRF-токены для форм ### Хранение данных - Пароль хешируется на сервере - Email и телефон шифруются в базе данных - Токен сессии сохраняется в localStorage ## Пример использования ### Полная регистрация ```typescript import { useState } from 'react' import { useAuthStore } from '@/store/auth' import { isValidEmail, isValidPhoneNumber } from '@/lib/phone-utils' function RegistrationPage() { const [step, setStep] = useState<'form' | 'verification'>('form') const [formData, setFormData] = useState({ login: '', email: '', phone: '', displayName: '', password: '', passwordConfirm: '', }) const { sendRegistrationEmail, verifyRegistrationEmail, isLoading, error } = useAuthStore() const handleSubmit = async () => { // Валидация if (!isValidEmail(formData.email)) return if (!isValidPhoneNumber(formData.phone)) return if (formData.password !== formData.passwordConfirm) return // Отправка await sendRegistrationEmail( formData.login, formData.password, formData.email, formData.phone, formData.displayName ) setStep('verification') } const handleVerify = async (code: string) => { await verifyRegistrationEmail(code) // Регистрация завершена } if (step === 'verification') { return ( setStep('form')} isLoading={isLoading} error={error} /> ) } return (
setFormData({...formData, login: e.target.value})} placeholder="Логин" /> setFormData({...formData, email: e.target.value})} placeholder="Email" /> setFormData({...formData, phone: e.target.value})} placeholder="+7 (999) 999-99-99" /> setFormData({...formData, password: e.target.value})} placeholder="Пароль" /> setFormData({...formData, passwordConfirm: e.target.value})} placeholder="Подтверждение пароля" /> {error &&

{error}

}
) } ``` ## Интеграция с бэкендом ### Эндпоинты Сервер должен поддерживать следующие эндпоинты: 1. **POST /v1/users** — создание учётной записи 2. **POST /v1/creds/email** — запрос кода подтверждения 3. **PUT /v1/creds/email** — проверка кода подтверждения ### Формат запроса ```json // Создание учётной записи { "login": "username", "password": "password123", "public": { "fn": "Display Name", "tel": "79991234567" }, "private": { "email": "user@example.com" }, "cred": { "email": "user@example.com", "tel": "79991234567" }, "login": false } // Запрос кода { "email": "user@example.com", "op": "add" } // Проверка кода { "email": "user@example.com", "val": "123456", "op": "add" } ``` ### Формат ответа ```json { "code": 200, "text": "OK", "params": { "user": "user123", "cred": "email:user@example.com" } } ``` ## Тестирование ### Тестовые email Для тестирования без реальной отправки email: ``` test+lastochka@example.com → код: 123456 ``` ### Mock email-провайдера ```typescript // В разработке можно использовать mock export async function sendEmailCode(email: string) { if (process.env.NODE_ENV === 'development') { console.log(`Email код для ${email}: 123456`) return { success: true } } // Реальная отправка email } ``` ## Отличия от SMS-верификации | Параметр | Email | SMS | |----------|-------|-----| | Стоимость | ~0 ₽ | ~2-5 ₽ за SMS | | Скорость доставки | 5-30 сек | 1-10 сек | | Надёжность | Высокая | Средняя | | Требует телефона | Нет | Да | | Международная поддержка | Да | Зависит от провайдера | --- **Ласточка** — народный мессенджер с открытым кодом 🕊️