mirror of
				https://github.com/juspay/hyperswitch.git
				synced 2025-11-01 02:57:02 +08:00 
			
		
		
		
	feat(tls): add support for https in actix web (#5089)
Co-authored-by: noagbmn <>
This commit is contained in:
		
							
								
								
									
										64
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										64
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							| @ -43,6 +43,7 @@ dependencies = [ | ||||
|  "actix-codec", | ||||
|  "actix-rt", | ||||
|  "actix-service", | ||||
|  "actix-tls", | ||||
|  "actix-utils", | ||||
|  "ahash 0.8.11", | ||||
|  "base64 0.21.7", | ||||
| @ -187,8 +188,10 @@ dependencies = [ | ||||
|  "http 1.1.0", | ||||
|  "impl-more", | ||||
|  "pin-project-lite", | ||||
|  "rustls-pki-types", | ||||
|  "tokio 1.37.0", | ||||
|  "tokio-rustls 0.23.4", | ||||
|  "tokio-rustls 0.25.0", | ||||
|  "tokio-util", | ||||
|  "tracing", | ||||
|  "webpki-roots 0.22.6", | ||||
| @ -217,6 +220,7 @@ dependencies = [ | ||||
|  "actix-rt", | ||||
|  "actix-server", | ||||
|  "actix-service", | ||||
|  "actix-tls", | ||||
|  "actix-utils", | ||||
|  "actix-web-codegen", | ||||
|  "ahash 0.8.11", | ||||
| @ -5800,7 +5804,7 @@ dependencies = [ | ||||
|  "percent-encoding", | ||||
|  "pin-project-lite", | ||||
|  "rustls 0.21.10", | ||||
|  "rustls-pemfile", | ||||
|  "rustls-pemfile 1.0.4", | ||||
|  "serde", | ||||
|  "serde_json", | ||||
|  "serde_urlencoded", | ||||
| @ -5990,6 +5994,8 @@ dependencies = [ | ||||
|  "roxmltree", | ||||
|  "rust_decimal", | ||||
|  "rustc-hash", | ||||
|  "rustls 0.22.4", | ||||
|  "rustls-pemfile 2.1.2", | ||||
|  "scheduler", | ||||
|  "serde", | ||||
|  "serde_json", | ||||
| @ -6219,10 +6225,24 @@ checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" | ||||
| dependencies = [ | ||||
|  "log", | ||||
|  "ring 0.17.8", | ||||
|  "rustls-webpki", | ||||
|  "rustls-webpki 0.101.7", | ||||
|  "sct", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "rustls" | ||||
| version = "0.22.4" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" | ||||
| dependencies = [ | ||||
|  "log", | ||||
|  "ring 0.17.8", | ||||
|  "rustls-pki-types", | ||||
|  "rustls-webpki 0.102.3", | ||||
|  "subtle", | ||||
|  "zeroize", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "rustls-native-certs" | ||||
| version = "0.6.3" | ||||
| @ -6230,7 +6250,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" | ||||
| dependencies = [ | ||||
|  "openssl-probe", | ||||
|  "rustls-pemfile", | ||||
|  "rustls-pemfile 1.0.4", | ||||
|  "schannel", | ||||
|  "security-framework", | ||||
| ] | ||||
| @ -6244,6 +6264,22 @@ dependencies = [ | ||||
|  "base64 0.21.7", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "rustls-pemfile" | ||||
| version = "2.1.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" | ||||
| dependencies = [ | ||||
|  "base64 0.22.0", | ||||
|  "rustls-pki-types", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "rustls-pki-types" | ||||
| version = "1.5.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "beb461507cee2c2ff151784c52762cf4d9ff6a61f3e80968600ed24fa837fa54" | ||||
|  | ||||
| [[package]] | ||||
| name = "rustls-webpki" | ||||
| version = "0.101.7" | ||||
| @ -6254,6 +6290,17 @@ dependencies = [ | ||||
|  "untrusted 0.9.0", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "rustls-webpki" | ||||
| version = "0.102.3" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "f3bce581c0dd41bce533ce695a1437fa16a7ab5ac3ccfa99fe1a620a7885eabf" | ||||
| dependencies = [ | ||||
|  "ring 0.17.8", | ||||
|  "rustls-pki-types", | ||||
|  "untrusted 0.9.0", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "rustversion" | ||||
| version = "1.0.14" | ||||
| @ -7625,6 +7672,17 @@ dependencies = [ | ||||
|  "tokio 1.37.0", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "tokio-rustls" | ||||
| version = "0.25.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" | ||||
| dependencies = [ | ||||
|  "rustls 0.22.4", | ||||
|  "rustls-pki-types", | ||||
|  "tokio 1.37.0", | ||||
| ] | ||||
|  | ||||
| [[package]] | ||||
| name = "tokio-stream" | ||||
| version = "0.1.15" | ||||
|  | ||||
| @ -11,6 +11,15 @@ host = "127.0.0.1" | ||||
| shutdown_timeout = 30 | ||||
| # HTTP Request body limit. Defaults to 32kB | ||||
| request_body_limit = 32_768 | ||||
|  | ||||
| # HTTPS Server Configuration | ||||
| # Self-signed Private Key and Certificate can be generated with mkcert for local development | ||||
| [server.tls] | ||||
| port = 8081 | ||||
| host = "127.0.0.1" | ||||
| private_key = "/path/to/private_key.pem" | ||||
| certificate = "/path/to/certificate.pem" | ||||
|  | ||||
| # Proxy server configuration for connecting to payment gateways. | ||||
| # Don't define the fields if a Proxy isn't needed. Empty strings will cause failure. | ||||
| [proxy] | ||||
|  | ||||
| @ -265,6 +265,14 @@ shutdown_timeout = 30 | ||||
| # HTTP Request body limit. Defaults to 32kB | ||||
| request_body_limit = 32_768 | ||||
|  | ||||
| # HTTPS Server Configuration | ||||
| # Self-signed Private Key and Certificate can be generated with mkcert for local development | ||||
| [server.tls] | ||||
| port = 8081 | ||||
| host = "127.0.0.1" | ||||
| private_key = "/path/to/private_key.pem" | ||||
| certificate = "/path/to/certificate.pem" | ||||
|  | ||||
| [secrets_management] | ||||
| secrets_manager = "aws_kms" # Secrets manager client to be used | ||||
|  | ||||
|  | ||||
| @ -9,7 +9,8 @@ readme = "README.md" | ||||
| license.workspace = true | ||||
|  | ||||
| [features] | ||||
| default = ["kv_store", "stripe", "oltp", "olap", "backwards_compatibility", "accounts_cache", "dummy_connector", "payouts", "payout_retry", "business_profile_routing", "connector_choice_mca_id", "profile_specific_fallback_routing", "retry", "frm"] | ||||
| default = ["kv_store", "stripe", "oltp", "olap", "backwards_compatibility", "accounts_cache", "dummy_connector", "payouts", "payout_retry", "business_profile_routing", "connector_choice_mca_id", "profile_specific_fallback_routing", "retry", "frm", "tls"] | ||||
| tls = ["actix-web/rustls-0_22"] | ||||
| email = ["external_services/email", "scheduler/email", "olap"] | ||||
| frm = ["api_models/frm", "hyperswitch_domain_models/frm"] | ||||
| stripe = ["dep:serde_qs"] | ||||
| @ -77,6 +78,8 @@ ring = "0.17.8" | ||||
| roxmltree = "0.19.0" | ||||
| rust_decimal = { version = "1.35.0", features = ["serde-with-float", "serde-with-str"] } | ||||
| rustc-hash = "1.1.0" | ||||
| rustls = "0.22" | ||||
| rustls-pemfile = "2" | ||||
| serde = { version = "1.0.197", features = ["derive"] } | ||||
| serde_json = "1.0.115" | ||||
| serde_path_to_error = "0.1.16" | ||||
|  | ||||
| @ -12,6 +12,8 @@ impl Default for super::settings::Server { | ||||
|             host: "localhost".into(), | ||||
|             request_body_limit: 16 * 1024, // POST request body is limited to 16KiB | ||||
|             shutdown_timeout: 30, | ||||
|             #[cfg(feature = "tls")] | ||||
|             tls: None, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -547,6 +547,8 @@ pub struct Server { | ||||
|     pub host: String, | ||||
|     pub request_body_limit: usize, | ||||
|     pub shutdown_timeout: u64, | ||||
|     #[cfg(feature = "tls")] | ||||
|     pub tls: Option<ServerTls>, | ||||
| } | ||||
|  | ||||
| #[derive(Debug, Deserialize, Clone)] | ||||
| @ -826,6 +828,19 @@ pub struct PayPalOnboarding { | ||||
|     pub enabled: bool, | ||||
| } | ||||
|  | ||||
| #[cfg(feature = "tls")] | ||||
| #[derive(Debug, Deserialize, Clone)] | ||||
| pub struct ServerTls { | ||||
|     /// Port to host the TLS secure server on | ||||
|     pub port: u16, | ||||
|     /// Use a different host (optional) (defaults to the host provided in [`Server`] config) | ||||
|     pub host: Option<String>, | ||||
|     /// private key file path associated with TLS (path to the private key file (`pem` format)) | ||||
|     pub private_key: PathBuf, | ||||
|     /// certificate file associated with TLS (path to the certificate file (`pem` format)) | ||||
|     pub certificate: PathBuf, | ||||
| } | ||||
|  | ||||
| fn deserialize_hashset_inner<T>(value: impl AsRef<str>) -> Result<HashSet<T>, String> | ||||
| where | ||||
|     T: Eq + std::str::FromStr + std::hash::Hash, | ||||
|  | ||||
| @ -200,11 +200,65 @@ pub async fn start_server(conf: settings::Settings<SecuredSecret>) -> Applicatio | ||||
|     ); | ||||
|     let state = Box::pin(AppState::new(conf, tx, api_client)).await; | ||||
|     let request_body_limit = server.request_body_limit; | ||||
|     let server = actix_web::HttpServer::new(move || mk_app(state.clone(), request_body_limit)) | ||||
|  | ||||
|     let server_builder = | ||||
|         actix_web::HttpServer::new(move || mk_app(state.clone(), request_body_limit)) | ||||
|             .bind((server.host.as_str(), server.port))? | ||||
|             .workers(server.workers) | ||||
|         .shutdown_timeout(server.shutdown_timeout) | ||||
|         .run(); | ||||
|             .shutdown_timeout(server.shutdown_timeout); | ||||
|  | ||||
|     #[cfg(feature = "tls")] | ||||
|     let server = match server.tls { | ||||
|         None => server_builder.run(), | ||||
|         Some(tls_conf) => { | ||||
|             let cert_file = | ||||
|                 &mut std::io::BufReader::new(std::fs::File::open(tls_conf.certificate).map_err( | ||||
|                     |err| errors::ApplicationError::InvalidConfigurationValueError(err.to_string()), | ||||
|                 )?); | ||||
|             let key_file = | ||||
|                 &mut std::io::BufReader::new(std::fs::File::open(tls_conf.private_key).map_err( | ||||
|                     |err| errors::ApplicationError::InvalidConfigurationValueError(err.to_string()), | ||||
|                 )?); | ||||
|  | ||||
|             let cert_chain = rustls_pemfile::certs(cert_file) | ||||
|                 .collect::<Result<Vec<_>, _>>() | ||||
|                 .map_err(|err| { | ||||
|                     errors::ApplicationError::InvalidConfigurationValueError(err.to_string()) | ||||
|                 })?; | ||||
|  | ||||
|             let mut keys = rustls_pemfile::pkcs8_private_keys(key_file) | ||||
|                 .map(|key| key.map(rustls::pki_types::PrivateKeyDer::Pkcs8)) | ||||
|                 .collect::<Result<Vec<_>, _>>() | ||||
|                 .map_err(|err| { | ||||
|                     errors::ApplicationError::InvalidConfigurationValueError(err.to_string()) | ||||
|                 })?; | ||||
|  | ||||
|             // exit if no keys could be parsed | ||||
|             if keys.is_empty() { | ||||
|                 return Err(errors::ApplicationError::InvalidConfigurationValueError( | ||||
|                     "Could not locate PKCS8 private keys.".into(), | ||||
|                 )); | ||||
|             } | ||||
|  | ||||
|             let config_builder = rustls::ServerConfig::builder().with_no_client_auth(); | ||||
|             let config = config_builder | ||||
|                 .with_single_cert(cert_chain, keys.remove(0)) | ||||
|                 .map_err(|err| { | ||||
|                     errors::ApplicationError::InvalidConfigurationValueError(err.to_string()) | ||||
|                 })?; | ||||
|  | ||||
|             server_builder | ||||
|                 .bind_rustls_0_22( | ||||
|                     (tls_conf.host.unwrap_or(server.host).as_str(), tls_conf.port), | ||||
|                     config, | ||||
|                 )? | ||||
|                 .run() | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     #[cfg(not(feature = "tls"))] | ||||
|     let server = server_builder.run(); | ||||
|  | ||||
|     let _task_handle = tokio::spawn(receiver_for_error(rx, server.handle()).in_current_span()); | ||||
|     Ok(server) | ||||
| } | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 Noa
					Noa