Skip to content

Commit f19931a

Browse files
authored
all: properly implement regenerate session ID (#115)
1 parent 15e62f0 commit f19931a

21 files changed

+175
-96
lines changed

.golangci.yml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,16 @@ linters-settings:
44

55
linters:
66
enable:
7-
- deadcode
87
- errcheck
98
- gosimple
109
- govet
1110
- ineffassign
1211
- staticcheck
13-
- structcheck
1412
- typecheck
1513
- unused
16-
- varcheck
1714
- nakedret
1815
- gofmt
1916
- rowserrcheck
2017
- unconvert
2118
- goimports
19+
- unused

file.go

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,18 +22,21 @@ type fileStore struct {
2222
nowFunc func() time.Time // The function to return the current time
2323
lifetime time.Duration // The duration to have no access to a session before being recycled
2424
rootDir string // The root directory of file session items stored on the local file system
25-
encoder Encoder // The encoder to encode the session data before saving
26-
decoder Decoder // The decoder to decode binary to session data after reading
25+
26+
encoder Encoder
27+
decoder Decoder
28+
idWriter IDWriter
2729
}
2830

2931
// newFileStore returns a new file session store based on given configuration.
30-
func newFileStore(cfg FileConfig) *fileStore {
32+
func newFileStore(cfg FileConfig, idWriter IDWriter) *fileStore {
3133
return &fileStore{
3234
nowFunc: cfg.nowFunc,
3335
lifetime: cfg.Lifetime,
3436
rootDir: cfg.RootDir,
3537
encoder: cfg.Encoder,
3638
decoder: cfg.Decoder,
39+
idWriter: idWriter,
3740
}
3841
}
3942

@@ -70,7 +73,7 @@ func (s *fileStore) Read(_ context.Context, sid string) (Session, error) {
7073
return nil, errors.Wrap(err, "create parent directory")
7174
}
7275

73-
return NewBaseSession(sid, s.encoder), nil
76+
return NewBaseSession(sid, s.encoder, s.idWriter), nil
7477
}
7578

7679
// Discard existing data if it's expired
@@ -79,7 +82,7 @@ func (s *fileStore) Read(_ context.Context, sid string) (Session, error) {
7982
return nil, errors.Wrap(err, "stat file")
8083
}
8184
if !fi.ModTime().Add(s.lifetime).After(s.nowFunc()) {
82-
return NewBaseSession(sid, s.encoder), nil
85+
return NewBaseSession(sid, s.encoder, s.idWriter), nil
8386
}
8487

8588
binary, err := os.ReadFile(filename)
@@ -91,7 +94,7 @@ func (s *fileStore) Read(_ context.Context, sid string) (Session, error) {
9194
if err != nil {
9295
return nil, errors.Wrap(err, "decode")
9396
}
94-
return NewBaseSessionWithData(sid, s.encoder, data), nil
97+
return NewBaseSessionWithData(sid, s.encoder, s.idWriter, data), nil
9598
}
9699

97100
func (s *fileStore) Destroy(_ context.Context, sid string) error {
@@ -169,7 +172,7 @@ func (s *fileStore) GC(ctx context.Context) error {
169172

170173
// FileConfig contains options for the file session store.
171174
type FileConfig struct {
172-
// For tests only
175+
// For tests only.
173176
nowFunc func() time.Time
174177

175178
// Lifetime is the duration to have no access to a session before being
@@ -188,12 +191,18 @@ type FileConfig struct {
188191
func FileIniter() Initer {
189192
return func(ctx context.Context, args ...interface{}) (Store, error) {
190193
var cfg *FileConfig
194+
var idWriter IDWriter
191195
for i := range args {
192196
switch v := args[i].(type) {
193197
case FileConfig:
194198
cfg = &v
199+
case IDWriter:
200+
idWriter = v
195201
}
196202
}
203+
if idWriter == nil {
204+
return nil, errors.New("IDWriter not given")
205+
}
197206

198207
if cfg == nil {
199208
return nil, fmt.Errorf("config object with the type '%T' not found", FileConfig{})
@@ -214,6 +223,6 @@ func FileIniter() Initer {
214223
cfg.Decoder = GobDecoder
215224
}
216225

217-
return newFileStore(*cfg), nil
226+
return newFileStore(*cfg, idWriter), nil
218227
}
219228
}

file_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ func TestFileStore_GC(t *testing.T) {
9191
RootDir: filepath.Join(os.TempDir(), "sessions"),
9292
Lifetime: time.Second,
9393
},
94+
IDWriter(func(http.ResponseWriter, *http.Request, string) {}),
9495
)
9596
require.Nil(t, err)
9697

@@ -137,6 +138,7 @@ func TestFileStore_Touch(t *testing.T) {
137138
RootDir: filepath.Join(os.TempDir(), "sessions"),
138139
Lifetime: time.Second,
139140
},
141+
IDWriter(func(http.ResponseWriter, *http.Request, string) {}),
140142
)
141143
require.Nil(t, err)
142144

go.mod

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ go 1.18
44

55
require (
66
github.com/flamego/flamego v1.9.4
7-
github.com/go-redis/redis/v8 v8.11.5
87
github.com/go-sql-driver/mysql v1.8.1
98
github.com/jackc/pgx/v5 v5.5.5
109
github.com/pkg/errors v0.9.1
10+
github.com/redis/go-redis/v9 v9.5.1
1111
github.com/stretchr/testify v1.9.0
1212
go.mongodb.org/mongo-driver v1.14.0
1313
modernc.org/sqlite v1.29.5
@@ -17,7 +17,7 @@ require (
1717
filippo.io/edwards25519 v1.1.0 // indirect
1818
github.com/alecthomas/participle/v2 v2.0.0 // indirect
1919
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
20-
github.com/cespare/xxhash/v2 v2.1.2 // indirect
20+
github.com/cespare/xxhash/v2 v2.2.0 // indirect
2121
github.com/charmbracelet/lipgloss v0.7.1 // indirect
2222
github.com/charmbracelet/log v0.2.3 // indirect
2323
github.com/davecgh/go-spew v1.1.1 // indirect
@@ -49,7 +49,6 @@ require (
4949
github.com/xdg-go/stringprep v1.0.4 // indirect
5050
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
5151
golang.org/x/crypto v0.18.0 // indirect
52-
golang.org/x/net v0.20.0 // indirect
5352
golang.org/x/sync v0.6.0 // indirect
5453
golang.org/x/sys v0.16.0 // indirect
5554
golang.org/x/text v0.14.0 // indirect

go.sum

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ github.com/alecthomas/participle/v2 v2.0.0/go.mod h1:rAKZdJldHu8084ojcWevWAL8KmE
66
github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk=
77
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
88
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
9-
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
10-
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
9+
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
10+
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
11+
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
12+
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
1113
github.com/charmbracelet/lipgloss v0.7.1 h1:17WMwi7N1b1rVWOjMT+rCh7sQkvDU75B2hbZpc5Kc1E=
1214
github.com/charmbracelet/lipgloss v0.7.1/go.mod h1:yG0k3giv8Qj8edTCbbg6AlQ5e8KNWpFujkNawKNhE2c=
1315
github.com/charmbracelet/log v0.2.3 h1:YVmBhJtpGL7nW/nlf5u+SEloU8XYljxozGzZpgwIvhs=
@@ -22,11 +24,8 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp
2224
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
2325
github.com/flamego/flamego v1.9.4 h1:SNsooIfNa6ljQM1rBmfg4cFcXPIhQdG/uvNHqXxPvD8=
2426
github.com/flamego/flamego v1.9.4/go.mod h1:2tAVbugA3fgX8xOBoqR2jmJSSvZDLBFGXTFCR5h5eAU=
25-
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
2627
github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
2728
github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
28-
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
29-
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
3029
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
3130
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
3231
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
@@ -71,13 +70,12 @@ github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo
7170
github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
7271
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
7372
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
74-
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
75-
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
76-
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
7773
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
7874
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
7975
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
8076
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
77+
github.com/redis/go-redis/v9 v9.5.1 h1:H1X4D3yHPaYrkL5X06Wh6xNVM/pX0Ft4RV0vMGvLBh8=
78+
github.com/redis/go-redis/v9 v9.5.1/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M=
8179
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
8280
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
8381
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
@@ -110,8 +108,6 @@ golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
110108
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
111109
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
112110
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
113-
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
114-
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
115111
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
116112
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
117113
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
@@ -141,8 +137,6 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
141137
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
142138
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
143139
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
144-
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
145-
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
146140
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
147141
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
148142
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

manager_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ func TestIsValidSessionID(t *testing.T) {
2626
}
2727

2828
func TestManager_startGC(t *testing.T) {
29-
m := newManager(newMemoryStore(MemoryConfig{}))
29+
m := newManager(newMemoryStore(MemoryConfig{}, nil))
3030
stop := m.startGC(
3131
context.Background(),
3232
time.Minute,

memory.go

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import (
99
"context"
1010
"sync"
1111
"time"
12+
13+
"github.com/pkg/errors"
1214
)
1315

1416
var _ Session = (*memorySession)(nil)
@@ -24,9 +26,9 @@ type memorySession struct {
2426
}
2527

2628
// newMemorySession returns a new memory session with given session ID.
27-
func newMemorySession(sid string) *memorySession {
29+
func newMemorySession(sid string, idWriter IDWriter) *memorySession {
2830
return &memorySession{
29-
BaseSession: NewBaseSession(sid, nil),
31+
BaseSession: NewBaseSession(sid, nil, idWriter),
3032
}
3133
}
3234

@@ -52,15 +54,18 @@ type memoryStore struct {
5254
lock sync.RWMutex // The mutex to guard accesses to the heap and index
5355
heap []*memorySession // The heap to be managed by operations of heap.Interface
5456
index map[string]*memorySession // The index to be managed by operations of heap.Interface
57+
58+
idWriter IDWriter
5559
}
5660

5761
// newMemoryStore returns a new memory session store based on given
5862
// configuration.
59-
func newMemoryStore(cfg MemoryConfig) *memoryStore {
63+
func newMemoryStore(cfg MemoryConfig, idWriter IDWriter) *memoryStore {
6064
return &memoryStore{
6165
nowFunc: cfg.nowFunc,
6266
lifetime: cfg.Lifetime,
6367
index: make(map[string]*memorySession),
68+
idWriter: idWriter,
6469
}
6570
}
6671

@@ -136,7 +141,7 @@ func (s *memoryStore) Read(_ context.Context, sid string) (Session, error) {
136141
return sess, nil
137142
}
138143

139-
sess = newMemorySession(sid)
144+
sess = newMemorySession(sid, s.idWriter)
140145
sess.SetLastAccessedAt(s.nowFunc())
141146
heap.Push(s, sess)
142147
return sess, nil
@@ -219,12 +224,18 @@ type MemoryConfig struct {
219224
func MemoryIniter() Initer {
220225
return func(_ context.Context, args ...interface{}) (Store, error) {
221226
var cfg *MemoryConfig
227+
var idWriter IDWriter
222228
for i := range args {
223229
switch v := args[i].(type) {
224230
case MemoryConfig:
225231
cfg = &v
232+
case IDWriter:
233+
idWriter = v
226234
}
227235
}
236+
if idWriter == nil {
237+
return nil, errors.New("IDWriter not given")
238+
}
228239

229240
if cfg == nil {
230241
cfg = &MemoryConfig{}
@@ -237,6 +248,6 @@ func MemoryIniter() Initer {
237248
cfg.Lifetime = 3600 * time.Second
238249
}
239250

240-
return newMemoryStore(*cfg), nil
251+
return newMemoryStore(*cfg, idWriter), nil
241252
}
242253
}

memory_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ func TestMemoryStore_GC(t *testing.T) {
8080
nowFunc: func() time.Time { return now },
8181
Lifetime: time.Second,
8282
},
83+
nil,
8384
)
8485

8586
sess1, err := store.Read(ctx, "1")
@@ -125,6 +126,7 @@ func TestMemoryStore_Touch(t *testing.T) {
125126
nowFunc: func() time.Time { return now },
126127
Lifetime: time.Second,
127128
},
129+
nil,
128130
)
129131

130132
sess, err := store.Read(ctx, "1")

mongo/mongo.go

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,19 +26,22 @@ type mongoStore struct {
2626
lifetime time.Duration // The duration to have access to a session before being recycled
2727
db *mongo.Database // The database connection
2828
collection string // The database collection for storing session data
29-
encoder session.Encoder // The encoder to encode the session data before saving
30-
decoder session.Decoder // The decoder to decode binary to session data after reading
29+
30+
encoder session.Encoder
31+
decoder session.Decoder
32+
idWriter session.IDWriter
3133
}
3234

3335
// newMongoStore returns a new MongoDB session store based on given configuration.
34-
func newMongoStore(cfg Config) *mongoStore {
36+
func newMongoStore(cfg Config, idWriter session.IDWriter) *mongoStore {
3537
return &mongoStore{
3638
nowFunc: cfg.nowFunc,
3739
lifetime: cfg.Lifetime,
3840
db: cfg.db,
3941
collection: cfg.Collection,
4042
encoder: cfg.Encoder,
4143
decoder: cfg.Decoder,
44+
idWriter: idWriter,
4245
}
4346
}
4447

@@ -63,19 +66,19 @@ func (s *mongoStore) Read(ctx context.Context, sid string) (session.Session, err
6366

6467
// Discard existing data if it's expired
6568
if !s.nowFunc().Before(expiredAt.Time().Add(s.lifetime)) {
66-
return session.NewBaseSession(sid, s.encoder), nil
69+
return session.NewBaseSession(sid, s.encoder, s.idWriter), nil
6770
}
6871

6972
data, err := s.decoder(binary.Data)
7073
if err != nil {
7174
return nil, errors.Wrap(err, "decode")
7275
}
73-
return session.NewBaseSessionWithData(sid, s.encoder, data), nil
76+
return session.NewBaseSessionWithData(sid, s.encoder, s.idWriter, data), nil
7477
} else if err != mongo.ErrNoDocuments {
7578
return nil, errors.Wrap(err, "find")
7679
}
7780

78-
return session.NewBaseSession(sid, s.encoder), nil
81+
return session.NewBaseSession(sid, s.encoder, s.idWriter), nil
7982
}
8083

8184
func (s *mongoStore) Destroy(ctx context.Context, sid string) error {
@@ -157,12 +160,18 @@ type Config struct {
157160
func Initer() session.Initer {
158161
return func(ctx context.Context, args ...interface{}) (session.Store, error) {
159162
var cfg *Config
163+
var idWriter session.IDWriter
160164
for i := range args {
161165
switch v := args[i].(type) {
162166
case Config:
163167
cfg = &v
168+
case session.IDWriter:
169+
idWriter = v
164170
}
165171
}
172+
if idWriter == nil {
173+
return nil, errors.New("IDWriter not given")
174+
}
166175

167176
if cfg == nil {
168177
return nil, fmt.Errorf("config object with the type '%T' not found", Config{})
@@ -194,6 +203,6 @@ func Initer() session.Initer {
194203
cfg.Decoder = session.GobDecoder
195204
}
196205

197-
return newMongoStore(*cfg), nil
206+
return newMongoStore(*cfg, idWriter), nil
198207
}
199208
}

0 commit comments

Comments
 (0)