itAdd tokens verification to submit flags - 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 02405c1d3835605e574f366f6b4fea04dcfae822 /scm/scoreboard/commit/02405c1d3835605e574f366f6b4fea04dcfae822.gph z3bra.org 70 1parent d4209a84c73bef28336b2f1f63b39181f7dfc8da /scm/scoreboard/commit/d4209a84c73bef28336b2f1f63b39181f7dfc8da.gph z3bra.org 70 hAuthor: Willy Goiffon URL:mailto:contact@z3bra.org z3bra.org 70 iDate: Wed, 7 Dec 2022 09:01:10 +0100 Err z3bra.org 70 i Err z3bra.org 70 iAdd tokens verification to submit flags Err z3bra.org 70 i Err z3bra.org 70 iDiffstat: Err z3bra.org 70 i M db.go | 51 ++++++++----------------------- Err z3bra.org 70 i M go.mod | 1 + Err z3bra.org 70 i M go.sum | 1 + Err z3bra.org 70 i M main.go | 37 +++++++++++++++++++++++++------ Err z3bra.org 70 i M player.go | 105 +++++++++++++++++++++++-------- Err z3bra.org 70 i M playerbox.go | 9 ++++++--- Err z3bra.org 70 i M ui.go | 23 ++++++++++++++++------- Err z3bra.org 70 i D util.go | 49 ------------------------------- Err z3bra.org 70 i Err z3bra.org 70 i8 files changed, 147 insertions(+), 129 deletions(-) Err z3bra.org 70 i--- Err z3bra.org 70 1diff --git a/db.go b/db.go /scm/scoreboard/file/db.go.gph z3bra.org 70 it@@ -22,33 +22,14 @@ import ( Err z3bra.org 70 i const ( Err z3bra.org 70 i // DB queries Err z3bra.org 70 i DB_CREATE string = ` Err z3bra.org 70 i- CREATE TABLE IF NOT EXISTS score(id INTEGER PRIMARY KEY, name TEXT, token TEXT, flag INT, score INT, ts INT); Err z3bra.org 70 i- ` Err z3bra.org 70 i- DB_FILL string = ` Err z3bra.org 70 i- DELETE FROM score; Err z3bra.org 70 i- INSERT INTO score(name,token,flag,score,ts) VALUES ('WGS', 'token0', 3, 302, 2); Err z3bra.org 70 i- INSERT INTO score(name,token,flag,score,ts) VALUES ('DQK', 'token1', 5, 1337, 20); Err z3bra.org 70 i- INSERT INTO score(name,token,flag,score,ts) VALUES ('VNM', 'token2', 5, 1000, 3); Err z3bra.org 70 i- INSERT INTO score(name,token,flag,score,ts) VALUES ('PLR', 'token3', 5, 1000, 2); Err z3bra.org 70 i- INSERT INTO score(name,token,flag,score,ts) VALUES ('UKN', 'token4', 2, 200, 200); Err z3bra.org 70 i- INSERT INTO score(name,token,flag,score,ts) VALUES ('JFK', 'token5', 3, 300, 200); Err z3bra.org 70 i- INSERT INTO score(name,token,flag,score,ts) VALUES ('AAA', 'token6', 1, 130, 1670260535); Err z3bra.org 70 i- INSERT INTO score(name,token,flag,score,ts) VALUES ('BBB', 'token7', 4, 400, 1670260535); Err z3bra.org 70 i- INSERT INTO score(name,token,flag,score,ts) VALUES ('CCC', 'token8', 4, 400, 1670260535); Err z3bra.org 70 i- INSERT INTO score(name,token,flag,score,ts) VALUES ('DDD', 'token9', 4, 407, 1670260535); Err z3bra.org 70 i- INSERT INTO score(name,token,flag,score,ts) VALUES ('EEE', 'tokenA', 4, 405, 1670260535); Err z3bra.org 70 i- INSERT INTO score(name,token,flag,score,ts) VALUES ('FFF', 'tokenB', 4, 401, 1670260535); Err z3bra.org 70 i- INSERT INTO score(name,token,flag,score,ts) VALUES ('GGG', 'tokenC', 4, 406, 1670260535); Err z3bra.org 70 i- INSERT INTO score(name,token,flag,score,ts) VALUES ('HHH', 'tokenD', 4, 408, 1670260445); Err z3bra.org 70 i- INSERT INTO score(name,token,flag,score,ts) VALUES ('III', 'tokenE', 4, 409, 1670260435); Err z3bra.org 70 i- INSERT INTO score(name,token,flag,score,ts) VALUES ('JJJ', 'tokenF', 4, 402, 1670260535); Err z3bra.org 70 i- INSERT INTO score(name,token,flag,score,ts) VALUES ('KKK', 'tokenG', 4, 400, 1670260535); Err z3bra.org 70 i- INSERT INTO score(name,token,flag,score,ts) VALUES ('LLL', 'tokenH', 4, 404, 1670260535); Err z3bra.org 70 i- INSERT INTO score(name,token,flag,score,ts) VALUES ('MMM', 'tokenI', 4, 403, 1670260535); Err z3bra.org 70 i- INSERT INTO score(name,token,flag,score,ts) VALUES ('NNN', 'tokenJ', 4, 400, 1670260535); Err z3bra.org 70 i- INSERT INTO score(name,token,flag,score,ts) VALUES ('OOO', 'tokenK', 4, 400, 1670260535); Err z3bra.org 70 i- INSERT INTO score(name,token,flag,score,ts) VALUES ('PPP', 'tokenL', 4, 400, 1670260535); Err z3bra.org 70 i- ` Err z3bra.org 70 i+ CREATE TABLE IF NOT EXISTS Err z3bra.org 70 i+ score( Err z3bra.org 70 i+ hash TEXT, Err z3bra.org 70 i+ name TEXT, Err z3bra.org 70 i+ flag INT, Err z3bra.org 70 i+ score INT, Err z3bra.org 70 i+ ts INT Err z3bra.org 70 i+ );` Err z3bra.org 70 i ) Err z3bra.org 70 i Err z3bra.org 70 i Err z3bra.org 70 it@@ -67,18 +48,12 @@ func db_init(file string) (*sql.DB, error) { Err z3bra.org 70 i if err != nil { Err z3bra.org 70 i return nil, err Err z3bra.org 70 i } Err z3bra.org 70 i- ///* Err z3bra.org 70 i- _, err = db.Exec(DB_FILL) 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- //*/ Err z3bra.org 70 i return db, nil Err z3bra.org 70 i } Err z3bra.org 70 i Err z3bra.org 70 i func db_count(db *sql.DB) int { Err z3bra.org 70 i var count int Err z3bra.org 70 i- query := `SELECT count(id) FROM score;` Err z3bra.org 70 i+ query := `SELECT count(*) FROM score;` Err z3bra.org 70 i row := db.QueryRow(query) Err z3bra.org 70 i row.Scan(&count) Err z3bra.org 70 i return count Err z3bra.org 70 it@@ -102,7 +77,7 @@ func db_score_count(db *sql.DB, score, ts int) int { Err z3bra.org 70 i func db_flag_count(db *sql.DB, flag int) int { Err z3bra.org 70 i var count int Err z3bra.org 70 i query := `SELECT Err z3bra.org 70 i- count(id) Err z3bra.org 70 i+ count(*) Err z3bra.org 70 i FROM score Err z3bra.org 70 i WHERE Err z3bra.org 70 i flag >= ? Err z3bra.org 70 it@@ -116,7 +91,7 @@ func db_flag_count(db *sql.DB, flag int) int { Err z3bra.org 70 i func db_id(db *sql.DB, nick string) bool { Err z3bra.org 70 i var count int Err z3bra.org 70 i query := `SELECT Err z3bra.org 70 i- count(id) Err z3bra.org 70 i+ count(*) Err z3bra.org 70 i FROM score Err z3bra.org 70 i WHERE Err z3bra.org 70 i name = ? Err z3bra.org 70 it@@ -129,7 +104,7 @@ func db_id(db *sql.DB, nick string) bool { Err z3bra.org 70 i Err z3bra.org 70 i func db_ranked_players(db *sql.DB, offset, limit int) ([]Player, error) { Err z3bra.org 70 i query := `SELECT Err z3bra.org 70 i- id,name,token,flag,score Err z3bra.org 70 i+ name,flag,score Err z3bra.org 70 i FROM score Err z3bra.org 70 i ORDER BY Err z3bra.org 70 i score DESC, Err z3bra.org 70 it@@ -147,7 +122,7 @@ func db_ranked_players(db *sql.DB, offset, limit int) ([]Player, error) { Err z3bra.org 70 i players := make([]Player, 0) Err z3bra.org 70 i for rows.Next() { Err z3bra.org 70 i var p Player Err z3bra.org 70 i- err := rows.Scan(&p.id, &p.name, &p.token, &p.flag, &p.score) Err z3bra.org 70 i+ err := rows.Scan(&p.name, &p.flag, &p.score) Err z3bra.org 70 i if err != nil { Err z3bra.org 70 i return nil, err Err z3bra.org 70 i } Err z3bra.org 70 1diff --git a/go.mod b/go.mod /scm/scoreboard/file/go.mod.gph z3bra.org 70 it@@ -9,6 +9,7 @@ require ( Err z3bra.org 70 i Err z3bra.org 70 i require ( Err z3bra.org 70 i github.com/dustin/go-humanize v1.0.0 Err z3bra.org 70 i+ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 Err z3bra.org 70 i modernc.org/sqlite v1.20.0 Err z3bra.org 70 i ) Err z3bra.org 70 i Err z3bra.org 70 1diff --git a/go.sum b/go.sum /scm/scoreboard/file/go.sum.gph z3bra.org 70 it@@ -28,6 +28,7 @@ github.com/rivo/uniseg v0.4.2/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUc Err z3bra.org 70 i github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= Err z3bra.org 70 i golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= Err z3bra.org 70 i golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= Err z3bra.org 70 i+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= Err z3bra.org 70 i golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= Err z3bra.org 70 i golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= Err z3bra.org 70 i golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= Err z3bra.org 70 1diff --git a/main.go b/main.go /scm/scoreboard/file/main.go.gph z3bra.org 70 it@@ -32,6 +32,13 @@ const ( Err z3bra.org 70 i BOARD_WIDTH int = 26 Err z3bra.org 70 i BOARD_HEIGHT int = 15 Err z3bra.org 70 i DB string = "leaderboard.db" Err z3bra.org 70 i+ TOKEN_REMINDER string = `TOKEN FOR %s: %s Err z3bra.org 70 i+ Err z3bra.org 70 i+This token will be requested when you submit flag #%d. Err z3bra.org 70 i+Save it carefully, and do not share it with anyone. Err z3bra.org 70 i+ Err z3bra.org 70 i+Good bye hunter. Good luck. Err z3bra.org 70 i+` Err z3bra.org 70 i ) Err z3bra.org 70 i Err z3bra.org 70 i type Application struct { Err z3bra.org 70 it@@ -41,7 +48,7 @@ type Application struct { Err z3bra.org 70 i pages *tview.Pages Err z3bra.org 70 i frame *tview.Grid Err z3bra.org 70 i board *tview.Flex Err z3bra.org 70 i- player Player Err z3bra.org 70 i+ player *Player Err z3bra.org 70 i } Err z3bra.org 70 i Err z3bra.org 70 i var flag_sha256 = [...]string { Err z3bra.org 70 it@@ -60,7 +67,7 @@ var flag_sha256 = [...]string { Err z3bra.org 70 i var cyboard Application Err z3bra.org 70 i Err z3bra.org 70 i func usage() { Err z3bra.org 70 i- fmt.Println("ssh board@cyb.farm [flag SHA256]") Err z3bra.org 70 i+ fmt.Println("ssh board@cyb.farm [FLAG]") Err z3bra.org 70 i os.Exit(0) Err z3bra.org 70 i } Err z3bra.org 70 i Err z3bra.org 70 it@@ -79,16 +86,29 @@ func pageToken() tview.Primitive { 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(28) 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- matched, err := regexp.Match(`^[a-zA-Z0-9]+$`, []byte(text)) 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+ if len(input.GetText()) != 24 { Err z3bra.org 70 i+ cyboard.Popup("ERROR", "Invalid token format") Err z3bra.org 70 i+ return Err z3bra.org 70 i+ } Err z3bra.org 70 i err := cyboard.player.FromToken(input.GetText()) Err z3bra.org 70 i if err != nil { Err z3bra.org 70 i cyboard.Fatal(err) Err z3bra.org 70 it@@ -136,7 +156,6 @@ func main() { 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- cyboard.player.db = cyboard.db Err z3bra.org 70 i defer cyboard.db.Close() Err z3bra.org 70 i Err z3bra.org 70 i cyboard.flag = 0 Err z3bra.org 70 it@@ -144,7 +163,7 @@ func main() { Err z3bra.org 70 i cyboard.pages = tview.NewPages() Err z3bra.org 70 i cyboard.frame = tview.NewGrid() Err z3bra.org 70 i cyboard.board = tview.NewFlex() Err z3bra.org 70 i- cyboard.player.id = -1 Err z3bra.org 70 i+ cyboard.player = &Player{ db: cyboard.db } Err z3bra.org 70 i Err z3bra.org 70 i cyboard.pages.SetBackgroundColor(tcell.ColorDefault) Err z3bra.org 70 i Err z3bra.org 70 it@@ -173,7 +192,7 @@ func main() { Err z3bra.org 70 i cyboard.NewPlayer(rank) Err z3bra.org 70 i cyboard.pages.SwitchToPage("board") Err z3bra.org 70 i case 2,3,4,5: Err z3bra.org 70 i- cyboard.pages.ShowPage("token") Err z3bra.org 70 i+ cyboard.pages.SwitchToPage("token") Err z3bra.org 70 i default: Err z3bra.org 70 i fmt.Println("Incorrect flag") Err z3bra.org 70 i return Err z3bra.org 70 it@@ -186,4 +205,8 @@ func main() { Err z3bra.org 70 i if err := cyboard.app.SetRoot(cyboard.pages, true).EnableMouse(true).Run(); err != nil { Err z3bra.org 70 i panic(err) Err z3bra.org 70 i } Err z3bra.org 70 i+ Err z3bra.org 70 i+ if cyboard.player.token != "" && cyboard.flag < (len(flag_sha256)) { Err z3bra.org 70 i+ fmt.Printf(TOKEN_REMINDER, cyboard.player.name, cyboard.player.token, cyboard.flag + 1) 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@@ -15,11 +15,13 @@ Err z3bra.org 70 i package main Err z3bra.org 70 i Err z3bra.org 70 i import ( Err z3bra.org 70 i+ "crypto/rand" Err z3bra.org 70 i+ "database/sql" Err z3bra.org 70 i+ "encoding/base32" Err z3bra.org 70 i "errors" Err z3bra.org 70 i "fmt" Err z3bra.org 70 i "time" Err z3bra.org 70 i- "database/sql" Err z3bra.org 70 i- //"golang.org/x/crypto/argon2" Err z3bra.org 70 i+ "golang.org/x/crypto/scrypt" Err z3bra.org 70 i "github.com/dustin/go-humanize" Err z3bra.org 70 i Err z3bra.org 70 i _ "modernc.org/sqlite" Err z3bra.org 70 it@@ -27,49 +29,85 @@ import ( Err z3bra.org 70 i Err z3bra.org 70 i type Player struct { Err z3bra.org 70 i db *sql.DB Err z3bra.org 70 i- id int Err z3bra.org 70 i- name string Err z3bra.org 70 i token string Err z3bra.org 70 i+ name string Err z3bra.org 70 i flag int Err z3bra.org 70 i score int Err z3bra.org 70 i ts int64 Err z3bra.org 70 i } Err z3bra.org 70 i Err z3bra.org 70 i-func (p *Player) Register() int64 { Err z3bra.org 70 i- query := `INSERT INTO score(name,token,flag,score,ts) VALUES(?,?,?,?,?);` Err z3bra.org 70 i- r, err := p.db.Exec(query, p.name, p.token, p.flag, p.score, p.ts) Err z3bra.org 70 i+func randbuf(length int64) []byte { Err z3bra.org 70 i+ b := make([]byte, length) Err z3bra.org 70 i+ _, err := rand.Read(b) 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 b Err z3bra.org 70 i+} Err z3bra.org 70 i+ Err z3bra.org 70 i+func tokenize(name string) (string, string, error) { Err z3bra.org 70 i+ key := randbuf(12) Err z3bra.org 70 i+ salt := base32.StdEncoding.EncodeToString([]byte(name)) Err z3bra.org 70 i Err z3bra.org 70 i- id, _ := r.LastInsertId() Err z3bra.org 70 i+ //token := []byte(name) Err z3bra.org 70 i+ //token = append(token, key...) Err z3bra.org 70 i+ token := key Err z3bra.org 70 i+ token = append(token, []byte(name)...) Err z3bra.org 70 i Err z3bra.org 70 i- return id Err z3bra.org 70 i+ // use name as salt Err z3bra.org 70 i+ dk, err := scrypt.Key(key, []byte(salt), 1<<15, 8, 1, 32) Err z3bra.org 70 i+ if err != nil { Err z3bra.org 70 i+ return "", "", err Err z3bra.org 70 i+ } Err z3bra.org 70 i+ hash32 := base32.StdEncoding.EncodeToString(dk) Err z3bra.org 70 i+ token32 := base32.StdEncoding.EncodeToString(token) Err z3bra.org 70 i+ Err z3bra.org 70 i+ return token32, hash32, nil Err z3bra.org 70 i } Err z3bra.org 70 i Err z3bra.org 70 i-func (p *Player) Update() int64 { Err z3bra.org 70 i- query := `UPDATE score SET flag = ?, score = ?, ts = ? WHERE id = ?;` Err z3bra.org 70 i- r, err := p.db.Exec(query, p.flag, p.score, p.ts, p.id) Err z3bra.org 70 i+func (p *Player) Register() error { Err z3bra.org 70 i+ var hash string Err z3bra.org 70 i+ var err error Err z3bra.org 70 i+ p.token, hash, err = tokenize(p.name) Err z3bra.org 70 i if err != nil { Err z3bra.org 70 i- panic(err) Err z3bra.org 70 i+ return err Err z3bra.org 70 i } Err z3bra.org 70 i Err z3bra.org 70 i- id, _ := r.LastInsertId() Err z3bra.org 70 i+ query := `INSERT INTO score(name,hash,flag,score,ts) VALUES(?,?,?,?,?);` Err z3bra.org 70 i+ _, err = p.db.Exec(query, p.name, hash, p.flag, p.score, p.ts) Err z3bra.org 70 i+ if err != nil { Err z3bra.org 70 i+ return err Err z3bra.org 70 i+ } Err z3bra.org 70 i+ Err z3bra.org 70 i+ return nil Err z3bra.org 70 i+} Err z3bra.org 70 i+ Err z3bra.org 70 i+func (p *Player) Update() error { Err z3bra.org 70 i+ var hash string Err z3bra.org 70 i+ var err error Err z3bra.org 70 i+ p.token, hash, err = tokenize(p.name) Err z3bra.org 70 i+ if err != nil { Err z3bra.org 70 i+ return err Err z3bra.org 70 i+ } Err z3bra.org 70 i+ query := `UPDATE score SET hash = ?, flag = ?, score = ?, ts = ? WHERE name = ?;` Err z3bra.org 70 i+ _, err = p.db.Exec(query, hash, p.flag, p.score, p.ts, p.name) Err z3bra.org 70 i+ if err != nil { Err z3bra.org 70 i+ return err Err z3bra.org 70 i+ } Err z3bra.org 70 i Err z3bra.org 70 i- return id Err z3bra.org 70 i+ return nil Err z3bra.org 70 i } Err z3bra.org 70 i Err z3bra.org 70 i func (p *Player) ScoreRank() int { Err z3bra.org 70 i var count int Err z3bra.org 70 i query := `SELECT Err z3bra.org 70 i- count(id) Err z3bra.org 70 i+ count(*) Err z3bra.org 70 i FROM score Err z3bra.org 70 i WHERE Err z3bra.org 70 i- score >= ? AND Err z3bra.org 70 i- ts <= ? Err z3bra.org 70 i+ score >= ? OR (score == ? AND ts <= ?) Err z3bra.org 70 i ;` Err z3bra.org 70 i Err z3bra.org 70 i- row := p.db.QueryRow(query, p.score, p.ts) Err z3bra.org 70 i+ row := p.db.QueryRow(query, p.score, p.score, p.ts) Err z3bra.org 70 i row.Scan(&count) Err z3bra.org 70 i return count Err z3bra.org 70 i } Err z3bra.org 70 it@@ -77,7 +115,7 @@ func (p *Player) ScoreRank() int { Err z3bra.org 70 i func (p *Player) FlagRank() int { Err z3bra.org 70 i var count int Err z3bra.org 70 i query := `SELECT Err z3bra.org 70 i- count(id) Err z3bra.org 70 i+ count(*) Err z3bra.org 70 i FROM score Err z3bra.org 70 i WHERE Err z3bra.org 70 i flag >= ? Err z3bra.org 70 it@@ -128,7 +166,7 @@ func (p *Player) Submit(flag int) error { Err z3bra.org 70 i } Err z3bra.org 70 i Err z3bra.org 70 i if flag != p.flag + 1 { Err z3bra.org 70 i- return errors.New(fmt.Sprintf("Missing %s flag", humanize.Ordinal(p.flag + 1))) Err z3bra.org 70 i+ return errors.New(fmt.Sprintf("Missing %s flag for %s", humanize.Ordinal(p.flag + 1), p.name)) Err z3bra.org 70 i } Err z3bra.org 70 i Err z3bra.org 70 i p.ts = time.Now().Unix() Err z3bra.org 70 it@@ -145,12 +183,29 @@ func (p *Player) Submit(flag int) error { Err z3bra.org 70 i } Err z3bra.org 70 i Err z3bra.org 70 i func (p *Player) FromToken(token string) error { Err z3bra.org 70 i- query := `SELECT id,name,token,flag,score,ts FROM score WHERE token = ?` Err z3bra.org 70 i+ var err error Err z3bra.org 70 i+ blob, err := base32.StdEncoding.DecodeString(token) Err z3bra.org 70 i+ if err != nil { Err z3bra.org 70 i+ return err Err z3bra.org 70 i+ } Err z3bra.org 70 i+ Err z3bra.org 70 i+ key := blob[:12] Err z3bra.org 70 i+ p.name = string(blob[12:]) Err z3bra.org 70 i+ Err z3bra.org 70 i+ salt := base32.StdEncoding.EncodeToString([]byte(p.name)) Err z3bra.org 70 i+ Err z3bra.org 70 i+ // use player id as salt Err z3bra.org 70 i+ dk, err := scrypt.Key(key, []byte(salt), 1<<15, 8, 1, 32) Err z3bra.org 70 i+ if err != nil { 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 name = ? AND hash = ?` Err z3bra.org 70 i Err z3bra.org 70 i- row := p.db.QueryRow(query, token) Err z3bra.org 70 i- err := row.Scan(&p.id, &p.name, &p.token, &p.flag, &p.score, &p.ts) Err z3bra.org 70 i+ row := p.db.QueryRow(query, p.name, hash) Err z3bra.org 70 i+ err = row.Scan(&p.name, &p.flag, &p.score, &p.ts) Err z3bra.org 70 i if err == sql.ErrNoRows { Err z3bra.org 70 i- return errors.New("Unmatched token") Err z3bra.org 70 i+ return errors.New("Invalid token") Err z3bra.org 70 i } Err z3bra.org 70 i Err z3bra.org 70 i return nil Err z3bra.org 70 1diff --git a/playerbox.go b/playerbox.go /scm/scoreboard/file/playerbox.go.gph z3bra.org 70 it@@ -59,7 +59,7 @@ func manipulatebox(event *tcell.EventKey) *tcell.EventKey { Err z3bra.org 70 i return event Err z3bra.org 70 i } Err z3bra.org 70 i Err z3bra.org 70 i-func PlayerBoxName(p Player) *tview.TextView { Err z3bra.org 70 i+func PlayerBoxName(p *Player) *tview.TextView { Err z3bra.org 70 i v := tview.NewTextView(). Err z3bra.org 70 i SetDynamicColors(true). Err z3bra.org 70 i SetTextAlign(tview.AlignRight). Err z3bra.org 70 it@@ -71,7 +71,10 @@ func PlayerBoxName(p Player) *tview.TextView { Err z3bra.org 70 i if key == tcell.KeyEnter { Err z3bra.org 70 i p.name = fmt.Sprintf("%3s", playerbox.name) Err z3bra.org 70 i if ! p.Exists() { Err z3bra.org 70 i- p.Register() Err z3bra.org 70 i+ err := p.Register() Err z3bra.org 70 i+ if err != nil { Err z3bra.org 70 i+ cyboard.Fatal(err) Err z3bra.org 70 i+ } Err z3bra.org 70 i cyboard.HighlightBoard(p.ScoreRank()) Err z3bra.org 70 i } else { Err z3bra.org 70 i cyboard.Popup("NOPE", "Player name unavailable\nPlease pick another one") Err z3bra.org 70 it@@ -88,7 +91,7 @@ func PlayerBoxName(p Player) *tview.TextView { Err z3bra.org 70 i return v Err z3bra.org 70 i } Err z3bra.org 70 i Err z3bra.org 70 i-func PlayerBoxGrid(p Player, rank int) *tview.Grid { Err z3bra.org 70 i+func PlayerBoxGrid(p *Player, rank int) *tview.Grid { Err z3bra.org 70 i gridcell := func (text string) *tview.TextView { Err z3bra.org 70 i return tview.NewTextView(). Err z3bra.org 70 i SetDynamicColors(true). Err z3bra.org 70 1diff --git a/ui.go b/ui.go /scm/scoreboard/file/ui.go.gph z3bra.org 70 it@@ -102,10 +102,10 @@ func (a *Application) NewPlayer(rank int) { Err z3bra.org 70 i } else { Err z3bra.org 70 i offset = 0 Err z3bra.org 70 i t1_sz = rank - 1 Err z3bra.org 70 i- t2_sz = BOARD_HEIGHT - rank - 1 Err z3bra.org 70 i+ t2_sz = BOARD_HEIGHT - rank Err z3bra.org 70 i } Err z3bra.org 70 i t1 := RankTable(offset, t1_sz, rank - t1_sz - 1, false).SetSelectable(false, false) Err z3bra.org 70 i- t2 := RankTable(rank - 1, BOARD_HEIGHT, t2_sz, true).SetSelectable(false, false) Err z3bra.org 70 i+ t2 := RankTable(rank - 1, BOARD_HEIGHT, rank, true).SetSelectable(false, false) Err z3bra.org 70 i box := PlayerBoxGrid(a.player, rank) Err z3bra.org 70 i Err z3bra.org 70 i a.board.Clear(). Err z3bra.org 70 it@@ -115,7 +115,7 @@ func (a *Application) NewPlayer(rank int) { Err z3bra.org 70 i AddItem(t2, t2_sz, 0, false) Err z3bra.org 70 i } Err z3bra.org 70 i Err z3bra.org 70 i-func popup(title, text string, callback func(key tcell.Key)) tview.Primitive { Err z3bra.org 70 i+func popup(title, text string, w, h int, callback func(key tcell.Key)) tview.Primitive { Err z3bra.org 70 i p := tview.NewTextView(). Err z3bra.org 70 i SetDynamicColors(true). Err z3bra.org 70 i SetTextAlign(tview.AlignCenter). Err z3bra.org 70 it@@ -123,16 +123,25 @@ func popup(title, text string, callback func(key tcell.Key)) tview.Primitive { Err z3bra.org 70 i SetDoneFunc(callback) Err z3bra.org 70 i Err z3bra.org 70 i popup := tview.NewFrame(p). Err z3bra.org 70 i- SetBorders(7, 0, 0, 0, 1, 1). Err z3bra.org 70 i+ SetBorders(1, 0, 0, 0, 1, 1). Err z3bra.org 70 i AddText("PRESS ENTER", false, tview.AlignRight, tcell.ColorGray) Err z3bra.org 70 i Err z3bra.org 70 i popup.SetBorder(true).SetTitle(fmt.Sprintf(" %s ", title)) Err z3bra.org 70 i Err z3bra.org 70 i- return center(28, 19, popup) Err z3bra.org 70 i+ return center(w, h, popup) Err z3bra.org 70 i+} Err z3bra.org 70 i+ Err z3bra.org 70 i+func (a *Application) Message(title, text string) { Err z3bra.org 70 i+ //p := popup(title, text, 52, 19, func(key tcell.Key) { Err z3bra.org 70 i+ p := popup(title, text, 64, 19, func(key tcell.Key) { Err z3bra.org 70 i+ a.pages.RemovePage("popup") Err z3bra.org 70 i+ }) 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) Popup(title, text string) { Err z3bra.org 70 i- p := popup(title, text, func(key tcell.Key) { Err z3bra.org 70 i+ p := popup(title, text, 28, 19, func(key tcell.Key) { Err z3bra.org 70 i a.pages.RemovePage("popup") Err z3bra.org 70 i }) Err z3bra.org 70 i Err z3bra.org 70 it@@ -140,7 +149,7 @@ func (a *Application) Popup(title, text string) { Err z3bra.org 70 i } Err z3bra.org 70 i Err z3bra.org 70 i func (a *Application) Fatal(err error) { Err z3bra.org 70 i- p := popup("ERROR", fmt.Sprintf("%s", err), func(key tcell.Key) { Err z3bra.org 70 i+ p := popup("ERROR", fmt.Sprintf("%s", err), 28, 19, func(key tcell.Key) { Err z3bra.org 70 i a.app.Stop() Err z3bra.org 70 i }) Err z3bra.org 70 i Err z3bra.org 70 1diff --git a/util.go b/util.go /scm/scoreboard/file/util.go.gph z3bra.org 70 it@@ -1,49 +0,0 @@ Err z3bra.org 70 i-package main Err z3bra.org 70 i- Err z3bra.org 70 i-import ( Err z3bra.org 70 i- "fmt" Err z3bra.org 70 i- "strings" Err z3bra.org 70 i- "github.com/rivo/tview" Err z3bra.org 70 i-) Err z3bra.org 70 i- Err z3bra.org 70 i-func flagid(hash string) int { Err z3bra.org 70 i- for i := 0; i "XXX.." Err z3bra.org 70 i-func flag2str(n int) string { Err z3bra.org 70 i- var flags [5]byte Err z3bra.org 70 i- for i:=0; i