1use hyper::client::HttpConnector;
2use hyper_tls::HttpsConnector;
3use native_tls::{TlsConnector, Identity, Protocol, Certificate};
4use crate::config::HttpsConfig;
5use crate::error::*;
6
7pub type HttpsConnectorType = HttpsConnector<HttpConnector>;
8
9pub struct HttpsSettings {
10 hc: HttpsConnectorType
11}
12
13impl From<HttpsConfig> for HttpsSettings {
14 fn from(config: HttpsConfig) -> HttpsSettings {
15 https_settings_from_config_f(config).unwrap_or_else(|e| panic!("https settings failure: {}", e))
16 }
17}
18
19pub type HttpsSettingsPtr = std::rc::Rc<HttpsSettings>;
20
21#[inline]
22pub fn https_settings_ptr(https_settings: HttpsSettings) -> HttpsSettingsPtr {
23 std::rc::Rc::new(https_settings)
24}
25
26pub fn https_connector(cfg: &HttpsSettingsPtr) -> HttpsConnectorType {
27 cfg.hc.clone()
28}
29
30fn _test_types() {
31 fn is_clone<T: Clone>() { }
32 is_clone::<HttpsConnectorType>();
33}
34
35
36pub fn read_identity_file(file_path: &str, password: &str) -> Result<Identity> {
37 use std::io::Read;
38 let mut file_data = vec![];
39 let _ = std::fs::File::open(file_path)?.read_to_end(&mut file_data)?;
40 let r = Identity::from_pkcs12(&file_data, password)?;
41 Ok(r)
42}
43
44pub fn read_cert_file(file_path: &str) -> Result<Certificate> {
45 use std::io::Read;
46 let mut file_data = vec![];
47 let _ = std::fs::File::open(file_path)?.read_to_end(&mut file_data)?;
48 let r = Certificate::from_der(&file_data)?;
49 Ok(r)
50}
51
52fn https_settings_from_config_f(config: HttpsConfig) -> Result<HttpsSettings> {
54 let identity_password: &str = if let Some(s) = &config.identity_password { &s } else { "" };
55
56 fn pv(s: String) -> Result<Option<Protocol>> {
57 match s.as_ref() {
58 "Sslv3" => Ok(Some(Protocol::Sslv3)),
59 "Tlsv10" => Ok(Some(Protocol::Tlsv10)),
60 "Tlsv11" => Ok(Some(Protocol::Tlsv11)),
61 "Tlsv12" => Ok(Some(Protocol::Tlsv12)),
62 "no_check" => Ok(None),
63 other => Err(app_error!(generic "Invalid TLS protocol version setting '{}'", other))
64 }
65 }
66
67 let mut cb = TlsConnector::builder();
68 if let Some(w) = config.danger_accept_invalid_certs { cb.danger_accept_invalid_certs(w); }
69 if let Some(w) = config.danger_accept_invalid_hostnames { cb.danger_accept_invalid_hostnames(w); }
70 if let Some(w) = config.use_sni { cb.use_sni(w); }
71 if let Some(w) = config.min_protocol_version { cb.min_protocol_version(pv(w)?); }
72 if let Some(w) = config.max_protocol_version { cb.max_protocol_version(pv(w)?); }
73 if let Some(w) = config.identity_file {
74 cb.identity(read_identity_file(&w,identity_password).aerr_f(|| format!("read_identity_file({}): error", &w))?);
75 }
76 if let Some(w) = config.root_certificates { for c in w { cb.add_root_certificate(read_cert_file(&c)?); } }
77 let tc = cb.build().unwrap_or_else(|e| panic!("HttpsConnector::new() failure: {}", e));
78 let mut httpc = HttpConnector::new();
79 httpc.enforce_http(false);
80 let hc: HttpsConnectorType = (httpc, tc.into()).into();
81 Ok(HttpsSettings { hc })
82}