diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index ea8af9d..e68f2db 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -6,11 +6,27 @@ on: - 'RUST' jobs: - docker: + test-build: runs-on: ubuntu-latest + outputs: + rust-version: ${{ steps.vars.outputs.rust_version }} + sha-short: ${{ steps.vars.outputs.sha_short }} steps: - uses: actions/checkout@v4 + - name: Set up Rust toolchain cache + uses: actions/cache@v4 + with: + path: | + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + target/ + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + ${{ runner.os }}-cargo- + - name: Extract version from Cargo.toml id: extract_version run: | @@ -19,22 +35,49 @@ jobs: echo "Extracted version: $VERSION" - name: Set outputs + id: vars + run: | + echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT + echo "rust_version=rs-${{ steps.extract_version.outputs.cargo_version }}" >> $GITHUB_OUTPUT + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Test build (linux/amd64 only) + uses: docker/build-push-action@v5 + with: + context: . + platforms: linux/amd64 + push: false + cache-from: | + type=registry,ref=ultradesu/outfleet:deps-cache + type=registry,ref=ultradesu/outfleet:builder-cache + build-args: | + GIT_COMMIT=${{ github.sha }} + GIT_COMMIT_SHORT=${{ steps.vars.outputs.sha_short }} + BUILD_DATE=$(date -u +'%Y-%m-%d %H:%M:%S UTC') + BRANCH_NAME=${GITHUB_REF#refs/heads/} + CARGO_VERSION=${{ steps.extract_version.outputs.cargo_version }} + + docker: + runs-on: ubuntu-latest + needs: test-build + steps: + - uses: actions/checkout@v4 + + - name: Set build variables id: vars run: | echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT echo "sha_full=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT echo "build_date=$(date -u +'%Y-%m-%d %H:%M:%S UTC')" >> $GITHUB_OUTPUT echo "branch_name=${GITHUB_REF#refs/heads/}" >> $GITHUB_OUTPUT - echo "rust_version=rs-${{ steps.extract_version.outputs.cargo_version }}" >> $GITHUB_OUTPUT - - name: Check outputs + - name: Extract version from Cargo.toml + id: extract_version run: | - echo "Short SHA: ${{ steps.vars.outputs.sha_short }}" - echo "Full SHA: ${{ steps.vars.outputs.sha_full }}" - echo "Build Date: ${{ steps.vars.outputs.build_date }}" - echo "Branch: ${{ steps.vars.outputs.branch_name }}" - echo "Cargo Version: ${{ steps.extract_version.outputs.cargo_version }}" - echo "Rust Version Tag: ${{ steps.vars.outputs.rust_version }}" + VERSION=$(grep '^version = ' Cargo.toml | head -1 | sed 's/version = "\(.*\)"/\1/') + echo "cargo_version=$VERSION" >> $GITHUB_OUTPUT - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 @@ -54,8 +97,14 @@ jobs: context: . platforms: linux/amd64,linux/arm64 push: true - cache-from: type=registry,ref=ultradesu/outfleet:rust-buildcache - cache-to: type=registry,ref=ultradesu/outfleet:rust-buildcache,mode=max + cache-from: | + type=registry,ref=ultradesu/outfleet:deps-cache + type=registry,ref=ultradesu/outfleet:builder-cache + type=registry,ref=ultradesu/outfleet:rust-buildcache + cache-to: | + type=registry,ref=ultradesu/outfleet:deps-cache,mode=max + type=registry,ref=ultradesu/outfleet:builder-cache,mode=max + type=registry,ref=ultradesu/outfleet:rust-buildcache,mode=max build-args: | GIT_COMMIT=${{ steps.vars.outputs.sha_full }} GIT_COMMIT_SHORT=${{ steps.vars.outputs.sha_short }} @@ -63,6 +112,6 @@ jobs: BRANCH_NAME=${{ steps.vars.outputs.branch_name }} CARGO_VERSION=${{ steps.extract_version.outputs.cargo_version }} tags: | - ultradesu/outfleet:${{ steps.vars.outputs.rust_version }} - ultradesu/outfleet:${{ steps.vars.outputs.rust_version }}-${{ steps.vars.outputs.sha_short }} + ultradesu/outfleet:rs-${{ steps.extract_version.outputs.cargo_version }} + ultradesu/outfleet:rs-${{ steps.extract_version.outputs.cargo_version }}-${{ steps.vars.outputs.sha_short }} ultradesu/outfleet:rust-latest \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index d5ead1e..5604ef5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,29 @@ +# Cargo dependencies stage +FROM rust:1.75-slim as deps + +WORKDIR /app + +# Install system dependencies needed for building +RUN apt-get update && apt-get install -y \ + pkg-config \ + libssl-dev \ + protobuf-compiler \ + && rm -rf /var/lib/apt/lists/* + +# Copy only dependency specification files +COPY Cargo.toml Cargo.lock ./ + +# Create dummy source to build dependencies +RUN mkdir -p src && \ + echo "fn main() {}" > src/main.rs && \ + echo "pub fn lib() {}" > src/lib.rs + +# Build dependencies - this layer will be cached unless Cargo.toml changes +RUN cargo build --release && \ + rm -rf src target/release/deps/xray_admin* target/release/xray-admin* + # Build stage -FROM rust:latest as builder +FROM deps as builder # Build arguments ARG GIT_COMMIT="development" @@ -15,27 +39,15 @@ ENV BUILD_DATE=${BUILD_DATE} ENV BRANCH_NAME=${BRANCH_NAME} ENV CARGO_VERSION=${CARGO_VERSION} -WORKDIR /app - -# Install system dependencies -RUN apt-get update && apt-get install -y \ - pkg-config \ - libssl-dev \ - protobuf-compiler \ - && rm -rf /var/lib/apt/lists/* - -# Copy dependency files -COPY Cargo.toml Cargo.lock ./ - -# Copy source code +# Copy actual source code COPY src ./src COPY static ./static -# Build the application +# Build the application (dependencies are already compiled) RUN cargo build --release -# Runtime stage -FROM ubuntu:24.04 +# Runtime stage - minimal Debian image +FROM debian:bookworm-slim as runtime # Build arguments (needed for runtime stage) ARG GIT_COMMIT="development" @@ -53,11 +65,13 @@ ENV CARGO_VERSION=${CARGO_VERSION} WORKDIR /app -# Install runtime dependencies +# Install minimal runtime dependencies RUN apt-get update && apt-get install -y \ ca-certificates \ libssl3 \ - && rm -rf /var/lib/apt/lists/* + libprotobuf32 \ + && rm -rf /var/lib/apt/lists/* \ + && apt-get clean # Copy the binary from builder COPY --from=builder /app/target/release/xray-admin /app/xray-admin @@ -68,6 +82,11 @@ COPY --from=builder /app/static ./static # Copy config file COPY config.docker.toml ./config.toml +# Create non-root user for security +RUN groupadd -r outfleet && useradd -r -g outfleet -s /bin/false outfleet +RUN chown -R outfleet:outfleet /app +USER outfleet + EXPOSE 8081 CMD ["/app/xray-admin", "--host", "0.0.0.0"] diff --git a/src/database/entities/mod.rs b/src/database/entities/mod.rs index a46e4dd..871bd12 100644 --- a/src/database/entities/mod.rs +++ b/src/database/entities/mod.rs @@ -11,13 +11,7 @@ pub mod user_request; pub mod prelude { pub use super::certificate::Entity as Certificate; - pub use super::dns_provider::Entity as DnsProvider; pub use super::inbound_template::Entity as InboundTemplate; - pub use super::inbound_users::Entity as InboundUsers; pub use super::server::Entity as Server; pub use super::server_inbound::Entity as ServerInbound; - pub use super::telegram_config::Entity as TelegramConfig; - pub use super::user::Entity as User; - pub use super::user_access::Entity as UserAccess; - pub use super::user_request::Entity as UserRequest; } diff --git a/src/database/repository/mod.rs b/src/database/repository/mod.rs index 7dc7cde..4639e73 100644 --- a/src/database/repository/mod.rs +++ b/src/database/repository/mod.rs @@ -6,7 +6,6 @@ pub mod server; pub mod server_inbound; pub mod telegram_config; pub mod user; -pub mod user_access; pub mod user_request; pub use certificate::CertificateRepository; @@ -17,5 +16,4 @@ pub use server::ServerRepository; pub use server_inbound::ServerInboundRepository; pub use telegram_config::TelegramConfigRepository; pub use user::UserRepository; -pub use user_access::UserAccessRepository; pub use user_request::UserRequestRepository; diff --git a/src/database/repository/server_inbound.rs b/src/database/repository/server_inbound.rs index 913f075..c6466b5 100644 --- a/src/database/repository/server_inbound.rs +++ b/src/database/repository/server_inbound.rs @@ -76,7 +76,6 @@ impl ServerInboundRepository { &self, server_id: Uuid, ) -> Result> { - use crate::database::entities::{certificate, inbound_template}; let inbounds = ServerInbound::find() .filter(server_inbound::Column::ServerId.eq(server_id)) @@ -193,7 +192,7 @@ impl ServerInboundRepository { Ok(inbound.update(&self.db).await?) } - pub async fn find_by_user_id(&self, user_id: Uuid) -> Result> { + pub async fn find_by_user_id(&self, _user_id: Uuid) -> Result> { // This would need a join with user_access table // For now, returning empty vec as placeholder // TODO: Implement proper join query diff --git a/src/database/repository/user_access.rs b/src/database/repository/user_access.rs deleted file mode 100644 index 63bf54d..0000000 --- a/src/database/repository/user_access.rs +++ /dev/null @@ -1,137 +0,0 @@ -use anyhow::Result; -use sea_orm::*; -use uuid::Uuid; - -use crate::database::entities::user_access::{ - self, ActiveModel, CreateUserAccessDto, Entity as UserAccess, Model, UpdateUserAccessDto, -}; - -pub struct UserAccessRepository { - db: DatabaseConnection, -} - -impl UserAccessRepository { - pub fn new(db: DatabaseConnection) -> Self { - Self { db } - } - - /// Find all user access records - pub async fn find_all(&self) -> Result> { - let records = UserAccess::find().all(&self.db).await?; - Ok(records) - } - - /// Find user access by ID - pub async fn find_by_id(&self, id: Uuid) -> Result> { - let record = UserAccess::find_by_id(id).one(&self.db).await?; - Ok(record) - } - - /// Find user access by user ID - pub async fn find_by_user_id(&self, user_id: Uuid) -> Result> { - let records = UserAccess::find() - .filter(user_access::Column::UserId.eq(user_id)) - .all(&self.db) - .await?; - Ok(records) - } - - /// Find user access by server and inbound - pub async fn find_by_server_inbound( - &self, - server_id: Uuid, - server_inbound_id: Uuid, - ) -> Result> { - let records = UserAccess::find() - .filter(user_access::Column::ServerId.eq(server_id)) - .filter(user_access::Column::ServerInboundId.eq(server_inbound_id)) - .all(&self.db) - .await?; - Ok(records) - } - - /// Find active user access for specific user, server and inbound - pub async fn find_active_access( - &self, - user_id: Uuid, - server_id: Uuid, - server_inbound_id: Uuid, - ) -> Result> { - let record = UserAccess::find() - .filter(user_access::Column::UserId.eq(user_id)) - .filter(user_access::Column::ServerId.eq(server_id)) - .filter(user_access::Column::ServerInboundId.eq(server_inbound_id)) - .filter(user_access::Column::IsActive.eq(true)) - .one(&self.db) - .await?; - Ok(record) - } - - /// Create new user access - pub async fn create(&self, dto: CreateUserAccessDto) -> Result { - let active_model: ActiveModel = dto.into(); - let model = active_model.insert(&self.db).await?; - Ok(model) - } - - /// Update user access - pub async fn update(&self, id: Uuid, dto: UpdateUserAccessDto) -> Result> { - let existing = match self.find_by_id(id).await? { - Some(model) => model, - None => return Ok(None), - }; - - let active_model = existing.apply_update(dto); - let updated = active_model.update(&self.db).await?; - Ok(Some(updated)) - } - - /// Delete user access - pub async fn delete(&self, id: Uuid) -> Result { - let result = UserAccess::delete_by_id(id).exec(&self.db).await?; - Ok(result.rows_affected > 0) - } - - /// Enable user access (set is_active = true) - pub async fn enable(&self, id: Uuid) -> Result> { - self.update( - id, - UpdateUserAccessDto { - is_active: Some(true), - level: None, - }, - ) - .await - } - - /// Disable user access (set is_active = false) - pub async fn disable(&self, id: Uuid) -> Result> { - self.update( - id, - UpdateUserAccessDto { - is_active: Some(false), - level: None, - }, - ) - .await - } - - /// Get all active access for a user - pub async fn find_active_for_user(&self, user_id: Uuid) -> Result> { - let records = UserAccess::find() - .filter(user_access::Column::UserId.eq(user_id)) - .filter(user_access::Column::IsActive.eq(true)) - .all(&self.db) - .await?; - Ok(records) - } - - /// Remove all access for a specific server inbound - pub async fn remove_all_for_inbound(&self, server_inbound_id: Uuid) -> Result { - let result = UserAccess::delete_many() - .filter(user_access::Column::ServerInboundId.eq(server_inbound_id)) - .exec(&self.db) - .await?; - Ok(result.rows_affected) - } -} diff --git a/src/services/acme/client.rs b/src/services/acme/client.rs index ebf6f31..43cad14 100644 --- a/src/services/acme/client.rs +++ b/src/services/acme/client.rs @@ -11,7 +11,6 @@ use crate::services::acme::{AcmeError, CloudflareClient}; pub struct AcmeClient { cloudflare: CloudflareClient, account: Account, - directory_url: String, } impl AcmeClient { @@ -43,7 +42,6 @@ impl AcmeClient { Ok(Self { cloudflare, account, - directory_url, }) } @@ -85,7 +83,7 @@ impl AcmeClient { } // Get challenge value and record ID first - let (challenge_value, record_id) = { + let (_challenge_value, record_id) = { // Find DNS challenge let mut challenge = authz .challenge(ChallengeType::Dns01) diff --git a/src/services/mod.rs b/src/services/mod.rs index d52eecd..6d0148d 100644 --- a/src/services/mod.rs +++ b/src/services/mod.rs @@ -6,7 +6,6 @@ pub mod telegram; pub mod uri_generator; pub mod xray; -pub use certificates::CertificateService; pub use tasks::TaskScheduler; pub use telegram::TelegramService; pub use uri_generator::UriGeneratorService; diff --git a/src/services/tasks.rs b/src/services/tasks.rs index 6e21ecb..f4086a0 100644 --- a/src/services/tasks.rs +++ b/src/services/tasks.rs @@ -1,4 +1,3 @@ -use crate::database::entities::inbound_users; use crate::database::repository::{ CertificateRepository, InboundTemplateRepository, InboundUsersRepository, ServerInboundRepository, ServerRepository, UserRepository, @@ -8,7 +7,6 @@ use crate::services::events::SyncEvent; use crate::services::XrayService; use anyhow::Result; use chrono::{DateTime, Utc}; -use sea_orm::{ColumnTrait, EntityTrait, JoinType, QueryFilter, RelationTrait}; use serde::{Deserialize, Serialize}; use serde_json::Value; use std::collections::HashMap; diff --git a/src/services/telegram/bot.rs b/src/services/telegram/bot.rs index 65898b3..79881ba 100644 --- a/src/services/telegram/bot.rs +++ b/src/services/telegram/bot.rs @@ -10,7 +10,7 @@ pub async fn run_polling( bot: Bot, db: DatabaseManager, app_config: AppConfig, - mut shutdown_rx: oneshot::Receiver<()>, + shutdown_rx: oneshot::Receiver<()>, ) { tracing::info!("Starting Telegram bot polling..."); diff --git a/src/services/telegram/handlers/admin.rs b/src/services/telegram/handlers/admin.rs index bc8f91d..dbbca3a 100644 --- a/src/services/telegram/handlers/admin.rs +++ b/src/services/telegram/handlers/admin.rs @@ -249,7 +249,7 @@ pub async fn handle_approve_request( }; match user_repo.create(dto).await { - Ok(new_user) => { + Ok(_new_user) => { // Approve the request request_repo .approve( @@ -297,9 +297,9 @@ pub async fn handle_approve_request( } // Send main menu to the user instead of just notification - let user_lang = Language::from_telegram_code(Some(&request.get_language())); + let _user_lang = Language::from_telegram_code(Some(&request.get_language())); let user_repo_for_user = UserRepository::new(db.connection()); - let is_admin = false; // New users are not admins by default + let _is_admin = false; // New users are not admins by default // Create a fake user object for language detection let fake_user = teloxide::types::User { @@ -633,7 +633,7 @@ pub async fn handle_select_server_access( short_request_id: &str, db: &DatabaseManager, ) -> Result<(), Box> { - let lang = Language::English; // Default admin language + let _lang = Language::English; // Default admin language let _l10n = LocalizationService::new(); let chat_id = q .message @@ -815,7 +815,7 @@ pub async fn handle_apply_server_access( short_request_id: &str, db: &DatabaseManager, ) -> Result<(), Box> { - let lang = Language::English; // Default admin language + let _lang = Language::English; // Default admin language let _l10n = LocalizationService::new(); let chat_id = q .message @@ -1177,7 +1177,7 @@ pub async fn handle_user_details( // Build keyboard let short_user_id = generate_short_user_id(&user_id.to_string()); - let mut keyboard_buttons = vec![ + let keyboard_buttons = vec![ vec![InlineKeyboardButton::callback( l10n.get(lang.clone(), "manage_access"), format!("user_manage:{}", short_user_id), diff --git a/src/services/telegram/handlers/mod.rs b/src/services/telegram/handlers/mod.rs index 2c72eea..a52933c 100644 --- a/src/services/telegram/handlers/mod.rs +++ b/src/services/telegram/handlers/mod.rs @@ -17,7 +17,7 @@ pub async fn handle_command( msg: Message, cmd: Command, db: DatabaseManager, - app_config: AppConfig, + _app_config: AppConfig, ) -> Result<(), Box> { let chat_id = msg.chat.id; let from = &msg.from.ok_or("No user info")?; diff --git a/src/services/telegram/handlers/types.rs b/src/services/telegram/handlers/types.rs index b0330de..1494371 100644 --- a/src/services/telegram/handlers/types.rs +++ b/src/services/telegram/handlers/types.rs @@ -289,21 +289,3 @@ pub fn get_new_user_keyboard(lang: Language) -> InlineKeyboardMarkup { )]]) } -/// Restore UUID from compact format (without dashes) -fn restore_uuid(compact: &str) -> Option { - if compact.len() != 32 { - return None; - } - - // Insert dashes at proper positions for UUID format - let uuid_str = format!( - "{}-{}-{}-{}-{}", - &compact[0..8], - &compact[8..12], - &compact[12..16], - &compact[16..20], - &compact[20..32] - ); - - Some(uuid_str) -} diff --git a/src/services/telegram/handlers/user.rs b/src/services/telegram/handlers/user.rs index 5138eac..ba4a008 100644 --- a/src/services/telegram/handlers/user.rs +++ b/src/services/telegram/handlers/user.rs @@ -6,7 +6,7 @@ use teloxide::{ use super::super::localization::{Language, LocalizationService}; use super::types::{get_main_keyboard, get_new_user_keyboard, get_user_language}; -use crate::database::entities::user_request::{CreateUserRequestDto, RequestStatus}; +use crate::database::entities::user_request::CreateUserRequestDto; use crate::database::repository::{UserRepository, UserRequestRepository}; use crate::database::DatabaseManager; diff --git a/src/services/telegram/mod.rs b/src/services/telegram/mod.rs index 05e7c5f..3935f9c 100644 --- a/src/services/telegram/mod.rs +++ b/src/services/telegram/mod.rs @@ -14,7 +14,6 @@ pub mod error; pub mod handlers; pub mod localization; -pub use error::TelegramError; /// Main Telegram service that manages the bot lifecycle pub struct TelegramService { diff --git a/src/services/uri_generator/builders/mod.rs b/src/services/uri_generator/builders/mod.rs index 1c86355..409b9d6 100644 --- a/src/services/uri_generator/builders/mod.rs +++ b/src/services/uri_generator/builders/mod.rs @@ -38,7 +38,6 @@ pub trait UriBuilder { /// Helper functions for URI building pub mod utils { - use crate::services::uri_generator::error::UriGeneratorError; use serde_json::Value; use std::collections::HashMap; diff --git a/src/services/uri_generator/builders/shadowsocks.rs b/src/services/uri_generator/builders/shadowsocks.rs index 321cdbd..d9b450a 100644 --- a/src/services/uri_generator/builders/shadowsocks.rs +++ b/src/services/uri_generator/builders/shadowsocks.rs @@ -1,5 +1,4 @@ use base64::{engine::general_purpose, Engine as _}; -use serde_json::Value; use super::{utils, UriBuilder}; use crate::services::uri_generator::{error::UriGeneratorError, ClientConfigData}; diff --git a/src/services/uri_generator/builders/vmess.rs b/src/services/uri_generator/builders/vmess.rs index 8fbebce..86d5e08 100644 --- a/src/services/uri_generator/builders/vmess.rs +++ b/src/services/uri_generator/builders/vmess.rs @@ -1,6 +1,5 @@ use base64::{engine::general_purpose, Engine as _}; use serde_json::{json, Value}; -use std::collections::HashMap; use super::{utils, UriBuilder}; use crate::services::uri_generator::{error::UriGeneratorError, ClientConfigData}; @@ -144,97 +143,6 @@ impl VmessUriBuilder { Ok(format!("vmess://{}", encoded)) } - /// Build VMess URI in query parameter format (alternative) - fn build_query_param_uri( - &self, - config: &ClientConfigData, - ) -> Result { - // Apply variable substitution to stream settings - let stream_settings = if !config.variable_values.is_null() { - apply_variables(&config.stream_settings, &config.variable_values)? - } else { - config.stream_settings.clone() - }; - - let mut params = HashMap::new(); - - // VMess uses auto encryption - params.insert("encryption".to_string(), "auto".to_string()); - - // Determine security layer - let has_certificate = config.certificate_domain.is_some(); - let security = utils::extract_security_type(&stream_settings, has_certificate); - if security != "none" { - params.insert("security".to_string(), security.clone()); - } - - // Transport type - let transport_type = utils::extract_transport_type(&stream_settings); - if transport_type != "tcp" { - params.insert("type".to_string(), transport_type.clone()); - } - - // Transport-specific parameters - match transport_type.as_str() { - "ws" => { - if let Some(path) = utils::extract_ws_path(&stream_settings) { - params.insert("path".to_string(), path); - } - if let Some(host) = utils::extract_ws_host(&stream_settings) { - params.insert("host".to_string(), host); - } - } - "grpc" => { - if let Some(service_name) = utils::extract_grpc_service_name(&stream_settings) { - params.insert("serviceName".to_string(), service_name); - } - params.insert("mode".to_string(), "gun".to_string()); - } - _ => {} - } - - // TLS specific parameters - if security != "none" { - if let Some(sni) = - utils::extract_tls_sni(&stream_settings, config.certificate_domain.as_deref()) - { - params.insert("sni".to_string(), sni); - } - - if let Some(fp) = stream_settings - .get("tlsSettings") - .and_then(|tls| tls.get("fingerprint")) - .and_then(|fp| fp.as_str()) - { - params.insert("fp".to_string(), fp.to_string()); - } - } - - // Build the URI - let query_string = utils::build_query_string(¶ms); - let alias = utils::generate_alias(&config.server_name, &config.template_name); - - let uri = if query_string.is_empty() { - format!( - "vmess://{}@{}:{}#{}", - config.xray_user_id, - config.hostname, - config.port, - utils::url_encode(&alias) - ) - } else { - format!( - "vmess://{}@{}:{}?{}#{}", - config.xray_user_id, - config.hostname, - config.port, - query_string, - utils::url_encode(&alias) - ) - }; - - Ok(uri) - } } impl UriBuilder for VmessUriBuilder { diff --git a/src/services/uri_generator/mod.rs b/src/services/uri_generator/mod.rs index e19d2de..e304ccb 100644 --- a/src/services/uri_generator/mod.rs +++ b/src/services/uri_generator/mod.rs @@ -107,7 +107,8 @@ impl UriGeneratorService { }) } - /// Apply variable substitution to JSON values + /// Apply variable substitution to JSON values (for testing) + #[cfg(test)] pub fn apply_variable_substitution( &self, template: &Value, @@ -132,6 +133,7 @@ impl UriGeneratorService { serde_json::from_str(&result) .map_err(|e| UriGeneratorError::VariableSubstitution(e.to_string())) } + } impl Default for UriGeneratorService { diff --git a/src/services/xray/inbounds.rs b/src/services/xray/inbounds.rs index 65e5966..9e4944c 100644 --- a/src/services/xray/inbounds.rs +++ b/src/services/xray/inbounds.rs @@ -9,7 +9,6 @@ use xray_core::{ common::protocol::User, common::serial::TypedMessage, core::InboundHandlerConfig, - prost_types, proxy::shadowsocks::ServerConfig as ShadowsocksServerConfig, proxy::shadowsocks::{Account as ShadowsocksAccount, CipherType}, proxy::trojan::Account as TrojanAccount, @@ -24,23 +23,6 @@ use xray_core::{ Client, }; -/// Convert PEM format to DER (x509) format -fn pem_to_der(pem_data: &str) -> Result> { - // Remove PEM headers and whitespace, then decode base64 - let base64_data: String = pem_data - .lines() - .filter(|line| !line.starts_with("-----") && !line.trim().is_empty()) - .map(|line| line.trim()) - .collect::>() - .join(""); - - tracing::debug!("PEM to DER conversion: {} bytes", base64_data.len()); - - use base64::{engine::general_purpose, Engine as _}; - general_purpose::STANDARD - .decode(&base64_data) - .map_err(|e| anyhow!("Failed to decode base64 PEM data: {}", e)) -} pub struct InboundClient<'a> { endpoint: String, @@ -364,7 +346,7 @@ impl<'a> InboundClient<'a> { /// Restart Xray with new configuration pub async fn restart_with_config( &self, - config: &crate::services::xray::XrayConfig, + _config: &crate::services::xray::XrayConfig, ) -> Result<()> { tracing::debug!( "Restarting Xray server at {} with new config", diff --git a/src/services/xray/mod.rs b/src/services/xray/mod.rs index f97b07a..c5500f5 100644 --- a/src/services/xray/mod.rs +++ b/src/services/xray/mod.rs @@ -4,7 +4,7 @@ use std::collections::HashMap; use std::sync::Arc; use tokio::sync::RwLock; use tokio::time::{timeout, Duration, Instant}; -use tracing::{error, warn}; +use tracing::warn; use uuid::Uuid; pub mod client; @@ -307,7 +307,7 @@ impl XrayService { #[cfg(test)] mod tests { use super::*; - use tokio::time::{sleep, Duration}; + use tokio::time::Duration; use uuid::Uuid; #[tokio::test] @@ -378,7 +378,7 @@ mod tests { fn test_cached_connection_expiration() { // Create a mock client for testing purposes // In real tests, we would use a mock framework - let now = Instant::now(); + let _now = Instant::now(); // Test the expiration logic directly without creating an actual client let short_ttl = Duration::from_nanos(1); diff --git a/src/services/xray/users.rs b/src/services/xray/users.rs index 2afb86e..ff0e7d5 100644 --- a/src/services/xray/users.rs +++ b/src/services/xray/users.rs @@ -13,13 +13,12 @@ use xray_core::{ }; pub struct UserClient<'a> { - endpoint: String, client: &'a Client, } impl<'a> UserClient<'a> { - pub fn new(endpoint: String, client: &'a Client) -> Self { - Self { endpoint, client } + pub fn new(_endpoint: String, client: &'a Client) -> Self { + Self { client } } /// Add user to inbound (simple version that works) diff --git a/src/web/handlers/client_configs.rs b/src/web/handlers/client_configs.rs index ba45152..1963f5d 100644 --- a/src/web/handlers/client_configs.rs +++ b/src/web/handlers/client_configs.rs @@ -101,7 +101,7 @@ pub async fn get_user_configs( /// Get all URIs for all users of a specific inbound pub async fn get_inbound_configs( State(app_state): State, - Path((server_id, inbound_id)): Path<(Uuid, Uuid)>, + Path((_server_id, inbound_id)): Path<(Uuid, Uuid)>, ) -> Result>, StatusCode> { let repo = InboundUsersRepository::new(app_state.db.connection().clone()); let uri_service = UriGeneratorService::new(); diff --git a/src/web/handlers/servers.rs b/src/web/handlers/servers.rs index 797c710..0e9bb4a 100644 --- a/src/web/handlers/servers.rs +++ b/src/web/handlers/servers.rs @@ -638,7 +638,7 @@ pub async fn remove_user_from_inbound( // Get inbound tag let template_repo = InboundTemplateRepository::new(app_state.db.connection().clone()); - let template = match template_repo.find_by_id(inbound.template_id).await { + let _template = match template_repo.find_by_id(inbound.template_id).await { Ok(Some(template)) => template, Ok(None) => return Err(StatusCode::NOT_FOUND), Err(_) => return Err(StatusCode::INTERNAL_SERVER_ERROR), diff --git a/src/web/handlers/tasks.rs b/src/web/handlers/tasks.rs index d1bc975..3c4f7bf 100644 --- a/src/web/handlers/tasks.rs +++ b/src/web/handlers/tasks.rs @@ -36,7 +36,7 @@ pub struct TasksSummary { /// Get status of all scheduled tasks pub async fn get_tasks_status( - State(state): State, + State(_state): State, ) -> Result, StatusCode> { // Get task status from the scheduler // For now, we'll return a mock response since we need to expose the scheduler diff --git a/src/web/handlers/user_requests.rs b/src/web/handlers/user_requests.rs index c54618a..adce1e5 100644 --- a/src/web/handlers/user_requests.rs +++ b/src/web/handlers/user_requests.rs @@ -7,7 +7,6 @@ use serde::{Deserialize, Serialize}; use uuid::Uuid; use crate::{ - database::entities::user_request::{CreateUserRequestDto, RequestStatus, UpdateUserRequestDto}, database::repository::UserRequestRepository, services::telegram::localization::{Language, LocalizationService}, web::AppState, diff --git a/src/web/mod.rs b/src/web/mod.rs index 167d162..43590cc 100644 --- a/src/web/mod.rs +++ b/src/web/mod.rs @@ -7,7 +7,7 @@ use tower_http::cors::CorsLayer; use tower_http::services::ServeDir; use tracing::info; -use crate::config::{AppConfig, WebConfig}; +use crate::config::AppConfig; use crate::database::DatabaseManager; use crate::services::{TelegramService, XrayService}; use std::sync::Arc; diff --git a/src/web/routes/mod.rs b/src/web/routes/mod.rs index 78a05df..4d479a7 100644 --- a/src/web/routes/mod.rs +++ b/src/web/routes/mod.rs @@ -1,5 +1,5 @@ use axum::{ - routing::{delete, get, post, put}, + routing::{get, post}, Router, };