mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-26 10:21:52 +00:00
appmgr: wrap up tor
This commit is contained in:
committed by
Aiden McClelland
parent
351ce2495d
commit
9630c356f4
@@ -18,7 +18,7 @@ use serde_json::{Number, Value};
|
||||
use super::util::{self, CharSet, NumRange, UniqueBy, STATIC_NULL};
|
||||
use super::{Config, MatchError, NoMatchWithPath, TimeoutError, TypeOf};
|
||||
use crate::config::ConfigurationError;
|
||||
use crate::id::InterfaceId;
|
||||
use crate::net::interface::InterfaceId;
|
||||
use crate::s9pk::manifest::{Manifest, PackageId};
|
||||
use crate::Error;
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@ use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::config::spec::{PackagePointerSpecVariant, SystemPointerSpec};
|
||||
use crate::id::InterfaceId;
|
||||
use crate::install::progress::InstallProgress;
|
||||
use crate::net::interface::InterfaceId;
|
||||
use crate::net::Network;
|
||||
use crate::s9pk::manifest::{Manifest, PackageId};
|
||||
use crate::status::health_check::HealthCheckId;
|
||||
|
||||
@@ -8,8 +8,8 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::action::ActionImplementation;
|
||||
use crate::config::{Config, ConfigSpec};
|
||||
use crate::id::InterfaceId;
|
||||
use crate::net::host::Hosts;
|
||||
use crate::net::interface::InterfaceId;
|
||||
use crate::s9pk::manifest::PackageId;
|
||||
use crate::status::health_check::{HealthCheckId, HealthCheckResult, HealthCheckResultVariant};
|
||||
use crate::status::{DependencyErrors, MainStatus, Status};
|
||||
|
||||
@@ -166,39 +166,3 @@ where
|
||||
Ok(ImageId(Deserialize::deserialize(deserializer)?))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize)]
|
||||
pub struct InterfaceId<S: AsRef<str> = String>(Id<S>);
|
||||
impl<S: AsRef<str>> std::fmt::Display for InterfaceId<S> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", &self.0)
|
||||
}
|
||||
}
|
||||
impl<S: AsRef<str>> std::ops::Deref for InterfaceId<S> {
|
||||
type Target = S;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&*self.0
|
||||
}
|
||||
}
|
||||
impl<S: AsRef<str>> AsRef<str> for InterfaceId<S> {
|
||||
fn as_ref(&self) -> &str {
|
||||
self.0.as_ref()
|
||||
}
|
||||
}
|
||||
impl<'de, S> Deserialize<'de> for InterfaceId<S>
|
||||
where
|
||||
S: AsRef<str>,
|
||||
Id<S>: Deserialize<'de>,
|
||||
{
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
Ok(InterfaceId(Deserialize::deserialize(deserializer)?))
|
||||
}
|
||||
}
|
||||
impl<S: AsRef<str>> AsRef<Path> for InterfaceId<S> {
|
||||
fn as_ref(&self) -> &Path {
|
||||
self.0.as_ref().as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -331,6 +331,7 @@ pub async fn install_s9pk<R: AsyncRead + AsyncSeek + Unpin>(
|
||||
progress_model.put(&mut db, &progress).await?;
|
||||
|
||||
let mut tx = db.begin().await?;
|
||||
let mut sql_tx = ctx.secret_store.begin().await?;
|
||||
|
||||
let mut network = crate::db::DatabaseModel::new()
|
||||
.network()
|
||||
@@ -348,7 +349,10 @@ pub async fn install_s9pk<R: AsyncRead + AsyncSeek + Unpin>(
|
||||
log::info!("Install {}@{}: Installed main", pkg_id, version);
|
||||
|
||||
log::info!("Install {}@{}: Installing interfaces", pkg_id, version);
|
||||
let interface_info = manifest.interfaces.install(ip).await?;
|
||||
let interface_info = manifest
|
||||
.interfaces
|
||||
.install(&ctx, &mut sql_tx, pkg_id, ip)
|
||||
.await?;
|
||||
log::info!("Install {}@{}: Installed interfaces", pkg_id, version);
|
||||
|
||||
log::info!("Install {}@{}: Complete", pkg_id, version);
|
||||
@@ -461,6 +465,8 @@ pub async fn install_s9pk<R: AsyncRead + AsyncSeek + Unpin>(
|
||||
}
|
||||
}
|
||||
|
||||
ctx.tor_controller.sync(&mut tx, &mut sql_tx).await?;
|
||||
|
||||
tx.commit(None).await?;
|
||||
|
||||
Ok(())
|
||||
|
||||
114
appmgr/src/net/interface.rs
Normal file
114
appmgr/src/net/interface.rs
Normal file
@@ -0,0 +1,114 @@
|
||||
use std::net::Ipv4Addr;
|
||||
use std::path::Path;
|
||||
|
||||
use indexmap::IndexMap;
|
||||
use patch_db::DbHandle;
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
use sqlx::{Executor, Sqlite};
|
||||
use torut::onion::TorSecretKeyV3;
|
||||
|
||||
use crate::context::RpcContext;
|
||||
use crate::db::model::{InterfaceAddressMap, InterfaceAddresses, InterfaceInfo};
|
||||
use crate::id::Id;
|
||||
use crate::s9pk::manifest::PackageId;
|
||||
use crate::Error;
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub struct Interfaces(pub IndexMap<InterfaceId, Interface>); // TODO
|
||||
impl Interfaces {
|
||||
pub async fn install<Ex>(
|
||||
&self,
|
||||
ctx: &RpcContext,
|
||||
secrets: &mut Ex,
|
||||
package_id: &PackageId,
|
||||
ip: Ipv4Addr,
|
||||
) -> Result<InterfaceInfo, Error>
|
||||
where
|
||||
for<'a> &'a mut Ex: Executor<'a, Database = Sqlite>,
|
||||
{
|
||||
let mut interface_info = InterfaceInfo {
|
||||
ip,
|
||||
addresses: InterfaceAddressMap(IndexMap::new()),
|
||||
};
|
||||
for (id, iface) in &self.0 {
|
||||
let mut addrs = InterfaceAddresses {
|
||||
tor_address: None,
|
||||
lan_address: None,
|
||||
};
|
||||
if iface.tor_config.is_some() {
|
||||
let key = TorSecretKeyV3::generate();
|
||||
let key_vec = key.as_bytes().to_vec();
|
||||
sqlx::query!(
|
||||
"INSERT INTO tor (package, interface, key) VALUES (?, ?, ?)",
|
||||
**package_id,
|
||||
**id,
|
||||
key_vec,
|
||||
)
|
||||
.execute(&mut *secrets)
|
||||
.await?;
|
||||
addrs.tor_address = Some(key.public().get_onion_address().to_string());
|
||||
}
|
||||
interface_info.addresses.0.insert(id.clone(), addrs);
|
||||
}
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize)]
|
||||
pub struct InterfaceId<S: AsRef<str> = String>(Id<S>);
|
||||
impl<S: AsRef<str>> std::fmt::Display for InterfaceId<S> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", &self.0)
|
||||
}
|
||||
}
|
||||
impl<S: AsRef<str>> std::ops::Deref for InterfaceId<S> {
|
||||
type Target = S;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&*self.0
|
||||
}
|
||||
}
|
||||
impl<S: AsRef<str>> AsRef<str> for InterfaceId<S> {
|
||||
fn as_ref(&self) -> &str {
|
||||
self.0.as_ref()
|
||||
}
|
||||
}
|
||||
impl<'de, S> Deserialize<'de> for InterfaceId<S>
|
||||
where
|
||||
S: AsRef<str>,
|
||||
Id<S>: Deserialize<'de>,
|
||||
{
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
Ok(InterfaceId(Deserialize::deserialize(deserializer)?))
|
||||
}
|
||||
}
|
||||
impl<S: AsRef<str>> AsRef<Path> for InterfaceId<S> {
|
||||
fn as_ref(&self) -> &Path {
|
||||
self.0.as_ref().as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub struct Interface {
|
||||
pub tor_config: Option<TorConfig>,
|
||||
pub lan_config: Option<IndexMap<u16, LanPortConfig>>,
|
||||
pub ui: bool,
|
||||
pub protocols: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub struct TorConfig {
|
||||
pub port_mapping: IndexMap<u16, u16>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub struct LanPortConfig {
|
||||
pub ssl: bool,
|
||||
pub mapping: u16,
|
||||
}
|
||||
@@ -10,6 +10,7 @@ use crate::s9pk::manifest::PackageId;
|
||||
use crate::{Error, ResultExt};
|
||||
|
||||
pub mod host;
|
||||
pub mod interface;
|
||||
#[cfg(feature = "avahi")]
|
||||
pub mod mdns;
|
||||
pub mod tor;
|
||||
|
||||
@@ -6,14 +6,13 @@ use futures::future::BoxFuture;
|
||||
use futures::FutureExt;
|
||||
use indexmap::IndexMap;
|
||||
use patch_db::DbHandle;
|
||||
use sqlx::pool::PoolConnection;
|
||||
use sqlx::Sqlite;
|
||||
use sqlx::{Executor, Sqlite};
|
||||
use tokio::net::TcpStream;
|
||||
use tokio::sync::RwLock;
|
||||
use torut::control::{AsyncEvent, AuthenticatedConn, ConnError};
|
||||
use torut::onion::TorSecretKeyV3;
|
||||
|
||||
use crate::s9pk::manifest::TorConfig;
|
||||
use super::interface::TorConfig;
|
||||
use crate::{Error, ResultExt as _};
|
||||
|
||||
fn event_handler(event: AsyncEvent<'static>) -> BoxFuture<'static, Result<(), ConnError>> {
|
||||
@@ -23,21 +22,23 @@ fn event_handler(event: AsyncEvent<'static>) -> BoxFuture<'static, Result<(), Co
|
||||
#[derive(Clone)]
|
||||
pub struct TorController(Arc<RwLock<TorControllerInner>>);
|
||||
impl TorController {
|
||||
pub async fn init<Db: DbHandle>(
|
||||
pub async fn init<Db: DbHandle, Ex>(
|
||||
tor_cp: SocketAddr,
|
||||
db: &mut Db,
|
||||
secrets: &mut PoolConnection<Sqlite>,
|
||||
) -> Result<Self, Error> {
|
||||
secrets: &mut Ex,
|
||||
) -> Result<Self, Error>
|
||||
where
|
||||
for<'a> &'a mut Ex: Executor<'a, Database = Sqlite>,
|
||||
{
|
||||
Ok(TorController(Arc::new(RwLock::new(
|
||||
TorControllerInner::init(tor_cp, db, secrets).await?,
|
||||
))))
|
||||
}
|
||||
|
||||
pub async fn sync<Db: DbHandle>(
|
||||
&self,
|
||||
db: &mut Db,
|
||||
secrets: &mut PoolConnection<Sqlite>,
|
||||
) -> Result<(), Error> {
|
||||
pub async fn sync<Db: DbHandle, Ex>(&self, db: &mut Db, secrets: &mut Ex) -> Result<(), Error>
|
||||
where
|
||||
for<'a> &'a mut Ex: Executor<'a, Database = Sqlite>,
|
||||
{
|
||||
let new = TorControllerInner::get_services(db, secrets).await?;
|
||||
if &new != &self.0.read().await.services {
|
||||
self.0.write().await.sync(new).await?;
|
||||
@@ -62,10 +63,13 @@ pub struct TorControllerInner {
|
||||
services: IndexMap<[u8; 64], HiddenServiceConfig>,
|
||||
}
|
||||
impl TorControllerInner {
|
||||
async fn get_services<Db: DbHandle>(
|
||||
async fn get_services<Db: DbHandle, Ex>(
|
||||
db: &mut Db,
|
||||
secrets: &mut PoolConnection<Sqlite>,
|
||||
) -> Result<IndexMap<[u8; 64], HiddenServiceConfig>, Error> {
|
||||
secrets: &mut Ex,
|
||||
) -> Result<IndexMap<[u8; 64], HiddenServiceConfig>, Error>
|
||||
where
|
||||
for<'a> &'a mut Ex: Executor<'a, Database = Sqlite>,
|
||||
{
|
||||
let pkg_ids = crate::db::DatabaseModel::new()
|
||||
.package_data()
|
||||
.keys(db)
|
||||
@@ -189,11 +193,14 @@ impl TorControllerInner {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn init<Db: DbHandle>(
|
||||
async fn init<Db: DbHandle, Ex>(
|
||||
tor_cp: SocketAddr,
|
||||
db: &mut Db,
|
||||
secrets: &mut PoolConnection<Sqlite>,
|
||||
) -> Result<Self, Error> {
|
||||
secrets: &mut Ex,
|
||||
) -> Result<Self, Error>
|
||||
where
|
||||
for<'a> &'a mut Ex: Executor<'a, Database = Sqlite>,
|
||||
{
|
||||
let mut conn = torut::control::UnauthenticatedConn::new(
|
||||
TcpStream::connect(tor_cp).await?, // TODO
|
||||
);
|
||||
|
||||
@@ -14,9 +14,10 @@ use crate::backup::BackupActions;
|
||||
use crate::config::action::ConfigActions;
|
||||
use crate::db::model::InterfaceInfo;
|
||||
use crate::dependencies::Dependencies;
|
||||
use crate::id::{Id, InterfaceId, InvalidId, SYSTEM_ID};
|
||||
use crate::id::{Id, InvalidId, SYSTEM_ID};
|
||||
use crate::migration::Migrations;
|
||||
use crate::net::host::Hosts;
|
||||
use crate::net::interface::Interfaces;
|
||||
use crate::status::health_check::{HealthCheckResult, HealthChecks};
|
||||
use crate::util::Version;
|
||||
use crate::volume::Volumes;
|
||||
@@ -132,37 +133,6 @@ pub struct Manifest {
|
||||
pub dependencies: Dependencies,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub struct Interfaces(pub IndexMap<InterfaceId, Interface>); // TODO
|
||||
impl Interfaces {
|
||||
pub async fn install(&self, ip: Ipv4Addr) -> Result<InterfaceInfo, Error> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub struct Interface {
|
||||
pub tor_config: Option<TorConfig>,
|
||||
pub lan_config: Option<IndexMap<u16, LanPortConfig>>,
|
||||
pub ui: bool,
|
||||
pub protocols: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub struct TorConfig {
|
||||
pub port_mapping: IndexMap<u16, u16>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub struct LanPortConfig {
|
||||
pub ssl: bool,
|
||||
pub mapping: u16,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
|
||||
pub struct Assets {
|
||||
#[serde(default)]
|
||||
|
||||
@@ -18,8 +18,8 @@ use crate::db::model::{
|
||||
CurrentDependencyInfo, InstalledPackageDataEntryModel, PackageDataEntryModel,
|
||||
};
|
||||
use crate::dependencies::{Dependencies, DependencyError};
|
||||
use crate::id::InterfaceId;
|
||||
use crate::net::host::Hosts;
|
||||
use crate::net::interface::InterfaceId;
|
||||
use crate::s9pk::manifest::{Manifest, PackageId};
|
||||
use crate::status::health_check::HealthCheckResultVariant;
|
||||
use crate::util::Invoke;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::future::Future;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::Deref;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::path::Path;
|
||||
use std::process::{exit, Stdio};
|
||||
use std::str::FromStr;
|
||||
@@ -12,6 +12,7 @@ use async_trait::async_trait;
|
||||
use clap::ArgMatches;
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use serde_json::Value;
|
||||
use sqlx::{Executor, Sqlite};
|
||||
use tokio::fs::File;
|
||||
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt, ReadBuf};
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
@@ -6,7 +6,8 @@ use indexmap::IndexMap;
|
||||
use patch_db::{HasModel, Map, MapModel};
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
|
||||
use crate::id::{Id, IdUnchecked, InterfaceId};
|
||||
use crate::id::{Id, IdUnchecked};
|
||||
use crate::net::interface::InterfaceId;
|
||||
use crate::s9pk::manifest::PackageId;
|
||||
|
||||
pub mod disk;
|
||||
@@ -129,8 +130,6 @@ pub enum Volume {
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
Certificate { interface_id: InterfaceId },
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
HiddenService { interface_id: InterfaceId },
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
#[serde(skip)]
|
||||
Backup { readonly: bool },
|
||||
}
|
||||
@@ -155,10 +154,6 @@ impl Volume {
|
||||
.join(pkg_id)
|
||||
.join("certificates")
|
||||
.join(interface_id),
|
||||
Volume::HiddenService { interface_id } => Path::new(PKG_VOLUME_DIR)
|
||||
.join(pkg_id)
|
||||
.join("hidden-services")
|
||||
.join(interface_id),
|
||||
Volume::Backup { .. } => Path::new(BACKUP_DIR).join(pkg_id),
|
||||
}
|
||||
}
|
||||
@@ -181,7 +176,6 @@ impl Volume {
|
||||
Volume::Data { readonly } => *readonly,
|
||||
Volume::Pointer { readonly, .. } => *readonly,
|
||||
Volume::Certificate { .. } => true,
|
||||
Volume::HiddenService { .. } => true,
|
||||
Volume::Backup { readonly } => *readonly,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user