From 9002151739e86574f6aa331a7125b833191c0542 Mon Sep 17 00:00:00 2001 From: Sergey Chubaryan Date: Sat, 27 Jul 2024 17:03:40 +0300 Subject: [PATCH 1/2] =?UTF-8?q?=D0=B4=D0=BE=D0=B4=D0=B5=D0=BB=D0=B0=D0=BD?= =?UTF-8?q?=20=D0=BA=D0=BE=D0=BD=D1=84=D0=B8=D0=B3=20=D1=87=D0=B5=D1=80?= =?UTF-8?q?=D0=B5=D0=B7=20=D1=84=D0=B0=D0=B9=D0=BB,=20=D0=B4=D0=BE=D0=B1?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=20=D1=82=D0=B5=D1=81=D1=82=D0=BE?= =?UTF-8?q?=D0=B2=D1=8B=D0=B9=20=D0=BA=D0=BE=D0=BD=D1=84=D0=B8=D0=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/config.go | 25 +++++++++++++++++ config/new.go | 10 +++++++ config/parser.go | 46 ++++++++++++++++++++++++++++++ config_example/config.yaml | 3 ++ config_example/jwt_signing_key | 51 ++++++++++++++++++++++++++++++++++ main.go | 29 +++++++++++++------ 6 files changed, 155 insertions(+), 9 deletions(-) create mode 100644 config/config.go create mode 100644 config/new.go create mode 100644 config/parser.go create mode 100644 config_example/config.yaml create mode 100644 config_example/jwt_signing_key diff --git a/config/config.go b/config/config.go new file mode 100644 index 0000000..adba7e8 --- /dev/null +++ b/config/config.go @@ -0,0 +1,25 @@ +package config + +type IConfig interface { + GetPort() uint16 + GetPostgresUrl() string + GetJwtSigningKey() string +} + +type Config struct { + Port uint16 `yaml:"port"` + PostgresUrl string `yaml:"postgres_url"` + JwtSigningKey string `yaml:"jwt_signing_key" validate:"file"` +} + +func (c *Config) GetPort() uint16 { + return c.Port +} + +func (c *Config) GetPostgresUrl() string { + return c.PostgresUrl +} + +func (c *Config) GetJwtSigningKey() string { + return c.JwtSigningKey +} diff --git a/config/new.go b/config/new.go new file mode 100644 index 0000000..6a52c39 --- /dev/null +++ b/config/new.go @@ -0,0 +1,10 @@ +package config + +func NewFromFile(path string) (IConfig, error) { + p := NewParser[Config]() + config, err := p.ParseFile(path) + if err != nil { + return nil, err + } + return &config, nil +} diff --git a/config/parser.go b/config/parser.go new file mode 100644 index 0000000..d0e6cb1 --- /dev/null +++ b/config/parser.go @@ -0,0 +1,46 @@ +package config + +import ( + "os" + + "github.com/go-playground/validator/v10" + "gopkg.in/yaml.v3" +) + +type Parser[T interface{}] interface { + ParseFile(path string) (T, error) +} + +func NewParser[T interface{}]() Parser[T] { + validate := validator.New(validator.WithRequiredStructEnabled()) + return &parser[T]{ + validate: validate, + } +} + +type parser[T interface{}] struct { + validate *validator.Validate +} + +func (p *parser[T]) ParseFile(path string) (T, error) { + fBytes, err := os.ReadFile(path) + if err != nil { + var t T + return t, err + } + + return p.parse(fBytes) +} + +func (p *parser[T]) parse(b []byte) (T, error) { + var t T + + if err := yaml.Unmarshal(b, &t); err != nil { + return t, err + } + if err := p.validate.Struct(t); err != nil { + return t, err + } + + return t, nil +} diff --git a/config_example/config.yaml b/config_example/config.yaml new file mode 100644 index 0000000..eb20078 --- /dev/null +++ b/config_example/config.yaml @@ -0,0 +1,3 @@ +port: 8080 +postgres_url: "postgres://postgres:postgres@localhost:5432/postgres" +jwt_signing_key: "./config_example/jwt_signing_key" \ No newline at end of file diff --git a/config_example/jwt_signing_key b/config_example/jwt_signing_key new file mode 100644 index 0000000..6416a98 --- /dev/null +++ b/config_example/jwt_signing_key @@ -0,0 +1,51 @@ +-----BEGIN PRIVATE KEY----- +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 +-----END PRIVATE KEY----- diff --git a/main.go b/main.go index f508396..5c5282e 100644 --- a/main.go +++ b/main.go @@ -1,14 +1,17 @@ package main import ( + "backend/config" "backend/src/handlers" "backend/src/middleware" "backend/src/models" "backend/src/repo" "backend/src/services" "backend/src/utils" - "crypto/rand" - "crypto/rsa" + "crypto/x509" + "encoding/pem" + "fmt" + "os" "github.com/gin-gonic/gin" "github.com/jackc/pgx" @@ -16,16 +19,24 @@ import ( ) func main() { - key, err := rsa.GenerateKey(rand.Reader, 4096) + conf, err := config.NewFromFile("./config_example/config.yaml") if err != nil { panic(err) } - // keyBytes, err := x509.MarshalPKCS8PrivateKey(key) - // if err != nil { - // panic(err) - // } - connConf, err := pgx.ParseConnectionString("postgres://postgres:postgres@localhost:5432/postgres") + keyRawBytes, err := os.ReadFile(conf.GetJwtSigningKey()) + if err != nil { + panic(err) + } + + keyPem, _ := pem.Decode(keyRawBytes) + key, err := x509.ParsePKCS1PrivateKey(keyPem.Bytes) + if err != nil { + panic(err) + } + + pgConnStr := conf.GetPostgresUrl() + connConf, err := pgx.ParseConnectionString(pgConnStr) if err != nil { panic(err) } @@ -61,5 +72,5 @@ func main() { dummyGroup.Use(middleware.NewAuthMiddleware(userService)) dummyGroup.GET("/", handlers.NewDummyHandler()) - r.Run(":8080") + r.Run(fmt.Sprintf(":%d", conf.GetPort())) } From 843695f3f921252d5fac1b0478a1c3d65753b3f0 Mon Sep 17 00:00:00 2001 From: Sergey Chubaryan Date: Sat, 27 Jul 2024 17:31:41 +0300 Subject: [PATCH 2/2] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D1=8B=20=D1=82=D0=B5=D1=81=D1=82=D1=8B=20=D0=B4=D0=BB?= =?UTF-8?q?=D1=8F=20=D0=BA=D0=BE=D0=BD=D1=84=D0=B8=D0=B3=20=D0=BF=D0=B0?= =?UTF-8?q?=D1=80=D1=81=D0=B5=D1=80=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/config_test.go | 43 +++++++++++++++++++++++++++++++++++++++++++ go.mod | 7 +++++-- 2 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 config/config_test.go diff --git a/config/config_test.go b/config/config_test.go new file mode 100644 index 0000000..8badd02 --- /dev/null +++ b/config/config_test.go @@ -0,0 +1,43 @@ +package config + +import ( + "os" + "testing" + + "github.com/stretchr/testify/assert" +) + +const testParserConf = ` +token: "test_token" +url: test.url +port: 5010 +` + +type TestConf struct { + Token string `yaml:"token"` + Url string `yaml:"url"` + Port int `yaml:"port"` +} + +func TestParser(t *testing.T) { + file, err := os.CreateTemp("", "config") + if err != nil { + t.Fatal(err) + } + defer file.Close() + + _, err = file.WriteString(testParserConf) + if err != nil { + t.Fatal(err) + } + + p := NewParser[TestConf]() + conf, err := p.ParseFile(file.Name()) + if err != nil { + t.Fatal(err) + } + + assert.Equal(t, "test_token", conf.Token) + assert.Equal(t, "test.url", conf.Url) + assert.Equal(t, 5010, conf.Port) +} diff --git a/go.mod b/go.mod index 077aeee..71d1934 100644 --- a/go.mod +++ b/go.mod @@ -4,9 +4,12 @@ go 1.22.5 require ( github.com/gin-gonic/gin v1.10.0 + github.com/go-playground/validator/v10 v10.22.0 github.com/golang-jwt/jwt/v5 v5.2.1 github.com/jackc/pgx v3.6.2+incompatible + github.com/stretchr/testify v1.9.0 golang.org/x/crypto v0.25.0 + gopkg.in/yaml.v3 v3.0.1 ) require ( @@ -15,11 +18,11 @@ require ( github.com/cloudwego/base64x v0.1.4 // indirect github.com/cloudwego/iasm v0.2.0 // indirect github.com/cockroachdb/apd v1.1.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect github.com/gabriel-vasile/mimetype v1.4.4 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.22.0 // indirect github.com/goccy/go-json v0.10.3 // indirect github.com/gofrs/uuid v4.4.0+incompatible // indirect github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 // indirect @@ -33,6 +36,7 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect github.com/shopspring/decimal v1.4.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.12 // indirect @@ -42,5 +46,4 @@ require ( golang.org/x/text v0.16.0 // indirect google.golang.org/protobuf v1.34.2 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect )