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/go_log" 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" // 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 go_log.Log) { adminAccountID, uuidErr := uuid.NewRandom() if uuidErr != nil { log.Error("Could not create new Uuid", "err", uuidErr.Error()) os.Exit(1) } _, 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.Verbose("Admin account already created, nothing written to database") } else if adminAccountErr != nil { log.Error("Could not create admin account", "err", adminAccountErr.Error()) os.Exit(1) } } // @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 := go_log.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.Warn("JWT_SHARED_SECRET ENV is not set, using very insecure \"changeMe\"") } if os.Getenv("ADMIN_API_KEY") == "changeMe" { log.Warn("ADMIN_API_KEY ENV is not set, using very insecure \"changeMe\"") } if os.Getenv("LOG_MIN_LVL") == "" { log.Info("LOG_MIN_LVL ENV is not set, using default \"Info\"") log.MinLogLvl = go_log.LogLvlFromStr("Info") } else { minLogLvl := go_log.LogLvlFromStr(os.Getenv("LOG_MIN_LVL")) if minLogLvl == 0 { log.Warn("Invalid LOG_MIN_LVL ENV, using default \"Info\"") log.MinLogLvl = go_log.LogLvlFromStr("Info") } else { log.MinLogLvl = minLogLvl } } jwtKey := []byte(os.Getenv("JWT_SHARED_SECRET")) dbPool, err := pgxpool.Connect(context.Background(), os.Getenv("DATABASE_URL")) for err != nil { log.Warn("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.Verbose("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.Get("/accounts", handlers.AccountsGet) 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) log.Info("Starting web server", "WEB_BIND_HOST", os.Getenv("WEB_BIND_HOST")) webBindHost := os.Getenv("WEB_BIND_HOST") err = app.Listen(webBindHost) for err != nil { log.Warn("Could not start web server", "err", err.Error(), "WEB_BIND_HOST", webBindHost) time.Sleep(1 * time.Second) err = app.Listen(webBindHost) } log.Info("Web server closed, shutting down") }