-
Notifications
You must be signed in to change notification settings - Fork 0
V0.22 maintenance #2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
a1d9a9b
e92d3cc
cbc88d7
3786e08
e18ea88
cffbe83
3dd644c
2ff2cd8
58a0b28
c4b1e2d
0b30435
cd14714
caaac6b
060a659
75d1c0b
08793ee
26ef0c6
9a9b667
8144ad1
0d34c00
dbb0b6b
671a6a3
51c083d
b83f924
eb78f59
0c966ab
fbb8fca
ae36612
18dcc13
7ec7ccc
f999037
3f14a6e
2ca9b63
ea73207
4c5d13f
cbc7846
9014604
37601fe
86cc345
81ab302
2e4c9db
529cb8c
fb120da
297d085
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,9 +19,9 @@ jobs: | |
| node-version: 20.11.0 | ||
|
|
||
| - name: Set up Go | ||
| uses: actions/setup-go@v5 | ||
| uses: actions/setup-go@v6 | ||
| with: | ||
| go-version: '>=1.22.5' | ||
| go-version: '>=1.25.6' | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using a semver range ('>=1.25.6') for the Go toolchain is non-deterministic and may fail if no matching version exists. It can also silently upgrade to a newer Go version that breaks the build. Pin to the project-declared version via go.mod (preferred) or to a specific major.minor.x series. Code Suggestion or Commentswith:
go-version-file: 'go.mod'Prompt for AI assistanceCopy the prompt below and paste it into ChatGPT, Claude, or any LLM: |
||
|
|
||
| # This step usually is not needed because the /ui/dist is pregenerated locally | ||
| # but its here to ensure that each release embeds the latest admin ui artifacts. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -245,7 +245,7 @@ func (api *realtimeApi) unregisterClientsByAuthModel(contextKey string, model mo | |
| if clientModel != nil && | ||
| clientModel.TableName() == model.TableName() && | ||
| clientModel.GetId() == model.GetId() { | ||
| api.app.SubscriptionsBroker().Unregister(client.Id()) | ||
| client.Unset(contextKey) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Replacing a full broker unregister with client.Unset(contextKey) may leave existing subscriptions active. If authorization is enforced only at subscribe time or relies on this context key, the client could continue receiving events for protected channels after the associated model is deleted, leading to privilege persistence/data leakage until the connection is reset or subscriptions are revalidated. Code Suggestion or Comments// Ensure client is fully unsubscribed to avoid privilege persistence on deleted auth model
api.app.SubscriptionsBroker().Unregister(client.Id())Prompt for AI assistanceCopy the prompt below and paste it into ChatGPT, Claude, or any LLM: |
||
| } | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,9 +1,12 @@ | ||
| package apis | ||
|
|
||
| import ( | ||
| cryptoRand "crypto/rand" | ||
| "fmt" | ||
| "log/slog" | ||
| "math/big" | ||
| "net/http" | ||
| "time" | ||
|
|
||
| "github.com/labstack/echo/v5" | ||
| "github.com/pocketbase/dbx" | ||
|
|
@@ -71,7 +74,13 @@ func (api *recordApi) list(c echo.Context) error { | |
|
|
||
| records := []*models.Record{} | ||
|
|
||
| result, err := searchProvider.ParseAndExec(c.QueryParams().Encode(), &records) | ||
| // note: in v0.23.0 this has been migrated as option check in the search.Provider | ||
| queryStr := c.QueryParams().Encode() | ||
| if len(queryStr) > 2048 { | ||
| return NewBadRequestError("query string is too large", nil) | ||
| } | ||
|
|
||
| result, err := searchProvider.ParseAndExec(queryStr, &records) | ||
| if err != nil { | ||
| return NewBadRequestError("", err) | ||
| } | ||
|
|
@@ -91,10 +100,43 @@ func (api *recordApi) list(c echo.Context) error { | |
| api.app.Logger().Debug("Failed to enrich list records", slog.String("error", err.Error())) | ||
| } | ||
|
|
||
| // note: in v0.23.0 this is combined with extra check for repeated attempts | ||
| // | ||
| // Add a randomized throttle in case of empty search filter attempts. | ||
| // | ||
| // This is just for extra precaution since security researches raised concern regarding the possibity of eventual | ||
| // timing attacks because the List API rule acts also as filter and executes in a single run with the client-side filters. | ||
| // This is by design and it is an accepted tradeoff between performance, usability and correctness. | ||
| // | ||
| // While technically the below doesn't fully guarantee protection against filter timing attacks, in practice combined with the network latency it makes them even less feasible. | ||
| // A properly configured rate limiter or individual fields Hidden checks are better suited if you are really concerned about eventual information disclosure by side-channel attacks. | ||
| // | ||
| // In all cases it doesn't really matter that much because it doesn't affect the builtin PocketBase security sensitive fields (e.g. password and tokenKey) since they | ||
| // are not client-side filterable and in the few places where they need to be compared against an external value, a constant time check is used. | ||
| if requestInfo.Admin == nil && | ||
| (collection.ListRule != nil && *collection.ListRule != "") && | ||
| (requestInfo.Query["filter"] != "") && | ||
| len(e.Records) == 0 { | ||
| api.app.Logger().Debug("Randomized throttle because of failed filter search", "collectionId", collection.Id) | ||
| randomizedThrottle(100) | ||
| } | ||
|
Comment on lines
+116
to
+122
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. randomizedThrottle is invoked within the request path and uses time.Sleep, which is not cancelable. If the client disconnects or the context is canceled, the handler will still sleep, delaying goroutine release and wasting resources. Code Suggestion or Commentsif requestInfo.Admin == nil &&
(collection.ListRule != nil && *collection.ListRule != "") &&
(requestInfo.Query["filter"] != "") &&
len(e.Records) == 0 {
api.app.Logger().Debug("Randomized throttle because of failed filter search", "collectionId", collection.Id)
randomizedThrottle(e.HttpContext.Request().Context(), 100)
}Prompt for AI assistanceCopy the prompt below and paste it into ChatGPT, Claude, or any LLM: |
||
|
|
||
| return e.HttpContext.JSON(http.StatusOK, e.Result) | ||
| }) | ||
| } | ||
|
|
||
| func randomizedThrottle(softMax int64) { | ||
| var timeout int64 | ||
| randRange, err := cryptoRand.Int(cryptoRand.Reader, big.NewInt(softMax)) | ||
| if err == nil { | ||
| timeout = randRange.Int64() | ||
| } else { | ||
| timeout = softMax | ||
| } | ||
|
|
||
| time.Sleep(time.Duration(timeout) * time.Millisecond) | ||
| } | ||
|
Comment on lines
+128
to
+138
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. time.Sleep cannot be canceled, so this function will always block the handler goroutine for up to softMax milliseconds even if the request context is canceled. Additionally, a negative softMax could lead to unexpected behavior. Consider making the delay context-aware and validating the input. Code Suggestion or Commentsfunc randomizedThrottle(ctx context.Context, softMax int64) {
if softMax <= 0 {
return
}
var timeout int64
randRange, err := cryptoRand.Int(cryptoRand.Reader, big.NewInt(softMax))
if err == nil {
timeout = randRange.Int64()
} else {
timeout = softMax
}
timer := time.NewTimer(time.Duration(timeout) * time.Millisecond)
defer timer.Stop()
select {
case <-ctx.Done():
return
case <-timer.C:
return
}
}Prompt for AI assistanceCopy the prompt below and paste it into ChatGPT, Claude, or any LLM: |
||
|
|
||
| func (api *recordApi) view(c echo.Context) error { | ||
| collection, _ := c.Get(ContextCollectionKey).(*models.Collection) | ||
| if collection == nil { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Referencing the GitHub Action by a mutable major tag ('v6') can expose the workflow to supply-chain risks or unexpected behavior if the tag is retagged. Pinning to an immutable release tag (or commit SHA) ensures reproducibility and reduces risk.
Code Suggestion or Comments
Prompt for AI assistance
Copy the prompt below and paste it into ChatGPT, Claude, or any LLM: