/*
 * Arc - Copyleft of Simone 'evilsocket' Margaritelli.
 * evilsocket at protonmail dot com
 * https://www.evilsocket.net/
 *
 * See LICENSE.
 */
package middlewares

import (
	"regexp"
	"strings"
	"time"

	"github.com/evilsocket/arc/config"
	"github.com/evilsocket/arc/events"
	"github.com/evilsocket/arc/utils"
	"github.com/evilsocket/islazy/log"
	"github.com/gin-gonic/gin"
	"github.com/golang-jwt/jwt/v5"
)

var authTokenParser = regexp.MustCompile("^(?i)Bearer:\\s*(.+)$")

func GenerateToken(k []byte, userId string) (string, error) {
	// Create the token
	token := jwt.New(jwt.SigningMethodHS256)
	// Set some claims
	claims := make(jwt.MapClaims)
	claims["user_id"] = userId
	claims["exp"] = time.Now().Add(time.Minute * time.Duration(config.Conf.TokenDuration)).Unix()
	token.Claims = claims
	// Sign and get the complete encoded token as a string
	tokenString, err := token.SignedString(k)
	return tokenString, err
}

func ValidateToken(t string, k string) (*jwt.Token, error) {
	token, err := jwt.Parse(t, func(token *jwt.Token) (interface{}, error) {
		return []byte(k), nil
	})

	return token, err
}

func AuthHandler() gin.HandlerFunc {
	return func(c *gin.Context) {
		user_id := c.GetString("user_id")
		// do we need to refresh session data?
		if user_id != config.Conf.Username {
			// Parse bearer token from Authorization header.
			authorization := c.Request.Header.Get("Authorization")
			m := authTokenParser.FindStringSubmatch(authorization)
			if len(m) != 2 {
				events.Add(events.InvalidToken(strings.Split(c.Request.RemoteAddr, ":")[0],
					authorization,
					nil))

				utils.Forbidden(c)
				return
			}
			// Validate token
			token := m[1]
			valid, err := ValidateToken(token, config.Conf.Secret)
			if err != nil {
				utils.Api(log.WARNING, c, "Error while validating bearer token: %s", err)
				events.Add(events.InvalidToken(strings.Split(c.Request.RemoteAddr, ":")[0],
					token,
					err))
				utils.Forbidden(c)
				return
			}

			// set session data
			c.Set("user_id", valid.Claims.(jwt.MapClaims)["user_id"])
		}

		c.Next()
	}
}
