Added Configuration Management
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,3 +1,3 @@
|
|||||||
database.db
|
appdata
|
||||||
.idea
|
.idea
|
||||||
*.exe
|
*.exe
|
||||||
56
config/config.go
Normal file
56
config/config.go
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
Port string `yaml:"port"`
|
||||||
|
DatabasePath string `yaml:"database_path"`
|
||||||
|
}
|
||||||
|
|
||||||
|
const configPath = "./appdata/config.yaml"
|
||||||
|
|
||||||
|
func CheckIfExists() error {
|
||||||
|
_, err := os.Stat(configPath)
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if !os.IsNotExist(err) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Config file %s doesn't exist, creating...", configPath)
|
||||||
|
err = os.MkdirAll(filepath.Dir(configPath), 0755)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultConfig := Config{
|
||||||
|
Port: "8080",
|
||||||
|
DatabasePath: "./appdata/database.db",
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := yaml.Marshal(defaultConfig)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return os.WriteFile(configPath, data, 0644)
|
||||||
|
}
|
||||||
|
func LoadConfig() (Config, error) {
|
||||||
|
var cfg Config
|
||||||
|
|
||||||
|
file, err := os.ReadFile(configPath)
|
||||||
|
if err != nil {
|
||||||
|
return cfg, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = yaml.Unmarshal(file, &cfg)
|
||||||
|
return cfg, err
|
||||||
|
}
|
||||||
2
go.mod
2
go.mod
@@ -4,8 +4,10 @@ go 1.26.0
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/glebarez/go-sqlite v1.22.0
|
github.com/glebarez/go-sqlite v1.22.0
|
||||||
|
github.com/golang-jwt/jwt/v5 v5.3.1
|
||||||
github.com/google/uuid v1.6.0
|
github.com/google/uuid v1.6.0
|
||||||
golang.org/x/crypto v0.48.0
|
golang.org/x/crypto v0.48.0
|
||||||
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
|||||||
6
go.sum
6
go.sum
@@ -2,6 +2,8 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp
|
|||||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||||
github.com/glebarez/go-sqlite v1.22.0 h1:uAcMJhaA6r3LHMTFgP0SifzgXg46yJkgxqyuyec+ruQ=
|
github.com/glebarez/go-sqlite v1.22.0 h1:uAcMJhaA6r3LHMTFgP0SifzgXg46yJkgxqyuyec+ruQ=
|
||||||
github.com/glebarez/go-sqlite v1.22.0/go.mod h1:PlBIdHe0+aUEFn+r2/uthrWq4FxbzugL0L8Li6yQJbc=
|
github.com/glebarez/go-sqlite v1.22.0/go.mod h1:PlBIdHe0+aUEFn+r2/uthrWq4FxbzugL0L8Li6yQJbc=
|
||||||
|
github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY=
|
||||||
|
github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
|
||||||
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
|
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
|
||||||
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
|
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
@@ -15,6 +17,10 @@ golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVo
|
|||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
|
golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
|
||||||
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
modernc.org/libc v1.37.6 h1:orZH3c5wmhIQFTXF+Nt+eeauyd+ZIt2BX6ARe+kD+aw=
|
modernc.org/libc v1.37.6 h1:orZH3c5wmhIQFTXF+Nt+eeauyd+ZIt2BX6ARe+kD+aw=
|
||||||
modernc.org/libc v1.37.6/go.mod h1:YAXkAZ8ktnkCKaN9sw/UDeUVkGYJ/YquGO4FTi5nmHE=
|
modernc.org/libc v1.37.6/go.mod h1:YAXkAZ8ktnkCKaN9sw/UDeUVkGYJ/YquGO4FTi5nmHE=
|
||||||
modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
|
modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
|
||||||
|
|||||||
17
main.go
17
main.go
@@ -2,20 +2,21 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"shap-planner-backend/server"
|
||||||
"shap-planner-backend/handlers"
|
|
||||||
"shap-planner-backend/storage"
|
"shap-planner-backend/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
err := storage.InitDB("database.db")
|
var SERVER = server.InitServer()
|
||||||
|
|
||||||
|
err := storage.InitDB(SERVER.DatabasePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
http.HandleFunc("/register", handlers.Register)
|
SERVER.Run()
|
||||||
http.HandleFunc("/login", handlers.Login)
|
}
|
||||||
|
|
||||||
log.Println("Server läuft auf :8080")
|
func Setup() {
|
||||||
log.Fatal(http.ListenAndServe(":8080", nil))
|
//TODO: first configuration
|
||||||
}
|
}
|
||||||
|
|||||||
50
server/server.go
Normal file
50
server/server.go
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"shap-planner-backend/config"
|
||||||
|
"shap-planner-backend/handlers"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Server struct {
|
||||||
|
Port string
|
||||||
|
JWTSecret []byte
|
||||||
|
DatabasePath string
|
||||||
|
}
|
||||||
|
|
||||||
|
func InitServer() *Server {
|
||||||
|
|
||||||
|
err := config.CheckIfExists()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg, err := config.LoadConfig()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
jwtSecret := os.Getenv("SHAP_JWT_SECRET")
|
||||||
|
if jwtSecret == "" {
|
||||||
|
log.Fatal("SHAP_JWT_SECRET environment variable not set.")
|
||||||
|
}
|
||||||
|
if len(jwtSecret) < 32 {
|
||||||
|
log.Fatal("SHAP_JWT_SECRET must be at least 32 characters long.")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Server{
|
||||||
|
Port: cfg.Port,
|
||||||
|
JWTSecret: []byte(jwtSecret),
|
||||||
|
DatabasePath: cfg.DatabasePath,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (server *Server) Run() {
|
||||||
|
http.HandleFunc("/register", handlers.Register)
|
||||||
|
http.HandleFunc("/login", handlers.Login)
|
||||||
|
|
||||||
|
log.Printf("Listening on port %s", server.Port)
|
||||||
|
log.Fatal(http.ListenAndServe(":"+server.Port, nil))
|
||||||
|
}
|
||||||
@@ -1,20 +1,53 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/base64"
|
||||||
|
|
||||||
|
"github.com/golang-jwt/jwt/v5"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var secret = []byte(os.Getenv("SHAP_JWT_SECRET"))
|
||||||
|
|
||||||
|
// Password Validation
|
||||||
func HashPassword(password string) (string, error) {
|
func HashPassword(password string) (string, error) {
|
||||||
bytes, err := bcrypt.GenerateFromPassword([]byte(password), 14)
|
bytes, err := bcrypt.GenerateFromPassword([]byte(password), 14)
|
||||||
return string(bytes), err
|
return string(bytes), err
|
||||||
}
|
}
|
||||||
|
|
||||||
func CheckPasswordHash(password, hash string) bool {
|
func CheckPasswordHash(password, hash string) bool {
|
||||||
err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
|
err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
|
||||||
return err == nil
|
return err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// JWT Validation
|
||||||
|
func GenerateJWT(userID string) (string, error) {
|
||||||
|
claims := jwt.MapClaims{
|
||||||
|
"userId": userID,
|
||||||
|
"exp": time.Now().Add(time.Hour * 1).Unix(),
|
||||||
|
}
|
||||||
|
|
||||||
|
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||||
|
return token.SignedString(secret)
|
||||||
|
}
|
||||||
|
func ValidateJWT(tokenString string) (*jwt.Token, error) {
|
||||||
|
return jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
|
||||||
|
return secret, nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func GenerateUUID() string {
|
func GenerateUUID() string {
|
||||||
return uuid.New().String()
|
return uuid.New().String()
|
||||||
}
|
}
|
||||||
|
func GenerateSecret() string {
|
||||||
|
b := make([]byte, 64)
|
||||||
|
_, err := rand.Read(b)
|
||||||
|
if err != nil {
|
||||||
|
return err.Error()
|
||||||
|
}
|
||||||
|
return base64.StdEncoding.EncodeToString(b)
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user