ripple-api/app/method.go

113 lines
2.8 KiB
Go
Raw Normal View History

2016-04-03 17:59:27 +00:00
package app
import (
2016-06-16 11:49:35 +00:00
"crypto/md5"
"encoding/json"
2016-06-16 11:49:35 +00:00
"fmt"
2016-04-03 17:59:27 +00:00
"io/ioutil"
"regexp"
2016-04-03 17:59:27 +00:00
2016-04-19 14:07:27 +00:00
"git.zxq.co/ripple/rippleapi/common"
2016-04-03 17:59:27 +00:00
"github.com/gin-gonic/gin"
)
// Method wraps an API method to a HandlerFunc.
func Method(f func(md common.MethodData) common.CodeMessager, privilegesNeeded ...int) gin.HandlerFunc {
2016-04-03 17:59:27 +00:00
return func(c *gin.Context) {
initialCaretaker(c, f, privilegesNeeded...)
}
}
2016-04-03 17:59:27 +00:00
func initialCaretaker(c *gin.Context, f func(md common.MethodData) common.CodeMessager, privilegesNeeded ...int) {
data, err := ioutil.ReadAll(c.Request.Body)
if err != nil {
c.Error(err)
}
c.Request.Body.Close()
2016-04-03 17:59:27 +00:00
token := ""
switch {
case c.Request.Header.Get("X-Ripple-Token") != "":
token = c.Request.Header.Get("X-Ripple-Token")
case c.Query("token") != "":
token = c.Query("token")
case c.Query("k") != "":
token = c.Query("k")
default:
token, _ = c.Cookie("X-Ripple-Token")
}
2016-06-16 11:49:35 +00:00
c.Set("token", fmt.Sprintf("%x", md5.Sum([]byte(token))))
2016-04-03 17:59:27 +00:00
md := common.MethodData{
DB: db,
RequestData: data,
C: c,
}
if token != "" {
tokenReal, exists := GetTokenFull(token, db)
if exists {
md.User = tokenReal
2016-04-03 17:59:27 +00:00
}
}
2016-04-03 17:59:27 +00:00
missingPrivileges := 0
for _, privilege := range privilegesNeeded {
if int(md.User.Privileges)&privilege == 0 {
missingPrivileges |= privilege
2016-04-03 17:59:27 +00:00
}
}
if missingPrivileges != 0 {
2016-04-16 16:05:24 +00:00
c.IndentedJSON(401, common.SimpleResponse(401, "You don't have the privilege(s): "+common.Privileges(missingPrivileges).String()+"."))
return
}
resp := f(md)
2016-04-16 16:05:24 +00:00
if resp.GetCode() == 0 {
// Dirty hack to set the code
type setCoder interface {
SetCode(int)
}
if newver, can := resp.(setCoder); can {
newver.SetCode(500)
}
}
if _, exists := c.GetQuery("pls200"); exists {
c.Writer.WriteHeader(200)
} else {
2016-04-16 16:05:24 +00:00
c.Writer.WriteHeader(resp.GetCode())
}
if _, exists := c.GetQuery("callback"); exists {
c.Header("Content-Type", "application/javascript; charset=utf-8")
} else {
c.Header("Content-Type", "application/json; charset=utf-8")
}
mkjson(c, resp)
}
// Very restrictive, but this way it shouldn't completely fuck up.
var callbackJSONP = regexp.MustCompile(`^[a-zA-Z_\$][a-zA-Z0-9_\$]*$`)
// mkjson auto indents json, and wraps json into a jsonp callback if specified by the request.
// then writes to the gin.Context the data.
func mkjson(c *gin.Context, data interface{}) {
exported, err := json.MarshalIndent(data, "", "\t")
if err != nil {
c.Error(err)
exported = []byte(`{ "code": 500, "message": "something has gone really really really really really really wrong.", "data": null }`)
}
cb := c.Query("callback")
willcb := cb != "" &&
len(cb) < 100 &&
callbackJSONP.MatchString(cb)
if willcb {
c.Writer.Write([]byte("/**/ typeof " + cb + " === 'function' && " + cb + "("))
}
c.Writer.Write(exported)
if willcb {
c.Writer.Write([]byte(");"))
}
2016-04-03 17:59:27 +00:00
}