init rust. WIP: tls for inbounds

This commit is contained in:
Ultradesu
2025-09-18 02:56:59 +03:00
parent 777af49ebf
commit 8aff8f2fb5
206 changed files with 14301 additions and 21560 deletions

View File

@@ -0,0 +1,135 @@
use sea_orm_migration::prelude::*;
#[derive(DeriveMigrationName)]
pub struct Migration;
#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
// Create users table
manager
.create_table(
Table::create()
.table(Users::Table)
.if_not_exists()
.col(
ColumnDef::new(Users::Id)
.uuid()
.not_null()
.primary_key(),
)
.col(
ColumnDef::new(Users::Name)
.string_len(255)
.not_null(),
)
.col(
ColumnDef::new(Users::Comment)
.text()
.null(),
)
.col(
ColumnDef::new(Users::TelegramId)
.big_integer()
.null(),
)
.col(
ColumnDef::new(Users::CreatedAt)
.timestamp_with_time_zone()
.not_null(),
)
.col(
ColumnDef::new(Users::UpdatedAt)
.timestamp_with_time_zone()
.not_null(),
)
.to_owned(),
)
.await?;
// Create index on name for faster searches
manager
.create_index(
Index::create()
.if_not_exists()
.name("idx_users_name")
.table(Users::Table)
.col(Users::Name)
.to_owned(),
)
.await?;
// Create unique index on telegram_id (if not null)
manager
.create_index(
Index::create()
.if_not_exists()
.name("idx_users_telegram_id")
.table(Users::Table)
.col(Users::TelegramId)
.unique()
.to_owned(),
)
.await?;
// Create index on created_at for sorting
manager
.create_index(
Index::create()
.if_not_exists()
.name("idx_users_created_at")
.table(Users::Table)
.col(Users::CreatedAt)
.to_owned(),
)
.await?;
Ok(())
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
// Drop indexes first
manager
.drop_index(
Index::drop()
.if_exists()
.name("idx_users_created_at")
.to_owned(),
)
.await?;
manager
.drop_index(
Index::drop()
.if_exists()
.name("idx_users_telegram_id")
.to_owned(),
)
.await?;
manager
.drop_index(
Index::drop()
.if_exists()
.name("idx_users_name")
.to_owned(),
)
.await?;
// Drop table
manager
.drop_table(Table::drop().table(Users::Table).to_owned())
.await
}
}
#[derive(DeriveIden)]
enum Users {
Table,
Id,
Name,
Comment,
TelegramId,
CreatedAt,
UpdatedAt,
}

View File

@@ -0,0 +1,120 @@
use sea_orm_migration::prelude::*;
#[derive(DeriveMigrationName)]
pub struct Migration;
#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.create_table(
Table::create()
.table(Certificates::Table)
.if_not_exists()
.col(
ColumnDef::new(Certificates::Id)
.uuid()
.not_null()
.primary_key(),
)
.col(
ColumnDef::new(Certificates::Name)
.string_len(255)
.not_null(),
)
.col(
ColumnDef::new(Certificates::CertType)
.string_len(50)
.not_null(),
)
.col(
ColumnDef::new(Certificates::Domain)
.string_len(255)
.not_null(),
)
.col(
ColumnDef::new(Certificates::CertData)
.blob()
.not_null(),
)
.col(
ColumnDef::new(Certificates::KeyData)
.blob()
.not_null(),
)
.col(
ColumnDef::new(Certificates::ChainData)
.blob()
.null(),
)
.col(
ColumnDef::new(Certificates::ExpiresAt)
.timestamp_with_time_zone()
.not_null(),
)
.col(
ColumnDef::new(Certificates::AutoRenew)
.boolean()
.default(false)
.not_null(),
)
.col(
ColumnDef::new(Certificates::CreatedAt)
.timestamp_with_time_zone()
.not_null(),
)
.col(
ColumnDef::new(Certificates::UpdatedAt)
.timestamp_with_time_zone()
.not_null(),
)
.to_owned(),
)
.await?;
// Index on domain for faster lookups
manager
.create_index(
Index::create()
.if_not_exists()
.name("idx_certificates_domain")
.table(Certificates::Table)
.col(Certificates::Domain)
.to_owned(),
)
.await?;
Ok(())
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.drop_index(
Index::drop()
.if_exists()
.name("idx_certificates_domain")
.to_owned(),
)
.await?;
manager
.drop_table(Table::drop().table(Certificates::Table).to_owned())
.await
}
}
#[derive(DeriveIden)]
enum Certificates {
Table,
Id,
Name,
CertType,
Domain,
CertData,
KeyData,
ChainData,
ExpiresAt,
AutoRenew,
CreatedAt,
UpdatedAt,
}

View File

@@ -0,0 +1,155 @@
use sea_orm_migration::prelude::*;
#[derive(DeriveMigrationName)]
pub struct Migration;
#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.create_table(
Table::create()
.table(InboundTemplates::Table)
.if_not_exists()
.col(
ColumnDef::new(InboundTemplates::Id)
.uuid()
.not_null()
.primary_key(),
)
.col(
ColumnDef::new(InboundTemplates::Name)
.string_len(255)
.not_null(),
)
.col(
ColumnDef::new(InboundTemplates::Description)
.text()
.null(),
)
.col(
ColumnDef::new(InboundTemplates::Protocol)
.string_len(50)
.not_null(),
)
.col(
ColumnDef::new(InboundTemplates::DefaultPort)
.integer()
.not_null(),
)
.col(
ColumnDef::new(InboundTemplates::BaseSettings)
.json()
.not_null(),
)
.col(
ColumnDef::new(InboundTemplates::StreamSettings)
.json()
.not_null(),
)
.col(
ColumnDef::new(InboundTemplates::RequiresTls)
.boolean()
.default(false)
.not_null(),
)
.col(
ColumnDef::new(InboundTemplates::RequiresDomain)
.boolean()
.default(false)
.not_null(),
)
.col(
ColumnDef::new(InboundTemplates::Variables)
.json()
.not_null(),
)
.col(
ColumnDef::new(InboundTemplates::IsActive)
.boolean()
.default(true)
.not_null(),
)
.col(
ColumnDef::new(InboundTemplates::CreatedAt)
.timestamp_with_time_zone()
.not_null(),
)
.col(
ColumnDef::new(InboundTemplates::UpdatedAt)
.timestamp_with_time_zone()
.not_null(),
)
.to_owned(),
)
.await?;
// Index on name for searches
manager
.create_index(
Index::create()
.if_not_exists()
.name("idx_inbound_templates_name")
.table(InboundTemplates::Table)
.col(InboundTemplates::Name)
.to_owned(),
)
.await?;
// Index on protocol
manager
.create_index(
Index::create()
.if_not_exists()
.name("idx_inbound_templates_protocol")
.table(InboundTemplates::Table)
.col(InboundTemplates::Protocol)
.to_owned(),
)
.await?;
Ok(())
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.drop_index(
Index::drop()
.if_exists()
.name("idx_inbound_templates_protocol")
.to_owned(),
)
.await?;
manager
.drop_index(
Index::drop()
.if_exists()
.name("idx_inbound_templates_name")
.to_owned(),
)
.await?;
manager
.drop_table(Table::drop().table(InboundTemplates::Table).to_owned())
.await
}
}
#[derive(DeriveIden)]
enum InboundTemplates {
Table,
Id,
Name,
Description,
Protocol,
DefaultPort,
BaseSettings,
StreamSettings,
RequiresTls,
RequiresDomain,
Variables,
IsActive,
CreatedAt,
UpdatedAt,
}

View File

@@ -0,0 +1,136 @@
use sea_orm_migration::prelude::*;
#[derive(DeriveMigrationName)]
pub struct Migration;
#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.create_table(
Table::create()
.table(Servers::Table)
.if_not_exists()
.col(
ColumnDef::new(Servers::Id)
.uuid()
.not_null()
.primary_key(),
)
.col(
ColumnDef::new(Servers::Name)
.string_len(255)
.not_null(),
)
.col(
ColumnDef::new(Servers::Hostname)
.string_len(255)
.not_null(),
)
.col(
ColumnDef::new(Servers::GrpcPort)
.integer()
.default(2053)
.not_null(),
)
.col(
ColumnDef::new(Servers::ApiCredentials)
.text()
.null(),
)
.col(
ColumnDef::new(Servers::Status)
.string_len(50)
.default("unknown")
.not_null(),
)
.col(
ColumnDef::new(Servers::DefaultCertificateId)
.uuid()
.null(),
)
.col(
ColumnDef::new(Servers::CreatedAt)
.timestamp_with_time_zone()
.not_null(),
)
.col(
ColumnDef::new(Servers::UpdatedAt)
.timestamp_with_time_zone()
.not_null(),
)
.to_owned(),
)
.await?;
// Foreign key to certificates
manager
.create_foreign_key(
ForeignKey::create()
.name("fk_servers_default_certificate")
.from(Servers::Table, Servers::DefaultCertificateId)
.to(Certificates::Table, Certificates::Id)
.on_delete(ForeignKeyAction::SetNull)
.to_owned(),
)
.await?;
// Index on hostname
manager
.create_index(
Index::create()
.if_not_exists()
.name("idx_servers_hostname")
.table(Servers::Table)
.col(Servers::Hostname)
.to_owned(),
)
.await?;
Ok(())
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.drop_foreign_key(
ForeignKey::drop()
.name("fk_servers_default_certificate")
.table(Servers::Table)
.to_owned(),
)
.await?;
manager
.drop_index(
Index::drop()
.if_exists()
.name("idx_servers_hostname")
.to_owned(),
)
.await?;
manager
.drop_table(Table::drop().table(Servers::Table).to_owned())
.await
}
}
#[derive(DeriveIden)]
enum Servers {
Table,
Id,
Name,
Hostname,
GrpcPort,
ApiCredentials,
Status,
DefaultCertificateId,
CreatedAt,
UpdatedAt,
}
#[derive(DeriveIden)]
enum Certificates {
Table,
Id,
}

View File

@@ -0,0 +1,195 @@
use sea_orm_migration::prelude::*;
#[derive(DeriveMigrationName)]
pub struct Migration;
#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.create_table(
Table::create()
.table(ServerInbounds::Table)
.if_not_exists()
.col(
ColumnDef::new(ServerInbounds::Id)
.uuid()
.not_null()
.primary_key(),
)
.col(
ColumnDef::new(ServerInbounds::ServerId)
.uuid()
.not_null(),
)
.col(
ColumnDef::new(ServerInbounds::TemplateId)
.uuid()
.not_null(),
)
.col(
ColumnDef::new(ServerInbounds::Tag)
.string_len(255)
.not_null(),
)
.col(
ColumnDef::new(ServerInbounds::PortOverride)
.integer()
.null(),
)
.col(
ColumnDef::new(ServerInbounds::CertificateId)
.uuid()
.null(),
)
.col(
ColumnDef::new(ServerInbounds::VariableValues)
.json()
.not_null(),
)
.col(
ColumnDef::new(ServerInbounds::IsActive)
.boolean()
.default(true)
.not_null(),
)
.col(
ColumnDef::new(ServerInbounds::CreatedAt)
.timestamp_with_time_zone()
.not_null(),
)
.col(
ColumnDef::new(ServerInbounds::UpdatedAt)
.timestamp_with_time_zone()
.not_null(),
)
.to_owned(),
)
.await?;
// Foreign keys
manager
.create_foreign_key(
ForeignKey::create()
.name("fk_server_inbounds_server")
.from(ServerInbounds::Table, ServerInbounds::ServerId)
.to(Servers::Table, Servers::Id)
.on_delete(ForeignKeyAction::Cascade)
.to_owned(),
)
.await?;
manager
.create_foreign_key(
ForeignKey::create()
.name("fk_server_inbounds_template")
.from(ServerInbounds::Table, ServerInbounds::TemplateId)
.to(InboundTemplates::Table, InboundTemplates::Id)
.on_delete(ForeignKeyAction::Restrict)
.to_owned(),
)
.await?;
manager
.create_foreign_key(
ForeignKey::create()
.name("fk_server_inbounds_certificate")
.from(ServerInbounds::Table, ServerInbounds::CertificateId)
.to(Certificates::Table, Certificates::Id)
.on_delete(ForeignKeyAction::SetNull)
.to_owned(),
)
.await?;
// Unique constraint on server_id + tag
manager
.create_index(
Index::create()
.if_not_exists()
.name("idx_server_inbounds_server_tag")
.table(ServerInbounds::Table)
.col(ServerInbounds::ServerId)
.col(ServerInbounds::Tag)
.unique()
.to_owned(),
)
.await?;
Ok(())
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.drop_foreign_key(
ForeignKey::drop()
.name("fk_server_inbounds_certificate")
.table(ServerInbounds::Table)
.to_owned(),
)
.await?;
manager
.drop_foreign_key(
ForeignKey::drop()
.name("fk_server_inbounds_template")
.table(ServerInbounds::Table)
.to_owned(),
)
.await?;
manager
.drop_foreign_key(
ForeignKey::drop()
.name("fk_server_inbounds_server")
.table(ServerInbounds::Table)
.to_owned(),
)
.await?;
manager
.drop_index(
Index::drop()
.if_exists()
.name("idx_server_inbounds_server_tag")
.to_owned(),
)
.await?;
manager
.drop_table(Table::drop().table(ServerInbounds::Table).to_owned())
.await
}
}
#[derive(DeriveIden)]
enum ServerInbounds {
Table,
Id,
ServerId,
TemplateId,
Tag,
PortOverride,
CertificateId,
VariableValues,
IsActive,
CreatedAt,
UpdatedAt,
}
#[derive(DeriveIden)]
enum Servers {
Table,
Id,
}
#[derive(DeriveIden)]
enum InboundTemplates {
Table,
Id,
}
#[derive(DeriveIden)]
enum Certificates {
Table,
Id,
}

View File

@@ -0,0 +1,196 @@
use sea_orm_migration::prelude::*;
#[derive(DeriveMigrationName)]
pub struct Migration;
#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.create_table(
Table::create()
.table(UserAccess::Table)
.if_not_exists()
.col(
ColumnDef::new(UserAccess::Id)
.uuid()
.not_null()
.primary_key(),
)
.col(
ColumnDef::new(UserAccess::UserId)
.uuid()
.not_null(),
)
.col(
ColumnDef::new(UserAccess::ServerId)
.uuid()
.not_null(),
)
.col(
ColumnDef::new(UserAccess::ServerInboundId)
.uuid()
.not_null(),
)
.col(
ColumnDef::new(UserAccess::XrayUserId)
.string()
.not_null(),
)
.col(
ColumnDef::new(UserAccess::XrayEmail)
.string()
.not_null(),
)
.col(
ColumnDef::new(UserAccess::Level)
.integer()
.not_null(),
)
.col(
ColumnDef::new(UserAccess::IsActive)
.boolean()
.not_null(),
)
.col(
ColumnDef::new(UserAccess::CreatedAt)
.timestamp_with_time_zone()
.not_null(),
)
.col(
ColumnDef::new(UserAccess::UpdatedAt)
.timestamp_with_time_zone()
.not_null(),
)
.foreign_key(
ForeignKey::create()
.name("fk_user_access_user_id")
.from(UserAccess::Table, UserAccess::UserId)
.to(Users::Table, Users::Id)
.on_delete(ForeignKeyAction::Cascade),
)
.foreign_key(
ForeignKey::create()
.name("fk_user_access_server_id")
.from(UserAccess::Table, UserAccess::ServerId)
.to(Servers::Table, Servers::Id)
.on_delete(ForeignKeyAction::Cascade),
)
.foreign_key(
ForeignKey::create()
.name("fk_user_access_server_inbound_id")
.from(UserAccess::Table, UserAccess::ServerInboundId)
.to(ServerInbounds::Table, ServerInbounds::Id)
.on_delete(ForeignKeyAction::Cascade),
)
.to_owned(),
)
.await?;
// Create indexes separately
manager
.create_index(
Index::create()
.if_not_exists()
.name("idx_user_access_server_inbound")
.table(UserAccess::Table)
.col(UserAccess::ServerId)
.col(UserAccess::ServerInboundId)
.to_owned(),
)
.await?;
manager
.create_index(
Index::create()
.if_not_exists()
.name("idx_user_access_user_server")
.table(UserAccess::Table)
.col(UserAccess::UserId)
.col(UserAccess::ServerId)
.to_owned(),
)
.await?;
manager
.create_index(
Index::create()
.if_not_exists()
.name("idx_user_access_xray_email")
.table(UserAccess::Table)
.col(UserAccess::XrayEmail)
.to_owned(),
)
.await?;
Ok(())
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
// Drop indexes first
manager
.drop_index(
Index::drop()
.if_exists()
.name("idx_user_access_xray_email")
.to_owned(),
)
.await?;
manager
.drop_index(
Index::drop()
.if_exists()
.name("idx_user_access_user_server")
.to_owned(),
)
.await?;
manager
.drop_index(
Index::drop()
.if_exists()
.name("idx_user_access_server_inbound")
.to_owned(),
)
.await?;
// Drop table
manager
.drop_table(Table::drop().table(UserAccess::Table).to_owned())
.await
}
}
#[derive(DeriveIden)]
enum UserAccess {
Table,
Id,
UserId,
ServerId,
ServerInboundId,
XrayUserId,
XrayEmail,
Level,
IsActive,
CreatedAt,
UpdatedAt,
}
#[derive(DeriveIden)]
enum Users {
Table,
Id,
}
#[derive(DeriveIden)]
enum Servers {
Table,
Id,
}
#[derive(DeriveIden)]
enum ServerInbounds {
Table,
Id,
}

View File

@@ -0,0 +1,125 @@
use sea_orm_migration::prelude::*;
#[derive(DeriveMigrationName)]
pub struct Migration;
#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.create_table(
Table::create()
.table(InboundUsers::Table)
.if_not_exists()
.col(
ColumnDef::new(InboundUsers::Id)
.uuid()
.not_null()
.primary_key(),
)
.col(
ColumnDef::new(InboundUsers::ServerInboundId)
.uuid()
.not_null(),
)
.col(
ColumnDef::new(InboundUsers::Username)
.string()
.not_null(),
)
.col(
ColumnDef::new(InboundUsers::Email)
.string()
.not_null(),
)
.col(
ColumnDef::new(InboundUsers::XrayUserId)
.string()
.not_null(),
)
.col(
ColumnDef::new(InboundUsers::Level)
.integer()
.not_null()
.default(0),
)
.col(
ColumnDef::new(InboundUsers::IsActive)
.boolean()
.not_null()
.default(true),
)
.col(
ColumnDef::new(InboundUsers::CreatedAt)
.timestamp_with_time_zone()
.not_null(),
)
.col(
ColumnDef::new(InboundUsers::UpdatedAt)
.timestamp_with_time_zone()
.not_null(),
)
.foreign_key(
ForeignKey::create()
.name("fk_inbound_users_server_inbound")
.from(InboundUsers::Table, InboundUsers::ServerInboundId)
.to(ServerInbounds::Table, ServerInbounds::Id)
.on_delete(ForeignKeyAction::Cascade),
)
.to_owned(),
)
.await?;
// Create unique constraint: one user per inbound
manager
.create_index(
Index::create()
.name("idx_inbound_users_unique_user_per_inbound")
.table(InboundUsers::Table)
.col(InboundUsers::ServerInboundId)
.col(InboundUsers::Username)
.unique()
.to_owned(),
)
.await?;
// Create index on email for faster lookups
manager
.create_index(
Index::create()
.name("idx_inbound_users_email")
.table(InboundUsers::Table)
.col(InboundUsers::Email)
.to_owned(),
)
.await?;
Ok(())
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.drop_table(Table::drop().table(InboundUsers::Table).to_owned())
.await
}
}
#[derive(DeriveIden)]
enum InboundUsers {
Table,
Id,
ServerInboundId,
Username,
Email,
XrayUserId,
Level,
IsActive,
CreatedAt,
UpdatedAt,
}
#[derive(DeriveIden)]
enum ServerInbounds {
Table,
Id,
}

View File

@@ -0,0 +1,26 @@
use sea_orm_migration::prelude::*;
mod m20241201_000001_create_users_table;
mod m20241201_000002_create_certificates_table;
mod m20241201_000003_create_inbound_templates_table;
mod m20241201_000004_create_servers_table;
mod m20241201_000005_create_server_inbounds_table;
mod m20241201_000006_create_user_access_table;
mod m20241201_000007_create_inbound_users_table;
pub struct Migrator;
#[async_trait::async_trait]
impl MigratorTrait for Migrator {
fn migrations() -> Vec<Box<dyn MigrationTrait>> {
vec![
Box::new(m20241201_000001_create_users_table::Migration),
Box::new(m20241201_000002_create_certificates_table::Migration),
Box::new(m20241201_000003_create_inbound_templates_table::Migration),
Box::new(m20241201_000004_create_servers_table::Migration),
Box::new(m20241201_000005_create_server_inbounds_table::Migration),
Box::new(m20241201_000006_create_user_access_table::Migration),
Box::new(m20241201_000007_create_inbound_users_table::Migration),
]
}
}