From 3c9821d812c401d9f6a6f8bea2560171b5309d8d Mon Sep 17 00:00:00 2001 From: adnano Date: Sun, 27 Sep 2020 21:13:42 -0400 Subject: [PATCH] Add more helper functions --- examples/auth/auth.go | 16 ++++++------- examples/client/client.go | 3 ++- gemini.go | 48 +++++++++++++++++++-------------------- server.go | 39 ++++++++++++++++++++++++++++++- 4 files changed, 72 insertions(+), 34 deletions(-) diff --git a/examples/auth/auth.go b/examples/auth/auth.go index 8567e90..a4dc86b 100644 --- a/examples/auth/auth.go +++ b/examples/auth/auth.go @@ -85,7 +85,7 @@ func login(rw *gmi.ResponseWriter, req *gmi.Request) { rw.WriteHeader(gmi.StatusRedirect, "/login/password") } } else { - rw.WriteHeader(gmi.StatusClientCertificateRequired, "Certificate required") + rw.WriteHeader(gmi.StatusCertificateRequired, "Certificate required") } } @@ -93,7 +93,7 @@ func loginPassword(rw *gmi.ResponseWriter, req *gmi.Request) { if len(req.TLS.PeerCertificates) > 0 { session, ok := getSession(req.TLS.PeerCertificates[0]) if !ok { - rw.WriteHeader(gmi.StatusCertificateNotAuthorised, "Not authorized") + rw.WriteHeader(gmi.StatusCertificateNotAuthorized, "Not authorized") return } @@ -109,7 +109,7 @@ func loginPassword(rw *gmi.ResponseWriter, req *gmi.Request) { } } } else { - rw.WriteHeader(gmi.StatusClientCertificateRequired, "Certificate required") + rw.WriteHeader(gmi.StatusCertificateRequired, "Certificate required") } } @@ -126,7 +126,7 @@ func profile(rw *gmi.ResponseWriter, req *gmi.Request) { if len(req.TLS.PeerCertificates) > 0 { session, ok := getSession(req.TLS.PeerCertificates[0]) if !ok { - rw.WriteHeader(gmi.StatusCertificateNotAuthorised, "Certificate not authorized") + rw.WriteHeader(gmi.StatusCertificateNotAuthorized, "Certificate not authorized") return } user := logins[session.username] @@ -134,7 +134,7 @@ func profile(rw *gmi.ResponseWriter, req *gmi.Request) { rw.WriteHeader(gmi.StatusSuccess, "text/gemini") rw.Write([]byte(profile)) } else { - rw.WriteHeader(gmi.StatusClientCertificateRequired, "Certificate required") + rw.WriteHeader(gmi.StatusCertificateRequired, "Certificate required") } } @@ -142,17 +142,17 @@ func admin(rw *gmi.ResponseWriter, req *gmi.Request) { if len(req.TLS.PeerCertificates) > 0 { session, ok := getSession(req.TLS.PeerCertificates[0]) if !ok { - rw.WriteHeader(gmi.StatusCertificateNotAuthorised, "Certificate not authorized") + rw.WriteHeader(gmi.StatusCertificateNotAuthorized, "Certificate not authorized") return } user := logins[session.username] if !user.admin { - rw.WriteHeader(gmi.StatusCertificateNotAuthorised, "Admins only!") + rw.WriteHeader(gmi.StatusCertificateNotAuthorized, "Admins only!") return } rw.WriteHeader(gmi.StatusSuccess, "text/gemini") rw.Write([]byte("Welcome to the admin portal.\n")) } else { - rw.WriteHeader(gmi.StatusClientCertificateRequired, "Certificate required") + rw.WriteHeader(gmi.StatusCertificateRequired, "Certificate required") } } diff --git a/examples/client/client.go b/examples/client/client.go index 12eaf04..9e7cc37 100644 --- a/examples/client/client.go +++ b/examples/client/client.go @@ -54,6 +54,7 @@ func sendRequest(req *gmi.Request) error { return err } + // TODO: More fine-grained analysis of the status code. switch resp.Status / 10 { case gmi.StatusClassInput: fmt.Printf("%s: ", resp.Meta) @@ -78,7 +79,7 @@ func sendRequest(req *gmi.Request) error { return fmt.Errorf("Temporary failure: %s", resp.Meta) case gmi.StatusClassPermanentFailure: return fmt.Errorf("Permanent failure: %s", resp.Meta) - case gmi.StatusClassClientCertificateRequired: + case gmi.StatusClassCertificateRequired: fmt.Println("Generating client certificate for", req.Hostname()) return nil // TODO: Generate and store client certificate } diff --git a/gemini.go b/gemini.go index 957dd43..12a146f 100644 --- a/gemini.go +++ b/gemini.go @@ -7,34 +7,34 @@ import ( // Status codes. const ( - StatusInput = 10 - StatusSensitiveInput = 11 - StatusSuccess = 20 - StatusRedirect = 30 - StatusRedirectPermanent = 31 - StatusTemporaryFailure = 40 - StatusServerUnavailable = 41 - StatusCGIError = 42 - StatusProxyError = 43 - StatusSlowDown = 44 - StatusPermanentFailure = 50 - StatusNotFound = 51 - StatusGone = 52 - StatusProxyRequestRefused = 53 - StatusBadRequest = 59 - StatusClientCertificateRequired = 60 - StatusCertificateNotAuthorised = 61 - StatusCertificateNotValid = 62 + StatusInput = 10 + StatusSensitiveInput = 11 + StatusSuccess = 20 + StatusRedirect = 30 + StatusRedirectPermanent = 31 + StatusTemporaryFailure = 40 + StatusServerUnavailable = 41 + StatusCGIError = 42 + StatusProxyError = 43 + StatusSlowDown = 44 + StatusPermanentFailure = 50 + StatusNotFound = 51 + StatusGone = 52 + StatusProxyRequestRefused = 53 + StatusBadRequest = 59 + StatusCertificateRequired = 60 + StatusCertificateNotAuthorized = 61 + StatusCertificateNotValid = 62 ) // Status code categories. const ( - StatusClassInput = 1 - StatusClassSuccess = 2 - StatusClassRedirect = 3 - StatusClassTemporaryFailure = 4 - StatusClassPermanentFailure = 5 - StatusClassClientCertificateRequired = 6 + StatusClassInput = 1 + StatusClassSuccess = 2 + StatusClassRedirect = 3 + StatusClassTemporaryFailure = 4 + StatusClassPermanentFailure = 5 + StatusClassCertificateRequired = 6 ) var ( diff --git a/server.go b/server.go index e401776..1bc9197 100644 --- a/server.go +++ b/server.go @@ -174,7 +174,7 @@ type Handler interface { Serve(*ResponseWriter, *Request) } -// NotFound replies to the request with a NotFound status code. +// NotFound replies to the request with the NotFound status code. func NotFound(rw *ResponseWriter, req *Request) { rw.WriteHeader(StatusNotFound, "Not found") } @@ -185,6 +185,17 @@ func NotFoundHandler() Handler { return HandlerFunc(NotFound) } +// Gone replies to the request with the Gone status code. +func Gone(rw *ResponseWriter, req *Request) { + rw.WriteHeader(StatusGone, "Gone") +} + +// GoneHandler returns a simple handler that responds to each request with +// the status code Gone. +func GoneHandler() Handler { + return HandlerFunc(Gone) +} + // Redirect replies to the request with a redirect to the given url. // If permanent is true, Redirect will respond with a permanent redirect. func Redirect(rw *ResponseWriter, req *Request, url string, permanent bool) { @@ -217,6 +228,32 @@ func InputHandler(prompt string) Handler { }) } +// Sensitive responds to the request with a request for sensitive input +// using the given prompt. +func SensitiveInput(rw *ResponseWriter, req *Request, prompt string) { + rw.WriteHeader(StatusSensitiveInput, prompt) +} + +// SensitiveInputHandler returns a simpler handler that responds to each request +// with a request for sensitive input. +func SensitiveInputHandler(prompt string) Handler { + return HandlerFunc(func(rw *ResponseWriter, req *Request) { + SensitiveInput(rw, req, prompt) + }) +} + +// CertificateRequired responds to the request with the CertificateRequired +// status code. +func CertificateRequired(rw *ResponseWriter, req *Request) { + rw.WriteHeader(StatusCertificateRequired, "Certificate required") +} + +// CertificateNotAuthorized responds to the request with +// the CertificateNotAuthorized status code. +func CertificateNotAuthorized(rw *ResponseWriter, req *Request) { + rw.WriteHeader(StatusCertificateNotAuthorized, "Certificate not authorized") +} + // ServeMux is a Gemini request multiplexer. // It matches the URL of each incoming request against a list of registered // patterns and calls the handler for the pattern that most closesly matches