mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-23 06:45:43 +00:00
initial commit
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
package utils
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// FlagType
|
||||
// -------------------------------------------------------------------
|
||||
type FlagType string
|
||||
|
||||
const (
|
||||
FlagIsActive FlagType = "IS_ACTIVE"
|
||||
)
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Validators
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
func IsValidFlagType(v string) bool {
|
||||
switch FlagType(v) {
|
||||
case FlagIsActive:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// example use
|
||||
|
||||
/**
|
||||
if !utils.IsValidFlagType(req.FlagName) {
|
||||
return fiber.NewError(fiber.StatusBadRequest, "invalid flag type")
|
||||
}
|
||||
*/
|
||||
@@ -0,0 +1,27 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/hafizhproject45/Golang-Boilerplate.git/internal/response"
|
||||
"github.com/hafizhproject45/Golang-Boilerplate.git/internal/validation"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
func ErrorHandler(c *fiber.Ctx, err error) error {
|
||||
if errorsMap := validation.CustomErrorMessages(err); len(errorsMap) > 0 {
|
||||
return response.Error(c, fiber.StatusBadRequest, "Bad Request", errorsMap)
|
||||
}
|
||||
|
||||
var fiberErr *fiber.Error
|
||||
if errors.As(err, &fiberErr) {
|
||||
return response.Error(c, fiberErr.Code, fiberErr.Message, nil)
|
||||
}
|
||||
|
||||
return response.Error(c, fiber.StatusInternalServerError, "Internal Server Error", nil)
|
||||
}
|
||||
|
||||
func NotFoundHandler(c *fiber.Ctx) error {
|
||||
return response.Error(c, fiber.StatusNotFound, "Endpoint Not Found", nil)
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type CustomFormatter struct {
|
||||
logrus.TextFormatter
|
||||
}
|
||||
|
||||
var Log *logrus.Logger
|
||||
|
||||
func init() {
|
||||
Log = logrus.New()
|
||||
|
||||
// Set logger to use the custom text formatter
|
||||
Log.SetFormatter(&CustomFormatter{
|
||||
TextFormatter: logrus.TextFormatter{
|
||||
TimestampFormat: "15:04:05.000",
|
||||
FullTimestamp: true,
|
||||
ForceColors: true,
|
||||
},
|
||||
})
|
||||
|
||||
Log.SetOutput(os.Stdout)
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package utils
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
type NullString struct {
|
||||
Set bool
|
||||
Value *string
|
||||
}
|
||||
|
||||
func (ns *NullString) UnmarshalJSON(b []byte) error {
|
||||
ns.Set = true
|
||||
if string(b) == "null" {
|
||||
ns.Value = nil
|
||||
return nil
|
||||
}
|
||||
var s string
|
||||
if err := json.Unmarshal(b, &s); err != nil {
|
||||
return err
|
||||
}
|
||||
ns.Value = &s
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package secure
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/subtle"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/crypto/argon2"
|
||||
)
|
||||
|
||||
type Params struct {
|
||||
Memory uint32
|
||||
Time uint32
|
||||
Threads uint8
|
||||
SaltLen uint32
|
||||
KeyLen uint32
|
||||
}
|
||||
|
||||
var Default = &Params{
|
||||
Memory: 64 * 1024,
|
||||
Time: 3,
|
||||
Threads: 2,
|
||||
SaltLen: 16,
|
||||
KeyLen: 32,
|
||||
}
|
||||
|
||||
func Hash(plain string, p *Params) (string, error) {
|
||||
if strings.TrimSpace(plain) == "" {
|
||||
return "", errors.New("empty password")
|
||||
}
|
||||
if p == nil { p = Default }
|
||||
|
||||
salt := make([]byte, p.SaltLen)
|
||||
if _, err := rand.Read(salt); err != nil { return "", err }
|
||||
|
||||
key := argon2.IDKey([]byte(plain), salt, p.Time, p.Memory, p.Threads, p.KeyLen)
|
||||
return fmt.Sprintf("$argon2id$v=19$m=%d,t=%d,p=%d$%s$%s",
|
||||
p.Memory, p.Time, p.Threads,
|
||||
base64.RawStdEncoding.EncodeToString(salt),
|
||||
base64.RawStdEncoding.EncodeToString(key),
|
||||
), nil
|
||||
}
|
||||
|
||||
func Verify(encoded, plain string) bool {
|
||||
parts := strings.Split(encoded, "$")
|
||||
if len(parts) != 6 { return false }
|
||||
|
||||
var m uint32; var t uint32; var p uint8
|
||||
if _, err := fmt.Sscanf(parts[3], "m=%d,t=%d,p=%d", &m, &t, &p); err != nil { return false }
|
||||
|
||||
salt, err := base64.RawStdEncoding.DecodeString(parts[4]); if err != nil { return false }
|
||||
want, err := base64.RawStdEncoding.DecodeString(parts[5]); if err != nil { return false }
|
||||
|
||||
got := argon2.IDKey([]byte(plain), salt, t, m, p, uint32(len(want)))
|
||||
return subtle.ConstantTimeCompare(want, got) == 1
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package secure
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
)
|
||||
|
||||
func RandomToken(n int) (string, error) {
|
||||
// n = bytes, 32 → 256-bit
|
||||
b := make([]byte, n)
|
||||
if _, err := rand.Read(b); err != nil { return "", err }
|
||||
return base64.RawURLEncoding.EncodeToString(b), nil
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package secure
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
)
|
||||
|
||||
func SHA256Hex(s string) string {
|
||||
h := sha256.Sum256([]byte(s))
|
||||
return hex.EncodeToString(h[:])
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strconv"
|
||||
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
)
|
||||
|
||||
func VerifyToken(tokenStr, secret, tokenType string) (uint, error) {
|
||||
token, err := jwt.Parse(tokenStr, func(_ *jwt.Token) (interface{}, error) {
|
||||
return []byte(secret), nil
|
||||
})
|
||||
if err != nil || !token.Valid {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
claims, ok := token.Claims.(jwt.MapClaims)
|
||||
if !ok {
|
||||
return 0, errors.New("invalid token claims")
|
||||
}
|
||||
|
||||
jwtType, ok := claims["type"].(string)
|
||||
if !ok || jwtType != tokenType {
|
||||
return 0, errors.New("invalid token type")
|
||||
}
|
||||
|
||||
sub, ok := claims["sub"]
|
||||
if !ok {
|
||||
return 0, errors.New("invalid token sub")
|
||||
}
|
||||
|
||||
switch v := sub.(type) {
|
||||
case float64:
|
||||
return uint(v), nil
|
||||
case string:
|
||||
id, err := strconv.Atoi(v)
|
||||
if err != nil {
|
||||
return 0, errors.New("invalid sub format")
|
||||
}
|
||||
return uint(id), nil
|
||||
default:
|
||||
return 0, errors.New("unsupported sub type")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user