This commit is contained in:
ragilap
2025-11-17 14:48:39 +07:00
90 changed files with 3299 additions and 690 deletions
+2 -2
View File
@@ -10,8 +10,8 @@ import (
)
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)
if message, errorsMap := validation.CustomErrorMessages(err); len(errorsMap) > 0 {
return response.Error(c, fiber.StatusBadRequest, message, nil)
}
var fiberErr *fiber.Error
+84
View File
@@ -0,0 +1,84 @@
package secure
import (
"crypto/rand"
"encoding/base64"
"fmt"
"strings"
)
const pkceCharset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~"
// RandomBytes returns securely generated random bytes of given length.
func RandomBytes(length int) ([]byte, error) {
if length <= 0 {
return nil, fmt.Errorf("length must be positive")
}
b := make([]byte, length)
if _, err := rand.Read(b); err != nil {
return nil, err
}
return b, nil
}
// RandomString returns a base64url encoded random string of approximately the requested length.
func RandomString(length int) (string, error) {
if length <= 0 {
return "", fmt.Errorf("length must be positive")
}
// Generate ceil(length * 6/8) bytes to have enough entropy for base64 url encoding.
byteLen := (length*6 + 7) / 8
bytes, err := RandomBytes(byteLen)
if err != nil {
return "", err
}
s := base64.RawURLEncoding.EncodeToString(bytes)
if len(s) > length {
return s[:length], nil
}
// If encoded string shorter, pad using charset
if len(s) < length {
sb := strings.Builder{}
sb.WriteString(s)
extraNeeded := length - len(s)
more, err := randomFromCharset(extraNeeded)
if err != nil {
return "", err
}
sb.WriteString(more)
return sb.String(), nil
}
return s, nil
}
// PKCECodeVerifier generates a random string compliant with RFC 7636.
func PKCECodeVerifier(length int) (string, error) {
if length < 43 {
length = 43
}
if length > 128 {
length = 128
}
return randomFromCharset(length)
}
// randomFromCharset returns a random string of given length using pkceCharset.
func randomFromCharset(length int) (string, error) {
if length <= 0 {
return "", fmt.Errorf("length must be positive")
}
bytes, err := RandomBytes(length)
if err != nil {
return "", err
}
out := make([]byte, length)
for i, b := range bytes {
out[i] = pkceCharset[int(b)%len(pkceCharset)]
}
return string(out), nil
}
// Base64URLEncode encodes the input bytes using base64 URL encoding without padding.
func Base64URLEncode(data []byte) string {
return base64.RawURLEncoding.EncodeToString(data)
}
-45
View File
@@ -1,45 +0,0 @@
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")
}
}