Skip to content

change the ctftime command to work with multiple urls at once #264

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 37 additions & 27 deletions commands/ctftime.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,37 +29,16 @@ func init() {
}

func CtfTimeHelp() string {
return "set the current ctftime url with ret\n\n" +
"the ctftime url is stored in " + theme.ColorCyan + "`~/.config/ret`" + theme.ColorReset + " using the " + theme.ColorYellow + "`\"ctftimeurl\"`" + theme.ColorReset + " field\n\n" +
"the command will use the ctftime.org api to fetch details about the currently set ctftime url and then display them\n\n" +
return "adds a ctftime url with ret\n\n" +
"the ctftime urls are stored in " + theme.ColorCyan + "`~/.config/ret`" + theme.ColorReset + " using the " + theme.ColorYellow + "`\"ctftimeurls\"`" + theme.ColorReset + " field\n\n" +
"the command will use the ctftime.org api to fetch details about all the currently set ctftime urls and then display them\n\n" +
"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" +
"for more details please see https://ctftime.org/api/\n\n" +
"the ctftime url will be used to aid in the generation of writeups with the " + theme.ColorGreen + "`writeup`" + theme.ColorReset + " command\n\n"
"the ctftime urls will be used to aid in the generation of writeups with the " + theme.ColorGreen + "`writeup`" + theme.ColorReset + " command\n\n"
}

func CtfTime(args []string) {
if len(args) > 0 {
fmt.Printf(theme.ColorGray+"old ctftime url: "+theme.ColorRed+"%v"+theme.ColorReset+"\n", config.CtfTimeUrl)

config.CtfTimeUrl = strings.Trim(args[0], "/")

config.WriteUserConfig()

fmt.Printf(theme.ColorGray+"new ctftime url: "+theme.ColorGreen+"%v"+theme.ColorReset+"\n", config.CtfTimeUrl)
return
}

if len(config.CtfTimeUrl) == 0 {
return
}

fmt.Printf(theme.ColorGray+"url: "+theme.ColorReset+"%v"+theme.ColorReset+"\n", config.CtfTimeUrl)

if !strings.Contains(config.CtfTimeUrl, "ctftime.org") {
return
}

splits := strings.Split(config.CtfTimeUrl, "/")
func showStats(ctfTimeUrl string) {
splits := strings.Split(ctfTimeUrl, "/")
eventId := splits[len(splits)-1]

url := fmt.Sprintf("https://ctftime.org/api/v1/events/%s/", eventId)
Expand Down Expand Up @@ -121,3 +100,34 @@ func CtfTime(args []string) {
fmt.Printf(theme.ColorGray+"time to finish: "+theme.ColorReset+"%v\n", finishTime.Sub(now))
}
}

func CtfTime(args []string) {
if len(args) > 0 {
newCtfTimeUrl := strings.Trim(args[0], "/")

for _, ctfTimeUrl := range config.CtfTimeUrls {
if newCtfTimeUrl == ctfTimeUrl {
log.Fatalf("💥 "+theme.ColorRed+" error"+theme.ColorReset+": a ctf with the url %v has already been registered\n", newCtfTimeUrl)
return
}
}

config.CtfTimeUrls = append(config.CtfTimeUrls, newCtfTimeUrl)

config.WriteUserConfig()

fmt.Printf(theme.ColorGray+"new ctftime url: "+theme.ColorGreen+"%v"+theme.ColorReset+"\n", newCtfTimeUrl)
return
}

for idx, ctfTimeUrl := range config.CtfTimeUrls {
fmt.Printf(theme.ColorGray+"url: "+theme.ColorReset+"%v"+theme.ColorReset+"\n", ctfTimeUrl)

if strings.Contains(ctfTimeUrl, "ctftime.org") {
showStats(ctfTimeUrl)
if idx+1 < len(config.CtfTimeUrls) {
fmt.Printf("\n")
}
}
}
}
9 changes: 7 additions & 2 deletions commands/writeup.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func WriteupHelp() string {
"the writeup will be saved in a file called `writeup.md`\n\n" +
"if a file called `writeup.md` already exists the command will abort\n" +
"there is a small window for a time-of-check/time-of-use race here - you have been warned!\n\n" +
"1. uses the " + theme.ColorYellow + "`\"ctftimeurl\"`" + theme.ColorReset + " to insert a url at the top of the writeup\n" +
"1. uses the first url from " + theme.ColorYellow + "`\"ctftimeurls\"`" + theme.ColorReset + " to insert a url at the top of the writeup\n" +
"2. imports all notes taken with the " + theme.ColorGreen + "`notes`" + theme.ColorReset + " command into the description area\n" +
"3. creates a space for a python script and then imports the script created by " + theme.ColorGreen + "`pwn`" + theme.ColorReset + " if it exists\n" +
"4. imports the flag captured with the " + theme.ColorGreen + "`capture`" + theme.ColorReset + " command if it exists\n" +
Expand All @@ -44,7 +44,12 @@ func Writeup(args []string) {
log.Fatalf("💥 "+theme.ColorRed+"error"+theme.ColorReset+": \"%s\" already exists!\n", filePath)
}

url := config.CtfTimeUrl
url := ""
if len(config.CtfTimeUrls) > 0 {
// we should do better than this
url = config.CtfTimeUrls[0]
}

if url == "" {
url = "https://ctftime.link.goes.here"
}
Expand Down
38 changes: 20 additions & 18 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,24 +37,24 @@ var (
ChatWebhookUrl3 = ""
GistToken = ""
ChefUrl = "https://gchq.github.io/CyberChef/"
CtfTimeUrl = ""
CtfTimeUrls = []string{}
)

type Config struct {
GhidraInstallPath string `json:"ghidrainstallpath"`
GhidraProject string `json:"ghidraproject"`
IdaInstallPath string `json:"idainstallpath"`
PwnScriptName string `json:"pwnscriptname"`
PwnScriptTemplate string `json:"pwnscripttemplate"`
CryptoScriptName string `json:"cryptoscriptname"`
CryptoScriptTemplate string `json:"cryptoscripttemplate"`
Username string `json:"username"`
ChatWebhookUrl string `json:"chatwebhookurl"`
ChatWebhookUrl2 string `json:"chatwebhookurl2"`
ChatWebhookUrl3 string `json:"chatwebhookurl3"`
GistToken string `json:"gisttoken"`
ChefUrl string `json:"chefurl"`
CtfTimeUrl string `json:"ctftimeurl"`
GhidraInstallPath string `json:"ghidrainstallpath"`
GhidraProject string `json:"ghidraproject"`
IdaInstallPath string `json:"idainstallpath"`
PwnScriptName string `json:"pwnscriptname"`
PwnScriptTemplate string `json:"pwnscripttemplate"`
CryptoScriptName string `json:"cryptoscriptname"`
CryptoScriptTemplate string `json:"cryptoscripttemplate"`
Username string `json:"username"`
ChatWebhookUrl string `json:"chatwebhookurl"`
ChatWebhookUrl2 string `json:"chatwebhookurl2"`
ChatWebhookUrl3 string `json:"chatwebhookurl3"`
GistToken string `json:"gisttoken"`
ChefUrl string `json:"chefurl"`
CtfTimeUrls []string `json:"ctftimeurls"`
}

func ParseUserConfig() {
Expand Down Expand Up @@ -130,8 +130,9 @@ func ParseUserConfig() {
ChefUrl = userConfig.ChefUrl
}

if len(userConfig.CtfTimeUrl) > 0 {
CtfTimeUrl = userConfig.CtfTimeUrl
if len(userConfig.CtfTimeUrls) > 0 {
CtfTimeUrls = make([]string, len(userConfig.CtfTimeUrls))
copy(CtfTimeUrls, userConfig.CtfTimeUrls)
}
}

Expand Down Expand Up @@ -166,7 +167,8 @@ func WriteUserConfig() {
userConfig.ChatWebhookUrl3 = ChatWebhookUrl3
userConfig.GistToken = GistToken
userConfig.ChefUrl = ChefUrl
userConfig.CtfTimeUrl = CtfTimeUrl
userConfig.CtfTimeUrls = make([]string, len(CtfTimeUrls))
copy(userConfig.CtfTimeUrls, CtfTimeUrls)

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