Add ssl-cert-file option (#341)
* Add ssl-cert-file option * Add reqwest support for ssl cert * Fix build * Include in install differences * Handle weird paths, include ENV setting in instructions
This commit is contained in:
parent
df0d8eb01f
commit
c128700130
|
@ -35,6 +35,7 @@ Differing from the current official [Nix](https://github.com/NixOS/nix) installe
|
|||
* `extra-nix-path` is set to `nixpkgs=flake:nixpkgs`
|
||||
* an installation receipt (for uninstalling) is stored at `/nix/receipt.json` as well as a copy of the install binary at `/nix/nix-installer`
|
||||
* `nix-channel --update` is not run, `~/.nix-channels` is not provisioned
|
||||
* `NIX_SSL_CERT_FILE` is set in the various shell profiles if the `ssl-cert-file` argument is used.
|
||||
|
||||
## Motivations
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::path::PathBuf;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use bytes::{Buf, Bytes};
|
||||
use reqwest::Url;
|
||||
use reqwest::{Certificate, Url};
|
||||
use tracing::{span, Span};
|
||||
|
||||
use crate::action::{Action, ActionDescription, ActionError, ActionTag, StatefulAction};
|
||||
|
@ -14,6 +14,7 @@ pub struct FetchAndUnpackNix {
|
|||
url: Url,
|
||||
dest: PathBuf,
|
||||
proxy: Option<Url>,
|
||||
ssl_cert_file: Option<PathBuf>,
|
||||
}
|
||||
|
||||
impl FetchAndUnpackNix {
|
||||
|
@ -22,6 +23,7 @@ impl FetchAndUnpackNix {
|
|||
url: Url,
|
||||
dest: PathBuf,
|
||||
proxy: Option<Url>,
|
||||
ssl_cert_file: Option<PathBuf>,
|
||||
) -> Result<StatefulAction<Self>, ActionError> {
|
||||
// TODO(@hoverbear): Check URL exists?
|
||||
// TODO(@hoverbear): Check tempdir exists
|
||||
|
@ -46,7 +48,17 @@ impl FetchAndUnpackNix {
|
|||
};
|
||||
}
|
||||
|
||||
Ok(Self { url, dest, proxy }.into())
|
||||
if let Some(ssl_cert_file) = &ssl_cert_file {
|
||||
parse_ssl_cert(&ssl_cert_file).await?;
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
url,
|
||||
dest,
|
||||
proxy,
|
||||
ssl_cert_file,
|
||||
}
|
||||
.into())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -66,11 +78,18 @@ impl Action for FetchAndUnpackNix {
|
|||
"fetch_and_unpack_nix",
|
||||
url = tracing::field::display(&self.url),
|
||||
proxy = tracing::field::Empty,
|
||||
ssl_cert_file = tracing::field::Empty,
|
||||
dest = tracing::field::display(self.dest.display()),
|
||||
);
|
||||
if let Some(proxy) = &self.proxy {
|
||||
span.record("proxy", tracing::field::display(&proxy));
|
||||
}
|
||||
if let Some(ssl_cert_file) = &self.ssl_cert_file {
|
||||
span.record(
|
||||
"ssl_cert_file",
|
||||
tracing::field::display(&ssl_cert_file.display()),
|
||||
);
|
||||
}
|
||||
span
|
||||
}
|
||||
|
||||
|
@ -89,6 +108,10 @@ impl Action for FetchAndUnpackNix {
|
|||
ActionError::Custom(Box::new(FetchUrlError::Reqwest(e)))
|
||||
})?)
|
||||
}
|
||||
if let Some(ssl_cert_file) = &self.ssl_cert_file {
|
||||
let ssl_cert = parse_ssl_cert(&ssl_cert_file).await?;
|
||||
buildable_client = buildable_client.add_root_certificate(ssl_cert);
|
||||
}
|
||||
let client = buildable_client
|
||||
.build()
|
||||
.map_err(|e| ActionError::Custom(Box::new(FetchUrlError::Reqwest(e))))?;
|
||||
|
@ -140,6 +163,23 @@ impl Action for FetchAndUnpackNix {
|
|||
}
|
||||
}
|
||||
|
||||
async fn parse_ssl_cert(ssl_cert_file: &Path) -> Result<Certificate, ActionError> {
|
||||
let cert_buf = tokio::fs::read(ssl_cert_file)
|
||||
.await
|
||||
.map_err(|e| ActionError::Read(ssl_cert_file.to_path_buf(), e))?;
|
||||
// We actually try them since things could be `.crt` and `pem` format or `der` format
|
||||
let cert = if let Ok(cert) = Certificate::from_pem(cert_buf.as_slice()) {
|
||||
cert
|
||||
} else if let Ok(cert) = Certificate::from_der(cert_buf.as_slice()) {
|
||||
cert
|
||||
} else {
|
||||
return Err(ActionError::Custom(Box::new(
|
||||
FetchUrlError::UnknownCertFormat,
|
||||
)));
|
||||
};
|
||||
Ok(cert)
|
||||
}
|
||||
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum FetchUrlError {
|
||||
|
@ -153,6 +193,8 @@ pub enum FetchUrlError {
|
|||
Unarchive(#[source] std::io::Error),
|
||||
#[error("Unknown url scheme, `file://`, `https://` and `http://` supported")]
|
||||
UnknownUrlScheme,
|
||||
#[error("Unknown url scheme, `https://`, `socks5://`, and `http://` supported")]
|
||||
#[error("Unknown proxy scheme, `https://`, `socks5://`, and `http://` supported")]
|
||||
UnknownProxyScheme,
|
||||
#[error("Unknown certificate format, `der` and `pem` supported")]
|
||||
UnknownCertFormat,
|
||||
}
|
||||
|
|
|
@ -29,9 +29,13 @@ impl ConfigureNix {
|
|||
.map_err(|e| ActionError::Child(SetupDefaultProfile::action_tag(), Box::new(e)))?;
|
||||
|
||||
let configure_shell_profile = if settings.modify_profile {
|
||||
Some(ConfigureShellProfile::plan().await.map_err(|e| {
|
||||
ActionError::Child(ConfigureShellProfile::action_tag(), Box::new(e))
|
||||
})?)
|
||||
Some(
|
||||
ConfigureShellProfile::plan(settings.ssl_cert_file.clone())
|
||||
.await
|
||||
.map_err(|e| {
|
||||
ActionError::Child(ConfigureShellProfile::action_tag(), Box::new(e))
|
||||
})?,
|
||||
)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
|
|
@ -52,13 +52,24 @@ pub struct ConfigureShellProfile {
|
|||
|
||||
impl ConfigureShellProfile {
|
||||
#[tracing::instrument(level = "debug", skip_all)]
|
||||
pub async fn plan() -> Result<StatefulAction<Self>, ActionError> {
|
||||
pub async fn plan(ssl_cert_file: Option<PathBuf>) -> Result<StatefulAction<Self>, ActionError> {
|
||||
let mut create_or_insert_files = Vec::default();
|
||||
let mut create_directories = Vec::default();
|
||||
|
||||
let maybe_ssl_cert_file_setting = if let Some(ssl_cert_file) = ssl_cert_file {
|
||||
format!(
|
||||
"export NIX_SSL_CERT_FILE={:?}\n",
|
||||
ssl_cert_file
|
||||
.canonicalize()
|
||||
.map_err(|e| { ActionError::Canonicalize(ssl_cert_file, e) })?
|
||||
)
|
||||
} else {
|
||||
"".to_string()
|
||||
};
|
||||
let shell_buf = format!(
|
||||
"\n\
|
||||
# Nix\n\
|
||||
{maybe_ssl_cert_file_setting}\
|
||||
if [ -e '{PROFILE_NIX_FILE_SHELL}' ]; then\n\
|
||||
{inde}. '{PROFILE_NIX_FILE_SHELL}'\n\
|
||||
fi\n\
|
||||
|
@ -103,6 +114,7 @@ impl ConfigureShellProfile {
|
|||
let fish_buf = format!(
|
||||
"\n\
|
||||
# Nix\n\
|
||||
{maybe_ssl_cert_file_setting}\
|
||||
if test -e '{PROFILE_NIX_FILE_FISH}'\n\
|
||||
{inde}. '{PROFILE_NIX_FILE_FISH}'\n\
|
||||
end\n\
|
||||
|
|
|
@ -28,6 +28,7 @@ impl ProvisionNix {
|
|||
settings.nix_package_url.clone(),
|
||||
PathBuf::from(SCRATCH_DIR),
|
||||
settings.proxy.clone(),
|
||||
settings.ssl_cert_file.clone(),
|
||||
)
|
||||
.await?;
|
||||
let create_users_and_group = CreateUsersAndGroups::plan(settings.clone())
|
||||
|
|
|
@ -369,6 +369,8 @@ pub enum ActionError {
|
|||
std::path::PathBuf,
|
||||
#[source] std::io::Error,
|
||||
),
|
||||
#[error("Canonicalizing `{0}`")]
|
||||
Canonicalize(std::path::PathBuf, #[source] std::io::Error),
|
||||
#[error("Read path `{0}`")]
|
||||
Read(std::path::PathBuf, #[source] std::io::Error),
|
||||
#[error("Reading directory `{0}`")]
|
||||
|
|
|
@ -114,7 +114,7 @@ impl CommandExecute for Install {
|
|||
serde_json::from_str(&install_plan_string)?
|
||||
},
|
||||
(None, None) => {
|
||||
let builtin_planner = BuiltinPlanner::from_common_settings(settings)
|
||||
let builtin_planner = BuiltinPlanner::from_common_settings(settings.clone())
|
||||
.await
|
||||
.map_err(|e| eyre::eyre!(e))?;
|
||||
|
||||
|
@ -249,7 +249,7 @@ impl CommandExecute for Install {
|
|||
println!(
|
||||
"\
|
||||
{success}\n\
|
||||
To get started using Nix, open a new shell or run `{shell_reminder}`\n\
|
||||
To get started using Nix, open a new shell or run `{maybe_ssl_cert_file_reminder}{shell_reminder}`\n\
|
||||
",
|
||||
success = "Nix was installed successfully!".green().bold(),
|
||||
shell_reminder = match std::env::var("SHELL") {
|
||||
|
@ -258,6 +258,16 @@ impl CommandExecute for Install {
|
|||
Ok(_) | Err(_) =>
|
||||
". /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh".bold(),
|
||||
},
|
||||
maybe_ssl_cert_file_reminder = if let Some(ssl_cert_file) = &settings.ssl_cert_file {
|
||||
format!(
|
||||
"export NIX_SSL_CERT_FILE={:?}; ",
|
||||
ssl_cert_file
|
||||
.canonicalize()
|
||||
.map_err(|e| { eyre!(e).wrap_err(format!("Could not canonicalize {}", ssl_cert_file.display())) })?
|
||||
)
|
||||
} else {
|
||||
"".to_string()
|
||||
}
|
||||
);
|
||||
},
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*! Configurable knobs and their related errors
|
||||
*/
|
||||
use std::collections::HashMap;
|
||||
use std::{collections::HashMap, path::PathBuf};
|
||||
|
||||
#[cfg(feature = "cli")]
|
||||
use clap::ArgAction;
|
||||
|
@ -176,6 +176,10 @@ pub struct CommonSettings {
|
|||
#[cfg_attr(feature = "cli", clap(long, env = "NIX_INSTALLER_PROXY"))]
|
||||
pub(crate) proxy: Option<Url>,
|
||||
|
||||
/// An SSL cert to use (if any), used for fetching Nix and sets `NIX_SSL_CERT_FILE` for Nix
|
||||
#[cfg_attr(feature = "cli", clap(long, env = "NIX_INSTALLER_SSL_CERT_FILE"))]
|
||||
pub(crate) ssl_cert_file: Option<PathBuf>,
|
||||
|
||||
/// Extra configuration lines for `/etc/nix.conf`
|
||||
#[cfg_attr(feature = "cli", clap(long, action = ArgAction::Set, num_args = 0.., value_delimiter = ',', env = "NIX_INSTALLER_EXTRA_CONF", global = true))]
|
||||
pub extra_conf: Vec<String>,
|
||||
|
@ -279,6 +283,7 @@ impl CommonSettings {
|
|||
proxy: Default::default(),
|
||||
extra_conf: Default::default(),
|
||||
force: false,
|
||||
ssl_cert_file: Default::default(),
|
||||
#[cfg(feature = "diagnostics")]
|
||||
diagnostic_endpoint: Some(
|
||||
"https://install.determinate.systems/nix/diagnostic".try_into()?,
|
||||
|
@ -299,6 +304,7 @@ impl CommonSettings {
|
|||
proxy,
|
||||
extra_conf,
|
||||
force,
|
||||
ssl_cert_file,
|
||||
#[cfg(feature = "diagnostics")]
|
||||
diagnostic_endpoint,
|
||||
} = self;
|
||||
|
@ -333,6 +339,7 @@ impl CommonSettings {
|
|||
serde_json::to_value(nix_package_url)?,
|
||||
);
|
||||
map.insert("proxy".into(), serde_json::to_value(proxy)?);
|
||||
map.insert("ssl_cert_file".into(), serde_json::to_value(ssl_cert_file)?);
|
||||
map.insert("extra_conf".into(), serde_json::to_value(extra_conf)?);
|
||||
map.insert("force".into(), serde_json::to_value(force)?);
|
||||
|
||||
|
|
Loading…
Reference in a new issue