diff --git a/certs/certs.go b/certs/certs.go index fc37210..dc801c9 100644 --- a/certs/certs.go +++ b/certs/certs.go @@ -1,10 +1,10 @@ package certs import ( - "code.mrmelon54.com/melon/certgen" "crypto/tls" "crypto/x509/pkix" "fmt" + "github.com/MrMelon54/certgen" "github.com/MrMelon54/violet/utils" "io/fs" "log" @@ -36,13 +36,15 @@ func New(certDir fs.FS, keyDir fs.FS, selfCert bool) *Certs { m: make(map[string]*tls.Certificate), } if c.ss { - ca, err := certgen.MakeCaTls(pkix.Name{ + ca, err := certgen.MakeCaTls(4096, pkix.Name{ Country: []string{"GB"}, Organization: []string{"Violet"}, OrganizationalUnit: []string{"Development"}, SerialNumber: "0", CommonName: fmt.Sprintf("%d.violet.test", time.Now().Unix()), - }, big.NewInt(0)) + }, big.NewInt(0), func(now time.Time) time.Time { + return now.AddDate(10, 0, 0) + }) if err != nil { log.Fatalln("Failed to generate CA cert for self-signed mode:", err) } @@ -67,13 +69,15 @@ func (c *Certs) GetCertForDomain(domain string) *tls.Certificate { // if self-signed certificate is enabled then generate a certificate if c.ss { sn := c.sn.Add(1) - serverTls, err := certgen.MakeServerTls(c.ca, pkix.Name{ + serverTls, err := certgen.MakeServerTls(c.ca, 4096, pkix.Name{ Country: []string{"GB"}, Organization: []string{domain}, OrganizationalUnit: []string{domain}, SerialNumber: fmt.Sprintf("%d", sn), CommonName: domain, - }, big.NewInt(sn), []string{domain}, nil) + }, big.NewInt(sn), func(now time.Time) time.Time { + return now.AddDate(10, 0, 0) + }, []string{domain}, nil) if err != nil { return nil } diff --git a/certs/certs_test.go b/certs/certs_test.go index a60efe8..42b9c58 100644 --- a/certs/certs_test.go +++ b/certs/certs_test.go @@ -1,9 +1,9 @@ package certs import ( - "code.mrmelon54.com/melon/certgen" "crypto/x509/pkix" "fmt" + "github.com/MrMelon54/certgen" "github.com/stretchr/testify/assert" "math/big" "testing" @@ -16,24 +16,28 @@ func TestCertsNew_Lookup(t *testing.T) { // type to test that certificate files can be found and read correctly. This // uses a MapFS for performance during tests. - ca, err := certgen.MakeCaTls(pkix.Name{ + ca, err := certgen.MakeCaTls(4096, pkix.Name{ Country: []string{"GB"}, Organization: []string{"Violet"}, OrganizationalUnit: []string{"Development"}, SerialNumber: "0", CommonName: fmt.Sprintf("%d.violet.test", time.Now().Unix()), - }, big.NewInt(0)) + }, big.NewInt(0), func(now time.Time) time.Time { + return now.AddDate(10, 0, 0) + }) assert.NoError(t, err) domain := "example.com" sn := int64(1) - serverTls, err := certgen.MakeServerTls(ca, pkix.Name{ + serverTls, err := certgen.MakeServerTls(ca, 4096, pkix.Name{ Country: []string{"GB"}, Organization: []string{domain}, OrganizationalUnit: []string{domain}, SerialNumber: fmt.Sprintf("%d", sn), CommonName: domain, - }, big.NewInt(sn), []string{domain}, nil) + }, big.NewInt(sn), func(now time.Time) time.Time { + return now.AddDate(10, 0, 0) + }, []string{domain}, nil) assert.NoError(t, err) certDir := fstest.MapFS{ diff --git a/favicons/favicon-list.go b/favicons/favicon-list.go index 5ec0e95..ab275b7 100644 --- a/favicons/favicon-list.go +++ b/favicons/favicon-list.go @@ -5,7 +5,7 @@ import ( "crypto/sha256" "encoding/hex" "fmt" - "github.com/mrmelon54/png2ico" + "github.com/MrMelon54/png2ico" "image/png" "io" "net/http" diff --git a/go.mod b/go.mod index 96917a5..f5a8609 100644 --- a/go.mod +++ b/go.mod @@ -3,16 +3,15 @@ module github.com/MrMelon54/violet go 1.20 require ( - code.mrmelon54.com/melon/certgen v0.0.0-20220830133534-0fb4cb7e67d1 - code.mrmelon54.com/melon/summer-utils v0.0.3 + github.com/MrMelon54/certgen v0.0.1 + github.com/MrMelon54/mjwt v0.0.2 + github.com/MrMelon54/png2ico v1.0.1 github.com/MrMelon54/trie v0.0.2 github.com/julienschmidt/httprouter v1.3.0 github.com/mattn/go-sqlite3 v1.14.16 - github.com/mrmelon54/mjwt v0.0.1 - github.com/mrmelon54/png2ico v1.0.0 github.com/rs/cors v1.9.0 github.com/sethvargo/go-limiter v0.7.2 - github.com/stretchr/testify v1.8.2 + github.com/stretchr/testify v1.8.4 golang.org/x/net v0.9.0 golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 ) diff --git a/go.sum b/go.sum index b5468e7..22efb14 100644 --- a/go.sum +++ b/go.sum @@ -1,10 +1,11 @@ -code.mrmelon54.com/melon/certgen v0.0.0-20220830133534-0fb4cb7e67d1 h1:tll8DwvO1CL+xXJIMLyDmQYoYr/gA4BkcUFtNHB1BFo= -code.mrmelon54.com/melon/certgen v0.0.0-20220830133534-0fb4cb7e67d1/go.mod h1:Liyhe1bkNyeVfw6LicCgrQ+4oUT/w/qONLjvejkUim0= -code.mrmelon54.com/melon/summer-utils v0.0.3 h1:Bz4o5BBOqWCNGpKkxUum4rwMn/DIdyMCKGQ/D6SXD6Q= -code.mrmelon54.com/melon/summer-utils v0.0.3/go.mod h1:Gh/baXSzkf1ZhHonpPP8oQkyhhmFZcC2yTMlrwclDUw= +github.com/MrMelon54/certgen v0.0.1 h1:ycWdZ2RlxQ5qSuejeBVv4aXjGo5hdqqL4j4EjrXnFMk= +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/go.mod h1:HzY8P6Je+ovS/fwK5sILRMq5mnZT4+WuFRc98LBy7z4= +github.com/MrMelon54/png2ico v1.0.1 h1:zJoSSl4OkvSIMWGyGPvb8fWNa0KrUvMIjgNGLNLJhVQ= +github.com/MrMelon54/png2ico v1.0.1/go.mod h1:NOv3tO4497mInG+3tcFkIohmxCywUwMLU8WNxJZLVmU= github.com/MrMelon54/trie v0.0.2 h1:ZXWcX5ij62O9K4I/anuHmVg8L3tF0UGdlPceAASwKEY= github.com/MrMelon54/trie v0.0.2/go.mod h1:sGCGOcqb+DxSxvHgSOpbpkmA7mFZR47YDExy9OCbVZI= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= @@ -18,10 +19,6 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= -github.com/mrmelon54/mjwt v0.0.1 h1:XgyWviTmgsbMiKXjxo+Jp/QSf7FF7/omkvrUag8/P5U= -github.com/mrmelon54/mjwt v0.0.1/go.mod h1:M+kZ6t9EArEQ2/CGjfgyNhAo542ot+S7gw5uJCK11Ms= -github.com/mrmelon54/png2ico v1.0.0 h1:YE20i0xao8rkuYaCq3Xj2hUkVkJ6xp412aGDMrGqufA= -github.com/mrmelon54/png2ico v1.0.0/go.mod h1:vp8Be9y5cz102ANon+BnsIzTUdet3VQRvOuWJTH9h0M= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -30,13 +27,8 @@ github.com/rs/cors v1.9.0 h1:l9HGsTsHJcvW14Nk7J9KFz8bzeAWXn3CG6bgt7LsrAE= github.com/rs/cors v1.9.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/sethvargo/go-limiter v0.7.2 h1:FgC4N7RMpV5gMrUdda15FaFTkQ/L4fEqM7seXMs4oO8= github.com/sethvargo/go-limiter v0.7.2/go.mod h1:C0kbSFbiriE5k2FFOe18M1YZbAR2Fiwf72uGu0CXCcU= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= -github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck= @@ -46,6 +38,5 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/proxy/reverse-proxy_test.go b/proxy/reverse-proxy_test.go deleted file mode 100644 index ddf43a3..0000000 --- a/proxy/reverse-proxy_test.go +++ /dev/null @@ -1,48 +0,0 @@ -package proxy - -import ( - "log" - "net/http" - "net/http/httptest" - "net/http/httputil" - "testing" -) - -type customTransport struct{} - -func (c *customTransport) RoundTrip(_ *http.Request) (*http.Response, error) { - res := httptest.NewRecorder() - res.WriteHeader(http.StatusOK) - res.Write([]byte{0x54, 0x54}) - return res.Result(), nil -} - -func SetupReverseProxy() *httputil.ReverseProxy { - return &httputil.ReverseProxy{ - Director: func(req *http.Request) {}, - Transport: &customTransport{}, - ModifyResponse: func(rw *http.Response) error { return nil }, - ErrorHandler: func(rw http.ResponseWriter, req *http.Request, err error) { - log.Printf("[ReverseProxy] Request: %#v\n -- Error: %s\n", req, err) - rw.WriteHeader(http.StatusBadGateway) - _, _ = rw.Write([]byte("502 Bad gateway\n")) - }, - } -} - -func BenchmarkHttpUtilReverseProxy(b *testing.B) { - rev := SetupReverseProxy() - req, _ := http.NewRequest(http.MethodGet, "https://example.com", nil) - for i := 0; i < b.N; i++ { - rec := httptest.NewRecorder() - rev.ServeHTTP(rec, req) - } -} - -func BenchmarkCustomTransport(b *testing.B) { - req, _ := http.NewRequest(http.MethodGet, "https://example.com", nil) - t := &customTransport{} - for i := 0; i < b.N; i++ { - _, _ = t.RoundTrip(req) - } -} diff --git a/router/manager.go b/router/manager.go index dd884d1..988d215 100644 --- a/router/manager.go +++ b/router/manager.go @@ -39,7 +39,7 @@ func NewManager(db *sql.DB, proxy *proxy.HybridTransport) *Manager { m := &Manager{ db: db, s: &sync.RWMutex{}, - r: New(nil), + r: New(proxy), p: proxy, } diff --git a/router/manager_test.go b/router/manager_test.go new file mode 100644 index 0000000..ccb8323 --- /dev/null +++ b/router/manager_test.go @@ -0,0 +1,50 @@ +package router + +import ( + "database/sql" + "github.com/MrMelon54/violet/proxy" + _ "github.com/mattn/go-sqlite3" + "github.com/stretchr/testify/assert" + "net/http" + "net/http/httptest" + "testing" +) + +type fakeTransport struct{ req *http.Request } + +func (f *fakeTransport) RoundTrip(req *http.Request) (*http.Response, error) { + f.req = req + rec := httptest.NewRecorder() + rec.WriteHeader(http.StatusOK) + return rec.Result(), nil +} + +func TestNewManager(t *testing.T) { + db, err := sql.Open("sqlite3", "file::memory:?cache=shared") + assert.NoError(t, err) + + ft := &fakeTransport{} + ht := proxy.NewHybridTransportWithCalls(ft, ft) + m := NewManager(db, ht) + assert.NoError(t, m.internalCompile(m.r)) + + rec := httptest.NewRecorder() + req, err := http.NewRequest(http.MethodGet, "https://test.example.com", nil) + assert.NoError(t, err) + + m.ServeHTTP(rec, req) + res := rec.Result() + assert.Equal(t, http.StatusTeapot, res.StatusCode) + assert.Nil(t, ft.req) + + _, err = db.Exec(`INSERT INTO routes (source, pre, destination, abs, cors, secure_mode, forward_host, forward_addr, ignore_cert, active) VALUES (?,?,?,?,?,?,?,?,?,?)`, "*.example.com", 0, "127.0.0.1:8080", 1, 0, 0, 1, 1, 0, 1) + assert.NoError(t, err) + + assert.NoError(t, m.internalCompile(m.r)) + + rec = httptest.NewRecorder() + m.ServeHTTP(rec, req) + res = rec.Result() + assert.Equal(t, http.StatusOK, res.StatusCode) + assert.NotNil(t, ft.req) +} diff --git a/router/router.go b/router/router.go index 53f21da..38227ec 100644 --- a/router/router.go +++ b/router/router.go @@ -86,6 +86,8 @@ func (r *Router) ServeHTTP(rw http.ResponseWriter, req *http.Request) { if r.serveRouteHTTP(rw, req, wildcardHost) { return } + + utils.RespondVioletError(rw, http.StatusTeapot, "No route") } func (r *Router) serveRouteHTTP(rw http.ResponseWriter, req *http.Request, host string) bool { diff --git a/router/router_test.go b/router/router_test.go index d2e14d3..5090c78 100644 --- a/router/router_test.go +++ b/router/router_test.go @@ -174,15 +174,6 @@ var ( } ) -type fakeTransport struct{ req *http.Request } - -func (f *fakeTransport) RoundTrip(req *http.Request) (*http.Response, error) { - f.req = req - rec := httptest.NewRecorder() - rec.WriteHeader(http.StatusOK) - return rec.Result(), nil -} - func TestRouter_AddRoute(t *testing.T) { transSecure := &fakeTransport{} transInsecure := &fakeTransport{} @@ -267,3 +258,42 @@ func outputUrl(u *url.URL) string { } return u.String() } + +func TestRouter_AddWildcardRoute(t *testing.T) { + transSecure := &fakeTransport{} + transInsecure := &fakeTransport{} + + for _, i := range routeTests { + r := New(proxy.NewHybridTransportWithCalls(transSecure, transInsecure)) + dst := i.dst + dst.Host = "127.0.0.1" + dst.Port = 8080 + t.Logf("Running tests for %#v\n", dst) + r.AddRoute("example.com", i.path, dst) + for k, v := range i.tests { + u1 := &url.URL{Scheme: "https", Host: "example.com", Path: k} + req, _ := http.NewRequest(http.MethodGet, u1.String(), nil) + rec := httptest.NewRecorder() + r.ServeHTTP(rec, req) + if v == "" { + if transSecure.req != nil { + t.Logf("Test URL: %#v\n", req.URL) + t.Log(r.redirect["example.com"].String()) + t.Fatalf("%s => %s\n", k, v) + } + } else { + if transSecure.req == nil { + t.Logf("Test URL: %#v\n", req.URL) + t.Log(r.route["example.com"].String()) + t.Fatalf("\nexpected %s => %s\n got %s => %s\n", k, v, k, "") + } + if v != transSecure.req.URL.Path { + t.Logf("Test URL: %#v\n", req.URL) + t.Log(r.route["example.com"].String()) + t.Fatalf("\nexpected %s => %s\n got %s => %s\n", k, v, k, transSecure.req.URL.Path) + } + transSecure.req = nil + } + } + } +} diff --git a/servers/api.go b/servers/api.go index e7cd1a7..cfd3f2b 100644 --- a/servers/api.go +++ b/servers/api.go @@ -1,10 +1,10 @@ package servers import ( - "code.mrmelon54.com/melon/summer-utils/claims/auth" + "github.com/MrMelon54/mjwt" + "github.com/MrMelon54/mjwt/auth" "github.com/MrMelon54/violet/utils" "github.com/julienschmidt/httprouter" - "github.com/mrmelon54/mjwt" "net/http" "time" ) @@ -68,7 +68,7 @@ func NewApiServer(conf *Conf, compileTarget utils.MultiCompilable) *http.Server } } -func hasPerms(verify mjwt.Provider, req *http.Request, perm string) bool { +func hasPerms(verify mjwt.Verifier, req *http.Request, perm string) bool { // Get bearer token bearer := utils.GetBearer(req) if bearer == "" { diff --git a/servers/api_test.go b/servers/api_test.go index f2a2c5c..d465998 100644 --- a/servers/api_test.go +++ b/servers/api_test.go @@ -1,12 +1,12 @@ package servers import ( - "code.mrmelon54.com/melon/summer-utils/claims" - "code.mrmelon54.com/melon/summer-utils/claims/auth" "crypto/rand" "crypto/rsa" + "github.com/MrMelon54/mjwt" + "github.com/MrMelon54/mjwt/auth" + "github.com/MrMelon54/mjwt/claims" "github.com/MrMelon54/violet/utils" - "github.com/mrmelon54/mjwt" "github.com/stretchr/testify/assert" "net/http" "net/http/httptest" @@ -20,7 +20,7 @@ type fakeDomains struct{} func (f *fakeDomains) IsValid(host string) bool { return host == "example.com" } -func genSnakeOilProv() mjwt.Provider { +func genSnakeOilProv() mjwt.Signer { key, err := rsa.GenerateKey(rand.Reader, 1024) if err != nil { panic(err) diff --git a/servers/conf.go b/servers/conf.go index c885978..ab3e877 100644 --- a/servers/conf.go +++ b/servers/conf.go @@ -3,10 +3,10 @@ package servers import ( "crypto/tls" "database/sql" + "github.com/MrMelon54/mjwt" errorPages "github.com/MrMelon54/violet/error-pages" "github.com/MrMelon54/violet/favicons" "github.com/MrMelon54/violet/router" - "github.com/mrmelon54/mjwt" ) // Conf stores the shared configuration for the API, HTTP and HTTPS servers. @@ -20,7 +20,7 @@ type Conf struct { Acme AcmeChallengeProvider Certs CertProvider Favicons *favicons.Favicons - Verify mjwt.Provider + Verify mjwt.Verifier ErrorPages *errorPages.ErrorPages Router *router.Manager } diff --git a/servers/https_test.go b/servers/https_test.go index 4c0ee04..cb763c3 100644 --- a/servers/https_test.go +++ b/servers/https_test.go @@ -47,7 +47,7 @@ func TestNewHttpsServer_RateLimit(t *testing.T) { rec := httptest.NewRecorder() srv.Handler.ServeHTTP(rec, req) res := rec.Result() - assert.Equal(t, http.StatusOK, res.StatusCode) + assert.Equal(t, http.StatusTeapot, res.StatusCode) }() } wg.Wait()