mirror of
https://github.com/yusing/godoxy.git
synced 2026-04-21 16:01:22 +02:00
Add per-provider obtain serialization and an RWMutex around shared provider fields. GetCert and SNI matching use snapshot helpers; rebuild the matcher atomically; GetExpiries returns a cloned map. Clone Config.HTTPClient (including Transport) per lego.Config so parallel providers do not mutate shared client state. Document the concurrency model in README.
134 lines
2.4 KiB
Go
134 lines
2.4 KiB
Go
package autocert
|
|
|
|
import (
|
|
"crypto/x509"
|
|
"strings"
|
|
)
|
|
|
|
type sniMatcher struct {
|
|
exact map[string]*Provider
|
|
root sniTreeNode
|
|
}
|
|
|
|
type sniTreeNode struct {
|
|
children map[string]*sniTreeNode
|
|
wildcard *Provider
|
|
}
|
|
|
|
func (m *sniMatcher) match(serverName string) *Provider {
|
|
if m == nil {
|
|
return nil
|
|
}
|
|
serverName = normalizeServerName(serverName)
|
|
if serverName == "" {
|
|
return nil
|
|
}
|
|
if m.exact != nil {
|
|
if p, ok := m.exact[serverName]; ok {
|
|
return p
|
|
}
|
|
}
|
|
return m.matchSuffixTree(serverName)
|
|
}
|
|
|
|
func (m *sniMatcher) matchSuffixTree(serverName string) *Provider {
|
|
n := &m.root
|
|
labels := strings.Split(serverName, ".")
|
|
|
|
var best *Provider
|
|
for i := len(labels) - 1; i >= 0; i-- {
|
|
if n.children == nil {
|
|
break
|
|
}
|
|
next := n.children[labels[i]]
|
|
if next == nil {
|
|
break
|
|
}
|
|
n = next
|
|
|
|
consumed := len(labels) - i
|
|
remaining := len(labels) - consumed
|
|
if remaining == 1 && n.wildcard != nil {
|
|
best = n.wildcard
|
|
}
|
|
}
|
|
return best
|
|
}
|
|
|
|
func normalizeServerName(s string) string {
|
|
s = strings.TrimSpace(s)
|
|
s = strings.TrimSuffix(s, ".")
|
|
return strings.ToLower(s)
|
|
}
|
|
|
|
func (m *sniMatcher) addProvider(p *Provider) {
|
|
if p == nil {
|
|
return
|
|
}
|
|
tlsCert := p.getTLSCert()
|
|
if tlsCert == nil || len(tlsCert.Certificate) == 0 {
|
|
return
|
|
}
|
|
leaf, err := x509.ParseCertificate(tlsCert.Certificate[0])
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
addName := func(name string) {
|
|
name = normalizeServerName(name)
|
|
if name == "" {
|
|
return
|
|
}
|
|
if after, ok := strings.CutPrefix(name, "*."); ok {
|
|
suffix := after
|
|
if suffix == "" {
|
|
return
|
|
}
|
|
m.insertWildcardSuffix(suffix, p)
|
|
return
|
|
}
|
|
m.insertExact(name, p)
|
|
}
|
|
|
|
if leaf.Subject.CommonName != "" {
|
|
addName(leaf.Subject.CommonName)
|
|
}
|
|
for _, n := range leaf.DNSNames {
|
|
addName(n)
|
|
}
|
|
}
|
|
|
|
func (m *sniMatcher) insertExact(name string, p *Provider) {
|
|
if name == "" || p == nil {
|
|
return
|
|
}
|
|
if m.exact == nil {
|
|
m.exact = make(map[string]*Provider)
|
|
}
|
|
if _, exists := m.exact[name]; !exists {
|
|
m.exact[name] = p
|
|
}
|
|
}
|
|
|
|
func (m *sniMatcher) insertWildcardSuffix(suffix string, p *Provider) {
|
|
if suffix == "" || p == nil {
|
|
return
|
|
}
|
|
n := &m.root
|
|
labels := strings.Split(suffix, ".")
|
|
for i := len(labels) - 1; i >= 0; i-- {
|
|
if n.children == nil {
|
|
n.children = make(map[string]*sniTreeNode)
|
|
}
|
|
next := n.children[labels[i]]
|
|
if next == nil {
|
|
next = &sniTreeNode{}
|
|
n.children[labels[i]] = next
|
|
}
|
|
n = next
|
|
}
|
|
if n.wildcard == nil {
|
|
n.wildcard = p
|
|
}
|
|
}
|