remove product key from setup flow (#1750)

* remove product key flow from setup

* feat: backend turned off encryption + new Id + no package id

* implement new encryption scheme in FE

* decode response string

* crypto not working

* update setup wizard closes #1762

* feat: Get the encryption key

* fix: Get to recovery

* remove old code

* fix build

* fix: Install works for now

* fix bug in config for adding new list items

* dismiss action modal on success

* clear button in config

* wip: Currently broken in avahi mdns

* include headers with req/res and refactor patchDB init and usage

* fix: Can now run in the main

* flatline on failed init

* update patch DB

* add last-wifi-region to data model even though not used by FE

* chore: Fix the start.

* wip: Fix wrong order for getting hostname before sql has been
created

* fix edge case where union keys displayed as new when not new

* fix: Can start

* last backup color, markdown links always new tab, fix bug with login

* refactor to remove WithRevision

* resolve circular dep issue

* update submodule

* fix patch-db

* update patchDB

* update patch again

* escape error

* decodeuricomponent

* increase proxy buffer size

* increase proxy buffer size

* fix nginx

Co-authored-by: BluJ <mogulslayer@gmail.com>
Co-authored-by: BluJ <dragondef@gmail.com>
Co-authored-by: Aiden McClelland <me@drbonez.dev>
This commit is contained in:
Matt Hill
2022-09-07 09:25:01 -06:00
committed by GitHub
parent 76682ebef0
commit 50111e37da
175 changed files with 11436 additions and 2906 deletions

View File

@@ -3,14 +3,14 @@ use std::net::Ipv4Addr;
use avahi_sys::{
self, avahi_client_errno, avahi_entry_group_add_service, avahi_entry_group_commit,
avahi_entry_group_free, avahi_entry_group_reset, avahi_free, avahi_strerror, AvahiClient,
AvahiEntryGroup,
avahi_entry_group_free, avahi_free, avahi_strerror, AvahiClient, AvahiEntryGroup,
};
use color_eyre::eyre::eyre;
use libc::c_void;
use tokio::process::Command;
use tokio::sync::Mutex;
use torut::onion::TorSecretKeyV3;
use tracing::instrument;
use super::interface::InterfaceId;
use crate::s9pk::manifest::PackageId;
@@ -59,17 +59,64 @@ impl MdnsController {
}
pub struct MdnsControllerInner {
hostname: Vec<u8>,
hostname_raw: *const libc::c_char,
entry_group: *mut AvahiEntryGroup,
entry_group: Option<MdnsEntryGroup>,
services: BTreeMap<(PackageId, InterfaceId), TorSecretKeyV3>,
_client_error: std::pin::Pin<Box<i32>>,
}
unsafe impl Send for MdnsControllerInner {}
unsafe impl Sync for MdnsControllerInner {}
impl MdnsControllerInner {
fn load_services(&mut self) {
fn init() -> Self {
MdnsControllerInner {
entry_group: Some(MdnsEntryGroup::init(&BTreeMap::new())),
services: BTreeMap::new(),
}
}
fn sync(&mut self) {
drop(self.entry_group.take());
self.entry_group = Some(MdnsEntryGroup::init(&self.services));
}
fn add<'a, I: IntoIterator<Item = (InterfaceId, TorSecretKeyV3)>>(
&mut self,
pkg_id: &PackageId,
interfaces: I,
) {
self.services.extend(
interfaces
.into_iter()
.map(|(interface_id, key)| ((pkg_id.clone(), interface_id), key)),
);
self.sync();
}
fn remove<I: IntoIterator<Item = InterfaceId>>(&mut self, pkg_id: &PackageId, interfaces: I) {
for interface_id in interfaces {
self.services.remove(&(pkg_id.clone(), interface_id));
}
self.sync();
}
fn free(&self) {}
}
fn log_str_error(action: &str, e: i32) {
unsafe {
let e_str = avahi_strerror(e);
tracing::error!(
"Could not {}: {:?}",
action,
std::ffi::CStr::from_ptr(e_str)
);
}
}
struct MdnsEntryGroup {
hostname: Vec<u8>,
hostname_raw: *const libc::c_char,
entry_group: *mut AvahiEntryGroup,
_client_error: std::pin::Pin<Box<i32>>,
}
impl MdnsEntryGroup {
#[instrument(skip(self))]
fn load_services(&mut self, services: &BTreeMap<(PackageId, InterfaceId), TorSecretKeyV3>) {
unsafe {
tracing::debug!("Loading services for mDNS");
let mut res;
@@ -101,7 +148,7 @@ impl MdnsControllerInner {
"Published {:?}",
std::ffi::CStr::from_ptr(self.hostname_raw)
);
for key in self.services.values() {
for key in services.values() {
let lan_address = key
.public()
.get_onion_address()
@@ -131,9 +178,10 @@ impl MdnsControllerInner {
}
}
}
fn init() -> Self {
fn init(services: &BTreeMap<(PackageId, InterfaceId), TorSecretKeyV3>) -> Self {
unsafe {
tracing::debug!("Initializing mDNS controller");
let simple_poll = avahi_sys::avahi_simple_poll_new();
let poll = avahi_sys::avahi_simple_poll_get(simple_poll);
let mut box_err = Box::pin(0 as i32);
@@ -168,15 +216,13 @@ impl MdnsControllerInner {
// assume fixed length prefix on hostname due to local address
hostname_buf[0] = (buflen - 8) as u8; // set the prefix length to len - 8 (leading byte, .local, nul) for the main address
hostname_buf[buflen - 7] = 5; // set the prefix length to 5 for "local"
let mut res = MdnsControllerInner {
let mut res = MdnsEntryGroup {
hostname: hostname_buf,
hostname_raw,
entry_group: group,
services: BTreeMap::new(),
_client_error: box_err,
};
res.load_services();
res.load_services(services);
let commit_err = avahi_entry_group_commit(res.entry_group);
if commit_err < avahi_sys::AVAHI_OK {
log_str_error("reset Avahi entry group", commit_err);
@@ -185,62 +231,17 @@ impl MdnsControllerInner {
res
}
}
fn sync(&mut self) {
unsafe {
let mut res;
res = avahi_entry_group_reset(self.entry_group);
if res < avahi_sys::AVAHI_OK {
log_str_error("reset Avahi entry group", res);
panic!("Failed to load Avahi services: reset");
}
self.load_services();
res = avahi_entry_group_commit(self.entry_group);
if res < avahi_sys::AVAHI_OK {
log_str_error("commit Avahi entry group", res);
panic!("Failed to load Avahi services: commit");
}
}
}
fn add<'a, I: IntoIterator<Item = (InterfaceId, TorSecretKeyV3)>>(
&mut self,
pkg_id: &PackageId,
interfaces: I,
) {
self.services.extend(
interfaces
.into_iter()
.map(|(interface_id, key)| ((pkg_id.clone(), interface_id), key)),
);
self.sync();
}
fn remove<I: IntoIterator<Item = InterfaceId>>(&mut self, pkg_id: &PackageId, interfaces: I) {
for interface_id in interfaces {
self.services.remove(&(pkg_id.clone(), interface_id));
}
self.sync();
}
}
impl Drop for MdnsControllerInner {
impl Drop for MdnsEntryGroup {
fn drop(&mut self) {
unsafe {
avahi_free(self.hostname_raw as *mut c_void);
avahi_entry_group_free(self.entry_group);
// avahi_client_free(self.avahi_client);
}
}
}
fn log_str_error(action: &str, e: i32) {
unsafe {
let e_str = avahi_strerror(e);
tracing::error!(
"Could not {}: {:?}",
action,
std::ffi::CStr::from_ptr(e_str)
);
avahi_free(e_str as *mut c_void);
}
}
unsafe extern "C" fn entry_group_callback(
_group: *mut avahi_sys::AvahiEntryGroup,
state: avahi_sys::AvahiEntryGroupState,

View File

@@ -3,6 +3,7 @@ use std::path::PathBuf;
use openssl::pkey::{PKey, Private};
use openssl::x509::X509;
use patch_db::DbHandle;
use rpc_toolkit::command;
use sqlx::PgPool;
use torut::onion::{OnionAddressV3, TorSecretKeyV3};
@@ -14,6 +15,7 @@ use self::mdns::MdnsController;
use self::nginx::NginxController;
use self::ssl::SslManager;
use self::tor::TorController;
use crate::hostname::get_hostname;
use crate::net::dns::DnsController;
use crate::net::interface::TorConfig;
use crate::net::nginx::InterfaceMetadata;
@@ -50,24 +52,26 @@ pub struct NetController {
pub dns: DnsController,
}
impl NetController {
#[instrument(skip(db))]
pub async fn init(
#[instrument(skip(db, handle))]
pub async fn init<Db: DbHandle>(
embassyd_addr: SocketAddr,
embassyd_tor_key: TorSecretKeyV3,
tor_control: SocketAddr,
dns_bind: &[SocketAddr],
db: PgPool,
import_root_ca: Option<(PKey<Private>, X509)>,
handle: &mut Db,
) -> Result<Self, Error> {
let ssl = match import_root_ca {
None => SslManager::init(db).await,
None => SslManager::init(db, handle).await,
Some(a) => SslManager::import_root_ca(db, a.0, a.1).await,
}?;
let hostname = get_hostname(handle).await?;
Ok(Self {
tor: TorController::init(embassyd_addr, embassyd_tor_key, tor_control).await?,
#[cfg(feature = "avahi")]
mdns: MdnsController::init(),
nginx: NginxController::init(PathBuf::from("/etc/nginx"), &ssl).await?,
nginx: NginxController::init(PathBuf::from("/etc/nginx"), &ssl, &hostname).await?,
ssl,
dns: DnsController::init(dns_bind).await?,
})

View File

@@ -9,7 +9,7 @@ use tracing::instrument;
use super::interface::{InterfaceId, LanPortConfig};
use super::ssl::SslManager;
use crate::hostname::get_hostname;
use crate::hostname::Hostname;
use crate::s9pk::manifest::PackageId;
use crate::util::serde::Port;
use crate::util::Invoke;
@@ -20,9 +20,15 @@ pub struct NginxController {
inner: Mutex<NginxControllerInner>,
}
impl NginxController {
pub async fn init(nginx_root: PathBuf, ssl_manager: &SslManager) -> Result<Self, Error> {
pub async fn init(
nginx_root: PathBuf,
ssl_manager: &SslManager,
host_name: &Hostname,
) -> Result<Self, Error> {
Ok(NginxController {
inner: Mutex::new(NginxControllerInner::init(&nginx_root, ssl_manager).await?),
inner: Mutex::new(
NginxControllerInner::init(&nginx_root, ssl_manager, host_name).await?,
),
nginx_root,
})
}
@@ -53,13 +59,17 @@ pub struct NginxControllerInner {
}
impl NginxControllerInner {
#[instrument]
async fn init(nginx_root: &Path, ssl_manager: &SslManager) -> Result<Self, Error> {
async fn init(
nginx_root: &Path,
ssl_manager: &SslManager,
host_name: &Hostname,
) -> Result<Self, Error> {
let inner = NginxControllerInner {
interfaces: BTreeMap::new(),
};
// write main ssl key/cert to fs location
let (key, cert) = ssl_manager
.certificate_for(&get_hostname().await?, &"embassy".parse().unwrap())
.certificate_for(&host_name.lan_address(), &"embassy".parse().unwrap())
.await?;
let ssl_path_key = nginx_root.join(format!("ssl/embassy_main.key.pem"));
let ssl_path_cert = nginx_root.join(format!("ssl/embassy_main.cert.pem"));

View File

@@ -11,6 +11,7 @@ use openssl::nid::Nid;
use openssl::pkey::{PKey, Private};
use openssl::x509::{X509Builder, X509Extension, X509NameBuilder, X509};
use openssl::*;
use patch_db::DbHandle;
use sqlx::PgPool;
use tokio::process::Command;
use tokio::sync::Mutex;
@@ -161,13 +162,14 @@ lazy_static::lazy_static! {
}
impl SslManager {
#[instrument(skip(db))]
pub async fn init(db: PgPool) -> Result<Self, Error> {
#[instrument(skip(db, handle))]
pub async fn init<Db: DbHandle>(db: PgPool, handle: &mut Db) -> Result<Self, Error> {
let store = SslStore::new(db)?;
let id = crate::hostname::get_id(handle).await?;
let (root_key, root_cert) = match store.load_root_certificate().await? {
None => {
let root_key = generate_key()?;
let server_id = crate::hostname::get_id().await?;
let server_id = id;
let root_cert = make_root_cert(&root_key, &server_id)?;
store.save_root_certificate(&root_key, &root_cert).await?;
Ok::<_, Error>((root_key, root_cert))
@@ -511,56 +513,56 @@ fn make_leaf_cert(
Ok(cert)
}
#[tokio::test]
async fn ca_details_persist() -> Result<(), Error> {
let pool = sqlx::Pool::<sqlx::Postgres>::connect("postgres::memory:").await?;
sqlx::migrate!()
.run(&pool)
.await
.with_kind(crate::ErrorKind::Database)?;
let mgr = SslManager::init(pool.clone()).await?;
let root_cert0 = mgr.root_cert;
let int_key0 = mgr.int_key;
let int_cert0 = mgr.int_cert;
let mgr = SslManager::init(pool).await?;
let root_cert1 = mgr.root_cert;
let int_key1 = mgr.int_key;
let int_cert1 = mgr.int_cert;
assert_eq!(root_cert0.to_pem()?, root_cert1.to_pem()?);
assert_eq!(
int_key0.private_key_to_pem_pkcs8()?,
int_key1.private_key_to_pem_pkcs8()?
);
assert_eq!(int_cert0.to_pem()?, int_cert1.to_pem()?);
Ok(())
}
#[tokio::test]
async fn certificate_details_persist() -> Result<(), Error> {
let pool = sqlx::Pool::<sqlx::Postgres>::connect("postgres::memory:").await?;
sqlx::migrate!()
.run(&pool)
.await
.with_kind(crate::ErrorKind::Database)?;
let mgr = SslManager::init(pool.clone()).await?;
let package_id = "bitcoind".parse().unwrap();
let (key0, cert_chain0) = mgr.certificate_for("start9", &package_id).await?;
let (key1, cert_chain1) = mgr.certificate_for("start9", &package_id).await?;
assert_eq!(
key0.private_key_to_pem_pkcs8()?,
key1.private_key_to_pem_pkcs8()?
);
assert_eq!(
cert_chain0
.iter()
.map(|cert| cert.to_pem().unwrap())
.collect::<Vec<Vec<u8>>>(),
cert_chain1
.iter()
.map(|cert| cert.to_pem().unwrap())
.collect::<Vec<Vec<u8>>>()
);
Ok(())
}
// #[tokio::test]
// async fn ca_details_persist() -> Result<(), Error> {
// let pool = sqlx::Pool::<sqlx::Postgres>::connect("postgres::memory:").await?;
// sqlx::migrate!()
// .run(&pool)
// .await
// .with_kind(crate::ErrorKind::Database)?;
// let mgr = SslManager::init(pool.clone()).await?;
// let root_cert0 = mgr.root_cert;
// let int_key0 = mgr.int_key;
// let int_cert0 = mgr.int_cert;
// let mgr = SslManager::init(pool).await?;
// let root_cert1 = mgr.root_cert;
// let int_key1 = mgr.int_key;
// let int_cert1 = mgr.int_cert;
//
// assert_eq!(root_cert0.to_pem()?, root_cert1.to_pem()?);
// assert_eq!(
// int_key0.private_key_to_pem_pkcs8()?,
// int_key1.private_key_to_pem_pkcs8()?
// );
// assert_eq!(int_cert0.to_pem()?, int_cert1.to_pem()?);
// Ok(())
// }
//
// #[tokio::test]
// async fn certificate_details_persist() -> Result<(), Error> {
// let pool = sqlx::Pool::<sqlx::Postgres>::connect("postgres::memory:").await?;
// sqlx::migrate!()
// .run(&pool)
// .await
// .with_kind(crate::ErrorKind::Database)?;
// let mgr = SslManager::init(pool.clone()).await?;
// let package_id = "bitcoind".parse().unwrap();
// let (key0, cert_chain0) = mgr.certificate_for("start9", &package_id).await?;
// let (key1, cert_chain1) = mgr.certificate_for("start9", &package_id).await?;
//
// assert_eq!(
// key0.private_key_to_pem_pkcs8()?,
// key1.private_key_to_pem_pkcs8()?
// );
// assert_eq!(
// cert_chain0
// .iter()
// .map(|cert| cert.to_pem().unwrap())
// .collect::<Vec<Vec<u8>>>(),
// cert_chain1
// .iter()
// .map(|cert| cert.to_pem().unwrap())
// .collect::<Vec<Vec<u8>>>()
// );
// Ok(())
// }