// provides jwt encode and decode functions
package jwt

import (
	"crypto/hmac"
	"crypto/sha256"
	"errors"
	"strings"

	"git.clearsky.net.au/cody/gex.git/utils"
	"git.clearsky.net.au/cody/gex.git/utils/base64"
)

// encode json bytes to a jwt token string
func Encode(jsonStr []byte, secret string) (string, error) {

	header := base64.EncodeURL([]byte("{\"alg\":\"HS256\",\"typ\":\"JWT\"}"))
	payload := base64.EncodeURL(jsonStr)
	mac := hmac.New(sha256.New, []byte(secret))
	mac.Write([]byte(header + "." + payload))
	sig := base64.EncodeURL(mac.Sum(nil))

	return header + "." + payload + "." + sig, nil
}

// decode a jwt token string to a json string to be processed
func Decode(tokenStr string, secret string) ([]byte, error) {
	parts := strings.Split(tokenStr, ".")
	if len(parts) < 3 {
		err := errors.New("cannot decode JWT")
		utils.Err(err)
		return []byte(""), err
	}
	header := parts[0]
	payload := parts[1]
	sig, err := base64.DecodeURL(parts[2])
	if err != nil {
		utils.Err(err)
		return []byte(""), err
	}

	mac := hmac.New(sha256.New, []byte(secret))
	mac.Write([]byte(header + "." + payload))
	expectedSig := mac.Sum(nil)

	if !hmac.Equal([]byte(sig), expectedSig) {
		return []byte(""), errors.New("signature don't match")
	}

	jsonStr, err := base64.DecodeURL(payload)

	if err != nil {
		utils.Err(err)
		return []byte(""), err
	}

	return jsonStr, nil
}