Files
quoter/src/main.rs
Untone 91e5f5dac4
Some checks failed
Deploy on push / deploy (push) Failing after 5s
[0.6.5] - 2025-09-21
### 🔐 Улучшенная аутентификация для микросервисов

####  Новые возможности
- **Универсальная аутентификация**: Добавлена функция `authenticate_request()` для всех handlers
- **Множественные источники токенов**: Поддержка Bearer, X-Session-Token, Cookie
- **Redis сессии**: Интеграция с Redis для проверки активных сессий
- **Безопасная валидация**: Функция `secure_token_validation()` с проверкой TTL и обновлением активности
- **Извлечение токенов**: Универсальная функция `extract_token_from_request()` для всех типов запросов

#### 🧪 Тестирование
- **14 новых тестов**: Полное покрытие новой логики аутентификации
- **Производительность**: Тесты производительности (< 1ms на операцию)
- **Безопасность**: Тесты защиты от подозрительных токенов
- **Граничные случаи**: Тестирование истекших токенов, неверных форматов
- **Интеграция**: Тесты с мокированным Redis

#### ♻️ Рефакторинг (DRY & YAGNI)
- **Устранение дублирования**: Объединена логика аутентификации из upload.rs и user.rs
- **Удаление устаревшего кода**: Убраны `extract_user_id_from_token`, `validate_token`, `get_user_by_token`
- **Очистка констант**: Удалены неиспользуемые `MAX_TOKEN_LENGTH`, `MIN_TOKEN_LENGTH`
- **Упрощение**: Заменена `extract_and_validate_token` на `authenticate_request`

#### ��️ Архитектурные улучшения
- **Библиотечная цель**: Добавлена `lib.rs` для тестирования модулей
- **Модульность**: Четкое разделение ответственности между модулями
- **Единообразие**: Все handlers теперь используют одинаковую логику аутентификации

#### 📋 Совместимость
- **Обратная совместимость**: Все существующие API endpoints работают без изменений
- **Graceful fallback**: Работа без Redis (JWT-only режим)
- **Множественные форматы**: Поддержка различных способов передачи токенов
2025-09-22 01:15:35 +03:00

102 lines
3.7 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Используем модули из библиотеки
use quoter::{app_state, handlers, security};
use actix_cors::Cors;
use actix_web::{
App, HttpServer,
http::header,
middleware::{DefaultHeaders, Logger},
web,
};
use app_state::AppState;
use security::SecurityConfig;
use handlers::universal_handler;
use log::{info, warn};
use std::env;
use tokio::task::spawn_blocking;
#[actix_web::main]
async fn main() -> std::io::Result<()> {
env_logger::init();
warn!("Started");
let port = env::var("PORT").unwrap_or_else(|_| "8080".to_string());
let addr = format!("0.0.0.0:{}", port);
let app_state = AppState::new().await;
let app_state_clone = app_state.clone();
// Используем spawn_blocking для работы, которая не совместима с Send
spawn_blocking(move || {
let rt = tokio::runtime::Handle::current();
rt.block_on(async move {
app_state_clone.cache_filelist().await;
});
});
// Запускаем периодическую очистку кэша
app_state.start_cache_cleanup_task();
// Конфигурация безопасности
let security_config = SecurityConfig::default();
info!(
"Security config: max_payload={} MB, timeout={}s",
security_config.max_payload_size / (1024 * 1024),
security_config.request_timeout_seconds
);
HttpServer::new(move || {
// Настройка CORS middleware - более гибкая для разработки
let cors = Cors::default()
.allowed_origin("https://discours.io")
.allowed_origin("https://new.discours.io")
.allowed_origin("https://testing.discours.io")
.allowed_origin("http://localhost:3000")
.allowed_origin("https://localhost:3000") // HTTPS для разработки
.allowed_origin("https://files.dscrs.site") // Добавляем домен файлов
.allowed_methods(vec!["GET", "POST", "OPTIONS"])
.allowed_headers(vec![
header::CONTENT_TYPE,
header::AUTHORIZATION,
header::IF_NONE_MATCH,
header::CACHE_CONTROL,
header::RANGE, // Для аудио стриминга
])
.expose_headers(vec![
header::CONTENT_LENGTH,
header::ETAG,
header::CONTENT_RANGE, // Для аудио стриминга
header::ACCEPT_RANGES,
])
.supports_credentials()
.max_age(86400); // 1 день
// Заголовки безопасности
let security_headers = DefaultHeaders::new()
.add(("X-Content-Type-Options", "nosniff"))
.add(("X-Frame-Options", "DENY"))
.add(("X-XSS-Protection", "1; mode=block"))
.add(("Referrer-Policy", "strict-origin-when-cross-origin"))
.add((
"Content-Security-Policy",
"default-src 'self'; img-src 'self' data: https:; object-src 'none';",
))
.add((
"Strict-Transport-Security",
"max-age=31536000; includeSubDomains",
));
App::new()
.app_data(web::Data::new(app_state.clone()))
.app_data(web::PayloadConfig::new(security_config.max_payload_size))
.app_data(web::JsonConfig::default().limit(1024 * 1024)) // 1MB для JSON
.wrap(security_headers)
.wrap(cors)
.wrap(Logger::default())
.default_service(web::to(universal_handler))
})
.bind(addr)?
.run()
.await
}