use async_trait::async_trait;
use bitflags::bitflags;
use std::ops::RangeInclusive;
use std::time::Duration;
use std::{
fmt::Formatter,
fmt::{self, Debug, Display},
io,
net::{IpAddr, Ipv4Addr},
};
use tokio::net::TcpSocket;
pub(crate) const DEFAULT_GREETING: &str = "Welcome to the libunftp FTP server";
pub(crate) const DEFAULT_IDLE_SESSION_TIMEOUT_SECS: u64 = 600;
pub(crate) const DEFAULT_PASSIVE_HOST: PassiveHost = PassiveHost::FromConnection;
pub(crate) const DEFAULT_PASSIVE_PORTS: RangeInclusive<u16> = 49152..=65535;
pub(crate) const DEFAULT_FTPS_REQUIRE: FtpsRequired = FtpsRequired::None;
pub(crate) const DEFAULT_FTPS_TRUST_STORE: &str = "./trusted.pem";
#[async_trait]
pub trait Binder: Debug + Send {
async fn bind(&mut self, local_addr: IpAddr, passive_ports: RangeInclusive<u16>) -> io::Result<TcpSocket>;
}
#[derive(Debug, PartialEq, Clone, Default)]
pub enum PassiveHost {
#[default]
FromConnection,
Ip(Ipv4Addr),
Dns(String),
}
impl Eq for PassiveHost {}
impl From<Ipv4Addr> for PassiveHost {
fn from(ip: Ipv4Addr) -> Self {
PassiveHost::Ip(ip)
}
}
impl From<[u8; 4]> for PassiveHost {
fn from(ip: [u8; 4]) -> Self {
PassiveHost::Ip(ip.into())
}
}
impl From<&str> for PassiveHost {
fn from(dns_or_ip: &str) -> Self {
match dns_or_ip.parse() {
Ok(IpAddr::V4(ip)) => PassiveHost::Ip(ip),
_ => PassiveHost::Dns(dns_or_ip.to_string()),
}
}
}
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum FtpsRequired {
All,
Accounts,
None, }
impl Eq for FtpsRequired {}
impl From<bool> for FtpsRequired {
fn from(on: bool) -> Self {
match on {
true => FtpsRequired::All,
false => FtpsRequired::None,
}
}
}
impl Display for FtpsRequired {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(
f,
"{}",
match self {
FtpsRequired::All => "All users, including anonymous, requires FTPS",
FtpsRequired::Accounts => "All non-anonymous users requires FTPS",
FtpsRequired::None => "FTPS not enforced",
}
)
}
}
bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct TlsFlags: u32 {
const V1_2 = 0b00000001;
const V1_3 = 0b00000010;
const RESUMPTION_SESS_ID = 0b00001000;
const RESUMPTION_TICKETS = 0b00010000;
const LATEST_VERSIONS = Self::V1_2.bits() | Self::V1_3.bits();
}
}
impl Default for TlsFlags {
fn default() -> TlsFlags {
TlsFlags::V1_2 | TlsFlags::RESUMPTION_SESS_ID | TlsFlags::RESUMPTION_TICKETS
}
}
#[derive(Debug, PartialEq, Clone, Copy, Default)]
pub enum FtpsClientAuth {
#[default]
Off,
Request,
Require,
}
impl Eq for FtpsClientAuth {}
impl From<bool> for FtpsClientAuth {
fn from(on: bool) -> Self {
match on {
true => FtpsClientAuth::Require,
false => FtpsClientAuth::Off,
}
}
}
#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
pub enum SiteMd5 {
All,
#[default]
Accounts,
None, }
pub struct Shutdown {
pub(crate) grace_period: Duration,
}
impl Shutdown {
pub fn new() -> Self {
Shutdown::default()
}
pub fn grace_period(mut self, d: impl Into<Duration>) -> Self {
self.grace_period = d.into();
self
}
}
impl Default for Shutdown {
fn default() -> Shutdown {
Shutdown {
grace_period: Duration::from_secs(10),
}
}
}
#[derive(Debug, Clone)]
pub enum FailedLoginsBlock {
UserAndIP,
IP,
User,
}
impl FailedLoginsPolicy {
pub fn new(max_attempts: u32, expires_after: Duration, block_by: FailedLoginsBlock) -> FailedLoginsPolicy {
FailedLoginsPolicy {
max_attempts,
expires_after,
block_by,
}
}
}
#[derive(Debug, Clone)]
pub struct FailedLoginsPolicy {
pub(crate) max_attempts: u32,
pub(crate) expires_after: Duration,
pub(crate) block_by: FailedLoginsBlock,
}
impl Default for FailedLoginsPolicy {
fn default() -> FailedLoginsPolicy {
FailedLoginsPolicy::new(3, Duration::from_secs(120), FailedLoginsBlock::UserAndIP)
}
}
#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
pub enum ActivePassiveMode {
#[default]
PassiveOnly,
ActiveOnly,
ActiveAndPassive,
}