Now accounts can be added
This commit is contained in:
parent
96ab03a5fb
commit
bb7e525adc
57
src/db/accounts.go
Normal file
57
src/db/accounts.go
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
package db
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AccountCreate writes a user to database
|
||||||
|
func (d Db) AccountCreate(input AccountCreateInput) (CreatedAccount, error) {
|
||||||
|
accountSQL := "INSERT INTO accounts (id, \"accountName\", \"apiKey\", password) VALUES($1,$2,$3,$4);"
|
||||||
|
|
||||||
|
_, err := d.DbPool.Exec(context.Background(), accountSQL, input.ID, input.AccountName, input.APIKey, input.Password)
|
||||||
|
if err != nil {
|
||||||
|
if strings.HasPrefix(err.Error(), "ERROR: duplicate key") {
|
||||||
|
log.WithFields(log.Fields{"accountName": input.AccountName}).Debug("Duplicate accountName in accounts database")
|
||||||
|
} else {
|
||||||
|
log.Error("Database error when trying to add account: " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return CreatedAccount{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"id": input.ID,
|
||||||
|
"accountName": input.AccountName,
|
||||||
|
}).Info("Added account to database")
|
||||||
|
|
||||||
|
accountFieldsSQL := "INSERT INTO \"accountsFields\" (id, \"accountId\", name, value) VALUES($1,$2,$3,$4);"
|
||||||
|
for _, field := range input.Fields {
|
||||||
|
newFieldID, uuidErr := uuid.NewRandom()
|
||||||
|
if uuidErr != nil {
|
||||||
|
log.Fatal("Could not create new Uuid, err: " + uuidErr.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := d.DbPool.Exec(context.Background(), accountFieldsSQL, newFieldID, input.ID, field.Name, field.Values)
|
||||||
|
if err != nil {
|
||||||
|
if strings.HasPrefix(err.Error(), "ERROR: duplicate key") {
|
||||||
|
log.Error("Database error when trying to account field: " + err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"accountId": input.ID,
|
||||||
|
"fieldName": field.Name,
|
||||||
|
"fieldValues": field.Values,
|
||||||
|
}).Debug("Added account field")
|
||||||
|
}
|
||||||
|
|
||||||
|
return CreatedAccount{
|
||||||
|
ID: input.ID,
|
||||||
|
AccountName: input.AccountName,
|
||||||
|
APIKey: input.APIKey,
|
||||||
|
}, nil
|
||||||
|
}
|
|
@ -5,8 +5,8 @@ import (
|
||||||
"github.com/jackc/pgx/v4/pgxpool"
|
"github.com/jackc/pgx/v4/pgxpool"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Account is an account in the system
|
// CreatedAccount is a newly created account in the system
|
||||||
type Account struct {
|
type CreatedAccount struct {
|
||||||
ID uuid.UUID `json:"id"`
|
ID uuid.UUID `json:"id"`
|
||||||
AccountName string `json:"accountName"`
|
AccountName string `json:"accountName"`
|
||||||
APIKey string `json:"apiKey"`
|
APIKey string `json:"apiKey"`
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package handlers
|
package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
@ -28,8 +27,6 @@ func (h Handlers) AccountCreate(c *fiber.Ctx) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println(accountInput)
|
|
||||||
|
|
||||||
var errors []ResJSONError
|
var errors []ResJSONError
|
||||||
|
|
||||||
if accountInput.AccountName == "" {
|
if accountInput.AccountName == "" {
|
||||||
|
|
75
src/main.go
Normal file
75
src/main.go
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/jackc/pgx/v4/pgxpool"
|
||||||
|
"github.com/joho/godotenv"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
"gitlab.larvit.se/power-plan/auth/src/db"
|
||||||
|
h "gitlab.larvit.se/power-plan/auth/src/handlers"
|
||||||
|
)
|
||||||
|
|
||||||
|
func createAdminAccount(Db db.Db) {
|
||||||
|
adminAccountID, uuidErr := uuid.NewRandom()
|
||||||
|
if uuidErr != nil {
|
||||||
|
log.Fatal("Could not create new Uuid, err: " + uuidErr.Error())
|
||||||
|
}
|
||||||
|
_, adminAccountErr := Db.AccountCreate(db.AccountCreateInput{
|
||||||
|
ID: adminAccountID,
|
||||||
|
AccountName: "admin",
|
||||||
|
APIKey: os.Getenv("ADMIN_API_KEY"),
|
||||||
|
Password: "",
|
||||||
|
})
|
||||||
|
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())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
err := godotenv.Load()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("Error loading .env file")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add this line for logging filename and line number!
|
||||||
|
// log.SetReportCaller(true)
|
||||||
|
log.SetLevel(log.DebugLevel)
|
||||||
|
|
||||||
|
dbPool, err := pgxpool.Connect(context.Background(), os.Getenv("DATABASE_URL"))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("Failed to open DB connection: ", err)
|
||||||
|
} else {
|
||||||
|
log.Info("Connected to PostgreSQL database")
|
||||||
|
}
|
||||||
|
defer dbPool.Close()
|
||||||
|
|
||||||
|
app := fiber.New()
|
||||||
|
|
||||||
|
Db := db.Db{DbPool: dbPool}
|
||||||
|
handlers := h.Handlers{Db: Db}
|
||||||
|
|
||||||
|
createAdminAccount(Db)
|
||||||
|
|
||||||
|
// Always require application/json
|
||||||
|
app.Use(handlers.RequireJSON)
|
||||||
|
|
||||||
|
app.Get("/", handlers.Hello)
|
||||||
|
app.Get("/account/:accountID", handlers.AccountGet)
|
||||||
|
app.Post("/account", handlers.AccountCreate)
|
||||||
|
app.Post("/auth/api-key", handlers.AccountAuthAPIKey)
|
||||||
|
|
||||||
|
log.WithFields(log.Fields{"WEB_BIND_HOST": os.Getenv("WEB_BIND_HOST")}).Info("Trying to start web server")
|
||||||
|
|
||||||
|
if err := app.Listen(os.Getenv("WEB_BIND_HOST")); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("Webb server closed, shutting down")
|
||||||
|
}
|
50
src/utils/utils.go
Normal file
50
src/utils/utils.go
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/rand"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
)
|
||||||
|
|
||||||
|
const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
|
const (
|
||||||
|
letterIdxBits = 6 // 6 bits to represent a letter index
|
||||||
|
letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
|
||||||
|
letterIdxMax = 63 / letterIdxBits // # of letter indices fitting in 63 bits
|
||||||
|
)
|
||||||
|
|
||||||
|
var src = rand.NewSource(time.Now().UnixNano())
|
||||||
|
|
||||||
|
// CheckPasswordHash checks a password hash
|
||||||
|
func CheckPasswordHash(password, hash string) bool {
|
||||||
|
err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
|
||||||
|
return err == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// HashPassword hashes a password
|
||||||
|
func HashPassword(password string) (string, error) {
|
||||||
|
bytes, err := bcrypt.GenerateFromPassword([]byte(password), 14)
|
||||||
|
return string(bytes), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// RandString generates a random string. Taken from https://stackoverflow.com/questions/22892120/how-to-generate-a-random-string-of-a-fixed-length-in-go (RandStringBytesMaskImprSrcSB())
|
||||||
|
func RandString(n int) string {
|
||||||
|
sb := strings.Builder{}
|
||||||
|
sb.Grow(n)
|
||||||
|
// A src.Int63() generates 63 random bits, enough for letterIdxMax characters!
|
||||||
|
for i, cache, remain := n-1, src.Int63(), letterIdxMax; i >= 0; {
|
||||||
|
if remain == 0 {
|
||||||
|
cache, remain = src.Int63(), letterIdxMax
|
||||||
|
}
|
||||||
|
if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
|
||||||
|
sb.WriteByte(letterBytes[idx])
|
||||||
|
i--
|
||||||
|
}
|
||||||
|
cache >>= letterIdxBits
|
||||||
|
remain--
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.String()
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user