Letsencrypt works

This commit is contained in:
Ultradesu
2025-09-24 00:30:03 +01:00
parent 59b8cbb582
commit 76afa0797b
26 changed files with 3169 additions and 60 deletions

View File

@@ -86,6 +86,7 @@ impl ActiveModelBehavior for ActiveModel {
pub enum CertificateType {
SelfSigned,
Imported,
LetsEncrypt,
}
impl From<CertificateType> for String {
@@ -93,6 +94,7 @@ impl From<CertificateType> for String {
match cert_type {
CertificateType::SelfSigned => "self_signed".to_string(),
CertificateType::Imported => "imported".to_string(),
CertificateType::LetsEncrypt => "letsencrypt".to_string(),
}
}
}
@@ -102,6 +104,7 @@ impl From<String> for CertificateType {
match s.as_str() {
"self_signed" => CertificateType::SelfSigned,
"imported" => CertificateType::Imported,
"letsencrypt" => CertificateType::LetsEncrypt,
_ => CertificateType::SelfSigned,
}
}
@@ -117,6 +120,9 @@ pub struct CreateCertificateDto {
pub certificate_pem: String,
#[serde(default)]
pub private_key: String,
// For Let's Encrypt certificates via DNS challenge
pub dns_provider_id: Option<Uuid>,
pub acme_email: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]

View File

@@ -0,0 +1,156 @@
use sea_orm::entity::prelude::*;
use sea_orm::{Set, ActiveModelTrait};
use serde::{Deserialize, Serialize};
use uuid::Uuid;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
#[sea_orm(table_name = "dns_providers")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: Uuid,
pub name: String,
pub provider_type: String, // "cloudflare", "route53", etc.
#[serde(skip_serializing)]
pub api_token: String, // Encrypted storage in production
pub is_active: bool,
pub created_at: DateTimeUtc,
pub updated_at: DateTimeUtc,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {}
impl ActiveModelBehavior for ActiveModel {
fn new() -> Self {
Self {
id: Set(Uuid::new_v4()),
created_at: Set(chrono::Utc::now()),
updated_at: Set(chrono::Utc::now()),
..ActiveModelTrait::default()
}
}
fn before_save<'life0, 'async_trait, C>(
mut self,
_db: &'life0 C,
insert: bool,
) -> core::pin::Pin<Box<dyn core::future::Future<Output = Result<Self, DbErr>> + Send + 'async_trait>>
where
'life0: 'async_trait,
C: 'async_trait + ConnectionTrait,
Self: 'async_trait,
{
Box::pin(async move {
if !insert {
self.updated_at = Set(chrono::Utc::now());
}
Ok(self)
})
}
}
// DTOs for API requests/responses
#[derive(Debug, Serialize, Deserialize)]
pub struct CreateDnsProviderDto {
pub name: String,
pub provider_type: String,
pub api_token: String,
pub is_active: Option<bool>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct UpdateDnsProviderDto {
pub name: Option<String>,
pub api_token: Option<String>,
pub is_active: Option<bool>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct DnsProviderResponseDto {
pub id: Uuid,
pub name: String,
pub provider_type: String,
pub is_active: bool,
pub created_at: DateTimeUtc,
pub updated_at: DateTimeUtc,
pub has_token: bool, // Don't expose actual token
}
impl From<CreateDnsProviderDto> for ActiveModel {
fn from(dto: CreateDnsProviderDto) -> Self {
ActiveModel {
id: Set(Uuid::new_v4()),
name: Set(dto.name),
provider_type: Set(dto.provider_type),
api_token: Set(dto.api_token),
is_active: Set(dto.is_active.unwrap_or(true)),
created_at: Set(chrono::Utc::now()),
updated_at: Set(chrono::Utc::now()),
}
}
}
impl Model {
/// Update this model with data from UpdateDnsProviderDto
pub fn apply_update(self, dto: UpdateDnsProviderDto) -> ActiveModel {
let mut active_model: ActiveModel = self.into();
if let Some(name) = dto.name {
active_model.name = Set(name);
}
if let Some(api_token) = dto.api_token {
active_model.api_token = Set(api_token);
}
if let Some(is_active) = dto.is_active {
active_model.is_active = Set(is_active);
}
active_model.updated_at = Set(chrono::Utc::now());
active_model
}
/// Convert to response DTO (without exposing API token)
pub fn to_response_dto(&self) -> DnsProviderResponseDto {
DnsProviderResponseDto {
id: self.id,
name: self.name.clone(),
provider_type: self.provider_type.clone(),
is_active: self.is_active,
created_at: self.created_at,
updated_at: self.updated_at,
has_token: !self.api_token.is_empty(),
}
}
}
/// Supported DNS provider types
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum DnsProviderType {
#[serde(rename = "cloudflare")]
Cloudflare,
}
impl DnsProviderType {
pub fn as_str(&self) -> &'static str {
match self {
DnsProviderType::Cloudflare => "cloudflare",
}
}
pub fn from_str(s: &str) -> Option<Self> {
match s {
"cloudflare" => Some(DnsProviderType::Cloudflare),
_ => None,
}
}
pub fn all() -> Vec<Self> {
vec![DnsProviderType::Cloudflare]
}
}

View File

@@ -1,5 +1,6 @@
pub mod user;
pub mod certificate;
pub mod dns_provider;
pub mod inbound_template;
pub mod server;
pub mod server_inbound;
@@ -7,7 +8,9 @@ pub mod user_access;
pub mod inbound_users;
pub mod prelude {
pub use super::user::Entity as User;
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::server::Entity as Server;
pub use super::server_inbound::Entity as ServerInbound;