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