You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
114 lines
2.8 KiB
114 lines
2.8 KiB
package utils
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
"strings"
|
|
|
|
"github.com/dustinpianalto/errors"
|
|
"github.com/dustinpianalto/quartermaster"
|
|
"github.com/golang-jwt/jwt"
|
|
"github.com/gorilla/mux"
|
|
)
|
|
|
|
var jwtKey = []byte(os.Getenv("JWT_KEY"))
|
|
|
|
func Mount(r *mux.Router, path string, handler http.Handler) {
|
|
r.PathPrefix(path).Handler(
|
|
http.StripPrefix(
|
|
strings.TrimSuffix(path, "/"),
|
|
handler,
|
|
),
|
|
)
|
|
}
|
|
|
|
type RootHandler func(http.ResponseWriter, *http.Request) error
|
|
|
|
func (rh RootHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
err := rh(w, r)
|
|
if err == nil {
|
|
return
|
|
}
|
|
|
|
log.Println(err)
|
|
|
|
e, ok := err.(*errors.Error)
|
|
if !ok {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
|
|
|
if errors.Is(errors.Permission, e) {
|
|
body := getErrorBody("Permission Denied")
|
|
w.WriteHeader(http.StatusForbidden)
|
|
w.Write(body)
|
|
}
|
|
|
|
if errors.Is(errors.Incorrect, e) && strings.Contains(string(e.Method), "login") {
|
|
body := getErrorBody("Invalid Login Credentials")
|
|
w.WriteHeader(http.StatusUnauthorized)
|
|
w.Write(body)
|
|
}
|
|
|
|
if errors.Is(errors.Incorrect, e) && strings.Contains(string(e.Method), "refresh") {
|
|
body := getErrorBody("Missing or Invalid Cookie")
|
|
w.WriteHeader(http.StatusUnauthorized)
|
|
w.Write(body)
|
|
}
|
|
|
|
if errors.Is(errors.Malformed, e) {
|
|
body := getErrorBody("Bad Request")
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
w.Write(body)
|
|
}
|
|
|
|
if errors.Is(errors.Internal, e) {
|
|
body := getErrorBody("Internal Server Error")
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
w.Write(body)
|
|
}
|
|
|
|
if errors.Is(errors.Conflict, e) && strings.Contains(string(e.Method), "register") {
|
|
body := getErrorBody("User already exists")
|
|
w.WriteHeader(http.StatusConflict)
|
|
w.Write(body)
|
|
}
|
|
}
|
|
|
|
func getErrorBody(s string) []byte {
|
|
return []byte(fmt.Sprintf("{\"error\": \"%s\"}", s))
|
|
}
|
|
|
|
func IsAuthenticated(r *http.Request) (*jwt.Token, error) {
|
|
const method errors.Method = "utils/IsAuthenticated"
|
|
c, err := r.Cookie("token")
|
|
if err != nil {
|
|
if err == http.ErrNoCookie {
|
|
return nil, errors.E(method, errors.Incorrect, "cookie not found", err)
|
|
}
|
|
return nil, errors.E(method, errors.Malformed, "failed to get cookie data", err)
|
|
}
|
|
tknStr := c.Value
|
|
claims := &quartermaster.Claims{}
|
|
tkn, err := jwt.ParseWithClaims(tknStr, claims, func(token *jwt.Token) (interface{}, error) {
|
|
return jwtKey, nil
|
|
})
|
|
if err != nil {
|
|
if err == jwt.ErrSignatureInvalid {
|
|
return nil, errors.E(method, errors.Incorrect, "cookie is invalid", err)
|
|
}
|
|
e, _ := err.(*jwt.ValidationError)
|
|
if e.Inner == jwt.ErrInvalidKeyType {
|
|
return nil, errors.E(method, errors.Internal, err)
|
|
} else if e.Inner == jwt.ErrHashUnavailable {
|
|
return nil, errors.E(method, errors.Internal, err)
|
|
}
|
|
return nil, errors.E(method, errors.Malformed, "failed to parse cookie", err)
|
|
}
|
|
return tkn, nil
|
|
}
|