Wrote proxy
This commit is contained in:
parent
987fd909a9
commit
944b787432
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -10,3 +10,4 @@ localcert.key
|
||||||
dev.json
|
dev.json
|
||||||
.bin
|
.bin
|
||||||
client/dist
|
client/dist
|
||||||
|
config_dev.json
|
|
@ -5,3 +5,4 @@ env("GOPATH", run("go", ["env", "GOROOT"]) + ":" + pwd() + "/go_modules" + ":" +
|
||||||
env("MONGODB", readJsonFile("dev.json").MONGODB)
|
env("MONGODB", readJsonFile("dev.json").MONGODB)
|
||||||
env("HTTP_PORT", 8080)
|
env("HTTP_PORT", 8080)
|
||||||
env("HTTPS_PORT", 8443)
|
env("HTTPS_PORT", 8443)
|
||||||
|
env("CONFIG_FILE", "./config_dev.json")
|
|
@ -20,6 +20,8 @@
|
||||||
"go://gopkg.in/ffmt.v1": "v1.5.6",
|
"go://gopkg.in/ffmt.v1": "v1.5.6",
|
||||||
"npm://@esbuild/linux-x64": "0.16.17",
|
"npm://@esbuild/linux-x64": "0.16.17",
|
||||||
"npm://@vitejs/plugin-react": "3.1.0",
|
"npm://@vitejs/plugin-react": "3.1.0",
|
||||||
|
"npm://express": "4.18.2",
|
||||||
|
"npm://express-ws": "5.0.2",
|
||||||
"npm://react": "18.2.0",
|
"npm://react": "18.2.0",
|
||||||
"npm://react-dom": "18.2.0",
|
"npm://react-dom": "18.2.0",
|
||||||
"npm://typescript": "4.9.5",
|
"npm://typescript": "4.9.5",
|
||||||
|
|
82
src/config.go
Normal file
82
src/config.go
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"regexp"
|
||||||
|
"./proxy"
|
||||||
|
"encoding/json"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
HTTPConfig HTTPConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
var defaultConfig = Config{
|
||||||
|
HTTPConfig: HTTPConfig{
|
||||||
|
TLSCert: "localcert.crt",
|
||||||
|
TLSKey: "localcert.key",
|
||||||
|
GenerateMissingTLSCert: true,
|
||||||
|
HTTPPort: "80",
|
||||||
|
HTTPSPort: "443",
|
||||||
|
ProxyConfig: proxy.Config{
|
||||||
|
Routes: []proxy.RouteConfig{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetConfig() Config {
|
||||||
|
configFile := os.Getenv("CONFIG_FILE")
|
||||||
|
|
||||||
|
if configFile == "" {
|
||||||
|
configFile = "/cosmos.config.json"
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("Using config file: " + configFile)
|
||||||
|
|
||||||
|
// if file does not exist, create it
|
||||||
|
if _, err := os.Stat(configFile); os.IsNotExist(err) {
|
||||||
|
log.Println("Config file does not exist. Creating default config file.")
|
||||||
|
file, err := os.Create(configFile)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("[ERROR] Creating Default Config File: " + err.Error())
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
encoder := json.NewEncoder(file)
|
||||||
|
encoder.SetIndent("", " ")
|
||||||
|
err = encoder.Encode(defaultConfig)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("[ERROR] Writing Default Config File: " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return defaultConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
file, err := os.Open(configFile)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("[ERROR] Opening Config File: " + err.Error())
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
decoder := json.NewDecoder(file)
|
||||||
|
config := Config{}
|
||||||
|
err = decoder.Decode(&config)
|
||||||
|
// check file is not empty
|
||||||
|
if err != nil {
|
||||||
|
// check error is not empty
|
||||||
|
if err.Error() == "EOF" {
|
||||||
|
log.Fatal("[ERROR] Reading Config File: File is empty.")
|
||||||
|
}
|
||||||
|
|
||||||
|
// get error string
|
||||||
|
errString := err.Error()
|
||||||
|
|
||||||
|
// replace string in error
|
||||||
|
m1 := regexp.MustCompile(`json: cannot unmarshal ([A-Za-z\.]+) into Go struct field ([A-Za-z\.]+) of type ([A-Za-z\.]+)`)
|
||||||
|
errString = m1.ReplaceAllString(errString, "Invalid JSON in config file.\n > Field $2 is wrong.\n > Type is $1 Should be $3")
|
||||||
|
log.Fatal("[ERROR] Reading Config File: " + errString)
|
||||||
|
}
|
||||||
|
|
||||||
|
return config
|
||||||
|
}
|
93
src/httpServer.go
Normal file
93
src/httpServer.go
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"./utils"
|
||||||
|
// "./file"
|
||||||
|
// "./user"
|
||||||
|
"./proxy"
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type HTTPConfig struct {
|
||||||
|
TLSCert string
|
||||||
|
TLSKey string
|
||||||
|
GenerateMissingTLSCert bool
|
||||||
|
HTTPPort string
|
||||||
|
HTTPSPort string
|
||||||
|
ProxyConfig proxy.Config
|
||||||
|
}
|
||||||
|
|
||||||
|
var serverPortHTTP = os.Getenv("HTTP_PORT")
|
||||||
|
var serverPortHTTPS = os.Getenv("HTTPS_PORT")
|
||||||
|
|
||||||
|
func startHTTPServer(router *mux.Router) {
|
||||||
|
log.Println("Listening to HTTP on :" + serverPortHTTP)
|
||||||
|
|
||||||
|
err := http.ListenAndServe("0.0.0.0:" + serverPortHTTP, router)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func startHTTPSServer(router *mux.Router, tlsCert string, tlsKey string) {
|
||||||
|
// redirect http to https
|
||||||
|
go (func () {
|
||||||
|
err := http.ListenAndServe("0.0.0.0:" + serverPortHTTP, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// change port in host
|
||||||
|
if strings.HasSuffix(r.Host, ":" + serverPortHTTP) {
|
||||||
|
if serverPortHTTPS != "443" {
|
||||||
|
r.Host = r.Host[:len(r.Host)-len(":" + serverPortHTTP)] + ":" + serverPortHTTPS
|
||||||
|
} else {
|
||||||
|
r.Host = r.Host[:len(r.Host)-len(":" + serverPortHTTP)]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
http.Redirect(w, r, "https://"+r.Host+r.URL.String(), http.StatusMovedPermanently)
|
||||||
|
}))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
|
||||||
|
log.Println("Listening to HTTP on :" + serverPortHTTP)
|
||||||
|
log.Println("Listening to HTTPS on :" + serverPortHTTPS)
|
||||||
|
|
||||||
|
// start https server
|
||||||
|
err := http.ListenAndServeTLS("0.0.0.0:" + serverPortHTTPS, tlsCert, tlsKey, router)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func StartServer(config HTTPConfig) {
|
||||||
|
var tlsCert = config.TLSCert
|
||||||
|
var tlsKey= config.TLSKey
|
||||||
|
|
||||||
|
if serverPortHTTP == "" {
|
||||||
|
serverPortHTTP = config.HTTPPort
|
||||||
|
}
|
||||||
|
|
||||||
|
if serverPortHTTPS == "" {
|
||||||
|
serverPortHTTPS = config.HTTPSPort
|
||||||
|
}
|
||||||
|
|
||||||
|
router := proxy.BuildFromConfig(config.ProxyConfig)
|
||||||
|
|
||||||
|
if utils.FileExists(tlsCert) && utils.FileExists(tlsKey) {
|
||||||
|
log.Println("TLS certificate found, starting HTTPS servers and redirecting HTTP to HTTPS")
|
||||||
|
startHTTPSServer(router, tlsCert, tlsKey)
|
||||||
|
} else {
|
||||||
|
log.Println("No TLS certificate found, starting HTTP server only")
|
||||||
|
startHTTPServer(router)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func StopServer() {
|
||||||
|
}
|
100
src/index.go
100
src/index.go
|
@ -1,106 +1,14 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
|
||||||
"./utils"
|
|
||||||
"./file"
|
|
||||||
"./user"
|
|
||||||
"github.com/gorilla/mux"
|
|
||||||
"log"
|
"log"
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var tlsCert = "localcert.crt"
|
|
||||||
var tlsKey= "localcert.key"
|
|
||||||
var serverPortHTTP = os.Getenv("HTTP_PORT")
|
|
||||||
var serverPortHTTPS = os.Getenv("HTTPS_PORT")
|
|
||||||
|
|
||||||
func startHTTPServer(router *mux.Router) {
|
|
||||||
log.Println("Listening to HTTP on :" + serverPortHTTP)
|
|
||||||
|
|
||||||
err := http.ListenAndServe("0.0.0.0:" + serverPortHTTP, router)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func startHTTPSServer(router *mux.Router) {
|
|
||||||
// redirect http to https
|
|
||||||
go (func () {
|
|
||||||
err := http.ListenAndServe("0.0.0.0:" + serverPortHTTP, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
// change port in host
|
|
||||||
if strings.HasSuffix(r.Host, ":" + serverPortHTTP) {
|
|
||||||
if serverPortHTTPS != "443" {
|
|
||||||
r.Host = r.Host[:len(r.Host)-len(":" + serverPortHTTP)] + ":" + serverPortHTTPS
|
|
||||||
} else {
|
|
||||||
r.Host = r.Host[:len(r.Host)-len(":" + serverPortHTTP)]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
http.Redirect(w, r, "https://"+r.Host+r.URL.String(), http.StatusMovedPermanently)
|
|
||||||
}))
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
})()
|
|
||||||
|
|
||||||
log.Println("Listening to HTTP on :" + serverPortHTTP)
|
|
||||||
log.Println("Listening to HTTPS on :" + serverPortHTTPS)
|
|
||||||
|
|
||||||
// start https server
|
|
||||||
err := http.ListenAndServeTLS("0.0.0.0:" + serverPortHTTPS, tlsCert, tlsKey, router)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
log.Println("Starting...")
|
log.Println("Starting...")
|
||||||
|
|
||||||
if serverPortHTTP == "" {
|
config := GetConfig()
|
||||||
serverPortHTTP = "80"
|
|
||||||
}
|
defer StopServer()
|
||||||
|
StartServer(config.HTTPConfig)
|
||||||
if serverPortHTTPS == "" {
|
|
||||||
serverPortHTTPS = "443"
|
|
||||||
}
|
|
||||||
|
|
||||||
router := mux.NewRouter().StrictSlash(true)
|
|
||||||
|
|
||||||
utils.DB()
|
|
||||||
defer utils.Disconnect()
|
|
||||||
|
|
||||||
router.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
w.WriteHeader(http.StatusOK)
|
|
||||||
w.Write([]byte("OK"))
|
|
||||||
})
|
|
||||||
|
|
||||||
router.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))
|
|
||||||
|
|
||||||
router.HandleFunc("/file/list", file.FileList)
|
|
||||||
router.HandleFunc("/file/get", file.FileGet)
|
|
||||||
router.HandleFunc("/file/delete", file.FileDelete)
|
|
||||||
router.HandleFunc("/file/copy", file.FileCopy)
|
|
||||||
router.HandleFunc("/file/move", file.FileMove)
|
|
||||||
|
|
||||||
router.HandleFunc("/user/login", user.UserLogin)
|
|
||||||
// router.HandleFunc("/user/register", user.UserRegister)
|
|
||||||
// router.HandleFunc("/user/edit", )
|
|
||||||
// router.HandleFunc("/user/delete", )
|
|
||||||
|
|
||||||
// router.HandleFunc("/config/get", )
|
|
||||||
// router.HandleFunc("/config/set", )
|
|
||||||
|
|
||||||
// router.HandleFunc("/db", )
|
|
||||||
|
|
||||||
if utils.FileExists(tlsCert) && utils.FileExists(tlsKey) {
|
|
||||||
log.Println("TLS certificate found, starting HTTPS servers and redirecting HTTP to HTTPS")
|
|
||||||
startHTTPSServer(router)
|
|
||||||
} else {
|
|
||||||
log.Println("No TLS certificate found, starting HTTP server only")
|
|
||||||
startHTTPServer(router)
|
|
||||||
}
|
|
||||||
}
|
}
|
33
src/proxy/buildFromConfig.go
Normal file
33
src/proxy/buildFromConfig.go
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
package proxy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RouteConfig struct {
|
||||||
|
Routing Route
|
||||||
|
Target string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
Routes []RouteConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
func BuildFromConfig(config Config) *mux.Router {
|
||||||
|
router := mux.NewRouter().StrictSlash(true)
|
||||||
|
|
||||||
|
router.HandleFunc("/_health", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
w.Write([]byte("OK"))
|
||||||
|
})
|
||||||
|
|
||||||
|
router.PathPrefix("/_static").Handler(http.StripPrefix("/_static", http.FileServer(http.Dir("static"))))
|
||||||
|
|
||||||
|
for i := len(config.Routes)-1; i >= 0; i-- {
|
||||||
|
routeConfig := config.Routes[i]
|
||||||
|
RouterGen(routeConfig.Routing, router, RouteTo(routeConfig.Target))
|
||||||
|
}
|
||||||
|
|
||||||
|
return router
|
||||||
|
}
|
51
src/proxy/routeTo.go
Normal file
51
src/proxy/routeTo.go
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
package proxy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"net/http/httputil"
|
||||||
|
"net/url"
|
||||||
|
"log"
|
||||||
|
// "io/ioutil"
|
||||||
|
// "io"
|
||||||
|
// "os"
|
||||||
|
// "golang.org/x/crypto/bcrypt"
|
||||||
|
|
||||||
|
// "../utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewProxy takes target host and creates a reverse proxy
|
||||||
|
func NewProxy(targetHost string) (*httputil.ReverseProxy, error) {
|
||||||
|
url, err := url.Parse(targetHost)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
proxy := httputil.NewSingleHostReverseProxy(url)
|
||||||
|
|
||||||
|
// upgrade the request to websocket
|
||||||
|
proxy.ModifyResponse = func(resp *http.Response) error {
|
||||||
|
log.Println("[INFO] Response from backend: ", resp.Status)
|
||||||
|
log.Println("[INFO] URL was ", resp.Request.URL)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return proxy, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProxyRequestHandler handles the http request using proxy
|
||||||
|
func ProxyRequestHandler(proxy *httputil.ReverseProxy) func(http.ResponseWriter, *http.Request) {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
proxy.ServeHTTP(w, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func RouteTo(destination string) *httputil.ReverseProxy /*func(http.ResponseWriter, *http.Request)*/ {
|
||||||
|
// initialize a reverse proxy and pass the actual backend server url here
|
||||||
|
proxy, err := NewProxy(destination)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a handler function which uses the reverse proxy
|
||||||
|
return proxy //ProxyRequestHandler(proxy)
|
||||||
|
}
|
41
src/proxy/routerGen.go
Normal file
41
src/proxy/routerGen.go
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
package proxy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"net/http/httputil"
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
// "log"
|
||||||
|
// "io/ioutil"
|
||||||
|
// "io"
|
||||||
|
// "os"
|
||||||
|
// "golang.org/x/crypto/bcrypt"
|
||||||
|
|
||||||
|
// "../utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Route struct {
|
||||||
|
UseHost bool
|
||||||
|
Host string
|
||||||
|
UsePathPrefix bool
|
||||||
|
PathPrefix string
|
||||||
|
}
|
||||||
|
|
||||||
|
func RouterGen(route Route, router *mux.Router, destination *httputil.ReverseProxy) *mux.Route {
|
||||||
|
var realDestination http.Handler
|
||||||
|
realDestination = destination
|
||||||
|
|
||||||
|
origin := router.Methods("GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS", "HEAD")
|
||||||
|
|
||||||
|
if(route.UseHost) {
|
||||||
|
origin = origin.Host(route.Host)
|
||||||
|
}
|
||||||
|
|
||||||
|
if(route.UsePathPrefix) {
|
||||||
|
origin = origin.PathPrefix(route.PathPrefix)
|
||||||
|
realDestination = http.StripPrefix(route.PathPrefix, destination)
|
||||||
|
}
|
||||||
|
|
||||||
|
origin.Handler(realDestination)
|
||||||
|
|
||||||
|
return origin
|
||||||
|
}
|
38
test-server.js
Normal file
38
test-server.js
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
|
||||||
|
const express = require('express')
|
||||||
|
const app = express()
|
||||||
|
const port = 3000
|
||||||
|
var expressWs = require('express-ws')(app);
|
||||||
|
|
||||||
|
// console log every request sent
|
||||||
|
app.use((req, res, next) => {
|
||||||
|
console.log(`[REQ] - ${req.method} ${req.url}`)
|
||||||
|
next()
|
||||||
|
});
|
||||||
|
|
||||||
|
app.get('/return/:status/:time', async (req, res) => {
|
||||||
|
const statusCode = parseInt(req.params.status);
|
||||||
|
const returnString =`Hello status ${statusCode} after ${req.params.time}ms !`
|
||||||
|
|
||||||
|
console.log(`[RES] - ${statusCode} ${returnString}`)
|
||||||
|
|
||||||
|
await new Promise(resolve => setTimeout(resolve, req.params.time));
|
||||||
|
|
||||||
|
return res.status(statusCode).send(returnString)
|
||||||
|
});
|
||||||
|
|
||||||
|
app.get('/', (req, res) => {
|
||||||
|
console.log("[RES] - Hello World!")
|
||||||
|
res.send('Hello World!')
|
||||||
|
})
|
||||||
|
|
||||||
|
app.listen(port, () => {
|
||||||
|
console.log(`Example app listening on port ${port}`)
|
||||||
|
})
|
||||||
|
|
||||||
|
app.ws('/ws', function(ws, req) {
|
||||||
|
ws.on('message', function(msg) {
|
||||||
|
console.log(msg);
|
||||||
|
ws.send(msg);
|
||||||
|
});
|
||||||
|
});
|
16
test-websocket.js
Normal file
16
test-websocket.js
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
const WebSocket = require('ws');
|
||||||
|
|
||||||
|
// send
|
||||||
|
|
||||||
|
const ws = new WebSocket('ws://localhost:8080/proxy/ws', {
|
||||||
|
rejectUnauthorized: false,
|
||||||
|
followRedirects : true,
|
||||||
|
});
|
||||||
|
|
||||||
|
ws.on('open', function open() {
|
||||||
|
ws.send('something');
|
||||||
|
});
|
||||||
|
|
||||||
|
ws.on('message', function incoming(data) {
|
||||||
|
console.log(data);
|
||||||
|
});
|
Loading…
Reference in a new issue