2018-02-20 12:49:03 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2018-02-20 13:55:32 +00:00
|
|
|
"crypto/hmac"
|
|
|
|
"crypto/sha512"
|
|
|
|
"encoding/base64"
|
2018-02-20 12:49:03 +00:00
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"log"
|
|
|
|
"net/http"
|
2018-02-20 13:55:32 +00:00
|
|
|
"strconv"
|
|
|
|
"time"
|
2018-02-20 12:49:03 +00:00
|
|
|
|
|
|
|
"github.com/julienschmidt/httprouter"
|
|
|
|
)
|
|
|
|
|
|
|
|
var router = httprouter.New()
|
|
|
|
|
|
|
|
func Router() *httprouter.Router {
|
|
|
|
return router
|
|
|
|
}
|
|
|
|
|
|
|
|
type DispatchFunction func(httprouter.Params, []byte) (interface{}, error)
|
|
|
|
|
2018-02-20 13:55:32 +00:00
|
|
|
func remoteValidatorHandler(f func(http.ResponseWriter, *http.Request, httprouter.Params)) func(http.ResponseWriter, *http.Request, httprouter.Params) {
|
|
|
|
return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
|
|
|
expectedMAC := hmac.New(sha512.New, []byte(sharedSecret)).Sum([]byte(fmt.Sprintf("%d", time.Now().Unix()/10)))
|
|
|
|
previousMAC := hmac.New(sha512.New, []byte(sharedSecret)).Sum([]byte(fmt.Sprintf("%d", time.Now().Unix()/10-1)))
|
|
|
|
|
|
|
|
if aauth, err := base64.StdEncoding.DecodeString(r.Header.Get("X-ADLIN-Authentication")); err != nil {
|
|
|
|
http.Error(w, fmt.Sprintf("{\"errmsg\":%q}", err), http.StatusUnauthorized)
|
|
|
|
} else if !hmac.Equal(expectedMAC, aauth) && !hmac.Equal(previousMAC, aauth) {
|
|
|
|
http.Error(w, fmt.Sprintf("{\"errmsg\":%q}", "Bad authentication header"), http.StatusUnauthorized)
|
|
|
|
} else {
|
|
|
|
f(w, r, ps)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-20 17:20:07 +00:00
|
|
|
func rawHandler(f func(*http.Request, httprouter.Params, []byte) (interface{}, error)) func(http.ResponseWriter, *http.Request, httprouter.Params) {
|
2018-02-20 12:49:03 +00:00
|
|
|
return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
|
|
|
if addr := r.Header.Get("X-Forwarded-For"); addr != "" {
|
|
|
|
r.RemoteAddr = addr
|
|
|
|
}
|
|
|
|
log.Printf("%s \"%s %s\" [%s]\n", r.RemoteAddr, r.Method, r.URL.Path, r.UserAgent())
|
|
|
|
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
|
|
|
|
|
|
var ret interface{}
|
|
|
|
var err error = nil
|
|
|
|
|
|
|
|
// Read the body
|
|
|
|
if r.ContentLength < 0 || r.ContentLength > 6553600 {
|
|
|
|
http.Error(w, fmt.Sprintf("{errmsg:\"Request too large or request size unknown\"}", err), http.StatusRequestEntityTooLarge)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
var body []byte
|
|
|
|
if r.ContentLength > 0 {
|
|
|
|
tmp := make([]byte, 1024)
|
|
|
|
for {
|
|
|
|
n, err := r.Body.Read(tmp)
|
|
|
|
for j := 0; j < n; j++ {
|
|
|
|
body = append(body, tmp[j])
|
|
|
|
}
|
|
|
|
if err != nil || n <= 0 {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-20 17:20:07 +00:00
|
|
|
ret, err = f(r, ps, body)
|
2018-02-20 12:49:03 +00:00
|
|
|
|
|
|
|
// Format response
|
|
|
|
resStatus := http.StatusOK
|
|
|
|
if err != nil {
|
|
|
|
ret = map[string]string{"errmsg": err.Error()}
|
|
|
|
resStatus = http.StatusBadRequest
|
|
|
|
log.Println(r.RemoteAddr, resStatus, err.Error())
|
|
|
|
}
|
|
|
|
|
|
|
|
if ret == nil {
|
|
|
|
ret = map[string]string{"errmsg": "Page not found"}
|
|
|
|
resStatus = http.StatusNotFound
|
|
|
|
}
|
|
|
|
|
|
|
|
if str, found := ret.(string); found {
|
|
|
|
w.WriteHeader(resStatus)
|
|
|
|
io.WriteString(w, str)
|
|
|
|
} else if bts, found := ret.([]byte); found {
|
|
|
|
w.WriteHeader(resStatus)
|
|
|
|
w.Write(bts)
|
|
|
|
} else if j, err := json.Marshal(ret); err != nil {
|
|
|
|
http.Error(w, fmt.Sprintf("{\"errmsg\":%q}", err), http.StatusInternalServerError)
|
|
|
|
} else {
|
|
|
|
w.WriteHeader(resStatus)
|
|
|
|
w.Write(j)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-02-20 13:55:32 +00:00
|
|
|
|
2018-02-20 17:20:07 +00:00
|
|
|
func apiHandler(f DispatchFunction) func(http.ResponseWriter, *http.Request, httprouter.Params) {
|
|
|
|
return rawHandler(func (_ *http.Request, ps httprouter.Params, b []byte) (interface{}, error) { return f(ps, b) })
|
|
|
|
}
|
|
|
|
|
2018-02-20 13:55:32 +00:00
|
|
|
func studentHandler(f func(Student, []byte) (interface{}, error)) func(httprouter.Params, []byte) (interface{}, error) {
|
|
|
|
return func(ps httprouter.Params, body []byte) (interface{}, error) {
|
|
|
|
if sid, err := strconv.Atoi(string(ps.ByName("sid"))); err != nil {
|
|
|
|
if student, err := getStudentByLogin(ps.ByName("sid")); err != nil {
|
|
|
|
return nil, err
|
|
|
|
} else {
|
|
|
|
return f(student, body)
|
|
|
|
}
|
|
|
|
} else if student, err := getStudent(sid); err != nil {
|
|
|
|
return nil, err
|
|
|
|
} else {
|
|
|
|
return f(student, body)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|