2023-03-29 22:44:46 +00:00
|
|
|
use std::fs;
|
2023-03-23 17:17:37 +00:00
|
|
|
use std::sync::mpsc::{Receiver, TryRecvError};
|
2023-03-28 16:16:00 +00:00
|
|
|
use base64::Engine;
|
|
|
|
use chrono::Local;
|
|
|
|
use log::{error, info, warn};
|
|
|
|
use url::Url;
|
2023-03-29 22:44:46 +00:00
|
|
|
use dnapi_rs::client_blocking::Client;
|
2023-03-28 16:16:00 +00:00
|
|
|
use trifid_pki::cert::{serialize_ed25519_public, serialize_x25519_public};
|
2023-03-27 16:32:26 +00:00
|
|
|
use trifid_pki::ed25519_dalek::{SecretKey, SigningKey};
|
|
|
|
use trifid_pki::rand_core::OsRng;
|
|
|
|
use trifid_pki::x25519_dalek::StaticSecret;
|
|
|
|
use crate::config::{load_cdata, save_cdata, TFClientConfig};
|
2023-03-22 18:34:06 +00:00
|
|
|
use crate::daemon::ThreadMessageSender;
|
2023-03-29 22:44:46 +00:00
|
|
|
use crate::dirs::get_nebulaconfig_file;
|
2023-03-29 22:52:15 +00:00
|
|
|
use crate::nebulaworker::NebulaWorkerMessage;
|
2023-03-22 18:34:06 +00:00
|
|
|
|
|
|
|
pub enum APIWorkerMessage {
|
2023-03-28 16:16:00 +00:00
|
|
|
Shutdown,
|
2023-03-29 13:37:03 +00:00
|
|
|
Enroll { code: String },
|
|
|
|
Timer
|
2023-03-22 18:34:06 +00:00
|
|
|
}
|
|
|
|
|
2023-03-29 22:52:15 +00:00
|
|
|
pub fn apiworker_main(config: TFClientConfig, instance: String, url: String, tx: ThreadMessageSender, rx: Receiver<APIWorkerMessage>) {
|
2023-03-28 16:16:00 +00:00
|
|
|
let server = Url::parse(&url).unwrap();
|
|
|
|
|
2023-03-29 22:44:46 +00:00
|
|
|
let client = Client::new(format!("tfclient/{}", env!("CARGO_PKG_VERSION")), server).unwrap();
|
|
|
|
|
2023-03-23 17:17:37 +00:00
|
|
|
loop {
|
|
|
|
match rx.try_recv() {
|
|
|
|
Ok(msg) => {
|
|
|
|
match msg {
|
|
|
|
APIWorkerMessage::Shutdown => {
|
|
|
|
info!("recv on command socket: shutdown, stopping");
|
|
|
|
break;
|
2023-03-28 16:16:00 +00:00
|
|
|
},
|
2023-03-29 13:37:03 +00:00
|
|
|
APIWorkerMessage::Timer => {
|
|
|
|
info!("updating config");
|
|
|
|
let mut cdata = match load_cdata(&instance) {
|
|
|
|
Ok(c) => c,
|
|
|
|
Err(e) => {
|
|
|
|
error!("error in api worker thread: {}", e);
|
|
|
|
error!("APIWorker exiting with error");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
};
|
2023-03-29 22:44:46 +00:00
|
|
|
if cdata.creds.is_none() {
|
2023-03-29 13:37:03 +00:00
|
|
|
info!("not enrolled, cannot perform config update");
|
2023-03-29 22:52:15 +00:00
|
|
|
match save_cdata(&instance, cdata) {
|
|
|
|
Ok(_) => (),
|
|
|
|
Err(e) => {
|
|
|
|
error!("Error saving cdata: {}", e);
|
|
|
|
error!("APIWorker exiting with error");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2023-03-29 13:37:03 +00:00
|
|
|
continue;
|
|
|
|
}
|
2023-03-29 22:52:15 +00:00
|
|
|
let creds = cdata.clone().creds.unwrap_or_else(|| unreachable!());
|
|
|
|
|
|
|
|
info!("checking for update");
|
|
|
|
let update_available = match client.check_for_update(&creds) {
|
|
|
|
Ok(ua) => ua,
|
|
|
|
Err(e) => {
|
|
|
|
error!("error checking for config update: {}", e);
|
|
|
|
match save_cdata(&instance, cdata) {
|
|
|
|
Ok(_) => (),
|
|
|
|
Err(e) => {
|
|
|
|
error!("Error saving cdata: {}", e);
|
|
|
|
error!("APIWorker exiting with error");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
if !update_available {
|
|
|
|
match save_cdata(&instance, cdata) {
|
|
|
|
Ok(_) => (),
|
|
|
|
Err(e) => {
|
|
|
|
error!("Error saving cdata: {}", e);
|
|
|
|
error!("APIWorker exiting with error");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
info!("no config update available");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
info!("updated configuration is avaliable");
|
|
|
|
info!("updating configuration");
|
|
|
|
|
|
|
|
let (config, dh_privkey, creds) = match client.do_update(&creds) {
|
|
|
|
Ok(d) => d,
|
|
|
|
Err(e) => {
|
|
|
|
error!("error requesting updating config: {}", e);
|
|
|
|
match save_cdata(&instance, cdata) {
|
|
|
|
Ok(_) => (),
|
|
|
|
Err(e) => {
|
|
|
|
error!("Error saving cdata: {}", e);
|
|
|
|
error!("APIWorker exiting with error");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
cdata.creds = Some(creds);
|
|
|
|
cdata.dh_privkey = Some(dh_privkey.try_into().expect("32 != 32"));
|
|
|
|
|
|
|
|
match fs::write(get_nebulaconfig_file(&instance).expect("Unable to determine nebula config file location"), config) {
|
|
|
|
Ok(_) => (),
|
|
|
|
Err(e) => {
|
|
|
|
error!("unable to save nebula config: {}", e);
|
|
|
|
match save_cdata(&instance, cdata) {
|
|
|
|
Ok(_) => (),
|
|
|
|
Err(e) => {
|
|
|
|
error!("Error saving cdata: {}", e);
|
|
|
|
error!("APIWorker exiting with error");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2023-03-29 13:37:03 +00:00
|
|
|
|
2023-03-29 22:52:15 +00:00
|
|
|
match save_cdata(&instance, cdata) {
|
|
|
|
Ok(_) => (),
|
|
|
|
Err(e) => {
|
|
|
|
error!("Error saving cdata: {}", e);
|
|
|
|
error!("APIWorker exiting with error");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
info!("configuration updated successfully!");
|
|
|
|
info!("sending signal to nebula thread to reload config");
|
|
|
|
|
|
|
|
match tx.nebula_thread.send(NebulaWorkerMessage::ConfigUpdated) {
|
|
|
|
Ok(_) => (),
|
|
|
|
Err(e) => {
|
|
|
|
error!("unable to tell nebula thread to update config: {}", e);
|
|
|
|
error!("APIWorker exiting with error");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2023-03-29 13:37:03 +00:00
|
|
|
},
|
2023-03-28 16:16:00 +00:00
|
|
|
APIWorkerMessage::Enroll { code } => {
|
|
|
|
info!("recv on command socket: enroll {}", code);
|
|
|
|
let mut cdata = match load_cdata(&instance) {
|
|
|
|
Ok(c) => c,
|
|
|
|
Err(e) => {
|
|
|
|
error!("error in api worker thread: {}", e);
|
|
|
|
error!("APIWorker exiting with error");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
};
|
2023-03-29 22:44:46 +00:00
|
|
|
if cdata.creds.is_some() {
|
2023-03-28 16:16:00 +00:00
|
|
|
warn!("enrollment failed: already enrolled");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2023-03-29 22:44:46 +00:00
|
|
|
let (config, dh_privkey, creds, meta) = match client.enroll(&code) {
|
|
|
|
Ok(resp) => resp,
|
2023-03-28 17:10:11 +00:00
|
|
|
Err(e) => {
|
2023-03-29 22:44:46 +00:00
|
|
|
error!("error with enrollment request: {}", e);
|
2023-03-28 17:10:11 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2023-03-29 22:44:46 +00:00
|
|
|
match fs::write(get_nebulaconfig_file(&instance).expect("Unable to determine nebula config file location"), config) {
|
|
|
|
Ok(_) => (),
|
2023-03-28 17:10:11 +00:00
|
|
|
Err(e) => {
|
2023-03-29 22:44:46 +00:00
|
|
|
error!("unable to save nebula config: {}", e);
|
2023-03-28 17:10:11 +00:00
|
|
|
continue;
|
|
|
|
}
|
2023-03-29 22:44:46 +00:00
|
|
|
}
|
2023-03-28 17:10:11 +00:00
|
|
|
|
2023-03-29 22:44:46 +00:00
|
|
|
cdata.creds = Some(creds);
|
|
|
|
cdata.dh_privkey = Some(dh_privkey.try_into().expect("32 != 32"));
|
|
|
|
cdata.meta = Some(meta);
|
2023-03-28 16:16:00 +00:00
|
|
|
|
|
|
|
// Save vardata
|
|
|
|
match save_cdata(&instance, cdata) {
|
|
|
|
Ok(_) => (),
|
|
|
|
Err(e) => {
|
|
|
|
error!("Error saving cdata: {}", e);
|
|
|
|
error!("APIWorker exiting with error");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2023-03-29 22:44:46 +00:00
|
|
|
|
|
|
|
info!("Configuration updated. Sending signal to Nebula worker thread");
|
2023-03-29 22:52:15 +00:00
|
|
|
|
|
|
|
match tx.nebula_thread.send(NebulaWorkerMessage::ConfigUpdated) {
|
|
|
|
Ok(_) => (),
|
|
|
|
Err(e) => {
|
|
|
|
error!("unable to tell nebula thread to update config: {}", e);
|
|
|
|
error!("APIWorker exiting with error");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2023-03-23 17:17:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
Err(e) => {
|
|
|
|
match e {
|
|
|
|
TryRecvError::Empty => {}
|
|
|
|
TryRecvError::Disconnected => {
|
|
|
|
error!("apiworker command socket disconnected, shutting down to prevent orphaning");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-03-22 18:34:06 +00:00
|
|
|
}
|