aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoradnano <[email protected]>2020-09-21 19:17:10 -0400
committeradnano <[email protected]>2020-09-21 19:17:10 -0400
commit39552c0f8fe0dbdb5491f4dcaba84ddbc44a7f61 (patch)
tree2568e67b4ce0505bd7a4e1a4843a27412842b5a1
parentUpdate Client documentation (diff)
downloadgo-gemini-39552c0f8fe0dbdb5491f4dcaba84ddbc44a7f61.tar.xz
go-gemini-39552c0f8fe0dbdb5491f4dcaba84ddbc44a7f61.zip
Provide Handler with client certificate information
-rw-r--r--client.go34
-rw-r--r--examples/client/client.go14
-rw-r--r--examples/server/server.go10
-rw-r--r--server.go35
4 files changed, 55 insertions, 38 deletions
diff --git a/client.go b/client.go
index 6a55a4d..913a655 100644
--- a/client.go
+++ b/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 {
diff --git a/examples/client/client.go b/examples/client/client.go
index 6289e95..3864789 100644
--- a/examples/client/client.go
+++ b/examples/client/client.go
@@ -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)
}
diff --git a/examples/server/server.go b/examples/server/server.go
index 9165898..1040af9 100644
--- a/examples/server/server.go
+++ b/examples/server/server.go
@@ -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()),
}
})
diff --git a/server.go b/server.go
index a42588b..134dfc2 100644
--- a/server.go
+++ b/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)
}