about summary refs log tree commit diff
path: root/src/seed.go
blob: dd836ff92e17c188e8ef2cb066f727d888c5db28 (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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
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
}

// Generate a JSON string from the stored challenges, just containing enough to call it statistics
func generateJSONFromChallengesForStats() (string, error) {
	// To include only required information for statistics, we need to strip the challenge
	var strippedChallenges []StatsStrippedChallenge
	categories := map[string]int{}

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

		categories[challenge.Category]++
	}

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