adding condition for no auth and adding new cors statement

This commit is contained in:
areeqakbr 2025-06-18 15:07:28 +07:00
parent be3893a1dc
commit 9456477767
14 changed files with 198 additions and 75 deletions

View File

@ -4,6 +4,7 @@ import (
"errors"
"os"
"strconv"
"time"
"github.com/joho/godotenv"
)
@ -15,6 +16,12 @@ type DbConfig struct {
DBPort string
DBName string
}
type AuthConfig struct {
UserAuthEnabled bool
JWTSecret string
TokenExpiry time.Duration
}
type LoginConfig struct {
LoginAPI string
AuthMeAPI string
@ -41,6 +48,7 @@ type Config struct {
TokenApi
ApiConfig
LoginConfig
AuthConfig
}
func (c *Config) readConfig() error {
@ -83,6 +91,29 @@ func (c *Config) readConfig() error {
SkipSSLVerification: skipSSL,
}
userAuthEnabled := true // Default to true for security
if authEnabledStr := os.Getenv("USER_AUTH_ENABLED"); authEnabledStr != "" {
var err error
userAuthEnabled, err = strconv.ParseBool(authEnabledStr)
if err != nil {
return errors.New("invalid USER_AUTH_ENABLED value, must be true or false")
}
}
// Parse token expiry (default to 24 hours)
tokenExpiry := 24 * time.Hour
if expiryStr := os.Getenv("JWT_TOKEN_EXPIRY_HOURS"); expiryStr != "" {
if hours, err := strconv.Atoi(expiryStr); err == nil {
tokenExpiry = time.Duration(hours) * time.Hour
}
}
c.AuthConfig = AuthConfig{
UserAuthEnabled: userAuthEnabled,
JWTSecret: os.Getenv("JWT_SECRET"),
TokenExpiry: tokenExpiry,
}
if c.ApiConfig.ApiPort == "" {
return errors.New("failed to read environment variables")
}

View File

@ -3,6 +3,7 @@ package controller
import (
"net/http"
"strconv"
"users_management/m/config"
"users_management/m/middleware"
"users_management/m/usecase"
"users_management/m/utils/common"
@ -15,26 +16,26 @@ import (
type ActivityLogController struct {
activityLogUC usecase.ActivityLogUseCase
rg *gin.RouterGroup
cfg *config.Config // Add config field for middleware
}
func NewActivityLogController(activityLogUC usecase.ActivityLogUseCase, rg *gin.RouterGroup) *ActivityLogController {
func NewActivityLogController(activityLogUC usecase.ActivityLogUseCase, rg *gin.RouterGroup, cfg *config.Config) *ActivityLogController {
return &ActivityLogController{
activityLogUC: activityLogUC,
rg: rg,
cfg: cfg, // Initialize config
}
}
func (c *ActivityLogController) Route() {
logs := c.rg.Group("/logs")
{
// Users can see their own logs (simplified response)
logs.GET("/my-logs", c.getMyLogs)
// Only admins and superadmins can see all logs (detailed response)
logs.GET("/all", middleware.RequireAdminRole(), c.getAllLogs)
logs.GET("/all", middleware.ConditionalRequireAnyRole(c.cfg, "Admin", "SuperAdmin"), c.getAllLogs)
// Admins and superadmins can see teknisi logs specifically (detailed response)
logs.GET("/teknisi", middleware.RequireAdminRole(), c.getTeknisinLogs)
logs.GET("/teknisi", middleware.ConditionalRequireAnyRole(c.cfg, "Admin", "SuperAdmin"), c.getTeknisinLogs)
}
}

View File

@ -3,6 +3,7 @@ package controller
import (
"log"
"net/http"
"users_management/m/config"
"users_management/m/middleware"
"users_management/m/model/dto/req"
"users_management/m/usecase"
@ -11,10 +12,10 @@ import (
"github.com/gin-gonic/gin"
"github.com/google/uuid"
)
type BackboneController struct {
bu usecase.BackboneUseCase
rg *gin.RouterGroup
cfg *config.Config
}
func (bc *BackboneController) Route() {
@ -23,19 +24,21 @@ func (bc *BackboneController) Route() {
rg.GET("", bc.GetBackbone())
rg.GET("/:uuid", bc.GetBackboneByID())
rg.POST("", middleware.RequireAnyRole("Teknisi", "Admin", "Superadmin"), bc.CreateBackbone())
rg.PUT("/:uuid", middleware.RequireAnyRole("Teknisi", "Admin", "Superadmin"), bc.UpdateBackbone())
rg.POST("", middleware.ConditionalRequireAnyRole(bc.cfg, "Teknisi", "Admin", "Superadmin"), bc.CreateBackbone())
rg.PUT("/:uuid", middleware.ConditionalRequireAnyRole(bc.cfg, "Teknisi", "Admin", "Superadmin"), bc.UpdateBackbone())
}
}
func NewBackboneController(bu usecase.BackboneUseCase, rg *gin.RouterGroup) *BackboneController {
func NewBackboneController(bu usecase.BackboneUseCase, rg *gin.RouterGroup, cfg *config.Config) *BackboneController {
return &BackboneController{
bu: bu,
rg: rg,
cfg: cfg,
}
}
func (bc *BackboneController) GetBackbone() gin.HandlerFunc {
return func(c *gin.Context) {
backbones, err := bc.bu.GetAllBackbone()

View File

@ -9,6 +9,7 @@ import (
"net/http"
"strconv"
"strings"
"users_management/m/config"
"users_management/m/middleware"
"users_management/m/model/dto/req"
"users_management/m/usecase"
@ -21,18 +22,20 @@ import (
type DeviceDetailsController struct {
deviceDetailsUC usecase.DeviceDetailsUseCase
rg *gin.RouterGroup
cfg *config.Config // Add config field for middleware
}
func NewDeviceDetailsController(deviceDetailsUC usecase.DeviceDetailsUseCase, rg *gin.RouterGroup) *DeviceDetailsController {
func NewDeviceDetailsController(deviceDetailsUC usecase.DeviceDetailsUseCase, rg *gin.RouterGroup, cfg *config.Config) *DeviceDetailsController {
return &DeviceDetailsController{
deviceDetailsUC: deviceDetailsUC,
rg: rg,
cfg: cfg,
}
}
func (c *DeviceDetailsController) Route() {
deviceDetails := c.rg.Group("/device-details")
deviceDetails.Use(middleware.RequireAnyRole("Teknisi", "Admin", "Superadmin"))
deviceDetails.Use(middleware.ConditionalRequireAnyRole(c.cfg, "Teknisi", "Admin", "Superadmin"))
{
deviceDetails.GET("", c.getAllDeviceDetails)
deviceDetails.POST("", c.createDeviceDetails)

View File

@ -7,6 +7,7 @@ import (
"net/http"
"strconv"
"strings"
"users_management/m/config"
"users_management/m/middleware"
"users_management/m/model/dto/req"
"users_management/m/usecase"
@ -19,11 +20,20 @@ import (
type DeviceController struct {
du usecase.DeviceUseCase
rg *gin.RouterGroup
cfg *config.Config
}
func NewDeviceController(du usecase.DeviceUseCase, rg *gin.RouterGroup, cfg *config.Config) *DeviceController {
return &DeviceController{
du: du,
rg: rg,
cfg: cfg,
}
}
func (dc *DeviceController) Route() {
rg := dc.rg.Group("/devices")
rg.Use(middleware.RequireAnyRole("Teknisi", "Admin", "Superadmin"))
rg.Use(middleware.ConditionalRequireAnyRole(dc.cfg,"Teknisi", "Admin", "Superadmin"))
{
rg.POST("", dc.CreateDevice())
rg.GET("", dc.GetAllDevices())
@ -34,12 +44,7 @@ func (dc *DeviceController) Route() {
}
}
func NewDeviceController(du usecase.DeviceUseCase, rg *gin.RouterGroup) *DeviceController {
return &DeviceController{
du: du,
rg: rg,
}
}
func (dc *DeviceController) BulkUploadImages() gin.HandlerFunc {
return func(c *gin.Context) {

View File

@ -3,6 +3,7 @@ package controller
import (
"log"
"net/http"
"users_management/m/config"
"users_management/m/middleware"
"users_management/m/model/dto/req"
"users_management/m/usecase"
@ -15,11 +16,20 @@ import (
type FishboneController struct {
fu usecase.FishboneUseCase
rg *gin.RouterGroup
cfg *config.Config
}
func NewFishboneController(fu usecase.FishboneUseCase, rg *gin.RouterGroup, cfg *config.Config) *FishboneController {
return &FishboneController{
fu: fu,
rg: rg,
cfg: cfg,
}
}
func (fc *FishboneController) Route() {
rg := fc.rg.Group("/fishbone")
rg.Use(middleware.RequireAnyRole("Teknisi", "Admin", "Superadmin"))
rg.Use(middleware.ConditionalRequireAnyRole(fc.cfg,"Teknisi", "Admin", "Superadmin"))
// Apply middleware to all routes
{
rg.GET("", fc.GetFishbone())
@ -30,12 +40,6 @@ func (fc *FishboneController) Route() {
}
}
func NewFishboneController(fu usecase.FishboneUseCase, rg *gin.RouterGroup) *FishboneController {
return &FishboneController{
fu: fu,
rg: rg,
}
}
func (fc *FishboneController) GetFishboneByBackboneID() gin.HandlerFunc {
return func(c *gin.Context) {

View File

@ -3,6 +3,7 @@ package controller
import (
"net/http"
"strconv"
"users_management/m/config"
"users_management/m/middleware"
"users_management/m/model/dto/req"
"users_management/m/usecase"
@ -15,18 +16,20 @@ import (
type NearestDeviceController struct {
nearestDeviceUC usecase.NearestDeviceUseCase
rg *gin.RouterGroup
cfg *config.Config
}
func NewNearestDeviceController(nearestDeviceUC usecase.NearestDeviceUseCase, rg *gin.RouterGroup) *NearestDeviceController {
func NewNearestDeviceController(nearestDeviceUC usecase.NearestDeviceUseCase, rg *gin.RouterGroup, cfg *config.Config) *NearestDeviceController {
return &NearestDeviceController{
nearestDeviceUC: nearestDeviceUC,
rg: rg,
cfg: cfg,
}
}
func (c *NearestDeviceController) Route() {
nearestDevices := c.rg.Group("/nearest-devices")
nearestDevices.Use(middleware.RequireAnyRole("Teknisi", "Admin", "Superadmin"))
nearestDevices.Use(middleware.ConditionalRequireAnyRole(c.cfg,"Teknisi", "Admin", "Superadmin"))
{
nearestDevices.POST("/search", c.getNearestDevices)
nearestDevices.GET("/:id", c.getNearestDeviceByID)

View File

@ -7,6 +7,7 @@ import (
"net/http"
"strconv"
"strings"
"users_management/m/config"
"users_management/m/middleware"
"users_management/m/model/dto/req"
"users_management/m/usecase"
@ -19,11 +20,12 @@ import (
type TowerController struct {
tu usecase.TowerUseCase
rg *gin.RouterGroup
cfg *config.Config
}
func (tc *TowerController) Route() {
rg := tc.rg.Group("/tower")
rg.Use(middleware.RequireAnyRole("Teknisi", "Admin", "Superadmin")) // Apply middleware to all routes
rg.Use(middleware.ConditionalRequireAnyRole(tc.cfg,"Teknisi", "Admin", "Superadmin")) // Apply middleware to all routes
{
rg.GET("", tc.GetTower())
rg.POST("", tc.CreateTower())
@ -35,10 +37,11 @@ func (tc *TowerController) Route() {
}
}
func NewTowerController(tu usecase.TowerUseCase, rg *gin.RouterGroup) *TowerController {
func NewTowerController(tu usecase.TowerUseCase, rg *gin.RouterGroup, cfg *config.Config) *TowerController {
return &TowerController{
tu: tu,
rg: rg,
cfg: cfg,
}
}

View File

@ -19,7 +19,7 @@ type UsersController struct {
func (uc *UsersController) Route() {
rg:= uc.rg.Group("/users")
rg.Use(middleware.CORSMiddleware())
rg.Use(middleware.RateLoginMiddleware())
// rg.Use(middleware.RateLoginMiddleware())
rg.OPTIONS("/login", func(c *gin.Context) {
c.Status(http.StatusNoContent)
})

View File

@ -15,6 +15,7 @@ type Server struct {
ucManager manager.UsecaseManager
engine *gin.Engine
host string
cfg *config.Config
}
func NewServer() *Server {
@ -31,6 +32,11 @@ func NewServer() *Server {
repoManager := manager.NewRepositoryManager(infraManager)
ucManager := manager.NewUsecaseManager(repoManager, cfg)
engine := gin.Default()
engine.Use(middleware.CORSMiddleware())
engine.Use(middleware.ConditionalAuthMiddleware(ucManager.NewUserUsecase(), cfg))
engine.Use(middleware.ConditionalActivityLoggingMiddleware(ucManager.NewActivityLogUsecase(), cfg))
engine.Use(common.LoggingToFile())
host := fmt.Sprintf(":%s", cfg.ApiPort)
@ -38,31 +44,26 @@ func NewServer() *Server {
ucManager: ucManager,
engine: engine,
host: host,
cfg: cfg,
}
}
func (s *Server) setupController() {
s.engine.Static("/uploads", "./uploads")
s.engine.Use(middleware.CORSMiddleware())
rg := s.engine.Group("/api/v1")
controller.NewUsersController(s.ucManager.NewUserUsecase(), s.ucManager.NewAuthUsecase(),rg).Route()
rg.Use(middleware.AuthMiddleware(s.ucManager.NewUserUsecase()))
controller.NewCountAssetsController(s.ucManager.NewCountAssetsUsecase(), rg).Route()
rg.Use(middleware.ActivityLoggingMiddleware(s.ucManager.NewActivityLogUsecase()))
{
controller.NewDeviceController(s.ucManager.NewDeviceUsecase(), rg).Route()
controller.NewBackboneController(s.ucManager.NewBackboneUsecase(), rg).Route()
controller.NewFishboneController(s.ucManager.NewFishboneUsecase(), rg).Route()
controller.NewTowerController(s.ucManager.NewTowerUsecase(), rg).Route()
controller.NewDeviceController(s.ucManager.NewDeviceUsecase(), rg,s.cfg).Route()
controller.NewBackboneController(s.ucManager.NewBackboneUsecase(), rg,s.cfg).Route()
controller.NewFishboneController(s.ucManager.NewFishboneUsecase(), rg,s.cfg).Route()
controller.NewTowerController(s.ucManager.NewTowerUsecase(), rg,s.cfg).Route()
controller.NewDevicePortController(s.ucManager.NewDevicePortUsecase(), rg).Route()
controller.NewActivityLogController(s.ucManager.NewActivityLogUsecase(), rg).Route()
controller.NewActivityLogController(s.ucManager.NewActivityLogUsecase(), rg,s.cfg).Route()
controller.NewDeviceInspectionController(s.ucManager.NewDeviceInspectionUsecase(), rg).Route()
controller.NewNearestDeviceController(s.ucManager.NewNearestDeviceUsecase(), rg).Route()
controller.NewDeviceDetailsController(s.ucManager.NewDeviceDetailsUsecase(), rg).Route()
}
controller.NewNearestDeviceController(s.ucManager.NewNearestDeviceUsecase(), rg,s.cfg).Route()
controller.NewDeviceDetailsController(s.ucManager.NewDeviceDetailsUsecase(), rg,s.cfg).Route()
}

View File

@ -6,6 +6,7 @@ import (
"fmt"
"io"
"strings"
"users_management/m/config"
"users_management/m/usecase"
"github.com/gin-gonic/gin"
@ -22,6 +23,19 @@ func (r responseWriter) Write(b []byte) (int, error) {
return r.ResponseWriter.Write(b)
}
// ConditionalActivityLoggingMiddleware that respects auth config
func ConditionalActivityLoggingMiddleware(activityLogUC usecase.ActivityLogUseCase, cfg *config.Config) gin.HandlerFunc {
return func(c *gin.Context) {
// If auth is disabled, skip activity logging
if !cfg.AuthConfig.UserAuthEnabled {
c.Next()
return
}
// If auth is enabled, run normal activity logging
ActivityLoggingMiddleware(activityLogUC)(c)
}
}
func ActivityLoggingMiddleware(activityLogUC usecase.ActivityLogUseCase) gin.HandlerFunc {
return func(c *gin.Context) {
// Skip logging for certain endpoints

View File

@ -8,14 +8,39 @@ import (
"strings"
"time"
"users_management/m/config"
"users_management/m/model/dto/res"
"users_management/m/model/entity"
"users_management/m/usecase"
"users_management/m/utils/common"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
)
// ConditionalAuthMiddleware checks config to decide whether to apply auth
func ConditionalAuthMiddleware(userUC usecase.UsersUsecase, cfg *config.Config) gin.HandlerFunc {
return func(c *gin.Context) {
// If auth is disabled, skip authentication but set default values
if !cfg.AuthConfig.UserAuthEnabled {
log.Println("Authentication disabled - skipping auth middleware")
// Set default values for when auth is disabled
c.Set("userID", uuid.New()) // Generate a dummy UUID
c.Set("userName", "system")
c.Set("userRole", "Admin") // Default role when auth is disabled
c.Set("token", "no-auth-mode")
c.Next()
return
}
// If auth is enabled, run the normal auth middleware
AuthMiddleware(userUC)(c)
}
}
func AuthMiddleware(userUC usecase.UsersUsecase) gin.HandlerFunc {
return func(c *gin.Context) {
token := c.GetHeader("Authorization")

View File

@ -19,6 +19,8 @@ func CORSMiddleware() gin.HandlerFunc {
"http://103.110.8.103:80",// Add production URL
"http://103.110.8.103",
"http://nam.winteraccess.id",
}
// Check if origin is in allowed list

View File

@ -2,11 +2,39 @@ package middleware
import (
"net/http"
"users_management/m/config"
"users_management/m/utils/common"
"github.com/gin-gonic/gin"
)
// ConditionalRequireRole middleware that respects auth config
func ConditionalRequireRole(cfg *config.Config, allowedRoles ...string) gin.HandlerFunc {
return func(c *gin.Context) {
// If auth is disabled, allow all requests
if !cfg.AuthConfig.UserAuthEnabled {
c.Next()
return
}
// If auth is enabled, check roles normally
RequireRole(allowedRoles...)(c)
}
}
// ConditionalRequireAnyRole middleware that respects auth config
func ConditionalRequireAnyRole(cfg *config.Config, roles ...string) gin.HandlerFunc {
return func(c *gin.Context) {
// If auth is disabled, allow all requests
if !cfg.AuthConfig.UserAuthEnabled {
c.Next()
return
}
// If auth is enabled, check roles normally
RequireAnyRole(roles...)(c)
}
}
// RequireRole middleware to check if user has required role
func RequireRole(allowedRoles ...string) gin.HandlerFunc {
return func(c *gin.Context) {