Skip to content

Commit dad8d79

Browse files
committed
fix: fix unsafe type assertions, to avoid the panic
1 parent 3755f25 commit dad8d79

1 file changed

Lines changed: 66 additions & 19 deletions

File tree

  • pkg/publicshare/manager/json

‎pkg/publicshare/manager/json/json.go‎

Lines changed: 66 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,32 @@ import (
5151
"github.com/pkg/errors"
5252
)
5353

54+
// shareField and passwordField are the keys used to store a share's encoded
55+
// proto and its bcrypt-hashed password in a db entry.
56+
const (
57+
shareField = "share"
58+
passwordField = "password"
59+
)
60+
5461
func init() {
5562
registry.Register("json", NewFile)
5663
registry.Register("jsoncs3", NewCS3)
5764
registry.Register("jsonmemory", NewMemory)
5865
}
5966

67+
// dbEntryString safely reads the string value stored under key in a db entry.
68+
// Entries are read back from persistence as interface{} (map[string]interface{}
69+
// with string values), so a corrupted or legacy record can hold an unexpected
70+
// type; this reports that via ok instead of panicking.
71+
func dbEntryString(v interface{}, key string) (string, bool) {
72+
m, ok := v.(map[string]interface{})
73+
if !ok {
74+
return "", false
75+
}
76+
s, ok := m[key].(string)
77+
return s, ok
78+
}
79+
6080
// NewFile returns a new filesystem public shares manager.
6181
func NewFile(c map[string]interface{}) (publicshare.Manager, error) {
6282
conf := &fileConfig{}
@@ -239,10 +259,16 @@ func (m *manager) Dump(ctx context.Context, shareChan chan<- *publicshare.WithPa
239259

240260
for _, v := range db {
241261
var local publicshare.WithPassword
242-
if err := utils.UnmarshalJSONToProtoV1([]byte(v.(map[string]interface{})["share"].(string)), &local.PublicShare); err != nil {
243-
log.Error().Err(err).Msg("error unmarshalling share")
262+
if share, ok := dbEntryString(v, shareField); ok {
263+
if err := utils.UnmarshalJSONToProtoV1([]byte(share), &local.PublicShare); err != nil {
264+
log.Error().Err(err).Msg("error unmarshalling share")
265+
}
266+
} else {
267+
log.Error().Msg("error reading share entry: missing or invalid \"share\" field")
244268
}
245-
local.Password = v.(map[string]interface{})["password"].(string)
269+
// password is optional: shares without password protection have no
270+
// password field, so a missing/invalid entry just means "no password".
271+
local.Password, _ = dbEntryString(v, passwordField)
246272
shareChan <- &local
247273
}
248274

@@ -271,8 +297,8 @@ func (m *manager) Load(ctx context.Context, shareChan <-chan *publicshare.WithPa
271297
}
272298

273299
dbCopy[ps.PublicShare.Id.GetOpaqueId()] = map[string]interface{}{
274-
"share": string(encShare),
275-
"password": ps.Password,
300+
shareField: string(encShare),
301+
passwordField: ps.Password,
276302
}
277303
}
278304
return m.persistence.Write(ctx, dbCopy)
@@ -350,8 +376,8 @@ func (m *manager) CreatePublicShare(ctx context.Context, u *user.User, rInfo *pr
350376

351377
if _, ok := dbCopy[s.Id.GetOpaqueId()]; !ok {
352378
dbCopy[s.Id.GetOpaqueId()] = map[string]interface{}{
353-
"share": string(encShare),
354-
"password": ps.Password,
379+
shareField: string(encShare),
380+
passwordField: ps.Password,
355381
}
356382
} else {
357383
return nil, errors.New("key already exists")
@@ -448,9 +474,9 @@ func (m *manager) UpdatePublicShare(ctx context.Context, u *user.User, req *link
448474
}
449475

450476
if ok && passwordChanged {
451-
data["password"] = newPasswordEncoded
477+
data[passwordField] = newPasswordEncoded
452478
}
453-
data["share"] = string(encShare)
479+
data[shareField] = string(encShare)
454480

455481
dbCopy[share.Id.OpaqueId] = data
456482

@@ -491,11 +517,14 @@ func (m *manager) GetPublicShare(ctx context.Context, u *user.User, ref *link.Pu
491517
}
492518

493519
for _, v := range db {
494-
d := v.(map[string]interface{})["share"]
495-
passDB := v.(map[string]interface{})["password"].(string)
520+
share, ok := dbEntryString(v, shareField)
521+
if !ok {
522+
continue
523+
}
524+
passDB, _ := dbEntryString(v, passwordField)
496525

497526
var ps link.PublicShare
498-
if err := utils.UnmarshalJSONToProtoV1([]byte(d.(string)), &ps); err != nil {
527+
if err := utils.UnmarshalJSONToProtoV1([]byte(share), &ps); err != nil {
499528
return nil, err
500529
}
501530

@@ -547,7 +576,12 @@ func (m *manager) ListPublicShares(ctx context.Context, u *user.User, filters []
547576
shares := []*link.PublicShare{}
548577
for _, v := range db {
549578
var local publicShare
550-
if err := utils.UnmarshalJSONToProtoV1([]byte(v.(map[string]interface{})["share"].(string)), &local.PublicShare); err != nil {
579+
share, ok := dbEntryString(v, shareField)
580+
if !ok {
581+
log.Warn().Interface("entry", v).Msg("ListPublicShares: skipping entry with missing or invalid \"share\" field")
582+
continue
583+
}
584+
if err := utils.UnmarshalJSONToProtoV1([]byte(share), &local.PublicShare); err != nil {
551585
return nil, err
552586
}
553587

@@ -637,10 +671,13 @@ func (m *manager) cleanupExpiredShares() error {
637671

638672
var changed bool
639673
for id, v := range db {
640-
d := v.(map[string]interface{})["share"]
674+
share, ok := dbEntryString(v, shareField)
675+
if !ok {
676+
continue
677+
}
641678

642679
var ps link.PublicShare
643-
if err := utils.UnmarshalJSONToProtoV1([]byte(d.(string)), &ps); err != nil {
680+
if err := utils.UnmarshalJSONToProtoV1([]byte(share), &ps); err != nil {
644681
continue
645682
}
646683

@@ -705,13 +742,18 @@ func (m *manager) getByToken(ctx context.Context, token string) (*link.PublicSha
705742
}
706743

707744
for _, v := range db {
745+
share, ok := dbEntryString(v, shareField)
746+
if !ok {
747+
continue
748+
}
749+
708750
var local link.PublicShare
709-
if err := utils.UnmarshalJSONToProtoV1([]byte(v.(map[string]interface{})["share"].(string)), &local); err != nil {
751+
if err := utils.UnmarshalJSONToProtoV1([]byte(share), &local); err != nil {
710752
return nil, "", err
711753
}
712754

713755
if local.Token == token {
714-
passDB := v.(map[string]interface{})["password"].(string)
756+
passDB, _ := dbEntryString(v, passwordField)
715757
return &local, passDB, nil
716758
}
717759
}
@@ -734,9 +776,14 @@ func (m *manager) GetPublicShareByToken(ctx context.Context, token string, auth
734776
}
735777

736778
for _, v := range db {
737-
passDB := v.(map[string]interface{})["password"].(string)
779+
share, ok := dbEntryString(v, shareField)
780+
if !ok {
781+
continue
782+
}
783+
784+
passDB, _ := dbEntryString(v, passwordField)
738785
var local link.PublicShare
739-
if err := utils.UnmarshalJSONToProtoV1([]byte(v.(map[string]interface{})["share"].(string)), &local); err != nil {
786+
if err := utils.UnmarshalJSONToProtoV1([]byte(share), &local); err != nil {
740787
return nil, err
741788
}
742789

0 commit comments

Comments
 (0)