Hardcode some file names

This commit is contained in:
Melon 2023-07-01 12:14:44 +01:00
parent 7e05271a79
commit 76e37f7af9
Signed by: melon
GPG Key ID: 6C9D970C50D26A25
10 changed files with 62 additions and 61 deletions

View File

@ -1,15 +1,12 @@
package main package main
type startUpConfig struct { type startUpConfig struct {
Database string `json:"db"`
MjwtPubKey string `json:"mjwt_pub_key"`
CertPath string `json:"cert_path"`
KeyPath string `json:"key_path"`
SelfSigned bool `json:"self_signed"` SelfSigned bool `json:"self_signed"`
ErrorPagePath string `json:"error_page_path"` ErrorPagePath string `json:"error_page_path"`
Listen listenConfig `json:"listen"` Listen listenConfig `json:"listen"`
InkscapeCmd string `json:"inkscape"` InkscapeCmd string `json:"inkscape"`
RateLimit uint64 `json:"rate_limit"` RateLimit uint64 `json:"rate_limit"`
SignerIssuer string `json:"signer_issuer"`
} }
type listenConfig struct { type listenConfig struct {

View File

@ -18,9 +18,11 @@ import (
"github.com/google/subcommands" "github.com/google/subcommands"
"io/fs" "io/fs"
"log" "log"
"math/rand"
"net/http" "net/http"
"os" "os"
"os/signal" "os/signal"
"path/filepath"
"syscall" "syscall"
"time" "time"
) )
@ -63,26 +65,24 @@ func (s *serveCmd) Execute(ctx context.Context, f *flag.FlagSet, _ ...interface{
return subcommands.ExitFailure return subcommands.ExitFailure
} }
normalLoad(conf) // working directory is the parent of the config file
wd := filepath.Dir(s.configPath)
normalLoad(conf, wd)
return subcommands.ExitSuccess return subcommands.ExitSuccess
} }
func normalLoad(conf startUpConfig) { func normalLoad(conf startUpConfig, wd string) {
// the cert and key paths are useless in self-signed mode // the cert and key paths are useless in self-signed mode
if !conf.SelfSigned { if !conf.SelfSigned {
if conf.CertPath != "" { // create path to cert dir
// create path to cert dir err := os.MkdirAll(filepath.Join(wd, "certs"), os.ModePerm)
err := os.MkdirAll(conf.CertPath, os.ModePerm) if err != nil {
if err != nil { log.Fatal("[Violet] Failed to create certificate path")
log.Fatalf("[Violet] Failed to create certificate path '%s'", conf.CertPath)
}
} }
if conf.KeyPath != "" { // create path to key dir
// create path to key dir err = os.MkdirAll(filepath.Join(wd, "keys"), os.ModePerm)
err := os.MkdirAll(conf.KeyPath, os.ModePerm) if err != nil {
if err != nil { log.Fatal("[Violet] Failed to create certificate key path")
log.Fatalf("[Violet] Failed to create certificate key path '%s'", conf.KeyPath)
}
} }
} }
@ -96,25 +96,28 @@ func normalLoad(conf startUpConfig) {
} }
} }
// load the MJWT RSA public key from a pem encoded file // load the MJWT RSA private key from a pem encoded file
mjwtVerify, err := mjwt.NewMJwtVerifierFromFile(conf.MjwtPubKey) mjwtSigner, err := mjwt.NewMJwtSignerFromFileOrCreate(conf.SignerIssuer, filepath.Join(wd, "violet.private.pem"), rand.New(rand.NewSource(time.Now().UnixNano())), 4096)
if err != nil { if err != nil {
log.Fatalf("[Violet] Failed to load MJWT verifier public key from file: '%s'", conf.MjwtPubKey) log.Fatal("[Violet] Failed to load MJWT verifier public key from file: ", err)
} }
// open sqlite database // open sqlite database
db, err := sql.Open("sqlite3", conf.Database) db, err := sql.Open("sqlite3", "violet.db.sqlite")
if err != nil { if err != nil {
log.Fatalf("[Violet] Failed to open database '%s'...", conf.Database) log.Fatal("[Violet] Failed to open database")
} }
allowedDomains := domains.New(db) // load allowed domains certDir := os.DirFS(filepath.Join(wd, "certs"))
acmeChallenges := utils.NewAcmeChallenge() // load acme challenge store keyDir := os.DirFS(filepath.Join(wd, "keys"))
allowedCerts := certs.New(os.DirFS(conf.CertPath), os.DirFS(conf.KeyPath), conf.SelfSigned) // load certificate manager
hybridTransport := proxy.NewHybridTransport() // load reverse proxy allowedDomains := domains.New(db) // load allowed domains
dynamicFavicons := favicons.New(db, conf.InkscapeCmd) // load dynamic favicon provider acmeChallenges := utils.NewAcmeChallenge() // load acme challenge store
dynamicErrorPages := errorPages.New(errorPageDir) // load dynamic error page provider allowedCerts := certs.New(certDir, keyDir, conf.SelfSigned) // load certificate manager
dynamicRouter := router.NewManager(db, hybridTransport) // load dynamic router manager hybridTransport := proxy.NewHybridTransport() // load reverse proxy
dynamicFavicons := favicons.New(db, conf.InkscapeCmd) // load dynamic favicon provider
dynamicErrorPages := errorPages.New(errorPageDir) // load dynamic error page provider
dynamicRouter := router.NewManager(db, hybridTransport) // load dynamic router manager
// struct containing config for the http servers // struct containing config for the http servers
srvConf := &servers.Conf{ srvConf := &servers.Conf{
@ -127,7 +130,7 @@ func normalLoad(conf startUpConfig) {
Acme: acmeChallenges, Acme: acmeChallenges,
Certs: allowedCerts, Certs: allowedCerts,
Favicons: dynamicFavicons, Favicons: dynamicFavicons,
Verify: mjwtVerify, Signer: mjwtSigner,
ErrorPages: dynamicErrorPages, ErrorPages: dynamicErrorPages,
Router: dynamicRouter, Router: dynamicRouter,
} }

View File

@ -59,14 +59,15 @@ func (s *setupCmd) Execute(_ context.Context, _ *flag.FlagSet, _ ...interface{})
// store answers from questions // store answers from questions
var answers struct { var answers struct {
SelfSigned bool SelfSigned bool
ErrorPages bool ErrorPages bool
ApiListen string ApiListen string
HttpListen string HttpListen string
HttpsListen string HttpsListen string
RateLimit uint64 RateLimit uint64
FirstDomain string FirstDomain string
ApiUrl string ApiUrl string
SignerIssuer string
} }
// ask main questions // ask main questions
@ -103,6 +104,10 @@ func (s *setupCmd) Execute(_ context.Context, _ *flag.FlagSet, _ ...interface{})
return nil return nil
}, },
}, },
{
Name: "SignerIssuer",
Prompt: &survey.Input{Message: "Issuer name to sign API tokens with", Default: "Violet"},
},
{ {
Name: "FirstDomain", Name: "FirstDomain",
Prompt: &survey.Input{Message: "First domain", Default: "example.com", Help: "Setup the first domain or it will be more difficult to setup later"}, Prompt: &survey.Input{Message: "First domain", Default: "example.com", Help: "Setup the first domain or it will be more difficult to setup later"},
@ -130,10 +135,6 @@ func (s *setupCmd) Execute(_ context.Context, _ *flag.FlagSet, _ ...interface{})
confEncode := json.NewEncoder(createConf) confEncode := json.NewEncoder(createConf)
confEncode.SetIndent("", " ") confEncode.SetIndent("", " ")
err = confEncode.Encode(startUpConfig{ err = confEncode.Encode(startUpConfig{
Database: filepath.Join(wdAbs, "violet.sqlite"),
MjwtPubKey: filepath.Join(wdAbs, "mjwt.public.key"),
CertPath: filepath.Join(wdAbs, "certs"),
KeyPath: filepath.Join(wdAbs, "keys"),
SelfSigned: answers.SelfSigned, SelfSigned: answers.SelfSigned,
ErrorPagePath: errorPagePath, ErrorPagePath: errorPagePath,
Listen: listenConfig{ Listen: listenConfig{
@ -141,8 +142,9 @@ func (s *setupCmd) Execute(_ context.Context, _ *flag.FlagSet, _ ...interface{})
Http: answers.HttpListen, Http: answers.HttpListen,
Https: answers.HttpsListen, Https: answers.HttpsListen,
}, },
InkscapeCmd: "inkscape", InkscapeCmd: "inkscape",
RateLimit: answers.RateLimit, RateLimit: answers.RateLimit,
SignerIssuer: answers.SignerIssuer,
}) })
if err != nil { if err != nil {
fmt.Println("[Violet] Failed to write config file: ", err) fmt.Println("[Violet] Failed to write config file: ", err)

2
go.mod
View File

@ -5,7 +5,7 @@ go 1.20
require ( require (
github.com/AlecAivazis/survey/v2 v2.3.7 github.com/AlecAivazis/survey/v2 v2.3.7
github.com/MrMelon54/certgen v0.0.1 github.com/MrMelon54/certgen v0.0.1
github.com/MrMelon54/mjwt v0.0.2 github.com/MrMelon54/mjwt v0.1.1
github.com/MrMelon54/png2ico v1.0.1 github.com/MrMelon54/png2ico v1.0.1
github.com/MrMelon54/rescheduler v0.0.1 github.com/MrMelon54/rescheduler v0.0.1
github.com/MrMelon54/trie v0.0.2 github.com/MrMelon54/trie v0.0.2

2
go.sum
View File

@ -4,6 +4,8 @@ github.com/MrMelon54/certgen v0.0.1 h1:ycWdZ2RlxQ5qSuejeBVv4aXjGo5hdqqL4j4EjrXnF
github.com/MrMelon54/certgen v0.0.1/go.mod h1:GHflVlSbtFLJZLpN1oWyUvDBRrR8qCWiwZLXCCnS2Gc= github.com/MrMelon54/certgen v0.0.1/go.mod h1:GHflVlSbtFLJZLpN1oWyUvDBRrR8qCWiwZLXCCnS2Gc=
github.com/MrMelon54/mjwt v0.0.2 h1:jDqyPnFloh80XdSmZ6jt9qhUj/ULcoQ4QSHXPdkAIE4= github.com/MrMelon54/mjwt v0.0.2 h1:jDqyPnFloh80XdSmZ6jt9qhUj/ULcoQ4QSHXPdkAIE4=
github.com/MrMelon54/mjwt v0.0.2/go.mod h1:HzY8P6Je+ovS/fwK5sILRMq5mnZT4+WuFRc98LBy7z4= github.com/MrMelon54/mjwt v0.0.2/go.mod h1:HzY8P6Je+ovS/fwK5sILRMq5mnZT4+WuFRc98LBy7z4=
github.com/MrMelon54/mjwt v0.1.1 h1:m+aTpxbhQCrOPKHN170DQMFR5r938LkviU38unob5Jw=
github.com/MrMelon54/mjwt v0.1.1/go.mod h1:oYrDBWK09Hju98xb+bRQ0wy+RuAzacxYvKYOZchR2Tk=
github.com/MrMelon54/png2ico v1.0.1 h1:zJoSSl4OkvSIMWGyGPvb8fWNa0KrUvMIjgNGLNLJhVQ= github.com/MrMelon54/png2ico v1.0.1 h1:zJoSSl4OkvSIMWGyGPvb8fWNa0KrUvMIjgNGLNLJhVQ=
github.com/MrMelon54/png2ico v1.0.1/go.mod h1:NOv3tO4497mInG+3tcFkIohmxCywUwMLU8WNxJZLVmU= github.com/MrMelon54/png2ico v1.0.1/go.mod h1:NOv3tO4497mInG+3tcFkIohmxCywUwMLU8WNxJZLVmU=
github.com/MrMelon54/rescheduler v0.0.1 h1:gzNvL8X81M00uYN0i9clFVrXCkG1UuLNYxDcvjKyBqo= github.com/MrMelon54/rescheduler v0.0.1 h1:gzNvL8X81M00uYN0i9clFVrXCkG1UuLNYxDcvjKyBqo=

View File

@ -18,7 +18,7 @@ func NewApiServer(conf *Conf, compileTarget utils.MultiCompilable) *http.Server
// Endpoint for compile action // Endpoint for compile action
r.POST("/compile", func(rw http.ResponseWriter, req *http.Request, _ httprouter.Params) { r.POST("/compile", func(rw http.ResponseWriter, req *http.Request, _ httprouter.Params) {
if !hasPerms(conf.Verify, req, "violet:compile") { if !hasPerms(conf.Signer, req, "violet:compile") {
utils.RespondHttpStatus(rw, http.StatusForbidden) utils.RespondHttpStatus(rw, http.StatusForbidden)
return return
} }
@ -30,7 +30,7 @@ func NewApiServer(conf *Conf, compileTarget utils.MultiCompilable) *http.Server
// Endpoint for domains // Endpoint for domains
r.PUT("/domain/:domain", func(rw http.ResponseWriter, req *http.Request, params httprouter.Params) { r.PUT("/domain/:domain", func(rw http.ResponseWriter, req *http.Request, params httprouter.Params) {
if !hasPerms(conf.Verify, req, "violet:domains") { if !hasPerms(conf.Signer, req, "violet:domains") {
utils.RespondHttpStatus(rw, http.StatusForbidden) utils.RespondHttpStatus(rw, http.StatusForbidden)
return return
} }
@ -41,7 +41,7 @@ func NewApiServer(conf *Conf, compileTarget utils.MultiCompilable) *http.Server
conf.Domains.Compile() conf.Domains.Compile()
}) })
r.DELETE("/domain/:domain", func(rw http.ResponseWriter, req *http.Request, params httprouter.Params) { r.DELETE("/domain/:domain", func(rw http.ResponseWriter, req *http.Request, params httprouter.Params) {
if !hasPerms(conf.Verify, req, "violet:domains") { if !hasPerms(conf.Signer, req, "violet:domains") {
utils.RespondHttpStatus(rw, http.StatusForbidden) utils.RespondHttpStatus(rw, http.StatusForbidden)
return return
} }
@ -59,7 +59,7 @@ func NewApiServer(conf *Conf, compileTarget utils.MultiCompilable) *http.Server
// Endpoint for acme-challenge // Endpoint for acme-challenge
r.PUT("/acme-challenge/:domain/:key/:value", func(rw http.ResponseWriter, req *http.Request, params httprouter.Params) { r.PUT("/acme-challenge/:domain/:key/:value", func(rw http.ResponseWriter, req *http.Request, params httprouter.Params) {
if !hasPerms(conf.Verify, req, "violet:acme-challenge") { if !hasPerms(conf.Signer, req, "violet:acme-challenge") {
utils.RespondHttpStatus(rw, http.StatusForbidden) utils.RespondHttpStatus(rw, http.StatusForbidden)
return return
} }
@ -72,7 +72,7 @@ func NewApiServer(conf *Conf, compileTarget utils.MultiCompilable) *http.Server
rw.WriteHeader(http.StatusAccepted) rw.WriteHeader(http.StatusAccepted)
}) })
r.DELETE("/acme-challenge/:domain/:key", func(rw http.ResponseWriter, req *http.Request, params httprouter.Params) { r.DELETE("/acme-challenge/:domain/:key", func(rw http.ResponseWriter, req *http.Request, params httprouter.Params) {
if !hasPerms(conf.Verify, req, "violet:acme-challenge") { if !hasPerms(conf.Signer, req, "violet:acme-challenge") {
utils.RespondHttpStatus(rw, http.StatusForbidden) utils.RespondHttpStatus(rw, http.StatusForbidden)
return return
} }

View File

@ -34,10 +34,7 @@ func genSnakeOilProv() mjwt.Signer {
func genSnakeOilKey(perm string) string { func genSnakeOilKey(perm string) string {
p := claims.NewPermStorage() p := claims.NewPermStorage()
p.Set(perm) p.Set(perm)
val, err := snakeOilProv.GenerateJwt("abc", "abc", 5*time.Minute, auth.AccessTokenClaims{ val, err := snakeOilProv.GenerateJwt("abc", "abc", nil, 5*time.Minute, auth.AccessTokenClaims{Perms: p})
UserId: 1,
Perms: p,
})
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -54,7 +51,7 @@ func TestNewApiServer_Compile(t *testing.T) {
apiConf := &Conf{ apiConf := &Conf{
Domains: &fakeDomains{}, Domains: &fakeDomains{},
Acme: utils.NewAcmeChallenge(), Acme: utils.NewAcmeChallenge(),
Verify: snakeOilProv, Signer: snakeOilProv,
} }
f := &fakeCompilable{} f := &fakeCompilable{}
srv := NewApiServer(apiConf, utils.MultiCompilable{f}) srv := NewApiServer(apiConf, utils.MultiCompilable{f})
@ -81,7 +78,7 @@ func TestNewApiServer_AcmeChallenge_Put(t *testing.T) {
apiConf := &Conf{ apiConf := &Conf{
Domains: &fakeDomains{}, Domains: &fakeDomains{},
Acme: utils.NewAcmeChallenge(), Acme: utils.NewAcmeChallenge(),
Verify: snakeOilProv, Signer: snakeOilProv,
} }
srv := NewApiServer(apiConf, utils.MultiCompilable{}) srv := NewApiServer(apiConf, utils.MultiCompilable{})
acmeKey := genSnakeOilKey("violet:acme-challenge") acmeKey := genSnakeOilKey("violet:acme-challenge")
@ -125,7 +122,7 @@ func TestNewApiServer_AcmeChallenge_Delete(t *testing.T) {
apiConf := &Conf{ apiConf := &Conf{
Domains: &fakeDomains{}, Domains: &fakeDomains{},
Acme: utils.NewAcmeChallenge(), Acme: utils.NewAcmeChallenge(),
Verify: snakeOilProv, Signer: snakeOilProv,
} }
srv := NewApiServer(apiConf, utils.MultiCompilable{}) srv := NewApiServer(apiConf, utils.MultiCompilable{})
acmeKey := genSnakeOilKey("violet:acme-challenge") acmeKey := genSnakeOilKey("violet:acme-challenge")

View File

@ -20,7 +20,7 @@ type Conf struct {
Acme AcmeChallengeProvider Acme AcmeChallengeProvider
Certs CertProvider Certs CertProvider
Favicons *favicons.Favicons Favicons *favicons.Favicons
Verify mjwt.Verifier Signer mjwt.Verifier
ErrorPages *errorPages.ErrorPages ErrorPages *errorPages.ErrorPages
Router *router.Manager Router *router.Manager
} }

View File

@ -14,7 +14,7 @@ func TestNewHttpServer_AcmeChallenge(t *testing.T) {
httpConf := &Conf{ httpConf := &Conf{
Domains: &fakeDomains{}, Domains: &fakeDomains{},
Acme: utils.NewAcmeChallenge(), Acme: utils.NewAcmeChallenge(),
Verify: snakeOilProv, Signer: snakeOilProv,
} }
srv := NewHttpServer(httpConf) srv := NewHttpServer(httpConf)
httpConf.Acme.Put("example.com", "456", "456def") httpConf.Acme.Put("example.com", "456", "456def")

View File

@ -30,7 +30,7 @@ func TestNewHttpsServer_RateLimit(t *testing.T) {
RateLimit: 5, RateLimit: 5,
Domains: &fakeDomains{}, Domains: &fakeDomains{},
Certs: certs.New(nil, nil, true), Certs: certs.New(nil, nil, true),
Verify: snakeOilProv, Signer: snakeOilProv,
Router: router.NewManager(db, proxy.NewHybridTransportWithCalls(ft, ft)), Router: router.NewManager(db, proxy.NewHybridTransportWithCalls(ft, ft)),
} }
srv := NewHttpsServer(httpsConf) srv := NewHttpsServer(httpsConf)