Files
nkode-core/handler/handler.go

398 lines
9.8 KiB
Go

package handler
import (
"errors"
"git.infra.nkode.tech/dkelly/nkode-core/api"
"git.infra.nkode.tech/dkelly/nkode-core/config"
"git.infra.nkode.tech/dkelly/nkode-core/entities"
"git.infra.nkode.tech/dkelly/nkode-core/models"
"git.infra.nkode.tech/dkelly/nkode-core/security"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
"log"
"strings"
)
type NkodeHandler struct {
API api.NKodeAPI
Logger *log.Logger
}
const (
malformedCustomerId = "malformed customer id"
malformedUserEmail = "malformed user email"
malformedSessionId = "malformed session id"
invalidKeypadDimensions = "invalid keypad dimensions"
)
func (h *NkodeHandler) RegisterRoutes(r *gin.Engine) {
r.Group("/v1/nkode")
{
r.POST("/create-new-customer", h.CreateNewCustomerHandler)
r.POST("/signup", h.SignupHandler)
r.POST("/set-nkode", h.SetNKodeHandler)
r.POST("/confirm-nkode", h.ConfirmNKodeHandler)
r.POST("/get-login-interface", h.GetLoginInterfaceHandler)
r.POST("/login", h.LoginHandler)
r.POST("/renew-attributes", h.RenewAttributesHandler)
r.POST("/random-svg-interface", h.RandomSvgInterfaceHandler)
r.POST("/refresh-token", h.RefreshTokenHandler)
r.POST("/forgot-nkode", h.ForgotNKodeHandler)
r.POST("/signout", h.SignoutHandler)
r.POST("/reset-nkode", h.ResetHandler)
}
}
func (h *NkodeHandler) CreateNewCustomerHandler(c *gin.Context) {
h.Logger.Println("create new customer")
var newCustomerPost entities.NKodePolicy
if err := c.ShouldBind(&newCustomerPost); err != nil {
handleError(c, err)
return
}
customerId, err := h.API.CreateNewCustomer(newCustomerPost)
if err != nil {
c.String(500, "Internal Server Error")
return
}
h.Logger.Println("create new customer")
c.JSON(200, gin.H{"customer_id": entities.CustomerIdToString(*customerId)})
}
func (h *NkodeHandler) SignupHandler(c *gin.Context) {
h.Logger.Println("generate signup reset interface")
var postBody models.SignupPostBody
if err := c.ShouldBind(&postBody); err != nil {
handleError(c, err)
return
}
kp := entities.KeypadDimension{
AttrsPerKey: postBody.AttrsPerKey,
NumbOfKeys: postBody.NumbOfKeys,
}
if err := kp.IsValidKeypadDimension(); err != nil {
c.String(400, invalidKeypadDimensions)
return
}
customerId, err := uuid.Parse(postBody.CustomerId)
if err != nil {
c.String(400, malformedCustomerId)
return
}
userEmail, err := entities.ParseEmail(postBody.UserEmail)
if err != nil {
c.String(400, malformedUserEmail)
return
}
resp, err := h.API.GenerateSignupResetInterface(userEmail, entities.CustomerId(customerId), kp, false)
if err != nil {
handleError(c, err)
return
}
c.JSON(200, resp)
}
func (h *NkodeHandler) SetNKodeHandler(c *gin.Context) {
h.Logger.Println("set nkode")
var postBody models.SetNKodePost
if err := c.ShouldBindJSON(&postBody); err != nil {
handleError(c, err)
return
}
customerId, err := uuid.Parse(postBody.CustomerId)
if err != nil {
c.String(400, malformedCustomerId)
return
}
sessionId, err := uuid.Parse(postBody.SessionId)
if err != nil {
c.String(400, malformedSessionId)
return
}
confirmInterface, err := h.API.SetNKode(entities.CustomerId(customerId), entities.SessionId(sessionId), postBody.KeySelection)
if err != nil {
handleError(c, err)
return
}
resp := models.SetNKodeResp{UserInterface: confirmInterface}
c.JSON(200, resp)
}
func (h *NkodeHandler) ConfirmNKodeHandler(c *gin.Context) {
h.Logger.Println("confirm nkode")
var postBody models.ConfirmNKodePost
if err := c.ShouldBindJSON(&postBody); err != nil {
handleError(c, err)
return
}
customerId, err := uuid.Parse(postBody.CustomerId)
if err != nil {
c.String(400, malformedCustomerId)
return
}
sessionId, err := uuid.Parse(postBody.SessionId)
if err != nil {
c.String(400, malformedSessionId)
return
}
if err := h.API.ConfirmNKode(entities.CustomerId(customerId), entities.SessionId(sessionId), postBody.KeySelection); err != nil {
handleError(c, err)
return
}
c.Status(200)
}
func (h *NkodeHandler) GetLoginInterfaceHandler(c *gin.Context) {
h.Logger.Println("get login interface")
var loginInterfacePost models.LoginInterfacePost
if err := c.ShouldBind(&loginInterfacePost); err != nil {
handleError(c, err)
return
}
customerId, err := uuid.Parse(loginInterfacePost.CustomerId)
if err != nil {
c.String(400, malformedCustomerId)
return
}
userEmail, err := entities.ParseEmail(loginInterfacePost.UserEmail)
if err != nil {
c.String(400, malformedUserEmail)
return
}
postBody, err := h.API.GetLoginInterface(userEmail, entities.CustomerId(customerId))
if err != nil {
handleError(c, err)
return
}
c.JSON(200, postBody)
}
func (h *NkodeHandler) LoginHandler(c *gin.Context) {
h.Logger.Println("login")
var loginPost models.LoginPost
if err := c.ShouldBindJSON(&loginPost); err != nil {
handleError(c, err)
return
}
customerId, err := uuid.Parse(loginPost.CustomerId)
if err != nil {
c.String(400, malformedCustomerId)
return
}
userEmail, err := entities.ParseEmail(loginPost.UserEmail)
if err != nil {
c.String(400, malformedUserEmail)
return
}
jwtToken, err := h.API.Login(entities.CustomerId(customerId), userEmail, loginPost.KeySelection)
if err != nil {
handleError(c, err)
return
}
c.JSON(200, jwtToken)
}
func (h *NkodeHandler) RenewAttributesHandler(c *gin.Context) {
h.Logger.Println("renew attributes")
var renewAttributesPost models.RenewAttributesPost
if err := c.ShouldBind(&renewAttributesPost); err != nil {
handleError(c, err)
return
}
customerId, err := uuid.Parse(renewAttributesPost.CustomerId)
if err != nil {
c.String(400, malformedCustomerId)
return
}
if err = h.API.RenewAttributes(entities.CustomerId(customerId)); err != nil {
handleError(c, err)
return
}
c.Status(200)
}
func (h *NkodeHandler) RandomSvgInterfaceHandler(c *gin.Context) {
h.Logger.Println("random svg interface")
svgs, err := h.API.RandomSvgInterface()
if err != nil {
handleError(c, err)
return
}
resp := models.RandomSvgInterfaceResp{Svgs: svgs}
c.JSON(200, resp)
}
func (h *NkodeHandler) RefreshTokenHandler(c *gin.Context) {
h.Logger.Println("refresh token")
refreshToken, err := getBearerToken(c)
if err != nil {
c.String(403, "forbidden")
return
}
refreshClaims, err := security.ParseRegisteredClaimToken(refreshToken)
customerId, err := uuid.Parse(refreshClaims.Issuer)
if err != nil {
c.String(400, malformedCustomerId)
return
}
userEmail, err := entities.ParseEmail(refreshClaims.Subject)
if err != nil {
c.String(400, malformedUserEmail)
return
}
accessToken, err := h.API.RefreshToken(userEmail, entities.CustomerId(customerId), refreshToken)
if err != nil {
handleError(c, err)
return
}
c.JSON(200, gin.H{"access_token": accessToken})
}
func (h *NkodeHandler) ForgotNKodeHandler(c *gin.Context) {
h.Logger.Println("forgot nkode")
var forgotNKodePost models.ForgotNKodePost
if err := c.ShouldBind(&forgotNKodePost); err != nil {
handleError(c, err)
return
}
customerId, err := uuid.Parse(forgotNKodePost.CustomerId)
if err != nil {
c.String(400, malformedCustomerId)
return
}
userEmail, err := entities.ParseEmail(forgotNKodePost.UserEmail)
if err != nil {
c.String(400, malformedUserEmail)
return
}
if err := h.API.ForgotNKode(userEmail, entities.CustomerId(customerId)); err != nil {
handleError(c, err)
return
}
c.Status(200)
}
func (h *NkodeHandler) SignoutHandler(c *gin.Context) {
h.Logger.Println("signout")
token, err := getBearerToken(c)
if err != nil {
c.String(403, "forbidden")
return
}
accessClaims, err := security.ParseRegisteredClaimToken(token)
if err != nil {
handleError(c, err)
return
}
customerId, err := uuid.Parse(accessClaims.Issuer)
if err != nil {
c.String(400, malformedCustomerId)
return
}
userEmail, err := entities.ParseEmail(accessClaims.Subject)
if err != nil {
c.String(400, malformedUserEmail)
return
}
if err = h.API.Signout(userEmail, entities.CustomerId(customerId)); err != nil {
handleError(c, err)
return
}
c.Status(200)
}
func (h *NkodeHandler) ResetHandler(c *gin.Context) {
h.Logger.Println("reset")
token, err := getBearerToken(c)
if err != nil {
c.String(403, "forbidden")
return
}
resetClaims, err := security.ParseRestNKodeToken(token)
if err != nil {
handleError(c, err)
return
}
var postBody models.SignupPostBody
if err = c.ShouldBind(&postBody); err != nil {
handleError(c, err)
return
}
customerId, err := uuid.Parse(postBody.CustomerId)
if err != nil {
c.String(400, malformedCustomerId)
return
}
userEmail, err := entities.ParseEmail(postBody.UserEmail)
if err != nil {
c.String(400, malformedUserEmail)
return
}
if postBody.UserEmail != resetClaims.Subject ||
postBody.CustomerId != resetClaims.Issuer {
c.String(403, "forbidden")
return
}
kp := entities.KeypadDimension{
AttrsPerKey: postBody.AttrsPerKey,
NumbOfKeys: postBody.NumbOfKeys,
}
if err := kp.IsValidKeypadDimension(); err != nil {
c.String(400, invalidKeypadDimensions)
return
}
resp, err := h.API.GenerateSignupResetInterface(userEmail, entities.CustomerId(customerId), kp, true)
if err != nil {
handleError(c, err)
return
}
c.JSON(200, resp)
}
func handleError(c *gin.Context, err error) {
log.Print("handling error: ", err)
statusCode, _ := config.HttpErrMap[err]
switch statusCode {
case 400:
c.String(400, err.Error())
case 403:
c.String(403, err.Error())
case 500:
c.String(500, "Internal Server Error")
default:
log.Print("unknown error: ", err)
c.String(500, "Internal Server Error")
}
}
func getBearerToken(c *gin.Context) (string, error) {
authHeader := c.GetHeader("Authorization")
// Check if the Authorization header is present and starts with "Bearer "
if authHeader == "" || !strings.HasPrefix(authHeader, "Bearer ") {
return "", errors.New("forbidden")
}
token := strings.TrimPrefix(authHeader, "Bearer ")
return token, nil
}