Skip to content

Commit a1b0eb4

Browse files
committed
Improved store. Added data folder. Jwt signing key is now randomly created at runtime. Decided to use hclogger as default logger
1 parent 1ed0c54 commit a1b0eb4

File tree

7 files changed

+108
-25
lines changed

7 files changed

+108
-25
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,6 @@ yarn-error.log
2424
selenium-debug.log
2525
test/unit/coverage
2626
test/e2e/reports
27+
28+
# data folder generated by gaia
29+
data/

cmd/gaia/main.go

+17-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ package main
22

33
import (
44
"flag"
5+
"os"
56

7+
hclog "github.com/hashicorp/go-hclog"
68
"github.com/kataras/iris"
79
"github.com/michelvocks/gaia"
810
"github.com/michelvocks/gaia/handlers"
@@ -19,6 +21,7 @@ func init() {
1921

2022
// command line arguments
2123
flag.StringVar(&cfg.ListenPort, "port", "8080", "Listen port for gaia")
24+
flag.StringVar(&cfg.DataPath, "datapath", "data", "Path to the data folder")
2225
flag.StringVar(&cfg.Bolt.Path, "dbpath", "gaia.db", "Path to gaia bolt db file")
2326

2427
// Default values
@@ -29,18 +32,30 @@ func main() {
2932
// Parse command line flgs
3033
flag.Parse()
3134

35+
// Initialize shared logger
36+
cfg.Logger = hclog.New(&hclog.LoggerOptions{
37+
Level: hclog.Trace,
38+
Output: hclog.DefaultOutput,
39+
Name: "Gaia",
40+
})
41+
3242
// Initialize IRIS
3343
irisInstance = iris.New()
3444

3545
// Initialize store
3646
s := store.NewStore()
3747
err := s.Init(cfg)
3848
if err != nil {
39-
panic(err)
49+
cfg.Logger.Error("cannot initialize store", "error", err.Error())
50+
os.Exit(1)
4051
}
4152

4253
// Initialize handlers
43-
handlers.InitHandlers(irisInstance, s)
54+
err = handlers.InitHandlers(cfg, irisInstance, s)
55+
if err != nil {
56+
cfg.Logger.Error("cannot initialize handlers", "error", err.Error())
57+
os.Exit(1)
58+
}
4459

4560
// Start listen
4661
irisInstance.Run(iris.Addr(":" + cfg.ListenPort))

gaia.go

+4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package gaia
22

33
import (
44
"os"
5+
6+
hclog "github.com/hashicorp/go-hclog"
57
)
68

79
// User is the user object
@@ -16,6 +18,8 @@ type User struct {
1618
// Config holds all config options
1719
type Config struct {
1820
ListenPort string
21+
DataPath string
22+
Logger hclog.Logger
1923

2024
Bolt struct {
2125
Path string

handlers/User.go

+3-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package handlers
22

33
import (
4-
"log"
54
"time"
65

76
jwt "github.com/dgrijalva/jwt-go"
@@ -31,7 +30,7 @@ func UserLogin(ctx iris.Context) {
3130
// Authenticate user
3231
user, err := storeService.UserAuth(u)
3332
if err != nil {
34-
log.Printf("error during UserAuth: %s", err)
33+
cfg.Logger.Error("error during UserAuth: %s", err)
3534
ctx.StatusCode(iris.StatusInternalServerError)
3635
return
3736
}
@@ -55,11 +54,10 @@ func UserLogin(ctx iris.Context) {
5554
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
5655

5756
// Sign and get encoded token
58-
b := []byte{'f', '2', 'f', 'f', 's', 'h', 's'}
59-
tokenstring, err := token.SignedString(b)
57+
tokenstring, err := token.SignedString(jwtKey)
6058
if err != nil {
6159
ctx.StatusCode(iris.StatusInternalServerError)
62-
log.Printf("Error signing jwt token: %s", err)
60+
cfg.Logger.Error("error signing jwt token: %s", err)
6361
return
6462
}
6563
user.JwtExpiry = claims.ExpiresAt

handlers/handler.go

+23-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
package handlers
22

33
import (
4+
"crypto/rand"
5+
46
"github.com/kataras/iris"
7+
"github.com/michelvocks/gaia"
58
"github.com/michelvocks/gaia/store"
69
)
710

@@ -13,13 +16,32 @@ const (
1316
// Use this to talk to the store.
1417
var storeService *store.Store
1518

19+
// cfg is a pointer to the global config
20+
var cfg *gaia.Config
21+
22+
// jwtKey is a random generated key for jwt signing
23+
var jwtKey []byte
24+
1625
// InitHandlers initializes(registers) all handlers
17-
func InitHandlers(i *iris.Application, s *store.Store) {
26+
func InitHandlers(c *gaia.Config, i *iris.Application, s *store.Store) error {
27+
// Set config
28+
cfg = c
29+
1830
// Set store instance
1931
storeService = s
2032

33+
// Generate signing key for jwt
34+
jwtKey = make([]byte, 64)
35+
_, err := rand.Read(jwtKey)
36+
if err != nil {
37+
return err
38+
}
39+
cfg.Logger.Info("jwt signing key generated", "key", jwtKey)
40+
2141
// Define prefix
2242
p := "/api/" + apiVersion + "/"
2343

2444
i.Post(p+"users/login", UserLogin)
45+
46+
return nil
2547
}

store/store.go

+37-8
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ package store
33
import (
44
"encoding/json"
55
"fmt"
6+
"os"
67

78
bolt "github.com/coreos/bbolt"
89
"github.com/michelvocks/gaia"
10+
"golang.org/x/crypto/bcrypt"
911
)
1012

1113
var (
@@ -32,10 +34,18 @@ func NewStore() *Store {
3234
return s
3335
}
3436

35-
// UserUpdate takes the given user and saves it
37+
// UserPut takes the given user and saves it
3638
// to the bolt database. User will be overwritten
3739
// if it already exists.
38-
func (s *Store) UserUpdate(u *gaia.User) error {
40+
// It also clears the password field afterwards.
41+
func (s *Store) UserPut(u *gaia.User) error {
42+
// Encrypt password before we save it
43+
hash, err := bcrypt.GenerateFromPassword([]byte(u.Password), bcrypt.MinCost)
44+
if err != nil {
45+
return err
46+
}
47+
u.Password = string(hash)
48+
3949
return s.db.Update(func(tx *bolt.Tx) error {
4050
// Get bucket
4151
b := tx.Bucket(userBucket)
@@ -46,6 +56,9 @@ func (s *Store) UserUpdate(u *gaia.User) error {
4656
return err
4757
}
4858

59+
// Clear password from origin object
60+
u.Password = ""
61+
4962
// Put user
5063
return b.Put([]byte(u.Username), m)
5164
})
@@ -65,7 +78,7 @@ func (s *Store) UserAuth(u *gaia.User) (*gaia.User, error) {
6578
}
6679

6780
// Check if password is valid
68-
if user.Password != u.Password {
81+
if err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(u.Password)); err != nil {
6982
return nil, nil
7083
}
7184

@@ -102,16 +115,32 @@ func (s *Store) UserGet(username string) (*gaia.User, error) {
102115
return user, err
103116
}
104117

105-
// Init initalizes the connection to the database.
118+
// Init creates the data folder if not exists,
119+
// generates private key and bolt database.
106120
// This should be called only once per database
107121
// because bolt holds a lock on the database file.
108122
func (s *Store) Init(cfg *gaia.Config) error {
109-
db, err := bolt.Open(cfg.Bolt.Path, cfg.Bolt.Mode, nil)
123+
// Make sure data folder exists
124+
err := os.MkdirAll(cfg.DataPath, 0700)
125+
if err != nil {
126+
return err
127+
}
128+
129+
// Open connection to bolt database
130+
path := cfg.DataPath + string(os.PathSeparator) + cfg.Bolt.Path
131+
db, err := bolt.Open(path, cfg.Bolt.Mode, nil)
110132
if err != nil {
111133
return err
112134
}
113135
s.db = db
114136

137+
// Setup database
138+
return setupDatabase(s)
139+
}
140+
141+
// setupDatabase create all buckets in the db.
142+
// Additionally, it makes sure that the admin user exists.
143+
func setupDatabase(s *Store) error {
115144
// Create bucket if not exists function
116145
var bucketName []byte
117146
c := func(tx *bolt.Tx) error {
@@ -124,12 +153,12 @@ func (s *Store) Init(cfg *gaia.Config) error {
124153

125154
// Make sure buckets exist
126155
bucketName = userBucket
127-
err = db.Update(c)
156+
err := s.db.Update(c)
128157
if err != nil {
129158
return err
130159
}
131160
bucketName = pipelineBucket
132-
err = db.Update(c)
161+
err = s.db.Update(c)
133162
if err != nil {
134163
return err
135164
}
@@ -142,7 +171,7 @@ func (s *Store) Init(cfg *gaia.Config) error {
142171

143172
// Create admin user if we cannot find it
144173
if admin == nil {
145-
err = s.UserUpdate(&gaia.User{
174+
err = s.UserPut(&gaia.User{
146175
DisplayName: adminUsername,
147176
Username: adminUsername,
148177
Password: adminPassword,

store/store_test.go

+21-9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package store
22

33
import (
4+
"fmt"
45
"os"
56
"testing"
67

@@ -13,10 +14,19 @@ var config *gaia.Config
1314
func TestMain(m *testing.M) {
1415
store = NewStore()
1516
config = &gaia.Config{}
17+
config.DataPath = "data"
1618
config.Bolt.Path = "test.db"
1719
config.Bolt.Mode = 0600
1820

19-
os.Exit(m.Run())
21+
r := m.Run()
22+
23+
// cleanup
24+
err := os.Remove("data")
25+
if err != nil {
26+
fmt.Printf("cannot remove data folder: %s\n", err.Error())
27+
r = 1
28+
}
29+
os.Exit(r)
2030
}
2131

2232
func TestInit(t *testing.T) {
@@ -26,7 +36,7 @@ func TestInit(t *testing.T) {
2636
}
2737

2838
// cleanup
29-
err = os.Remove("test.db")
39+
err = os.Remove("data/test.db")
3040
if err != nil {
3141
t.Fatal(err)
3242
}
@@ -42,7 +52,7 @@ func TestUserGet(t *testing.T) {
4252
u.Username = "testuser"
4353
u.Password = "12345!#+21+"
4454
u.DisplayName = "Test"
45-
err = store.UserUpdate(u)
55+
err = store.UserPut(u)
4656
if err != nil {
4757
t.Fatal(err)
4858
}
@@ -64,13 +74,13 @@ func TestUserGet(t *testing.T) {
6474
}
6575

6676
// cleanup
67-
err = os.Remove("test.db")
77+
err = os.Remove("data/test.db")
6878
if err != nil {
6979
t.Fatal(err)
7080
}
7181
}
7282

73-
func TestUserUpdate(t *testing.T) {
83+
func TestUserPut(t *testing.T) {
7484
err := store.Init(config)
7585
if err != nil {
7686
t.Fatal(err)
@@ -80,13 +90,13 @@ func TestUserUpdate(t *testing.T) {
8090
u.Username = "testuser"
8191
u.Password = "12345!#+21+"
8292
u.DisplayName = "Test"
83-
err = store.UserUpdate(u)
93+
err = store.UserPut(u)
8494
if err != nil {
8595
t.Fatal(err)
8696
}
8797

8898
// cleanup
89-
err = os.Remove("test.db")
99+
err = os.Remove("data/test.db")
90100
if err != nil {
91101
t.Fatal(err)
92102
}
@@ -102,12 +112,14 @@ func TestUserAuth(t *testing.T) {
102112
u.Username = "testuser"
103113
u.Password = "12345!#+21+"
104114
u.DisplayName = "Test"
105-
err = store.UserUpdate(u)
115+
err = store.UserPut(u)
106116
if err != nil {
107117
t.Fatal(err)
108118
return
109119
}
110120

121+
// Password field has been cleared after last UserPut
122+
u.Password = "12345!#+21+"
111123
r, err := store.UserAuth(u)
112124
if err != nil {
113125
t.Fatal(err)
@@ -140,7 +152,7 @@ func TestUserAuth(t *testing.T) {
140152
}
141153

142154
// cleanup
143-
err = os.Remove("test.db")
155+
err = os.Remove("data/test.db")
144156
if err != nil {
145157
t.Fatal(err)
146158
}

0 commit comments

Comments
 (0)