about summary refs log tree commit diff
path: root/src/seed.go
blob: af14d38fa32e36609cdea7626ad3e338189cc72f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"github.com/pkg/errors"
	"io/ioutil"
	"log"
	"time"
)

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, error) {
	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, readError
	}

	// 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, unmarshalError
	}

	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,
				FoundFlag: time.Unix(0, 0),
				FlagTries: 0,
				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, nil
}

// Read the file we set up using flags and store the returned challenge array
func getChallengesFromSeedFile() (error) {
	tmpChallenges, error := readSeedFile(*seedFilePath)

	if error != nil {
		// Couldn't read file, return error
		return error
	}

	if tmpChallenges == nil {
		// Could read file, but it didn't contain any parseable challenges - return
		return errors.New(fmt.Sprintf("Empty seed file at %s? No challenges found", *seedFilePath))
	}

	if tmpChallenges != nil {
		// returned challenges found! Set them.
		challenges = tmpChallenges
	}

	return nil
}

// 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
	categories := map[string]int{}

	for _, challenge := range challenges {
		// Append challenge to list
		strippedChallenges = append(strippedChallenges, stripChallenge(challenge))

		categories[challenge.Category]++
	}

	marshalled, marshalError := json.Marshal(map[string]interface{}{
		"challenges": strippedChallenges,
		"categories": categories,
	})
	return string(marshalled), marshalError
}