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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
|
package main
import (
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"log"
"strconv"
"time"
"github.com/pkg/errors"
)
var (
challenges = []Challenge{}
seedFilePath *string
user 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)
pointsStr, pointsOK := challenge["points"].(string)
points, _ := strconv.Atoi(pointsStr)
if nameOK && descOK && flagOK && contOK && categoryOK && pointsOK {
tmpChallenges = append(tmpChallenges, Challenge{
Name: name,
Description: desc,
Flag: flag,
FoundFlag: time.Unix(0, 0),
FlagTries: 0,
Container: cont,
Category: category,
Points: points,
})
} else {
log.Printf("Ignoring challenge at position %d: Not all values are parseable (name: %b, desc: %b, flag: %b, container: %b, category: %b, points: %b", index, nameOK, descOK, flagOK, contOK, categoryOK, pointsOK)
}
}
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
score := 0
categories := map[string]int{}
for _, challenge := range challenges {
// Append challenge to list
strippedChallenges = append(strippedChallenges, stripChallengeForStatistics(challenge))
// Raise category counter
categories[challenge.Category]++
// Raise score if flag was found
if challenge.FoundFlag.Unix() > 0 {
score = score + challenge.Points
}
}
marshalled, marshalError := json.Marshal(map[string]interface{}{
"user": user,
"challenges": strippedChallenges,
"score": score,
})
return string(marshalled), marshalError
}
|