aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-08-11 00:07:15 +0900
committernsfisis <nsfisis@gmail.com>2026-08-11 00:08:05 +0900
commit144d059b725e2d178d7f4a6403cde9474fe65dcc (patch)
tree09f48dc2296a1c1e052018968b34fec31b364767 /crates
parentb65e338d4cf06afb8237512e49a51e354277196d (diff)
downloadphp-shirabe-144d059b725e2d178d7f4a6403cde9474fe65dcc.tar.gz
php-shirabe-144d059b725e2d178d7f4a6403cde9474fe65dcc.tar.zst
php-shirabe-144d059b725e2d178d7f4a6403cde9474fe65dcc.zip
refactor(util): drop the unused TlsHelper port
Composer's Composer\Util\TlsHelper is marked deprecated for removal in Composer 3.0 and has no caller in composer/composer outside its own test: PHP's stream layer verifies certificate hostnames itself, and the one surviving method delegates to composer/ca-bundle. The Rust port had no caller either, so it, its test, and the openssl_x509_parse shim it was the sole user of are removed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'crates')
-rw-r--r--crates/shirabe-php-shim/src/openssl.rs10
-rw-r--r--crates/shirabe/src/util.rs2
-rw-r--r--crates/shirabe/src/util/tls_helper.rs149
-rw-r--r--crates/shirabe/tests/util/main.rs1
-rw-r--r--crates/shirabe/tests/util/tls_helper_test.rs138
5 files changed, 0 insertions, 300 deletions
diff --git a/crates/shirabe-php-shim/src/openssl.rs b/crates/shirabe-php-shim/src/openssl.rs
index d24caa63..471f80f3 100644
--- a/crates/shirabe-php-shim/src/openssl.rs
+++ b/crates/shirabe-php-shim/src/openssl.rs
@@ -1,13 +1,3 @@
-use crate::PhpMixed;
-use indexmap::IndexMap;
-
pub const OPENSSL_ALGO_SHA384: i64 = 9;
pub const OPENSSL_VERSION_NUMBER: i64 = 0;
pub const OPENSSL_VERSION_TEXT: &str = "";
-
-pub fn openssl_x509_parse(
- _certificate: &str,
- _short_names: bool,
-) -> Option<IndexMap<String, PhpMixed>> {
- todo!()
-}
diff --git a/crates/shirabe/src/util.rs b/crates/shirabe/src/util.rs
index 35402d79..613b615e 100644
--- a/crates/shirabe/src/util.rs
+++ b/crates/shirabe/src/util.rs
@@ -28,7 +28,6 @@ pub mod svn;
pub mod sync_executor;
pub mod sync_helper;
pub mod tar;
-pub mod tls_helper;
pub mod url;
pub mod zip;
@@ -60,6 +59,5 @@ pub use stream_context_factory::*;
pub use svn::*;
pub use sync_helper::*;
pub use tar::*;
-pub use tls_helper::*;
pub use url::*;
pub use zip::*;
diff --git a/crates/shirabe/src/util/tls_helper.rs b/crates/shirabe/src/util/tls_helper.rs
deleted file mode 100644
index 0c3f44dc..00000000
--- a/crates/shirabe/src/util/tls_helper.rs
+++ /dev/null
@@ -1,149 +0,0 @@
-//! ref: composer/src/Composer/Util/TlsHelper.php
-
-use shirabe_ca_bundle::ca_bundle::CaBundle;
-use shirabe_pcre::Preg;
-use shirabe_php_shim::{
- PhpMixed, ltrim, php_regex, preg_quote, str_replace, strtolower, substr, substr_count,
-};
-
-/// Extracted certificate names. Mirrors PHP's `array{cn: string, san: string[]}`.
-#[derive(Debug, Clone)]
-pub struct CertificateNames {
- pub cn: String,
- pub san: Vec<String>,
-}
-
-/// Match hostname against a certificate.
-///
-/// @deprecated Use composer/ca-bundle and composer/composer 2.2 if you still need PHP 5
-/// compatibility, this class will be removed in Composer 3.0
-#[derive(Debug)]
-pub struct TlsHelper;
-
-impl TlsHelper {
- /// Match hostname against a certificate. Sets `cn` to the common name of the
- /// certificate iff a match is found.
- pub fn check_certificate_host(
- certificate: &PhpMixed,
- hostname: &str,
- cn: &mut Option<String>,
- ) -> bool {
- let names = Self::get_certificate_names(certificate);
-
- let Some(names) = names else {
- return false;
- };
-
- let mut combined_names = names.san.clone();
- combined_names.push(names.cn.clone());
- let hostname = strtolower(hostname);
-
- for cert_name in &combined_names {
- let matcher = Self::cert_name_matcher(cert_name);
-
- if let Some(matcher) = matcher
- && matcher(&hostname)
- {
- *cn = Some(names.cn);
-
- return true;
- }
- }
-
- false
- }
-
- /// Extract DNS names out of an X.509 certificate.
- pub fn get_certificate_names(certificate: &PhpMixed) -> Option<CertificateNames> {
- let info: Option<&PhpMixed> = if certificate.as_array().is_some() {
- Some(certificate)
- } else if CaBundle::is_openssl_parse_safe() {
- // TODO(phase-c): openssl_x509_parse on a PEM string certificate.
- todo!("openssl_x509_parse for non-array certificates")
- } else {
- None
- };
-
- let info = info?.as_array()?;
-
- let common_name = info
- .get("subject")
- .and_then(|s| s.as_array())
- .and_then(|s| s.get("commonName"))
- .and_then(|c| c.as_string());
-
- let common_name = strtolower(common_name?);
- let mut subject_alt_names: Vec<String> = Vec::new();
-
- if let Some(san) = info
- .get("extensions")
- .and_then(|e| e.as_array())
- .and_then(|e| e.get("subjectAltName"))
- .and_then(|s| s.as_string())
- {
- let split = Preg::split(php_regex!("{\\s*,\\s*}"), san);
- subject_alt_names = split
- .into_iter()
- .filter_map(|name| {
- if name.starts_with("DNS:") {
- Some(strtolower(&ltrim(&substr(&name, 4, None), None)))
- } else {
- None
- }
- })
- .collect();
- }
-
- Some(CertificateNames {
- cn: common_name,
- san: subject_alt_names,
- })
- }
-
- /// Get the certificate pin.
- pub fn get_certificate_fingerprint(_certificate: &str) -> String {
- todo!("openssl public key extraction and sha1 fingerprint")
- }
-
- /// Test if it is safe to use the PHP function openssl_x509_parse().
- pub fn is_openssl_parse_safe() -> bool {
- CaBundle::is_openssl_parse_safe()
- }
-
- /// Convert certificate name into matching function.
- fn cert_name_matcher(cert_name: &str) -> Option<Box<dyn Fn(&str) -> bool>> {
- let wildcards = substr_count(cert_name, "*");
-
- if wildcards == 0 {
- // Literal match.
- let cert_name = cert_name.to_string();
- return Some(Box::new(move |hostname: &str| hostname == cert_name));
- }
-
- if wildcards == 1 {
- let components: Vec<&str> = cert_name.split('.').collect();
-
- if components.len() < 3 {
- // Must have 3+ components
- return None;
- }
-
- let first_component = components[0];
-
- // Wildcard must be the last character.
- if !first_component.ends_with('*') {
- return None;
- }
-
- let mut wildcard_regex = preg_quote(cert_name, None);
- wildcard_regex = str_replace("\\*", "[a-z0-9-]+", &wildcard_regex);
- let wildcard_regex = format!("{{^{}$}}", wildcard_regex);
-
- return Some(Box::new(move |hostname: &str| {
- Preg::is_match(&wildcard_regex, hostname)
- }));
- }
-
- None
- }
-}
diff --git a/crates/shirabe/tests/util/main.rs b/crates/shirabe/tests/util/main.rs
index 0208ca48..05e8ea14 100644
--- a/crates/shirabe/tests/util/main.rs
+++ b/crates/shirabe/tests/util/main.rs
@@ -33,6 +33,5 @@ mod silencer_test;
mod stream_context_factory_test;
mod svn_test;
mod tar_test;
-mod tls_helper_test;
mod url_test;
mod zip_test;
diff --git a/crates/shirabe/tests/util/tls_helper_test.rs b/crates/shirabe/tests/util/tls_helper_test.rs
deleted file mode 100644
index 53e39d69..00000000
--- a/crates/shirabe/tests/util/tls_helper_test.rs
+++ /dev/null
@@ -1,138 +0,0 @@
-//! ref: composer/tests/Composer/Test/Util/TlsHelperTest.php
-
-use indexmap::IndexMap;
-use shirabe::util::tls_helper::TlsHelper;
-use shirabe_php_shim::PhpMixed;
-
-// Builds the `['subject' => ['commonName' => ..], 'extensions' => ['subjectAltName' => ..]]`
-// certificate array used by the test, given the common name and the subjectAltName string.
-fn certificate(common_name: &str, subject_alt_name: &str) -> PhpMixed {
- let mut subject = IndexMap::new();
- subject.insert(
- "commonName".to_string(),
- PhpMixed::String(common_name.to_string()),
- );
- let mut extensions = IndexMap::new();
- extensions.insert(
- "subjectAltName".to_string(),
- PhpMixed::String(subject_alt_name.to_string()),
- );
- let mut cert = IndexMap::new();
- cert.insert("subject".to_string(), PhpMixed::Array(subject));
- cert.insert("extensions".to_string(), PhpMixed::Array(extensions));
- PhpMixed::Array(cert)
-}
-
-/// ref: TlsHelperTest::dataCheckCertificateHost
-fn data_check_certificate_host() -> Vec<(bool, &'static str, Vec<&'static str>)> {
- vec![
- (true, "getcomposer.org", vec!["getcomposer.org"]),
- (
- true,
- "getcomposer.org",
- vec!["getcomposer.org", "packagist.org"],
- ),
- (
- true,
- "getcomposer.org",
- vec!["packagist.org", "getcomposer.org"],
- ),
- (true, "foo.getcomposer.org", vec!["*.getcomposer.org"]),
- (false, "xyz.foo.getcomposer.org", vec!["*.getcomposer.org"]),
- (
- true,
- "foo.getcomposer.org",
- vec!["getcomposer.org", "*.getcomposer.org"],
- ),
- (
- true,
- "foo.getcomposer.org",
- vec!["foo.getcomposer.org", "foo*.getcomposer.org"],
- ),
- (
- true,
- "foo1.getcomposer.org",
- vec!["foo.getcomposer.org", "foo*.getcomposer.org"],
- ),
- (
- true,
- "foo2.getcomposer.org",
- vec!["foo.getcomposer.org", "foo*.getcomposer.org"],
- ),
- (
- false,
- "foo2.another.getcomposer.org",
- vec!["foo.getcomposer.org", "foo*.getcomposer.org"],
- ),
- (
- false,
- "test.example.net",
- vec!["**.example.net", "**.example.net"],
- ),
- (
- false,
- "test.example.net",
- vec!["t*t.example.net", "t*t.example.net"],
- ),
- (
- false,
- "xyz.example.org",
- vec!["*z.example.org", "*z.example.org"],
- ),
- (
- false,
- "foo.bar.example.com",
- vec!["foo.*.example.com", "foo.*.example.com"],
- ),
- (false, "example.com", vec!["example.*", "example.*"]),
- (true, "localhost", vec!["localhost"]),
- (false, "localhost", vec!["*"]),
- (false, "localhost", vec!["local*"]),
- (false, "example.net", vec!["*.net", "*.org", "ex*.net"]),
- (true, "example.net", vec!["*.net", "*.org", "example.net"]),
- ]
-}
-
-#[test]
-fn test_check_certificate_host() {
- for (expected_result, hostname, mut cert_names) in data_check_certificate_host() {
- let expected_cn = cert_names.remove(0);
- let subject_alt_name = if cert_names.is_empty() {
- String::new()
- } else {
- format!("DNS:{}", cert_names.join(",DNS:"))
- };
- let cert = certificate(expected_cn, &subject_alt_name);
-
- let mut found_cn: Option<String> = None;
- let result = TlsHelper::check_certificate_host(&cert, hostname, &mut found_cn);
-
- if expected_result {
- assert!(result, "hostname {hostname} should match");
- assert_eq!(found_cn.as_deref(), Some(expected_cn));
- } else {
- assert!(!result, "hostname {hostname} should not match");
- assert_eq!(found_cn, None);
- }
- }
-}
-
-#[test]
-fn test_get_certificate_names() {
- let cert = certificate(
- "example.net",
- "DNS: example.com, IP: 127.0.0.1, DNS: getcomposer.org, Junk: blah, DNS: composer.example.org",
- );
-
- let names = TlsHelper::get_certificate_names(&cert).unwrap();
-
- assert_eq!(names.cn, "example.net");
- assert_eq!(
- names.san,
- vec![
- "example.com".to_string(),
- "getcomposer.org".to_string(),
- "composer.example.org".to_string(),
- ]
- );
-}