103 lines
2.2 KiB
Go
103 lines
2.2 KiB
Go
|
package main
|
||
|
|
||
|
import (
|
||
|
"net/http"
|
||
|
"net/url"
|
||
|
"log"
|
||
|
"os"
|
||
|
"strconv"
|
||
|
"crypto/hmac"
|
||
|
"crypto/sha256"
|
||
|
"encoding/base64"
|
||
|
"io"
|
||
|
"github.com/gorilla/mux"
|
||
|
"github.com/BurntSushi/toml"
|
||
|
)
|
||
|
|
||
|
type tomlConfig struct {
|
||
|
Port int `toml:"port"`
|
||
|
Secret string `toml:"secret"`
|
||
|
}
|
||
|
|
||
|
func proxyRequest(w http.ResponseWriter, r *http.Request, secret []byte) {
|
||
|
vars := mux.Vars(r)
|
||
|
requestUrl, err := url.QueryUnescape(vars["url"])
|
||
|
if err != nil {
|
||
|
log.Printf("Failed to url decode url: %s", err)
|
||
|
return
|
||
|
}
|
||
|
macRaw, err := url.QueryUnescape(vars["hmac"])
|
||
|
if err != nil {
|
||
|
log.Printf("Failed to url decode HMAC: %s", err)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
mac := hmac.New(sha256.New, secret)
|
||
|
mac.Write([]byte(requestUrl))
|
||
|
|
||
|
expectedMac := mac.Sum(nil)
|
||
|
receivedMac, err := base64.StdEncoding.DecodeString(macRaw)
|
||
|
if err != nil {
|
||
|
log.Printf("Failed to decode HMAC: %s", err)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
if !hmac.Equal(expectedMac, receivedMac) {
|
||
|
log.Printf("invalid-hmac:%s", r.RemoteAddr)
|
||
|
log.Printf("URL: '%s'", requestUrl)
|
||
|
http.Error(w, "Invalid HMAC", http.StatusUnauthorized)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
client := &http.Client{}
|
||
|
resp, err := client.Get(requestUrl)
|
||
|
defer resp.Body.Close()
|
||
|
|
||
|
if err != nil {
|
||
|
log.Fatalf("Failed to perform GET: %s", err)
|
||
|
}
|
||
|
|
||
|
w.WriteHeader(resp.StatusCode)
|
||
|
io.Copy(w, resp.Body)
|
||
|
}
|
||
|
|
||
|
func makeProxyRequestHandler(secret []byte) http.HandlerFunc {
|
||
|
fn := func(w http.ResponseWriter, r *http.Request) {
|
||
|
proxyRequest(w, r, secret)
|
||
|
}
|
||
|
|
||
|
return http.HandlerFunc(fn)
|
||
|
}
|
||
|
|
||
|
func exists(path string) bool {
|
||
|
// Returns true if path exists. false otherwise
|
||
|
_, err := os.Stat(path)
|
||
|
return !os.IsNotExist(err)
|
||
|
}
|
||
|
|
||
|
func main() {
|
||
|
config := tomlConfig {
|
||
|
Port: 8080,
|
||
|
}
|
||
|
|
||
|
switch {
|
||
|
case exists("./config.toml"):
|
||
|
_, err := toml.DecodeFile("./config.toml", &config)
|
||
|
if err != nil {
|
||
|
log.Fatalf("Failed to read ./config.toml: %s", err)
|
||
|
}
|
||
|
case exists("/etc/miniproxy/config.toml"):
|
||
|
_, err := toml.DecodeFile("/etc/miniproxy/config.toml", &config)
|
||
|
if err != nil {
|
||
|
log.Fatalf("Failed to read /etc/miniproxy/config.toml: %s", err)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
log.Printf("Running on :%d\n", config.Port)
|
||
|
|
||
|
r := mux.NewRouter()
|
||
|
r.UseEncodedPath()
|
||
|
r.HandleFunc("/proxy/{hmac}/{url:.+}", makeProxyRequestHandler([]byte(config.Secret)))
|
||
|
log.Fatal(http.ListenAndServe(":" + strconv.Itoa(config.Port), r))
|
||
|
}
|