2021-01-02 12:09:16 +01:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"os"
|
|
|
|
"strings"
|
2021-09-04 16:24:48 +02:00
|
|
|
"time"
|
2021-01-02 12:09:16 +01:00
|
|
|
|
2022-01-22 15:43:33 +01:00
|
|
|
"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"
|
2021-06-22 22:52:48 +02:00
|
|
|
swagger "github.com/arsmn/fiber-swagger/v2"
|
2021-01-02 12:09:16 +01:00
|
|
|
"github.com/gofiber/fiber/v2"
|
|
|
|
"github.com/google/uuid"
|
|
|
|
"github.com/jackc/pgx/v4/pgxpool"
|
|
|
|
"github.com/joho/godotenv"
|
2021-06-22 22:52:48 +02:00
|
|
|
"go.uber.org/zap"
|
|
|
|
|
|
|
|
// docs are generated by Swag CLI, you have to import them.
|
2022-01-22 15:43:33 +01:00
|
|
|
_ "gitea.larvit.se/pwrpln/auth-api/src/docs"
|
2021-01-02 12:09:16 +01:00
|
|
|
)
|
|
|
|
|
2021-06-22 22:52:48 +02:00
|
|
|
// 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) {
|
2021-01-02 12:09:16 +01:00
|
|
|
adminAccountID, uuidErr := uuid.NewRandom()
|
|
|
|
if uuidErr != nil {
|
2021-06-22 22:52:48 +02:00
|
|
|
log.Fatal("Could not create new Uuid", "err", uuidErr.Error())
|
2021-01-02 12:09:16 +01:00
|
|
|
}
|
|
|
|
_, adminAccountErr := Db.AccountCreate(db.AccountCreateInput{
|
2021-01-03 18:21:42 +01:00
|
|
|
ID: adminAccountID,
|
|
|
|
Name: "admin",
|
|
|
|
APIKey: os.Getenv("ADMIN_API_KEY"),
|
|
|
|
Password: "",
|
|
|
|
Fields: []db.AccountCreateInputFields{{Name: "role", Values: []string{"admin"}}},
|
2021-01-02 12:09:16 +01:00
|
|
|
})
|
|
|
|
if adminAccountErr != nil && strings.HasPrefix(adminAccountErr.Error(), "ERROR: duplicate key") {
|
|
|
|
log.Info("Admin account already created, nothing written to database")
|
|
|
|
} else if adminAccountErr != nil {
|
2021-06-22 22:52:48 +02:00
|
|
|
log.Fatal("Could not create admin account", "err", adminAccountErr.Error())
|
2021-01-02 12:09:16 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-22 22:52:48 +02:00
|
|
|
// @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
|
2021-06-22 23:49:11 +02:00
|
|
|
// @contact.url https://pwrpln.com/
|
2021-06-22 22:52:48 +02:00
|
|
|
// @contact.email lilleman@larvit.se
|
|
|
|
|
|
|
|
// @license.name MIT
|
|
|
|
|
|
|
|
// @BasePath /
|
2021-01-02 12:09:16 +01:00
|
|
|
func main() {
|
2021-06-22 22:52:48 +02:00
|
|
|
log := utils.GetLog()
|
|
|
|
|
2021-01-02 12:09:16 +01:00
|
|
|
err := godotenv.Load()
|
|
|
|
if err != nil {
|
2021-06-22 22:52:48 +02:00
|
|
|
log.Warn("Error loading .env file, this could be ok if the env file does not exist", "err", err.Error())
|
2021-01-02 12:09:16 +01:00
|
|
|
}
|
|
|
|
|
2021-01-03 18:21:42 +01:00
|
|
|
if os.Getenv("JWT_SHARED_SECRET") == "changeMe" {
|
2021-09-04 16:24:48 +02:00
|
|
|
log.Error("JWT_SHARED_SECRET ENV is not set, using very insecure \"changeMe\"")
|
2021-01-03 18:21:42 +01:00
|
|
|
}
|
|
|
|
if os.Getenv("ADMIN_API_KEY") == "changeMe" {
|
2021-09-04 16:24:48 +02:00
|
|
|
log.Error("ADMIN_API_KEY ENV is not set, using very insecure \"changeMe\"")
|
2021-01-03 18:21:42 +01:00
|
|
|
}
|
|
|
|
jwtKey := []byte(os.Getenv("JWT_SHARED_SECRET"))
|
|
|
|
|
2021-01-02 12:09:16 +01:00
|
|
|
dbPool, err := pgxpool.Connect(context.Background(), os.Getenv("DATABASE_URL"))
|
2021-09-04 16:24:48 +02:00
|
|
|
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"))
|
2021-01-02 12:09:16 +01:00
|
|
|
}
|
2021-09-04 16:24:48 +02:00
|
|
|
log.Info("Connected to PostgreSQL database")
|
2021-01-02 12:09:16 +01:00
|
|
|
defer dbPool.Close()
|
|
|
|
|
|
|
|
app := fiber.New()
|
|
|
|
|
2021-06-22 22:52:48 +02:00
|
|
|
Db := db.Db{DbPool: dbPool, Log: log}
|
|
|
|
handlers := h.Handlers{Db: Db, JwtKey: jwtKey, Log: log}
|
2021-01-02 12:09:16 +01:00
|
|
|
|
2021-06-22 22:52:48 +02:00
|
|
|
createAdminAccount(Db, log)
|
2021-01-02 12:09:16 +01:00
|
|
|
|
2021-01-03 18:21:42 +01:00
|
|
|
// Log all requests
|
2021-06-22 22:52:48 +02:00
|
|
|
app.Use(handlers.LogReq)
|
2021-01-03 18:21:42 +01:00
|
|
|
|
2021-01-02 12:09:16 +01:00
|
|
|
// Always require application/json
|
|
|
|
app.Use(handlers.RequireJSON)
|
|
|
|
|
2021-06-22 22:52:48 +02:00
|
|
|
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") })
|
2022-02-18 19:38:35 +01:00
|
|
|
app.Get("/swagger/*", swagger.HandlerDefault)
|
2021-06-22 22:52:48 +02:00
|
|
|
|
2021-06-24 00:42:54 +02:00
|
|
|
app.Delete("/account/:accountID", handlers.AccountDel)
|
2021-01-02 12:09:16 +01:00
|
|
|
app.Get("/account/:accountID", handlers.AccountGet)
|
|
|
|
app.Post("/account", handlers.AccountCreate)
|
|
|
|
app.Post("/auth/api-key", handlers.AccountAuthAPIKey)
|
2021-01-05 16:23:18 +01:00
|
|
|
app.Post("/auth/password", handlers.AccountAuthPassword)
|
2021-06-22 22:52:48 +02:00
|
|
|
app.Post("/renew-token", handlers.RenewToken)
|
2021-06-24 01:55:47 +02:00
|
|
|
app.Put("/account/:accountID/fields", handlers.AccountUpdateFields)
|
|
|
|
// app.Put("")
|
2021-01-02 12:09:16 +01:00
|
|
|
|
2021-06-22 22:52:48 +02:00
|
|
|
log.Info("Trying to start web server", "WEB_BIND_HOST", os.Getenv("WEB_BIND_HOST"))
|
2021-01-02 12:09:16 +01:00
|
|
|
|
2021-09-04 16:24:48 +02:00
|
|
|
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)
|
2021-01-02 12:09:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
log.Info("Webb server closed, shutting down")
|
|
|
|
}
|