diff --git a/README.md b/README.md index f8ef274..97552aa 100644 --- a/README.md +++ b/README.md @@ -32,4 +32,13 @@ Obtain an admin GWT: `curl -d '"api-key-goes-here"' -H "Content-Type: applicatio Use a bearer token to make a call: `curl -H "Content-Type: application/json" -H "Authorization: bearer your-JWT-token-goes-here" -i http://localhost:4000/accounts/{accountID}` -Create account: `curl -d '{"name": "Bosse", "password": "Hemligt", "fields": [{ "name":"role", "values":["user"]}]}' -H "Content-Type: application/json" -H "Authorization: bearer your-JWT-token-goes-here" -i http://localhost:4000/account` \ No newline at end of file +Create account: `curl -d '{"name": "Bosse", "password": "Hemligt", "fields": [{ "name":"role", "values":["user"]}]}' -H "Content-Type: application/json" -H "Authorization: bearer your-JWT-token-goes-here" -i http://localhost:4000/account` + +## Development + +For local development, run with .env like: `eval $(cat .env) go run src/main.go` + +To regenerate the swagger docs folder: + +1. Make sure you have swag installed: https://github.com/swaggo/swag +2. cd src && swag init \ No newline at end of file diff --git a/go.mod b/go.mod index 0c83f9e..20b947e 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,6 @@ require ( github.com/gofiber/fiber/v2 v2.44.0 github.com/google/uuid v1.3.0 github.com/jackc/pgx/v4 v4.18.1 - github.com/joho/godotenv v1.5.1 github.com/swaggo/swag v1.16.1 golang.org/x/crypto v0.8.0 ) diff --git a/go.sum b/go.sum index b952d2b..6a1aaee 100644 --- a/go.sum +++ b/go.sum @@ -101,8 +101,6 @@ github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0f github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.3.0 h1:eHK/5clGOatcjX3oWGBO/MpxpbHzSwud5EWTSCI+MX0= github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= -github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= diff --git a/pkgs/db/accounts.go b/src/db/accounts.go similarity index 100% rename from pkgs/db/accounts.go rename to src/db/accounts.go diff --git a/pkgs/db/renewalTokens.go b/src/db/renewalTokens.go similarity index 97% rename from pkgs/db/renewalTokens.go rename to src/db/renewalTokens.go index 2917fa9..052edde 100644 --- a/pkgs/db/renewalTokens.go +++ b/src/db/renewalTokens.go @@ -3,7 +3,7 @@ package db import ( "context" - "gitea.larvit.se/pwrpln/auth-api/pkgs/utils" + "gitea.larvit.se/pwrpln/auth-api/src/utils" ) // RenewalTokenCreate obtain a new renewal token diff --git a/pkgs/db/types.go b/src/db/types.go similarity index 100% rename from pkgs/db/types.go rename to src/db/types.go diff --git a/docs/docs.go b/src/docs/docs.go similarity index 100% rename from docs/docs.go rename to src/docs/docs.go diff --git a/docs/swagger.json b/src/docs/swagger.json similarity index 100% rename from docs/swagger.json rename to src/docs/swagger.json diff --git a/docs/swagger.yaml b/src/docs/swagger.yaml similarity index 100% rename from docs/swagger.yaml rename to src/docs/swagger.yaml diff --git a/pkgs/handlers/delete.go b/src/handlers/delete.go similarity index 90% rename from pkgs/handlers/delete.go rename to src/handlers/delete.go index 86b482a..cc32cf1 100644 --- a/pkgs/handlers/delete.go +++ b/src/handlers/delete.go @@ -37,9 +37,10 @@ func (h Handlers) AccountDel(c *fiber.Ctx) error { err := h.Db.AccountDel(accountID) if err != nil { - if err.Error() == "No account found for given accountID" { + if err.Error() == "no account found for given accountID" { return c.Status(404).JSON([]ResJSONError{{Error: err.Error()}}) } else { + h.Log.Error("Database error when trying to remove account", "err", err.Error()) return c.Status(500).JSON([]ResJSONError{{Error: "Database error when trying to remove account"}}) } } diff --git a/pkgs/handlers/get.go b/src/handlers/get.go similarity index 100% rename from pkgs/handlers/get.go rename to src/handlers/get.go diff --git a/pkgs/handlers/helpers.go b/src/handlers/helpers.go similarity index 98% rename from pkgs/handlers/helpers.go rename to src/handlers/helpers.go index 06d3c8a..b43624c 100644 --- a/pkgs/handlers/helpers.go +++ b/src/handlers/helpers.go @@ -5,7 +5,7 @@ import ( "strings" "time" - "gitea.larvit.se/pwrpln/auth-api/pkgs/db" + "gitea.larvit.se/pwrpln/auth-api/src/db" jwt "github.com/dgrijalva/jwt-go" "github.com/gofiber/fiber/v2" ) diff --git a/pkgs/handlers/middlewares.go b/src/handlers/middlewares.go similarity index 100% rename from pkgs/handlers/middlewares.go rename to src/handlers/middlewares.go diff --git a/pkgs/handlers/post.go b/src/handlers/post.go similarity index 98% rename from pkgs/handlers/post.go rename to src/handlers/post.go index 2a73d33..2d1d162 100644 --- a/pkgs/handlers/post.go +++ b/src/handlers/post.go @@ -3,8 +3,8 @@ package handlers import ( "strings" - "gitea.larvit.se/pwrpln/auth-api/pkgs/db" - "gitea.larvit.se/pwrpln/auth-api/pkgs/utils" + "gitea.larvit.se/pwrpln/auth-api/src/db" + "gitea.larvit.se/pwrpln/auth-api/src/utils" "github.com/gofiber/fiber/v2" "github.com/google/uuid" ) diff --git a/pkgs/handlers/put.go b/src/handlers/put.go similarity index 97% rename from pkgs/handlers/put.go rename to src/handlers/put.go index 758fd95..f268d95 100644 --- a/pkgs/handlers/put.go +++ b/src/handlers/put.go @@ -1,7 +1,7 @@ package handlers import ( - "gitea.larvit.se/pwrpln/auth-api/pkgs/db" + "gitea.larvit.se/pwrpln/auth-api/src/db" "github.com/gofiber/fiber/v2" "github.com/google/uuid" ) diff --git a/pkgs/handlers/types.go b/src/handlers/types.go similarity index 95% rename from pkgs/handlers/types.go rename to src/handlers/types.go index 297e5ac..c6040c3 100644 --- a/pkgs/handlers/types.go +++ b/src/handlers/types.go @@ -1,7 +1,7 @@ package handlers import ( - "gitea.larvit.se/pwrpln/auth-api/pkgs/db" + "gitea.larvit.se/pwrpln/auth-api/src/db" "gitea.larvit.se/pwrpln/go_log" jwt "github.com/dgrijalva/jwt-go" ) diff --git a/main.go b/src/main.go similarity index 80% rename from main.go rename to src/main.go index 421a19f..dfb8ef9 100644 --- a/main.go +++ b/src/main.go @@ -6,21 +6,20 @@ import ( "strings" "time" - "gitea.larvit.se/pwrpln/auth-api/pkgs/db" - h "gitea.larvit.se/pwrpln/auth-api/pkgs/handlers" + "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/docs" + _ "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) { +func createAdminAccount(Db db.Db, log go_log.Log, ADMIN_API_KEY string) { adminAccountID, uuidErr := uuid.NewRandom() if uuidErr != nil { log.Error("Could not create new Uuid", "err", uuidErr.Error()) @@ -29,7 +28,7 @@ func createAdminAccount(Db db.Db, log go_log.Log) { _, adminAccountErr := Db.AccountCreate(db.AccountCreateInput{ ID: adminAccountID, Name: "admin", - APIKey: os.Getenv("ADMIN_API_KEY"), + APIKey: ADMIN_API_KEY, Password: "", Fields: []db.AccountCreateInputFields{{Name: "role", Values: []string{"admin"}}}, }) @@ -55,11 +54,6 @@ func createAdminAccount(Db db.Db, log go_log.Log) { 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\"") } @@ -79,13 +73,18 @@ func main() { log.MinLogLvl = minLogLvl } } + + ADMIN_API_KEY := os.Getenv("ADMIN_API_KEY") + WEB_BIND_HOST := os.Getenv("WEB_BIND_HOST") + DATABASE_URL := os.Getenv("DATABASE_URL") + jwtKey := []byte(os.Getenv("JWT_SHARED_SECRET")) - dbPool, err := pgxpool.Connect(context.Background(), os.Getenv("DATABASE_URL")) + dbPool, err := pgxpool.Connect(context.Background(), 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")) + dbPool, err = pgxpool.Connect(context.Background(), DATABASE_URL) } log.Verbose("Connected to PostgreSQL database") defer dbPool.Close() @@ -95,7 +94,7 @@ func main() { Db := db.Db{DbPool: dbPool, Log: log} handlers := h.Handlers{Db: Db, JwtKey: jwtKey, Log: log} - createAdminAccount(Db, log) + createAdminAccount(Db, log, ADMIN_API_KEY) // Log all requests app.Use(handlers.LogReq) @@ -116,14 +115,13 @@ func main() { app.Post("/renew-token", handlers.RenewToken) app.Put("/accounts/:accountID/fields", handlers.AccountUpdateFields) - log.Info("Starting web server", "WEB_BIND_HOST", os.Getenv("WEB_BIND_HOST")) + log.Info("Starting web server", "WEB_BIND_HOST", WEB_BIND_HOST) - webBindHost := os.Getenv("WEB_BIND_HOST") - err = app.Listen(webBindHost) + err = app.Listen(WEB_BIND_HOST) for err != nil { - log.Warn("Could not start web server", "err", err.Error(), "WEB_BIND_HOST", webBindHost) + log.Warn("Could not start web server", "err", err.Error(), "WEB_BIND_HOST", WEB_BIND_HOST) time.Sleep(1 * time.Second) - err = app.Listen(webBindHost) + err = app.Listen(WEB_BIND_HOST) } log.Info("Web server closed, shutting down") diff --git a/pkgs/utils/utils.go b/src/utils/utils.go similarity index 100% rename from pkgs/utils/utils.go rename to src/utils/utils.go diff --git a/tests/.env_example b/tests/.env_example index fb54241..55b07a6 100644 --- a/tests/.env_example +++ b/tests/.env_example @@ -1,3 +1,3 @@ ADMIN_API_KEY=hihi -AUTH_URL=http://localhost:4000 +AUTH_URL=http://127.0.0.1:4000 JWT_SHARED_SECRET=hihi diff --git a/tests/test-cases/00start.js b/tests/test-cases/00start.js index 1ceb81e..ad0da8a 100644 --- a/tests/test-cases/00start.js +++ b/tests/test-cases/00start.js @@ -6,7 +6,7 @@ import setConfig from '../test-helpers/config.js'; test('test-cases/00start.js: Wait for auth API to be ready', async t => { setConfig({ printConfig: true }); - const backendHealthCheck = await got(process.env.AUTH_URL, { retry: 2000 }); + const backendHealthCheck = await got(process.env.AUTH_URL, { retry: { limit: 2000 }}); t.equal(backendHealthCheck.statusCode, 200, 'Auth API should answer with status code 200'); }); diff --git a/tests/test-cases/01basic.js b/tests/test-cases/01basic.js index 3a68780..42dc2fe 100644 --- a/tests/test-cases/01basic.js +++ b/tests/test-cases/01basic.js @@ -54,7 +54,7 @@ test('test-cases/01basic.js: GETting the admin account, with the token we just o }); test('test-cases/01basic.js: Creating a new account', async t => { - const res = await got.post(`${process.env.AUTH_URL}/account`, { + const res = await got.post(`${process.env.AUTH_URL}/accounts`, { headers: { 'Authorization': `bearer ${adminJWTString}`}, json: { fields: [ @@ -79,7 +79,7 @@ test('test-cases/01basic.js: Creating a new account', async t => { t.notEqual(user.apiKey, undefined, 'The new account should have an apiKey'); try { - await got.post(`${process.env.AUTH_URL}/account`, { + await got.post(`${process.env.AUTH_URL}/accounts`, { headers: { 'Authorization': `bearer ${adminJWTString}`}, json: { fields: [{name: 'role',values: ['user'],}], @@ -187,7 +187,7 @@ test('test-cases/01basic.js: Remove an account', async t => { await got.delete(`${process.env.AUTH_URL}/accounts/a423e690-74b9-4f37-9976-f5bf75a5ea32`, { headers: { 'Authorization': `bearer ${adminJWTString}`}, responseType: 'json', - retry: 0, + retry: { limit: 0 }, }); t.fail('Response status for DELETing an account that does not exist should be 404'); } catch (err) { @@ -197,7 +197,7 @@ test('test-cases/01basic.js: Remove an account', async t => { const delRes = await got.delete(`${process.env.AUTH_URL}/accounts/${user.id}`, { headers: { 'Authorization': `bearer ${adminJWTString}`}, responseType: 'json', - retry: 0, + retry: { limit: 0 }, }); t.equal(delRes.statusCode, 204, 'Response status for DELETE should be 204'); @@ -206,7 +206,7 @@ test('test-cases/01basic.js: Remove an account', async t => { await got(`${process.env.AUTH_URL}/accounts/${user.id}`, { headers: { 'Authorization': `bearer ${adminJWTString}`}, responseType: 'json', - retry: 0, + retry: { limit: 0 }, }); t.fail('Response status for GETing the account again should be 404'); } catch (err) {