~adnano/astronaut

716e8b7c3fcd0c825d1e480eaaae92bc21f82ec7 — Adnan Maolood 24 days ago 7b19a97
tab: Implement certificate creation page
2 files changed, 37 insertions(+), 29 deletions(-)

A about/certificate.tmpl
M tab.go
A about/certificate.tmpl => about/certificate.tmpl +6 -0
@@ 0,0 1,6 @@
# Certificate required

{{.Hostname}} requires a certificate to continue.

=> create Create certificate
=> abort Abort

M tab.go => tab.go +31 -29
@@ 6,7 6,6 @@ import (
	"bufio"
	"bytes"
	"context"
	"crypto/tls"
	"crypto/x509"
	"errors"
	"fmt"


@@ 392,10 391,19 @@ func (t *Tab) do(ctx context.Context, req *gemini.Request, via []*gemini.Request

	// Create a certificate if necessary
	if resp.Status == gemini.StatusCertificateRequired && req.Certificate == nil {
		cert, ok := t.createCertificate(req.URL.Hostname())
		if !ok {
		hostname := req.URL.Hostname()
		if !t.createCertificate(hostname) {
			return nil
		}
		cert, err := certificate.Create(certificate.CreateOptions{
			Duration: 100 * 365 * 24 * time.Hour,
		})
		if err != nil {
			return err
		}
		if err := t.browser.certs.Add(hostname, cert); err != nil {
			return err
		}
		req.Certificate = &cert
		return t.do(ctx, req, via)
	}


@@ 490,35 498,29 @@ func (t *Tab) handleAbout(w gemini.ResponseWriter, r *gemini.Request) {
}

// createCertificate is called when the server requests a certificate.
func (t *Tab) createCertificate(hostname string) (tls.Certificate, bool) {
	b := t.browser
	if cert, ok := b.certs.Lookup(hostname); ok {
		return cert, true
	}
func (t *Tab) createCertificate(hostname string) bool {
	t.setStyle(styles.Warning)
	defer t.setStyle(tcell.StyleDefault)

	// TODO: Certificate creation page
	input, ok := b.Input("Certificate duration:", "", false)
	if !ok {
		return tls.Certificate{}, false
	}
	duration, err := time.ParseDuration(input)
	if err != nil {
		b.tabs[b.tab].Error(err)
		return tls.Certificate{}, false
	}
	cert, err := certificate.Create(certificate.CreateOptions{
		Duration: duration,
	})
	if err != nil {
		b.tabs[b.tab].Error(err)
		return cert, false
	}
	var buf bytes.Buffer
	templates.ExecuteTemplate(&buf, "certificate.tmpl", &struct {
		Hostname string
	}{hostname})

	if err := b.certs.Add(hostname, cert); err != nil {
		b.tabs[b.tab].Error(err)
		return cert, false
	ch := make(chan bool)
	gem := NewParsedGemText(t.view, t, io.NopCloser(&buf))
	gem.action = func(action string) {
		switch action {
		case "create":
			ch <- true
		default:
			close(ch)
		}
	}
	return cert, true
	t.setText(gem)
	defer t.setText(nil)

	return <-ch
}

// trustCertificate is called to determine if the client trusts the certificate.