split checker from token-validator

This commit is contained in:
nemunaire 2020-03-27 14:57:14 +01:00
parent 685dc0b0ea
commit 0c661f36f6
20 changed files with 634 additions and 748 deletions

View file

@ -1,37 +1,36 @@
package main
import (
"crypto/hmac"
"crypto/sha512"
"encoding/json"
"fmt"
"log"
"strings"
"time"
"github.com/julienschmidt/httprouter"
"git.nemunai.re/lectures/adlin/libadlin"
)
func init() {
router.GET("/api/progress", apiHandler(
func(httprouter.Params, []byte) (interface{}, error) {
if stds, err := getStudents(); err != nil {
if stds, err := adlin.GetStudents(); err != nil {
return nil, err
} else {
ret := map[string]map[string]UnlockedChallenge{}
ret := map[string]map[string]adlin.UnlockedChallenge{}
for _, std := range stds {
if sts, err := std.getStates(); err == nil {
ret[std.Login] = map[string]UnlockedChallenge{}
if sts, err := std.GetStates(); err == nil {
ret[std.Login] = map[string]adlin.UnlockedChallenge{}
for _, s := range sts {
ret[std.Login][fmt.Sprintf("%d", s.Challenge)] = s
}
if pongs, err := std.lastPongs(); err == nil && len(pongs) > 0 {
ret[std.Login]["ping"] = UnlockedChallenge{
if pongs, err := std.LastPongs(); err == nil && len(pongs) > 0 {
ret[std.Login]["ping"] = adlin.UnlockedChallenge{
IdStudent: std.Id,
Time: pongs[0].Date,
Value: pongs[0].State,
Time: pongs[0].Date,
Value: pongs[0].State,
}
} else if err != nil {
log.Println(err)
@ -43,23 +42,23 @@ func init() {
}))
router.GET("/api/students/", apiHandler(
func(httprouter.Params, []byte) (interface{}, error) {
return getStudents()
return adlin.GetStudents()
}))
router.POST("/api/students/", remoteValidatorHandler(apiHandler(createStudent)))
router.GET("/api/students/:sid/", apiHandler(studentHandler(
func(std Student, _ []byte) (interface{}, error) {
func(std adlin.Student, _ []byte) (interface{}, error) {
return std, nil
})))
router.PUT("/api/students/:sid/", remoteValidatorHandler(apiHandler(studentHandler(updateStudent))))
router.DELETE("/api/students/:sid/", remoteValidatorHandler(apiHandler(studentHandler(
func(std Student, _ []byte) (interface{}, error) {
func(std adlin.Student, _ []byte) (interface{}, error) {
return std.Delete()
}))))
router.GET("/api/students/:sid/progress", apiHandler(studentHandler(
func(std Student, _ []byte) (interface{}, error) {
ret := map[string]UnlockedChallenge{}
func(std adlin.Student, _ []byte) (interface{}, error) {
ret := map[string]adlin.UnlockedChallenge{}
if sts, err := std.getStates(); err == nil {
if sts, err := std.GetStates(); err == nil {
for _, s := range sts {
ret[fmt.Sprintf("%d", s.Challenge)] = s
}
@ -69,102 +68,12 @@ func init() {
})))
}
type Student struct {
Id int64 `json:"id"`
Login string `json:"login"`
Time *time.Time `json:"time"`
IP *string `json:"ip"`
MAC *string `json:"mac"`
}
type uploadedStudent struct {
Login string `json:"login"`
IP string `json:"ip"`
MAC string `json:"mac"`
}
func getStudents() (students []Student, err error) {
if rows, errr := DBQuery("SELECT S.id_student, S.login, MAX(L.time), L.ip, L.mac FROM students S INNER JOIN (SELECT a.id_student, a.time, a.ip, a.mac FROM student_login a INNER JOIN (SELECT id_student, MAX(time) AS time FROM student_login GROUP BY id_student) b ON a.id_student = b.id_student AND a.time = b.time) L ON S.id_student = L.id_student GROUP BY id_student"); errr != nil {
return nil, errr
} else {
defer rows.Close()
for rows.Next() {
var s Student
if err = rows.Scan(&s.Id, &s.Login, &s.Time, &s.IP, &s.MAC); err != nil {
return
}
students = append(students, s)
}
if err = rows.Err(); err != nil {
return
}
return
}
}
func getStudent(id int) (s Student, err error) {
err = DBQueryRow("SELECT S.id_student, S.login, MAX(L.time), L.ip, L.mac FROM students S INNER JOIN (SELECT a.id_student, a.time, a.ip, a.mac FROM student_login a INNER JOIN (SELECT id_student, MAX(time) AS time FROM student_login GROUP BY id_student) b ON a.id_student = b.id_student AND a.time = b.time) L ON S.id_student = L.id_student WHERE S.id_student=?", id).Scan(&s.Id, &s.Login, &s.Time, &s.IP, &s.MAC)
return
}
func getStudentByLogin(login string) (s Student, err error) {
err = DBQueryRow("SELECT S.id_student, S.login, MAX(L.time), L.ip, L.mac FROM students S INNER JOIN (SELECT a.id_student, a.time, a.ip, a.mac FROM student_login a INNER JOIN (SELECT id_student, MAX(time) AS time FROM student_login GROUP BY id_student) b ON a.id_student = b.id_student AND a.time = b.time) L ON S.id_student = L.id_student WHERE login=?", login).Scan(&s.Id, &s.Login, &s.Time, &s.IP, &s.MAC)
return
}
func studentExists(login string) bool {
var z int
err := DBQueryRow("SELECT 1 FROM students WHERE login=?", login).Scan(&z)
return err == nil && z == 1
}
func NewStudent(login string) (Student, error) {
t := time.Now()
if res, err := DBExec("INSERT INTO students (login, time) VALUES (?, ?)", login, t); err != nil {
return Student{}, err
} else if sid, err := res.LastInsertId(); err != nil {
return Student{}, err
} else {
return Student{sid, login, &t, nil, nil}, nil
}
}
func (s Student) GetPKey() []byte {
return hmac.New(sha512.New512_224, []byte(sharedSecret)).Sum([]byte(s.Login))
}
func (s Student) Update() (int64, error) {
if res, err := DBExec("UPDATE students SET login = ?, time = ? WHERE id_student = ?", s.Login, s.Time, s.Id); err != nil {
return 0, err
} else if nb, err := res.RowsAffected(); err != nil {
return 0, err
} else {
return nb, err
}
}
func (s Student) Delete() (int64, error) {
if res, err := DBExec("DELETE FROM students WHERE id_student = ?", s.Id); err != nil {
return 0, err
} else if nb, err := res.RowsAffected(); err != nil {
return 0, err
} else {
return nb, err
}
}
func ClearStudents() (int64, error) {
if res, err := DBExec("DELETE FROM students"); err != nil {
return 0, err
} else if nb, err := res.RowsAffected(); err != nil {
return 0, err
} else {
return nb, err
}
}
func createStudent(_ httprouter.Params, body []byte) (interface{}, error) {
var err error
var std uploadedStudent
@ -172,22 +81,22 @@ func createStudent(_ httprouter.Params, body []byte) (interface{}, error) {
return nil, err
}
var exist Student
if exist, err = getStudentByLogin(strings.TrimSpace(std.Login)); err != nil {
if exist, err = NewStudent(strings.TrimSpace(std.Login)); err != nil {
var exist adlin.Student
if exist, err = adlin.GetStudentByLogin(strings.TrimSpace(std.Login)); err != nil {
if exist, err = adlin.NewStudent(strings.TrimSpace(std.Login)); err != nil {
return nil, err
}
}
exist.registerAccess(std.IP, std.MAC)
exist.RegisterAccess(std.IP, std.MAC)
ip := fmt.Sprintf("172.23.0.%d", exist.IPSuffix())
ip := fmt.Sprintf("172.23.0.%d", IPSuffix(exist))
exist.IP = &ip
return exist, nil
}
func updateStudent(current Student, body []byte) (interface{}, error) {
var new Student
func updateStudent(current adlin.Student, body []byte) (interface{}, error) {
var new adlin.Student
if err := json.Unmarshal(body, &new); err != nil {
return nil, err
}
@ -196,83 +105,3 @@ func updateStudent(current Student, body []byte) (interface{}, error) {
current.Time = new.Time
return current.Update()
}
type UnlockedChallenge struct {
Id int64 `json:"id,omitempty"`
IdStudent int64 `json:"id_student"`
Challenge int `json:"challenge,omitempty"`
Time time.Time `json:"time"`
Value interface{} `json:"value,omitempty"`
}
func (s Student) getStates() (ucs []UnlockedChallenge, err error) {
if rows, errr := DBQuery("SELECT id_st, challenge, time FROM student_challenges WHERE id_student = ?", s.Id); errr != nil {
return nil, errr
} else {
defer rows.Close()
for rows.Next() {
var u UnlockedChallenge
u.IdStudent = s.Id
if err = rows.Scan(&u.Id, &u.Challenge, &u.Time); err != nil {
return
}
ucs = append(ucs, u)
}
if err = rows.Err(); err != nil {
return
}
return
}
}
func (s Student) getStatesByChallenge() (ucs []UnlockedChallenge, err error) {
if rows, errr := DBQuery("SELECT id_st, challenge, MIN(time), value FROM student_challenges WHERE id_student = ? GROUP BY challenge, id_student", s.Id); errr != nil {
return nil, errr
} else {
defer rows.Close()
for rows.Next() {
var u UnlockedChallenge
u.IdStudent = s.Id
if err = rows.Scan(&u.Id, &u.Challenge, &u.Time, &u.Value); err != nil {
return
}
ucs = append(ucs, u)
}
if err = rows.Err(); err != nil {
return
}
return
}
}
func (s Student) UnlockNewChallenge(challenge int, value string) (UnlockedChallenge, error) {
if res, err := DBExec("INSERT INTO student_challenges (id_student, challenge, time, value) VALUES (?, ?, ?, ?)", s.Id, challenge, time.Now(), value); err != nil {
return UnlockedChallenge{}, err
} else if utid, err := res.LastInsertId(); err != nil {
return UnlockedChallenge{}, err
} else {
return UnlockedChallenge{utid, s.Id, challenge, time.Now(), value}, err
}
}
func (s Student) UpdateUnlockedChallenge(challenge int, value string) (UnlockedChallenge, error) {
if _, err := DBExec("UPDATE student_challenges SET time = ?, value = ? WHERE id_student = ? AND challenge = ?", time.Now(), value, s.Id, challenge); err != nil {
return UnlockedChallenge{}, err
} else {
return UnlockedChallenge{0, s.Id, challenge, time.Now(), value}, err
}
}
func (s Student) registerAccess(ip, mac string) error {
if res, err := DBExec("INSERT INTO student_login (id_student, ip, mac, time) VALUES (?, ?, ?, ?)", s.Id, ip, mac, time.Now()); err != nil {
return err
} else if _, err := res.LastInsertId(); err != nil {
return err
} else {
return err
}
}