From 2c54a9b868e77083e5933c62a9c73e8688109c7e Mon Sep 17 00:00:00 2001
From: Jeremy Soller <jackpot51@gmail.com>
Date: Tue, 15 Mar 2022 13:50:48 -0600
Subject: [PATCH] installer_tui: support password encryption

---
 src/bin/installer_tui.rs | 151 +++++++++++++++++++--------------------
 1 file changed, 74 insertions(+), 77 deletions(-)

diff --git a/src/bin/installer_tui.rs b/src/bin/installer_tui.rs
index bd1c13c..69c5d4c 100644
--- a/src/bin/installer_tui.rs
+++ b/src/bin/installer_tui.rs
@@ -2,6 +2,7 @@ extern crate arg_parser;
 extern crate redox_installer;
 extern crate redoxfs;
 extern crate serde;
+extern crate termion;
 extern crate toml;
 
 use redox_installer::Config;
@@ -12,6 +13,7 @@ use std::io::{Read, Write};
 use std::ops::DerefMut;
 use std::path::Path;
 use std::process::Command;
+use termion::input::TermRead;
 
 #[cfg(not(target_os = "redox"))]
 fn disk_paths(_paths: &mut Vec<(String, u64)>) {}
@@ -81,7 +83,7 @@ fn format_size(size: u64) -> String {
     }
 }
 
-fn with_redoxfs<P, T, F>(disk_path: &P, bootloader: &[u8], callback: F)
+fn with_redoxfs<P, T, F>(disk_path: &P, password_opt: Option<&[u8]>, bootloader: &[u8], callback: F)
     -> T where
         P: AsRef<Path>,
         T: Send + Sync + 'static,
@@ -99,7 +101,7 @@ fn with_redoxfs<P, T, F>(disk_path: &P, bootloader: &[u8], callback: F)
         }
 
         let ctime = time::SystemTime::now().duration_since(time::UNIX_EPOCH).unwrap();
-        let fs = FileSystem::create_reserved(disk, None, bootloader, ctime.as_secs(), ctime.subsec_nanos()).unwrap();
+        let fs = FileSystem::create_reserved(disk, password_opt, bootloader, ctime.as_secs(), ctime.subsec_nanos()).unwrap();
 
         let callback_mutex = sync::Arc::new(sync::Mutex::new(callback));
         let join_handle = redoxfs::mount(fs, mount_path, move |real_path| {
@@ -163,91 +165,91 @@ fn dir_files(dir: &str, files: &mut Vec<String>) -> io::Result<()> {
     Ok(())
 }
 
-fn package_files(config: &mut Config, files: &mut Vec<String>) -> io::Result<()> {
-    //TODO: Remove packages from config where all files are located (and have valid shasum?)
-    config.packages.clear();
-
-    for entry_res in fs::read_dir("file:/pkg")? {
-        let entry = entry_res?;
-        let path = entry.path();
-        if path.extension() == Some(OsStr::new("sha256sums")) {
-            let sha256sums = fs::read_to_string(&path)?;
-            for line in sha256sums.lines() {
-                //TODO: Support binary format (second space turns into an asterisk)
-                let mut parts = line.splitn(2, "  ");
-                let _sha256sum = parts.next().ok_or(io::Error::new(
-                    io::ErrorKind::InvalidData,
-                    "Missing checksum in sha256sums"
-                ))?;
-                let name = parts.next().ok_or(io::Error::new(
-                    io::ErrorKind::InvalidData,
-                    "Missing filename in sha256sums"
-                ))?;
-                files.push(name.to_string());
-            }
+fn choose_disk() -> String {
+    let mut paths = Vec::new();
+    disk_paths(&mut paths);
+    loop {
+        for (i, (path, size)) in paths.iter().enumerate() {
+            eprintln!("\x1B[1m{}\x1B[0m: {}: {}", i + 1, path, format_size(*size));
         }
-    }
 
-    Ok(())
-}
-
-fn main() {
-    let disk_path = {
-        let mut paths = Vec::new();
-        disk_paths(&mut paths);
-        loop {
-            for (i, (path, size)) in paths.iter().enumerate() {
-                eprintln!("\x1B[1m{}\x1B[0m: {}: {}", i + 1, path, format_size(*size));
-            }
+        if paths.is_empty() {
+            eprintln!("installer_tui: no drives found");
+            process::exit(1);
+        } else {
+            eprint!("Select a drive from 1 to {}: ", paths.len());
 
-            if paths.is_empty() {
-                eprintln!("installer_tui: no drives found");
-                process::exit(1);
-            } else {
-                eprint!("Select a drive from 1 to {}: ", paths.len());
-
-                let mut line = String::new();
-                match io::stdin().read_line(&mut line) {
-                    Ok(0) => {
-                        eprintln!("installer_tui: failed to read line: end of input");
-                        process::exit(1);
-                    },
-                    Ok(_) => (),
-                    Err(err) => {
-                        eprintln!("installer_tui: failed to read line: {}", err);
-                        process::exit(1);
-                    }
+            let mut line = String::new();
+            match io::stdin().read_line(&mut line) {
+                Ok(0) => {
+                    eprintln!("installer_tui: failed to read line: end of input");
+                    process::exit(1);
+                },
+                Ok(_) => (),
+                Err(err) => {
+                    eprintln!("installer_tui: failed to read line: {}", err);
+                    process::exit(1);
                 }
+            }
 
-                match line.trim().parse::<usize>() {
-                    Ok(i) => {
-                        if i >= 1 && i <= paths.len() {
-                            break paths[i - 1].0.clone();
-                        } else {
-                            eprintln!("{} not from 1 to {}", i, paths.len());
-                        }
-                    },
-                    Err(err) => {
-                        eprintln!("invalid input: {}", err);
+            match line.trim().parse::<usize>() {
+                Ok(i) => {
+                    if i >= 1 && i <= paths.len() {
+                        break paths[i - 1].0.clone();
+                    } else {
+                        eprintln!("{} not from 1 to {}", i, paths.len());
                     }
+                },
+                Err(err) => {
+                    eprintln!("invalid input: {}", err);
                 }
             }
         }
-    };
+    }
+}
+
+fn choose_password() -> Option<String> {
+    eprint!("installer_tui: redoxfs password (empty for none): ");
+
+    let password = io::stdin()
+        .read_passwd(&mut io::stderr())
+        .unwrap()
+        .unwrap_or(String::new());
+
+    eprintln!();
+
+    if password.is_empty() {
+       return None;
+    }
+
+    Some(password)
+}
+
+fn main() {
+    let disk_path = choose_disk();
+
+    let password_opt = choose_password();
 
     let bootloader = {
         let path = "file:/bootloader";
-        match fs::read(path) {
+        let mut bootloader = match fs::read(path) {
             Ok(ok) => ok,
             Err(err) => {
                 eprintln!("installer_tui: {}: failed to read: {}", path, err);
                 process::exit(1);
             }
+        };
+
+        // Pad to 1MiB
+        while bootloader.len() < 1024 * 1024 {
+            bootloader.push(0);
         }
+
+        bootloader
     };
 
-    let res = with_redoxfs(&disk_path, &bootloader, |mount_path| -> Result<(), failure::Error> {
-        let mut config = {
+    let res = with_redoxfs(&disk_path, password_opt.as_ref().map(|x| x.as_bytes()), &bootloader, |mount_path| -> Result<(), failure::Error> {
+        let mut config: Config = {
             let path = "file:/filesystem.toml";
             match fs::read_to_string(path) {
                 Ok(config_data) => {
@@ -279,9 +281,9 @@ fn main() {
             "kernel".to_string()
         ];
 
-        // Copy files in /include, /lib, and /pkg
-        //TODO: Convert this data into package data
-        for dir in ["include", "lib", "pkg"].iter() {
+        // Copy files from known directories
+        //TODO: Use package data
+        for dir in ["bin", "etc", "include", "lib", "pkg", "share", "ssl", "ui"].iter() {
             if let Err(err) = dir_files(dir, &mut files) {
                 eprintln!("installer_tui: failed to read files from {}: {}", dir, err);
                 return Err(failure::Error::from_boxed_compat(
@@ -290,13 +292,8 @@ fn main() {
             }
         }
 
-        // Copy files from locally installed packages
-        if let Err(err) = package_files(&mut config, &mut files) {
-            eprintln!("installer_tui: failed to read package files: {}", err);
-            return Err(failure::Error::from_boxed_compat(
-                Box::new(err))
-            );
-        }
+        // Packages are copied by previous code
+        config.packages.clear();
 
         let mut buf = vec![0; 4 * 1024 * 1024];
         for (i, name) in files.iter().enumerate() {
-- 
GitLab