package main import ( "context" "os" "strings" "time" "gitea.larvit.se/pwrpln/auth-api/src/db" h "gitea.larvit.se/pwrpln/auth-api/src/handlers" "gitea.larvit.se/pwrpln/auth-api/src/utils" swagger "github.com/arsmn/fiber-swagger/v2" "github.com/gofiber/fiber/v2" "github.com/google/uuid" "github.com/jackc/pgx/v4/pgxpool" "github.com/joho/godotenv" "go.uber.org/zap" // docs are generated by Swag CLI, you have to import them. _ "gitea.larvit.se/pwrpln/auth-api/src/docs" ) // Don't put in utils, because it creates import cycle with db... just left it here for now func createAdminAccount(Db db.Db, log *zap.SugaredLogger) { adminAccountID, uuidErr := uuid.NewRandom() if uuidErr != nil { log.Fatal("Could not create new Uuid", "err", uuidErr.Error()) } _, adminAccountErr := Db.AccountCreate(db.AccountCreateInput{ ID: adminAccountID, Name: "admin", APIKey: os.Getenv("ADMIN_API_KEY"), Password: "", Fields: []db.AccountCreateInputFields{{Name: "role", Values: []string{"admin"}}}, }) if adminAccountErr != nil && strings.HasPrefix(adminAccountErr.Error(), "ERROR: duplicate key") { log.Info("Admin account already created, nothing written to database") } else if adminAccountErr != nil { log.Fatal("Could not create admin account", "err", adminAccountErr.Error()) } } // @title JWT Auth API // @version 0.1 // @description This is a tiny http API for auth. Register accounts, auth with api-key or name/password, renew JWT tokens... // @contact.name Power Plan // @contact.url https://pwrpln.com/ // @contact.email lilleman@larvit.se // @license.name MIT // @BasePath / func main() { log := utils.GetLog() err := godotenv.Load() if err != nil { log.Warn("Error loading .env file, this could be ok if the env file does not exist", "err", err.Error()) } if os.Getenv("JWT_SHARED_SECRET") == "changeMe" { log.Error("JWT_SHARED_SECRET ENV is not set, using very insecure \"changeMe\"") } if os.Getenv("ADMIN_API_KEY") == "changeMe" { log.Error("ADMIN_API_KEY ENV is not set, using very insecure \"changeMe\"") } jwtKey := []byte(os.Getenv("JWT_SHARED_SECRET")) dbPool, err := pgxpool.Connect(context.Background(), os.Getenv("DATABASE_URL")) for err != nil { log.Error("Failed to open connection to PostgreSQL database, retrying in 1 second", "err", err.Error()) time.Sleep(1 * time.Second) dbPool, err = pgxpool.Connect(context.Background(), os.Getenv("DATABASE_URL")) } log.Info("Connected to PostgreSQL database") defer dbPool.Close() app := fiber.New() Db := db.Db{DbPool: dbPool, Log: log} handlers := h.Handlers{Db: Db, JwtKey: jwtKey, Log: log} createAdminAccount(Db, log) // Log all requests app.Use(handlers.LogReq) // Always require application/json app.Use(handlers.RequireJSON) app.Get("/", func(c *fiber.Ctx) error { return c.Redirect("/swagger/index.html") }) app.Get("/swagger", func(c *fiber.Ctx) error { return c.Redirect("/swagger/index.html") }) app.Get("/swagger/*", swagger.HandlerDefault) app.Delete("/account/:accountID", handlers.AccountDel) app.Get("/account/:accountID", handlers.AccountGet) app.Post("/account", handlers.AccountCreate) app.Post("/auth/api-key", handlers.AccountAuthAPIKey) app.Post("/auth/password", handlers.AccountAuthPassword) app.Post("/renew-token", handlers.RenewToken) app.Put("/account/:accountID/fields", handlers.AccountUpdateFields) // app.Put("") log.Info("Trying to start web server", "WEB_BIND_HOST", os.Getenv("WEB_BIND_HOST")) webBindHost := os.Getenv("WEB_BIND_HOST") err = app.Listen(webBindHost) for err != nil { log.Error("Could not start web server", "err", err.Error(), "WEB_BIND_HOST", webBindHost) time.Sleep(1 * time.Second) err = app.Listen(webBindHost) } log.Info("Webb server closed, shutting down") }