package main import ( "crypto/hmac" "crypto/sha256" "encoding/hex" "fmt" "io" "log" "net/http" "os" "github.com/go-redis/redis/v8" "github.com/gorilla/mux" "golang.org/x/net/context" ) var client = redis.NewClient(&redis.Options{ Addr: "redis:6379", Password: "", DB: 0, }) var SECRET string func main() { r := mux.NewRouter() r.HandleFunc("/{shortlink}", shortlinkHandler) r.HandleFunc("/", indexHandler) listenAddress := "0.0.0.0:80" if p, ok := os.LookupEnv("LISTEN_ADDRESS"); ok { listenAddress = p } if p, ok := os.LookupEnv("SECRET"); ok { SECRET = p } log.Fatal(http.ListenAndServe(listenAddress, r)) } func indexHandler(w http.ResponseWriter, r *http.Request) { fmt.Println("indexHandler called") if r.Method != "POST" { http.Redirect(w, r, "http://alv.cx", 302) return } r.ParseForm() command := r.PostForm.Get("Command") shortlink := r.PostForm.Get("Shortlink") value := r.PostForm.Get("Value") fmt.Printf("command: %v, shortlink: %v, value: %v\n", command, shortlink, value) fmt.Println(shortlink) fmt.Println(value) signature := r.Header.Get("Signature") calculatedSignature := fmt.Sprintf( "SUS-SIGNATURE-%v", getSha256HMACSignature( []byte(SECRET), command+":"+shortlink+":"+value, ), ) if signature != calculatedSignature { fmt.Println("signature do no match") fmt.Println(signature) fmt.Println(calculatedSignature) w.WriteHeader(401) w.Write([]byte("401 Unauthorized")) return } if command == "create" { ctx := context.Background() _, err := client.Get(ctx, shortlink).Result() if err == redis.Nil { err = client.Set(ctx, shortlink, value, 0).Err() if err != nil { fmt.Println(err) w.WriteHeader(500) w.Write([]byte("500 Internal Server Error")) return } w.WriteHeader(200) w.Write([]byte("200 Success")) return } else if err != nil { fmt.Println(err) w.WriteHeader(500) w.Write([]byte("500 Internal Server Error")) return } fmt.Println(err) w.WriteHeader(403) w.Write([]byte("403 Forbidden")) return } if command == "delete" { if value != "confirm" { w.WriteHeader(400) w.Write([]byte("400 Bad Request")) } ctx := context.Background() if err := client.Del(ctx, shortlink).Err(); err != nil { w.WriteHeader(500) w.Write([]byte("500 Internal Server Error")) } } } func shortlinkHandler(w http.ResponseWriter, r *http.Request) { fmt.Println("shortlinkHandler called") shortlink := string(mux.Vars(r)["shortlink"]) ctx := context.Background() redirect, err := client.Get(ctx, shortlink).Result() fmt.Printf("shortlink: %v, redirect: %v\n", shortlink, redirect) if err == redis.Nil { w.WriteHeader(404) w.Write([]byte("404 Not Found")) return } else if err != nil { fmt.Println(err) w.WriteHeader(500) w.Write([]byte("500 Internal Server Error")) return } http.Redirect(w, r, redirect, 302) return } func getSha256HMACSignature(secret []byte, data string) string { h := hmac.New(sha256.New, secret) io.WriteString(h, data) return hex.EncodeToString(h.Sum(nil)) }