With session elevation, we cannot use DELETE /client as this requires
elevation. It should be possible to logout without an elevated session.
This makes the logout endpoint public api to be used by the android app.
Add two new endpoints for native app OIDC authentication using the
PKCE relay pattern (similar to Vaultwarden's SSO implementation):
- POST /auth/oidc/external/authorize - accepts a PKCE code_challenge
from the client, forwards it to the IdP, and returns the authorize URL
- POST /auth/oidc/external/token - accepts the auth code and
code_verifier, relays them to the IdP for token exchange, and returns
a gotify client token
The server never generates its own PKCE pair for this flow. It then relays
the client's code_challenge to the IdP during authorization and the
code_verifier during token exchange. The IdP validates the binding.
Pending auth sessions are stored in memory with a 10-minute TTL.
CSRF protection is provided by the state parameter, which contains a
cryptographically random nonce and is validated on the token exchange.
The state is single-use (deleted from the pending session map on lookup),
preventing replay attacks. Even without single-use enforcement, replay
would be harmless since the IdP's authorization code can only be
exchanged once.
Improve the performance of the unique function by:
1. Pre-allocating map capacity with len(s) to avoid frequent map resizing
2. Pre-allocating result slice capacity with len(s) to reduce append overhead
3. Reducing the number of traversals performs well under the condition of a large number of elements
These changes maintain the original behavior (preserving element order)
while reducing memory allocation operations, especially effective for
large slices (100k+ elements) with benchmark showing ~25% speedup.
No breaking changes, the function signature and output order remain unchanged.
We should use `(*regexp.Regexp).MatchString` instead of
`(*regexp.Regexp).Match([]byte(...))` when matching string to avoid
unnecessary `[]byte` conversions and reduce allocations.
Example benchmark:
var allowedOrigin = regexp.MustCompile(".*.example.com")
func BenchmarkMatch(b *testing.B) {
for i := 0; i < b.N; i++ {
if match := allowedOrigin.Match([]byte("www.example.com")); !match {
b.Fail()
}
}
}
func BenchmarkMatchString(b *testing.B) {
for i := 0; i < b.N; i++ {
if match := allowedOrigin.MatchString("wwww.example.com"); !match {
b.Fail()
}
}
}
goos: linux
goarch: amd64
pkg: github.com/gotify/server/v2/api/stream
cpu: AMD Ryzen 7 PRO 4750U with Radeon Graphics
BenchmarkMatch-16 2076819 647.7 ns/op 16 B/op 1 allocs/op
BenchmarkMatchString-16 2536326 442.0 ns/op 0 B/op 0 allocs/op
PASS
ok github.com/gotify/server/v2/api/stream 3.552s
Signed-off-by: Eng Zer Jun <engzerjun@gmail.com>
The application image file upload allowed authenticated users to upload
malious .html files. Opening such a file like
https://push.gotify.net/image/ViaxrjzNowdgL-xnEfVV-Ggv5.html
would allow the attacker to execute client side scripts.
The application image upload will now only allow the upload of files
with the following extensions: .gif, .png, .jpg and .jpeg.
For ids uint is used, this is platform specific and either uint32
or uint64. The parsing for parameters in the api expected the ids to
have 32bit size.
I thought about changing all our ids to int64 but we sadly have one uint
usage in the plugin api:
b0e2eca8e3/plugin.go (L13-L14)