package main import ( "crypto/sha256" "flag" "fmt" "html/template" "io/ioutil" "log" "net/http" "strconv" "strings" "github.com/gorilla/mux" ) var ( port *int ) func registerHTTPFlags() { port = flag.Int("port", 8080, "The port for HTTP") } func setupHTTPServer() http.Server { r := mux.NewRouter() r.HandleFunc("/", indexHandler) r.HandleFunc("/create", createGetHandler).Methods("GET") r.HandleFunc("/create", createPostHandler).Methods("POST") r.HandleFunc("/view", viewGetHandler).Methods("GET") r.HandleFunc("/edit", editGetHandler).Methods("GET") r.HandleFunc("/edit", editPostHandler).Methods("POST") r.HandleFunc("/delete", deleteHandler) r.HandleFunc("/editSelect", editSelectGetHandler).Methods("GET") r.HandleFunc("/api/getChallenges", getChallenges).Methods("GET") return http.Server{ Addr: fmt.Sprintf("0.0.0.0:%d", *port), Handler: r, } } // Host the index file func indexHandler(w http.ResponseWriter, r *http.Request) { readFileToResponse(w, "/index.html") } func createGetHandler(w http.ResponseWriter, r *http.Request) { log.Println("create GET") readFileToResponse(w, "/create.html") } // createPostHandler handles HTTP POST requests to the /create endpoint creating // new challenges in the database func createPostHandler(w http.ResponseWriter, r *http.Request) { // parse the Post Request form r.ParseForm() points, err := strconv.ParseInt(r.Form.Get("challengePoints"), 10, 64) if err != nil { log.Printf("Could not parse points: %v", err) return } var static bool if r.Form.Get("challengeStatic") == "on" { static = true } else if r.Form.Get("challengeStatic") == "off" { static = false } else { log.Printf("Could not parse static: %v", r.Form.Get("challengeStatic")) return } // Define the new challenge newChallenge := Challenge{ Name: r.Form.Get("challengeName"), Description: r.Form.Get("challengeDescription"), Flag: r.Form.Get("challengeFlag"), Container: r.Form.Get("challengeContainer"), Category: r.Form.Get("challengeCategory"), Points: int(points), Static: static, } // Create the new challenge in the database uuid, err := dbNewChallenge(newChallenge) if err != nil { log.Println(err) return } log.Printf("Create a new challenge. UUID: %s", uuid) http.Redirect(w, r, "/view", http.StatusSeeOther) } // viewGetHandler returns a list of all challenges in the database func viewGetHandler(w http.ResponseWriter, r *http.Request) { // get all challenges from the db challs := dbGetAllChallenges() // define a challenges struct storing the challenges. // This struct can be used in a template challenges := Challenges{} for _, chal := range challs { challenges.Challenge = append(challenges.Challenge, chal) } // define a new template to render the challenges in t := template.New("") t, err := t.ParseFiles("./hosted/view.html") if err != nil { log.Println(err) return } // execure the template using the challenges struct t.ExecuteTemplate(w, "view", challenges) } func editSelectGetHandler(w http.ResponseWriter, r *http.Request) { // get all challenges from the db challs := dbGetAllChallenges() // define a challenges struct storing the challenges. // This struct can be used in a template challenges := Challenges{} for _, chal := range challs { challenges.Challenge = append(challenges.Challenge, chal) } // define a new template to render the challenges in t := template.New("") t, err := t.ParseFiles("./hosted/edit.html") if err != nil { log.Println(err) return } // execure the template using the challenges struct t.ExecuteTemplate(w, "edit", challenges) } func editGetHandler(w http.ResponseWriter, r *http.Request) { var uuid string if r.URL.Query()["uuid"] == nil { log.Println("editnoparam") http.Redirect(w, r, "/editSelect", http.StatusSeeOther) return } uuid = r.URL.Query()["uuid"][0] log.Printf("fetching challenge with the uuid %s", uuid) chall, err := dbGetChallengeByUUID(uuid) if err != nil { log.Println(err) } // define a new template to render the challenges in t := template.New("") t, err = t.ParseFiles("./hosted/edit_uuid.html") if err != nil { log.Println(err) return } // execute the template using the challenges struct t.ExecuteTemplate(w, "edit_uuid", chall) return } func editPostHandler(w http.ResponseWriter, r *http.Request) { log.Println("edit POST") // parse the Post Request form err := r.ParseForm() if err != nil { log.Println("could not parse the http post form!") return } // parse the challenge points points, err := strconv.ParseInt(r.PostFormValue("challengePoints"), 10, 64) if err != nil { log.Printf("Could not parse points: %v (%#v)", err, r.Form.Get("challengePoints")) return } // parse the static value var static bool if r.Form.Get("challengeStatic") == "true" { static = true } else if r.Form.Get("challengeStatic") == "false" { static = false } else { log.Println("[edit POST] Could not parse static: %v", r.Form.Get("challengeStatic")) return } // define the new edited challenge editedChallenge := Challenge{ UUID: r.Form.Get("challengeUUID"), Name: r.Form.Get("challengeName"), Description: r.Form.Get("challengeDescription"), Flag: r.Form.Get("challengeFlag"), Container: r.Form.Get("challengeContainer"), Category: r.Form.Get("challengeCategory"), Points: int(points), Static: static, } // update the challenge in the database EditError := dbEditChallengeUUID(r.Form.Get("challengeUUID"), editedChallenge) if EditError != nil { log.Println("Could not edit:") log.Println(EditError) } log.Println("done editing challenge!") http.Redirect(w, r, "/edit", http.StatusSeeOther) } func deleteHandler(w http.ResponseWriter, r *http.Request) { err := r.ParseForm() if err != nil { log.Println("deleteHandler could not parse the form") log.Println(err) } if r.URL.Query()["uuid"] == nil { log.Println("delete: no uuid given") return } uuid := r.URL.Query()["uuid"][0] log.Printf("Deleteing challenge with uuid %s\n", uuid) dbDeleteChallengeByUUID(uuid) http.Redirect(w, r, "/editSelect", http.StatusSeeOther) } // Helper function to host files off of "hosted/" directory func readFileToResponse(w http.ResponseWriter, path string) { requestedFile := strings.Replace(path, "..", "", -1) contents, readError := ioutil.ReadFile(fmt.Sprintf("hosted/%s", requestedFile)) if readError != nil { w.Write([]byte(fmt.Sprintf("unable to read %s", requestedFile))) } else { w.Write([]byte(contents)) } } func stripChallenge(challenge Challenge) StrippedChallenge { // Hash the flag using sha256 FlagSha256Sum := fmt.Sprintf("%x", sha256.Sum256([]byte(challenge.Flag))) strippedChallenge := StrippedChallenge{ Name: challenge.Name, Description: challenge.Description, FlagHash: FlagSha256Sum, Container: challenge.Container, Category: challenge.Category, Points: challenge.Points, Static: challenge.Static, } return strippedChallenge }