Some checks failed
Deploy on push / deploy (push) Failing after 5s
### 🔐 Улучшенная аутентификация для микросервисов #### ✨ Новые возможности - **Универсальная аутентификация**: Добавлена функция `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 режим) - **Множественные форматы**: Поддержка различных способов передачи токенов
102 lines
3.7 KiB
Rust
102 lines
3.7 KiB
Rust
// Используем модули из библиотеки
|
||
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
|
||
}
|