improved /install

This commit is contained in:
Ramil_Algayev 2024-12-27 23:04:17 +04:00
parent 7864c53236
commit b1049c4dcc
4 changed files with 81 additions and 32 deletions

38
dtrfs_api/Cargo.lock generated

@ -1,6 +1,6 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
version = 4
[[package]]
name = "actix-codec"
@ -678,6 +678,9 @@ dependencies = [
"serde",
"sev",
"sha3",
"tokio",
"tokio-stream",
"tokio-util",
]
[[package]]
@ -2104,9 +2107,9 @@ dependencies = [
[[package]]
name = "tokio"
version = "1.41.1"
version = "1.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33"
checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551"
dependencies = [
"backtrace",
"bytes",
@ -2116,9 +2119,21 @@ dependencies = [
"pin-project-lite",
"signal-hook-registry",
"socket2",
"tokio-macros",
"windows-sys 0.52.0",
]
[[package]]
name = "tokio-macros"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "tokio-rustls"
version = "0.26.0"
@ -2131,10 +2146,21 @@ dependencies = [
]
[[package]]
name = "tokio-util"
version = "0.7.12"
name = "tokio-stream"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a"
checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047"
dependencies = [
"futures-core",
"pin-project-lite",
"tokio",
]
[[package]]
name = "tokio-util"
version = "0.7.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078"
dependencies = [
"bytes",
"futures-core",

@ -11,6 +11,9 @@ regex = "1.11.1"
sev = { version = "4.0", default-features = false, features = ['crypto_nossl','snp'] }
ed25519-dalek = { version = "2.1.1", features = ["pem", "pkcs8"] }
lazy_static = "1.5.0"
tokio = { version = "1.42.0", features = ["full"] }
tokio-util = "0.7.13"
tokio-stream = { version = "0.1.17", features = ["io-util"] }
actix-web = { version = "4.9.0", features = ["rustls-0_23"] }
sha3 = "0.10.8"
rustls = "0.23.18"

@ -93,8 +93,8 @@ async fn post_install_form(req: HttpRequest, form: web::Form<InstallForm>) -> Ht
if let Err(e) = verify(&req) {
return HttpResponse::BadRequest().body(format!("Signature verification failed: {}", e));
};
match os::encrypt_and_install_os(&form.url, &form.sha, &form.keyfile) {
Ok(s) => HttpResponse::Ok().body(s),
match os::encrypt_and_install_os(&form.url, &form.sha, &form.keyfile).await {
Ok(s) => s,
Err(e) => HttpResponse::InternalServerError().body(format!("{e:?}")),
}
}

@ -1,47 +1,67 @@
use crate::snp::get_derived_key;
use actix_web::{web::Bytes, HttpResponse};
use anyhow::{anyhow, Result};
use base64::prelude::{Engine, BASE64_URL_SAFE};
use std::process::Command;
use std::{
fs::File,
io::{BufRead, BufReader, Write},
path::Path,
process::Command,
process::Stdio,
};
const SNP_KEYFILE_PATH: &str = "/tmp/detee_snp_keyfile";
const BACKUP_KEYFILE_PATH: &str = "/tmp/detee_backup_keyfile";
pub fn encrypt_and_install_os(
pub async fn encrypt_and_install_os(
install_url: &str,
install_sha: &str,
keyfile: &str,
) -> Result<String> {
let binary_keyfile = BASE64_URL_SAFE.decode(keyfile)?;
std::fs::write(BACKUP_KEYFILE_PATH, binary_keyfile)?;
// this path is hardcoded also in the initrd creation script
let install_result = Command::new("/usr/lib/dtrfs/install_os.sh")
) -> Result<HttpResponse, actix_web::Error> {
use tokio::process::Command;
use tokio::io::{BufReader, AsyncBufReadExt};
use tokio_stream::{StreamExt, wrappers::LinesStream};
let binary_keyfile = base64::engine::general_purpose::URL_SAFE.decode(keyfile)
.map_err(|e| actix_web::error::ErrorBadRequest(e.to_string()))?;
// Write the decoded keyfile to the backup path asynchronously
tokio::fs::write(BACKUP_KEYFILE_PATH, &binary_keyfile)
.await
.map_err(|e| actix_web::error::ErrorInternalServerError(e.to_string()))?;
// Spawn the installation script as a child process
let mut child = Command::new("/usr/lib/dtrfs/install_os.sh")
.env("INSTALL_URL", install_url)
.env("INSTALL_SHA", install_sha)
.env("SNP_KEY_FILE", SNP_KEYFILE_PATH)
.env("ROOT_KEYFILE", BACKUP_KEYFILE_PATH)
.output()?;
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.map_err(|e| actix_web::error::ErrorInternalServerError(e.to_string()))?;
if !install_result.status.success() {
return Err(anyhow!(
"OS installation script failed.\nScript stdout:\n{}\nScript stderr:\n{}",
String::from_utf8(install_result.stdout)
.unwrap_or("Could not grab stdout from installation script.".to_string()),
String::from_utf8(install_result.stderr)
.unwrap_or("Could not grab stderr from installation script.".to_string()),
));
}
Ok(format!(
"Successfully installed OS. Script stdout:\n{}\nScript stderr:\n{}",
String::from_utf8(install_result.stdout)
.unwrap_or("Could not grab stdout from installation script.".to_string()),
String::from_utf8(install_result.stderr)
.unwrap_or("Could not grab stderr from installation script.".to_string()),
))
// Take stdout and stderr from the child process
let stdout = child.stdout.take().ok_or_else(|| {
actix_web::error::ErrorInternalServerError("Failed to capture stdout".to_string())
})?;
let stderr = child.stderr.take().ok_or_else(|| {
actix_web::error::ErrorInternalServerError("Failed to capture stderr".to_string())
})?;
// Merge stdout and stderr into a single stream
let stdout_lines = LinesStream::new(BufReader::new(stdout).lines());
let stderr_lines = LinesStream::new(BufReader::new(stderr).lines());
let merged_stream = stdout_lines.merge(stderr_lines).map(|line_result| {
line_result
.map(|line| Bytes::from(line + "\n"))
.map_err(|e| actix_web::error::ErrorInternalServerError(e.to_string()))
});
// Return the merged stream as the HTTP response
Ok(HttpResponse::Ok()
.content_type("text/plain; charset=utf-8")
.streaming(merged_stream))
}
pub fn try_hot_keyfile() -> Result<()> {