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
|
package server
|
||||||
|
|
||||||
|
import "github.com/jcelliott/lumber"
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
hotTemplateReloading = true
|
hotTemplateReloading = true
|
||||||
|
LogLevel = lumber.TRACE
|
||||||
}
|
}
|
||||||
|
@ -51,6 +51,7 @@ func (s *Site) defaultLock() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var hotTemplateReloading bool
|
var hotTemplateReloading bool
|
||||||
|
var LogLevel int = lumber.WARN
|
||||||
|
|
||||||
func Serve(
|
func Serve(
|
||||||
filepathToData,
|
filepathToData,
|
||||||
|
Loading…
Reference in New Issue
Block a user