itRearrange pages to reuse token box - scoreboard - Interactive scoreboard for CTF-like games Err z3bra.org 70 hgit clone git://git.z3bra.org/scoreboard.git URL:git://git.z3bra.org/scoreboard.git z3bra.org 70 1Log /scm/scoreboard/log.gph z3bra.org 70 1Files /scm/scoreboard/files.gph z3bra.org 70 1Refs /scm/scoreboard/refs.gph z3bra.org 70 i--- Err z3bra.org 70 1commit 4ccfc4d4d29f20d328168684842cf8ea1ac31581 /scm/scoreboard/commit/4ccfc4d4d29f20d328168684842cf8ea1ac31581.gph z3bra.org 70 1parent 37c53b0f0c56f05121f7fd0a3626eb278efa5f76 /scm/scoreboard/commit/37c53b0f0c56f05121f7fd0a3626eb278efa5f76.gph z3bra.org 70 hAuthor: Willy Goiffon URL:mailto:contact@z3bra.org z3bra.org 70 iDate: Fri, 27 Sep 2024 00:01:25 +0200 Err z3bra.org 70 i Err z3bra.org 70 iRearrange pages to reuse token box Err z3bra.org 70 i Err z3bra.org 70 iDiffstat: Err z3bra.org 70 i M main.go | 81 ++++++++++--------------------- Err z3bra.org 70 i M player.go | 30 +++++++++++++++++++++++++++++- Err z3bra.org 70 i M playerbox.go | 19 +++++++++---------- Err z3bra.org 70 i M ui.go | 46 +++++++++++++++++++++++++++++++ Err z3bra.org 70 i Err z3bra.org 70 i4 files changed, 109 insertions(+), 67 deletions(-) Err z3bra.org 70 i--- Err z3bra.org 70 1diff --git a/main.go b/main.go /scm/scoreboard/file/main.go.gph z3bra.org 70 it@@ -18,7 +18,6 @@ import ( Err z3bra.org 70 i "flag" Err z3bra.org 70 i "fmt" Err z3bra.org 70 i "os" Err z3bra.org 70 i- "regexp" Err z3bra.org 70 i "strings" Err z3bra.org 70 i "time" Err z3bra.org 70 i "database/sql" Err z3bra.org 70 it@@ -33,7 +32,7 @@ const ( Err z3bra.org 70 i BOARD_HEIGHT int = 15 Err z3bra.org 70 i HTML string = "score.html" Err z3bra.org 70 i DB string = "score.db" Err z3bra.org 70 i- TOKEN_REMINDER string = `%s, use the token below to submit your next flag. Err z3bra.org 70 i+ TOKEN_REMINDER string = `%s, use the token below to submit your flags. Err z3bra.org 70 i Save it carefully, do not share it. Err z3bra.org 70 i Err z3bra.org 70 i 🔑%s Err z3bra.org 70 it@@ -76,57 +75,6 @@ func flagid(hash string) int { Err z3bra.org 70 i return -1 Err z3bra.org 70 i } Err z3bra.org 70 i Err z3bra.org 70 i-func pageToken() tview.Primitive { Err z3bra.org 70 i- input := tview.NewInputField(). Err z3bra.org 70 i- SetLabel("TOKEN "). Err z3bra.org 70 i- SetPlaceholder(""). Err z3bra.org 70 i- SetFieldStyle(tcell.StyleDefault.Reverse(true)). Err z3bra.org 70 i- SetFieldWidth(30) Err z3bra.org 70 i- Err z3bra.org 70 i- input.SetAcceptanceFunc(func(text string, ch rune) bool { Err z3bra.org 70 i- if len(text) > 24 { Err z3bra.org 70 i- return false Err z3bra.org 70 i- } Err z3bra.org 70 i- Err z3bra.org 70 i- // tokens are base32 strings Err z3bra.org 70 i- matched, err := regexp.Match(`^[A-Z2-7]+$`, []byte(text)) Err z3bra.org 70 i- if err != nil { Err z3bra.org 70 i- panic(err) Err z3bra.org 70 i- } Err z3bra.org 70 i- return matched Err z3bra.org 70 i- }) Err z3bra.org 70 i- input.SetDoneFunc(func(key tcell.Key) { Err z3bra.org 70 i- if key != tcell.KeyEnter { Err z3bra.org 70 i- return Err z3bra.org 70 i- } Err z3bra.org 70 i- Err z3bra.org 70 i- token := input.GetText() Err z3bra.org 70 i- Err z3bra.org 70 i- if len(token) != 24 { Err z3bra.org 70 i- scoreboard.Popup("ERROR", "Invalid token format") Err z3bra.org 70 i- return Err z3bra.org 70 i- } Err z3bra.org 70 i- err := scoreboard.player.FromToken(token) Err z3bra.org 70 i- if err != nil { Err z3bra.org 70 i- scoreboard.Fatal(err) Err z3bra.org 70 i- return Err z3bra.org 70 i- } Err z3bra.org 70 i- Err z3bra.org 70 i- scoreboard.player.token = token; Err z3bra.org 70 i- Err z3bra.org 70 i- err = scoreboard.player.Submit(scoreboard.flag) Err z3bra.org 70 i- if err != nil { Err z3bra.org 70 i- scoreboard.Fatal(err) Err z3bra.org 70 i- return Err z3bra.org 70 i- } Err z3bra.org 70 i- scoreboard.HighlightBoard(scoreboard.player.ScoreRank() + 1) Err z3bra.org 70 i- scoreboard.pages.SwitchToPage("board") Err z3bra.org 70 i- scoreboard.GenerateHTML() Err z3bra.org 70 i- }) Err z3bra.org 70 i- Err z3bra.org 70 i- return center(40, 1, input) Err z3bra.org 70 i-} Err z3bra.org 70 i- Err z3bra.org 70 i func pageBoard() tview.Primitive { Err z3bra.org 70 i scoreboard.SetupFrame() Err z3bra.org 70 i scoreboard.DrawBoard() Err z3bra.org 70 it@@ -137,6 +85,7 @@ func pageBoard() tview.Primitive { Err z3bra.org 70 i Err z3bra.org 70 i func main() { Err z3bra.org 70 i var err error Err z3bra.org 70 i+ var reminder bool = false Err z3bra.org 70 i Err z3bra.org 70 i html := flag.String("o", HTML, "Output HTML file") Err z3bra.org 70 i db := flag.String("d", DB, "Database file") Err z3bra.org 70 it@@ -175,7 +124,6 @@ func main() { Err z3bra.org 70 i Err z3bra.org 70 i scoreboard.pages.SetBackgroundColor(tcell.ColorDefault) Err z3bra.org 70 i Err z3bra.org 70 i- scoreboard.pages.AddPage("token", pageToken(), true, false) Err z3bra.org 70 i scoreboard.pages.AddPage("board", pageBoard(), true, false) Err z3bra.org 70 i Err z3bra.org 70 i args := flag.Args() Err z3bra.org 70 it@@ -204,6 +152,14 @@ func main() { Err z3bra.org 70 i rank, _ := db_count_players(scoreboard.db) Err z3bra.org 70 i scoreboard.NewPlayer(rank + 1) Err z3bra.org 70 i scoreboard.pages.SwitchToPage("board") Err z3bra.org 70 i+ reminder = true Err z3bra.org 70 i+ Err z3bra.org 70 i+ case "badges": Err z3bra.org 70 i+ badgepage := scoreboard.Token(func () { Err z3bra.org 70 i+ scoreboard.app.Stop() Err z3bra.org 70 i+ fmt.Printf("Collection: %d/%d\n\n%s", scoreboard.player.flag, len(scoreboard.flag_ref), scoreboard.player.BadgeStr()) Err z3bra.org 70 i+ }) Err z3bra.org 70 i+ scoreboard.pages.AddAndSwitchToPage("badge", badgepage, true) Err z3bra.org 70 i Err z3bra.org 70 i /* anything not a command is treated as a flag */ Err z3bra.org 70 i default: Err z3bra.org 70 it@@ -212,7 +168,20 @@ func main() { Err z3bra.org 70 i fmt.Println("Incorrect flag") Err z3bra.org 70 i return Err z3bra.org 70 i } Err z3bra.org 70 i- scoreboard.pages.SwitchToPage("token") Err z3bra.org 70 i+ Err z3bra.org 70 i+ submitpage := scoreboard.Token(func () { Err z3bra.org 70 i+ err = scoreboard.player.Submit(scoreboard.flag) Err z3bra.org 70 i+ if err != nil { Err z3bra.org 70 i+ scoreboard.Fatal(err) Err z3bra.org 70 i+ return Err z3bra.org 70 i+ } Err z3bra.org 70 i+ scoreboard.HighlightBoard(scoreboard.player.ScoreRank() + 1) Err z3bra.org 70 i+ scoreboard.pages.RemovePage("submit") Err z3bra.org 70 i+ scoreboard.pages.ShowPage("board") Err z3bra.org 70 i+ scoreboard.GenerateHTML() Err z3bra.org 70 i+ }) Err z3bra.org 70 i+ Err z3bra.org 70 i+ scoreboard.pages.AddAndSwitchToPage("submit", submitpage, true) Err z3bra.org 70 i } Err z3bra.org 70 i } Err z3bra.org 70 i Err z3bra.org 70 it@@ -223,7 +192,7 @@ func main() { Err z3bra.org 70 i } Err z3bra.org 70 i Err z3bra.org 70 i /* Print a token reminder on exit in case one has been generated or provided */ Err z3bra.org 70 i- if scoreboard.player.token != "" { Err z3bra.org 70 i+ if reminder { Err z3bra.org 70 i fmt.Printf(TOKEN_REMINDER, scoreboard.player.name, scoreboard.player.token) Err z3bra.org 70 i } Err z3bra.org 70 i } Err z3bra.org 70 1diff --git a/player.go b/player.go /scm/scoreboard/file/player.go.gph z3bra.org 70 it@@ -20,6 +20,7 @@ import ( Err z3bra.org 70 i "encoding/base32" Err z3bra.org 70 i "errors" Err z3bra.org 70 i "fmt" Err z3bra.org 70 i+ "strings" Err z3bra.org 70 i "time" Err z3bra.org 70 i "golang.org/x/crypto/scrypt" Err z3bra.org 70 i "github.com/dustin/go-humanize" Err z3bra.org 70 it@@ -146,6 +147,33 @@ func (p *Player) FlagStr() string { Err z3bra.org 70 i return fmt.Sprintf("%2d/%d", p.flag, len(scoreboard.flag_ref)) Err z3bra.org 70 i } Err z3bra.org 70 i Err z3bra.org 70 i+func (p *Player) BadgeStr() string { Err z3bra.org 70 i+ var badges strings.Builder Err z3bra.org 70 i+ Err z3bra.org 70 i+ query := `SELECT Err z3bra.org 70 i+ flag.badge, flag.value, flag.score Err z3bra.org 70 i+ FROM flag Err z3bra.org 70 i+ INNER JOIN score ON score.flag = flag.value Err z3bra.org 70 i+ WHERE score.name = ?;` Err z3bra.org 70 i+ Err z3bra.org 70 i+ rows, err := p.db.Query(query, p.name) Err z3bra.org 70 i+ if err != nil { Err z3bra.org 70 i+ return "" Err z3bra.org 70 i+ } Err z3bra.org 70 i+ Err z3bra.org 70 i+ for rows.Next() { Err z3bra.org 70 i+ var b, v string Err z3bra.org 70 i+ var s int Err z3bra.org 70 i+ err := rows.Scan(&b, &v, &s) Err z3bra.org 70 i+ if err != nil { Err z3bra.org 70 i+ return "" Err z3bra.org 70 i+ } Err z3bra.org 70 i+ badges.WriteString(fmt.Sprintf("%s %s (%d pts)\n", b, v, s)) Err z3bra.org 70 i+ } Err z3bra.org 70 i+ Err z3bra.org 70 i+ return badges.String(); Err z3bra.org 70 i+} Err z3bra.org 70 i+ Err z3bra.org 70 i func (p *Player) RankStr() string { Err z3bra.org 70 i return humanize.Ordinal(p.ScoreRank() + 1) Err z3bra.org 70 i } Err z3bra.org 70 it@@ -221,7 +249,7 @@ func (p *Player) FromToken(token string) error { Err z3bra.org 70 i return err Err z3bra.org 70 i } Err z3bra.org 70 i hash := base32.StdEncoding.EncodeToString(dk) Err z3bra.org 70 i- query := `SELECT name,flag,score,ts FROM score WHERE hash = ?` Err z3bra.org 70 i+ query := `SELECT name,flag,score,ts FROM user WHERE hash = ?` Err z3bra.org 70 i Err z3bra.org 70 i row := p.db.QueryRow(query, hash) Err z3bra.org 70 i err = row.Scan(&p.name, &p.flag, &p.score, &p.ts) Err z3bra.org 70 1diff --git a/playerbox.go b/playerbox.go /scm/scoreboard/file/playerbox.go.gph z3bra.org 70 it@@ -16,19 +16,18 @@ type PlayerBox struct { Err z3bra.org 70 i } Err z3bra.org 70 i Err z3bra.org 70 i const ( Err z3bra.org 70 i- TOKEN_WELCOME string = `%s, your progression has Err z3bra.org 70 i-been saved. To update it, Err z3bra.org 70 i-you will need this token: Err z3bra.org 70 i+ TOKEN_WELCOME string = ` Err z3bra.org 70 i+%s, your registration is Err z3bra.org 70 i+now complete. To update Err z3bra.org 70 i+your progression, you Err z3bra.org 70 i+will need this token: Err z3bra.org 70 i Err z3bra.org 70 i 🔑%s Err z3bra.org 70 i Err z3bra.org 70 i-Save it. Err z3bra.org 70 i-Do not share it. Err z3bra.org 70 i Err z3bra.org 70 i-Tokens are single-use. Err z3bra.org 70 i-A new token is generated Err z3bra.org 70 i-and displayed each time Err z3bra.org 70 i-you submit a flag. Err z3bra.org 70 i+ Err z3bra.org 70 i+Save it carefully. Err z3bra.org 70 i+Do not share it. Err z3bra.org 70 i ` Err z3bra.org 70 i ) Err z3bra.org 70 i Err z3bra.org 70 it@@ -125,7 +124,7 @@ func PlayerBoxGrid(p *Player, rank int) *tview.Grid { Err z3bra.org 70 i playerbox.score = gridcell(fmt.Sprintf("%5d ", p.score)) Err z3bra.org 70 i Err z3bra.org 70 i grid := tview.NewGrid(). Err z3bra.org 70 i- SetColumns(4,4,6,7). Err z3bra.org 70 i+ SetColumns(5,4,6,7). Err z3bra.org 70 i SetGap(0, 2). Err z3bra.org 70 i SetRows(1). Err z3bra.org 70 i AddItem(gridcell(rankstr), 0, 0, 1, 1, 0, 0, false). Err z3bra.org 70 1diff --git a/ui.go b/ui.go /scm/scoreboard/file/ui.go.gph z3bra.org 70 it@@ -3,6 +3,7 @@ package main Err z3bra.org 70 i import ( Err z3bra.org 70 i "fmt" Err z3bra.org 70 i "math" Err z3bra.org 70 i+ "regexp" Err z3bra.org 70 i "github.com/gdamore/tcell/v2" Err z3bra.org 70 i "github.com/rivo/tview" Err z3bra.org 70 i "github.com/dustin/go-humanize" Err z3bra.org 70 it@@ -171,3 +172,48 @@ func (a *Application) Fatal(err error) { Err z3bra.org 70 i Err z3bra.org 70 i a.pages.AddAndSwitchToPage("popup", p, true) Err z3bra.org 70 i } Err z3bra.org 70 i+ Err z3bra.org 70 i+func (a *Application) Token(callback func()) tview.Primitive { Err z3bra.org 70 i+ input := tview.NewInputField(). Err z3bra.org 70 i+ SetLabel("TOKEN "). Err z3bra.org 70 i+ SetPlaceholder(""). Err z3bra.org 70 i+ SetFieldStyle(tcell.StyleDefault.Reverse(true)). Err z3bra.org 70 i+ SetFieldWidth(30) Err z3bra.org 70 i+ Err z3bra.org 70 i+ input.SetAcceptanceFunc(func(text string, ch rune) bool { Err z3bra.org 70 i+ if len(text) > 24 { Err z3bra.org 70 i+ return false Err z3bra.org 70 i+ } Err z3bra.org 70 i+ Err z3bra.org 70 i+ // tokens are base32 strings Err z3bra.org 70 i+ matched, err := regexp.Match(`^[A-Z2-7]+$`, []byte(text)) Err z3bra.org 70 i+ if err != nil { Err z3bra.org 70 i+ panic(err) Err z3bra.org 70 i+ } Err z3bra.org 70 i+ return matched Err z3bra.org 70 i+ }) Err z3bra.org 70 i+ input.SetDoneFunc(func(key tcell.Key) { Err z3bra.org 70 i+ if key != tcell.KeyEnter { Err z3bra.org 70 i+ return Err z3bra.org 70 i+ } Err z3bra.org 70 i+ Err z3bra.org 70 i+ token := input.GetText() Err z3bra.org 70 i+ Err z3bra.org 70 i+ if len(token) != 24 { Err z3bra.org 70 i+ scoreboard.Popup("ERROR", "Invalid token format") Err z3bra.org 70 i+ return Err z3bra.org 70 i+ } Err z3bra.org 70 i+ err := scoreboard.player.FromToken(token) Err z3bra.org 70 i+ if err != nil { Err z3bra.org 70 i+ scoreboard.Fatal(err) Err z3bra.org 70 i+ return Err z3bra.org 70 i+ } Err z3bra.org 70 i+ Err z3bra.org 70 i+ scoreboard.player.token = token; Err z3bra.org 70 i+ scoreboard.player.Fetch() Err z3bra.org 70 i+ scoreboard.pages.RemovePage("token"); Err z3bra.org 70 i+ callback() Err z3bra.org 70 i+ }) Err z3bra.org 70 i+ Err z3bra.org 70 i+ return center(40, 1, input) Err z3bra.org 70 i+} Err z3bra.org 70 .