diff --git a/.golangci.yml b/.golangci.yml index 8017cdba..25c9e906 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,7 +1,3 @@ -run: - skip-dirs: - - testing - - dist linters: enable-all: true disable: @@ -37,6 +33,7 @@ linters-settings: - to - ok - fs + - ca presets: - bugs - comment diff --git a/README.md b/README.md index 0cf4b251..57774271 100644 --- a/README.md +++ b/README.md @@ -94,7 +94,7 @@ docker run -p 80:3000 evg4b/uncors --from 'http://local.github.com' --to 'https: ## Stew (Cross-platform) -Also you can install binaris using [Stew](https://github.com/marwanhawari/) with the following commands: +Also, you can install binaris using [Stew](https://github.com/marwanhawari/) with the following commands: ```bash stew install evg4b/uncors diff --git a/internal/config/helpers.go b/internal/config/helpers.go index 3898a501..09c15206 100644 --- a/internal/config/helpers.go +++ b/internal/config/helpers.go @@ -32,18 +32,16 @@ func readURLMapping(config *viper.Viper, configuration *UncorsConfig) error { } for index, key := range from { - value := to[index] prev, ok := lo.Find(configuration.Mappings, func(item Mapping) bool { return strings.EqualFold(item.From, key) }) if ok { - // log.Warningf("Mapping for %s from (%s) replaced new value (%s)", key, prev, value) - prev.To = value + prev.To = to[index] } else { configuration.Mappings = append(configuration.Mappings, Mapping{ From: key, - To: value, + To: to[index], }) } } diff --git a/internal/config/hooks/time_decode_hook.go b/internal/config/hooks/time_decode_hook.go index d6e77a43..1968e084 100644 --- a/internal/config/hooks/time_decode_hook.go +++ b/internal/config/hooks/time_decode_hook.go @@ -10,16 +10,13 @@ import ( func StringToTimeDurationHookFunc() mapstructure.DecodeHookFunc { return func(f reflect.Type, t reflect.Type, data any) (any, error) { - if f.Kind() != reflect.String { + if f.Kind() != reflect.String || t != reflect.TypeOf(time.Second) { return data, nil } - if t != reflect.TypeOf(time.Second) { - return data, nil - } - - trimmed := strings.ReplaceAll(data.(string), " ", "") //nolint: forcetypeassert - - return time.ParseDuration(trimmed) //nolint:wrapcheck + //nolint:wrapcheck + return time.ParseDuration( + strings.ReplaceAll(data.(string), " ", ""), //nolint: forcetypeassert + ) } } diff --git a/internal/config/mapping.go b/internal/config/mapping.go index c868defb..dd51394e 100644 --- a/internal/config/mapping.go +++ b/internal/config/mapping.go @@ -8,28 +8,18 @@ import ( ) type Mapping struct { - From string `mapstructure:"from"` - To string `mapstructure:"to"` - Statics StaticDirs `mapstructure:"statics"` - Mocks []Mock `mapstructure:"mocks"` + From string `mapstructure:"from"` + To string `mapstructure:"to"` + Statics StaticDirectories `mapstructure:"statics"` + Mocks Mocks `mapstructure:"mocks"` } -func (u Mapping) Clone() Mapping { +func (u *Mapping) Clone() Mapping { return Mapping{ - From: u.From, - To: u.To, - Statics: lo.If(u.Statics == nil, StaticDirs(nil)). - ElseF(func() StaticDirs { - return lo.Map(u.Statics, func(item StaticDir, index int) StaticDir { - return item.Clone() - }) - }), - Mocks: lo.If(u.Mocks == nil, []Mock(nil)). - ElseF(func() []Mock { - return lo.Map(u.Mocks, func(item Mock, index int) Mock { - return item.Clone() - }) - }), + From: u.From, + To: u.To, + Statics: u.Statics.Clone(), + Mocks: u.Mocks.Clone(), } } diff --git a/internal/config/mapping_test.go b/internal/config/mapping_test.go index e37fcdc2..09cbfb49 100644 --- a/internal/config/mapping_test.go +++ b/internal/config/mapping_test.go @@ -90,7 +90,7 @@ func TestURLMappingClone(t *testing.T) { expected: config.Mapping{ From: localhost, To: localhostSecure, - Statics: []config.StaticDir{ + Statics: []config.StaticDirectory{ {Path: "/cc", Dir: "cc"}, }, }, diff --git a/internal/config/model.go b/internal/config/model.go index 3d5e59cf..a8f6e941 100644 --- a/internal/config/model.go +++ b/internal/config/model.go @@ -4,6 +4,7 @@ import ( "time" "github.com/evg4b/uncors/internal/helpers" + "github.com/samber/lo" ) type Response struct { @@ -14,7 +15,7 @@ type Response struct { Delay time.Duration `mapstructure:"delay"` } -func (r Response) Clone() Response { +func (r *Response) Clone() Response { return Response{ Code: r.Code, Headers: helpers.CloneMap(r.Headers), @@ -32,7 +33,7 @@ type Mock struct { Response Response `mapstructure:"response"` } -func (m Mock) Clone() Mock { +func (m *Mock) Clone() Mock { return Mock{ Path: m.Path, Method: m.Method, @@ -41,3 +42,15 @@ func (m Mock) Clone() Mock { Response: m.Response.Clone(), } } + +type Mocks []Mock + +func (m Mocks) Clone() Mocks { + if m == nil { + return nil + } + + return lo.Map(m, func(item Mock, index int) Mock { + return item.Clone() + }) +} diff --git a/internal/config/static.go b/internal/config/static.go index d14469ad..8e6818cf 100644 --- a/internal/config/static.go +++ b/internal/config/static.go @@ -4,25 +4,36 @@ import ( "reflect" "github.com/mitchellh/mapstructure" + "github.com/samber/lo" ) -type StaticDirs = []StaticDir - -type StaticDir struct { +type StaticDirectory struct { Path string `mapstructure:"path"` Dir string `mapstructure:"dir"` Index string `mapstructure:"index"` } -func (s StaticDir) Clone() StaticDir { - return StaticDir{ +func (s *StaticDirectory) Clone() StaticDirectory { + return StaticDirectory{ Path: s.Path, Dir: s.Dir, Index: s.Index, } } -var staticDirMappingsType = reflect.TypeOf(StaticDirs{}) +type StaticDirectories []StaticDirectory + +func (d StaticDirectories) Clone() StaticDirectories { + if d == nil { + return nil + } + + return lo.Map(d, func(item StaticDirectory, index int) StaticDirectory { + return item.Clone() + }) +} + +var staticDirMappingsType = reflect.TypeOf(StaticDirectories{}) func StaticDirMappingHookFunc() mapstructure.DecodeHookFunc { //nolint: ireturn return func(f reflect.Type, t reflect.Type, rawData any) (any, error) { @@ -35,10 +46,10 @@ func StaticDirMappingHookFunc() mapstructure.DecodeHookFunc { //nolint: ireturn return rawData, nil } - var mappings StaticDirs + var mappings StaticDirectories for path, mappingDef := range mappingsDefs { if def, ok := mappingDef.(string); ok { - mappings = append(mappings, StaticDir{ + mappings = append(mappings, StaticDirectory{ Path: path, Dir: def, }) @@ -46,7 +57,7 @@ func StaticDirMappingHookFunc() mapstructure.DecodeHookFunc { //nolint: ireturn continue } - mapping := StaticDir{} + mapping := StaticDirectory{} err := decodeConfig(mappingDef, &mapping) if err != nil { return nil, err diff --git a/internal/config/static_test.go b/internal/config/static_test.go index 4aca8b29..b64ca8bc 100644 --- a/internal/config/static_test.go +++ b/internal/config/static_test.go @@ -19,13 +19,13 @@ const ( func TestStaticDirMappingHookFunc(t *testing.T) { const configFile = "config.yaml" type testType struct { - Statics config.StaticDirs `mapstructure:"statics"` + Statics config.StaticDirectories `mapstructure:"statics"` } tests := []struct { name string config string - expected config.StaticDirs + expected config.StaticDirectories }{ { name: "decode plan mapping", @@ -34,7 +34,7 @@ statics: /path: /static-dir /another-path: /another-static-dir `, - expected: config.StaticDirs{ + expected: config.StaticDirectories{ {Path: anotherPath, Dir: anotherStaticDir}, {Path: path, Dir: staticDir}, }, @@ -46,7 +46,7 @@ statics: /path: { dir: /static-dir } /another-path: { dir: /another-static-dir } `, - expected: config.StaticDirs{ + expected: config.StaticDirectories{ {Path: path, Dir: staticDir}, {Path: anotherPath, Dir: anotherStaticDir}, }, @@ -58,7 +58,7 @@ statics: /path: { dir: /static-dir, index: index.html } /another-path: { dir: /another-static-dir, index: default.html } `, - expected: config.StaticDirs{ + expected: config.StaticDirectories{ {Path: path, Dir: staticDir, Index: "index.html"}, {Path: anotherPath, Dir: anotherStaticDir, Index: "default.html"}, }, @@ -70,7 +70,7 @@ statics: /path: { dir: /static-dir, index: index.html } /another-path: /another-static-dir `, - expected: config.StaticDirs{ + expected: config.StaticDirectories{ {Path: path, Dir: staticDir, Index: "index.html"}, {Path: anotherPath, Dir: anotherStaticDir}, }, @@ -101,28 +101,28 @@ statics: func TestStaticDirMappingClone(t *testing.T) { tests := []struct { name string - expected config.StaticDir + expected config.StaticDirectory }{ { name: "empty structure", - expected: config.StaticDir{}, + expected: config.StaticDirectory{}, }, { name: "structure with 1 field", - expected: config.StaticDir{ + expected: config.StaticDirectory{ Dir: "dir", }, }, { name: "structure with 2 field", - expected: config.StaticDir{ + expected: config.StaticDirectory{ Dir: "dir", Path: "/some-path", }, }, { name: "structure with all field", - expected: config.StaticDir{ + expected: config.StaticDirectory{ Dir: "dir", Path: "/one-more-path", Index: "index.html", diff --git a/internal/handler/static_routes.go b/internal/handler/static_routes.go index 1d3ec9a1..90837076 100644 --- a/internal/handler/static_routes.go +++ b/internal/handler/static_routes.go @@ -11,7 +11,7 @@ import ( "github.com/spf13/afero" ) -func (m *RequestHandler) makeStaticRoutes(router *mux.Router, statics config.StaticDirs, next http.Handler) { +func (m *RequestHandler) makeStaticRoutes(router *mux.Router, statics config.StaticDirectories, next http.Handler) { for _, staticDir := range statics { clearPath := strings.TrimSuffix(staticDir.Path, "/") path := clearPath + "/" diff --git a/internal/handler/uncors_handler_test.go b/internal/handler/uncors_handler_test.go index 05b36b13..fa9afe62 100644 --- a/internal/handler/uncors_handler_test.go +++ b/internal/handler/uncors_handler_test.go @@ -56,7 +56,7 @@ func TestUncorsRequestHandler(t *testing.T) { { From: localhost, To: localhostSecure, - Statics: []config.StaticDir{ + Statics: []config.StaticDirectory{ {Dir: "/assets", Path: "/cc/", Index: indexHTML}, {Dir: "/assets", Path: "/pnp/", Index: "index.php"}, {Dir: "/images", Path: "/img/"}, diff --git a/internal/helpers/clone.go b/internal/helpers/clone.go index 8ea5858a..f2272075 100644 --- a/internal/helpers/clone.go +++ b/internal/helpers/clone.go @@ -11,6 +11,8 @@ func CloneMap[K comparable, V any](data map[K]V) map[K]V { for key, value := range data { if cloneable, ok := any(value).(lo.Clonable[V]); ok { cloned[key] = cloneable.Clone() + } else if cloneablePtr, ok := any(&value).(lo.Clonable[V]); ok { //nolint:gosec + cloned[key] = cloneablePtr.Clone() } else { cloned[key] = value } diff --git a/internal/helpers/clone_test.go b/internal/helpers/clone_test.go index 1abc6796..b4e193b7 100644 --- a/internal/helpers/clone_test.go +++ b/internal/helpers/clone_test.go @@ -10,7 +10,7 @@ import ( type clonableTestStruct struct{ Value string } -func (t clonableTestStruct) Clone() clonableTestStruct { +func (t *clonableTestStruct) Clone() clonableTestStruct { return clonableTestStruct{Value: "Cloned:" + t.Value} } diff --git a/internal/infra/cors_test.go b/internal/infra/cors_test.go index 8d32fcef..b538909f 100644 --- a/internal/infra/cors_test.go +++ b/internal/infra/cors_test.go @@ -7,6 +7,7 @@ import ( "github.com/evg4b/uncors/internal/infra" "github.com/evg4b/uncors/testing/mocks" "github.com/go-http-utils/headers" + "github.com/stretchr/testify/assert" ) func TestWriteCorsHeaders(t *testing.T) { @@ -59,6 +60,8 @@ func TestWriteCorsHeaders(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { infra.WriteCorsHeaders(tt.header) + + assert.Equal(t, tt.expected, tt.header) }) } } diff --git a/internal/infra/http_error.go b/internal/infra/http_error.go index ca6c274b..8a356482 100644 --- a/internal/infra/http_error.go +++ b/internal/infra/http_error.go @@ -1,14 +1,12 @@ package infra import ( - "io" "net/http" "github.com/evg4b/uncors/internal/sfmt" "github.com/go-http-utils/headers" "github.com/pterm/pterm" "github.com/pterm/pterm/putils" - "github.com/samber/lo" ) var style = pterm.Style{} @@ -21,10 +19,10 @@ func HTTPError(writer http.ResponseWriter, err error) { writer.WriteHeader(http.StatusInternalServerError) message := sfmt.Sprintf("%d Error", http.StatusInternalServerError) - writeLine(writer) - writeLine(writer, pageHeader(message)) - writeLine(writer) - writeLine(writer, sfmt.Sprintf("Occurred error: %s", err)) + sfmt.Fprintln(writer) + sfmt.Fprintln(writer, pageHeader(message)) + sfmt.Fprintln(writer) + sfmt.Fprintln(writer, sfmt.Sprintf("Occurred error: %s", err)) } func pageHeader(message string) string { @@ -36,7 +34,3 @@ func pageHeader(message string) string { return text } - -func writeLine(writer io.Writer, data ...string) { - sfmt.Fprintln(writer, lo.ToAnySlice(data)...) -} diff --git a/internal/infra/httpclient.go b/internal/infra/httpclient.go index fab175a8..04f3f702 100644 --- a/internal/infra/httpclient.go +++ b/internal/infra/httpclient.go @@ -1,7 +1,6 @@ package infra import ( - "crypto/tls" "net/http" "time" @@ -16,9 +15,6 @@ var defaultHTTPClient = http.Client{ return http.ErrUseLastResponse }, Transport: &http.Transport{ - TLSClientConfig: &tls.Config{ - InsecureSkipVerify: true, //nolint: gosec - }, Proxy: http.ProxyFromEnvironment, }, Jar: nil, @@ -33,11 +29,7 @@ func MakeHTTPClient(proxy string) (*http.Client, error) { } httpClient := defaultHTTPClient - httpClient.Transport = &http.Transport{ - TLSClientConfig: &tls.Config{ - InsecureSkipVerify: true, //nolint: gosec - }, Proxy: http.ProxyURL(parsedURL), } diff --git a/internal/infra/panic_test.go b/internal/infra/panic_test.go index 9c617390..24e8adaf 100644 --- a/internal/infra/panic_test.go +++ b/internal/infra/panic_test.go @@ -4,9 +4,10 @@ package infra_test import ( "errors" + "testing" + "github.com/evg4b/uncors/internal/infra" "github.com/stretchr/testify/assert" - "testing" ) func TestPanicInterceptor(t *testing.T) { diff --git a/internal/log/log.go b/internal/log/log.go index 121c3075..5b975419 100644 --- a/internal/log/log.go +++ b/internal/log/log.go @@ -1,9 +1,10 @@ package log import ( + "io" + "github.com/evg4b/uncors/internal/sfmt" "github.com/pterm/pterm" - "io" ) func Error(a ...any) { diff --git a/internal/version/new_version_check.go b/internal/version/new_version_check.go index 20ae066b..b84608c8 100644 --- a/internal/version/new_version_check.go +++ b/internal/version/new_version_check.go @@ -5,12 +5,13 @@ package version import ( "context" "encoding/json" + "net/http" + "github.com/evg4b/uncors/internal/contracts" "github.com/evg4b/uncors/internal/helpers" "github.com/evg4b/uncors/internal/log" "github.com/evg4b/uncors/internal/ui" "github.com/hashicorp/go-version" - "net/http" ) const lastVersionURL = "https://api.github.com/repos/evg4b/uncors/releases/latest" diff --git a/internal/version/new_version_check_test.go b/internal/version/new_version_check_test.go index bea883f0..adacf74c 100644 --- a/internal/version/new_version_check_test.go +++ b/internal/version/new_version_check_test.go @@ -6,16 +6,17 @@ import ( "bytes" "context" "errors" + "io" + "net/http" + "strings" + "testing" + "github.com/evg4b/uncors/internal/contracts" "github.com/evg4b/uncors/internal/log" "github.com/evg4b/uncors/internal/version" "github.com/evg4b/uncors/testing/mocks" "github.com/evg4b/uncors/testing/testutils" "github.com/stretchr/testify/assert" - "io" - "net/http" - "strings" - "testing" ) func TestCheckNewVersion(t *testing.T) { diff --git a/main.go b/main.go index d23b10fc..3ba3670b 100644 --- a/main.go +++ b/main.go @@ -97,21 +97,21 @@ func main() { finisher.Add(uncorsServer) go func() { + defer finisher.Trigger() log.Debugf("Starting http server on port %d", uncorsConfig.HTTPPort) addr := net.JoinHostPort(baseAddress, strconv.Itoa(uncorsConfig.HTTPPort)) err := uncorsServer.ListenAndServe(addr) handleHTTPServerError("HTTP", err) - finisher.Trigger() }() if uncorsConfig.IsHTTPSEnabled() { log.Debug("Found cert file and key file. Https server will be started") addr := net.JoinHostPort(baseAddress, strconv.Itoa(uncorsConfig.HTTPSPort)) go func() { + defer finisher.Trigger() log.Debugf("Starting https server on port %d", uncorsConfig.HTTPSPort) err := uncorsServer.ListenAndServeTLS(addr, uncorsConfig.CertFile, uncorsConfig.KeyFile) handleHTTPServerError("HTTPS", err) - finisher.Trigger() }() } diff --git a/testing/mocks/constants.go b/testing/mocks/constants.go index 548b1bcc..609bdcf1 100644 --- a/testing/mocks/constants.go +++ b/testing/mocks/constants.go @@ -1,11 +1,15 @@ package mocks -var SourceHost1 = "host1" -var SourceHost2 = "host2" -var SourceHost3 = "host3" +var ( + SourceHost1 = "host1" + SourceHost2 = "host2" + SourceHost3 = "host3" +) -var TargetHost1 = "target-host1" -var TargetHost2 = "target-host2" -var TargetHost3 = "target-host3" +var ( + TargetHost1 = "target-host1" + TargetHost2 = "target-host2" + TargetHost3 = "target-host3" +) const AllMethods = "GET, PUT, POST, HEAD, TRACE, DELETE, PATCH, COPY, HEAD, LINK, OPTIONS" diff --git a/testing/mocks/errors.go b/testing/mocks/errors.go index b0c089cb..196ab6af 100644 --- a/testing/mocks/errors.go +++ b/testing/mocks/errors.go @@ -2,6 +2,4 @@ package mocks import "errors" -var ( - ErrTest1 = errors.New("test error #1") -) +var ErrTest1 = errors.New("test error #1") diff --git a/testing/testutils/certs.go b/testing/testutils/certs.go index 68769fdd..19361995 100644 --- a/testing/testutils/certs.go +++ b/testing/testutils/certs.go @@ -1,3 +1,4 @@ +// nolint: gomnd package testutils import ( diff --git a/testing/testutils/fs.go b/testing/testutils/fs.go index 6e5d8562..e9ad93e8 100644 --- a/testing/testutils/fs.go +++ b/testing/testutils/fs.go @@ -1,11 +1,12 @@ package testutils import ( - "github.com/spf13/afero" "os" "path/filepath" "runtime" "testing" + + "github.com/spf13/afero" ) // FsFromMap creates afero.Fs in memory from map. @@ -26,7 +27,7 @@ func FsFromMap(t *testing.T, files map[string]string) afero.Fs { func PrepareFsForTests(t *testing.T, folder string) afero.Fs { t.Helper() - _, filename, _, _ := runtime.Caller(1) + _, filename, _, _ := runtime.Caller(1) //nolint: dogsled dirname := filepath.Join(filepath.Dir(filename), folder) return afero.NewReadOnlyFs(afero.NewBasePathFs(afero.NewOsFs(), dirname)) diff --git a/testing/testutils/http_body..go b/testing/testutils/http_body..go index ed6f608e..76191242 100644 --- a/testing/testutils/http_body..go +++ b/testing/testutils/http_body..go @@ -1,11 +1,12 @@ package testutils import ( - "github.com/evg4b/uncors/internal/helpers" "io" "net/http" "net/http/httptest" "testing" + + "github.com/evg4b/uncors/internal/helpers" ) func ReadBody(t *testing.T, recorder *httptest.ResponseRecorder) string { diff --git a/testing/testutils/log.go b/testing/testutils/log.go index 59022fc1..7487cbe5 100644 --- a/testing/testutils/log.go +++ b/testing/testutils/log.go @@ -2,12 +2,13 @@ package testutils import ( "bytes" - "github.com/evg4b/uncors/internal/log" "testing" + + "github.com/evg4b/uncors/internal/log" ) func LogTest(action func(t *testing.T, output *bytes.Buffer)) func(t *testing.T) { - var buffer = &bytes.Buffer{} + buffer := &bytes.Buffer{} log.SetOutput(buffer) return func(t *testing.T) { diff --git a/testing/testutils/params/constants.go b/testing/testutils/params/constants.go index a0f4aa73..38f5c459 100644 --- a/testing/testutils/params/constants.go +++ b/testing/testutils/params/constants.go @@ -1,6 +1,8 @@ package params -const Config = "--config" -const From = "--from" -const To = "--to" -const HTTPPort = "--http-port" +const ( + Config = "--config" + From = "--from" + To = "--to" + HTTPPort = "--http-port" +)