mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-26 02:11:53 +00:00
feat(core): allow setting server hostname
This commit is contained in:
@@ -994,6 +994,20 @@ disk.mount.binding:
|
|||||||
fr_FR: "Liaison de %{src} à %{dst}"
|
fr_FR: "Liaison de %{src} à %{dst}"
|
||||||
pl_PL: "Wiązanie %{src} do %{dst}"
|
pl_PL: "Wiązanie %{src} do %{dst}"
|
||||||
|
|
||||||
|
hostname.empty:
|
||||||
|
en_US: "Hostname cannot be empty"
|
||||||
|
de_DE: "Der Hostname darf nicht leer sein"
|
||||||
|
es_ES: "El nombre de host no puede estar vacío"
|
||||||
|
fr_FR: "Le nom d'hôte ne peut pas être vide"
|
||||||
|
pl_PL: "Nazwa hosta nie może być pusta"
|
||||||
|
|
||||||
|
hostname.invalid-character:
|
||||||
|
en_US: "Invalid character in hostname: %{char}"
|
||||||
|
de_DE: "Ungültiges Zeichen im Hostnamen: %{char}"
|
||||||
|
es_ES: "Carácter no válido en el nombre de host: %{char}"
|
||||||
|
fr_FR: "Caractère invalide dans le nom d'hôte : %{char}"
|
||||||
|
pl_PL: "Nieprawidłowy znak w nazwie hosta: %{char}"
|
||||||
|
|
||||||
# init.rs
|
# init.rs
|
||||||
init.running-preinit:
|
init.running-preinit:
|
||||||
en_US: "Running preinit.sh"
|
en_US: "Running preinit.sh"
|
||||||
@@ -5197,6 +5211,13 @@ about.set-country:
|
|||||||
fr_FR: "Définir le pays"
|
fr_FR: "Définir le pays"
|
||||||
pl_PL: "Ustaw kraj"
|
pl_PL: "Ustaw kraj"
|
||||||
|
|
||||||
|
about.set-hostname:
|
||||||
|
en_US: "Set the server hostname"
|
||||||
|
de_DE: "Den Server-Hostnamen festlegen"
|
||||||
|
es_ES: "Establecer el nombre de host del servidor"
|
||||||
|
fr_FR: "Définir le nom d'hôte du serveur"
|
||||||
|
pl_PL: "Ustaw nazwę hosta serwera"
|
||||||
|
|
||||||
about.set-gateway-enabled-for-binding:
|
about.set-gateway-enabled-for-binding:
|
||||||
en_US: "Set gateway enabled for binding"
|
en_US: "Set gateway enabled for binding"
|
||||||
de_DE: "Gateway für Bindung aktivieren"
|
de_DE: "Gateway für Bindung aktivieren"
|
||||||
|
|||||||
@@ -31,9 +31,17 @@ pub struct AccountInfo {
|
|||||||
pub developer_key: ed25519_dalek::SigningKey,
|
pub developer_key: ed25519_dalek::SigningKey,
|
||||||
}
|
}
|
||||||
impl AccountInfo {
|
impl AccountInfo {
|
||||||
pub fn new(password: &str, start_time: SystemTime) -> Result<Self, Error> {
|
pub fn new(
|
||||||
|
password: &str,
|
||||||
|
start_time: SystemTime,
|
||||||
|
hostname: Option<InternedString>,
|
||||||
|
) -> Result<Self, Error> {
|
||||||
let server_id = generate_id();
|
let server_id = generate_id();
|
||||||
let hostname = generate_hostname();
|
let hostname = if let Some(h) = hostname {
|
||||||
|
Hostname::validate(h)?
|
||||||
|
} else {
|
||||||
|
generate_hostname()
|
||||||
|
};
|
||||||
let root_ca_key = gen_nistp256()?;
|
let root_ca_key = gen_nistp256()?;
|
||||||
let root_ca_cert = make_root_cert(&root_ca_key, &hostname, start_time)?;
|
let root_ca_cert = make_root_cert(&root_ca_key, &hostname, start_time)?;
|
||||||
let ssh_key = ssh_key::PrivateKey::from(ssh_key::private::Ed25519Keypair::random(
|
let ssh_key = ssh_key::PrivateKey::from(ssh_key::private::Ed25519Keypair::random(
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ use crate::db::model::Database;
|
|||||||
use crate::disk::mount::backup::BackupMountGuard;
|
use crate::disk::mount::backup::BackupMountGuard;
|
||||||
use crate::disk::mount::filesystem::ReadWrite;
|
use crate::disk::mount::filesystem::ReadWrite;
|
||||||
use crate::disk::mount::guard::{GenericMountGuard, TmpMountGuard};
|
use crate::disk::mount::guard::{GenericMountGuard, TmpMountGuard};
|
||||||
|
use crate::hostname::Hostname;
|
||||||
use crate::init::init;
|
use crate::init::init;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::progress::ProgressUnits;
|
use crate::progress::ProgressUnits;
|
||||||
@@ -90,6 +91,7 @@ pub async fn recover_full_server(
|
|||||||
server_id: &str,
|
server_id: &str,
|
||||||
recovery_password: &str,
|
recovery_password: &str,
|
||||||
kiosk: Option<bool>,
|
kiosk: Option<bool>,
|
||||||
|
hostname: Option<InternedString>,
|
||||||
SetupExecuteProgress {
|
SetupExecuteProgress {
|
||||||
init_phases,
|
init_phases,
|
||||||
restore_phase,
|
restore_phase,
|
||||||
@@ -115,6 +117,10 @@ pub async fn recover_full_server(
|
|||||||
)
|
)
|
||||||
.with_kind(ErrorKind::PasswordHashGeneration)?;
|
.with_kind(ErrorKind::PasswordHashGeneration)?;
|
||||||
|
|
||||||
|
if let Some(h) = hostname {
|
||||||
|
os_backup.account.hostname = Hostname::validate(h)?;
|
||||||
|
}
|
||||||
|
|
||||||
let kiosk = Some(kiosk.unwrap_or(true)).filter(|_| &*PLATFORM != "raspberrypi");
|
let kiosk = Some(kiosk.unwrap_or(true)).filter(|_| &*PLATFORM != "raspberrypi");
|
||||||
sync_kiosk(kiosk).await?;
|
sync_kiosk(kiosk).await?;
|
||||||
|
|
||||||
|
|||||||
@@ -165,8 +165,7 @@ impl RpcContext {
|
|||||||
{
|
{
|
||||||
(net_ctrl, os_net_service)
|
(net_ctrl, os_net_service)
|
||||||
} else {
|
} else {
|
||||||
let net_ctrl =
|
let net_ctrl = Arc::new(NetController::init(db.clone(), socks_proxy).await?);
|
||||||
Arc::new(NetController::init(db.clone(), &account.hostname, socks_proxy).await?);
|
|
||||||
webserver.send_modify(|wl| wl.set_ip_info(net_ctrl.net_iface.watcher.subscribe()));
|
webserver.send_modify(|wl| wl.set_ip_info(net_ctrl.net_iface.watcher.subscribe()));
|
||||||
let os_net_service = net_ctrl.os_bindings().await?;
|
let os_net_service = net_ctrl.os_bindings().await?;
|
||||||
(net_ctrl, os_net_service)
|
(net_ctrl, os_net_service)
|
||||||
|
|||||||
@@ -45,7 +45,12 @@ impl Database {
|
|||||||
.collect(),
|
.collect(),
|
||||||
ssh_privkey: Pem(account.ssh_key.clone()),
|
ssh_privkey: Pem(account.ssh_key.clone()),
|
||||||
ssh_pubkeys: SshKeys::new(),
|
ssh_pubkeys: SshKeys::new(),
|
||||||
available_ports: AvailablePorts::new(),
|
available_ports: {
|
||||||
|
let mut ports = AvailablePorts::new();
|
||||||
|
ports.set_ssl(80, false);
|
||||||
|
ports.set_ssl(443, true);
|
||||||
|
ports
|
||||||
|
},
|
||||||
sessions: Sessions::new(),
|
sessions: Sessions::new(),
|
||||||
notifications: Notifications::new(),
|
notifications: Notifications::new(),
|
||||||
cifs: CifsTargets::new(),
|
cifs: CifsTargets::new(),
|
||||||
|
|||||||
@@ -1,11 +1,16 @@
|
|||||||
|
use clap::Parser;
|
||||||
use imbl_value::InternedString;
|
use imbl_value::InternedString;
|
||||||
use lazy_format::lazy_format;
|
use lazy_format::lazy_format;
|
||||||
use rand::{Rng, rng};
|
use rand::{Rng, rng};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use tokio::process::Command;
|
use tokio::process::Command;
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
|
use ts_rs::TS;
|
||||||
|
|
||||||
|
use crate::context::RpcContext;
|
||||||
|
use crate::prelude::*;
|
||||||
use crate::util::Invoke;
|
use crate::util::Invoke;
|
||||||
use crate::{Error, ErrorKind};
|
|
||||||
#[derive(Clone, Debug, Default, serde::Deserialize, serde::Serialize, ts_rs::TS)]
|
#[derive(Clone, Debug, Default, serde::Deserialize, serde::Serialize, ts_rs::TS)]
|
||||||
#[ts(type = "string")]
|
#[ts(type = "string")]
|
||||||
pub struct Hostname(pub InternedString);
|
pub struct Hostname(pub InternedString);
|
||||||
@@ -21,6 +26,25 @@ impl AsRef<str> for Hostname {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Hostname {
|
impl Hostname {
|
||||||
|
pub fn validate(h: InternedString) -> Result<Self, Error> {
|
||||||
|
if h.is_empty() {
|
||||||
|
return Err(Error::new(
|
||||||
|
eyre!("{}", t!("hostname.empty")),
|
||||||
|
ErrorKind::InvalidRequest,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if let Some(c) = h
|
||||||
|
.chars()
|
||||||
|
.find(|c| !(c.is_ascii_alphanumeric() || c == &'-') || c.is_ascii_uppercase())
|
||||||
|
{
|
||||||
|
return Err(Error::new(
|
||||||
|
eyre!("{}", t!("hostname.invalid-character", char = c)),
|
||||||
|
ErrorKind::InvalidRequest,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Ok(Self(h))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn lan_address(&self) -> InternedString {
|
pub fn lan_address(&self) -> InternedString {
|
||||||
InternedString::from_display(&lazy_format!("https://{}.local", self.0))
|
InternedString::from_display(&lazy_format!("https://{}.local", self.0))
|
||||||
}
|
}
|
||||||
@@ -87,3 +111,31 @@ pub async fn sync_hostname(hostname: &Hostname) -> Result<(), Error> {
|
|||||||
.await?;
|
.await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize, Parser, TS)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
#[command(rename_all = "kebab-case")]
|
||||||
|
#[ts(export)]
|
||||||
|
pub struct SetServerHostnameParams {
|
||||||
|
hostname: InternedString,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn set_hostname_rpc(
|
||||||
|
ctx: RpcContext,
|
||||||
|
SetServerHostnameParams { hostname }: SetServerHostnameParams,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let hostname = Hostname::validate(hostname)?;
|
||||||
|
ctx.db
|
||||||
|
.mutate(|db| {
|
||||||
|
db.as_public_mut()
|
||||||
|
.as_server_info_mut()
|
||||||
|
.as_hostname_mut()
|
||||||
|
.ser(&hostname.0)
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.result?;
|
||||||
|
ctx.account.mutate(|a| a.hostname = hostname.clone());
|
||||||
|
sync_hostname(&hostname).await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|||||||
@@ -211,12 +211,7 @@ pub async fn init(
|
|||||||
|
|
||||||
start_net.start();
|
start_net.start();
|
||||||
let net_ctrl = Arc::new(
|
let net_ctrl = Arc::new(
|
||||||
NetController::init(
|
NetController::init(db.clone(), cfg.socks_listen.unwrap_or(DEFAULT_SOCKS_LISTEN)).await?,
|
||||||
db.clone(),
|
|
||||||
&account.hostname,
|
|
||||||
cfg.socks_listen.unwrap_or(DEFAULT_SOCKS_LISTEN),
|
|
||||||
)
|
|
||||||
.await?,
|
|
||||||
);
|
);
|
||||||
webserver.send_modify(|wl| wl.set_ip_info(net_ctrl.net_iface.watcher.subscribe()));
|
webserver.send_modify(|wl| wl.set_ip_info(net_ctrl.net_iface.watcher.subscribe()));
|
||||||
let os_net_service = net_ctrl.os_bindings().await?;
|
let os_net_service = net_ctrl.os_bindings().await?;
|
||||||
|
|||||||
@@ -377,6 +377,13 @@ pub fn server<C: Context>() -> ParentHandler<C> {
|
|||||||
"host",
|
"host",
|
||||||
net::host::server_host_api::<C>().with_about("about.commands-host-system-ui"),
|
net::host::server_host_api::<C>().with_about("about.commands-host-system-ui"),
|
||||||
)
|
)
|
||||||
|
.subcommand(
|
||||||
|
"set-hostname",
|
||||||
|
from_fn_async(hostname::set_hostname_rpc)
|
||||||
|
.no_display()
|
||||||
|
.with_about("about.set-hostname")
|
||||||
|
.with_call_remote::<CliContext>(),
|
||||||
|
)
|
||||||
.subcommand(
|
.subcommand(
|
||||||
"set-ifconfig-url",
|
"set-ifconfig-url",
|
||||||
from_fn_async(system::set_ifconfig_url)
|
from_fn_async(system::set_ifconfig_url)
|
||||||
|
|||||||
@@ -76,6 +76,11 @@ impl AvailablePorts {
|
|||||||
self.0.insert(port, ssl);
|
self.0.insert(port, ssl);
|
||||||
Some(port)
|
Some(port)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_ssl(&mut self, port: u16, ssl: bool) {
|
||||||
|
self.0.insert(port, ssl);
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns whether a given allocated port is SSL.
|
/// Returns whether a given allocated port is SSL.
|
||||||
pub fn is_ssl(&self, port: u16) -> bool {
|
pub fn is_ssl(&self, port: u16) -> bool {
|
||||||
self.0.get(&port).copied().unwrap_or(false)
|
self.0.get(&port).copied().unwrap_or(false)
|
||||||
|
|||||||
@@ -5,14 +5,13 @@ use std::sync::{Arc, Weak};
|
|||||||
use color_eyre::eyre::eyre;
|
use color_eyre::eyre::eyre;
|
||||||
use imbl_value::InternedString;
|
use imbl_value::InternedString;
|
||||||
use nix::net::if_::if_nametoindex;
|
use nix::net::if_::if_nametoindex;
|
||||||
|
use patch_db::json_ptr::JsonPointer;
|
||||||
use tokio::process::Command;
|
use tokio::process::Command;
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
use tokio::task::JoinHandle;
|
use tokio::task::JoinHandle;
|
||||||
use tokio_rustls::rustls::ClientConfig as TlsClientConfig;
|
use tokio_rustls::rustls::ClientConfig as TlsClientConfig;
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
|
|
||||||
use patch_db::json_ptr::JsonPointer;
|
|
||||||
|
|
||||||
use crate::db::model::Database;
|
use crate::db::model::Database;
|
||||||
use crate::hostname::Hostname;
|
use crate::hostname::Hostname;
|
||||||
use crate::net::dns::DnsController;
|
use crate::net::dns::DnsController;
|
||||||
@@ -41,16 +40,11 @@ pub struct NetController {
|
|||||||
pub(super) dns: DnsController,
|
pub(super) dns: DnsController,
|
||||||
pub(super) forward: InterfacePortForwardController,
|
pub(super) forward: InterfacePortForwardController,
|
||||||
pub(super) socks: SocksController,
|
pub(super) socks: SocksController,
|
||||||
pub(super) server_hostnames: Vec<Option<InternedString>>,
|
|
||||||
pub(crate) callbacks: Arc<ServiceCallbacks>,
|
pub(crate) callbacks: Arc<ServiceCallbacks>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NetController {
|
impl NetController {
|
||||||
pub async fn init(
|
pub async fn init(db: TypedPatchDb<Database>, socks_listen: SocketAddr) -> Result<Self, Error> {
|
||||||
db: TypedPatchDb<Database>,
|
|
||||||
hostname: &Hostname,
|
|
||||||
socks_listen: SocketAddr,
|
|
||||||
) -> Result<Self, Error> {
|
|
||||||
let net_iface = Arc::new(NetworkInterfaceController::new(db.clone()));
|
let net_iface = Arc::new(NetworkInterfaceController::new(db.clone()));
|
||||||
let socks = SocksController::new(socks_listen)?;
|
let socks = SocksController::new(socks_listen)?;
|
||||||
let crypto_provider = Arc::new(tokio_rustls::rustls::crypto::ring::default_provider());
|
let crypto_provider = Arc::new(tokio_rustls::rustls::crypto::ring::default_provider());
|
||||||
@@ -90,18 +84,6 @@ impl NetController {
|
|||||||
forward: InterfacePortForwardController::new(net_iface.watcher.subscribe()),
|
forward: InterfacePortForwardController::new(net_iface.watcher.subscribe()),
|
||||||
net_iface,
|
net_iface,
|
||||||
socks,
|
socks,
|
||||||
server_hostnames: vec![
|
|
||||||
// LAN IP
|
|
||||||
None,
|
|
||||||
// Internal DNS
|
|
||||||
Some("embassy".into()),
|
|
||||||
Some("startos".into()),
|
|
||||||
// localhost
|
|
||||||
Some("localhost".into()),
|
|
||||||
Some(hostname.no_dot_host_name()),
|
|
||||||
// LAN mDNS
|
|
||||||
Some(hostname.local_domain_name()),
|
|
||||||
],
|
|
||||||
callbacks: Arc::new(ServiceCallbacks::default()),
|
callbacks: Arc::new(ServiceCallbacks::default()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -183,12 +165,7 @@ impl NetServiceData {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn update(
|
async fn update(&mut self, ctrl: &NetController, id: HostId, host: Host) -> Result<(), Error> {
|
||||||
&mut self,
|
|
||||||
ctrl: &NetController,
|
|
||||||
id: HostId,
|
|
||||||
host: Host,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
let mut forwards: BTreeMap<u16, (SocketAddrV4, ForwardRequirements)> = BTreeMap::new();
|
let mut forwards: BTreeMap<u16, (SocketAddrV4, ForwardRequirements)> = BTreeMap::new();
|
||||||
let mut vhosts: BTreeMap<(Option<InternedString>, u16), ProxyTarget> = BTreeMap::new();
|
let mut vhosts: BTreeMap<(Option<InternedString>, u16), ProxyTarget> = BTreeMap::new();
|
||||||
let mut private_dns: BTreeSet<InternedString> = BTreeSet::new();
|
let mut private_dns: BTreeSet<InternedString> = BTreeSet::new();
|
||||||
@@ -247,23 +224,21 @@ impl NetServiceData {
|
|||||||
.cloned()
|
.cloned()
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
// Server hostname vhosts (on assigned_ssl_port)
|
// * vhost (on assigned_ssl_port)
|
||||||
if !server_private_ips.is_empty() || !server_public_gateways.is_empty() {
|
if !server_private_ips.is_empty() || !server_public_gateways.is_empty() {
|
||||||
for hostname in ctrl.server_hostnames.iter().cloned() {
|
vhosts.insert(
|
||||||
vhosts.insert(
|
(None, assigned_ssl_port),
|
||||||
(hostname, assigned_ssl_port),
|
ProxyTarget {
|
||||||
ProxyTarget {
|
public: server_public_gateways.clone(),
|
||||||
public: server_public_gateways.clone(),
|
private: server_private_ips.clone(),
|
||||||
private: server_private_ips.clone(),
|
acme: None,
|
||||||
acme: None,
|
addr,
|
||||||
addr,
|
add_x_forwarded_headers: ssl.add_x_forwarded_headers,
|
||||||
add_x_forwarded_headers: ssl.add_x_forwarded_headers,
|
connect_ssl: connect_ssl
|
||||||
connect_ssl: connect_ssl
|
.clone()
|
||||||
.clone()
|
.map(|_| ctrl.tls_client_config.clone()),
|
||||||
.map(|_| ctrl.tls_client_config.clone()),
|
},
|
||||||
},
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -435,7 +410,6 @@ impl NetServiceData {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct NetService {
|
pub struct NetService {
|
||||||
@@ -474,9 +448,7 @@ impl NetService {
|
|||||||
let thread_data = data.clone();
|
let thread_data = data.clone();
|
||||||
let sync_task = tokio::spawn(async move {
|
let sync_task = tokio::spawn(async move {
|
||||||
if let Some(ref id) = pkg_id {
|
if let Some(ref id) = pkg_id {
|
||||||
let ptr: JsonPointer = format!("/public/packageData/{}/hosts", id)
|
let ptr: JsonPointer = format!("/public/packageData/{}/hosts", id).parse().unwrap();
|
||||||
.parse()
|
|
||||||
.unwrap();
|
|
||||||
let mut watch = db.watch(ptr).await.typed::<Hosts>();
|
let mut watch = db.watch(ptr).await.typed::<Hosts>();
|
||||||
|
|
||||||
// Outbound gateway enforcement
|
// Outbound gateway enforcement
|
||||||
@@ -484,9 +456,12 @@ impl NetService {
|
|||||||
// Purge any stale rules from a previous instance
|
// Purge any stale rules from a previous instance
|
||||||
loop {
|
loop {
|
||||||
if Command::new("ip")
|
if Command::new("ip")
|
||||||
.arg("rule").arg("del")
|
.arg("rule")
|
||||||
.arg("from").arg(&service_ip)
|
.arg("del")
|
||||||
.arg("priority").arg("100")
|
.arg("from")
|
||||||
|
.arg(&service_ip)
|
||||||
|
.arg("priority")
|
||||||
|
.arg("100")
|
||||||
.invoke(ErrorKind::Network)
|
.invoke(ErrorKind::Network)
|
||||||
.await
|
.await
|
||||||
.is_err()
|
.is_err()
|
||||||
@@ -555,10 +530,14 @@ impl NetService {
|
|||||||
if let Some(old_table) = current_outbound_table.take() {
|
if let Some(old_table) = current_outbound_table.take() {
|
||||||
let old_table_str = old_table.to_string();
|
let old_table_str = old_table.to_string();
|
||||||
let _ = Command::new("ip")
|
let _ = Command::new("ip")
|
||||||
.arg("rule").arg("del")
|
.arg("rule")
|
||||||
.arg("from").arg(&service_ip)
|
.arg("del")
|
||||||
.arg("lookup").arg(&old_table_str)
|
.arg("from")
|
||||||
.arg("priority").arg("100")
|
.arg(&service_ip)
|
||||||
|
.arg("lookup")
|
||||||
|
.arg(&old_table_str)
|
||||||
|
.arg("priority")
|
||||||
|
.arg("100")
|
||||||
.invoke(ErrorKind::Network)
|
.invoke(ErrorKind::Network)
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
@@ -580,10 +559,14 @@ impl NetService {
|
|||||||
{
|
{
|
||||||
let table_str = table_id.to_string();
|
let table_str = table_id.to_string();
|
||||||
Command::new("ip")
|
Command::new("ip")
|
||||||
.arg("rule").arg("add")
|
.arg("rule")
|
||||||
.arg("from").arg(&service_ip)
|
.arg("add")
|
||||||
.arg("lookup").arg(&table_str)
|
.arg("from")
|
||||||
.arg("priority").arg("100")
|
.arg(&service_ip)
|
||||||
|
.arg("lookup")
|
||||||
|
.arg(&table_str)
|
||||||
|
.arg("priority")
|
||||||
|
.arg("100")
|
||||||
.invoke(ErrorKind::Network)
|
.invoke(ErrorKind::Network)
|
||||||
.await
|
.await
|
||||||
.log_err();
|
.log_err();
|
||||||
@@ -606,10 +589,14 @@ impl NetService {
|
|||||||
if let Some(table_id) = current_outbound_table {
|
if let Some(table_id) = current_outbound_table {
|
||||||
let table_str = table_id.to_string();
|
let table_str = table_id.to_string();
|
||||||
let _ = Command::new("ip")
|
let _ = Command::new("ip")
|
||||||
.arg("rule").arg("del")
|
.arg("rule")
|
||||||
.arg("from").arg(&service_ip)
|
.arg("del")
|
||||||
.arg("lookup").arg(&table_str)
|
.arg("from")
|
||||||
.arg("priority").arg("100")
|
.arg(&service_ip)
|
||||||
|
.arg("lookup")
|
||||||
|
.arg(&table_str)
|
||||||
|
.arg("priority")
|
||||||
|
.arg("100")
|
||||||
.invoke(ErrorKind::Network)
|
.invoke(ErrorKind::Network)
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
@@ -763,9 +750,12 @@ impl NetService {
|
|||||||
let service_ip = self.data.lock().await.ip.to_string();
|
let service_ip = self.data.lock().await.ip.to_string();
|
||||||
loop {
|
loop {
|
||||||
if Command::new("ip")
|
if Command::new("ip")
|
||||||
.arg("rule").arg("del")
|
.arg("rule")
|
||||||
.arg("from").arg(&service_ip)
|
.arg("del")
|
||||||
.arg("priority").arg("100")
|
.arg("from")
|
||||||
|
.arg(&service_ip)
|
||||||
|
.arg("priority")
|
||||||
|
.arg("100")
|
||||||
.invoke(ErrorKind::Network)
|
.invoke(ErrorKind::Network)
|
||||||
.await
|
.await
|
||||||
.is_err()
|
.is_err()
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ use crate::disk::mount::filesystem::ReadWrite;
|
|||||||
use crate::disk::mount::filesystem::cifs::Cifs;
|
use crate::disk::mount::filesystem::cifs::Cifs;
|
||||||
use crate::disk::mount::guard::{GenericMountGuard, TmpMountGuard};
|
use crate::disk::mount::guard::{GenericMountGuard, TmpMountGuard};
|
||||||
use crate::disk::util::{DiskInfo, StartOsRecoveryInfo, pvscan, recovery_info};
|
use crate::disk::util::{DiskInfo, StartOsRecoveryInfo, pvscan, recovery_info};
|
||||||
|
use crate::hostname::Hostname;
|
||||||
use crate::init::{InitPhases, InitResult, init};
|
use crate::init::{InitPhases, InitResult, init};
|
||||||
use crate::net::ssl::root_ca_start_time;
|
use crate::net::ssl::root_ca_start_time;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
@@ -115,6 +116,7 @@ async fn setup_init(
|
|||||||
ctx: &SetupContext,
|
ctx: &SetupContext,
|
||||||
password: Option<String>,
|
password: Option<String>,
|
||||||
kiosk: Option<bool>,
|
kiosk: Option<bool>,
|
||||||
|
hostname: Option<InternedString>,
|
||||||
init_phases: InitPhases,
|
init_phases: InitPhases,
|
||||||
) -> Result<(AccountInfo, InitResult), Error> {
|
) -> Result<(AccountInfo, InitResult), Error> {
|
||||||
let init_result = init(&ctx.webserver, &ctx.config.peek(|c| c.clone()), init_phases).await?;
|
let init_result = init(&ctx.webserver, &ctx.config.peek(|c| c.clone()), init_phases).await?;
|
||||||
@@ -129,6 +131,9 @@ async fn setup_init(
|
|||||||
if let Some(password) = &password {
|
if let Some(password) = &password {
|
||||||
account.set_password(password)?;
|
account.set_password(password)?;
|
||||||
}
|
}
|
||||||
|
if let Some(hostname) = hostname {
|
||||||
|
account.hostname = Hostname::validate(hostname)?;
|
||||||
|
}
|
||||||
account.save(m)?;
|
account.save(m)?;
|
||||||
let info = m.as_public_mut().as_server_info_mut();
|
let info = m.as_public_mut().as_server_info_mut();
|
||||||
info.as_password_hash_mut().ser(&account.password)?;
|
info.as_password_hash_mut().ser(&account.password)?;
|
||||||
@@ -171,6 +176,7 @@ pub struct AttachParams {
|
|||||||
pub guid: InternedString,
|
pub guid: InternedString,
|
||||||
#[ts(optional)]
|
#[ts(optional)]
|
||||||
pub kiosk: Option<bool>,
|
pub kiosk: Option<bool>,
|
||||||
|
pub hostname: Option<InternedString>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(skip_all)]
|
#[instrument(skip_all)]
|
||||||
@@ -180,6 +186,7 @@ pub async fn attach(
|
|||||||
password,
|
password,
|
||||||
guid: disk_guid,
|
guid: disk_guid,
|
||||||
kiosk,
|
kiosk,
|
||||||
|
hostname,
|
||||||
}: AttachParams,
|
}: AttachParams,
|
||||||
) -> Result<SetupProgress, Error> {
|
) -> Result<SetupProgress, Error> {
|
||||||
let setup_ctx = ctx.clone();
|
let setup_ctx = ctx.clone();
|
||||||
@@ -233,7 +240,14 @@ pub async fn attach(
|
|||||||
}
|
}
|
||||||
disk_phase.complete();
|
disk_phase.complete();
|
||||||
|
|
||||||
let (account, net_ctrl) = setup_init(&setup_ctx, password, kiosk, init_phases).await?;
|
let (account, net_ctrl) = setup_init(
|
||||||
|
&setup_ctx,
|
||||||
|
password,
|
||||||
|
kiosk,
|
||||||
|
hostname.filter(|h| !h.is_empty()),
|
||||||
|
init_phases,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
let rpc_ctx = RpcContext::init(
|
let rpc_ctx = RpcContext::init(
|
||||||
&setup_ctx.webserver,
|
&setup_ctx.webserver,
|
||||||
@@ -406,6 +420,7 @@ pub struct SetupExecuteParams {
|
|||||||
recovery_source: Option<RecoverySource<EncryptedWire>>,
|
recovery_source: Option<RecoverySource<EncryptedWire>>,
|
||||||
#[ts(optional)]
|
#[ts(optional)]
|
||||||
kiosk: Option<bool>,
|
kiosk: Option<bool>,
|
||||||
|
hostname: Option<InternedString>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[command(rpc_only)]
|
// #[command(rpc_only)]
|
||||||
@@ -416,6 +431,7 @@ pub async fn execute(
|
|||||||
password,
|
password,
|
||||||
recovery_source,
|
recovery_source,
|
||||||
kiosk,
|
kiosk,
|
||||||
|
hostname,
|
||||||
}: SetupExecuteParams,
|
}: SetupExecuteParams,
|
||||||
) -> Result<SetupProgress, Error> {
|
) -> Result<SetupProgress, Error> {
|
||||||
let password = match password.decrypt(&ctx) {
|
let password = match password.decrypt(&ctx) {
|
||||||
@@ -447,7 +463,16 @@ pub async fn execute(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let setup_ctx = ctx.clone();
|
let setup_ctx = ctx.clone();
|
||||||
ctx.run_setup(move || execute_inner(setup_ctx, guid, password, recovery, kiosk))?;
|
ctx.run_setup(move || {
|
||||||
|
execute_inner(
|
||||||
|
setup_ctx,
|
||||||
|
guid,
|
||||||
|
password,
|
||||||
|
recovery,
|
||||||
|
kiosk,
|
||||||
|
hostname.filter(|h| !h.is_empty()),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
Ok(ctx.progress().await)
|
Ok(ctx.progress().await)
|
||||||
}
|
}
|
||||||
@@ -536,6 +561,7 @@ pub async fn execute_inner(
|
|||||||
password: String,
|
password: String,
|
||||||
recovery_source: Option<RecoverySource<String>>,
|
recovery_source: Option<RecoverySource<String>>,
|
||||||
kiosk: Option<bool>,
|
kiosk: Option<bool>,
|
||||||
|
hostname: Option<InternedString>,
|
||||||
) -> Result<(SetupResult, RpcContext), Error> {
|
) -> Result<(SetupResult, RpcContext), Error> {
|
||||||
let progress = &ctx.progress;
|
let progress = &ctx.progress;
|
||||||
let restore_phase = match recovery_source.as_ref() {
|
let restore_phase = match recovery_source.as_ref() {
|
||||||
@@ -570,14 +596,15 @@ pub async fn execute_inner(
|
|||||||
server_id,
|
server_id,
|
||||||
recovery_password,
|
recovery_password,
|
||||||
kiosk,
|
kiosk,
|
||||||
|
hostname,
|
||||||
progress,
|
progress,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
Some(RecoverySource::Migrate { guid: old_guid }) => {
|
Some(RecoverySource::Migrate { guid: old_guid }) => {
|
||||||
migrate(&ctx, guid, &old_guid, password, kiosk, progress).await
|
migrate(&ctx, guid, &old_guid, password, kiosk, hostname, progress).await
|
||||||
}
|
}
|
||||||
None => fresh_setup(&ctx, guid, &password, kiosk, progress).await,
|
None => fresh_setup(&ctx, guid, &password, kiosk, hostname, progress).await,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -592,13 +619,14 @@ async fn fresh_setup(
|
|||||||
guid: InternedString,
|
guid: InternedString,
|
||||||
password: &str,
|
password: &str,
|
||||||
kiosk: Option<bool>,
|
kiosk: Option<bool>,
|
||||||
|
hostname: Option<InternedString>,
|
||||||
SetupExecuteProgress {
|
SetupExecuteProgress {
|
||||||
init_phases,
|
init_phases,
|
||||||
rpc_ctx_phases,
|
rpc_ctx_phases,
|
||||||
..
|
..
|
||||||
}: SetupExecuteProgress,
|
}: SetupExecuteProgress,
|
||||||
) -> Result<(SetupResult, RpcContext), Error> {
|
) -> Result<(SetupResult, RpcContext), Error> {
|
||||||
let account = AccountInfo::new(password, root_ca_start_time().await)?;
|
let account = AccountInfo::new(password, root_ca_start_time().await, hostname)?;
|
||||||
let db = ctx.db().await?;
|
let db = ctx.db().await?;
|
||||||
let kiosk = Some(kiosk.unwrap_or(true)).filter(|_| &*PLATFORM != "raspberrypi");
|
let kiosk = Some(kiosk.unwrap_or(true)).filter(|_| &*PLATFORM != "raspberrypi");
|
||||||
sync_kiosk(kiosk).await?;
|
sync_kiosk(kiosk).await?;
|
||||||
@@ -652,6 +680,7 @@ async fn recover(
|
|||||||
server_id: String,
|
server_id: String,
|
||||||
recovery_password: String,
|
recovery_password: String,
|
||||||
kiosk: Option<bool>,
|
kiosk: Option<bool>,
|
||||||
|
hostname: Option<InternedString>,
|
||||||
progress: SetupExecuteProgress,
|
progress: SetupExecuteProgress,
|
||||||
) -> Result<(SetupResult, RpcContext), Error> {
|
) -> Result<(SetupResult, RpcContext), Error> {
|
||||||
let recovery_source = TmpMountGuard::mount(&recovery_source, ReadWrite).await?;
|
let recovery_source = TmpMountGuard::mount(&recovery_source, ReadWrite).await?;
|
||||||
@@ -663,6 +692,7 @@ async fn recover(
|
|||||||
&server_id,
|
&server_id,
|
||||||
&recovery_password,
|
&recovery_password,
|
||||||
kiosk,
|
kiosk,
|
||||||
|
hostname,
|
||||||
progress,
|
progress,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
@@ -675,6 +705,7 @@ async fn migrate(
|
|||||||
old_guid: &str,
|
old_guid: &str,
|
||||||
password: String,
|
password: String,
|
||||||
kiosk: Option<bool>,
|
kiosk: Option<bool>,
|
||||||
|
hostname: Option<InternedString>,
|
||||||
SetupExecuteProgress {
|
SetupExecuteProgress {
|
||||||
init_phases,
|
init_phases,
|
||||||
restore_phase,
|
restore_phase,
|
||||||
@@ -753,7 +784,8 @@ async fn migrate(
|
|||||||
crate::disk::main::export(&old_guid, "/media/startos/migrate").await?;
|
crate::disk::main::export(&old_guid, "/media/startos/migrate").await?;
|
||||||
restore_phase.complete();
|
restore_phase.complete();
|
||||||
|
|
||||||
let (account, net_ctrl) = setup_init(&ctx, Some(password), kiosk, init_phases).await?;
|
let (account, net_ctrl) =
|
||||||
|
setup_init(&ctx, Some(password), kiosk, hostname, init_phases).await?;
|
||||||
|
|
||||||
let rpc_ctx = RpcContext::init(
|
let rpc_ctx = RpcContext::init(
|
||||||
&ctx.webserver,
|
&ctx.webserver,
|
||||||
|
|||||||
Reference in New Issue
Block a user