docker_registry/v2/
config.rs

1use log::trace;
2use reqwest::Certificate;
3
4use crate::{mediatypes::MediaTypes, v2::*};
5
6/// Configuration for a `Client`.
7#[derive(Debug)]
8pub struct Config {
9  index: String,
10  insecure_registry: bool,
11  user_agent: Option<String>,
12  username: Option<String>,
13  password: Option<String>,
14  accept_invalid_certs: bool,
15  root_certificates: Vec<Certificate>,
16  accepted_types: Option<Vec<(MediaTypes, Option<f64>)>>,
17}
18
19impl Config {
20  /// Set registry service to use (vhost or IP).
21  pub fn registry(mut self, reg: &str) -> Self {
22    self.index = reg.to_owned();
23    self
24  }
25
26  /// Whether to use an insecure HTTP connection to the registry.
27  pub fn insecure_registry(mut self, insecure: bool) -> Self {
28    self.insecure_registry = insecure;
29    self
30  }
31
32  /// Set whether or not to accept invalid certificates.
33  pub fn accept_invalid_certs(mut self, accept_invalid_certs: bool) -> Self {
34    self.accept_invalid_certs = accept_invalid_certs;
35    self
36  }
37
38  /// Add a root certificate the client should trust for TLS verification
39  pub fn add_root_certificate(mut self, certificate: Certificate) -> Self {
40    self.root_certificates.push(certificate);
41    self
42  }
43
44  /// Set custom Accept headers
45  pub fn accepted_types(mut self, accepted_types: Option<Vec<(MediaTypes, Option<f64>)>>) -> Self {
46    self.accepted_types = accepted_types;
47    self
48  }
49
50  /// Set the user-agent to be used for registry authentication.
51  pub fn user_agent(mut self, user_agent: Option<String>) -> Self {
52    self.user_agent = user_agent;
53    self
54  }
55
56  /// Set the username to be used for registry authentication.
57  pub fn username(mut self, user: Option<String>) -> Self {
58    self.username = user;
59    self
60  }
61
62  /// Set the password to be used for registry authentication.
63  pub fn password(mut self, password: Option<String>) -> Self {
64    self.password = password;
65    self
66  }
67
68  /// Read credentials from a JSON config file
69  pub fn read_credentials<T: ::std::io::Read>(mut self, reader: T) -> Self {
70    if let Ok(creds) = crate::get_credentials(reader, &self.index) {
71      self.username = creds.0;
72      self.password = creds.1;
73    };
74    self
75  }
76
77  /// Return a `Client` to interact with a v2 registry.
78  pub fn build(self) -> Result<Client> {
79    let base = if self.insecure_registry {
80      "http://".to_string() + &self.index
81    } else {
82      "https://".to_string() + &self.index
83    };
84    trace!(
85      "Built client for {:?}: endpoint {:?} - user {:?}",
86      self.index, base, self.username
87    );
88    let creds = match (self.username, self.password) {
89      (None, None) => None,
90      (u, p) => Some((u.unwrap_or_else(|| "".into()), p.unwrap_or_else(|| "".into()))),
91    };
92
93    let mut builder = reqwest::ClientBuilder::new().danger_accept_invalid_certs(self.accept_invalid_certs);
94
95    for ca in self.root_certificates {
96      builder = builder.add_root_certificate(ca)
97    }
98
99    let client = builder.build()?;
100
101    let accepted_types = match self.accepted_types {
102      Some(a) => a,
103      None => match self.index == "gcr.io" || self.index.ends_with(".gcr.io") || self.index.ends_with(".k8s.io") {
104        false => vec![
105          // accept header types and their q value, as documented in
106          // https://tools.ietf.org/html/rfc7231#section-5.3.2
107          (MediaTypes::ManifestV2S2, Some(0.5)),
108          (MediaTypes::ManifestV2S1Signed, Some(0.4)),
109          (MediaTypes::ManifestList, Some(0.5)),
110          (MediaTypes::OciImageManifest, Some(0.5)),
111          (MediaTypes::OciImageIndexV1, Some(0.5)),
112        ],
113        // GCR incorrectly parses `q` parameters, so we use special Accept for it.
114        // Bug: https://issuetracker.google.com/issues/159827510.
115        // TODO: when bug is fixed, this workaround should be removed.
116        // *.k8s.io container registries use GCR and are similarly affected.
117        true => vec![
118          (MediaTypes::ManifestV2S2, None),
119          (MediaTypes::ManifestV2S1Signed, None),
120          (MediaTypes::ManifestList, None),
121          (MediaTypes::OciImageManifest, None),
122          (MediaTypes::OciImageIndexV1, None),
123        ],
124      },
125    };
126    let c = Client {
127      base_url: base,
128      credentials: creds,
129      user_agent: self.user_agent,
130      auth: None,
131      client,
132      accepted_types,
133    };
134    Ok(c)
135  }
136}
137
138impl Default for Config {
139  /// Initialize `Config` with default values.
140  fn default() -> Self {
141    Self {
142      index: "registry-1.docker.io".into(),
143      insecure_registry: false,
144      accept_invalid_certs: false,
145      root_certificates: Default::default(),
146      accepted_types: None,
147      user_agent: Some(crate::USER_AGENT.to_owned()),
148      username: None,
149      password: None,
150    }
151  }
152}