aboutsummaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
authorBobby <[email protected]>2026-03-07 14:25:54 +0530
committerBobby <[email protected]>2026-03-07 14:25:54 +0530
commit41926c10ea2e8496ce4b528262f5047ccbe6f155 (patch)
tree67ff5a27bb50faec368cf7ef38a1b1f2866459dd /utils
parented2a033d7c08e448f5c6fd035e2de8f51431b597 (diff)
downloaddove-41926c10ea2e8496ce4b528262f5047ccbe6f155.tar.xz
dove-41926c10ea2e8496ce4b528262f5047ccbe6f155.zip
Implement authentication system with login/logout functionality and session management
Diffstat (limited to 'utils')
-rw-r--r--utils/auth/auth.go46
-rw-r--r--utils/auth/constants.go5
-rw-r--r--utils/meta/body.go12
-rw-r--r--utils/shortcuts/error.go65
-rw-r--r--utils/shortcuts/functions.go97
-rw-r--r--utils/shortcuts/redirect.go25
-rw-r--r--utils/shortcuts/render.go22
7 files changed, 272 insertions, 0 deletions
diff --git a/utils/auth/auth.go b/utils/auth/auth.go
new file mode 100644
index 0000000..5abb496
--- /dev/null
+++ b/utils/auth/auth.go
@@ -0,0 +1,46 @@
+package auth
+
+import (
+ "dove/session"
+
+ "github.com/gofiber/fiber/v2"
+)
+
+func IsAuthenticated(context *fiber.Ctx) bool {
+ activeSession, sessionError := session.Store.Get(context)
+ if sessionError != nil {
+ return false
+ }
+
+ return activeSession.Get(SESSION_AUTHENTICATED_KEY) != nil
+}
+
+func RequireAuthentication(handler fiber.Handler) fiber.Handler {
+ return func(context *fiber.Ctx) error {
+ switch IsAuthenticated(context) {
+ case true:
+ return handler(context)
+ default:
+ return fiber.ErrUnauthorized
+ }
+ }
+}
+
+func Authenticate(context *fiber.Ctx) error {
+ activeSession, sessionError := session.Store.Get(context)
+ if sessionError != nil {
+ return sessionError
+ }
+
+ activeSession.Set(SESSION_AUTHENTICATED_KEY, true)
+ return activeSession.Save()
+}
+
+func Deauthenticate(context *fiber.Ctx) error {
+ activeSession, sessionError := session.Store.Get(context)
+ if sessionError != nil {
+ return sessionError
+ }
+
+ return activeSession.Destroy()
+}
diff --git a/utils/auth/constants.go b/utils/auth/constants.go
new file mode 100644
index 0000000..99f5a85
--- /dev/null
+++ b/utils/auth/constants.go
@@ -0,0 +1,5 @@
+package auth
+
+const (
+ SESSION_AUTHENTICATED_KEY = "authenticated"
+)
diff --git a/utils/meta/body.go b/utils/meta/body.go
new file mode 100644
index 0000000..ce10bde
--- /dev/null
+++ b/utils/meta/body.go
@@ -0,0 +1,12 @@
+package meta
+
+import "github.com/gofiber/fiber/v2"
+
+func Body[T any](context *fiber.Ctx) (T, error) {
+ var body T
+ if parseError := context.BodyParser(&body); parseError != nil {
+ return body, parseError
+ }
+
+ return body, nil
+}
diff --git a/utils/shortcuts/error.go b/utils/shortcuts/error.go
new file mode 100644
index 0000000..71fa4bd
--- /dev/null
+++ b/utils/shortcuts/error.go
@@ -0,0 +1,65 @@
+package shortcuts
+
+import (
+ "dove/enums"
+ "dove/types"
+
+ "github.com/gofiber/fiber/v2"
+)
+
+var statusMap = map[enums.ErrorKind]int{
+ enums.BadRequest: fiber.StatusBadRequest,
+ enums.Forbidden: fiber.StatusForbidden,
+ enums.Internal: fiber.StatusInternalServerError,
+ enums.NotFound: fiber.StatusNotFound,
+ enums.Unauthorized: fiber.StatusUnauthorized,
+ enums.Unprocessable: fiber.StatusUnprocessableEntity,
+}
+
+func ServiceError(kind enums.ErrorKind, message string) *types.ServiceError {
+ return &types.ServiceError{
+ Kind: kind,
+ Message: message,
+ }
+}
+
+func HandleError(context *fiber.Ctx, serviceError *types.ServiceError) error {
+ statusCode, exists := statusMap[serviceError.Kind]
+ if !exists {
+ statusCode = fiber.StatusInternalServerError
+ }
+
+ return RenderWithStatus(context, "error", fiber.Map{
+ "ErrorMessage": serviceError.Message,
+ }, statusCode)
+}
+
+func BadRequest(context *fiber.Ctx, err error) error {
+ return RenderWithStatus(context, "error", fiber.Map{
+ "ErrorMessage": err.Error(),
+ }, fiber.StatusBadRequest)
+}
+
+func Forbidden(context *fiber.Ctx, err error) error {
+ return RenderWithStatus(context, "error", fiber.Map{
+ "ErrorMessage": err.Error(),
+ }, fiber.StatusForbidden)
+}
+
+func InternalServerError(context *fiber.Ctx, err error) error {
+ return RenderWithStatus(context, "error", fiber.Map{
+ "ErrorMessage": err.Error(),
+ }, fiber.StatusInternalServerError)
+}
+
+func NotFound(context *fiber.Ctx, err error) error {
+ return RenderWithStatus(context, "error", fiber.Map{
+ "ErrorMessage": err.Error(),
+ }, fiber.StatusNotFound)
+}
+
+func Unauthorized(context *fiber.Ctx, err error) error {
+ return RenderWithStatus(context, "error", fiber.Map{
+ "ErrorMessage": err.Error(),
+ }, fiber.StatusUnauthorized)
+}
diff --git a/utils/shortcuts/functions.go b/utils/shortcuts/functions.go
new file mode 100644
index 0000000..df00dcf
--- /dev/null
+++ b/utils/shortcuts/functions.go
@@ -0,0 +1,97 @@
+package shortcuts
+
+import (
+ "maps"
+ "reflect"
+ "strings"
+
+ "dove/messages"
+ "dove/utils/errors"
+
+ "github.com/gofiber/fiber/v2"
+)
+
+func mergeContextValues(context *fiber.Ctx, targetMap fiber.Map) {
+ context.Context().VisitUserValues(func(key []byte, value any) {
+ targetMap[string(key)] = value
+ })
+}
+
+func mergeBindData(targetMap fiber.Map, data any) error {
+ normalizedData, normalizeError := normalizeToMap(data)
+ if normalizeError != nil {
+ return normalizeError
+ }
+
+ maps.Copy(targetMap, normalizedData)
+ return nil
+}
+
+func normalizeToMap(data any) (fiber.Map, error) {
+ switch typedData := data.(type) {
+ case fiber.Map:
+ return typedData, nil
+ case map[string]any:
+ return fiber.Map(typedData), nil
+ default:
+ return convertStructToMap(data)
+ }
+}
+
+func convertStructToMap(data any) (fiber.Map, error) {
+ structValue := reflect.ValueOf(data)
+
+ switch structValue.Kind() {
+ case reflect.Pointer:
+ structValue = structValue.Elem()
+ }
+
+ switch structValue.Kind() {
+ case reflect.Struct:
+ return extractStructFields(structValue), nil
+ default:
+ return nil, errors.Error(messages.ShortcutUnsupportedBindType)
+ }
+}
+
+func extractStructFields(structValue reflect.Value) fiber.Map {
+ structType := structValue.Type()
+ fieldMap := make(fiber.Map, structValue.NumField())
+
+ for fieldIndex := range structType.NumField() {
+ fieldDescriptor := structType.Field(fieldIndex)
+
+ if !fieldDescriptor.IsExported() {
+ continue
+ }
+
+ fieldKey := resolveFieldKey(fieldDescriptor)
+ fieldMap[fieldKey] = structValue.Field(fieldIndex).Interface()
+ }
+
+ return fieldMap
+}
+
+func resolveFieldKey(fieldDescriptor reflect.StructField) string {
+ jsonTag := fieldDescriptor.Tag.Get("json")
+
+ switch {
+ case jsonTag == "" || jsonTag == "-":
+ return fieldDescriptor.Name
+ default:
+ return extractTagName(jsonTag, fieldDescriptor.Name)
+ }
+}
+
+func extractTagName(jsonTag string, fallbackName string) string {
+ separatorIndex := strings.IndexByte(jsonTag, ',')
+
+ switch {
+ case separatorIndex < 0:
+ return jsonTag
+ case separatorIndex > 0:
+ return jsonTag[:separatorIndex]
+ default:
+ return fallbackName
+ }
+} \ No newline at end of file
diff --git a/utils/shortcuts/redirect.go b/utils/shortcuts/redirect.go
new file mode 100644
index 0000000..627538d
--- /dev/null
+++ b/utils/shortcuts/redirect.go
@@ -0,0 +1,25 @@
+package shortcuts
+
+import (
+ "dove/utils/urls"
+
+ "github.com/gofiber/fiber/v2"
+)
+
+func Redirect(context *fiber.Ctx, routeName string) error {
+ fullPath, exists := urls.GetFullPath(routeName)
+ if !exists {
+ return fiber.ErrNotFound
+ }
+
+ return context.Redirect(fullPath)
+}
+
+func RedirectWithStatus(context *fiber.Ctx, routeName string, statusCode int) error {
+ fullPath, exists := urls.GetFullPath(routeName)
+ if !exists {
+ return fiber.ErrNotFound
+ }
+
+ return context.Redirect(fullPath, statusCode)
+} \ No newline at end of file
diff --git a/utils/shortcuts/render.go b/utils/shortcuts/render.go
new file mode 100644
index 0000000..29c7a8f
--- /dev/null
+++ b/utils/shortcuts/render.go
@@ -0,0 +1,22 @@
+package shortcuts
+
+import "github.com/gofiber/fiber/v2"
+
+func Render(context *fiber.Ctx, templateName string, data any) error {
+ templateData := make(fiber.Map)
+
+ mergeContextValues(context, templateData)
+
+ if data != nil {
+ if mergeError := mergeBindData(templateData, data); mergeError != nil {
+ return mergeError
+ }
+ }
+
+ return context.Render(templateName, templateData)
+}
+
+func RenderWithStatus(context *fiber.Ctx, templateName string, data any, statusCode int) error {
+ context.Status(statusCode)
+ return Render(context, templateName, data)
+}