~sotirisp/kindleto

77bee3cd0733eca955ca731d7a2616b26b055b32 — Sotiris Papatheodorou 1 year, 11 months ago ab520df
Manage certificates from settings page
5 files changed, 54 insertions(+), 90 deletions(-)

M gemini/gemini.go
M handlers.go
M kindleto.go
M templates/template_strings.go
M templates/templates.go
M gemini/gemini.go => gemini/gemini.go +7 -9
@@ 54,10 54,9 @@ func ProxyGemini(w http.ResponseWriter, r *http.Request, u *url.URL) (*url.URL, 
			return u, fmt.Errorf("ProxyGemini: failed to open home file: %v", err)
		}
		td := templates.TemplateData{
			URL:         u.String(),
			Charset:     "utf-8",
			Lang:        settings.Current.DefaultLang,
			ManageCerts: certificates.NumClientCerts() > 0,
			URL:     u.String(),
			Charset: "utf-8",
			Lang:    settings.Current.DefaultLang,
		}
		err = GemtextToHTML(w, u, bufio.NewReader(f), td)
		return u, err


@@ 104,11 103,10 @@ func ProxyGemini(w http.ResponseWriter, r *http.Request, u *url.URL) (*url.URL, 
	}

	td := templates.TemplateData{
		URL:         u.String(),
		ParentURL:   util.ParentURL(*u),
		Charset:     "utf-8",
		Lang:        settings.Current.DefaultLang,
		ManageCerts: certificates.NumClientCerts() > 0,
		URL:       u.String(),
		ParentURL: util.ParentURL(*u),
		Charset:   "utf-8",
		Lang:      settings.Current.DefaultLang,
	}

	switch response.Status.Class() {

M handlers.go => handlers.go +23 -48
@@ 123,9 123,6 @@ func clientCertificateRequired(w http.ResponseWriter, r *http.Request) {
		var td templates.TemplateData
		td.URL = r.URL.Query().Get("url")
		td.Count = certificates.ClientCertYears
		if certificates.NumClientCerts() > 0 {
			td.ManageCerts = true
		}
		err := templates.Templates.ExecuteTemplate(w, "gemini-certificate.html.tmpl", td)
		if err != nil {
			log.Println("clientCertificateRequired:", err)


@@ 147,44 144,6 @@ func clientCertificateRequired(w http.ResponseWriter, r *http.Request) {
	}
}

// manageClientCertificate lets the user view and delete client certificates.
func manageClientCertificates(w http.ResponseWriter, r *http.Request) {
	var err error

	if r.Method == http.MethodGet {
		var td templates.TemplateData
		td.Certs, td.ExpiredCerts = certificates.ClientCerts()
		if len(td.Certs) > 0 {
			td.ManageCerts = true
		}
		err = templates.Templates.ExecuteTemplate(w, "certificates.html.tmpl", td)
		if err != nil {
			log.Println("manageClientCertificates:", err)
			http.Error(w, "Internal Server Error", 500)
		}
	} else if r.Method == http.MethodPost && r.FormValue("delete") == "single" && r.FormValue("scope") != "" {
		scope := r.FormValue("scope")
		err = certificates.DeleteClientCert(scope)
		if err != nil {
			log.Printf("manageClientCertificates: failed to delete certificate for scope '%s': %v", scope, err)
			http.Error(w, "Internal Server Error", 500)
		}
		http.Redirect(w, r, "/settings/certificates", http.StatusFound)
	} else if r.Method == http.MethodPost && r.FormValue("delete") == "expired" {
		err = certificates.DeleteExpiredClientCerts()
		if err != nil {
			log.Printf("manageClientCertificates: failed to delete expired certificates: %v", err)
			http.Error(w, "Internal Server Error", 500)
		}
		http.Redirect(w, r, "/settings/certificates", http.StatusFound)
	} else {
		if settings.Current.LogLevel > 0 {
			log.Println("manageClientCertificates: invalid request")
		}
		http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
	}
}

// certificateChanged lets the user accept changed server certificates.
func certificateChanged(w http.ResponseWriter, r *http.Request) {
	if r.FormValue("url") == "" {


@@ 259,9 218,6 @@ func proxy(w http.ResponseWriter, r *http.Request) {
			gemini.ProxyGemini(w, r, homepage)
		} else {
			var td templates.TemplateData
			if certificates.NumClientCerts() > 0 {
				td.ManageCerts = true
			}
			err = templates.Templates.ExecuteTemplate(w, "home.html.tmpl", td)
			if err != nil {
				log.Println("proxy:", err)


@@ 319,9 275,6 @@ func proxy(w http.ResponseWriter, r *http.Request) {
		td.Error = err.Error()
		td.URL = u.String()
		td.ParentURL = util.ParentURL(*u)
		if certificates.NumClientCerts() > 0 {
			td.ManageCerts = true
		}
		err = templates.Templates.ExecuteTemplate(w, "home.html.tmpl", td)
		if err != nil {
			log.Println(err)


@@ 333,7 286,28 @@ func proxy(w http.ResponseWriter, r *http.Request) {
// settings handles serving the settings page.
func handleSettings(w http.ResponseWriter, r *http.Request) {
	if r.Method == http.MethodPost {
		if r.FormValue("restart") == "yes" {
		if r.FormValue("delete") == "expired" {
			if settings.Current.LogLevel > 0 {
				log.Println("handleSettings: deleting expired certificates")
			}
			err := certificates.DeleteExpiredClientCerts()
			if err != nil {
				log.Printf("certificates.DeleteExpiredClientCerts: failed to delete expired certificates: %v", err)
				http.Error(w, "Internal Server Error", 500)
				return
			}
		} else if r.FormValue("delete") == "single" {
			scope := r.FormValue("scope")
			if settings.Current.LogLevel > 0 {
				log.Println("handleSettings: deleting certificate for", scope)
			}
			err := certificates.DeleteClientCert(scope)
			if err != nil {
				log.Printf("certificates.DeleteClientCert: failed to delete certificate for scope '%s': %v", scope, err)
				http.Error(w, "Internal Server Error", 500)
				return
			}
		} else if r.FormValue("restart") == "yes" {
			if settings.Current.LogLevel > 0 {
				log.Println("handleSettings: restarting kindleto")
			}


@@ 379,6 353,7 @@ func handleSettings(w http.ResponseWriter, r *http.Request) {
		}
	}
	var td = templates.TemplateData{Settings: settings.Current}
	td.Certs, td.ExpiredCerts = certificates.ClientCerts()
	err := templates.Templates.ExecuteTemplate(w, "settings.html.tmpl", td)
	if err != nil {
		log.Println("settings:", err)

M kindleto.go => kindleto.go +0 -1
@@ 74,7 74,6 @@ func main() {
	mux.HandleFunc("/", proxy)
	mux.HandleFunc("/certificate", clientCertificateRequired)
	mux.HandleFunc("/settings", handleSettings)
	mux.HandleFunc("/settings/certificates", manageClientCertificates)
	mux.HandleFunc("/tofu", certificateChanged)
	mux.HandleFunc("/kindleto.css", css)
	mux.HandleFunc("/about", about)

M templates/template_strings.go => templates/template_strings.go +24 -30
@@ 4,34 4,6 @@

package templates

const Certificates string = `{{template "header" .}}
{{if .Error}}
<div class="error">ERROR: {{.Error}}</div>
{{end}}
<h1>Manage Client Certificates</h1>
{{if gt .ExpiredCerts 0}}
<form action="/settings/certificates" method="POST">
<input type="hidden" name="delete" value="expired">
<input type="submit" value="Delete {{.ExpiredCerts}} expired certificate{{if gt .ExpiredCerts 1}}s{{end}}">
</form>
{{end}}
{{range .Certs}}
<div class="client-cert">
<h2>{{.Scope}}</h2>
<p>CommonName: {{.Name}}<br/>
Valid from: {{.NotBefore}}<br/>
Valid until: {{.NotAfter}}<br/>
{{if .Expired}}Expired!{{end}}</p>
<form action="/settings/certificates" method="POST">
<input type="hidden" name="delete" value="single">
<input type="hidden" name="scope" value="{{.Scope}}">
<input type="submit" value="DELETE">
</form>
{{else}}
<p>No client certificates found.</p>
{{end}}
{{template "footer"}}`

const FooterOnly string = `{{template "footer" .}}`

const Footer string = `{{define "footer"}}


@@ 120,7 92,6 @@ const Header string = `{{define "header"}}
{{if .ParentURL}}<a href="/?url={{.ParentURL}}">Parent</a>{{end}}
<a href="#footer">Bottom</a>
<span style="float:right;">
{{if .ManageCerts}}<a href="/settings/certificates">Certificates</a>{{end}}
<a href="/settings">Settings</a>
</span>
</div>


@@ 142,7 113,30 @@ const Settings string = `{{define "title"}}Kindleto settings{{end}}
{{if .Error}}
<div class="error">{{.Error}}</div>
{{end}}
<h1>Kindleto settings</h1>
<h1>Client certificates</h1>
{{if gt .ExpiredCerts 0}}
<form action="/settings" method="POST">
<input type="hidden" name="delete" value="expired">
<input type="submit" value="Delete {{.ExpiredCerts}} expired certificate{{if gt .ExpiredCerts 1}}s{{end}}">
</form>
{{end}}
{{range .Certs}}
<div class="client-cert">
<h2>{{.Scope}}</h2>
<p>CommonName: {{.Name}}<br/>
Valid from: {{.NotBefore}}<br/>
Valid until: {{.NotAfter}}<br/>
{{if .Expired}}Expired!{{end}}</p>
<form action="/settings" method="POST">
<input type="hidden" name="delete" value="single">
<input type="hidden" name="scope" value="{{.Scope}}">
<input type="submit" value="Delete">
</form>
{{else}}
<p>No client certificates.</p>
{{end}}

<h1>Settings</h1>
<form action="/settings" method="POST">

<h2>Enable client certificates</h2>

M templates/templates.go => templates/templates.go +0 -2
@@ 19,7 19,6 @@ type TemplateData struct {
	Error        string
	HTML         template.HTML
	Lang         string
	ManageCerts  bool
	Meta         string
	URL          string
	ParentURL    string


@@ 33,7 32,6 @@ var Templates *template.Template
func init() {
	Templates = template.New("")
	Templates = template.Must(Templates.New("about.html.tmpl").Parse(About))
	Templates = template.Must(Templates.New("certificates.html.tmpl").Parse(Certificates))
	Templates = template.Must(Templates.New("footer-only.html.tmpl").Parse(FooterOnly))
	Templates = template.Must(Templates.New("footer.html.tmpl").Parse(Footer))
	Templates = template.Must(Templates.New("gemini-certificate.html.tmpl").Parse(GeminiCertificate))