mirror of
https://github.com/schollz/cowyo.git
synced 2023-08-10 21:13:00 +03:00
Add 'tomlo', configure cowyo via TOML
This commit is contained in:
parent
f567f86bab
commit
3b91b699e3
14
cmd/tomlo/tomlo.go
Normal file
14
cmd/tomlo/tomlo.go
Normal file
@ -0,0 +1,14 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/schollz/cowyo/config"
|
||||
)
|
||||
|
||||
func main() {
|
||||
c, err := config.ParseFile("multisite_sample.toml")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
panic(c.ListenAndServe())
|
||||
}
|
55
config/config.go
Normal file
55
config/config.go
Normal file
@ -0,0 +1,55 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"github.com/BurntSushi/toml"
|
||||
)
|
||||
|
||||
func ParseFile(path string) (Config, error) {
|
||||
c := Config{}
|
||||
if _, err := toml.DecodeFile("multisite_sample.toml", &c); err != nil {
|
||||
// handle error
|
||||
return c, err
|
||||
}
|
||||
c.SetDefaults()
|
||||
c.Validate()
|
||||
return c, nil
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
Default SiteConfig
|
||||
Sites []SiteConfig
|
||||
}
|
||||
|
||||
type SiteConfig struct {
|
||||
Host *string
|
||||
Port *int
|
||||
DataDir *string
|
||||
DefaultPage *string
|
||||
AllowInsecureMarkup *bool
|
||||
Lock *string
|
||||
DebounceSave *int
|
||||
Diary *bool
|
||||
AccessCode *string
|
||||
FileUploadsAllowed *bool
|
||||
MaxFileUploadMb *uint
|
||||
MaxDocumentLength *uint
|
||||
TLS *TLSConfig
|
||||
CookieKeys []CookieKey
|
||||
}
|
||||
|
||||
type TLSConfig struct {
|
||||
CertPath string
|
||||
KeyPath string
|
||||
Port int
|
||||
}
|
||||
|
||||
type CookieKey struct {
|
||||
AuthenticateBase64 string
|
||||
EncryptBase64 string
|
||||
}
|
||||
|
||||
func (c Config) Validate() {
|
||||
for _, v := range c.Sites {
|
||||
v.sessionStore()
|
||||
}
|
||||
}
|
102
config/defaults.go
Normal file
102
config/defaults.go
Normal file
@ -0,0 +1,102 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"crypto/rand"
|
||||
)
|
||||
var DefaultSiteConfig SiteConfig
|
||||
|
||||
|
||||
func makeAuthKey() string {
|
||||
secret := make([]byte, 32)
|
||||
_, err := rand.Read(secret)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return base64.StdEncoding.EncodeToString(secret)
|
||||
}
|
||||
|
||||
func init() {
|
||||
host := "*"
|
||||
port := 8050
|
||||
debounce := 500
|
||||
dataDir := "data"
|
||||
empty := ""
|
||||
zer := uint(0)
|
||||
lots := uint(100000000)
|
||||
fal := false
|
||||
|
||||
ck := CookieKey{
|
||||
AuthenticateBase64: "",
|
||||
EncryptBase64: "",
|
||||
}
|
||||
|
||||
DefaultSiteConfig = SiteConfig{
|
||||
Host:&host,
|
||||
Port:&port,
|
||||
DataDir:&dataDir,
|
||||
DebounceSave:&debounce,
|
||||
CookieKeys: []CookieKey{ck},
|
||||
DefaultPage:&empty,
|
||||
AllowInsecureMarkup:&fal,
|
||||
Lock:&empty,
|
||||
Diary:&fal,
|
||||
AccessCode:&empty,
|
||||
FileUploadsAllowed:&fal,
|
||||
MaxFileUploadMb:&zer,
|
||||
MaxDocumentLength:&lots,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func copyDefaults(base, defaults *SiteConfig) {
|
||||
if base.Host == nil {
|
||||
base.Host = defaults.Host
|
||||
}
|
||||
if base.Port == nil {
|
||||
base.Port = defaults.Port
|
||||
}
|
||||
if base.DataDir == nil {
|
||||
base.DataDir = defaults.DataDir
|
||||
}
|
||||
if base.DefaultPage == nil {
|
||||
base.DefaultPage = defaults.DefaultPage
|
||||
}
|
||||
if base.AllowInsecureMarkup == nil {
|
||||
base.AllowInsecureMarkup = defaults.AllowInsecureMarkup
|
||||
}
|
||||
if base.Lock == nil {
|
||||
base.Lock = defaults.Lock
|
||||
}
|
||||
if base.DebounceSave == nil {
|
||||
base.DebounceSave = defaults.DebounceSave
|
||||
}
|
||||
if base.Diary == nil {
|
||||
base.Diary = defaults.Diary
|
||||
}
|
||||
if base.AccessCode == nil {
|
||||
base.AccessCode = defaults.AccessCode
|
||||
}
|
||||
if base.FileUploadsAllowed == nil {
|
||||
base.FileUploadsAllowed = defaults.FileUploadsAllowed
|
||||
}
|
||||
if base.MaxFileUploadMb == nil {
|
||||
base.MaxFileUploadMb = defaults.MaxFileUploadMb
|
||||
}
|
||||
if base.MaxDocumentLength == nil {
|
||||
base.MaxDocumentLength = defaults.MaxDocumentLength
|
||||
}
|
||||
if base.TLS == nil {
|
||||
base.TLS = defaults.TLS
|
||||
}
|
||||
if base.CookieKeys == nil {
|
||||
base.CookieKeys = defaults.CookieKeys
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Config) SetDefaults() {
|
||||
copyDefaults(&c.Default, &DefaultSiteConfig)
|
||||
for i := range c.Sites {
|
||||
copyDefaults(&c.Sites[i], &c.Default)
|
||||
}
|
||||
}
|
105
config/http.go
Normal file
105
config/http.go
Normal file
@ -0,0 +1,105 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"encoding/base64"
|
||||
"net/http"
|
||||
"github.com/gin-contrib/sessions"
|
||||
"github.com/jcelliott/lumber"
|
||||
"github.com/schollz/cowyo/server"
|
||||
"strings"
|
||||
)
|
||||
func (c Config) ListenAndServe() error {
|
||||
insecurePorts := map[int]bool{}
|
||||
securePorts := map[int]bool{}
|
||||
err := make(chan error)
|
||||
for _, s := range c.Sites {
|
||||
if !insecurePorts[*s.Port] {
|
||||
insecurePorts[*s.Port] = true
|
||||
go func(s SiteConfig) {
|
||||
err <- http.ListenAndServe(fmt.Sprintf("localhost:%d", *s.Port), c)
|
||||
}(s)
|
||||
}
|
||||
if s.TLS != nil && !securePorts[s.TLS.Port] {
|
||||
securePorts[s.TLS.Port] = true
|
||||
go func(s SiteConfig) {
|
||||
err <- http.ListenAndServeTLS(
|
||||
fmt.Sprintf("localhost:%d", s.TLS.Port),
|
||||
s.TLS.CertPath,
|
||||
s.TLS.KeyPath,
|
||||
c,
|
||||
)
|
||||
}(s)
|
||||
}
|
||||
}
|
||||
for {
|
||||
return <- err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c Config) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
||||
for i := range c.Sites {
|
||||
if c.Sites[i].MatchesRequest(r) {
|
||||
c.Sites[i].Handle(rw, r)
|
||||
return
|
||||
}
|
||||
}
|
||||
http.NotFound(rw, r)
|
||||
}
|
||||
|
||||
func (s SiteConfig) MatchesRequest(r *http.Request) bool {
|
||||
sh := *s.Host
|
||||
if strings.HasPrefix(sh, "*") {
|
||||
return strings.HasSuffix(r.Host, sh[1:])
|
||||
}
|
||||
return sh == r.Host
|
||||
}
|
||||
|
||||
func (s SiteConfig) sessionStore() sessions.Store {
|
||||
keys := [][]byte{}
|
||||
for _, k := range s.CookieKeys {
|
||||
key, err := base64.StdEncoding.DecodeString(k.AuthenticateBase64)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if len(key) != 32 {
|
||||
log.Panicf("AuthenticateBase64 key %s must be 32 bytes; suggest %s", k.AuthenticateBase64, makeAuthKey())
|
||||
}
|
||||
|
||||
keys = append(keys, key)
|
||||
key, err = base64.StdEncoding.DecodeString(k.EncryptBase64)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if len(key) != 32 {
|
||||
log.Panicf("EncryptBase64 key %s must be 32 bytes, suggest %s", k.EncryptBase64, makeAuthKey())
|
||||
}
|
||||
keys = append(keys, key)
|
||||
}
|
||||
return sessions.NewCookieStore(keys...)
|
||||
}
|
||||
|
||||
func (s SiteConfig) Handle(rw http.ResponseWriter, r *http.Request) {
|
||||
dataDir := strings.Replace(*s.DataDir, "${HOST}", r.Host, -1)
|
||||
|
||||
router := server.Site{
|
||||
PathToData: dataDir,
|
||||
Css: []byte{},
|
||||
DefaultPage: *s.DefaultPage,
|
||||
DefaultPassword: *s.Lock,
|
||||
Debounce: *s.DebounceSave,
|
||||
Diary: *s.Diary,
|
||||
SessionStore: s.sessionStore(),
|
||||
SecretCode: *s.AccessCode,
|
||||
AllowInsecure: *s.AllowInsecureMarkup,
|
||||
Fileuploads: *s.MaxFileUploadMb > 0,
|
||||
MaxUploadSize: *s.MaxFileUploadMb,
|
||||
Logger: lumber.NewConsoleLogger(server.LogLevel),
|
||||
MaxDocumentSize: *s.MaxDocumentLength,
|
||||
}.Router()
|
||||
|
||||
router.ServeHTTP(rw, r)
|
||||
}
|
40
multisite_sample.toml
Normal file
40
multisite_sample.toml
Normal file
@ -0,0 +1,40 @@
|
||||
[default]
|
||||
dataDir = "root_data/${HOST}"
|
||||
maxDocumentLength = 100000000
|
||||
|
||||
# Specify multiple times to change keys without expiring sessions
|
||||
[[default.CookieKeys]]
|
||||
authenticateBase64 = "RpW4LjGCPNOx75G8DrywmzlEHLB/ISXCAAayZ47Ifkc="
|
||||
encryptBase64 = "ofCKkrfosQb5T4cvz7R5IMP4BQUDHOPsLSMZZy2CUOA="
|
||||
|
||||
[[sites]]
|
||||
host = "nerdy.party"
|
||||
dataDir = "somewhere else"
|
||||
# theme = "custom.css" # TODO: Theme support. Would prefer to move to a complete directory replacement.
|
||||
defaultPage = "welcome"
|
||||
allowInsecureMarkup = true
|
||||
lock = "1234"
|
||||
debounceSave = 600
|
||||
diary = true
|
||||
accessCode = "correct horse battery staple"
|
||||
fileUploadsAllowed = true
|
||||
maxFileUploadMb = 6
|
||||
port = 8090
|
||||
|
||||
#[sites.TLS]
|
||||
# TODO: ACME support eg letsencrypt
|
||||
#certPath = "path.crt"
|
||||
#keyPath = "path.key"
|
||||
#port = 8443
|
||||
|
||||
[[sites]]
|
||||
host = "cowyo.com"
|
||||
allowInsecureMarkup = false
|
||||
fileUploadsAllowed = false
|
||||
port = 8090
|
||||
|
||||
# Catchall config
|
||||
[[sites]]
|
||||
host = "*"
|
||||
port = 8100
|
||||
cookieSecret = "ASADFGKLJSH+4t4cC2X3f7GzsLZ+wtST67qoLuErpugJz06ZIpdDHEjcMxR+XOLM"
|
@ -2,6 +2,9 @@
|
||||
|
||||
package server
|
||||
|
||||
import "github.com/jcelliott/lumber"
|
||||
|
||||
func init() {
|
||||
hotTemplateReloading = true
|
||||
LogLevel = lumber.TRACE
|
||||
}
|
||||
|
@ -51,6 +51,7 @@ func (s *Site) defaultLock() string {
|
||||
}
|
||||
|
||||
var hotTemplateReloading bool
|
||||
var LogLevel int = lumber.WARN
|
||||
|
||||
func Serve(
|
||||
filepathToData,
|
||||
|
Loading…
Reference in New Issue
Block a user