all repos — flounder @ 08597a8cdf70f93bd5305c5c1ff3fe0cc2274c60

A small site builder for the Gemini protocol

gemini.go (view raw)

  1package main
  2
  3import (
  4	"bytes"
  5	"crypto/tls"
  6	"crypto/x509/pkix"
  7	gmi "git.sr.ht/~adnano/go-gemini"
  8	"io/ioutil"
  9	"log"
 10	"path"
 11	"path/filepath"
 12	"strings"
 13	"text/template"
 14	"time"
 15)
 16
 17var gt *template.Template
 18
 19func generateGemfeedPage(user string) string {
 20	return ""
 21}
 22
 23func generateFolderPage(fullpath string) string {
 24	files, _ := ioutil.ReadDir(fullpath)
 25	var renderedFiles = []File{}
 26	for _, file := range files {
 27		// Very awkward
 28		res := fileFromPath(path.Join(fullpath, file.Name()))
 29		renderedFiles = append(renderedFiles, res)
 30	}
 31	var buff bytes.Buffer
 32	data := struct {
 33		Host   string
 34		Folder string
 35		Files  []File
 36	}{c.Host, getLocalPath(fullpath), renderedFiles}
 37	err := gt.ExecuteTemplate(&buff, "folder.gmi", data)
 38	if err != nil {
 39		log.Println(err)
 40		return ""
 41	}
 42	return buff.String()
 43}
 44
 45func gmiIndex(w *gmi.ResponseWriter, r *gmi.Request) {
 46	log.Println("Index request")
 47	t, err := template.ParseFiles("templates/index.gmi")
 48	if err != nil {
 49		log.Fatal(err)
 50	}
 51	files, err := getIndexFiles(false)
 52	users, err := getActiveUserNames()
 53	if err != nil {
 54		log.Println(err)
 55		w.WriteHeader(40, "Internal server error")
 56	}
 57	data := struct {
 58		Host      string
 59		SiteTitle string
 60		Files     []*File
 61		Users     []string
 62	}{
 63		Host:      c.Host,
 64		SiteTitle: c.SiteTitle,
 65		Files:     files,
 66		Users:     users,
 67	}
 68	t.Execute(w, data)
 69}
 70
 71func gmiPage(w *gmi.ResponseWriter, r *gmi.Request) {
 72	userName := filepath.Clean(strings.Split(r.URL.Host, ".")[0]) // clean probably unnecessary
 73	fileName := filepath.Clean(r.URL.Path)
 74	if fileName == "/" {
 75		fileName = "index.gmi"
 76	} else if strings.HasPrefix(fileName, "/.hidden") {
 77		w.WriteStatus(gmi.StatusNotFound)
 78		return
 79	}
 80	log.Println("Request for gemini file", fileName, "for user", userName)
 81
 82	gmi.ServeFile(w, gmi.Dir(path.Join(c.FilesDirectory, userName)), fileName)
 83}
 84
 85func runGeminiServer() {
 86	log.Println("Starting gemini server")
 87	var err error
 88	gt, err = template.ParseGlob(path.Join(c.TemplatesDirectory, "*.gmi"))
 89	if err != nil {
 90		log.Fatal(err)
 91	}
 92	var server gmi.Server
 93	server.ReadTimeout = 1 * time.Minute
 94	server.WriteTimeout = 2 * time.Minute
 95
 96	hostname := strings.SplitN(c.Host, ":", 2)[0]
 97	// is this necc?
 98	err = server.Certificates.Load(c.GeminiCertStore)
 99	if err != nil {
100	}
101	server.CreateCertificate = func(h string) (tls.Certificate, error) {
102		log.Println("Generating certificate for", h)
103		return gmi.CreateCertificate(gmi.CertificateOptions{
104			Subject: pkix.Name{
105				CommonName: hostname,
106			},
107			DNSNames: []string{h},
108			Duration: time.Hour * 760, // one month
109		})
110	}
111
112	var mux gmi.ServeMux
113	// replace with wildcard cert
114	mux.HandleFunc("/", gmiIndex)
115
116	var wildcardMux gmi.ServeMux
117	wildcardMux.HandleFunc("/", gmiPage)
118	server.Register(hostname, &mux)
119	server.Register("*."+hostname, &wildcardMux)
120
121	err = server.ListenAndServe()
122	if err != nil {
123		log.Fatal(err)
124	}
125}