feat: enhance SSL detection in importer and improve certificate status handling in ProxyHosts
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user