aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYotam Nachum <me@yotam.net>2019-11-01 13:04:47 +0200
committerYotam Nachum <me@yotam.net>2019-11-01 13:04:47 +0200
commit24a8642761c2e12c384178274074adac48a9866c (patch)
tree8c18f59f7505e2e7c73c3fbd829c92b7a36b2467
downloadshavit-24a8642761c2e12c384178274074adac48a9866c.tar.gz
shavit-24a8642761c2e12c384178274074adac48a9866c.zip
Initial commit
-rw-r--r--.gitignore4
-rw-r--r--config.go29
-rw-r--r--config.toml3
-rw-r--r--go.mod9
-rw-r--r--go.sum10
-rw-r--r--main.go61
6 files changed, 116 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..01e530c
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+go-gemini-server
+server.crt
+server.key
+/source/*
diff --git a/config.go b/config.go
new file mode 100644
index 0000000..6b24a9d
--- /dev/null
+++ b/config.go
@@ -0,0 +1,29 @@
+package main
+
+import (
+ "fmt"
+ "io/ioutil"
+
+ "github.com/BurntSushi/toml"
+)
+
+type Config struct {
+ SourceDir string `toml:"source"`
+ TLSCert string `toml:"tls_certificate"`
+ TLSKey string `toml:"tls_key"`
+}
+
+func getConfig(path string) (Config, error) {
+ raw, err := ioutil.ReadFile(path)
+ if err != nil {
+ return Config{}, fmt.Errorf("failed to read config file: %v", err)
+ }
+
+ var cfg Config
+ err = toml.Unmarshal(raw, &cfg)
+ if err != nil {
+ return Config{}, fmt.Errorf("failed to parse config file: %v", err)
+ }
+
+ return cfg, nil
+}
diff --git a/config.toml b/config.toml
new file mode 100644
index 0000000..5e52f8c
--- /dev/null
+++ b/config.toml
@@ -0,0 +1,3 @@
+source = "source"
+tls_certificate = "server.crt"
+tls_key = "server.key"
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..64752a3
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,9 @@
+module git.sr.ht/~yotam/go-gemini-server
+
+go 1.12
+
+require (
+ git.sr.ht/~yotam/go-gemini v0.0.0-20191101110121-e84e0b63cd37
+ github.com/BurntSushi/toml v0.3.1
+ github.com/pelletier/go-toml v1.6.0 // indirect
+)
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..3faa810
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,10 @@
+git.sr.ht/~yotam/go-gemini v0.0.0-20191101110121-e84e0b63cd37 h1:NWDz215k8nz6PGmbCb1YsUWrp9ocqnyKLnUoDCzzgU8=
+git.sr.ht/~yotam/go-gemini v0.0.0-20191101110121-e84e0b63cd37/go.mod h1:KxQlipD0Ti7MfV3itYJfuvgcvd+SOlRTtbOK+A0DCCE=
+github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
diff --git a/main.go b/main.go
new file mode 100644
index 0000000..5e1e5e4
--- /dev/null
+++ b/main.go
@@ -0,0 +1,61 @@
+package main
+
+import (
+ "log"
+ "net/url"
+ "os"
+ "path/filepath"
+ "strings"
+
+ "git.sr.ht/~yotam/go-gemini"
+)
+
+type MainHandler struct {
+ source string
+}
+
+func (h MainHandler) Handle(r gemini.Request) gemini.Response {
+ u, err := url.Parse(r.URL)
+ if err != nil {
+ return gemini.Response{gemini.StatusBadRequest, err.Error(), nil}
+ }
+
+ itemPath, err := filepath.Abs(filepath.Join(h.source, u.Path))
+ if err != nil {
+ return gemini.Response{gemini.StatusTemporaryFailure, err.Error(), nil}
+ }
+
+ log.Println("Serving file from", itemPath)
+
+ if !strings.HasPrefix(itemPath, h.source) {
+ return gemini.Response{gemini.StatusBadRequest, "Permission denied", nil}
+ }
+
+ if _, err := os.Stat(itemPath); os.IsNotExist(err) {
+ return gemini.Response{gemini.StatusNotFound, "Not found", nil}
+ }
+
+ file, err := os.Open(itemPath)
+ if err != nil {
+ return gemini.Response{gemini.StatusTemporaryFailure, err.Error(), nil}
+ }
+
+ return gemini.Response{gemini.StatusSuccess, "text/gemini", file}
+}
+
+func main() {
+ cfg, err := getConfig("config.toml")
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ absSourceDir, err := filepath.Abs(cfg.SourceDir)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ err = gemini.ListenAndServe("", cfg.TLSCert, cfg.TLSKey, MainHandler{absSourceDir})
+ if err != nil {
+ log.Fatal(err)
+ }
+}