tFix flag submission - scoreboard - Interactive scoreboard for CTF-like games
(HTM) git clone git://git.z3bra.org/scoreboard.git
(DIR) Log
(DIR) Files
(DIR) Refs
---
(DIR) commit 307cde02b7be14d34c37e7f02eeaea907d1c0d84
(DIR) parent cc20e9fc44c4a724943a4eb8d8a1edb741ecbb39
(HTM) Author: Willy Goiffon <contact@z3bra.org>
Date: Thu, 26 Sep 2024 00:11:35 +0200
Fix flag submission
Diffstat:
M db.go | 26 ++++++++++++++++++++++++++
M main.go | 28 +++++++++++++++-------------
M player.go | 46 ++++++++++++++++++++++---------
M ui.go | 4 +---
4 files changed, 75 insertions(+), 29 deletions(-)
---
(DIR) diff --git a/db.go b/db.go
t@@ -74,6 +74,32 @@ func db_count_players(db *sql.DB) (int, error) {
return count, err
}
+func db_count_user_flags(db *sql.DB, name string) (int, error) {
+ var count int
+
+ query := `SELECT count(*) FROM score WHERE name = ?;`
+
+ row := db.QueryRow(query, name)
+ err := row.Scan(&count)
+
+ return count, err
+}
+
+func db_calculate_user_score(db *sql.DB, name string) (int, error) {
+ var count int
+
+ query := `SELECT
+ sum(flag.score)
+ FROM flag
+ INNER JOIN score ON score.flag = flag.value
+ WHERE score.name = ?;`
+
+ row := db.QueryRow(query, name)
+ err := row.Scan(&count)
+
+ return count, err
+}
+
func db_get_flags(db *sql.DB) ([]Flag, error) {
query := `SELECT rowid,value,badge,score FROM flag ORDER BY score;`
(DIR) diff --git a/main.go b/main.go
t@@ -24,7 +24,6 @@ import (
"database/sql"
"github.com/gdamore/tcell/v2"
"github.com/rivo/tview"
- "github.com/dustin/go-humanize"
_ "modernc.org/sqlite"
)
t@@ -34,7 +33,7 @@ const (
BOARD_HEIGHT int = 15
HTML string = "score.html"
DB string = "score.db"
- TOKEN_REMINDER string = `%s, use the token below to submit your %s flag.
+ TOKEN_REMINDER string = `%s, use the token below to submit your next flag.
Save it carefully, do not share it.
🔑%s
t@@ -49,7 +48,7 @@ type Flag struct {
}
type Application struct {
- flag int
+ flag string
flag_ref []Flag
db *sql.DB
app *tview.Application
t@@ -101,22 +100,26 @@ func pageToken() tview.Primitive {
return
}
- if len(input.GetText()) != 24 {
+ token := input.GetText()
+
+ if len(token) != 24 {
scoreboard.Popup("ERROR", "Invalid token format")
return
}
- err := scoreboard.player.FromToken(input.GetText())
+ err := scoreboard.player.FromToken(token)
if err != nil {
scoreboard.Fatal(err)
return
}
+ scoreboard.player.token = token;
+
err = scoreboard.player.Submit(scoreboard.flag)
if err != nil {
scoreboard.Fatal(err)
return
}
- scoreboard.HighlightBoard(scoreboard.player.ScoreRank())
+ scoreboard.HighlightBoard(scoreboard.player.ScoreRank() + 1)
scoreboard.pages.SwitchToPage("board")
scoreboard.GenerateHTML()
})
t@@ -163,7 +166,7 @@ func main() {
scoreboard.flag_ref, err = db_get_flags(scoreboard.db)
- scoreboard.flag = 0
+ scoreboard.flag = ""
scoreboard.html = *html
scoreboard.app = tview.NewApplication()
scoreboard.pages = tview.NewPages()
t@@ -196,13 +199,12 @@ func main() {
scoreboard.NewPlayer(rank + 1)
scoreboard.pages.SwitchToPage("board")
} else {
- switch scoreboard.flag = flagid(args[0]) + 1; scoreboard.flag {
- case 0:
+ if flagid(args[0]) < 0 {
fmt.Println("Incorrect flag")
return
- default:
- scoreboard.pages.SwitchToPage("token")
}
+ scoreboard.flag = args[0]
+ scoreboard.pages.SwitchToPage("token")
}
} else {
scoreboard.pages.SwitchToPage("board")
t@@ -214,7 +216,7 @@ func main() {
os.Exit(1)
}
- if scoreboard.player.token != "" && scoreboard.flag < 7 {
- fmt.Printf(TOKEN_REMINDER, scoreboard.player.name, humanize.Ordinal(scoreboard.flag + 1), scoreboard.player.token)
+ if scoreboard.player.token != "" {
+ fmt.Printf(TOKEN_REMINDER, scoreboard.player.name, scoreboard.player.token)
}
}
(DIR) diff --git a/player.go b/player.go
t@@ -76,7 +76,7 @@ func (p *Player) Register() error {
return err
}
- query := `INSERT INTO score(name,hash,ts) VALUES(?,?,?);`
+ query := `INSERT INTO user(name,hash,score,flag,ts) VALUES(?,?,0,0,?);`
_, err = p.db.Exec(query, p.name, hash, p.ts)
if err != nil {
return err
t@@ -104,11 +104,21 @@ func (p *Player) Fetch() error {
return nil
}
-func (p *Player) Refresh(score int, flag int, ts int64) error {
+func (p *Player) Refresh(ts int64) error {
var err error
+ p.flag, err = db_count_user_flags(p.db, p.name)
+ if err != nil {
+ return err
+ }
+
+ p.score, err = db_calculate_user_score(p.db, p.name)
+ if err != nil {
+ return err
+ }
+
query := `UPDATE user SET score = ?, flag = ?, ts = ? WHERE name = ?;`
- _, err = p.db.Exec(query, score, flag, ts, p.name)
+ _, err = p.db.Exec(query, p.score, p.flag, ts, p.name)
if err != nil {
return err
}
t@@ -161,20 +171,30 @@ func (p *Player) Exists() bool {
return (count > 0)
}
-func (p *Player) Submit(flag int) error {
+func (p *Player) HasFlag(flag string) bool {
+ var count int
+ query := `SELECT count(*) FROM score WHERE name = ? AND flag = ?;`
+ row := p.db.QueryRow(query, p.name, flag)
+ row.Scan(&count)
+ return (count > 0)
+}
+
+func (p *Player) Submit(flag string) error {
+ var err error
var ts int64
- var score int
- var flags int
- // TODO: check flag existence
- // TODO: check flag already submitted
- // TODO: retrieve flag score
- ts = time.Now().Unix()
- score = p.score // + flag_score
- flags = p.flag + 1
+ if p.HasFlag(flag) {
+ return errors.New("Flag already submitted")
+ } else {
+ query := `INSERT INTO score(name,flag) VALUES(?,?);`
+ _, err = p.db.Exec(query, p.name, flag)
+ if err != nil {
+ return err
+ }
+ }
// update user status in database
- err := p.Refresh(score, flags, ts)
+ err = p.Refresh(ts)
if err != nil {
return err
}
(DIR) diff --git a/ui.go b/ui.go
t@@ -107,9 +107,7 @@ func (a *Application) HighlightBoard(line int) {
AddItem(RankTable(0, -1, 0, true).Select(line - 1, 0), BOARD_HEIGHT, 1, true)
a.app.SetFocus(a.board)
- if (a.flag < 7) {
- a.frame.AddText(fmt.Sprintf(" 🔑%s", a.player.token), false, tview.AlignCenter, 0)
- }
+ a.frame.AddText(fmt.Sprintf(" 🔑%s", a.player.token), false, tview.AlignCenter, 0)
}
func (a *Application) NewPlayer(rank int) {