Skip to content

Commit f9f1858

Browse files
authored
Merge pull request #264 from dmur1/support-multiple-ctfs-#262
change the ctftime command to work with multiple urls at once
2 parents e94949f + 839c445 commit f9f1858

File tree

3 files changed

+64
-47
lines changed

3 files changed

+64
-47
lines changed

commands/ctftime.go

Lines changed: 37 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -29,37 +29,16 @@ func init() {
2929
}
3030

3131
func CtfTimeHelp() string {
32-
return "set the current ctftime url with ret\n\n" +
33-
"the ctftime url is stored in " + theme.ColorCyan + "`~/.config/ret`" + theme.ColorReset + " using the " + theme.ColorYellow + "`\"ctftimeurl\"`" + theme.ColorReset + " field\n\n" +
34-
"the command will use the ctftime.org api to fetch details about the currently set ctftime url and then display them\n\n" +
32+
return "adds a ctftime url with ret\n\n" +
33+
"the ctftime urls are stored in " + theme.ColorCyan + "`~/.config/ret`" + theme.ColorReset + " using the " + theme.ColorYellow + "`\"ctftimeurls\"`" + theme.ColorReset + " field\n\n" +
34+
"the command will use the ctftime.org api to fetch details about all the currently set ctftime urls and then display them\n\n" +
3535
"the ctf's title, start time and finish time will be displayed along with an indication of the time to the start or finish depending on the context\n\n" +
3636
"for more details please see https://ctftime.org/api/\n\n" +
37-
"the ctftime url will be used to aid in the generation of writeups with the " + theme.ColorGreen + "`writeup`" + theme.ColorReset + " command\n\n"
37+
"the ctftime urls will be used to aid in the generation of writeups with the " + theme.ColorGreen + "`writeup`" + theme.ColorReset + " command\n\n"
3838
}
3939

40-
func CtfTime(args []string) {
41-
if len(args) > 0 {
42-
fmt.Printf(theme.ColorGray+"old ctftime url: "+theme.ColorRed+"%v"+theme.ColorReset+"\n", config.CtfTimeUrl)
43-
44-
config.CtfTimeUrl = strings.Trim(args[0], "/")
45-
46-
config.WriteUserConfig()
47-
48-
fmt.Printf(theme.ColorGray+"new ctftime url: "+theme.ColorGreen+"%v"+theme.ColorReset+"\n", config.CtfTimeUrl)
49-
return
50-
}
51-
52-
if len(config.CtfTimeUrl) == 0 {
53-
return
54-
}
55-
56-
fmt.Printf(theme.ColorGray+"url: "+theme.ColorReset+"%v"+theme.ColorReset+"\n", config.CtfTimeUrl)
57-
58-
if !strings.Contains(config.CtfTimeUrl, "ctftime.org") {
59-
return
60-
}
61-
62-
splits := strings.Split(config.CtfTimeUrl, "/")
40+
func showStats(ctfTimeUrl string) {
41+
splits := strings.Split(ctfTimeUrl, "/")
6342
eventId := splits[len(splits)-1]
6443

6544
url := fmt.Sprintf("https://ctftime.org/api/v1/events/%s/", eventId)
@@ -121,3 +100,34 @@ func CtfTime(args []string) {
121100
fmt.Printf(theme.ColorGray+"time to finish: "+theme.ColorReset+"%v\n", finishTime.Sub(now))
122101
}
123102
}
103+
104+
func CtfTime(args []string) {
105+
if len(args) > 0 {
106+
newCtfTimeUrl := strings.Trim(args[0], "/")
107+
108+
for _, ctfTimeUrl := range config.CtfTimeUrls {
109+
if newCtfTimeUrl == ctfTimeUrl {
110+
log.Fatalf("💥 "+theme.ColorRed+" error"+theme.ColorReset+": a ctf with the url %v has already been registered\n", newCtfTimeUrl)
111+
return
112+
}
113+
}
114+
115+
config.CtfTimeUrls = append(config.CtfTimeUrls, newCtfTimeUrl)
116+
117+
config.WriteUserConfig()
118+
119+
fmt.Printf(theme.ColorGray+"new ctftime url: "+theme.ColorGreen+"%v"+theme.ColorReset+"\n", newCtfTimeUrl)
120+
return
121+
}
122+
123+
for idx, ctfTimeUrl := range config.CtfTimeUrls {
124+
fmt.Printf(theme.ColorGray+"url: "+theme.ColorReset+"%v"+theme.ColorReset+"\n", ctfTimeUrl)
125+
126+
if strings.Contains(ctfTimeUrl, "ctftime.org") {
127+
showStats(ctfTimeUrl)
128+
if idx+1 < len(config.CtfTimeUrls) {
129+
fmt.Printf("\n")
130+
}
131+
}
132+
}
133+
}

commands/writeup.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ func WriteupHelp() string {
2727
"the writeup will be saved in a file called `writeup.md`\n\n" +
2828
"if a file called `writeup.md` already exists the command will abort\n" +
2929
"there is a small window for a time-of-check/time-of-use race here - you have been warned!\n\n" +
30-
"1. uses the " + theme.ColorYellow + "`\"ctftimeurl\"`" + theme.ColorReset + " to insert a url at the top of the writeup\n" +
30+
"1. uses the first url from " + theme.ColorYellow + "`\"ctftimeurls\"`" + theme.ColorReset + " to insert a url at the top of the writeup\n" +
3131
"2. imports all notes taken with the " + theme.ColorGreen + "`notes`" + theme.ColorReset + " command into the description area\n" +
3232
"3. creates a space for a python script and then imports the script created by " + theme.ColorGreen + "`pwn`" + theme.ColorReset + " if it exists\n" +
3333
"4. imports the flag captured with the " + theme.ColorGreen + "`capture`" + theme.ColorReset + " command if it exists\n" +
@@ -44,7 +44,12 @@ func Writeup(args []string) {
4444
log.Fatalf("💥 "+theme.ColorRed+"error"+theme.ColorReset+": \"%s\" already exists!\n", filePath)
4545
}
4646

47-
url := config.CtfTimeUrl
47+
url := ""
48+
if len(config.CtfTimeUrls) > 0 {
49+
// we should do better than this
50+
url = config.CtfTimeUrls[0]
51+
}
52+
4853
if url == "" {
4954
url = "https://ctftime.link.goes.here"
5055
}

config/config.go

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -37,24 +37,24 @@ var (
3737
ChatWebhookUrl3 = ""
3838
GistToken = ""
3939
ChefUrl = "https://gchq.github.io/CyberChef/"
40-
CtfTimeUrl = ""
40+
CtfTimeUrls = []string{}
4141
)
4242

4343
type Config struct {
44-
GhidraInstallPath string `json:"ghidrainstallpath"`
45-
GhidraProject string `json:"ghidraproject"`
46-
IdaInstallPath string `json:"idainstallpath"`
47-
PwnScriptName string `json:"pwnscriptname"`
48-
PwnScriptTemplate string `json:"pwnscripttemplate"`
49-
CryptoScriptName string `json:"cryptoscriptname"`
50-
CryptoScriptTemplate string `json:"cryptoscripttemplate"`
51-
Username string `json:"username"`
52-
ChatWebhookUrl string `json:"chatwebhookurl"`
53-
ChatWebhookUrl2 string `json:"chatwebhookurl2"`
54-
ChatWebhookUrl3 string `json:"chatwebhookurl3"`
55-
GistToken string `json:"gisttoken"`
56-
ChefUrl string `json:"chefurl"`
57-
CtfTimeUrl string `json:"ctftimeurl"`
44+
GhidraInstallPath string `json:"ghidrainstallpath"`
45+
GhidraProject string `json:"ghidraproject"`
46+
IdaInstallPath string `json:"idainstallpath"`
47+
PwnScriptName string `json:"pwnscriptname"`
48+
PwnScriptTemplate string `json:"pwnscripttemplate"`
49+
CryptoScriptName string `json:"cryptoscriptname"`
50+
CryptoScriptTemplate string `json:"cryptoscripttemplate"`
51+
Username string `json:"username"`
52+
ChatWebhookUrl string `json:"chatwebhookurl"`
53+
ChatWebhookUrl2 string `json:"chatwebhookurl2"`
54+
ChatWebhookUrl3 string `json:"chatwebhookurl3"`
55+
GistToken string `json:"gisttoken"`
56+
ChefUrl string `json:"chefurl"`
57+
CtfTimeUrls []string `json:"ctftimeurls"`
5858
}
5959

6060
func ParseUserConfig() {
@@ -130,8 +130,9 @@ func ParseUserConfig() {
130130
ChefUrl = userConfig.ChefUrl
131131
}
132132

133-
if len(userConfig.CtfTimeUrl) > 0 {
134-
CtfTimeUrl = userConfig.CtfTimeUrl
133+
if len(userConfig.CtfTimeUrls) > 0 {
134+
CtfTimeUrls = make([]string, len(userConfig.CtfTimeUrls))
135+
copy(CtfTimeUrls, userConfig.CtfTimeUrls)
135136
}
136137
}
137138

@@ -166,7 +167,8 @@ func WriteUserConfig() {
166167
userConfig.ChatWebhookUrl3 = ChatWebhookUrl3
167168
userConfig.GistToken = GistToken
168169
userConfig.ChefUrl = ChefUrl
169-
userConfig.CtfTimeUrl = CtfTimeUrl
170+
userConfig.CtfTimeUrls = make([]string, len(CtfTimeUrls))
171+
copy(userConfig.CtfTimeUrls, CtfTimeUrls)
170172

171173
jsonData, err := json.MarshalIndent(userConfig, "", " ")
172174
if err != nil {

0 commit comments

Comments
 (0)