Skip to content

Commit

Permalink
updated Dao.CanAccessRecord to return the invalid filter or db error
Browse files Browse the repository at this point in the history
  • Loading branch information
ganigeorgiev committed Jul 11, 2023
1 parent 7bb33d4 commit 3d3fe5c
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 24 deletions.
33 changes: 19 additions & 14 deletions daos/record.go
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ func (dao *Dao) FindFirstRecordByData(
// If the limit argument is <= 0, no limit is applied to the query and
// all matching records are returned.
//
// NB Don't put untrusted user input in the filter string as it
// NB! Don't put untrusted user input in the filter string as it
// practically would allow the users to inject their own custom filter.
//
// Example:
Expand Down Expand Up @@ -294,7 +294,7 @@ func (dao *Dao) FindRecordsByFilter(

// FindFirstRecordByFilter returns the first available record matching the provided filter.
//
// NB Don't put untrusted user input in the filter string as it
// NB! Don't put untrusted user input in the filter string as it
// practically would allow the users to inject their own custom filter.
//
// Example:
Expand Down Expand Up @@ -484,30 +484,35 @@ func (dao *Dao) SuggestUniqueAuthRecordUsername(
// CanAccessRecord checks if a record is allowed to be accessed by the
// specified requestData and accessRule.
//
// Always return false on invalid access rule or db error.
// Rule and db checks are ignored in case requestData.Admin is set.
//
// The returned error indicate that something unexpected happened during
// the check (eg. invalid rule or db error).
//
// The method always return false on invalid access rule or db error.
//
// Example:
//
// requestData := apis.RequestData(c /* echo.Context */)
// record, _ := dao.FindRecordById("example", "RECORD_ID")
// // custom rule
// // or use one of the record collection's, eg. record.Collection().ViewRule
// rule := types.Pointer("@request.auth.id != '' || status = 'public'")
// // ... or use one of the record collection's rule, eg. record.Collection().ViewRule
//
// canAccess := dao.CanAccessRecord(record, requestData, rule)
func (dao *Dao) CanAccessRecord(record *models.Record, requestData *models.RequestData, accessRule *string) bool {
// if ok, _ := dao.CanAccessRecord(record, requestData, rule); ok { ... }
func (dao *Dao) CanAccessRecord(record *models.Record, requestData *models.RequestData, accessRule *string) (bool, error) {
if requestData.Admin != nil {
// admins can access everything
return true
return true, nil
}

if accessRule == nil {
// only admins can access this record
return false
return false, nil
}

if *accessRule == "" {
return true // empty public rule, aka. everyone can access
// empty public rule, aka. everyone can access
return true, nil
}

var exists bool
Expand All @@ -520,16 +525,16 @@ func (dao *Dao) CanAccessRecord(record *models.Record, requestData *models.Reque
resolver := resolvers.NewRecordFieldResolver(dao, record.Collection(), requestData, true)
expr, err := search.FilterData(*accessRule).BuildExpr(resolver)
if err != nil {
return false
return false, err
}
resolver.UpdateQuery(query)
query.AndWhere(expr)

if err := query.Limit(1).Row(&exists); err != nil {
return false
if err := query.Limit(1).Row(&exists); err != nil && !errors.Is(err, sql.ErrNoRows) {
return false, err
}

return exists
return exists, nil
}

// SaveRecord persists the provided Record model in the database.
Expand Down
50 changes: 47 additions & 3 deletions daos/record_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,7 @@ func TestCanAccessRecord(t *testing.T) {
requestData *models.RequestData
rule *string
expected bool
expectError bool
}{
{
"as admin with nil rule",
Expand All @@ -616,6 +617,7 @@ func TestCanAccessRecord(t *testing.T) {
},
nil,
true,
false,
},
{
"as admin with non-empty rule",
Expand All @@ -625,27 +627,49 @@ func TestCanAccessRecord(t *testing.T) {
},
types.Pointer("id = ''"), // the filter rule should be ignored
true,
false,
},
{
"as admin with invalid rule",
record,
&models.RequestData{
Admin: admin,
},
types.Pointer("id ?!@ 1"), // the filter rule should be ignored
true,
false,
},
{
"as guest with nil rule",
record,
&models.RequestData{},
nil,
false,
false,
},
{
"as guest with empty rule",
nil,
record,
&models.RequestData{},
types.Pointer(""),
true,
false,
},
{
"as guest with invalid rule",
record,
&models.RequestData{},
types.Pointer("id ?!@ 1"),
false,
true,
},
{
"as guest with mismatched rule",
record,
&models.RequestData{},
types.Pointer("@request.auth.id != ''"),
false,
false,
},
{
"as guest with matched rule",
Expand All @@ -655,6 +679,7 @@ func TestCanAccessRecord(t *testing.T) {
},
types.Pointer("@request.auth.id != '' || @request.data.test = 1"),
true,
false,
},
{
"as auth record with nil rule",
Expand All @@ -664,15 +689,27 @@ func TestCanAccessRecord(t *testing.T) {
},
nil,
false,
false,
},
{
"as auth record with empty rule",
nil,
record,
&models.RequestData{
AuthRecord: authRecord,
},
types.Pointer(""),
true,
false,
},
{
"as auth record with invalid rule",
record,
&models.RequestData{
AuthRecord: authRecord,
},
types.Pointer("id ?!@ 1"),
false,
true,
},
{
"as auth record with mismatched rule",
Expand All @@ -683,6 +720,7 @@ func TestCanAccessRecord(t *testing.T) {
},
types.Pointer("@request.auth.id != '' && @request.data.test > 1"),
false,
false,
},
{
"as auth record with matched rule",
Expand All @@ -693,15 +731,21 @@ func TestCanAccessRecord(t *testing.T) {
},
types.Pointer("@request.auth.id != '' && @request.data.test > 1"),
true,
false,
},
}

for _, s := range scenarios {
result := app.Dao().CanAccessRecord(s.record, s.requestData, s.rule)
result, err := app.Dao().CanAccessRecord(s.record, s.requestData, s.rule)

if result != s.expected {
t.Errorf("[%s] Expected %v, got %v", s.name, s.expected, result)
}

hasErr := err != nil
if hasErr != s.expectError {
t.Errorf("[%s] Expected hasErr %v, got %v (%v)", s.name, s.expectError, hasErr, err)
}
}
}

Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ go 1.18

require (
github.com/AlecAivazis/survey/v2 v2.3.7
github.com/aws/aws-sdk-go v1.44.298
github.com/aws/aws-sdk-go v1.44.299
github.com/disintegration/imaging v1.6.2
github.com/domodwyer/mailyak/v3 v3.6.0
github.com/dop251/goja v0.0.0-20230707174833-636fdf960de1
Expand Down Expand Up @@ -79,7 +79,7 @@ require (
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/api v0.130.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230706204954-ccb25ca9f130 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230710151506-e685fd7b542b // indirect
google.golang.org/grpc v1.56.2 // indirect
google.golang.org/protobuf v1.31.0 // indirect
lukechampine.com/uint128 v1.3.0 // indirect
Expand Down
10 changes: 5 additions & 5 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -773,8 +773,8 @@ github.com/aws/aws-sdk-go v1.43.31/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4
github.com/aws/aws-sdk-go v1.44.156/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
github.com/aws/aws-sdk-go v1.44.245/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
github.com/aws/aws-sdk-go v1.44.284/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
github.com/aws/aws-sdk-go v1.44.298 h1:5qTxdubgV7PptZJmp/2qDwD2JL187ePL7VOxsSh1i3g=
github.com/aws/aws-sdk-go v1.44.298/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
github.com/aws/aws-sdk-go v1.44.299 h1:HVD9lU4CAFHGxleMJp95FV/sRhtg7P4miHD1v88JAQk=
github.com/aws/aws-sdk-go v1.44.299/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
github.com/aws/aws-sdk-go-v2 v1.9.1/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4=
github.com/aws/aws-sdk-go-v2 v1.18.1 h1:+tefE750oAb7ZQGzla6bLkOwfcQCEtC5y2RqoqCeqKo=
github.com/aws/aws-sdk-go-v2 v1.18.1/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw=
Expand Down Expand Up @@ -3091,7 +3091,7 @@ google.golang.org/genproto v0.0.0-20230403163135-c38d8f061ccd/go.mod h1:UUQDJDOl
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU=
google.golang.org/genproto v0.0.0-20230525234025-438c736192d0/go.mod h1:9ExIQyXL5hZrHzQceCwuSYwZZ5QZBazOcprJ5rgs3lY=
google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64=
google.golang.org/genproto v0.0.0-20230629202037-9506855d4529 h1:9JucMWR7sPvCxUFd6UsOUNmA5kCcWOfORaT3tpAsKQs=
google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130 h1:Au6te5hbKUV8pIYWHqOUZ1pva5qK/rwbIhoXEUB9Lu8=
google.golang.org/genproto/googleapis/api v0.0.0-20230525234020-1aefcd67740a/go.mod h1:ts19tUU+Z0ZShN1y3aPyq2+O3d5FUNNgT6FtOzmrNn8=
google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig=
google.golang.org/genproto/googleapis/api v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig=
Expand All @@ -3102,8 +3102,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234015-3fc162c6f38a/go.
google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230706204954-ccb25ca9f130 h1:2FZP5XuJY9zQyGM5N0rtovnoXjiMUEIUMvw0m9wlpLc=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:8mL13HKkDa+IuJ8yruA3ci0q+0vsUz4m//+ottjwS5o=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230710151506-e685fd7b542b h1:BC7Q0uXfp6VFXnNWp5RqATIN/viqCGkqBO8+HxzH/jY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230710151506-e685fd7b542b/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM=
google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
Expand Down

0 comments on commit 3d3fe5c

Please sign in to comment.