-
Notifications
You must be signed in to change notification settings - Fork 0
/
config.go
135 lines (108 loc) · 3.37 KB
/
config.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package main
import (
"encoding/base32"
"errors"
"fmt"
"html/template"
"path/filepath"
"strings"
"time"
"github.com/BurntSushi/toml"
session "github.com/fasthttp/session/v2"
"github.com/fasthttp/session/v2/providers/memory"
htpasswd "github.com/tg123/go-htpasswd"
)
var MissingVHostErr = errors.New("unknown virtual host")
// Config maps a set of virtualhosts with host names
type Config map[string]*VirtualHost
// VirtualHost contains the various configurables for specific
// virtual hosts, such as various auth stuff, or whatever
type VirtualHost struct {
TemplateDir string `toml:"templates"`
PasswdFile string `toml:"passwd"`
Redirect string `toml:"redirect"`
TOTPFile string `toml:"totp"`
CookieDomain string `toml:"domain"`
// Origins contains the permitted x-forwarded-host values
// allowed to authenticate against this virtual host
Origins []string `toml:"origins"`
passwd *htpasswd.File `toml:"-"`
templates *template.Template `toml:"-"`
sm SessionManager `toml:"-"`
}
// ReadConfig takes a config file, and organises the various
// virtual hosts and what have you.
//
// This function errors when:
//
// 1. The server config file does not exist
// 2. VHost configurations are wrong, such as missing htpasswd or templates
// 3. The config file doesn't contain a default vhost
func ReadConfig(fn string) (c *Config, err error) {
c = new(Config)
_, err = toml.DecodeFile(fn, c)
if err != nil {
return
}
for _, vh := range *c {
err = vh.Configure()
if err != nil {
return
}
}
return
}
// MatchVHost returns either a named vhost or the default vhost, depending
// on whether the vhost exists
func (c Config) MatchVHost(host []byte) (vh *VirtualHost, err error) {
vh, ok := c[string(host)]
if !ok {
err = MissingVHostErr
}
return
}
// MatchVHostByOrigin returns either a specific vhost or the default vhost
// based on the requested origin.
//
// This allows us to have many different services use a single vhost
func (c Config) MatchVHostByOrigin(host []byte) (addr string, vh *VirtualHost, err error) {
h := string(host)
for addr, vh = range c {
for _, o := range vh.Origins {
if h == o {
addr = "https://" + addr
return
}
}
}
err = MissingVHostErr
return
}
// Configure will configure the specfied vhost, with an htpasswd matcher,
// a set of templates, and a session manager
func (vh *VirtualHost) Configure() (err error) {
vh.passwd, err = htpasswd.New(vh.PasswdFile, htpasswd.DefaultSystems, nil)
if err != nil {
return
}
vh.templates, err = template.New("login").ParseGlob(filepath.Join(vh.TemplateDir, "*.html.tmpl"))
if err != nil {
return
}
cfg := session.NewDefaultConfig()
cfg.CookieName = strings.ReplaceAll(base32.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s_%s", vh.CookieDomain, vh.Redirect))), "=", "")
cfg.Domain = vh.CookieDomain
cfg.Expiration = time.Second * 604800
cfg.Secure = true
cfg.EncodeFunc = session.MSGPEncode
cfg.DecodeFunc = session.MSGPDecode
vh.sm = session.New(cfg)
// According to https://github.com/fasthttp/session/blob/v2.5.3/providers/memory/provider.go#L29
// there _are_ no errors that can be returned here because fuck me for
// expecting quality
provider, _ := memory.New(memory.Config{})
return vh.sm.SetProvider(provider)
}
func (vh *VirtualHost) Authenticate(username, password string) bool {
return vh.passwd.Match(username, password)
}