nixos/filesystems: don't silently ignore label when device is set (#361418)
[NixPkgs.git] / pkgs / build-support / node / fetch-npm-deps / src / util.rs
blob023ba56793b9094004dc9d2029254ffbf3dae46a
1 use backoff::{retry, ExponentialBackoff};
2 use data_encoding::BASE64;
3 use digest::Digest;
4 use isahc::{
5     config::{CaCertificate, Configurable, RedirectPolicy, SslOption},
6     Body, Request, RequestExt,
7 };
8 use nix_nar::{Encoder, NarError};
9 use serde_json::{Map, Value};
10 use sha2::Sha256;
11 use std::{
12     env,
13     io::{self, Read},
14     path::Path,
16 use url::Url;
18 pub fn get_url(url: &Url) -> Result<Body, isahc::Error> {
19     let mut request = Request::get(url.as_str()).redirect_policy(RedirectPolicy::Limit(10));
21     // Respect SSL_CERT_FILE if environment variable exists
22     if let Ok(ssl_cert_file) = env::var("SSL_CERT_FILE") {
23         if Path::new(&ssl_cert_file).exists() {
24             // When file exists, use it. NIX_SSL_CERT_FILE will still override.
25             request = request.ssl_ca_certificate(CaCertificate::file(ssl_cert_file));
26         } else if env::var("outputHash").is_ok() {
27             // When file does not exist, assume we are downloading in a FOD and
28             // therefore do not need to check certificates, since the output is
29             // already hashed.
30             request = request.ssl_options(SslOption::DANGER_ACCEPT_INVALID_CERTS);
31         }
32     }
34     // Respect NIX_NPM_TOKENS environment variable, which should be a JSON mapping in the shape of:
35     // `{ "registry.example.com": "example-registry-bearer-token", ... }`
36     if let Some(host) = url.host_str() {
37         if let Ok(npm_tokens) = env::var("NIX_NPM_TOKENS") {
38             if let Ok(tokens) = serde_json::from_str::<Map<String, Value>>(&npm_tokens) {
39                 if let Some(token) = tokens.get(host).and_then(serde_json::Value::as_str) {
40                     request = request.header("Authorization", format!("Bearer {token}"));
41                 }
42             }
43         }
44     }
46     Ok(request.body(())?.send()?.into_body())
49 pub fn get_url_body_with_retry(url: &Url) -> Result<Vec<u8>, isahc::Error> {
50     retry(ExponentialBackoff::default(), || {
51         get_url(url)
52             .and_then(|mut body| {
53                 let mut buf = Vec::new();
55                 body.read_to_end(&mut buf)?;
57                 Ok(buf)
58             })
59             .map_err(|err| {
60                 if err.is_network() || err.is_timeout() {
61                     backoff::Error::transient(err)
62                 } else {
63                     backoff::Error::permanent(err)
64                 }
65             })
66     })
67     .map_err(|backoff_err| match backoff_err {
68         backoff::Error::Permanent(err)
69         | backoff::Error::Transient {
70             err,
71             retry_after: _,
72         } => err,
73     })
76 pub fn make_sri_hash(path: &Path) -> Result<String, NarError> {
77     let mut encoder = Encoder::new(path)?;
78     let mut hasher = Sha256::new();
80     io::copy(&mut encoder, &mut hasher)?;
82     Ok(format!("sha256-{}", BASE64.encode(&hasher.finalize())))