From 6a66ed60af5ba83d3e9c064d41dbd1b7a0f23468 Mon Sep 17 00:00:00 2001 From: maride Date: Tue, 14 Aug 2018 17:28:47 +0200 Subject: Add challenges --- src/challenge.go | 23 +++++++++++++++ src/http.go | 21 ++++++++++++++ src/main.go | 5 ++++ src/seed.go | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 135 insertions(+) create mode 100644 src/challenge.go create mode 100644 src/seed.go (limited to 'src') diff --git a/src/challenge.go b/src/challenge.go new file mode 100644 index 0000000..a1f9893 --- /dev/null +++ b/src/challenge.go @@ -0,0 +1,23 @@ +package main + +type Challenge struct { + Name string + Description string + Flag string // this should never leave the server + Container string // this could, but is not required as well + Category string +} + +type StrippedChallenge struct { + Name string `json:"name"` + Description string `json:"description"` + Category string `json:"category"` +} + +func stripChallenge(c Challenge) (StrippedChallenge) { + return StrippedChallenge{ + Name: c.Name, + Description: c.Description, + Category: c.Category, + } +} diff --git a/src/http.go b/src/http.go index 9f97352..1ddebe5 100644 --- a/src/http.go +++ b/src/http.go @@ -8,6 +8,7 @@ import ( "strings" "io/ioutil" "time" + "log" ) var ( @@ -26,6 +27,7 @@ func runHTTPServer() (error) { r.HandleFunc("/login", loginGetHandler).Methods("GET") r.HandleFunc("/login", loginPostHandler).Methods("POST") r.HandleFunc("/logout", logoutHandler).Methods("GET") + r.HandleFunc("/api/getChallenges", getChallengesHandler).Methods("GET") address := fmt.Sprintf(":%d", *port) return http.ListenAndServe(address, r) @@ -141,3 +143,22 @@ func logoutHandler(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, "/", http.StatusTemporaryRedirect) } + +func getChallengesHandler(w http.ResponseWriter, r *http.Request) { + session, cookieNotFoundError := r.Cookie("session") + + if cookieNotFoundError != nil || !isValidSession(session.Value) { + // either no session cookie found, or it contains an invalid session token. Redirect. + http.Redirect(w, r, "/login", http.StatusTemporaryRedirect) + } else { + // valid session token found, send out JSON array containing all challenges + json, jsonErr := generateJSONFromChallenges() + + if jsonErr == nil { + w.Write([]byte(json)) + } else { + log.Println(jsonErr) + w.WriteHeader(500) + } + } +} diff --git a/src/main.go b/src/main.go index 519943a..8ca13a7 100644 --- a/src/main.go +++ b/src/main.go @@ -10,8 +10,13 @@ func main() { registerHTTPFlags() registerSessionFlags() registerCredentialsFlags() + registerSeedFlags() flag.Parse() + // Read challenges from file + getChallengesFromSeedFile() + generateJSONFromChallenges() + // Run HTTP server log.Fatalln(runHTTPServer()) } \ No newline at end of file diff --git a/src/seed.go b/src/seed.go new file mode 100644 index 0000000..8256929 --- /dev/null +++ b/src/seed.go @@ -0,0 +1,86 @@ +package main + +import ( + "flag" + "io/ioutil" + "log" + "encoding/json" +) + +var ( + challenges = []Challenge{} + seedFilePath* string +) + +func registerSeedFlags() { + seedFilePath = flag.String("seedFile", "/etc/companion.json", "Path to seedfile") +} + +// Read a given seed file and return their containing challenges +func readSeedFile(path string) ([]Challenge) { + var jsonContents map[string]interface{} + + // Read file + rawContents, readError := ioutil.ReadFile(path) + if readError != nil { + log.Printf("Failed to read seed file at %s: %s", *seedFilePath, readError.Error()) + return nil + } + + // Convert JSON String to map + unmarshalError := json.Unmarshal(rawContents, &jsonContents) + if unmarshalError != nil { + log.Printf("Failed to parse JSON in seed file at %s: %s", *seedFilePath, unmarshalError.Error()) + return nil + } + + tmpChallenges := []Challenge{} + + // Iterate over challenges + for index, challengeObject := range jsonContents["challenges"].([]interface{}) { + challenge := challengeObject.(map[string]interface{}) + // add our parsed challenge to array + + name, nameOK := challenge["name"].(string) + desc, descOK := challenge["description"].(string) + flag, flagOK := challenge["flag"].(string) + cont, contOK := challenge["container"].(string) + category, categoryOK := challenge["category"].(string) + + if nameOK && descOK && flagOK && contOK && categoryOK { + tmpChallenges = append(tmpChallenges, Challenge{ + Name: name, + Description: desc, + Flag: flag, + Container: cont, + Category: category, + }) + } else { + log.Printf("Ignoring challenge at position %d: Not all values are parseable (name: %b, desc: %b, flag: %b, container: %b, category: %b", index, nameOK, descOK, flagOK, contOK, categoryOK) + } + } + + return tmpChallenges +} + +// Read the file we set up using flags and store the returned challenge array +func getChallengesFromSeedFile() { + tmpChallenges := readSeedFile(*seedFilePath) + + if tmpChallenges != nil { + challenges = tmpChallenges + } +} + +// Generate a JSON string from the stored challenges, stripped from content which might spoil the user +func generateJSONFromChallenges() (string, error) { + // To avoid leakage of container name or the flag towards the user, we need to strip the challenges + var strippedChallenges []StrippedChallenge + + for _, challenge := range challenges { + strippedChallenges = append(strippedChallenges, stripChallenge(challenge)) + } + + marshalled, marshalError := json.Marshal(strippedChallenges) + return string(marshalled), marshalError +} -- cgit 1.4.1