Skip to content

Commit f6efb2c

Browse files
authored
Merge pull request #92 from cryptopay-dev/B2B-7314-force-ssl
[B2B-7314] Force SSL
2 parents afb97f6 + 8beec7e commit f6efb2c

File tree

5 files changed

+178
-29
lines changed

5 files changed

+178
-29
lines changed

.github/workflows/ci.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,19 @@ jobs:
1616
services:
1717
redis:
1818
image: redis
19+
postgres:
20+
image: postgres
21+
env:
22+
POSTGRES_PASSWORD: postgres
1923
steps:
2024
- name: Install common dependencies
2125
run: apk add --no-cache gcc libc-dev
2226
- uses: actions/checkout@v4
2327
- run: go test -v ./...
2428
env:
2529
REDIS_ADDR: redis:6379
30+
DATABASE_ADDR: postgres:5432
31+
DATABASE_USER: postgres
32+
DATABASE_PASSWORD: postgres
33+
DATABASE_DATABASE: postgres
34+
DATABASE_SSL: false

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,4 +76,5 @@ database:
7676
password: ""
7777
database: ""
7878
pool: 10
79+
ssl: true
7980
```

clients/pg.go

Lines changed: 92 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,16 @@ package clients
22

33
import (
44
"context"
5+
"crypto/tls"
6+
"database/sql"
7+
"errors"
8+
"fmt"
9+
"net/url"
10+
"strings"
511
"time"
612

7-
"github.com/go-pg/pg/v10"
13+
pg "github.com/go-pg/pg/v10"
14+
_ "github.com/lib/pq"
815
"github.com/sirupsen/logrus"
916
"github.com/spf13/viper"
1017
)
@@ -15,6 +22,16 @@ type (
1522
}
1623

1724
ctxKey int
25+
26+
dbConfig struct {
27+
addr string
28+
user string
29+
password string
30+
database string
31+
poolSize int
32+
ssl bool
33+
debug bool
34+
}
1835
)
1936

2037
const ctxRequestStartKey ctxKey = 1 + iota
@@ -43,24 +60,86 @@ func (d dbQueryHook) AfterQuery(ctx context.Context, event *pg.QueryEvent) error
4360
return nil
4461
}
4562

46-
func NewPostgreSQL(config *viper.Viper, logger *logrus.Logger) *pg.DB {
47-
config.SetDefault("database.pool", 10)
48-
config.SetDefault("database.debug", false)
63+
func NewPostgreSQL(config *viper.Viper, logger *logrus.Logger) (*pg.DB, error) {
64+
cfg, err := parseDBConfig(config)
65+
if err != nil {
66+
return nil, err
67+
}
4968

50-
connection := pg.Connect(&pg.Options{
51-
Addr: config.GetString("database.addr"),
52-
User: config.GetString("database.user"),
53-
Password: config.GetString("database.password"),
54-
Database: config.GetString("database.database"),
55-
PoolSize: config.GetInt("database.pool"),
56-
})
69+
opts := &pg.Options{
70+
Addr: cfg.addr,
71+
User: cfg.user,
72+
Password: cfg.password,
73+
Database: cfg.database,
74+
PoolSize: cfg.poolSize,
75+
}
5776

58-
if config.GetBool("database.debug") {
77+
if cfg.ssl {
78+
hp := strings.Split(cfg.addr, ":")
79+
if len(hp) != 2 {
80+
return nil, errors.New("database address has wrong format")
81+
}
82+
83+
opts.TLSConfig = &tls.Config{
84+
InsecureSkipVerify: false,
85+
ServerName: hp[0],
86+
}
87+
}
88+
89+
connection := pg.Connect(opts)
90+
91+
if cfg.debug {
5992
entry := logger.WithField("module", "db")
6093
connection.AddQueryHook(dbQueryHook{
6194
logger: entry,
6295
})
6396
}
6497

65-
return connection
98+
return connection, nil
99+
}
100+
101+
// NewPostgreSQLForMigrations is a connection that is used for migrations.
102+
// Migrations are implemented with `goose`, which supports only `*sql.DB`.
103+
func NewPostgreSQLForMigrations(config *viper.Viper) (*sql.DB, error) {
104+
cfg, err := parseDBConfig(config)
105+
if err != nil {
106+
return nil, err
107+
}
108+
109+
dsn := fmt.Sprintf(
110+
"postgres://%s:%s@%s/%s",
111+
cfg.user,
112+
strings.ReplaceAll(url.QueryEscape(cfg.password), ":", "%3A"),
113+
cfg.addr,
114+
cfg.database,
115+
)
116+
117+
if cfg.ssl {
118+
dsn += "?sslmode=verify-ca"
119+
} else {
120+
dsn += "?sslmode=disable"
121+
}
122+
123+
return sql.Open("postgres", dsn)
124+
}
125+
126+
func parseDBConfig(config *viper.Viper) (dbConfig, error) {
127+
config.SetDefault("database.pool", 10)
128+
config.SetDefault("database.debug", false)
129+
config.SetDefault("database.ssl", false)
130+
131+
dbAddr := config.GetString("database.addr")
132+
if dbAddr == "" {
133+
return dbConfig{}, errors.New("missing database address")
134+
}
135+
136+
return dbConfig{
137+
addr: dbAddr,
138+
user: config.GetString("database.user"),
139+
password: config.GetString("database.password"),
140+
database: config.GetString("database.database"),
141+
poolSize: config.GetInt("database.pool"),
142+
ssl: config.GetBool("database.ssl"),
143+
debug: config.GetBool("database.debug"),
144+
}, nil
66145
}

clients/pg_test.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package clients
2+
3+
import (
4+
"os"
5+
"testing"
6+
7+
"github.com/sirupsen/logrus"
8+
"github.com/spf13/viper"
9+
)
10+
11+
func TestNewPostgreSQL(t *testing.T) {
12+
if testing.Short() {
13+
t.Skip("skipping test in short mode")
14+
}
15+
16+
cfg := setupConfig()
17+
logger := logrus.New()
18+
19+
db, err := NewPostgreSQL(cfg, logger)
20+
if err != nil {
21+
t.Fatal(err)
22+
}
23+
24+
type StringResult struct {
25+
Message string
26+
}
27+
var res StringResult
28+
_, err = db.QueryOne(&res, "SELECT 'hello' AS message")
29+
if err != nil {
30+
t.Fatal(err)
31+
}
32+
33+
if res.Message != "hello" {
34+
t.Error("unexpected message")
35+
}
36+
}
37+
38+
func TestNewPostgreSQLForMigrations(t *testing.T) {
39+
if testing.Short() {
40+
t.Skip("skipping test in short mode")
41+
}
42+
43+
cfg := setupConfig()
44+
45+
db, err := NewPostgreSQLForMigrations(cfg)
46+
if err != nil {
47+
t.Fatal(err)
48+
}
49+
50+
type StringResult struct {
51+
Message string
52+
}
53+
var res StringResult
54+
err = db.QueryRow("SELECT 'hello' AS message").Scan(&res.Message)
55+
if err != nil {
56+
t.Fatal(err)
57+
}
58+
59+
if res.Message != "hello" {
60+
t.Error("unexpected message")
61+
}
62+
}
63+
64+
func setupConfig() *viper.Viper {
65+
cfg := viper.New()
66+
cfg.Set("database.addr", os.Getenv("DATABASE_ADDR"))
67+
cfg.Set("database.user", os.Getenv("DATABASE_USER"))
68+
cfg.Set("database.password", os.Getenv("DATABASE_PASSWORD"))
69+
cfg.Set("database.database", os.Getenv("DATABASE_DATABASE"))
70+
cfg.Set("database.ssl", os.Getenv("DATABASE_SSL"))
71+
72+
return cfg
73+
}

narada/commands/migrations.go

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
package commands
22

33
import (
4-
"database/sql"
54
"errors"
6-
"fmt"
75

86
"github.com/cryptopay-dev/narada"
7+
"github.com/cryptopay-dev/narada/clients"
98

109
"github.com/pressly/goose"
1110
"github.com/sirupsen/logrus"
@@ -31,7 +30,7 @@ func MigrateUp(p *narada.Narada) *cli.Command {
3130
logger.Println("starting migrations")
3231
dir := c.String("dir")
3332

34-
db, err := connect(v)
33+
db, err := clients.NewPostgreSQLForMigrations(v)
3534
if err != nil {
3635
return err
3736
}
@@ -61,7 +60,7 @@ func MigrateDown(p *narada.Narada) *cli.Command {
6160
logger.Println("rolling back migration")
6261
dir := c.String("dir")
6362

64-
db, err := connect(v)
63+
db, err := clients.NewPostgreSQLForMigrations(v)
6564
if err != nil {
6665
return err
6766
}
@@ -107,15 +106,3 @@ func CreateMigration(p *narada.Narada) *cli.Command {
107106
},
108107
}
109108
}
110-
111-
func connect(v *viper.Viper) (*sql.DB, error) {
112-
dsn := fmt.Sprintf(
113-
"postgres://%s:%s@%s/%s?sslmode=disable",
114-
v.GetString("database.user"),
115-
v.GetString("database.password"),
116-
v.GetString("database.addr"),
117-
v.GetString("database.database"),
118-
)
119-
120-
return sql.Open("postgres", dsn)
121-
}

0 commit comments

Comments
 (0)