server: Populate (*Request).Certificate field
This commit is contained in:
parent
cc372e8768
commit
b6475aa7d9
@ -3,9 +3,11 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"time"
|
||||||
|
|
||||||
"git.sr.ht/~adnano/go-gemini"
|
"git.sr.ht/~adnano/go-gemini"
|
||||||
)
|
)
|
||||||
@ -44,6 +46,12 @@ func main() {
|
|||||||
if err := server.Certificates.Load("/var/lib/gemini/certs"); err != nil {
|
if err := server.Certificates.Load("/var/lib/gemini/certs"); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
server.CreateCertificate = func(hostname string) (tls.Certificate, error) {
|
||||||
|
return gemini.CreateCertificate(gemini.CertificateOptions{
|
||||||
|
DNSNames: []string{hostname},
|
||||||
|
Duration: time.Hour,
|
||||||
|
})
|
||||||
|
}
|
||||||
server.Register("localhost", &mux)
|
server.Register("localhost", &mux)
|
||||||
|
|
||||||
if err := server.ListenAndServe(); err != nil {
|
if err := server.ListenAndServe(); err != nil {
|
||||||
@ -58,8 +66,7 @@ func getSession(cert *x509.Certificate) (*session, bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func login(w *gemini.ResponseWriter, r *gemini.Request) {
|
func login(w *gemini.ResponseWriter, r *gemini.Request) {
|
||||||
cert := gemini.Certificate(r)
|
if r.Certificate == nil {
|
||||||
if cert == nil {
|
|
||||||
w.WriteStatus(gemini.StatusCertificateRequired)
|
w.WriteStatus(gemini.StatusCertificateRequired)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -68,7 +75,7 @@ func login(w *gemini.ResponseWriter, r *gemini.Request) {
|
|||||||
w.WriteHeader(gemini.StatusInput, "Username")
|
w.WriteHeader(gemini.StatusInput, "Username")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fingerprint := gemini.Fingerprint(cert)
|
fingerprint := gemini.Fingerprint(r.Certificate.Leaf)
|
||||||
sessions[fingerprint] = &session{
|
sessions[fingerprint] = &session{
|
||||||
username: username,
|
username: username,
|
||||||
}
|
}
|
||||||
@ -76,12 +83,11 @@ func login(w *gemini.ResponseWriter, r *gemini.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func loginPassword(w *gemini.ResponseWriter, r *gemini.Request) {
|
func loginPassword(w *gemini.ResponseWriter, r *gemini.Request) {
|
||||||
cert := gemini.Certificate(r)
|
if r.Certificate == nil {
|
||||||
if cert == nil {
|
|
||||||
w.WriteStatus(gemini.StatusCertificateRequired)
|
w.WriteStatus(gemini.StatusCertificateRequired)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
session, ok := getSession(cert)
|
session, ok := getSession(r.Certificate.Leaf)
|
||||||
if !ok {
|
if !ok {
|
||||||
w.WriteStatus(gemini.StatusCertificateNotAuthorized)
|
w.WriteStatus(gemini.StatusCertificateNotAuthorized)
|
||||||
return
|
return
|
||||||
@ -102,23 +108,21 @@ func loginPassword(w *gemini.ResponseWriter, r *gemini.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func logout(w *gemini.ResponseWriter, r *gemini.Request) {
|
func logout(w *gemini.ResponseWriter, r *gemini.Request) {
|
||||||
cert := gemini.Certificate(r)
|
if r.Certificate == nil {
|
||||||
if cert == nil {
|
|
||||||
w.WriteStatus(gemini.StatusCertificateRequired)
|
w.WriteStatus(gemini.StatusCertificateRequired)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fingerprint := gemini.Fingerprint(cert)
|
fingerprint := gemini.Fingerprint(r.Certificate.Leaf)
|
||||||
delete(sessions, fingerprint)
|
delete(sessions, fingerprint)
|
||||||
fmt.Fprintln(w, "Successfully logged out.")
|
fmt.Fprintln(w, "Successfully logged out.")
|
||||||
}
|
}
|
||||||
|
|
||||||
func profile(w *gemini.ResponseWriter, r *gemini.Request) {
|
func profile(w *gemini.ResponseWriter, r *gemini.Request) {
|
||||||
cert := gemini.Certificate(r)
|
if r.Certificate == nil {
|
||||||
if cert == nil {
|
|
||||||
w.WriteStatus(gemini.StatusCertificateRequired)
|
w.WriteStatus(gemini.StatusCertificateRequired)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
session, ok := getSession(cert)
|
session, ok := getSession(r.Certificate.Leaf)
|
||||||
if !ok {
|
if !ok {
|
||||||
w.WriteStatus(gemini.StatusCertificateNotAuthorized)
|
w.WriteStatus(gemini.StatusCertificateNotAuthorized)
|
||||||
return
|
return
|
||||||
@ -130,12 +134,11 @@ func profile(w *gemini.ResponseWriter, r *gemini.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func admin(w *gemini.ResponseWriter, r *gemini.Request) {
|
func admin(w *gemini.ResponseWriter, r *gemini.Request) {
|
||||||
cert := gemini.Certificate(r)
|
if r.Certificate == nil {
|
||||||
if cert == nil {
|
|
||||||
w.WriteStatus(gemini.StatusCertificateRequired)
|
w.WriteStatus(gemini.StatusCertificateRequired)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
session, ok := getSession(cert)
|
session, ok := getSession(r.Certificate.Leaf)
|
||||||
if !ok {
|
if !ok {
|
||||||
w.WriteStatus(gemini.StatusCertificateNotAuthorized)
|
w.WriteStatus(gemini.StatusCertificateNotAuthorized)
|
||||||
return
|
return
|
||||||
|
@ -19,7 +19,9 @@ type Request struct {
|
|||||||
|
|
||||||
// Certificate specifies the TLS certificate to use for the request.
|
// Certificate specifies the TLS certificate to use for the request.
|
||||||
// Request certificates take precedence over client certificates.
|
// Request certificates take precedence over client certificates.
|
||||||
// This field is ignored by the server.
|
//
|
||||||
|
// On the server side, if the client provided a certificate then
|
||||||
|
// Certificate.Leaf is guaranteed to be non-nil.
|
||||||
Certificate *tls.Certificate
|
Certificate *tls.Certificate
|
||||||
|
|
||||||
// RemoteAddr allows servers and other software to record the network
|
// RemoteAddr allows servers and other software to record the network
|
||||||
|
40
server.go
40
server.go
@ -3,7 +3,6 @@ package gemini
|
|||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
@ -199,10 +198,24 @@ func (s *Server) respond(conn net.Conn) {
|
|||||||
if url.Scheme == "" {
|
if url.Scheme == "" {
|
||||||
url.Scheme = "gemini"
|
url.Scheme = "gemini"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Store information about the TLS connection
|
||||||
|
connState := conn.(*tls.Conn).ConnectionState()
|
||||||
|
var cert *tls.Certificate
|
||||||
|
if len(connState.PeerCertificates) > 0 {
|
||||||
|
peerCert := connState.PeerCertificates[0]
|
||||||
|
// Store the TLS certificate
|
||||||
|
cert = &tls.Certificate{
|
||||||
|
Certificate: [][]byte{peerCert.Raw},
|
||||||
|
Leaf: peerCert,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
req := &Request{
|
req := &Request{
|
||||||
URL: url,
|
URL: url,
|
||||||
RemoteAddr: conn.RemoteAddr(),
|
RemoteAddr: conn.RemoteAddr(),
|
||||||
TLS: conn.(*tls.Conn).ConnectionState(),
|
TLS: connState,
|
||||||
|
Certificate: cert,
|
||||||
}
|
}
|
||||||
resp := s.responder(req)
|
resp := s.responder(req)
|
||||||
if resp != nil {
|
if resp != nil {
|
||||||
@ -330,22 +343,3 @@ func Input(r *Request) (query string, ok bool) {
|
|||||||
}
|
}
|
||||||
return "", false
|
return "", false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Certificate returns the request certificate.
|
|
||||||
// It returns nil if no certificate was provided.
|
|
||||||
//
|
|
||||||
// Example:
|
|
||||||
//
|
|
||||||
// cert := gemini.Certificate(req)
|
|
||||||
// if cert == nil {
|
|
||||||
// w.WriteStatus(gemini.StatusCertificateRequired)
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// // ...
|
|
||||||
//
|
|
||||||
func Certificate(r *Request) *x509.Certificate {
|
|
||||||
if len(r.TLS.PeerCertificates) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return r.TLS.PeerCertificates[0]
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user