commit 040b36a936a4c3b4bcc480dc44ddbc248086b090 Author: Neur0toxine Date: Thu Oct 14 18:27:22 2021 +0300 initial diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..1a83886 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 4 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + +[{*.md,go.mod,go.sum}] +trim_trailing_whitespace = false diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..339fe5d --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,27 @@ +name: build + +on: + push: + pull_request: + branches: [master] + +jobs: + build: + name: build + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Setup Go 1.17 + uses: actions/setup-go@v2 + with: + go-version: ^1.17 + - name: Build + run: make build + - name: Tests + run: go test ./... -v -race -cover -covermode=count -coverprofile=coverage.txt + - name: Upload Coverage + uses: codecov/codecov-action@v1.0.0 + with: + token: ${{ secrets.CODECOV_TOKEN }} + file: ./coverage.txt diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..18da77e --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,32 @@ +name: release + +on: + push: + pull_request: + branches: [master] + +jobs: + release: + name: release + runs-on: ubuntu-latest + if: startsWith(github.ref, 'refs/tags/v') + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Setup Go + uses: actions/setup-go@v2 + with: + go-version: ^1.17 + - name: Set GOVERSION + run: echo "GOVERSION=$(go version | sed -r 's/go version go(.*)\ .*/\1/')" >> $GITHUB_ENV + - name: Set package version + run: echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV + - name: Show versions + run: echo Go ${{ env.GOVERSION }}, app ${{ env.VERSION }} + - name: Run GoReleaser + uses: goreleaser/goreleaser-action@v2 + with: + version: latest + args: release --rm-dist + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..346ffe6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +vendor +.idea +dist/ + +dist/ diff --git a/.goreleaser.yml b/.goreleaser.yml new file mode 100644 index 0000000..228f884 --- /dev/null +++ b/.goreleaser.yml @@ -0,0 +1,27 @@ +before: + hooks: + - go mod tidy +builds: + - env: + - CGO_ENABLED=0 + goos: + - linux + - windows + - darwin +archives: + - replacements: + darwin: Darwin + linux: Linux + windows: Windows + 386: i386 + amd64: x86_64 +checksum: + name_template: 'checksums.txt' +snapshot: + name_template: "{{ incpatch .Version }}-next" +changelog: + sort: asc + filters: + exclude: + - '^docs:' + - '^test:' diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..61db175 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Pavel Kovalenko + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..b52a80e --- /dev/null +++ b/go.mod @@ -0,0 +1,11 @@ +module github.com/Neur0toxine/webhook-receiver + +go 1.17 + +require github.com/fatih/color v1.13.0 + +require ( + github.com/mattn/go-colorable v0.1.9 // indirect + github.com/mattn/go-isatty v0.0.14 // indirect + golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..6ab7ee4 --- /dev/null +++ b/go.sum @@ -0,0 +1,11 @@ +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/mattn/go-colorable v0.1.9 h1:sqDoxXbdeALODt0DAeJCVp38ps9ZogZEAXjus69YV3U= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/handler.go b/handler.go new file mode 100644 index 0000000..5f46978 --- /dev/null +++ b/handler.go @@ -0,0 +1,69 @@ +package main + +import ( + "fmt" + "io" + "log" + "net/http" + + "github.com/fatih/color" +) + +type Handler struct { + body func(a ...interface{}) string + method func(a ...interface{}) string + keyPrint func(a ...interface{}) string + prefixPrint func(a ...interface{}) string +} + +func NewHandler() *Handler { + return &Handler{ + body: color.New(color.Bold, color.FgHiGreen).SprintFunc(), + method: color.New(color.Bold, color.FgBlack, color.BgGreen).SprintFunc(), + keyPrint: color.New(color.FgYellow).SprintFunc(), + prefixPrint: color.New(color.Faint, color.FgCyan).SprintFunc(), + } +} + +func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + log.Printf("%s %s %s\n", + color.HiMagentaString(r.Proto), h.method(r.Method), color.CyanString(r.URL.String())) + log.Printf(" > %s: %s\n", h.keyPrint("RemoteAddr"), r.RemoteAddr) + log.Printf(" > %s: %s\n", h.keyPrint("Host"), r.Host) + log.Printf(" > %s: %d\n", h.keyPrint("Length"), r.ContentLength) + + for _, encoding := range r.TransferEncoding { + log.Printf(" > %s: %s\n", h.keyPrint("Transfer-Encoding"), encoding) + } + + for header, values := range r.Header { + for _, value := range values { + log.Printf("%s %s: %s\n", h.prefixPrint("[header]"), h.keyPrint(header), value) + } + } + + if r.Body == nil { + log.Printf("%s\n", color.HiMagentaString("No body is present.")) + } + + data, err := io.ReadAll(r.Body) + if err != nil { + log.Printf("%s\n", color.HiRedString("Cannot read body: " + err.Error())) + } + + if len(data) == 0 { + log.Printf("%s\n", color.HiMagentaString("Body is empty.")) + } else { + log.Printf("%s\n%s\n", h.body("Body:"), string(data)) + } + + for header, values := range r.Trailer { + for _, value := range values { + log.Printf("%s %s: %s\n", h.prefixPrint("[trailer header]"), h.keyPrint(header), value) + } + } + + fmt.Println() + + w.WriteHeader(http.StatusOK) +} diff --git a/install.sh b/install.sh new file mode 100644 index 0000000..f2c9cbd --- /dev/null +++ b/install.sh @@ -0,0 +1,389 @@ +#!/bin/sh +set -e +# Code generated by godownloader on 2021-09-24T12:55:59Z. DO NOT EDIT. +# + +usage() { + this=$1 + cat </dev/null +} +echoerr() { + echo "$@" 1>&2 +} +log_prefix() { + echo "$0" +} +_logp=6 +log_set_priority() { + _logp="$1" +} +log_priority() { + if test -z "$1"; then + echo "$_logp" + return + fi + [ "$1" -le "$_logp" ] +} +log_tag() { + case $1 in + 0) echo "emerg" ;; + 1) echo "alert" ;; + 2) echo "crit" ;; + 3) echo "err" ;; + 4) echo "warning" ;; + 5) echo "notice" ;; + 6) echo "info" ;; + 7) echo "debug" ;; + *) echo "$1" ;; + esac +} +log_debug() { + log_priority 7 || return 0 + echoerr "$(log_prefix)" "$(log_tag 7)" "$@" +} +log_info() { + log_priority 6 || return 0 + echoerr "$(log_prefix)" "$(log_tag 6)" "$@" +} +log_err() { + log_priority 3 || return 0 + echoerr "$(log_prefix)" "$(log_tag 3)" "$@" +} +log_crit() { + log_priority 2 || return 0 + echoerr "$(log_prefix)" "$(log_tag 2)" "$@" +} +uname_os() { + os=$(uname -s | tr '[:upper:]' '[:lower:]') + case "$os" in + cygwin_nt*) os="windows" ;; + mingw*) os="windows" ;; + msys_nt*) os="windows" ;; + esac + echo "$os" +} +uname_arch() { + arch=$(uname -m) + case $arch in + x86_64) arch="amd64" ;; + x86) arch="386" ;; + i686) arch="386" ;; + i386) arch="386" ;; + aarch64) arch="arm64" ;; + armv5*) arch="armv5" ;; + armv6*) arch="armv6" ;; + armv7*) arch="armv7" ;; + esac + echo ${arch} +} +uname_os_check() { + os=$(uname_os) + case "$os" in + darwin) return 0 ;; + dragonfly) return 0 ;; + freebsd) return 0 ;; + linux) return 0 ;; + android) return 0 ;; + nacl) return 0 ;; + netbsd) return 0 ;; + openbsd) return 0 ;; + plan9) return 0 ;; + solaris) return 0 ;; + windows) return 0 ;; + esac + log_crit "uname_os_check '$(uname -s)' got converted to '$os' which is not a GOOS value. Please file bug at https://github.com/client9/shlib" + return 1 +} +uname_arch_check() { + arch=$(uname_arch) + case "$arch" in + 386) return 0 ;; + amd64) return 0 ;; + arm64) return 0 ;; + armv5) return 0 ;; + armv6) return 0 ;; + armv7) return 0 ;; + ppc64) return 0 ;; + ppc64le) return 0 ;; + mips) return 0 ;; + mipsle) return 0 ;; + mips64) return 0 ;; + mips64le) return 0 ;; + s390x) return 0 ;; + amd64p32) return 0 ;; + esac + log_crit "uname_arch_check '$(uname -m)' got converted to '$arch' which is not a GOARCH value. Please file bug report at https://github.com/client9/shlib" + return 1 +} +untar() { + tarball=$1 + case "${tarball}" in + *.tar.gz | *.tgz) tar --no-same-owner -xzf "${tarball}" ;; + *.tar) tar --no-same-owner -xf "${tarball}" ;; + *.zip) unzip "${tarball}" ;; + *) + log_err "untar unknown archive format for ${tarball}" + return 1 + ;; + esac +} +http_download_curl() { + local_file=$1 + source_url=$2 + header=$3 + if [ -z "$header" ]; then + code=$(curl -w '%{http_code}' -sL -o "$local_file" "$source_url") + else + code=$(curl -w '%{http_code}' -sL -H "$header" -o "$local_file" "$source_url") + fi + if [ "$code" != "200" ]; then + log_debug "http_download_curl received HTTP status $code" + return 1 + fi + return 0 +} +http_download_wget() { + local_file=$1 + source_url=$2 + header=$3 + if [ -z "$header" ]; then + wget -q -O "$local_file" "$source_url" + else + wget -q --header "$header" -O "$local_file" "$source_url" + fi +} +http_download() { + log_debug "http_download $2" + if is_command curl; then + http_download_curl "$@" + return + elif is_command wget; then + http_download_wget "$@" + return + fi + log_crit "http_download unable to find wget or curl" + return 1 +} +http_copy() { + tmp=$(mktemp) + http_download "${tmp}" "$1" "$2" || return 1 + body=$(cat "$tmp") + rm -f "${tmp}" + echo "$body" +} +github_release() { + owner_repo=$1 + version=$2 + test -z "$version" && version="latest" + giturl="https://github.com/${owner_repo}/releases/${version}" + json=$(http_copy "$giturl" "Accept:application/json") + test -z "$json" && return 1 + version=$(echo "$json" | tr -s '\n' ' ' | sed 's/.*"tag_name":"//' | sed 's/".*//') + test -z "$version" && return 1 + echo "$version" +} +hash_sha256() { + TARGET=${1:-/dev/stdin} + if is_command gsha256sum; then + hash=$(gsha256sum "$TARGET") || return 1 + echo "$hash" | cut -d ' ' -f 1 + elif is_command sha256sum; then + hash=$(sha256sum "$TARGET") || return 1 + echo "$hash" | cut -d ' ' -f 1 + elif is_command shasum; then + hash=$(shasum -a 256 "$TARGET" 2>/dev/null) || return 1 + echo "$hash" | cut -d ' ' -f 1 + elif is_command openssl; then + hash=$(openssl -dst openssl dgst -sha256 "$TARGET") || return 1 + echo "$hash" | cut -d ' ' -f a + else + log_crit "hash_sha256 unable to find command to compute sha-256 hash" + return 1 + fi +} +hash_sha256_verify() { + TARGET=$1 + checksums=$2 + if [ -z "$checksums" ]; then + log_err "hash_sha256_verify checksum file not specified in arg2" + return 1 + fi + BASENAME=${TARGET##*/} + want=$(grep "${BASENAME}" "${checksums}" 2>/dev/null | tr '\t' ' ' | cut -d ' ' -f 1) + if [ -z "$want" ]; then + log_err "hash_sha256_verify unable to find checksum for '${TARGET}' in '${checksums}'" + return 1 + fi + got=$(hash_sha256 "$TARGET") + if [ "$want" != "$got" ]; then + log_err "hash_sha256_verify checksum for '$TARGET' did not verify ${want} vs $got" + return 1 + fi +} +cat /dev/null < 1 { + addr = os.Args[1] + } + + log.Printf("Listening %s...\n\n", addr) + err := http.ListenAndServe(addr, NewHandler()) + if err != nil { + log.Fatal(err) + } +} diff --git a/signals.go b/signals.go new file mode 100644 index 0000000..b13b1a9 --- /dev/null +++ b/signals.go @@ -0,0 +1,19 @@ +package main + +import ( + "log" + "os" + "os/signal" + "syscall" +) + +func processSignals() { + c := make(chan os.Signal, 1) + signal.Notify(c, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT) + + for { + <-c + log.Println("Quitting...") + os.Exit(0) + } +}