package api import ( "fmt" "github.com/gin-gonic/gin" db "main.go/database" "main.go/tools" . "main.go/type" "math" ) // hasAlreadySolved 检查某道题是否已经被某用户解出。 func hasAlreadySolved(uid int, cid int) (exists bool) { Link() DB := db.DBsnctf err := DB.Raw("SELECT EXISTS(SELECT 1 FROM solve WHERE uid=? AND cid=?)", uid, cid).Scan(&exists).Error if err != nil { return false } return exists } // isChallengeExisted 检查数据库中是否存在某个题目。 func isChallengeExisted(id int) (exists bool) { Link() DB := db.DBsnctf command := "SELECT EXISTS(SELECT 1 FROM challenge WHERE id = ?);" err := DB.Raw(command, id).Scan(&exists).Error if err != nil { return false } return exists } //addSubmission 添加一个提交记录。 func addSubmission(s *Submission) error { Link() DB := db.DBsnctf err := DB.Table("submission").Create(&s).Error if err != nil { return err } return nil } // getFlag 根据题目id获取该题的flag func getFlag(id int) (flag string, err error) { Link() DB := db.DBsnctf err = DB.Table("challenge").Select("flag").Where("id = ?", id).Find(&flag).Error if err != nil { return "", err } return flag, nil } // addSolve 操作数据库加入一条正确的flag提交记录。 func addSolve(s *Solve) error { DB := db.DBsnctf err := DB.Table("solve").Create(&s).Error if err != nil { return err } return nil } // addUserScore 操作数据库为指定用户增加某题的分数。 func addUserScore(username string, cid int) error { var newScore int DB := db.DBsnctf err := DB.Table("challenge").Select("score").Where("id = ?", cid).Find(&newScore).Error if err != nil { return err } command := "UPDATE score SET score=score+? WHERE username=?" err = DB.Exec(command, newScore, username).Error if err != nil { return err } return nil } // updateUserScores 操作数据库更新解出用户的分数。 func updateUserScores(reducedScore, cid int) error { DB := db.DBsnctf command := "UPDATE score SET score=score-? WHERE EXISTS(SELECT 1 FROM user,solve WHERE user.id=solve.uid AND score.username=user.username AND solve.cid=?);" err := DB.Exec(command, reducedScore, cid).Error return err } // editChallengeScore 操作数据库修改指定题目增的动态分数。 func editChallengeScore(cid int) (reducedScore int, err error) { DB := db.DBsnctf var currentScore int err = DB.Table("challenge").Select("score").Where("id = ?", cid).Find(¤tScore).Error command := "SELECT score FROM challenge WHERE id=? LIMIT 1;" if err != nil { return 0, err } solverCount, err := getSolverCount(cid) if err != nil { return 0, err } // According to https://github.com/o-o-overflow/scoring-playground newScore := int(100 + (1000-100)/(1.0+float64(solverCount)*0.04*math.Log(float64(solverCount)))) reducedScore = currentScore - newScore command = "UPDATE challenge SET score=? WHERE id=?;" err = DB.Exec(command, newScore, cid).Error if err != nil { return 0, err } return reducedScore, nil } // SubmitFlag 提交flag func SubmitFlag(c *gin.Context) { var request SubmissionRequest if err := c.ShouldBindJSON(&request); err != nil { c.JSON(400, gin.H{"code": 400, "msg": "Request format wrong!"}) return } session, err := Store.Get(c.Request, "SNCTFSESSID") if err != nil { c.JSON(400, gin.H{"code": 400, "msg": "GET SNCTFSESSID error!"}) return } user, ok := session.Values["user"].(User) if !ok { c.JSON(400, gin.H{"code": 400, "msg": "GET user error!"}) return } // 检查题目是否存在 if !isChallengeExisted(request.Cid) { c.JSON(400, gin.H{"code": 400, "msg": "Challenge not existed!"}) return } // Submission记录 solvedTime := tools.Timestamp() submission := &Submission{ UserID: user.ID, ChallengeID: request.Cid, Flag: request.Flag, IP: c.ClientIP(), Time: solvedTime, } err = addSubmission(submission) if err != nil { c.JSON(400, gin.H{"code": 400, "msg": "Record submission failure!"}) return } // 是否已经解出该题 if hasAlreadySolved(user.ID, request.Cid) { c.JSON(200, gin.H{"code": 400, "msg": "Already solved!"}) return } // 获取flag flag, err := getFlag(request.Cid) if err != nil { fmt.Println(err) c.JSON(200, gin.H{"code": 400, "msg": "Get flag failure!"}) return } // 检查flag是否正确 if flag != request.Flag { c.JSON(200, gin.H{"code": 400, "msg": "Wrong flag!"}) return } else { // Solve记录 solve := &Solve{ UserID: user.ID, ChallengeID: request.Cid, Time: solvedTime, } err = addSolve(solve) if err != nil { c.JSON(200, gin.H{"code": 400, "msg": "Record solve failure!"}) return } //加分 err = addUserScore(user.Username, request.Cid) if err != nil { c.JSON(400, gin.H{"code": 400, "msg": "Add score failure!"}) return } // 题目动态分数 reducedScore, err := editChallengeScore(request.Cid) if err != nil { c.JSON(400, gin.H{"code": 400, "msg": "Edit challenge score failure!"}) return } //更新所有用户分数 err = updateUserScores(reducedScore, request.Cid) if err != nil { c.JSON(400, gin.H{"code": 400, "msg": "Update user scores failure!"}) return } c.JSON(200, gin.H{"code": 200, "msg": "Correct flag!"}) return } }