Files
SNCTF/api/submissions.go
2022-06-24 00:48:11 +08:00

214 lines
5.2 KiB
Go

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(&currentScore).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
}
}