mirror of
https://code.rocketnine.space/tslocum/gmitohtml.git
synced 2024-11-27 13:58:15 +01:00
Parse configuration file
This commit is contained in:
parent
9cf58a9982
commit
d17e5ab9cf
7 changed files with 140 additions and 9 deletions
33
CONFIGURATION.md
Normal file
33
CONFIGURATION.md
Normal file
|
@ -0,0 +1,33 @@
|
|||
`gmitohtml` loads its configuration from `~/.config/gmitohtml/config.yaml` by
|
||||
default. You may specify a different location via the `--config` argument.
|
||||
|
||||
# Configuration options
|
||||
|
||||
## Client certificates
|
||||
|
||||
Client certificates may be specified via the `Certs` option.
|
||||
|
||||
To generate a client certificate, run the following:
|
||||
|
||||
```bash
|
||||
openssl req -x509 -out localhost.crt -keyout localhost.key \
|
||||
-newkey rsa:2048 -nodes -sha256 \
|
||||
-subj '/CN=localhost' -extensions EXT -config <( \
|
||||
printf "[dn]\nCN=localhost\n[req]\ndistinguished_name = dn\n[EXT]\nsubjectAltName=DNS:localhost\nkeyUsage=digitalSignature\nextendedKeyUsage=serverAuth")
|
||||
```
|
||||
|
||||
Files `localhost.crt` and `localhost.key` are generated. Rename these files to
|
||||
match the domain where the certificate will be used.
|
||||
|
||||
# Example config.yaml
|
||||
|
||||
```yaml
|
||||
certs:
|
||||
astrobotany.mozz.us:
|
||||
cert: /home/dioscuri/.config/gmitohtml/astrobotany.mozz.us.crt
|
||||
key: /home/dioscuri/.config/gmitohtml/astrobotany.mozz.us.crt
|
||||
gemini.rocks:
|
||||
cert: /home/dioscuri/.config/gmitohtml/gemini.rocks.crt
|
||||
key: /home/dioscuri/.config/gmitohtml/gemini.rocks.key
|
||||
|
||||
```
|
|
@ -17,6 +17,10 @@ go get gitlab.com/tslocum/gmitohtml
|
|||
|
||||
The resulting binary is available as `~/go/bin/gmitohtml`.
|
||||
|
||||
## Configure
|
||||
|
||||
See [CONFIGURATION.md](https://gitlab.com/tslocum/gmitohtml/blob/master/CONFIGURATION.md)
|
||||
|
||||
## Usage
|
||||
|
||||
Run daemon at [http://localhost:1967](http://localhost:1967):
|
||||
|
|
44
config.go
Normal file
44
config.go
Normal file
|
@ -0,0 +1,44 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
type certConfig struct {
|
||||
Cert string
|
||||
Key string
|
||||
|
||||
cert tls.Certificate
|
||||
}
|
||||
|
||||
type appConfig struct {
|
||||
Certs map[string]*certConfig
|
||||
}
|
||||
|
||||
var config = &appConfig{
|
||||
Certs: make(map[string]*certConfig),
|
||||
}
|
||||
|
||||
func readconfig(configPath string) error {
|
||||
if configPath == "" {
|
||||
return errors.New("file unspecified")
|
||||
}
|
||||
|
||||
configData, err := ioutil.ReadFile(configPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var newConfig *appConfig
|
||||
err = yaml.Unmarshal(configData, &newConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
config = newConfig
|
||||
|
||||
return nil
|
||||
}
|
2
go.mod
2
go.mod
|
@ -1,3 +1,5 @@
|
|||
module gitlab.com/tslocum/gmitohtml
|
||||
|
||||
go 1.15
|
||||
|
||||
require gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776
|
||||
|
|
4
go.sum
4
go.sum
|
@ -0,0 +1,4 @@
|
|||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
40
main.go
40
main.go
|
@ -1,6 +1,8 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"path"
|
||||
|
||||
"gitlab.com/tslocum/gmitohtml/pkg/gmitohtml"
|
||||
|
||||
"flag"
|
||||
|
@ -33,11 +35,47 @@ func openBrowser(url string) {
|
|||
func main() {
|
||||
var view bool
|
||||
var daemon string
|
||||
var configFile string
|
||||
flag.BoolVar(&view, "view", false, "open web browser")
|
||||
flag.StringVar(&daemon, "daemon", "", "start daemon on specified address")
|
||||
flag.StringVar(&configFile, "config", "", "path to configuration file")
|
||||
// TODO option to include response header in page
|
||||
flag.Parse()
|
||||
|
||||
if configFile == "" {
|
||||
homedir, err := os.UserHomeDir()
|
||||
if err == nil && homedir != "" {
|
||||
defaultConfig := path.Join(homedir, ".config", "gmitohtml", "config.yaml")
|
||||
if _, err := os.Stat(defaultConfig); !os.IsNotExist(err) {
|
||||
configFile = defaultConfig
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if configFile != "" {
|
||||
err := readconfig(configFile)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to read configuration file at %s: %v\nSee CONFIGURATION.md for information on configuring gmitohtml", configFile, err)
|
||||
}
|
||||
}
|
||||
|
||||
for domain, cc := range config.Certs {
|
||||
certData, err := ioutil.ReadFile(cc.Cert)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to load client certificate for domain %s: %s", domain, err)
|
||||
}
|
||||
|
||||
keyData, err := ioutil.ReadFile(cc.Key)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to load client certificate for domain %s: %s", domain, err)
|
||||
}
|
||||
|
||||
err = gmitohtml.SetClientCertificate(domain, certData, keyData)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to load client certificate for domain %s", domain)
|
||||
}
|
||||
}
|
||||
|
||||
if daemon != "" {
|
||||
err := gmitohtml.StartDaemon(daemon)
|
||||
if err != nil {
|
||||
|
@ -48,7 +86,7 @@ func main() {
|
|||
openBrowser("http://" + daemon)
|
||||
}
|
||||
|
||||
select {} //TODO
|
||||
select {}
|
||||
}
|
||||
|
||||
data, err := ioutil.ReadAll(os.Stdin)
|
||||
|
|
|
@ -3,6 +3,7 @@ package gmitohtml
|
|||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
|
@ -147,13 +148,6 @@ func handleRequest(writer http.ResponseWriter, request *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
inputText := request.PostFormValue("input")
|
||||
if inputText != "" {
|
||||
request.URL.RawQuery = inputText
|
||||
http.Redirect(writer, request, request.URL.String(), http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
|
||||
pathSplit := strings.Split(request.URL.Path, "/")
|
||||
if len(pathSplit) < 2 || pathSplit[1] != "gemini" {
|
||||
writer.Write([]byte("Error: invalid protocol, only Gemini is supported"))
|
||||
|
@ -169,6 +163,13 @@ func handleRequest(writer http.ResponseWriter, request *http.Request) {
|
|||
u.RawQuery = request.URL.RawQuery
|
||||
}
|
||||
|
||||
inputText := request.PostFormValue("input")
|
||||
if inputText != "" {
|
||||
u.RawQuery = inputText
|
||||
http.Redirect(writer, request, rewriteURL(u.String(), u), http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
|
||||
header, data, err := fetch(u.String())
|
||||
if err != nil {
|
||||
fmt.Fprintf(writer, "Error: failed to fetch %s: %s", u, err)
|
||||
|
@ -178,7 +179,7 @@ func handleRequest(writer http.ResponseWriter, request *http.Request) {
|
|||
if len(header) > 0 && header[0] == '3' {
|
||||
split := bytes.SplitN(header, []byte(" "), 2)
|
||||
if len(split) == 2 {
|
||||
http.Redirect(writer, request, rewriteURL(string(split[1]), request.URL), http.StatusSeeOther)
|
||||
http.Redirect(writer, request, rewriteURL(string(split[1]), u), http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -234,6 +235,11 @@ func SetClientCertificate(domain string, certificate []byte, privateKey []byte)
|
|||
return ErrInvalidCertificate
|
||||
}
|
||||
|
||||
leafCert, err := x509.ParseCertificate(clientCert.Certificate[0])
|
||||
if err == nil {
|
||||
clientCert.Leaf = leafCert
|
||||
}
|
||||
|
||||
clientCerts[domain] = clientCert
|
||||
return nil
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue