mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 04:01:58 +00:00
Bugfix/alpha.13 (#3053)
* bugfixes for alpha.13 * minor fixes * version bump * start-tunnel workflow * sdk beta 44 * defaultFilter * fix reset-password on tunnel auth * explicitly rebuild types * fix typo * ubuntu-latest runner * add cleanup steps * fix env on attach
This commit is contained in:
@@ -260,11 +260,7 @@ impl NetworkInterfaceInfo {
|
||||
}
|
||||
|
||||
pub fn secure(&self) -> bool {
|
||||
self.secure.unwrap_or_else(|| {
|
||||
self.ip_info.as_ref().map_or(false, |ip_info| {
|
||||
ip_info.device_type == Some(NetworkInterfaceType::Wireguard)
|
||||
}) && !self.public()
|
||||
})
|
||||
self.secure.unwrap_or(false)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -366,6 +366,7 @@ impl LxcContainer {
|
||||
}
|
||||
tokio::time::sleep(Duration::from_millis(100)).await;
|
||||
}
|
||||
tracing::info!("Connected to socket in {:?}", started.elapsed());
|
||||
Ok(UnixRpcClient::new(sock_path))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -649,16 +649,6 @@ async fn torctl(
|
||||
.invoke(ErrorKind::Tor)
|
||||
.await?;
|
||||
|
||||
let logs = journalctl(
|
||||
LogSource::Unit(SYSTEMD_UNIT),
|
||||
Some(0),
|
||||
None,
|
||||
Some("0"),
|
||||
false,
|
||||
true,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let mut tcp_stream = None;
|
||||
for _ in 0..60 {
|
||||
if let Ok(conn) = TcpStream::connect(tor_control).await {
|
||||
@@ -720,7 +710,7 @@ async fn torctl(
|
||||
ErrorKind::Tor,
|
||||
));
|
||||
}
|
||||
Ok((connection, logs))
|
||||
Ok(connection)
|
||||
};
|
||||
let pre_handler = async {
|
||||
while let Some(command) = recv.recv().await {
|
||||
@@ -745,7 +735,7 @@ async fn torctl(
|
||||
Ok(())
|
||||
};
|
||||
|
||||
let (mut connection, mut logs) = tokio::select! {
|
||||
let mut connection = tokio::select! {
|
||||
res = bootstrap => res?,
|
||||
res = pre_handler => return res,
|
||||
};
|
||||
@@ -851,46 +841,59 @@ async fn torctl(
|
||||
Ok(())
|
||||
};
|
||||
let log_parser = async {
|
||||
while let Some(log) = logs.try_next().await? {
|
||||
for (regex, severity) in &*LOG_REGEXES {
|
||||
if regex.is_match(&log.message) {
|
||||
let (check, wipe_state) = match severity {
|
||||
ErrorLogSeverity::Fatal { wipe_state } => (false, *wipe_state),
|
||||
ErrorLogSeverity::Unknown { wipe_state } => (true, *wipe_state),
|
||||
};
|
||||
let addr = hck_key.public().get_onion_address().to_string();
|
||||
if !check
|
||||
|| TcpStream::connect(tor_socks)
|
||||
.map_err(|e| Error::new(e, ErrorKind::Tor))
|
||||
.and_then(|mut tor_socks| async move {
|
||||
tokio::time::timeout(
|
||||
Duration::from_secs(30),
|
||||
socks5_impl::client::connect(&mut tor_socks, (addr, 80), None)
|
||||
.map_err(|e| Error::new(e, ErrorKind::Tor)),
|
||||
)
|
||||
loop {
|
||||
let mut logs = journalctl(
|
||||
LogSource::Unit(SYSTEMD_UNIT),
|
||||
Some(0),
|
||||
None,
|
||||
Some("0"),
|
||||
false,
|
||||
true,
|
||||
)
|
||||
.await?;
|
||||
while let Some(log) = logs.try_next().await? {
|
||||
for (regex, severity) in &*LOG_REGEXES {
|
||||
if regex.is_match(&log.message) {
|
||||
let (check, wipe_state) = match severity {
|
||||
ErrorLogSeverity::Fatal { wipe_state } => (false, *wipe_state),
|
||||
ErrorLogSeverity::Unknown { wipe_state } => (true, *wipe_state),
|
||||
};
|
||||
let addr = hck_key.public().get_onion_address().to_string();
|
||||
if !check
|
||||
|| TcpStream::connect(tor_socks)
|
||||
.map_err(|e| Error::new(e, ErrorKind::Tor))
|
||||
.await?
|
||||
})
|
||||
.await
|
||||
.with_ctx(|_| (ErrorKind::Tor, "Tor is confirmed to be down"))
|
||||
.log_err()
|
||||
.is_some()
|
||||
{
|
||||
if wipe_state {
|
||||
Command::new("systemctl")
|
||||
.arg("stop")
|
||||
.arg("tor")
|
||||
.invoke(ErrorKind::Tor)
|
||||
.await?;
|
||||
tokio::fs::remove_dir_all("/var/lib/tor").await?;
|
||||
.and_then(|mut tor_socks| async move {
|
||||
tokio::time::timeout(
|
||||
Duration::from_secs(30),
|
||||
socks5_impl::client::connect(
|
||||
&mut tor_socks,
|
||||
(addr, 80),
|
||||
None,
|
||||
)
|
||||
.map_err(|e| Error::new(e, ErrorKind::Tor)),
|
||||
)
|
||||
.map_err(|e| Error::new(e, ErrorKind::Tor))
|
||||
.await?
|
||||
})
|
||||
.await
|
||||
.with_ctx(|_| (ErrorKind::Tor, "Tor is confirmed to be down"))
|
||||
.log_err()
|
||||
.is_some()
|
||||
{
|
||||
if wipe_state {
|
||||
Command::new("systemctl")
|
||||
.arg("stop")
|
||||
.arg("tor")
|
||||
.invoke(ErrorKind::Tor)
|
||||
.await?;
|
||||
tokio::fs::remove_dir_all("/var/lib/tor").await?;
|
||||
}
|
||||
return Err(Error::new(eyre!("{}", log.message), ErrorKind::Tor));
|
||||
}
|
||||
return Err(Error::new(eyre!("{}", log.message), ErrorKind::Tor));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Err(Error::new(eyre!("Log stream terminated"), ErrorKind::Tor))
|
||||
Ok(())
|
||||
};
|
||||
let health_checker = async {
|
||||
let mut last_success = Instant::now();
|
||||
@@ -960,20 +963,23 @@ impl TorControl {
|
||||
_thread: tokio::spawn(async move {
|
||||
let wipe_state = AtomicBool::new(false);
|
||||
let mut health_timeout = Duration::from_secs(STARTING_HEALTH_TIMEOUT);
|
||||
while let Err(e) = torctl(
|
||||
tor_control,
|
||||
tor_socks,
|
||||
&mut recv,
|
||||
&mut thread_services,
|
||||
&wipe_state,
|
||||
&mut health_timeout,
|
||||
)
|
||||
.await
|
||||
{
|
||||
tracing::error!("{e}: Restarting tor");
|
||||
tracing::debug!("{e:?}");
|
||||
loop {
|
||||
if let Err(e) = torctl(
|
||||
tor_control,
|
||||
tor_socks,
|
||||
&mut recv,
|
||||
&mut thread_services,
|
||||
&wipe_state,
|
||||
&mut health_timeout,
|
||||
)
|
||||
.await
|
||||
{
|
||||
tracing::error!("TorControl : {e}");
|
||||
tracing::debug!("{e:?}");
|
||||
}
|
||||
tracing::info!("Restarting Tor");
|
||||
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||
}
|
||||
tracing::info!("TorControl is shut down.")
|
||||
})
|
||||
.into(),
|
||||
send,
|
||||
|
||||
@@ -106,7 +106,9 @@ pub struct ExecParams {
|
||||
#[arg(long)]
|
||||
pty_size: Option<TermSize>,
|
||||
#[arg(short, long)]
|
||||
env: Option<PathBuf>,
|
||||
env: Vec<String>,
|
||||
#[arg(long)]
|
||||
env_file: Option<PathBuf>,
|
||||
#[arg(short, long)]
|
||||
workdir: Option<PathBuf>,
|
||||
#[arg(short, long)]
|
||||
@@ -119,6 +121,7 @@ impl ExecParams {
|
||||
fn exec(&self) -> Result<(), Error> {
|
||||
let ExecParams {
|
||||
env,
|
||||
env_file,
|
||||
workdir,
|
||||
user,
|
||||
chroot,
|
||||
@@ -131,14 +134,15 @@ impl ExecParams {
|
||||
ErrorKind::InvalidRequest,
|
||||
));
|
||||
};
|
||||
let env_string = if let Some(env) = &env {
|
||||
std::fs::read_to_string(env)
|
||||
let env_string = if let Some(env_file) = &env_file {
|
||||
std::fs::read_to_string(env_file)
|
||||
.with_ctx(|_| (ErrorKind::Filesystem, lazy_format!("read {env:?}")))?
|
||||
} else {
|
||||
Default::default()
|
||||
};
|
||||
let env = env_string
|
||||
.lines()
|
||||
.chain(env.iter().map(|l| l.as_str()))
|
||||
.map(|l| l.trim())
|
||||
.filter_map(|l| l.split_once("="))
|
||||
.collect::<BTreeMap<_, _>>();
|
||||
@@ -199,6 +203,7 @@ pub fn launch(
|
||||
force_stderr_tty,
|
||||
pty_size,
|
||||
env,
|
||||
env_file,
|
||||
workdir,
|
||||
user,
|
||||
chroot,
|
||||
@@ -294,8 +299,11 @@ pub fn launch(
|
||||
let (pty, pts) = pty_process::open().with_kind(ErrorKind::Filesystem)?;
|
||||
let mut cmd = pty_process::Command::new("/usr/bin/start-container");
|
||||
cmd = cmd.arg("subcontainer").arg("launch-init");
|
||||
if let Some(env) = env {
|
||||
cmd = cmd.arg("--env").arg(env);
|
||||
for env in env {
|
||||
cmd = cmd.arg("-e").arg(env)
|
||||
}
|
||||
if let Some(env_file) = env_file {
|
||||
cmd = cmd.arg("--env-file").arg(env_file);
|
||||
}
|
||||
if let Some(workdir) = workdir {
|
||||
cmd = cmd.arg("--workdir").arg(workdir);
|
||||
@@ -349,8 +357,11 @@ pub fn launch(
|
||||
} else {
|
||||
let mut cmd = StdCommand::new("/usr/bin/start-container");
|
||||
cmd.arg("subcontainer").arg("launch-init");
|
||||
if let Some(env) = env {
|
||||
cmd.arg("--env").arg(env);
|
||||
for env in env {
|
||||
cmd.arg("-e").arg(env);
|
||||
}
|
||||
if let Some(env_file) = env_file {
|
||||
cmd.arg("--env-file").arg(env_file);
|
||||
}
|
||||
if let Some(workdir) = workdir {
|
||||
cmd.arg("--workdir").arg(workdir);
|
||||
@@ -441,6 +452,7 @@ pub fn exec(
|
||||
force_stderr_tty,
|
||||
pty_size,
|
||||
env,
|
||||
env_file,
|
||||
workdir,
|
||||
user,
|
||||
chroot,
|
||||
@@ -544,8 +556,11 @@ pub fn exec(
|
||||
let (pty, pts) = pty_process::open().with_kind(ErrorKind::Filesystem)?;
|
||||
let mut cmd = pty_process::Command::new("/usr/bin/start-container");
|
||||
cmd = cmd.arg("subcontainer").arg("exec-command");
|
||||
if let Some(env) = env {
|
||||
cmd = cmd.arg("--env").arg(env);
|
||||
for env in env {
|
||||
cmd = cmd.arg("-e").arg(env);
|
||||
}
|
||||
if let Some(env_file) = env_file {
|
||||
cmd = cmd.arg("--env-file").arg(env_file);
|
||||
}
|
||||
if let Some(workdir) = workdir {
|
||||
cmd = cmd.arg("--workdir").arg(workdir);
|
||||
@@ -599,8 +614,11 @@ pub fn exec(
|
||||
} else {
|
||||
let mut cmd = StdCommand::new("/usr/bin/start-container");
|
||||
cmd.arg("subcontainer").arg("exec-command");
|
||||
if let Some(env) = env {
|
||||
cmd.arg("--env").arg(env);
|
||||
for env in env {
|
||||
cmd.arg("-e").arg(env);
|
||||
}
|
||||
if let Some(env_file) = env_file {
|
||||
cmd.arg("--env-file").arg(env_file);
|
||||
}
|
||||
if let Some(workdir) = workdir {
|
||||
cmd.arg("--workdir").arg(workdir);
|
||||
|
||||
@@ -885,7 +885,7 @@ pub async fn attach(
|
||||
.arg("start-container")
|
||||
.arg("subcontainer")
|
||||
.arg("exec")
|
||||
.arg("--env")
|
||||
.arg("--env-file")
|
||||
.arg(
|
||||
Path::new("/media/startos/images")
|
||||
.join(image_id)
|
||||
|
||||
@@ -43,7 +43,7 @@ use crate::util::rpc_client::UnixRpcClient;
|
||||
use crate::volume::data_dir;
|
||||
use crate::{ARCH, DATA_DIR, PACKAGE_DATA};
|
||||
|
||||
const RPC_CONNECT_TIMEOUT: Duration = Duration::from_secs(10);
|
||||
const RPC_CONNECT_TIMEOUT: Duration = Duration::from_secs(30);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ServiceState {
|
||||
|
||||
@@ -117,6 +117,8 @@ impl ServiceMap {
|
||||
match Service::load(ctx, id, disposition).await {
|
||||
Ok(s) => *service = s.into(),
|
||||
Err(e) => {
|
||||
tracing::error!("Error loading service: {e}");
|
||||
tracing::debug!("{e:?}");
|
||||
let e = ErrorData::from(e);
|
||||
ctx.db
|
||||
.mutate(|db| {
|
||||
|
||||
@@ -3,7 +3,7 @@ use imbl::HashMap;
|
||||
use imbl_value::InternedString;
|
||||
use itertools::Itertools;
|
||||
use patch_db::HasModel;
|
||||
use rpc_toolkit::{Context, HandlerArgs, HandlerExt, ParentHandler, from_fn_async};
|
||||
use rpc_toolkit::{Context, Empty, HandlerArgs, HandlerExt, ParentHandler, from_fn_async};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ts_rs::TS;
|
||||
|
||||
@@ -113,27 +113,12 @@ impl AuthContext for TunnelContext {
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, HasModel, TS, Parser)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[model = "Model<Self>"]
|
||||
#[ts(export)]
|
||||
pub struct SignerInfo {
|
||||
pub name: InternedString,
|
||||
}
|
||||
|
||||
pub fn auth_api<C: Context>() -> ParentHandler<C> {
|
||||
ParentHandler::new()
|
||||
.subcommand(
|
||||
"login",
|
||||
from_fn_async(crate::auth::login_impl::<TunnelContext>)
|
||||
.with_metadata("login", Value::Bool(true))
|
||||
.no_cli(),
|
||||
)
|
||||
.subcommand(
|
||||
"logout",
|
||||
from_fn_async(crate::auth::logout::<TunnelContext>)
|
||||
.with_metadata("get_session", Value::Bool(true))
|
||||
.no_display()
|
||||
.with_about("Log out of current auth session")
|
||||
.with_call_remote::<CliContext>(),
|
||||
)
|
||||
crate::auth::auth::<C, TunnelContext>()
|
||||
.subcommand("set-password", from_fn_async(set_password_rpc).no_cli())
|
||||
.subcommand(
|
||||
"set-password",
|
||||
@@ -173,19 +158,15 @@ pub fn auth_api<C: Context>() -> ParentHandler<C> {
|
||||
.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 => "NAME", "KEY"]);
|
||||
for (key, info) in res {
|
||||
table.add_row(row![info.name, key]);
|
||||
}
|
||||
|
||||
table.print_tty(false)?;
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.with_about("List authorized keys")
|
||||
@@ -194,7 +175,7 @@ pub fn auth_api<C: Context>() -> ParentHandler<C> {
|
||||
)
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Parser)]
|
||||
#[derive(Debug, Deserialize, Serialize, Parser, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AddKeyParams {
|
||||
pub name: InternedString,
|
||||
@@ -216,7 +197,7 @@ pub async fn add_key(
|
||||
.result
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Parser)]
|
||||
#[derive(Debug, Deserialize, Serialize, Parser, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RemoveKeyParams {
|
||||
pub key: AnyVerifyingKey,
|
||||
@@ -240,7 +221,7 @@ pub async fn list_keys(ctx: TunnelContext) -> Result<HashMap<AnyVerifyingKey, Si
|
||||
ctx.db.peek().await.into_auth_pubkeys().de()
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, TS)]
|
||||
pub struct SetPasswordParams {
|
||||
pub password: String,
|
||||
}
|
||||
|
||||
@@ -53,8 +53,9 @@ mod v0_4_0_alpha_10;
|
||||
mod v0_4_0_alpha_11;
|
||||
mod v0_4_0_alpha_12;
|
||||
mod v0_4_0_alpha_13;
|
||||
mod v0_4_0_alpha_14;
|
||||
|
||||
pub type Current = v0_4_0_alpha_13::Version; // VERSION_BUMP
|
||||
pub type Current = v0_4_0_alpha_14::Version; // VERSION_BUMP
|
||||
|
||||
impl Current {
|
||||
#[instrument(skip(self, db))]
|
||||
@@ -169,7 +170,8 @@ enum Version {
|
||||
V0_4_0_alpha_10(Wrapper<v0_4_0_alpha_10::Version>),
|
||||
V0_4_0_alpha_11(Wrapper<v0_4_0_alpha_11::Version>),
|
||||
V0_4_0_alpha_12(Wrapper<v0_4_0_alpha_12::Version>),
|
||||
V0_4_0_alpha_13(Wrapper<v0_4_0_alpha_13::Version>), // VERSION_BUMP
|
||||
V0_4_0_alpha_13(Wrapper<v0_4_0_alpha_13::Version>),
|
||||
V0_4_0_alpha_14(Wrapper<v0_4_0_alpha_14::Version>), // VERSION_BUMP
|
||||
Other(exver::Version),
|
||||
}
|
||||
|
||||
@@ -225,7 +227,8 @@ impl Version {
|
||||
Self::V0_4_0_alpha_10(v) => DynVersion(Box::new(v.0)),
|
||||
Self::V0_4_0_alpha_11(v) => DynVersion(Box::new(v.0)),
|
||||
Self::V0_4_0_alpha_12(v) => DynVersion(Box::new(v.0)),
|
||||
Self::V0_4_0_alpha_13(v) => DynVersion(Box::new(v.0)), // VERSION_BUMP
|
||||
Self::V0_4_0_alpha_13(v) => DynVersion(Box::new(v.0)),
|
||||
Self::V0_4_0_alpha_14(v) => DynVersion(Box::new(v.0)), // VERSION_BUMP
|
||||
Self::Other(v) => {
|
||||
return Err(Error::new(
|
||||
eyre!("unknown version {v}"),
|
||||
@@ -273,7 +276,8 @@ impl Version {
|
||||
Version::V0_4_0_alpha_10(Wrapper(x)) => x.semver(),
|
||||
Version::V0_4_0_alpha_11(Wrapper(x)) => x.semver(),
|
||||
Version::V0_4_0_alpha_12(Wrapper(x)) => x.semver(),
|
||||
Version::V0_4_0_alpha_13(Wrapper(x)) => x.semver(), // VERSION_BUMP
|
||||
Version::V0_4_0_alpha_13(Wrapper(x)) => x.semver(),
|
||||
Version::V0_4_0_alpha_14(Wrapper(x)) => x.semver(), // VERSION_BUMP
|
||||
Version::Other(x) => x.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ use exver::{PreReleaseSegment, VersionRange};
|
||||
use imbl_value::InternedString;
|
||||
|
||||
use super::v0_3_5::V0_3_0_COMPAT;
|
||||
use super::{VersionT, v0_4_0_alpha_11};
|
||||
use super::{v0_4_0_alpha_11, VersionT};
|
||||
use crate::net::tor::TorSecretKey;
|
||||
use crate::prelude::*;
|
||||
|
||||
@@ -75,7 +75,10 @@ impl VersionT for Version {
|
||||
}
|
||||
fix_host(&mut db["public"]["serverInfo"]["network"]["host"])?;
|
||||
|
||||
db["private"]["keyStore"]["localCerts"] = db["private"]["keyStore"]["local_certs"].clone();
|
||||
if db["private"]["keyStore"]["localCerts"].is_null() {
|
||||
db["private"]["keyStore"]["localCerts"] =
|
||||
db["private"]["keyStore"]["local_certs"].clone();
|
||||
}
|
||||
|
||||
Ok(Value::Null)
|
||||
}
|
||||
|
||||
37
core/startos/src/version/v0_4_0_alpha_14.rs
Normal file
37
core/startos/src/version/v0_4_0_alpha_14.rs
Normal file
@@ -0,0 +1,37 @@
|
||||
use exver::{PreReleaseSegment, VersionRange};
|
||||
|
||||
use super::v0_3_5::V0_3_0_COMPAT;
|
||||
use super::{VersionT, v0_4_0_alpha_13};
|
||||
use crate::prelude::*;
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref V0_4_0_alpha_14: exver::Version = exver::Version::new(
|
||||
[0, 4, 0],
|
||||
[PreReleaseSegment::String("alpha".into()), 14.into()]
|
||||
);
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
pub struct Version;
|
||||
|
||||
impl VersionT for Version {
|
||||
type Previous = v0_4_0_alpha_13::Version;
|
||||
type PreUpRes = ();
|
||||
|
||||
async fn pre_up(self) -> Result<Self::PreUpRes, Error> {
|
||||
Ok(())
|
||||
}
|
||||
fn semver(self) -> exver::Version {
|
||||
V0_4_0_alpha_14.clone()
|
||||
}
|
||||
fn compat(self) -> &'static VersionRange {
|
||||
&V0_3_0_COMPAT
|
||||
}
|
||||
#[instrument(skip_all)]
|
||||
fn up(self, _db: &mut Value, _: Self::PreUpRes) -> Result<Value, Error> {
|
||||
Ok(Value::Null)
|
||||
}
|
||||
fn down(self, _db: &mut Value) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user