nuts_tool/cli/container/
create.rs1use anyhow::{ensure, Result};
24use clap::{value_parser, ArgAction, Args};
25use log::debug;
26use nuts_container::{Cipher, Container, CreateOptionsBuilder, Kdf};
27use nuts_tool_api::tool::Plugin;
28use std::cell::RefCell;
29use std::os::fd::RawFd;
30use std::path::PathBuf;
31
32use crate::backend::{PluginBackend, PluginBackendCreateBuilder};
33use crate::cli::container::{CliCipher, AES256_GCM};
34use crate::cli::global::PasswordSource;
35use crate::cli::password::password_from_source_twice;
36use crate::config::{ContainerConfig, PluginConfig};
37
38thread_local! {
39 static SOURCE: RefCell<PasswordSource> = RefCell::new(Default::default());
40}
41
42fn password_callback() -> Result<Vec<u8>, String> {
43 SOURCE.with_borrow(|src| password_from_source_twice(src, "Enter a password"))
44}
45
46#[derive(Args, Debug)]
47pub struct ContainerCreateArgs {
48 name: String,
50
51 #[clap(short, long)]
53 plugin: String,
54
55 #[clap(short, long, value_parser = value_parser!(CliCipher), default_value = AES256_GCM)]
57 cipher: CliCipher,
58
59 #[clap(short, long, value_parser)]
75 kdf: Option<Kdf>,
76
77 #[clap(short, long, action = ArgAction::SetTrue)]
79 overwrite: bool,
80
81 #[clap(value_name = "PLUGIN ARGS")]
83 plugin_args: Vec<String>,
84
85 #[clap(from_global)]
86 verbose: u8,
87
88 #[clap(from_global)]
89 password_from_fd: Option<RawFd>,
90
91 #[clap(from_global)]
92 password_from_file: Option<PathBuf>,
93}
94
95impl ContainerCreateArgs {
96 pub fn run(&self) -> Result<()> {
97 debug!("args: {:?}", self);
98
99 let plugin_config = PluginConfig::load()?;
100 let mut container_config = ContainerConfig::load()?;
101
102 let exe = plugin_config.path(&self.plugin)?;
103 let plugin = Plugin::new(&exe);
104
105 let ok = container_config.add_plugin(&self.name, &self.plugin, self.overwrite);
106 ensure!(
107 ok,
108 "you already have a container with the name {}",
109 self.name
110 );
111
112 SOURCE.with_borrow_mut(|src| {
113 *src = PasswordSource::new(self.password_from_fd, self.password_from_file.clone())
114 });
115
116 let backend_options =
117 PluginBackendCreateBuilder::new(plugin, &self.name, self.verbose, &self.plugin_args)?;
118 let mut builder = CreateOptionsBuilder::new(*self.cipher)
119 .with_password_callback(password_callback)
120 .with_overwrite(self.overwrite);
121
122 if self.cipher != Cipher::None {
123 if let Some(kdf) = self.kdf.clone() {
124 debug!("kdf: {:?}", kdf);
125 builder = builder.with_kdf(kdf);
126 }
127 }
128
129 let options = builder.build::<PluginBackend>()?;
130 Container::<PluginBackend>::create(backend_options, options)?;
131
132 container_config.save()?;
133
134 Ok(())
135 }
136}