tmain.go - scoreboard - Interactive scoreboard for CTF-like games
 (HTM) git clone git://git.z3bra.org/scoreboard.git
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
       tmain.go (5149B)
       ---
            1 // Copyright 2016 The Tcell Authors
            2 //
            3 // Licensed under the Apache License, Version 2.0 (the "License");
            4 // you may not use file except in compliance with the License.
            5 // You may obtain a copy of the license at
            6 //
            7 //    http://www.apache.org/licenses/LICENSE-2.0
            8 //
            9 // Unless required by applicable law or agreed to in writing, software
           10 // distributed under the License is distributed on an "AS IS" BASIS,
           11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
           12 // See the License for the specific language governing permissions and
           13 // limitations under the License.
           14 
           15 package main
           16 
           17 import (
           18         "errors"
           19         "flag"
           20         "fmt"
           21         "os"
           22         "strings"
           23         "time"
           24         "database/sql"
           25         "github.com/gdamore/tcell/v2"
           26         "github.com/rivo/tview"
           27 
           28         _ "modernc.org/sqlite"
           29 )
           30 
           31 const (
           32         BOARD_WIDTH int = 28
           33         BOARD_HEIGHT int = 15
           34         HTML string = "scores.html"
           35         TMPL string = "template.html"
           36         DB string = "score.db"
           37         TOKEN_REMINDER string = `%s, use the token below to submit your flags.
           38 Save it carefully, do not share it.
           39 
           40   🔑%s
           41 `
           42         FLAG_SUBMITTED string = `[::-]
           43 You found a flag
           44 worth [::b]%d[::-] points!
           45 
           46 
           47 %s
           48 `
           49 )
           50 
           51 type Flag struct {
           52         id int
           53         value string
           54         badge string
           55         score int
           56 }
           57 
           58 type Application struct {
           59         flag Flag
           60         flag_ref []Flag
           61         db *sql.DB
           62         app *tview.Application
           63         html string
           64         tmpl string
           65         pages *tview.Pages
           66         frame *tview.Frame
           67         board *tview.Flex
           68         player *Player
           69 }
           70 
           71 var scoreboard Application
           72 
           73 func usage() {
           74         fmt.Println("ssh -t score@5r.wtf [FLAG]")
           75         os.Exit(0)
           76 }
           77 
           78 
           79 func checkflag(ref []Flag, flag string) (Flag, error) {
           80         for _, f := range ref {
           81                 if strings.ToUpper(flag) == f.value {
           82                         return f, nil
           83                 }
           84         }
           85         return Flag{}, errors.New("Unknown flag")
           86 }
           87 
           88 func pageBoard() tview.Primitive {
           89         scoreboard.SetupFrame()
           90         scoreboard.DrawBoard()
           91 
           92         // center frame on screen, counting borders + header + footer
           93         return center(BOARD_WIDTH + 2, BOARD_HEIGHT + 7, scoreboard.frame)
           94 }
           95 
           96 func main() {
           97         var err error
           98         var reminder bool = false
           99 
          100         html := flag.String("o", HTML, "Output HTML file")
          101         tmpl := flag.String("t", HTML, "Template HTML file")
          102         db := flag.String("d", DB, "Database file")
          103 
          104         flag.Parse()
          105 
          106         // Override default borders
          107         tview.Borders.HorizontalFocus  = tview.BoxDrawingsLightHorizontal
          108         tview.Borders.VerticalFocus    = tview.BoxDrawingsLightVertical
          109         tview.Borders.TopLeftFocus     = tview.BoxDrawingsLightDownAndRight
          110         tview.Borders.TopRightFocus    = tview.BoxDrawingsLightDownAndLeft
          111         tview.Borders.BottomLeftFocus  = tview.BoxDrawingsLightUpAndRight
          112         tview.Borders.BottomRightFocus = tview.BoxDrawingsLightUpAndLeft
          113 
          114         // Set default colors
          115         tview.Styles.PrimitiveBackgroundColor = tcell.ColorDefault
          116         tview.Styles.BorderColor              = tcell.ColorDefault
          117         tview.Styles.TitleColor               = tcell.ColorDefault
          118         tview.Styles.GraphicsColor            = tcell.ColorDefault
          119         tview.Styles.PrimaryTextColor         = tcell.ColorDefault
          120 
          121         scoreboard.db, err = db_init(*db)
          122         if err != nil {
          123                 panic(err)
          124         }
          125         defer scoreboard.db.Close()
          126 
          127         scoreboard.flag_ref, err = db_get_flags(scoreboard.db)
          128 
          129         scoreboard.flag = Flag{}
          130         scoreboard.html = *html
          131         scoreboard.tmpl = *tmpl
          132         scoreboard.app = tview.NewApplication()
          133         scoreboard.pages = tview.NewPages()
          134         scoreboard.board = tview.NewFlex()
          135         scoreboard.player = &Player{
          136                 db: scoreboard.db,
          137                 id: -1,
          138                 token: "",
          139                 name: "",
          140                 flags: make([]Flag,0),
          141                 score: 0,
          142                 ts: time.Now().Unix(),
          143         }
          144 
          145         scoreboard.pages.SetBackgroundColor(tcell.ColorDefault)
          146 
          147         scoreboard.pages.AddPage("board",  pageBoard(), true, false)
          148 
          149         args := flag.Args()
          150 
          151         if len(args) > 1 {
          152                 usage()
          153         }
          154         if len(args) == 0 {
          155                 scoreboard.pages.SwitchToPage("board")
          156                 scoreboard.DrawBoard()
          157         }
          158 
          159         if len(args) == 1 {
          160                 switch args[0] {
          161                 case "help":
          162                         usage()
          163                 case "refresh":
          164                         scoreboard.GenerateHTML()
          165                         os.Exit(0)
          166 
          167                 case "register":
          168                         rank, _ := db_count_players(scoreboard.db)
          169                         scoreboard.NewPlayer(rank + 1)
          170                         scoreboard.pages.SwitchToPage("board")
          171                         reminder = true
          172 
          173                 /* anything not a command is treated as a flag */
          174                 default:
          175                         scoreboard.flag, err = checkflag(scoreboard.flag_ref, args[0])
          176                         if err != nil {
          177                                 fmt.Println("Incorrect flag")
          178                                 return
          179                         }
          180 
          181                         page := scoreboard.Token(func () {
          182                                 err = scoreboard.player.Submit(scoreboard.flag)
          183                                 if err != nil {
          184                                         scoreboard.Fatal(err)
          185                                         return
          186                                 }
          187                                 scoreboard.HighlightBoard(scoreboard.player.Rank() + 1)
          188                                 scoreboard.pages.RemovePage("token")
          189                                 scoreboard.GenerateHTML()
          190                                 collection := strings.Replace(scoreboard.player.BadgeStr(),
          191                                         scoreboard.flag.badge,
          192                                         fmt.Sprintf("[::l]%s[::-]", scoreboard.flag.badge), -1)
          193                                 scoreboard.Popup("CONGRATULATIONS",
          194                                         fmt.Sprintf(FLAG_SUBMITTED,
          195                                         scoreboard.flag.score, collection))
          196                         })
          197 
          198                         scoreboard.pages.AddAndSwitchToPage("token", page, true)
          199                 }
          200         }
          201 
          202         /* Run application */
          203         if err := scoreboard.app.SetRoot(scoreboard.pages, true).EnableMouse(true).Run(); err != nil {
          204                 fmt.Println(err)
          205                 os.Exit(1)
          206         }
          207 
          208         /* Print a token reminder on exit in case one has been generated or provided */
          209         if reminder && scoreboard.player.token != "" {
          210                 fmt.Printf(TOKEN_REMINDER, scoreboard.player.name, scoreboard.player.token)
          211         }
          212 }