In the beginning the was darkness and then there was a reverse proxy.
Some checks failed
continuous-integration/drone Build is failing

This commit is contained in:
Elia el Lazkani 2023-07-11 03:10:24 +02:00
commit 98876106ed
9 changed files with 254 additions and 0 deletions

86
.drone.yml Normal file
View file

@ -0,0 +1,86 @@
---
kind: pipeline
name: test
steps:
- name: test-code
image: golang
commands:
- go get
- go test
---
kind: pipeline
name: test-build
steps:
- name: prepare
image: golang
commands:
- go version
- name: build-linux-amd64
image: golang
environment:
GOOS: linux
GOARCH: amd64
commands:
- go get
- go build -o sidoxy-linux-amd64-${DRONE_COMMIT_SHA:0:8}
depends_on:
- prepare
depends_on:
- test
---
kind: pipeline
name: build
steps:
- name: prepare
image: golang
commands:
- mkdir bin/
- name: build-linux-amd64
image: golang
environment:
GOOS: linux
GOARCH: amd64
commands:
- go get
- go build -o bin/sidoxy-linux-amd64-${DRONE_TAG}
depends_on:
- prepare
- name: generate-checksum
image: golang
commands:
- cd bin
- md5sum * > ../md5sums.txt
- sha512sum * > ../sha512sums.txt
- cp ../md5sums.txt .
- cp ../sha512sums.txt .
depends_on:
- build-linux-amd64
- name: gitea_release
image: plugins/gitea-release
settings:
title: Release ${DRONE_TAG}
note: This is the cmw release of version ${DRONE_TAG}
api_key:
from_secret:
gitea_release
base_url: https://scm.project42.io
files: bin/*
depends_on:
- generate-checksum
depends_on:
- test-build
trigger:
event:
- tag

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
.envrc
go.sum

4
README.md Normal file
View file

@ -0,0 +1,4 @@
Sidoxy
======
`Sidoxy` is a simple proxy written in [Go](https://go.dev/).

12
env.go Normal file
View file

@ -0,0 +1,12 @@
package main
import (
"os"
)
func getEnvironmentVariables() (proxyHostURL, proxyServerURL, jwtKey string) {
proxyHostURL = os.Getenv("PROXY_HOST_URL")
proxyServerURL = os.Getenv("PROXY_SERVER_URL")
jwtKey = os.Getenv("PROXY_JWT_KEY")
return
}

5
go.mod Normal file
View file

@ -0,0 +1,5 @@
module sidoxy
go 1.20
require github.com/golang-jwt/jwt/v5 v5.0.0

21
main.go Normal file
View file

@ -0,0 +1,21 @@
package main
import (
"fmt"
"log"
)
func main() {
proxyHostURL, proxyServerURL, jwtKey := getEnvironmentVariables()
// define origin server URL
originServerURL := parse_url(proxyServerURL)
reverseProxy := &ReverseProxy{URL: originServerURL, jwtKey: jwtKey}
fmt.Printf("[sidoxy] Listening on \"%s\"\n", proxyHostURL)
fmt.Printf("[sidoxy] Forwarding to \"%s\"\n", proxyServerURL)
fmt.Printf("[sidoxy] jwtKey is \"%s\"\n", jwtKey)
log.Fatal(listen_and_serve(proxyHostURL, reverseProxy.reverseProxyHandlerFunc()))
}

94
proxy.go Normal file
View file

@ -0,0 +1,94 @@
package main
import (
"fmt"
"io"
"net"
"log"
"net/http"
"net/url"
"time"
)
type ReverseProxy struct {
URL *url.URL
jwtKey string
}
func (rp *ReverseProxy) reverseProxyHandlerFunc() http.Handler {
return http.HandlerFunc(rp.reverseProxyHandler)
}
func (rp *ReverseProxy) reverseProxyHandler(rw http.ResponseWriter, req *http.Request) {
fmt.Printf("[sidoxy] Reverse proxy received request at: %s\n", time.Now())
// set req Host, URL and Request URI to forward a request to the origin server
req.Host = rp.URL.Host
req.URL.Host = rp.URL.Host
req.URL.Scheme = rp.URL.Scheme
req.RequestURI = ""
// set X-FORWARDED-FOR
xForwardedFor := req.Header.Get("X-Forwarded-For")
var remoteAddr string
if xForwardedFor != "" {
remoteAddr = xForwardedFor
} else {
remoteAddr, _, _ = net.SplitHostPort(req.RemoteAddr)
}
req.Header.Set("X-Forwarded-For", remoteAddr)
fmt.Printf("[sidoxy] Reverse proxy setting X-Forwarded-For to %s\n", remoteAddr)
// TODO: To be implemented
// decode JWT if key present
if rp.jwtKey != "" {
jwtDecode(rp.jwtKey, req.Header.Get("JWT_TOKEN"), req)
}
// save the response from the origin server
originServerResponse, err := http.DefaultClient.Do(req)
if err != nil {
rw.WriteHeader(http.StatusInternalServerError)
_, _ = fmt.Fprint(rw, err)
return
}
fmt.Printf("[sidoxy] Reverse proxy setting the following return headers\n")
// return Header response
for key, values := range originServerResponse.Header {
for _, value := range values {
fmt.Printf("[sidoxy] \t%v: %v\n", key, value)
rw.Header().Set(key, value)
}
}
// support stream
done := make(chan bool)
defer close(done)
go func() {
for {
select {
case <-time.Tick(10 * time.Millisecond):
rw.(http.Flusher).Flush()
case <-done:
return
}
}
}()
// return response to the client
rw.WriteHeader(http.StatusOK)
io.Copy(rw, originServerResponse.Body)
}
func parse_url(host_url string) *url.URL {
h_url, err := url.Parse(host_url)
if err != nil {
log.Fatal("[sidoxy] Invalid server URL: %v", host_url)
}
return h_url
}
func listen_and_serve(address string, handler http.Handler) error {
return http.ListenAndServe(address, handler)
}

1
server.sh Normal file
View file

@ -0,0 +1 @@
docker run --rm -it -p 8080:80 strm/helloworld-http

29
token.go Normal file
View file

@ -0,0 +1,29 @@
package main
import (
"fmt"
"log"
"net/http"
jwt "github.com/golang-jwt/jwt/v5"
)
func jwtDecode(jwtKey string, jwtToken string, req *http.Request) {
claims := jwt.MapClaims{}
token, err := jwt.ParseWithClaims(jwtToken, claims, func(token *jwt.Token) (interface{}, error) {
return []byte(jwtKey), nil
})
if err != nil {
log.Panic("Failed to parse JWT:\n", err, "\n")
}
if token != nil {
log.Panic("Failed to parse JWT token:\n", token, "\n")
}
// do something with decoded claims
for key, val := range claims {
req.Header.Set(key, fmt.Sprint(val))
fmt.Printf("Key: %v, value: %v\n", key, val)
}
}