rename u_panel server -> gui, use doh to resolve u_server addr

master
plazmoid 2 years ago
parent 699896f335
commit 7eb15b33be
  1. 2
      Makefile.toml
  2. 3
      bin/u_agent/Cargo.toml
  3. 35
      bin/u_agent/src/lib.rs
  4. 2
      bin/u_panel/src/argparse.rs
  5. 0
      bin/u_panel/src/gui/error.rs
  6. 16
      bin/u_panel/src/gui/fe/.browserslistrc
  7. 16
      bin/u_panel/src/gui/fe/.editorconfig
  8. 0
      bin/u_panel/src/gui/fe/.gitignore
  9. 0
      bin/u_panel/src/gui/fe/README.md
  10. 0
      bin/u_panel/src/gui/fe/angular.json
  11. 0
      bin/u_panel/src/gui/fe/karma.conf.js
  12. 0
      bin/u_panel/src/gui/fe/package.json
  13. 0
      bin/u_panel/src/gui/fe/src/app/app-routing.module.ts
  14. 0
      bin/u_panel/src/gui/fe/src/app/app.component.html
  15. 0
      bin/u_panel/src/gui/fe/src/app/app.component.less
  16. 0
      bin/u_panel/src/gui/fe/src/app/app.component.spec.ts
  17. 0
      bin/u_panel/src/gui/fe/src/app/app.component.ts
  18. 0
      bin/u_panel/src/gui/fe/src/app/app.module.ts
  19. 0
      bin/u_panel/src/gui/fe/src/app/core/index.ts
  20. 0
      bin/u_panel/src/gui/fe/src/app/core/models/agent.model.ts
  21. 0
      bin/u_panel/src/gui/fe/src/app/core/models/index.ts
  22. 0
      bin/u_panel/src/gui/fe/src/app/core/models/job.model.ts
  23. 0
      bin/u_panel/src/gui/fe/src/app/core/models/result.model.ts
  24. 0
      bin/u_panel/src/gui/fe/src/app/core/services/api.service.ts
  25. 0
      bin/u_panel/src/gui/fe/src/app/core/services/index.ts
  26. 0
      bin/u_panel/src/gui/fe/src/app/core/tables/agent.component.html
  27. 0
      bin/u_panel/src/gui/fe/src/app/core/tables/agent.component.ts
  28. 0
      bin/u_panel/src/gui/fe/src/app/core/tables/dialogs/agent-info-dialog.html
  29. 0
      bin/u_panel/src/gui/fe/src/app/core/tables/dialogs/agent_info.component.ts
  30. 0
      bin/u_panel/src/gui/fe/src/app/core/tables/dialogs/assign-job-dialog.html
  31. 0
      bin/u_panel/src/gui/fe/src/app/core/tables/dialogs/assign_job.component.ts
  32. 0
      bin/u_panel/src/gui/fe/src/app/core/tables/dialogs/index.ts
  33. 0
      bin/u_panel/src/gui/fe/src/app/core/tables/dialogs/info-dialog.component.less
  34. 0
      bin/u_panel/src/gui/fe/src/app/core/tables/dialogs/job-info-dialog.html
  35. 0
      bin/u_panel/src/gui/fe/src/app/core/tables/dialogs/job_info.component.ts
  36. 0
      bin/u_panel/src/gui/fe/src/app/core/tables/dialogs/result-info-dialog.html
  37. 0
      bin/u_panel/src/gui/fe/src/app/core/tables/dialogs/result_info.component.ts
  38. 0
      bin/u_panel/src/gui/fe/src/app/core/tables/index.ts
  39. 0
      bin/u_panel/src/gui/fe/src/app/core/tables/job.component.html
  40. 0
      bin/u_panel/src/gui/fe/src/app/core/tables/job.component.ts
  41. 0
      bin/u_panel/src/gui/fe/src/app/core/tables/result.component.html
  42. 0
      bin/u_panel/src/gui/fe/src/app/core/tables/result.component.ts
  43. 0
      bin/u_panel/src/gui/fe/src/app/core/tables/table.component.less
  44. 0
      bin/u_panel/src/gui/fe/src/app/core/tables/table.component.ts
  45. 0
      bin/u_panel/src/gui/fe/src/app/core/utils.ts
  46. 0
      bin/u_panel/src/gui/fe/src/environments/environment.prod.ts
  47. 0
      bin/u_panel/src/gui/fe/src/environments/environment.ts
  48. 0
      bin/u_panel/src/gui/fe/src/favicon.ico
  49. 0
      bin/u_panel/src/gui/fe/src/index.html
  50. 0
      bin/u_panel/src/gui/fe/src/main.ts
  51. 0
      bin/u_panel/src/gui/fe/src/polyfills.ts
  52. 0
      bin/u_panel/src/gui/fe/src/styles.less
  53. 0
      bin/u_panel/src/gui/fe/src/test.ts
  54. 0
      bin/u_panel/src/gui/fe/tsconfig.app.json
  55. 0
      bin/u_panel/src/gui/fe/tsconfig.json
  56. 0
      bin/u_panel/src/gui/fe/tsconfig.spec.json
  57. 2
      bin/u_panel/src/gui/mod.rs
  58. 4
      bin/u_panel/src/main.rs
  59. 3
      bin/u_server/src/handlers.rs
  60. 17
      bin/u_server/src/u_server.rs
  61. 1
      deploy/podman-compose.yml
  62. 1
      integration/docker-compose.yml
  63. 4
      integration/tests/fixtures/agent.rs
  64. 5
      integration/tests/helpers/panel.rs
  65. 40
      integration/tests/integration/behaviour.rs
  66. 2
      integration/tests/integration/connection.rs
  67. 9
      lib/u_lib/Cargo.toml
  68. 58
      lib/u_lib/src/api.rs
  69. 2
      lib/u_lib/src/combined_result.rs
  70. 0
      lib/u_lib/src/conv.rs
  71. 0
      lib/u_lib/src/error/chan.rs
  72. 0
      lib/u_lib/src/error/mod.rs
  73. 16
      lib/u_lib/src/lib.rs
  74. 2
      lib/u_lib/src/messaging/base.rs
  75. 0
      lib/u_lib/src/misc.rs
  76. 23
      lib/u_lib/src/models/agent.rs
  77. 2
      lib/u_lib/src/models/jobs/meta.rs
  78. 1
      lib/u_lib/src/models/jobs/misc.rs
  79. 0
      lib/u_lib/src/platform.rs
  80. 2
      lib/u_lib/src/proc_output.rs
  81. 8
      lib/u_lib/src/runner.rs
  82. 0
      lib/u_lib/src/storage.rs
  83. 4
      lib/u_lib/src/tempfile.rs
  84. 7
      lib/u_lib/src/unix.rs
  85. 20
      lib/u_lib/src/utils/mod.rs
  86. 40
      lib/u_lib/src/utils/vec_display.rs
  87. 2
      migrations/2020-10-24-111622_create_all/up.sql
  88. 2
      scripts/deploy.sh
  89. 2
      spec.txt

@ -35,7 +35,7 @@ script = "./scripts/build_musl_libs.sh"
[tasks.build_frontend] [tasks.build_frontend]
script = ''' script = '''
cd ./bin/u_panel/src/server/fe cd ./bin/u_panel/src/gui/fe
ng build ng build
''' '''

@ -7,8 +7,7 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
daemonize = "0.4.1" log = { version = "0.4", features = ["release_max_level_off"] }
log = "^0.4"
reqwest = { workspace = true } reqwest = { workspace = true }
sysinfo = "0.10.5" sysinfo = "0.10.5"
tokio = { workspace = true, features = ["macros", "rt-multi-thread", "process", "time"] } tokio = { workspace = true, features = ["macros", "rt-multi-thread", "process", "time"] }

@ -5,14 +5,18 @@
#[macro_use] #[macro_use]
extern crate log; extern crate log;
use daemonize::Daemonize; use std::process::exit;
use std::sync::Arc;
use tokio::runtime::Builder; use tokio::runtime::Builder;
use tokio::time::{sleep, Duration}; use tokio::time::{sleep, Duration};
use u_lib::config;
use u_lib::{ use u_lib::{
api::ClientHandler, cache::JobCache, config::get_self_uid, errors::ErrChan, api::ClientHandler,
executor::pop_completed, logging::init_logger, messaging::Reportable, models::AssignedJobById, cache::JobCache,
config::{endpoints, get_self_uid},
error::ErrChan,
executor::pop_completed,
logging::init_logger,
messaging::Reportable,
models::AssignedJobById,
runner::JobRunner, runner::JobRunner,
}; };
@ -53,7 +57,7 @@ pub async fn process_request(jobs: Vec<AssignedJobById>, client: &ClientHandler)
} }
} }
async fn error_reporting(client: Arc<ClientHandler>) -> ! { async fn error_reporting(client: ClientHandler) -> ! {
loop { loop {
match ErrChan::recv().await { match ErrChan::recv().await {
Some(err) => { Some(err) => {
@ -72,7 +76,7 @@ async fn error_reporting(client: Arc<ClientHandler>) -> ! {
} }
} }
async fn agent_loop(client: Arc<ClientHandler>) -> ! { async fn agent_loop(client: ClientHandler) -> ! {
loop { loop {
match client.get_personal_jobs(get_self_uid()).await { match client.get_personal_jobs(get_self_uid()).await {
Ok(jobs) => { Ok(jobs) => {
@ -97,9 +101,8 @@ async fn agent_loop(client: Arc<ClientHandler>) -> ! {
} }
} }
pub fn run_forever() { pub fn run_forever() -> ! {
let env = config::endpoints::load().unwrap(); let env = endpoints::load().unwrap();
let client = Arc::new(ClientHandler::new(&env.u_server, None));
if cfg!(debug_assertions) { if cfg!(debug_assertions) {
init_logger(Some(format!( init_logger(Some(format!(
@ -112,8 +115,10 @@ pub fn run_forever() {
.unwrap() .unwrap()
))); )));
} else { } else {
Daemonize::new().start().unwrap(); #[cfg(unix)]
u_lib::unix::daemonize()
} }
info!("Starting agent {}", get_self_uid()); info!("Starting agent {}", get_self_uid());
Builder::new_multi_thread() Builder::new_multi_thread()
@ -121,7 +126,15 @@ pub fn run_forever() {
.build() .build()
.unwrap() .unwrap()
.block_on(async { .block_on(async {
match ClientHandler::new(&env.u_server, None).await {
Ok(client) => {
tokio::spawn(error_reporting(client.clone())); tokio::spawn(error_reporting(client.clone()));
agent_loop(client).await agent_loop(client).await
}
Err(e) => {
error!("client init failed: {}", e);
exit(7)
}
}
}) })
} }

@ -113,7 +113,7 @@ pub async fn process_cmd(client: ClientHandler, args: Args) -> PanelResult<Value
}, },
Cmd::Ping => into_value(client.ping().await?), Cmd::Ping => into_value(client.ping().await?),
Cmd::Serve => { Cmd::Serve => {
crate::server::serve(client) crate::gui::serve(client)
.await .await
.map_err(|e| UError::PanelError(format!("{e:?}")))?; .map_err(|e| UError::PanelError(format!("{e:?}")))?;
Value::Null Value::Null

@ -0,0 +1,16 @@
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
# For additional information regarding the format and rule options, please see:
# https://github.com/browserslist/browserslist#queries
# For the full list of supported browsers by the Angular framework, please see:
# https://angular.io/guide/browser-support
# You can see what browsers were selected by your queries by running:
# npx browserslist
last 1 Chrome version
last 1 Firefox version
last 2 Edge major versions
last 2 Safari major versions
last 2 iOS major versions
Firefox ESR

@ -0,0 +1,16 @@
# Editor configuration, see https://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
[*.ts]
quote_type = single
[*.md]
max_line_length = off
trim_trailing_whitespace = false

Before

Width:  |  Height:  |  Size: 948 B

After

Width:  |  Height:  |  Size: 948 B

@ -11,7 +11,7 @@ use structopt::StructOpt;
use u_lib::{api::ClientHandler, unwrap_enum}; use u_lib::{api::ClientHandler, unwrap_enum};
#[derive(RustEmbed)] #[derive(RustEmbed)]
#[folder = "./src/server/fe/dist/fe/"] #[folder = "./src/gui/fe/dist/fe/"]
struct Files; struct Files;
impl Files { impl Files {

@ -1,5 +1,5 @@
mod argparse; mod argparse;
mod server; mod gui;
#[macro_use] #[macro_use]
extern crate tracing; extern crate tracing;
@ -14,7 +14,7 @@ use u_lib::logging::init_logger;
#[actix_web::main] #[actix_web::main]
async fn main() -> AnyResult<()> { async fn main() -> AnyResult<()> {
let env = admin::load()?; let env = admin::load()?;
let client = ClientHandler::new(&env.u_server, Some(env.admin_auth_token)); let client = ClientHandler::new(&env.u_server, Some(env.admin_auth_token)).await?;
let args = Args::from_args(); let args = Args::from_args();
init_logger(None::<&str>); init_logger(None::<&str>);

@ -4,8 +4,8 @@ use crate::db::{PgRepo, UDB};
use crate::error::Error; use crate::error::Error;
use u_lib::{ use u_lib::{
messaging::{AsMsg, BaseMessage, Reportable}, messaging::{AsMsg, BaseMessage, Reportable},
misc::OneOrVec,
models::*, models::*,
utils::OneOrVec,
}; };
use uuid::Uuid; use uuid::Uuid;
use warp::Rejection; use warp::Rejection;
@ -147,6 +147,7 @@ impl Endpoints {
None => warn!("Empty agent data"), None => warn!("Empty agent data"),
}, },
JobType::Shell => (), JobType::Shell => (),
JobType::Service => (),
JobType::Terminate => todo!(), JobType::Terminate => todo!(),
JobType::Update => todo!(), JobType::Update => todo!(),
} }

@ -12,7 +12,7 @@ mod handlers;
use db::PgRepo; use db::PgRepo;
use error::{Error as ServerError, RejResponse}; use error::{Error as ServerError, RejResponse};
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
use std::{convert::Infallible, path::PathBuf, sync::Arc}; use std::{convert::Infallible, sync::Arc};
use u_lib::{ use u_lib::{
config, config,
db::async_pool, db::async_pool,
@ -47,8 +47,10 @@ pub fn init_endpoints(
let path = |p: &'static str| warp::post().and(warp::path(p)); let path = |p: &'static str| warp::post().and(warp::path(p));
let infallible_none = |_| async { Ok::<_, Infallible>((None::<Uuid>,)) }; let infallible_none = |_| async { Ok::<_, Infallible>((None::<Uuid>,)) };
let with_db = {
let adb = Arc::new(db); let adb = Arc::new(db);
let with_db = warp::any().map(move || adb.clone()); warp::any().map(move || adb.clone())
};
let get_agents = path("get_agents") let get_agents = path("get_agents")
.and(with_db.clone()) .and(with_db.clone())
@ -179,17 +181,20 @@ pub async fn serve() -> Result<(), ServerError> {
preload_jobs(&db).await?; preload_jobs(&db).await?;
let certs_dir = PathBuf::from("certs");
let env = config::admin::load().map_err(|e| ServerError::Other(e.to_string()))?; let env = config::admin::load().map_err(|e| ServerError::Other(e.to_string()))?;
let routes = init_endpoints(&env.admin_auth_token, db) let routes = init_endpoints(&env.admin_auth_token, db)
.recover(handle_rejection) .recover(handle_rejection)
.with(custom(logger)); .with(custom(logger));
let server_cert = include_bytes!("../../../certs/server.crt");
let server_key = include_bytes!("../../../certs/server.key");
let ca = include_bytes!("../../../certs/ca.crt");
warp::serve(routes) warp::serve(routes)
.tls() .tls()
.cert_path(certs_dir.join("server.crt")) .cert(server_cert)
.key_path(certs_dir.join("server.key")) .key(server_key)
.client_auth_required_path(certs_dir.join("ca.crt")) .client_auth_required(ca)
.run(([0, 0, 0, 0], config::MASTER_PORT)) .run(([0, 0, 0, 0], config::MASTER_PORT))
.await; .await;
Ok(()) Ok(())

@ -11,7 +11,6 @@ services:
- u_net - u_net
volumes: volumes:
- ./u_server:/unki/u_server - ./u_server:/unki/u_server
- ./certs:/unki/certs
- ./logs:/unki/logs:rw - ./logs:/unki/logs:rw
working_dir: /unki working_dir: /unki
command: /unki/u_server command: /unki/u_server

@ -16,7 +16,6 @@ services:
- u_net - u_net
volumes: volumes:
- ../target/x86_64-unknown-linux-musl/${PROFILE:-debug}/u_server:/unki/u_server - ../target/x86_64-unknown-linux-musl/${PROFILE:-debug}/u_server:/unki/u_server
- ../certs:/unki/certs
- ../logs:/unki/logs:rw - ../logs:/unki/logs:rw
working_dir: /unki working_dir: /unki
command: /unki/u_server command: /unki/u_server

@ -8,14 +8,14 @@ pub struct RegisteredAgent {
impl RegisteredAgent { impl RegisteredAgent {
pub async fn unregister(self) { pub async fn unregister(self) {
let cli = ClientHandler::new(&ENV.u_server, None); let cli = ClientHandler::new(&ENV.u_server, None).await.unwrap();
cli.del(self.uid).await.unwrap(); cli.del(self.uid).await.unwrap();
} }
} }
#[fixture] #[fixture]
pub async fn register_agent() -> RegisteredAgent { pub async fn register_agent() -> RegisteredAgent {
let cli = ClientHandler::new(&ENV.u_server, None); let cli = ClientHandler::new(&ENV.u_server, None).await.unwrap();
let agent_uid = Uuid::new_v4(); let agent_uid = Uuid::new_v4();
println!("registering agent {agent_uid}"); println!("registering agent {agent_uid}");
let resp = cli let resp = cli

@ -2,10 +2,7 @@ use serde::de::DeserializeOwned;
use serde_json::{from_slice, Value}; use serde_json::{from_slice, Value};
use std::fmt::{Debug, Display}; use std::fmt::{Debug, Display};
use std::process::{Command, Output}; use std::process::{Command, Output};
use u_lib::{ use u_lib::{conv::bytes_to_string, datatypes::PanelResult, proc_output::ProcOutput};
datatypes::PanelResult,
utils::{bytes_to_string, ProcOutput},
};
const PANEL_BINARY: &str = "/u_panel"; const PANEL_BINARY: &str = "/u_panel";

@ -4,6 +4,7 @@ use crate::helpers::Panel;
use rstest::rstest; use rstest::rstest;
use serde_json::{json, to_string}; use serde_json::{json, to_string};
use std::error::Error; use std::error::Error;
use std::fs;
use std::time::Duration; use std::time::Duration;
use tokio::time::sleep; use tokio::time::sleep;
use u_lib::models::*; use u_lib::models::*;
@ -13,7 +14,7 @@ type TestResult<R = ()> = Result<R, Box<dyn Error>>;
#[rstest] #[rstest]
#[tokio::test] #[tokio::test]
async fn test_registration(#[future] register_agent: RegisteredAgent) -> TestResult { async fn registration(#[future] register_agent: RegisteredAgent) -> TestResult {
let agent = register_agent.await; let agent = register_agent.await;
let agents: Vec<Agent> = Panel::check_output("agents read"); let agents: Vec<Agent> = Panel::check_output("agents read");
let found = agents.iter().find(|v| v.id == agent.uid); let found = agents.iter().find(|v| v.id == agent.uid);
@ -23,20 +24,47 @@ async fn test_registration(#[future] register_agent: RegisteredAgent) -> TestRes
} }
#[tokio::test] #[tokio::test]
async fn test_setup_tasks() -> TestResult { async fn setup_tasks() -> TestResult {
let agents: Vec<Agent> = Panel::check_output("agents read"); let agents: Vec<Agent> = Panel::check_output("agents read");
let agent_uid = match agents.get(0) { let agent_uid = agents[0].id;
Some(a) => a.id,
None => panic!("Some independent agents should present"),
};
let job_alias = "passwd_contents"; let job_alias = "passwd_contents";
let job = json!( let job = json!(
{"alias": job_alias, "payload": b"cat /etc/passwd", "argv": "/bin/bash {}" } {"alias": job_alias, "payload": b"cat /etc/passwd", "argv": "/bin/bash {}" }
); );
let cmd = format!("jobs create '{}'", to_string(&job).unwrap()); let cmd = format!("jobs create '{}'", to_string(&job).unwrap());
Panel::check_status(cmd); Panel::check_status(cmd);
let cmd = format!("map create {} {}", agent_uid, job_alias); let cmd = format!("map create {} {}", agent_uid, job_alias);
let assigned_uids: Vec<Uuid> = Panel::check_output(cmd); let assigned_uids: Vec<Uuid> = Panel::check_output(cmd);
for _ in 0..3 {
let result: Vec<AssignedJob> =
Panel::check_output(format!("map read {}", assigned_uids[0]));
if result[0].state == JobState::Finished {
return Ok(());
} else {
sleep(Duration::from_secs(5)).await;
eprintln!("waiting for task");
}
}
panic!("Job didn't appear in the job map");
}
#[tokio::test]
async fn large_payload() -> TestResult {
let agent_uid = Panel::check_output::<Vec<Agent>>("agents read")[0].id;
let job_alias = "large_payload";
let payload = fs::read("./tests/bin/echoer").unwrap();
let job = json!(
{"alias": job_alias, "payload": payload, "argv": "/bin/bash {}" }
);
let cmd = format!("jobs create '{}'", to_string(&job).unwrap());
Panel::check_status(cmd);
let cmd = format!("map create {} {}", agent_uid, job_alias);
let assigned_uids: Vec<Uuid> = Panel::check_output(cmd);
for _ in 0..3 { for _ in 0..3 {
let result: Vec<AssignedJob> = let result: Vec<AssignedJob> =
Panel::check_output(format!("map read {}", assigned_uids[0])); Panel::check_output(format!("map read {}", assigned_uids[0]));

@ -2,7 +2,7 @@ use crate::helpers::ENV;
use u_lib::config::MASTER_PORT; use u_lib::config::MASTER_PORT;
#[tokio::test] #[tokio::test]
async fn test_non_auth_connection_dropped() { async fn non_auth_connection_dropped() {
let client = reqwest::ClientBuilder::new() let client = reqwest::ClientBuilder::new()
.danger_accept_invalid_certs(true) .danger_accept_invalid_certs(true)
.build() .build()

@ -18,21 +18,24 @@ futures = "0.3.5"
guess_host_triple = "0.1.2" guess_host_triple = "0.1.2"
libc = "^0.2" libc = "^0.2"
lazy_static = "1.4.0" lazy_static = "1.4.0"
log = "*"
nix = "0.17"
once_cell = "1.7.2" once_cell = "1.7.2"
platforms = "3.0.1" platforms = "3.0.1"
reqwest = { workspace = true, features = ["native-tls"] } reqwest = { workspace = true, features = ["native-tls", "blocking"] }
shlex = "1.0.0" shlex = "1.0.0"
serde = { workspace = true } serde = { workspace = true }
serde_json = { workspace = true } serde_json = { workspace = true }
strum = { version = "0.20", features = ["derive"] } strum = { version = "0.20", features = ["derive"] }
thiserror = { workspace = true } thiserror = { workspace = true }
tokio = { workspace = true, features = ["rt-multi-thread", "sync", "macros", "process", "time"] } tokio = { workspace = true, features = ["rt-multi-thread", "sync", "macros", "process", "time"] }
tracing = { workspace = true }
tracing-appender = { workspace = true } tracing-appender = { workspace = true }
tracing-subscriber = { workspace = true, features = ["env-filter"] } tracing-subscriber = { workspace = true, features = ["env-filter"] }
uuid = { workspace = true, features = ["serde", "v4"] } uuid = { workspace = true, features = ["serde", "v4"] }
[target.'cfg(unix)'.dependencies]
daemonize = "0.4.1"
nix = "0.17"
[features] [features]
panel = [] panel = []
server = ["dep:diesel", "dep:diesel-derive-enum", "dep:deadpool-diesel"] server = ["dep:diesel", "dep:diesel-derive-enum", "dep:deadpool-diesel"]

@ -1,18 +1,21 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt::Debug; use std::fmt::Debug;
use std::net::SocketAddr;
use anyhow::{Context, Result};
use reqwest::{header, header::HeaderMap, Certificate, Client, Identity, Method, Url};
use serde::de::DeserializeOwned;
use serde_json::{from_str, Value};
use uuid::Uuid;
use crate::{ use crate::{
config::{get_self_uid, MASTER_PORT}, config::{get_self_uid, MASTER_PORT},
conv::opt_to_string,
messaging::{self, AsMsg, BaseMessage}, messaging::{self, AsMsg, BaseMessage},
misc::OneOrVec,
models::{self}, models::{self},
utils::{opt_to_string, OneOrVec}, UError, UResult,
UError,
}; };
use anyhow::{Context, Result};
use reqwest::{header::HeaderMap, Certificate, Client, Identity, Url};
use serde::de::DeserializeOwned;
use serde_json::from_str;
use uuid::Uuid;
const AGENT_IDENTITY: &[u8] = include_bytes!("../../../certs/alice.p12"); const AGENT_IDENTITY: &[u8] = include_bytes!("../../../certs/alice.p12");
const ROOT_CA_CERT: &[u8] = include_bytes!("../../../certs/ca.crt"); const ROOT_CA_CERT: &[u8] = include_bytes!("../../../certs/ca.crt");
@ -24,28 +27,51 @@ pub struct ClientHandler {
} }
impl ClientHandler { impl ClientHandler {
pub fn new(server: &str, password: Option<String>) -> Self { pub async fn new(server: &str, password: Option<String>) -> UResult<Self> {
let identity = Identity::from_pkcs12_der(AGENT_IDENTITY, "").unwrap(); let identity = Identity::from_pkcs12_der(AGENT_IDENTITY, "").unwrap();
let mut default_headers = HashMap::from([( let mut default_headers =
"user-agent".to_string(), HashMap::from([(header::USER_AGENT, get_self_uid().hyphenated().to_string())]);
get_self_uid().hyphenated().to_string(),
)]);
if let Some(pwd) = password { if let Some(pwd) = password {
default_headers.insert("authorization".to_string(), format!("Bearer {pwd}")); default_headers.insert(header::AUTHORIZATION, format!("Bearer {pwd}"));
} }
let dns_response = Client::new()
.request(
Method::GET,
format!("https://1.1.1.1/dns-query?name={server}&type=A"),
)
.header(header::ACCEPT, "application/dns-json")
.send()
.await?
.text()
.await?;
let client = {
let client = Client::builder() let client = Client::builder()
.identity(identity) .identity(identity)
.default_headers(HeaderMap::try_from(&default_headers).unwrap()) .default_headers(HeaderMap::try_from(&default_headers).unwrap())
.add_root_certificate(Certificate::from_pem(ROOT_CA_CERT).unwrap()) .add_root_certificate(Certificate::from_pem(ROOT_CA_CERT).unwrap());
match from_str::<Value>(&dns_response).unwrap()["Answer"]
.get(0)
.and_then(|a| a.get("data"))
{
Some(ip) => {
let raw_addr = format!("{}:{MASTER_PORT}", ip.as_str().unwrap());
let addr: SocketAddr = raw_addr.parse().unwrap();
client.resolve(server, addr)
}
None => client,
}
}
.build() .build()
.unwrap(); .unwrap();
Self { Ok(Self {
client, client,
base_url: Url::parse(&format!("https://{}:{}", server, MASTER_PORT)).unwrap(), base_url: Url::parse(&format!("https://{}:{}", server, MASTER_PORT)).unwrap(),
} })
} }
async fn req<R: AsMsg + DeserializeOwned + Default>(&self, url: impl AsRef<str>) -> Result<R> { async fn req<R: AsMsg + DeserializeOwned + Default>(&self, url: impl AsRef<str>) -> Result<R> {

@ -1,6 +1,6 @@
use std::fmt::Debug; use std::fmt::Debug;
use crate::utils::OneOrVec; use crate::misc::OneOrVec;
use anyhow::Error; use anyhow::Error;
pub struct CombinedResult<T, E: Debug = Error> { pub struct CombinedResult<T, E: Debug = Error> {

@ -1,19 +1,27 @@
#![allow(non_upper_case_globals)] #![allow(non_upper_case_globals)]
pub mod api; pub mod api;
pub mod cache; pub mod cache;
pub mod combined_result;
pub mod config; pub mod config;
pub mod conv;
pub mod datatypes; pub mod datatypes;
#[cfg(feature = "server")] #[cfg(feature = "server")]
pub mod db; pub mod db;
pub mod errors; pub mod error;
pub mod executor; pub mod executor;
pub mod logging; pub mod logging;
pub mod messaging; pub mod messaging;
pub mod misc;
pub mod models; pub mod models;
pub mod platform;
pub mod proc_output;
pub mod runner; pub mod runner;
pub mod utils; pub mod storage;
pub mod tempfile;
#[cfg(unix)]
pub mod unix;
pub use errors::{UError, UResult}; pub use error::{UError, UResult};
#[cfg(feature = "server")] #[cfg(feature = "server")]
pub mod schema_exports { pub mod schema_exports {
@ -25,7 +33,7 @@ pub mod schema_exports {
extern crate diesel; extern crate diesel;
#[macro_use] #[macro_use]
extern crate log; extern crate tracing;
#[cfg(test)] #[cfg(test)]
#[macro_use] #[macro_use]

@ -1,8 +1,6 @@
use crate::config::get_self_uid; use crate::config::get_self_uid;
//use crate::utils::VecDisplay;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::borrow::Cow; use std::borrow::Cow;
//use std::fmt::Display;
use uuid::Uuid; use uuid::Uuid;
pub struct Moo<'cow, T: AsMsg + Clone>(pub Cow<'cow, T>); pub struct Moo<'cow, T: AsMsg + Clone>(pub Cow<'cow, T>);

@ -11,7 +11,9 @@ mod server {
#[cfg(feature = "server")] #[cfg(feature = "server")]
use self::server::*; use self::server::*;
use crate::{config::get_self_uid, executor::ExecResult, runner::NamedJobRunner, utils::Platform}; use crate::{
config::get_self_uid, executor::ExecResult, platform::Platform, runner::NamedJobRunner,
};
use uuid::Uuid; use uuid::Uuid;
@ -63,17 +65,24 @@ impl Agent {
self.last_active = SystemTime::now(); self.last_active = SystemTime::now();
} }
#[cfg(unix)]
pub async fn gather() -> Self { pub async fn gather() -> Self {
let mut builder = NamedJobRunner::from_shell(vec![ #[cfg(unix)]
let cmds = vec![
("hostname", "uname -a"),
("host_info", "hostnamectl --json=pretty"),
("is_root", "id -u"),
("username", "id -un"),
];
#[cfg(windows)]
let cmds = vec![
("hostname", "uname -a"), ("hostname", "uname -a"),
("host_info", "hostnamectl --json=pretty"), ("host_info", "hostnamectl --json=pretty"),
("is_root", "id -u"), ("is_root", "id -u"),
("username", "id -un"), ("username", "id -un"),
]) ];
.unwrap_one()
.wait() let mut builder = NamedJobRunner::from_shell(cmds).unwrap_one().wait().await;
.await;
let decoder = let decoder =
|job_result: ExecResult| job_result.unwrap().to_str_result().trim().to_string(); |job_result: ExecResult| job_result.unwrap().to_str_result().trim().to_string();

@ -1,7 +1,7 @@
use super::JobType; use super::JobType;
#[cfg(feature = "server")] #[cfg(feature = "server")]
use crate::models::schema::*; use crate::models::schema::*;
use crate::utils::Platform; use crate::platform::Platform;
use crate::{UError, UResult}; use crate::{UError, UResult};
#[cfg(feature = "server")] #[cfg(feature = "server")]
use diesel::{Identifiable, Insertable, Queryable}; use diesel::{Identifiable, Insertable, Queryable};

@ -34,6 +34,7 @@ pub enum JobState {
)] )]
pub enum JobType { pub enum JobType {
Init, Init,
Service,
#[default] #[default]
Shell, Shell,
Terminate, Terminate,

@ -63,7 +63,7 @@ impl ProcOutput {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::utils::{bytes_to_string, ProcOutput}; use crate::{conv::bytes_to_string, proc_output::ProcOutput};
use std::str; use std::str;
const STDERR_DELIMETER: &'static str = const STDERR_DELIMETER: &'static str =

@ -1,9 +1,12 @@
use crate::{ use crate::{
cache::JobCache, cache::JobCache,
combined_result::CombinedResult,
executor::{ExecResult, Waiter}, executor::{ExecResult, Waiter},
misc::OneOrVec,
models::{Agent, AssignedJob, AssignedJobById, JobMeta, JobType}, models::{Agent, AssignedJob, AssignedJobById, JobMeta, JobType},
utils::{CombinedResult, OneOrVec, Platform}, platform::Platform,
utils::{ProcOutput, TempFile}, proc_output::ProcOutput,
tempfile::TempFile,
UError, UResult, UError, UResult,
}; };
use std::collections::HashMap; use std::collections::HashMap;
@ -128,6 +131,7 @@ pub async fn run_assigned_job(mut job: AssignedJob) -> ExecResult {
job.set_result(&Agent::run().await); job.set_result(&Agent::run().await);
job.retcode = Some(0); job.retcode = Some(0);
} }
JobType::Service => todo!(),
JobType::Update => todo!(), JobType::Update => todo!(),
JobType::Terminate => exit(0), JobType::Terminate => exit(0),
}; };

@ -49,13 +49,13 @@ impl Drop for TempFile {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::utils::bytes_to_string; use crate::conv::bytes_to_string;
use std::path::Path; use std::path::Path;
use std::process::Command; use std::process::Command;
#[test] #[test]
fn test_file_is_not_busy() { fn test_file_is_not_busy() {
let binary = include_bytes!("../../tests/fixtures/echoer"); let binary = include_bytes!("../tests/fixtures/echoer");
for _ in 0..100 { for _ in 0..100 {
let executable = TempFile::write_exec(binary).unwrap(); let executable = TempFile::write_exec(binary).unwrap();
let path = executable.get_path(); let path = executable.get_path();

@ -1,10 +1,11 @@
use daemonize::Daemonize;
use nix::{ use nix::{
sys::signal::{signal, SigHandler, Signal}, sys::signal::{signal, SigHandler, Signal},
unistd::{chdir, close as fdclose, fork, getppid, setsid, ForkResult}, unistd::{chdir, close as fdclose, fork, getppid, setsid, ForkResult},
}; };
use std::process::exit; use std::process::exit;
pub fn daemonize() { fn _daemonize() {
if getppid().as_raw() != 1 { if getppid().as_raw() != 1 {
setsig(Signal::SIGTTOU, SigHandler::SigIgn); setsig(Signal::SIGTTOU, SigHandler::SigIgn);
setsig(Signal::SIGTTIN, SigHandler::SigIgn); setsig(Signal::SIGTTIN, SigHandler::SigIgn);
@ -30,6 +31,10 @@ pub fn daemonize() {
} }
} }
pub fn daemonize() {
Daemonize::new().start().unwrap()
}
pub fn setsig(sig: Signal, hnd: SigHandler) { pub fn setsig(sig: Signal, hnd: SigHandler) {
unsafe { unsafe {
signal(sig, hnd).unwrap(); signal(sig, hnd).unwrap();

@ -1,20 +0,0 @@
pub mod combined_result;
pub mod conv;
pub mod misc;
pub mod platform;
pub mod proc_output;
pub mod storage;
pub mod tempfile;
#[cfg(unix)]
pub mod unix;
pub use combined_result::*;
pub use conv::*;
pub use misc::*;
pub use platform::*;
pub use proc_output::*;
pub use storage::*;
pub use tempfile::*;
#[cfg(unix)]
pub use unix::*;

@ -1,40 +0,0 @@
use crate::{messaging::AsMsg, utils::OneOrVec};
use serde::{Deserialize, Serialize};
use std::fmt::{self, Display, Formatter};
use std::ops::{Deref, DerefMut};
#[derive(Serialize, Deserialize, Clone, Default)]
pub struct VecDisplay<T: AsMsg + Display>(pub Vec<T>);
impl<T: AsMsg + Display> VecDisplay<T> {
pub fn new(inner: impl OneOrVec<T>) -> Self {
VecDisplay(inner.into_vec())
}
pub fn into_builtin_vec(self) -> Vec<T> {
self.0
}
}
impl<T: AsMsg + Display> Deref for VecDisplay<T> {
type Target = Vec<T>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T: AsMsg + Display> DerefMut for VecDisplay<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<T: AsMsg + Display> Display for VecDisplay<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
for (i, itm) in self.0.iter().enumerate() {
writeln!(f, "### {}:\n{}\n", i, itm)?;
}
Ok(())
}
}

@ -1,5 +1,5 @@
CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE TYPE JobType AS ENUM ('shell', 'init', 'python'); CREATE TYPE JobType AS ENUM ('shell', 'init', 'python', 'service');
CREATE TYPE JobState AS ENUM ('queued', 'running', 'finished'); CREATE TYPE JobState AS ENUM ('queued', 'running', 'finished');
CREATE TYPE AgentState AS ENUM ('new', 'active', 'banned'); CREATE TYPE AgentState AS ENUM ('new', 'active', 'banned');

@ -10,8 +10,6 @@ RSYNC="rsync -arzh --progress"
ssh $SERVER mkdir -p $REMOTE_DIR/data ssh $SERVER mkdir -p $REMOTE_DIR/data
$RSYNC $ROOTDIR/target/x86_64-unknown-linux-musl/release/{u_server,migrator} $REMOTE_PATH/ $RSYNC $ROOTDIR/target/x86_64-unknown-linux-musl/release/{u_server,migrator} $REMOTE_PATH/
$RSYNC $ROOTDIR/certs/server.{crt,key} $REMOTE_PATH/certs/
$RSYNC $ROOTDIR/certs/ca.crt $REMOTE_PATH/certs/
$RSYNC $ROOTDIR/.env* $REMOTE_PATH/ $RSYNC $ROOTDIR/.env* $REMOTE_PATH/
$RSYNC $ROOTDIR/deploy/* $REMOTE_PATH/ $RSYNC $ROOTDIR/deploy/* $REMOTE_PATH/
$RSYNC $ROOTDIR/images/{u_server,u_db}.Dockerfile $REMOTE_PATH/ $RSYNC $ROOTDIR/images/{u_server,u_db}.Dockerfile $REMOTE_PATH/

@ -2,8 +2,6 @@ todos:
Upload/download files Upload/download files
More tests More tests
Agent update (use more JobType's) Agent update (use more JobType's)
Erase log macros in release mode
Bump wine version to test agent on windows Bump wine version to test agent on windows
Store downloaded payload on disk instead of ram Store downloaded payload on disk instead of ram
Improve web interface Improve web interface
Migrator binary

Loading…
Cancel
Save