214 lines
5.2 KiB
Go
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(¤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
|
|
|
|
}
|
|
|
|
}
|