mirror of
https://github.com/matrix-org/dendrite.git
synced 2026-01-09 07:03:10 -06:00
Merge branch 'main' into s7evink/accountdata
This commit is contained in:
commit
634cc74967
36
.github/workflows/dendrite.yml
vendored
36
.github/workflows/dendrite.yml
vendored
|
|
@ -19,10 +19,10 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
if: ${{ false }} # disable for now
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: 1.18
|
||||
|
||||
|
|
@ -66,8 +66,12 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: 1.18
|
||||
- name: golangci-lint
|
||||
uses: golangci/golangci-lint-action@v2
|
||||
uses: golangci/golangci-lint-action@v3
|
||||
|
||||
# run go test with different go versions
|
||||
test:
|
||||
|
|
@ -97,11 +101,11 @@ jobs:
|
|||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
go: ["1.18"]
|
||||
go: ["1.18", "1.19"]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Setup go
|
||||
uses: actions/setup-go@v2
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: ${{ matrix.go }}
|
||||
- uses: actions/cache@v3
|
||||
|
|
@ -127,13 +131,13 @@ jobs:
|
|||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
go: ["1.18"]
|
||||
go: ["1.18", "1.19"]
|
||||
goos: ["linux"]
|
||||
goarch: ["amd64", "386"]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Setup go
|
||||
uses: actions/setup-go@v2
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: ${{ matrix.go }}
|
||||
- name: Install dependencies x86
|
||||
|
|
@ -151,6 +155,7 @@ jobs:
|
|||
GOOS: ${{ matrix.goos }}
|
||||
GOARCH: ${{ matrix.goarch }}
|
||||
CGO_ENABLED: 1
|
||||
CGO_CFLAGS: -fno-stack-protector
|
||||
run: go build -trimpath -v -o "bin/" ./cmd/...
|
||||
|
||||
# build for Windows 64-bit
|
||||
|
|
@ -160,13 +165,13 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
go: ["1.18"]
|
||||
go: ["1.18", "1.19"]
|
||||
goos: ["windows"]
|
||||
goarch: ["amd64"]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Setup Go ${{ matrix.go }}
|
||||
uses: actions/setup-go@v2
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: ${{ matrix.go }}
|
||||
- name: Install dependencies
|
||||
|
|
@ -207,7 +212,7 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Setup go
|
||||
uses: actions/setup-go@v2
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: "1.18"
|
||||
- uses: actions/cache@v3
|
||||
|
|
@ -232,7 +237,7 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Setup go
|
||||
uses: actions/setup-go@v2
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: "1.18"
|
||||
- uses: actions/cache@v3
|
||||
|
|
@ -384,7 +389,14 @@ jobs:
|
|||
|
||||
integration-tests-done:
|
||||
name: Integration tests passed
|
||||
needs: [initial-tests-done, upgrade_test, upgrade_test_direct, sytest, complement]
|
||||
needs:
|
||||
[
|
||||
initial-tests-done,
|
||||
upgrade_test,
|
||||
upgrade_test_direct,
|
||||
sytest,
|
||||
complement,
|
||||
]
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ !cancelled() }} # Run this even if prior jobs were skipped
|
||||
steps:
|
||||
|
|
|
|||
44
CHANGES.md
44
CHANGES.md
|
|
@ -1,5 +1,49 @@
|
|||
# Changelog
|
||||
|
||||
## Dendrite 0.9.1 (2022-08-03)
|
||||
|
||||
### Fixes
|
||||
|
||||
* Upgrades a dependency which caused issues building Dendrite with Go 1.19
|
||||
* The roomserver will no longer give up prematurely after failing to call `/state_ids`
|
||||
* Removes the faulty room info cache, which caused of a number of race conditions and occasional bugs (including when creating and joining rooms)
|
||||
* The media endpoint now sets the `Cache-Control` header correctly to prevent web-based clients from hitting media endpoints excessively
|
||||
* The sync API will now advance the PDU stream position correctly in all cases (contributed by [sergekh2](https://github.com/sergekh2))
|
||||
* The sync API will now delete the correct range of send-to-device messages when advancing the stream position
|
||||
* The device list `changed` key in the `/sync` response should now return the correct users
|
||||
* A data race when looking up missing state has been fixed
|
||||
* The `/send_join` API is now applying stronger validation to the received membership event
|
||||
|
||||
## Dendrite 0.9.0 (2022-08-01)
|
||||
|
||||
### Features
|
||||
|
||||
* Dendrite now uses Ristretto for managing in-memory caches
|
||||
* Should improve cache utilisation considerably over time by more intelligently selecting and managing cache entries compared to the previous LRU-based cache
|
||||
* Defaults to a 1GB cache size if not configured otherwise
|
||||
* The estimated cache size in memory and maximum age can now be configured with new [configuration options](https://github.com/matrix-org/dendrite/blob/e94ef84aaba30e12baf7f524c4e7a36d2fdeb189/dendrite-sample.monolith.yaml#L44-L61) to prevent unbounded cache growth
|
||||
* Added support for serving the `/.well-known/matrix/client` hint directly from Dendrite
|
||||
* Configurable with the new [configuration option](https://github.com/matrix-org/dendrite/blob/e94ef84aaba30e12baf7f524c4e7a36d2fdeb189/dendrite-sample.monolith.yaml#L67-L69)
|
||||
* Refactored membership updater, which should eliminate some bugs caused by the membership table getting out of sync with the room state
|
||||
* The User API is now responsible for sending account data updates to other components, which may fix some races and duplicate account data events
|
||||
* Optimised database query for checking whether a remote server is allowed to request an event over federation without using anywhere near as much CPU time (PostgreSQL only)
|
||||
* Database migrations have been refactored to eliminate some problems that were present with `goose` and upgrading from older Dendrite versions
|
||||
* Media fetching will now use the `/v3` endpoints for downloading media from remote homeservers
|
||||
* HTTP 404 and HTTP 405 errors from the client-facing APIs should now be returned with CORS headers so that web-based clients do not produce incorrect access control warnings for unknown endpoints
|
||||
* Some preparation work for full history visibility support
|
||||
|
||||
### Fixes
|
||||
|
||||
* Fixes a crash that could occur during event redaction
|
||||
* The `/members` endpoint will no longer incorrectly return HTTP 500 as a result of some invite events
|
||||
* Send-to-device messages should now be ordered more reliably and the last position in the stream updated correctly
|
||||
* Parsing of appservice configuration files is now less strict (contributed by [Kab1r](https://github.com/Kab1r))
|
||||
* The sync API should now identify shared users correctly when waking up for E2EE key changes
|
||||
* The federation `/state` endpoint will now return a HTTP 403 when the state before an event isn't known instead of a HTTP 500
|
||||
* Presence timestamps should now be calculated with the correct precision
|
||||
* A race condition in the roomserver's room info has been fixed
|
||||
* A race condition in the sync API has been fixed
|
||||
|
||||
## Dendrite 0.8.9 (2022-07-01)
|
||||
|
||||
### Features
|
||||
|
|
|
|||
59
README.md
59
README.md
|
|
@ -21,8 +21,7 @@ As of October 2020 (current [progress below](#progress)), Dendrite has now enter
|
|||
This does not mean:
|
||||
|
||||
- Dendrite is bug-free. It has not yet been battle-tested in the real world and so will be error prone initially.
|
||||
- All of the CS/Federation APIs are implemented. We are tracking progress via a script called 'Are We Synapse Yet?'. In particular,
|
||||
presence and push notifications are entirely missing from Dendrite. See [CHANGES.md](CHANGES.md) for updates.
|
||||
- Dendrite is feature-complete. There may be client or federation APIs that are not implemented.
|
||||
- Dendrite is ready for massive homeserver deployments. You cannot shard each microservice, only run each one on a different machine.
|
||||
|
||||
Currently, we expect Dendrite to function well for small (10s/100s of users) homeserver deployments as well as P2P Matrix nodes in-browser or on mobile devices.
|
||||
|
|
@ -36,6 +35,9 @@ If you have further questions, please take a look at [our FAQ](docs/FAQ.md) or j
|
|||
|
||||
## Requirements
|
||||
|
||||
See the [Planning your Installation](https://matrix-org.github.io/dendrite/installation/planning) page for
|
||||
more information on requirements.
|
||||
|
||||
To build Dendrite, you will need Go 1.18 or later.
|
||||
|
||||
For a usable federating Dendrite deployment, you will also need:
|
||||
|
|
@ -83,11 +85,11 @@ $ ./bin/create-account --config dendrite.yaml -username alice
|
|||
|
||||
Then point your favourite Matrix client at `http://localhost:8008` or `https://localhost:8448`.
|
||||
|
||||
## <a id="progress"></a> Progress
|
||||
## Progress
|
||||
|
||||
We use a script called Are We Synapse Yet which checks Sytest compliance rates. Sytest is a black-box homeserver
|
||||
test rig with around 900 tests. The script works out how many of these tests are passing on Dendrite and it
|
||||
updates with CI. As of April 2022 we're at around 83% CS API coverage and 95% Federation coverage, though check
|
||||
updates with CI. As of August 2022 we're at around 83% CS API coverage and 95% Federation coverage, though check
|
||||
CI for the latest numbers. In practice, this means you can communicate locally and via federation with Synapse
|
||||
servers such as matrix.org reasonably well, although there are still some missing features (like Search).
|
||||
|
||||
|
|
@ -119,53 +121,8 @@ We would be grateful for any help on issues marked as
|
|||
all have related Sytests which need to pass in order for the issue to be closed. Once you've written your
|
||||
code, you can quickly run Sytest to ensure that the test names are now passing.
|
||||
|
||||
For example, if the test `Local device key changes get to remote servers` was marked as failing, find the
|
||||
test file (e.g via `grep` or via the
|
||||
[CI log output](https://buildkite.com/matrix-dot-org/dendrite/builds/2826#39cff5de-e032-4ad0-ad26-f819e6919c42)
|
||||
it's `tests/50federation/40devicelists.pl` ) then to run Sytest:
|
||||
|
||||
```
|
||||
docker run --rm --name sytest
|
||||
-v "/Users/kegan/github/sytest:/sytest"
|
||||
-v "/Users/kegan/github/dendrite:/src"
|
||||
-v "/Users/kegan/logs:/logs"
|
||||
-v "/Users/kegan/go/:/gopath"
|
||||
-e "POSTGRES=1" -e "DENDRITE_TRACE_HTTP=1"
|
||||
matrixdotorg/sytest-dendrite:latest tests/50federation/40devicelists.pl
|
||||
```
|
||||
|
||||
See [sytest.md](docs/sytest.md) for the full description of these flags.
|
||||
|
||||
You can try running sytest outside of docker for faster runs, but the dependencies can be temperamental
|
||||
and we recommend using docker where possible.
|
||||
|
||||
```
|
||||
cd sytest
|
||||
export PERL5LIB=$HOME/lib/perl5
|
||||
export PERL_MB_OPT=--install_base=$HOME
|
||||
export PERL_MM_OPT=INSTALL_BASE=$HOME
|
||||
./install-deps.pl
|
||||
|
||||
./run-tests.pl -I Dendrite::Monolith -d $PATH_TO_DENDRITE_BINARIES
|
||||
```
|
||||
|
||||
Sometimes Sytest is testing the wrong thing or is flakey, so it will need to be patched.
|
||||
Ask on `#dendrite-dev:matrix.org` if you think this is the case for you and we'll be happy to help.
|
||||
|
||||
If you're new to the project, see [CONTRIBUTING.md](docs/CONTRIBUTING.md) to get up to speed then
|
||||
If you're new to the project, see our
|
||||
[Contributing page](https://matrix-org.github.io/dendrite/development/contributing) to get up to speed, then
|
||||
look for [Good First Issues](https://github.com/matrix-org/dendrite/labels/good%20first%20issue). If you're
|
||||
familiar with the project, look for [Help Wanted](https://github.com/matrix-org/dendrite/labels/help-wanted)
|
||||
issues.
|
||||
|
||||
## Hardware requirements
|
||||
|
||||
Dendrite in Monolith + SQLite works in a range of environments including iOS and in-browser via WASM.
|
||||
|
||||
For small homeserver installations joined on ~10s rooms on matrix.org with ~100s of users in those rooms, including some
|
||||
encrypted rooms:
|
||||
|
||||
- Memory: uses around 100MB of RAM, with peaks at around 200MB.
|
||||
- Disk space: After a few months of usage, the database grew to around 2GB (in Monolith mode).
|
||||
- CPU: Brief spikes when processing events, typically idles at 1% CPU.
|
||||
|
||||
This means Dendrite should comfortably work on things like Raspberry Pis.
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import (
|
|||
|
||||
"github.com/matrix-org/dendrite/appservice/api"
|
||||
"github.com/matrix-org/dendrite/internal/httputil"
|
||||
"github.com/opentracing/opentracing-go"
|
||||
)
|
||||
|
||||
// HTTP paths for the internal HTTP APIs
|
||||
|
|
@ -42,11 +41,10 @@ func (h *httpAppServiceQueryAPI) RoomAliasExists(
|
|||
request *api.RoomAliasExistsRequest,
|
||||
response *api.RoomAliasExistsResponse,
|
||||
) error {
|
||||
span, ctx := opentracing.StartSpanFromContext(ctx, "appserviceRoomAliasExists")
|
||||
defer span.Finish()
|
||||
|
||||
apiURL := h.appserviceURL + AppServiceRoomAliasExistsPath
|
||||
return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response)
|
||||
return httputil.CallInternalRPCAPI(
|
||||
"RoomAliasExists", h.appserviceURL+AppServiceRoomAliasExistsPath,
|
||||
h.httpClient, ctx, request, response,
|
||||
)
|
||||
}
|
||||
|
||||
// UserIDExists implements AppServiceQueryAPI
|
||||
|
|
@ -55,9 +53,8 @@ func (h *httpAppServiceQueryAPI) UserIDExists(
|
|||
request *api.UserIDExistsRequest,
|
||||
response *api.UserIDExistsResponse,
|
||||
) error {
|
||||
span, ctx := opentracing.StartSpanFromContext(ctx, "appserviceUserIDExists")
|
||||
defer span.Finish()
|
||||
|
||||
apiURL := h.appserviceURL + AppServiceUserIDExistsPath
|
||||
return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response)
|
||||
return httputil.CallInternalRPCAPI(
|
||||
"UserIDExists", h.appserviceURL+AppServiceUserIDExistsPath,
|
||||
h.httpClient, ctx, request, response,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,43 +1,20 @@
|
|||
package inthttp
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/matrix-org/dendrite/appservice/api"
|
||||
"github.com/matrix-org/dendrite/internal/httputil"
|
||||
"github.com/matrix-org/util"
|
||||
)
|
||||
|
||||
// AddRoutes adds the AppServiceQueryAPI handlers to the http.ServeMux.
|
||||
func AddRoutes(a api.AppServiceInternalAPI, internalAPIMux *mux.Router) {
|
||||
internalAPIMux.Handle(
|
||||
AppServiceRoomAliasExistsPath,
|
||||
httputil.MakeInternalAPI("appserviceRoomAliasExists", func(req *http.Request) util.JSONResponse {
|
||||
var request api.RoomAliasExistsRequest
|
||||
var response api.RoomAliasExistsResponse
|
||||
if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
|
||||
return util.ErrorResponse(err)
|
||||
}
|
||||
if err := a.RoomAliasExists(req.Context(), &request, &response); err != nil {
|
||||
return util.ErrorResponse(err)
|
||||
}
|
||||
return util.JSONResponse{Code: http.StatusOK, JSON: &response}
|
||||
}),
|
||||
httputil.MakeInternalRPCAPI("AppserviceRoomAliasExists", a.RoomAliasExists),
|
||||
)
|
||||
|
||||
internalAPIMux.Handle(
|
||||
AppServiceUserIDExistsPath,
|
||||
httputil.MakeInternalAPI("appserviceUserIDExists", func(req *http.Request) util.JSONResponse {
|
||||
var request api.UserIDExistsRequest
|
||||
var response api.UserIDExistsResponse
|
||||
if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
|
||||
return util.ErrorResponse(err)
|
||||
}
|
||||
if err := a.UserIDExists(req.Context(), &request, &response); err != nil {
|
||||
return util.ErrorResponse(err)
|
||||
}
|
||||
return util.JSONResponse{Code: http.StatusOK, JSON: &response}
|
||||
}),
|
||||
httputil.MakeInternalRPCAPI("AppserviceUserIDExists", a.UserIDExists),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,4 +13,4 @@ go build ./cmd/...
|
|||
./build/scripts/find-lint.sh
|
||||
|
||||
echo "Testing..."
|
||||
go test -v ./...
|
||||
go test --race -v ./...
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ import (
|
|||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
|
||||
|
|
@ -34,7 +33,7 @@ import (
|
|||
// If the final return value is non-nil, an error occurred and the cleanup function
|
||||
// is nil.
|
||||
func LoginFromJSONReader(ctx context.Context, r io.Reader, useraccountAPI uapi.UserLoginAPI, userAPI UserInternalAPIForLogin, cfg *config.ClientAPI) (*Login, LoginCleanupFunc, *util.JSONResponse) {
|
||||
reqBytes, err := ioutil.ReadAll(r)
|
||||
reqBytes, err := io.ReadAll(r)
|
||||
if err != nil {
|
||||
err := &util.JSONResponse{
|
||||
Code: http.StatusBadRequest,
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import (
|
|||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"sync"
|
||||
|
||||
"github.com/matrix-org/dendrite/clientapi/jsonerror"
|
||||
"github.com/matrix-org/dendrite/setup/config"
|
||||
|
|
@ -102,6 +103,7 @@ type userInteractiveFlow struct {
|
|||
// the user already has a valid access token, but we want to double-check
|
||||
// that it isn't stolen by re-authenticating them.
|
||||
type UserInteractive struct {
|
||||
sync.RWMutex
|
||||
Flows []userInteractiveFlow
|
||||
// Map of login type to implementation
|
||||
Types map[string]Type
|
||||
|
|
@ -128,6 +130,8 @@ func NewUserInteractive(userAccountAPI api.UserLoginAPI, cfg *config.ClientAPI)
|
|||
}
|
||||
|
||||
func (u *UserInteractive) IsSingleStageFlow(authType string) bool {
|
||||
u.RLock()
|
||||
defer u.RUnlock()
|
||||
for _, f := range u.Flows {
|
||||
if len(f.Stages) == 1 && f.Stages[0] == authType {
|
||||
return true
|
||||
|
|
@ -137,8 +141,10 @@ func (u *UserInteractive) IsSingleStageFlow(authType string) bool {
|
|||
}
|
||||
|
||||
func (u *UserInteractive) AddCompletedStage(sessionID, authType string) {
|
||||
u.Lock()
|
||||
// TODO: Handle multi-stage flows
|
||||
delete(u.Sessions, sessionID)
|
||||
u.Unlock()
|
||||
}
|
||||
|
||||
type Challenge struct {
|
||||
|
|
@ -150,12 +156,17 @@ type Challenge struct {
|
|||
}
|
||||
|
||||
// Challenge returns an HTTP 401 with the supported flows for authenticating
|
||||
func (u *UserInteractive) Challenge(sessionID string) *util.JSONResponse {
|
||||
func (u *UserInteractive) challenge(sessionID string) *util.JSONResponse {
|
||||
u.RLock()
|
||||
completed := u.Sessions[sessionID]
|
||||
flows := u.Flows
|
||||
u.RUnlock()
|
||||
|
||||
return &util.JSONResponse{
|
||||
Code: 401,
|
||||
JSON: Challenge{
|
||||
Completed: u.Sessions[sessionID],
|
||||
Flows: u.Flows,
|
||||
Completed: completed,
|
||||
Flows: flows,
|
||||
Session: sessionID,
|
||||
Params: make(map[string]interface{}),
|
||||
},
|
||||
|
|
@ -170,8 +181,10 @@ func (u *UserInteractive) NewSession() *util.JSONResponse {
|
|||
res := jsonerror.InternalServerError()
|
||||
return &res
|
||||
}
|
||||
u.Lock()
|
||||
u.Sessions[sessionID] = []string{}
|
||||
return u.Challenge(sessionID)
|
||||
u.Unlock()
|
||||
return u.challenge(sessionID)
|
||||
}
|
||||
|
||||
// ResponseWithChallenge mixes together a JSON body (e.g an error with errcode/message) with the
|
||||
|
|
@ -184,7 +197,7 @@ func (u *UserInteractive) ResponseWithChallenge(sessionID string, response inter
|
|||
return &ise
|
||||
}
|
||||
_ = json.Unmarshal(b, &mixedObjects)
|
||||
challenge := u.Challenge(sessionID)
|
||||
challenge := u.challenge(sessionID)
|
||||
b, err = json.Marshal(challenge.JSON)
|
||||
if err != nil {
|
||||
ise := jsonerror.InternalServerError()
|
||||
|
|
@ -213,7 +226,11 @@ func (u *UserInteractive) Verify(ctx context.Context, bodyBytes []byte, device *
|
|||
|
||||
// extract the type so we know which login type to use
|
||||
authType := gjson.GetBytes(bodyBytes, "auth.type").Str
|
||||
|
||||
u.RLock()
|
||||
loginType, ok := u.Types[authType]
|
||||
u.RUnlock()
|
||||
|
||||
if !ok {
|
||||
return nil, &util.JSONResponse{
|
||||
Code: http.StatusBadRequest,
|
||||
|
|
@ -223,7 +240,12 @@ func (u *UserInteractive) Verify(ctx context.Context, bodyBytes []byte, device *
|
|||
|
||||
// retrieve the session
|
||||
sessionID := gjson.GetBytes(bodyBytes, "auth.session").Str
|
||||
if _, ok = u.Sessions[sessionID]; !ok {
|
||||
|
||||
u.RLock()
|
||||
_, ok = u.Sessions[sessionID]
|
||||
u.RUnlock()
|
||||
|
||||
if !ok {
|
||||
// if the login type is part of a single stage flow then allow them to omit the session ID
|
||||
if !u.IsSingleStageFlow(authType) {
|
||||
return nil, &util.JSONResponse{
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ package httputil
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"net/http"
|
||||
"unicode/utf8"
|
||||
|
||||
|
|
@ -29,9 +29,9 @@ import (
|
|||
func UnmarshalJSONRequest(req *http.Request, iface interface{}) *util.JSONResponse {
|
||||
// encoding/json allows invalid utf-8, matrix does not
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.1#api-standards
|
||||
body, err := ioutil.ReadAll(req.Body)
|
||||
body, err := io.ReadAll(req.Body)
|
||||
if err != nil {
|
||||
util.GetLogger(req.Context()).WithError(err).Error("ioutil.ReadAll failed")
|
||||
util.GetLogger(req.Context()).WithError(err).Error("io.ReadAll failed")
|
||||
resp := jsonerror.InternalServerError()
|
||||
return &resp
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,11 +15,13 @@
|
|||
package jsonerror
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/matrix-org/gomatrixserverlib"
|
||||
"github.com/matrix-org/util"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// MatrixError represents the "standard error response" in Matrix.
|
||||
|
|
@ -213,3 +215,15 @@ func NotTrusted(serverName string) *MatrixError {
|
|||
Err: fmt.Sprintf("Untrusted server '%s'", serverName),
|
||||
}
|
||||
}
|
||||
|
||||
// InternalAPIError is returned when Dendrite failed to reach an internal API.
|
||||
func InternalAPIError(ctx context.Context, err error) util.JSONResponse {
|
||||
logrus.WithContext(ctx).WithError(err).Error("Error reaching an internal API")
|
||||
return util.JSONResponse{
|
||||
Code: http.StatusInternalServerError,
|
||||
JSON: &MatrixError{
|
||||
ErrCode: "M_INTERNAL_SERVER_ERROR",
|
||||
Err: "Dendrite encountered an error reaching an internal API.",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ package routing
|
|||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/matrix-org/dendrite/clientapi/httputil"
|
||||
|
|
@ -101,9 +101,9 @@ func SaveAccountData(
|
|||
}
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(req.Body)
|
||||
body, err := io.ReadAll(req.Body)
|
||||
if err != nil {
|
||||
util.GetLogger(req.Context()).WithError(err).Error("ioutil.ReadAll failed")
|
||||
util.GetLogger(req.Context()).WithError(err).Error("io.ReadAll failed")
|
||||
return jsonerror.InternalServerError()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,13 +30,15 @@ func AdminEvacuateRoom(req *http.Request, device *userapi.Device, rsAPI roomserv
|
|||
}
|
||||
}
|
||||
res := &roomserverAPI.PerformAdminEvacuateRoomResponse{}
|
||||
rsAPI.PerformAdminEvacuateRoom(
|
||||
if err := rsAPI.PerformAdminEvacuateRoom(
|
||||
req.Context(),
|
||||
&roomserverAPI.PerformAdminEvacuateRoomRequest{
|
||||
RoomID: roomID,
|
||||
},
|
||||
res,
|
||||
)
|
||||
); err != nil {
|
||||
return util.ErrorResponse(err)
|
||||
}
|
||||
if err := res.Error; err != nil {
|
||||
return err.JSONResponse()
|
||||
}
|
||||
|
|
@ -67,13 +69,15 @@ func AdminEvacuateUser(req *http.Request, device *userapi.Device, rsAPI roomserv
|
|||
}
|
||||
}
|
||||
res := &roomserverAPI.PerformAdminEvacuateUserResponse{}
|
||||
rsAPI.PerformAdminEvacuateUser(
|
||||
if err := rsAPI.PerformAdminEvacuateUser(
|
||||
req.Context(),
|
||||
&roomserverAPI.PerformAdminEvacuateUserRequest{
|
||||
UserID: userID,
|
||||
},
|
||||
res,
|
||||
)
|
||||
); err != nil {
|
||||
return jsonerror.InternalAPIError(req.Context(), err)
|
||||
}
|
||||
if err := res.Error; err != nil {
|
||||
return err.JSONResponse()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -556,10 +556,12 @@ func createRoom(
|
|||
if r.Visibility == "public" {
|
||||
// expose this room in the published room list
|
||||
var pubRes roomserverAPI.PerformPublishResponse
|
||||
rsAPI.PerformPublish(ctx, &roomserverAPI.PerformPublishRequest{
|
||||
if err := rsAPI.PerformPublish(ctx, &roomserverAPI.PerformPublishRequest{
|
||||
RoomID: roomID,
|
||||
Visibility: "public",
|
||||
}, &pubRes)
|
||||
}, &pubRes); err != nil {
|
||||
return jsonerror.InternalAPIError(ctx, err)
|
||||
}
|
||||
if pubRes.Error != nil {
|
||||
// treat as non-fatal since the room is already made by this point
|
||||
util.GetLogger(ctx).WithError(pubRes.Error).Error("failed to visibility:public")
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package routing
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/matrix-org/dendrite/clientapi/auth"
|
||||
|
|
@ -20,7 +20,7 @@ func Deactivate(
|
|||
) util.JSONResponse {
|
||||
ctx := req.Context()
|
||||
defer req.Body.Close() // nolint:errcheck
|
||||
bodyBytes, err := ioutil.ReadAll(req.Body)
|
||||
bodyBytes, err := io.ReadAll(req.Body)
|
||||
if err != nil {
|
||||
return util.JSONResponse{
|
||||
Code: http.StatusBadRequest,
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
package routing
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
|
||||
|
|
@ -175,7 +175,7 @@ func DeleteDeviceById(
|
|||
}()
|
||||
ctx := req.Context()
|
||||
defer req.Body.Close() // nolint:errcheck
|
||||
bodyBytes, err := ioutil.ReadAll(req.Body)
|
||||
bodyBytes, err := io.ReadAll(req.Body)
|
||||
if err != nil {
|
||||
return util.JSONResponse{
|
||||
Code: http.StatusBadRequest,
|
||||
|
|
|
|||
|
|
@ -302,10 +302,12 @@ func SetVisibility(
|
|||
}
|
||||
|
||||
var publishRes roomserverAPI.PerformPublishResponse
|
||||
rsAPI.PerformPublish(req.Context(), &roomserverAPI.PerformPublishRequest{
|
||||
if err := rsAPI.PerformPublish(req.Context(), &roomserverAPI.PerformPublishRequest{
|
||||
RoomID: roomID,
|
||||
Visibility: v.Visibility,
|
||||
}, &publishRes)
|
||||
}, &publishRes); err != nil {
|
||||
return jsonerror.InternalAPIError(req.Context(), err)
|
||||
}
|
||||
if publishRes.Error != nil {
|
||||
util.GetLogger(req.Context()).WithError(publishRes.Error).Error("PerformPublish failed")
|
||||
return publishRes.Error.JSONResponse()
|
||||
|
|
|
|||
|
|
@ -23,13 +23,14 @@ import (
|
|||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/matrix-org/gomatrixserverlib"
|
||||
"github.com/matrix-org/util"
|
||||
|
||||
"github.com/matrix-org/dendrite/clientapi/api"
|
||||
"github.com/matrix-org/dendrite/clientapi/httputil"
|
||||
"github.com/matrix-org/dendrite/clientapi/jsonerror"
|
||||
roomserverAPI "github.com/matrix-org/dendrite/roomserver/api"
|
||||
"github.com/matrix-org/dendrite/setup/config"
|
||||
"github.com/matrix-org/gomatrixserverlib"
|
||||
"github.com/matrix-org/util"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
@ -196,14 +197,14 @@ func fillPublicRoomsReq(httpReq *http.Request, request *PublicRoomReq) *util.JSO
|
|||
|
||||
// sliceInto returns a subslice of `slice` which honours the since/limit values given.
|
||||
//
|
||||
// 0 1 2 3 4 5 6 index
|
||||
// [A, B, C, D, E, F, G] slice
|
||||
// 0 1 2 3 4 5 6 index
|
||||
// [A, B, C, D, E, F, G] slice
|
||||
//
|
||||
// limit=3 => A,B,C (prev='', next='3')
|
||||
// limit=3&since=3 => D,E,F (prev='0', next='6')
|
||||
// limit=3&since=6 => G (prev='3', next='')
|
||||
// limit=3 => A,B,C (prev='', next='3')
|
||||
// limit=3&since=3 => D,E,F (prev='0', next='6')
|
||||
// limit=3&since=6 => G (prev='3', next='')
|
||||
//
|
||||
// A value of '-1' for prev/next indicates no position.
|
||||
// A value of '-1' for prev/next indicates no position.
|
||||
func sliceInto(slice []gomatrixserverlib.PublicRoom, since int64, limit int16) (subset []gomatrixserverlib.PublicRoom, prev, next int) {
|
||||
prev = -1
|
||||
next = -1
|
||||
|
|
|
|||
|
|
@ -81,8 +81,9 @@ func JoinRoomByIDOrAlias(
|
|||
done := make(chan util.JSONResponse, 1)
|
||||
go func() {
|
||||
defer close(done)
|
||||
rsAPI.PerformJoin(req.Context(), &joinReq, &joinRes)
|
||||
if joinRes.Error != nil {
|
||||
if err := rsAPI.PerformJoin(req.Context(), &joinReq, &joinRes); err != nil {
|
||||
done <- jsonerror.InternalAPIError(req.Context(), err)
|
||||
} else if joinRes.Error != nil {
|
||||
done <- joinRes.Error.JSONResponse()
|
||||
} else {
|
||||
done <- util.JSONResponse{
|
||||
|
|
|
|||
|
|
@ -91,10 +91,12 @@ func CreateKeyBackupVersion(req *http.Request, userAPI userapi.ClientUserAPI, de
|
|||
// Implements GET /_matrix/client/r0/room_keys/version and GET /_matrix/client/r0/room_keys/version/{version}
|
||||
func KeyBackupVersion(req *http.Request, userAPI userapi.ClientUserAPI, device *userapi.Device, version string) util.JSONResponse {
|
||||
var queryResp userapi.QueryKeyBackupResponse
|
||||
userAPI.QueryKeyBackup(req.Context(), &userapi.QueryKeyBackupRequest{
|
||||
if err := userAPI.QueryKeyBackup(req.Context(), &userapi.QueryKeyBackupRequest{
|
||||
UserID: device.UserID,
|
||||
Version: version,
|
||||
}, &queryResp)
|
||||
}, &queryResp); err != nil {
|
||||
return jsonerror.InternalAPIError(req.Context(), err)
|
||||
}
|
||||
if queryResp.Error != "" {
|
||||
return util.ErrorResponse(fmt.Errorf("QueryKeyBackup: %s", queryResp.Error))
|
||||
}
|
||||
|
|
@ -233,13 +235,15 @@ func GetBackupKeys(
|
|||
req *http.Request, userAPI userapi.ClientUserAPI, device *userapi.Device, version, roomID, sessionID string,
|
||||
) util.JSONResponse {
|
||||
var queryResp userapi.QueryKeyBackupResponse
|
||||
userAPI.QueryKeyBackup(req.Context(), &userapi.QueryKeyBackupRequest{
|
||||
if err := userAPI.QueryKeyBackup(req.Context(), &userapi.QueryKeyBackupRequest{
|
||||
UserID: device.UserID,
|
||||
Version: version,
|
||||
ReturnKeys: true,
|
||||
KeysForRoomID: roomID,
|
||||
KeysForSessionID: sessionID,
|
||||
}, &queryResp)
|
||||
}, &queryResp); err != nil {
|
||||
return jsonerror.InternalAPIError(req.Context(), err)
|
||||
}
|
||||
if queryResp.Error != "" {
|
||||
return util.ErrorResponse(fmt.Errorf("QueryKeyBackup: %s", queryResp.Error))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,7 +72,9 @@ func UploadCrossSigningDeviceKeys(
|
|||
sessions.addCompletedSessionStage(sessionID, authtypes.LoginTypePassword)
|
||||
|
||||
uploadReq.UserID = device.UserID
|
||||
keyserverAPI.PerformUploadDeviceKeys(req.Context(), &uploadReq.PerformUploadDeviceKeysRequest, uploadRes)
|
||||
if err := keyserverAPI.PerformUploadDeviceKeys(req.Context(), &uploadReq.PerformUploadDeviceKeysRequest, uploadRes); err != nil {
|
||||
return jsonerror.InternalAPIError(req.Context(), err)
|
||||
}
|
||||
|
||||
if err := uploadRes.Error; err != nil {
|
||||
switch {
|
||||
|
|
@ -114,7 +116,9 @@ func UploadCrossSigningDeviceSignatures(req *http.Request, keyserverAPI api.Clie
|
|||
}
|
||||
|
||||
uploadReq.UserID = device.UserID
|
||||
keyserverAPI.PerformUploadDeviceSignatures(req.Context(), uploadReq, uploadRes)
|
||||
if err := keyserverAPI.PerformUploadDeviceSignatures(req.Context(), uploadReq, uploadRes); err != nil {
|
||||
return jsonerror.InternalAPIError(req.Context(), err)
|
||||
}
|
||||
|
||||
if err := uploadRes.Error; err != nil {
|
||||
switch {
|
||||
|
|
|
|||
|
|
@ -62,7 +62,9 @@ func UploadKeys(req *http.Request, keyAPI api.ClientKeyAPI, device *userapi.Devi
|
|||
}
|
||||
|
||||
var uploadRes api.PerformUploadKeysResponse
|
||||
keyAPI.PerformUploadKeys(req.Context(), uploadReq, &uploadRes)
|
||||
if err := keyAPI.PerformUploadKeys(req.Context(), uploadReq, &uploadRes); err != nil {
|
||||
return util.ErrorResponse(err)
|
||||
}
|
||||
if uploadRes.Error != nil {
|
||||
util.GetLogger(req.Context()).WithError(uploadRes.Error).Error("Failed to PerformUploadKeys")
|
||||
return jsonerror.InternalServerError()
|
||||
|
|
@ -107,12 +109,14 @@ func QueryKeys(req *http.Request, keyAPI api.ClientKeyAPI, device *userapi.Devic
|
|||
return *resErr
|
||||
}
|
||||
queryRes := api.QueryKeysResponse{}
|
||||
keyAPI.QueryKeys(req.Context(), &api.QueryKeysRequest{
|
||||
if err := keyAPI.QueryKeys(req.Context(), &api.QueryKeysRequest{
|
||||
UserID: device.UserID,
|
||||
UserToDevices: r.DeviceKeys,
|
||||
Timeout: r.GetTimeout(),
|
||||
// TODO: Token?
|
||||
}, &queryRes)
|
||||
}, &queryRes); err != nil {
|
||||
return util.ErrorResponse(err)
|
||||
}
|
||||
return util.JSONResponse{
|
||||
Code: 200,
|
||||
JSON: map[string]interface{}{
|
||||
|
|
@ -145,10 +149,12 @@ func ClaimKeys(req *http.Request, keyAPI api.ClientKeyAPI) util.JSONResponse {
|
|||
return *resErr
|
||||
}
|
||||
claimRes := api.PerformClaimKeysResponse{}
|
||||
keyAPI.PerformClaimKeys(req.Context(), &api.PerformClaimKeysRequest{
|
||||
if err := keyAPI.PerformClaimKeys(req.Context(), &api.PerformClaimKeysRequest{
|
||||
OneTimeKeys: r.OneTimeKeys,
|
||||
Timeout: r.GetTimeout(),
|
||||
}, &claimRes)
|
||||
}, &claimRes); err != nil {
|
||||
return jsonerror.InternalAPIError(req.Context(), err)
|
||||
}
|
||||
if claimRes.Error != nil {
|
||||
util.GetLogger(req.Context()).WithError(claimRes.Error).Error("failed to PerformClaimKeys")
|
||||
return jsonerror.InternalServerError()
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ package routing
|
|||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/matrix-org/dendrite/clientapi/jsonerror"
|
||||
roomserverAPI "github.com/matrix-org/dendrite/roomserver/api"
|
||||
"github.com/matrix-org/dendrite/userapi/api"
|
||||
"github.com/matrix-org/gomatrixserverlib"
|
||||
|
|
@ -54,7 +55,9 @@ func PeekRoomByIDOrAlias(
|
|||
}
|
||||
|
||||
// Ask the roomserver to perform the peek.
|
||||
rsAPI.PerformPeek(req.Context(), &peekReq, &peekRes)
|
||||
if err := rsAPI.PerformPeek(req.Context(), &peekReq, &peekRes); err != nil {
|
||||
return util.ErrorResponse(err)
|
||||
}
|
||||
if peekRes.Error != nil {
|
||||
return peekRes.Error.JSONResponse()
|
||||
}
|
||||
|
|
@ -89,7 +92,9 @@ func UnpeekRoomByID(
|
|||
}
|
||||
unpeekRes := roomserverAPI.PerformUnpeekResponse{}
|
||||
|
||||
rsAPI.PerformUnpeek(req.Context(), &unpeekReq, &unpeekRes)
|
||||
if err := rsAPI.PerformUnpeek(req.Context(), &unpeekReq, &unpeekRes); err != nil {
|
||||
return jsonerror.InternalAPIError(req.Context(), err)
|
||||
}
|
||||
if unpeekRes.Error != nil {
|
||||
return unpeekRes.Error.JSONResponse()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ import (
|
|||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"regexp"
|
||||
|
|
@ -371,7 +371,7 @@ func validateRecaptcha(
|
|||
|
||||
// Grab the body of the response from the captcha server
|
||||
var r recaptchaResponse
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return &util.JSONResponse{
|
||||
Code: http.StatusGatewayTimeout,
|
||||
|
|
@ -539,7 +539,7 @@ func Register(
|
|||
cfg *config.ClientAPI,
|
||||
) util.JSONResponse {
|
||||
defer req.Body.Close() // nolint: errcheck
|
||||
reqBody, err := ioutil.ReadAll(req.Body)
|
||||
reqBody, err := io.ReadAll(req.Body)
|
||||
if err != nil {
|
||||
return util.JSONResponse{
|
||||
Code: http.StatusBadRequest,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ package routing
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"github.com/patrickmn/go-cache"
|
||||
|
|
@ -13,7 +13,7 @@ func TestSharedSecretRegister(t *testing.T) {
|
|||
jsonStr := []byte(`{"admin":false,"mac":"f1ba8d37123866fd659b40de4bad9b0f8965c565","nonce":"759f047f312b99ff428b21d581256f8592b8976e58bc1b543972dc6147e529a79657605b52d7becd160ff5137f3de11975684319187e06901955f79e5a6c5a79","password":"wonderland","username":"alice"}`)
|
||||
sharedSecret := "dendritetest"
|
||||
|
||||
req, err := NewSharedSecretRegistrationRequest(ioutil.NopCloser(bytes.NewBuffer(jsonStr)))
|
||||
req, err := NewSharedSecretRegistrationRequest(io.NopCloser(bytes.NewBuffer(jsonStr)))
|
||||
if err != nil {
|
||||
t.Fatalf("failed to read request: %s", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,9 +63,10 @@ var sendEventDuration = prometheus.NewHistogramVec(
|
|||
)
|
||||
|
||||
// SendEvent implements:
|
||||
// /rooms/{roomID}/send/{eventType}
|
||||
// /rooms/{roomID}/send/{eventType}/{txnID}
|
||||
// /rooms/{roomID}/state/{eventType}/{stateKey}
|
||||
//
|
||||
// /rooms/{roomID}/send/{eventType}
|
||||
// /rooms/{roomID}/send/{eventType}/{txnID}
|
||||
// /rooms/{roomID}/state/{eventType}/{stateKey}
|
||||
func SendEvent(
|
||||
req *http.Request,
|
||||
device *userapi.Device,
|
||||
|
|
|
|||
|
|
@ -38,8 +38,9 @@ type threePIDsResponse struct {
|
|||
}
|
||||
|
||||
// RequestEmailToken implements:
|
||||
// POST /account/3pid/email/requestToken
|
||||
// POST /register/email/requestToken
|
||||
//
|
||||
// POST /account/3pid/email/requestToken
|
||||
// POST /register/email/requestToken
|
||||
func RequestEmailToken(req *http.Request, threePIDAPI api.ClientUserAPI, cfg *config.ClientAPI) util.JSONResponse {
|
||||
var body threepid.EmailAssociationRequest
|
||||
if reqErr := httputil.UnmarshalJSONRequest(req, &body); reqErr != nil {
|
||||
|
|
|
|||
|
|
@ -64,7 +64,9 @@ func UpgradeRoom(
|
|||
}
|
||||
upgradeResp := roomserverAPI.PerformRoomUpgradeResponse{}
|
||||
|
||||
rsAPI.PerformRoomUpgrade(req.Context(), &upgradeReq, &upgradeResp)
|
||||
if err := rsAPI.PerformRoomUpgrade(req.Context(), &upgradeReq, &upgradeResp); err != nil {
|
||||
return jsonerror.InternalAPIError(req.Context(), err)
|
||||
}
|
||||
|
||||
if upgradeResp.Error != nil {
|
||||
if upgradeResp.Error.Code == roomserverAPI.PerformErrorNoRoom {
|
||||
|
|
|
|||
|
|
@ -22,15 +22,17 @@ import (
|
|||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/matrix-org/gomatrix"
|
||||
"github.com/matrix-org/util"
|
||||
|
||||
"github.com/matrix-org/dendrite/clientapi/jsonerror"
|
||||
"github.com/matrix-org/dendrite/setup/config"
|
||||
"github.com/matrix-org/dendrite/userapi/api"
|
||||
"github.com/matrix-org/gomatrix"
|
||||
"github.com/matrix-org/util"
|
||||
)
|
||||
|
||||
// RequestTurnServer implements:
|
||||
// GET /voip/turnServer
|
||||
//
|
||||
// GET /voip/turnServer
|
||||
func RequestTurnServer(req *http.Request, device *api.Device, cfg *config.ClientAPI) util.JSONResponse {
|
||||
turnConfig := cfg.TURN
|
||||
|
||||
|
|
|
|||
|
|
@ -24,8 +24,6 @@ import (
|
|||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
|
@ -232,7 +230,7 @@ func getRegisterMac(sharedSecret, nonce, localpart, password, adminStr string) (
|
|||
func getPassword(password, pwdFile string, pwdStdin bool, r io.Reader) (string, error) {
|
||||
// read password from file
|
||||
if pwdFile != "" {
|
||||
pw, err := ioutil.ReadFile(pwdFile)
|
||||
pw, err := os.ReadFile(pwdFile)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Unable to read password from file: %v", err)
|
||||
}
|
||||
|
|
@ -241,7 +239,7 @@ func getPassword(password, pwdFile string, pwdStdin bool, r io.Reader) (string,
|
|||
|
||||
// read password from stdin
|
||||
if pwdStdin {
|
||||
data, err := ioutil.ReadAll(r)
|
||||
data, err := io.ReadAll(r)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Unable to read password from stdin: %v", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ import (
|
|||
"encoding/hex"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
|
|
@ -76,11 +75,11 @@ func main() {
|
|||
if pk, sk, err = ed25519.GenerateKey(nil); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err = ioutil.WriteFile(keyfile, sk, 0644); err != nil {
|
||||
if err = os.WriteFile(keyfile, sk, 0644); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
} else if err == nil {
|
||||
if sk, err = ioutil.ReadFile(keyfile); err != nil {
|
||||
if sk, err = os.ReadFile(keyfile); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if len(sk) != ed25519.PrivateKeySize {
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ import (
|
|||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
|
|
@ -69,7 +68,7 @@ func Setup(instanceName, storageDirectory, peerURI string) (*Node, error) {
|
|||
|
||||
yggfile := fmt.Sprintf("%s/%s-yggdrasil.conf", storageDirectory, instanceName)
|
||||
if _, err := os.Stat(yggfile); !os.IsNotExist(err) {
|
||||
yggconf, e := ioutil.ReadFile(yggfile)
|
||||
yggconf, e := os.ReadFile(yggfile)
|
||||
if e != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
@ -88,7 +87,7 @@ func Setup(instanceName, storageDirectory, peerURI string) (*Node, error) {
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if e := ioutil.WriteFile(yggfile, j, 0600); e != nil {
|
||||
if e := os.WriteFile(yggfile, j, 0600); e != nil {
|
||||
n.log.Printf("Couldn't write private key to file '%s': %s\n", yggfile, e)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import (
|
|||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
|
|
@ -47,7 +47,7 @@ const HEAD = "HEAD"
|
|||
// We cannot use the dockerfile associated with the repo with each version sadly due to changes in
|
||||
// Docker versions. Specifically, earlier Dendrite versions are incompatible with newer Docker clients
|
||||
// due to the error:
|
||||
// When using COPY with more than one source file, the destination must be a directory and end with a /
|
||||
// When using COPY with more than one source file, the destination must be a directory and end with a /
|
||||
// We need to run a postgres anyway, so use the dockerfile associated with Complement instead.
|
||||
const Dockerfile = `FROM golang:1.18-stretch as build
|
||||
RUN apt-get update && apt-get install -y postgresql
|
||||
|
|
@ -95,7 +95,9 @@ CMD /build/run_dendrite.sh `
|
|||
const dendriteUpgradeTestLabel = "dendrite_upgrade_test"
|
||||
|
||||
// downloadArchive downloads an arbitrary github archive of the form:
|
||||
// https://github.com/matrix-org/dendrite/archive/v0.3.11.tar.gz
|
||||
//
|
||||
// https://github.com/matrix-org/dendrite/archive/v0.3.11.tar.gz
|
||||
//
|
||||
// and re-tarballs it without the top-level directory which contains branch information. It inserts
|
||||
// the contents of `dockerfile` as a root file `Dockerfile` in the re-tarballed directory such that
|
||||
// you can directly feed the retarballed archive to `ImageBuild` to have it run said dockerfile.
|
||||
|
|
@ -126,7 +128,7 @@ func downloadArchive(cli *http.Client, tmpDir, archiveURL string, dockerfile []b
|
|||
return nil, err
|
||||
}
|
||||
// add top level Dockerfile
|
||||
err = ioutil.WriteFile(path.Join(tmpDir, "Dockerfile"), dockerfile, os.ModePerm)
|
||||
err = os.WriteFile(path.Join(tmpDir, "Dockerfile"), dockerfile, os.ModePerm)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to inject /Dockerfile: %w", err)
|
||||
}
|
||||
|
|
@ -148,7 +150,7 @@ func buildDendrite(httpClient *http.Client, dockerClient *client.Client, tmpDir,
|
|||
if branchOrTagName == HEAD && *flagHead != "" {
|
||||
log.Printf("%s: Using %s as HEAD", branchOrTagName, *flagHead)
|
||||
// add top level Dockerfile
|
||||
err = ioutil.WriteFile(path.Join(*flagHead, "Dockerfile"), []byte(Dockerfile), os.ModePerm)
|
||||
err = os.WriteFile(path.Join(*flagHead, "Dockerfile"), []byte(Dockerfile), os.ModePerm)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("custom HEAD: failed to inject /Dockerfile: %w", err)
|
||||
}
|
||||
|
|
@ -386,7 +388,7 @@ func runImage(dockerClient *client.Client, volumeName, version, imageID string)
|
|||
})
|
||||
// ignore errors when cannot get logs, it's just for debugging anyways
|
||||
if err == nil {
|
||||
logbody, err := ioutil.ReadAll(logs)
|
||||
logbody, err := io.ReadAll(logs)
|
||||
if err == nil {
|
||||
log.Printf("Container logs:\n\n%s\n\n", string(logbody))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,9 +18,9 @@ type user struct {
|
|||
}
|
||||
|
||||
// runTests performs the following operations:
|
||||
// - register alice and bob with branch name muxed into the localpart
|
||||
// - create a DM room for the 2 users and exchange messages
|
||||
// - create/join a public #global room and exchange messages
|
||||
// - register alice and bob with branch name muxed into the localpart
|
||||
// - create a DM room for the 2 users and exchange messages
|
||||
// - create/join a public #global room and exchange messages
|
||||
func runTests(baseURL, branchName string) error {
|
||||
// register 2 users
|
||||
users := []user{
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ import (
|
|||
"encoding/pem"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/url"
|
||||
"os"
|
||||
|
||||
|
|
@ -30,7 +29,7 @@ func main() {
|
|||
os.Exit(1)
|
||||
}
|
||||
|
||||
data, err := ioutil.ReadFile(*requestKey)
|
||||
data, err := os.ReadFile(*requestKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -113,6 +113,11 @@ global:
|
|||
addresses:
|
||||
# - localhost:4222
|
||||
|
||||
# Disable the validation of TLS certificates of NATS. This is
|
||||
# not recommended in production since it may allow NATS traffic
|
||||
# to be sent to an insecure endpoint.
|
||||
disable_tls_validation: false
|
||||
|
||||
# Persistent directory to store JetStream streams in. This directory should be
|
||||
# preserved across Dendrite restarts.
|
||||
storage_path: ./
|
||||
|
|
@ -173,13 +178,16 @@ client_api:
|
|||
|
||||
# TURN server information that this homeserver should send to clients.
|
||||
turn:
|
||||
turn_user_lifetime: ""
|
||||
turn_user_lifetime: "5m"
|
||||
turn_uris:
|
||||
# - turn:turn.server.org?transport=udp
|
||||
# - turn:turn.server.org?transport=tcp
|
||||
turn_shared_secret: ""
|
||||
turn_username: ""
|
||||
turn_password: ""
|
||||
# If your TURN server requires static credentials, then you will need to enter
|
||||
# them here instead of supplying a shared secret. Note that these credentials
|
||||
# will be visible to clients!
|
||||
# turn_username: ""
|
||||
# turn_password: ""
|
||||
|
||||
# Settings for rate-limited endpoints. Rate limiting kicks in after the threshold
|
||||
# number of "slots" have been taken by requests from a specific host. Each "slot"
|
||||
|
|
@ -187,7 +195,7 @@ client_api:
|
|||
# and appservice users are exempt from rate limiting by default.
|
||||
rate_limiting:
|
||||
enabled: true
|
||||
threshold: 5
|
||||
threshold: 20
|
||||
cooloff_ms: 500
|
||||
exempt_user_ids:
|
||||
# - "@user:domain.com"
|
||||
|
|
|
|||
|
|
@ -103,6 +103,11 @@ global:
|
|||
addresses:
|
||||
- hostname:4222
|
||||
|
||||
# Disable the validation of TLS certificates of NATS. This is
|
||||
# not recommended in production since it may allow NATS traffic
|
||||
# to be sent to an insecure endpoint.
|
||||
disable_tls_validation: false
|
||||
|
||||
# The prefix to use for stream names for this homeserver - really only useful
|
||||
# if you are running more than one Dendrite server on the same NATS deployment.
|
||||
topic_prefix: Dendrite
|
||||
|
|
@ -176,13 +181,16 @@ client_api:
|
|||
|
||||
# TURN server information that this homeserver should send to clients.
|
||||
turn:
|
||||
turn_user_lifetime: ""
|
||||
turn_user_lifetime: "5m"
|
||||
turn_uris:
|
||||
# - turn:turn.server.org?transport=udp
|
||||
# - turn:turn.server.org?transport=tcp
|
||||
turn_shared_secret: ""
|
||||
turn_username: ""
|
||||
turn_password: ""
|
||||
# If your TURN server requires static credentials, then you will need to enter
|
||||
# them here instead of supplying a shared secret. Note that these credentials
|
||||
# will be visible to clients!
|
||||
# turn_username: ""
|
||||
# turn_password: ""
|
||||
|
||||
# Settings for rate-limited endpoints. Rate limiting kicks in after the threshold
|
||||
# number of "slots" have been taken by requests from a specific host. Each "slot"
|
||||
|
|
@ -190,7 +198,7 @@ client_api:
|
|||
# and appservice users are exempt from rate limiting by default.
|
||||
rate_limiting:
|
||||
enabled: true
|
||||
threshold: 5
|
||||
threshold: 20
|
||||
cooloff_ms: 500
|
||||
exempt_user_ids:
|
||||
# - "@user:domain.com"
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ comment. Please avoid doing this if you can.
|
|||
We also have unit tests which we run via:
|
||||
|
||||
```bash
|
||||
go test ./...
|
||||
go test --race ./...
|
||||
```
|
||||
|
||||
In general, we like submissions that come with tests. Anything that proves that the
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ type FederationClientError struct {
|
|||
Blacklisted bool
|
||||
}
|
||||
|
||||
func (e *FederationClientError) Error() string {
|
||||
func (e FederationClientError) Error() string {
|
||||
return fmt.Sprintf("%s - (retry_after=%s, blacklisted=%v)", e.Err, e.RetryAfter.String(), e.Blacklisted)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -208,9 +208,11 @@ func (s *OutputRoomEventConsumer) processMessage(ore api.OutputNewRoomEvent, rew
|
|||
// joinedHostsAtEvent works out a list of matrix servers that were joined to
|
||||
// the room at the event (including peeking ones)
|
||||
// It is important to use the state at the event for sending messages because:
|
||||
// 1) We shouldn't send messages to servers that weren't in the room.
|
||||
// 2) If a server is kicked from the rooms it should still be told about the
|
||||
// kick event,
|
||||
//
|
||||
// 1. We shouldn't send messages to servers that weren't in the room.
|
||||
// 2. If a server is kicked from the rooms it should still be told about the
|
||||
// kick event.
|
||||
//
|
||||
// Usually the list can be calculated locally, but sometimes it will need fetch
|
||||
// events from the room server.
|
||||
// Returns an error if there was a problem talking to the room server.
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@
|
|||
package federationapi
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/matrix-org/dendrite/federationapi/api"
|
||||
federationAPI "github.com/matrix-org/dendrite/federationapi/api"
|
||||
|
|
@ -167,5 +169,16 @@ func NewInternalAPI(
|
|||
if err = presenceConsumer.Start(); err != nil {
|
||||
logrus.WithError(err).Panic("failed to start presence consumer")
|
||||
}
|
||||
|
||||
var cleanExpiredEDUs func()
|
||||
cleanExpiredEDUs = func() {
|
||||
logrus.Infof("Cleaning expired EDUs")
|
||||
if err := federationDB.DeleteExpiredEDUs(base.Context()); err != nil {
|
||||
logrus.WithError(err).Error("Failed to clean expired EDUs")
|
||||
}
|
||||
time.AfterFunc(time.Hour, cleanExpiredEDUs)
|
||||
}
|
||||
time.AfterFunc(time.Minute, cleanExpiredEDUs)
|
||||
|
||||
return internal.NewFederationInternalAPI(federationDB, cfg, rsAPI, federation, stats, caches, queues, keyRing)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import (
|
|||
"crypto/ed25519"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"testing"
|
||||
|
|
@ -66,7 +66,7 @@ func TestMain(m *testing.M) {
|
|||
s.cache = caching.NewRistrettoCache(8*1024*1024, time.Hour, false)
|
||||
|
||||
// Create a temporary directory for JetStream.
|
||||
d, err := ioutil.TempDir("./", "jetstream*")
|
||||
d, err := os.MkdirTemp("./", "jetstream*")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
@ -136,7 +136,7 @@ func (m *MockRoundTripper) RoundTrip(req *http.Request) (res *http.Response, err
|
|||
// And respond.
|
||||
res = &http.Response{
|
||||
StatusCode: 200,
|
||||
Body: ioutil.NopCloser(bytes.NewReader(body)),
|
||||
Body: io.NopCloser(bytes.NewReader(body)),
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
|
@ -31,11 +32,12 @@ type fedRoomserverAPI struct {
|
|||
}
|
||||
|
||||
// PerformJoin will call this function
|
||||
func (f *fedRoomserverAPI) InputRoomEvents(ctx context.Context, req *rsapi.InputRoomEventsRequest, res *rsapi.InputRoomEventsResponse) {
|
||||
func (f *fedRoomserverAPI) InputRoomEvents(ctx context.Context, req *rsapi.InputRoomEventsRequest, res *rsapi.InputRoomEventsResponse) error {
|
||||
if f.inputRoomEvents == nil {
|
||||
return
|
||||
return nil
|
||||
}
|
||||
f.inputRoomEvents(ctx, req, res)
|
||||
return nil
|
||||
}
|
||||
|
||||
// keychange consumer calls this
|
||||
|
|
@ -48,6 +50,7 @@ func (f *fedRoomserverAPI) QueryRoomsForUser(ctx context.Context, req *rsapi.Que
|
|||
|
||||
// TODO: This struct isn't generic, only works for TestFederationAPIJoinThenKeyUpdate
|
||||
type fedClient struct {
|
||||
fedClientMutex sync.Mutex
|
||||
api.FederationClient
|
||||
allowJoins []*test.Room
|
||||
keys map[gomatrixserverlib.ServerName]struct {
|
||||
|
|
@ -59,6 +62,8 @@ type fedClient struct {
|
|||
}
|
||||
|
||||
func (f *fedClient) GetServerKeys(ctx context.Context, matrixServer gomatrixserverlib.ServerName) (gomatrixserverlib.ServerKeys, error) {
|
||||
f.fedClientMutex.Lock()
|
||||
defer f.fedClientMutex.Unlock()
|
||||
fmt.Println("GetServerKeys:", matrixServer)
|
||||
var keys gomatrixserverlib.ServerKeys
|
||||
var keyID gomatrixserverlib.KeyID
|
||||
|
|
@ -122,6 +127,8 @@ func (f *fedClient) MakeJoin(ctx context.Context, s gomatrixserverlib.ServerName
|
|||
return
|
||||
}
|
||||
func (f *fedClient) SendJoin(ctx context.Context, s gomatrixserverlib.ServerName, event *gomatrixserverlib.Event) (res gomatrixserverlib.RespSendJoin, err error) {
|
||||
f.fedClientMutex.Lock()
|
||||
defer f.fedClientMutex.Unlock()
|
||||
for _, r := range f.allowJoins {
|
||||
if r.ID == event.RoomID() {
|
||||
r.InsertEvent(f.t, event.Headered(r.Version))
|
||||
|
|
@ -134,6 +141,8 @@ func (f *fedClient) SendJoin(ctx context.Context, s gomatrixserverlib.ServerName
|
|||
}
|
||||
|
||||
func (f *fedClient) SendTransaction(ctx context.Context, t gomatrixserverlib.Transaction) (res gomatrixserverlib.RespSend, err error) {
|
||||
f.fedClientMutex.Lock()
|
||||
defer f.fedClientMutex.Unlock()
|
||||
for _, edu := range t.EDUs {
|
||||
if edu.Type == gomatrixserverlib.MDeviceListUpdate {
|
||||
f.sentTxn = true
|
||||
|
|
@ -242,6 +251,8 @@ func testFederationAPIJoinThenKeyUpdate(t *testing.T, dbType test.DBType) {
|
|||
|
||||
testrig.MustPublishMsgs(t, jsctx, msg)
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
fc.fedClientMutex.Lock()
|
||||
defer fc.fedClientMutex.Unlock()
|
||||
if !fc.sentTxn {
|
||||
t.Fatalf("did not send device list update")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import (
|
|||
"github.com/matrix-org/dendrite/internal/httputil"
|
||||
"github.com/matrix-org/gomatrix"
|
||||
"github.com/matrix-org/gomatrixserverlib"
|
||||
"github.com/opentracing/opentracing-go"
|
||||
)
|
||||
|
||||
// HTTP paths for the internal HTTP API
|
||||
|
|
@ -48,7 +47,11 @@ func NewFederationAPIClient(federationSenderURL string, httpClient *http.Client,
|
|||
if httpClient == nil {
|
||||
return nil, errors.New("NewFederationInternalAPIHTTP: httpClient is <nil>")
|
||||
}
|
||||
return &httpFederationInternalAPI{federationSenderURL, httpClient, cache}, nil
|
||||
return &httpFederationInternalAPI{
|
||||
federationAPIURL: federationSenderURL,
|
||||
httpClient: httpClient,
|
||||
cache: cache,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type httpFederationInternalAPI struct {
|
||||
|
|
@ -63,11 +66,10 @@ func (h *httpFederationInternalAPI) PerformLeave(
|
|||
request *api.PerformLeaveRequest,
|
||||
response *api.PerformLeaveResponse,
|
||||
) error {
|
||||
span, ctx := opentracing.StartSpanFromContext(ctx, "PerformLeaveRequest")
|
||||
defer span.Finish()
|
||||
|
||||
apiURL := h.federationAPIURL + FederationAPIPerformLeaveRequestPath
|
||||
return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response)
|
||||
return httputil.CallInternalRPCAPI(
|
||||
"PerformLeave", h.federationAPIURL+FederationAPIPerformLeaveRequestPath,
|
||||
h.httpClient, ctx, request, response,
|
||||
)
|
||||
}
|
||||
|
||||
// Handle sending an invite to a remote server.
|
||||
|
|
@ -76,11 +78,10 @@ func (h *httpFederationInternalAPI) PerformInvite(
|
|||
request *api.PerformInviteRequest,
|
||||
response *api.PerformInviteResponse,
|
||||
) error {
|
||||
span, ctx := opentracing.StartSpanFromContext(ctx, "PerformInviteRequest")
|
||||
defer span.Finish()
|
||||
|
||||
apiURL := h.federationAPIURL + FederationAPIPerformInviteRequestPath
|
||||
return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response)
|
||||
return httputil.CallInternalRPCAPI(
|
||||
"PerformInvite", h.federationAPIURL+FederationAPIPerformInviteRequestPath,
|
||||
h.httpClient, ctx, request, response,
|
||||
)
|
||||
}
|
||||
|
||||
// Handle starting a peek on a remote server.
|
||||
|
|
@ -89,11 +90,10 @@ func (h *httpFederationInternalAPI) PerformOutboundPeek(
|
|||
request *api.PerformOutboundPeekRequest,
|
||||
response *api.PerformOutboundPeekResponse,
|
||||
) error {
|
||||
span, ctx := opentracing.StartSpanFromContext(ctx, "PerformOutboundPeekRequest")
|
||||
defer span.Finish()
|
||||
|
||||
apiURL := h.federationAPIURL + FederationAPIPerformOutboundPeekRequestPath
|
||||
return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response)
|
||||
return httputil.CallInternalRPCAPI(
|
||||
"PerformOutboundPeek", h.federationAPIURL+FederationAPIPerformOutboundPeekRequestPath,
|
||||
h.httpClient, ctx, request, response,
|
||||
)
|
||||
}
|
||||
|
||||
// QueryJoinedHostServerNamesInRoom implements FederationInternalAPI
|
||||
|
|
@ -102,11 +102,10 @@ func (h *httpFederationInternalAPI) QueryJoinedHostServerNamesInRoom(
|
|||
request *api.QueryJoinedHostServerNamesInRoomRequest,
|
||||
response *api.QueryJoinedHostServerNamesInRoomResponse,
|
||||
) error {
|
||||
span, ctx := opentracing.StartSpanFromContext(ctx, "QueryJoinedHostServerNamesInRoom")
|
||||
defer span.Finish()
|
||||
|
||||
apiURL := h.federationAPIURL + FederationAPIQueryJoinedHostServerNamesInRoomPath
|
||||
return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response)
|
||||
return httputil.CallInternalRPCAPI(
|
||||
"QueryJoinedHostServerNamesInRoom", h.federationAPIURL+FederationAPIQueryJoinedHostServerNamesInRoomPath,
|
||||
h.httpClient, ctx, request, response,
|
||||
)
|
||||
}
|
||||
|
||||
// Handle an instruction to make_join & send_join with a remote server.
|
||||
|
|
@ -115,12 +114,10 @@ func (h *httpFederationInternalAPI) PerformJoin(
|
|||
request *api.PerformJoinRequest,
|
||||
response *api.PerformJoinResponse,
|
||||
) {
|
||||
span, ctx := opentracing.StartSpanFromContext(ctx, "PerformJoinRequest")
|
||||
defer span.Finish()
|
||||
|
||||
apiURL := h.federationAPIURL + FederationAPIPerformJoinRequestPath
|
||||
err := httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response)
|
||||
if err != nil {
|
||||
if err := httputil.CallInternalRPCAPI(
|
||||
"PerformJoinRequest", h.federationAPIURL+FederationAPIPerformJoinRequestPath,
|
||||
h.httpClient, ctx, request, response,
|
||||
); err != nil {
|
||||
response.LastError = &gomatrix.HTTPError{
|
||||
Message: err.Error(),
|
||||
Code: 0,
|
||||
|
|
@ -135,11 +132,10 @@ func (h *httpFederationInternalAPI) PerformDirectoryLookup(
|
|||
request *api.PerformDirectoryLookupRequest,
|
||||
response *api.PerformDirectoryLookupResponse,
|
||||
) error {
|
||||
span, ctx := opentracing.StartSpanFromContext(ctx, "PerformDirectoryLookup")
|
||||
defer span.Finish()
|
||||
|
||||
apiURL := h.federationAPIURL + FederationAPIPerformDirectoryLookupRequestPath
|
||||
return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response)
|
||||
return httputil.CallInternalRPCAPI(
|
||||
"PerformDirectoryLookup", h.federationAPIURL+FederationAPIPerformDirectoryLookupRequestPath,
|
||||
h.httpClient, ctx, request, response,
|
||||
)
|
||||
}
|
||||
|
||||
// Handle an instruction to broadcast an EDU to all servers in rooms we are joined to.
|
||||
|
|
@ -148,101 +144,61 @@ func (h *httpFederationInternalAPI) PerformBroadcastEDU(
|
|||
request *api.PerformBroadcastEDURequest,
|
||||
response *api.PerformBroadcastEDUResponse,
|
||||
) error {
|
||||
span, ctx := opentracing.StartSpanFromContext(ctx, "PerformBroadcastEDU")
|
||||
defer span.Finish()
|
||||
|
||||
apiURL := h.federationAPIURL + FederationAPIPerformBroadcastEDUPath
|
||||
return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response)
|
||||
return httputil.CallInternalRPCAPI(
|
||||
"PerformBroadcastEDU", h.federationAPIURL+FederationAPIPerformBroadcastEDUPath,
|
||||
h.httpClient, ctx, request, response,
|
||||
)
|
||||
}
|
||||
|
||||
type getUserDevices struct {
|
||||
S gomatrixserverlib.ServerName
|
||||
UserID string
|
||||
Res *gomatrixserverlib.RespUserDevices
|
||||
Err *api.FederationClientError
|
||||
}
|
||||
|
||||
func (h *httpFederationInternalAPI) GetUserDevices(
|
||||
ctx context.Context, s gomatrixserverlib.ServerName, userID string,
|
||||
) (gomatrixserverlib.RespUserDevices, error) {
|
||||
span, ctx := opentracing.StartSpanFromContext(ctx, "GetUserDevices")
|
||||
defer span.Finish()
|
||||
|
||||
var result gomatrixserverlib.RespUserDevices
|
||||
request := getUserDevices{
|
||||
S: s,
|
||||
UserID: userID,
|
||||
}
|
||||
var response getUserDevices
|
||||
apiURL := h.federationAPIURL + FederationAPIGetUserDevicesPath
|
||||
err := httputil.PostJSON(ctx, span, h.httpClient, apiURL, &request, &response)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
if response.Err != nil {
|
||||
return result, response.Err
|
||||
}
|
||||
return *response.Res, nil
|
||||
return httputil.CallInternalProxyAPI[getUserDevices, gomatrixserverlib.RespUserDevices, *api.FederationClientError](
|
||||
"GetUserDevices", h.federationAPIURL+FederationAPIGetUserDevicesPath, h.httpClient,
|
||||
ctx, &getUserDevices{
|
||||
S: s,
|
||||
UserID: userID,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
type claimKeys struct {
|
||||
S gomatrixserverlib.ServerName
|
||||
OneTimeKeys map[string]map[string]string
|
||||
Res *gomatrixserverlib.RespClaimKeys
|
||||
Err *api.FederationClientError
|
||||
}
|
||||
|
||||
func (h *httpFederationInternalAPI) ClaimKeys(
|
||||
ctx context.Context, s gomatrixserverlib.ServerName, oneTimeKeys map[string]map[string]string,
|
||||
) (gomatrixserverlib.RespClaimKeys, error) {
|
||||
span, ctx := opentracing.StartSpanFromContext(ctx, "ClaimKeys")
|
||||
defer span.Finish()
|
||||
|
||||
var result gomatrixserverlib.RespClaimKeys
|
||||
request := claimKeys{
|
||||
S: s,
|
||||
OneTimeKeys: oneTimeKeys,
|
||||
}
|
||||
var response claimKeys
|
||||
apiURL := h.federationAPIURL + FederationAPIClaimKeysPath
|
||||
err := httputil.PostJSON(ctx, span, h.httpClient, apiURL, &request, &response)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
if response.Err != nil {
|
||||
return result, response.Err
|
||||
}
|
||||
return *response.Res, nil
|
||||
return httputil.CallInternalProxyAPI[claimKeys, gomatrixserverlib.RespClaimKeys, *api.FederationClientError](
|
||||
"ClaimKeys", h.federationAPIURL+FederationAPIClaimKeysPath, h.httpClient,
|
||||
ctx, &claimKeys{
|
||||
S: s,
|
||||
OneTimeKeys: oneTimeKeys,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
type queryKeys struct {
|
||||
S gomatrixserverlib.ServerName
|
||||
Keys map[string][]string
|
||||
Res *gomatrixserverlib.RespQueryKeys
|
||||
Err *api.FederationClientError
|
||||
}
|
||||
|
||||
func (h *httpFederationInternalAPI) QueryKeys(
|
||||
ctx context.Context, s gomatrixserverlib.ServerName, keys map[string][]string,
|
||||
) (gomatrixserverlib.RespQueryKeys, error) {
|
||||
span, ctx := opentracing.StartSpanFromContext(ctx, "QueryKeys")
|
||||
defer span.Finish()
|
||||
|
||||
var result gomatrixserverlib.RespQueryKeys
|
||||
request := queryKeys{
|
||||
S: s,
|
||||
Keys: keys,
|
||||
}
|
||||
var response queryKeys
|
||||
apiURL := h.federationAPIURL + FederationAPIQueryKeysPath
|
||||
err := httputil.PostJSON(ctx, span, h.httpClient, apiURL, &request, &response)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
if response.Err != nil {
|
||||
return result, response.Err
|
||||
}
|
||||
return *response.Res, nil
|
||||
return httputil.CallInternalProxyAPI[queryKeys, gomatrixserverlib.RespQueryKeys, *api.FederationClientError](
|
||||
"QueryKeys", h.federationAPIURL+FederationAPIQueryKeysPath, h.httpClient,
|
||||
ctx, &queryKeys{
|
||||
S: s,
|
||||
Keys: keys,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
type backfill struct {
|
||||
|
|
@ -250,32 +206,20 @@ type backfill struct {
|
|||
RoomID string
|
||||
Limit int
|
||||
EventIDs []string
|
||||
Res *gomatrixserverlib.Transaction
|
||||
Err *api.FederationClientError
|
||||
}
|
||||
|
||||
func (h *httpFederationInternalAPI) Backfill(
|
||||
ctx context.Context, s gomatrixserverlib.ServerName, roomID string, limit int, eventIDs []string,
|
||||
) (gomatrixserverlib.Transaction, error) {
|
||||
span, ctx := opentracing.StartSpanFromContext(ctx, "Backfill")
|
||||
defer span.Finish()
|
||||
|
||||
request := backfill{
|
||||
S: s,
|
||||
RoomID: roomID,
|
||||
Limit: limit,
|
||||
EventIDs: eventIDs,
|
||||
}
|
||||
var response backfill
|
||||
apiURL := h.federationAPIURL + FederationAPIBackfillPath
|
||||
err := httputil.PostJSON(ctx, span, h.httpClient, apiURL, &request, &response)
|
||||
if err != nil {
|
||||
return gomatrixserverlib.Transaction{}, err
|
||||
}
|
||||
if response.Err != nil {
|
||||
return gomatrixserverlib.Transaction{}, response.Err
|
||||
}
|
||||
return *response.Res, nil
|
||||
return httputil.CallInternalProxyAPI[backfill, gomatrixserverlib.Transaction, *api.FederationClientError](
|
||||
"Backfill", h.federationAPIURL+FederationAPIBackfillPath, h.httpClient,
|
||||
ctx, &backfill{
|
||||
S: s,
|
||||
RoomID: roomID,
|
||||
Limit: limit,
|
||||
EventIDs: eventIDs,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
type lookupState struct {
|
||||
|
|
@ -283,63 +227,39 @@ type lookupState struct {
|
|||
RoomID string
|
||||
EventID string
|
||||
RoomVersion gomatrixserverlib.RoomVersion
|
||||
Res *gomatrixserverlib.RespState
|
||||
Err *api.FederationClientError
|
||||
}
|
||||
|
||||
func (h *httpFederationInternalAPI) LookupState(
|
||||
ctx context.Context, s gomatrixserverlib.ServerName, roomID, eventID string, roomVersion gomatrixserverlib.RoomVersion,
|
||||
) (gomatrixserverlib.RespState, error) {
|
||||
span, ctx := opentracing.StartSpanFromContext(ctx, "LookupState")
|
||||
defer span.Finish()
|
||||
|
||||
request := lookupState{
|
||||
S: s,
|
||||
RoomID: roomID,
|
||||
EventID: eventID,
|
||||
RoomVersion: roomVersion,
|
||||
}
|
||||
var response lookupState
|
||||
apiURL := h.federationAPIURL + FederationAPILookupStatePath
|
||||
err := httputil.PostJSON(ctx, span, h.httpClient, apiURL, &request, &response)
|
||||
if err != nil {
|
||||
return gomatrixserverlib.RespState{}, err
|
||||
}
|
||||
if response.Err != nil {
|
||||
return gomatrixserverlib.RespState{}, response.Err
|
||||
}
|
||||
return *response.Res, nil
|
||||
return httputil.CallInternalProxyAPI[lookupState, gomatrixserverlib.RespState, *api.FederationClientError](
|
||||
"LookupState", h.federationAPIURL+FederationAPILookupStatePath, h.httpClient,
|
||||
ctx, &lookupState{
|
||||
S: s,
|
||||
RoomID: roomID,
|
||||
EventID: eventID,
|
||||
RoomVersion: roomVersion,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
type lookupStateIDs struct {
|
||||
S gomatrixserverlib.ServerName
|
||||
RoomID string
|
||||
EventID string
|
||||
Res *gomatrixserverlib.RespStateIDs
|
||||
Err *api.FederationClientError
|
||||
}
|
||||
|
||||
func (h *httpFederationInternalAPI) LookupStateIDs(
|
||||
ctx context.Context, s gomatrixserverlib.ServerName, roomID, eventID string,
|
||||
) (gomatrixserverlib.RespStateIDs, error) {
|
||||
span, ctx := opentracing.StartSpanFromContext(ctx, "LookupStateIDs")
|
||||
defer span.Finish()
|
||||
|
||||
request := lookupStateIDs{
|
||||
S: s,
|
||||
RoomID: roomID,
|
||||
EventID: eventID,
|
||||
}
|
||||
var response lookupStateIDs
|
||||
apiURL := h.federationAPIURL + FederationAPILookupStateIDsPath
|
||||
err := httputil.PostJSON(ctx, span, h.httpClient, apiURL, &request, &response)
|
||||
if err != nil {
|
||||
return gomatrixserverlib.RespStateIDs{}, err
|
||||
}
|
||||
if response.Err != nil {
|
||||
return gomatrixserverlib.RespStateIDs{}, response.Err
|
||||
}
|
||||
return *response.Res, nil
|
||||
return httputil.CallInternalProxyAPI[lookupStateIDs, gomatrixserverlib.RespStateIDs, *api.FederationClientError](
|
||||
"LookupStateIDs", h.federationAPIURL+FederationAPILookupStateIDsPath, h.httpClient,
|
||||
ctx, &lookupStateIDs{
|
||||
S: s,
|
||||
RoomID: roomID,
|
||||
EventID: eventID,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
type lookupMissingEvents struct {
|
||||
|
|
@ -347,64 +267,38 @@ type lookupMissingEvents struct {
|
|||
RoomID string
|
||||
Missing gomatrixserverlib.MissingEvents
|
||||
RoomVersion gomatrixserverlib.RoomVersion
|
||||
Res struct {
|
||||
Events []gomatrixserverlib.RawJSON `json:"events"`
|
||||
}
|
||||
Err *api.FederationClientError
|
||||
}
|
||||
|
||||
func (h *httpFederationInternalAPI) LookupMissingEvents(
|
||||
ctx context.Context, s gomatrixserverlib.ServerName, roomID string,
|
||||
missing gomatrixserverlib.MissingEvents, roomVersion gomatrixserverlib.RoomVersion,
|
||||
) (res gomatrixserverlib.RespMissingEvents, err error) {
|
||||
span, ctx := opentracing.StartSpanFromContext(ctx, "LookupMissingEvents")
|
||||
defer span.Finish()
|
||||
|
||||
request := lookupMissingEvents{
|
||||
S: s,
|
||||
RoomID: roomID,
|
||||
Missing: missing,
|
||||
RoomVersion: roomVersion,
|
||||
}
|
||||
apiURL := h.federationAPIURL + FederationAPILookupMissingEventsPath
|
||||
err = httputil.PostJSON(ctx, span, h.httpClient, apiURL, &request, &request)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
if request.Err != nil {
|
||||
return res, request.Err
|
||||
}
|
||||
res.Events = request.Res.Events
|
||||
return res, nil
|
||||
return httputil.CallInternalProxyAPI[lookupMissingEvents, gomatrixserverlib.RespMissingEvents, *api.FederationClientError](
|
||||
"LookupMissingEvents", h.federationAPIURL+FederationAPILookupMissingEventsPath, h.httpClient,
|
||||
ctx, &lookupMissingEvents{
|
||||
S: s,
|
||||
RoomID: roomID,
|
||||
Missing: missing,
|
||||
RoomVersion: roomVersion,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
type getEvent struct {
|
||||
S gomatrixserverlib.ServerName
|
||||
EventID string
|
||||
Res *gomatrixserverlib.Transaction
|
||||
Err *api.FederationClientError
|
||||
}
|
||||
|
||||
func (h *httpFederationInternalAPI) GetEvent(
|
||||
ctx context.Context, s gomatrixserverlib.ServerName, eventID string,
|
||||
) (gomatrixserverlib.Transaction, error) {
|
||||
span, ctx := opentracing.StartSpanFromContext(ctx, "GetEvent")
|
||||
defer span.Finish()
|
||||
|
||||
request := getEvent{
|
||||
S: s,
|
||||
EventID: eventID,
|
||||
}
|
||||
var response getEvent
|
||||
apiURL := h.federationAPIURL + FederationAPIGetEventPath
|
||||
err := httputil.PostJSON(ctx, span, h.httpClient, apiURL, &request, &response)
|
||||
if err != nil {
|
||||
return gomatrixserverlib.Transaction{}, err
|
||||
}
|
||||
if response.Err != nil {
|
||||
return gomatrixserverlib.Transaction{}, response.Err
|
||||
}
|
||||
return *response.Res, nil
|
||||
return httputil.CallInternalProxyAPI[getEvent, gomatrixserverlib.Transaction, *api.FederationClientError](
|
||||
"GetEvent", h.federationAPIURL+FederationAPIGetEventPath, h.httpClient,
|
||||
ctx, &getEvent{
|
||||
S: s,
|
||||
EventID: eventID,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
type getEventAuth struct {
|
||||
|
|
@ -412,135 +306,86 @@ type getEventAuth struct {
|
|||
RoomVersion gomatrixserverlib.RoomVersion
|
||||
RoomID string
|
||||
EventID string
|
||||
Res *gomatrixserverlib.RespEventAuth
|
||||
Err *api.FederationClientError
|
||||
}
|
||||
|
||||
func (h *httpFederationInternalAPI) GetEventAuth(
|
||||
ctx context.Context, s gomatrixserverlib.ServerName,
|
||||
roomVersion gomatrixserverlib.RoomVersion, roomID, eventID string,
|
||||
) (gomatrixserverlib.RespEventAuth, error) {
|
||||
span, ctx := opentracing.StartSpanFromContext(ctx, "GetEventAuth")
|
||||
defer span.Finish()
|
||||
|
||||
request := getEventAuth{
|
||||
S: s,
|
||||
RoomVersion: roomVersion,
|
||||
RoomID: roomID,
|
||||
EventID: eventID,
|
||||
}
|
||||
var response getEventAuth
|
||||
apiURL := h.federationAPIURL + FederationAPIGetEventAuthPath
|
||||
err := httputil.PostJSON(ctx, span, h.httpClient, apiURL, &request, &response)
|
||||
if err != nil {
|
||||
return gomatrixserverlib.RespEventAuth{}, err
|
||||
}
|
||||
if response.Err != nil {
|
||||
return gomatrixserverlib.RespEventAuth{}, response.Err
|
||||
}
|
||||
return *response.Res, nil
|
||||
return httputil.CallInternalProxyAPI[getEventAuth, gomatrixserverlib.RespEventAuth, *api.FederationClientError](
|
||||
"GetEventAuth", h.federationAPIURL+FederationAPIGetEventAuthPath, h.httpClient,
|
||||
ctx, &getEventAuth{
|
||||
S: s,
|
||||
RoomVersion: roomVersion,
|
||||
RoomID: roomID,
|
||||
EventID: eventID,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func (h *httpFederationInternalAPI) QueryServerKeys(
|
||||
ctx context.Context, req *api.QueryServerKeysRequest, res *api.QueryServerKeysResponse,
|
||||
) error {
|
||||
span, ctx := opentracing.StartSpanFromContext(ctx, "QueryServerKeys")
|
||||
defer span.Finish()
|
||||
|
||||
apiURL := h.federationAPIURL + FederationAPIQueryServerKeysPath
|
||||
return httputil.PostJSON(ctx, span, h.httpClient, apiURL, req, res)
|
||||
return httputil.CallInternalRPCAPI(
|
||||
"QueryServerKeys", h.federationAPIURL+FederationAPIQueryServerKeysPath,
|
||||
h.httpClient, ctx, req, res,
|
||||
)
|
||||
}
|
||||
|
||||
type lookupServerKeys struct {
|
||||
S gomatrixserverlib.ServerName
|
||||
KeyRequests map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.Timestamp
|
||||
ServerKeys []gomatrixserverlib.ServerKeys
|
||||
Err *api.FederationClientError
|
||||
}
|
||||
|
||||
func (h *httpFederationInternalAPI) LookupServerKeys(
|
||||
ctx context.Context, s gomatrixserverlib.ServerName, keyRequests map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.Timestamp,
|
||||
) ([]gomatrixserverlib.ServerKeys, error) {
|
||||
span, ctx := opentracing.StartSpanFromContext(ctx, "LookupServerKeys")
|
||||
defer span.Finish()
|
||||
|
||||
request := lookupServerKeys{
|
||||
S: s,
|
||||
KeyRequests: keyRequests,
|
||||
}
|
||||
var response lookupServerKeys
|
||||
apiURL := h.federationAPIURL + FederationAPILookupServerKeysPath
|
||||
err := httputil.PostJSON(ctx, span, h.httpClient, apiURL, &request, &response)
|
||||
if err != nil {
|
||||
return []gomatrixserverlib.ServerKeys{}, err
|
||||
}
|
||||
if response.Err != nil {
|
||||
return []gomatrixserverlib.ServerKeys{}, response.Err
|
||||
}
|
||||
return response.ServerKeys, nil
|
||||
return httputil.CallInternalProxyAPI[lookupServerKeys, []gomatrixserverlib.ServerKeys, *api.FederationClientError](
|
||||
"LookupServerKeys", h.federationAPIURL+FederationAPILookupServerKeysPath, h.httpClient,
|
||||
ctx, &lookupServerKeys{
|
||||
S: s,
|
||||
KeyRequests: keyRequests,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
type eventRelationships struct {
|
||||
S gomatrixserverlib.ServerName
|
||||
Req gomatrixserverlib.MSC2836EventRelationshipsRequest
|
||||
RoomVer gomatrixserverlib.RoomVersion
|
||||
Res gomatrixserverlib.MSC2836EventRelationshipsResponse
|
||||
Err *api.FederationClientError
|
||||
}
|
||||
|
||||
func (h *httpFederationInternalAPI) MSC2836EventRelationships(
|
||||
ctx context.Context, s gomatrixserverlib.ServerName, r gomatrixserverlib.MSC2836EventRelationshipsRequest,
|
||||
roomVersion gomatrixserverlib.RoomVersion,
|
||||
) (res gomatrixserverlib.MSC2836EventRelationshipsResponse, err error) {
|
||||
span, ctx := opentracing.StartSpanFromContext(ctx, "MSC2836EventRelationships")
|
||||
defer span.Finish()
|
||||
|
||||
request := eventRelationships{
|
||||
S: s,
|
||||
Req: r,
|
||||
RoomVer: roomVersion,
|
||||
}
|
||||
var response eventRelationships
|
||||
apiURL := h.federationAPIURL + FederationAPIEventRelationshipsPath
|
||||
err = httputil.PostJSON(ctx, span, h.httpClient, apiURL, &request, &response)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
if response.Err != nil {
|
||||
return res, response.Err
|
||||
}
|
||||
return response.Res, nil
|
||||
return httputil.CallInternalProxyAPI[eventRelationships, gomatrixserverlib.MSC2836EventRelationshipsResponse, *api.FederationClientError](
|
||||
"MSC2836EventRelationships", h.federationAPIURL+FederationAPIEventRelationshipsPath, h.httpClient,
|
||||
ctx, &eventRelationships{
|
||||
S: s,
|
||||
Req: r,
|
||||
RoomVer: roomVersion,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
type spacesReq struct {
|
||||
S gomatrixserverlib.ServerName
|
||||
SuggestedOnly bool
|
||||
RoomID string
|
||||
Res gomatrixserverlib.MSC2946SpacesResponse
|
||||
Err *api.FederationClientError
|
||||
}
|
||||
|
||||
func (h *httpFederationInternalAPI) MSC2946Spaces(
|
||||
ctx context.Context, dst gomatrixserverlib.ServerName, roomID string, suggestedOnly bool,
|
||||
) (res gomatrixserverlib.MSC2946SpacesResponse, err error) {
|
||||
span, ctx := opentracing.StartSpanFromContext(ctx, "MSC2946Spaces")
|
||||
defer span.Finish()
|
||||
|
||||
request := spacesReq{
|
||||
S: dst,
|
||||
SuggestedOnly: suggestedOnly,
|
||||
RoomID: roomID,
|
||||
}
|
||||
var response spacesReq
|
||||
apiURL := h.federationAPIURL + FederationAPISpacesSummaryPath
|
||||
err = httputil.PostJSON(ctx, span, h.httpClient, apiURL, &request, &response)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
if response.Err != nil {
|
||||
return res, response.Err
|
||||
}
|
||||
return response.Res, nil
|
||||
return httputil.CallInternalProxyAPI[spacesReq, gomatrixserverlib.MSC2946SpacesResponse, *api.FederationClientError](
|
||||
"MSC2836EventRelationships", h.federationAPIURL+FederationAPISpacesSummaryPath, h.httpClient,
|
||||
ctx, &spacesReq{
|
||||
S: dst,
|
||||
SuggestedOnly: suggestedOnly,
|
||||
RoomID: roomID,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func (s *httpFederationInternalAPI) KeyRing() *gomatrixserverlib.KeyRing {
|
||||
|
|
@ -614,11 +459,10 @@ func (h *httpFederationInternalAPI) InputPublicKeys(
|
|||
request *api.InputPublicKeysRequest,
|
||||
response *api.InputPublicKeysResponse,
|
||||
) error {
|
||||
span, ctx := opentracing.StartSpanFromContext(ctx, "InputPublicKey")
|
||||
defer span.Finish()
|
||||
|
||||
apiURL := h.federationAPIURL + FederationAPIInputPublicKeyPath
|
||||
return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response)
|
||||
return httputil.CallInternalRPCAPI(
|
||||
"InputPublicKey", h.federationAPIURL+FederationAPIInputPublicKeyPath,
|
||||
h.httpClient, ctx, request, response,
|
||||
)
|
||||
}
|
||||
|
||||
func (h *httpFederationInternalAPI) QueryPublicKeys(
|
||||
|
|
@ -626,9 +470,8 @@ func (h *httpFederationInternalAPI) QueryPublicKeys(
|
|||
request *api.QueryPublicKeysRequest,
|
||||
response *api.QueryPublicKeysResponse,
|
||||
) error {
|
||||
span, ctx := opentracing.StartSpanFromContext(ctx, "QueryPublicKey")
|
||||
defer span.Finish()
|
||||
|
||||
apiURL := h.federationAPIURL + FederationAPIQueryPublicKeyPath
|
||||
return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response)
|
||||
return httputil.CallInternalRPCAPI(
|
||||
"QueryPublicKeys", h.federationAPIURL+FederationAPIQueryPublicKeyPath,
|
||||
h.httpClient, ctx, request, response,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,14 @@
|
|||
package inthttp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/matrix-org/dendrite/federationapi/api"
|
||||
"github.com/matrix-org/dendrite/internal/httputil"
|
||||
"github.com/matrix-org/gomatrixserverlib"
|
||||
"github.com/matrix-org/util"
|
||||
)
|
||||
|
||||
|
|
@ -15,372 +17,180 @@ import (
|
|||
func AddRoutes(intAPI api.FederationInternalAPI, internalAPIMux *mux.Router) {
|
||||
internalAPIMux.Handle(
|
||||
FederationAPIQueryJoinedHostServerNamesInRoomPath,
|
||||
httputil.MakeInternalAPI("QueryJoinedHostServerNamesInRoom", func(req *http.Request) util.JSONResponse {
|
||||
var request api.QueryJoinedHostServerNamesInRoomRequest
|
||||
var response api.QueryJoinedHostServerNamesInRoomResponse
|
||||
if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
|
||||
return util.ErrorResponse(err)
|
||||
}
|
||||
if err := intAPI.QueryJoinedHostServerNamesInRoom(req.Context(), &request, &response); err != nil {
|
||||
return util.ErrorResponse(err)
|
||||
}
|
||||
return util.JSONResponse{Code: http.StatusOK, JSON: &response}
|
||||
}),
|
||||
)
|
||||
internalAPIMux.Handle(
|
||||
FederationAPIPerformJoinRequestPath,
|
||||
httputil.MakeInternalAPI("PerformJoinRequest", func(req *http.Request) util.JSONResponse {
|
||||
var request api.PerformJoinRequest
|
||||
var response api.PerformJoinResponse
|
||||
if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
|
||||
return util.MessageResponse(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
intAPI.PerformJoin(req.Context(), &request, &response)
|
||||
return util.JSONResponse{Code: http.StatusOK, JSON: &response}
|
||||
}),
|
||||
)
|
||||
internalAPIMux.Handle(
|
||||
FederationAPIPerformLeaveRequestPath,
|
||||
httputil.MakeInternalAPI("PerformLeaveRequest", func(req *http.Request) util.JSONResponse {
|
||||
var request api.PerformLeaveRequest
|
||||
var response api.PerformLeaveResponse
|
||||
if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
|
||||
return util.MessageResponse(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
if err := intAPI.PerformLeave(req.Context(), &request, &response); err != nil {
|
||||
return util.ErrorResponse(err)
|
||||
}
|
||||
return util.JSONResponse{Code: http.StatusOK, JSON: &response}
|
||||
}),
|
||||
httputil.MakeInternalRPCAPI("FederationAPIQueryJoinedHostServerNamesInRoom", intAPI.QueryJoinedHostServerNamesInRoom),
|
||||
)
|
||||
|
||||
internalAPIMux.Handle(
|
||||
FederationAPIPerformInviteRequestPath,
|
||||
httputil.MakeInternalAPI("PerformInviteRequest", func(req *http.Request) util.JSONResponse {
|
||||
var request api.PerformInviteRequest
|
||||
var response api.PerformInviteResponse
|
||||
if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
|
||||
return util.MessageResponse(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
if err := intAPI.PerformInvite(req.Context(), &request, &response); err != nil {
|
||||
return util.ErrorResponse(err)
|
||||
}
|
||||
return util.JSONResponse{Code: http.StatusOK, JSON: &response}
|
||||
}),
|
||||
httputil.MakeInternalRPCAPI("FederationAPIPerformInvite", intAPI.PerformInvite),
|
||||
)
|
||||
|
||||
internalAPIMux.Handle(
|
||||
FederationAPIPerformLeaveRequestPath,
|
||||
httputil.MakeInternalRPCAPI("FederationAPIPerformLeave", intAPI.PerformLeave),
|
||||
)
|
||||
|
||||
internalAPIMux.Handle(
|
||||
FederationAPIPerformDirectoryLookupRequestPath,
|
||||
httputil.MakeInternalAPI("PerformDirectoryLookupRequest", func(req *http.Request) util.JSONResponse {
|
||||
var request api.PerformDirectoryLookupRequest
|
||||
var response api.PerformDirectoryLookupResponse
|
||||
if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
|
||||
return util.MessageResponse(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
if err := intAPI.PerformDirectoryLookup(req.Context(), &request, &response); err != nil {
|
||||
return util.ErrorResponse(err)
|
||||
}
|
||||
return util.JSONResponse{Code: http.StatusOK, JSON: &response}
|
||||
}),
|
||||
httputil.MakeInternalRPCAPI("FederationAPIPerformDirectoryLookupRequest", intAPI.PerformDirectoryLookup),
|
||||
)
|
||||
|
||||
internalAPIMux.Handle(
|
||||
FederationAPIPerformBroadcastEDUPath,
|
||||
httputil.MakeInternalAPI("PerformBroadcastEDU", func(req *http.Request) util.JSONResponse {
|
||||
var request api.PerformBroadcastEDURequest
|
||||
var response api.PerformBroadcastEDUResponse
|
||||
if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
|
||||
return util.MessageResponse(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
if err := intAPI.PerformBroadcastEDU(req.Context(), &request, &response); err != nil {
|
||||
return util.ErrorResponse(err)
|
||||
}
|
||||
return util.JSONResponse{Code: http.StatusOK, JSON: &response}
|
||||
}),
|
||||
httputil.MakeInternalRPCAPI("FederationAPIPerformBroadcastEDU", intAPI.PerformBroadcastEDU),
|
||||
)
|
||||
|
||||
internalAPIMux.Handle(
|
||||
FederationAPIPerformJoinRequestPath,
|
||||
httputil.MakeInternalRPCAPI(
|
||||
"FederationAPIPerformJoinRequest",
|
||||
func(ctx context.Context, req *api.PerformJoinRequest, res *api.PerformJoinResponse) error {
|
||||
intAPI.PerformJoin(ctx, req, res)
|
||||
return nil
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
internalAPIMux.Handle(
|
||||
FederationAPIGetUserDevicesPath,
|
||||
httputil.MakeInternalAPI("GetUserDevices", func(req *http.Request) util.JSONResponse {
|
||||
var request getUserDevices
|
||||
if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
|
||||
return util.MessageResponse(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
res, err := intAPI.GetUserDevices(req.Context(), request.S, request.UserID)
|
||||
if err != nil {
|
||||
ferr, ok := err.(*api.FederationClientError)
|
||||
if ok {
|
||||
request.Err = ferr
|
||||
} else {
|
||||
request.Err = &api.FederationClientError{
|
||||
Err: err.Error(),
|
||||
}
|
||||
}
|
||||
}
|
||||
request.Res = &res
|
||||
return util.JSONResponse{Code: http.StatusOK, JSON: request}
|
||||
}),
|
||||
httputil.MakeInternalProxyAPI(
|
||||
"FederationAPIGetUserDevices",
|
||||
func(ctx context.Context, req *getUserDevices) (*gomatrixserverlib.RespUserDevices, error) {
|
||||
res, err := intAPI.GetUserDevices(ctx, req.S, req.UserID)
|
||||
return &res, federationClientError(err)
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
internalAPIMux.Handle(
|
||||
FederationAPIClaimKeysPath,
|
||||
httputil.MakeInternalAPI("ClaimKeys", func(req *http.Request) util.JSONResponse {
|
||||
var request claimKeys
|
||||
if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
|
||||
return util.MessageResponse(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
res, err := intAPI.ClaimKeys(req.Context(), request.S, request.OneTimeKeys)
|
||||
if err != nil {
|
||||
ferr, ok := err.(*api.FederationClientError)
|
||||
if ok {
|
||||
request.Err = ferr
|
||||
} else {
|
||||
request.Err = &api.FederationClientError{
|
||||
Err: err.Error(),
|
||||
}
|
||||
}
|
||||
}
|
||||
request.Res = &res
|
||||
return util.JSONResponse{Code: http.StatusOK, JSON: request}
|
||||
}),
|
||||
httputil.MakeInternalProxyAPI(
|
||||
"FederationAPIClaimKeys",
|
||||
func(ctx context.Context, req *claimKeys) (*gomatrixserverlib.RespClaimKeys, error) {
|
||||
res, err := intAPI.ClaimKeys(ctx, req.S, req.OneTimeKeys)
|
||||
return &res, federationClientError(err)
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
internalAPIMux.Handle(
|
||||
FederationAPIQueryKeysPath,
|
||||
httputil.MakeInternalAPI("QueryKeys", func(req *http.Request) util.JSONResponse {
|
||||
var request queryKeys
|
||||
if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
|
||||
return util.MessageResponse(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
res, err := intAPI.QueryKeys(req.Context(), request.S, request.Keys)
|
||||
if err != nil {
|
||||
ferr, ok := err.(*api.FederationClientError)
|
||||
if ok {
|
||||
request.Err = ferr
|
||||
} else {
|
||||
request.Err = &api.FederationClientError{
|
||||
Err: err.Error(),
|
||||
}
|
||||
}
|
||||
}
|
||||
request.Res = &res
|
||||
return util.JSONResponse{Code: http.StatusOK, JSON: request}
|
||||
}),
|
||||
httputil.MakeInternalProxyAPI(
|
||||
"FederationAPIQueryKeys",
|
||||
func(ctx context.Context, req *queryKeys) (*gomatrixserverlib.RespQueryKeys, error) {
|
||||
res, err := intAPI.QueryKeys(ctx, req.S, req.Keys)
|
||||
return &res, federationClientError(err)
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
internalAPIMux.Handle(
|
||||
FederationAPIBackfillPath,
|
||||
httputil.MakeInternalAPI("Backfill", func(req *http.Request) util.JSONResponse {
|
||||
var request backfill
|
||||
if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
|
||||
return util.MessageResponse(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
res, err := intAPI.Backfill(req.Context(), request.S, request.RoomID, request.Limit, request.EventIDs)
|
||||
if err != nil {
|
||||
ferr, ok := err.(*api.FederationClientError)
|
||||
if ok {
|
||||
request.Err = ferr
|
||||
} else {
|
||||
request.Err = &api.FederationClientError{
|
||||
Err: err.Error(),
|
||||
}
|
||||
}
|
||||
}
|
||||
request.Res = &res
|
||||
return util.JSONResponse{Code: http.StatusOK, JSON: request}
|
||||
}),
|
||||
httputil.MakeInternalProxyAPI(
|
||||
"FederationAPIBackfill",
|
||||
func(ctx context.Context, req *backfill) (*gomatrixserverlib.Transaction, error) {
|
||||
res, err := intAPI.Backfill(ctx, req.S, req.RoomID, req.Limit, req.EventIDs)
|
||||
return &res, federationClientError(err)
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
internalAPIMux.Handle(
|
||||
FederationAPILookupStatePath,
|
||||
httputil.MakeInternalAPI("LookupState", func(req *http.Request) util.JSONResponse {
|
||||
var request lookupState
|
||||
if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
|
||||
return util.MessageResponse(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
res, err := intAPI.LookupState(req.Context(), request.S, request.RoomID, request.EventID, request.RoomVersion)
|
||||
if err != nil {
|
||||
ferr, ok := err.(*api.FederationClientError)
|
||||
if ok {
|
||||
request.Err = ferr
|
||||
} else {
|
||||
request.Err = &api.FederationClientError{
|
||||
Err: err.Error(),
|
||||
}
|
||||
}
|
||||
}
|
||||
request.Res = &res
|
||||
return util.JSONResponse{Code: http.StatusOK, JSON: request}
|
||||
}),
|
||||
httputil.MakeInternalProxyAPI(
|
||||
"FederationAPILookupState",
|
||||
func(ctx context.Context, req *lookupState) (*gomatrixserverlib.RespState, error) {
|
||||
res, err := intAPI.LookupState(ctx, req.S, req.RoomID, req.EventID, req.RoomVersion)
|
||||
return &res, federationClientError(err)
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
internalAPIMux.Handle(
|
||||
FederationAPILookupStateIDsPath,
|
||||
httputil.MakeInternalAPI("LookupStateIDs", func(req *http.Request) util.JSONResponse {
|
||||
var request lookupStateIDs
|
||||
if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
|
||||
return util.MessageResponse(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
res, err := intAPI.LookupStateIDs(req.Context(), request.S, request.RoomID, request.EventID)
|
||||
if err != nil {
|
||||
ferr, ok := err.(*api.FederationClientError)
|
||||
if ok {
|
||||
request.Err = ferr
|
||||
} else {
|
||||
request.Err = &api.FederationClientError{
|
||||
Err: err.Error(),
|
||||
}
|
||||
}
|
||||
}
|
||||
request.Res = &res
|
||||
return util.JSONResponse{Code: http.StatusOK, JSON: request}
|
||||
}),
|
||||
httputil.MakeInternalProxyAPI(
|
||||
"FederationAPILookupStateIDs",
|
||||
func(ctx context.Context, req *lookupStateIDs) (*gomatrixserverlib.RespStateIDs, error) {
|
||||
res, err := intAPI.LookupStateIDs(ctx, req.S, req.RoomID, req.EventID)
|
||||
return &res, federationClientError(err)
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
internalAPIMux.Handle(
|
||||
FederationAPILookupMissingEventsPath,
|
||||
httputil.MakeInternalAPI("LookupMissingEvents", func(req *http.Request) util.JSONResponse {
|
||||
var request lookupMissingEvents
|
||||
if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
|
||||
return util.MessageResponse(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
res, err := intAPI.LookupMissingEvents(req.Context(), request.S, request.RoomID, request.Missing, request.RoomVersion)
|
||||
if err != nil {
|
||||
ferr, ok := err.(*api.FederationClientError)
|
||||
if ok {
|
||||
request.Err = ferr
|
||||
} else {
|
||||
request.Err = &api.FederationClientError{
|
||||
Err: err.Error(),
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, event := range res.Events {
|
||||
js, err := json.Marshal(event)
|
||||
if err != nil {
|
||||
return util.MessageResponse(http.StatusInternalServerError, err.Error())
|
||||
}
|
||||
request.Res.Events = append(request.Res.Events, js)
|
||||
}
|
||||
return util.JSONResponse{Code: http.StatusOK, JSON: request}
|
||||
}),
|
||||
httputil.MakeInternalProxyAPI(
|
||||
"FederationAPILookupMissingEvents",
|
||||
func(ctx context.Context, req *lookupMissingEvents) (*gomatrixserverlib.RespMissingEvents, error) {
|
||||
res, err := intAPI.LookupMissingEvents(ctx, req.S, req.RoomID, req.Missing, req.RoomVersion)
|
||||
return &res, federationClientError(err)
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
internalAPIMux.Handle(
|
||||
FederationAPIGetEventPath,
|
||||
httputil.MakeInternalAPI("GetEvent", func(req *http.Request) util.JSONResponse {
|
||||
var request getEvent
|
||||
if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
|
||||
return util.MessageResponse(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
res, err := intAPI.GetEvent(req.Context(), request.S, request.EventID)
|
||||
if err != nil {
|
||||
ferr, ok := err.(*api.FederationClientError)
|
||||
if ok {
|
||||
request.Err = ferr
|
||||
} else {
|
||||
request.Err = &api.FederationClientError{
|
||||
Err: err.Error(),
|
||||
}
|
||||
}
|
||||
}
|
||||
request.Res = &res
|
||||
return util.JSONResponse{Code: http.StatusOK, JSON: request}
|
||||
}),
|
||||
httputil.MakeInternalProxyAPI(
|
||||
"FederationAPIGetEvent",
|
||||
func(ctx context.Context, req *getEvent) (*gomatrixserverlib.Transaction, error) {
|
||||
res, err := intAPI.GetEvent(ctx, req.S, req.EventID)
|
||||
return &res, federationClientError(err)
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
internalAPIMux.Handle(
|
||||
FederationAPIGetEventAuthPath,
|
||||
httputil.MakeInternalAPI("GetEventAuth", func(req *http.Request) util.JSONResponse {
|
||||
var request getEventAuth
|
||||
if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
|
||||
return util.MessageResponse(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
res, err := intAPI.GetEventAuth(req.Context(), request.S, request.RoomVersion, request.RoomID, request.EventID)
|
||||
if err != nil {
|
||||
ferr, ok := err.(*api.FederationClientError)
|
||||
if ok {
|
||||
request.Err = ferr
|
||||
} else {
|
||||
request.Err = &api.FederationClientError{
|
||||
Err: err.Error(),
|
||||
}
|
||||
}
|
||||
}
|
||||
request.Res = &res
|
||||
return util.JSONResponse{Code: http.StatusOK, JSON: request}
|
||||
}),
|
||||
httputil.MakeInternalProxyAPI(
|
||||
"FederationAPIGetEventAuth",
|
||||
func(ctx context.Context, req *getEventAuth) (*gomatrixserverlib.RespEventAuth, error) {
|
||||
res, err := intAPI.GetEventAuth(ctx, req.S, req.RoomVersion, req.RoomID, req.EventID)
|
||||
return &res, federationClientError(err)
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
internalAPIMux.Handle(
|
||||
FederationAPIQueryServerKeysPath,
|
||||
httputil.MakeInternalAPI("QueryServerKeys", func(req *http.Request) util.JSONResponse {
|
||||
var request api.QueryServerKeysRequest
|
||||
var response api.QueryServerKeysResponse
|
||||
if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
|
||||
return util.MessageResponse(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
if err := intAPI.QueryServerKeys(req.Context(), &request, &response); err != nil {
|
||||
return util.ErrorResponse(err)
|
||||
}
|
||||
return util.JSONResponse{Code: http.StatusOK, JSON: &response}
|
||||
}),
|
||||
httputil.MakeInternalRPCAPI("FederationAPIQueryServerKeys", intAPI.QueryServerKeys),
|
||||
)
|
||||
|
||||
internalAPIMux.Handle(
|
||||
FederationAPILookupServerKeysPath,
|
||||
httputil.MakeInternalAPI("LookupServerKeys", func(req *http.Request) util.JSONResponse {
|
||||
var request lookupServerKeys
|
||||
if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
|
||||
return util.MessageResponse(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
res, err := intAPI.LookupServerKeys(req.Context(), request.S, request.KeyRequests)
|
||||
if err != nil {
|
||||
ferr, ok := err.(*api.FederationClientError)
|
||||
if ok {
|
||||
request.Err = ferr
|
||||
} else {
|
||||
request.Err = &api.FederationClientError{
|
||||
Err: err.Error(),
|
||||
}
|
||||
}
|
||||
}
|
||||
request.ServerKeys = res
|
||||
return util.JSONResponse{Code: http.StatusOK, JSON: request}
|
||||
}),
|
||||
httputil.MakeInternalProxyAPI(
|
||||
"FederationAPILookupServerKeys",
|
||||
func(ctx context.Context, req *lookupServerKeys) (*[]gomatrixserverlib.ServerKeys, error) {
|
||||
res, err := intAPI.LookupServerKeys(ctx, req.S, req.KeyRequests)
|
||||
return &res, federationClientError(err)
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
internalAPIMux.Handle(
|
||||
FederationAPIEventRelationshipsPath,
|
||||
httputil.MakeInternalAPI("MSC2836EventRelationships", func(req *http.Request) util.JSONResponse {
|
||||
var request eventRelationships
|
||||
if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
|
||||
return util.MessageResponse(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
res, err := intAPI.MSC2836EventRelationships(req.Context(), request.S, request.Req, request.RoomVer)
|
||||
if err != nil {
|
||||
ferr, ok := err.(*api.FederationClientError)
|
||||
if ok {
|
||||
request.Err = ferr
|
||||
} else {
|
||||
request.Err = &api.FederationClientError{
|
||||
Err: err.Error(),
|
||||
}
|
||||
}
|
||||
}
|
||||
request.Res = res
|
||||
return util.JSONResponse{Code: http.StatusOK, JSON: request}
|
||||
}),
|
||||
httputil.MakeInternalProxyAPI(
|
||||
"FederationAPIMSC2836EventRelationships",
|
||||
func(ctx context.Context, req *eventRelationships) (*gomatrixserverlib.MSC2836EventRelationshipsResponse, error) {
|
||||
res, err := intAPI.MSC2836EventRelationships(ctx, req.S, req.Req, req.RoomVer)
|
||||
return &res, federationClientError(err)
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
internalAPIMux.Handle(
|
||||
FederationAPISpacesSummaryPath,
|
||||
httputil.MakeInternalAPI("MSC2946SpacesSummary", func(req *http.Request) util.JSONResponse {
|
||||
var request spacesReq
|
||||
if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
|
||||
return util.MessageResponse(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
res, err := intAPI.MSC2946Spaces(req.Context(), request.S, request.RoomID, request.SuggestedOnly)
|
||||
if err != nil {
|
||||
ferr, ok := err.(*api.FederationClientError)
|
||||
if ok {
|
||||
request.Err = ferr
|
||||
} else {
|
||||
request.Err = &api.FederationClientError{
|
||||
Err: err.Error(),
|
||||
}
|
||||
}
|
||||
}
|
||||
request.Res = res
|
||||
return util.JSONResponse{Code: http.StatusOK, JSON: request}
|
||||
}),
|
||||
httputil.MakeInternalProxyAPI(
|
||||
"FederationAPIMSC2946SpacesSummary",
|
||||
func(ctx context.Context, req *spacesReq) (*gomatrixserverlib.MSC2946SpacesResponse, error) {
|
||||
res, err := intAPI.MSC2946Spaces(ctx, req.S, req.RoomID, req.SuggestedOnly)
|
||||
return &res, federationClientError(err)
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
// TODO: Look at this shape
|
||||
internalAPIMux.Handle(FederationAPIQueryPublicKeyPath,
|
||||
httputil.MakeInternalAPI("queryPublicKeys", func(req *http.Request) util.JSONResponse {
|
||||
httputil.MakeInternalAPI("FederationAPIQueryPublicKeys", func(req *http.Request) util.JSONResponse {
|
||||
request := api.QueryPublicKeysRequest{}
|
||||
response := api.QueryPublicKeysResponse{}
|
||||
if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
|
||||
|
|
@ -394,8 +204,10 @@ func AddRoutes(intAPI api.FederationInternalAPI, internalAPIMux *mux.Router) {
|
|||
return util.JSONResponse{Code: http.StatusOK, JSON: &response}
|
||||
}),
|
||||
)
|
||||
|
||||
// TODO: Look at this shape
|
||||
internalAPIMux.Handle(FederationAPIInputPublicKeyPath,
|
||||
httputil.MakeInternalAPI("inputPublicKeys", func(req *http.Request) util.JSONResponse {
|
||||
httputil.MakeInternalAPI("FederationAPIInputPublicKeys", func(req *http.Request) util.JSONResponse {
|
||||
request := api.InputPublicKeysRequest{}
|
||||
response := api.InputPublicKeysResponse{}
|
||||
if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
|
||||
|
|
@ -408,3 +220,18 @@ func AddRoutes(intAPI api.FederationInternalAPI, internalAPIMux *mux.Router) {
|
|||
}),
|
||||
)
|
||||
}
|
||||
|
||||
func federationClientError(err error) error {
|
||||
switch ferr := err.(type) {
|
||||
case nil:
|
||||
return nil
|
||||
case api.FederationClientError:
|
||||
return &ferr
|
||||
case *api.FederationClientError:
|
||||
return ferr
|
||||
default:
|
||||
return &api.FederationClientError{
|
||||
Err: err.Error(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -127,6 +127,7 @@ func (oq *destinationQueue) sendEDU(event *gomatrixserverlib.EDU, receipt *share
|
|||
oq.destination, // the destination server name
|
||||
receipt, // NIDs from federationapi_queue_json table
|
||||
event.Type,
|
||||
nil, // this will use the default expireEDUTypes map
|
||||
); err != nil {
|
||||
logrus.WithError(err).Errorf("failed to associate EDU with destination %q", oq.destination)
|
||||
return
|
||||
|
|
|
|||
|
|
@ -158,7 +158,7 @@ func (oqs *OutgoingQueues) getQueue(destination gomatrixserverlib.ServerName) *d
|
|||
oqs.queuesMutex.Lock()
|
||||
defer oqs.queuesMutex.Unlock()
|
||||
oq, ok := oqs.queues[destination]
|
||||
if !ok || oq != nil {
|
||||
if !ok || oq == nil {
|
||||
destinationQueueTotal.Inc()
|
||||
oq = &destinationQueue{
|
||||
queues: oqs,
|
||||
|
|
|
|||
|
|
@ -30,9 +30,11 @@ func GetUserDevices(
|
|||
userID string,
|
||||
) util.JSONResponse {
|
||||
var res keyapi.QueryDeviceMessagesResponse
|
||||
keyAPI.QueryDeviceMessages(req.Context(), &keyapi.QueryDeviceMessagesRequest{
|
||||
if err := keyAPI.QueryDeviceMessages(req.Context(), &keyapi.QueryDeviceMessagesRequest{
|
||||
UserID: userID,
|
||||
}, &res)
|
||||
}, &res); err != nil {
|
||||
return util.ErrorResponse(err)
|
||||
}
|
||||
if res.Error != nil {
|
||||
util.GetLogger(req.Context()).WithError(res.Error).Error("keyAPI.QueryDeviceMessages failed")
|
||||
return jsonerror.InternalServerError()
|
||||
|
|
@ -47,7 +49,9 @@ func GetUserDevices(
|
|||
for _, dev := range res.Devices {
|
||||
sigReq.TargetIDs[userID] = append(sigReq.TargetIDs[userID], gomatrixserverlib.KeyID(dev.DeviceID))
|
||||
}
|
||||
keyAPI.QuerySignatures(req.Context(), sigReq, sigRes)
|
||||
if err := keyAPI.QuerySignatures(req.Context(), sigReq, sigRes); err != nil {
|
||||
return jsonerror.InternalAPIError(req.Context(), err)
|
||||
}
|
||||
|
||||
response := gomatrixserverlib.RespUserDevices{
|
||||
UserID: userID,
|
||||
|
|
|
|||
|
|
@ -21,13 +21,14 @@ import (
|
|||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/matrix-org/gomatrixserverlib"
|
||||
"github.com/matrix-org/util"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/matrix-org/dendrite/clientapi/jsonerror"
|
||||
"github.com/matrix-org/dendrite/internal/eventutil"
|
||||
"github.com/matrix-org/dendrite/roomserver/api"
|
||||
"github.com/matrix-org/dendrite/setup/config"
|
||||
"github.com/matrix-org/gomatrixserverlib"
|
||||
"github.com/matrix-org/util"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// MakeJoin implements the /make_join API
|
||||
|
|
@ -202,6 +203,14 @@ func SendJoin(
|
|||
}
|
||||
}
|
||||
|
||||
// Check that the event is from the server sending the request.
|
||||
if event.Origin() != request.Origin() {
|
||||
return util.JSONResponse{
|
||||
Code: http.StatusForbidden,
|
||||
JSON: jsonerror.Forbidden("The join must be sent by the server it originated on"),
|
||||
}
|
||||
}
|
||||
|
||||
// Check that a state key is provided.
|
||||
if event.StateKey() == nil || event.StateKeyEquals("") {
|
||||
return util.JSONResponse{
|
||||
|
|
@ -216,6 +225,22 @@ func SendJoin(
|
|||
}
|
||||
}
|
||||
|
||||
// Check that the sender belongs to the server that is sending us
|
||||
// the request. By this point we've already asserted that the sender
|
||||
// and the state key are equal so we don't need to check both.
|
||||
var domain gomatrixserverlib.ServerName
|
||||
if _, domain, err = gomatrixserverlib.SplitID('@', event.Sender()); err != nil {
|
||||
return util.JSONResponse{
|
||||
Code: http.StatusForbidden,
|
||||
JSON: jsonerror.Forbidden("The sender of the join is invalid"),
|
||||
}
|
||||
} else if domain != request.Origin() {
|
||||
return util.JSONResponse{
|
||||
Code: http.StatusForbidden,
|
||||
JSON: jsonerror.Forbidden("The sender of the join must belong to the origin server"),
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the room ID is correct.
|
||||
if event.RoomID() != roomID {
|
||||
return util.JSONResponse{
|
||||
|
|
@ -242,14 +267,6 @@ func SendJoin(
|
|||
}
|
||||
}
|
||||
|
||||
// Check that the event is from the server sending the request.
|
||||
if event.Origin() != request.Origin() {
|
||||
return util.JSONResponse{
|
||||
Code: http.StatusForbidden,
|
||||
JSON: jsonerror.Forbidden("The join must be sent by the server it originated on"),
|
||||
}
|
||||
}
|
||||
|
||||
// Check that this is in fact a join event
|
||||
membership, err := event.Membership()
|
||||
if err != nil {
|
||||
|
|
@ -375,7 +392,7 @@ func SendJoin(
|
|||
// the room, so set SendAsServer to cfg.Matrix.ServerName
|
||||
if !alreadyJoined {
|
||||
var response api.InputRoomEventsResponse
|
||||
rsAPI.InputRoomEvents(httpReq.Context(), &api.InputRoomEventsRequest{
|
||||
if err := rsAPI.InputRoomEvents(httpReq.Context(), &api.InputRoomEventsRequest{
|
||||
InputRoomEvents: []api.InputRoomEvent{
|
||||
{
|
||||
Kind: api.KindNew,
|
||||
|
|
@ -384,7 +401,9 @@ func SendJoin(
|
|||
TransactionID: nil,
|
||||
},
|
||||
},
|
||||
}, &response)
|
||||
}, &response); err != nil {
|
||||
return jsonerror.InternalAPIError(httpReq.Context(), err)
|
||||
}
|
||||
if response.ErrMsg != "" {
|
||||
util.GetLogger(httpReq.Context()).WithField(logrus.ErrorKey, response.ErrMsg).Error("SendEvents failed")
|
||||
if response.NotAllowed {
|
||||
|
|
@ -419,13 +438,13 @@ func SendJoin(
|
|||
// a restricted room join. If the room version does not support restricted
|
||||
// joins then this function returns with no side effects. This returns three
|
||||
// values:
|
||||
// * an optional JSON response body (i.e. M_UNABLE_TO_AUTHORISE_JOIN) which
|
||||
// should always be sent back to the client if one is specified
|
||||
// * a user ID of an authorising user, typically a user that has power to
|
||||
// issue invites in the room, if one has been found
|
||||
// * an error if there was a problem finding out if this was allowable,
|
||||
// like if the room version isn't known or a problem happened talking to
|
||||
// the roomserver
|
||||
// - an optional JSON response body (i.e. M_UNABLE_TO_AUTHORISE_JOIN) which
|
||||
// should always be sent back to the client if one is specified
|
||||
// - a user ID of an authorising user, typically a user that has power to
|
||||
// issue invites in the room, if one has been found
|
||||
// - an error if there was a problem finding out if this was allowable,
|
||||
// like if the room version isn't known or a problem happened talking to
|
||||
// the roomserver
|
||||
func checkRestrictedJoin(
|
||||
httpReq *http.Request,
|
||||
rsAPI api.FederationRoomserverAPI,
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ import (
|
|||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/matrix-org/dendrite/clientapi/httputil"
|
||||
clienthttputil "github.com/matrix-org/dendrite/clientapi/httputil"
|
||||
"github.com/matrix-org/dendrite/clientapi/jsonerror"
|
||||
federationAPI "github.com/matrix-org/dendrite/federationapi/api"
|
||||
"github.com/matrix-org/dendrite/keyserver/api"
|
||||
|
|
@ -61,9 +61,11 @@ func QueryDeviceKeys(
|
|||
}
|
||||
|
||||
var queryRes api.QueryKeysResponse
|
||||
keyAPI.QueryKeys(httpReq.Context(), &api.QueryKeysRequest{
|
||||
if err := keyAPI.QueryKeys(httpReq.Context(), &api.QueryKeysRequest{
|
||||
UserToDevices: qkr.DeviceKeys,
|
||||
}, &queryRes)
|
||||
}, &queryRes); err != nil {
|
||||
return jsonerror.InternalAPIError(httpReq.Context(), err)
|
||||
}
|
||||
if queryRes.Error != nil {
|
||||
util.GetLogger(httpReq.Context()).WithError(queryRes.Error).Error("Failed to QueryKeys")
|
||||
return jsonerror.InternalServerError()
|
||||
|
|
@ -113,9 +115,11 @@ func ClaimOneTimeKeys(
|
|||
}
|
||||
|
||||
var claimRes api.PerformClaimKeysResponse
|
||||
keyAPI.PerformClaimKeys(httpReq.Context(), &api.PerformClaimKeysRequest{
|
||||
if err := keyAPI.PerformClaimKeys(httpReq.Context(), &api.PerformClaimKeysRequest{
|
||||
OneTimeKeys: cor.OneTimeKeys,
|
||||
}, &claimRes)
|
||||
}, &claimRes); err != nil {
|
||||
return jsonerror.InternalAPIError(httpReq.Context(), err)
|
||||
}
|
||||
if claimRes.Error != nil {
|
||||
util.GetLogger(httpReq.Context()).WithError(claimRes.Error).Error("Failed to PerformClaimKeys")
|
||||
return jsonerror.InternalServerError()
|
||||
|
|
@ -184,7 +188,7 @@ func NotaryKeys(
|
|||
) util.JSONResponse {
|
||||
if req == nil {
|
||||
req = &gomatrixserverlib.PublicKeyNotaryLookupRequest{}
|
||||
if reqErr := httputil.UnmarshalJSONRequest(httpReq, &req); reqErr != nil {
|
||||
if reqErr := clienthttputil.UnmarshalJSONRequest(httpReq, &req); reqErr != nil {
|
||||
return *reqErr
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -277,7 +277,7 @@ func SendLeave(
|
|||
// We are responsible for notifying other servers that the user has left
|
||||
// the room, so set SendAsServer to cfg.Matrix.ServerName
|
||||
var response api.InputRoomEventsResponse
|
||||
rsAPI.InputRoomEvents(httpReq.Context(), &api.InputRoomEventsRequest{
|
||||
if err := rsAPI.InputRoomEvents(httpReq.Context(), &api.InputRoomEventsRequest{
|
||||
InputRoomEvents: []api.InputRoomEvent{
|
||||
{
|
||||
Kind: api.KindNew,
|
||||
|
|
@ -286,7 +286,9 @@ func SendLeave(
|
|||
TransactionID: nil,
|
||||
},
|
||||
},
|
||||
}, &response)
|
||||
}, &response); err != nil {
|
||||
return jsonerror.InternalAPIError(httpReq.Context(), err)
|
||||
}
|
||||
|
||||
if response.ErrMsg != "" {
|
||||
util.GetLogger(httpReq.Context()).WithField(logrus.ErrorKey, response.ErrMsg).WithField("not_allowed", response.NotAllowed).Error("producer.SendEvents failed")
|
||||
|
|
|
|||
|
|
@ -458,7 +458,9 @@ func (t *txnReq) processSigningKeyUpdate(ctx context.Context, e gomatrixserverli
|
|||
UserID: updatePayload.UserID,
|
||||
}
|
||||
uploadRes := &keyapi.PerformUploadDeviceKeysResponse{}
|
||||
t.keyAPI.PerformUploadDeviceKeys(ctx, uploadReq, uploadRes)
|
||||
if err := t.keyAPI.PerformUploadDeviceKeys(ctx, uploadReq, uploadRes); err != nil {
|
||||
return err
|
||||
}
|
||||
if uploadRes.Error != nil {
|
||||
return uploadRes.Error
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,11 +64,12 @@ func (t *testRoomserverAPI) InputRoomEvents(
|
|||
ctx context.Context,
|
||||
request *api.InputRoomEventsRequest,
|
||||
response *api.InputRoomEventsResponse,
|
||||
) {
|
||||
) error {
|
||||
t.inputRoomEvents = append(t.inputRoomEvents, request.InputRoomEvents...)
|
||||
for _, ire := range request.InputRoomEvents {
|
||||
fmt.Println("InputRoomEvents: ", ire.Event.EventID())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Query the latest events and state for a room from the room server.
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ package storage
|
|||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/matrix-org/dendrite/federationapi/storage/shared"
|
||||
"github.com/matrix-org/dendrite/federationapi/types"
|
||||
|
|
@ -38,7 +39,7 @@ type Database interface {
|
|||
GetPendingEDUs(ctx context.Context, serverName gomatrixserverlib.ServerName, limit int) (edus map[*shared.Receipt]*gomatrixserverlib.EDU, err error)
|
||||
|
||||
AssociatePDUWithDestination(ctx context.Context, transactionID gomatrixserverlib.TransactionID, serverName gomatrixserverlib.ServerName, receipt *shared.Receipt) error
|
||||
AssociateEDUWithDestination(ctx context.Context, serverName gomatrixserverlib.ServerName, receipt *shared.Receipt, eduType string) error
|
||||
AssociateEDUWithDestination(ctx context.Context, serverName gomatrixserverlib.ServerName, receipt *shared.Receipt, eduType string, expireEDUTypes map[string]time.Duration) error
|
||||
|
||||
CleanPDUs(ctx context.Context, serverName gomatrixserverlib.ServerName, receipts []*shared.Receipt) error
|
||||
CleanEDUs(ctx context.Context, serverName gomatrixserverlib.ServerName, receipts []*shared.Receipt) error
|
||||
|
|
@ -70,4 +71,6 @@ type Database interface {
|
|||
// Query the notary for the server keys for the given server. If `optKeyIDs` is not empty, multiple server keys may be returned (between 1 - len(optKeyIDs))
|
||||
// such that the combination of all server keys will include all the `optKeyIDs`.
|
||||
GetNotaryKeys(ctx context.Context, serverName gomatrixserverlib.ServerName, optKeyIDs []gomatrixserverlib.KeyID) ([]gomatrixserverlib.ServerKeys, error)
|
||||
// DeleteExpiredEDUs cleans up expired EDUs
|
||||
DeleteExpiredEDUs(ctx context.Context) error
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
// Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package deltas
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/matrix-org/gomatrixserverlib"
|
||||
)
|
||||
|
||||
func UpAddexpiresat(ctx context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.ExecContext(ctx, "ALTER TABLE federationsender_queue_edus ADD COLUMN IF NOT EXISTS expires_at BIGINT NOT NULL DEFAULT 0;")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to execute upgrade: %w", err)
|
||||
}
|
||||
_, err = tx.ExecContext(ctx, "UPDATE federationsender_queue_edus SET expires_at = $1 WHERE edu_type != 'm.direct_to_device'", gomatrixserverlib.AsTimestamp(time.Now().Add(time.Hour*24)))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to update queue_edus: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DownAddexpiresat(ctx context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.ExecContext(ctx, "ALTER TABLE federationsender_queue_edus DROP COLUMN expires_at;")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to execute downgrade: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -19,9 +19,11 @@ import (
|
|||
"database/sql"
|
||||
|
||||
"github.com/lib/pq"
|
||||
"github.com/matrix-org/gomatrixserverlib"
|
||||
|
||||
"github.com/matrix-org/dendrite/federationapi/storage/postgres/deltas"
|
||||
"github.com/matrix-org/dendrite/internal"
|
||||
"github.com/matrix-org/dendrite/internal/sqlutil"
|
||||
"github.com/matrix-org/gomatrixserverlib"
|
||||
)
|
||||
|
||||
const queueEDUsSchema = `
|
||||
|
|
@ -31,7 +33,9 @@ CREATE TABLE IF NOT EXISTS federationsender_queue_edus (
|
|||
-- The domain part of the user ID the EDU event is for.
|
||||
server_name TEXT NOT NULL,
|
||||
-- The JSON NID from the federationsender_queue_edus_json table.
|
||||
json_nid BIGINT NOT NULL
|
||||
json_nid BIGINT NOT NULL,
|
||||
-- The expiry time of this edu, if any.
|
||||
expires_at BIGINT NOT NULL DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS federationsender_queue_edus_json_nid_idx
|
||||
|
|
@ -43,8 +47,8 @@ CREATE INDEX IF NOT EXISTS federationsender_queue_edus_server_name_idx
|
|||
`
|
||||
|
||||
const insertQueueEDUSQL = "" +
|
||||
"INSERT INTO federationsender_queue_edus (edu_type, server_name, json_nid)" +
|
||||
" VALUES ($1, $2, $3)"
|
||||
"INSERT INTO federationsender_queue_edus (edu_type, server_name, json_nid, expires_at)" +
|
||||
" VALUES ($1, $2, $3, $4)"
|
||||
|
||||
const deleteQueueEDUSQL = "" +
|
||||
"DELETE FROM federationsender_queue_edus WHERE server_name = $1 AND json_nid = ANY($2)"
|
||||
|
|
@ -65,6 +69,12 @@ const selectQueueEDUCountSQL = "" +
|
|||
const selectQueueServerNamesSQL = "" +
|
||||
"SELECT DISTINCT server_name FROM federationsender_queue_edus"
|
||||
|
||||
const selectExpiredEDUsSQL = "" +
|
||||
"SELECT DISTINCT json_nid FROM federationsender_queue_edus WHERE expires_at > 0 AND expires_at <= $1"
|
||||
|
||||
const deleteExpiredEDUsSQL = "" +
|
||||
"DELETE FROM federationsender_queue_edus WHERE expires_at > 0 AND expires_at <= $1"
|
||||
|
||||
type queueEDUsStatements struct {
|
||||
db *sql.DB
|
||||
insertQueueEDUStmt *sql.Stmt
|
||||
|
|
@ -73,6 +83,8 @@ type queueEDUsStatements struct {
|
|||
selectQueueEDUReferenceJSONCountStmt *sql.Stmt
|
||||
selectQueueEDUCountStmt *sql.Stmt
|
||||
selectQueueEDUServerNamesStmt *sql.Stmt
|
||||
selectExpiredEDUsStmt *sql.Stmt
|
||||
deleteExpiredEDUsStmt *sql.Stmt
|
||||
}
|
||||
|
||||
func NewPostgresQueueEDUsTable(db *sql.DB) (s *queueEDUsStatements, err error) {
|
||||
|
|
@ -81,27 +93,34 @@ func NewPostgresQueueEDUsTable(db *sql.DB) (s *queueEDUsStatements, err error) {
|
|||
}
|
||||
_, err = s.db.Exec(queueEDUsSchema)
|
||||
if err != nil {
|
||||
return
|
||||
return s, err
|
||||
}
|
||||
if s.insertQueueEDUStmt, err = s.db.Prepare(insertQueueEDUSQL); err != nil {
|
||||
return
|
||||
|
||||
m := sqlutil.NewMigrator(db)
|
||||
m.AddMigrations(
|
||||
sqlutil.Migration{
|
||||
Version: "federationapi: add expiresat column",
|
||||
Up: deltas.UpAddexpiresat,
|
||||
},
|
||||
)
|
||||
if err := m.Up(context.Background()); err != nil {
|
||||
return s, err
|
||||
}
|
||||
if s.deleteQueueEDUStmt, err = s.db.Prepare(deleteQueueEDUSQL); err != nil {
|
||||
return
|
||||
}
|
||||
if s.selectQueueEDUStmt, err = s.db.Prepare(selectQueueEDUSQL); err != nil {
|
||||
return
|
||||
}
|
||||
if s.selectQueueEDUReferenceJSONCountStmt, err = s.db.Prepare(selectQueueEDUReferenceJSONCountSQL); err != nil {
|
||||
return
|
||||
}
|
||||
if s.selectQueueEDUCountStmt, err = s.db.Prepare(selectQueueEDUCountSQL); err != nil {
|
||||
return
|
||||
}
|
||||
if s.selectQueueEDUServerNamesStmt, err = s.db.Prepare(selectQueueServerNamesSQL); err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (s *queueEDUsStatements) Prepare() error {
|
||||
return sqlutil.StatementList{
|
||||
{&s.insertQueueEDUStmt, insertQueueEDUSQL},
|
||||
{&s.deleteQueueEDUStmt, deleteQueueEDUSQL},
|
||||
{&s.selectQueueEDUStmt, selectQueueEDUSQL},
|
||||
{&s.selectQueueEDUReferenceJSONCountStmt, selectQueueEDUReferenceJSONCountSQL},
|
||||
{&s.selectQueueEDUCountStmt, selectQueueEDUCountSQL},
|
||||
{&s.selectQueueEDUServerNamesStmt, selectQueueServerNamesSQL},
|
||||
{&s.selectExpiredEDUsStmt, selectExpiredEDUsSQL},
|
||||
{&s.deleteExpiredEDUsStmt, deleteExpiredEDUsSQL},
|
||||
}.Prepare(s.db)
|
||||
}
|
||||
|
||||
func (s *queueEDUsStatements) InsertQueueEDU(
|
||||
|
|
@ -110,6 +129,7 @@ func (s *queueEDUsStatements) InsertQueueEDU(
|
|||
eduType string,
|
||||
serverName gomatrixserverlib.ServerName,
|
||||
nid int64,
|
||||
expiresAt gomatrixserverlib.Timestamp,
|
||||
) error {
|
||||
stmt := sqlutil.TxStmt(txn, s.insertQueueEDUStmt)
|
||||
_, err := stmt.ExecContext(
|
||||
|
|
@ -117,6 +137,7 @@ func (s *queueEDUsStatements) InsertQueueEDU(
|
|||
eduType, // the EDU type
|
||||
serverName, // destination server name
|
||||
nid, // JSON blob NID
|
||||
expiresAt, // timestamp of expiry
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
|
@ -150,7 +171,7 @@ func (s *queueEDUsStatements) SelectQueueEDUs(
|
|||
}
|
||||
result = append(result, nid)
|
||||
}
|
||||
return result, nil
|
||||
return result, rows.Err()
|
||||
}
|
||||
|
||||
func (s *queueEDUsStatements) SelectQueueEDUReferenceJSONCount(
|
||||
|
|
@ -200,3 +221,33 @@ func (s *queueEDUsStatements) SelectQueueEDUServerNames(
|
|||
|
||||
return result, rows.Err()
|
||||
}
|
||||
|
||||
func (s *queueEDUsStatements) SelectExpiredEDUs(
|
||||
ctx context.Context, txn *sql.Tx,
|
||||
expiredBefore gomatrixserverlib.Timestamp,
|
||||
) ([]int64, error) {
|
||||
stmt := sqlutil.TxStmt(txn, s.selectExpiredEDUsStmt)
|
||||
rows, err := stmt.QueryContext(ctx, expiredBefore)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer internal.CloseAndLogIfError(ctx, rows, "SelectExpiredEDUs: rows.close() failed")
|
||||
var result []int64
|
||||
var nid int64
|
||||
for rows.Next() {
|
||||
if err = rows.Scan(&nid); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, nid)
|
||||
}
|
||||
return result, rows.Err()
|
||||
}
|
||||
|
||||
func (s *queueEDUsStatements) DeleteExpiredEDUs(
|
||||
ctx context.Context, txn *sql.Tx,
|
||||
expiredBefore gomatrixserverlib.Timestamp,
|
||||
) error {
|
||||
stmt := sqlutil.TxStmt(txn, s.deleteExpiredEDUsStmt)
|
||||
_, err := stmt.ExecContext(ctx, expiredBefore)
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -91,6 +91,9 @@ func NewDatabase(base *base.BaseDendrite, dbProperties *config.DatabaseOptions,
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = queueEDUs.Prepare(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
d.Database = shared.Database{
|
||||
DB: d.db,
|
||||
ServerName: serverName,
|
||||
|
|
|
|||
|
|
@ -20,10 +20,21 @@ import (
|
|||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/matrix-org/gomatrixserverlib"
|
||||
)
|
||||
|
||||
// defaultExpiry for EDUs if not listed below
|
||||
var defaultExpiry = time.Hour * 24
|
||||
|
||||
// defaultExpireEDUTypes contains EDUs which can/should be expired after a given time
|
||||
// if the target server isn't reachable for some reason.
|
||||
var defaultExpireEDUTypes = map[string]time.Duration{
|
||||
gomatrixserverlib.MTyping: time.Minute,
|
||||
gomatrixserverlib.MPresence: time.Minute * 10,
|
||||
}
|
||||
|
||||
// AssociateEDUWithDestination creates an association that the
|
||||
// destination queues will use to determine which JSON blobs to send
|
||||
// to which servers.
|
||||
|
|
@ -32,7 +43,21 @@ func (d *Database) AssociateEDUWithDestination(
|
|||
serverName gomatrixserverlib.ServerName,
|
||||
receipt *Receipt,
|
||||
eduType string,
|
||||
expireEDUTypes map[string]time.Duration,
|
||||
) error {
|
||||
if expireEDUTypes == nil {
|
||||
expireEDUTypes = defaultExpireEDUTypes
|
||||
}
|
||||
expiresAt := gomatrixserverlib.AsTimestamp(time.Now().Add(defaultExpiry))
|
||||
if duration, ok := expireEDUTypes[eduType]; ok {
|
||||
// Keep EDUs for at least x minutes before deleting them
|
||||
expiresAt = gomatrixserverlib.AsTimestamp(time.Now().Add(duration))
|
||||
}
|
||||
// We forcibly set m.direct_to_device events to 0, as we always want them
|
||||
// to be delivered. (required for E2EE)
|
||||
if eduType == gomatrixserverlib.MDirectToDevice {
|
||||
expiresAt = 0
|
||||
}
|
||||
return d.Writer.Do(d.DB, nil, func(txn *sql.Tx) error {
|
||||
if err := d.FederationQueueEDUs.InsertQueueEDU(
|
||||
ctx, // context
|
||||
|
|
@ -40,6 +65,7 @@ func (d *Database) AssociateEDUWithDestination(
|
|||
eduType, // EDU type for coalescing
|
||||
serverName, // destination server name
|
||||
receipt.nid, // NID from the federationapi_queue_json table
|
||||
expiresAt, // The timestamp this EDU will expire
|
||||
); err != nil {
|
||||
return fmt.Errorf("InsertQueueEDU: %w", err)
|
||||
}
|
||||
|
|
@ -150,3 +176,26 @@ func (d *Database) GetPendingEDUServerNames(
|
|||
) ([]gomatrixserverlib.ServerName, error) {
|
||||
return d.FederationQueueEDUs.SelectQueueEDUServerNames(ctx, nil)
|
||||
}
|
||||
|
||||
// DeleteExpiredEDUs deletes expired EDUs
|
||||
func (d *Database) DeleteExpiredEDUs(ctx context.Context) error {
|
||||
return d.Writer.Do(d.DB, nil, func(txn *sql.Tx) error {
|
||||
expiredBefore := gomatrixserverlib.AsTimestamp(time.Now())
|
||||
jsonNIDs, err := d.FederationQueueEDUs.SelectExpiredEDUs(ctx, txn, expiredBefore)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(jsonNIDs) == 0 {
|
||||
return nil
|
||||
}
|
||||
for i := range jsonNIDs {
|
||||
d.Cache.EvictFederationQueuedEDU(jsonNIDs[i])
|
||||
}
|
||||
|
||||
if err = d.FederationQueueJSON.DeleteQueueJSON(ctx, txn, jsonNIDs); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return d.FederationQueueEDUs.DeleteExpiredEDUs(ctx, txn, expiredBefore)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,68 @@
|
|||
// Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package deltas
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/matrix-org/gomatrixserverlib"
|
||||
)
|
||||
|
||||
func UpAddexpiresat(ctx context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.ExecContext(ctx, "ALTER TABLE federationsender_queue_edus RENAME TO federationsender_queue_edus_old;")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to rename table: %w", err)
|
||||
}
|
||||
|
||||
_, err = tx.ExecContext(ctx, `
|
||||
CREATE TABLE IF NOT EXISTS federationsender_queue_edus (
|
||||
edu_type TEXT NOT NULL,
|
||||
server_name TEXT NOT NULL,
|
||||
json_nid BIGINT NOT NULL,
|
||||
expires_at BIGINT NOT NULL DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS federationsender_queue_edus_json_nid_idx
|
||||
ON federationsender_queue_edus (json_nid, server_name);
|
||||
`)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create new table: %w", err)
|
||||
}
|
||||
_, err = tx.ExecContext(ctx, `
|
||||
INSERT
|
||||
INTO federationsender_queue_edus (
|
||||
edu_type, server_name, json_nid, expires_at
|
||||
) SELECT edu_type, server_name, json_nid, 0 FROM federationsender_queue_edus_old;
|
||||
`)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to update queue_edus: %w", err)
|
||||
}
|
||||
_, err = tx.ExecContext(ctx, "UPDATE federationsender_queue_edus SET expires_at = $1 WHERE edu_type != 'm.direct_to_device'", gomatrixserverlib.AsTimestamp(time.Now().Add(time.Hour*24)))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to update queue_edus: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DownAddexpiresat(ctx context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.ExecContext(ctx, "ALTER TABLE federationsender_queue_edus DROP COLUMN expires_at;")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to rename table: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -20,9 +20,11 @@ import (
|
|||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/matrix-org/gomatrixserverlib"
|
||||
|
||||
"github.com/matrix-org/dendrite/federationapi/storage/sqlite3/deltas"
|
||||
"github.com/matrix-org/dendrite/internal"
|
||||
"github.com/matrix-org/dendrite/internal/sqlutil"
|
||||
"github.com/matrix-org/gomatrixserverlib"
|
||||
)
|
||||
|
||||
const queueEDUsSchema = `
|
||||
|
|
@ -32,7 +34,9 @@ CREATE TABLE IF NOT EXISTS federationsender_queue_edus (
|
|||
-- The domain part of the user ID the EDU event is for.
|
||||
server_name TEXT NOT NULL,
|
||||
-- The JSON NID from the federationsender_queue_edus_json table.
|
||||
json_nid BIGINT NOT NULL
|
||||
json_nid BIGINT NOT NULL,
|
||||
-- The expiry time of this edu, if any.
|
||||
expires_at BIGINT NOT NULL DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS federationsender_queue_edus_json_nid_idx
|
||||
|
|
@ -44,8 +48,8 @@ CREATE INDEX IF NOT EXISTS federationsender_queue_edus_server_name_idx
|
|||
`
|
||||
|
||||
const insertQueueEDUSQL = "" +
|
||||
"INSERT INTO federationsender_queue_edus (edu_type, server_name, json_nid)" +
|
||||
" VALUES ($1, $2, $3)"
|
||||
"INSERT INTO federationsender_queue_edus (edu_type, server_name, json_nid, expires_at)" +
|
||||
" VALUES ($1, $2, $3, $4)"
|
||||
|
||||
const deleteQueueEDUsSQL = "" +
|
||||
"DELETE FROM federationsender_queue_edus WHERE server_name = $1 AND json_nid IN ($2)"
|
||||
|
|
@ -66,13 +70,22 @@ const selectQueueEDUCountSQL = "" +
|
|||
const selectQueueServerNamesSQL = "" +
|
||||
"SELECT DISTINCT server_name FROM federationsender_queue_edus"
|
||||
|
||||
const selectExpiredEDUsSQL = "" +
|
||||
"SELECT DISTINCT json_nid FROM federationsender_queue_edus WHERE expires_at > 0 AND expires_at <= $1"
|
||||
|
||||
const deleteExpiredEDUsSQL = "" +
|
||||
"DELETE FROM federationsender_queue_edus WHERE expires_at > 0 AND expires_at <= $1"
|
||||
|
||||
type queueEDUsStatements struct {
|
||||
db *sql.DB
|
||||
insertQueueEDUStmt *sql.Stmt
|
||||
db *sql.DB
|
||||
insertQueueEDUStmt *sql.Stmt
|
||||
// deleteQueueEDUStmt *sql.Stmt - prepared at runtime due to variadic
|
||||
selectQueueEDUStmt *sql.Stmt
|
||||
selectQueueEDUReferenceJSONCountStmt *sql.Stmt
|
||||
selectQueueEDUCountStmt *sql.Stmt
|
||||
selectQueueEDUServerNamesStmt *sql.Stmt
|
||||
selectExpiredEDUsStmt *sql.Stmt
|
||||
deleteExpiredEDUsStmt *sql.Stmt
|
||||
}
|
||||
|
||||
func NewSQLiteQueueEDUsTable(db *sql.DB) (s *queueEDUsStatements, err error) {
|
||||
|
|
@ -81,24 +94,33 @@ func NewSQLiteQueueEDUsTable(db *sql.DB) (s *queueEDUsStatements, err error) {
|
|||
}
|
||||
_, err = db.Exec(queueEDUsSchema)
|
||||
if err != nil {
|
||||
return
|
||||
return s, err
|
||||
}
|
||||
if s.insertQueueEDUStmt, err = db.Prepare(insertQueueEDUSQL); err != nil {
|
||||
return
|
||||
|
||||
m := sqlutil.NewMigrator(db)
|
||||
m.AddMigrations(
|
||||
sqlutil.Migration{
|
||||
Version: "federationapi: add expiresat column",
|
||||
Up: deltas.UpAddexpiresat,
|
||||
},
|
||||
)
|
||||
if err := m.Up(context.Background()); err != nil {
|
||||
return s, err
|
||||
}
|
||||
if s.selectQueueEDUStmt, err = db.Prepare(selectQueueEDUSQL); err != nil {
|
||||
return
|
||||
}
|
||||
if s.selectQueueEDUReferenceJSONCountStmt, err = db.Prepare(selectQueueEDUReferenceJSONCountSQL); err != nil {
|
||||
return
|
||||
}
|
||||
if s.selectQueueEDUCountStmt, err = db.Prepare(selectQueueEDUCountSQL); err != nil {
|
||||
return
|
||||
}
|
||||
if s.selectQueueEDUServerNamesStmt, err = db.Prepare(selectQueueServerNamesSQL); err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (s *queueEDUsStatements) Prepare() error {
|
||||
return sqlutil.StatementList{
|
||||
{&s.insertQueueEDUStmt, insertQueueEDUSQL},
|
||||
{&s.selectQueueEDUStmt, selectQueueEDUSQL},
|
||||
{&s.selectQueueEDUReferenceJSONCountStmt, selectQueueEDUReferenceJSONCountSQL},
|
||||
{&s.selectQueueEDUCountStmt, selectQueueEDUCountSQL},
|
||||
{&s.selectQueueEDUServerNamesStmt, selectQueueServerNamesSQL},
|
||||
{&s.selectExpiredEDUsStmt, selectExpiredEDUsSQL},
|
||||
{&s.deleteExpiredEDUsStmt, deleteExpiredEDUsSQL},
|
||||
}.Prepare(s.db)
|
||||
}
|
||||
|
||||
func (s *queueEDUsStatements) InsertQueueEDU(
|
||||
|
|
@ -107,6 +129,7 @@ func (s *queueEDUsStatements) InsertQueueEDU(
|
|||
eduType string,
|
||||
serverName gomatrixserverlib.ServerName,
|
||||
nid int64,
|
||||
expiresAt gomatrixserverlib.Timestamp,
|
||||
) error {
|
||||
stmt := sqlutil.TxStmt(txn, s.insertQueueEDUStmt)
|
||||
_, err := stmt.ExecContext(
|
||||
|
|
@ -114,6 +137,7 @@ func (s *queueEDUsStatements) InsertQueueEDU(
|
|||
eduType, // the EDU type
|
||||
serverName, // destination server name
|
||||
nid, // JSON blob NID
|
||||
expiresAt, // timestamp of expiry
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
|
@ -159,7 +183,7 @@ func (s *queueEDUsStatements) SelectQueueEDUs(
|
|||
}
|
||||
result = append(result, nid)
|
||||
}
|
||||
return result, nil
|
||||
return result, rows.Err()
|
||||
}
|
||||
|
||||
func (s *queueEDUsStatements) SelectQueueEDUReferenceJSONCount(
|
||||
|
|
@ -209,3 +233,33 @@ func (s *queueEDUsStatements) SelectQueueEDUServerNames(
|
|||
|
||||
return result, rows.Err()
|
||||
}
|
||||
|
||||
func (s *queueEDUsStatements) SelectExpiredEDUs(
|
||||
ctx context.Context, txn *sql.Tx,
|
||||
expiredBefore gomatrixserverlib.Timestamp,
|
||||
) ([]int64, error) {
|
||||
stmt := sqlutil.TxStmt(txn, s.selectExpiredEDUsStmt)
|
||||
rows, err := stmt.QueryContext(ctx, expiredBefore)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer internal.CloseAndLogIfError(ctx, rows, "SelectExpiredEDUs: rows.close() failed")
|
||||
var result []int64
|
||||
var nid int64
|
||||
for rows.Next() {
|
||||
if err = rows.Scan(&nid); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, nid)
|
||||
}
|
||||
return result, rows.Err()
|
||||
}
|
||||
|
||||
func (s *queueEDUsStatements) DeleteExpiredEDUs(
|
||||
ctx context.Context, txn *sql.Tx,
|
||||
expiredBefore gomatrixserverlib.Timestamp,
|
||||
) error {
|
||||
stmt := sqlutil.TxStmt(txn, s.deleteExpiredEDUsStmt)
|
||||
_, err := stmt.ExecContext(ctx, expiredBefore)
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -90,6 +90,9 @@ func NewDatabase(base *base.BaseDendrite, dbProperties *config.DatabaseOptions,
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = queueEDUs.Prepare(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
d.Database = shared.Database{
|
||||
DB: d.db,
|
||||
ServerName: serverName,
|
||||
|
|
|
|||
81
federationapi/storage/storage_test.go
Normal file
81
federationapi/storage/storage_test.go
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
package storage_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/matrix-org/gomatrixserverlib"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/matrix-org/dendrite/federationapi/storage"
|
||||
"github.com/matrix-org/dendrite/setup/config"
|
||||
"github.com/matrix-org/dendrite/test"
|
||||
"github.com/matrix-org/dendrite/test/testrig"
|
||||
)
|
||||
|
||||
func mustCreateFederationDatabase(t *testing.T, dbType test.DBType) (storage.Database, func()) {
|
||||
b, baseClose := testrig.CreateBaseDendrite(t, dbType)
|
||||
connStr, dbClose := test.PrepareDBConnectionString(t, dbType)
|
||||
db, err := storage.NewDatabase(b, &config.DatabaseOptions{
|
||||
ConnectionString: config.DataSource(connStr),
|
||||
}, b.Caches, b.Cfg.Global.ServerName)
|
||||
if err != nil {
|
||||
t.Fatalf("NewDatabase returned %s", err)
|
||||
}
|
||||
return db, func() {
|
||||
dbClose()
|
||||
baseClose()
|
||||
}
|
||||
}
|
||||
|
||||
func TestExpireEDUs(t *testing.T) {
|
||||
var expireEDUTypes = map[string]time.Duration{
|
||||
gomatrixserverlib.MReceipt: time.Millisecond,
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
|
||||
db, close := mustCreateFederationDatabase(t, dbType)
|
||||
defer close()
|
||||
// insert some data
|
||||
for i := 0; i < 100; i++ {
|
||||
receipt, err := db.StoreJSON(ctx, "{}")
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = db.AssociateEDUWithDestination(ctx, "localhost", receipt, gomatrixserverlib.MReceipt, expireEDUTypes)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
// add data without expiry
|
||||
receipt, err := db.StoreJSON(ctx, "{}")
|
||||
assert.NoError(t, err)
|
||||
|
||||
// m.read_marker gets the default expiry of 24h, so won't be deleted further down in this test
|
||||
err = db.AssociateEDUWithDestination(ctx, "localhost", receipt, "m.read_marker", expireEDUTypes)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Delete expired EDUs
|
||||
err = db.DeleteExpiredEDUs(ctx)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// verify the data is gone
|
||||
data, err := db.GetPendingEDUs(ctx, "localhost", 100)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 1, len(data))
|
||||
|
||||
// check that m.direct_to_device is never expired
|
||||
receipt, err = db.StoreJSON(ctx, "{}")
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = db.AssociateEDUWithDestination(ctx, "localhost", receipt, gomatrixserverlib.MDirectToDevice, expireEDUTypes)
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = db.DeleteExpiredEDUs(ctx)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// We should get two EDUs, the m.read_marker and the m.direct_to_device
|
||||
data, err = db.GetPendingEDUs(ctx, "localhost", 100)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 2, len(data))
|
||||
})
|
||||
}
|
||||
|
|
@ -34,12 +34,15 @@ type FederationQueuePDUs interface {
|
|||
}
|
||||
|
||||
type FederationQueueEDUs interface {
|
||||
InsertQueueEDU(ctx context.Context, txn *sql.Tx, eduType string, serverName gomatrixserverlib.ServerName, nid int64) error
|
||||
InsertQueueEDU(ctx context.Context, txn *sql.Tx, eduType string, serverName gomatrixserverlib.ServerName, nid int64, expiresAt gomatrixserverlib.Timestamp) error
|
||||
DeleteQueueEDUs(ctx context.Context, txn *sql.Tx, serverName gomatrixserverlib.ServerName, jsonNIDs []int64) error
|
||||
SelectQueueEDUs(ctx context.Context, txn *sql.Tx, serverName gomatrixserverlib.ServerName, limit int) ([]int64, error)
|
||||
SelectQueueEDUReferenceJSONCount(ctx context.Context, txn *sql.Tx, jsonNID int64) (int64, error)
|
||||
SelectQueueEDUCount(ctx context.Context, txn *sql.Tx, serverName gomatrixserverlib.ServerName) (int64, error)
|
||||
SelectQueueEDUServerNames(ctx context.Context, txn *sql.Tx) ([]gomatrixserverlib.ServerName, error)
|
||||
SelectExpiredEDUs(ctx context.Context, txn *sql.Tx, expiredBefore gomatrixserverlib.Timestamp) ([]int64, error)
|
||||
DeleteExpiredEDUs(ctx context.Context, txn *sql.Tx, expiredBefore gomatrixserverlib.Timestamp) error
|
||||
Prepare() error
|
||||
}
|
||||
|
||||
type FederationQueueJSON interface {
|
||||
|
|
|
|||
19
go.mod
19
go.mod
|
|
@ -21,8 +21,8 @@ require (
|
|||
github.com/matrix-org/dugong v0.0.0-20210921133753-66e6b1c67e2e
|
||||
github.com/matrix-org/go-sqlite3-js v0.0.0-20220419092513-28aa791a1c91
|
||||
github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16
|
||||
github.com/matrix-org/gomatrixserverlib v0.0.0-20220725104114-b6003e522771
|
||||
github.com/matrix-org/pinecone v0.0.0-20220708135211-1ce778fcde6a
|
||||
github.com/matrix-org/gomatrixserverlib v0.0.0-20220801083850-5ff38e2c2839
|
||||
github.com/matrix-org/pinecone v0.0.0-20220803093810-b7a830c08fb9
|
||||
github.com/matrix-org/util v0.0.0-20200807132607-55161520e1d4
|
||||
github.com/mattn/go-sqlite3 v1.14.13
|
||||
github.com/nats-io/nats-server/v2 v2.8.5-0.20220731184415-903a06a5b4ee
|
||||
|
|
@ -34,7 +34,7 @@ require (
|
|||
github.com/patrickmn/go-cache v2.1.0+incompatible
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/prometheus/client_golang v1.12.2
|
||||
github.com/sirupsen/logrus v1.8.1
|
||||
github.com/sirupsen/logrus v1.9.0
|
||||
github.com/stretchr/testify v1.7.1
|
||||
github.com/tidwall/gjson v1.14.1
|
||||
github.com/tidwall/sjson v1.2.4
|
||||
|
|
@ -42,10 +42,10 @@ require (
|
|||
github.com/uber/jaeger-lib v2.4.1+incompatible
|
||||
github.com/yggdrasil-network/yggdrasil-go v0.4.3
|
||||
go.uber.org/atomic v1.9.0
|
||||
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e
|
||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa
|
||||
golang.org/x/image v0.0.0-20220413100746-70e8d0d3baa9
|
||||
golang.org/x/mobile v0.0.0-20220518205345-8578da9835fd
|
||||
golang.org/x/net v0.0.0-20220524220425-1d687d428aca
|
||||
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e
|
||||
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467
|
||||
gopkg.in/h2non/bimg.v1 v1.1.9
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
|
|
@ -73,10 +73,11 @@ require (
|
|||
github.com/juju/errors v0.0.0-20220203013757-bd733f3c86b9 // indirect
|
||||
github.com/juju/testing v0.0.0-20220203020004-a0ff61f03494 // indirect
|
||||
github.com/klauspost/compress v1.15.9 // indirect
|
||||
github.com/lucas-clemente/quic-go v0.26.0 // indirect
|
||||
github.com/lucas-clemente/quic-go v0.28.1 // indirect
|
||||
github.com/marten-seemann/qtls-go1-16 v0.1.5 // indirect
|
||||
github.com/marten-seemann/qtls-go1-17 v0.1.1 // indirect
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.1 // indirect
|
||||
github.com/marten-seemann/qtls-go1-17 v0.1.2 // indirect
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.2 // indirect
|
||||
github.com/marten-seemann/qtls-go1-19 v0.1.0-beta.1 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
|
||||
github.com/miekg/dns v1.1.49 // indirect
|
||||
github.com/minio/highwayhash v1.0.2 // indirect
|
||||
|
|
@ -98,7 +99,7 @@ require (
|
|||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/tidwall/pretty v1.2.0 // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect
|
||||
golang.org/x/sys v0.0.0-20220731174439-a90be440212d // indirect
|
||||
golang.org/x/text v0.3.8-0.20211004125949-5bd84dd9b33b // indirect
|
||||
golang.org/x/time v0.0.0-20220411224347-583f2d630306 // indirect
|
||||
golang.org/x/tools v0.1.10 // indirect
|
||||
|
|
|
|||
41
go.sum
41
go.sum
|
|
@ -321,8 +321,8 @@ github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
|
|||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||
github.com/lib/pq v1.10.5 h1:J+gdV2cUmX7ZqL2B0lFcW0m+egaHC2V3lpO8nWxyYiQ=
|
||||
github.com/lib/pq v1.10.5/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/lucas-clemente/quic-go v0.26.0 h1:ALBQXr9UJ8A1LyzvceX4jd9QFsHvlI0RR6BkV16o00A=
|
||||
github.com/lucas-clemente/quic-go v0.26.0/go.mod h1:AzgQoPda7N+3IqMMMkywBKggIFo2KT6pfnlrQ2QieeI=
|
||||
github.com/lucas-clemente/quic-go v0.28.1 h1:Uo0lvVxWg5la9gflIF9lwa39ONq85Xq2D91YNEIslzU=
|
||||
github.com/lucas-clemente/quic-go v0.28.1/go.mod h1:oGz5DKK41cJt5+773+BSO9BXDsREY4HLf7+0odGAPO0=
|
||||
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
|
||||
github.com/lxn/walk v0.0.0-20210112085537-c389da54e794/go.mod h1:E23UucZGqpuUANJooIbHWCufXvOcT6E7Stq81gU+CSQ=
|
||||
github.com/lxn/win v0.0.0-20210218163916-a377121e959e/go.mod h1:KxxjdtRkfNoYDCUP5ryK7XJJNTnpC8atvtmTheChOtk=
|
||||
|
|
@ -330,10 +330,12 @@ github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN
|
|||
github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc=
|
||||
github.com/marten-seemann/qtls-go1-16 v0.1.5 h1:o9JrYPPco/Nukd/HpOHMHZoBDXQqoNtUCmny98/1uqQ=
|
||||
github.com/marten-seemann/qtls-go1-16 v0.1.5/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZEQMXjYK+dQSBFbethAk=
|
||||
github.com/marten-seemann/qtls-go1-17 v0.1.1 h1:DQjHPq+aOzUeh9/lixAGunn6rIOQyWChPSI4+hgW7jc=
|
||||
github.com/marten-seemann/qtls-go1-17 v0.1.1/go.mod h1:C2ekUKcDdz9SDWxec1N/MvcXBpaX9l3Nx67XaR84L5s=
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.1 h1:qp7p7XXUFL7fpBvSS1sWD+uSqPvzNQK43DH+/qEkj0Y=
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.1/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4=
|
||||
github.com/marten-seemann/qtls-go1-17 v0.1.2 h1:JADBlm0LYiVbuSySCHeY863dNkcpMmDR7s0bLKJeYlQ=
|
||||
github.com/marten-seemann/qtls-go1-17 v0.1.2/go.mod h1:C2ekUKcDdz9SDWxec1N/MvcXBpaX9l3Nx67XaR84L5s=
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.2 h1:JH6jmzbduz0ITVQ7ShevK10Av5+jBEKAHMntXmIV7kM=
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.2/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4=
|
||||
github.com/marten-seemann/qtls-go1-19 v0.1.0-beta.1 h1:7m/WlWcSROrcK5NxuXaxYD32BZqe/LEEnBrWcH/cOqQ=
|
||||
github.com/marten-seemann/qtls-go1-19 v0.1.0-beta.1/go.mod h1:5HTDWtVudo/WFsHKRNuOhWlbdjrfs5JHrYb0wIJqGpI=
|
||||
github.com/matrix-org/dugong v0.0.0-20210921133753-66e6b1c67e2e h1:DP5RC0Z3XdyBEW5dKt8YPeN6vZbm6OzVaGVp7f1BQRM=
|
||||
github.com/matrix-org/dugong v0.0.0-20210921133753-66e6b1c67e2e/go.mod h1:NgPCr+UavRGH6n5jmdX8DuqFZ4JiCWIJoZiuhTRLSUg=
|
||||
github.com/matrix-org/go-sqlite3-js v0.0.0-20220419092513-28aa791a1c91 h1:s7fexw2QV3YD/fRrzEDPNGgTlJlvXY0EHHnT87wF3OA=
|
||||
|
|
@ -341,10 +343,10 @@ github.com/matrix-org/go-sqlite3-js v0.0.0-20220419092513-28aa791a1c91/go.mod h1
|
|||
github.com/matrix-org/gomatrix v0.0.0-20190528120928-7df988a63f26/go.mod h1:3fxX6gUjWyI/2Bt7J1OLhpCzOfO/bB3AiX0cJtEKud0=
|
||||
github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16 h1:ZtO5uywdd5dLDCud4r0r55eP4j9FuUNpl60Gmntcop4=
|
||||
github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16/go.mod h1:/gBX06Kw0exX1HrwmoBibFA98yBk/jxKpGVeyQbff+s=
|
||||
github.com/matrix-org/gomatrixserverlib v0.0.0-20220725104114-b6003e522771 h1:ZIPHFIPNDS9dmEbPEiJbNmyCGJtn9exfpLC7JOcn/bE=
|
||||
github.com/matrix-org/gomatrixserverlib v0.0.0-20220725104114-b6003e522771/go.mod h1:jX38yp3SSLJNftBg3PXU1ayd0PCLIiDHQ4xAc9DIixk=
|
||||
github.com/matrix-org/pinecone v0.0.0-20220708135211-1ce778fcde6a h1:DdG8vXMlZ65EAtc4V+3t7zHZ2Gqs24pSnyXS+4BRHUs=
|
||||
github.com/matrix-org/pinecone v0.0.0-20220708135211-1ce778fcde6a/go.mod h1:ulJzsVOTssIVp1j/m5eI//4VpAGDkMt5NrRuAVX7wpc=
|
||||
github.com/matrix-org/gomatrixserverlib v0.0.0-20220801083850-5ff38e2c2839 h1:QEFxKWH8PlEt3ZQKl31yJNAm8lvpNUwT51IMNTl9v1k=
|
||||
github.com/matrix-org/gomatrixserverlib v0.0.0-20220801083850-5ff38e2c2839/go.mod h1:jX38yp3SSLJNftBg3PXU1ayd0PCLIiDHQ4xAc9DIixk=
|
||||
github.com/matrix-org/pinecone v0.0.0-20220803093810-b7a830c08fb9 h1:ed8yvWhTLk7+sNeK/eOZRTvESFTOHDRevoRoyeqPtvY=
|
||||
github.com/matrix-org/pinecone v0.0.0-20220803093810-b7a830c08fb9/go.mod h1:P4MqPf+u83OPulPJ+XTbSDbbWrdFYNY4LZ/B1PIduFE=
|
||||
github.com/matrix-org/util v0.0.0-20190711121626-527ce5ddefc7/go.mod h1:vVQlW/emklohkZnOPwD3LrZUBqdfsbiyO3p1lNV8F6U=
|
||||
github.com/matrix-org/util v0.0.0-20200807132607-55161520e1d4 h1:eCEHXWDv9Rm335MSuB49mFUK44bwZPFSDde3ORE3syk=
|
||||
github.com/matrix-org/util v0.0.0-20200807132607-55161520e1d4/go.mod h1:vVQlW/emklohkZnOPwD3LrZUBqdfsbiyO3p1lNV8F6U=
|
||||
|
|
@ -491,8 +493,8 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx
|
|||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
|
||||
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s=
|
||||
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
|
||||
|
|
@ -549,7 +551,6 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
|||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
|
||||
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
|
||||
|
|
@ -568,8 +569,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
|
|||
golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e h1:T8NU3HyQ8ClP4SEE+KbFlg6n0NhuTsN4MyznaarGsZM=
|
||||
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c=
|
||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
|
|
@ -659,8 +660,8 @@ golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qx
|
|||
golang.org/x/net v0.0.0-20210927181540-4e4d966f7476/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211011170408-caeb26a5c8c0/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211101193420-4a448f8816b3/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220524220425-1d687d428aca h1:xTaFYiPROfpPhqrfTIDXj0ri1SpfueYT951s4bAuDO8=
|
||||
golang.org/x/net v0.0.0-20220524220425-1d687d428aca/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e h1:TsQ7F31D3bUCLeqPT0u+yjp1guoArKaNKmCr22PYgTQ=
|
||||
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
|
|
@ -747,9 +748,12 @@ golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.0.0-20211102192858-4dd72447c267/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220405052023-b1e9470b6e64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220731174439-a90be440212d h1:Sv5ogFZatcgIMMtBSTTAgMYsicp25MXBubjXNDKwm80=
|
||||
golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 h1:CBpWXWQpIRjzmkkA+M7q9Fqnwd2mZr3AFqexg8YTfoM=
|
||||
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
|
@ -758,6 +762,7 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3
|
|||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.3.8-0.20211004125949-5bd84dd9b33b h1:NXqSWXSRUSCaFuvitrWtU169I3876zRTalMRbfd6LL0=
|
||||
golang.org/x/text v0.3.8-0.20211004125949-5bd84dd9b33b/go.mod h1:EFNZuWvGYxIRUEX+K8UmCFwYmZjqcrnq15ZuVldZkZ0=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ type lazyLoadingCacheKey struct {
|
|||
type LazyLoadCache interface {
|
||||
StoreLazyLoadedUser(device *userapi.Device, roomID, userID, eventID string)
|
||||
IsLazyLoadedUserCached(device *userapi.Device, roomID, userID string) (string, bool)
|
||||
InvalidateLazyLoadedUser(device *userapi.Device, roomID, userID string)
|
||||
}
|
||||
|
||||
func (c Caches) StoreLazyLoadedUser(device *userapi.Device, roomID, userID, eventID string) {
|
||||
|
|
@ -33,3 +34,12 @@ func (c Caches) IsLazyLoadedUserCached(device *userapi.Device, roomID, userID st
|
|||
TargetUserID: userID,
|
||||
})
|
||||
}
|
||||
|
||||
func (c Caches) InvalidateLazyLoadedUser(device *userapi.Device, roomID, userID string) {
|
||||
c.LazyLoading.Unset(lazyLoadingCacheKey{
|
||||
UserID: device.UserID,
|
||||
DeviceID: device.ID,
|
||||
RoomID: roomID,
|
||||
TargetUserID: userID,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,33 +0,0 @@
|
|||
package caching
|
||||
|
||||
import (
|
||||
"github.com/matrix-org/dendrite/roomserver/types"
|
||||
)
|
||||
|
||||
// WARNING: This cache is mutable because it's entirely possible that
|
||||
// the IsStub or StateSnaphotNID fields can change, even though the
|
||||
// room version and room NID fields will not. This is only safe because
|
||||
// the RoomInfoCache is used ONLY within the roomserver and because it
|
||||
// will be kept up-to-date by the latest events updater. It MUST NOT be
|
||||
// used from other components as we currently have no way to invalidate
|
||||
// the cache in downstream components.
|
||||
|
||||
// RoomInfosCache contains the subset of functions needed for
|
||||
// a room Info cache. It must only be used from the roomserver only
|
||||
// It is not safe for use from other components.
|
||||
type RoomInfoCache interface {
|
||||
GetRoomInfo(roomID string) (roomInfo *types.RoomInfo, ok bool)
|
||||
StoreRoomInfo(roomID string, roomInfo *types.RoomInfo)
|
||||
}
|
||||
|
||||
// GetRoomInfo must only be called from the roomserver only. It is not
|
||||
// safe for use from other components.
|
||||
func (c Caches) GetRoomInfo(roomID string) (*types.RoomInfo, bool) {
|
||||
return c.RoomInfos.Get(roomID)
|
||||
}
|
||||
|
||||
// StoreRoomInfo must only be called from the roomserver only. It is not
|
||||
// safe for use from other components.
|
||||
func (c Caches) StoreRoomInfo(roomID string, roomInfo *types.RoomInfo) {
|
||||
c.RoomInfos.Set(roomID, roomInfo)
|
||||
}
|
||||
|
|
@ -7,7 +7,6 @@ import (
|
|||
type RoomServerCaches interface {
|
||||
RoomServerNIDsCache
|
||||
RoomVersionCache
|
||||
RoomInfoCache
|
||||
RoomServerEventsCache
|
||||
EventStateKeyCache
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ type Caches struct {
|
|||
RoomServerRoomIDs Cache[types.RoomNID, string] // room NID -> room ID
|
||||
RoomServerEvents Cache[int64, *gomatrixserverlib.Event] // event NID -> event
|
||||
RoomServerStateKeys Cache[types.EventStateKeyNID, string] // event NID -> event state key
|
||||
RoomInfos Cache[string, *types.RoomInfo] // room ID -> room info
|
||||
FederationPDUs Cache[int64, *gomatrixserverlib.HeaderedEvent] // queue NID -> PDU
|
||||
FederationEDUs Cache[int64, *gomatrixserverlib.EDU] // queue NID -> EDU
|
||||
SpaceSummaryRooms Cache[string, gomatrixserverlib.MSC2946SpacesResponse] // room ID -> space response
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@ const (
|
|||
roomNIDsCache
|
||||
roomIDsCache
|
||||
roomEventsCache
|
||||
roomInfosCache
|
||||
federationPDUsCache
|
||||
federationEDUsCache
|
||||
spaceSummaryRoomsCache
|
||||
|
|
@ -106,12 +105,6 @@ func NewRistrettoCache(maxCost config.DataUnit, maxAge time.Duration, enableProm
|
|||
Prefix: eventStateKeyCache,
|
||||
MaxAge: maxAge,
|
||||
},
|
||||
RoomInfos: &RistrettoCachePartition[string, *types.RoomInfo]{ // room ID -> room info
|
||||
cache: cache,
|
||||
Prefix: roomInfosCache,
|
||||
Mutable: true,
|
||||
MaxAge: maxAge,
|
||||
},
|
||||
FederationPDUs: &RistrettoCostedCachePartition[int64, *gomatrixserverlib.HeaderedEvent]{ // queue NID -> PDU
|
||||
&RistrettoCachePartition[int64, *gomatrixserverlib.HeaderedEvent]{
|
||||
cache: cache,
|
||||
|
|
@ -153,7 +146,7 @@ func (c *RistrettoCostedCachePartition[K, V]) Set(key K, value V) {
|
|||
}
|
||||
|
||||
type RistrettoCachePartition[K keyable, V any] struct {
|
||||
cache *ristretto.Cache
|
||||
cache *ristretto.Cache //nolint:all,unused
|
||||
Prefix byte
|
||||
Mutable bool
|
||||
MaxAge time.Duration
|
||||
|
|
|
|||
|
|
@ -19,19 +19,21 @@ import (
|
|||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/matrix-org/dendrite/userapi/api"
|
||||
opentracing "github.com/opentracing/opentracing-go"
|
||||
"github.com/opentracing/opentracing-go/ext"
|
||||
)
|
||||
|
||||
// PostJSON performs a POST request with JSON on an internal HTTP API
|
||||
func PostJSON(
|
||||
// PostJSON performs a POST request with JSON on an internal HTTP API.
|
||||
// The error will match the errtype if returned from the remote API, or
|
||||
// will be a different type if there was a problem reaching the API.
|
||||
func PostJSON[reqtype, restype any, errtype error](
|
||||
ctx context.Context, span opentracing.Span, httpClient *http.Client,
|
||||
apiURL string, request, response interface{},
|
||||
apiURL string, request *reqtype, response *restype,
|
||||
) error {
|
||||
jsonBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
|
|
@ -69,17 +71,23 @@ func PostJSON(
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if res.StatusCode != http.StatusOK {
|
||||
var errorBody struct {
|
||||
Message string `json:"message"`
|
||||
}
|
||||
if _, ok := response.(*api.PerformKeyBackupResponse); ok { // TODO: remove this, once cross-boundary errors are a thing
|
||||
return nil
|
||||
}
|
||||
if msgerr := json.NewDecoder(res.Body).Decode(&errorBody); msgerr == nil {
|
||||
return fmt.Errorf("internal API: %d from %s: %s", res.StatusCode, apiURL, errorBody.Message)
|
||||
}
|
||||
return fmt.Errorf("internal API: %d from %s", res.StatusCode, apiURL)
|
||||
var body []byte
|
||||
body, err = io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return json.NewDecoder(res.Body).Decode(response)
|
||||
if res.StatusCode != http.StatusOK {
|
||||
if len(body) == 0 {
|
||||
return fmt.Errorf("HTTP %d from %s (no response body)", res.StatusCode, apiURL)
|
||||
}
|
||||
var reserr errtype
|
||||
if err = json.Unmarshal(body, reserr); err != nil {
|
||||
return fmt.Errorf("HTTP %d from %s", res.StatusCode, apiURL)
|
||||
}
|
||||
return reserr
|
||||
}
|
||||
if err = json.Unmarshal(body, response); err != nil {
|
||||
return fmt.Errorf("json.Unmarshal: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
93
internal/httputil/internalapi.go
Normal file
93
internal/httputil/internalapi.go
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
// Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package httputil
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"reflect"
|
||||
|
||||
"github.com/matrix-org/util"
|
||||
opentracing "github.com/opentracing/opentracing-go"
|
||||
)
|
||||
|
||||
type InternalAPIError struct {
|
||||
Type string
|
||||
Message string
|
||||
}
|
||||
|
||||
func (e InternalAPIError) Error() string {
|
||||
return fmt.Sprintf("internal API returned %q error: %s", e.Type, e.Message)
|
||||
}
|
||||
|
||||
func MakeInternalRPCAPI[reqtype, restype any](metricsName string, f func(context.Context, *reqtype, *restype) error) http.Handler {
|
||||
return MakeInternalAPI(metricsName, func(req *http.Request) util.JSONResponse {
|
||||
var request reqtype
|
||||
var response restype
|
||||
if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
|
||||
return util.MessageResponse(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
if err := f(req.Context(), &request, &response); err != nil {
|
||||
return util.JSONResponse{
|
||||
Code: http.StatusInternalServerError,
|
||||
JSON: &InternalAPIError{
|
||||
Type: reflect.TypeOf(err).String(),
|
||||
Message: fmt.Sprintf("%s", err),
|
||||
},
|
||||
}
|
||||
}
|
||||
return util.JSONResponse{
|
||||
Code: http.StatusOK,
|
||||
JSON: &response,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func MakeInternalProxyAPI[reqtype, restype any](metricsName string, f func(context.Context, *reqtype) (*restype, error)) http.Handler {
|
||||
return MakeInternalAPI(metricsName, func(req *http.Request) util.JSONResponse {
|
||||
var request reqtype
|
||||
if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
|
||||
return util.MessageResponse(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
response, err := f(req.Context(), &request)
|
||||
if err != nil {
|
||||
return util.JSONResponse{
|
||||
Code: http.StatusInternalServerError,
|
||||
JSON: err,
|
||||
}
|
||||
}
|
||||
return util.JSONResponse{
|
||||
Code: http.StatusOK,
|
||||
JSON: response,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func CallInternalRPCAPI[reqtype, restype any](name, url string, client *http.Client, ctx context.Context, request *reqtype, response *restype) error {
|
||||
span, ctx := opentracing.StartSpanFromContext(ctx, name)
|
||||
defer span.Finish()
|
||||
|
||||
return PostJSON[reqtype, restype, InternalAPIError](ctx, span, client, url, request, response)
|
||||
}
|
||||
|
||||
func CallInternalProxyAPI[reqtype, restype any, errtype error](name, url string, client *http.Client, ctx context.Context, request *reqtype) (restype, error) {
|
||||
span, ctx := opentracing.StartSpanFromContext(ctx, name)
|
||||
defer span.Finish()
|
||||
|
||||
var response restype
|
||||
return response, PostJSON[reqtype, restype, errtype](ctx, span, client, url, request, &response)
|
||||
}
|
||||
|
|
@ -27,9 +27,10 @@ import (
|
|||
|
||||
"github.com/matrix-org/util"
|
||||
|
||||
"github.com/matrix-org/dendrite/setup/config"
|
||||
"github.com/matrix-org/dugong"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/matrix-org/dendrite/setup/config"
|
||||
)
|
||||
|
||||
type utcFormatter struct {
|
||||
|
|
@ -145,7 +146,7 @@ func setupFileHook(hook config.LogrusHook, level logrus.Level, componentName str
|
|||
})
|
||||
}
|
||||
|
||||
//CloseAndLogIfError Closes io.Closer and logs the error if any
|
||||
// CloseAndLogIfError Closes io.Closer and logs the error if any
|
||||
func CloseAndLogIfError(ctx context.Context, closer io.Closer, message string) {
|
||||
if closer == nil {
|
||||
return
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
package internal
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"log/syslog"
|
||||
|
||||
"github.com/MFAshby/stdemuxerhook"
|
||||
|
|
@ -63,7 +63,7 @@ func SetupHookLogging(hooks []config.LogrusHook, componentName string) {
|
|||
setupStdLogHook(logrus.InfoLevel)
|
||||
}
|
||||
// Hooks are now configured for stdout/err, so throw away the default logger output
|
||||
logrus.SetOutput(ioutil.Discard)
|
||||
logrus.SetOutput(io.Discard)
|
||||
}
|
||||
|
||||
func checkSyslogHookParams(params map[string]interface{}) {
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@ var build string
|
|||
|
||||
const (
|
||||
VersionMajor = 0
|
||||
VersionMinor = 8
|
||||
VersionPatch = 9
|
||||
VersionMinor = 9
|
||||
VersionPatch = 1
|
||||
VersionTag = "" // example: "rc1"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -38,32 +38,32 @@ type KeyInternalAPI interface {
|
|||
|
||||
// API functions required by the clientapi
|
||||
type ClientKeyAPI interface {
|
||||
QueryKeys(ctx context.Context, req *QueryKeysRequest, res *QueryKeysResponse)
|
||||
PerformUploadKeys(ctx context.Context, req *PerformUploadKeysRequest, res *PerformUploadKeysResponse)
|
||||
PerformUploadDeviceKeys(ctx context.Context, req *PerformUploadDeviceKeysRequest, res *PerformUploadDeviceKeysResponse)
|
||||
PerformUploadDeviceSignatures(ctx context.Context, req *PerformUploadDeviceSignaturesRequest, res *PerformUploadDeviceSignaturesResponse)
|
||||
QueryKeys(ctx context.Context, req *QueryKeysRequest, res *QueryKeysResponse) error
|
||||
PerformUploadKeys(ctx context.Context, req *PerformUploadKeysRequest, res *PerformUploadKeysResponse) error
|
||||
PerformUploadDeviceKeys(ctx context.Context, req *PerformUploadDeviceKeysRequest, res *PerformUploadDeviceKeysResponse) error
|
||||
PerformUploadDeviceSignatures(ctx context.Context, req *PerformUploadDeviceSignaturesRequest, res *PerformUploadDeviceSignaturesResponse) error
|
||||
// PerformClaimKeys claims one-time keys for use in pre-key messages
|
||||
PerformClaimKeys(ctx context.Context, req *PerformClaimKeysRequest, res *PerformClaimKeysResponse)
|
||||
PerformClaimKeys(ctx context.Context, req *PerformClaimKeysRequest, res *PerformClaimKeysResponse) error
|
||||
}
|
||||
|
||||
// API functions required by the userapi
|
||||
type UserKeyAPI interface {
|
||||
PerformUploadKeys(ctx context.Context, req *PerformUploadKeysRequest, res *PerformUploadKeysResponse)
|
||||
PerformDeleteKeys(ctx context.Context, req *PerformDeleteKeysRequest, res *PerformDeleteKeysResponse)
|
||||
PerformUploadKeys(ctx context.Context, req *PerformUploadKeysRequest, res *PerformUploadKeysResponse) error
|
||||
PerformDeleteKeys(ctx context.Context, req *PerformDeleteKeysRequest, res *PerformDeleteKeysResponse) error
|
||||
}
|
||||
|
||||
// API functions required by the syncapi
|
||||
type SyncKeyAPI interface {
|
||||
QueryKeyChanges(ctx context.Context, req *QueryKeyChangesRequest, res *QueryKeyChangesResponse)
|
||||
QueryOneTimeKeys(ctx context.Context, req *QueryOneTimeKeysRequest, res *QueryOneTimeKeysResponse)
|
||||
QueryKeyChanges(ctx context.Context, req *QueryKeyChangesRequest, res *QueryKeyChangesResponse) error
|
||||
QueryOneTimeKeys(ctx context.Context, req *QueryOneTimeKeysRequest, res *QueryOneTimeKeysResponse) error
|
||||
}
|
||||
|
||||
type FederationKeyAPI interface {
|
||||
QueryKeys(ctx context.Context, req *QueryKeysRequest, res *QueryKeysResponse)
|
||||
QuerySignatures(ctx context.Context, req *QuerySignaturesRequest, res *QuerySignaturesResponse)
|
||||
QueryDeviceMessages(ctx context.Context, req *QueryDeviceMessagesRequest, res *QueryDeviceMessagesResponse)
|
||||
PerformUploadDeviceKeys(ctx context.Context, req *PerformUploadDeviceKeysRequest, res *PerformUploadDeviceKeysResponse)
|
||||
PerformClaimKeys(ctx context.Context, req *PerformClaimKeysRequest, res *PerformClaimKeysResponse)
|
||||
QueryKeys(ctx context.Context, req *QueryKeysRequest, res *QueryKeysResponse) error
|
||||
QuerySignatures(ctx context.Context, req *QuerySignaturesRequest, res *QuerySignaturesResponse) error
|
||||
QueryDeviceMessages(ctx context.Context, req *QueryDeviceMessagesRequest, res *QueryDeviceMessagesResponse) error
|
||||
PerformUploadDeviceKeys(ctx context.Context, req *PerformUploadDeviceKeysRequest, res *PerformUploadDeviceKeysResponse) error
|
||||
PerformClaimKeys(ctx context.Context, req *PerformClaimKeysRequest, res *PerformClaimKeysResponse) error
|
||||
}
|
||||
|
||||
// KeyError is returned if there was a problem performing/querying the server
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ func sanityCheckKey(key gomatrixserverlib.CrossSigningKey, userID string, purpos
|
|||
}
|
||||
|
||||
// nolint:gocyclo
|
||||
func (a *KeyInternalAPI) PerformUploadDeviceKeys(ctx context.Context, req *api.PerformUploadDeviceKeysRequest, res *api.PerformUploadDeviceKeysResponse) {
|
||||
func (a *KeyInternalAPI) PerformUploadDeviceKeys(ctx context.Context, req *api.PerformUploadDeviceKeysRequest, res *api.PerformUploadDeviceKeysResponse) error {
|
||||
// Find the keys to store.
|
||||
byPurpose := map[gomatrixserverlib.CrossSigningKeyPurpose]gomatrixserverlib.CrossSigningKey{}
|
||||
toStore := types.CrossSigningKeyMap{}
|
||||
|
|
@ -115,7 +115,7 @@ func (a *KeyInternalAPI) PerformUploadDeviceKeys(ctx context.Context, req *api.P
|
|||
Err: "Master key sanity check failed: " + err.Error(),
|
||||
IsInvalidParam: true,
|
||||
}
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
byPurpose[gomatrixserverlib.CrossSigningKeyPurposeMaster] = req.MasterKey
|
||||
|
|
@ -131,7 +131,7 @@ func (a *KeyInternalAPI) PerformUploadDeviceKeys(ctx context.Context, req *api.P
|
|||
Err: "Self-signing key sanity check failed: " + err.Error(),
|
||||
IsInvalidParam: true,
|
||||
}
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
byPurpose[gomatrixserverlib.CrossSigningKeyPurposeSelfSigning] = req.SelfSigningKey
|
||||
|
|
@ -146,7 +146,7 @@ func (a *KeyInternalAPI) PerformUploadDeviceKeys(ctx context.Context, req *api.P
|
|||
Err: "User-signing key sanity check failed: " + err.Error(),
|
||||
IsInvalidParam: true,
|
||||
}
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
byPurpose[gomatrixserverlib.CrossSigningKeyPurposeUserSigning] = req.UserSigningKey
|
||||
|
|
@ -161,7 +161,7 @@ func (a *KeyInternalAPI) PerformUploadDeviceKeys(ctx context.Context, req *api.P
|
|||
Err: "No keys were supplied in the request",
|
||||
IsMissingParam: true,
|
||||
}
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
// We can't have a self-signing or user-signing key without a master
|
||||
|
|
@ -174,7 +174,7 @@ func (a *KeyInternalAPI) PerformUploadDeviceKeys(ctx context.Context, req *api.P
|
|||
res.Error = &api.KeyError{
|
||||
Err: "Retrieving cross-signing keys from database failed: " + err.Error(),
|
||||
}
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
// If we still can't find a master key for the user then stop the upload.
|
||||
|
|
@ -185,7 +185,7 @@ func (a *KeyInternalAPI) PerformUploadDeviceKeys(ctx context.Context, req *api.P
|
|||
Err: "No master key was found",
|
||||
IsMissingParam: true,
|
||||
}
|
||||
return
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -212,7 +212,7 @@ func (a *KeyInternalAPI) PerformUploadDeviceKeys(ctx context.Context, req *api.P
|
|||
}
|
||||
}
|
||||
if !changed {
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
// Store the keys.
|
||||
|
|
@ -220,7 +220,7 @@ func (a *KeyInternalAPI) PerformUploadDeviceKeys(ctx context.Context, req *api.P
|
|||
res.Error = &api.KeyError{
|
||||
Err: fmt.Sprintf("a.DB.StoreCrossSigningKeysForUser: %s", err),
|
||||
}
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
// Now upload any signatures that were included with the keys.
|
||||
|
|
@ -238,7 +238,7 @@ func (a *KeyInternalAPI) PerformUploadDeviceKeys(ctx context.Context, req *api.P
|
|||
res.Error = &api.KeyError{
|
||||
Err: fmt.Sprintf("a.DB.StoreCrossSigningSigsForTarget: %s", err),
|
||||
}
|
||||
return
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -255,17 +255,18 @@ func (a *KeyInternalAPI) PerformUploadDeviceKeys(ctx context.Context, req *api.P
|
|||
update.SelfSigningKey = &ssk
|
||||
}
|
||||
if update.MasterKey == nil && update.SelfSigningKey == nil {
|
||||
return
|
||||
return nil
|
||||
}
|
||||
if err := a.Producer.ProduceSigningKeyUpdate(update); err != nil {
|
||||
res.Error = &api.KeyError{
|
||||
Err: fmt.Sprintf("a.Producer.ProduceSigningKeyUpdate: %s", err),
|
||||
}
|
||||
return
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *KeyInternalAPI) PerformUploadDeviceSignatures(ctx context.Context, req *api.PerformUploadDeviceSignaturesRequest, res *api.PerformUploadDeviceSignaturesResponse) {
|
||||
func (a *KeyInternalAPI) PerformUploadDeviceSignatures(ctx context.Context, req *api.PerformUploadDeviceSignaturesRequest, res *api.PerformUploadDeviceSignaturesResponse) error {
|
||||
// Before we do anything, we need the master and self-signing keys for this user.
|
||||
// Then we can verify the signatures make sense.
|
||||
queryReq := &api.QueryKeysRequest{
|
||||
|
|
@ -276,7 +277,7 @@ func (a *KeyInternalAPI) PerformUploadDeviceSignatures(ctx context.Context, req
|
|||
for userID := range req.Signatures {
|
||||
queryReq.UserToDevices[userID] = []string{}
|
||||
}
|
||||
a.QueryKeys(ctx, queryReq, queryRes)
|
||||
_ = a.QueryKeys(ctx, queryReq, queryRes)
|
||||
|
||||
selfSignatures := map[string]map[gomatrixserverlib.KeyID]gomatrixserverlib.CrossSigningForKeyOrDevice{}
|
||||
otherSignatures := map[string]map[gomatrixserverlib.KeyID]gomatrixserverlib.CrossSigningForKeyOrDevice{}
|
||||
|
|
@ -322,14 +323,14 @@ func (a *KeyInternalAPI) PerformUploadDeviceSignatures(ctx context.Context, req
|
|||
res.Error = &api.KeyError{
|
||||
Err: fmt.Sprintf("a.processSelfSignatures: %s", err),
|
||||
}
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := a.processOtherSignatures(ctx, req.UserID, queryRes, otherSignatures); err != nil {
|
||||
res.Error = &api.KeyError{
|
||||
Err: fmt.Sprintf("a.processOtherSignatures: %s", err),
|
||||
}
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
// Finally, generate a notification that we updated the signatures.
|
||||
|
|
@ -345,9 +346,10 @@ func (a *KeyInternalAPI) PerformUploadDeviceSignatures(ctx context.Context, req
|
|||
res.Error = &api.KeyError{
|
||||
Err: fmt.Sprintf("a.Producer.ProduceSigningKeyUpdate: %s", err),
|
||||
}
|
||||
return
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *KeyInternalAPI) processSelfSignatures(
|
||||
|
|
@ -520,7 +522,7 @@ func (a *KeyInternalAPI) crossSigningKeysFromDatabase(
|
|||
}
|
||||
}
|
||||
|
||||
func (a *KeyInternalAPI) QuerySignatures(ctx context.Context, req *api.QuerySignaturesRequest, res *api.QuerySignaturesResponse) {
|
||||
func (a *KeyInternalAPI) QuerySignatures(ctx context.Context, req *api.QuerySignaturesRequest, res *api.QuerySignaturesResponse) error {
|
||||
for targetUserID, forTargetUser := range req.TargetIDs {
|
||||
keyMap, err := a.DB.CrossSigningKeysForUser(ctx, targetUserID)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
|
|
@ -559,7 +561,7 @@ func (a *KeyInternalAPI) QuerySignatures(ctx context.Context, req *api.QuerySign
|
|||
res.Error = &api.KeyError{
|
||||
Err: fmt.Sprintf("a.DB.CrossSigningSigsForTarget: %s", err),
|
||||
}
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
for sourceUserID, forSourceUser := range sigMap {
|
||||
|
|
@ -581,4 +583,5 @@ func (a *KeyInternalAPI) QuerySignatures(ctx context.Context, req *api.QuerySign
|
|||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,12 +22,13 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
fedsenderapi "github.com/matrix-org/dendrite/federationapi/api"
|
||||
"github.com/matrix-org/dendrite/keyserver/api"
|
||||
"github.com/matrix-org/gomatrixserverlib"
|
||||
"github.com/matrix-org/util"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
fedsenderapi "github.com/matrix-org/dendrite/federationapi/api"
|
||||
"github.com/matrix-org/dendrite/keyserver/api"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
@ -66,12 +67,14 @@ func init() {
|
|||
// - We don't have unbounded growth in proportion to the number of servers (this is more important in a P2P world where
|
||||
// we have many many servers)
|
||||
// - We can adjust concurrency (at the cost of memory usage) by tuning N, to accommodate mobile devices vs servers.
|
||||
//
|
||||
// The downsides are that:
|
||||
// - Query requests can get queued behind other servers if they hash to the same worker, even if there are other free
|
||||
// workers elsewhere. Whilst suboptimal, provided we cap how long a single request can last (e.g using context timeouts)
|
||||
// we guarantee we will get around to it. Also, more users on a given server does not increase the number of requests
|
||||
// (as /keys/query allows multiple users to be specified) so being stuck behind matrix.org won't materially be any worse
|
||||
// than being stuck behind foo.bar
|
||||
//
|
||||
// In the event that the query fails, a lock is acquired and the server name along with the time to wait before retrying is
|
||||
// set in a map. A restarter goroutine periodically probes this map and injects servers which are ready to be retried.
|
||||
type DeviceListUpdater struct {
|
||||
|
|
@ -116,7 +119,7 @@ type DeviceListUpdaterDatabase interface {
|
|||
}
|
||||
|
||||
type DeviceListUpdaterAPI interface {
|
||||
PerformUploadDeviceKeys(ctx context.Context, req *api.PerformUploadDeviceKeysRequest, res *api.PerformUploadDeviceKeysResponse)
|
||||
PerformUploadDeviceKeys(ctx context.Context, req *api.PerformUploadDeviceKeysRequest, res *api.PerformUploadDeviceKeysResponse) error
|
||||
}
|
||||
|
||||
// KeyChangeProducer is the interface for producers.KeyChange useful for testing.
|
||||
|
|
@ -418,7 +421,7 @@ func (u *DeviceListUpdater) processServer(serverName gomatrixserverlib.ServerNam
|
|||
uploadReq.SelfSigningKey = *res.SelfSigningKey
|
||||
}
|
||||
}
|
||||
u.api.PerformUploadDeviceKeys(ctx, uploadReq, uploadRes)
|
||||
_ = u.api.PerformUploadDeviceKeys(ctx, uploadReq, uploadRes)
|
||||
}
|
||||
err = u.updateDeviceList(&res)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ import (
|
|||
"context"
|
||||
"crypto/ed25519"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"reflect"
|
||||
|
|
@ -27,8 +27,9 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/matrix-org/dendrite/keyserver/api"
|
||||
"github.com/matrix-org/gomatrixserverlib"
|
||||
|
||||
"github.com/matrix-org/dendrite/keyserver/api"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
@ -112,8 +113,8 @@ func (d *mockDeviceListUpdaterDatabase) DeviceKeysJSON(ctx context.Context, keys
|
|||
type mockDeviceListUpdaterAPI struct {
|
||||
}
|
||||
|
||||
func (d *mockDeviceListUpdaterAPI) PerformUploadDeviceKeys(ctx context.Context, req *api.PerformUploadDeviceKeysRequest, res *api.PerformUploadDeviceKeysResponse) {
|
||||
|
||||
func (d *mockDeviceListUpdaterAPI) PerformUploadDeviceKeys(ctx context.Context, req *api.PerformUploadDeviceKeysRequest, res *api.PerformUploadDeviceKeysResponse) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type roundTripper struct {
|
||||
|
|
@ -202,7 +203,7 @@ func TestUpdateNoPrevID(t *testing.T) {
|
|||
}
|
||||
return &http.Response{
|
||||
StatusCode: 200,
|
||||
Body: ioutil.NopCloser(strings.NewReader(`
|
||||
Body: io.NopCloser(strings.NewReader(`
|
||||
{
|
||||
"user_id": "` + remoteUserID + `",
|
||||
"stream_id": 5,
|
||||
|
|
@ -317,7 +318,7 @@ func TestDebounce(t *testing.T) {
|
|||
// now send the response over federation
|
||||
fedCh <- &http.Response{
|
||||
StatusCode: 200,
|
||||
Body: ioutil.NopCloser(strings.NewReader(`
|
||||
Body: io.NopCloser(strings.NewReader(`
|
||||
{
|
||||
"user_id": "` + userID + `",
|
||||
"stream_id": 5,
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import (
|
|||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
|
@ -47,18 +48,20 @@ func (a *KeyInternalAPI) SetUserAPI(i userapi.KeyserverUserAPI) {
|
|||
a.UserAPI = i
|
||||
}
|
||||
|
||||
func (a *KeyInternalAPI) QueryKeyChanges(ctx context.Context, req *api.QueryKeyChangesRequest, res *api.QueryKeyChangesResponse) {
|
||||
func (a *KeyInternalAPI) QueryKeyChanges(ctx context.Context, req *api.QueryKeyChangesRequest, res *api.QueryKeyChangesResponse) error {
|
||||
userIDs, latest, err := a.DB.KeyChanges(ctx, req.Offset, req.ToOffset)
|
||||
if err != nil {
|
||||
res.Error = &api.KeyError{
|
||||
Err: err.Error(),
|
||||
}
|
||||
return nil
|
||||
}
|
||||
res.Offset = latest
|
||||
res.UserIDs = userIDs
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *KeyInternalAPI) PerformUploadKeys(ctx context.Context, req *api.PerformUploadKeysRequest, res *api.PerformUploadKeysResponse) {
|
||||
func (a *KeyInternalAPI) PerformUploadKeys(ctx context.Context, req *api.PerformUploadKeysRequest, res *api.PerformUploadKeysResponse) error {
|
||||
res.KeyErrors = make(map[string]map[string]*api.KeyError)
|
||||
if len(req.DeviceKeys) > 0 {
|
||||
a.uploadLocalDeviceKeys(ctx, req, res)
|
||||
|
|
@ -66,9 +69,10 @@ func (a *KeyInternalAPI) PerformUploadKeys(ctx context.Context, req *api.Perform
|
|||
if len(req.OneTimeKeys) > 0 {
|
||||
a.uploadOneTimeKeys(ctx, req, res)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *KeyInternalAPI) PerformClaimKeys(ctx context.Context, req *api.PerformClaimKeysRequest, res *api.PerformClaimKeysResponse) {
|
||||
func (a *KeyInternalAPI) PerformClaimKeys(ctx context.Context, req *api.PerformClaimKeysRequest, res *api.PerformClaimKeysResponse) error {
|
||||
res.OneTimeKeys = make(map[string]map[string]map[string]json.RawMessage)
|
||||
res.Failures = make(map[string]interface{})
|
||||
// wrap request map in a top-level by-domain map
|
||||
|
|
@ -112,6 +116,7 @@ func (a *KeyInternalAPI) PerformClaimKeys(ctx context.Context, req *api.PerformC
|
|||
if len(domainToDeviceKeys) > 0 {
|
||||
a.claimRemoteKeys(ctx, req.Timeout, res, domainToDeviceKeys)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *KeyInternalAPI) claimRemoteKeys(
|
||||
|
|
@ -171,32 +176,34 @@ func (a *KeyInternalAPI) claimRemoteKeys(
|
|||
util.GetLogger(ctx).WithField("num_keys", keysClaimed).Info("Claimed remote keys")
|
||||
}
|
||||
|
||||
func (a *KeyInternalAPI) PerformDeleteKeys(ctx context.Context, req *api.PerformDeleteKeysRequest, res *api.PerformDeleteKeysResponse) {
|
||||
func (a *KeyInternalAPI) PerformDeleteKeys(ctx context.Context, req *api.PerformDeleteKeysRequest, res *api.PerformDeleteKeysResponse) error {
|
||||
if err := a.DB.DeleteDeviceKeys(ctx, req.UserID, req.KeyIDs); err != nil {
|
||||
res.Error = &api.KeyError{
|
||||
Err: fmt.Sprintf("Failed to delete device keys: %s", err),
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *KeyInternalAPI) QueryOneTimeKeys(ctx context.Context, req *api.QueryOneTimeKeysRequest, res *api.QueryOneTimeKeysResponse) {
|
||||
func (a *KeyInternalAPI) QueryOneTimeKeys(ctx context.Context, req *api.QueryOneTimeKeysRequest, res *api.QueryOneTimeKeysResponse) error {
|
||||
count, err := a.DB.OneTimeKeysCount(ctx, req.UserID, req.DeviceID)
|
||||
if err != nil {
|
||||
res.Error = &api.KeyError{
|
||||
Err: fmt.Sprintf("Failed to query OTK counts: %s", err),
|
||||
}
|
||||
return
|
||||
return nil
|
||||
}
|
||||
res.Count = *count
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *KeyInternalAPI) QueryDeviceMessages(ctx context.Context, req *api.QueryDeviceMessagesRequest, res *api.QueryDeviceMessagesResponse) {
|
||||
func (a *KeyInternalAPI) QueryDeviceMessages(ctx context.Context, req *api.QueryDeviceMessagesRequest, res *api.QueryDeviceMessagesResponse) error {
|
||||
msgs, err := a.DB.DeviceKeysForUser(ctx, req.UserID, nil, false)
|
||||
if err != nil {
|
||||
res.Error = &api.KeyError{
|
||||
Err: fmt.Sprintf("failed to query DB for device keys: %s", err),
|
||||
}
|
||||
return
|
||||
return nil
|
||||
}
|
||||
maxStreamID := int64(0)
|
||||
for _, m := range msgs {
|
||||
|
|
@ -214,10 +221,11 @@ func (a *KeyInternalAPI) QueryDeviceMessages(ctx context.Context, req *api.Query
|
|||
}
|
||||
res.Devices = result
|
||||
res.StreamID = maxStreamID
|
||||
return nil
|
||||
}
|
||||
|
||||
// nolint:gocyclo
|
||||
func (a *KeyInternalAPI) QueryKeys(ctx context.Context, req *api.QueryKeysRequest, res *api.QueryKeysResponse) {
|
||||
func (a *KeyInternalAPI) QueryKeys(ctx context.Context, req *api.QueryKeysRequest, res *api.QueryKeysResponse) error {
|
||||
res.DeviceKeys = make(map[string]map[string]json.RawMessage)
|
||||
res.MasterKeys = make(map[string]gomatrixserverlib.CrossSigningKey)
|
||||
res.SelfSigningKeys = make(map[string]gomatrixserverlib.CrossSigningKey)
|
||||
|
|
@ -243,7 +251,7 @@ func (a *KeyInternalAPI) QueryKeys(ctx context.Context, req *api.QueryKeysReques
|
|||
res.Error = &api.KeyError{
|
||||
Err: fmt.Sprintf("failed to query local device keys: %s", err),
|
||||
}
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
// pull out display names after we have the keys so we handle wildcards correctly
|
||||
|
|
@ -314,6 +322,11 @@ func (a *KeyInternalAPI) QueryKeys(ctx context.Context, req *api.QueryKeysReques
|
|||
for targetKeyID := range masterKey.Keys {
|
||||
sigMap, err := a.DB.CrossSigningSigsForTarget(ctx, req.UserID, targetUserID, targetKeyID)
|
||||
if err != nil {
|
||||
// Stop executing the function if the context was canceled/the deadline was exceeded,
|
||||
// as we can't continue without a valid context.
|
||||
if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
|
||||
return nil
|
||||
}
|
||||
logrus.WithError(err).Errorf("a.DB.CrossSigningSigsForTarget failed")
|
||||
continue
|
||||
}
|
||||
|
|
@ -335,6 +348,11 @@ func (a *KeyInternalAPI) QueryKeys(ctx context.Context, req *api.QueryKeysReques
|
|||
for targetKeyID, key := range forUserID {
|
||||
sigMap, err := a.DB.CrossSigningSigsForTarget(ctx, req.UserID, targetUserID, gomatrixserverlib.KeyID(targetKeyID))
|
||||
if err != nil {
|
||||
// Stop executing the function if the context was canceled/the deadline was exceeded,
|
||||
// as we can't continue without a valid context.
|
||||
if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
|
||||
return nil
|
||||
}
|
||||
logrus.WithError(err).Errorf("a.DB.CrossSigningSigsForTarget failed")
|
||||
continue
|
||||
}
|
||||
|
|
@ -361,6 +379,7 @@ func (a *KeyInternalAPI) QueryKeys(ctx context.Context, req *api.QueryKeysReques
|
|||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *KeyInternalAPI) remoteKeysFromDatabase(
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ import (
|
|||
"github.com/matrix-org/dendrite/internal/httputil"
|
||||
"github.com/matrix-org/dendrite/keyserver/api"
|
||||
userapi "github.com/matrix-org/dendrite/userapi/api"
|
||||
"github.com/opentracing/opentracing-go"
|
||||
)
|
||||
|
||||
// HTTP paths for the internal HTTP APIs
|
||||
|
|
@ -68,168 +67,108 @@ func (h *httpKeyInternalAPI) PerformClaimKeys(
|
|||
ctx context.Context,
|
||||
request *api.PerformClaimKeysRequest,
|
||||
response *api.PerformClaimKeysResponse,
|
||||
) {
|
||||
span, ctx := opentracing.StartSpanFromContext(ctx, "PerformClaimKeys")
|
||||
defer span.Finish()
|
||||
|
||||
apiURL := h.apiURL + PerformClaimKeysPath
|
||||
err := httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response)
|
||||
if err != nil {
|
||||
response.Error = &api.KeyError{
|
||||
Err: err.Error(),
|
||||
}
|
||||
}
|
||||
) error {
|
||||
return httputil.CallInternalRPCAPI(
|
||||
"PerformClaimKeys", h.apiURL+PerformClaimKeysPath,
|
||||
h.httpClient, ctx, request, response,
|
||||
)
|
||||
}
|
||||
|
||||
func (h *httpKeyInternalAPI) PerformDeleteKeys(
|
||||
ctx context.Context,
|
||||
request *api.PerformDeleteKeysRequest,
|
||||
response *api.PerformDeleteKeysResponse,
|
||||
) {
|
||||
span, ctx := opentracing.StartSpanFromContext(ctx, "PerformClaimKeys")
|
||||
defer span.Finish()
|
||||
|
||||
apiURL := h.apiURL + PerformClaimKeysPath
|
||||
err := httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response)
|
||||
if err != nil {
|
||||
response.Error = &api.KeyError{
|
||||
Err: err.Error(),
|
||||
}
|
||||
}
|
||||
) error {
|
||||
return httputil.CallInternalRPCAPI(
|
||||
"PerformDeleteKeys", h.apiURL+PerformDeleteKeysPath,
|
||||
h.httpClient, ctx, request, response,
|
||||
)
|
||||
}
|
||||
|
||||
func (h *httpKeyInternalAPI) PerformUploadKeys(
|
||||
ctx context.Context,
|
||||
request *api.PerformUploadKeysRequest,
|
||||
response *api.PerformUploadKeysResponse,
|
||||
) {
|
||||
span, ctx := opentracing.StartSpanFromContext(ctx, "PerformUploadKeys")
|
||||
defer span.Finish()
|
||||
|
||||
apiURL := h.apiURL + PerformUploadKeysPath
|
||||
err := httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response)
|
||||
if err != nil {
|
||||
response.Error = &api.KeyError{
|
||||
Err: err.Error(),
|
||||
}
|
||||
}
|
||||
) error {
|
||||
return httputil.CallInternalRPCAPI(
|
||||
"PerformUploadKeys", h.apiURL+PerformUploadKeysPath,
|
||||
h.httpClient, ctx, request, response,
|
||||
)
|
||||
}
|
||||
|
||||
func (h *httpKeyInternalAPI) QueryKeys(
|
||||
ctx context.Context,
|
||||
request *api.QueryKeysRequest,
|
||||
response *api.QueryKeysResponse,
|
||||
) {
|
||||
span, ctx := opentracing.StartSpanFromContext(ctx, "QueryKeys")
|
||||
defer span.Finish()
|
||||
|
||||
apiURL := h.apiURL + QueryKeysPath
|
||||
err := httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response)
|
||||
if err != nil {
|
||||
response.Error = &api.KeyError{
|
||||
Err: err.Error(),
|
||||
}
|
||||
}
|
||||
) error {
|
||||
return httputil.CallInternalRPCAPI(
|
||||
"QueryKeys", h.apiURL+QueryKeysPath,
|
||||
h.httpClient, ctx, request, response,
|
||||
)
|
||||
}
|
||||
|
||||
func (h *httpKeyInternalAPI) QueryOneTimeKeys(
|
||||
ctx context.Context,
|
||||
request *api.QueryOneTimeKeysRequest,
|
||||
response *api.QueryOneTimeKeysResponse,
|
||||
) {
|
||||
span, ctx := opentracing.StartSpanFromContext(ctx, "QueryOneTimeKeys")
|
||||
defer span.Finish()
|
||||
|
||||
apiURL := h.apiURL + QueryOneTimeKeysPath
|
||||
err := httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response)
|
||||
if err != nil {
|
||||
response.Error = &api.KeyError{
|
||||
Err: err.Error(),
|
||||
}
|
||||
}
|
||||
) error {
|
||||
return httputil.CallInternalRPCAPI(
|
||||
"QueryOneTimeKeys", h.apiURL+QueryOneTimeKeysPath,
|
||||
h.httpClient, ctx, request, response,
|
||||
)
|
||||
}
|
||||
|
||||
func (h *httpKeyInternalAPI) QueryDeviceMessages(
|
||||
ctx context.Context,
|
||||
request *api.QueryDeviceMessagesRequest,
|
||||
response *api.QueryDeviceMessagesResponse,
|
||||
) {
|
||||
span, ctx := opentracing.StartSpanFromContext(ctx, "QueryDeviceMessages")
|
||||
defer span.Finish()
|
||||
|
||||
apiURL := h.apiURL + QueryDeviceMessagesPath
|
||||
err := httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response)
|
||||
if err != nil {
|
||||
response.Error = &api.KeyError{
|
||||
Err: err.Error(),
|
||||
}
|
||||
}
|
||||
) error {
|
||||
return httputil.CallInternalRPCAPI(
|
||||
"QueryDeviceMessages", h.apiURL+QueryDeviceMessagesPath,
|
||||
h.httpClient, ctx, request, response,
|
||||
)
|
||||
}
|
||||
|
||||
func (h *httpKeyInternalAPI) QueryKeyChanges(
|
||||
ctx context.Context,
|
||||
request *api.QueryKeyChangesRequest,
|
||||
response *api.QueryKeyChangesResponse,
|
||||
) {
|
||||
span, ctx := opentracing.StartSpanFromContext(ctx, "QueryKeyChanges")
|
||||
defer span.Finish()
|
||||
|
||||
apiURL := h.apiURL + QueryKeyChangesPath
|
||||
err := httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response)
|
||||
if err != nil {
|
||||
response.Error = &api.KeyError{
|
||||
Err: err.Error(),
|
||||
}
|
||||
}
|
||||
) error {
|
||||
return httputil.CallInternalRPCAPI(
|
||||
"QueryKeyChanges", h.apiURL+QueryKeyChangesPath,
|
||||
h.httpClient, ctx, request, response,
|
||||
)
|
||||
}
|
||||
|
||||
func (h *httpKeyInternalAPI) PerformUploadDeviceKeys(
|
||||
ctx context.Context,
|
||||
request *api.PerformUploadDeviceKeysRequest,
|
||||
response *api.PerformUploadDeviceKeysResponse,
|
||||
) {
|
||||
span, ctx := opentracing.StartSpanFromContext(ctx, "PerformUploadDeviceKeys")
|
||||
defer span.Finish()
|
||||
|
||||
apiURL := h.apiURL + PerformUploadDeviceKeysPath
|
||||
err := httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response)
|
||||
if err != nil {
|
||||
response.Error = &api.KeyError{
|
||||
Err: err.Error(),
|
||||
}
|
||||
}
|
||||
) error {
|
||||
return httputil.CallInternalRPCAPI(
|
||||
"PerformUploadDeviceKeys", h.apiURL+PerformUploadDeviceKeysPath,
|
||||
h.httpClient, ctx, request, response,
|
||||
)
|
||||
}
|
||||
|
||||
func (h *httpKeyInternalAPI) PerformUploadDeviceSignatures(
|
||||
ctx context.Context,
|
||||
request *api.PerformUploadDeviceSignaturesRequest,
|
||||
response *api.PerformUploadDeviceSignaturesResponse,
|
||||
) {
|
||||
span, ctx := opentracing.StartSpanFromContext(ctx, "PerformUploadDeviceSignatures")
|
||||
defer span.Finish()
|
||||
|
||||
apiURL := h.apiURL + PerformUploadDeviceSignaturesPath
|
||||
err := httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response)
|
||||
if err != nil {
|
||||
response.Error = &api.KeyError{
|
||||
Err: err.Error(),
|
||||
}
|
||||
}
|
||||
) error {
|
||||
return httputil.CallInternalRPCAPI(
|
||||
"PerformUploadDeviceSignatures", h.apiURL+PerformUploadDeviceSignaturesPath,
|
||||
h.httpClient, ctx, request, response,
|
||||
)
|
||||
}
|
||||
|
||||
func (h *httpKeyInternalAPI) QuerySignatures(
|
||||
ctx context.Context,
|
||||
request *api.QuerySignaturesRequest,
|
||||
response *api.QuerySignaturesResponse,
|
||||
) {
|
||||
span, ctx := opentracing.StartSpanFromContext(ctx, "QuerySignatures")
|
||||
defer span.Finish()
|
||||
|
||||
apiURL := h.apiURL + QuerySignaturesPath
|
||||
err := httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response)
|
||||
if err != nil {
|
||||
response.Error = &api.KeyError{
|
||||
Err: err.Error(),
|
||||
}
|
||||
}
|
||||
) error {
|
||||
return httputil.CallInternalRPCAPI(
|
||||
"QuerySignatures", h.apiURL+QuerySignaturesPath,
|
||||
h.httpClient, ctx, request, response,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,124 +15,59 @@
|
|||
package inthttp
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/matrix-org/dendrite/internal/httputil"
|
||||
"github.com/matrix-org/dendrite/keyserver/api"
|
||||
"github.com/matrix-org/util"
|
||||
)
|
||||
|
||||
func AddRoutes(internalAPIMux *mux.Router, s api.KeyInternalAPI) {
|
||||
internalAPIMux.Handle(PerformClaimKeysPath,
|
||||
httputil.MakeInternalAPI("performClaimKeys", func(req *http.Request) util.JSONResponse {
|
||||
request := api.PerformClaimKeysRequest{}
|
||||
response := api.PerformClaimKeysResponse{}
|
||||
if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
|
||||
return util.MessageResponse(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
s.PerformClaimKeys(req.Context(), &request, &response)
|
||||
return util.JSONResponse{Code: http.StatusOK, JSON: &response}
|
||||
}),
|
||||
internalAPIMux.Handle(
|
||||
PerformClaimKeysPath,
|
||||
httputil.MakeInternalRPCAPI("KeyserverPerformClaimKeys", s.PerformClaimKeys),
|
||||
)
|
||||
internalAPIMux.Handle(PerformDeleteKeysPath,
|
||||
httputil.MakeInternalAPI("performDeleteKeys", func(req *http.Request) util.JSONResponse {
|
||||
request := api.PerformDeleteKeysRequest{}
|
||||
response := api.PerformDeleteKeysResponse{}
|
||||
if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
|
||||
return util.MessageResponse(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
s.PerformDeleteKeys(req.Context(), &request, &response)
|
||||
return util.JSONResponse{Code: http.StatusOK, JSON: &response}
|
||||
}),
|
||||
|
||||
internalAPIMux.Handle(
|
||||
PerformDeleteKeysPath,
|
||||
httputil.MakeInternalRPCAPI("KeyserverPerformDeleteKeys", s.PerformDeleteKeys),
|
||||
)
|
||||
internalAPIMux.Handle(PerformUploadKeysPath,
|
||||
httputil.MakeInternalAPI("performUploadKeys", func(req *http.Request) util.JSONResponse {
|
||||
request := api.PerformUploadKeysRequest{}
|
||||
response := api.PerformUploadKeysResponse{}
|
||||
if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
|
||||
return util.MessageResponse(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
s.PerformUploadKeys(req.Context(), &request, &response)
|
||||
return util.JSONResponse{Code: http.StatusOK, JSON: &response}
|
||||
}),
|
||||
|
||||
internalAPIMux.Handle(
|
||||
PerformUploadKeysPath,
|
||||
httputil.MakeInternalRPCAPI("KeyserverPerformUploadKeys", s.PerformUploadKeys),
|
||||
)
|
||||
internalAPIMux.Handle(PerformUploadDeviceKeysPath,
|
||||
httputil.MakeInternalAPI("performUploadDeviceKeys", func(req *http.Request) util.JSONResponse {
|
||||
request := api.PerformUploadDeviceKeysRequest{}
|
||||
response := api.PerformUploadDeviceKeysResponse{}
|
||||
if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
|
||||
return util.MessageResponse(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
s.PerformUploadDeviceKeys(req.Context(), &request, &response)
|
||||
return util.JSONResponse{Code: http.StatusOK, JSON: &response}
|
||||
}),
|
||||
|
||||
internalAPIMux.Handle(
|
||||
PerformUploadDeviceKeysPath,
|
||||
httputil.MakeInternalRPCAPI("KeyserverPerformUploadDeviceKeys", s.PerformUploadDeviceKeys),
|
||||
)
|
||||
internalAPIMux.Handle(PerformUploadDeviceSignaturesPath,
|
||||
httputil.MakeInternalAPI("performUploadDeviceSignatures", func(req *http.Request) util.JSONResponse {
|
||||
request := api.PerformUploadDeviceSignaturesRequest{}
|
||||
response := api.PerformUploadDeviceSignaturesResponse{}
|
||||
if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
|
||||
return util.MessageResponse(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
s.PerformUploadDeviceSignatures(req.Context(), &request, &response)
|
||||
return util.JSONResponse{Code: http.StatusOK, JSON: &response}
|
||||
}),
|
||||
|
||||
internalAPIMux.Handle(
|
||||
PerformUploadDeviceSignaturesPath,
|
||||
httputil.MakeInternalRPCAPI("KeyserverPerformUploadDeviceSignatures", s.PerformUploadDeviceSignatures),
|
||||
)
|
||||
internalAPIMux.Handle(QueryKeysPath,
|
||||
httputil.MakeInternalAPI("queryKeys", func(req *http.Request) util.JSONResponse {
|
||||
request := api.QueryKeysRequest{}
|
||||
response := api.QueryKeysResponse{}
|
||||
if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
|
||||
return util.MessageResponse(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
s.QueryKeys(req.Context(), &request, &response)
|
||||
return util.JSONResponse{Code: http.StatusOK, JSON: &response}
|
||||
}),
|
||||
|
||||
internalAPIMux.Handle(
|
||||
QueryKeysPath,
|
||||
httputil.MakeInternalRPCAPI("KeyserverQueryKeys", s.QueryKeys),
|
||||
)
|
||||
internalAPIMux.Handle(QueryOneTimeKeysPath,
|
||||
httputil.MakeInternalAPI("queryOneTimeKeys", func(req *http.Request) util.JSONResponse {
|
||||
request := api.QueryOneTimeKeysRequest{}
|
||||
response := api.QueryOneTimeKeysResponse{}
|
||||
if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
|
||||
return util.MessageResponse(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
s.QueryOneTimeKeys(req.Context(), &request, &response)
|
||||
return util.JSONResponse{Code: http.StatusOK, JSON: &response}
|
||||
}),
|
||||
|
||||
internalAPIMux.Handle(
|
||||
QueryOneTimeKeysPath,
|
||||
httputil.MakeInternalRPCAPI("KeyserverQueryOneTimeKeys", s.QueryOneTimeKeys),
|
||||
)
|
||||
internalAPIMux.Handle(QueryDeviceMessagesPath,
|
||||
httputil.MakeInternalAPI("queryDeviceMessages", func(req *http.Request) util.JSONResponse {
|
||||
request := api.QueryDeviceMessagesRequest{}
|
||||
response := api.QueryDeviceMessagesResponse{}
|
||||
if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
|
||||
return util.MessageResponse(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
s.QueryDeviceMessages(req.Context(), &request, &response)
|
||||
return util.JSONResponse{Code: http.StatusOK, JSON: &response}
|
||||
}),
|
||||
|
||||
internalAPIMux.Handle(
|
||||
QueryDeviceMessagesPath,
|
||||
httputil.MakeInternalRPCAPI("KeyserverQueryDeviceMessages", s.QueryDeviceMessages),
|
||||
)
|
||||
internalAPIMux.Handle(QueryKeyChangesPath,
|
||||
httputil.MakeInternalAPI("queryKeyChanges", func(req *http.Request) util.JSONResponse {
|
||||
request := api.QueryKeyChangesRequest{}
|
||||
response := api.QueryKeyChangesResponse{}
|
||||
if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
|
||||
return util.MessageResponse(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
s.QueryKeyChanges(req.Context(), &request, &response)
|
||||
return util.JSONResponse{Code: http.StatusOK, JSON: &response}
|
||||
}),
|
||||
|
||||
internalAPIMux.Handle(
|
||||
QueryKeyChangesPath,
|
||||
httputil.MakeInternalRPCAPI("KeyserverQueryKeyChanges", s.QueryKeyChanges),
|
||||
)
|
||||
internalAPIMux.Handle(QuerySignaturesPath,
|
||||
httputil.MakeInternalAPI("querySignatures", func(req *http.Request) util.JSONResponse {
|
||||
request := api.QuerySignaturesRequest{}
|
||||
response := api.QuerySignaturesResponse{}
|
||||
if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
|
||||
return util.MessageResponse(http.StatusBadRequest, err.Error())
|
||||
}
|
||||
s.QuerySignatures(req.Context(), &request, &response)
|
||||
return util.JSONResponse{Code: http.StatusOK, JSON: &response}
|
||||
}),
|
||||
|
||||
internalAPIMux.Handle(
|
||||
QuerySignaturesPath,
|
||||
httputil.MakeInternalRPCAPI("KeyserverQuerySignatures", s.QuerySignatures),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ import (
|
|||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/lib/pq"
|
||||
|
||||
"github.com/matrix-org/dendrite/internal"
|
||||
"github.com/matrix-org/dendrite/internal/sqlutil"
|
||||
"github.com/matrix-org/dendrite/keyserver/storage/postgres/deltas"
|
||||
|
|
@ -64,7 +66,8 @@ func NewPostgresKeyChangesTable(db *sql.DB) (tables.KeyChanges, error) {
|
|||
// TODO: Remove when we are sure we are not having goose artefacts in the db
|
||||
// This forces an error, which indicates the migration is already applied, since the
|
||||
// column partition was removed from the table
|
||||
err = db.QueryRow("SELECT partition FROM keyserver_key_changes LIMIT 1;").Scan()
|
||||
var count int
|
||||
err = db.QueryRow("SELECT partition FROM keyserver_key_changes LIMIT 1;").Scan(&count)
|
||||
if err == nil {
|
||||
m := sqlutil.NewMigrator(db)
|
||||
m.AddMigrations(sqlutil.Migration{
|
||||
|
|
@ -72,6 +75,16 @@ func NewPostgresKeyChangesTable(db *sql.DB) (tables.KeyChanges, error) {
|
|||
Up: deltas.UpRefactorKeyChanges,
|
||||
})
|
||||
return s, m.Up(context.Background())
|
||||
} else {
|
||||
switch e := err.(type) {
|
||||
case *pq.Error:
|
||||
// ignore undefined_column (42703) errors, as this is expected at this point
|
||||
if e.Code != "42703" {
|
||||
return nil, err
|
||||
}
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,7 +61,8 @@ func NewSqliteKeyChangesTable(db *sql.DB) (tables.KeyChanges, error) {
|
|||
// TODO: Remove when we are sure we are not having goose artefacts in the db
|
||||
// This forces an error, which indicates the migration is already applied, since the
|
||||
// column partition was removed from the table
|
||||
err = db.QueryRow("SELECT partition FROM keyserver_key_changes LIMIT 1;").Scan()
|
||||
var count int
|
||||
err = db.QueryRow("SELECT partition FROM keyserver_key_changes LIMIT 1;").Scan(&count)
|
||||
if err == nil {
|
||||
m := sqlutil.NewMigrator(db)
|
||||
m.AddMigrations(sqlutil.Migration{
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package storage_test
|
|||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/matrix-org/dendrite/keyserver/api"
|
||||
|
|
@ -103,6 +104,9 @@ func TestKeyChangesUpperLimit(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
var dbLock sync.Mutex
|
||||
var deviceArray = []string{"AAA", "another_device"}
|
||||
|
||||
// The purpose of this test is to make sure that the storage layer is generating sequential stream IDs per user,
|
||||
// and that they are returned correctly when querying for device keys.
|
||||
func TestDeviceKeysStreamIDGeneration(t *testing.T) {
|
||||
|
|
@ -169,8 +173,11 @@ func TestDeviceKeysStreamIDGeneration(t *testing.T) {
|
|||
t.Fatalf("Expected StoreLocalDeviceKeys to set StreamID=3 (new key same device) but got %d", msgs[0].StreamID)
|
||||
}
|
||||
|
||||
dbLock.Lock()
|
||||
defer dbLock.Unlock()
|
||||
// Querying for device keys returns the latest stream IDs
|
||||
msgs, err = db.DeviceKeysForUser(ctx, alice, []string{"AAA", "another_device"}, false)
|
||||
msgs, err = db.DeviceKeysForUser(ctx, alice, deviceArray, false)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("DeviceKeysForUser returned error: %s", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ import (
|
|||
"encoding/base64"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
|
@ -180,7 +179,7 @@ func createTempDir(baseDirectory config.Path) (types.Path, error) {
|
|||
if err := os.MkdirAll(baseTmpDir, 0770); err != nil {
|
||||
return "", fmt.Errorf("failed to create base temp dir: %w", err)
|
||||
}
|
||||
tmpDir, err := ioutil.TempDir(baseTmpDir, "")
|
||||
tmpDir, err := os.MkdirTemp(baseTmpDir, "")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to create temp dir: %w", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"mime"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
|
@ -695,7 +694,7 @@ func (r *downloadRequest) GetContentLengthAndReader(contentLengthHeader string,
|
|||
|
||||
// We successfully parsed the Content-Length, so we'll return a limited
|
||||
// reader that restricts us to reading only up to this size.
|
||||
reader = ioutil.NopCloser(io.LimitReader(*body, parsedLength))
|
||||
reader = io.NopCloser(io.LimitReader(*body, parsedLength))
|
||||
contentLength = parsedLength
|
||||
} else {
|
||||
// Content-Length header is missing. If we have a maximum file size
|
||||
|
|
@ -704,7 +703,7 @@ func (r *downloadRequest) GetContentLengthAndReader(contentLengthHeader string,
|
|||
// ultimately it will get rewritten later when the temp file is written
|
||||
// to disk.
|
||||
if maxFileSizeBytes > 0 {
|
||||
reader = ioutil.NopCloser(io.LimitReader(*body, int64(maxFileSizeBytes)))
|
||||
reader = io.NopCloser(io.LimitReader(*body, int64(maxFileSizeBytes)))
|
||||
}
|
||||
contentLength = 0
|
||||
}
|
||||
|
|
|
|||
|
|
@ -149,6 +149,9 @@ func makeDownloadAPI(
|
|||
}
|
||||
}
|
||||
|
||||
// Cache media for at least one day.
|
||||
w.Header().Set("Cache-Control", "public,max-age=86400,s-maxage=86400")
|
||||
|
||||
Download(
|
||||
w,
|
||||
req,
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ type InputRoomEventsAPI interface {
|
|||
ctx context.Context,
|
||||
req *InputRoomEventsRequest,
|
||||
res *InputRoomEventsResponse,
|
||||
)
|
||||
) error
|
||||
}
|
||||
|
||||
// Query the latest events and state for a room from the room server.
|
||||
|
|
@ -97,6 +97,14 @@ type SyncRoomserverAPI interface {
|
|||
req *PerformBackfillRequest,
|
||||
res *PerformBackfillResponse,
|
||||
) error
|
||||
|
||||
// QueryMembershipAtEvent queries the memberships at the given events.
|
||||
// Returns a map from eventID to a slice of gomatrixserverlib.HeaderedEvent.
|
||||
QueryMembershipAtEvent(
|
||||
ctx context.Context,
|
||||
request *QueryMembershipAtEventRequest,
|
||||
response *QueryMembershipAtEventResponse,
|
||||
) error
|
||||
}
|
||||
|
||||
type AppserviceRoomserverAPI interface {
|
||||
|
|
@ -139,15 +147,15 @@ type ClientRoomserverAPI interface {
|
|||
GetAliasesForRoomID(ctx context.Context, req *GetAliasesForRoomIDRequest, res *GetAliasesForRoomIDResponse) error
|
||||
|
||||
// PerformRoomUpgrade upgrades a room to a newer version
|
||||
PerformRoomUpgrade(ctx context.Context, req *PerformRoomUpgradeRequest, resp *PerformRoomUpgradeResponse)
|
||||
PerformAdminEvacuateRoom(ctx context.Context, req *PerformAdminEvacuateRoomRequest, res *PerformAdminEvacuateRoomResponse)
|
||||
PerformAdminEvacuateUser(ctx context.Context, req *PerformAdminEvacuateUserRequest, res *PerformAdminEvacuateUserResponse)
|
||||
PerformPeek(ctx context.Context, req *PerformPeekRequest, res *PerformPeekResponse)
|
||||
PerformUnpeek(ctx context.Context, req *PerformUnpeekRequest, res *PerformUnpeekResponse)
|
||||
PerformRoomUpgrade(ctx context.Context, req *PerformRoomUpgradeRequest, resp *PerformRoomUpgradeResponse) error
|
||||
PerformAdminEvacuateRoom(ctx context.Context, req *PerformAdminEvacuateRoomRequest, res *PerformAdminEvacuateRoomResponse) error
|
||||
PerformAdminEvacuateUser(ctx context.Context, req *PerformAdminEvacuateUserRequest, res *PerformAdminEvacuateUserResponse) error
|
||||
PerformPeek(ctx context.Context, req *PerformPeekRequest, res *PerformPeekResponse) error
|
||||
PerformUnpeek(ctx context.Context, req *PerformUnpeekRequest, res *PerformUnpeekResponse) error
|
||||
PerformInvite(ctx context.Context, req *PerformInviteRequest, res *PerformInviteResponse) error
|
||||
PerformJoin(ctx context.Context, req *PerformJoinRequest, res *PerformJoinResponse)
|
||||
PerformJoin(ctx context.Context, req *PerformJoinRequest, res *PerformJoinResponse) error
|
||||
PerformLeave(ctx context.Context, req *PerformLeaveRequest, res *PerformLeaveResponse) error
|
||||
PerformPublish(ctx context.Context, req *PerformPublishRequest, res *PerformPublishResponse)
|
||||
PerformPublish(ctx context.Context, req *PerformPublishRequest, res *PerformPublishResponse) error
|
||||
// PerformForget forgets a rooms history for a specific user
|
||||
PerformForget(ctx context.Context, req *PerformForgetRequest, resp *PerformForgetResponse) error
|
||||
SetRoomAlias(ctx context.Context, req *SetRoomAliasRequest, res *SetRoomAliasResponse) error
|
||||
|
|
@ -158,7 +166,7 @@ type UserRoomserverAPI interface {
|
|||
QueryLatestEventsAndStateAPI
|
||||
QueryCurrentState(ctx context.Context, req *QueryCurrentStateRequest, res *QueryCurrentStateResponse) error
|
||||
QueryMembershipsForRoom(ctx context.Context, req *QueryMembershipsForRoomRequest, res *QueryMembershipsForRoomResponse) error
|
||||
PerformAdminEvacuateUser(ctx context.Context, req *PerformAdminEvacuateUserRequest, res *PerformAdminEvacuateUserResponse)
|
||||
PerformAdminEvacuateUser(ctx context.Context, req *PerformAdminEvacuateUserRequest, res *PerformAdminEvacuateUserResponse) error
|
||||
}
|
||||
|
||||
type FederationRoomserverAPI interface {
|
||||
|
|
|
|||
|
|
@ -35,9 +35,10 @@ func (t *RoomserverInternalAPITrace) InputRoomEvents(
|
|||
ctx context.Context,
|
||||
req *InputRoomEventsRequest,
|
||||
res *InputRoomEventsResponse,
|
||||
) {
|
||||
t.Impl.InputRoomEvents(ctx, req, res)
|
||||
util.GetLogger(ctx).Infof("InputRoomEvents req=%+v res=%+v", js(req), js(res))
|
||||
) error {
|
||||
err := t.Impl.InputRoomEvents(ctx, req, res)
|
||||
util.GetLogger(ctx).WithError(err).Infof("InputRoomEvents req=%+v res=%+v", js(req), js(res))
|
||||
return err
|
||||
}
|
||||
|
||||
func (t *RoomserverInternalAPITrace) PerformInvite(
|
||||
|
|
@ -45,44 +46,49 @@ func (t *RoomserverInternalAPITrace) PerformInvite(
|
|||
req *PerformInviteRequest,
|
||||
res *PerformInviteResponse,
|
||||
) error {
|
||||
util.GetLogger(ctx).Infof("PerformInvite req=%+v res=%+v", js(req), js(res))
|
||||
return t.Impl.PerformInvite(ctx, req, res)
|
||||
err := t.Impl.PerformInvite(ctx, req, res)
|
||||
util.GetLogger(ctx).WithError(err).Infof("PerformInvite req=%+v res=%+v", js(req), js(res))
|
||||
return err
|
||||
}
|
||||
|
||||
func (t *RoomserverInternalAPITrace) PerformPeek(
|
||||
ctx context.Context,
|
||||
req *PerformPeekRequest,
|
||||
res *PerformPeekResponse,
|
||||
) {
|
||||
t.Impl.PerformPeek(ctx, req, res)
|
||||
util.GetLogger(ctx).Infof("PerformPeek req=%+v res=%+v", js(req), js(res))
|
||||
) error {
|
||||
err := t.Impl.PerformPeek(ctx, req, res)
|
||||
util.GetLogger(ctx).WithError(err).Infof("PerformPeek req=%+v res=%+v", js(req), js(res))
|
||||
return err
|
||||
}
|
||||
|
||||
func (t *RoomserverInternalAPITrace) PerformUnpeek(
|
||||
ctx context.Context,
|
||||
req *PerformUnpeekRequest,
|
||||
res *PerformUnpeekResponse,
|
||||
) {
|
||||
t.Impl.PerformUnpeek(ctx, req, res)
|
||||
util.GetLogger(ctx).Infof("PerformUnpeek req=%+v res=%+v", js(req), js(res))
|
||||
) error {
|
||||
err := t.Impl.PerformUnpeek(ctx, req, res)
|
||||
util.GetLogger(ctx).WithError(err).Infof("PerformUnpeek req=%+v res=%+v", js(req), js(res))
|
||||
return err
|
||||
}
|
||||
|
||||
func (t *RoomserverInternalAPITrace) PerformRoomUpgrade(
|
||||
ctx context.Context,
|
||||
req *PerformRoomUpgradeRequest,
|
||||
res *PerformRoomUpgradeResponse,
|
||||
) {
|
||||
t.Impl.PerformRoomUpgrade(ctx, req, res)
|
||||
util.GetLogger(ctx).Infof("PerformRoomUpgrade req=%+v res=%+v", js(req), js(res))
|
||||
) error {
|
||||
err := t.Impl.PerformRoomUpgrade(ctx, req, res)
|
||||
util.GetLogger(ctx).WithError(err).Infof("PerformRoomUpgrade req=%+v res=%+v", js(req), js(res))
|
||||
return err
|
||||
}
|
||||
|
||||
func (t *RoomserverInternalAPITrace) PerformJoin(
|
||||
ctx context.Context,
|
||||
req *PerformJoinRequest,
|
||||
res *PerformJoinResponse,
|
||||
) {
|
||||
t.Impl.PerformJoin(ctx, req, res)
|
||||
util.GetLogger(ctx).Infof("PerformJoin req=%+v res=%+v", js(req), js(res))
|
||||
) error {
|
||||
err := t.Impl.PerformJoin(ctx, req, res)
|
||||
util.GetLogger(ctx).WithError(err).Infof("PerformJoin req=%+v res=%+v", js(req), js(res))
|
||||
return err
|
||||
}
|
||||
|
||||
func (t *RoomserverInternalAPITrace) PerformLeave(
|
||||
|
|
@ -99,27 +105,30 @@ func (t *RoomserverInternalAPITrace) PerformPublish(
|
|||
ctx context.Context,
|
||||
req *PerformPublishRequest,
|
||||
res *PerformPublishResponse,
|
||||
) {
|
||||
t.Impl.PerformPublish(ctx, req, res)
|
||||
util.GetLogger(ctx).Infof("PerformPublish req=%+v res=%+v", js(req), js(res))
|
||||
) error {
|
||||
err := t.Impl.PerformPublish(ctx, req, res)
|
||||
util.GetLogger(ctx).WithError(err).Infof("PerformPublish req=%+v res=%+v", js(req), js(res))
|
||||
return err
|
||||
}
|
||||
|
||||
func (t *RoomserverInternalAPITrace) PerformAdminEvacuateRoom(
|
||||
ctx context.Context,
|
||||
req *PerformAdminEvacuateRoomRequest,
|
||||
res *PerformAdminEvacuateRoomResponse,
|
||||
) {
|
||||
t.Impl.PerformAdminEvacuateRoom(ctx, req, res)
|
||||
util.GetLogger(ctx).Infof("PerformAdminEvacuateRoom req=%+v res=%+v", js(req), js(res))
|
||||
) error {
|
||||
err := t.Impl.PerformAdminEvacuateRoom(ctx, req, res)
|
||||
util.GetLogger(ctx).WithError(err).Infof("PerformAdminEvacuateRoom req=%+v res=%+v", js(req), js(res))
|
||||
return err
|
||||
}
|
||||
|
||||
func (t *RoomserverInternalAPITrace) PerformAdminEvacuateUser(
|
||||
ctx context.Context,
|
||||
req *PerformAdminEvacuateUserRequest,
|
||||
res *PerformAdminEvacuateUserResponse,
|
||||
) {
|
||||
t.Impl.PerformAdminEvacuateUser(ctx, req, res)
|
||||
util.GetLogger(ctx).Infof("PerformAdminEvacuateUser req=%+v res=%+v", js(req), js(res))
|
||||
) error {
|
||||
err := t.Impl.PerformAdminEvacuateUser(ctx, req, res)
|
||||
util.GetLogger(ctx).WithError(err).Infof("PerformAdminEvacuateUser req=%+v res=%+v", js(req), js(res))
|
||||
return err
|
||||
}
|
||||
|
||||
func (t *RoomserverInternalAPITrace) PerformInboundPeek(
|
||||
|
|
@ -128,7 +137,7 @@ func (t *RoomserverInternalAPITrace) PerformInboundPeek(
|
|||
res *PerformInboundPeekResponse,
|
||||
) error {
|
||||
err := t.Impl.PerformInboundPeek(ctx, req, res)
|
||||
util.GetLogger(ctx).Infof("PerformInboundPeek req=%+v res=%+v", js(req), js(res))
|
||||
util.GetLogger(ctx).WithError(err).Infof("PerformInboundPeek req=%+v res=%+v", js(req), js(res))
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
@ -373,6 +382,16 @@ func (t *RoomserverInternalAPITrace) QueryRestrictedJoinAllowed(
|
|||
return err
|
||||
}
|
||||
|
||||
func (t *RoomserverInternalAPITrace) QueryMembershipAtEvent(
|
||||
ctx context.Context,
|
||||
request *QueryMembershipAtEventRequest,
|
||||
response *QueryMembershipAtEventResponse,
|
||||
) error {
|
||||
err := t.Impl.QueryMembershipAtEvent(ctx, request, response)
|
||||
util.GetLogger(ctx).WithError(err).Infof("QueryMembershipAtEvent req=%+v res=%+v", js(request), js(response))
|
||||
return err
|
||||
}
|
||||
|
||||
func js(thing interface{}) string {
|
||||
b, err := json.Marshal(thing)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -427,3 +427,17 @@ func (r *QueryCurrentStateResponse) UnmarshalJSON(data []byte) error {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// QueryMembershipAtEventRequest requests the membership events for a user
|
||||
// for a list of eventIDs.
|
||||
type QueryMembershipAtEventRequest struct {
|
||||
RoomID string
|
||||
EventIDs []string
|
||||
UserID string
|
||||
}
|
||||
|
||||
// QueryMembershipAtEventResponse is the response to QueryMembershipAtEventRequest.
|
||||
type QueryMembershipAtEventResponse struct {
|
||||
// Memberships is a map from eventID to a list of events (if any).
|
||||
Memberships map[string][]*gomatrixserverlib.HeaderedEvent `json:"memberships"`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -90,7 +90,9 @@ func SendInputRoomEvents(
|
|||
Asynchronous: async,
|
||||
}
|
||||
var response InputRoomEventsResponse
|
||||
rsAPI.InputRoomEvents(ctx, &request, &response)
|
||||
if err := rsAPI.InputRoomEvents(ctx, &request, &response); err != nil {
|
||||
return err
|
||||
}
|
||||
return response.Err()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -50,14 +50,14 @@ func CheckForSoftFail(
|
|||
if err != nil {
|
||||
return false, fmt.Errorf("db.RoomNID: %w", err)
|
||||
}
|
||||
if roomInfo == nil || roomInfo.IsStub {
|
||||
if roomInfo == nil || roomInfo.IsStub() {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// Then get the state entries for the current state snapshot.
|
||||
// We'll use this to check if the event is allowed right now.
|
||||
roomState := state.NewStateResolution(db, roomInfo)
|
||||
authStateEntries, err = roomState.LoadStateAtSnapshot(ctx, roomInfo.StateSnapshotNID)
|
||||
authStateEntries, err = roomState.LoadStateAtSnapshot(ctx, roomInfo.StateSnapshotNID())
|
||||
if err != nil {
|
||||
return true, fmt.Errorf("roomState.LoadStateAtSnapshot: %w", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -208,6 +208,12 @@ func StateBeforeEvent(ctx context.Context, db storage.Database, info *types.Room
|
|||
return roomState.LoadCombinedStateAfterEvents(ctx, prevState)
|
||||
}
|
||||
|
||||
func MembershipAtEvent(ctx context.Context, db storage.Database, info *types.RoomInfo, eventIDs []string, stateKeyNID types.EventStateKeyNID) (map[string][]types.StateEntry, error) {
|
||||
roomState := state.NewStateResolution(db, info)
|
||||
// Fetch the state as it was when this event was fired
|
||||
return roomState.LoadMembershipAtEvent(ctx, eventIDs, stateKeyNID)
|
||||
}
|
||||
|
||||
func LoadEvents(
|
||||
ctx context.Context, db storage.Database, eventNIDs []types.EventNID,
|
||||
) ([]*gomatrixserverlib.Event, error) {
|
||||
|
|
@ -409,7 +415,7 @@ func QueryLatestEventsAndState(
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if roomInfo == nil || roomInfo.IsStub {
|
||||
if roomInfo == nil || roomInfo.IsStub() {
|
||||
response.RoomExists = false
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,11 @@ import (
|
|||
|
||||
"github.com/Arceliar/phony"
|
||||
"github.com/getsentry/sentry-go"
|
||||
"github.com/matrix-org/gomatrixserverlib"
|
||||
"github.com/nats-io/nats.go"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
fedapi "github.com/matrix-org/dendrite/federationapi/api"
|
||||
"github.com/matrix-org/dendrite/roomserver/acls"
|
||||
"github.com/matrix-org/dendrite/roomserver/api"
|
||||
|
|
@ -35,10 +40,6 @@ import (
|
|||
"github.com/matrix-org/dendrite/setup/config"
|
||||
"github.com/matrix-org/dendrite/setup/jetstream"
|
||||
"github.com/matrix-org/dendrite/setup/process"
|
||||
"github.com/matrix-org/gomatrixserverlib"
|
||||
"github.com/nats-io/nats.go"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// Inputer is responsible for consuming from the roomserver input
|
||||
|
|
@ -60,9 +61,9 @@ import (
|
|||
// per-room durable consumers will only progress through the stream
|
||||
// as events are processed.
|
||||
//
|
||||
// A BC * -> positions of each consumer (* = ephemeral)
|
||||
// ⌄ ⌄⌄ ⌄
|
||||
// ABAABCAABCAA -> newest (letter = subject for each message)
|
||||
// A BC * -> positions of each consumer (* = ephemeral)
|
||||
// ⌄ ⌄⌄ ⌄
|
||||
// ABAABCAABCAA -> newest (letter = subject for each message)
|
||||
//
|
||||
// In this example, A is still processing an event but has two
|
||||
// pending events to process afterwards. Both B and C are caught
|
||||
|
|
@ -336,18 +337,18 @@ func (r *Inputer) InputRoomEvents(
|
|||
ctx context.Context,
|
||||
request *api.InputRoomEventsRequest,
|
||||
response *api.InputRoomEventsResponse,
|
||||
) {
|
||||
) error {
|
||||
// Queue up the event into the roomserver.
|
||||
replySub, err := r.queueInputRoomEvents(ctx, request)
|
||||
if err != nil {
|
||||
response.ErrMsg = err.Error()
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
// If we aren't waiting for synchronous responses then we can
|
||||
// give up here, there is nothing further to do.
|
||||
if replySub == nil {
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
// Otherwise, we'll want to sit and wait for the responses
|
||||
|
|
@ -359,12 +360,14 @@ func (r *Inputer) InputRoomEvents(
|
|||
msg, err := replySub.NextMsgWithContext(ctx)
|
||||
if err != nil {
|
||||
response.ErrMsg = err.Error()
|
||||
return
|
||||
return nil
|
||||
}
|
||||
if len(msg.Data) > 0 {
|
||||
response.ErrMsg = string(msg.Data)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var roomserverInputBackpressure = prometheus.NewGaugeVec(
|
||||
|
|
|
|||
|
|
@ -299,7 +299,7 @@ func (r *Inputer) processRoomEvent(
|
|||
// allowed at the time, and also to get the history visibility. We won't
|
||||
// bother doing this if the event was already rejected as it just ends up
|
||||
// burning CPU time.
|
||||
historyVisibility := gomatrixserverlib.HistoryVisibilityJoined // Default to restrictive.
|
||||
historyVisibility := gomatrixserverlib.HistoryVisibilityShared // Default to shared.
|
||||
if rejectionErr == nil && !isRejected && !softfail {
|
||||
var err error
|
||||
historyVisibility, rejectionErr, err = r.processStateBefore(ctx, input, missingPrev)
|
||||
|
|
@ -429,7 +429,7 @@ func (r *Inputer) processStateBefore(
|
|||
input *api.InputRoomEvent,
|
||||
missingPrev bool,
|
||||
) (historyVisibility gomatrixserverlib.HistoryVisibility, rejectionErr error, err error) {
|
||||
historyVisibility = gomatrixserverlib.HistoryVisibilityJoined // Default to restrictive.
|
||||
historyVisibility = gomatrixserverlib.HistoryVisibilityShared // Default to shared.
|
||||
event := input.Event.Unwrap()
|
||||
isCreateEvent := event.Type() == gomatrixserverlib.MRoomCreate && event.StateKeyEquals("")
|
||||
var stateBeforeEvent []*gomatrixserverlib.Event
|
||||
|
|
|
|||
|
|
@ -20,32 +20,32 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/matrix-org/gomatrixserverlib"
|
||||
"github.com/matrix-org/util"
|
||||
"github.com/opentracing/opentracing-go"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/matrix-org/dendrite/internal/sqlutil"
|
||||
"github.com/matrix-org/dendrite/roomserver/api"
|
||||
"github.com/matrix-org/dendrite/roomserver/state"
|
||||
"github.com/matrix-org/dendrite/roomserver/storage/shared"
|
||||
"github.com/matrix-org/dendrite/roomserver/types"
|
||||
"github.com/matrix-org/gomatrixserverlib"
|
||||
"github.com/matrix-org/util"
|
||||
"github.com/opentracing/opentracing-go"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// updateLatestEvents updates the list of latest events for this room in the database and writes the
|
||||
// event to the output log.
|
||||
// The latest events are the events that aren't referenced by another event in the database:
|
||||
//
|
||||
// Time goes down the page. 1 is the m.room.create event (root).
|
||||
//
|
||||
// 1 After storing 1 the latest events are {1}
|
||||
// | After storing 2 the latest events are {2}
|
||||
// 2 After storing 3 the latest events are {3}
|
||||
// / \ After storing 4 the latest events are {3,4}
|
||||
// 3 4 After storing 5 the latest events are {5,4}
|
||||
// | | After storing 6 the latest events are {5,6}
|
||||
// 5 6 <--- latest After storing 7 the latest events are {6,7}
|
||||
// |
|
||||
// 7 <----- latest
|
||||
// Time goes down the page. 1 is the m.room.create event (root).
|
||||
// 1 After storing 1 the latest events are {1}
|
||||
// | After storing 2 the latest events are {2}
|
||||
// 2 After storing 3 the latest events are {3}
|
||||
// / \ After storing 4 the latest events are {3,4}
|
||||
// 3 4 After storing 5 the latest events are {5,4}
|
||||
// | | After storing 6 the latest events are {5,6}
|
||||
// 5 6 <--- latest After storing 7 the latest events are {6,7}
|
||||
// |
|
||||
// 7 <----- latest
|
||||
//
|
||||
// Can only be called once at a time
|
||||
func (r *Inputer) updateLatestEvents(
|
||||
|
|
|
|||
|
|
@ -326,8 +326,10 @@ func (t *missingStateReq) lookupStateAfterEvent(ctx context.Context, roomVersion
|
|||
return respState, true, nil
|
||||
}
|
||||
|
||||
logrus.WithContext(ctx).Warnf("State for event %s not available locally, falling back to federation (via %d servers)", eventID, len(t.servers))
|
||||
respState, err := t.lookupStateBeforeEvent(ctx, roomVersion, roomID, eventID)
|
||||
if err != nil {
|
||||
logrus.WithContext(ctx).WithError(err).Errorf("Failed to look up state before event %s", eventID)
|
||||
return nil, false, fmt.Errorf("t.lookupStateBeforeEvent: %w", err)
|
||||
}
|
||||
|
||||
|
|
@ -339,6 +341,7 @@ func (t *missingStateReq) lookupStateAfterEvent(ctx context.Context, roomVersion
|
|||
case nil:
|
||||
// do nothing
|
||||
default:
|
||||
logrus.WithContext(ctx).WithError(err).Errorf("Failed to look up event %s", eventID)
|
||||
return nil, false, fmt.Errorf("t.lookupEvent: %w", err)
|
||||
}
|
||||
h = t.cacheAndReturn(h)
|
||||
|
|
@ -375,11 +378,7 @@ func (t *missingStateReq) lookupStateAfterEventLocally(ctx context.Context, room
|
|||
defer span.Finish()
|
||||
|
||||
var res parsedRespState
|
||||
roomInfo, err := t.db.RoomInfo(ctx, roomID)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
roomState := state.NewStateResolution(t.db, roomInfo)
|
||||
roomState := state.NewStateResolution(t.db, t.roomInfo)
|
||||
stateAtEvents, err := t.db.StateAtEventIDs(ctx, []string{eventID})
|
||||
if err != nil {
|
||||
util.GetLogger(ctx).WithField("room_id", roomID).WithError(err).Warnf("failed to get state after %s locally", eventID)
|
||||
|
|
@ -666,9 +665,22 @@ func (t *missingStateReq) lookupMissingStateViaStateIDs(ctx context.Context, roo
|
|||
|
||||
util.GetLogger(ctx).WithField("room_id", roomID).Infof("lookupMissingStateViaStateIDs %s", eventID)
|
||||
// fetch the state event IDs at the time of the event
|
||||
stateIDs, err := t.federation.LookupStateIDs(ctx, t.origin, roomID, eventID)
|
||||
var stateIDs gomatrixserverlib.RespStateIDs
|
||||
var err error
|
||||
count := 0
|
||||
totalctx, totalcancel := context.WithTimeout(ctx, time.Minute*5)
|
||||
for _, serverName := range t.servers {
|
||||
reqctx, reqcancel := context.WithTimeout(totalctx, time.Second*20)
|
||||
stateIDs, err = t.federation.LookupStateIDs(reqctx, serverName, roomID, eventID)
|
||||
reqcancel()
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
count++
|
||||
}
|
||||
totalcancel()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("t.federation.LookupStateIDs tried %d server(s), last error: %w", count, err)
|
||||
}
|
||||
// work out which auth/state IDs are missing
|
||||
wantIDs := append(stateIDs.StateEventIDs, stateIDs.AuthEventIDs...)
|
||||
|
|
@ -754,9 +766,8 @@ func (t *missingStateReq) lookupMissingStateViaStateIDs(ctx context.Context, roo
|
|||
|
||||
// Define what we'll do in order to fetch the missing event ID.
|
||||
fetch := func(missingEventID string) {
|
||||
var h *gomatrixserverlib.Event
|
||||
h, err = t.lookupEvent(ctx, roomVersion, roomID, missingEventID, false)
|
||||
switch err.(type) {
|
||||
h, herr := t.lookupEvent(ctx, roomVersion, roomID, missingEventID, false)
|
||||
switch herr.(type) {
|
||||
case verifySigError:
|
||||
return
|
||||
case nil:
|
||||
|
|
@ -765,7 +776,7 @@ func (t *missingStateReq) lookupMissingStateViaStateIDs(ctx context.Context, roo
|
|||
util.GetLogger(ctx).WithFields(logrus.Fields{
|
||||
"event_id": missingEventID,
|
||||
"room_id": roomID,
|
||||
}).Warn("Failed to fetch missing event")
|
||||
}).WithError(herr).Warn("Failed to fetch missing event")
|
||||
return
|
||||
}
|
||||
haveEventsMutex.Lock()
|
||||
|
|
|
|||
|
|
@ -43,21 +43,21 @@ func (r *Admin) PerformAdminEvacuateRoom(
|
|||
ctx context.Context,
|
||||
req *api.PerformAdminEvacuateRoomRequest,
|
||||
res *api.PerformAdminEvacuateRoomResponse,
|
||||
) {
|
||||
) error {
|
||||
roomInfo, err := r.DB.RoomInfo(ctx, req.RoomID)
|
||||
if err != nil {
|
||||
res.Error = &api.PerformError{
|
||||
Code: api.PerformErrorBadRequest,
|
||||
Msg: fmt.Sprintf("r.DB.RoomInfo: %s", err),
|
||||
}
|
||||
return
|
||||
return nil
|
||||
}
|
||||
if roomInfo == nil || roomInfo.IsStub {
|
||||
if roomInfo == nil || roomInfo.IsStub() {
|
||||
res.Error = &api.PerformError{
|
||||
Code: api.PerformErrorNoRoom,
|
||||
Msg: fmt.Sprintf("Room %s not found", req.RoomID),
|
||||
}
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
memberNIDs, err := r.DB.GetMembershipEventNIDsForRoom(ctx, roomInfo.RoomNID, true, true)
|
||||
|
|
@ -66,7 +66,7 @@ func (r *Admin) PerformAdminEvacuateRoom(
|
|||
Code: api.PerformErrorBadRequest,
|
||||
Msg: fmt.Sprintf("r.DB.GetMembershipEventNIDsForRoom: %s", err),
|
||||
}
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
memberEvents, err := r.DB.Events(ctx, memberNIDs)
|
||||
|
|
@ -75,7 +75,7 @@ func (r *Admin) PerformAdminEvacuateRoom(
|
|||
Code: api.PerformErrorBadRequest,
|
||||
Msg: fmt.Sprintf("r.DB.Events: %s", err),
|
||||
}
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
inputEvents := make([]api.InputRoomEvent, 0, len(memberEvents))
|
||||
|
|
@ -89,7 +89,7 @@ func (r *Admin) PerformAdminEvacuateRoom(
|
|||
Code: api.PerformErrorBadRequest,
|
||||
Msg: fmt.Sprintf("r.Queryer.QueryLatestEventsAndState: %s", err),
|
||||
}
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
prevEvents := latestRes.LatestEvents
|
||||
|
|
@ -104,7 +104,7 @@ func (r *Admin) PerformAdminEvacuateRoom(
|
|||
Code: api.PerformErrorBadRequest,
|
||||
Msg: fmt.Sprintf("json.Unmarshal: %s", err),
|
||||
}
|
||||
return
|
||||
return nil
|
||||
}
|
||||
memberContent.Membership = gomatrixserverlib.Leave
|
||||
|
||||
|
|
@ -122,7 +122,7 @@ func (r *Admin) PerformAdminEvacuateRoom(
|
|||
Code: api.PerformErrorBadRequest,
|
||||
Msg: fmt.Sprintf("json.Marshal: %s", err),
|
||||
}
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
eventsNeeded, err := gomatrixserverlib.StateNeededForEventBuilder(fledglingEvent)
|
||||
|
|
@ -131,7 +131,7 @@ func (r *Admin) PerformAdminEvacuateRoom(
|
|||
Code: api.PerformErrorBadRequest,
|
||||
Msg: fmt.Sprintf("gomatrixserverlib.StateNeededForEventBuilder: %s", err),
|
||||
}
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
event, err := eventutil.BuildEvent(ctx, fledglingEvent, r.Cfg.Matrix, time.Now(), &eventsNeeded, latestRes)
|
||||
|
|
@ -140,7 +140,7 @@ func (r *Admin) PerformAdminEvacuateRoom(
|
|||
Code: api.PerformErrorBadRequest,
|
||||
Msg: fmt.Sprintf("eventutil.BuildEvent: %s", err),
|
||||
}
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
inputEvents = append(inputEvents, api.InputRoomEvent{
|
||||
|
|
@ -160,28 +160,28 @@ func (r *Admin) PerformAdminEvacuateRoom(
|
|||
Asynchronous: true,
|
||||
}
|
||||
inputRes := &api.InputRoomEventsResponse{}
|
||||
r.Inputer.InputRoomEvents(ctx, inputReq, inputRes)
|
||||
return r.Inputer.InputRoomEvents(ctx, inputReq, inputRes)
|
||||
}
|
||||
|
||||
func (r *Admin) PerformAdminEvacuateUser(
|
||||
ctx context.Context,
|
||||
req *api.PerformAdminEvacuateUserRequest,
|
||||
res *api.PerformAdminEvacuateUserResponse,
|
||||
) {
|
||||
) error {
|
||||
_, domain, err := gomatrixserverlib.SplitID('@', req.UserID)
|
||||
if err != nil {
|
||||
res.Error = &api.PerformError{
|
||||
Code: api.PerformErrorBadRequest,
|
||||
Msg: fmt.Sprintf("Malformed user ID: %s", err),
|
||||
}
|
||||
return
|
||||
return nil
|
||||
}
|
||||
if domain != r.Cfg.Matrix.ServerName {
|
||||
res.Error = &api.PerformError{
|
||||
Code: api.PerformErrorBadRequest,
|
||||
Msg: "Can only evacuate local users using this endpoint",
|
||||
}
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
roomIDs, err := r.DB.GetRoomsByMembership(ctx, req.UserID, gomatrixserverlib.Join)
|
||||
|
|
@ -190,7 +190,7 @@ func (r *Admin) PerformAdminEvacuateUser(
|
|||
Code: api.PerformErrorBadRequest,
|
||||
Msg: fmt.Sprintf("r.DB.GetRoomsByMembership: %s", err),
|
||||
}
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
inviteRoomIDs, err := r.DB.GetRoomsByMembership(ctx, req.UserID, gomatrixserverlib.Invite)
|
||||
|
|
@ -199,7 +199,7 @@ func (r *Admin) PerformAdminEvacuateUser(
|
|||
Code: api.PerformErrorBadRequest,
|
||||
Msg: fmt.Sprintf("r.DB.GetRoomsByMembership: %s", err),
|
||||
}
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, roomID := range append(roomIDs, inviteRoomIDs...) {
|
||||
|
|
@ -214,7 +214,7 @@ func (r *Admin) PerformAdminEvacuateUser(
|
|||
Code: api.PerformErrorBadRequest,
|
||||
Msg: fmt.Sprintf("r.Leaver.PerformLeave: %s", err),
|
||||
}
|
||||
return
|
||||
return nil
|
||||
}
|
||||
if len(outputEvents) == 0 {
|
||||
continue
|
||||
|
|
@ -224,9 +224,10 @@ func (r *Admin) PerformAdminEvacuateUser(
|
|||
Code: api.PerformErrorBadRequest,
|
||||
Msg: fmt.Sprintf("r.Inputer.WriteOutputEvents: %s", err),
|
||||
}
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
res.Affected = append(res.Affected, roomID)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,10 @@ import (
|
|||
"fmt"
|
||||
|
||||
"github.com/getsentry/sentry-go"
|
||||
"github.com/matrix-org/gomatrixserverlib"
|
||||
"github.com/matrix-org/util"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
federationAPI "github.com/matrix-org/dendrite/federationapi/api"
|
||||
"github.com/matrix-org/dendrite/internal/eventutil"
|
||||
"github.com/matrix-org/dendrite/roomserver/api"
|
||||
|
|
@ -26,9 +30,6 @@ import (
|
|||
"github.com/matrix-org/dendrite/roomserver/internal/helpers"
|
||||
"github.com/matrix-org/dendrite/roomserver/storage"
|
||||
"github.com/matrix-org/dendrite/roomserver/types"
|
||||
"github.com/matrix-org/gomatrixserverlib"
|
||||
"github.com/matrix-org/util"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// the max number of servers to backfill from per request. If this is too low we may fail to backfill when
|
||||
|
|
@ -73,7 +74,7 @@ func (r *Backfiller) PerformBackfill(
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if info == nil || info.IsStub {
|
||||
if info == nil || info.IsStub() {
|
||||
return fmt.Errorf("PerformBackfill: missing room info for room %s", request.RoomID)
|
||||
}
|
||||
|
||||
|
|
@ -106,7 +107,7 @@ func (r *Backfiller) backfillViaFederation(ctx context.Context, req *api.Perform
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if info == nil || info.IsStub {
|
||||
if info == nil || info.IsStub() {
|
||||
return fmt.Errorf("backfillViaFederation: missing room info for room %s", req.RoomID)
|
||||
}
|
||||
requester := newBackfillRequester(r.DB, r.FSAPI, r.ServerName, req.BackwardsExtremities, r.PreferServers)
|
||||
|
|
@ -434,7 +435,7 @@ FindSuccessor:
|
|||
logrus.WithError(err).WithField("room_id", roomID).Error("ServersAtEvent: failed to get RoomInfo for room")
|
||||
return nil
|
||||
}
|
||||
if info == nil || info.IsStub {
|
||||
if info == nil || info.IsStub() {
|
||||
logrus.WithField("room_id", roomID).Error("ServersAtEvent: failed to get RoomInfo for room, room is missing")
|
||||
return nil
|
||||
}
|
||||
|
|
@ -522,8 +523,9 @@ func (b *backfillRequester) ProvideEvents(roomVer gomatrixserverlib.RoomVersion,
|
|||
}
|
||||
|
||||
// joinEventsFromHistoryVisibility returns all CURRENTLY joined members if our server can read the room history
|
||||
//
|
||||
// TODO: Long term we probably want a history_visibility table which stores eventNID | visibility_enum so we can just
|
||||
// pull all events and then filter by that table.
|
||||
// pull all events and then filter by that table.
|
||||
func joinEventsFromHistoryVisibility(
|
||||
ctx context.Context, db storage.Database, roomID string, stateEntries []types.StateEntry,
|
||||
thisServer gomatrixserverlib.ServerName) ([]types.Event, error) {
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ func (r *InboundPeeker) PerformInboundPeek(
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if info == nil || info.IsStub {
|
||||
if info == nil || info.IsStub() {
|
||||
return nil
|
||||
}
|
||||
response.RoomExists = true
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue