Provide Handler with client certificate information
This commit is contained in:
parent
81974a9e00
commit
39552c0f8f
34
client.go
34
client.go
@ -15,21 +15,7 @@ var (
|
||||
)
|
||||
|
||||
// Client is a Gemini client.
|
||||
// To use a client-side certificate, provide it here.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// config := tls.Config{}
|
||||
// cert, err := tls.LoadX509KeyPair("client.crt", "client.key")
|
||||
// if err != nil {
|
||||
// panic(err)
|
||||
// }
|
||||
// config.Certificates = append(config.Certificates, cert)
|
||||
//
|
||||
type Client struct {
|
||||
// The client's TLS configuration.
|
||||
TLSConfig tls.Config
|
||||
}
|
||||
type Client struct{}
|
||||
|
||||
// Request makes a request for the provided URL. The host is inferred from the URL.
|
||||
func (c *Client) Request(url string) (*Response, error) {
|
||||
@ -50,9 +36,20 @@ func (c *Client) ProxyRequest(host, url string) (*Response, error) {
|
||||
}
|
||||
|
||||
// Request is a Gemini request.
|
||||
//
|
||||
// A Request can optionally be configured with a client certificate. Example:
|
||||
//
|
||||
// req := NewRequest(url)
|
||||
// cert, err := tls.LoadX509KeyPair("client.crt", "client.key")
|
||||
// if err != nil {
|
||||
// panic(err)
|
||||
// }
|
||||
// req.Certificates = append(req.Certificates, cert)
|
||||
//
|
||||
type Request struct {
|
||||
Host string // host or host:port
|
||||
URL *url.URL // The URL to request
|
||||
Host string // host or host:port
|
||||
URL *url.URL // the requested URL
|
||||
Certificates []tls.Certificate // client certificates
|
||||
}
|
||||
|
||||
// NewRequest returns a new request. The host is inferred from the provided url.
|
||||
@ -95,9 +92,10 @@ func (c *Client) Do(req *Request) (*Response, error) {
|
||||
host += ":1965"
|
||||
}
|
||||
|
||||
config := tls.Config{}
|
||||
// Allow self signed certificates
|
||||
config := c.TLSConfig
|
||||
config.InsecureSkipVerify = true
|
||||
config.Certificates = req.Certificates
|
||||
|
||||
conn, err := tls.Dial("tcp", host, &config)
|
||||
if err != nil {
|
||||
|
@ -13,6 +13,7 @@ import (
|
||||
)
|
||||
|
||||
var client gemini.Client
|
||||
var cert tls.Certificate
|
||||
|
||||
func init() {
|
||||
// Configure a client side certificate.
|
||||
@ -22,17 +23,20 @@ func init() {
|
||||
// openssl ecparam -genkey -name secp384r1 -out client.key
|
||||
// openssl req -new -x509 -sha256 -key client.key -out client.crt -days 3650
|
||||
//
|
||||
config := tls.Config{}
|
||||
cert, err := tls.LoadX509KeyPair("examples/client/client.crt", "examples/client/client.key")
|
||||
var err error
|
||||
cert, err = tls.LoadX509KeyPair("examples/client/client.crt", "examples/client/client.key")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
config.Certificates = append(config.Certificates, cert)
|
||||
client.TLSConfig = config
|
||||
}
|
||||
|
||||
func makeRequest(url string) {
|
||||
resp, err := client.Request(url)
|
||||
req, err := gemini.NewRequest(url)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
req.Certificates = append(req.Certificates, cert)
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
@ -4,9 +4,9 @@ package main
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"git.sr.ht/~adnano/go-gemini"
|
||||
"log"
|
||||
"net/url"
|
||||
|
||||
"git.sr.ht/~adnano/go-gemini"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@ -23,13 +23,15 @@ func main() {
|
||||
log.Fatal(err)
|
||||
}
|
||||
config.Certificates = append(config.Certificates, cert)
|
||||
config.ClientAuth = tls.RequestClientCert
|
||||
|
||||
mux := &gemini.Mux{}
|
||||
mux.HandleFunc("/", func(url *url.URL) *gemini.Response {
|
||||
mux.HandleFunc("/", func(req *gemini.RequestInfo) *gemini.Response {
|
||||
log.Printf("Request for %s with certificates %v", req.URL.String(), req.Certificates)
|
||||
return &gemini.Response{
|
||||
Status: gemini.StatusSuccess,
|
||||
Meta: "text/gemini",
|
||||
Body: []byte("You requested " + url.String()),
|
||||
Body: []byte("You requested " + req.URL.String()),
|
||||
}
|
||||
})
|
||||
|
||||
|
35
server.go
35
server.go
@ -2,6 +2,7 @@ package gemini
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"io"
|
||||
"net"
|
||||
"net/url"
|
||||
@ -99,17 +100,29 @@ func (s *Server) Serve(ln net.Listener) error {
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
resp := s.Handler.Serve(url)
|
||||
|
||||
// Gather information about the request
|
||||
certs := rw.(*tls.Conn).ConnectionState().PeerCertificates
|
||||
reqInfo := &RequestInfo{
|
||||
URL: url,
|
||||
Certificates: certs,
|
||||
}
|
||||
resp := s.Handler.Serve(reqInfo)
|
||||
resp.Write(rw)
|
||||
rw.Close()
|
||||
}
|
||||
}
|
||||
|
||||
// RequestInfo contains information about a request.
|
||||
type RequestInfo struct {
|
||||
URL *url.URL
|
||||
Certificates []*x509.Certificate
|
||||
}
|
||||
|
||||
// A Handler responds to a Gemini request.
|
||||
type Handler interface {
|
||||
// Serve accepts a url, as that is the only information that is provided in
|
||||
// a Gemini request.
|
||||
Serve(*url.URL) *Response
|
||||
// Serve accepts a Request and returns a Response.
|
||||
Serve(*RequestInfo) *Response
|
||||
}
|
||||
|
||||
// Mux is a Gemini request multiplexer.
|
||||
@ -153,26 +166,26 @@ func (m *Mux) Handle(pattern string, handler Handler) {
|
||||
}
|
||||
|
||||
// HandleFunc registers a HandlerFunc for the given pattern.
|
||||
func (m *Mux) HandleFunc(pattern string, handlerFunc func(url *url.URL) *Response) {
|
||||
func (m *Mux) HandleFunc(pattern string, handlerFunc func(req *RequestInfo) *Response) {
|
||||
handler := HandlerFunc(handlerFunc)
|
||||
m.Handle(pattern, handler)
|
||||
}
|
||||
|
||||
// Serve responds to the request with the appropriate handler.
|
||||
func (m *Mux) Serve(url *url.URL) *Response {
|
||||
h := m.match(url)
|
||||
func (m *Mux) Serve(req *RequestInfo) *Response {
|
||||
h := m.match(req.URL)
|
||||
if h == nil {
|
||||
return &Response{
|
||||
Status: StatusNotFound,
|
||||
Meta: "Not found",
|
||||
}
|
||||
}
|
||||
return h.Serve(url)
|
||||
return h.Serve(req)
|
||||
}
|
||||
|
||||
// A wrapper around a bare function that implements Handler.
|
||||
type HandlerFunc func(url *url.URL) *Response
|
||||
type HandlerFunc func(req *RequestInfo) *Response
|
||||
|
||||
func (f HandlerFunc) Serve(url *url.URL) *Response {
|
||||
return f(url)
|
||||
func (f HandlerFunc) Serve(req *RequestInfo) *Response {
|
||||
return f(req)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user