Update documentation

This commit is contained in:
Adnan Maolood 2020-10-28 16:02:04 -04:00
parent 34ae2a9066
commit b5fbd197a1
4 changed files with 37 additions and 45 deletions

29
cert.go
View File

@ -8,7 +8,6 @@ import (
"crypto/x509" "crypto/x509"
"math/big" "math/big"
"net" "net"
"path"
"path/filepath" "path/filepath"
"strings" "strings"
"time" "time"
@ -36,9 +35,9 @@ func (c *CertificateStore) Add(scope string, cert tls.Certificate) {
c.store[scope] = cert c.store[scope] = cert
} }
// Lookup returns the certificate for the given hostname. // Lookup returns the certificate for the given scope.
func (c *CertificateStore) Lookup(hostname string) (*tls.Certificate, error) { func (c *CertificateStore) Lookup(scope string) (*tls.Certificate, error) {
cert, ok := c.store[hostname] cert, ok := c.store[scope]
if !ok { if !ok {
return nil, ErrCertificateUnknown return nil, ErrCertificateUnknown
} }
@ -49,25 +48,9 @@ func (c *CertificateStore) Lookup(hostname string) (*tls.Certificate, error) {
return &cert, nil return &cert, nil
} }
// lookup returns the certificate for the given hostname + path.
func (c *CertificateStore) lookup(scope string) (*tls.Certificate, error) {
for {
cert, err := c.Lookup(scope)
switch err {
case ErrCertificateExpired, nil:
return cert, err
}
scope = path.Dir(scope)
if scope == "." {
break
}
}
return nil, ErrCertificateUnknown
}
// Load loads certificates from the given path. // Load loads certificates from the given path.
// The path should lead to a directory containing certificates and private keys // The path should lead to a directory containing certificates and private keys
// in the form hostname.crt and hostname.key. // in the form scope.crt and scope.key.
// For example, the hostname "localhost" would have the corresponding files // For example, the hostname "localhost" would have the corresponding files
// localhost.crt (certificate) and localhost.key (private key). // localhost.crt (certificate) and localhost.key (private key).
func (c *CertificateStore) Load(path string) error { func (c *CertificateStore) Load(path string) error {
@ -81,8 +64,8 @@ func (c *CertificateStore) Load(path string) error {
if err != nil { if err != nil {
continue continue
} }
hostname := strings.TrimSuffix(filepath.Base(crtPath), ".crt") scope := strings.TrimSuffix(filepath.Base(crtPath), ".crt")
c.Add(hostname, cert) c.Add(scope, cert)
} }
return nil return nil
} }

View File

@ -6,6 +6,7 @@ import (
"crypto/x509" "crypto/x509"
"net" "net"
"net/url" "net/url"
"path"
"strings" "strings"
) )
@ -153,12 +154,23 @@ func (c *Client) getClientCertificate(req *Request) (*tls.Certificate, error) {
if req.Certificate != nil { if req.Certificate != nil {
return req.Certificate, nil return req.Certificate, nil
} }
hostname, path := req.URL.Hostname(), strings.TrimSuffix(req.URL.Path, "/")
if cert, err := c.Certificates.lookup(hostname + path); err == nil { // Search recursively for the certificate
// Remember the certificate used scope := req.URL.Hostname() + strings.TrimSuffix(req.URL.Path, "/")
req.Certificate = cert for {
return cert, nil cert, err := c.Certificates.Lookup(scope)
if err == nil {
return cert, err
}
if err == ErrCertificateExpired {
break
}
scope = path.Dir(scope)
if scope == "." {
break
}
} }
return &tls.Certificate{}, nil return &tls.Certificate{}, nil
} }

22
doc.go
View File

@ -41,22 +41,12 @@ Clients can control when to trust certificates with TrustCertificate:
return knownHosts.Lookup(hostname, cert) return knownHosts.Lookup(hostname, cert)
} }
Clients can control what to do when a server requests a certificate: Clients can create client certificates upon the request of a server:
client.GetCertificate = func(hostname string, store *gemini.CertificateStore) *tls.Certificate { client.CreateCertificate = func(hostname, path string) *tls.Certificate {
// If the certificate is in the store, return it return gemini.CreateCertificate(gemini.CertificateOptions{
if cert, err := store.Lookup(hostname); err == nil { Duration: time.Hour,
return &cert })
}
// Otherwise, generate a certificate
duration := time.Hour
cert, err := gemini.NewCertificate(hostname, duration)
if err != nil {
return nil
}
// Store and return the certificate
store.Add(hostname, cert)
return &cert
} }
Server is a Gemini server. Server is a Gemini server.
@ -65,7 +55,7 @@ Server is a Gemini server.
Servers must be configured with certificates: Servers must be configured with certificates:
err := server.CertificateStore.Load("/var/lib/gemini/certs") err := server.Certificates.Load("/var/lib/gemini/certs")
if err != nil { if err != nil {
// handle error // handle error
} }

View File

@ -36,9 +36,16 @@ type responderKey struct {
} }
// Register registers a responder for the given pattern. // Register registers a responder for the given pattern.
// Patterns must be in the form of scheme://hostname (e.g. gemini://example.com). //
// Patterns must be in the form of hostname or scheme://hostname
// (e.g. gemini://example.com).
// If no scheme is specified, a default scheme of gemini:// is assumed. // If no scheme is specified, a default scheme of gemini:// is assumed.
//
// Wildcard patterns are supported (e.g. *.example.com). // Wildcard patterns are supported (e.g. *.example.com).
// To register a certificate for a wildcard domain, call Certificates.Add:
//
// var s gemini.Server
// s.Certificates.Add("*.example.com", cert)
func (s *Server) Register(pattern string, responder Responder) { func (s *Server) Register(pattern string, responder Responder) {
if pattern == "" { if pattern == "" {
panic("gemini: invalid pattern") panic("gemini: invalid pattern")