1
0
mirror of https://git.sr.ht/~adnano/go-gemini synced 2024-09-22 09:20:41 +02:00

Add Certificate helper function

This commit is contained in:
Adnan Maolood 2020-10-21 17:47:34 -04:00
parent 8c4c00b31a
commit 1634c2c11c
2 changed files with 84 additions and 73 deletions

View File

@ -33,19 +33,19 @@ var (
) )
func main() { func main() {
handler := &gmi.ServeMux{} var mux gmi.ServeMux
handler.HandleFunc("/", welcome) mux.HandleFunc("/", welcome)
handler.HandleFunc("/login", login) mux.HandleFunc("/login", login)
handler.HandleFunc("/login/password", loginPassword) mux.HandleFunc("/login/password", loginPassword)
handler.HandleFunc("/profile", profile) mux.HandleFunc("/profile", profile)
handler.HandleFunc("/admin", admin) mux.HandleFunc("/admin", admin)
handler.HandleFunc("/logout", logout) mux.HandleFunc("/logout", logout)
server := &gmi.Server{} var server gmi.Server
if err := server.CertificateStore.Load("/var/lib/gemini/certs"); err != nil { if err := server.CertificateStore.Load("/var/lib/gemini/certs"); err != nil {
log.Fatal(err) log.Fatal(err)
} }
server.Register("localhost", handler) server.Register("localhost", &mux)
if err := server.ListenAndServe(); err != nil { if err := server.ListenAndServe(); err != nil {
log.Fatal(err) log.Fatal(err)
@ -59,11 +59,15 @@ func getSession(crt *x509.Certificate) (*session, bool) {
} }
func welcome(w *gmi.ResponseWriter, r *gmi.Request) { func welcome(w *gmi.ResponseWriter, r *gmi.Request) {
w.Write([]byte("Welcome to this example.\n=> /login Login\n")) fmt.Fprintln(w, "Welcome to this example.")
fmt.Fprintln(w, "=> /login Login")
} }
func login(w *gmi.ResponseWriter, r *gmi.Request) { func login(w *gmi.ResponseWriter, r *gmi.Request) {
gmi.WithCertificate(w, r, func(cert *x509.Certificate) { cert, ok := gmi.Certificate(w, r)
if !ok {
return
}
username, ok := gmi.Input(w, r, "Username") username, ok := gmi.Input(w, r, "Username")
if !ok { if !ok {
return return
@ -73,11 +77,13 @@ func login(w *gmi.ResponseWriter, r *gmi.Request) {
username: username, username: username,
} }
gmi.Redirect(w, r, "/login/password") gmi.Redirect(w, r, "/login/password")
})
} }
func loginPassword(w *gmi.ResponseWriter, r *gmi.Request) { func loginPassword(w *gmi.ResponseWriter, r *gmi.Request) {
gmi.WithCertificate(w, r, func(cert *x509.Certificate) { cert, ok := gmi.Certificate(w, r)
if !ok {
return
}
session, ok := getSession(cert) session, ok := getSession(cert)
if !ok { if !ok {
gmi.CertificateNotAuthorized(w, r) gmi.CertificateNotAuthorized(w, r)
@ -95,32 +101,39 @@ func loginPassword(w *gmi.ResponseWriter, r *gmi.Request) {
} else { } else {
gmi.SensitiveInput(w, r, "Wrong password. Try again") gmi.SensitiveInput(w, r, "Wrong password. Try again")
} }
})
} }
func logout(w *gmi.ResponseWriter, r *gmi.Request) { func logout(w *gmi.ResponseWriter, r *gmi.Request) {
gmi.WithCertificate(w, r, func(cert *x509.Certificate) { cert, ok := gmi.Certificate(w, r)
if !ok {
return
}
fingerprint := gmi.Fingerprint(cert) fingerprint := gmi.Fingerprint(cert)
delete(sessions, fingerprint) delete(sessions, fingerprint)
}) fmt.Fprintln(w, "Successfully logged out.")
w.Write([]byte("Successfully logged out.\n"))
} }
func profile(w *gmi.ResponseWriter, r *gmi.Request) { func profile(w *gmi.ResponseWriter, r *gmi.Request) {
gmi.WithCertificate(w, r, func(cert *x509.Certificate) { cert, ok := gmi.Certificate(w, r)
if !ok {
return
}
session, ok := getSession(cert) session, ok := getSession(cert)
if !ok { if !ok {
gmi.CertificateNotAuthorized(w, r) gmi.CertificateNotAuthorized(w, r)
return return
} }
user := logins[session.username] user := logins[session.username]
profile := fmt.Sprintf("Username: %s\nAdmin: %t\n=> /logout Logout", session.username, user.admin) fmt.Fprintln(w, "Username:", session.username)
w.Write([]byte(profile)) fmt.Fprintln(w, "Admin:", user.admin)
}) fmt.Fprintln(w, "=> /logout Logout")
} }
func admin(w *gmi.ResponseWriter, r *gmi.Request) { func admin(w *gmi.ResponseWriter, r *gmi.Request) {
gmi.WithCertificate(w, r, func(cert *x509.Certificate) { cert, ok := gmi.Certificate(w, r)
if !ok {
return
}
session, ok := getSession(cert) session, ok := getSession(cert)
if !ok { if !ok {
gmi.CertificateNotAuthorized(w, r) gmi.CertificateNotAuthorized(w, r)
@ -131,6 +144,5 @@ func admin(w *gmi.ResponseWriter, r *gmi.Request) {
gmi.CertificateNotAuthorized(w, r) gmi.CertificateNotAuthorized(w, r)
return return
} }
w.Write([]byte("Welcome to the admin portal.\n")) fmt.Fprintln(w, "Welcome to the admin portal.")
})
} }

View File

@ -311,15 +311,14 @@ func CertificateNotAuthorized(w *ResponseWriter, r *Request) {
w.WriteHeader(StatusCertificateNotAuthorized, "Certificate not authorized") w.WriteHeader(StatusCertificateNotAuthorized, "Certificate not authorized")
} }
// WithCertificate either responds with CertificateRequired if the client did // Certificate returns the request certificate. If one is not provided,
// not provide a certificate, or calls f with the first ceritificate provided. // it returns nil and responds with StatusCertificateRequired.
func WithCertificate(w *ResponseWriter, r *Request, f func(*x509.Certificate)) { func Certificate(w *ResponseWriter, r *Request) (*x509.Certificate, bool) {
if len(r.TLS.PeerCertificates) == 0 { if len(r.TLS.PeerCertificates) == 0 {
CertificateRequired(w, r) CertificateRequired(w, r)
return return nil, false
} }
cert := r.TLS.PeerCertificates[0] return r.TLS.PeerCertificates[0], true
f(cert)
} }
// ResponderFunc is a wrapper around a bare function that implements Handler. // ResponderFunc is a wrapper around a bare function that implements Handler.