updated changelog formatting and temp moved the admin only rule checks to the record_helpers

This commit is contained in:
Gani Georgiev 2023-12-10 21:06:02 +02:00
parent 98c8c98603
commit b0f027d27a
5 changed files with 67 additions and 48 deletions

View File

@ -38,36 +38,35 @@
For better performance and to minimize blocking on hot paths, logs are currently written with For better performance and to minimize blocking on hot paths, logs are currently written with
debounce and on batches: debounce and on batches:
- 3 seconds after the last debounced log write
- 3 seconds after the last debounced log write - when the batch threshold is reached (currently 200)
- when the batch threshold is reached (currently 200) - right before app termination to attempt saving everything from the existing logs queue
- right before app termination to attempt saving everything from the existing logs queue
Some notable log related changes: Some notable log related changes:
- ⚠️ Bumped the minimum required Go version to 1.21. - ⚠️ Bumped the minimum required Go version to 1.21.
- ⚠️ Removed `_requests` table in favor of the generalized `_logs`. - ⚠️ Removed `_requests` table in favor of the generalized `_logs`.
_Note that existing logs will be deleted!_ _Note that existing logs will be deleted!_
- ⚠️ Renamed the following `Dao` log methods: - ⚠️ Renamed the following `Dao` log methods:
```go ```go
Dao.RequestQuery(...) -> Dao.LogQuery(...) Dao.RequestQuery(...) -> Dao.LogQuery(...)
Dao.FindRequestById(...) -> Dao.FindLogById(...) Dao.FindRequestById(...) -> Dao.FindLogById(...)
Dao.RequestsStats(...) -> Dao.LogsStats(...) Dao.RequestsStats(...) -> Dao.LogsStats(...)
Dao.DeleteOldRequests(...) -> Dao.DeleteOldLogs(...) Dao.DeleteOldRequests(...) -> Dao.DeleteOldLogs(...)
Dao.SaveRequest(...) -> Dao.SaveLog(...) Dao.SaveRequest(...) -> Dao.SaveLog(...)
``` ```
- ⚠️ Removed `app.IsDebug()` and the `--debug` flag. - ⚠️ Removed `app.IsDebug()` and the `--debug` flag.
This was done to avoid the confusion with the new logger and its debug severity level. This was done to avoid the confusion with the new logger and its debug severity level.
If you want to store debug logs you can set `-4` as min log level from the Admin UI. If you want to store debug logs you can set `-4` as min log level from the Admin UI.
- Refactored Admin UI Logs: - Refactored Admin UI Logs:
- Added new logs table listing. - Added new logs table listing.
- Added log settings option to toggle the IP logging for the activity logger. - Added log settings option to toggle the IP logging for the activity logger.
- Added log settings option to specify a minimum log level. - Added log settings option to specify a minimum log level.
- Added controls to export individual or bulk selected logs as json. - Added controls to export individual or bulk selected logs as json.
- Other minor improvements and fixes. - Other minor improvements and fixes.
- Added new `filesystem/System.Copy(src, dest)` method to copy existing files from one location to another. - Added new `filesystem/System.Copy(src, dest)` method to copy existing files from one location to another.
_This is usually useful when duplicating records with `file` field(s) programmatically._ _This is usually useful when duplicating records with `file` field(s) programmatically._

View File

@ -568,6 +568,10 @@ func (api *realtimeApi) canAccessRecord(
return true // no further checks needed return true // no further checks needed
} }
if err := checkForAdminOnlyRuleFields(requestInfo); err != nil {
return false
}
ruleFunc := func(q *dbx.SelectQuery) error { ruleFunc := func(q *dbx.SelectQuery) error {
resolver := resolvers.NewRecordFieldResolver(api.app.Dao(), record.Collection(), requestInfo, false) resolver := resolvers.NewRecordFieldResolver(api.app.Dao(), record.Collection(), requestInfo, false)

View File

@ -4,7 +4,6 @@ import (
"fmt" "fmt"
"log/slog" "log/slog"
"net/http" "net/http"
"strings"
"github.com/labstack/echo/v5" "github.com/labstack/echo/v5"
"github.com/pocketbase/dbx" "github.com/pocketbase/dbx"
@ -43,13 +42,13 @@ func (api *recordApi) list(c echo.Context) error {
return NewNotFoundError("", "Missing collection context.") return NewNotFoundError("", "Missing collection context.")
} }
requestInfo := RequestInfo(c)
// forbid users and guests to query special filter/sort fields // forbid users and guests to query special filter/sort fields
if err := api.checkForForbiddenQueryFields(c); err != nil { if err := checkForAdminOnlyRuleFields(requestInfo); err != nil {
return err return err
} }
requestInfo := RequestInfo(c)
if requestInfo.Admin == nil && collection.ListRule == nil { if requestInfo.Admin == nil && collection.ListRule == nil {
// only admins can access if the rule is nil // only admins can access if the rule is nil
return NewForbiddenError("Only admins can perform this action.", nil) return NewForbiddenError("Only admins can perform this action.", nil)
@ -409,21 +408,3 @@ func (api *recordApi) delete(c echo.Context) error {
}) })
}) })
} }
func (api *recordApi) checkForForbiddenQueryFields(c echo.Context) error {
admin, _ := c.Get(ContextAdminKey).(*models.Admin)
if admin != nil {
return nil // admins are allowed to query everything
}
decodedQuery := c.QueryParam(search.FilterQueryParam) + c.QueryParam(search.SortQueryParam)
forbiddenFields := []string{"@collection.", "@request."}
for _, field := range forbiddenFields {
if strings.Contains(decodedQuery, field) {
return NewForbiddenError("Only admins can filter by @collection and @request query params", nil)
}
}
return nil
}

View File

@ -43,9 +43,16 @@ func TestRecordCrudList(t *testing.T) {
ExpectedContent: []string{`"data":{}`}, ExpectedContent: []string{`"data":{}`},
}, },
{ {
Name: "public collection but with admin only filter/sort (aka. @collection)", Name: "public collection but with admin only filter param (aka. @collection, @request, etc.)",
Method: http.MethodGet, Method: http.MethodGet,
Url: "/api/collections/demo2/records?filter=@collection.demo2.title='test1'", Url: "/api/collections/demo2/records?filter=%40collection.demo2.title='test1'",
ExpectedStatus: 403,
ExpectedContent: []string{`"data":{}`},
},
{
Name: "public collection but with admin only sort param (aka. @collection, @request, etc.)",
Method: http.MethodGet,
Url: "/api/collections/demo2/records?sort=@request.auth.title",
ExpectedStatus: 403, ExpectedStatus: 403,
ExpectedContent: []string{`"data":{}`}, ExpectedContent: []string{`"data":{}`},
}, },

View File

@ -314,3 +314,31 @@ func hasAuthManageAccess(
return findErr == nil return findErr == nil
} }
var ruleQueryParams = []string{search.FilterQueryParam, search.SortQueryParam}
var adminOnlyRuleFields = []string{"@collection.", "@request."}
// @todo consider moving the rules check to the RecordFieldResolver.
//
// checkForAdminOnlyRuleFields loosely checks and returns an error if
// the provided RequestInfo contains rule fields that only the admin can use.
func checkForAdminOnlyRuleFields(requestInfo *models.RequestInfo) error {
if requestInfo.Admin != nil || len(requestInfo.Query) == 0 {
return nil // admin or nothing to check
}
for _, param := range ruleQueryParams {
v, _ := requestInfo.Query[param].(string)
if v == "" {
continue
}
for _, field := range adminOnlyRuleFields {
if strings.Contains(v, field) {
return NewForbiddenError("Only admins can filter by "+field, nil)
}
}
}
return nil
}