diff --git a/app.go b/app.go new file mode 100644 index 0000000000000000000000000000000000000000..76e48a9224144b03c4a70d631bda3fdf1364bd6b --- /dev/null +++ b/app.go @@ -0,0 +1,42 @@ +package main + +import ( + "log" + "time" + + "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v2/middleware/cors" + "github.com/gofiber/fiber/v2/middleware/limiter" +) + +func serve() error { + app := fiber.New() + + // cors + app.Use(cors.New(cors.Config{ + AllowOrigins: conf[allowedOrigins], + AllowHeaders: "Origin, Content-Type, Accept", + })) + + // rate limiting + app.Use(limiter.New(limiter.Config{ + Max: 5, + Expiration: 7 * 24 * time.Hour, // 1 week expiration + LimitReached: func(c *fiber.Ctx) error { + log.Printf("Rate limit exceeded for IP: %s", c.IP()) + return c.Status(fiber.StatusTooManyRequests).JSON(fiber.Map{ + "message": "Rate limit exceeded. Max 5 registrations per week.", + }) + }, + })) + + // /register + routeRegister(app) + + // Graceful shutdown + app.Use(func(c *fiber.Ctx) error { + return c.Next() + }) + + return app.Listen(conf[listenAddr]) +} diff --git a/main.go b/main.go index e2faff58730e4ee8c994bf0cf4692a9f7692b497..64f6fd7857849f80d7031dd0c06b3e7e35c30011 100644 --- a/main.go +++ b/main.go @@ -3,22 +3,11 @@ package main import ( "log" "regexp" - "time" - - "github.com/gofiber/fiber/v2" - "github.com/gofiber/fiber/v2/middleware/cors" - "github.com/gofiber/fiber/v2/middleware/limiter" ) var emailRegex = regexp.MustCompile(`^[a-z0-9._%+\-]+@[a-z0-9.\-]+\.[a-z]{2,4}$`) func main() { - app := fiber.New() - - app.Use(cors.New(cors.Config{ - AllowOrigins: conf[allowedOrigins], - AllowHeaders: "Origin, Content-Type, Accept", - })) if err := InitDB(conf[dbPath]); err != nil { log.Fatalf("Failed to initialize LevelDB: %v", err) @@ -26,72 +15,9 @@ func main() { defer CloseDB() - app.Use(limiter.New(limiter.Config{ - Max: 5, - Expiration: 7 * 24 * time.Hour, // 1 week expiration - LimitReached: func(c *fiber.Ctx) error { - log.Printf("Rate limit exceeded for IP: %s", c.IP()) - return c.Status(fiber.StatusTooManyRequests).JSON(fiber.Map{ - "message": "Rate limit exceeded. Max 5 registrations per week.", - }) - }, - })) - - // Waitlist registration route - app.Post("/register", func(c *fiber.Ctx) error { - type Request struct { - Email string `json:"email"` - } - req := new(Request) - - if err := c.BodyParser(req); err != nil { - log.Printf("Invalid request body: %v", err) - return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{ - "message": "Invalid request", - }) - } - - // Validate email format - if !emailRegex.MatchString(req.Email) { - log.Printf("Invalid email format: %s", req.Email) - return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{ - "message": "Invalid email format", - }) - } - - // Check if email is already registered - registered, err := IsEmailRegistered(req.Email) - if err != nil { - log.Printf("Error checking email registration: %v", err) - return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ - "message": "Error checking registration status", - }) - } - if registered { - log.Printf("Email already registered: %s", req.Email) - return c.Status(fiber.StatusConflict).JSON(fiber.Map{ - "message": "Email already registered", - }) - } - - // Save the email to the waitlist - if err := SaveEmail(req.Email); err != nil { - log.Printf("Error registering email: %v", err) - return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ - "message": "Error registering email", - }) - } - - log.Printf("Email registered successfully: %s", req.Email) - return c.JSON(fiber.Map{ - "message": "Email registered successfully", - }) - }) - - // Graceful shutdown - app.Use(func(c *fiber.Ctx) error { - return c.Next() - }) + if err := serve(); err != nil { + log.Printf("cannot serve: %s", err) + } - log.Fatal(app.Listen(conf[listenAddr])) + log.Println("application exit") } diff --git a/register.go b/register.go new file mode 100644 index 0000000000000000000000000000000000000000..de99ce9b9d86d2729a07acbd249743e7c8e62ff3 --- /dev/null +++ b/register.go @@ -0,0 +1,60 @@ +package main + +import ( + "log" + + "github.com/gofiber/fiber/v2" +) + +// Waitlist registration route +func routeRegister(app *fiber.App) { + app.Post("/register", func(c *fiber.Ctx) error { + type Request struct { + Email string `json:"email"` + } + req := new(Request) + + if err := c.BodyParser(req); err != nil { + log.Printf("Invalid request body: %v", err) + return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{ + "message": "Invalid request", + }) + } + + // Validate email format + if !emailRegex.MatchString(req.Email) { + log.Printf("Invalid email format: %s", req.Email) + return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{ + "message": "Invalid email format", + }) + } + + // Check if email is already registered + registered, err := IsEmailRegistered(req.Email) + if err != nil { + log.Printf("Error checking email registration: %v", err) + return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ + "message": "Error checking registration status", + }) + } + if registered { + log.Printf("Email already registered: %s", req.Email) + return c.Status(fiber.StatusConflict).JSON(fiber.Map{ + "message": "Email already registered", + }) + } + + // Save the email to the waitlist + if err := SaveEmail(req.Email); err != nil { + log.Printf("Error registering email: %v", err) + return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ + "message": "Error registering email", + }) + } + + log.Printf("Email registered successfully: %s", req.Email) + return c.JSON(fiber.Map{ + "message": "Email registered successfully", + }) + }) +}