From 37fe025cec23fc8d3263ca7278b34c7e05ef748c Mon Sep 17 00:00:00 2001 From: Thomas Bellembois Date: Thu, 1 Sep 2022 16:25:09 +0200 Subject: [PATCH] Add missing files. --- .gitignore | 23 ++++++ .golangci.yml | 102 +++++++++++++++++++++++++ Dockerfile | 18 +++++ README.md | 2 + entrypoint.sh | 10 +++ go.mod | 10 +++ go.sum | 14 ++++ main.go | 204 ++++++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 383 insertions(+) create mode 100644 .gitignore create mode 100644 .golangci.yml create mode 100644 Dockerfile create mode 100644 README.md create mode 100644 entrypoint.sh create mode 100644 go.mod create mode 100644 go.sum create mode 100644 main.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..adf8f72 --- /dev/null +++ b/.gitignore @@ -0,0 +1,23 @@ +# ---> Go +# If you prefer the allow list template instead of the deny list, see community template: +# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore +# +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ + +# Go workspace file +go.work + diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..4cb2a6a --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,102 @@ +# options for analysis running +run: + # timeout for analysis, e.g. 30s, 5m, default is 1m + timeout: 1m + + # exit code when at least one issue was found, default is 1 + issues-exit-code: 0 + + # include test files or not, default is true + tests: false + + # which dirs to skip: issues from them won't be reported; + # can use regexp here: generated.*, regexp is applied on full path; + # default value is empty list, but default dirs are skipped independently + # from this option's value (see skip-dirs-use-default). + # "/" will be replaced by current OS file path separator to properly work + # on Windows. + skip-dirs: + - wasm + - static + - node_modules + - documents + - docker + - bind-* + + # default is true. Enables skipping of directories: + # vendor$, third_party$, testdata$, examples$, Godeps$, builtin$ + skip-dirs-use-default: true + + # by default isn't set. If set we pass it to "go list -mod={option}". From "go help modules": + # If invoked with -mod=readonly, the go command is disallowed from the implicit + # automatic updating of go.mod described above. Instead, it fails when any changes + # to go.mod are needed. This setting is most useful to check that go.mod does + # not need updates, such as in a continuous integration and testing system. + # If invoked with -mod=vendor, the go command assumes that the vendor + # directory holds the correct copies of dependencies and ignores + # the dependency descriptions in go.mod. + modules-download-mode: mod + + # Allow multiple parallel golangci-lint instances running. + # If false (default) - golangci-lint acquires file lock on start. + allow-parallel-runners: true + + +# output configuration options +output: + # colored-line-number|line-number|json|tab|checkstyle|code-climate|junit-xml|github-actions + # default is "colored-line-number" + format: colored-line-number + + # print lines of code with issue, default is true + print-issued-lines: true + + # print linter name in the end of issue text, default is true + print-linter-name: true + + # make issues output unique by line, default is true + uniq-by-line: true + + # add a prefix to the output file references; default is no prefix + path-prefix: "" + + # sorts results by: filepath, line and column + sort-results: false + + +# all available settings of specific linters +linters-settings: + gofmt: + # simplify code: gofmt with `-s` option, true by default + simplify: true + staticcheck: + # Select the Go version to target. The default is '1.13'. + go: "1.16" + # https://staticcheck.io/docs/options#checks + checks: ["all"] + stylecheck: + # Select the Go version to target. The default is '1.13'. + go: "1.18" + # https://staticcheck.io/docs/options#checks + checks: ["all"] + errcheck: + # report about assignment of errors to blank identifier: `num, _ := strconv.Atoi(numStr)`; + # default is false: such cases aren't reported by default. + check-blank: true + +linters: + enable: + # go install github.com/kisielk/errcheck@latest + # go install github.com/gordonklaus/ineffassign@latest + # go install honnef.co/go/tools/cmd/staticcheck@latest + # go install gitlab.com/opennota/check/cmd/varcheck@latest + # go install github.com/go-critic/go-critic/cmd/gocritic@latest + - errcheck + - staticcheck + - stylecheck + - ineffassign + - varcheck + - gofmt + - gocritic + - wsl + fast: false diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..c2d3fe4 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,18 @@ +FROM golang:1.18-bullseye +LABEL author="Thomas Bellembois" + +# Copying sources. +WORKDIR /go/src/github.com/tbellembois/codefirst-menuwrapper/ +COPY . . + +# Installing. +RUN go install -v ./... +RUN chmod +x /go/bin/codefirst-menuwrapper + +# Copying entrypoint. +COPY entrypoint.sh / +RUN chmod +x /entrypoint.sh + +USER www-data +EXPOSE 8081 +CMD ["/entrypoint.sh"] \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..1e5a809 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# codefirst-menuwrapper + diff --git a/entrypoint.sh b/entrypoint.sh new file mode 100644 index 0000000..1a4095f --- /dev/null +++ b/entrypoint.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +debug="" + +if [ ! -z "$DEBUG" ] +then + debug="-debug" +fi + +/go/bin/codefirst-menuwrapper -proxyurl=$PROXYURL -codefirsturl=$CODEFIRSTURL $debug \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..f549282 --- /dev/null +++ b/go.mod @@ -0,0 +1,10 @@ +module codefirst.iut.uca.fr/git/thomas.bellembois/codefirst-menuwrapper + +go 1.19 + +require ( + codefirst.iut.uca.fr/git/thomas.bellembois/codefirst-menu/v2 v2.0.0-20220901141305-9da5f43fc873 + github.com/sirupsen/logrus v1.9.0 +) + +require golang.org/x/sys v0.0.0-20220829200755-d48e67d00261 // indirect diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..7895a3d --- /dev/null +++ b/go.sum @@ -0,0 +1,14 @@ +codefirst.iut.uca.fr/git/thomas.bellembois/codefirst-menu/v2 v2.0.0-20220901141305-9da5f43fc873 h1:GYYkgzYWIYV5qLSVguwerESYAfFSESlsJAV3drN1mno= +codefirst.iut.uca.fr/git/thomas.bellembois/codefirst-menu/v2 v2.0.0-20220901141305-9da5f43fc873/go.mod h1:hQ1fdhe5i32sO3pl+kic2sPFTA1uw3X3U82aDV77LoU= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220829200755-d48e67d00261 h1:v6hYoSR9T5oet+pMXwUWkbiVqx/63mlHjefrHmxwfeY= +golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/main.go b/main.go new file mode 100644 index 0000000..aa7e847 --- /dev/null +++ b/main.go @@ -0,0 +1,204 @@ +package main + +import ( + "bytes" + "compress/gzip" + "errors" + "flag" + "fmt" + "io" + "io/ioutil" + "net/http" + "net/http/httputil" + "net/url" + "os" + "strings" + + "codefirst.iut.uca.fr/git/thomas.bellembois/codefirst-menu/v2/menu" + log "github.com/sirupsen/logrus" +) + +var ( + updatedMenu, updatedStringbody string + proxyURL, codefirstURL string + debug, dump bool +) + +func gUnzipData(data []byte) (resData []byte, err error) { + b := bytes.NewBuffer(data) + + var r io.Reader + r, err = gzip.NewReader(b) + + if err != nil { + return + } + + var resB bytes.Buffer + _, err = resB.ReadFrom(r) + + if err != nil { + return + } + + resData = resB.Bytes() + + return +} + +func UpdateResponse(r *http.Response) error { + + contentType := r.Header[http.CanonicalHeaderKey("content-type")] + contentEncoding := r.Header[http.CanonicalHeaderKey("content-encoding")] + location := r.Header[http.CanonicalHeaderKey("location")] + statusCode := r.StatusCode + + log.WithFields( + log.Fields{ + "r.Header": r.Header, + "statusCode": statusCode, + "contentType": contentType, + "contentEncoding": contentEncoding, + "location": location, + }, + ).Debug() + + if statusCode == http.StatusFound && strings.HasPrefix(proxyURL, "http://pastebin") && len(contentType) == 0 { + if len(location) > 0 { + r.Header.Del("location") + r.Header.Set("location", fmt.Sprintf("/pastebin%s", location[0])) + } + } + + if statusCode != http.StatusOK { + log.Debug("skipping not status ok reponse") + return nil + } + + if len(contentType) > 0 && strings.HasPrefix(contentType[0], "text/html") { + var ( + body []byte + err error + ) + + if body, err = io.ReadAll(r.Body); err != nil { + fmt.Println(err) + return err + } + + if len(contentEncoding) > 0 && strings.HasPrefix(contentEncoding[0], "gzip") { + if body, err = gUnzipData(body); err != nil { + fmt.Println(err) + return err + } + } + + stringBody := string(body) + + if strings.HasPrefix(proxyURL, "http://pastebin") { + updatedStringbody = strings.Replace(stringBody, "action=\"/\"", "action=\"/pastebin/\"", 1) + } else if strings.HasPrefix(proxyURL, "http://cinny") { + updatedStringbody = strings.Replace(stringBody, ``, ``+updatedMenu, 1) + } else { + updatedStringbody = strings.Replace(stringBody, "", ""+updatedMenu, 1) + } + + buf := bytes.NewBufferString(updatedStringbody) + r.Body = ioutil.NopCloser(buf) + + r.Header.Del("content-encoding") + r.Header.Del("content-type") + r.Header.Set("content-type", "text/html; charset=utf-8") + r.Header.Set("content-length", fmt.Sprint(buf.Len())) + } + + return nil +} + +func init() { + flag.StringVar(&proxyURL, "proxyurl", "", "proxy URL") + flag.StringVar(&codefirstURL, "codefirsturl", "", "codefirst URL") + flag.BoolVar(&debug, "debug", false, "enable debug") + flag.BoolVar(&dump, "dump", false, "dump menu") + flag.Parse() + + updatedMenu = menu.CodeFirstMenu + + if dump { + updatedMenu = strings.Replace(updatedMenu, "", "", 1) + fmt.Println(updatedMenu) + os.Exit(0) + } + + if proxyURL == "" { + panic(errors.New("empty proxy URL")) + } + + if debug { + log.SetLevel(log.DebugLevel) + } + + updatedMenu = strings.ReplaceAll(updatedMenu, "CODEFIRST_HOSTNAME", codefirstURL) + + if strings.HasPrefix(proxyURL, "http://gitea") { + updatedMenu = strings.Replace(updatedMenu, "", "", 1) + } else if strings.HasPrefix(proxyURL, "http://drone") { + updatedMenu = strings.Replace(updatedMenu, "", "", 1) + } else if strings.HasPrefix(proxyURL, "http://dockerrunner") { + updatedMenu = strings.Replace(updatedMenu, "", "", 1) + } else if strings.HasPrefix(proxyURL, "http://registryui") { + updatedMenu = strings.Replace(updatedMenu, "", "", 1) + } else if strings.HasPrefix(proxyURL, "http://sonarqube") { + updatedMenu = strings.Replace(updatedMenu, "", "", 1) + } else if strings.HasPrefix(proxyURL, "http://nginx") { + updatedMenu = strings.Replace(updatedMenu, "", "", 1) + } else if strings.HasPrefix(proxyURL, "http://cinny") { + updatedMenu = strings.Replace(updatedMenu, "", "", 1) + } +} + +func main() { + remote, err := url.Parse(proxyURL) + if err != nil { + panic(err) + } + + log.WithFields( + log.Fields{ + "proxyURL": proxyURL, + "updatedMenu": updatedMenu, + }, + ).Debug() + + handler := func(p *httputil.ReverseProxy) func(http.ResponseWriter, *http.Request) { + return func(w http.ResponseWriter, r *http.Request) { + log.WithFields( + log.Fields{ + "r.Host": r.Host, + "r.RequestURI": r.RequestURI, + }, + ).Debug() + + r.Host = remote.Host + p.ServeHTTP(w, r) + } + } + + proxy := httputil.NewSingleHostReverseProxy(remote) + proxy.ModifyResponse = UpdateResponse + + http.HandleFunc("/", handler(proxy)) + err = http.ListenAndServe(":8081", nil) + + if err != nil { + panic(err) + } +}