forked from lix-project/lix-installer
Scaffold
This commit is contained in:
parent
6678b1cdee
commit
7c4f3206f9
39
Cargo.lock
generated
39
Cargo.lock
generated
|
@ -786,6 +786,7 @@ dependencies = [
|
|||
"nix",
|
||||
"owo-colors",
|
||||
"plist",
|
||||
"rand 0.8.5",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
@ -1333,6 +1334,12 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error"
|
||||
version = "1.0.4"
|
||||
|
@ -1394,6 +1401,27 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.3.1"
|
||||
|
@ -1409,6 +1437,15 @@ version = "0.4.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rdrand"
|
||||
version = "0.4.0"
|
||||
|
@ -1808,7 +1845,7 @@ version = "0.3.7"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8"
|
||||
dependencies = [
|
||||
"rand",
|
||||
"rand 0.4.6",
|
||||
"remove_dir_all",
|
||||
]
|
||||
|
||||
|
|
|
@ -48,3 +48,4 @@ dirs = "4.0.0"
|
|||
erased-serde = "0.3.23"
|
||||
typetag = "0.2.3"
|
||||
dyn-clone = "1.0.9"
|
||||
rand = "0.8.5"
|
||||
|
|
|
@ -18,14 +18,14 @@ use crate::{
|
|||
BoxableError,
|
||||
};
|
||||
|
||||
const NIX_VOLUME_MOUNTD_DEST: &str = "/Library/LaunchDaemons/org.nixos.darwin-store.plist";
|
||||
pub const NIX_VOLUME_MOUNTD_DEST: &str = "/Library/LaunchDaemons/org.nixos.darwin-store.plist";
|
||||
|
||||
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
||||
pub struct CreateApfsVolume {
|
||||
disk: PathBuf,
|
||||
name: String,
|
||||
case_sensitive: bool,
|
||||
encrypt: Option<String>,
|
||||
encrypt: bool,
|
||||
create_or_append_synthetic_conf: CreateOrAppendFile,
|
||||
create_synthetic_objects: CreateSyntheticObjects,
|
||||
unmount_volume: UnmountVolume,
|
||||
|
@ -44,7 +44,7 @@ impl CreateApfsVolume {
|
|||
disk: impl AsRef<Path>,
|
||||
name: String,
|
||||
case_sensitive: bool,
|
||||
encrypt: Option<String>,
|
||||
encrypt: bool,
|
||||
) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
|
||||
let disk = disk.as_ref();
|
||||
let create_or_append_synthetic_conf = CreateOrAppendFile::plan(
|
||||
|
@ -73,13 +73,13 @@ impl CreateApfsVolume {
|
|||
.await
|
||||
.map_err(|e| e.boxed())?;
|
||||
|
||||
let encrypt_volume = if let Some(password) = encrypt.as_ref() {
|
||||
Some(EncryptVolume::plan(disk, password.to_string()).await?)
|
||||
let encrypt_volume = if encrypt {
|
||||
Some(EncryptVolume::plan(disk, &name).await?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let mount_command = if encrypt.is_some() {
|
||||
let mount_command = if encrypt {
|
||||
vec![
|
||||
"/bin/sh",
|
||||
"-c",
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
use crate::{
|
||||
action::{darwin::NIX_VOLUME_MOUNTD_DEST, Action, ActionDescription, ActionState},
|
||||
execute_command,
|
||||
};
|
||||
use rand::Rng;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use crate::action::{Action, ActionDescription, ActionState};
|
||||
use tokio::process::Command;
|
||||
|
||||
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
||||
pub struct EncryptVolume {
|
||||
disk: PathBuf,
|
||||
password: String,
|
||||
name: String,
|
||||
action_state: ActionState,
|
||||
}
|
||||
|
||||
|
@ -13,11 +17,12 @@ impl EncryptVolume {
|
|||
#[tracing::instrument(skip_all)]
|
||||
pub async fn plan(
|
||||
disk: impl AsRef<Path>,
|
||||
password: String,
|
||||
name: impl AsRef<str>,
|
||||
) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
|
||||
let name = name.as_ref().to_owned();
|
||||
Ok(Self {
|
||||
name,
|
||||
disk: disk.as_ref().to_path_buf(),
|
||||
password,
|
||||
action_state: ActionState::Uncompleted,
|
||||
})
|
||||
}
|
||||
|
@ -42,8 +47,8 @@ impl Action for EncryptVolume {
|
|||
))]
|
||||
async fn execute(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
let Self {
|
||||
disk: _,
|
||||
password: _,
|
||||
disk,
|
||||
name,
|
||||
action_state,
|
||||
} = self;
|
||||
if *action_state == ActionState::Completed {
|
||||
|
@ -52,7 +57,65 @@ impl Action for EncryptVolume {
|
|||
}
|
||||
tracing::debug!("Encrypting volume");
|
||||
|
||||
todo!();
|
||||
// Generate a random password.
|
||||
let password: String = {
|
||||
const CHARSET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
|
||||
abcdefghijklmnopqrstuvwxyz\
|
||||
0123456789)(*&^%$#@!~";
|
||||
const PASSWORD_LEN: usize = 32;
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
(0..PASSWORD_LEN)
|
||||
.map(|_| {
|
||||
let idx = rng.gen_range(0..CHARSET.len());
|
||||
CHARSET[idx] as char
|
||||
})
|
||||
.collect()
|
||||
};
|
||||
|
||||
let disk_str = disk.to_str().expect("Could not turn disk into string"); /* Should not reasonably ever fail */
|
||||
|
||||
// Add the password to the user keychain so they can unlock it later.
|
||||
let _password_output = execute_command(
|
||||
Command::new("/usr/bin/security").args([
|
||||
"add-generic-password",
|
||||
"-a",
|
||||
disk_str,
|
||||
"-s",
|
||||
name.as_str(),
|
||||
"-l",
|
||||
format!("{} encryption password", disk_str).as_str(),
|
||||
"-D",
|
||||
"Encrypted volume password",
|
||||
"-j",
|
||||
format!(
|
||||
"Added automatically by the Nix installer for use by {NIX_VOLUME_MOUNTD_DEST}"
|
||||
)
|
||||
.as_str(),
|
||||
"-w",
|
||||
password.as_str(),
|
||||
"-T",
|
||||
"/System/Library/CoreServices/APFSUserAgent",
|
||||
"-T",
|
||||
"/System/Library/CoreServices/CSUserAgent",
|
||||
"-T",
|
||||
"/usr/bin/security",
|
||||
"/Library/Keychains/System.keychain",
|
||||
]),
|
||||
)
|
||||
.await?;
|
||||
|
||||
// Encrypt the mounted volume
|
||||
execute_command(Command::new("/usr/sbin/diskutil").args([
|
||||
"apfs",
|
||||
"encryptVolume",
|
||||
disk_str,
|
||||
"-user",
|
||||
"disk",
|
||||
"-passphrase",
|
||||
password.as_str(),
|
||||
]))
|
||||
.await?;
|
||||
|
||||
tracing::trace!("Encrypted volume");
|
||||
*action_state = ActionState::Completed;
|
||||
|
@ -73,7 +136,7 @@ impl Action for EncryptVolume {
|
|||
async fn revert(&mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
let Self {
|
||||
disk: _,
|
||||
password: _,
|
||||
name: _,
|
||||
action_state,
|
||||
} = self;
|
||||
if *action_state == ActionState::Uncompleted {
|
||||
|
|
|
@ -8,7 +8,7 @@ mod kickstart_launchctl_service;
|
|||
mod unmount_volume;
|
||||
|
||||
pub use bootstrap_volume::{BootstrapVolume, BootstrapVolumeError};
|
||||
pub use create_apfs_volume::{CreateApfsVolume, CreateApfsVolumeError};
|
||||
pub use create_apfs_volume::{CreateApfsVolume, CreateApfsVolumeError, NIX_VOLUME_MOUNTD_DEST};
|
||||
pub use create_synthetic_objects::{CreateSyntheticObjects, CreateSyntheticObjectsError};
|
||||
pub use create_volume::{CreateVolume, CreateVolumeError};
|
||||
pub use enable_ownership::{EnableOwnership, EnableOwnershipError};
|
||||
|
|
|
@ -18,6 +18,7 @@ use crate::{
|
|||
pub struct DarwinMulti {
|
||||
#[clap(flatten)]
|
||||
pub settings: CommonSettings,
|
||||
/// Force encryption on the volume
|
||||
#[clap(
|
||||
long,
|
||||
action(ArgAction::SetTrue),
|
||||
|
@ -25,6 +26,14 @@ pub struct DarwinMulti {
|
|||
env = "HARMONIC_VOLUME_ENCRYPT"
|
||||
)]
|
||||
pub volume_encrypt: bool,
|
||||
/// Use a case sensitive volume
|
||||
#[clap(
|
||||
long,
|
||||
action(ArgAction::SetTrue),
|
||||
default_value = "false",
|
||||
env = "HARMONIC_CASE_SENSITIVE"
|
||||
)]
|
||||
pub case_sensitive: bool,
|
||||
#[clap(long, default_value = "Nix Store", env = "HARMONIC_VOLUME_LABEL")]
|
||||
pub volume_label: String,
|
||||
#[clap(long, env = "HARMONIC_ROOT_DISK")]
|
||||
|
@ -48,6 +57,7 @@ impl Planner for DarwinMulti {
|
|||
Ok(Self {
|
||||
settings: CommonSettings::default()?,
|
||||
root_disk: Some(default_root_disk().await?),
|
||||
case_sensitive: false,
|
||||
volume_encrypt: false,
|
||||
volume_label: "Nix Store".into(),
|
||||
})
|
||||
|
@ -71,7 +81,14 @@ impl Planner for DarwinMulti {
|
|||
},
|
||||
};
|
||||
|
||||
let volume_label = "Nix Store".into();
|
||||
if self.volume_encrypt == false {
|
||||
self.volume_encrypt = execute_command(Command::new("/usr/bin/fdesetup").arg("isactive"))
|
||||
.await?
|
||||
.status
|
||||
.code()
|
||||
.map(|v| if v == 0 { false } else { true })
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
Ok(InstallPlan {
|
||||
planner: Box::new(self.clone()),
|
||||
|
@ -83,9 +100,9 @@ impl Planner for DarwinMulti {
|
|||
Box::new(
|
||||
CreateApfsVolume::plan(
|
||||
self.root_disk.unwrap(), /* We just ensured it was populated */
|
||||
volume_label,
|
||||
self.volume_label,
|
||||
false,
|
||||
None,
|
||||
self.volume_encrypt,
|
||||
)
|
||||
.await?,
|
||||
),
|
||||
|
@ -105,6 +122,7 @@ impl Planner for DarwinMulti {
|
|||
settings,
|
||||
volume_encrypt,
|
||||
volume_label,
|
||||
case_sensitive,
|
||||
root_disk,
|
||||
} = self;
|
||||
let mut map = HashMap::default();
|
||||
|
@ -116,6 +134,10 @@ impl Planner for DarwinMulti {
|
|||
);
|
||||
map.insert("volume_label".into(), serde_json::to_value(volume_label)?);
|
||||
map.insert("root_disk".into(), serde_json::to_value(root_disk)?);
|
||||
map.insert(
|
||||
"case_sensitive".into(),
|
||||
serde_json::to_value(case_sensitive)?,
|
||||
);
|
||||
|
||||
Ok(map)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue