feat: enhance SSL detection in importer and improve certificate status handling in ProxyHosts

This commit is contained in:
Wikid82
2025-11-25 02:31:02 +00:00
parent c6dbd1291c
commit ea034ba102
3 changed files with 57 additions and 4 deletions

View File

@@ -42,6 +42,7 @@ type CaddyHTTP struct {
// CaddyServer represents a single server configuration.
type CaddyServer struct {
Listen []string `json:"listen,omitempty"`
Routes []*CaddyRoute `json:"routes,omitempty"`
TLSConnectionPolicies interface{} `json:"tls_connection_policies,omitempty"`
}
@@ -173,6 +174,16 @@ func (i *Importer) ExtractHosts(caddyJSON []byte) (*ImportResult, error) {
seenDomains := make(map[string]bool)
for serverName, server := range config.Apps.HTTP.Servers {
// Detect if this server uses SSL based on listen address or TLS policies
serverUsesSSL := server.TLSConnectionPolicies != nil
for _, listenAddr := range server.Listen {
// Check if listening on :443 or any HTTPS port indicator
if strings.Contains(listenAddr, ":443") || strings.HasSuffix(listenAddr, "443") {
serverUsesSSL = true
break
}
}
for routeIdx, route := range server.Routes {
for _, match := range route.Match {
for _, hostMatcher := range match.Host {
@@ -188,7 +199,7 @@ func (i *Importer) ExtractHosts(caddyJSON []byte) (*ImportResult, error) {
// Extract reverse proxy handler
host := ParsedHost{
DomainNames: domain,
SSLForced: strings.HasPrefix(domain, "https") || server.TLSConnectionPolicies != nil,
SSLForced: strings.HasPrefix(domain, "https") || serverUsesSSL,
}
// Find reverse_proxy handler (may be nested in subroute)

View File

@@ -166,6 +166,35 @@ func TestImporter_ExtractHosts(t *testing.T) {
assert.Len(t, result.Hosts[0].Warnings, 2)
assert.Contains(t, result.Hosts[0].Warnings, "File server directives not supported")
assert.Contains(t, result.Hosts[0].Warnings, "Rewrite rules not supported - manual configuration required")
// Test Case 6: SSL Detection via Listen Address (:443)
sslViaListenJSON := []byte(`{
"apps": {
"http": {
"servers": {
"srv0": {
"listen": [":443"],
"routes": [
{
"match": [{"host": ["secure.example.com"]}],
"handle": [
{
"handler": "reverse_proxy",
"upstreams": [{"dial": "127.0.0.1:9000"}]
}
]
}
]
}
}
}
}
}`)
result, err = importer.ExtractHosts(sslViaListenJSON)
assert.NoError(t, err)
assert.Len(t, result.Hosts, 1)
assert.Equal(t, "secure.example.com", result.Hosts[0].DomainNames)
assert.True(t, result.Hosts[0].SSLForced, "SSLForced should be true when server listens on :443")
}
func TestImporter_ImportFile(t *testing.T) {

View File

@@ -22,10 +22,18 @@ export default function ProxyHosts() {
const linkBehavior = settings?.['ui.domain_link_behavior'] || 'new_tab'
// Create a map of domain -> certificate status for quick lookup
// Handles both single domains and comma-separated multi-domain certs
const certStatusByDomain = useMemo(() => {
const map: Record<string, { status: string; provider: string }> = {}
certificates.forEach(cert => {
map[cert.domain] = { status: cert.status, provider: cert.provider }
// Handle comma-separated domains (SANs)
const domains = cert.domain.split(',').map(d => d.trim().toLowerCase())
domains.forEach(domain => {
// Only set if not already set (first cert wins)
if (!map[domain]) {
map[domain] = { status: cert.status, provider: cert.provider }
}
})
})
return map
}, [certificates])
@@ -148,11 +156,12 @@ export default function ProxyHosts() {
</td>
<td className="px-6 py-4 whitespace-nowrap">
{(() => {
// Get the primary domain to look up cert status
const primaryDomain = host.domain_names.split(',')[0]?.trim()
// Get the primary domain to look up cert status (case-insensitive)
const primaryDomain = host.domain_names.split(',')[0]?.trim().toLowerCase()
const certInfo = certStatusByDomain[primaryDomain]
const isUntrusted = certInfo?.status === 'untrusted'
const isStaging = certInfo?.provider?.includes('staging')
const hasCertInfo = !!certInfo
return (
<div className="flex flex-col gap-2">
@@ -185,6 +194,10 @@ export default function ProxyHosts() {
<div className="text-xs text-orange-400">
Staging cert - browsers won't trust
</div>
) : hasCertInfo ? (
<div className="text-xs text-green-400">
Let's Encrypt
</div>
) : (
<div className="text-xs text-blue-400">
Let's Encrypt (Auto)