mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-04-02 05:23:14 +00:00
domains api + migration
This commit is contained in:
@@ -14,7 +14,7 @@ keywords = [
|
||||
name = "start-os"
|
||||
readme = "README.md"
|
||||
repository = "https://github.com/Start9Labs/start-os"
|
||||
version = "0.4.0-alpha.9" # VERSION_BUMP
|
||||
version = "0.4.0-alpha.10" # VERSION_BUMP
|
||||
license = "MIT"
|
||||
|
||||
[lib]
|
||||
@@ -228,7 +228,8 @@ tracing-error = "0.2.0"
|
||||
tracing-futures = "0.2.5"
|
||||
tracing-journald = "0.3.0"
|
||||
tracing-subscriber = { version = "0.3.17", features = ["env-filter"] }
|
||||
trust-dns-server = "0.23.1"
|
||||
trust-dns-server = "0.23.2"
|
||||
trust-dns-client = "0.23.2"
|
||||
ts-rs = { git = "https://github.com/dr-bonez/ts-rs.git", branch = "feature/top-level-as" } # "8.1.0"
|
||||
typed-builder = "0.21.0"
|
||||
unix-named-pipe = "0.2.0"
|
||||
|
||||
@@ -12,7 +12,7 @@ use tracing::instrument;
|
||||
use crate::context::config::ServerConfig;
|
||||
use crate::context::rpc::InitRpcContextPhases;
|
||||
use crate::context::{DiagnosticContext, InitContext, RpcContext};
|
||||
use crate::net::network_interface::SelfContainedNetworkInterfaceListener;
|
||||
use crate::net::gateway::SelfContainedNetworkInterfaceListener;
|
||||
use crate::net::web_server::{Acceptor, UpgradableListener, WebServer};
|
||||
use crate::shutdown::Shutdown;
|
||||
use crate::system::launch_metrics_task;
|
||||
|
||||
@@ -92,8 +92,9 @@ impl Public {
|
||||
enabled: true,
|
||||
..Default::default()
|
||||
},
|
||||
network_interfaces: OrdMap::new(),
|
||||
gateways: OrdMap::new(),
|
||||
acme: BTreeMap::new(),
|
||||
domains: BTreeMap::new(),
|
||||
},
|
||||
status_info: ServerStatus {
|
||||
backup_progress: None,
|
||||
@@ -191,9 +192,12 @@ pub struct NetworkInfo {
|
||||
pub host: Host,
|
||||
#[ts(as = "BTreeMap::<GatewayId, NetworkInterfaceInfo>")]
|
||||
#[serde(default)]
|
||||
pub network_interfaces: OrdMap<GatewayId, NetworkInterfaceInfo>,
|
||||
pub gateways: OrdMap<GatewayId, NetworkInterfaceInfo>,
|
||||
#[serde(default)]
|
||||
pub acme: BTreeMap<AcmeProvider, AcmeSettings>,
|
||||
#[serde(default)]
|
||||
#[ts(as = "BTreeMap::<String, DomainSettings>")]
|
||||
pub domains: BTreeMap<InternedString, DomainSettings>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Deserialize, Serialize, HasModel, TS)]
|
||||
@@ -303,6 +307,14 @@ pub struct AcmeSettings {
|
||||
pub contact: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, HasModel, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[model = "Model<Self>"]
|
||||
#[ts(export)]
|
||||
pub struct DomainSettings {
|
||||
pub gateway: GatewayId,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Deserialize, Serialize, HasModel, TS)]
|
||||
#[model = "Model<Self>"]
|
||||
#[ts(export)]
|
||||
|
||||
@@ -150,7 +150,7 @@ pub fn main_api<C: Context>() -> ParentHandler<C> {
|
||||
)
|
||||
.subcommand(
|
||||
"net",
|
||||
net::net::<C>().with_about("Network commands related to tor and dhcp"),
|
||||
net::net_api::<C>().with_about("Network commands related to tor and dhcp"),
|
||||
)
|
||||
.subcommand(
|
||||
"auth",
|
||||
|
||||
@@ -174,7 +174,7 @@ impl<'a> async_acme::cache::AcmeCache for AcmeCertCache<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn acme<C: Context>() -> ParentHandler<C> {
|
||||
pub fn acme_api<C: Context>() -> ParentHandler<C> {
|
||||
ParentHandler::new()
|
||||
.subcommand(
|
||||
"init",
|
||||
|
||||
204
core/startos/src/net/domain.rs
Normal file
204
core/startos/src/net/domain.rs
Normal file
@@ -0,0 +1,204 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use clap::Parser;
|
||||
use futures::TryFutureExt;
|
||||
use helpers::NonDetachingJoinHandle;
|
||||
use imbl_value::InternedString;
|
||||
use models::GatewayId;
|
||||
use rpc_toolkit::{from_fn_async, Context, HandlerArgs, HandlerExt, ParentHandler};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::context::{CliContext, RpcContext};
|
||||
use crate::db::model::public::DomainSettings;
|
||||
use crate::prelude::*;
|
||||
use crate::util::new_guid;
|
||||
use crate::util::serde::{display_serializable, HandlerExtSerde};
|
||||
|
||||
pub fn domain_api<C: Context>() -> ParentHandler<C> {
|
||||
ParentHandler::new()
|
||||
.subcommand(
|
||||
"list",
|
||||
from_fn_async(list)
|
||||
.with_display_serializable()
|
||||
.with_custom_display_fn(|HandlerArgs { params, .. }, res| {
|
||||
use prettytable::*;
|
||||
|
||||
if let Some(format) = params.format {
|
||||
return display_serializable(format, res);
|
||||
}
|
||||
|
||||
let mut table = Table::new();
|
||||
table.add_row(row![bc => "DOMAIN", "GATEWAY"]);
|
||||
for (domain, info) in res {
|
||||
table.add_row(row![domain, info.gateway]);
|
||||
}
|
||||
|
||||
table.print_tty(false)?;
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.with_about("List domains available to StartOS")
|
||||
.with_call_remote::<CliContext>(),
|
||||
)
|
||||
.subcommand(
|
||||
"add",
|
||||
from_fn_async(add)
|
||||
.with_metadata("sync_db", Value::Bool(true))
|
||||
.no_display()
|
||||
.with_about("Add a domain for use with StartOS")
|
||||
.with_call_remote::<CliContext>(),
|
||||
)
|
||||
.subcommand(
|
||||
"remove",
|
||||
from_fn_async(remove)
|
||||
.with_metadata("sync_db", Value::Bool(true))
|
||||
.no_display()
|
||||
.with_about("Remove a domain for use with StartOS")
|
||||
.with_call_remote::<CliContext>(),
|
||||
)
|
||||
.subcommand(
|
||||
"test-dns",
|
||||
from_fn_async(test_dns)
|
||||
.with_display_serializable()
|
||||
.with_custom_display_fn(|HandlerArgs { params, .. }, res| {
|
||||
use prettytable::*;
|
||||
|
||||
if let Some(format) = params.format {
|
||||
return display_serializable(format, res);
|
||||
}
|
||||
|
||||
let mut table = Table::new();
|
||||
table.add_row(row![bc -> "ROOT", if res.root { "✅️" } else { "❌️" }]);
|
||||
table.add_row(row![bc -> "WILDCARD", if res.wildcard { "✅️" } else { "❌️" }]);
|
||||
|
||||
table.print_tty(false)?;
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.with_about("Test the DNS configuration for a domain"),
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn list(ctx: RpcContext) -> Result<BTreeMap<InternedString, DomainSettings>, Error> {
|
||||
ctx.db
|
||||
.peek()
|
||||
.await
|
||||
.into_public()
|
||||
.into_server_info()
|
||||
.into_network()
|
||||
.into_domains()
|
||||
.de()
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Parser)]
|
||||
pub struct AddDomainParams {
|
||||
pub fqdn: InternedString,
|
||||
pub gateway: GatewayId,
|
||||
}
|
||||
|
||||
pub async fn add(
|
||||
ctx: RpcContext,
|
||||
AddDomainParams { fqdn, gateway }: AddDomainParams,
|
||||
) -> Result<(), Error> {
|
||||
ctx.db
|
||||
.mutate(|db| {
|
||||
db.as_public_mut()
|
||||
.as_server_info_mut()
|
||||
.as_network_mut()
|
||||
.as_domains_mut()
|
||||
.insert(&fqdn, &DomainSettings { gateway })
|
||||
})
|
||||
.await
|
||||
.result?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Parser)]
|
||||
pub struct RemoveDomainParams {
|
||||
pub fqdn: InternedString,
|
||||
}
|
||||
|
||||
pub async fn remove(
|
||||
ctx: RpcContext,
|
||||
RemoveDomainParams { fqdn }: RemoveDomainParams,
|
||||
) -> Result<(), Error> {
|
||||
ctx.db
|
||||
.mutate(|db| {
|
||||
db.as_public_mut()
|
||||
.as_server_info_mut()
|
||||
.as_network_mut()
|
||||
.as_domains_mut()
|
||||
.remove(&fqdn)
|
||||
})
|
||||
.await
|
||||
.result?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct TestDnsResult {
|
||||
pub root: bool,
|
||||
pub wildcard: bool,
|
||||
}
|
||||
|
||||
pub async fn test_dns(
|
||||
ctx: RpcContext,
|
||||
AddDomainParams { fqdn, ref gateway }: AddDomainParams,
|
||||
) -> Result<TestDnsResult, Error> {
|
||||
use tokio::net::UdpSocket;
|
||||
use trust_dns_client::client::{AsyncClient, ClientHandle};
|
||||
use trust_dns_client::op::DnsResponse;
|
||||
use trust_dns_client::proto::error::ProtoError;
|
||||
use trust_dns_client::rr::{DNSClass, Name, RecordType};
|
||||
use trust_dns_client::udp::UdpClientStream;
|
||||
|
||||
let wan_ip = ctx
|
||||
.db
|
||||
.peek()
|
||||
.await
|
||||
.into_public()
|
||||
.into_server_info()
|
||||
.into_network()
|
||||
.into_gateways()
|
||||
.into_idx(&gateway)
|
||||
.or_not_found(&gateway)?
|
||||
.into_ip_info()
|
||||
.transpose()
|
||||
.and_then(|i| i.into_wan_ip().transpose())
|
||||
.or_not_found(lazy_format!("WAN IP for {gateway}"))?
|
||||
.de()?;
|
||||
let stream = UdpClientStream::<UdpSocket>::new(([127, 0, 0, 53], 53).into());
|
||||
let (mut client, bg) = AsyncClient::connect(stream.map_err(ProtoError::from))
|
||||
.await
|
||||
.with_kind(ErrorKind::Network)?;
|
||||
let bg: NonDetachingJoinHandle<_> = tokio::spawn(bg).into();
|
||||
|
||||
let root = fqdn.parse::<Name>().with_kind(ErrorKind::Network)?;
|
||||
let wildcard = new_guid()
|
||||
.parse::<Name>()
|
||||
.with_kind(ErrorKind::Network)?
|
||||
.append_domain(&root)
|
||||
.with_kind(ErrorKind::Network)?;
|
||||
let q_root = client
|
||||
.query(root, DNSClass::IN, RecordType::A)
|
||||
.await
|
||||
.with_kind(ErrorKind::Network)?;
|
||||
let q_wildcard = client
|
||||
.query(wildcard, DNSClass::IN, RecordType::A)
|
||||
.await
|
||||
.with_kind(ErrorKind::Network)?;
|
||||
|
||||
bg.abort();
|
||||
|
||||
let check_q = |q: DnsResponse| {
|
||||
q.answers().iter().any(|a| {
|
||||
a.data()
|
||||
.and_then(|d| d.as_a())
|
||||
.map_or(false, |d| d.0 == wan_ip)
|
||||
})
|
||||
};
|
||||
Ok(TestDnsResult {
|
||||
root: check_q(q_root),
|
||||
wildcard: check_q(q_wildcard),
|
||||
})
|
||||
}
|
||||
@@ -12,7 +12,7 @@ use tokio::process::Command;
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
use crate::db::model::public::NetworkInterfaceInfo;
|
||||
use crate::net::network_interface::{DynInterfaceFilter, InterfaceFilter};
|
||||
use crate::net::gateway::{DynInterfaceFilter, InterfaceFilter};
|
||||
use crate::net::utils::ipv6_is_link_local;
|
||||
use crate::prelude::*;
|
||||
use crate::util::sync::Watch;
|
||||
|
||||
@@ -32,7 +32,7 @@ use crate::context::{CliContext, RpcContext};
|
||||
use crate::db::model::public::{IpInfo, NetworkInterfaceInfo, NetworkInterfaceType};
|
||||
use crate::db::model::Database;
|
||||
use crate::net::forward::START9_BRIDGE_IFACE;
|
||||
use crate::net::network_interface::device::DeviceProxy;
|
||||
use crate::net::gateway::device::DeviceProxy;
|
||||
use crate::net::utils::ipv6_is_link_local;
|
||||
use crate::net::web_server::Accept;
|
||||
use crate::prelude::*;
|
||||
@@ -43,7 +43,7 @@ use crate::util::serde::{display_serializable, HandlerExtSerde};
|
||||
use crate::util::sync::{SyncMutex, Watch};
|
||||
use crate::util::Invoke;
|
||||
|
||||
pub fn network_interface_api<C: Context>() -> ParentHandler<C> {
|
||||
pub fn gateway_api<C: Context>() -> ParentHandler<C> {
|
||||
ParentHandler::new()
|
||||
.subcommand(
|
||||
"list",
|
||||
@@ -88,7 +88,7 @@ pub fn network_interface_api<C: Context>() -> ParentHandler<C> {
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.with_about("Show network interfaces StartOS can listen on")
|
||||
.with_about("Show gateways StartOS can listen on")
|
||||
.with_call_remote::<CliContext>(),
|
||||
)
|
||||
.subcommand(
|
||||
@@ -96,26 +96,26 @@ pub fn network_interface_api<C: Context>() -> ParentHandler<C> {
|
||||
from_fn_async(set_public)
|
||||
.with_metadata("sync_db", Value::Bool(true))
|
||||
.no_display()
|
||||
.with_about("Indicate whether this interface has inbound access from the WAN")
|
||||
.with_about("Indicate whether this gateway has inbound access from the WAN")
|
||||
.with_call_remote::<CliContext>(),
|
||||
).subcommand(
|
||||
"unset-inbound",
|
||||
"unset-public",
|
||||
from_fn_async(unset_public)
|
||||
.with_metadata("sync_db", Value::Bool(true))
|
||||
.no_display()
|
||||
.with_about("Allow this interface to infer whether it has inbound access from the WAN based on its IPv4 address")
|
||||
.with_about("Allow this gateway to infer whether it has inbound access from the WAN based on its IPv4 address")
|
||||
.with_call_remote::<CliContext>(),
|
||||
).subcommand("forget",
|
||||
from_fn_async(forget_iface)
|
||||
.with_metadata("sync_db", Value::Bool(true))
|
||||
.no_display()
|
||||
.with_about("Forget a disconnected interface")
|
||||
.with_about("Forget a disconnected gateway")
|
||||
.with_call_remote::<CliContext>()
|
||||
).subcommand("set-name",
|
||||
from_fn_async(set_name)
|
||||
.with_metadata("sync_db", Value::Bool(true))
|
||||
.no_display()
|
||||
.with_about("Rename an interface")
|
||||
.with_about("Rename a gateway")
|
||||
.with_call_remote::<CliContext>()
|
||||
)
|
||||
}
|
||||
@@ -814,7 +814,7 @@ impl NetworkInterfaceController {
|
||||
db.as_public_mut()
|
||||
.as_server_info_mut()
|
||||
.as_network_mut()
|
||||
.as_network_interfaces_mut()
|
||||
.as_gateways_mut()
|
||||
.ser(info)
|
||||
})
|
||||
.await
|
||||
@@ -881,7 +881,7 @@ impl NetworkInterfaceController {
|
||||
.as_public()
|
||||
.as_server_info()
|
||||
.as_network()
|
||||
.as_network_interfaces()
|
||||
.as_gateways()
|
||||
.de()
|
||||
{
|
||||
Ok(mut info) => {
|
||||
@@ -940,7 +940,7 @@ impl NetworkInterfaceController {
|
||||
let mut sub = self
|
||||
.db
|
||||
.subscribe(
|
||||
"/public/serverInfo/network/networkInterfaces"
|
||||
"/public/serverInfo/network/gateways"
|
||||
.parse::<JsonPointer<_, _>>()
|
||||
.with_kind(ErrorKind::Database)?,
|
||||
)
|
||||
@@ -973,7 +973,7 @@ impl NetworkInterfaceController {
|
||||
let mut sub = self
|
||||
.db
|
||||
.subscribe(
|
||||
"/public/serverInfo/network/networkInterfaces"
|
||||
"/public/serverInfo/network/gateways"
|
||||
.parse::<JsonPointer<_, _>>()
|
||||
.with_kind(ErrorKind::Database)?,
|
||||
)
|
||||
@@ -1043,7 +1043,7 @@ impl NetworkInterfaceController {
|
||||
let (dump, mut sub) = self
|
||||
.db
|
||||
.dump_and_sub(
|
||||
"/public/serverInfo/network/networkInterfaces"
|
||||
"/public/serverInfo/network/gateways"
|
||||
.parse::<JsonPointer<_, _>>()
|
||||
.with_kind(ErrorKind::Database)?
|
||||
.join_end(interface.as_str())
|
||||
@@ -34,6 +34,8 @@ pub enum HostAddress {
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, TS)]
|
||||
pub struct DomainConfig {
|
||||
#[ts(type = "string")]
|
||||
pub root: InternedString,
|
||||
pub public: bool,
|
||||
pub acme: Option<AcmeProvider>,
|
||||
}
|
||||
@@ -177,7 +179,7 @@ pub struct AddDomainParams {
|
||||
pub async fn add_domain<Kind: HostApiKind>(
|
||||
ctx: RpcContext,
|
||||
AddDomainParams {
|
||||
domain,
|
||||
ref domain,
|
||||
private,
|
||||
acme,
|
||||
}: AddDomainParams,
|
||||
@@ -185,24 +187,41 @@ pub async fn add_domain<Kind: HostApiKind>(
|
||||
) -> Result<(), Error> {
|
||||
ctx.db
|
||||
.mutate(|db| {
|
||||
let root = db
|
||||
.as_public()
|
||||
.as_server_info()
|
||||
.as_network()
|
||||
.as_domains()
|
||||
.keys()?
|
||||
.into_iter()
|
||||
.find(|root| domain.ends_with(&**root))
|
||||
.or_not_found(lazy_format!("root domain for {domain}"))?;
|
||||
|
||||
if let Some(acme) = &acme {
|
||||
if !db.as_public().as_server_info().as_network().as_acme().contains_key(&acme)? {
|
||||
if !db
|
||||
.as_public()
|
||||
.as_server_info()
|
||||
.as_network()
|
||||
.as_acme()
|
||||
.contains_key(&acme)?
|
||||
{
|
||||
return Err(Error::new(eyre!("unknown acme provider {}, please run acme.init for this provider first", acme.0), ErrorKind::InvalidRequest));
|
||||
}
|
||||
}
|
||||
|
||||
Kind::host_for(&inheritance, db)?
|
||||
.as_domains_mut()
|
||||
.insert(
|
||||
&domain,
|
||||
&DomainConfig {
|
||||
public: !private,
|
||||
acme,
|
||||
},
|
||||
)?;
|
||||
|
||||
Kind::host_for(&inheritance, db)?.as_domains_mut().insert(
|
||||
domain,
|
||||
&DomainConfig {
|
||||
root,
|
||||
public: !private,
|
||||
acme,
|
||||
},
|
||||
)?;
|
||||
check_duplicates(db)
|
||||
})
|
||||
.await.result?;
|
||||
.await
|
||||
.result?;
|
||||
Kind::sync_host(&ctx, inheritance).await?;
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -13,7 +13,7 @@ use crate::context::{CliContext, RpcContext};
|
||||
use crate::db::model::public::NetworkInterfaceInfo;
|
||||
use crate::net::forward::AvailablePorts;
|
||||
use crate::net::host::HostApiKind;
|
||||
use crate::net::network_interface::InterfaceFilter;
|
||||
use crate::net::gateway::InterfaceFilter;
|
||||
use crate::net::vhost::AlpnInfo;
|
||||
use crate::prelude::*;
|
||||
use crate::util::serde::{display_serializable, HandlerExtSerde};
|
||||
|
||||
@@ -53,7 +53,7 @@ impl Host {
|
||||
self.domains
|
||||
.iter()
|
||||
.map(
|
||||
|(address, DomainConfig { public, acme })| HostAddress::Domain {
|
||||
|(address, DomainConfig { public, acme, .. })| HostAddress::Domain {
|
||||
address: address.clone(),
|
||||
public: *public,
|
||||
acme: acme.clone(),
|
||||
|
||||
@@ -2,12 +2,13 @@ use rpc_toolkit::{Context, HandlerExt, ParentHandler};
|
||||
|
||||
pub mod acme;
|
||||
pub mod dns;
|
||||
pub mod domain;
|
||||
pub mod forward;
|
||||
pub mod gateway;
|
||||
pub mod host;
|
||||
pub mod keys;
|
||||
pub mod mdns;
|
||||
pub mod net_controller;
|
||||
pub mod network_interface;
|
||||
pub mod service_interface;
|
||||
pub mod ssl;
|
||||
pub mod static_server;
|
||||
@@ -18,20 +19,23 @@ pub mod vhost;
|
||||
pub mod web_server;
|
||||
pub mod wifi;
|
||||
|
||||
pub fn net<C: Context>() -> ParentHandler<C> {
|
||||
pub fn net_api<C: Context>() -> ParentHandler<C> {
|
||||
ParentHandler::new()
|
||||
.subcommand(
|
||||
"tor",
|
||||
tor::tor::<C>().with_about("Tor commands such as list-services, logs, and reset"),
|
||||
tor::tor_api::<C>().with_about("Tor commands such as list-services, logs, and reset"),
|
||||
)
|
||||
.subcommand(
|
||||
"acme",
|
||||
acme::acme::<C>().with_about("Setup automatic clearnet certificate acquisition"),
|
||||
acme::acme_api::<C>().with_about("Setup automatic clearnet certificate acquisition"),
|
||||
)
|
||||
.subcommand(
|
||||
"network-interface",
|
||||
network_interface::network_interface_api::<C>()
|
||||
.with_about("View and edit network interface configurations"),
|
||||
"domain",
|
||||
domain::domain_api::<C>().with_about("Setup clearnet domains"),
|
||||
)
|
||||
.subcommand(
|
||||
"gateway",
|
||||
gateway::gateway_api::<C>().with_about("View and edit gateway configurations"),
|
||||
)
|
||||
.subcommand(
|
||||
"tunnel",
|
||||
|
||||
@@ -17,13 +17,13 @@ use crate::error::ErrorCollection;
|
||||
use crate::hostname::Hostname;
|
||||
use crate::net::dns::DnsController;
|
||||
use crate::net::forward::{PortForwardController, START9_BRIDGE_IFACE};
|
||||
use crate::net::host::address::HostAddress;
|
||||
use crate::net::host::binding::{AddSslOptions, BindId, BindOptions};
|
||||
use crate::net::host::{host_for, Host, Hosts};
|
||||
use crate::net::network_interface::{
|
||||
use crate::net::gateway::{
|
||||
AndFilter, DynInterfaceFilter, InterfaceFilter, LoopbackFilter, NetworkInterfaceController,
|
||||
SecureFilter,
|
||||
};
|
||||
use crate::net::host::address::HostAddress;
|
||||
use crate::net::host::binding::{AddSslOptions, BindId, BindOptions};
|
||||
use crate::net::host::{host_for, Host, Hosts};
|
||||
use crate::net::service_interface::{HostnameInfo, IpHostname, OnionHostname};
|
||||
use crate::net::tor::TorController;
|
||||
use crate::net::utils::ipv6_is_local;
|
||||
|
||||
@@ -84,7 +84,7 @@ lazy_static! {
|
||||
static ref PROGRESS_REGEX: Regex = Regex::new("PROGRESS=([0-9]+)").unwrap();
|
||||
}
|
||||
|
||||
pub fn tor<C: Context>() -> ParentHandler<C> {
|
||||
pub fn tor_api<C: Context>() -> ParentHandler<C> {
|
||||
ParentHandler::new()
|
||||
.subcommand(
|
||||
"list-services",
|
||||
|
||||
@@ -53,7 +53,7 @@ pub async fn add_tunnel(
|
||||
.into_public()
|
||||
.into_server_info()
|
||||
.into_network()
|
||||
.into_network_interfaces()
|
||||
.into_gateways()
|
||||
.keys()?;
|
||||
let mut iface = GatewayId::from("wg0");
|
||||
for id in 1.. {
|
||||
@@ -105,7 +105,7 @@ pub async fn remove_tunnel(
|
||||
.into_public()
|
||||
.into_server_info()
|
||||
.into_network()
|
||||
.into_network_interfaces()
|
||||
.into_gateways()
|
||||
.into_idx(&id)
|
||||
.and_then(|e| e.into_ip_info().transpose())
|
||||
else {
|
||||
|
||||
@@ -36,7 +36,7 @@ use crate::context::{CliContext, RpcContext};
|
||||
use crate::db::model::public::NetworkInterfaceInfo;
|
||||
use crate::db::model::Database;
|
||||
use crate::net::acme::{AcmeCertCache, AcmeProvider};
|
||||
use crate::net::network_interface::{
|
||||
use crate::net::gateway::{
|
||||
Accepted, AnyFilter, DynInterfaceFilter, InterfaceFilter, NetworkInterfaceController,
|
||||
NetworkInterfaceListener,
|
||||
};
|
||||
|
||||
@@ -14,7 +14,7 @@ use tokio::net::{TcpListener, TcpStream};
|
||||
use tokio::sync::oneshot;
|
||||
|
||||
use crate::context::{DiagnosticContext, InitContext, InstallContext, RpcContext, SetupContext};
|
||||
use crate::net::network_interface::{
|
||||
use crate::net::gateway::{
|
||||
lookup_info_by_addr, NetworkInterfaceListener, SelfContainedNetworkInterfaceListener,
|
||||
};
|
||||
use crate::net::static_server::{
|
||||
|
||||
@@ -90,7 +90,7 @@ pub async fn get_ssl_certificate(
|
||||
.as_public()
|
||||
.as_server_info()
|
||||
.as_network()
|
||||
.as_network_interfaces()
|
||||
.as_gateways()
|
||||
.as_entries()?
|
||||
.into_iter()
|
||||
.flat_map(|(_, net)| net.as_ip_info().transpose_ref())
|
||||
|
||||
@@ -20,7 +20,7 @@ use crate::context::CliContext;
|
||||
use crate::middleware::auth::AuthContext;
|
||||
use crate::middleware::signature::SignatureAuthContext;
|
||||
use crate::net::forward::PortForwardController;
|
||||
use crate::net::network_interface::NetworkInterfaceWatcher;
|
||||
use crate::net::gateway::NetworkInterfaceWatcher;
|
||||
use crate::prelude::*;
|
||||
use crate::rpc_continuations::{OpenAuthedContinuations, RpcContinuations};
|
||||
use crate::tunnel::db::TunnelDatabase;
|
||||
|
||||
@@ -49,7 +49,9 @@ mod v0_4_0_alpha_7;
|
||||
mod v0_4_0_alpha_8;
|
||||
mod v0_4_0_alpha_9;
|
||||
|
||||
pub type Current = v0_4_0_alpha_9::Version; // VERSION_BUMP
|
||||
mod v0_4_0_alpha_10;
|
||||
|
||||
pub type Current = v0_4_0_alpha_10::Version; // VERSION_BUMP
|
||||
|
||||
impl Current {
|
||||
#[instrument(skip(self, db))]
|
||||
@@ -161,7 +163,8 @@ enum Version {
|
||||
V0_4_0_alpha_6(Wrapper<v0_4_0_alpha_6::Version>),
|
||||
V0_4_0_alpha_7(Wrapper<v0_4_0_alpha_7::Version>),
|
||||
V0_4_0_alpha_8(Wrapper<v0_4_0_alpha_8::Version>),
|
||||
V0_4_0_alpha_9(Wrapper<v0_4_0_alpha_9::Version>), // VERSION_BUMP
|
||||
V0_4_0_alpha_9(Wrapper<v0_4_0_alpha_9::Version>),
|
||||
V0_4_0_alpha_10(Wrapper<v0_4_0_alpha_10::Version>), // VERSION_BUMP
|
||||
Other(exver::Version),
|
||||
}
|
||||
|
||||
@@ -213,7 +216,8 @@ impl Version {
|
||||
Self::V0_4_0_alpha_6(v) => DynVersion(Box::new(v.0)),
|
||||
Self::V0_4_0_alpha_7(v) => DynVersion(Box::new(v.0)),
|
||||
Self::V0_4_0_alpha_8(v) => DynVersion(Box::new(v.0)),
|
||||
Self::V0_4_0_alpha_9(v) => DynVersion(Box::new(v.0)), // VERSION_BUMP
|
||||
Self::V0_4_0_alpha_9(v) => DynVersion(Box::new(v.0)),
|
||||
Self::V0_4_0_alpha_10(v) => DynVersion(Box::new(v.0)), // VERSION_BUMP
|
||||
Self::Other(v) => {
|
||||
return Err(Error::new(
|
||||
eyre!("unknown version {v}"),
|
||||
@@ -257,7 +261,8 @@ impl Version {
|
||||
Version::V0_4_0_alpha_6(Wrapper(x)) => x.semver(),
|
||||
Version::V0_4_0_alpha_7(Wrapper(x)) => x.semver(),
|
||||
Version::V0_4_0_alpha_8(Wrapper(x)) => x.semver(),
|
||||
Version::V0_4_0_alpha_9(Wrapper(x)) => x.semver(), // VERSION_BUMP
|
||||
Version::V0_4_0_alpha_9(Wrapper(x)) => x.semver(),
|
||||
Version::V0_4_0_alpha_10(Wrapper(x)) => x.semver(), // VERSION_BUMP
|
||||
Version::Other(x) => x.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,8 +72,9 @@ impl VersionT for Version {
|
||||
}
|
||||
HostAddress::Domain { address } => {
|
||||
domains.insert(
|
||||
address,
|
||||
address.clone(),
|
||||
DomainConfig {
|
||||
root: address,
|
||||
public: true,
|
||||
acme: None,
|
||||
},
|
||||
|
||||
108
core/startos/src/version/v0_4_0_alpha_10.rs
Normal file
108
core/startos/src/version/v0_4_0_alpha_10.rs
Normal file
@@ -0,0 +1,108 @@
|
||||
use std::collections::BTreeSet;
|
||||
use std::sync::Arc;
|
||||
|
||||
use exver::{PreReleaseSegment, VersionRange};
|
||||
use imbl_value::json;
|
||||
|
||||
use super::v0_3_5::V0_3_0_COMPAT;
|
||||
use super::{v0_4_0_alpha_9, VersionT};
|
||||
use crate::prelude::*;
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref V0_4_0_alpha_10: exver::Version = exver::Version::new(
|
||||
[0, 4, 0],
|
||||
[PreReleaseSegment::String("alpha".into()), 10.into()]
|
||||
);
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
pub struct Version;
|
||||
|
||||
impl VersionT for Version {
|
||||
type Previous = v0_4_0_alpha_9::Version;
|
||||
type PreUpRes = ();
|
||||
|
||||
async fn pre_up(self) -> Result<Self::PreUpRes, Error> {
|
||||
Ok(())
|
||||
}
|
||||
fn semver(self) -> exver::Version {
|
||||
V0_4_0_alpha_10.clone()
|
||||
}
|
||||
fn compat(self) -> &'static VersionRange {
|
||||
&V0_3_0_COMPAT
|
||||
}
|
||||
#[instrument]
|
||||
fn up(self, db: &mut Value, _: Self::PreUpRes) -> Result<Value, Error> {
|
||||
let default_gateway = db["public"]["serverInfo"]["network"]["networkInterfaces"]
|
||||
.as_object()
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.find(|(_, i)| i["ipInfo"]["wanIp"].is_string())
|
||||
.map(|(g, _)| g.clone());
|
||||
let mut roots = BTreeSet::new();
|
||||
for (_, package) in db["public"]["packageData"]
|
||||
.as_object_mut()
|
||||
.ok_or_else(|| {
|
||||
Error::new(
|
||||
eyre!("expected public.packageData to be an object"),
|
||||
ErrorKind::Database,
|
||||
)
|
||||
})?
|
||||
.iter_mut()
|
||||
{
|
||||
for (_, host) in package["hosts"]
|
||||
.as_object_mut()
|
||||
.ok_or_else(|| {
|
||||
Error::new(
|
||||
eyre!("expected public.packageData[id].hosts to be an object"),
|
||||
ErrorKind::Database,
|
||||
)
|
||||
})?
|
||||
.iter_mut()
|
||||
{
|
||||
if default_gateway.is_none() {
|
||||
host["domains"] = json!({});
|
||||
continue;
|
||||
}
|
||||
for (domain, info) in host["domains"]
|
||||
.as_object_mut()
|
||||
.ok_or_else(|| {
|
||||
Error::new(
|
||||
eyre!(
|
||||
"expected public.packageData[id].hosts[id].domains to be an object"
|
||||
),
|
||||
ErrorKind::Database,
|
||||
)
|
||||
})?
|
||||
.iter_mut()
|
||||
{
|
||||
let Some(info) = info.as_object_mut() else {
|
||||
continue;
|
||||
};
|
||||
let root = domain.clone();
|
||||
info.insert("root".into(), Value::String(Arc::new((&*root).to_owned())));
|
||||
roots.insert(root);
|
||||
}
|
||||
}
|
||||
}
|
||||
let network = db["public"]["serverInfo"]["network"]
|
||||
.as_object_mut()
|
||||
.ok_or_else(|| {
|
||||
Error::new(
|
||||
eyre!("expected public.serverInfo.network to be an object"),
|
||||
ErrorKind::Database,
|
||||
)
|
||||
})?;
|
||||
network["gateways"] = network["networkInterfaces"].clone();
|
||||
if let Some(gateway) = default_gateway {
|
||||
for root in roots {
|
||||
network["domains"][&*root] = json!({ "gateway": gateway });
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Value::Null)
|
||||
}
|
||||
fn down(self, _db: &mut Value) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user