package auth import ( "crypto/sha512" "encoding/hex" "log" "net/http" "strconv" "strings" "time" "git.xdrm.io/go/aicra" "git.xdrm.io/go/aicra/api" ) // Service manages the url shortener type Service struct{} // New returns a bare service func New() (*Service, error) { log.Printf("[auth] creating service") log.Printf("[auth] service created") return &Service{}, nil } // Wire to the aicra server func (svc *Service) Wire(server *aicra.Server) { log.Printf("[auth] service wired") server.HandleFunc(http.MethodPost, "/token", svc.generateToken) } // generateToken generates a token valid for 5 mintes func (svc *Service) generateToken(req api.Request, res *api.Response) { // 1. extract input role, err := req.Param.GetString("role") if err != nil { res.SetError(api.ErrorInvalidParam(), "role", err.Error()) return } // 2. generate token hasher := sha512.New() defer hasher.Reset() hasher.Write([]byte(strconv.FormatInt(time.Now().Unix(), 5))) token := hex.EncodeToString(hasher.Sum(nil)) // 3. store token model := NewModel(token, role, 5*time.Minute) if model.Create() != nil { res.SetError(api.ErrorFailure()) return } // 4. return data log.Printf("[auth] new token") res.Data["token"] = token res.SetError(api.ErrorSuccess()) } // CheckToken returns whether a token is valid func (svc *Service) CheckToken(handler api.HandlerFunc) api.HandlerFunc { return func(req api.Request, res *api.Response) { // success if no scope [['admin']] if req.Scope == nil || len(req.Scope) < 1 { handler(req, res) return } headerToken := req.Request.Header.Get("Authorization") // fail if invalid header if len(headerToken) != 128 || strings.ContainsAny(headerToken, "$-_") { res.SetError(api.ErrorToken()) return } model := NewModel(headerToken, "", 0) if model.Search() != nil { res.SetError(api.ErrorToken()) return } // fail if the role of the token does not match any scope for _, scope := range req.Scope { if scope == nil || len(scope) != 1 { continue } // success if scope[0] == model.role { handler(req, res) return } } // failure res.SetError(api.ErrorPermission()) return } }