mirror of
https://github.com/matrix-org/dendrite.git
synced 2025-12-06 22:43:10 -06:00
Merge remote-tracking branch 'ldap/syncloud' into daniel/ldap-integration
This commit is contained in:
commit
74e795d23d
1
.github/workflows/helm.yml
vendored
1
.github/workflows/helm.yml
vendored
|
|
@ -6,6 +6,7 @@ on:
|
||||||
- main
|
- main
|
||||||
paths:
|
paths:
|
||||||
- 'helm/**' # only execute if we have helm chart changes
|
- 'helm/**' # only execute if we have helm chart changes
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
release:
|
release:
|
||||||
|
|
|
||||||
1
.github/workflows/k8s.yml
vendored
1
.github/workflows/k8s.yml
vendored
|
|
@ -84,6 +84,7 @@ jobs:
|
||||||
kubectl get pods -A
|
kubectl get pods -A
|
||||||
kubectl get services
|
kubectl get services
|
||||||
kubectl get ingress
|
kubectl get ingress
|
||||||
|
kubectl logs -l app.kubernetes.io/name=dendrite
|
||||||
- name: Run create account
|
- name: Run create account
|
||||||
run: |
|
run: |
|
||||||
podName=$(kubectl get pods -l app.kubernetes.io/name=dendrite -o name)
|
podName=$(kubectl get pods -l app.kubernetes.io/name=dendrite -o name)
|
||||||
|
|
|
||||||
72
.github/workflows/schedules.yaml
vendored
72
.github/workflows/schedules.yaml
vendored
|
|
@ -65,10 +65,11 @@ jobs:
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v2
|
||||||
if: ${{ always() }}
|
if: ${{ always() }}
|
||||||
with:
|
with:
|
||||||
name: Sytest Logs - ${{ job.status }} - (Dendrite, ${{ join(matrix.*, ', ') }})
|
name: Sytest Logs - ${{ job.status }} - (Dendrite ${{ join(matrix.*, ' ') }})
|
||||||
path: |
|
path: |
|
||||||
/logs/results.tap
|
/logs/results.tap
|
||||||
/logs/**/*.log*
|
/logs/**/*.log*
|
||||||
|
/logs/**/covdatafiles/**
|
||||||
|
|
||||||
sytest-coverage:
|
sytest-coverage:
|
||||||
timeout-minutes: 5
|
timeout-minutes: 5
|
||||||
|
|
@ -85,16 +86,15 @@ jobs:
|
||||||
cache: true
|
cache: true
|
||||||
- name: Download all artifacts
|
- name: Download all artifacts
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v3
|
||||||
- name: Install gocovmerge
|
- name: Collect coverage
|
||||||
run: go install github.com/wadey/gocovmerge@latest
|
|
||||||
- name: Run gocovmerge
|
|
||||||
run: |
|
run: |
|
||||||
find -name 'integrationcover.log' -printf '"%p"\n' | xargs gocovmerge | grep -Ev 'relayapi|setup/mscs|api_trace' > sytest.cov
|
go tool covdata textfmt -i="$(find Sytest* -name 'covmeta*' -type f -exec dirname {} \; | uniq | paste -s -d ',' -)" -o sytest.cov
|
||||||
go tool cover -func=sytest.cov
|
grep -Ev 'relayapi|setup/mscs|api_trace' sytest.cov > final.cov
|
||||||
|
go tool covdata func -i="$(find Sytest* -name 'covmeta*' -type f -exec dirname {} \; | uniq | paste -s -d ',' -)"
|
||||||
- name: Upload coverage to Codecov
|
- name: Upload coverage to Codecov
|
||||||
uses: codecov/codecov-action@v3
|
uses: codecov/codecov-action@v3
|
||||||
with:
|
with:
|
||||||
files: ./sytest.cov
|
files: ./final.cov
|
||||||
flags: sytest
|
flags: sytest
|
||||||
fail_ci_if_error: true
|
fail_ci_if_error: true
|
||||||
|
|
||||||
|
|
@ -167,7 +167,7 @@ jobs:
|
||||||
cat <<EOF > /tmp/posttest.sh
|
cat <<EOF > /tmp/posttest.sh
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
mkdir -p /tmp/Complement/logs/\$2/\$1/
|
mkdir -p /tmp/Complement/logs/\$2/\$1/
|
||||||
docker cp \$1:/dendrite/complementcover.log /tmp/Complement/logs/\$2/\$1/
|
docker cp \$1:/tmp/covdatafiles/. /tmp/Complement/logs/\$2/\$1/
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
chmod +x /tmp/posttest.sh
|
chmod +x /tmp/posttest.sh
|
||||||
|
|
@ -188,9 +188,9 @@ jobs:
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v2
|
||||||
if: ${{ always() }}
|
if: ${{ always() }}
|
||||||
with:
|
with:
|
||||||
name: Complement Logs - (Dendrite, ${{ join(matrix.*, ', ') }})
|
name: Complement Logs - (Dendrite ${{ join(matrix.*, ' ') }})
|
||||||
path: |
|
path: |
|
||||||
/tmp/Complement/**/complementcover.log
|
/tmp/Complement/logs/**
|
||||||
|
|
||||||
complement-coverage:
|
complement-coverage:
|
||||||
timeout-minutes: 5
|
timeout-minutes: 5
|
||||||
|
|
@ -207,20 +207,19 @@ jobs:
|
||||||
cache: true
|
cache: true
|
||||||
- name: Download all artifacts
|
- name: Download all artifacts
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v3
|
||||||
- name: Install gocovmerge
|
- name: Collect coverage
|
||||||
run: go install github.com/wadey/gocovmerge@latest
|
|
||||||
- name: Run gocovmerge
|
|
||||||
run: |
|
run: |
|
||||||
find -name 'complementcover.log' -printf '"%p"\n' | xargs gocovmerge | grep -Ev 'relayapi|setup/mscs|api_trace' > complement.cov
|
go tool covdata textfmt -i="$(find Complement* -name 'covmeta*' -type f -exec dirname {} \; | uniq | paste -s -d ',' -)" -o complement.cov
|
||||||
go tool cover -func=complement.cov
|
grep -Ev 'relayapi|setup/mscs|api_trace' complement.cov > final.cov
|
||||||
|
go tool covdata func -i="$(find Complement* -name 'covmeta*' -type f -exec dirname {} \; | uniq | paste -s -d ',' -)"
|
||||||
- name: Upload coverage to Codecov
|
- name: Upload coverage to Codecov
|
||||||
uses: codecov/codecov-action@v3
|
uses: codecov/codecov-action@v3
|
||||||
with:
|
with:
|
||||||
files: ./complement.cov
|
files: ./final.cov
|
||||||
flags: complement
|
flags: complement
|
||||||
fail_ci_if_error: true
|
fail_ci_if_error: true
|
||||||
|
|
||||||
element_web:
|
element-web:
|
||||||
timeout-minutes: 120
|
timeout-minutes: 120
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
|
@ -258,3 +257,42 @@ jobs:
|
||||||
env:
|
env:
|
||||||
PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: true
|
PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: true
|
||||||
TMPDIR: ${{ runner.temp }}
|
TMPDIR: ${{ runner.temp }}
|
||||||
|
|
||||||
|
element-web-pinecone:
|
||||||
|
timeout-minutes: 120
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: tecolicom/actions-use-apt-tools@v1
|
||||||
|
with:
|
||||||
|
# Our test suite includes some screenshot tests with unusual diacritics, which are
|
||||||
|
# supposed to be covered by STIXGeneral.
|
||||||
|
tools: fonts-stix
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
repository: matrix-org/matrix-react-sdk
|
||||||
|
- uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
cache: 'yarn'
|
||||||
|
- name: Fetch layered build
|
||||||
|
run: scripts/ci/layered.sh
|
||||||
|
- name: Copy config
|
||||||
|
run: cp element.io/develop/config.json config.json
|
||||||
|
working-directory: ./element-web
|
||||||
|
- name: Build
|
||||||
|
env:
|
||||||
|
CI_PACKAGE: true
|
||||||
|
NODE_OPTIONS: "--openssl-legacy-provider"
|
||||||
|
run: yarn build
|
||||||
|
working-directory: ./element-web
|
||||||
|
- name: Edit Test Config
|
||||||
|
run: |
|
||||||
|
sed -i '/HOMESERVER/c\ HOMESERVER: "dendritePinecone",' cypress.config.ts
|
||||||
|
- name: "Run cypress tests"
|
||||||
|
uses: cypress-io/github-action@v4.1.1
|
||||||
|
with:
|
||||||
|
browser: chrome
|
||||||
|
start: npx serve -p 8080 ./element-web/webapp
|
||||||
|
wait-on: 'http://localhost:8080'
|
||||||
|
env:
|
||||||
|
PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: true
|
||||||
|
TMPDIR: ${{ runner.temp }}
|
||||||
|
|
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -80,3 +80,4 @@ media_store/
|
||||||
__debug_bin
|
__debug_bin
|
||||||
|
|
||||||
cmd/dendrite-monolith-server/dendrite-monolith-server
|
cmd/dendrite-monolith-server/dendrite-monolith-server
|
||||||
|
build
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,6 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
|
"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
|
||||||
userapi "github.com/matrix-org/dendrite/userapi/api"
|
userapi "github.com/matrix-org/dendrite/userapi/api"
|
||||||
)
|
)
|
||||||
|
|
@ -150,6 +148,10 @@ type ASLocationResponse struct {
|
||||||
Fields json.RawMessage `json:"fields"`
|
Fields json.RawMessage `json:"fields"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ErrProfileNotExists is returned when trying to lookup a user's profile that
|
||||||
|
// doesn't exist locally.
|
||||||
|
var ErrProfileNotExists = errors.New("no known profile for given user ID")
|
||||||
|
|
||||||
// RetrieveUserProfile is a wrapper that queries both the local database and
|
// RetrieveUserProfile is a wrapper that queries both the local database and
|
||||||
// application services for a given user's profile
|
// application services for a given user's profile
|
||||||
// TODO: Remove this, it's called from federationapi and clientapi but is a pure function
|
// TODO: Remove this, it's called from federationapi and clientapi but is a pure function
|
||||||
|
|
@ -157,25 +159,11 @@ func RetrieveUserProfile(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
userID string,
|
userID string,
|
||||||
asAPI AppServiceInternalAPI,
|
asAPI AppServiceInternalAPI,
|
||||||
profileAPI userapi.ClientUserAPI,
|
profileAPI userapi.ProfileAPI,
|
||||||
) (*authtypes.Profile, error) {
|
) (*authtypes.Profile, error) {
|
||||||
localpart, _, err := gomatrixserverlib.SplitID('@', userID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to query the user from the local database
|
// Try to query the user from the local database
|
||||||
res := &userapi.QueryProfileResponse{}
|
profile, err := profileAPI.QueryProfile(ctx, userID)
|
||||||
err = profileAPI.QueryProfile(ctx, &userapi.QueryProfileRequest{UserID: userID}, res)
|
if err == nil {
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
profile := &authtypes.Profile{
|
|
||||||
Localpart: localpart,
|
|
||||||
DisplayName: res.DisplayName,
|
|
||||||
AvatarURL: res.AvatarURL,
|
|
||||||
}
|
|
||||||
if res.UserExists {
|
|
||||||
return profile, nil
|
return profile, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -188,19 +176,15 @@ func RetrieveUserProfile(
|
||||||
|
|
||||||
// If no user exists, return
|
// If no user exists, return
|
||||||
if !userResp.UserIDExists {
|
if !userResp.UserIDExists {
|
||||||
return nil, errors.New("no known profile for given user ID")
|
return nil, ErrProfileNotExists
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to query the user from the local database again
|
// Try to query the user from the local database again
|
||||||
err = profileAPI.QueryProfile(ctx, &userapi.QueryProfileRequest{UserID: userID}, res)
|
profile, err = profileAPI.QueryProfile(ctx, userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// profile should not be nil at this point
|
// profile should not be nil at this point
|
||||||
return &authtypes.Profile{
|
return profile, nil
|
||||||
Localpart: localpart,
|
|
||||||
DisplayName: res.DisplayName,
|
|
||||||
AvatarURL: res.AvatarURL,
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,11 +16,10 @@ package appservice
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
|
||||||
"net/http"
|
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
|
||||||
|
|
||||||
|
"github.com/matrix-org/dendrite/setup/jetstream"
|
||||||
|
"github.com/matrix-org/dendrite/setup/process"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
|
@ -29,7 +28,6 @@ import (
|
||||||
"github.com/matrix-org/dendrite/appservice/consumers"
|
"github.com/matrix-org/dendrite/appservice/consumers"
|
||||||
"github.com/matrix-org/dendrite/appservice/query"
|
"github.com/matrix-org/dendrite/appservice/query"
|
||||||
roomserverAPI "github.com/matrix-org/dendrite/roomserver/api"
|
roomserverAPI "github.com/matrix-org/dendrite/roomserver/api"
|
||||||
"github.com/matrix-org/dendrite/setup/base"
|
|
||||||
"github.com/matrix-org/dendrite/setup/config"
|
"github.com/matrix-org/dendrite/setup/config"
|
||||||
userapi "github.com/matrix-org/dendrite/userapi/api"
|
userapi "github.com/matrix-org/dendrite/userapi/api"
|
||||||
)
|
)
|
||||||
|
|
@ -37,39 +35,31 @@ import (
|
||||||
// NewInternalAPI returns a concerete implementation of the internal API. Callers
|
// NewInternalAPI returns a concerete implementation of the internal API. Callers
|
||||||
// can call functions directly on the returned API or via an HTTP interface using AddInternalRoutes.
|
// can call functions directly on the returned API or via an HTTP interface using AddInternalRoutes.
|
||||||
func NewInternalAPI(
|
func NewInternalAPI(
|
||||||
base *base.BaseDendrite,
|
processContext *process.ProcessContext,
|
||||||
|
cfg *config.Dendrite,
|
||||||
|
natsInstance *jetstream.NATSInstance,
|
||||||
userAPI userapi.AppserviceUserAPI,
|
userAPI userapi.AppserviceUserAPI,
|
||||||
rsAPI roomserverAPI.RoomserverInternalAPI,
|
rsAPI roomserverAPI.RoomserverInternalAPI,
|
||||||
) appserviceAPI.AppServiceInternalAPI {
|
) appserviceAPI.AppServiceInternalAPI {
|
||||||
client := &http.Client{
|
|
||||||
Timeout: time.Second * 30,
|
|
||||||
Transport: &http.Transport{
|
|
||||||
DisableKeepAlives: true,
|
|
||||||
TLSClientConfig: &tls.Config{
|
|
||||||
InsecureSkipVerify: base.Cfg.AppServiceAPI.DisableTLSValidation,
|
|
||||||
},
|
|
||||||
Proxy: http.ProxyFromEnvironment,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
// Create appserivce query API with an HTTP client that will be used for all
|
// Create appserivce query API with an HTTP client that will be used for all
|
||||||
// outbound and inbound requests (inbound only for the internal API)
|
// outbound and inbound requests (inbound only for the internal API)
|
||||||
appserviceQueryAPI := &query.AppServiceQueryAPI{
|
appserviceQueryAPI := &query.AppServiceQueryAPI{
|
||||||
HTTPClient: client,
|
Cfg: &cfg.AppServiceAPI,
|
||||||
Cfg: &base.Cfg.AppServiceAPI,
|
|
||||||
ProtocolCache: map[string]appserviceAPI.ASProtocolResponse{},
|
ProtocolCache: map[string]appserviceAPI.ASProtocolResponse{},
|
||||||
CacheMu: sync.Mutex{},
|
CacheMu: sync.Mutex{},
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(base.Cfg.Derived.ApplicationServices) == 0 {
|
if len(cfg.Derived.ApplicationServices) == 0 {
|
||||||
return appserviceQueryAPI
|
return appserviceQueryAPI
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wrap application services in a type that relates the application service and
|
// Wrap application services in a type that relates the application service and
|
||||||
// a sync.Cond object that can be used to notify workers when there are new
|
// a sync.Cond object that can be used to notify workers when there are new
|
||||||
// events to be sent out.
|
// events to be sent out.
|
||||||
for _, appservice := range base.Cfg.Derived.ApplicationServices {
|
for _, appservice := range cfg.Derived.ApplicationServices {
|
||||||
// Create bot account for this AS if it doesn't already exist
|
// Create bot account for this AS if it doesn't already exist
|
||||||
if err := generateAppServiceAccount(userAPI, appservice, base.Cfg.Global.ServerName); err != nil {
|
if err := generateAppServiceAccount(userAPI, appservice, cfg.Global.ServerName); err != nil {
|
||||||
logrus.WithFields(logrus.Fields{
|
logrus.WithFields(logrus.Fields{
|
||||||
"appservice": appservice.ID,
|
"appservice": appservice.ID,
|
||||||
}).WithError(err).Panicf("failed to generate bot account for appservice")
|
}).WithError(err).Panicf("failed to generate bot account for appservice")
|
||||||
|
|
@ -78,10 +68,10 @@ func NewInternalAPI(
|
||||||
|
|
||||||
// Only consume if we actually have ASes to track, else we'll just chew cycles needlessly.
|
// Only consume if we actually have ASes to track, else we'll just chew cycles needlessly.
|
||||||
// We can't add ASes at runtime so this is safe to do.
|
// We can't add ASes at runtime so this is safe to do.
|
||||||
js, _ := base.NATS.Prepare(base.ProcessContext, &base.Cfg.Global.JetStream)
|
js, _ := natsInstance.Prepare(processContext, &cfg.Global.JetStream)
|
||||||
consumer := consumers.NewOutputRoomEventConsumer(
|
consumer := consumers.NewOutputRoomEventConsumer(
|
||||||
base.ProcessContext, &base.Cfg.AppServiceAPI,
|
processContext, &cfg.AppServiceAPI,
|
||||||
client, js, rsAPI,
|
js, rsAPI,
|
||||||
)
|
)
|
||||||
if err := consumer.Start(); err != nil {
|
if err := consumer.Start(); err != nil {
|
||||||
logrus.WithError(err).Panicf("failed to start appservice roomserver consumer")
|
logrus.WithError(err).Panicf("failed to start appservice roomserver consumer")
|
||||||
|
|
|
||||||
|
|
@ -3,19 +3,31 @@ package appservice_test
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
|
"path"
|
||||||
"reflect"
|
"reflect"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/appservice"
|
"github.com/matrix-org/dendrite/appservice"
|
||||||
"github.com/matrix-org/dendrite/appservice/api"
|
"github.com/matrix-org/dendrite/appservice/api"
|
||||||
|
"github.com/matrix-org/dendrite/appservice/consumers"
|
||||||
|
"github.com/matrix-org/dendrite/internal/caching"
|
||||||
|
"github.com/matrix-org/dendrite/internal/sqlutil"
|
||||||
"github.com/matrix-org/dendrite/roomserver"
|
"github.com/matrix-org/dendrite/roomserver"
|
||||||
|
rsapi "github.com/matrix-org/dendrite/roomserver/api"
|
||||||
"github.com/matrix-org/dendrite/setup/config"
|
"github.com/matrix-org/dendrite/setup/config"
|
||||||
|
"github.com/matrix-org/dendrite/setup/jetstream"
|
||||||
"github.com/matrix-org/dendrite/test"
|
"github.com/matrix-org/dendrite/test"
|
||||||
"github.com/matrix-org/dendrite/userapi"
|
"github.com/matrix-org/dendrite/userapi"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/test/testrig"
|
"github.com/matrix-org/dendrite/test/testrig"
|
||||||
)
|
)
|
||||||
|
|
@ -104,12 +116,11 @@ func TestAppserviceInternalAPI(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
|
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
|
||||||
base, closeBase := testrig.CreateBaseDendrite(t, dbType)
|
cfg, ctx, close := testrig.CreateConfig(t, dbType)
|
||||||
defer closeBase()
|
defer close()
|
||||||
|
|
||||||
// Create a dummy application service
|
// Create a dummy application service
|
||||||
base.Cfg.AppServiceAPI.Derived.ApplicationServices = []config.ApplicationService{
|
as := &config.ApplicationService{
|
||||||
{
|
|
||||||
ID: "someID",
|
ID: "someID",
|
||||||
URL: srv.URL,
|
URL: srv.URL,
|
||||||
ASToken: "",
|
ASToken: "",
|
||||||
|
|
@ -120,18 +131,123 @@ func TestAppserviceInternalAPI(t *testing.T) {
|
||||||
"aliases": {{RegexpObject: regexp.MustCompile("asroom-.*")}},
|
"aliases": {{RegexpObject: regexp.MustCompile("asroom-.*")}},
|
||||||
},
|
},
|
||||||
Protocols: []string{existingProtocol},
|
Protocols: []string{existingProtocol},
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
as.CreateHTTPClient(cfg.AppServiceAPI.DisableTLSValidation)
|
||||||
|
cfg.AppServiceAPI.Derived.ApplicationServices = []config.ApplicationService{*as}
|
||||||
|
|
||||||
|
t.Cleanup(func() {
|
||||||
|
ctx.ShutdownDendrite()
|
||||||
|
ctx.WaitForShutdown()
|
||||||
|
})
|
||||||
|
caches := caching.NewRistrettoCache(128*1024*1024, time.Hour, caching.DisableMetrics)
|
||||||
// Create required internal APIs
|
// Create required internal APIs
|
||||||
rsAPI := roomserver.NewInternalAPI(base)
|
natsInstance := jetstream.NATSInstance{}
|
||||||
usrAPI := userapi.NewInternalAPI(base, rsAPI, nil)
|
cm := sqlutil.NewConnectionManager(ctx, cfg.Global.DatabaseOptions)
|
||||||
asAPI := appservice.NewInternalAPI(base, usrAPI, rsAPI)
|
rsAPI := roomserver.NewInternalAPI(ctx, cfg, cm, &natsInstance, caches, caching.DisableMetrics)
|
||||||
|
usrAPI := userapi.NewInternalAPI(ctx, cfg, cm, &natsInstance, rsAPI, nil)
|
||||||
|
asAPI := appservice.NewInternalAPI(ctx, cfg, &natsInstance, usrAPI, rsAPI)
|
||||||
|
|
||||||
runCases(t, asAPI)
|
runCases(t, asAPI)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAppserviceInternalAPI_UnixSocket_Simple(t *testing.T) {
|
||||||
|
|
||||||
|
// Set expected results
|
||||||
|
existingProtocol := "irc"
|
||||||
|
wantLocationResponse := []api.ASLocationResponse{{Protocol: existingProtocol, Fields: []byte("{}")}}
|
||||||
|
wantUserResponse := []api.ASUserResponse{{Protocol: existingProtocol, Fields: []byte("{}")}}
|
||||||
|
wantProtocolResponse := api.ASProtocolResponse{Instances: []api.ProtocolInstance{{Fields: []byte("{}")}}}
|
||||||
|
|
||||||
|
// create a dummy AS url, handling some cases
|
||||||
|
srv := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
switch {
|
||||||
|
case strings.Contains(r.URL.Path, "location"):
|
||||||
|
// Check if we've got an existing protocol, if so, return a proper response.
|
||||||
|
if r.URL.Path[len(r.URL.Path)-len(existingProtocol):] == existingProtocol {
|
||||||
|
if err := json.NewEncoder(w).Encode(wantLocationResponse); err != nil {
|
||||||
|
t.Fatalf("failed to encode response: %s", err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := json.NewEncoder(w).Encode([]api.ASLocationResponse{}); err != nil {
|
||||||
|
t.Fatalf("failed to encode response: %s", err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
case strings.Contains(r.URL.Path, "user"):
|
||||||
|
if r.URL.Path[len(r.URL.Path)-len(existingProtocol):] == existingProtocol {
|
||||||
|
if err := json.NewEncoder(w).Encode(wantUserResponse); err != nil {
|
||||||
|
t.Fatalf("failed to encode response: %s", err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := json.NewEncoder(w).Encode([]api.UserResponse{}); err != nil {
|
||||||
|
t.Fatalf("failed to encode response: %s", err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
case strings.Contains(r.URL.Path, "protocol"):
|
||||||
|
if r.URL.Path[len(r.URL.Path)-len(existingProtocol):] == existingProtocol {
|
||||||
|
if err := json.NewEncoder(w).Encode(wantProtocolResponse); err != nil {
|
||||||
|
t.Fatalf("failed to encode response: %s", err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := json.NewEncoder(w).Encode(nil); err != nil {
|
||||||
|
t.Fatalf("failed to encode response: %s", err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
t.Logf("hit location: %s", r.URL.Path)
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
|
||||||
|
tmpDir := t.TempDir()
|
||||||
|
socket := path.Join(tmpDir, "socket")
|
||||||
|
l, err := net.Listen("unix", socket)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
_ = srv.Listener.Close()
|
||||||
|
srv.Listener = l
|
||||||
|
srv.Start()
|
||||||
|
defer srv.Close()
|
||||||
|
|
||||||
|
cfg, ctx, tearDown := testrig.CreateConfig(t, test.DBTypeSQLite)
|
||||||
|
defer tearDown()
|
||||||
|
|
||||||
|
// Create a dummy application service
|
||||||
|
as := &config.ApplicationService{
|
||||||
|
ID: "someID",
|
||||||
|
URL: fmt.Sprintf("unix://%s", socket),
|
||||||
|
ASToken: "",
|
||||||
|
HSToken: "",
|
||||||
|
SenderLocalpart: "senderLocalPart",
|
||||||
|
NamespaceMap: map[string][]config.ApplicationServiceNamespace{
|
||||||
|
"users": {{RegexpObject: regexp.MustCompile("as-.*")}},
|
||||||
|
"aliases": {{RegexpObject: regexp.MustCompile("asroom-.*")}},
|
||||||
|
},
|
||||||
|
Protocols: []string{existingProtocol},
|
||||||
|
}
|
||||||
|
as.CreateHTTPClient(cfg.AppServiceAPI.DisableTLSValidation)
|
||||||
|
cfg.AppServiceAPI.Derived.ApplicationServices = []config.ApplicationService{*as}
|
||||||
|
|
||||||
|
t.Cleanup(func() {
|
||||||
|
ctx.ShutdownDendrite()
|
||||||
|
ctx.WaitForShutdown()
|
||||||
|
})
|
||||||
|
caches := caching.NewRistrettoCache(128*1024*1024, time.Hour, caching.DisableMetrics)
|
||||||
|
// Create required internal APIs
|
||||||
|
natsInstance := jetstream.NATSInstance{}
|
||||||
|
cm := sqlutil.NewConnectionManager(ctx, cfg.Global.DatabaseOptions)
|
||||||
|
rsAPI := roomserver.NewInternalAPI(ctx, cfg, cm, &natsInstance, caches, caching.DisableMetrics)
|
||||||
|
usrAPI := userapi.NewInternalAPI(ctx, cfg, cm, &natsInstance, rsAPI, nil)
|
||||||
|
asAPI := appservice.NewInternalAPI(ctx, cfg, &natsInstance, usrAPI, rsAPI)
|
||||||
|
|
||||||
|
t.Run("UserIDExists", func(t *testing.T) {
|
||||||
|
testUserIDExists(t, asAPI, "@as-testing:test", true)
|
||||||
|
testUserIDExists(t, asAPI, "@as1-testing:test", false)
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func testUserIDExists(t *testing.T, asAPI api.AppServiceInternalAPI, userID string, wantExists bool) {
|
func testUserIDExists(t *testing.T, asAPI api.AppServiceInternalAPI, userID string, wantExists bool) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
userResp := &api.UserIDExistsResponse{}
|
userResp := &api.UserIDExistsResponse{}
|
||||||
|
|
@ -201,3 +317,87 @@ func testProtocol(t *testing.T, asAPI api.AppServiceInternalAPI, proto string, w
|
||||||
t.Errorf("unexpected result for Protocols(%s): %+v, expected %+v", proto, protoResp.Protocols[proto], wantResult)
|
t.Errorf("unexpected result for Protocols(%s): %+v, expected %+v", proto, protoResp.Protocols[proto], wantResult)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tests that the roomserver consumer only receives one invite
|
||||||
|
func TestRoomserverConsumerOneInvite(t *testing.T) {
|
||||||
|
|
||||||
|
alice := test.NewUser(t)
|
||||||
|
bob := test.NewUser(t)
|
||||||
|
room := test.NewRoom(t, alice)
|
||||||
|
|
||||||
|
// Invite Bob
|
||||||
|
room.CreateAndInsert(t, alice, gomatrixserverlib.MRoomMember, map[string]interface{}{
|
||||||
|
"membership": "invite",
|
||||||
|
}, test.WithStateKey(bob.ID))
|
||||||
|
|
||||||
|
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
|
||||||
|
cfg, processCtx, closeDB := testrig.CreateConfig(t, dbType)
|
||||||
|
defer closeDB()
|
||||||
|
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
|
||||||
|
natsInstance := &jetstream.NATSInstance{}
|
||||||
|
|
||||||
|
evChan := make(chan struct{})
|
||||||
|
// create a dummy AS url, handling the events
|
||||||
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var txn consumers.ApplicationServiceTransaction
|
||||||
|
err := json.NewDecoder(r.Body).Decode(&txn)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
for _, ev := range txn.Events {
|
||||||
|
if ev.Type != gomatrixserverlib.MRoomMember {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// Usually we would check the event content for the membership, but since
|
||||||
|
// we only invited bob, this should be fine for this test.
|
||||||
|
if ev.StateKey != nil && *ev.StateKey == bob.ID {
|
||||||
|
evChan <- struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
defer srv.Close()
|
||||||
|
|
||||||
|
as := &config.ApplicationService{
|
||||||
|
ID: "someID",
|
||||||
|
URL: srv.URL,
|
||||||
|
ASToken: "",
|
||||||
|
HSToken: "",
|
||||||
|
SenderLocalpart: "senderLocalPart",
|
||||||
|
NamespaceMap: map[string][]config.ApplicationServiceNamespace{
|
||||||
|
"users": {{RegexpObject: regexp.MustCompile(bob.ID)}},
|
||||||
|
"aliases": {{RegexpObject: regexp.MustCompile(room.ID)}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
as.CreateHTTPClient(cfg.AppServiceAPI.DisableTLSValidation)
|
||||||
|
|
||||||
|
// Create a dummy application service
|
||||||
|
cfg.AppServiceAPI.Derived.ApplicationServices = []config.ApplicationService{*as}
|
||||||
|
|
||||||
|
caches := caching.NewRistrettoCache(128*1024*1024, time.Hour, caching.DisableMetrics)
|
||||||
|
// Create required internal APIs
|
||||||
|
rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, natsInstance, caches, caching.DisableMetrics)
|
||||||
|
rsAPI.SetFederationAPI(nil, nil)
|
||||||
|
usrAPI := userapi.NewInternalAPI(processCtx, cfg, cm, natsInstance, rsAPI, nil)
|
||||||
|
// start the consumer
|
||||||
|
appservice.NewInternalAPI(processCtx, cfg, natsInstance, usrAPI, rsAPI)
|
||||||
|
|
||||||
|
// Create the room
|
||||||
|
if err := rsapi.SendEvents(context.Background(), rsAPI, rsapi.KindNew, room.Events(), "test", "test", "test", nil, false); err != nil {
|
||||||
|
t.Fatalf("failed to send events: %v", err)
|
||||||
|
}
|
||||||
|
var seenInvitesForBob int
|
||||||
|
waitLoop:
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-time.After(time.Millisecond * 50): // wait for the AS to process the events
|
||||||
|
break waitLoop
|
||||||
|
case <-evChan:
|
||||||
|
seenInvitesForBob++
|
||||||
|
if seenInvitesForBob != 1 {
|
||||||
|
t.Fatalf("received unexpected invites: %d", seenInvitesForBob)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close(evChan)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,15 +32,21 @@ import (
|
||||||
"github.com/matrix-org/dendrite/setup/config"
|
"github.com/matrix-org/dendrite/setup/config"
|
||||||
"github.com/matrix-org/dendrite/setup/jetstream"
|
"github.com/matrix-org/dendrite/setup/jetstream"
|
||||||
"github.com/matrix-org/dendrite/setup/process"
|
"github.com/matrix-org/dendrite/setup/process"
|
||||||
|
"github.com/matrix-org/dendrite/syncapi/synctypes"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ApplicationServiceTransaction is the transaction that is sent off to an
|
||||||
|
// application service.
|
||||||
|
type ApplicationServiceTransaction struct {
|
||||||
|
Events []synctypes.ClientEvent `json:"events"`
|
||||||
|
}
|
||||||
|
|
||||||
// OutputRoomEventConsumer consumes events that originated in the room server.
|
// OutputRoomEventConsumer consumes events that originated in the room server.
|
||||||
type OutputRoomEventConsumer struct {
|
type OutputRoomEventConsumer struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
cfg *config.AppServiceAPI
|
cfg *config.AppServiceAPI
|
||||||
client *http.Client
|
|
||||||
jetstream nats.JetStreamContext
|
jetstream nats.JetStreamContext
|
||||||
topic string
|
topic string
|
||||||
rsAPI api.AppserviceRoomserverAPI
|
rsAPI api.AppserviceRoomserverAPI
|
||||||
|
|
@ -56,14 +62,12 @@ type appserviceState struct {
|
||||||
func NewOutputRoomEventConsumer(
|
func NewOutputRoomEventConsumer(
|
||||||
process *process.ProcessContext,
|
process *process.ProcessContext,
|
||||||
cfg *config.AppServiceAPI,
|
cfg *config.AppServiceAPI,
|
||||||
client *http.Client,
|
|
||||||
js nats.JetStreamContext,
|
js nats.JetStreamContext,
|
||||||
rsAPI api.AppserviceRoomserverAPI,
|
rsAPI api.AppserviceRoomserverAPI,
|
||||||
) *OutputRoomEventConsumer {
|
) *OutputRoomEventConsumer {
|
||||||
return &OutputRoomEventConsumer{
|
return &OutputRoomEventConsumer{
|
||||||
ctx: process.Context(),
|
ctx: process.Context(),
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
client: client,
|
|
||||||
jetstream: js,
|
jetstream: js,
|
||||||
topic: cfg.Matrix.JetStream.Prefixed(jetstream.OutputRoomEvent),
|
topic: cfg.Matrix.JetStream.Prefixed(jetstream.OutputRoomEvent),
|
||||||
rsAPI: rsAPI,
|
rsAPI: rsAPI,
|
||||||
|
|
@ -140,12 +144,6 @@ func (s *OutputRoomEventConsumer) onMessage(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case api.OutputTypeNewInviteEvent:
|
|
||||||
if output.NewInviteEvent == nil || !s.appserviceIsInterestedInEvent(ctx, output.NewInviteEvent.Event, state.ApplicationService) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
events = append(events, output.NewInviteEvent.Event)
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
@ -180,8 +178,8 @@ func (s *OutputRoomEventConsumer) sendEvents(
|
||||||
) error {
|
) error {
|
||||||
// Create the transaction body.
|
// Create the transaction body.
|
||||||
transaction, err := json.Marshal(
|
transaction, err := json.Marshal(
|
||||||
gomatrixserverlib.ApplicationServiceTransaction{
|
ApplicationServiceTransaction{
|
||||||
Events: gomatrixserverlib.HeaderedToClientEvents(events, gomatrixserverlib.FormatAll),
|
Events: synctypes.HeaderedToClientEvents(events, synctypes.FormatAll),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -195,13 +193,13 @@ func (s *OutputRoomEventConsumer) sendEvents(
|
||||||
|
|
||||||
// Send the transaction to the appservice.
|
// Send the transaction to the appservice.
|
||||||
// https://matrix.org/docs/spec/application_service/r0.1.2#put-matrix-app-v1-transactions-txnid
|
// https://matrix.org/docs/spec/application_service/r0.1.2#put-matrix-app-v1-transactions-txnid
|
||||||
address := fmt.Sprintf("%s/transactions/%s?access_token=%s", state.URL, txnID, url.QueryEscape(state.HSToken))
|
address := fmt.Sprintf("%s/transactions/%s?access_token=%s", state.RequestUrl(), txnID, url.QueryEscape(state.HSToken))
|
||||||
req, err := http.NewRequestWithContext(ctx, "PUT", address, bytes.NewBuffer(transaction))
|
req, err := http.NewRequestWithContext(ctx, "PUT", address, bytes.NewBuffer(transaction))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
req.Header.Set("Content-Type", "application/json")
|
req.Header.Set("Content-Type", "application/json")
|
||||||
resp, err := s.client.Do(req)
|
resp, err := state.HTTPClient.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return state.backoffAndPause(err)
|
return state.backoffAndPause(err)
|
||||||
}
|
}
|
||||||
|
|
@ -212,7 +210,7 @@ func (s *OutputRoomEventConsumer) sendEvents(
|
||||||
case http.StatusOK:
|
case http.StatusOK:
|
||||||
state.backoff = 0
|
state.backoff = 0
|
||||||
default:
|
default:
|
||||||
return state.backoffAndPause(fmt.Errorf("received HTTP status code %d from appservice", resp.StatusCode))
|
return state.backoffAndPause(fmt.Errorf("received HTTP status code %d from appservice url %s", resp.StatusCode, address))
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,6 @@ const userIDExistsPath = "/users/"
|
||||||
|
|
||||||
// AppServiceQueryAPI is an implementation of api.AppServiceQueryAPI
|
// AppServiceQueryAPI is an implementation of api.AppServiceQueryAPI
|
||||||
type AppServiceQueryAPI struct {
|
type AppServiceQueryAPI struct {
|
||||||
HTTPClient *http.Client
|
|
||||||
Cfg *config.AppServiceAPI
|
Cfg *config.AppServiceAPI
|
||||||
ProtocolCache map[string]api.ASProtocolResponse
|
ProtocolCache map[string]api.ASProtocolResponse
|
||||||
CacheMu sync.Mutex
|
CacheMu sync.Mutex
|
||||||
|
|
@ -57,7 +56,7 @@ func (a *AppServiceQueryAPI) RoomAliasExists(
|
||||||
for _, appservice := range a.Cfg.Derived.ApplicationServices {
|
for _, appservice := range a.Cfg.Derived.ApplicationServices {
|
||||||
if appservice.URL != "" && appservice.IsInterestedInRoomAlias(request.Alias) {
|
if appservice.URL != "" && appservice.IsInterestedInRoomAlias(request.Alias) {
|
||||||
// The full path to the rooms API, includes hs token
|
// The full path to the rooms API, includes hs token
|
||||||
URL, err := url.Parse(appservice.URL + roomAliasExistsPath)
|
URL, err := url.Parse(appservice.RequestUrl() + roomAliasExistsPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -73,7 +72,7 @@ func (a *AppServiceQueryAPI) RoomAliasExists(
|
||||||
}
|
}
|
||||||
req = req.WithContext(ctx)
|
req = req.WithContext(ctx)
|
||||||
|
|
||||||
resp, err := a.HTTPClient.Do(req)
|
resp, err := appservice.HTTPClient.Do(req)
|
||||||
if resp != nil {
|
if resp != nil {
|
||||||
defer func() {
|
defer func() {
|
||||||
err = resp.Body.Close()
|
err = resp.Body.Close()
|
||||||
|
|
@ -124,7 +123,7 @@ func (a *AppServiceQueryAPI) UserIDExists(
|
||||||
for _, appservice := range a.Cfg.Derived.ApplicationServices {
|
for _, appservice := range a.Cfg.Derived.ApplicationServices {
|
||||||
if appservice.URL != "" && appservice.IsInterestedInUserID(request.UserID) {
|
if appservice.URL != "" && appservice.IsInterestedInUserID(request.UserID) {
|
||||||
// The full path to the rooms API, includes hs token
|
// The full path to the rooms API, includes hs token
|
||||||
URL, err := url.Parse(appservice.URL + userIDExistsPath)
|
URL, err := url.Parse(appservice.RequestUrl() + userIDExistsPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -137,7 +136,7 @@ func (a *AppServiceQueryAPI) UserIDExists(
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
resp, err := a.HTTPClient.Do(req.WithContext(ctx))
|
resp, err := appservice.HTTPClient.Do(req.WithContext(ctx))
|
||||||
if resp != nil {
|
if resp != nil {
|
||||||
defer func() {
|
defer func() {
|
||||||
err = resp.Body.Close()
|
err = resp.Body.Close()
|
||||||
|
|
@ -212,12 +211,12 @@ func (a *AppServiceQueryAPI) Locations(
|
||||||
var asLocations []api.ASLocationResponse
|
var asLocations []api.ASLocationResponse
|
||||||
params.Set("access_token", as.HSToken)
|
params.Set("access_token", as.HSToken)
|
||||||
|
|
||||||
url := as.URL + api.ASLocationPath
|
url := as.RequestUrl() + api.ASLocationPath
|
||||||
if req.Protocol != "" {
|
if req.Protocol != "" {
|
||||||
url += "/" + req.Protocol
|
url += "/" + req.Protocol
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := requestDo[[]api.ASLocationResponse](a.HTTPClient, url+"?"+params.Encode(), &asLocations); err != nil {
|
if err := requestDo[[]api.ASLocationResponse](as.HTTPClient, url+"?"+params.Encode(), &asLocations); err != nil {
|
||||||
log.WithError(err).Error("unable to get 'locations' from application service")
|
log.WithError(err).Error("unable to get 'locations' from application service")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
@ -247,12 +246,12 @@ func (a *AppServiceQueryAPI) User(
|
||||||
var asUsers []api.ASUserResponse
|
var asUsers []api.ASUserResponse
|
||||||
params.Set("access_token", as.HSToken)
|
params.Set("access_token", as.HSToken)
|
||||||
|
|
||||||
url := as.URL + api.ASUserPath
|
url := as.RequestUrl() + api.ASUserPath
|
||||||
if req.Protocol != "" {
|
if req.Protocol != "" {
|
||||||
url += "/" + req.Protocol
|
url += "/" + req.Protocol
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := requestDo[[]api.ASUserResponse](a.HTTPClient, url+"?"+params.Encode(), &asUsers); err != nil {
|
if err := requestDo[[]api.ASUserResponse](as.HTTPClient, url+"?"+params.Encode(), &asUsers); err != nil {
|
||||||
log.WithError(err).Error("unable to get 'user' from application service")
|
log.WithError(err).Error("unable to get 'user' from application service")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
@ -290,7 +289,7 @@ func (a *AppServiceQueryAPI) Protocols(
|
||||||
response := api.ASProtocolResponse{}
|
response := api.ASProtocolResponse{}
|
||||||
for _, as := range a.Cfg.Derived.ApplicationServices {
|
for _, as := range a.Cfg.Derived.ApplicationServices {
|
||||||
var proto api.ASProtocolResponse
|
var proto api.ASProtocolResponse
|
||||||
if err := requestDo[api.ASProtocolResponse](a.HTTPClient, as.URL+api.ASProtocolPath+req.Protocol, &proto); err != nil {
|
if err := requestDo[api.ASProtocolResponse](as.HTTPClient, as.RequestUrl()+api.ASProtocolPath+req.Protocol, &proto); err != nil {
|
||||||
log.WithError(err).Error("unable to get 'protocol' from application service")
|
log.WithError(err).Error("unable to get 'protocol' from application service")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
@ -320,7 +319,7 @@ func (a *AppServiceQueryAPI) Protocols(
|
||||||
for _, as := range a.Cfg.Derived.ApplicationServices {
|
for _, as := range a.Cfg.Derived.ApplicationServices {
|
||||||
for _, p := range as.Protocols {
|
for _, p := range as.Protocols {
|
||||||
var proto api.ASProtocolResponse
|
var proto api.ASProtocolResponse
|
||||||
if err := requestDo[api.ASProtocolResponse](a.HTTPClient, as.URL+api.ASProtocolPath+p, &proto); err != nil {
|
if err := requestDo[api.ASProtocolResponse](as.HTTPClient, as.RequestUrl()+api.ASProtocolPath+p, &proto); err != nil {
|
||||||
log.WithError(err).Error("unable to get 'protocol' from application service")
|
log.WithError(err).Error("unable to get 'protocol' from application service")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/getsentry/sentry-go"
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/matrix-org/dendrite/appservice"
|
"github.com/matrix-org/dendrite/appservice"
|
||||||
"github.com/matrix-org/dendrite/cmd/dendrite-demo-yggdrasil/signing"
|
"github.com/matrix-org/dendrite/cmd/dendrite-demo-yggdrasil/signing"
|
||||||
|
|
@ -19,11 +20,15 @@ import (
|
||||||
"github.com/matrix-org/dendrite/cmd/dendrite-demo-yggdrasil/yggrooms"
|
"github.com/matrix-org/dendrite/cmd/dendrite-demo-yggdrasil/yggrooms"
|
||||||
"github.com/matrix-org/dendrite/federationapi"
|
"github.com/matrix-org/dendrite/federationapi"
|
||||||
"github.com/matrix-org/dendrite/federationapi/api"
|
"github.com/matrix-org/dendrite/federationapi/api"
|
||||||
|
"github.com/matrix-org/dendrite/internal"
|
||||||
|
"github.com/matrix-org/dendrite/internal/caching"
|
||||||
"github.com/matrix-org/dendrite/internal/httputil"
|
"github.com/matrix-org/dendrite/internal/httputil"
|
||||||
|
"github.com/matrix-org/dendrite/internal/sqlutil"
|
||||||
"github.com/matrix-org/dendrite/roomserver"
|
"github.com/matrix-org/dendrite/roomserver"
|
||||||
"github.com/matrix-org/dendrite/setup"
|
"github.com/matrix-org/dendrite/setup"
|
||||||
"github.com/matrix-org/dendrite/setup/base"
|
basepkg "github.com/matrix-org/dendrite/setup/base"
|
||||||
"github.com/matrix-org/dendrite/setup/config"
|
"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/dendrite/setup/process"
|
||||||
"github.com/matrix-org/dendrite/test"
|
"github.com/matrix-org/dendrite/test"
|
||||||
"github.com/matrix-org/dendrite/userapi"
|
"github.com/matrix-org/dendrite/userapi"
|
||||||
|
|
@ -148,25 +153,71 @@ func (m *DendriteMonolith) Start() {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
base := base.NewBaseDendrite(cfg)
|
configErrors := &config.ConfigErrors{}
|
||||||
base.ConfigureAdminEndpoints()
|
cfg.Verify(configErrors)
|
||||||
m.processContext = base.ProcessContext
|
if len(*configErrors) > 0 {
|
||||||
defer base.Close() // nolint: errcheck
|
for _, err := range *configErrors {
|
||||||
|
logrus.Errorf("Configuration error: %s", err)
|
||||||
|
}
|
||||||
|
logrus.Fatalf("Failed to start due to configuration errors")
|
||||||
|
}
|
||||||
|
|
||||||
federation := ygg.CreateFederationClient(base)
|
internal.SetupStdLogging()
|
||||||
|
internal.SetupHookLogging(cfg.Logging)
|
||||||
|
internal.SetupPprof()
|
||||||
|
|
||||||
|
logrus.Infof("Dendrite version %s", internal.VersionString())
|
||||||
|
|
||||||
|
if !cfg.ClientAPI.RegistrationDisabled && cfg.ClientAPI.OpenRegistrationWithoutVerificationEnabled {
|
||||||
|
logrus.Warn("Open registration is enabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
closer, err := cfg.SetupTracing()
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithError(err).Panicf("failed to start opentracing")
|
||||||
|
}
|
||||||
|
defer closer.Close()
|
||||||
|
|
||||||
|
if cfg.Global.Sentry.Enabled {
|
||||||
|
logrus.Info("Setting up Sentry for debugging...")
|
||||||
|
err = sentry.Init(sentry.ClientOptions{
|
||||||
|
Dsn: cfg.Global.Sentry.DSN,
|
||||||
|
Environment: cfg.Global.Sentry.Environment,
|
||||||
|
Debug: true,
|
||||||
|
ServerName: string(cfg.Global.ServerName),
|
||||||
|
Release: "dendrite@" + internal.VersionString(),
|
||||||
|
AttachStacktrace: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithError(err).Panic("failed to start Sentry")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
processCtx := process.NewProcessContext()
|
||||||
|
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
|
||||||
|
routers := httputil.NewRouters()
|
||||||
|
basepkg.ConfigureAdminEndpoints(processCtx, routers)
|
||||||
|
m.processContext = processCtx
|
||||||
|
defer func() {
|
||||||
|
processCtx.ShutdownDendrite()
|
||||||
|
processCtx.WaitForShutdown()
|
||||||
|
}() // nolint: errcheck
|
||||||
|
|
||||||
|
federation := ygg.CreateFederationClient(cfg)
|
||||||
|
|
||||||
serverKeyAPI := &signing.YggdrasilKeys{}
|
serverKeyAPI := &signing.YggdrasilKeys{}
|
||||||
keyRing := serverKeyAPI.KeyRing()
|
keyRing := serverKeyAPI.KeyRing()
|
||||||
|
|
||||||
rsAPI := roomserver.NewInternalAPI(base)
|
caches := caching.NewRistrettoCache(cfg.Global.Cache.EstimatedMaxSize, cfg.Global.Cache.MaxAge, caching.EnableMetrics)
|
||||||
|
natsInstance := jetstream.NATSInstance{}
|
||||||
|
rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, &natsInstance, caches, caching.EnableMetrics)
|
||||||
|
|
||||||
fsAPI := federationapi.NewInternalAPI(
|
fsAPI := federationapi.NewInternalAPI(
|
||||||
base, federation, rsAPI, base.Caches, keyRing, true,
|
processCtx, cfg, cm, &natsInstance, federation, rsAPI, caches, keyRing, true,
|
||||||
)
|
)
|
||||||
|
|
||||||
userAPI := userapi.NewInternalAPI(base, rsAPI, federation)
|
userAPI := userapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, rsAPI, federation)
|
||||||
|
|
||||||
asAPI := appservice.NewInternalAPI(base, userAPI, rsAPI)
|
asAPI := appservice.NewInternalAPI(processCtx, cfg, &natsInstance, userAPI, rsAPI)
|
||||||
rsAPI.SetAppserviceAPI(asAPI)
|
rsAPI.SetAppserviceAPI(asAPI)
|
||||||
|
|
||||||
// The underlying roomserver implementation needs to be able to call the fedsender.
|
// The underlying roomserver implementation needs to be able to call the fedsender.
|
||||||
|
|
@ -174,8 +225,8 @@ func (m *DendriteMonolith) Start() {
|
||||||
rsAPI.SetFederationAPI(fsAPI, keyRing)
|
rsAPI.SetFederationAPI(fsAPI, keyRing)
|
||||||
|
|
||||||
monolith := setup.Monolith{
|
monolith := setup.Monolith{
|
||||||
Config: base.Cfg,
|
Config: cfg,
|
||||||
Client: ygg.CreateClient(base),
|
Client: ygg.CreateClient(),
|
||||||
FedClient: federation,
|
FedClient: federation,
|
||||||
KeyRing: keyRing,
|
KeyRing: keyRing,
|
||||||
|
|
||||||
|
|
@ -187,17 +238,17 @@ func (m *DendriteMonolith) Start() {
|
||||||
ygg, fsAPI, federation,
|
ygg, fsAPI, federation,
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
monolith.AddAllPublicRoutes(base)
|
monolith.AddAllPublicRoutes(processCtx, cfg, routers, cm, &natsInstance, caches, caching.EnableMetrics)
|
||||||
|
|
||||||
httpRouter := mux.NewRouter()
|
httpRouter := mux.NewRouter()
|
||||||
httpRouter.PathPrefix(httputil.PublicClientPathPrefix).Handler(base.PublicClientAPIMux)
|
httpRouter.PathPrefix(httputil.PublicClientPathPrefix).Handler(routers.Client)
|
||||||
httpRouter.PathPrefix(httputil.PublicMediaPathPrefix).Handler(base.PublicMediaAPIMux)
|
httpRouter.PathPrefix(httputil.PublicMediaPathPrefix).Handler(routers.Media)
|
||||||
httpRouter.PathPrefix(httputil.DendriteAdminPathPrefix).Handler(base.DendriteAdminMux)
|
httpRouter.PathPrefix(httputil.DendriteAdminPathPrefix).Handler(routers.DendriteAdmin)
|
||||||
httpRouter.PathPrefix(httputil.SynapseAdminPathPrefix).Handler(base.SynapseAdminMux)
|
httpRouter.PathPrefix(httputil.SynapseAdminPathPrefix).Handler(routers.SynapseAdmin)
|
||||||
|
|
||||||
yggRouter := mux.NewRouter()
|
yggRouter := mux.NewRouter()
|
||||||
yggRouter.PathPrefix(httputil.PublicFederationPathPrefix).Handler(base.PublicFederationAPIMux)
|
yggRouter.PathPrefix(httputil.PublicFederationPathPrefix).Handler(routers.Federation)
|
||||||
yggRouter.PathPrefix(httputil.PublicMediaPathPrefix).Handler(base.PublicMediaAPIMux)
|
yggRouter.PathPrefix(httputil.PublicMediaPathPrefix).Handler(routers.Media)
|
||||||
|
|
||||||
// Build both ends of a HTTP multiplex.
|
// Build both ends of a HTTP multiplex.
|
||||||
m.httpServer = &http.Server{
|
m.httpServer = &http.Server{
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#syntax=docker/dockerfile:1.2
|
#syntax=docker/dockerfile:1.2
|
||||||
|
|
||||||
FROM golang:1.18-stretch as build
|
FROM golang:1.20-bullseye as build
|
||||||
RUN apt-get update && apt-get install -y sqlite3
|
RUN apt-get update && apt-get install -y sqlite3
|
||||||
WORKDIR /build
|
WORKDIR /build
|
||||||
|
|
||||||
|
|
@ -17,7 +17,7 @@ RUN --mount=target=. \
|
||||||
CGO_ENABLED=${CGO} go build -o /dendrite ./cmd/generate-config && \
|
CGO_ENABLED=${CGO} go build -o /dendrite ./cmd/generate-config && \
|
||||||
CGO_ENABLED=${CGO} go build -o /dendrite ./cmd/generate-keys && \
|
CGO_ENABLED=${CGO} go build -o /dendrite ./cmd/generate-keys && \
|
||||||
CGO_ENABLED=${CGO} go build -o /dendrite/dendrite ./cmd/dendrite && \
|
CGO_ENABLED=${CGO} go build -o /dendrite/dendrite ./cmd/dendrite && \
|
||||||
CGO_ENABLED=${CGO} go test -c -cover -covermode=atomic -o /dendrite/dendrite-cover -coverpkg "github.com/matrix-org/..." ./cmd/dendrite && \
|
CGO_ENABLED=${CGO} go build -cover -covermode=atomic -o /dendrite/dendrite-cover -coverpkg "github.com/matrix-org/..." ./cmd/dendrite && \
|
||||||
cp build/scripts/complement-cmd.sh /complement-cmd.sh
|
cp build/scripts/complement-cmd.sh /complement-cmd.sh
|
||||||
|
|
||||||
WORKDIR /dendrite
|
WORKDIR /dendrite
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,19 @@
|
||||||
#syntax=docker/dockerfile:1.2
|
#syntax=docker/dockerfile:1.2
|
||||||
|
|
||||||
FROM golang:1.18-stretch as build
|
FROM golang:1.20-bullseye as build
|
||||||
RUN apt-get update && apt-get install -y postgresql
|
RUN apt-get update && apt-get install -y postgresql
|
||||||
WORKDIR /build
|
WORKDIR /build
|
||||||
|
|
||||||
# No password when connecting over localhost
|
# No password when connecting over localhost
|
||||||
RUN sed -i "s%127.0.0.1/32 md5%127.0.0.1/32 trust%g" /etc/postgresql/9.6/main/pg_hba.conf && \
|
RUN sed -i "s%127.0.0.1/32 md5%127.0.0.1/32 trust%g" /etc/postgresql/13/main/pg_hba.conf && \
|
||||||
# Bump up max conns for moar concurrency
|
# Bump up max conns for moar concurrency
|
||||||
sed -i 's/max_connections = 100/max_connections = 2000/g' /etc/postgresql/9.6/main/postgresql.conf
|
sed -i 's/max_connections = 100/max_connections = 2000/g' /etc/postgresql/13/main/postgresql.conf
|
||||||
|
|
||||||
# This entry script starts postgres, waits for it to be up then starts dendrite
|
# This entry script starts postgres, waits for it to be up then starts dendrite
|
||||||
RUN echo '\
|
RUN echo '\
|
||||||
#!/bin/bash -eu \n\
|
#!/bin/bash -eu \n\
|
||||||
pg_lsclusters \n\
|
pg_lsclusters \n\
|
||||||
pg_ctlcluster 9.6 main start \n\
|
pg_ctlcluster 13 main start \n\
|
||||||
\n\
|
\n\
|
||||||
until pg_isready \n\
|
until pg_isready \n\
|
||||||
do \n\
|
do \n\
|
||||||
|
|
@ -35,7 +35,7 @@ RUN --mount=target=. \
|
||||||
CGO_ENABLED=${CGO} go build -o /dendrite ./cmd/generate-config && \
|
CGO_ENABLED=${CGO} go build -o /dendrite ./cmd/generate-config && \
|
||||||
CGO_ENABLED=${CGO} go build -o /dendrite ./cmd/generate-keys && \
|
CGO_ENABLED=${CGO} go build -o /dendrite ./cmd/generate-keys && \
|
||||||
CGO_ENABLED=${CGO} go build -o /dendrite/dendrite ./cmd/dendrite && \
|
CGO_ENABLED=${CGO} go build -o /dendrite/dendrite ./cmd/dendrite && \
|
||||||
CGO_ENABLED=${CGO} go test -c -cover -covermode=atomic -o /dendrite/dendrite-cover -coverpkg "github.com/matrix-org/..." ./cmd/dendrite && \
|
CGO_ENABLED=${CGO} go build -cover -covermode=atomic -o /dendrite/dendrite-cover -coverpkg "github.com/matrix-org/..." ./cmd/dendrite && \
|
||||||
cp build/scripts/complement-cmd.sh /complement-cmd.sh
|
cp build/scripts/complement-cmd.sh /complement-cmd.sh
|
||||||
|
|
||||||
WORKDIR /dendrite
|
WORKDIR /dendrite
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,15 @@
|
||||||
|
|
||||||
# This script is intended to be used inside a docker container for Complement
|
# This script is intended to be used inside a docker container for Complement
|
||||||
|
|
||||||
|
export GOCOVERDIR=/tmp/covdatafiles
|
||||||
|
mkdir -p "${GOCOVERDIR}"
|
||||||
if [[ "${COVER}" -eq 1 ]]; then
|
if [[ "${COVER}" -eq 1 ]]; then
|
||||||
echo "Running with coverage"
|
echo "Running with coverage"
|
||||||
exec /dendrite/dendrite-cover \
|
exec /dendrite/dendrite-cover \
|
||||||
--really-enable-open-registration \
|
--really-enable-open-registration \
|
||||||
--tls-cert server.crt \
|
--tls-cert server.crt \
|
||||||
--tls-key server.key \
|
--tls-key server.key \
|
||||||
--config dendrite.yaml \
|
--config dendrite.yaml
|
||||||
--test.coverprofile=complementcover.log
|
|
||||||
else
|
else
|
||||||
echo "Not running with coverage"
|
echo "Not running with coverage"
|
||||||
exec /dendrite/dendrite \
|
exec /dendrite/dendrite \
|
||||||
|
|
|
||||||
|
|
@ -4,15 +4,22 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
|
|
||||||
"github.com/matrix-org/dendrite/federationapi"
|
"github.com/matrix-org/dendrite/federationapi"
|
||||||
|
"github.com/matrix-org/dendrite/internal/caching"
|
||||||
|
"github.com/matrix-org/dendrite/internal/httputil"
|
||||||
|
"github.com/matrix-org/dendrite/internal/sqlutil"
|
||||||
"github.com/matrix-org/dendrite/roomserver"
|
"github.com/matrix-org/dendrite/roomserver"
|
||||||
"github.com/matrix-org/dendrite/roomserver/api"
|
"github.com/matrix-org/dendrite/roomserver/api"
|
||||||
|
basepkg "github.com/matrix-org/dendrite/setup/base"
|
||||||
"github.com/matrix-org/dendrite/setup/config"
|
"github.com/matrix-org/dendrite/setup/config"
|
||||||
|
"github.com/matrix-org/dendrite/setup/jetstream"
|
||||||
"github.com/matrix-org/dendrite/syncapi"
|
"github.com/matrix-org/dendrite/syncapi"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib/fclient"
|
||||||
"github.com/matrix-org/util"
|
"github.com/matrix-org/util"
|
||||||
"github.com/tidwall/gjson"
|
"github.com/tidwall/gjson"
|
||||||
|
|
||||||
|
|
@ -29,54 +36,30 @@ func TestAdminResetPassword(t *testing.T) {
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
|
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
|
||||||
base, baseClose := testrig.CreateBaseDendrite(t, dbType)
|
cfg, processCtx, close := testrig.CreateConfig(t, dbType)
|
||||||
defer baseClose()
|
defer close()
|
||||||
|
natsInstance := jetstream.NATSInstance{}
|
||||||
// add a vhost
|
// add a vhost
|
||||||
base.Cfg.Global.VirtualHosts = append(base.Cfg.Global.VirtualHosts, &config.VirtualHost{
|
cfg.Global.VirtualHosts = append(cfg.Global.VirtualHosts, &config.VirtualHost{
|
||||||
SigningIdentity: gomatrixserverlib.SigningIdentity{ServerName: "vh1"},
|
SigningIdentity: fclient.SigningIdentity{ServerName: "vh1"},
|
||||||
})
|
})
|
||||||
|
|
||||||
rsAPI := roomserver.NewInternalAPI(base)
|
routers := httputil.NewRouters()
|
||||||
|
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
|
||||||
|
caches := caching.NewRistrettoCache(128*1024*1024, time.Hour, caching.DisableMetrics)
|
||||||
|
rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, &natsInstance, caches, caching.DisableMetrics)
|
||||||
// Needed for changing the password/login
|
// Needed for changing the password/login
|
||||||
userAPI := userapi.NewInternalAPI(base, rsAPI, nil)
|
userAPI := userapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, rsAPI, nil)
|
||||||
// We mostly need the userAPI for this test, so nil for other APIs/caches etc.
|
// We mostly need the userAPI for this test, so nil for other APIs/caches etc.
|
||||||
AddPublicRoutes(base, nil, rsAPI, nil, nil, nil, userAPI, nil, nil)
|
AddPublicRoutes(processCtx, routers, cfg, &natsInstance, nil, rsAPI, nil, nil, nil, userAPI, nil, nil, caching.DisableMetrics)
|
||||||
|
|
||||||
// Create the users in the userapi and login
|
// Create the users in the userapi and login
|
||||||
accessTokens := map[*test.User]string{
|
accessTokens := map[*test.User]userDevice{
|
||||||
aliceAdmin: "",
|
aliceAdmin: {},
|
||||||
bob: "",
|
bob: {},
|
||||||
vhUser: "",
|
vhUser: {},
|
||||||
}
|
|
||||||
for u := range accessTokens {
|
|
||||||
localpart, serverName, _ := gomatrixserverlib.SplitID('@', u.ID)
|
|
||||||
userRes := &uapi.PerformAccountCreationResponse{}
|
|
||||||
password := util.RandomString(8)
|
|
||||||
if err := userAPI.PerformAccountCreation(ctx, &uapi.PerformAccountCreationRequest{
|
|
||||||
AccountType: u.AccountType,
|
|
||||||
Localpart: localpart,
|
|
||||||
ServerName: serverName,
|
|
||||||
Password: password,
|
|
||||||
}, userRes); err != nil {
|
|
||||||
t.Errorf("failed to create account: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
req := test.NewRequest(t, http.MethodPost, "/_matrix/client/v3/login", test.WithJSONBody(t, map[string]interface{}{
|
|
||||||
"type": authtypes.LoginTypePassword,
|
|
||||||
"identifier": map[string]interface{}{
|
|
||||||
"type": "m.id.user",
|
|
||||||
"user": u.ID,
|
|
||||||
},
|
|
||||||
"password": password,
|
|
||||||
}))
|
|
||||||
rec := httptest.NewRecorder()
|
|
||||||
base.PublicClientAPIMux.ServeHTTP(rec, req)
|
|
||||||
if rec.Code != http.StatusOK {
|
|
||||||
t.Fatalf("failed to login: %s", rec.Body.String())
|
|
||||||
}
|
|
||||||
accessTokens[u] = gjson.GetBytes(rec.Body.Bytes(), "access_token").String()
|
|
||||||
}
|
}
|
||||||
|
createAccessTokens(t, accessTokens, userAPI, ctx, routers)
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
|
|
@ -120,11 +103,11 @@ func TestAdminResetPassword(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if tc.withHeader {
|
if tc.withHeader {
|
||||||
req.Header.Set("Authorization", "Bearer "+accessTokens[tc.requestingUser])
|
req.Header.Set("Authorization", "Bearer "+accessTokens[tc.requestingUser].accessToken)
|
||||||
}
|
}
|
||||||
|
|
||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
base.DendriteAdminMux.ServeHTTP(rec, req)
|
routers.DendriteAdmin.ServeHTTP(rec, req)
|
||||||
t.Logf("%s", rec.Body.String())
|
t.Logf("%s", rec.Body.String())
|
||||||
if tc.wantOK && rec.Code != http.StatusOK {
|
if tc.wantOK && rec.Code != http.StatusOK {
|
||||||
t.Fatalf("expected http status %d, got %d: %s", http.StatusOK, rec.Code, rec.Body.String())
|
t.Fatalf("expected http status %d, got %d: %s", http.StatusOK, rec.Code, rec.Body.String())
|
||||||
|
|
@ -147,16 +130,19 @@ func TestPurgeRoom(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
|
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
|
||||||
base, baseClose := testrig.CreateBaseDendrite(t, dbType)
|
cfg, processCtx, close := testrig.CreateConfig(t, dbType)
|
||||||
defer baseClose()
|
caches := caching.NewRistrettoCache(128*1024*1024, time.Hour, caching.DisableMetrics)
|
||||||
|
natsInstance := jetstream.NATSInstance{}
|
||||||
|
defer close()
|
||||||
|
|
||||||
fedClient := base.CreateFederationClient()
|
routers := httputil.NewRouters()
|
||||||
rsAPI := roomserver.NewInternalAPI(base)
|
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
|
||||||
userAPI := userapi.NewInternalAPI(base, rsAPI, nil)
|
rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, &natsInstance, caches, caching.DisableMetrics)
|
||||||
|
userAPI := userapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, rsAPI, nil)
|
||||||
|
|
||||||
// this starts the JetStream consumers
|
// this starts the JetStream consumers
|
||||||
syncapi.AddPublicRoutes(base, userAPI, rsAPI)
|
syncapi.AddPublicRoutes(processCtx, routers, cfg, cm, &natsInstance, userAPI, rsAPI, caches, caching.DisableMetrics)
|
||||||
federationapi.NewInternalAPI(base, fedClient, rsAPI, base.Caches, nil, true)
|
federationapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, nil, rsAPI, caches, nil, true)
|
||||||
rsAPI.SetFederationAPI(nil, nil)
|
rsAPI.SetFederationAPI(nil, nil)
|
||||||
|
|
||||||
// Create the room
|
// Create the room
|
||||||
|
|
@ -165,40 +151,13 @@ func TestPurgeRoom(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// We mostly need the rsAPI for this test, so nil for other APIs/caches etc.
|
// We mostly need the rsAPI for this test, so nil for other APIs/caches etc.
|
||||||
AddPublicRoutes(base, nil, rsAPI, nil, nil, nil, userAPI, nil, nil)
|
AddPublicRoutes(processCtx, routers, cfg, &natsInstance, nil, rsAPI, nil, nil, nil, userAPI, nil, nil, caching.DisableMetrics)
|
||||||
|
|
||||||
// Create the users in the userapi and login
|
// Create the users in the userapi and login
|
||||||
accessTokens := map[*test.User]string{
|
accessTokens := map[*test.User]userDevice{
|
||||||
aliceAdmin: "",
|
aliceAdmin: {},
|
||||||
}
|
|
||||||
for u := range accessTokens {
|
|
||||||
localpart, serverName, _ := gomatrixserverlib.SplitID('@', u.ID)
|
|
||||||
userRes := &uapi.PerformAccountCreationResponse{}
|
|
||||||
password := util.RandomString(8)
|
|
||||||
if err := userAPI.PerformAccountCreation(ctx, &uapi.PerformAccountCreationRequest{
|
|
||||||
AccountType: u.AccountType,
|
|
||||||
Localpart: localpart,
|
|
||||||
ServerName: serverName,
|
|
||||||
Password: password,
|
|
||||||
}, userRes); err != nil {
|
|
||||||
t.Errorf("failed to create account: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
req := test.NewRequest(t, http.MethodPost, "/_matrix/client/v3/login", test.WithJSONBody(t, map[string]interface{}{
|
|
||||||
"type": authtypes.LoginTypePassword,
|
|
||||||
"identifier": map[string]interface{}{
|
|
||||||
"type": "m.id.user",
|
|
||||||
"user": u.ID,
|
|
||||||
},
|
|
||||||
"password": password,
|
|
||||||
}))
|
|
||||||
rec := httptest.NewRecorder()
|
|
||||||
base.PublicClientAPIMux.ServeHTTP(rec, req)
|
|
||||||
if rec.Code != http.StatusOK {
|
|
||||||
t.Fatalf("failed to login: %s", rec.Body.String())
|
|
||||||
}
|
|
||||||
accessTokens[u] = gjson.GetBytes(rec.Body.Bytes(), "access_token").String()
|
|
||||||
}
|
}
|
||||||
|
createAccessTokens(t, accessTokens, userAPI, ctx, routers)
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
|
|
@ -215,10 +174,10 @@ func TestPurgeRoom(t *testing.T) {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
req := test.NewRequest(t, http.MethodPost, "/_dendrite/admin/purgeRoom/"+tc.roomID)
|
req := test.NewRequest(t, http.MethodPost, "/_dendrite/admin/purgeRoom/"+tc.roomID)
|
||||||
|
|
||||||
req.Header.Set("Authorization", "Bearer "+accessTokens[aliceAdmin])
|
req.Header.Set("Authorization", "Bearer "+accessTokens[aliceAdmin].accessToken)
|
||||||
|
|
||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
base.DendriteAdminMux.ServeHTTP(rec, req)
|
routers.DendriteAdmin.ServeHTTP(rec, req)
|
||||||
t.Logf("%s", rec.Body.String())
|
t.Logf("%s", rec.Body.String())
|
||||||
if tc.wantOK && rec.Code != http.StatusOK {
|
if tc.wantOK && rec.Code != http.StatusOK {
|
||||||
t.Fatalf("expected http status %d, got %d: %s", http.StatusOK, rec.Code, rec.Body.String())
|
t.Fatalf("expected http status %d, got %d: %s", http.StatusOK, rec.Code, rec.Body.String())
|
||||||
|
|
@ -228,3 +187,256 @@ func TestPurgeRoom(t *testing.T) {
|
||||||
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAdminEvacuateRoom(t *testing.T) {
|
||||||
|
aliceAdmin := test.NewUser(t, test.WithAccountType(uapi.AccountTypeAdmin))
|
||||||
|
bob := test.NewUser(t)
|
||||||
|
room := test.NewRoom(t, aliceAdmin)
|
||||||
|
|
||||||
|
// Join Bob
|
||||||
|
room.CreateAndInsert(t, bob, gomatrixserverlib.MRoomMember, map[string]interface{}{
|
||||||
|
"membership": "join",
|
||||||
|
}, test.WithStateKey(bob.ID))
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
|
||||||
|
cfg, processCtx, close := testrig.CreateConfig(t, dbType)
|
||||||
|
caches := caching.NewRistrettoCache(128*1024*1024, time.Hour, caching.DisableMetrics)
|
||||||
|
natsInstance := jetstream.NATSInstance{}
|
||||||
|
defer close()
|
||||||
|
|
||||||
|
routers := httputil.NewRouters()
|
||||||
|
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
|
||||||
|
rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, &natsInstance, caches, caching.DisableMetrics)
|
||||||
|
userAPI := userapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, rsAPI, nil)
|
||||||
|
|
||||||
|
// this starts the JetStream consumers
|
||||||
|
fsAPI := federationapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, nil, rsAPI, caches, nil, true)
|
||||||
|
rsAPI.SetFederationAPI(fsAPI, nil)
|
||||||
|
|
||||||
|
// Create the room
|
||||||
|
if err := api.SendEvents(ctx, rsAPI, api.KindNew, room.Events(), "test", "test", api.DoNotSendToOtherServers, nil, false); err != nil {
|
||||||
|
t.Fatalf("failed to send events: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We mostly need the rsAPI for this test, so nil for other APIs/caches etc.
|
||||||
|
AddPublicRoutes(processCtx, routers, cfg, &natsInstance, nil, rsAPI, nil, nil, nil, userAPI, nil, nil, caching.DisableMetrics)
|
||||||
|
|
||||||
|
// Create the users in the userapi and login
|
||||||
|
accessTokens := map[*test.User]userDevice{
|
||||||
|
aliceAdmin: {},
|
||||||
|
}
|
||||||
|
createAccessTokens(t, accessTokens, userAPI, ctx, routers)
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
roomID string
|
||||||
|
wantOK bool
|
||||||
|
wantAffected []string
|
||||||
|
}{
|
||||||
|
{name: "Can evacuate existing room", wantOK: true, roomID: room.ID, wantAffected: []string{aliceAdmin.ID, bob.ID}},
|
||||||
|
{name: "Can not evacuate non-existent room", wantOK: false, roomID: "!doesnotexist:localhost", wantAffected: []string{}},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
req := test.NewRequest(t, http.MethodPost, "/_dendrite/admin/evacuateRoom/"+tc.roomID)
|
||||||
|
|
||||||
|
req.Header.Set("Authorization", "Bearer "+accessTokens[aliceAdmin].accessToken)
|
||||||
|
|
||||||
|
rec := httptest.NewRecorder()
|
||||||
|
routers.DendriteAdmin.ServeHTTP(rec, req)
|
||||||
|
t.Logf("%s", rec.Body.String())
|
||||||
|
if tc.wantOK && rec.Code != http.StatusOK {
|
||||||
|
t.Fatalf("expected http status %d, got %d: %s", http.StatusOK, rec.Code, rec.Body.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
affectedArr := gjson.GetBytes(rec.Body.Bytes(), "affected").Array()
|
||||||
|
affected := make([]string, 0, len(affectedArr))
|
||||||
|
for _, x := range affectedArr {
|
||||||
|
affected = append(affected, x.Str)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(affected, tc.wantAffected) {
|
||||||
|
t.Fatalf("expected affected %#v, but got %#v", tc.wantAffected, affected)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for the FS API to have consumed every message
|
||||||
|
js, _ := natsInstance.Prepare(processCtx, &cfg.Global.JetStream)
|
||||||
|
timeout := time.After(time.Second)
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-timeout:
|
||||||
|
t.Fatalf("FS API didn't process all events in time")
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
info, err := js.ConsumerInfo(cfg.Global.JetStream.Prefixed(jetstream.OutputRoomEvent), cfg.Global.JetStream.Durable("FederationAPIRoomServerConsumer")+"Pull")
|
||||||
|
if err != nil {
|
||||||
|
time.Sleep(time.Millisecond * 10)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if info.NumPending == 0 && info.NumAckPending == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAdminEvacuateUser(t *testing.T) {
|
||||||
|
aliceAdmin := test.NewUser(t, test.WithAccountType(uapi.AccountTypeAdmin))
|
||||||
|
bob := test.NewUser(t)
|
||||||
|
room := test.NewRoom(t, aliceAdmin)
|
||||||
|
room2 := test.NewRoom(t, aliceAdmin)
|
||||||
|
|
||||||
|
// Join Bob
|
||||||
|
room.CreateAndInsert(t, bob, gomatrixserverlib.MRoomMember, map[string]interface{}{
|
||||||
|
"membership": "join",
|
||||||
|
}, test.WithStateKey(bob.ID))
|
||||||
|
room2.CreateAndInsert(t, bob, gomatrixserverlib.MRoomMember, map[string]interface{}{
|
||||||
|
"membership": "join",
|
||||||
|
}, test.WithStateKey(bob.ID))
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
|
||||||
|
cfg, processCtx, close := testrig.CreateConfig(t, dbType)
|
||||||
|
caches := caching.NewRistrettoCache(128*1024*1024, time.Hour, caching.DisableMetrics)
|
||||||
|
natsInstance := jetstream.NATSInstance{}
|
||||||
|
defer close()
|
||||||
|
|
||||||
|
routers := httputil.NewRouters()
|
||||||
|
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
|
||||||
|
rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, &natsInstance, caches, caching.DisableMetrics)
|
||||||
|
userAPI := userapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, rsAPI, nil)
|
||||||
|
|
||||||
|
// this starts the JetStream consumers
|
||||||
|
fsAPI := federationapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, basepkg.CreateFederationClient(cfg, nil), rsAPI, caches, nil, true)
|
||||||
|
rsAPI.SetFederationAPI(fsAPI, nil)
|
||||||
|
|
||||||
|
// Create the room
|
||||||
|
if err := api.SendEvents(ctx, rsAPI, api.KindNew, room.Events(), "test", "test", api.DoNotSendToOtherServers, nil, false); err != nil {
|
||||||
|
t.Fatalf("failed to send events: %v", err)
|
||||||
|
}
|
||||||
|
if err := api.SendEvents(ctx, rsAPI, api.KindNew, room2.Events(), "test", "test", api.DoNotSendToOtherServers, nil, false); err != nil {
|
||||||
|
t.Fatalf("failed to send events: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We mostly need the rsAPI for this test, so nil for other APIs/caches etc.
|
||||||
|
AddPublicRoutes(processCtx, routers, cfg, &natsInstance, nil, rsAPI, nil, nil, nil, userAPI, nil, nil, caching.DisableMetrics)
|
||||||
|
|
||||||
|
// Create the users in the userapi and login
|
||||||
|
accessTokens := map[*test.User]userDevice{
|
||||||
|
aliceAdmin: {},
|
||||||
|
}
|
||||||
|
createAccessTokens(t, accessTokens, userAPI, ctx, routers)
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
userID string
|
||||||
|
wantOK bool
|
||||||
|
wantAffectedRooms []string
|
||||||
|
}{
|
||||||
|
{name: "Can evacuate existing user", wantOK: true, userID: bob.ID, wantAffectedRooms: []string{room.ID, room2.ID}},
|
||||||
|
{name: "invalid userID is rejected", wantOK: false, userID: "!notauserid:test", wantAffectedRooms: []string{}},
|
||||||
|
{name: "Can not evacuate user from different server", wantOK: false, userID: "@doesnotexist:localhost", wantAffectedRooms: []string{}},
|
||||||
|
{name: "Can not evacuate non-existent user", wantOK: false, userID: "@doesnotexist:test", wantAffectedRooms: []string{}},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
req := test.NewRequest(t, http.MethodPost, "/_dendrite/admin/evacuateUser/"+tc.userID)
|
||||||
|
|
||||||
|
req.Header.Set("Authorization", "Bearer "+accessTokens[aliceAdmin].accessToken)
|
||||||
|
|
||||||
|
rec := httptest.NewRecorder()
|
||||||
|
routers.DendriteAdmin.ServeHTTP(rec, req)
|
||||||
|
t.Logf("%s", rec.Body.String())
|
||||||
|
if tc.wantOK && rec.Code != http.StatusOK {
|
||||||
|
t.Fatalf("expected http status %d, got %d: %s", http.StatusOK, rec.Code, rec.Body.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
affectedArr := gjson.GetBytes(rec.Body.Bytes(), "affected").Array()
|
||||||
|
affected := make([]string, 0, len(affectedArr))
|
||||||
|
for _, x := range affectedArr {
|
||||||
|
affected = append(affected, x.Str)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(affected, tc.wantAffectedRooms) {
|
||||||
|
t.Fatalf("expected affected %#v, but got %#v", tc.wantAffectedRooms, affected)
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// Wait for the FS API to have consumed every message
|
||||||
|
js, _ := natsInstance.Prepare(processCtx, &cfg.Global.JetStream)
|
||||||
|
timeout := time.After(time.Second)
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-timeout:
|
||||||
|
t.Fatalf("FS API didn't process all events in time")
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
info, err := js.ConsumerInfo(cfg.Global.JetStream.Prefixed(jetstream.OutputRoomEvent), cfg.Global.JetStream.Durable("FederationAPIRoomServerConsumer")+"Pull")
|
||||||
|
if err != nil {
|
||||||
|
time.Sleep(time.Millisecond * 10)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if info.NumPending == 0 && info.NumAckPending == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAdminMarkAsStale(t *testing.T) {
|
||||||
|
aliceAdmin := test.NewUser(t, test.WithAccountType(uapi.AccountTypeAdmin))
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
|
||||||
|
cfg, processCtx, close := testrig.CreateConfig(t, dbType)
|
||||||
|
caches := caching.NewRistrettoCache(128*1024*1024, time.Hour, caching.DisableMetrics)
|
||||||
|
natsInstance := jetstream.NATSInstance{}
|
||||||
|
defer close()
|
||||||
|
|
||||||
|
routers := httputil.NewRouters()
|
||||||
|
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
|
||||||
|
rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, &natsInstance, caches, caching.DisableMetrics)
|
||||||
|
userAPI := userapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, rsAPI, nil)
|
||||||
|
|
||||||
|
// We mostly need the rsAPI for this test, so nil for other APIs/caches etc.
|
||||||
|
AddPublicRoutes(processCtx, routers, cfg, &natsInstance, nil, rsAPI, nil, nil, nil, userAPI, nil, nil, caching.DisableMetrics)
|
||||||
|
|
||||||
|
// Create the users in the userapi and login
|
||||||
|
accessTokens := map[*test.User]userDevice{
|
||||||
|
aliceAdmin: {},
|
||||||
|
}
|
||||||
|
createAccessTokens(t, accessTokens, userAPI, ctx, routers)
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
userID string
|
||||||
|
wantOK bool
|
||||||
|
}{
|
||||||
|
{name: "local user is not allowed", userID: aliceAdmin.ID},
|
||||||
|
{name: "invalid userID", userID: "!notvalid:test"},
|
||||||
|
{name: "remote user is allowed", userID: "@alice:localhost", wantOK: true},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
req := test.NewRequest(t, http.MethodPost, "/_dendrite/admin/refreshDevices/"+tc.userID)
|
||||||
|
|
||||||
|
req.Header.Set("Authorization", "Bearer "+accessTokens[aliceAdmin].accessToken)
|
||||||
|
|
||||||
|
rec := httptest.NewRecorder()
|
||||||
|
routers.DendriteAdmin.ServeHTTP(rec, req)
|
||||||
|
t.Logf("%s", rec.Body.String())
|
||||||
|
if tc.wantOK && rec.Code != http.StatusOK {
|
||||||
|
t.Fatalf("expected http status %d, got %d: %s", http.StatusOK, rec.Code, rec.Body.String())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,10 +14,10 @@
|
||||||
|
|
||||||
package api
|
package api
|
||||||
|
|
||||||
import "github.com/matrix-org/gomatrixserverlib"
|
import "github.com/matrix-org/gomatrixserverlib/fclient"
|
||||||
|
|
||||||
// ExtraPublicRoomsProvider provides a way to inject extra published rooms into /publicRooms requests.
|
// ExtraPublicRoomsProvider provides a way to inject extra published rooms into /publicRooms requests.
|
||||||
type ExtraPublicRoomsProvider interface {
|
type ExtraPublicRoomsProvider interface {
|
||||||
// Rooms returns the extra rooms. This is called on-demand by clients, so cache appropriately.
|
// Rooms returns the extra rooms. This is called on-demand by clients, so cache appropriately.
|
||||||
Rooms() []gomatrixserverlib.PublicRoom
|
Rooms() []fclient.PublicRoom
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,4 +18,6 @@ package authtypes
|
||||||
type ThreePID struct {
|
type ThreePID struct {
|
||||||
Address string `json:"address"`
|
Address string `json:"address"`
|
||||||
Medium string `json:"medium"`
|
Medium string `json:"medium"`
|
||||||
|
AddedAt int64 `json:"added_at"`
|
||||||
|
ValidatedAt int64 `json:"validated_at"`
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,7 @@ func LoginFromJSONReader(ctx context.Context, r io.Reader, useraccountAPI uapi.C
|
||||||
Config: cfg,
|
Config: cfg,
|
||||||
Rt: rt,
|
Rt: rt,
|
||||||
InhibitDevice: header.InhibitDevice,
|
InhibitDevice: header.InhibitDevice,
|
||||||
|
UserAPI: useraccountAPI,
|
||||||
}
|
}
|
||||||
case authtypes.LoginTypeToken:
|
case authtypes.LoginTypeToken:
|
||||||
typ = &LoginTypeToken{
|
typ = &LoginTypeToken{
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ import (
|
||||||
"github.com/matrix-org/dendrite/clientapi/userutil"
|
"github.com/matrix-org/dendrite/clientapi/userutil"
|
||||||
"github.com/matrix-org/dendrite/setup/config"
|
"github.com/matrix-org/dendrite/setup/config"
|
||||||
uapi "github.com/matrix-org/dendrite/userapi/api"
|
uapi "github.com/matrix-org/dendrite/userapi/api"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib/fclient"
|
||||||
"github.com/matrix-org/util"
|
"github.com/matrix-org/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -69,7 +69,7 @@ func TestLoginFromJSONReader(t *testing.T) {
|
||||||
var userAPI fakeUserInternalAPI
|
var userAPI fakeUserInternalAPI
|
||||||
cfg := &config.ClientAPI{
|
cfg := &config.ClientAPI{
|
||||||
Matrix: &config.Global{
|
Matrix: &config.Global{
|
||||||
SigningIdentity: gomatrixserverlib.SigningIdentity{
|
SigningIdentity: fclient.SigningIdentity{
|
||||||
ServerName: serverName,
|
ServerName: serverName,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -152,7 +152,7 @@ func TestBadLoginFromJSONReader(t *testing.T) {
|
||||||
var userAPI fakeUserInternalAPI
|
var userAPI fakeUserInternalAPI
|
||||||
cfg := &config.ClientAPI{
|
cfg := &config.ClientAPI{
|
||||||
Matrix: &config.Global{
|
Matrix: &config.Global{
|
||||||
SigningIdentity: gomatrixserverlib.SigningIdentity{
|
SigningIdentity: fclient.SigningIdentity{
|
||||||
ServerName: serverName,
|
ServerName: serverName,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -16,9 +16,14 @@ package auth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"database/sql"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/go-ldap/ldap/v3"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
|
"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
|
||||||
"github.com/matrix-org/dendrite/clientapi/httputil"
|
"github.com/matrix-org/dendrite/clientapi/httputil"
|
||||||
"github.com/matrix-org/dendrite/clientapi/jsonerror"
|
"github.com/matrix-org/dendrite/clientapi/jsonerror"
|
||||||
|
|
@ -29,8 +34,6 @@ import (
|
||||||
"github.com/matrix-org/util"
|
"github.com/matrix-org/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
type GetAccountByPassword func(ctx context.Context, req *api.QueryAccountByPasswordRequest, res *api.QueryAccountByPasswordResponse) error
|
|
||||||
|
|
||||||
type PasswordRequest struct {
|
type PasswordRequest struct {
|
||||||
Login
|
Login
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
|
|
@ -46,6 +49,7 @@ type LoginTypePassword struct {
|
||||||
Config *config.ClientAPI
|
Config *config.ClientAPI
|
||||||
Rt *ratelimit.RtFailedLogin
|
Rt *ratelimit.RtFailedLogin
|
||||||
InhibitDevice bool
|
InhibitDevice bool
|
||||||
|
UserAPI api.UserLoginAPI
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *LoginTypePassword) Name() string {
|
func (t *LoginTypePassword) Name() string {
|
||||||
|
|
@ -123,6 +127,7 @@ func (t *LoginTypePassword) Login(ctx context.Context, req interface{}) (*Login,
|
||||||
JSON: jsonerror.InvalidUsername("The server name is not known."),
|
JSON: jsonerror.InvalidUsername("The server name is not known."),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Squash username to all lowercase letters
|
// Squash username to all lowercase letters
|
||||||
res := &api.QueryAccountByPasswordResponse{}
|
res := &api.QueryAccountByPasswordResponse{}
|
||||||
if t.Rt != nil {
|
if t.Rt != nil {
|
||||||
|
|
@ -146,13 +151,53 @@ func (t *LoginTypePassword) Login(ctx context.Context, req interface{}) (*Login,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var account *api.Account
|
||||||
|
if t.Config.Ldap.Enabled {
|
||||||
|
isAdmin, err := t.authenticateLdap(localpart, r.Password)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
acc, err := t.getOrCreateAccount(ctx, localpart, domain, isAdmin)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
account = acc
|
||||||
|
} else {
|
||||||
|
acc, err := t.authenticateDb(ctx, localpart, domain, r.Password)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
account = acc
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the user, so login.Username() can do the right thing
|
||||||
|
r.Identifier.User = account.UserID
|
||||||
|
r.User = account.UserID
|
||||||
|
r.Login.User = username
|
||||||
|
return &r.Login, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *LoginTypePassword) authenticateDb(ctx context.Context, localpart string, domain gomatrixserverlib.ServerName, password string) (*api.Account, *util.JSONResponse) {
|
||||||
|
res := &api.QueryAccountByPasswordResponse{}
|
||||||
|
err := t.UserAPI.QueryAccountByPassword(ctx, &api.QueryAccountByPasswordRequest{
|
||||||
|
Localpart: strings.ToLower(localpart),
|
||||||
|
ServerName: domain,
|
||||||
|
PlaintextPassword: password,
|
||||||
|
}, res)
|
||||||
|
if err != nil {
|
||||||
|
return nil, &util.JSONResponse{
|
||||||
|
Code: http.StatusInternalServerError,
|
||||||
|
JSON: jsonerror.Unknown("Unable to fetch account by password."),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If we couldn't find the user by the lower cased localpart, try the provided
|
// If we couldn't find the user by the lower cased localpart, try the provided
|
||||||
// localpart as is.
|
// localpart as is.
|
||||||
if !res.Exists {
|
if !res.Exists {
|
||||||
err = t.UserApi.QueryAccountByPassword(ctx, &api.QueryAccountByPasswordRequest{
|
err = t.UserAPI.QueryAccountByPassword(ctx, &api.QueryAccountByPasswordRequest{
|
||||||
Localpart: localpart,
|
Localpart: localpart,
|
||||||
ServerName: domain,
|
ServerName: domain,
|
||||||
PlaintextPassword: r.Password,
|
PlaintextPassword: password,
|
||||||
}, res)
|
}, res)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, &util.JSONResponse{
|
return nil, &util.JSONResponse{
|
||||||
|
|
@ -163,18 +208,149 @@ func (t *LoginTypePassword) Login(ctx context.Context, req interface{}) (*Login,
|
||||||
// Technically we could tell them if the user does not exist by checking if err == sql.ErrNoRows
|
// Technically we could tell them if the user does not exist by checking if err == sql.ErrNoRows
|
||||||
// but that would leak the existence of the user.
|
// but that would leak the existence of the user.
|
||||||
if !res.Exists {
|
if !res.Exists {
|
||||||
if t.Rt != nil {
|
|
||||||
t.Rt.Act(localpart)
|
|
||||||
}
|
|
||||||
return nil, &util.JSONResponse{
|
return nil, &util.JSONResponse{
|
||||||
Code: http.StatusForbidden,
|
Code: http.StatusForbidden,
|
||||||
JSON: jsonerror.Forbidden("Invalid username or password"),
|
JSON: jsonerror.Forbidden("The username or password was incorrect or the account does not exist."),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Set the user, so login.Username() can do the right thing
|
return res.Account, nil
|
||||||
r.Identifier.User = res.Account.UserID
|
}
|
||||||
r.User = res.Account.UserID
|
|
||||||
r.Login.User = username
|
func (t *LoginTypePassword) authenticateLdap(username, password string) (bool, *util.JSONResponse) {
|
||||||
return &r.Login, nil
|
var conn *ldap.Conn
|
||||||
|
conn, err := ldap.DialURL(t.Config.Ldap.Uri)
|
||||||
|
if err != nil {
|
||||||
|
return false, &util.JSONResponse{
|
||||||
|
Code: http.StatusInternalServerError,
|
||||||
|
JSON: jsonerror.Unknown("unable to connect to ldap: " + err.Error()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
if t.Config.Ldap.AdminBindEnabled {
|
||||||
|
err = conn.Bind(t.Config.Ldap.AdminBindDn, t.Config.Ldap.AdminBindPassword)
|
||||||
|
if err != nil {
|
||||||
|
return false, &util.JSONResponse{
|
||||||
|
Code: http.StatusInternalServerError,
|
||||||
|
JSON: jsonerror.Unknown("unable to bind to ldap: " + err.Error()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
filter := strings.ReplaceAll(t.Config.Ldap.SearchFilter, "{username}", username)
|
||||||
|
searchRequest := ldap.NewSearchRequest(
|
||||||
|
t.Config.Ldap.BaseDn, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases,
|
||||||
|
0, 0, false, filter, []string{t.Config.Ldap.SearchAttribute}, nil,
|
||||||
|
)
|
||||||
|
var result *ldap.SearchResult
|
||||||
|
result, err = conn.Search(searchRequest)
|
||||||
|
if err != nil {
|
||||||
|
return false, &util.JSONResponse{
|
||||||
|
Code: http.StatusInternalServerError,
|
||||||
|
JSON: jsonerror.Unknown("unable to bind to search ldap: " + err.Error()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(result.Entries) > 1 {
|
||||||
|
return false, &util.JSONResponse{
|
||||||
|
Code: http.StatusUnauthorized,
|
||||||
|
JSON: jsonerror.BadJSON("'user' must be duplicated."),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(result.Entries) < 1 {
|
||||||
|
return false, &util.JSONResponse{
|
||||||
|
Code: http.StatusUnauthorized,
|
||||||
|
JSON: jsonerror.BadJSON("'user' not found."),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
userDN := result.Entries[0].DN
|
||||||
|
err = conn.Bind(userDN, password)
|
||||||
|
if err != nil {
|
||||||
|
return false, &util.JSONResponse{
|
||||||
|
Code: http.StatusUnauthorized,
|
||||||
|
JSON: jsonerror.InvalidUsername(err.Error()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
bindDn := strings.ReplaceAll(t.Config.Ldap.UserBindDn, "{username}", username)
|
||||||
|
err = conn.Bind(bindDn, password)
|
||||||
|
if err != nil {
|
||||||
|
return false, &util.JSONResponse{
|
||||||
|
Code: http.StatusUnauthorized,
|
||||||
|
JSON: jsonerror.InvalidUsername(err.Error()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isAdmin, err := t.isLdapAdmin(conn, username)
|
||||||
|
if err != nil {
|
||||||
|
return false, &util.JSONResponse{
|
||||||
|
Code: http.StatusUnauthorized,
|
||||||
|
JSON: jsonerror.InvalidUsername(err.Error()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return isAdmin, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *LoginTypePassword) isLdapAdmin(conn *ldap.Conn, username string) (bool, error) {
|
||||||
|
searchRequest := ldap.NewSearchRequest(
|
||||||
|
t.Config.Ldap.AdminGroupDn,
|
||||||
|
ldap.ScopeWholeSubtree, ldap.DerefAlways, 0, 0, false,
|
||||||
|
strings.ReplaceAll(t.Config.Ldap.AdminGroupFilter, "{username}", username),
|
||||||
|
[]string{t.Config.Ldap.AdminGroupAttribute},
|
||||||
|
nil)
|
||||||
|
|
||||||
|
sr, err := conn.Search(searchRequest)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(sr.Entries) < 1 {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *LoginTypePassword) getOrCreateAccount(ctx context.Context, username string, domain gomatrixserverlib.ServerName, admin bool) (*api.Account, *util.JSONResponse) {
|
||||||
|
var existing api.QueryAccountByLocalpartResponse
|
||||||
|
err := t.UserAPI.QueryAccountByLocalpart(ctx, &api.QueryAccountByLocalpartRequest{
|
||||||
|
Localpart: username,
|
||||||
|
ServerName: domain,
|
||||||
|
}, &existing)
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
return existing.Account, nil
|
||||||
|
}
|
||||||
|
if err != sql.ErrNoRows {
|
||||||
|
return nil, &util.JSONResponse{
|
||||||
|
Code: http.StatusUnauthorized,
|
||||||
|
JSON: jsonerror.InvalidUsername(err.Error()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
accountType := api.AccountTypeUser
|
||||||
|
if admin {
|
||||||
|
accountType = api.AccountTypeAdmin
|
||||||
|
}
|
||||||
|
var created api.PerformAccountCreationResponse
|
||||||
|
err = t.UserAPI.PerformAccountCreation(ctx, &api.PerformAccountCreationRequest{
|
||||||
|
AppServiceID: "ldap",
|
||||||
|
Localpart: username,
|
||||||
|
Password: uuid.New().String(),
|
||||||
|
AccountType: accountType,
|
||||||
|
OnConflict: api.ConflictAbort,
|
||||||
|
}, &created)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
if _, ok := err.(*api.ErrorConflict); ok {
|
||||||
|
return nil, &util.JSONResponse{
|
||||||
|
Code: http.StatusBadRequest,
|
||||||
|
JSON: jsonerror.UserInUse("Desired user ID is already taken."),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, &util.JSONResponse{
|
||||||
|
Code: http.StatusInternalServerError,
|
||||||
|
JSON: jsonerror.Unknown("failed to create account: " + err.Error()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return created.Account, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -115,6 +115,7 @@ type UserInteractive struct {
|
||||||
func NewUserInteractive(userAccountAPI api.ClientUserAPI, cfg *config.ClientAPI) *UserInteractive {
|
func NewUserInteractive(userAccountAPI api.ClientUserAPI, cfg *config.ClientAPI) *UserInteractive {
|
||||||
typePassword := &LoginTypePassword{
|
typePassword := &LoginTypePassword{
|
||||||
UserApi: userAccountAPI,
|
UserApi: userAccountAPI,
|
||||||
|
UserAPI: userAccountAPI,
|
||||||
Config: cfg,
|
Config: cfg,
|
||||||
}
|
}
|
||||||
return &UserInteractive{
|
return &UserInteractive{
|
||||||
|
|
@ -141,7 +142,7 @@ func (u *UserInteractive) IsSingleStageFlow(authType string) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *UserInteractive) AddCompletedStage(sessionID, authType string) {
|
func (u *UserInteractive) AddCompletedStage(sessionID, _ string) {
|
||||||
u.Lock()
|
u.Lock()
|
||||||
// TODO: Handle multi-stage flows
|
// TODO: Handle multi-stage flows
|
||||||
delete(u.Sessions, sessionID)
|
delete(u.Sessions, sessionID)
|
||||||
|
|
@ -215,7 +216,7 @@ func (u *UserInteractive) ResponseWithChallenge(sessionID string, response inter
|
||||||
// Verify returns an error/challenge response to send to the client, or nil if the user is authenticated.
|
// Verify returns an error/challenge response to send to the client, or nil if the user is authenticated.
|
||||||
// `bodyBytes` is the HTTP request body which must contain an `auth` key.
|
// `bodyBytes` is the HTTP request body which must contain an `auth` key.
|
||||||
// Returns the login that was verified for additional checks if required.
|
// Returns the login that was verified for additional checks if required.
|
||||||
func (u *UserInteractive) Verify(ctx context.Context, bodyBytes []byte, device *api.Device) (*Login, *util.JSONResponse) {
|
func (u *UserInteractive) Verify(ctx context.Context, bodyBytes []byte, _ *api.Device) (*Login, *util.JSONResponse) {
|
||||||
// TODO: rate limit
|
// TODO: rate limit
|
||||||
|
|
||||||
// "A client should first make a request with no auth parameter. The homeserver returns an HTTP 401 response, with a JSON body"
|
// "A client should first make a request with no auth parameter. The homeserver returns an HTTP 401 response, with a JSON body"
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"github.com/matrix-org/dendrite/setup/config"
|
"github.com/matrix-org/dendrite/setup/config"
|
||||||
"github.com/matrix-org/dendrite/userapi/api"
|
"github.com/matrix-org/dendrite/userapi/api"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib/fclient"
|
||||||
"github.com/matrix-org/util"
|
"github.com/matrix-org/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -49,7 +50,7 @@ func (d *fakeAccountDatabase) QueryAccountByPassword(ctx context.Context, req *a
|
||||||
func setup() *UserInteractive {
|
func setup() *UserInteractive {
|
||||||
cfg := &config.ClientAPI{
|
cfg := &config.ClientAPI{
|
||||||
Matrix: &config.Global{
|
Matrix: &config.Global{
|
||||||
SigningIdentity: gomatrixserverlib.SigningIdentity{
|
SigningIdentity: fclient.SigningIdentity{
|
||||||
ServerName: serverName,
|
ServerName: serverName,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,11 @@
|
||||||
package clientapi
|
package clientapi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/matrix-org/dendrite/internal/httputil"
|
||||||
|
"github.com/matrix-org/dendrite/setup/config"
|
||||||
|
"github.com/matrix-org/dendrite/setup/process"
|
||||||
userapi "github.com/matrix-org/dendrite/userapi/api"
|
userapi "github.com/matrix-org/dendrite/userapi/api"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib/fclient"
|
||||||
|
|
||||||
appserviceAPI "github.com/matrix-org/dendrite/appservice/api"
|
appserviceAPI "github.com/matrix-org/dendrite/appservice/api"
|
||||||
"github.com/matrix-org/dendrite/clientapi/api"
|
"github.com/matrix-org/dendrite/clientapi/api"
|
||||||
|
|
@ -25,42 +28,42 @@ import (
|
||||||
federationAPI "github.com/matrix-org/dendrite/federationapi/api"
|
federationAPI "github.com/matrix-org/dendrite/federationapi/api"
|
||||||
"github.com/matrix-org/dendrite/internal/transactions"
|
"github.com/matrix-org/dendrite/internal/transactions"
|
||||||
roomserverAPI "github.com/matrix-org/dendrite/roomserver/api"
|
roomserverAPI "github.com/matrix-org/dendrite/roomserver/api"
|
||||||
"github.com/matrix-org/dendrite/setup/base"
|
|
||||||
"github.com/matrix-org/dendrite/setup/jetstream"
|
"github.com/matrix-org/dendrite/setup/jetstream"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AddPublicRoutes sets up and registers HTTP handlers for the ClientAPI component.
|
// AddPublicRoutes sets up and registers HTTP handlers for the ClientAPI component.
|
||||||
func AddPublicRoutes(
|
func AddPublicRoutes(
|
||||||
base *base.BaseDendrite,
|
processContext *process.ProcessContext,
|
||||||
federation *gomatrixserverlib.FederationClient,
|
routers httputil.Routers,
|
||||||
|
cfg *config.Dendrite,
|
||||||
|
natsInstance *jetstream.NATSInstance,
|
||||||
|
federation *fclient.FederationClient,
|
||||||
rsAPI roomserverAPI.ClientRoomserverAPI,
|
rsAPI roomserverAPI.ClientRoomserverAPI,
|
||||||
asAPI appserviceAPI.AppServiceInternalAPI,
|
asAPI appserviceAPI.AppServiceInternalAPI,
|
||||||
transactionsCache *transactions.Cache,
|
transactionsCache *transactions.Cache,
|
||||||
fsAPI federationAPI.ClientFederationAPI,
|
fsAPI federationAPI.ClientFederationAPI,
|
||||||
userAPI userapi.ClientUserAPI,
|
userAPI userapi.ClientUserAPI,
|
||||||
userDirectoryProvider userapi.QuerySearchProfilesAPI,
|
userDirectoryProvider userapi.QuerySearchProfilesAPI,
|
||||||
extRoomsProvider api.ExtraPublicRoomsProvider,
|
extRoomsProvider api.ExtraPublicRoomsProvider, enableMetrics bool,
|
||||||
) {
|
) {
|
||||||
cfg := &base.Cfg.ClientAPI
|
js, natsClient := natsInstance.Prepare(processContext, &cfg.Global.JetStream)
|
||||||
mscCfg := &base.Cfg.MSCs
|
|
||||||
js, natsClient := base.NATS.Prepare(base.ProcessContext, &cfg.Matrix.JetStream)
|
|
||||||
|
|
||||||
syncProducer := &producers.SyncAPIProducer{
|
syncProducer := &producers.SyncAPIProducer{
|
||||||
JetStream: js,
|
JetStream: js,
|
||||||
TopicReceiptEvent: cfg.Matrix.JetStream.Prefixed(jetstream.OutputReceiptEvent),
|
TopicReceiptEvent: cfg.Global.JetStream.Prefixed(jetstream.OutputReceiptEvent),
|
||||||
TopicSendToDeviceEvent: cfg.Matrix.JetStream.Prefixed(jetstream.OutputSendToDeviceEvent),
|
TopicSendToDeviceEvent: cfg.Global.JetStream.Prefixed(jetstream.OutputSendToDeviceEvent),
|
||||||
TopicTypingEvent: cfg.Matrix.JetStream.Prefixed(jetstream.OutputTypingEvent),
|
TopicTypingEvent: cfg.Global.JetStream.Prefixed(jetstream.OutputTypingEvent),
|
||||||
TopicPresenceEvent: cfg.Matrix.JetStream.Prefixed(jetstream.OutputPresenceEvent),
|
TopicPresenceEvent: cfg.Global.JetStream.Prefixed(jetstream.OutputPresenceEvent),
|
||||||
TopicMultiRoomCast: cfg.Matrix.JetStream.Prefixed(jetstream.OutputMultiRoomCast),
|
TopicMultiRoomCast: cfg.Global.JetStream.Prefixed(jetstream.OutputMultiRoomCast),
|
||||||
UserAPI: userAPI,
|
UserAPI: userAPI,
|
||||||
ServerName: cfg.Matrix.ServerName,
|
ServerName: cfg.Global.ServerName,
|
||||||
}
|
}
|
||||||
|
|
||||||
routing.Setup(
|
routing.Setup(
|
||||||
base,
|
routers,
|
||||||
cfg, rsAPI, asAPI,
|
cfg, rsAPI, asAPI,
|
||||||
userAPI, userDirectoryProvider, federation,
|
userAPI, userDirectoryProvider, federation,
|
||||||
syncProducer, transactionsCache, fsAPI,
|
syncProducer, transactionsCache, fsAPI,
|
||||||
extRoomsProvider, mscCfg, natsClient,
|
extRoomsProvider, natsClient, enableMetrics,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
1237
clientapi/clientapi_test.go
Normal file
1237
clientapi/clientapi_test.go
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -22,23 +22,16 @@ import (
|
||||||
"github.com/matrix-org/dendrite/userapi/api"
|
"github.com/matrix-org/dendrite/userapi/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
func AdminEvacuateRoom(req *http.Request, cfg *config.ClientAPI, device *api.Device, rsAPI roomserverAPI.ClientRoomserverAPI) util.JSONResponse {
|
func AdminEvacuateRoom(req *http.Request, rsAPI roomserverAPI.ClientRoomserverAPI) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
}
|
}
|
||||||
roomID, ok := vars["roomID"]
|
|
||||||
if !ok {
|
|
||||||
return util.JSONResponse{
|
|
||||||
Code: http.StatusBadRequest,
|
|
||||||
JSON: jsonerror.MissingArgument("Expecting room ID."),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
res := &roomserverAPI.PerformAdminEvacuateRoomResponse{}
|
res := &roomserverAPI.PerformAdminEvacuateRoomResponse{}
|
||||||
if err := rsAPI.PerformAdminEvacuateRoom(
|
if err := rsAPI.PerformAdminEvacuateRoom(
|
||||||
req.Context(),
|
req.Context(),
|
||||||
&roomserverAPI.PerformAdminEvacuateRoomRequest{
|
&roomserverAPI.PerformAdminEvacuateRoomRequest{
|
||||||
RoomID: roomID,
|
RoomID: vars["roomID"],
|
||||||
},
|
},
|
||||||
res,
|
res,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
|
|
@ -55,18 +48,13 @@ func AdminEvacuateRoom(req *http.Request, cfg *config.ClientAPI, device *api.Dev
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func AdminEvacuateUser(req *http.Request, cfg *config.ClientAPI, device *api.Device, rsAPI roomserverAPI.ClientRoomserverAPI) util.JSONResponse {
|
func AdminEvacuateUser(req *http.Request, cfg *config.ClientAPI, rsAPI roomserverAPI.ClientRoomserverAPI) util.JSONResponse {
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
}
|
}
|
||||||
userID, ok := vars["userID"]
|
userID := vars["userID"]
|
||||||
if !ok {
|
|
||||||
return util.JSONResponse{
|
|
||||||
Code: http.StatusBadRequest,
|
|
||||||
JSON: jsonerror.MissingArgument("Expecting user ID."),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_, domain, err := gomatrixserverlib.SplitID('@', userID)
|
_, domain, err := gomatrixserverlib.SplitID('@', userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.MessageResponse(http.StatusBadRequest, err.Error())
|
return util.MessageResponse(http.StatusBadRequest, err.Error())
|
||||||
|
|
@ -103,13 +91,8 @@ func AdminPurgeRoom(req *http.Request, cfg *config.ClientAPI, device *api.Device
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
}
|
}
|
||||||
roomID, ok := vars["roomID"]
|
roomID := vars["roomID"]
|
||||||
if !ok {
|
|
||||||
return util.JSONResponse{
|
|
||||||
Code: http.StatusBadRequest,
|
|
||||||
JSON: jsonerror.MissingArgument("Expecting room ID."),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
res := &roomserverAPI.PerformAdminPurgeRoomResponse{}
|
res := &roomserverAPI.PerformAdminPurgeRoomResponse{}
|
||||||
if err := rsAPI.PerformAdminPurgeRoom(
|
if err := rsAPI.PerformAdminPurgeRoom(
|
||||||
context.Background(),
|
context.Background(),
|
||||||
|
|
|
||||||
|
|
@ -10,30 +10,28 @@ import (
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
|
"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
|
||||||
"github.com/matrix-org/dendrite/setup/config"
|
"github.com/matrix-org/dendrite/setup/config"
|
||||||
"github.com/matrix-org/dendrite/test/testrig"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_AuthFallback(t *testing.T) {
|
func Test_AuthFallback(t *testing.T) {
|
||||||
base, _, _ := testrig.Base(nil)
|
cfg := config.Dendrite{}
|
||||||
defer base.Close()
|
cfg.Defaults(config.DefaultOpts{Generate: true, SingleDatabase: true})
|
||||||
|
|
||||||
for _, useHCaptcha := range []bool{false, true} {
|
for _, useHCaptcha := range []bool{false, true} {
|
||||||
for _, recaptchaEnabled := range []bool{false, true} {
|
for _, recaptchaEnabled := range []bool{false, true} {
|
||||||
for _, wantErr := range []bool{false, true} {
|
for _, wantErr := range []bool{false, true} {
|
||||||
t.Run(fmt.Sprintf("useHCaptcha(%v) - recaptchaEnabled(%v) - wantErr(%v)", useHCaptcha, recaptchaEnabled, wantErr), func(t *testing.T) {
|
t.Run(fmt.Sprintf("useHCaptcha(%v) - recaptchaEnabled(%v) - wantErr(%v)", useHCaptcha, recaptchaEnabled, wantErr), func(t *testing.T) {
|
||||||
// Set the defaults for each test
|
// Set the defaults for each test
|
||||||
base.Cfg.ClientAPI.Defaults(config.DefaultOpts{Generate: true, SingleDatabase: true})
|
cfg.ClientAPI.Defaults(config.DefaultOpts{Generate: true, SingleDatabase: true})
|
||||||
base.Cfg.ClientAPI.RecaptchaEnabled = recaptchaEnabled
|
cfg.ClientAPI.RecaptchaEnabled = recaptchaEnabled
|
||||||
base.Cfg.ClientAPI.RecaptchaPublicKey = "pub"
|
cfg.ClientAPI.RecaptchaPublicKey = "pub"
|
||||||
base.Cfg.ClientAPI.RecaptchaPrivateKey = "priv"
|
cfg.ClientAPI.RecaptchaPrivateKey = "priv"
|
||||||
if useHCaptcha {
|
if useHCaptcha {
|
||||||
base.Cfg.ClientAPI.RecaptchaSiteVerifyAPI = "https://hcaptcha.com/siteverify"
|
cfg.ClientAPI.RecaptchaSiteVerifyAPI = "https://hcaptcha.com/siteverify"
|
||||||
base.Cfg.ClientAPI.RecaptchaApiJsUrl = "https://js.hcaptcha.com/1/api.js"
|
cfg.ClientAPI.RecaptchaApiJsUrl = "https://js.hcaptcha.com/1/api.js"
|
||||||
base.Cfg.ClientAPI.RecaptchaFormField = "h-captcha-response"
|
cfg.ClientAPI.RecaptchaFormField = "h-captcha-response"
|
||||||
base.Cfg.ClientAPI.RecaptchaSitekeyClass = "h-captcha"
|
cfg.ClientAPI.RecaptchaSitekeyClass = "h-captcha"
|
||||||
}
|
}
|
||||||
cfgErrs := &config.ConfigErrors{}
|
cfgErrs := &config.ConfigErrors{}
|
||||||
base.Cfg.ClientAPI.Verify(cfgErrs)
|
cfg.ClientAPI.Verify(cfgErrs)
|
||||||
if len(*cfgErrs) > 0 {
|
if len(*cfgErrs) > 0 {
|
||||||
t.Fatalf("(hCaptcha=%v) unexpected config errors: %s", useHCaptcha, cfgErrs.Error())
|
t.Fatalf("(hCaptcha=%v) unexpected config errors: %s", useHCaptcha, cfgErrs.Error())
|
||||||
}
|
}
|
||||||
|
|
@ -41,7 +39,7 @@ func Test_AuthFallback(t *testing.T) {
|
||||||
req := httptest.NewRequest(http.MethodGet, "/?session=1337", nil)
|
req := httptest.NewRequest(http.MethodGet, "/?session=1337", nil)
|
||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
|
|
||||||
AuthFallback(rec, req, authtypes.LoginTypeRecaptcha, &base.Cfg.ClientAPI)
|
AuthFallback(rec, req, authtypes.LoginTypeRecaptcha, &cfg.ClientAPI)
|
||||||
if !recaptchaEnabled {
|
if !recaptchaEnabled {
|
||||||
if rec.Code != http.StatusBadRequest {
|
if rec.Code != http.StatusBadRequest {
|
||||||
t.Fatalf("unexpected response code: %d, want %d", rec.Code, http.StatusBadRequest)
|
t.Fatalf("unexpected response code: %d, want %d", rec.Code, http.StatusBadRequest)
|
||||||
|
|
@ -50,8 +48,8 @@ func Test_AuthFallback(t *testing.T) {
|
||||||
t.Fatalf("unexpected response body: %s", rec.Body.String())
|
t.Fatalf("unexpected response body: %s", rec.Body.String())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if !strings.Contains(rec.Body.String(), base.Cfg.ClientAPI.RecaptchaSitekeyClass) {
|
if !strings.Contains(rec.Body.String(), cfg.ClientAPI.RecaptchaSitekeyClass) {
|
||||||
t.Fatalf("body does not contain %s: %s", base.Cfg.ClientAPI.RecaptchaSitekeyClass, rec.Body.String())
|
t.Fatalf("body does not contain %s: %s", cfg.ClientAPI.RecaptchaSitekeyClass, rec.Body.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -64,14 +62,14 @@ func Test_AuthFallback(t *testing.T) {
|
||||||
}))
|
}))
|
||||||
defer srv.Close() // nolint: errcheck
|
defer srv.Close() // nolint: errcheck
|
||||||
|
|
||||||
base.Cfg.ClientAPI.RecaptchaSiteVerifyAPI = srv.URL
|
cfg.ClientAPI.RecaptchaSiteVerifyAPI = srv.URL
|
||||||
|
|
||||||
// check the result after sending the captcha
|
// check the result after sending the captcha
|
||||||
req = httptest.NewRequest(http.MethodPost, "/?session=1337", nil)
|
req = httptest.NewRequest(http.MethodPost, "/?session=1337", nil)
|
||||||
req.Form = url.Values{}
|
req.Form = url.Values{}
|
||||||
req.Form.Add(base.Cfg.ClientAPI.RecaptchaFormField, "someRandomValue")
|
req.Form.Add(cfg.ClientAPI.RecaptchaFormField, "someRandomValue")
|
||||||
rec = httptest.NewRecorder()
|
rec = httptest.NewRecorder()
|
||||||
AuthFallback(rec, req, authtypes.LoginTypeRecaptcha, &base.Cfg.ClientAPI)
|
AuthFallback(rec, req, authtypes.LoginTypeRecaptcha, &cfg.ClientAPI)
|
||||||
if recaptchaEnabled {
|
if recaptchaEnabled {
|
||||||
if !wantErr {
|
if !wantErr {
|
||||||
if rec.Code != http.StatusOK {
|
if rec.Code != http.StatusOK {
|
||||||
|
|
@ -105,7 +103,7 @@ func Test_AuthFallback(t *testing.T) {
|
||||||
t.Run("unknown fallbacks are handled correctly", func(t *testing.T) {
|
t.Run("unknown fallbacks are handled correctly", func(t *testing.T) {
|
||||||
req := httptest.NewRequest(http.MethodPost, "/?session=1337", nil)
|
req := httptest.NewRequest(http.MethodPost, "/?session=1337", nil)
|
||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
AuthFallback(rec, req, "DoesNotExist", &base.Cfg.ClientAPI)
|
AuthFallback(rec, req, "DoesNotExist", &cfg.ClientAPI)
|
||||||
if rec.Code != http.StatusNotImplemented {
|
if rec.Code != http.StatusNotImplemented {
|
||||||
t.Fatalf("unexpected http status: %d, want %d", rec.Code, http.StatusNotImplemented)
|
t.Fatalf("unexpected http status: %d, want %d", rec.Code, http.StatusNotImplemented)
|
||||||
}
|
}
|
||||||
|
|
@ -114,7 +112,7 @@ func Test_AuthFallback(t *testing.T) {
|
||||||
t.Run("unknown methods are handled correctly", func(t *testing.T) {
|
t.Run("unknown methods are handled correctly", func(t *testing.T) {
|
||||||
req := httptest.NewRequest(http.MethodDelete, "/?session=1337", nil)
|
req := httptest.NewRequest(http.MethodDelete, "/?session=1337", nil)
|
||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
AuthFallback(rec, req, authtypes.LoginTypeRecaptcha, &base.Cfg.ClientAPI)
|
AuthFallback(rec, req, authtypes.LoginTypeRecaptcha, &cfg.ClientAPI)
|
||||||
if rec.Code != http.StatusMethodNotAllowed {
|
if rec.Code != http.StatusMethodNotAllowed {
|
||||||
t.Fatalf("unexpected http status: %d, want %d", rec.Code, http.StatusMethodNotAllowed)
|
t.Fatalf("unexpected http status: %d, want %d", rec.Code, http.StatusMethodNotAllowed)
|
||||||
}
|
}
|
||||||
|
|
@ -123,7 +121,7 @@ func Test_AuthFallback(t *testing.T) {
|
||||||
t.Run("missing session parameter is handled correctly", func(t *testing.T) {
|
t.Run("missing session parameter is handled correctly", func(t *testing.T) {
|
||||||
req := httptest.NewRequest(http.MethodGet, "/", nil)
|
req := httptest.NewRequest(http.MethodGet, "/", nil)
|
||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
AuthFallback(rec, req, authtypes.LoginTypeRecaptcha, &base.Cfg.ClientAPI)
|
AuthFallback(rec, req, authtypes.LoginTypeRecaptcha, &cfg.ClientAPI)
|
||||||
if rec.Code != http.StatusBadRequest {
|
if rec.Code != http.StatusBadRequest {
|
||||||
t.Fatalf("unexpected http status: %d, want %d", rec.Code, http.StatusBadRequest)
|
t.Fatalf("unexpected http status: %d, want %d", rec.Code, http.StatusBadRequest)
|
||||||
}
|
}
|
||||||
|
|
@ -132,7 +130,7 @@ func Test_AuthFallback(t *testing.T) {
|
||||||
t.Run("missing session parameter is handled correctly", func(t *testing.T) {
|
t.Run("missing session parameter is handled correctly", func(t *testing.T) {
|
||||||
req := httptest.NewRequest(http.MethodGet, "/", nil)
|
req := httptest.NewRequest(http.MethodGet, "/", nil)
|
||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
AuthFallback(rec, req, authtypes.LoginTypeRecaptcha, &base.Cfg.ClientAPI)
|
AuthFallback(rec, req, authtypes.LoginTypeRecaptcha, &cfg.ClientAPI)
|
||||||
if rec.Code != http.StatusBadRequest {
|
if rec.Code != http.StatusBadRequest {
|
||||||
t.Fatalf("unexpected http status: %d, want %d", rec.Code, http.StatusBadRequest)
|
t.Fatalf("unexpected http status: %d, want %d", rec.Code, http.StatusBadRequest)
|
||||||
}
|
}
|
||||||
|
|
@ -141,7 +139,7 @@ func Test_AuthFallback(t *testing.T) {
|
||||||
t.Run("missing 'response' is handled correctly", func(t *testing.T) {
|
t.Run("missing 'response' is handled correctly", func(t *testing.T) {
|
||||||
req := httptest.NewRequest(http.MethodPost, "/?session=1337", nil)
|
req := httptest.NewRequest(http.MethodPost, "/?session=1337", nil)
|
||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
AuthFallback(rec, req, authtypes.LoginTypeRecaptcha, &base.Cfg.ClientAPI)
|
AuthFallback(rec, req, authtypes.LoginTypeRecaptcha, &cfg.ClientAPI)
|
||||||
if rec.Code != http.StatusBadRequest {
|
if rec.Code != http.StatusBadRequest {
|
||||||
t.Fatalf("unexpected http status: %d, want %d", rec.Code, http.StatusBadRequest)
|
t.Fatalf("unexpected http status: %d, want %d", rec.Code, http.StatusBadRequest)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,26 +17,21 @@ package routing
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/clientapi/jsonerror"
|
"github.com/matrix-org/dendrite/roomserver/version"
|
||||||
roomserverAPI "github.com/matrix-org/dendrite/roomserver/api"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
|
||||||
"github.com/matrix-org/util"
|
"github.com/matrix-org/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetCapabilities returns information about the server's supported feature set
|
// GetCapabilities returns information about the server's supported feature set
|
||||||
// and other relevant capabilities to an authenticated user.
|
// and other relevant capabilities to an authenticated user.
|
||||||
func GetCapabilities(
|
func GetCapabilities() util.JSONResponse {
|
||||||
req *http.Request, rsAPI roomserverAPI.ClientRoomserverAPI,
|
versionsMap := map[gomatrixserverlib.RoomVersion]string{}
|
||||||
) util.JSONResponse {
|
for v, desc := range version.SupportedRoomVersions() {
|
||||||
roomVersionsQueryReq := roomserverAPI.QueryRoomVersionCapabilitiesRequest{}
|
if desc.Stable {
|
||||||
roomVersionsQueryRes := roomserverAPI.QueryRoomVersionCapabilitiesResponse{}
|
versionsMap[v] = "stable"
|
||||||
if err := rsAPI.QueryRoomVersionCapabilities(
|
} else {
|
||||||
req.Context(),
|
versionsMap[v] = "unstable"
|
||||||
&roomVersionsQueryReq,
|
}
|
||||||
&roomVersionsQueryRes,
|
|
||||||
); err != nil {
|
|
||||||
util.GetLogger(req.Context()).WithError(err).Error("queryAPI.QueryRoomVersionCapabilities failed")
|
|
||||||
return jsonerror.InternalServerError()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
response := map[string]interface{}{
|
response := map[string]interface{}{
|
||||||
|
|
@ -44,7 +39,10 @@ func GetCapabilities(
|
||||||
"m.change_password": map[string]bool{
|
"m.change_password": map[string]bool{
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
},
|
},
|
||||||
"m.room_versions": roomVersionsQueryRes,
|
"m.room_versions": map[string]interface{}{
|
||||||
|
"default": version.DefaultRoomVersion(),
|
||||||
|
"available": versionsMap,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,8 @@ func Deactivate(
|
||||||
} else {
|
} else {
|
||||||
userId = deviceAPI.UserID
|
userId = deviceAPI.UserID
|
||||||
}
|
}
|
||||||
localpart, _, err := gomatrixserverlib.SplitID('@', userId)
|
|
||||||
|
localpart, serverName, err := gomatrixserverlib.SplitID('@', userId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
util.GetLogger(req.Context()).WithError(err).Error("gomatrixserverlib.SplitID failed")
|
util.GetLogger(req.Context()).WithError(err).Error("gomatrixserverlib.SplitID failed")
|
||||||
return jsonerror.InternalServerError()
|
return jsonerror.InternalServerError()
|
||||||
|
|
@ -46,6 +47,7 @@ func Deactivate(
|
||||||
var res api.PerformAccountDeactivationResponse
|
var res api.PerformAccountDeactivationResponse
|
||||||
err = accountAPI.PerformAccountDeactivation(ctx, &api.PerformAccountDeactivationRequest{
|
err = accountAPI.PerformAccountDeactivation(ctx, &api.PerformAccountDeactivationRequest{
|
||||||
Localpart: localpart,
|
Localpart: localpart,
|
||||||
|
ServerName: serverName,
|
||||||
}, &res)
|
}, &res)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
util.GetLogger(ctx).WithError(err).Error("userAPI.PerformAccountDeactivation failed")
|
util.GetLogger(ctx).WithError(err).Error("userAPI.PerformAccountDeactivation failed")
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
package routing
|
package routing
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
@ -146,12 +147,6 @@ func UpdateDeviceByID(
|
||||||
JSON: jsonerror.Forbidden("device does not exist"),
|
JSON: jsonerror.Forbidden("device does not exist"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if performRes.Forbidden {
|
|
||||||
return util.JSONResponse{
|
|
||||||
Code: http.StatusForbidden,
|
|
||||||
JSON: jsonerror.Forbidden("device not owned by current user"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusOK,
|
Code: http.StatusOK,
|
||||||
|
|
@ -189,7 +184,7 @@ func DeleteDeviceById(
|
||||||
if dev != deviceID {
|
if dev != deviceID {
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusForbidden,
|
Code: http.StatusForbidden,
|
||||||
JSON: jsonerror.Forbidden("session & device mismatch"),
|
JSON: jsonerror.Forbidden("session and device mismatch"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -242,16 +237,37 @@ func DeleteDeviceById(
|
||||||
|
|
||||||
// DeleteDevices handles POST requests to /delete_devices
|
// DeleteDevices handles POST requests to /delete_devices
|
||||||
func DeleteDevices(
|
func DeleteDevices(
|
||||||
req *http.Request, userAPI api.ClientUserAPI, device *api.Device,
|
req *http.Request, userInteractiveAuth *auth.UserInteractive, userAPI api.ClientUserAPI, device *api.Device,
|
||||||
) util.JSONResponse {
|
) util.JSONResponse {
|
||||||
ctx := req.Context()
|
ctx := req.Context()
|
||||||
payload := devicesDeleteJSON{}
|
|
||||||
|
|
||||||
if resErr := httputil.UnmarshalJSONRequest(req, &payload); resErr != nil {
|
bodyBytes, err := io.ReadAll(req.Body)
|
||||||
return *resErr
|
if err != nil {
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusBadRequest,
|
||||||
|
JSON: jsonerror.BadJSON("The request body could not be read: " + err.Error()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
defer req.Body.Close() // nolint:errcheck
|
||||||
|
|
||||||
|
// initiate UIA
|
||||||
|
login, errRes := userInteractiveAuth.Verify(ctx, bodyBytes, device)
|
||||||
|
if errRes != nil {
|
||||||
|
return *errRes
|
||||||
}
|
}
|
||||||
|
|
||||||
defer req.Body.Close() // nolint: errcheck
|
if login.Username() != device.UserID {
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusForbidden,
|
||||||
|
JSON: jsonerror.Forbidden("unable to delete devices for other user"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
payload := devicesDeleteJSON{}
|
||||||
|
if err = json.Unmarshal(bodyBytes, &payload); err != nil {
|
||||||
|
util.GetLogger(ctx).WithError(err).Error("unable to unmarshal device deletion request")
|
||||||
|
return jsonerror.InternalServerError()
|
||||||
|
}
|
||||||
|
|
||||||
var res api.PerformDeviceDeletionResponse
|
var res api.PerformDeviceDeletionResponse
|
||||||
if err := userAPI.PerformDeviceDeletion(ctx, &api.PerformDeviceDeletionRequest{
|
if err := userAPI.PerformDeviceDeletion(ctx, &api.PerformDeviceDeletionRequest{
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib/fclient"
|
||||||
"github.com/matrix-org/util"
|
"github.com/matrix-org/util"
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/clientapi/httputil"
|
"github.com/matrix-org/dendrite/clientapi/httputil"
|
||||||
|
|
@ -45,7 +46,7 @@ func (r *roomDirectoryResponse) fillServers(servers []gomatrixserverlib.ServerNa
|
||||||
func DirectoryRoom(
|
func DirectoryRoom(
|
||||||
req *http.Request,
|
req *http.Request,
|
||||||
roomAlias string,
|
roomAlias string,
|
||||||
federation *gomatrixserverlib.FederationClient,
|
federation *fclient.FederationClient,
|
||||||
cfg *config.ClientAPI,
|
cfg *config.ClientAPI,
|
||||||
rsAPI roomserverAPI.ClientRoomserverAPI,
|
rsAPI roomserverAPI.ClientRoomserverAPI,
|
||||||
fedSenderAPI federationAPI.ClientFederationAPI,
|
fedSenderAPI federationAPI.ClientFederationAPI,
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib/fclient"
|
||||||
"github.com/matrix-org/util"
|
"github.com/matrix-org/util"
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/clientapi/api"
|
"github.com/matrix-org/dendrite/clientapi/api"
|
||||||
|
|
@ -35,7 +36,7 @@ import (
|
||||||
|
|
||||||
var (
|
var (
|
||||||
cacheMu sync.Mutex
|
cacheMu sync.Mutex
|
||||||
publicRoomsCache []gomatrixserverlib.PublicRoom
|
publicRoomsCache []fclient.PublicRoom
|
||||||
)
|
)
|
||||||
|
|
||||||
type PublicRoomReq struct {
|
type PublicRoomReq struct {
|
||||||
|
|
@ -56,7 +57,7 @@ type filter struct {
|
||||||
func GetPostPublicRooms(
|
func GetPostPublicRooms(
|
||||||
req *http.Request, rsAPI roomserverAPI.ClientRoomserverAPI,
|
req *http.Request, rsAPI roomserverAPI.ClientRoomserverAPI,
|
||||||
extRoomsProvider api.ExtraPublicRoomsProvider,
|
extRoomsProvider api.ExtraPublicRoomsProvider,
|
||||||
federation *gomatrixserverlib.FederationClient,
|
federation *fclient.FederationClient,
|
||||||
cfg *config.ClientAPI,
|
cfg *config.ClientAPI,
|
||||||
) util.JSONResponse {
|
) util.JSONResponse {
|
||||||
var request PublicRoomReq
|
var request PublicRoomReq
|
||||||
|
|
@ -102,10 +103,10 @@ func GetPostPublicRooms(
|
||||||
|
|
||||||
func publicRooms(
|
func publicRooms(
|
||||||
ctx context.Context, request PublicRoomReq, rsAPI roomserverAPI.ClientRoomserverAPI, extRoomsProvider api.ExtraPublicRoomsProvider,
|
ctx context.Context, request PublicRoomReq, rsAPI roomserverAPI.ClientRoomserverAPI, extRoomsProvider api.ExtraPublicRoomsProvider,
|
||||||
) (*gomatrixserverlib.RespPublicRooms, error) {
|
) (*fclient.RespPublicRooms, error) {
|
||||||
|
|
||||||
response := gomatrixserverlib.RespPublicRooms{
|
response := fclient.RespPublicRooms{
|
||||||
Chunk: []gomatrixserverlib.PublicRoom{},
|
Chunk: []fclient.PublicRoom{},
|
||||||
}
|
}
|
||||||
var limit int64
|
var limit int64
|
||||||
var offset int64
|
var offset int64
|
||||||
|
|
@ -122,7 +123,7 @@ func publicRooms(
|
||||||
}
|
}
|
||||||
err = nil
|
err = nil
|
||||||
|
|
||||||
var rooms []gomatrixserverlib.PublicRoom
|
var rooms []fclient.PublicRoom
|
||||||
if request.Since == "" {
|
if request.Since == "" {
|
||||||
rooms = refreshPublicRoomCache(ctx, rsAPI, extRoomsProvider, request)
|
rooms = refreshPublicRoomCache(ctx, rsAPI, extRoomsProvider, request)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -146,14 +147,14 @@ func publicRooms(
|
||||||
return &response, err
|
return &response, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func filterRooms(rooms []gomatrixserverlib.PublicRoom, searchTerm string) []gomatrixserverlib.PublicRoom {
|
func filterRooms(rooms []fclient.PublicRoom, searchTerm string) []fclient.PublicRoom {
|
||||||
if searchTerm == "" {
|
if searchTerm == "" {
|
||||||
return rooms
|
return rooms
|
||||||
}
|
}
|
||||||
|
|
||||||
normalizedTerm := strings.ToLower(searchTerm)
|
normalizedTerm := strings.ToLower(searchTerm)
|
||||||
|
|
||||||
result := make([]gomatrixserverlib.PublicRoom, 0)
|
result := make([]fclient.PublicRoom, 0)
|
||||||
for _, room := range rooms {
|
for _, room := range rooms {
|
||||||
if strings.Contains(strings.ToLower(room.Name), normalizedTerm) ||
|
if strings.Contains(strings.ToLower(room.Name), normalizedTerm) ||
|
||||||
strings.Contains(strings.ToLower(room.Topic), normalizedTerm) ||
|
strings.Contains(strings.ToLower(room.Topic), normalizedTerm) ||
|
||||||
|
|
@ -214,7 +215,7 @@ func fillPublicRoomsReq(httpReq *http.Request, request *PublicRoomReq) *util.JSO
|
||||||
// limit=3&since=6 => G (prev='3', next='')
|
// 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 int64) (subset []gomatrixserverlib.PublicRoom, prev, next int) {
|
func sliceInto(slice []fclient.PublicRoom, since int64, limit int64) (subset []fclient.PublicRoom, prev, next int) {
|
||||||
prev = -1
|
prev = -1
|
||||||
next = -1
|
next = -1
|
||||||
|
|
||||||
|
|
@ -241,10 +242,10 @@ func sliceInto(slice []gomatrixserverlib.PublicRoom, since int64, limit int64) (
|
||||||
func refreshPublicRoomCache(
|
func refreshPublicRoomCache(
|
||||||
ctx context.Context, rsAPI roomserverAPI.ClientRoomserverAPI, extRoomsProvider api.ExtraPublicRoomsProvider,
|
ctx context.Context, rsAPI roomserverAPI.ClientRoomserverAPI, extRoomsProvider api.ExtraPublicRoomsProvider,
|
||||||
request PublicRoomReq,
|
request PublicRoomReq,
|
||||||
) []gomatrixserverlib.PublicRoom {
|
) []fclient.PublicRoom {
|
||||||
cacheMu.Lock()
|
cacheMu.Lock()
|
||||||
defer cacheMu.Unlock()
|
defer cacheMu.Unlock()
|
||||||
var extraRooms []gomatrixserverlib.PublicRoom
|
var extraRooms []fclient.PublicRoom
|
||||||
if extRoomsProvider != nil {
|
if extRoomsProvider != nil {
|
||||||
extraRooms = extRoomsProvider.Rooms()
|
extraRooms = extRoomsProvider.Rooms()
|
||||||
}
|
}
|
||||||
|
|
@ -269,7 +270,7 @@ func refreshPublicRoomCache(
|
||||||
util.GetLogger(ctx).WithError(err).Error("PopulatePublicRooms failed")
|
util.GetLogger(ctx).WithError(err).Error("PopulatePublicRooms failed")
|
||||||
return publicRoomsCache
|
return publicRoomsCache
|
||||||
}
|
}
|
||||||
publicRoomsCache = []gomatrixserverlib.PublicRoom{}
|
publicRoomsCache = []fclient.PublicRoom{}
|
||||||
publicRoomsCache = append(publicRoomsCache, pubRooms...)
|
publicRoomsCache = append(publicRoomsCache, pubRooms...)
|
||||||
publicRoomsCache = append(publicRoomsCache, extraRooms...)
|
publicRoomsCache = append(publicRoomsCache, extraRooms...)
|
||||||
publicRoomsCache = dedupeAndShuffle(publicRoomsCache)
|
publicRoomsCache = dedupeAndShuffle(publicRoomsCache)
|
||||||
|
|
@ -281,16 +282,16 @@ func refreshPublicRoomCache(
|
||||||
return publicRoomsCache
|
return publicRoomsCache
|
||||||
}
|
}
|
||||||
|
|
||||||
func getPublicRoomsFromCache() []gomatrixserverlib.PublicRoom {
|
func getPublicRoomsFromCache() []fclient.PublicRoom {
|
||||||
cacheMu.Lock()
|
cacheMu.Lock()
|
||||||
defer cacheMu.Unlock()
|
defer cacheMu.Unlock()
|
||||||
return publicRoomsCache
|
return publicRoomsCache
|
||||||
}
|
}
|
||||||
|
|
||||||
func dedupeAndShuffle(in []gomatrixserverlib.PublicRoom) []gomatrixserverlib.PublicRoom {
|
func dedupeAndShuffle(in []fclient.PublicRoom) []fclient.PublicRoom {
|
||||||
// de-duplicate rooms with the same room ID. We can join the room via any of these aliases as we know these servers
|
// de-duplicate rooms with the same room ID. We can join the room via any of these aliases as we know these servers
|
||||||
// are alive and well, so we arbitrarily pick one (purposefully shuffling them to spread the load a bit)
|
// are alive and well, so we arbitrarily pick one (purposefully shuffling them to spread the load a bit)
|
||||||
var publicRooms []gomatrixserverlib.PublicRoom
|
var publicRooms []fclient.PublicRoom
|
||||||
haveRoomIDs := make(map[string]bool)
|
haveRoomIDs := make(map[string]bool)
|
||||||
rand.Shuffle(len(in), func(i, j int) {
|
rand.Shuffle(len(in), func(i, j int) {
|
||||||
in[i], in[j] = in[j], in[i]
|
in[i], in[j] = in[j], in[i]
|
||||||
|
|
|
||||||
|
|
@ -4,17 +4,17 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib/fclient"
|
||||||
)
|
)
|
||||||
|
|
||||||
func pubRoom(name string) gomatrixserverlib.PublicRoom {
|
func pubRoom(name string) fclient.PublicRoom {
|
||||||
return gomatrixserverlib.PublicRoom{
|
return fclient.PublicRoom{
|
||||||
Name: name,
|
Name: name,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSliceInto(t *testing.T) {
|
func TestSliceInto(t *testing.T) {
|
||||||
slice := []gomatrixserverlib.PublicRoom{
|
slice := []fclient.PublicRoom{
|
||||||
pubRoom("a"), pubRoom("b"), pubRoom("c"), pubRoom("d"), pubRoom("e"), pubRoom("f"), pubRoom("g"),
|
pubRoom("a"), pubRoom("b"), pubRoom("c"), pubRoom("d"), pubRoom("e"), pubRoom("f"), pubRoom("g"),
|
||||||
}
|
}
|
||||||
limit := int64(3)
|
limit := int64(3)
|
||||||
|
|
@ -22,7 +22,7 @@ func TestSliceInto(t *testing.T) {
|
||||||
since int64
|
since int64
|
||||||
wantPrev int
|
wantPrev int
|
||||||
wantNext int
|
wantNext int
|
||||||
wantSubset []gomatrixserverlib.PublicRoom
|
wantSubset []fclient.PublicRoom
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
since: 0,
|
since: 0,
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
appserviceAPI "github.com/matrix-org/dendrite/appservice/api"
|
||||||
"github.com/matrix-org/dendrite/clientapi/httputil"
|
"github.com/matrix-org/dendrite/clientapi/httputil"
|
||||||
"github.com/matrix-org/dendrite/clientapi/jsonerror"
|
"github.com/matrix-org/dendrite/clientapi/jsonerror"
|
||||||
roomserverAPI "github.com/matrix-org/dendrite/roomserver/api"
|
roomserverAPI "github.com/matrix-org/dendrite/roomserver/api"
|
||||||
|
|
@ -61,21 +62,19 @@ func JoinRoomByIDOrAlias(
|
||||||
// Work out our localpart for the client profile request.
|
// Work out our localpart for the client profile request.
|
||||||
|
|
||||||
// Request our profile content to populate the request content with.
|
// Request our profile content to populate the request content with.
|
||||||
res := &api.QueryProfileResponse{}
|
profile, err := profileAPI.QueryProfile(req.Context(), device.UserID)
|
||||||
err := profileAPI.QueryProfile(req.Context(), &api.QueryProfileRequest{UserID: device.UserID}, res)
|
|
||||||
if err != nil || !res.UserExists {
|
switch err {
|
||||||
if !res.UserExists {
|
case nil:
|
||||||
|
joinReq.Content["displayname"] = profile.DisplayName
|
||||||
|
joinReq.Content["avatar_url"] = profile.AvatarURL
|
||||||
|
case appserviceAPI.ErrProfileNotExists:
|
||||||
util.GetLogger(req.Context()).Error("Unable to query user profile, no profile found.")
|
util.GetLogger(req.Context()).Error("Unable to query user profile, no profile found.")
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusInternalServerError,
|
Code: http.StatusInternalServerError,
|
||||||
JSON: jsonerror.Unknown("Unable to query user profile, no profile found."),
|
JSON: jsonerror.Unknown("Unable to query user profile, no profile found."),
|
||||||
}
|
}
|
||||||
}
|
default:
|
||||||
|
|
||||||
util.GetLogger(req.Context()).WithError(err).Error("UserProfileAPI.QueryProfile failed")
|
|
||||||
} else {
|
|
||||||
joinReq.Content["displayname"] = res.DisplayName
|
|
||||||
joinReq.Content["avatar_url"] = res.AvatarURL
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ask the roomserver to perform the join.
|
// Ask the roomserver to perform the join.
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,9 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/matrix-org/dendrite/internal/caching"
|
||||||
|
"github.com/matrix-org/dendrite/internal/sqlutil"
|
||||||
|
"github.com/matrix-org/dendrite/setup/jetstream"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/appservice"
|
"github.com/matrix-org/dendrite/appservice"
|
||||||
|
|
@ -24,12 +27,15 @@ func TestJoinRoomByIDOrAlias(t *testing.T) {
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
|
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
|
||||||
base, baseClose := testrig.CreateBaseDendrite(t, dbType)
|
cfg, processCtx, close := testrig.CreateConfig(t, dbType)
|
||||||
defer baseClose()
|
defer close()
|
||||||
|
|
||||||
rsAPI := roomserver.NewInternalAPI(base)
|
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
|
||||||
userAPI := userapi.NewInternalAPI(base, rsAPI, nil)
|
caches := caching.NewRistrettoCache(128*1024*1024, time.Hour, caching.DisableMetrics)
|
||||||
asAPI := appservice.NewInternalAPI(base, userAPI, rsAPI)
|
natsInstance := jetstream.NATSInstance{}
|
||||||
|
rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, &natsInstance, caches, caching.DisableMetrics)
|
||||||
|
userAPI := userapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, rsAPI, nil)
|
||||||
|
asAPI := appservice.NewInternalAPI(processCtx, cfg, &natsInstance, userAPI, rsAPI)
|
||||||
rsAPI.SetFederationAPI(nil, nil) // creates the rs.Inputer etc
|
rsAPI.SetFederationAPI(nil, nil) // creates the rs.Inputer etc
|
||||||
|
|
||||||
// Create the users in the userapi
|
// Create the users in the userapi
|
||||||
|
|
@ -61,7 +67,7 @@ func TestJoinRoomByIDOrAlias(t *testing.T) {
|
||||||
RoomAliasName: "alias",
|
RoomAliasName: "alias",
|
||||||
Invite: []string{bob.ID},
|
Invite: []string{bob.ID},
|
||||||
GuestCanJoin: false,
|
GuestCanJoin: false,
|
||||||
}, aliceDev, &base.Cfg.ClientAPI, userAPI, rsAPI, asAPI, time.Now())
|
}, aliceDev, &cfg.ClientAPI, userAPI, rsAPI, asAPI, time.Now())
|
||||||
crResp, ok := resp.JSON.(createRoomResponse)
|
crResp, ok := resp.JSON.(createRoomResponse)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Fatalf("response is not a createRoomResponse: %+v", resp)
|
t.Fatalf("response is not a createRoomResponse: %+v", resp)
|
||||||
|
|
@ -76,7 +82,7 @@ func TestJoinRoomByIDOrAlias(t *testing.T) {
|
||||||
Preset: presetPublicChat,
|
Preset: presetPublicChat,
|
||||||
Invite: []string{charlie.ID},
|
Invite: []string{charlie.ID},
|
||||||
GuestCanJoin: true,
|
GuestCanJoin: true,
|
||||||
}, aliceDev, &base.Cfg.ClientAPI, userAPI, rsAPI, asAPI, time.Now())
|
}, aliceDev, &cfg.ClientAPI, userAPI, rsAPI, asAPI, time.Now())
|
||||||
crRespWithGuestAccess, ok := resp.JSON.(createRoomResponse)
|
crRespWithGuestAccess, ok := resp.JSON.(createRoomResponse)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Fatalf("response is not a createRoomResponse: %+v", resp)
|
t.Fatalf("response is not a createRoomResponse: %+v", resp)
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ type crossSigningRequest struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func UploadCrossSigningDeviceKeys(
|
func UploadCrossSigningDeviceKeys(
|
||||||
req *http.Request, userInteractiveAuth *auth.UserInteractive,
|
req *http.Request,
|
||||||
keyserverAPI api.ClientKeyAPI, device *api.Device,
|
keyserverAPI api.ClientKeyAPI, device *api.Device,
|
||||||
accountAPI api.ClientUserAPI, cfg *config.ClientAPI,
|
accountAPI api.ClientUserAPI, cfg *config.ClientAPI,
|
||||||
) util.JSONResponse {
|
) util.JSONResponse {
|
||||||
|
|
@ -63,6 +63,7 @@ func UploadCrossSigningDeviceKeys(
|
||||||
}
|
}
|
||||||
typePassword := auth.LoginTypePassword{
|
typePassword := auth.LoginTypePassword{
|
||||||
UserApi: accountAPI,
|
UserApi: accountAPI,
|
||||||
|
UserAPI: accountAPI,
|
||||||
Config: cfg,
|
Config: cfg,
|
||||||
}
|
}
|
||||||
if _, authErr := typePassword.Login(req.Context(), &uploadReq.Auth.PasswordRequest); authErr != nil {
|
if _, authErr := typePassword.Login(req.Context(), &uploadReq.Auth.PasswordRequest); authErr != nil {
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,17 @@ import (
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
|
"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
|
||||||
|
"github.com/matrix-org/dendrite/internal/caching"
|
||||||
|
"github.com/matrix-org/dendrite/internal/httputil"
|
||||||
|
"github.com/matrix-org/dendrite/internal/sqlutil"
|
||||||
"github.com/matrix-org/dendrite/roomserver"
|
"github.com/matrix-org/dendrite/roomserver"
|
||||||
"github.com/matrix-org/dendrite/setup/config"
|
"github.com/matrix-org/dendrite/setup/config"
|
||||||
|
"github.com/matrix-org/dendrite/setup/jetstream"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib/fclient"
|
||||||
"github.com/matrix-org/util"
|
"github.com/matrix-org/util"
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/test"
|
"github.com/matrix-org/dendrite/test"
|
||||||
|
|
@ -28,20 +34,24 @@ func TestLogin(t *testing.T) {
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
|
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
|
||||||
base, baseClose := testrig.CreateBaseDendrite(t, dbType)
|
cfg, processCtx, close := testrig.CreateConfig(t, dbType)
|
||||||
defer baseClose()
|
defer close()
|
||||||
base.Cfg.ClientAPI.RateLimiting.Enabled = false
|
cfg.ClientAPI.RateLimiting.Enabled = false
|
||||||
|
natsInstance := jetstream.NATSInstance{}
|
||||||
// add a vhost
|
// add a vhost
|
||||||
base.Cfg.Global.VirtualHosts = append(base.Cfg.Global.VirtualHosts, &config.VirtualHost{
|
cfg.Global.VirtualHosts = append(cfg.Global.VirtualHosts, &config.VirtualHost{
|
||||||
SigningIdentity: gomatrixserverlib.SigningIdentity{ServerName: "vh1"},
|
SigningIdentity: fclient.SigningIdentity{ServerName: "vh1"},
|
||||||
})
|
})
|
||||||
|
|
||||||
rsAPI := roomserver.NewInternalAPI(base)
|
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
|
||||||
|
routers := httputil.NewRouters()
|
||||||
|
caches := caching.NewRistrettoCache(128*1024*1024, time.Hour, caching.DisableMetrics)
|
||||||
|
rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, &natsInstance, caches, caching.DisableMetrics)
|
||||||
// Needed for /login
|
// Needed for /login
|
||||||
userAPI := userapi.NewInternalAPI(base, rsAPI, nil)
|
userAPI := userapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, rsAPI, nil)
|
||||||
|
|
||||||
// We mostly need the userAPI for this test, so nil for other APIs/caches etc.
|
// We mostly need the userAPI for this test, so nil for other APIs/caches etc.
|
||||||
Setup(base, &base.Cfg.ClientAPI, nil, nil, userAPI, nil, nil, nil, nil, nil, nil, &base.Cfg.MSCs, nil)
|
Setup(routers, cfg, nil, nil, userAPI, nil, nil, nil, nil, nil, nil, nil, caching.DisableMetrics)
|
||||||
|
|
||||||
// Create password
|
// Create password
|
||||||
password := util.RandomString(8)
|
password := util.RandomString(8)
|
||||||
|
|
@ -114,7 +124,7 @@ func TestLogin(t *testing.T) {
|
||||||
"password": password,
|
"password": password,
|
||||||
}))
|
}))
|
||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
base.PublicClientAPIMux.ServeHTTP(rec, req)
|
routers.Client.ServeHTTP(rec, req)
|
||||||
if tc.wantOK && rec.Code != http.StatusOK {
|
if tc.wantOK && rec.Code != http.StatusOK {
|
||||||
t.Fatalf("failed to login: %s", rec.Body.String())
|
t.Fatalf("failed to login: %s", rec.Body.String())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,11 +16,12 @@ package routing
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
|
||||||
appserviceAPI "github.com/matrix-org/dendrite/appservice/api"
|
appserviceAPI "github.com/matrix-org/dendrite/appservice/api"
|
||||||
"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
|
"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
|
||||||
"github.com/matrix-org/dendrite/clientapi/httputil"
|
"github.com/matrix-org/dendrite/clientapi/httputil"
|
||||||
|
|
@ -31,76 +32,56 @@ import (
|
||||||
roomserverAPI "github.com/matrix-org/dendrite/roomserver/api"
|
roomserverAPI "github.com/matrix-org/dendrite/roomserver/api"
|
||||||
"github.com/matrix-org/dendrite/setup/config"
|
"github.com/matrix-org/dendrite/setup/config"
|
||||||
userapi "github.com/matrix-org/dendrite/userapi/api"
|
userapi "github.com/matrix-org/dendrite/userapi/api"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
|
||||||
|
|
||||||
"github.com/matrix-org/util"
|
"github.com/matrix-org/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
var errMissingUserID = errors.New("'user_id' must be supplied")
|
|
||||||
|
|
||||||
func SendBan(
|
func SendBan(
|
||||||
req *http.Request, profileAPI userapi.ClientUserAPI, device *userapi.Device,
|
req *http.Request, profileAPI userapi.ClientUserAPI, device *userapi.Device,
|
||||||
roomID string, cfg *config.ClientAPI,
|
roomID string, cfg *config.ClientAPI,
|
||||||
rsAPI roomserverAPI.ClientRoomserverAPI, asAPI appserviceAPI.AppServiceInternalAPI,
|
rsAPI roomserverAPI.ClientRoomserverAPI, asAPI appserviceAPI.AppServiceInternalAPI,
|
||||||
) util.JSONResponse {
|
) util.JSONResponse {
|
||||||
body, evTime, roomVer, reqErr := extractRequestData(req, roomID, rsAPI)
|
body, evTime, reqErr := extractRequestData(req)
|
||||||
if reqErr != nil {
|
if reqErr != nil {
|
||||||
return *reqErr
|
return *reqErr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if body.UserID == "" {
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusBadRequest,
|
||||||
|
JSON: jsonerror.BadJSON("missing user_id"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
errRes := checkMemberInRoom(req.Context(), rsAPI, device.UserID, roomID)
|
errRes := checkMemberInRoom(req.Context(), rsAPI, device.UserID, roomID)
|
||||||
if errRes != nil {
|
if errRes != nil {
|
||||||
return *errRes
|
return *errRes
|
||||||
}
|
}
|
||||||
|
|
||||||
plEvent := roomserverAPI.GetStateEvent(req.Context(), rsAPI, roomID, gomatrixserverlib.StateKeyTuple{
|
pl, errRes := getPowerlevels(req, rsAPI, roomID)
|
||||||
EventType: gomatrixserverlib.MRoomPowerLevels,
|
if errRes != nil {
|
||||||
StateKey: "",
|
return *errRes
|
||||||
})
|
|
||||||
if plEvent == nil {
|
|
||||||
return util.JSONResponse{
|
|
||||||
Code: 403,
|
|
||||||
JSON: jsonerror.Forbidden("You don't have permission to ban this user, no power_levels event in this room."),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pl, err := plEvent.PowerLevels()
|
|
||||||
if err != nil {
|
|
||||||
return util.JSONResponse{
|
|
||||||
Code: 403,
|
|
||||||
JSON: jsonerror.Forbidden("You don't have permission to ban this user, the power_levels event for this room is malformed so auth checks cannot be performed."),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
allowedToBan := pl.UserLevel(device.UserID) >= pl.Ban
|
allowedToBan := pl.UserLevel(device.UserID) >= pl.Ban
|
||||||
if !allowedToBan {
|
if !allowedToBan {
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: 403,
|
Code: http.StatusForbidden,
|
||||||
JSON: jsonerror.Forbidden("You don't have permission to ban this user, power level too low."),
|
JSON: jsonerror.Forbidden("You don't have permission to ban this user, power level too low."),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return sendMembership(req.Context(), profileAPI, device, roomID, "ban", body.Reason, cfg, body.UserID, evTime, roomVer, rsAPI, asAPI)
|
return sendMembership(req.Context(), profileAPI, device, roomID, gomatrixserverlib.Ban, body.Reason, cfg, body.UserID, evTime, rsAPI, asAPI)
|
||||||
}
|
}
|
||||||
|
|
||||||
func sendMembership(ctx context.Context, profileAPI userapi.ClientUserAPI, device *userapi.Device,
|
func sendMembership(ctx context.Context, profileAPI userapi.ClientUserAPI, device *userapi.Device,
|
||||||
roomID, membership, reason string, cfg *config.ClientAPI, targetUserID string, evTime time.Time,
|
roomID, membership, reason string, cfg *config.ClientAPI, targetUserID string, evTime time.Time,
|
||||||
roomVer gomatrixserverlib.RoomVersion,
|
|
||||||
rsAPI roomserverAPI.ClientRoomserverAPI, asAPI appserviceAPI.AppServiceInternalAPI) util.JSONResponse {
|
rsAPI roomserverAPI.ClientRoomserverAPI, asAPI appserviceAPI.AppServiceInternalAPI) util.JSONResponse {
|
||||||
|
|
||||||
event, err := buildMembershipEvent(
|
event, err := buildMembershipEvent(
|
||||||
ctx, targetUserID, reason, profileAPI, device, membership,
|
ctx, targetUserID, reason, profileAPI, device, membership,
|
||||||
roomID, false, cfg, evTime, rsAPI, asAPI,
|
roomID, false, cfg, evTime, rsAPI, asAPI,
|
||||||
)
|
)
|
||||||
if err == errMissingUserID {
|
if err != nil {
|
||||||
return util.JSONResponse{
|
|
||||||
Code: http.StatusBadRequest,
|
|
||||||
JSON: jsonerror.BadJSON(err.Error()),
|
|
||||||
}
|
|
||||||
} else if err == eventutil.ErrRoomNoExists {
|
|
||||||
return util.JSONResponse{
|
|
||||||
Code: http.StatusNotFound,
|
|
||||||
JSON: jsonerror.NotFound(err.Error()),
|
|
||||||
}
|
|
||||||
} else if err != nil {
|
|
||||||
util.GetLogger(ctx).WithError(err).Error("buildMembershipEvent failed")
|
util.GetLogger(ctx).WithError(err).Error("buildMembershipEvent failed")
|
||||||
return jsonerror.InternalServerError()
|
return jsonerror.InternalServerError()
|
||||||
}
|
}
|
||||||
|
|
@ -109,7 +90,7 @@ func sendMembership(ctx context.Context, profileAPI userapi.ClientUserAPI, devic
|
||||||
if err = roomserverAPI.SendEvents(
|
if err = roomserverAPI.SendEvents(
|
||||||
ctx, rsAPI,
|
ctx, rsAPI,
|
||||||
roomserverAPI.KindNew,
|
roomserverAPI.KindNew,
|
||||||
[]*gomatrixserverlib.HeaderedEvent{event.Event.Headered(roomVer)},
|
[]*gomatrixserverlib.HeaderedEvent{event},
|
||||||
device.UserDomain(),
|
device.UserDomain(),
|
||||||
serverName,
|
serverName,
|
||||||
serverName,
|
serverName,
|
||||||
|
|
@ -131,13 +112,65 @@ func SendKick(
|
||||||
roomID string, cfg *config.ClientAPI,
|
roomID string, cfg *config.ClientAPI,
|
||||||
rsAPI roomserverAPI.ClientRoomserverAPI, asAPI appserviceAPI.AppServiceInternalAPI,
|
rsAPI roomserverAPI.ClientRoomserverAPI, asAPI appserviceAPI.AppServiceInternalAPI,
|
||||||
) util.JSONResponse {
|
) util.JSONResponse {
|
||||||
body, evTime, roomVer, reqErr := extractRequestData(req, roomID, rsAPI)
|
body, evTime, reqErr := extractRequestData(req)
|
||||||
if reqErr != nil {
|
if reqErr != nil {
|
||||||
return *reqErr
|
return *reqErr
|
||||||
}
|
}
|
||||||
if body.UserID == "" {
|
if body.UserID == "" {
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: 400,
|
Code: http.StatusBadRequest,
|
||||||
|
JSON: jsonerror.BadJSON("missing user_id"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
errRes := checkMemberInRoom(req.Context(), rsAPI, device.UserID, roomID)
|
||||||
|
if errRes != nil {
|
||||||
|
return *errRes
|
||||||
|
}
|
||||||
|
|
||||||
|
pl, errRes := getPowerlevels(req, rsAPI, roomID)
|
||||||
|
if errRes != nil {
|
||||||
|
return *errRes
|
||||||
|
}
|
||||||
|
allowedToKick := pl.UserLevel(device.UserID) >= pl.Kick
|
||||||
|
if !allowedToKick {
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusForbidden,
|
||||||
|
JSON: jsonerror.Forbidden("You don't have permission to kick this user, power level too low."),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var queryRes roomserverAPI.QueryMembershipForUserResponse
|
||||||
|
err := rsAPI.QueryMembershipForUser(req.Context(), &roomserverAPI.QueryMembershipForUserRequest{
|
||||||
|
RoomID: roomID,
|
||||||
|
UserID: body.UserID,
|
||||||
|
}, &queryRes)
|
||||||
|
if err != nil {
|
||||||
|
return util.ErrorResponse(err)
|
||||||
|
}
|
||||||
|
// kick is only valid if the user is not currently banned or left (that is, they are joined or invited)
|
||||||
|
if queryRes.Membership != gomatrixserverlib.Join && queryRes.Membership != gomatrixserverlib.Invite {
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusForbidden,
|
||||||
|
JSON: jsonerror.Unknown("cannot /kick banned or left users"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: should we be using SendLeave instead?
|
||||||
|
return sendMembership(req.Context(), profileAPI, device, roomID, gomatrixserverlib.Leave, body.Reason, cfg, body.UserID, evTime, rsAPI, asAPI)
|
||||||
|
}
|
||||||
|
|
||||||
|
func SendUnban(
|
||||||
|
req *http.Request, profileAPI userapi.ClientUserAPI, device *userapi.Device,
|
||||||
|
roomID string, cfg *config.ClientAPI,
|
||||||
|
rsAPI roomserverAPI.ClientRoomserverAPI, asAPI appserviceAPI.AppServiceInternalAPI,
|
||||||
|
) util.JSONResponse {
|
||||||
|
body, evTime, reqErr := extractRequestData(req)
|
||||||
|
if reqErr != nil {
|
||||||
|
return *reqErr
|
||||||
|
}
|
||||||
|
if body.UserID == "" {
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusBadRequest,
|
||||||
JSON: jsonerror.BadJSON("missing user_id"),
|
JSON: jsonerror.BadJSON("missing user_id"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -155,56 +188,16 @@ func SendKick(
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
}
|
}
|
||||||
// kick is only valid if the user is not currently banned or left (that is, they are joined or invited)
|
|
||||||
if queryRes.Membership != "join" && queryRes.Membership != "invite" {
|
|
||||||
return util.JSONResponse{
|
|
||||||
Code: 403,
|
|
||||||
JSON: jsonerror.Unknown("cannot /kick banned or left users"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// TODO: should we be using SendLeave instead?
|
|
||||||
return sendMembership(req.Context(), profileAPI, device, roomID, "leave", body.Reason, cfg, body.UserID, evTime, roomVer, rsAPI, asAPI)
|
|
||||||
}
|
|
||||||
|
|
||||||
func SendUnban(
|
|
||||||
req *http.Request, profileAPI userapi.ClientUserAPI, device *userapi.Device,
|
|
||||||
roomID string, cfg *config.ClientAPI,
|
|
||||||
rsAPI roomserverAPI.ClientRoomserverAPI, asAPI appserviceAPI.AppServiceInternalAPI,
|
|
||||||
) util.JSONResponse {
|
|
||||||
body, evTime, roomVer, reqErr := extractRequestData(req, roomID, rsAPI)
|
|
||||||
if reqErr != nil {
|
|
||||||
return *reqErr
|
|
||||||
}
|
|
||||||
if body.UserID == "" {
|
|
||||||
return util.JSONResponse{
|
|
||||||
Code: 400,
|
|
||||||
JSON: jsonerror.BadJSON("missing user_id"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var queryRes roomserverAPI.QueryMembershipForUserResponse
|
|
||||||
err := rsAPI.QueryMembershipForUser(req.Context(), &roomserverAPI.QueryMembershipForUserRequest{
|
|
||||||
RoomID: roomID,
|
|
||||||
UserID: body.UserID,
|
|
||||||
}, &queryRes)
|
|
||||||
if err != nil {
|
|
||||||
return util.ErrorResponse(err)
|
|
||||||
}
|
|
||||||
if !queryRes.RoomExists {
|
|
||||||
return util.JSONResponse{
|
|
||||||
Code: http.StatusForbidden,
|
|
||||||
JSON: jsonerror.Forbidden("room does not exist"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// unban is only valid if the user is currently banned
|
// unban is only valid if the user is currently banned
|
||||||
if queryRes.Membership != "ban" {
|
if queryRes.Membership != gomatrixserverlib.Ban {
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: 400,
|
Code: http.StatusBadRequest,
|
||||||
JSON: jsonerror.Unknown("can only /unban users that are banned"),
|
JSON: jsonerror.Unknown("can only /unban users that are banned"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: should we be using SendLeave instead?
|
// TODO: should we be using SendLeave instead?
|
||||||
return sendMembership(req.Context(), profileAPI, device, roomID, "leave", body.Reason, cfg, body.UserID, evTime, roomVer, rsAPI, asAPI)
|
return sendMembership(req.Context(), profileAPI, device, roomID, gomatrixserverlib.Leave, body.Reason, cfg, body.UserID, evTime, rsAPI, asAPI)
|
||||||
}
|
}
|
||||||
|
|
||||||
func SendInvite(
|
func SendInvite(
|
||||||
|
|
@ -212,7 +205,7 @@ func SendInvite(
|
||||||
roomID string, cfg *config.ClientAPI,
|
roomID string, cfg *config.ClientAPI,
|
||||||
rsAPI roomserverAPI.ClientRoomserverAPI, asAPI appserviceAPI.AppServiceInternalAPI,
|
rsAPI roomserverAPI.ClientRoomserverAPI, asAPI appserviceAPI.AppServiceInternalAPI,
|
||||||
) util.JSONResponse {
|
) util.JSONResponse {
|
||||||
body, evTime, _, reqErr := extractRequestData(req, roomID, rsAPI)
|
body, evTime, reqErr := extractRequestData(req)
|
||||||
if reqErr != nil {
|
if reqErr != nil {
|
||||||
return *reqErr
|
return *reqErr
|
||||||
}
|
}
|
||||||
|
|
@ -234,6 +227,18 @@ func SendInvite(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if body.UserID == "" {
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusBadRequest,
|
||||||
|
JSON: jsonerror.BadJSON("missing user_id"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
errRes := checkMemberInRoom(req.Context(), rsAPI, device.UserID, roomID)
|
||||||
|
if errRes != nil {
|
||||||
|
return *errRes
|
||||||
|
}
|
||||||
|
|
||||||
// We already received the return value, so no need to check for an error here.
|
// We already received the return value, so no need to check for an error here.
|
||||||
response, _ := sendInvite(req.Context(), profileAPI, device, roomID, body.UserID, body.Reason, cfg, rsAPI, asAPI, evTime)
|
response, _ := sendInvite(req.Context(), profileAPI, device, roomID, body.UserID, body.Reason, cfg, rsAPI, asAPI, evTime)
|
||||||
return response
|
return response
|
||||||
|
|
@ -250,20 +255,10 @@ func sendInvite(
|
||||||
asAPI appserviceAPI.AppServiceInternalAPI, evTime time.Time,
|
asAPI appserviceAPI.AppServiceInternalAPI, evTime time.Time,
|
||||||
) (util.JSONResponse, error) {
|
) (util.JSONResponse, error) {
|
||||||
event, err := buildMembershipEvent(
|
event, err := buildMembershipEvent(
|
||||||
ctx, userID, reason, profileAPI, device, "invite",
|
ctx, userID, reason, profileAPI, device, gomatrixserverlib.Invite,
|
||||||
roomID, false, cfg, evTime, rsAPI, asAPI,
|
roomID, false, cfg, evTime, rsAPI, asAPI,
|
||||||
)
|
)
|
||||||
if err == errMissingUserID {
|
if err != nil {
|
||||||
return util.JSONResponse{
|
|
||||||
Code: http.StatusBadRequest,
|
|
||||||
JSON: jsonerror.BadJSON(err.Error()),
|
|
||||||
}, err
|
|
||||||
} else if err == eventutil.ErrRoomNoExists {
|
|
||||||
return util.JSONResponse{
|
|
||||||
Code: http.StatusNotFound,
|
|
||||||
JSON: jsonerror.NotFound(err.Error()),
|
|
||||||
}, err
|
|
||||||
} else if err != nil {
|
|
||||||
util.GetLogger(ctx).WithError(err).Error("buildMembershipEvent failed")
|
util.GetLogger(ctx).WithError(err).Error("buildMembershipEvent failed")
|
||||||
return jsonerror.InternalServerError(), err
|
return jsonerror.InternalServerError(), err
|
||||||
}
|
}
|
||||||
|
|
@ -357,19 +352,7 @@ func loadProfile(
|
||||||
return profile, err
|
return profile, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func extractRequestData(req *http.Request, roomID string, rsAPI roomserverAPI.ClientRoomserverAPI) (
|
func extractRequestData(req *http.Request) (body *threepid.MembershipRequest, evTime time.Time, resErr *util.JSONResponse) {
|
||||||
body *threepid.MembershipRequest, evTime time.Time, roomVer gomatrixserverlib.RoomVersion, resErr *util.JSONResponse,
|
|
||||||
) {
|
|
||||||
verReq := roomserverAPI.QueryRoomVersionForRoomRequest{RoomID: roomID}
|
|
||||||
verRes := roomserverAPI.QueryRoomVersionForRoomResponse{}
|
|
||||||
if err := rsAPI.QueryRoomVersionForRoom(req.Context(), &verReq, &verRes); err != nil {
|
|
||||||
resErr = &util.JSONResponse{
|
|
||||||
Code: http.StatusBadRequest,
|
|
||||||
JSON: jsonerror.UnsupportedRoomVersion(err.Error()),
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
roomVer = verRes.RoomVersion
|
|
||||||
|
|
||||||
if reqErr := httputil.UnmarshalJSONRequest(req, &body); reqErr != nil {
|
if reqErr := httputil.UnmarshalJSONRequest(req, &body); reqErr != nil {
|
||||||
resErr = reqErr
|
resErr = reqErr
|
||||||
|
|
@ -432,34 +415,17 @@ func checkAndProcessThreepid(
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkMemberInRoom(ctx context.Context, rsAPI roomserverAPI.ClientRoomserverAPI, userID, roomID string) *util.JSONResponse {
|
func checkMemberInRoom(ctx context.Context, rsAPI roomserverAPI.ClientRoomserverAPI, userID, roomID string) *util.JSONResponse {
|
||||||
tuple := gomatrixserverlib.StateKeyTuple{
|
var membershipRes roomserverAPI.QueryMembershipForUserResponse
|
||||||
EventType: gomatrixserverlib.MRoomMember,
|
err := rsAPI.QueryMembershipForUser(ctx, &roomserverAPI.QueryMembershipForUserRequest{
|
||||||
StateKey: userID,
|
|
||||||
}
|
|
||||||
var membershipRes roomserverAPI.QueryCurrentStateResponse
|
|
||||||
err := rsAPI.QueryCurrentState(ctx, &roomserverAPI.QueryCurrentStateRequest{
|
|
||||||
RoomID: roomID,
|
RoomID: roomID,
|
||||||
StateTuples: []gomatrixserverlib.StateKeyTuple{tuple},
|
UserID: userID,
|
||||||
}, &membershipRes)
|
}, &membershipRes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
util.GetLogger(ctx).WithError(err).Error("QueryCurrentState: could not query membership for user")
|
util.GetLogger(ctx).WithError(err).Error("QueryMembershipForUser: could not query membership for user")
|
||||||
e := jsonerror.InternalServerError()
|
e := jsonerror.InternalServerError()
|
||||||
return &e
|
return &e
|
||||||
}
|
}
|
||||||
ev := membershipRes.StateEvents[tuple]
|
if !membershipRes.IsInRoom {
|
||||||
if ev == nil {
|
|
||||||
return &util.JSONResponse{
|
|
||||||
Code: http.StatusForbidden,
|
|
||||||
JSON: jsonerror.Forbidden("user does not belong to room"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
membership, err := ev.Membership()
|
|
||||||
if err != nil {
|
|
||||||
util.GetLogger(ctx).WithError(err).Error("Member event isn't valid")
|
|
||||||
e := jsonerror.InternalServerError()
|
|
||||||
return &e
|
|
||||||
}
|
|
||||||
if membership != gomatrixserverlib.Join {
|
|
||||||
return &util.JSONResponse{
|
return &util.JSONResponse{
|
||||||
Code: http.StatusForbidden,
|
Code: http.StatusForbidden,
|
||||||
JSON: jsonerror.Forbidden("user does not belong to room"),
|
JSON: jsonerror.Forbidden("user does not belong to room"),
|
||||||
|
|
@ -511,3 +477,24 @@ func SendForget(
|
||||||
JSON: struct{}{},
|
JSON: struct{}{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getPowerlevels(req *http.Request, rsAPI roomserverAPI.ClientRoomserverAPI, roomID string) (*gomatrixserverlib.PowerLevelContent, *util.JSONResponse) {
|
||||||
|
plEvent := roomserverAPI.GetStateEvent(req.Context(), rsAPI, roomID, gomatrixserverlib.StateKeyTuple{
|
||||||
|
EventType: gomatrixserverlib.MRoomPowerLevels,
|
||||||
|
StateKey: "",
|
||||||
|
})
|
||||||
|
if plEvent == nil {
|
||||||
|
return nil, &util.JSONResponse{
|
||||||
|
Code: http.StatusForbidden,
|
||||||
|
JSON: jsonerror.Forbidden("You don't have permission to perform this action, no power_levels event in this room."),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pl, err := plEvent.PowerLevels()
|
||||||
|
if err != nil {
|
||||||
|
return nil, &util.JSONResponse{
|
||||||
|
Code: http.StatusForbidden,
|
||||||
|
JSON: jsonerror.Forbidden("You don't have permission to perform this action, the power_levels event for this room is malformed so auth checks cannot be performed."),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pl, nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,7 @@ func Password(
|
||||||
bound bool
|
bound bool
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
bound, threePid.Address, threePid.Medium, err = threepid.CheckAssociation(req.Context(), r.Auth.ThreePidCreds, cfg)
|
bound, threePid.Address, threePid.Medium, err = threepid.CheckAssociation(req.Context(), r.Auth.ThreePidCreds, cfg, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
util.GetLogger(req.Context()).WithError(err).Error("threepid.CheckAssociation failed")
|
util.GetLogger(req.Context()).WithError(err).Error("threepid.CheckAssociation failed")
|
||||||
return jsonerror.InternalServerError()
|
return jsonerror.InternalServerError()
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib/fclient"
|
||||||
|
|
||||||
appserviceAPI "github.com/matrix-org/dendrite/appservice/api"
|
appserviceAPI "github.com/matrix-org/dendrite/appservice/api"
|
||||||
"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
|
"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
|
||||||
|
|
@ -36,14 +37,14 @@ import (
|
||||||
|
|
||||||
// GetProfile implements GET /profile/{userID}
|
// GetProfile implements GET /profile/{userID}
|
||||||
func GetProfile(
|
func GetProfile(
|
||||||
req *http.Request, profileAPI userapi.ClientUserAPI, cfg *config.ClientAPI,
|
req *http.Request, profileAPI userapi.ProfileAPI, cfg *config.ClientAPI,
|
||||||
userID string,
|
userID string,
|
||||||
asAPI appserviceAPI.AppServiceInternalAPI,
|
asAPI appserviceAPI.AppServiceInternalAPI,
|
||||||
federation *gomatrixserverlib.FederationClient,
|
federation *fclient.FederationClient,
|
||||||
) util.JSONResponse {
|
) util.JSONResponse {
|
||||||
profile, err := getProfile(req.Context(), profileAPI, cfg, userID, asAPI, federation)
|
profile, err := getProfile(req.Context(), profileAPI, cfg, userID, asAPI, federation)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == eventutil.ErrProfileNoExists {
|
if err == appserviceAPI.ErrProfileNotExists {
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusNotFound,
|
Code: http.StatusNotFound,
|
||||||
JSON: jsonerror.NotFound("The user does not exist or does not have a profile"),
|
JSON: jsonerror.NotFound("The user does not exist or does not have a profile"),
|
||||||
|
|
@ -56,7 +57,7 @@ func GetProfile(
|
||||||
|
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusOK,
|
Code: http.StatusOK,
|
||||||
JSON: eventutil.ProfileResponse{
|
JSON: eventutil.UserProfile{
|
||||||
AvatarURL: profile.AvatarURL,
|
AvatarURL: profile.AvatarURL,
|
||||||
DisplayName: profile.DisplayName,
|
DisplayName: profile.DisplayName,
|
||||||
},
|
},
|
||||||
|
|
@ -65,34 +66,28 @@ func GetProfile(
|
||||||
|
|
||||||
// GetAvatarURL implements GET /profile/{userID}/avatar_url
|
// GetAvatarURL implements GET /profile/{userID}/avatar_url
|
||||||
func GetAvatarURL(
|
func GetAvatarURL(
|
||||||
req *http.Request, profileAPI userapi.ClientUserAPI, cfg *config.ClientAPI,
|
req *http.Request, profileAPI userapi.ProfileAPI, cfg *config.ClientAPI,
|
||||||
userID string, asAPI appserviceAPI.AppServiceInternalAPI,
|
userID string, asAPI appserviceAPI.AppServiceInternalAPI,
|
||||||
federation *gomatrixserverlib.FederationClient,
|
federation *fclient.FederationClient,
|
||||||
) util.JSONResponse {
|
) util.JSONResponse {
|
||||||
profile, err := getProfile(req.Context(), profileAPI, cfg, userID, asAPI, federation)
|
profile := GetProfile(req, profileAPI, cfg, userID, asAPI, federation)
|
||||||
if err != nil {
|
p, ok := profile.JSON.(eventutil.UserProfile)
|
||||||
if err == eventutil.ErrProfileNoExists {
|
// not a profile response, so most likely an error, return that
|
||||||
return util.JSONResponse{
|
if !ok {
|
||||||
Code: http.StatusNotFound,
|
return profile
|
||||||
JSON: jsonerror.NotFound("The user does not exist or does not have a profile"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
util.GetLogger(req.Context()).WithError(err).Error("getProfile failed")
|
|
||||||
return jsonerror.InternalServerError()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusOK,
|
Code: http.StatusOK,
|
||||||
JSON: eventutil.AvatarURL{
|
JSON: eventutil.UserProfile{
|
||||||
AvatarURL: profile.AvatarURL,
|
AvatarURL: p.AvatarURL,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetAvatarURL implements PUT /profile/{userID}/avatar_url
|
// SetAvatarURL implements PUT /profile/{userID}/avatar_url
|
||||||
func SetAvatarURL(
|
func SetAvatarURL(
|
||||||
req *http.Request, profileAPI userapi.ClientUserAPI,
|
req *http.Request, profileAPI userapi.ProfileAPI,
|
||||||
device *userapi.Device, userID string, cfg *config.ClientAPI, rsAPI api.ClientRoomserverAPI,
|
device *userapi.Device, userID string, cfg *config.ClientAPI, rsAPI api.ClientRoomserverAPI,
|
||||||
) util.JSONResponse {
|
) util.JSONResponse {
|
||||||
if userID != device.UserID {
|
if userID != device.UserID {
|
||||||
|
|
@ -102,7 +97,7 @@ func SetAvatarURL(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var r eventutil.AvatarURL
|
var r eventutil.UserProfile
|
||||||
if resErr := httputil.UnmarshalJSONRequest(req, &r); resErr != nil {
|
if resErr := httputil.UnmarshalJSONRequest(req, &r); resErr != nil {
|
||||||
return *resErr
|
return *resErr
|
||||||
}
|
}
|
||||||
|
|
@ -128,24 +123,20 @@ func SetAvatarURL(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setRes := &userapi.PerformSetAvatarURLResponse{}
|
profile, changed, err := profileAPI.SetAvatarURL(req.Context(), localpart, domain, r.AvatarURL)
|
||||||
if err = profileAPI.SetAvatarURL(req.Context(), &userapi.PerformSetAvatarURLRequest{
|
if err != nil {
|
||||||
Localpart: localpart,
|
|
||||||
ServerName: domain,
|
|
||||||
AvatarURL: r.AvatarURL,
|
|
||||||
}, setRes); err != nil {
|
|
||||||
util.GetLogger(req.Context()).WithError(err).Error("profileAPI.SetAvatarURL failed")
|
util.GetLogger(req.Context()).WithError(err).Error("profileAPI.SetAvatarURL failed")
|
||||||
return jsonerror.InternalServerError()
|
return jsonerror.InternalServerError()
|
||||||
}
|
}
|
||||||
// No need to build new membership events, since nothing changed
|
// No need to build new membership events, since nothing changed
|
||||||
if !setRes.Changed {
|
if !changed {
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusOK,
|
Code: http.StatusOK,
|
||||||
JSON: struct{}{},
|
JSON: struct{}{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
response, err := updateProfile(req.Context(), rsAPI, device, setRes.Profile, userID, cfg, evTime)
|
response, err := updateProfile(req.Context(), rsAPI, device, profile, userID, cfg, evTime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
@ -158,34 +149,28 @@ func SetAvatarURL(
|
||||||
|
|
||||||
// GetDisplayName implements GET /profile/{userID}/displayname
|
// GetDisplayName implements GET /profile/{userID}/displayname
|
||||||
func GetDisplayName(
|
func GetDisplayName(
|
||||||
req *http.Request, profileAPI userapi.ClientUserAPI, cfg *config.ClientAPI,
|
req *http.Request, profileAPI userapi.ProfileAPI, cfg *config.ClientAPI,
|
||||||
userID string, asAPI appserviceAPI.AppServiceInternalAPI,
|
userID string, asAPI appserviceAPI.AppServiceInternalAPI,
|
||||||
federation *gomatrixserverlib.FederationClient,
|
federation *fclient.FederationClient,
|
||||||
) util.JSONResponse {
|
) util.JSONResponse {
|
||||||
profile, err := getProfile(req.Context(), profileAPI, cfg, userID, asAPI, federation)
|
profile := GetProfile(req, profileAPI, cfg, userID, asAPI, federation)
|
||||||
if err != nil {
|
p, ok := profile.JSON.(eventutil.UserProfile)
|
||||||
if err == eventutil.ErrProfileNoExists {
|
// not a profile response, so most likely an error, return that
|
||||||
return util.JSONResponse{
|
if !ok {
|
||||||
Code: http.StatusNotFound,
|
return profile
|
||||||
JSON: jsonerror.NotFound("The user does not exist or does not have a profile"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
util.GetLogger(req.Context()).WithError(err).Error("getProfile failed")
|
|
||||||
return jsonerror.InternalServerError()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusOK,
|
Code: http.StatusOK,
|
||||||
JSON: eventutil.DisplayName{
|
JSON: eventutil.UserProfile{
|
||||||
DisplayName: profile.DisplayName,
|
DisplayName: p.DisplayName,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetDisplayName implements PUT /profile/{userID}/displayname
|
// SetDisplayName implements PUT /profile/{userID}/displayname
|
||||||
func SetDisplayName(
|
func SetDisplayName(
|
||||||
req *http.Request, profileAPI userapi.ClientUserAPI,
|
req *http.Request, profileAPI userapi.ProfileAPI,
|
||||||
device *userapi.Device, userID string, cfg *config.ClientAPI, rsAPI api.ClientRoomserverAPI,
|
device *userapi.Device, userID string, cfg *config.ClientAPI, rsAPI api.ClientRoomserverAPI,
|
||||||
) util.JSONResponse {
|
) util.JSONResponse {
|
||||||
if userID != device.UserID {
|
if userID != device.UserID {
|
||||||
|
|
@ -195,7 +180,7 @@ func SetDisplayName(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var r eventutil.DisplayName
|
var r eventutil.UserProfile
|
||||||
if resErr := httputil.UnmarshalJSONRequest(req, &r); resErr != nil {
|
if resErr := httputil.UnmarshalJSONRequest(req, &r); resErr != nil {
|
||||||
return *resErr
|
return *resErr
|
||||||
}
|
}
|
||||||
|
|
@ -227,25 +212,20 @@ func SetDisplayName(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
profileRes := &userapi.PerformUpdateDisplayNameResponse{}
|
profile, changed, err := profileAPI.SetDisplayName(req.Context(), localpart, domain, r.DisplayName)
|
||||||
err = profileAPI.SetDisplayName(req.Context(), &userapi.PerformUpdateDisplayNameRequest{
|
|
||||||
Localpart: localpart,
|
|
||||||
ServerName: domain,
|
|
||||||
DisplayName: r.DisplayName,
|
|
||||||
}, profileRes)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
util.GetLogger(req.Context()).WithError(err).Error("profileAPI.SetDisplayName failed")
|
util.GetLogger(req.Context()).WithError(err).Error("profileAPI.SetDisplayName failed")
|
||||||
return jsonerror.InternalServerError()
|
return jsonerror.InternalServerError()
|
||||||
}
|
}
|
||||||
// No need to build new membership events, since nothing changed
|
// No need to build new membership events, since nothing changed
|
||||||
if !profileRes.Changed {
|
if !changed {
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusOK,
|
Code: http.StatusOK,
|
||||||
JSON: struct{}{},
|
JSON: struct{}{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
response, err := updateProfile(req.Context(), rsAPI, device, profileRes.Profile, userID, cfg, evTime)
|
response, err := updateProfile(req.Context(), rsAPI, device, profile, userID, cfg, evTime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
@ -302,12 +282,12 @@ func updateProfile(
|
||||||
// getProfile gets the full profile of a user by querying the database or a
|
// getProfile gets the full profile of a user by querying the database or a
|
||||||
// remote homeserver.
|
// remote homeserver.
|
||||||
// Returns an error when something goes wrong or specifically
|
// Returns an error when something goes wrong or specifically
|
||||||
// eventutil.ErrProfileNoExists when the profile doesn't exist.
|
// eventutil.ErrProfileNotExists when the profile doesn't exist.
|
||||||
func getProfile(
|
func getProfile(
|
||||||
ctx context.Context, profileAPI userapi.ClientUserAPI, cfg *config.ClientAPI,
|
ctx context.Context, profileAPI userapi.ProfileAPI, cfg *config.ClientAPI,
|
||||||
userID string,
|
userID string,
|
||||||
asAPI appserviceAPI.AppServiceInternalAPI,
|
asAPI appserviceAPI.AppServiceInternalAPI,
|
||||||
federation *gomatrixserverlib.FederationClient,
|
federation *fclient.FederationClient,
|
||||||
) (*authtypes.Profile, error) {
|
) (*authtypes.Profile, error) {
|
||||||
localpart, domain, err := gomatrixserverlib.SplitID('@', userID)
|
localpart, domain, err := gomatrixserverlib.SplitID('@', userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -319,7 +299,7 @@ func getProfile(
|
||||||
if fedErr != nil {
|
if fedErr != nil {
|
||||||
if x, ok := fedErr.(gomatrix.HTTPError); ok {
|
if x, ok := fedErr.(gomatrix.HTTPError); ok {
|
||||||
if x.Code == http.StatusNotFound {
|
if x.Code == http.StatusNotFound {
|
||||||
return nil, eventutil.ErrProfileNoExists
|
return nil, appserviceAPI.ErrProfileNotExists
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -734,7 +734,7 @@ func handleRegistrationFlow(
|
||||||
bound bool
|
bound bool
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
bound, threePid.Address, threePid.Medium, err = threepid.CheckAssociation(req.Context(), r.Auth.ThreePidCreds, cfg)
|
bound, threePid.Address, threePid.Medium, err = threepid.CheckAssociation(req.Context(), r.Auth.ThreePidCreds, cfg, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
util.GetLogger(req.Context()).WithError(err).Error("threepid.CheckAssociation failed")
|
util.GetLogger(req.Context()).WithError(err).Error("threepid.CheckAssociation failed")
|
||||||
return jsonerror.InternalServerError()
|
return jsonerror.InternalServerError()
|
||||||
|
|
@ -930,13 +930,7 @@ func completeRegistration(
|
||||||
}
|
}
|
||||||
|
|
||||||
if displayName != "" {
|
if displayName != "" {
|
||||||
nameReq := userapi.PerformUpdateDisplayNameRequest{
|
_, _, err = userAPI.SetDisplayName(ctx, username, serverName, displayName)
|
||||||
Localpart: username,
|
|
||||||
ServerName: serverName,
|
|
||||||
DisplayName: displayName,
|
|
||||||
}
|
|
||||||
var nameRes userapi.PerformUpdateDisplayNameResponse
|
|
||||||
err = userAPI.SetDisplayName(ctx, &nameReq, &nameRes)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusInternalServerError,
|
Code: http.StatusInternalServerError,
|
||||||
|
|
|
||||||
|
|
@ -30,8 +30,11 @@ import (
|
||||||
"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
|
"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
|
||||||
"github.com/matrix-org/dendrite/clientapi/jsonerror"
|
"github.com/matrix-org/dendrite/clientapi/jsonerror"
|
||||||
"github.com/matrix-org/dendrite/internal"
|
"github.com/matrix-org/dendrite/internal"
|
||||||
|
"github.com/matrix-org/dendrite/internal/caching"
|
||||||
|
"github.com/matrix-org/dendrite/internal/sqlutil"
|
||||||
"github.com/matrix-org/dendrite/roomserver"
|
"github.com/matrix-org/dendrite/roomserver"
|
||||||
"github.com/matrix-org/dendrite/setup/config"
|
"github.com/matrix-org/dendrite/setup/config"
|
||||||
|
"github.com/matrix-org/dendrite/setup/jetstream"
|
||||||
"github.com/matrix-org/dendrite/test"
|
"github.com/matrix-org/dendrite/test"
|
||||||
"github.com/matrix-org/dendrite/test/testrig"
|
"github.com/matrix-org/dendrite/test/testrig"
|
||||||
"github.com/matrix-org/dendrite/userapi"
|
"github.com/matrix-org/dendrite/userapi"
|
||||||
|
|
@ -404,11 +407,15 @@ func Test_register(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
|
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
|
||||||
base, baseClose := testrig.CreateBaseDendrite(t, dbType)
|
cfg, processCtx, close := testrig.CreateConfig(t, dbType)
|
||||||
defer baseClose()
|
defer close()
|
||||||
|
|
||||||
rsAPI := roomserver.NewInternalAPI(base)
|
caches := caching.NewRistrettoCache(128*1024*1024, time.Hour, caching.DisableMetrics)
|
||||||
userAPI := userapi.NewInternalAPI(base, rsAPI, nil)
|
natsInstance := jetstream.NATSInstance{}
|
||||||
|
|
||||||
|
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
|
||||||
|
rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, &natsInstance, caches, caching.DisableMetrics)
|
||||||
|
userAPI := userapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, rsAPI, nil)
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
|
@ -430,16 +437,16 @@ func Test_register(t *testing.T) {
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
defer srv.Close()
|
defer srv.Close()
|
||||||
base.Cfg.ClientAPI.RecaptchaSiteVerifyAPI = srv.URL
|
cfg.ClientAPI.RecaptchaSiteVerifyAPI = srv.URL
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := base.Cfg.Derive(); err != nil {
|
if err := cfg.Derive(); err != nil {
|
||||||
t.Fatalf("failed to derive config: %s", err)
|
t.Fatalf("failed to derive config: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
base.Cfg.ClientAPI.RecaptchaEnabled = tc.enableRecaptcha
|
cfg.ClientAPI.RecaptchaEnabled = tc.enableRecaptcha
|
||||||
base.Cfg.ClientAPI.RegistrationDisabled = tc.registrationDisabled
|
cfg.ClientAPI.RegistrationDisabled = tc.registrationDisabled
|
||||||
base.Cfg.ClientAPI.GuestsDisabled = tc.guestsDisabled
|
cfg.ClientAPI.GuestsDisabled = tc.guestsDisabled
|
||||||
|
|
||||||
if tc.kind == "" {
|
if tc.kind == "" {
|
||||||
tc.kind = "user"
|
tc.kind = "user"
|
||||||
|
|
@ -467,15 +474,15 @@ func Test_register(t *testing.T) {
|
||||||
|
|
||||||
req := httptest.NewRequest(http.MethodPost, fmt.Sprintf("/?kind=%s", tc.kind), body)
|
req := httptest.NewRequest(http.MethodPost, fmt.Sprintf("/?kind=%s", tc.kind), body)
|
||||||
|
|
||||||
resp := Register(req, userAPI, &base.Cfg.ClientAPI)
|
resp := Register(req, userAPI, &cfg.ClientAPI)
|
||||||
t.Logf("Resp: %+v", resp)
|
t.Logf("Resp: %+v", resp)
|
||||||
|
|
||||||
// The first request should return a userInteractiveResponse
|
// The first request should return a userInteractiveResponse
|
||||||
switch r := resp.JSON.(type) {
|
switch r := resp.JSON.(type) {
|
||||||
case userInteractiveResponse:
|
case userInteractiveResponse:
|
||||||
// Check that the flows are the ones we configured
|
// Check that the flows are the ones we configured
|
||||||
if !reflect.DeepEqual(r.Flows, base.Cfg.Derived.Registration.Flows) {
|
if !reflect.DeepEqual(r.Flows, cfg.Derived.Registration.Flows) {
|
||||||
t.Fatalf("unexpected registration flows: %+v, want %+v", r.Flows, base.Cfg.Derived.Registration.Flows)
|
t.Fatalf("unexpected registration flows: %+v, want %+v", r.Flows, cfg.Derived.Registration.Flows)
|
||||||
}
|
}
|
||||||
case *jsonerror.MatrixError:
|
case *jsonerror.MatrixError:
|
||||||
if !reflect.DeepEqual(tc.wantResponse, resp) {
|
if !reflect.DeepEqual(tc.wantResponse, resp) {
|
||||||
|
|
@ -531,7 +538,7 @@ func Test_register(t *testing.T) {
|
||||||
|
|
||||||
req = httptest.NewRequest(http.MethodPost, "/", body)
|
req = httptest.NewRequest(http.MethodPost, "/", body)
|
||||||
|
|
||||||
resp = Register(req, userAPI, &base.Cfg.ClientAPI)
|
resp = Register(req, userAPI, &cfg.ClientAPI)
|
||||||
|
|
||||||
switch resp.JSON.(type) {
|
switch resp.JSON.(type) {
|
||||||
case *jsonerror.MatrixError:
|
case *jsonerror.MatrixError:
|
||||||
|
|
@ -574,16 +581,19 @@ func Test_register(t *testing.T) {
|
||||||
|
|
||||||
func TestRegisterUserWithDisplayName(t *testing.T) {
|
func TestRegisterUserWithDisplayName(t *testing.T) {
|
||||||
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
|
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
|
||||||
base, baseClose := testrig.CreateBaseDendrite(t, dbType)
|
cfg, processCtx, close := testrig.CreateConfig(t, dbType)
|
||||||
defer baseClose()
|
defer close()
|
||||||
base.Cfg.Global.ServerName = "server"
|
cfg.Global.ServerName = "server"
|
||||||
|
|
||||||
rsAPI := roomserver.NewInternalAPI(base)
|
caches := caching.NewRistrettoCache(128*1024*1024, time.Hour, caching.DisableMetrics)
|
||||||
userAPI := userapi.NewInternalAPI(base, rsAPI, nil)
|
natsInstance := jetstream.NATSInstance{}
|
||||||
|
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
|
||||||
|
rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, &natsInstance, caches, caching.DisableMetrics)
|
||||||
|
userAPI := userapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, rsAPI, nil)
|
||||||
deviceName, deviceID := "deviceName", "deviceID"
|
deviceName, deviceID := "deviceName", "deviceID"
|
||||||
expectedDisplayName := "DisplayName"
|
expectedDisplayName := "DisplayName"
|
||||||
response := completeRegistration(
|
response := completeRegistration(
|
||||||
base.Context(),
|
processCtx.Context(),
|
||||||
userAPI,
|
userAPI,
|
||||||
"user",
|
"user",
|
||||||
"server",
|
"server",
|
||||||
|
|
@ -602,24 +612,25 @@ func TestRegisterUserWithDisplayName(t *testing.T) {
|
||||||
|
|
||||||
assert.Equal(t, http.StatusOK, response.Code)
|
assert.Equal(t, http.StatusOK, response.Code)
|
||||||
|
|
||||||
req := api.QueryProfileRequest{UserID: "@user:server"}
|
profile, err := userAPI.QueryProfile(processCtx.Context(), "@user:server")
|
||||||
var res api.QueryProfileResponse
|
|
||||||
err := userAPI.QueryProfile(base.Context(), &req, &res)
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, expectedDisplayName, res.DisplayName)
|
assert.Equal(t, expectedDisplayName, profile.DisplayName)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRegisterAdminUsingSharedSecret(t *testing.T) {
|
func TestRegisterAdminUsingSharedSecret(t *testing.T) {
|
||||||
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
|
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
|
||||||
base, baseClose := testrig.CreateBaseDendrite(t, dbType)
|
cfg, processCtx, close := testrig.CreateConfig(t, dbType)
|
||||||
defer baseClose()
|
defer close()
|
||||||
base.Cfg.Global.ServerName = "server"
|
natsInstance := jetstream.NATSInstance{}
|
||||||
|
cfg.Global.ServerName = "server"
|
||||||
sharedSecret := "dendritetest"
|
sharedSecret := "dendritetest"
|
||||||
base.Cfg.ClientAPI.RegistrationSharedSecret = sharedSecret
|
cfg.ClientAPI.RegistrationSharedSecret = sharedSecret
|
||||||
|
|
||||||
rsAPI := roomserver.NewInternalAPI(base)
|
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
|
||||||
userAPI := userapi.NewInternalAPI(base, rsAPI, nil)
|
caches := caching.NewRistrettoCache(128*1024*1024, time.Hour, caching.DisableMetrics)
|
||||||
|
rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, &natsInstance, caches, caching.DisableMetrics)
|
||||||
|
userAPI := userapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, rsAPI, nil)
|
||||||
|
|
||||||
expectedDisplayName := "rabbit"
|
expectedDisplayName := "rabbit"
|
||||||
jsonStr := []byte(`{"admin":true,"mac":"24dca3bba410e43fe64b9b5c28306693bf3baa9f","nonce":"759f047f312b99ff428b21d581256f8592b8976e58bc1b543972dc6147e529a79657605b52d7becd160ff5137f3de11975684319187e06901955f79e5a6c5a79","password":"wonderland","username":"alice","displayname":"rabbit"}`)
|
jsonStr := []byte(`{"admin":true,"mac":"24dca3bba410e43fe64b9b5c28306693bf3baa9f","nonce":"759f047f312b99ff428b21d581256f8592b8976e58bc1b543972dc6147e529a79657605b52d7becd160ff5137f3de11975684319187e06901955f79e5a6c5a79","password":"wonderland","username":"alice","displayname":"rabbit"}`)
|
||||||
|
|
@ -643,17 +654,15 @@ func TestRegisterAdminUsingSharedSecret(t *testing.T) {
|
||||||
ssrr := httptest.NewRequest(http.MethodPost, "/", body)
|
ssrr := httptest.NewRequest(http.MethodPost, "/", body)
|
||||||
|
|
||||||
response := handleSharedSecretRegistration(
|
response := handleSharedSecretRegistration(
|
||||||
&base.Cfg.ClientAPI,
|
&cfg.ClientAPI,
|
||||||
userAPI,
|
userAPI,
|
||||||
r,
|
r,
|
||||||
ssrr,
|
ssrr,
|
||||||
)
|
)
|
||||||
assert.Equal(t, http.StatusOK, response.Code)
|
assert.Equal(t, http.StatusOK, response.Code)
|
||||||
|
|
||||||
profilReq := api.QueryProfileRequest{UserID: "@alice:server"}
|
profile, err := userAPI.QueryProfile(processCtx.Context(), "@alice:server")
|
||||||
var profileRes api.QueryProfileResponse
|
|
||||||
err = userAPI.QueryProfile(base.Context(), &profilReq, &profileRes)
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, expectedDisplayName, profileRes.DisplayName)
|
assert.Equal(t, expectedDisplayName, profile.DisplayName)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,12 +18,12 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/matrix-org/dendrite/setup/base"
|
"github.com/matrix-org/dendrite/setup/base"
|
||||||
userapi "github.com/matrix-org/dendrite/userapi/api"
|
userapi "github.com/matrix-org/dendrite/userapi/api"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib/fclient"
|
||||||
"github.com/matrix-org/util"
|
"github.com/matrix-org/util"
|
||||||
"github.com/nats-io/nats.go"
|
"github.com/nats-io/nats.go"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
|
@ -51,25 +51,27 @@ import (
|
||||||
// applied:
|
// applied:
|
||||||
// nolint: gocyclo
|
// nolint: gocyclo
|
||||||
func Setup(
|
func Setup(
|
||||||
base *base.BaseDendrite,
|
routers httputil.Routers,
|
||||||
cfg *config.ClientAPI,
|
dendriteCfg *config.Dendrite,
|
||||||
rsAPI roomserverAPI.ClientRoomserverAPI,
|
rsAPI roomserverAPI.ClientRoomserverAPI,
|
||||||
asAPI appserviceAPI.AppServiceInternalAPI,
|
asAPI appserviceAPI.AppServiceInternalAPI,
|
||||||
userAPI userapi.ClientUserAPI,
|
userAPI userapi.ClientUserAPI,
|
||||||
userDirectoryProvider userapi.QuerySearchProfilesAPI,
|
userDirectoryProvider userapi.QuerySearchProfilesAPI,
|
||||||
federation *gomatrixserverlib.FederationClient,
|
federation *fclient.FederationClient,
|
||||||
syncProducer *producers.SyncAPIProducer,
|
syncProducer *producers.SyncAPIProducer,
|
||||||
transactionsCache *transactions.Cache,
|
transactionsCache *transactions.Cache,
|
||||||
federationSender federationAPI.ClientFederationAPI,
|
federationSender federationAPI.ClientFederationAPI,
|
||||||
extRoomsProvider api.ExtraPublicRoomsProvider,
|
extRoomsProvider api.ExtraPublicRoomsProvider,
|
||||||
mscCfg *config.MSCs, natsClient *nats.Conn,
|
natsClient *nats.Conn, enableMetrics bool,
|
||||||
) {
|
) {
|
||||||
publicAPIMux := base.PublicClientAPIMux
|
cfg := &dendriteCfg.ClientAPI
|
||||||
wkMux := base.PublicWellKnownAPIMux
|
mscCfg := &dendriteCfg.MSCs
|
||||||
synapseAdminRouter := base.SynapseAdminMux
|
publicAPIMux := routers.Client
|
||||||
dendriteAdminRouter := base.DendriteAdminMux
|
wkMux := routers.WellKnown
|
||||||
|
synapseAdminRouter := routers.SynapseAdmin
|
||||||
|
dendriteAdminRouter := routers.DendriteAdmin
|
||||||
|
|
||||||
if base.EnableMetrics {
|
if enableMetrics {
|
||||||
prometheus.MustRegister(amtRegUsers, sendEventDuration)
|
prometheus.MustRegister(amtRegUsers, sendEventDuration)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -156,15 +158,15 @@ func Setup(
|
||||||
|
|
||||||
dendriteAdminRouter.Handle("/admin/evacuateRoom/{roomID}",
|
dendriteAdminRouter.Handle("/admin/evacuateRoom/{roomID}",
|
||||||
httputil.MakeAdminAPI("admin_evacuate_room", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAdminAPI("admin_evacuate_room", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
return AdminEvacuateRoom(req, cfg, device, rsAPI)
|
return AdminEvacuateRoom(req, rsAPI)
|
||||||
}),
|
}),
|
||||||
).Methods(http.MethodGet, http.MethodOptions)
|
).Methods(http.MethodPost, http.MethodOptions)
|
||||||
|
|
||||||
dendriteAdminRouter.Handle("/admin/evacuateUser/{userID}",
|
dendriteAdminRouter.Handle("/admin/evacuateUser/{userID}",
|
||||||
httputil.MakeAdminAPI("admin_evacuate_user", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAdminAPI("admin_evacuate_user", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
return AdminEvacuateUser(req, cfg, device, rsAPI)
|
return AdminEvacuateUser(req, cfg, rsAPI)
|
||||||
}),
|
}),
|
||||||
).Methods(http.MethodGet, http.MethodOptions)
|
).Methods(http.MethodPost, http.MethodOptions)
|
||||||
|
|
||||||
dendriteAdminRouter.Handle("/admin/purgeRoom/{roomID}",
|
dendriteAdminRouter.Handle("/admin/purgeRoom/{roomID}",
|
||||||
httputil.MakeAdminAPI("admin_purge_room", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAdminAPI("admin_purge_room", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
|
|
@ -199,18 +201,13 @@ func Setup(
|
||||||
// server notifications
|
// server notifications
|
||||||
if cfg.Matrix.ServerNotices.Enabled {
|
if cfg.Matrix.ServerNotices.Enabled {
|
||||||
logrus.Info("Enabling server notices at /_synapse/admin/v1/send_server_notice")
|
logrus.Info("Enabling server notices at /_synapse/admin/v1/send_server_notice")
|
||||||
var serverNotificationSender *userapi.Device
|
serverNotificationSender, err := getSenderDevice(context.Background(), rsAPI, userAPI, cfg)
|
||||||
var err error
|
|
||||||
notificationSenderOnce := &sync.Once{}
|
|
||||||
|
|
||||||
synapseAdminRouter.Handle("/admin/v1/send_server_notice/{txnID}",
|
|
||||||
httputil.MakeAuthAPI("send_server_notice", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
|
||||||
notificationSenderOnce.Do(func() {
|
|
||||||
serverNotificationSender, err = getSenderDevice(context.Background(), rsAPI, userAPI, cfg)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.WithError(err).Fatal("unable to get account for sending sending server notices")
|
logrus.WithError(err).Fatal("unable to get account for sending sending server notices")
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
synapseAdminRouter.Handle("/admin/v1/send_server_notice/{txnID}",
|
||||||
|
httputil.MakeAuthAPI("send_server_notice", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
// not specced, but ensure we're rate limiting requests to this endpoint
|
// not specced, but ensure we're rate limiting requests to this endpoint
|
||||||
if r := rateLimits.Limit(req, device); r != nil {
|
if r := rateLimits.Limit(req, device); r != nil {
|
||||||
return *r
|
return *r
|
||||||
|
|
@ -232,12 +229,6 @@ func Setup(
|
||||||
|
|
||||||
synapseAdminRouter.Handle("/admin/v1/send_server_notice",
|
synapseAdminRouter.Handle("/admin/v1/send_server_notice",
|
||||||
httputil.MakeAuthAPI("send_server_notice", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("send_server_notice", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
notificationSenderOnce.Do(func() {
|
|
||||||
serverNotificationSender, err = getSenderDevice(context.Background(), rsAPI, userAPI, cfg)
|
|
||||||
if err != nil {
|
|
||||||
logrus.WithError(err).Fatal("unable to get account for sending sending server notices")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
// not specced, but ensure we're rate limiting requests to this endpoint
|
// not specced, but ensure we're rate limiting requests to this endpoint
|
||||||
if r := rateLimits.Limit(req, device); r != nil {
|
if r := rateLimits.Limit(req, device); r != nil {
|
||||||
return *r
|
return *r
|
||||||
|
|
@ -669,7 +660,7 @@ func Setup(
|
||||||
).Methods(http.MethodGet, http.MethodPost, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodPost, http.MethodOptions)
|
||||||
|
|
||||||
v3mux.Handle("/auth/{authType}/fallback/web",
|
v3mux.Handle("/auth/{authType}/fallback/web",
|
||||||
httputil.MakeHTMLAPI("auth_fallback", base.EnableMetrics, func(w http.ResponseWriter, req *http.Request) {
|
httputil.MakeHTMLAPI("auth_fallback", enableMetrics, func(w http.ResponseWriter, req *http.Request) {
|
||||||
vars := mux.Vars(req)
|
vars := mux.Vars(req)
|
||||||
AuthFallback(w, req, vars["authType"], cfg)
|
AuthFallback(w, req, vars["authType"], cfg)
|
||||||
}),
|
}),
|
||||||
|
|
@ -873,6 +864,8 @@ func Setup(
|
||||||
// Browsers use the OPTIONS HTTP method to check if the CORS policy allows
|
// Browsers use the OPTIONS HTTP method to check if the CORS policy allows
|
||||||
// PUT requests, so we need to allow this method
|
// PUT requests, so we need to allow this method
|
||||||
|
|
||||||
|
threePIDClient := base.CreateClient(dendriteCfg, nil) // TODO: Move this somewhere else, e.g. pass in as parameter
|
||||||
|
|
||||||
v3mux.Handle("/account/3pid",
|
v3mux.Handle("/account/3pid",
|
||||||
httputil.MakeAuthAPI("account_3pid", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("account_3pid", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
return GetAssociated3PIDs(req, userAPI, device)
|
return GetAssociated3PIDs(req, userAPI, device)
|
||||||
|
|
@ -881,11 +874,11 @@ func Setup(
|
||||||
|
|
||||||
v3mux.Handle("/account/3pid",
|
v3mux.Handle("/account/3pid",
|
||||||
httputil.MakeAuthAPI("account_3pid", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("account_3pid", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
return CheckAndSave3PIDAssociation(req, userAPI, device, cfg)
|
return CheckAndSave3PIDAssociation(req, userAPI, device, cfg, threePIDClient)
|
||||||
}),
|
}),
|
||||||
).Methods(http.MethodPost, http.MethodOptions)
|
).Methods(http.MethodPost, http.MethodOptions)
|
||||||
|
|
||||||
unstableMux.Handle("/account/3pid/delete",
|
v3mux.Handle("/account/3pid/delete",
|
||||||
httputil.MakeAuthAPI("account_3pid", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("account_3pid", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
return Forget3PID(req, userAPI)
|
return Forget3PID(req, userAPI)
|
||||||
}),
|
}),
|
||||||
|
|
@ -893,7 +886,7 @@ func Setup(
|
||||||
|
|
||||||
v3mux.Handle("/{path:(?:account/3pid|register)}/email/requestToken",
|
v3mux.Handle("/{path:(?:account/3pid|register)}/email/requestToken",
|
||||||
httputil.MakeExternalAPI("account_3pid_request_token", func(req *http.Request) util.JSONResponse {
|
httputil.MakeExternalAPI("account_3pid_request_token", func(req *http.Request) util.JSONResponse {
|
||||||
return RequestEmailToken(req, userAPI, cfg)
|
return RequestEmailToken(req, userAPI, cfg, threePIDClient)
|
||||||
}),
|
}),
|
||||||
).Methods(http.MethodPost, http.MethodOptions)
|
).Methods(http.MethodPost, http.MethodOptions)
|
||||||
|
|
||||||
|
|
@ -1127,7 +1120,7 @@ func Setup(
|
||||||
|
|
||||||
v3mux.Handle("/delete_devices",
|
v3mux.Handle("/delete_devices",
|
||||||
httputil.MakeAuthAPI("delete_devices", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("delete_devices", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
return DeleteDevices(req, userAPI, device)
|
return DeleteDevices(req, userInteractiveAuth, userAPI, device)
|
||||||
}),
|
}),
|
||||||
).Methods(http.MethodPost, http.MethodOptions)
|
).Methods(http.MethodPost, http.MethodOptions)
|
||||||
|
|
||||||
|
|
@ -1206,7 +1199,7 @@ func Setup(
|
||||||
if r := rateLimits.Limit(req, device); r != nil {
|
if r := rateLimits.Limit(req, device); r != nil {
|
||||||
return *r
|
return *r
|
||||||
}
|
}
|
||||||
return GetCapabilities(req, rsAPI)
|
return GetCapabilities()
|
||||||
}, httputil.WithAllowGuests()),
|
}, httputil.WithAllowGuests()),
|
||||||
).Methods(http.MethodGet, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
|
|
@ -1383,7 +1376,7 @@ func Setup(
|
||||||
// Cross-signing device keys
|
// Cross-signing device keys
|
||||||
|
|
||||||
postDeviceSigningKeys := httputil.MakeAuthAPI("post_device_signing_keys", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
postDeviceSigningKeys := httputil.MakeAuthAPI("post_device_signing_keys", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
return UploadCrossSigningDeviceKeys(req, userInteractiveAuth, userAPI, device, userAPI, cfg)
|
return UploadCrossSigningDeviceKeys(req, userAPI, device, userAPI, cfg)
|
||||||
})
|
})
|
||||||
|
|
||||||
postDeviceSigningSignatures := httputil.MakeAuthAPI("post_device_signing_signatures", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
postDeviceSigningSignatures := httputil.MakeAuthAPI("post_device_signing_signatures", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
|
|
|
||||||
|
|
@ -15,12 +15,13 @@ package routing
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/matrix-org/util"
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/clientapi/httputil"
|
"github.com/matrix-org/dendrite/clientapi/httputil"
|
||||||
"github.com/matrix-org/dendrite/clientapi/jsonerror"
|
"github.com/matrix-org/dendrite/clientapi/jsonerror"
|
||||||
"github.com/matrix-org/dendrite/clientapi/producers"
|
"github.com/matrix-org/dendrite/clientapi/producers"
|
||||||
roomserverAPI "github.com/matrix-org/dendrite/roomserver/api"
|
roomserverAPI "github.com/matrix-org/dendrite/roomserver/api"
|
||||||
userapi "github.com/matrix-org/dendrite/userapi/api"
|
userapi "github.com/matrix-org/dendrite/userapi/api"
|
||||||
"github.com/matrix-org/util"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type typingContentJSON struct {
|
type typingContentJSON struct {
|
||||||
|
|
|
||||||
|
|
@ -295,30 +295,28 @@ func getSenderDevice(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the avatarurl for the user
|
// Set the avatarurl for the user
|
||||||
avatarRes := &userapi.PerformSetAvatarURLResponse{}
|
profile, avatarChanged, err := userAPI.SetAvatarURL(ctx,
|
||||||
if err = userAPI.SetAvatarURL(ctx, &userapi.PerformSetAvatarURLRequest{
|
cfg.Matrix.ServerNotices.LocalPart,
|
||||||
Localpart: cfg.Matrix.ServerNotices.LocalPart,
|
cfg.Matrix.ServerName,
|
||||||
ServerName: cfg.Matrix.ServerName,
|
cfg.Matrix.ServerNotices.AvatarURL,
|
||||||
AvatarURL: cfg.Matrix.ServerNotices.AvatarURL,
|
)
|
||||||
}, avatarRes); err != nil {
|
if err != nil {
|
||||||
util.GetLogger(ctx).WithError(err).Error("userAPI.SetAvatarURL failed")
|
util.GetLogger(ctx).WithError(err).Error("userAPI.SetAvatarURL failed")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
profile := avatarRes.Profile
|
|
||||||
|
|
||||||
// Set the displayname for the user
|
// Set the displayname for the user
|
||||||
displayNameRes := &userapi.PerformUpdateDisplayNameResponse{}
|
_, displayNameChanged, err := userAPI.SetDisplayName(ctx,
|
||||||
if err = userAPI.SetDisplayName(ctx, &userapi.PerformUpdateDisplayNameRequest{
|
cfg.Matrix.ServerNotices.LocalPart,
|
||||||
Localpart: cfg.Matrix.ServerNotices.LocalPart,
|
cfg.Matrix.ServerName,
|
||||||
ServerName: cfg.Matrix.ServerName,
|
cfg.Matrix.ServerNotices.DisplayName,
|
||||||
DisplayName: cfg.Matrix.ServerNotices.DisplayName,
|
)
|
||||||
}, displayNameRes); err != nil {
|
if err != nil {
|
||||||
util.GetLogger(ctx).WithError(err).Error("userAPI.SetDisplayName failed")
|
util.GetLogger(ctx).WithError(err).Error("userAPI.SetDisplayName failed")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if displayNameRes.Changed {
|
if displayNameChanged {
|
||||||
profile.DisplayName = cfg.Matrix.ServerNotices.DisplayName
|
profile.DisplayName = cfg.Matrix.ServerNotices.DisplayName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -334,7 +332,7 @@ func getSenderDevice(
|
||||||
// We've got an existing account, return the first device of it
|
// We've got an existing account, return the first device of it
|
||||||
if len(deviceRes.Devices) > 0 {
|
if len(deviceRes.Devices) > 0 {
|
||||||
// If there were changes to the profile, create a new membership event
|
// If there were changes to the profile, create a new membership event
|
||||||
if displayNameRes.Changed || avatarRes.Changed {
|
if displayNameChanged || avatarChanged {
|
||||||
_, err = updateProfile(ctx, rsAPI, &deviceRes.Devices[0], profile, accRes.Account.UserID, cfg, time.Now())
|
_, err = updateProfile(ctx, rsAPI, &deviceRes.Devices[0], profile, accRes.Account.UserID, cfg, time.Now())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ import (
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/clientapi/jsonerror"
|
"github.com/matrix-org/dendrite/clientapi/jsonerror"
|
||||||
"github.com/matrix-org/dendrite/roomserver/api"
|
"github.com/matrix-org/dendrite/roomserver/api"
|
||||||
|
"github.com/matrix-org/dendrite/syncapi/synctypes"
|
||||||
userapi "github.com/matrix-org/dendrite/userapi/api"
|
userapi "github.com/matrix-org/dendrite/userapi/api"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
"github.com/matrix-org/util"
|
"github.com/matrix-org/util"
|
||||||
|
|
@ -29,7 +30,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type stateEventInStateResp struct {
|
type stateEventInStateResp struct {
|
||||||
gomatrixserverlib.ClientEvent
|
synctypes.ClientEvent
|
||||||
PrevContent json.RawMessage `json:"prev_content,omitempty"`
|
PrevContent json.RawMessage `json:"prev_content,omitempty"`
|
||||||
ReplacesState string `json:"replaces_state,omitempty"`
|
ReplacesState string `json:"replaces_state,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
@ -122,7 +123,7 @@ func OnIncomingStateRequest(ctx context.Context, device *userapi.Device, rsAPI a
|
||||||
"state_at_event": !wantLatestState,
|
"state_at_event": !wantLatestState,
|
||||||
}).Info("Fetching all state")
|
}).Info("Fetching all state")
|
||||||
|
|
||||||
stateEvents := []gomatrixserverlib.ClientEvent{}
|
stateEvents := []synctypes.ClientEvent{}
|
||||||
if wantLatestState {
|
if wantLatestState {
|
||||||
// If we are happy to use the latest state, either because the user is
|
// If we are happy to use the latest state, either because the user is
|
||||||
// still in the room, or because the room is world-readable, then just
|
// still in the room, or because the room is world-readable, then just
|
||||||
|
|
@ -131,7 +132,7 @@ func OnIncomingStateRequest(ctx context.Context, device *userapi.Device, rsAPI a
|
||||||
for _, ev := range stateRes.StateEvents {
|
for _, ev := range stateRes.StateEvents {
|
||||||
stateEvents = append(
|
stateEvents = append(
|
||||||
stateEvents,
|
stateEvents,
|
||||||
gomatrixserverlib.HeaderedToClientEvent(ev, gomatrixserverlib.FormatAll),
|
synctypes.HeaderedToClientEvent(ev, synctypes.FormatAll),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -150,7 +151,7 @@ func OnIncomingStateRequest(ctx context.Context, device *userapi.Device, rsAPI a
|
||||||
for _, ev := range stateAfterRes.StateEvents {
|
for _, ev := range stateAfterRes.StateEvents {
|
||||||
stateEvents = append(
|
stateEvents = append(
|
||||||
stateEvents,
|
stateEvents,
|
||||||
gomatrixserverlib.HeaderedToClientEvent(ev, gomatrixserverlib.FormatAll),
|
synctypes.HeaderedToClientEvent(ev, synctypes.FormatAll),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -309,7 +310,7 @@ func OnIncomingStateTypeRequest(
|
||||||
}
|
}
|
||||||
|
|
||||||
stateEvent := stateEventInStateResp{
|
stateEvent := stateEventInStateResp{
|
||||||
ClientEvent: gomatrixserverlib.HeaderedToClientEvent(event, gomatrixserverlib.FormatAll),
|
ClientEvent: synctypes.HeaderedToClientEvent(event, synctypes.FormatAll),
|
||||||
}
|
}
|
||||||
|
|
||||||
var res interface{}
|
var res interface{}
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import (
|
||||||
"github.com/matrix-org/dendrite/setup/config"
|
"github.com/matrix-org/dendrite/setup/config"
|
||||||
"github.com/matrix-org/dendrite/userapi/api"
|
"github.com/matrix-org/dendrite/userapi/api"
|
||||||
userdb "github.com/matrix-org/dendrite/userapi/storage"
|
userdb "github.com/matrix-org/dendrite/userapi/storage"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib/fclient"
|
||||||
|
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
"github.com/matrix-org/util"
|
"github.com/matrix-org/util"
|
||||||
|
|
@ -33,7 +34,7 @@ type reqTokenResponse struct {
|
||||||
SID string `json:"sid"`
|
SID string `json:"sid"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type threePIDsResponse struct {
|
type ThreePIDsResponse struct {
|
||||||
ThreePIDs []authtypes.ThreePID `json:"threepids"`
|
ThreePIDs []authtypes.ThreePID `json:"threepids"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -41,7 +42,7 @@ type threePIDsResponse struct {
|
||||||
//
|
//
|
||||||
// POST /account/3pid/email/requestToken
|
// POST /account/3pid/email/requestToken
|
||||||
// POST /register/email/requestToken
|
// POST /register/email/requestToken
|
||||||
func RequestEmailToken(req *http.Request, threePIDAPI api.ClientUserAPI, cfg *config.ClientAPI) util.JSONResponse {
|
func RequestEmailToken(req *http.Request, threePIDAPI api.ClientUserAPI, cfg *config.ClientAPI, client *fclient.Client) util.JSONResponse {
|
||||||
var body threepid.EmailAssociationRequest
|
var body threepid.EmailAssociationRequest
|
||||||
if reqErr := httputil.UnmarshalJSONRequest(req, &body); reqErr != nil {
|
if reqErr := httputil.UnmarshalJSONRequest(req, &body); reqErr != nil {
|
||||||
return *reqErr
|
return *reqErr
|
||||||
|
|
@ -72,7 +73,7 @@ func RequestEmailToken(req *http.Request, threePIDAPI api.ClientUserAPI, cfg *co
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resp.SID, err = threepid.CreateSession(req.Context(), body, cfg)
|
resp.SID, err = threepid.CreateSession(req.Context(), body, cfg, client)
|
||||||
if err == threepid.ErrNotTrusted {
|
if err == threepid.ErrNotTrusted {
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusBadRequest,
|
Code: http.StatusBadRequest,
|
||||||
|
|
@ -92,7 +93,7 @@ func RequestEmailToken(req *http.Request, threePIDAPI api.ClientUserAPI, cfg *co
|
||||||
// CheckAndSave3PIDAssociation implements POST /account/3pid
|
// CheckAndSave3PIDAssociation implements POST /account/3pid
|
||||||
func CheckAndSave3PIDAssociation(
|
func CheckAndSave3PIDAssociation(
|
||||||
req *http.Request, threePIDAPI api.ClientUserAPI, device *api.Device,
|
req *http.Request, threePIDAPI api.ClientUserAPI, device *api.Device,
|
||||||
cfg *config.ClientAPI,
|
cfg *config.ClientAPI, client *fclient.Client,
|
||||||
) util.JSONResponse {
|
) util.JSONResponse {
|
||||||
var body threepid.EmailAssociationCheckRequest
|
var body threepid.EmailAssociationCheckRequest
|
||||||
if reqErr := httputil.UnmarshalJSONRequest(req, &body); reqErr != nil {
|
if reqErr := httputil.UnmarshalJSONRequest(req, &body); reqErr != nil {
|
||||||
|
|
@ -100,7 +101,7 @@ func CheckAndSave3PIDAssociation(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the association has been validated
|
// Check if the association has been validated
|
||||||
verified, address, medium, err := threepid.CheckAssociation(req.Context(), body.Creds, cfg)
|
verified, address, medium, err := threepid.CheckAssociation(req.Context(), body.Creds, cfg, client)
|
||||||
if err == threepid.ErrNotTrusted {
|
if err == threepid.ErrNotTrusted {
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusBadRequest,
|
Code: http.StatusBadRequest,
|
||||||
|
|
@ -123,13 +124,8 @@ func CheckAndSave3PIDAssociation(
|
||||||
|
|
||||||
if body.Bind {
|
if body.Bind {
|
||||||
// Publish the association on the identity server if requested
|
// Publish the association on the identity server if requested
|
||||||
err = threepid.PublishAssociation(body.Creds, device.UserID, cfg)
|
err = threepid.PublishAssociation(req.Context(), body.Creds, device.UserID, cfg, client)
|
||||||
if err == threepid.ErrNotTrusted {
|
if err != nil {
|
||||||
return util.JSONResponse{
|
|
||||||
Code: http.StatusBadRequest,
|
|
||||||
JSON: jsonerror.NotTrusted(body.Creds.IDServer),
|
|
||||||
}
|
|
||||||
} else if err != nil {
|
|
||||||
util.GetLogger(req.Context()).WithError(err).Error("threepid.PublishAssociation failed")
|
util.GetLogger(req.Context()).WithError(err).Error("threepid.PublishAssociation failed")
|
||||||
return jsonerror.InternalServerError()
|
return jsonerror.InternalServerError()
|
||||||
}
|
}
|
||||||
|
|
@ -180,7 +176,7 @@ func GetAssociated3PIDs(
|
||||||
|
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusOK,
|
Code: http.StatusOK,
|
||||||
JSON: threePIDsResponse{res.ThreePIDs},
|
JSON: ThreePIDsResponse{res.ThreePIDs},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -191,7 +187,10 @@ func Forget3PID(req *http.Request, threepidAPI api.ClientUserAPI) util.JSONRespo
|
||||||
return *reqErr
|
return *reqErr
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := threepidAPI.PerformForgetThreePID(req.Context(), &api.PerformForgetThreePIDRequest{}, &struct{}{}); err != nil {
|
if err := threepidAPI.PerformForgetThreePID(req.Context(), &api.PerformForgetThreePIDRequest{
|
||||||
|
ThreePID: body.Address,
|
||||||
|
Medium: body.Medium,
|
||||||
|
}, &struct{}{}); err != nil {
|
||||||
util.GetLogger(req.Context()).WithError(err).Error("threepidAPI.PerformForgetThreePID failed")
|
util.GetLogger(req.Context()).WithError(err).Error("threepidAPI.PerformForgetThreePID failed")
|
||||||
return jsonerror.InternalServerError()
|
return jsonerror.InternalServerError()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ import (
|
||||||
userapi "github.com/matrix-org/dendrite/userapi/api"
|
userapi "github.com/matrix-org/dendrite/userapi/api"
|
||||||
"github.com/matrix-org/gomatrix"
|
"github.com/matrix-org/gomatrix"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib/fclient"
|
||||||
"github.com/matrix-org/util"
|
"github.com/matrix-org/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -41,7 +42,7 @@ func SearchUserDirectory(
|
||||||
provider userapi.QuerySearchProfilesAPI,
|
provider userapi.QuerySearchProfilesAPI,
|
||||||
searchString string,
|
searchString string,
|
||||||
limit int,
|
limit int,
|
||||||
federation *gomatrixserverlib.FederationClient,
|
federation *fclient.FederationClient,
|
||||||
localServerName gomatrixserverlib.ServerName,
|
localServerName gomatrixserverlib.ServerName,
|
||||||
) util.JSONResponse {
|
) util.JSONResponse {
|
||||||
if limit < 10 {
|
if limit < 10 {
|
||||||
|
|
|
||||||
|
|
@ -209,24 +209,17 @@ func queryIDServerStoreInvite(
|
||||||
body *MembershipRequest, roomID string,
|
body *MembershipRequest, roomID string,
|
||||||
) (*idServerStoreInviteResponse, error) {
|
) (*idServerStoreInviteResponse, error) {
|
||||||
// Retrieve the sender's profile to get their display name
|
// Retrieve the sender's profile to get their display name
|
||||||
localpart, serverName, err := gomatrixserverlib.SplitID('@', device.UserID)
|
_, serverName, err := gomatrixserverlib.SplitID('@', device.UserID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var profile *authtypes.Profile
|
var profile *authtypes.Profile
|
||||||
if cfg.Matrix.IsLocalServerName(serverName) {
|
if cfg.Matrix.IsLocalServerName(serverName) {
|
||||||
res := &userapi.QueryProfileResponse{}
|
profile, err = userAPI.QueryProfile(ctx, device.UserID)
|
||||||
err = userAPI.QueryProfile(ctx, &userapi.QueryProfileRequest{UserID: device.UserID}, res)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
profile = &authtypes.Profile{
|
|
||||||
Localpart: localpart,
|
|
||||||
DisplayName: res.DisplayName,
|
|
||||||
AvatarURL: res.AvatarURL,
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
profile = &authtypes.Profile{}
|
profile = &authtypes.Profile{}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/setup/config"
|
"github.com/matrix-org/dendrite/setup/config"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib/fclient"
|
||||||
)
|
)
|
||||||
|
|
||||||
// EmailAssociationRequest represents the request defined at https://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-register-email-requesttoken
|
// EmailAssociationRequest represents the request defined at https://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-register-email-requesttoken
|
||||||
|
|
@ -37,7 +38,7 @@ type EmailAssociationRequest struct {
|
||||||
|
|
||||||
// EmailAssociationCheckRequest represents the request defined at https://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-account-3pid
|
// EmailAssociationCheckRequest represents the request defined at https://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-account-3pid
|
||||||
type EmailAssociationCheckRequest struct {
|
type EmailAssociationCheckRequest struct {
|
||||||
Creds Credentials `json:"threePidCreds"`
|
Creds Credentials `json:"three_pid_creds"`
|
||||||
Bind bool `json:"bind"`
|
Bind bool `json:"bind"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -48,12 +49,16 @@ type Credentials struct {
|
||||||
Secret string `json:"client_secret"`
|
Secret string `json:"client_secret"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SID struct {
|
||||||
|
SID string `json:"sid"`
|
||||||
|
}
|
||||||
|
|
||||||
// CreateSession creates a session on an identity server.
|
// CreateSession creates a session on an identity server.
|
||||||
// Returns the session's ID.
|
// Returns the session's ID.
|
||||||
// Returns an error if there was a problem sending the request or decoding the
|
// Returns an error if there was a problem sending the request or decoding the
|
||||||
// response, or if the identity server responded with a non-OK status.
|
// response, or if the identity server responded with a non-OK status.
|
||||||
func CreateSession(
|
func CreateSession(
|
||||||
ctx context.Context, req EmailAssociationRequest, cfg *config.ClientAPI,
|
ctx context.Context, req EmailAssociationRequest, cfg *config.ClientAPI, client *fclient.Client,
|
||||||
) (string, error) {
|
) (string, error) {
|
||||||
if err := isTrusted(req.IDServer, cfg); err != nil {
|
if err := isTrusted(req.IDServer, cfg); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
|
@ -73,8 +78,7 @@ func CreateSession(
|
||||||
}
|
}
|
||||||
request.Header.Add("Content-Type", "application/x-www-form-urlencoded")
|
request.Header.Add("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
|
||||||
client := http.Client{}
|
resp, err := client.DoHTTPRequest(ctx, request)
|
||||||
resp, err := client.Do(request.WithContext(ctx))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
@ -85,14 +89,20 @@ func CreateSession(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract the SID from the response and return it
|
// Extract the SID from the response and return it
|
||||||
var sid struct {
|
var sid SID
|
||||||
SID string `json:"sid"`
|
|
||||||
}
|
|
||||||
err = json.NewDecoder(resp.Body).Decode(&sid)
|
err = json.NewDecoder(resp.Body).Decode(&sid)
|
||||||
|
|
||||||
return sid.SID, err
|
return sid.SID, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type GetValidatedResponse struct {
|
||||||
|
Medium string `json:"medium"`
|
||||||
|
ValidatedAt int64 `json:"validated_at"`
|
||||||
|
Address string `json:"address"`
|
||||||
|
ErrCode string `json:"errcode"`
|
||||||
|
Error string `json:"error"`
|
||||||
|
}
|
||||||
|
|
||||||
// CheckAssociation checks the status of an ongoing association validation on an
|
// CheckAssociation checks the status of an ongoing association validation on an
|
||||||
// identity server.
|
// identity server.
|
||||||
// Returns a boolean set to true if the association has been validated, false if not.
|
// Returns a boolean set to true if the association has been validated, false if not.
|
||||||
|
|
@ -102,6 +112,7 @@ func CreateSession(
|
||||||
// response, or if the identity server responded with a non-OK status.
|
// response, or if the identity server responded with a non-OK status.
|
||||||
func CheckAssociation(
|
func CheckAssociation(
|
||||||
ctx context.Context, creds Credentials, cfg *config.ClientAPI,
|
ctx context.Context, creds Credentials, cfg *config.ClientAPI,
|
||||||
|
client *fclient.Client,
|
||||||
) (bool, string, string, error) {
|
) (bool, string, string, error) {
|
||||||
|
|
||||||
requestURL := fmt.Sprintf("%s/_matrix/identity/api/v1/3pid/getValidated3pid?sid=%s&client_secret=%s", cfg.ThreePidDelegate, creds.SID, creds.Secret)
|
requestURL := fmt.Sprintf("%s/_matrix/identity/api/v1/3pid/getValidated3pid?sid=%s&client_secret=%s", cfg.ThreePidDelegate, creds.SID, creds.Secret)
|
||||||
|
|
@ -109,19 +120,20 @@ func CheckAssociation(
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, "", "", err
|
return false, "", "", err
|
||||||
}
|
}
|
||||||
resp, err := http.DefaultClient.Do(req.WithContext(ctx))
|
var resp *http.Response
|
||||||
|
if client != nil {
|
||||||
|
resp, err = client.DoHTTPRequest(ctx, req)
|
||||||
|
if err != nil {
|
||||||
|
return false, "", "", err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
resp, err = http.DefaultClient.Do(req.WithContext(ctx))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, "", "", err
|
return false, "", "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
var respBody struct {
|
|
||||||
Medium string `json:"medium"`
|
|
||||||
ValidatedAt int64 `json:"validated_at"`
|
|
||||||
Address string `json:"address"`
|
|
||||||
ErrCode string `json:"errcode"`
|
|
||||||
Error string `json:"error"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var respBody GetValidatedResponse
|
||||||
if err = json.NewDecoder(resp.Body).Decode(&respBody); err != nil {
|
if err = json.NewDecoder(resp.Body).Decode(&respBody); err != nil {
|
||||||
return false, "", "", err
|
return false, "", "", err
|
||||||
}
|
}
|
||||||
|
|
@ -139,7 +151,7 @@ func CheckAssociation(
|
||||||
// identifier and a Matrix ID.
|
// identifier and a Matrix ID.
|
||||||
// Returns an error if there was a problem sending the request or decoding the
|
// Returns an error if there was a problem sending the request or decoding the
|
||||||
// response, or if the identity server responded with a non-OK status.
|
// response, or if the identity server responded with a non-OK status.
|
||||||
func PublishAssociation(creds Credentials, userID string, cfg *config.ClientAPI) error {
|
func PublishAssociation(ctx context.Context, creds Credentials, userID string, cfg *config.ClientAPI, client *fclient.Client) error {
|
||||||
if err := isTrusted(creds.IDServer, cfg); err != nil {
|
if err := isTrusted(creds.IDServer, cfg); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -157,8 +169,7 @@ func PublishAssociation(creds Credentials, userID string, cfg *config.ClientAPI)
|
||||||
}
|
}
|
||||||
request.Header.Add("Content-Type", "application/x-www-form-urlencoded")
|
request.Header.Add("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
|
||||||
client := http.Client{}
|
resp, err := client.DoHTTPRequest(ctx, request)
|
||||||
resp, err := client.Do(request)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ import (
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/setup/config"
|
"github.com/matrix-org/dendrite/setup/config"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib/fclient"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -30,7 +31,7 @@ var (
|
||||||
// TestGoodUserID checks that correct localpart is returned for a valid user ID.
|
// TestGoodUserID checks that correct localpart is returned for a valid user ID.
|
||||||
func TestGoodUserID(t *testing.T) {
|
func TestGoodUserID(t *testing.T) {
|
||||||
cfg := &config.Global{
|
cfg := &config.Global{
|
||||||
SigningIdentity: gomatrixserverlib.SigningIdentity{
|
SigningIdentity: fclient.SigningIdentity{
|
||||||
ServerName: serverName,
|
ServerName: serverName,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -49,7 +50,7 @@ func TestGoodUserID(t *testing.T) {
|
||||||
// TestWithLocalpartOnly checks that localpart is returned when usernameParam contains only localpart.
|
// TestWithLocalpartOnly checks that localpart is returned when usernameParam contains only localpart.
|
||||||
func TestWithLocalpartOnly(t *testing.T) {
|
func TestWithLocalpartOnly(t *testing.T) {
|
||||||
cfg := &config.Global{
|
cfg := &config.Global{
|
||||||
SigningIdentity: gomatrixserverlib.SigningIdentity{
|
SigningIdentity: fclient.SigningIdentity{
|
||||||
ServerName: serverName,
|
ServerName: serverName,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -68,7 +69,7 @@ func TestWithLocalpartOnly(t *testing.T) {
|
||||||
// TestIncorrectDomain checks for error when there's server name mismatch.
|
// TestIncorrectDomain checks for error when there's server name mismatch.
|
||||||
func TestIncorrectDomain(t *testing.T) {
|
func TestIncorrectDomain(t *testing.T) {
|
||||||
cfg := &config.Global{
|
cfg := &config.Global{
|
||||||
SigningIdentity: gomatrixserverlib.SigningIdentity{
|
SigningIdentity: fclient.SigningIdentity{
|
||||||
ServerName: invalidServerName,
|
ServerName: invalidServerName,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -83,7 +84,7 @@ func TestIncorrectDomain(t *testing.T) {
|
||||||
// TestBadUserID checks that ParseUsernameParam fails for invalid user ID
|
// TestBadUserID checks that ParseUsernameParam fails for invalid user ID
|
||||||
func TestBadUserID(t *testing.T) {
|
func TestBadUserID(t *testing.T) {
|
||||||
cfg := &config.Global{
|
cfg := &config.Global{
|
||||||
SigningIdentity: gomatrixserverlib.SigningIdentity{
|
SigningIdentity: fclient.SigningIdentity{
|
||||||
ServerName: serverName,
|
ServerName: serverName,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,11 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/getsentry/sentry-go"
|
||||||
|
"github.com/matrix-org/dendrite/internal/caching"
|
||||||
|
"github.com/matrix-org/dendrite/internal/sqlutil"
|
||||||
|
"github.com/matrix-org/dendrite/setup/jetstream"
|
||||||
|
"github.com/matrix-org/dendrite/setup/process"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
|
@ -41,7 +46,7 @@ import (
|
||||||
"github.com/matrix-org/dendrite/internal/httputil"
|
"github.com/matrix-org/dendrite/internal/httputil"
|
||||||
"github.com/matrix-org/dendrite/roomserver"
|
"github.com/matrix-org/dendrite/roomserver"
|
||||||
"github.com/matrix-org/dendrite/setup"
|
"github.com/matrix-org/dendrite/setup"
|
||||||
"github.com/matrix-org/dendrite/setup/base"
|
basepkg "github.com/matrix-org/dendrite/setup/base"
|
||||||
"github.com/matrix-org/dendrite/setup/config"
|
"github.com/matrix-org/dendrite/setup/config"
|
||||||
"github.com/matrix-org/dendrite/setup/mscs"
|
"github.com/matrix-org/dendrite/setup/mscs"
|
||||||
"github.com/matrix-org/dendrite/test"
|
"github.com/matrix-org/dendrite/test"
|
||||||
|
|
@ -57,6 +62,7 @@ var (
|
||||||
instanceDir = flag.String("dir", ".", "the directory to store the databases in (if --config not specified)")
|
instanceDir = flag.String("dir", ".", "the directory to store the databases in (if --config not specified)")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// nolint: gocyclo
|
||||||
func main() {
|
func main() {
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
internal.SetupPprof()
|
internal.SetupPprof()
|
||||||
|
|
@ -142,37 +148,83 @@ func main() {
|
||||||
cfg.Global.ServerName = gomatrixserverlib.ServerName(hex.EncodeToString(pk))
|
cfg.Global.ServerName = gomatrixserverlib.ServerName(hex.EncodeToString(pk))
|
||||||
cfg.Global.KeyID = gomatrixserverlib.KeyID(signing.KeyID)
|
cfg.Global.KeyID = gomatrixserverlib.KeyID(signing.KeyID)
|
||||||
|
|
||||||
base := base.NewBaseDendrite(cfg)
|
configErrors := &config.ConfigErrors{}
|
||||||
base.ConfigureAdminEndpoints()
|
cfg.Verify(configErrors)
|
||||||
defer base.Close() // nolint: errcheck
|
if len(*configErrors) > 0 {
|
||||||
|
for _, err := range *configErrors {
|
||||||
|
logrus.Errorf("Configuration error: %s", err)
|
||||||
|
}
|
||||||
|
logrus.Fatalf("Failed to start due to configuration errors")
|
||||||
|
}
|
||||||
|
|
||||||
|
internal.SetupStdLogging()
|
||||||
|
internal.SetupHookLogging(cfg.Logging)
|
||||||
|
internal.SetupPprof()
|
||||||
|
|
||||||
|
logrus.Infof("Dendrite version %s", internal.VersionString())
|
||||||
|
|
||||||
|
if !cfg.ClientAPI.RegistrationDisabled && cfg.ClientAPI.OpenRegistrationWithoutVerificationEnabled {
|
||||||
|
logrus.Warn("Open registration is enabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
closer, err := cfg.SetupTracing()
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithError(err).Panicf("failed to start opentracing")
|
||||||
|
}
|
||||||
|
defer closer.Close() // nolint: errcheck
|
||||||
|
|
||||||
|
if cfg.Global.Sentry.Enabled {
|
||||||
|
logrus.Info("Setting up Sentry for debugging...")
|
||||||
|
err = sentry.Init(sentry.ClientOptions{
|
||||||
|
Dsn: cfg.Global.Sentry.DSN,
|
||||||
|
Environment: cfg.Global.Sentry.Environment,
|
||||||
|
Debug: true,
|
||||||
|
ServerName: string(cfg.Global.ServerName),
|
||||||
|
Release: "dendrite@" + internal.VersionString(),
|
||||||
|
AttachStacktrace: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithError(err).Panic("failed to start Sentry")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
processCtx := process.NewProcessContext()
|
||||||
|
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
|
||||||
|
routers := httputil.NewRouters()
|
||||||
|
|
||||||
|
basepkg.ConfigureAdminEndpoints(processCtx, routers)
|
||||||
|
defer func() {
|
||||||
|
processCtx.ShutdownDendrite()
|
||||||
|
processCtx.WaitForShutdown()
|
||||||
|
}() // nolint: errcheck
|
||||||
|
|
||||||
ygg, err := yggconn.Setup(sk, *instanceName, ".", *instancePeer, *instanceListen)
|
ygg, err := yggconn.Setup(sk, *instanceName, ".", *instancePeer, *instanceListen)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
federation := ygg.CreateFederationClient(base)
|
federation := ygg.CreateFederationClient(cfg)
|
||||||
|
|
||||||
serverKeyAPI := &signing.YggdrasilKeys{}
|
serverKeyAPI := &signing.YggdrasilKeys{}
|
||||||
keyRing := serverKeyAPI.KeyRing()
|
keyRing := serverKeyAPI.KeyRing()
|
||||||
|
|
||||||
rsAPI := roomserver.NewInternalAPI(
|
caches := caching.NewRistrettoCache(cfg.Global.Cache.EstimatedMaxSize, cfg.Global.Cache.MaxAge, caching.EnableMetrics)
|
||||||
base,
|
natsInstance := jetstream.NATSInstance{}
|
||||||
)
|
rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, &natsInstance, caches, caching.EnableMetrics)
|
||||||
|
|
||||||
userAPI := userapi.NewInternalAPI(base, rsAPI, federation)
|
userAPI := userapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, rsAPI, federation)
|
||||||
|
|
||||||
asAPI := appservice.NewInternalAPI(base, userAPI, rsAPI)
|
asAPI := appservice.NewInternalAPI(processCtx, cfg, &natsInstance, userAPI, rsAPI)
|
||||||
rsAPI.SetAppserviceAPI(asAPI)
|
rsAPI.SetAppserviceAPI(asAPI)
|
||||||
fsAPI := federationapi.NewInternalAPI(
|
fsAPI := federationapi.NewInternalAPI(
|
||||||
base, federation, rsAPI, base.Caches, keyRing, true,
|
processCtx, cfg, cm, &natsInstance, federation, rsAPI, caches, keyRing, true,
|
||||||
)
|
)
|
||||||
|
|
||||||
rsAPI.SetFederationAPI(fsAPI, keyRing)
|
rsAPI.SetFederationAPI(fsAPI, keyRing)
|
||||||
|
|
||||||
monolith := setup.Monolith{
|
monolith := setup.Monolith{
|
||||||
Config: base.Cfg,
|
Config: cfg,
|
||||||
Client: ygg.CreateClient(base),
|
Client: ygg.CreateClient(),
|
||||||
FedClient: federation,
|
FedClient: federation,
|
||||||
KeyRing: keyRing,
|
KeyRing: keyRing,
|
||||||
|
|
||||||
|
|
@ -184,21 +236,21 @@ func main() {
|
||||||
ygg, fsAPI, federation,
|
ygg, fsAPI, federation,
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
monolith.AddAllPublicRoutes(base)
|
monolith.AddAllPublicRoutes(processCtx, cfg, routers, cm, &natsInstance, caches, caching.EnableMetrics)
|
||||||
if err := mscs.Enable(base, &monolith); err != nil {
|
if err := mscs.Enable(cfg, cm, routers, &monolith, caches); err != nil {
|
||||||
logrus.WithError(err).Fatalf("Failed to enable MSCs")
|
logrus.WithError(err).Fatalf("Failed to enable MSCs")
|
||||||
}
|
}
|
||||||
|
|
||||||
httpRouter := mux.NewRouter().SkipClean(true).UseEncodedPath()
|
httpRouter := mux.NewRouter().SkipClean(true).UseEncodedPath()
|
||||||
httpRouter.PathPrefix(httputil.PublicClientPathPrefix).Handler(base.PublicClientAPIMux)
|
httpRouter.PathPrefix(httputil.PublicClientPathPrefix).Handler(routers.Client)
|
||||||
httpRouter.PathPrefix(httputil.PublicMediaPathPrefix).Handler(base.PublicMediaAPIMux)
|
httpRouter.PathPrefix(httputil.PublicMediaPathPrefix).Handler(routers.Media)
|
||||||
httpRouter.PathPrefix(httputil.DendriteAdminPathPrefix).Handler(base.DendriteAdminMux)
|
httpRouter.PathPrefix(httputil.DendriteAdminPathPrefix).Handler(routers.DendriteAdmin)
|
||||||
httpRouter.PathPrefix(httputil.SynapseAdminPathPrefix).Handler(base.SynapseAdminMux)
|
httpRouter.PathPrefix(httputil.SynapseAdminPathPrefix).Handler(routers.SynapseAdmin)
|
||||||
embed.Embed(httpRouter, *instancePort, "Yggdrasil Demo")
|
embed.Embed(httpRouter, *instancePort, "Yggdrasil Demo")
|
||||||
|
|
||||||
yggRouter := mux.NewRouter().SkipClean(true).UseEncodedPath()
|
yggRouter := mux.NewRouter().SkipClean(true).UseEncodedPath()
|
||||||
yggRouter.PathPrefix(httputil.PublicFederationPathPrefix).Handler(base.PublicFederationAPIMux)
|
yggRouter.PathPrefix(httputil.PublicFederationPathPrefix).Handler(routers.Federation)
|
||||||
yggRouter.PathPrefix(httputil.PublicMediaPathPrefix).Handler(base.PublicMediaAPIMux)
|
yggRouter.PathPrefix(httputil.PublicMediaPathPrefix).Handler(routers.Media)
|
||||||
|
|
||||||
// Build both ends of a HTTP multiplex.
|
// Build both ends of a HTTP multiplex.
|
||||||
httpServer := &http.Server{
|
httpServer := &http.Server{
|
||||||
|
|
@ -232,5 +284,5 @@ func main() {
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// We want to block forever to let the HTTP and HTTPS handler serve the APIs
|
// We want to block forever to let the HTTP and HTTPS handler serve the APIs
|
||||||
base.WaitForShutdown()
|
basepkg.WaitForShutdown(processCtx)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/setup/base"
|
"github.com/matrix-org/dendrite/setup/config"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib/fclient"
|
||||||
)
|
)
|
||||||
|
|
||||||
type yggroundtripper struct {
|
type yggroundtripper struct {
|
||||||
|
|
@ -17,9 +17,7 @@ func (y *yggroundtripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||||
return y.inner.RoundTrip(req)
|
return y.inner.RoundTrip(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Node) CreateClient(
|
func (n *Node) CreateClient() *fclient.Client {
|
||||||
base *base.BaseDendrite,
|
|
||||||
) *gomatrixserverlib.Client {
|
|
||||||
tr := &http.Transport{}
|
tr := &http.Transport{}
|
||||||
tr.RegisterProtocol(
|
tr.RegisterProtocol(
|
||||||
"matrix", &yggroundtripper{
|
"matrix", &yggroundtripper{
|
||||||
|
|
@ -33,14 +31,14 @@ func (n *Node) CreateClient(
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
return gomatrixserverlib.NewClient(
|
return fclient.NewClient(
|
||||||
gomatrixserverlib.WithTransport(tr),
|
fclient.WithTransport(tr),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Node) CreateFederationClient(
|
func (n *Node) CreateFederationClient(
|
||||||
base *base.BaseDendrite,
|
cfg *config.Dendrite,
|
||||||
) *gomatrixserverlib.FederationClient {
|
) *fclient.FederationClient {
|
||||||
tr := &http.Transport{}
|
tr := &http.Transport{}
|
||||||
tr.RegisterProtocol(
|
tr.RegisterProtocol(
|
||||||
"matrix", &yggroundtripper{
|
"matrix", &yggroundtripper{
|
||||||
|
|
@ -54,8 +52,8 @@ func (n *Node) CreateFederationClient(
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
return gomatrixserverlib.NewFederationClient(
|
return fclient.NewFederationClient(
|
||||||
base.Cfg.Global.SigningIdentities(),
|
cfg.Global.SigningIdentities(),
|
||||||
gomatrixserverlib.WithTransport(tr),
|
fclient.WithTransport(tr),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,17 +22,18 @@ import (
|
||||||
"github.com/matrix-org/dendrite/cmd/dendrite-demo-yggdrasil/yggconn"
|
"github.com/matrix-org/dendrite/cmd/dendrite-demo-yggdrasil/yggconn"
|
||||||
"github.com/matrix-org/dendrite/federationapi/api"
|
"github.com/matrix-org/dendrite/federationapi/api"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib/fclient"
|
||||||
"github.com/matrix-org/util"
|
"github.com/matrix-org/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
type YggdrasilRoomProvider struct {
|
type YggdrasilRoomProvider struct {
|
||||||
node *yggconn.Node
|
node *yggconn.Node
|
||||||
fedSender api.FederationInternalAPI
|
fedSender api.FederationInternalAPI
|
||||||
fedClient *gomatrixserverlib.FederationClient
|
fedClient *fclient.FederationClient
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewYggdrasilRoomProvider(
|
func NewYggdrasilRoomProvider(
|
||||||
node *yggconn.Node, fedSender api.FederationInternalAPI, fedClient *gomatrixserverlib.FederationClient,
|
node *yggconn.Node, fedSender api.FederationInternalAPI, fedClient *fclient.FederationClient,
|
||||||
) *YggdrasilRoomProvider {
|
) *YggdrasilRoomProvider {
|
||||||
p := &YggdrasilRoomProvider{
|
p := &YggdrasilRoomProvider{
|
||||||
node: node,
|
node: node,
|
||||||
|
|
@ -42,7 +43,7 @@ func NewYggdrasilRoomProvider(
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *YggdrasilRoomProvider) Rooms() []gomatrixserverlib.PublicRoom {
|
func (p *YggdrasilRoomProvider) Rooms() []fclient.PublicRoom {
|
||||||
return bulkFetchPublicRoomsFromServers(
|
return bulkFetchPublicRoomsFromServers(
|
||||||
context.Background(), p.fedClient,
|
context.Background(), p.fedClient,
|
||||||
gomatrixserverlib.ServerName(p.node.DerivedServerName()),
|
gomatrixserverlib.ServerName(p.node.DerivedServerName()),
|
||||||
|
|
@ -53,14 +54,14 @@ func (p *YggdrasilRoomProvider) Rooms() []gomatrixserverlib.PublicRoom {
|
||||||
// bulkFetchPublicRoomsFromServers fetches public rooms from the list of homeservers.
|
// bulkFetchPublicRoomsFromServers fetches public rooms from the list of homeservers.
|
||||||
// Returns a list of public rooms.
|
// Returns a list of public rooms.
|
||||||
func bulkFetchPublicRoomsFromServers(
|
func bulkFetchPublicRoomsFromServers(
|
||||||
ctx context.Context, fedClient *gomatrixserverlib.FederationClient,
|
ctx context.Context, fedClient *fclient.FederationClient,
|
||||||
origin gomatrixserverlib.ServerName,
|
origin gomatrixserverlib.ServerName,
|
||||||
homeservers []gomatrixserverlib.ServerName,
|
homeservers []gomatrixserverlib.ServerName,
|
||||||
) (publicRooms []gomatrixserverlib.PublicRoom) {
|
) (publicRooms []fclient.PublicRoom) {
|
||||||
limit := 200
|
limit := 200
|
||||||
// follow pipeline semantics, see https://blog.golang.org/pipelines for more info.
|
// follow pipeline semantics, see https://blog.golang.org/pipelines for more info.
|
||||||
// goroutines send rooms to this channel
|
// goroutines send rooms to this channel
|
||||||
roomCh := make(chan gomatrixserverlib.PublicRoom, int(limit))
|
roomCh := make(chan fclient.PublicRoom, int(limit))
|
||||||
// signalling channel to tell goroutines to stop sending rooms and quit
|
// signalling channel to tell goroutines to stop sending rooms and quit
|
||||||
done := make(chan bool)
|
done := make(chan bool)
|
||||||
// signalling to say when we can close the room channel
|
// signalling to say when we can close the room channel
|
||||||
|
|
|
||||||
|
|
@ -259,10 +259,20 @@ func buildDendrite(httpClient *http.Client, dockerClient *client.Client, tmpDir
|
||||||
|
|
||||||
func getAndSortVersionsFromGithub(httpClient *http.Client) (semVers []*semver.Version, err error) {
|
func getAndSortVersionsFromGithub(httpClient *http.Client) (semVers []*semver.Version, err error) {
|
||||||
u := "https://api.github.com/repos/matrix-org/dendrite/tags"
|
u := "https://api.github.com/repos/matrix-org/dendrite/tags"
|
||||||
res, err := httpClient.Get(u)
|
|
||||||
|
var res *http.Response
|
||||||
|
for i := 0; i < 3; i++ {
|
||||||
|
res, err = httpClient.Get(u)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if res.StatusCode == 200 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
log.Printf("Github API returned HTTP %d, retrying\n", res.StatusCode)
|
||||||
|
time.Sleep(time.Second * 5)
|
||||||
|
}
|
||||||
|
|
||||||
if res.StatusCode != 200 {
|
if res.StatusCode != 200 {
|
||||||
return nil, fmt.Errorf("%s returned HTTP %d", u, res.StatusCode)
|
return nil, fmt.Errorf("%s returned HTTP %d", u, res.StatusCode)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,16 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"io/fs"
|
"time"
|
||||||
|
|
||||||
|
"github.com/getsentry/sentry-go"
|
||||||
|
"github.com/matrix-org/dendrite/internal"
|
||||||
|
"github.com/matrix-org/dendrite/internal/caching"
|
||||||
|
"github.com/matrix-org/dendrite/internal/httputil"
|
||||||
|
"github.com/matrix-org/dendrite/internal/sqlutil"
|
||||||
|
"github.com/matrix-org/dendrite/setup/jetstream"
|
||||||
|
"github.com/matrix-org/dendrite/setup/process"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib/fclient"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/appservice"
|
"github.com/matrix-org/dendrite/appservice"
|
||||||
|
|
@ -34,8 +42,8 @@ var (
|
||||||
unixSocket = flag.String("unix-socket", "",
|
unixSocket = flag.String("unix-socket", "",
|
||||||
"EXPERIMENTAL(unstable): The HTTP listening unix socket for the server (disables http[s]-bind-address feature)",
|
"EXPERIMENTAL(unstable): The HTTP listening unix socket for the server (disables http[s]-bind-address feature)",
|
||||||
)
|
)
|
||||||
unixSocketPermission = flag.Int("unix-socket-permission", 0755,
|
unixSocketPermission = flag.String("unix-socket-permission", "755",
|
||||||
"EXPERIMENTAL(unstable): The HTTP listening unix socket permission for the server",
|
"EXPERIMENTAL(unstable): The HTTP listening unix socket permission for the server (in chmod format like 755)",
|
||||||
)
|
)
|
||||||
httpBindAddr = flag.String("http-bind-address", ":8008", "The HTTP listening port for the server")
|
httpBindAddr = flag.String("http-bind-address", ":8008", "The HTTP listening port for the server")
|
||||||
httpsBindAddr = flag.String("https-bind-address", ":8448", "The HTTPS listening port for the server")
|
httpsBindAddr = flag.String("https-bind-address", ":8448", "The HTTPS listening port for the server")
|
||||||
|
|
@ -59,27 +67,97 @@ func main() {
|
||||||
}
|
}
|
||||||
httpsAddr = https
|
httpsAddr = https
|
||||||
} else {
|
} else {
|
||||||
httpAddr = config.UnixSocketAddress(*unixSocket, fs.FileMode(*unixSocketPermission))
|
socket, err := config.UnixSocketAddress(*unixSocket, *unixSocketPermission)
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithError(err).Fatalf("Failed to parse unix socket")
|
||||||
|
}
|
||||||
|
httpAddr = socket
|
||||||
}
|
}
|
||||||
|
|
||||||
options := []basepkg.BaseDendriteOptions{}
|
configErrors := &config.ConfigErrors{}
|
||||||
|
cfg.Verify(configErrors)
|
||||||
|
if len(*configErrors) > 0 {
|
||||||
|
for _, err := range *configErrors {
|
||||||
|
logrus.Errorf("Configuration error: %s", err)
|
||||||
|
}
|
||||||
|
logrus.Fatalf("Failed to start due to configuration errors")
|
||||||
|
}
|
||||||
|
processCtx := process.NewProcessContext()
|
||||||
|
|
||||||
base := basepkg.NewBaseDendrite(cfg, options...)
|
internal.SetupStdLogging()
|
||||||
defer base.Close() // nolint: errcheck
|
internal.SetupHookLogging(cfg.Logging)
|
||||||
|
internal.SetupPprof()
|
||||||
|
|
||||||
federation := base.CreateFederationClient()
|
basepkg.PlatformSanityChecks()
|
||||||
|
|
||||||
rsAPI := roomserver.NewInternalAPI(base)
|
logrus.Infof("Dendrite version %s", internal.VersionString())
|
||||||
|
if !cfg.ClientAPI.RegistrationDisabled && cfg.ClientAPI.OpenRegistrationWithoutVerificationEnabled {
|
||||||
|
logrus.Warn("Open registration is enabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
// create DNS cache
|
||||||
|
var dnsCache *fclient.DNSCache
|
||||||
|
if cfg.Global.DNSCache.Enabled {
|
||||||
|
dnsCache = fclient.NewDNSCache(
|
||||||
|
cfg.Global.DNSCache.CacheSize,
|
||||||
|
cfg.Global.DNSCache.CacheLifetime,
|
||||||
|
)
|
||||||
|
logrus.Infof(
|
||||||
|
"DNS cache enabled (size %d, lifetime %s)",
|
||||||
|
cfg.Global.DNSCache.CacheSize,
|
||||||
|
cfg.Global.DNSCache.CacheLifetime,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// setup tracing
|
||||||
|
closer, err := cfg.SetupTracing()
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithError(err).Panicf("failed to start opentracing")
|
||||||
|
}
|
||||||
|
defer closer.Close() // nolint: errcheck
|
||||||
|
|
||||||
|
// setup sentry
|
||||||
|
if cfg.Global.Sentry.Enabled {
|
||||||
|
logrus.Info("Setting up Sentry for debugging...")
|
||||||
|
err = sentry.Init(sentry.ClientOptions{
|
||||||
|
Dsn: cfg.Global.Sentry.DSN,
|
||||||
|
Environment: cfg.Global.Sentry.Environment,
|
||||||
|
Debug: true,
|
||||||
|
ServerName: string(cfg.Global.ServerName),
|
||||||
|
Release: "dendrite@" + internal.VersionString(),
|
||||||
|
AttachStacktrace: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithError(err).Panic("failed to start Sentry")
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
processCtx.ComponentStarted()
|
||||||
|
<-processCtx.WaitForShutdown()
|
||||||
|
if !sentry.Flush(time.Second * 5) {
|
||||||
|
logrus.Warnf("failed to flush all Sentry events!")
|
||||||
|
}
|
||||||
|
processCtx.ComponentFinished()
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
federationClient := basepkg.CreateFederationClient(cfg, dnsCache)
|
||||||
|
httpClient := basepkg.CreateClient(cfg, dnsCache)
|
||||||
|
|
||||||
|
// prepare required dependencies
|
||||||
|
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
|
||||||
|
routers := httputil.NewRouters()
|
||||||
|
|
||||||
|
caches := caching.NewRistrettoCache(cfg.Global.Cache.EstimatedMaxSize, cfg.Global.Cache.MaxAge, caching.EnableMetrics)
|
||||||
|
natsInstance := jetstream.NATSInstance{}
|
||||||
|
rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, &natsInstance, caches, caching.EnableMetrics)
|
||||||
fsAPI := federationapi.NewInternalAPI(
|
fsAPI := federationapi.NewInternalAPI(
|
||||||
base, federation, rsAPI, base.Caches, nil, false,
|
processCtx, cfg, cm, &natsInstance, federationClient, rsAPI, caches, nil, false,
|
||||||
)
|
)
|
||||||
|
|
||||||
keyRing := fsAPI.KeyRing()
|
keyRing := fsAPI.KeyRing()
|
||||||
|
|
||||||
userAPI := userapi.NewInternalAPI(base, rsAPI, federation)
|
userAPI := userapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, rsAPI, federationClient)
|
||||||
|
asAPI := appservice.NewInternalAPI(processCtx, cfg, &natsInstance, userAPI, rsAPI)
|
||||||
asAPI := appservice.NewInternalAPI(base, userAPI, rsAPI)
|
|
||||||
|
|
||||||
// The underlying roomserver implementation needs to be able to call the fedsender.
|
// The underlying roomserver implementation needs to be able to call the fedsender.
|
||||||
// This is different to rsAPI which can be the http client which doesn't need this
|
// This is different to rsAPI which can be the http client which doesn't need this
|
||||||
|
|
@ -89,9 +167,9 @@ func main() {
|
||||||
rsAPI.SetUserAPI(userAPI)
|
rsAPI.SetUserAPI(userAPI)
|
||||||
|
|
||||||
monolith := setup.Monolith{
|
monolith := setup.Monolith{
|
||||||
Config: base.Cfg,
|
Config: cfg,
|
||||||
Client: base.CreateClient(),
|
Client: httpClient,
|
||||||
FedClient: federation,
|
FedClient: federationClient,
|
||||||
KeyRing: keyRing,
|
KeyRing: keyRing,
|
||||||
|
|
||||||
AppserviceAPI: asAPI,
|
AppserviceAPI: asAPI,
|
||||||
|
|
@ -101,25 +179,25 @@ func main() {
|
||||||
RoomserverAPI: rsAPI,
|
RoomserverAPI: rsAPI,
|
||||||
UserAPI: userAPI,
|
UserAPI: userAPI,
|
||||||
}
|
}
|
||||||
monolith.AddAllPublicRoutes(base)
|
monolith.AddAllPublicRoutes(processCtx, cfg, routers, cm, &natsInstance, caches, caching.EnableMetrics)
|
||||||
|
|
||||||
if len(base.Cfg.MSCs.MSCs) > 0 {
|
if len(cfg.MSCs.MSCs) > 0 {
|
||||||
if err := mscs.Enable(base, &monolith); err != nil {
|
if err := mscs.Enable(cfg, cm, routers, &monolith, caches); err != nil {
|
||||||
logrus.WithError(err).Fatalf("Failed to enable MSCs")
|
logrus.WithError(err).Fatalf("Failed to enable MSCs")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Expose the matrix APIs directly rather than putting them under a /api path.
|
// Expose the matrix APIs directly rather than putting them under a /api path.
|
||||||
go func() {
|
go func() {
|
||||||
base.SetupAndServeHTTP(httpAddr, nil, nil)
|
basepkg.SetupAndServeHTTP(processCtx, cfg, routers, httpAddr, nil, nil)
|
||||||
}()
|
}()
|
||||||
// Handle HTTPS if certificate and key are provided
|
// Handle HTTPS if certificate and key are provided
|
||||||
if *unixSocket == "" && *certFile != "" && *keyFile != "" {
|
if *unixSocket == "" && *certFile != "" && *keyFile != "" {
|
||||||
go func() {
|
go func() {
|
||||||
base.SetupAndServeHTTP(httpsAddr, certFile, keyFile)
|
basepkg.SetupAndServeHTTP(processCtx, cfg, routers, httpsAddr, certFile, keyFile)
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
// We want to block forever to let the HTTP and HTTPS handler serve the APIs
|
// We want to block forever to let the HTTP and HTTPS handler serve the APIs
|
||||||
base.WaitForShutdown()
|
basepkg.WaitForShutdown(processCtx)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib/fclient"
|
||||||
)
|
)
|
||||||
|
|
||||||
var requestFrom = flag.String("from", "", "the server name that the request should originate from")
|
var requestFrom = flag.String("from", "", "the server name that the request should originate from")
|
||||||
|
|
@ -49,8 +50,8 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
serverName := gomatrixserverlib.ServerName(*requestFrom)
|
serverName := gomatrixserverlib.ServerName(*requestFrom)
|
||||||
client := gomatrixserverlib.NewFederationClient(
|
client := fclient.NewFederationClient(
|
||||||
[]*gomatrixserverlib.SigningIdentity{
|
[]*fclient.SigningIdentity{
|
||||||
{
|
{
|
||||||
ServerName: serverName,
|
ServerName: serverName,
|
||||||
KeyID: gomatrixserverlib.KeyID(keyBlock.Headers["Key-ID"]),
|
KeyID: gomatrixserverlib.KeyID(keyBlock.Headers["Key-ID"]),
|
||||||
|
|
|
||||||
|
|
@ -10,12 +10,13 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/internal/caching"
|
"github.com/matrix-org/dendrite/internal/caching"
|
||||||
|
"github.com/matrix-org/dendrite/internal/sqlutil"
|
||||||
"github.com/matrix-org/dendrite/roomserver/state"
|
"github.com/matrix-org/dendrite/roomserver/state"
|
||||||
"github.com/matrix-org/dendrite/roomserver/storage"
|
"github.com/matrix-org/dendrite/roomserver/storage"
|
||||||
"github.com/matrix-org/dendrite/roomserver/types"
|
"github.com/matrix-org/dendrite/roomserver/types"
|
||||||
"github.com/matrix-org/dendrite/setup"
|
"github.com/matrix-org/dendrite/setup"
|
||||||
"github.com/matrix-org/dendrite/setup/base"
|
|
||||||
"github.com/matrix-org/dendrite/setup/config"
|
"github.com/matrix-org/dendrite/setup/config"
|
||||||
|
"github.com/matrix-org/dendrite/setup/process"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -40,7 +41,7 @@ func main() {
|
||||||
Level: "error",
|
Level: "error",
|
||||||
})
|
})
|
||||||
cfg.ClientAPI.RegistrationDisabled = true
|
cfg.ClientAPI.RegistrationDisabled = true
|
||||||
base := base.NewBaseDendrite(cfg, base.DisableMetrics)
|
|
||||||
args := flag.Args()
|
args := flag.Args()
|
||||||
|
|
||||||
fmt.Println("Room version", *roomVersion)
|
fmt.Println("Room version", *roomVersion)
|
||||||
|
|
@ -54,8 +55,10 @@ func main() {
|
||||||
|
|
||||||
fmt.Println("Fetching", len(snapshotNIDs), "snapshot NIDs")
|
fmt.Println("Fetching", len(snapshotNIDs), "snapshot NIDs")
|
||||||
|
|
||||||
|
processCtx := process.NewProcessContext()
|
||||||
|
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
|
||||||
roomserverDB, err := storage.Open(
|
roomserverDB, err := storage.Open(
|
||||||
base, &cfg.RoomServer.Database,
|
processCtx.Context(), cm, &cfg.RoomServer.Database,
|
||||||
caching.NewRistrettoCache(128*1024*1024, time.Hour, true),
|
caching.NewRistrettoCache(128*1024*1024, time.Hour, true),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ Mostly, although there are still bugs and missing features. If you are a confide
|
||||||
|
|
||||||
## Is Dendrite feature-complete?
|
## Is Dendrite feature-complete?
|
||||||
|
|
||||||
No, although a good portion of the Matrix specification has been implemented. Mostly missing are client features - see the [readme](../README.md) at the root of the repository for more information.
|
No, although a good portion of the Matrix specification has been implemented. Mostly missing are client features - see the [readme](https://github.com/matrix-org/dendrite/blob/main/README.md) at the root of the repository for more information.
|
||||||
|
|
||||||
## Why doesn't Dendrite have "x" yet?
|
## Why doesn't Dendrite have "x" yet?
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ UPDATE userapi_accounts SET account_type = 3 WHERE localpart = '$localpart';
|
||||||
|
|
||||||
Where `$localpart` is the username only (e.g. `alice`).
|
Where `$localpart` is the username only (e.g. `alice`).
|
||||||
|
|
||||||
## GET `/_dendrite/admin/evacuateRoom/{roomID}`
|
## POST `/_dendrite/admin/evacuateRoom/{roomID}`
|
||||||
|
|
||||||
This endpoint will instruct Dendrite to part all local users from the given `roomID`
|
This endpoint will instruct Dendrite to part all local users from the given `roomID`
|
||||||
in the URL. It may take some time to complete. A JSON body will be returned containing
|
in the URL. It may take some time to complete. A JSON body will be returned containing
|
||||||
|
|
@ -41,7 +41,7 @@ the user IDs of all affected users.
|
||||||
If the room has an alias set (e.g. is published), the room's ID will not be visible in the URL, but it can
|
If the room has an alias set (e.g. is published), the room's ID will not be visible in the URL, but it can
|
||||||
be found as the room's "internal ID" in Element Web (Settings -> Advanced)
|
be found as the room's "internal ID" in Element Web (Settings -> Advanced)
|
||||||
|
|
||||||
## GET `/_dendrite/admin/evacuateUser/{userID}`
|
## POST `/_dendrite/admin/evacuateUser/{userID}`
|
||||||
|
|
||||||
This endpoint will instruct Dendrite to part the given local `userID` in the URL from
|
This endpoint will instruct Dendrite to part the given local `userID` in the URL from
|
||||||
all rooms which they are currently joined. A JSON body will be returned containing
|
all rooms which they are currently joined. A JSON body will be returned containing
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,6 @@ When debugging, the following Docker `run` options may also be useful:
|
||||||
* `-e "DENDRITE_TRACE_HTTP=1"`: Adds HTTP tracing to server logs.
|
* `-e "DENDRITE_TRACE_HTTP=1"`: Adds HTTP tracing to server logs.
|
||||||
* `-e "DENDRITE_TRACE_INTERNAL=1"`: Adds roomserver internal API tracing to
|
* `-e "DENDRITE_TRACE_INTERNAL=1"`: Adds roomserver internal API tracing to
|
||||||
server logs.
|
server logs.
|
||||||
* `-e "DENDRITE_TRACE_SQL=1"`: Adds tracing to all SQL statements to server logs.
|
|
||||||
|
|
||||||
The docker command also supports a single positional argument for the test file to
|
The docker command also supports a single positional argument for the test file to
|
||||||
run, so you can run a single `.pl` file rather than the whole test suite. For example:
|
run, so you can run a single `.pl` file rather than the whole test suite. For example:
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ permalink: /installation/configuration
|
||||||
A YAML configuration file is used to configure Dendrite. A sample configuration file is
|
A YAML configuration file is used to configure Dendrite. A sample configuration file is
|
||||||
present in the top level of the Dendrite repository:
|
present in the top level of the Dendrite repository:
|
||||||
|
|
||||||
* [`dendrite-sample.monolith.yaml`](https://github.com/matrix-org/dendrite/blob/main/dendrite-sample.monolith.yaml)
|
* [`dendrite-sample.yaml`](https://github.com/matrix-org/dendrite/blob/main/dendrite-sample.yaml)
|
||||||
|
|
||||||
You will need to duplicate the sample, calling it `dendrite.yaml` for example, and then
|
You will need to duplicate the sample, calling it `dendrite.yaml` for example, and then
|
||||||
tailor it to your installation. At a minimum, you will need to populate the following
|
tailor it to your installation. At a minimum, you will need to populate the following
|
||||||
|
|
@ -86,9 +86,8 @@ that you chose.
|
||||||
|
|
||||||
### Global connection pool
|
### Global connection pool
|
||||||
|
|
||||||
If you are running a monolith deployment and want to use a single connection pool to a
|
If you want to use a single connection pool to a single PostgreSQL database, then you must
|
||||||
single PostgreSQL database, then you must uncomment and configure the `database` section
|
uncomment and configure the `database` section within the `global` section:
|
||||||
within the `global` section:
|
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
global:
|
global:
|
||||||
|
|
@ -102,15 +101,15 @@ global:
|
||||||
|
|
||||||
**You must then remove or comment out** the `database` sections from other areas of the
|
**You must then remove or comment out** the `database` sections from other areas of the
|
||||||
configuration file, e.g. under the `app_service_api`, `federation_api`, `key_server`,
|
configuration file, e.g. under the `app_service_api`, `federation_api`, `key_server`,
|
||||||
`media_api`, `mscs`, `room_server`, `sync_api` and `user_api` blocks, otherwise these will
|
`media_api`, `mscs`, `relay_api`, `room_server`, `sync_api` and `user_api` blocks, otherwise
|
||||||
override the `global` database configuration.
|
these will override the `global` database configuration.
|
||||||
|
|
||||||
### Per-component connections (all other configurations)
|
### Per-component connections (all other configurations)
|
||||||
|
|
||||||
If you are are using SQLite databases or separate PostgreSQL
|
If you are are using SQLite databases or separate PostgreSQL
|
||||||
databases per component, then you must instead configure the `database` sections under each
|
databases per component, then you must instead configure the `database` sections under each
|
||||||
of the component blocks ,e.g. under the `app_service_api`, `federation_api`, `key_server`,
|
of the component blocks ,e.g. under the `app_service_api`, `federation_api`, `key_server`,
|
||||||
`media_api`, `mscs`, `room_server`, `sync_api` and `user_api` blocks.
|
`media_api`, `mscs`, `relay_api`, `room_server`, `sync_api` and `user_api` blocks.
|
||||||
|
|
||||||
For example, with PostgreSQL:
|
For example, with PostgreSQL:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import (
|
||||||
|
|
||||||
"github.com/matrix-org/gomatrix"
|
"github.com/matrix-org/gomatrix"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib/fclient"
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/federationapi/types"
|
"github.com/matrix-org/dendrite/federationapi/types"
|
||||||
)
|
)
|
||||||
|
|
@ -22,8 +23,8 @@ type FederationInternalAPI interface {
|
||||||
|
|
||||||
QueryServerKeys(ctx context.Context, request *QueryServerKeysRequest, response *QueryServerKeysResponse) error
|
QueryServerKeys(ctx context.Context, request *QueryServerKeysRequest, response *QueryServerKeysResponse) error
|
||||||
LookupServerKeys(ctx context.Context, s gomatrixserverlib.ServerName, keyRequests map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.Timestamp) ([]gomatrixserverlib.ServerKeys, error)
|
LookupServerKeys(ctx context.Context, s gomatrixserverlib.ServerName, keyRequests map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.Timestamp) ([]gomatrixserverlib.ServerKeys, error)
|
||||||
MSC2836EventRelationships(ctx context.Context, origin, dst gomatrixserverlib.ServerName, r gomatrixserverlib.MSC2836EventRelationshipsRequest, roomVersion gomatrixserverlib.RoomVersion) (res gomatrixserverlib.MSC2836EventRelationshipsResponse, err error)
|
MSC2836EventRelationships(ctx context.Context, origin, dst gomatrixserverlib.ServerName, r fclient.MSC2836EventRelationshipsRequest, roomVersion gomatrixserverlib.RoomVersion) (res fclient.MSC2836EventRelationshipsResponse, err error)
|
||||||
MSC2946Spaces(ctx context.Context, origin, dst gomatrixserverlib.ServerName, roomID string, suggestedOnly bool) (res gomatrixserverlib.MSC2946SpacesResponse, err error)
|
MSC2946Spaces(ctx context.Context, origin, dst gomatrixserverlib.ServerName, roomID string, suggestedOnly bool) (res fclient.MSC2946SpacesResponse, err error)
|
||||||
|
|
||||||
// Broadcasts an EDU to all servers in rooms we are joined to. Used in the yggdrasil demos.
|
// Broadcasts an EDU to all servers in rooms we are joined to. Used in the yggdrasil demos.
|
||||||
PerformBroadcastEDU(
|
PerformBroadcastEDU(
|
||||||
|
|
@ -66,9 +67,9 @@ type RoomserverFederationAPI interface {
|
||||||
// containing only the server names (without information for membership events).
|
// containing only the server names (without information for membership events).
|
||||||
// The response will include this server if they are joined to the room.
|
// The response will include this server if they are joined to the room.
|
||||||
QueryJoinedHostServerNamesInRoom(ctx context.Context, request *QueryJoinedHostServerNamesInRoomRequest, response *QueryJoinedHostServerNamesInRoomResponse) error
|
QueryJoinedHostServerNamesInRoom(ctx context.Context, request *QueryJoinedHostServerNamesInRoomRequest, response *QueryJoinedHostServerNamesInRoomResponse) error
|
||||||
GetEventAuth(ctx context.Context, origin, s gomatrixserverlib.ServerName, roomVersion gomatrixserverlib.RoomVersion, roomID, eventID string) (res gomatrixserverlib.RespEventAuth, err error)
|
GetEventAuth(ctx context.Context, origin, s gomatrixserverlib.ServerName, roomVersion gomatrixserverlib.RoomVersion, roomID, eventID string) (res fclient.RespEventAuth, err error)
|
||||||
GetEvent(ctx context.Context, origin, s gomatrixserverlib.ServerName, eventID string) (res gomatrixserverlib.Transaction, err error)
|
GetEvent(ctx context.Context, origin, s gomatrixserverlib.ServerName, eventID string) (res gomatrixserverlib.Transaction, err error)
|
||||||
LookupMissingEvents(ctx context.Context, origin, s gomatrixserverlib.ServerName, roomID string, missing gomatrixserverlib.MissingEvents, roomVersion gomatrixserverlib.RoomVersion) (res gomatrixserverlib.RespMissingEvents, err error)
|
LookupMissingEvents(ctx context.Context, origin, s gomatrixserverlib.ServerName, roomID string, missing fclient.MissingEvents, roomVersion gomatrixserverlib.RoomVersion) (res fclient.RespMissingEvents, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type P2PFederationAPI interface {
|
type P2PFederationAPI interface {
|
||||||
|
|
@ -98,45 +99,45 @@ type P2PFederationAPI interface {
|
||||||
// implements as proxy calls, with built-in backoff/retries/etc. Errors returned from functions in
|
// implements as proxy calls, with built-in backoff/retries/etc. Errors returned from functions in
|
||||||
// this interface are of type FederationClientError
|
// this interface are of type FederationClientError
|
||||||
type KeyserverFederationAPI interface {
|
type KeyserverFederationAPI interface {
|
||||||
GetUserDevices(ctx context.Context, origin, s gomatrixserverlib.ServerName, userID string) (res gomatrixserverlib.RespUserDevices, err error)
|
GetUserDevices(ctx context.Context, origin, s gomatrixserverlib.ServerName, userID string) (res fclient.RespUserDevices, err error)
|
||||||
ClaimKeys(ctx context.Context, origin, s gomatrixserverlib.ServerName, oneTimeKeys map[string]map[string]string) (res gomatrixserverlib.RespClaimKeys, err error)
|
ClaimKeys(ctx context.Context, origin, s gomatrixserverlib.ServerName, oneTimeKeys map[string]map[string]string) (res fclient.RespClaimKeys, err error)
|
||||||
QueryKeys(ctx context.Context, origin, s gomatrixserverlib.ServerName, keys map[string][]string) (res gomatrixserverlib.RespQueryKeys, err error)
|
QueryKeys(ctx context.Context, origin, s gomatrixserverlib.ServerName, keys map[string][]string) (res fclient.RespQueryKeys, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// an interface for gmsl.FederationClient - contains functions called by federationapi only.
|
// an interface for gmsl.FederationClient - contains functions called by federationapi only.
|
||||||
type FederationClient interface {
|
type FederationClient interface {
|
||||||
P2PFederationClient
|
P2PFederationClient
|
||||||
gomatrixserverlib.KeyClient
|
gomatrixserverlib.KeyClient
|
||||||
SendTransaction(ctx context.Context, t gomatrixserverlib.Transaction) (res gomatrixserverlib.RespSend, err error)
|
SendTransaction(ctx context.Context, t gomatrixserverlib.Transaction) (res fclient.RespSend, err error)
|
||||||
|
|
||||||
// Perform operations
|
// Perform operations
|
||||||
LookupRoomAlias(ctx context.Context, origin, s gomatrixserverlib.ServerName, roomAlias string) (res gomatrixserverlib.RespDirectory, err error)
|
LookupRoomAlias(ctx context.Context, origin, s gomatrixserverlib.ServerName, roomAlias string) (res fclient.RespDirectory, err error)
|
||||||
Peek(ctx context.Context, origin, s gomatrixserverlib.ServerName, roomID, peekID string, roomVersions []gomatrixserverlib.RoomVersion) (res gomatrixserverlib.RespPeek, err error)
|
Peek(ctx context.Context, origin, s gomatrixserverlib.ServerName, roomID, peekID string, roomVersions []gomatrixserverlib.RoomVersion) (res fclient.RespPeek, err error)
|
||||||
MakeJoin(ctx context.Context, origin, s gomatrixserverlib.ServerName, roomID, userID string, roomVersions []gomatrixserverlib.RoomVersion) (res gomatrixserverlib.RespMakeJoin, err error)
|
MakeJoin(ctx context.Context, origin, s gomatrixserverlib.ServerName, roomID, userID string, roomVersions []gomatrixserverlib.RoomVersion) (res fclient.RespMakeJoin, err error)
|
||||||
SendJoin(ctx context.Context, origin, s gomatrixserverlib.ServerName, event *gomatrixserverlib.Event) (res gomatrixserverlib.RespSendJoin, err error)
|
SendJoin(ctx context.Context, origin, s gomatrixserverlib.ServerName, event *gomatrixserverlib.Event) (res fclient.RespSendJoin, err error)
|
||||||
MakeLeave(ctx context.Context, origin, s gomatrixserverlib.ServerName, roomID, userID string) (res gomatrixserverlib.RespMakeLeave, err error)
|
MakeLeave(ctx context.Context, origin, s gomatrixserverlib.ServerName, roomID, userID string) (res fclient.RespMakeLeave, err error)
|
||||||
SendLeave(ctx context.Context, origin, s gomatrixserverlib.ServerName, event *gomatrixserverlib.Event) (err error)
|
SendLeave(ctx context.Context, origin, s gomatrixserverlib.ServerName, event *gomatrixserverlib.Event) (err error)
|
||||||
SendInviteV2(ctx context.Context, origin, s gomatrixserverlib.ServerName, request gomatrixserverlib.InviteV2Request) (res gomatrixserverlib.RespInviteV2, err error)
|
SendInviteV2(ctx context.Context, origin, s gomatrixserverlib.ServerName, request gomatrixserverlib.InviteV2Request) (res fclient.RespInviteV2, err error)
|
||||||
|
|
||||||
GetEvent(ctx context.Context, origin, s gomatrixserverlib.ServerName, eventID string) (res gomatrixserverlib.Transaction, err error)
|
GetEvent(ctx context.Context, origin, s gomatrixserverlib.ServerName, eventID string) (res gomatrixserverlib.Transaction, err error)
|
||||||
|
|
||||||
GetEventAuth(ctx context.Context, origin, s gomatrixserverlib.ServerName, roomVersion gomatrixserverlib.RoomVersion, roomID, eventID string) (res gomatrixserverlib.RespEventAuth, err error)
|
GetEventAuth(ctx context.Context, origin, s gomatrixserverlib.ServerName, roomVersion gomatrixserverlib.RoomVersion, roomID, eventID string) (res fclient.RespEventAuth, err error)
|
||||||
GetUserDevices(ctx context.Context, origin, s gomatrixserverlib.ServerName, userID string) (gomatrixserverlib.RespUserDevices, error)
|
GetUserDevices(ctx context.Context, origin, s gomatrixserverlib.ServerName, userID string) (fclient.RespUserDevices, error)
|
||||||
ClaimKeys(ctx context.Context, origin, s gomatrixserverlib.ServerName, oneTimeKeys map[string]map[string]string) (gomatrixserverlib.RespClaimKeys, error)
|
ClaimKeys(ctx context.Context, origin, s gomatrixserverlib.ServerName, oneTimeKeys map[string]map[string]string) (fclient.RespClaimKeys, error)
|
||||||
QueryKeys(ctx context.Context, origin, s gomatrixserverlib.ServerName, keys map[string][]string) (gomatrixserverlib.RespQueryKeys, error)
|
QueryKeys(ctx context.Context, origin, s gomatrixserverlib.ServerName, keys map[string][]string) (fclient.RespQueryKeys, error)
|
||||||
Backfill(ctx context.Context, origin, s gomatrixserverlib.ServerName, roomID string, limit int, eventIDs []string) (res gomatrixserverlib.Transaction, err error)
|
Backfill(ctx context.Context, origin, s gomatrixserverlib.ServerName, roomID string, limit int, eventIDs []string) (res gomatrixserverlib.Transaction, err error)
|
||||||
MSC2836EventRelationships(ctx context.Context, origin, dst gomatrixserverlib.ServerName, r gomatrixserverlib.MSC2836EventRelationshipsRequest, roomVersion gomatrixserverlib.RoomVersion) (res gomatrixserverlib.MSC2836EventRelationshipsResponse, err error)
|
MSC2836EventRelationships(ctx context.Context, origin, dst gomatrixserverlib.ServerName, r fclient.MSC2836EventRelationshipsRequest, roomVersion gomatrixserverlib.RoomVersion) (res fclient.MSC2836EventRelationshipsResponse, err error)
|
||||||
MSC2946Spaces(ctx context.Context, origin, dst gomatrixserverlib.ServerName, roomID string, suggestedOnly bool) (res gomatrixserverlib.MSC2946SpacesResponse, err error)
|
MSC2946Spaces(ctx context.Context, origin, dst gomatrixserverlib.ServerName, roomID string, suggestedOnly bool) (res fclient.MSC2946SpacesResponse, err error)
|
||||||
|
|
||||||
ExchangeThirdPartyInvite(ctx context.Context, origin, s gomatrixserverlib.ServerName, builder gomatrixserverlib.EventBuilder) (err error)
|
ExchangeThirdPartyInvite(ctx context.Context, origin, s gomatrixserverlib.ServerName, builder gomatrixserverlib.EventBuilder) (err error)
|
||||||
LookupState(ctx context.Context, origin, s gomatrixserverlib.ServerName, roomID string, eventID string, roomVersion gomatrixserverlib.RoomVersion) (res gomatrixserverlib.RespState, err error)
|
LookupState(ctx context.Context, origin, s gomatrixserverlib.ServerName, roomID string, eventID string, roomVersion gomatrixserverlib.RoomVersion) (res fclient.RespState, err error)
|
||||||
LookupStateIDs(ctx context.Context, origin, s gomatrixserverlib.ServerName, roomID string, eventID string) (res gomatrixserverlib.RespStateIDs, err error)
|
LookupStateIDs(ctx context.Context, origin, s gomatrixserverlib.ServerName, roomID string, eventID string) (res fclient.RespStateIDs, err error)
|
||||||
LookupMissingEvents(ctx context.Context, origin, s gomatrixserverlib.ServerName, roomID string, missing gomatrixserverlib.MissingEvents, roomVersion gomatrixserverlib.RoomVersion) (res gomatrixserverlib.RespMissingEvents, err error)
|
LookupMissingEvents(ctx context.Context, origin, s gomatrixserverlib.ServerName, roomID string, missing fclient.MissingEvents, roomVersion gomatrixserverlib.RoomVersion) (res fclient.RespMissingEvents, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type P2PFederationClient interface {
|
type P2PFederationClient interface {
|
||||||
P2PSendTransactionToRelay(ctx context.Context, u gomatrixserverlib.UserID, t gomatrixserverlib.Transaction, forwardingServer gomatrixserverlib.ServerName) (res gomatrixserverlib.EmptyResp, err error)
|
P2PSendTransactionToRelay(ctx context.Context, u gomatrixserverlib.UserID, t gomatrixserverlib.Transaction, forwardingServer gomatrixserverlib.ServerName) (res fclient.EmptyResp, err error)
|
||||||
P2PGetTransactionFromRelay(ctx context.Context, u gomatrixserverlib.UserID, prev gomatrixserverlib.RelayEntry, relayServer gomatrixserverlib.ServerName) (res gomatrixserverlib.RespGetRelayTransaction, err error)
|
P2PGetTransactionFromRelay(ctx context.Context, u gomatrixserverlib.UserID, prev fclient.RelayEntry, relayServer gomatrixserverlib.ServerName) (res fclient.RespGetRelayTransaction, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FederationClientError is returned from FederationClient methods in the event of a problem.
|
// FederationClientError is returned from FederationClient methods in the event of a problem.
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,11 @@ package federationapi
|
||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/matrix-org/dendrite/internal/httputil"
|
||||||
|
"github.com/matrix-org/dendrite/internal/sqlutil"
|
||||||
|
"github.com/matrix-org/dendrite/setup/config"
|
||||||
|
"github.com/matrix-org/dendrite/setup/process"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib/fclient"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/federationapi/api"
|
"github.com/matrix-org/dendrite/federationapi/api"
|
||||||
|
|
@ -29,7 +34,6 @@ import (
|
||||||
"github.com/matrix-org/dendrite/federationapi/storage"
|
"github.com/matrix-org/dendrite/federationapi/storage"
|
||||||
"github.com/matrix-org/dendrite/internal/caching"
|
"github.com/matrix-org/dendrite/internal/caching"
|
||||||
roomserverAPI "github.com/matrix-org/dendrite/roomserver/api"
|
roomserverAPI "github.com/matrix-org/dendrite/roomserver/api"
|
||||||
"github.com/matrix-org/dendrite/setup/base"
|
|
||||||
"github.com/matrix-org/dendrite/setup/jetstream"
|
"github.com/matrix-org/dendrite/setup/jetstream"
|
||||||
userapi "github.com/matrix-org/dendrite/userapi/api"
|
userapi "github.com/matrix-org/dendrite/userapi/api"
|
||||||
|
|
||||||
|
|
@ -40,17 +44,21 @@ import (
|
||||||
|
|
||||||
// AddPublicRoutes sets up and registers HTTP handlers on the base API muxes for the FederationAPI component.
|
// AddPublicRoutes sets up and registers HTTP handlers on the base API muxes for the FederationAPI component.
|
||||||
func AddPublicRoutes(
|
func AddPublicRoutes(
|
||||||
base *base.BaseDendrite,
|
processContext *process.ProcessContext,
|
||||||
|
routers httputil.Routers,
|
||||||
|
dendriteConfig *config.Dendrite,
|
||||||
|
natsInstance *jetstream.NATSInstance,
|
||||||
userAPI userapi.FederationUserAPI,
|
userAPI userapi.FederationUserAPI,
|
||||||
federation *gomatrixserverlib.FederationClient,
|
federation *fclient.FederationClient,
|
||||||
keyRing gomatrixserverlib.JSONVerifier,
|
keyRing gomatrixserverlib.JSONVerifier,
|
||||||
rsAPI roomserverAPI.FederationRoomserverAPI,
|
rsAPI roomserverAPI.FederationRoomserverAPI,
|
||||||
fedAPI federationAPI.FederationInternalAPI,
|
fedAPI federationAPI.FederationInternalAPI,
|
||||||
servers federationAPI.ServersInRoomProvider,
|
servers federationAPI.ServersInRoomProvider,
|
||||||
|
enableMetrics bool,
|
||||||
) {
|
) {
|
||||||
cfg := &base.Cfg.FederationAPI
|
cfg := &dendriteConfig.FederationAPI
|
||||||
mscCfg := &base.Cfg.MSCs
|
mscCfg := &dendriteConfig.MSCs
|
||||||
js, _ := base.NATS.Prepare(base.ProcessContext, &cfg.Matrix.JetStream)
|
js, _ := natsInstance.Prepare(processContext, &cfg.Matrix.JetStream)
|
||||||
producer := &producers.SyncAPIProducer{
|
producer := &producers.SyncAPIProducer{
|
||||||
JetStream: js,
|
JetStream: js,
|
||||||
TopicReceiptEvent: cfg.Matrix.JetStream.Prefixed(jetstream.OutputReceiptEvent),
|
TopicReceiptEvent: cfg.Matrix.JetStream.Prefixed(jetstream.OutputReceiptEvent),
|
||||||
|
|
@ -75,26 +83,30 @@ func AddPublicRoutes(
|
||||||
}
|
}
|
||||||
|
|
||||||
routing.Setup(
|
routing.Setup(
|
||||||
base,
|
routers,
|
||||||
|
dendriteConfig,
|
||||||
rsAPI, f, keyRing,
|
rsAPI, f, keyRing,
|
||||||
federation, userAPI, mscCfg,
|
federation, userAPI, mscCfg,
|
||||||
servers, producer,
|
servers, producer, enableMetrics,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewInternalAPI returns a concerete implementation of the internal API. Callers
|
// NewInternalAPI returns a concerete implementation of the internal API. Callers
|
||||||
// can call functions directly on the returned API or via an HTTP interface using AddInternalRoutes.
|
// can call functions directly on the returned API or via an HTTP interface using AddInternalRoutes.
|
||||||
func NewInternalAPI(
|
func NewInternalAPI(
|
||||||
base *base.BaseDendrite,
|
processContext *process.ProcessContext,
|
||||||
|
dendriteCfg *config.Dendrite,
|
||||||
|
cm sqlutil.Connections,
|
||||||
|
natsInstance *jetstream.NATSInstance,
|
||||||
federation api.FederationClient,
|
federation api.FederationClient,
|
||||||
rsAPI roomserverAPI.FederationRoomserverAPI,
|
rsAPI roomserverAPI.FederationRoomserverAPI,
|
||||||
caches *caching.Caches,
|
caches *caching.Caches,
|
||||||
keyRing *gomatrixserverlib.KeyRing,
|
keyRing *gomatrixserverlib.KeyRing,
|
||||||
resetBlacklist bool,
|
resetBlacklist bool,
|
||||||
) api.FederationInternalAPI {
|
) api.FederationInternalAPI {
|
||||||
cfg := &base.Cfg.FederationAPI
|
cfg := &dendriteCfg.FederationAPI
|
||||||
|
|
||||||
federationDB, err := storage.NewDatabase(base, &cfg.Database, base.Caches, base.Cfg.Global.IsLocalServerName)
|
federationDB, err := storage.NewDatabase(processContext.Context(), cm, &cfg.Database, caches, dendriteCfg.Global.IsLocalServerName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.WithError(err).Panic("failed to connect to federation sender db")
|
logrus.WithError(err).Panic("failed to connect to federation sender db")
|
||||||
}
|
}
|
||||||
|
|
@ -108,51 +120,51 @@ func NewInternalAPI(
|
||||||
cfg.FederationMaxRetries+1,
|
cfg.FederationMaxRetries+1,
|
||||||
cfg.P2PFederationRetriesUntilAssumedOffline+1)
|
cfg.P2PFederationRetriesUntilAssumedOffline+1)
|
||||||
|
|
||||||
js, nats := base.NATS.Prepare(base.ProcessContext, &cfg.Matrix.JetStream)
|
js, nats := natsInstance.Prepare(processContext, &cfg.Matrix.JetStream)
|
||||||
|
|
||||||
signingInfo := base.Cfg.Global.SigningIdentities()
|
signingInfo := dendriteCfg.Global.SigningIdentities()
|
||||||
|
|
||||||
queues := queue.NewOutgoingQueues(
|
queues := queue.NewOutgoingQueues(
|
||||||
federationDB, base.ProcessContext,
|
federationDB, processContext,
|
||||||
cfg.Matrix.DisableFederation,
|
cfg.Matrix.DisableFederation,
|
||||||
cfg.Matrix.ServerName, federation, rsAPI, &stats,
|
cfg.Matrix.ServerName, federation, rsAPI, &stats,
|
||||||
signingInfo,
|
signingInfo,
|
||||||
)
|
)
|
||||||
|
|
||||||
rsConsumer := consumers.NewOutputRoomEventConsumer(
|
rsConsumer := consumers.NewOutputRoomEventConsumer(
|
||||||
base.ProcessContext, cfg, js, nats, queues,
|
processContext, cfg, js, nats, queues,
|
||||||
federationDB, rsAPI,
|
federationDB, rsAPI,
|
||||||
)
|
)
|
||||||
if err = rsConsumer.Start(); err != nil {
|
if err = rsConsumer.Start(); err != nil {
|
||||||
logrus.WithError(err).Panic("failed to start room server consumer")
|
logrus.WithError(err).Panic("failed to start room server consumer")
|
||||||
}
|
}
|
||||||
tsConsumer := consumers.NewOutputSendToDeviceConsumer(
|
tsConsumer := consumers.NewOutputSendToDeviceConsumer(
|
||||||
base.ProcessContext, cfg, js, queues, federationDB,
|
processContext, cfg, js, queues, federationDB,
|
||||||
)
|
)
|
||||||
if err = tsConsumer.Start(); err != nil {
|
if err = tsConsumer.Start(); err != nil {
|
||||||
logrus.WithError(err).Panic("failed to start send-to-device consumer")
|
logrus.WithError(err).Panic("failed to start send-to-device consumer")
|
||||||
}
|
}
|
||||||
receiptConsumer := consumers.NewOutputReceiptConsumer(
|
receiptConsumer := consumers.NewOutputReceiptConsumer(
|
||||||
base.ProcessContext, cfg, js, queues, federationDB,
|
processContext, cfg, js, queues, federationDB,
|
||||||
)
|
)
|
||||||
if err = receiptConsumer.Start(); err != nil {
|
if err = receiptConsumer.Start(); err != nil {
|
||||||
logrus.WithError(err).Panic("failed to start receipt consumer")
|
logrus.WithError(err).Panic("failed to start receipt consumer")
|
||||||
}
|
}
|
||||||
typingConsumer := consumers.NewOutputTypingConsumer(
|
typingConsumer := consumers.NewOutputTypingConsumer(
|
||||||
base.ProcessContext, cfg, js, queues, federationDB,
|
processContext, cfg, js, queues, federationDB,
|
||||||
)
|
)
|
||||||
if err = typingConsumer.Start(); err != nil {
|
if err = typingConsumer.Start(); err != nil {
|
||||||
logrus.WithError(err).Panic("failed to start typing consumer")
|
logrus.WithError(err).Panic("failed to start typing consumer")
|
||||||
}
|
}
|
||||||
keyConsumer := consumers.NewKeyChangeConsumer(
|
keyConsumer := consumers.NewKeyChangeConsumer(
|
||||||
base.ProcessContext, &base.Cfg.KeyServer, js, queues, federationDB, rsAPI,
|
processContext, &dendriteCfg.KeyServer, js, queues, federationDB, rsAPI,
|
||||||
)
|
)
|
||||||
if err = keyConsumer.Start(); err != nil {
|
if err = keyConsumer.Start(); err != nil {
|
||||||
logrus.WithError(err).Panic("failed to start key server consumer")
|
logrus.WithError(err).Panic("failed to start key server consumer")
|
||||||
}
|
}
|
||||||
|
|
||||||
presenceConsumer := consumers.NewOutputPresenceConsumer(
|
presenceConsumer := consumers.NewOutputPresenceConsumer(
|
||||||
base.ProcessContext, cfg, js, queues, federationDB, rsAPI,
|
processContext, cfg, js, queues, federationDB, rsAPI,
|
||||||
)
|
)
|
||||||
if err = presenceConsumer.Start(); err != nil {
|
if err = presenceConsumer.Start(); err != nil {
|
||||||
logrus.WithError(err).Panic("failed to start presence consumer")
|
logrus.WithError(err).Panic("failed to start presence consumer")
|
||||||
|
|
@ -161,7 +173,7 @@ func NewInternalAPI(
|
||||||
var cleanExpiredEDUs func()
|
var cleanExpiredEDUs func()
|
||||||
cleanExpiredEDUs = func() {
|
cleanExpiredEDUs = func() {
|
||||||
logrus.Infof("Cleaning expired EDUs")
|
logrus.Infof("Cleaning expired EDUs")
|
||||||
if err := federationDB.DeleteExpiredEDUs(base.Context()); err != nil {
|
if err := federationDB.DeleteExpiredEDUs(processContext.Context()); err != nil {
|
||||||
logrus.WithError(err).Error("Failed to clean expired EDUs")
|
logrus.WithError(err).Error("Failed to clean expired EDUs")
|
||||||
}
|
}
|
||||||
time.AfterFunc(time.Hour, cleanExpiredEDUs)
|
time.AfterFunc(time.Hour, cleanExpiredEDUs)
|
||||||
|
|
|
||||||
|
|
@ -12,12 +12,15 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/matrix-org/dendrite/internal/sqlutil"
|
||||||
|
"github.com/matrix-org/dendrite/setup/jetstream"
|
||||||
|
"github.com/matrix-org/dendrite/setup/process"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib/fclient"
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/federationapi/api"
|
"github.com/matrix-org/dendrite/federationapi/api"
|
||||||
"github.com/matrix-org/dendrite/federationapi/routing"
|
"github.com/matrix-org/dendrite/federationapi/routing"
|
||||||
"github.com/matrix-org/dendrite/internal/caching"
|
"github.com/matrix-org/dendrite/internal/caching"
|
||||||
"github.com/matrix-org/dendrite/setup/base"
|
|
||||||
"github.com/matrix-org/dendrite/setup/config"
|
"github.com/matrix-org/dendrite/setup/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -25,7 +28,7 @@ type server struct {
|
||||||
name gomatrixserverlib.ServerName // server name
|
name gomatrixserverlib.ServerName // server name
|
||||||
validity time.Duration // key validity duration from now
|
validity time.Duration // key validity duration from now
|
||||||
config *config.FederationAPI // skeleton config, from TestMain
|
config *config.FederationAPI // skeleton config, from TestMain
|
||||||
fedclient *gomatrixserverlib.FederationClient // uses MockRoundTripper
|
fedclient *fclient.FederationClient // uses MockRoundTripper
|
||||||
cache *caching.Caches // server-specific cache
|
cache *caching.Caches // server-specific cache
|
||||||
api api.FederationInternalAPI // server-specific server key API
|
api api.FederationInternalAPI // server-specific server key API
|
||||||
}
|
}
|
||||||
|
|
@ -65,7 +68,7 @@ func TestMain(m *testing.M) {
|
||||||
|
|
||||||
// Create a new cache but don't enable prometheus!
|
// Create a new cache but don't enable prometheus!
|
||||||
s.cache = caching.NewRistrettoCache(8*1024*1024, time.Hour, false)
|
s.cache = caching.NewRistrettoCache(8*1024*1024, time.Hour, false)
|
||||||
|
natsInstance := jetstream.NATSInstance{}
|
||||||
// Create a temporary directory for JetStream.
|
// Create a temporary directory for JetStream.
|
||||||
d, err := os.MkdirTemp("./", "jetstream*")
|
d, err := os.MkdirTemp("./", "jetstream*")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -103,14 +106,15 @@ func TestMain(m *testing.M) {
|
||||||
transport.RegisterProtocol("matrix", &MockRoundTripper{})
|
transport.RegisterProtocol("matrix", &MockRoundTripper{})
|
||||||
|
|
||||||
// Create the federation client.
|
// Create the federation client.
|
||||||
s.fedclient = gomatrixserverlib.NewFederationClient(
|
s.fedclient = fclient.NewFederationClient(
|
||||||
s.config.Matrix.SigningIdentities(),
|
s.config.Matrix.SigningIdentities(),
|
||||||
gomatrixserverlib.WithTransport(transport),
|
fclient.WithTransport(transport),
|
||||||
)
|
)
|
||||||
|
|
||||||
// Finally, build the server key APIs.
|
// Finally, build the server key APIs.
|
||||||
sbase := base.NewBaseDendrite(cfg, base.DisableMetrics)
|
processCtx := process.NewProcessContext()
|
||||||
s.api = NewInternalAPI(sbase, s.fedclient, nil, s.cache, nil, true)
|
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
|
||||||
|
s.api = NewInternalAPI(processCtx, cfg, cm, &natsInstance, s.fedclient, nil, s.cache, nil, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now that we have built our server key APIs, start the
|
// Now that we have built our server key APIs, start the
|
||||||
|
|
|
||||||
|
|
@ -10,16 +10,18 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/matrix-org/dendrite/internal/caching"
|
||||||
|
"github.com/matrix-org/dendrite/internal/httputil"
|
||||||
|
"github.com/matrix-org/dendrite/internal/sqlutil"
|
||||||
"github.com/matrix-org/gomatrix"
|
"github.com/matrix-org/gomatrix"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib/fclient"
|
||||||
"github.com/nats-io/nats.go"
|
"github.com/nats-io/nats.go"
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/federationapi"
|
"github.com/matrix-org/dendrite/federationapi"
|
||||||
"github.com/matrix-org/dendrite/federationapi/api"
|
"github.com/matrix-org/dendrite/federationapi/api"
|
||||||
"github.com/matrix-org/dendrite/federationapi/internal"
|
"github.com/matrix-org/dendrite/federationapi/internal"
|
||||||
rsapi "github.com/matrix-org/dendrite/roomserver/api"
|
rsapi "github.com/matrix-org/dendrite/roomserver/api"
|
||||||
"github.com/matrix-org/dendrite/setup/base"
|
|
||||||
"github.com/matrix-org/dendrite/setup/config"
|
|
||||||
"github.com/matrix-org/dendrite/setup/jetstream"
|
"github.com/matrix-org/dendrite/setup/jetstream"
|
||||||
"github.com/matrix-org/dendrite/test"
|
"github.com/matrix-org/dendrite/test"
|
||||||
"github.com/matrix-org/dendrite/test/testrig"
|
"github.com/matrix-org/dendrite/test/testrig"
|
||||||
|
|
@ -103,7 +105,7 @@ func (f *fedClient) GetServerKeys(ctx context.Context, matrixServer gomatrixserv
|
||||||
return keys, nil
|
return keys, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *fedClient) MakeJoin(ctx context.Context, origin, s gomatrixserverlib.ServerName, roomID, userID string, roomVersions []gomatrixserverlib.RoomVersion) (res gomatrixserverlib.RespMakeJoin, err error) {
|
func (f *fedClient) MakeJoin(ctx context.Context, origin, s gomatrixserverlib.ServerName, roomID, userID string, roomVersions []gomatrixserverlib.RoomVersion) (res fclient.RespMakeJoin, err error) {
|
||||||
for _, r := range f.allowJoins {
|
for _, r := range f.allowJoins {
|
||||||
if r.ID == roomID {
|
if r.ID == roomID {
|
||||||
res.RoomVersion = r.Version
|
res.RoomVersion = r.Version
|
||||||
|
|
@ -127,7 +129,7 @@ func (f *fedClient) MakeJoin(ctx context.Context, origin, s gomatrixserverlib.Se
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
func (f *fedClient) SendJoin(ctx context.Context, origin, s gomatrixserverlib.ServerName, event *gomatrixserverlib.Event) (res gomatrixserverlib.RespSendJoin, err error) {
|
func (f *fedClient) SendJoin(ctx context.Context, origin, s gomatrixserverlib.ServerName, event *gomatrixserverlib.Event) (res fclient.RespSendJoin, err error) {
|
||||||
f.fedClientMutex.Lock()
|
f.fedClientMutex.Lock()
|
||||||
defer f.fedClientMutex.Unlock()
|
defer f.fedClientMutex.Unlock()
|
||||||
for _, r := range f.allowJoins {
|
for _, r := range f.allowJoins {
|
||||||
|
|
@ -141,7 +143,7 @@ func (f *fedClient) SendJoin(ctx context.Context, origin, s gomatrixserverlib.Se
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *fedClient) SendTransaction(ctx context.Context, t gomatrixserverlib.Transaction) (res gomatrixserverlib.RespSend, err error) {
|
func (f *fedClient) SendTransaction(ctx context.Context, t gomatrixserverlib.Transaction) (res fclient.RespSend, err error) {
|
||||||
f.fedClientMutex.Lock()
|
f.fedClientMutex.Lock()
|
||||||
defer f.fedClientMutex.Unlock()
|
defer f.fedClientMutex.Unlock()
|
||||||
for _, edu := range t.EDUs {
|
for _, edu := range t.EDUs {
|
||||||
|
|
@ -162,21 +164,24 @@ func TestFederationAPIJoinThenKeyUpdate(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testFederationAPIJoinThenKeyUpdate(t *testing.T, dbType test.DBType) {
|
func testFederationAPIJoinThenKeyUpdate(t *testing.T, dbType test.DBType) {
|
||||||
base, close := testrig.CreateBaseDendrite(t, dbType)
|
cfg, processCtx, close := testrig.CreateConfig(t, dbType)
|
||||||
base.Cfg.FederationAPI.PreferDirectFetch = true
|
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
|
||||||
base.Cfg.FederationAPI.KeyPerspectives = nil
|
caches := caching.NewRistrettoCache(128*1024*1024, time.Hour, caching.DisableMetrics)
|
||||||
|
natsInstance := jetstream.NATSInstance{}
|
||||||
|
cfg.FederationAPI.PreferDirectFetch = true
|
||||||
|
cfg.FederationAPI.KeyPerspectives = nil
|
||||||
defer close()
|
defer close()
|
||||||
jsctx, _ := base.NATS.Prepare(base.ProcessContext, &base.Cfg.Global.JetStream)
|
jsctx, _ := natsInstance.Prepare(processCtx, &cfg.Global.JetStream)
|
||||||
defer jetstream.DeleteAllStreams(jsctx, &base.Cfg.Global.JetStream)
|
defer jetstream.DeleteAllStreams(jsctx, &cfg.Global.JetStream)
|
||||||
|
|
||||||
serverA := gomatrixserverlib.ServerName("server.a")
|
serverA := gomatrixserverlib.ServerName("server.a")
|
||||||
serverAKeyID := gomatrixserverlib.KeyID("ed25519:servera")
|
serverAKeyID := gomatrixserverlib.KeyID("ed25519:servera")
|
||||||
serverAPrivKey := test.PrivateKeyA
|
serverAPrivKey := test.PrivateKeyA
|
||||||
creator := test.NewUser(t, test.WithSigningServer(serverA, serverAKeyID, serverAPrivKey))
|
creator := test.NewUser(t, test.WithSigningServer(serverA, serverAKeyID, serverAPrivKey))
|
||||||
|
|
||||||
myServer := base.Cfg.Global.ServerName
|
myServer := cfg.Global.ServerName
|
||||||
myServerKeyID := base.Cfg.Global.KeyID
|
myServerKeyID := cfg.Global.KeyID
|
||||||
myServerPrivKey := base.Cfg.Global.PrivateKey
|
myServerPrivKey := cfg.Global.PrivateKey
|
||||||
joiningUser := test.NewUser(t, test.WithSigningServer(myServer, myServerKeyID, myServerPrivKey))
|
joiningUser := test.NewUser(t, test.WithSigningServer(myServer, myServerKeyID, myServerPrivKey))
|
||||||
fmt.Printf("creator: %v joining user: %v\n", creator.ID, joiningUser.ID)
|
fmt.Printf("creator: %v joining user: %v\n", creator.ID, joiningUser.ID)
|
||||||
room := test.NewRoom(t, creator)
|
room := test.NewRoom(t, creator)
|
||||||
|
|
@ -212,7 +217,7 @@ func testFederationAPIJoinThenKeyUpdate(t *testing.T, dbType test.DBType) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
fsapi := federationapi.NewInternalAPI(base, fc, rsapi, base.Caches, nil, false)
|
fsapi := federationapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, fc, rsapi, caches, nil, false)
|
||||||
|
|
||||||
var resp api.PerformJoinResponse
|
var resp api.PerformJoinResponse
|
||||||
fsapi.PerformJoin(context.Background(), &api.PerformJoinRequest{
|
fsapi.PerformJoin(context.Background(), &api.PerformJoinRequest{
|
||||||
|
|
@ -245,7 +250,7 @@ func testFederationAPIJoinThenKeyUpdate(t *testing.T, dbType test.DBType) {
|
||||||
}
|
}
|
||||||
|
|
||||||
msg := &nats.Msg{
|
msg := &nats.Msg{
|
||||||
Subject: base.Cfg.Global.JetStream.Prefixed(jetstream.OutputKeyChangeEvent),
|
Subject: cfg.Global.JetStream.Prefixed(jetstream.OutputKeyChangeEvent),
|
||||||
Header: nats.Header{},
|
Header: nats.Header{},
|
||||||
Data: b,
|
Data: b,
|
||||||
}
|
}
|
||||||
|
|
@ -263,30 +268,6 @@ func testFederationAPIJoinThenKeyUpdate(t *testing.T, dbType test.DBType) {
|
||||||
// Tests that event IDs with '/' in them (escaped as %2F) are correctly passed to the right handler and don't 404.
|
// Tests that event IDs with '/' in them (escaped as %2F) are correctly passed to the right handler and don't 404.
|
||||||
// Relevant for v3 rooms and a cause of flakey sytests as the IDs are randomly generated.
|
// Relevant for v3 rooms and a cause of flakey sytests as the IDs are randomly generated.
|
||||||
func TestRoomsV3URLEscapeDoNot404(t *testing.T) {
|
func TestRoomsV3URLEscapeDoNot404(t *testing.T) {
|
||||||
_, privKey, _ := ed25519.GenerateKey(nil)
|
|
||||||
cfg := &config.Dendrite{}
|
|
||||||
cfg.Defaults(config.DefaultOpts{
|
|
||||||
Generate: true,
|
|
||||||
SingleDatabase: false,
|
|
||||||
})
|
|
||||||
cfg.Global.KeyID = gomatrixserverlib.KeyID("ed25519:auto")
|
|
||||||
cfg.Global.ServerName = gomatrixserverlib.ServerName("localhost")
|
|
||||||
cfg.Global.PrivateKey = privKey
|
|
||||||
cfg.Global.JetStream.InMemory = true
|
|
||||||
b := base.NewBaseDendrite(cfg, base.DisableMetrics)
|
|
||||||
keyRing := &test.NopJSONVerifier{}
|
|
||||||
// TODO: This is pretty fragile, as if anything calls anything on these nils this test will break.
|
|
||||||
// Unfortunately, it makes little sense to instantiate these dependencies when we just want to test routing.
|
|
||||||
federationapi.AddPublicRoutes(b, nil, nil, keyRing, nil, &internal.FederationInternalAPI{}, nil)
|
|
||||||
baseURL, cancel := test.ListenAndServe(t, b.PublicFederationAPIMux, true)
|
|
||||||
defer cancel()
|
|
||||||
serverName := gomatrixserverlib.ServerName(strings.TrimPrefix(baseURL, "https://"))
|
|
||||||
|
|
||||||
fedCli := gomatrixserverlib.NewFederationClient(
|
|
||||||
cfg.Global.SigningIdentities(),
|
|
||||||
gomatrixserverlib.WithSkipVerify(true),
|
|
||||||
)
|
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
roomVer gomatrixserverlib.RoomVersion
|
roomVer gomatrixserverlib.RoomVersion
|
||||||
eventJSON string
|
eventJSON string
|
||||||
|
|
@ -315,6 +296,29 @@ func TestRoomsV3URLEscapeDoNot404(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cfg, processCtx, close := testrig.CreateConfig(t, test.DBTypeSQLite)
|
||||||
|
defer close()
|
||||||
|
routers := httputil.NewRouters()
|
||||||
|
|
||||||
|
_, privKey, _ := ed25519.GenerateKey(nil)
|
||||||
|
cfg.Global.KeyID = gomatrixserverlib.KeyID("ed25519:auto")
|
||||||
|
cfg.Global.ServerName = gomatrixserverlib.ServerName("localhost")
|
||||||
|
cfg.Global.PrivateKey = privKey
|
||||||
|
cfg.Global.JetStream.InMemory = true
|
||||||
|
keyRing := &test.NopJSONVerifier{}
|
||||||
|
natsInstance := jetstream.NATSInstance{}
|
||||||
|
// TODO: This is pretty fragile, as if anything calls anything on these nils this test will break.
|
||||||
|
// Unfortunately, it makes little sense to instantiate these dependencies when we just want to test routing.
|
||||||
|
federationapi.AddPublicRoutes(processCtx, routers, cfg, &natsInstance, nil, nil, keyRing, nil, &internal.FederationInternalAPI{}, nil, caching.DisableMetrics)
|
||||||
|
baseURL, cancel := test.ListenAndServe(t, routers.Federation, true)
|
||||||
|
defer cancel()
|
||||||
|
serverName := gomatrixserverlib.ServerName(strings.TrimPrefix(baseURL, "https://"))
|
||||||
|
|
||||||
|
fedCli := fclient.NewFederationClient(
|
||||||
|
cfg.Global.SigningIdentities(),
|
||||||
|
fclient.WithSkipVerify(true),
|
||||||
|
)
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
ev, err := gomatrixserverlib.NewEventFromTrustedJSON([]byte(tc.eventJSON), false, tc.roomVer)
|
ev, err := gomatrixserverlib.NewEventFromTrustedJSON([]byte(tc.eventJSON), false, tc.roomVer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib/fclient"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Functions here are "proxying" calls to the gomatrixserverlib federation
|
// Functions here are "proxying" calls to the gomatrixserverlib federation
|
||||||
|
|
@ -13,56 +14,56 @@ import (
|
||||||
func (a *FederationInternalAPI) GetEventAuth(
|
func (a *FederationInternalAPI) GetEventAuth(
|
||||||
ctx context.Context, origin, s gomatrixserverlib.ServerName,
|
ctx context.Context, origin, s gomatrixserverlib.ServerName,
|
||||||
roomVersion gomatrixserverlib.RoomVersion, roomID, eventID string,
|
roomVersion gomatrixserverlib.RoomVersion, roomID, eventID string,
|
||||||
) (res gomatrixserverlib.RespEventAuth, err error) {
|
) (res fclient.RespEventAuth, err error) {
|
||||||
ctx, cancel := context.WithTimeout(ctx, time.Second*30)
|
ctx, cancel := context.WithTimeout(ctx, time.Second*30)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
ires, err := a.doRequestIfNotBlacklisted(s, func() (interface{}, error) {
|
ires, err := a.doRequestIfNotBlacklisted(s, func() (interface{}, error) {
|
||||||
return a.federation.GetEventAuth(ctx, origin, s, roomVersion, roomID, eventID)
|
return a.federation.GetEventAuth(ctx, origin, s, roomVersion, roomID, eventID)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return gomatrixserverlib.RespEventAuth{}, err
|
return fclient.RespEventAuth{}, err
|
||||||
}
|
}
|
||||||
return ires.(gomatrixserverlib.RespEventAuth), nil
|
return ires.(fclient.RespEventAuth), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *FederationInternalAPI) GetUserDevices(
|
func (a *FederationInternalAPI) GetUserDevices(
|
||||||
ctx context.Context, origin, s gomatrixserverlib.ServerName, userID string,
|
ctx context.Context, origin, s gomatrixserverlib.ServerName, userID string,
|
||||||
) (gomatrixserverlib.RespUserDevices, error) {
|
) (fclient.RespUserDevices, error) {
|
||||||
ctx, cancel := context.WithTimeout(ctx, time.Second*30)
|
ctx, cancel := context.WithTimeout(ctx, time.Second*30)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
ires, err := a.doRequestIfNotBlacklisted(s, func() (interface{}, error) {
|
ires, err := a.doRequestIfNotBlacklisted(s, func() (interface{}, error) {
|
||||||
return a.federation.GetUserDevices(ctx, origin, s, userID)
|
return a.federation.GetUserDevices(ctx, origin, s, userID)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return gomatrixserverlib.RespUserDevices{}, err
|
return fclient.RespUserDevices{}, err
|
||||||
}
|
}
|
||||||
return ires.(gomatrixserverlib.RespUserDevices), nil
|
return ires.(fclient.RespUserDevices), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *FederationInternalAPI) ClaimKeys(
|
func (a *FederationInternalAPI) ClaimKeys(
|
||||||
ctx context.Context, origin, s gomatrixserverlib.ServerName, oneTimeKeys map[string]map[string]string,
|
ctx context.Context, origin, s gomatrixserverlib.ServerName, oneTimeKeys map[string]map[string]string,
|
||||||
) (gomatrixserverlib.RespClaimKeys, error) {
|
) (fclient.RespClaimKeys, error) {
|
||||||
ctx, cancel := context.WithTimeout(ctx, time.Second*30)
|
ctx, cancel := context.WithTimeout(ctx, time.Second*30)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
ires, err := a.doRequestIfNotBlacklisted(s, func() (interface{}, error) {
|
ires, err := a.doRequestIfNotBlacklisted(s, func() (interface{}, error) {
|
||||||
return a.federation.ClaimKeys(ctx, origin, s, oneTimeKeys)
|
return a.federation.ClaimKeys(ctx, origin, s, oneTimeKeys)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return gomatrixserverlib.RespClaimKeys{}, err
|
return fclient.RespClaimKeys{}, err
|
||||||
}
|
}
|
||||||
return ires.(gomatrixserverlib.RespClaimKeys), nil
|
return ires.(fclient.RespClaimKeys), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *FederationInternalAPI) QueryKeys(
|
func (a *FederationInternalAPI) QueryKeys(
|
||||||
ctx context.Context, origin, s gomatrixserverlib.ServerName, keys map[string][]string,
|
ctx context.Context, origin, s gomatrixserverlib.ServerName, keys map[string][]string,
|
||||||
) (gomatrixserverlib.RespQueryKeys, error) {
|
) (fclient.RespQueryKeys, error) {
|
||||||
ires, err := a.doRequestIfNotBackingOffOrBlacklisted(s, func() (interface{}, error) {
|
ires, err := a.doRequestIfNotBackingOffOrBlacklisted(s, func() (interface{}, error) {
|
||||||
return a.federation.QueryKeys(ctx, origin, s, keys)
|
return a.federation.QueryKeys(ctx, origin, s, keys)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return gomatrixserverlib.RespQueryKeys{}, err
|
return fclient.RespQueryKeys{}, err
|
||||||
}
|
}
|
||||||
return ires.(gomatrixserverlib.RespQueryKeys), nil
|
return ires.(fclient.RespQueryKeys), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *FederationInternalAPI) Backfill(
|
func (a *FederationInternalAPI) Backfill(
|
||||||
|
|
@ -81,45 +82,46 @@ func (a *FederationInternalAPI) Backfill(
|
||||||
|
|
||||||
func (a *FederationInternalAPI) LookupState(
|
func (a *FederationInternalAPI) LookupState(
|
||||||
ctx context.Context, origin, s gomatrixserverlib.ServerName, roomID, eventID string, roomVersion gomatrixserverlib.RoomVersion,
|
ctx context.Context, origin, s gomatrixserverlib.ServerName, roomID, eventID string, roomVersion gomatrixserverlib.RoomVersion,
|
||||||
) (res gomatrixserverlib.RespState, err error) {
|
) (res gomatrixserverlib.StateResponse, err error) {
|
||||||
ctx, cancel := context.WithTimeout(ctx, time.Second*30)
|
ctx, cancel := context.WithTimeout(ctx, time.Second*30)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
ires, err := a.doRequestIfNotBlacklisted(s, func() (interface{}, error) {
|
ires, err := a.doRequestIfNotBlacklisted(s, func() (interface{}, error) {
|
||||||
return a.federation.LookupState(ctx, origin, s, roomID, eventID, roomVersion)
|
return a.federation.LookupState(ctx, origin, s, roomID, eventID, roomVersion)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return gomatrixserverlib.RespState{}, err
|
return &fclient.RespState{}, err
|
||||||
}
|
}
|
||||||
return ires.(gomatrixserverlib.RespState), nil
|
r := ires.(fclient.RespState)
|
||||||
|
return &r, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *FederationInternalAPI) LookupStateIDs(
|
func (a *FederationInternalAPI) LookupStateIDs(
|
||||||
ctx context.Context, origin, s gomatrixserverlib.ServerName, roomID, eventID string,
|
ctx context.Context, origin, s gomatrixserverlib.ServerName, roomID, eventID string,
|
||||||
) (res gomatrixserverlib.RespStateIDs, err error) {
|
) (res gomatrixserverlib.StateIDResponse, err error) {
|
||||||
ctx, cancel := context.WithTimeout(ctx, time.Second*30)
|
ctx, cancel := context.WithTimeout(ctx, time.Second*30)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
ires, err := a.doRequestIfNotBlacklisted(s, func() (interface{}, error) {
|
ires, err := a.doRequestIfNotBlacklisted(s, func() (interface{}, error) {
|
||||||
return a.federation.LookupStateIDs(ctx, origin, s, roomID, eventID)
|
return a.federation.LookupStateIDs(ctx, origin, s, roomID, eventID)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return gomatrixserverlib.RespStateIDs{}, err
|
return fclient.RespStateIDs{}, err
|
||||||
}
|
}
|
||||||
return ires.(gomatrixserverlib.RespStateIDs), nil
|
return ires.(fclient.RespStateIDs), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *FederationInternalAPI) LookupMissingEvents(
|
func (a *FederationInternalAPI) LookupMissingEvents(
|
||||||
ctx context.Context, origin, s gomatrixserverlib.ServerName, roomID string,
|
ctx context.Context, origin, s gomatrixserverlib.ServerName, roomID string,
|
||||||
missing gomatrixserverlib.MissingEvents, roomVersion gomatrixserverlib.RoomVersion,
|
missing fclient.MissingEvents, roomVersion gomatrixserverlib.RoomVersion,
|
||||||
) (res gomatrixserverlib.RespMissingEvents, err error) {
|
) (res fclient.RespMissingEvents, err error) {
|
||||||
ctx, cancel := context.WithTimeout(ctx, time.Second*30)
|
ctx, cancel := context.WithTimeout(ctx, time.Second*30)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
ires, err := a.doRequestIfNotBlacklisted(s, func() (interface{}, error) {
|
ires, err := a.doRequestIfNotBlacklisted(s, func() (interface{}, error) {
|
||||||
return a.federation.LookupMissingEvents(ctx, origin, s, roomID, missing, roomVersion)
|
return a.federation.LookupMissingEvents(ctx, origin, s, roomID, missing, roomVersion)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return gomatrixserverlib.RespMissingEvents{}, err
|
return fclient.RespMissingEvents{}, err
|
||||||
}
|
}
|
||||||
return ires.(gomatrixserverlib.RespMissingEvents), nil
|
return ires.(fclient.RespMissingEvents), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *FederationInternalAPI) GetEvent(
|
func (a *FederationInternalAPI) GetEvent(
|
||||||
|
|
@ -151,9 +153,9 @@ func (a *FederationInternalAPI) LookupServerKeys(
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *FederationInternalAPI) MSC2836EventRelationships(
|
func (a *FederationInternalAPI) MSC2836EventRelationships(
|
||||||
ctx context.Context, origin, s gomatrixserverlib.ServerName, r gomatrixserverlib.MSC2836EventRelationshipsRequest,
|
ctx context.Context, origin, s gomatrixserverlib.ServerName, r fclient.MSC2836EventRelationshipsRequest,
|
||||||
roomVersion gomatrixserverlib.RoomVersion,
|
roomVersion gomatrixserverlib.RoomVersion,
|
||||||
) (res gomatrixserverlib.MSC2836EventRelationshipsResponse, err error) {
|
) (res fclient.MSC2836EventRelationshipsResponse, err error) {
|
||||||
ctx, cancel := context.WithTimeout(ctx, time.Minute)
|
ctx, cancel := context.WithTimeout(ctx, time.Minute)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
ires, err := a.doRequestIfNotBlacklisted(s, func() (interface{}, error) {
|
ires, err := a.doRequestIfNotBlacklisted(s, func() (interface{}, error) {
|
||||||
|
|
@ -162,12 +164,12 @@ func (a *FederationInternalAPI) MSC2836EventRelationships(
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
return ires.(gomatrixserverlib.MSC2836EventRelationshipsResponse), nil
|
return ires.(fclient.MSC2836EventRelationshipsResponse), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *FederationInternalAPI) MSC2946Spaces(
|
func (a *FederationInternalAPI) MSC2946Spaces(
|
||||||
ctx context.Context, origin, s gomatrixserverlib.ServerName, roomID string, suggestedOnly bool,
|
ctx context.Context, origin, s gomatrixserverlib.ServerName, roomID string, suggestedOnly bool,
|
||||||
) (res gomatrixserverlib.MSC2946SpacesResponse, err error) {
|
) (res fclient.MSC2946SpacesResponse, err error) {
|
||||||
ctx, cancel := context.WithTimeout(ctx, time.Minute)
|
ctx, cancel := context.WithTimeout(ctx, time.Minute)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
ires, err := a.doRequestIfNotBlacklisted(s, func() (interface{}, error) {
|
ires, err := a.doRequestIfNotBlacklisted(s, func() (interface{}, error) {
|
||||||
|
|
@ -176,5 +178,5 @@ func (a *FederationInternalAPI) MSC2946Spaces(
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
return ires.(gomatrixserverlib.MSC2946SpacesResponse), nil
|
return ires.(fclient.MSC2946SpacesResponse), nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ import (
|
||||||
"github.com/matrix-org/dendrite/setup/process"
|
"github.com/matrix-org/dendrite/setup/process"
|
||||||
"github.com/matrix-org/dendrite/test"
|
"github.com/matrix-org/dendrite/test"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib/fclient"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -33,20 +34,20 @@ const (
|
||||||
FailuresUntilBlacklist = 8
|
FailuresUntilBlacklist = 8
|
||||||
)
|
)
|
||||||
|
|
||||||
func (t *testFedClient) QueryKeys(ctx context.Context, origin, s gomatrixserverlib.ServerName, keys map[string][]string) (gomatrixserverlib.RespQueryKeys, error) {
|
func (t *testFedClient) QueryKeys(ctx context.Context, origin, s gomatrixserverlib.ServerName, keys map[string][]string) (fclient.RespQueryKeys, error) {
|
||||||
t.queryKeysCalled = true
|
t.queryKeysCalled = true
|
||||||
if t.shouldFail {
|
if t.shouldFail {
|
||||||
return gomatrixserverlib.RespQueryKeys{}, fmt.Errorf("Failure")
|
return fclient.RespQueryKeys{}, fmt.Errorf("Failure")
|
||||||
}
|
}
|
||||||
return gomatrixserverlib.RespQueryKeys{}, nil
|
return fclient.RespQueryKeys{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *testFedClient) ClaimKeys(ctx context.Context, origin, s gomatrixserverlib.ServerName, oneTimeKeys map[string]map[string]string) (gomatrixserverlib.RespClaimKeys, error) {
|
func (t *testFedClient) ClaimKeys(ctx context.Context, origin, s gomatrixserverlib.ServerName, oneTimeKeys map[string]map[string]string) (fclient.RespClaimKeys, error) {
|
||||||
t.claimKeysCalled = true
|
t.claimKeysCalled = true
|
||||||
if t.shouldFail {
|
if t.shouldFail {
|
||||||
return gomatrixserverlib.RespClaimKeys{}, fmt.Errorf("Failure")
|
return fclient.RespClaimKeys{}, fmt.Errorf("Failure")
|
||||||
}
|
}
|
||||||
return gomatrixserverlib.RespClaimKeys{}, nil
|
return fclient.RespClaimKeys{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFederationClientQueryKeys(t *testing.T) {
|
func TestFederationClientQueryKeys(t *testing.T) {
|
||||||
|
|
@ -54,7 +55,7 @@ func TestFederationClientQueryKeys(t *testing.T) {
|
||||||
|
|
||||||
cfg := config.FederationAPI{
|
cfg := config.FederationAPI{
|
||||||
Matrix: &config.Global{
|
Matrix: &config.Global{
|
||||||
SigningIdentity: gomatrixserverlib.SigningIdentity{
|
SigningIdentity: fclient.SigningIdentity{
|
||||||
ServerName: "server",
|
ServerName: "server",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -85,7 +86,7 @@ func TestFederationClientQueryKeysBlacklisted(t *testing.T) {
|
||||||
|
|
||||||
cfg := config.FederationAPI{
|
cfg := config.FederationAPI{
|
||||||
Matrix: &config.Global{
|
Matrix: &config.Global{
|
||||||
SigningIdentity: gomatrixserverlib.SigningIdentity{
|
SigningIdentity: fclient.SigningIdentity{
|
||||||
ServerName: "server",
|
ServerName: "server",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -115,7 +116,7 @@ func TestFederationClientQueryKeysFailure(t *testing.T) {
|
||||||
|
|
||||||
cfg := config.FederationAPI{
|
cfg := config.FederationAPI{
|
||||||
Matrix: &config.Global{
|
Matrix: &config.Global{
|
||||||
SigningIdentity: gomatrixserverlib.SigningIdentity{
|
SigningIdentity: fclient.SigningIdentity{
|
||||||
ServerName: "server",
|
ServerName: "server",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -145,7 +146,7 @@ func TestFederationClientClaimKeys(t *testing.T) {
|
||||||
|
|
||||||
cfg := config.FederationAPI{
|
cfg := config.FederationAPI{
|
||||||
Matrix: &config.Global{
|
Matrix: &config.Global{
|
||||||
SigningIdentity: gomatrixserverlib.SigningIdentity{
|
SigningIdentity: fclient.SigningIdentity{
|
||||||
ServerName: "server",
|
ServerName: "server",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -176,7 +177,7 @@ func TestFederationClientClaimKeysBlacklisted(t *testing.T) {
|
||||||
|
|
||||||
cfg := config.FederationAPI{
|
cfg := config.FederationAPI{
|
||||||
Matrix: &config.Global{
|
Matrix: &config.Global{
|
||||||
SigningIdentity: gomatrixserverlib.SigningIdentity{
|
SigningIdentity: fclient.SigningIdentity{
|
||||||
ServerName: "server",
|
ServerName: "server",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import (
|
||||||
|
|
||||||
"github.com/matrix-org/gomatrix"
|
"github.com/matrix-org/gomatrix"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib/fclient"
|
||||||
"github.com/matrix-org/util"
|
"github.com/matrix-org/util"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
|
@ -255,7 +256,7 @@ func (r *FederationInternalAPI) performJoinUsingServer(
|
||||||
// waste the effort.
|
// waste the effort.
|
||||||
// TODO: Can we expand Check here to return a list of missing auth
|
// TODO: Can we expand Check here to return a list of missing auth
|
||||||
// events rather than failing one at a time?
|
// events rather than failing one at a time?
|
||||||
var respState *gomatrixserverlib.RespState
|
var respState *fclient.RespState
|
||||||
respState, err = respSendJoin.Check(
|
respState, err = respSendJoin.Check(
|
||||||
context.Background(),
|
context.Background(),
|
||||||
respMakeJoin.RoomVersion,
|
respMakeJoin.RoomVersion,
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ import (
|
||||||
"github.com/matrix-org/dendrite/setup/process"
|
"github.com/matrix-org/dendrite/setup/process"
|
||||||
"github.com/matrix-org/dendrite/test"
|
"github.com/matrix-org/dendrite/test"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib/fclient"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -35,8 +36,8 @@ type testFedClient struct {
|
||||||
shouldFail bool
|
shouldFail bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *testFedClient) LookupRoomAlias(ctx context.Context, origin, s gomatrixserverlib.ServerName, roomAlias string) (res gomatrixserverlib.RespDirectory, err error) {
|
func (t *testFedClient) LookupRoomAlias(ctx context.Context, origin, s gomatrixserverlib.ServerName, roomAlias string) (res fclient.RespDirectory, err error) {
|
||||||
return gomatrixserverlib.RespDirectory{}, nil
|
return fclient.RespDirectory{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPerformWakeupServers(t *testing.T) {
|
func TestPerformWakeupServers(t *testing.T) {
|
||||||
|
|
@ -54,7 +55,7 @@ func TestPerformWakeupServers(t *testing.T) {
|
||||||
|
|
||||||
cfg := config.FederationAPI{
|
cfg := config.FederationAPI{
|
||||||
Matrix: &config.Global{
|
Matrix: &config.Global{
|
||||||
SigningIdentity: gomatrixserverlib.SigningIdentity{
|
SigningIdentity: fclient.SigningIdentity{
|
||||||
ServerName: "relay",
|
ServerName: "relay",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -96,7 +97,7 @@ func TestQueryRelayServers(t *testing.T) {
|
||||||
|
|
||||||
cfg := config.FederationAPI{
|
cfg := config.FederationAPI{
|
||||||
Matrix: &config.Global{
|
Matrix: &config.Global{
|
||||||
SigningIdentity: gomatrixserverlib.SigningIdentity{
|
SigningIdentity: fclient.SigningIdentity{
|
||||||
ServerName: "relay",
|
ServerName: "relay",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -133,7 +134,7 @@ func TestRemoveRelayServers(t *testing.T) {
|
||||||
|
|
||||||
cfg := config.FederationAPI{
|
cfg := config.FederationAPI{
|
||||||
Matrix: &config.Global{
|
Matrix: &config.Global{
|
||||||
SigningIdentity: gomatrixserverlib.SigningIdentity{
|
SigningIdentity: fclient.SigningIdentity{
|
||||||
ServerName: "relay",
|
ServerName: "relay",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -169,7 +170,7 @@ func TestPerformDirectoryLookup(t *testing.T) {
|
||||||
|
|
||||||
cfg := config.FederationAPI{
|
cfg := config.FederationAPI{
|
||||||
Matrix: &config.Global{
|
Matrix: &config.Global{
|
||||||
SigningIdentity: gomatrixserverlib.SigningIdentity{
|
SigningIdentity: fclient.SigningIdentity{
|
||||||
ServerName: "relay",
|
ServerName: "relay",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -204,7 +205,7 @@ func TestPerformDirectoryLookupRelaying(t *testing.T) {
|
||||||
|
|
||||||
cfg := config.FederationAPI{
|
cfg := config.FederationAPI{
|
||||||
Matrix: &config.Global{
|
Matrix: &config.Global{
|
||||||
SigningIdentity: gomatrixserverlib.SigningIdentity{
|
SigningIdentity: fclient.SigningIdentity{
|
||||||
ServerName: server,
|
ServerName: server,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import (
|
||||||
|
|
||||||
"github.com/matrix-org/gomatrix"
|
"github.com/matrix-org/gomatrix"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib/fclient"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"go.uber.org/atomic"
|
"go.uber.org/atomic"
|
||||||
|
|
||||||
|
|
@ -50,7 +51,7 @@ type destinationQueue struct {
|
||||||
queues *OutgoingQueues
|
queues *OutgoingQueues
|
||||||
db storage.Database
|
db storage.Database
|
||||||
process *process.ProcessContext
|
process *process.ProcessContext
|
||||||
signing map[gomatrixserverlib.ServerName]*gomatrixserverlib.SigningIdentity
|
signing map[gomatrixserverlib.ServerName]*fclient.SigningIdentity
|
||||||
rsAPI api.FederationRoomserverAPI
|
rsAPI api.FederationRoomserverAPI
|
||||||
client fedapi.FederationClient // federation client
|
client fedapi.FederationClient // federation client
|
||||||
origin gomatrixserverlib.ServerName // origin of requests
|
origin gomatrixserverlib.ServerName // origin of requests
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ import (
|
||||||
|
|
||||||
"github.com/getsentry/sentry-go"
|
"github.com/getsentry/sentry-go"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib/fclient"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
@ -45,7 +46,7 @@ type OutgoingQueues struct {
|
||||||
origin gomatrixserverlib.ServerName
|
origin gomatrixserverlib.ServerName
|
||||||
client fedapi.FederationClient
|
client fedapi.FederationClient
|
||||||
statistics *statistics.Statistics
|
statistics *statistics.Statistics
|
||||||
signing map[gomatrixserverlib.ServerName]*gomatrixserverlib.SigningIdentity
|
signing map[gomatrixserverlib.ServerName]*fclient.SigningIdentity
|
||||||
queuesMutex sync.Mutex // protects the below
|
queuesMutex sync.Mutex // protects the below
|
||||||
queues map[gomatrixserverlib.ServerName]*destinationQueue
|
queues map[gomatrixserverlib.ServerName]*destinationQueue
|
||||||
}
|
}
|
||||||
|
|
@ -90,7 +91,7 @@ func NewOutgoingQueues(
|
||||||
client fedapi.FederationClient,
|
client fedapi.FederationClient,
|
||||||
rsAPI api.FederationRoomserverAPI,
|
rsAPI api.FederationRoomserverAPI,
|
||||||
statistics *statistics.Statistics,
|
statistics *statistics.Statistics,
|
||||||
signing []*gomatrixserverlib.SigningIdentity,
|
signing []*fclient.SigningIdentity,
|
||||||
) *OutgoingQueues {
|
) *OutgoingQueues {
|
||||||
queues := &OutgoingQueues{
|
queues := &OutgoingQueues{
|
||||||
disabled: disabled,
|
disabled: disabled,
|
||||||
|
|
@ -100,7 +101,7 @@ func NewOutgoingQueues(
|
||||||
origin: origin,
|
origin: origin,
|
||||||
client: client,
|
client: client,
|
||||||
statistics: statistics,
|
statistics: statistics,
|
||||||
signing: map[gomatrixserverlib.ServerName]*gomatrixserverlib.SigningIdentity{},
|
signing: map[gomatrixserverlib.ServerName]*fclient.SigningIdentity{},
|
||||||
queues: map[gomatrixserverlib.ServerName]*destinationQueue{},
|
queues: map[gomatrixserverlib.ServerName]*destinationQueue{},
|
||||||
}
|
}
|
||||||
for _, identity := range signing {
|
for _, identity := range signing {
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,10 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/matrix-org/dendrite/internal/caching"
|
||||||
|
"github.com/matrix-org/dendrite/internal/sqlutil"
|
||||||
|
"github.com/matrix-org/dendrite/test/testrig"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib/fclient"
|
||||||
"go.uber.org/atomic"
|
"go.uber.org/atomic"
|
||||||
"gotest.tools/v3/poll"
|
"gotest.tools/v3/poll"
|
||||||
|
|
||||||
|
|
@ -34,31 +38,29 @@ import (
|
||||||
"github.com/matrix-org/dendrite/setup/config"
|
"github.com/matrix-org/dendrite/setup/config"
|
||||||
"github.com/matrix-org/dendrite/setup/process"
|
"github.com/matrix-org/dendrite/setup/process"
|
||||||
"github.com/matrix-org/dendrite/test"
|
"github.com/matrix-org/dendrite/test"
|
||||||
"github.com/matrix-org/dendrite/test/testrig"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func mustCreateFederationDatabase(t *testing.T, dbType test.DBType, realDatabase bool) (storage.Database, *process.ProcessContext, func()) {
|
func mustCreateFederationDatabase(t *testing.T, dbType test.DBType, realDatabase bool) (storage.Database, *process.ProcessContext, func()) {
|
||||||
if realDatabase {
|
if realDatabase {
|
||||||
// Real Database/s
|
// Real Database/s
|
||||||
b, baseClose := testrig.CreateBaseDendrite(t, dbType)
|
cfg, processCtx, close := testrig.CreateConfig(t, dbType)
|
||||||
|
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
|
||||||
|
caches := caching.NewRistrettoCache(128*1024*1024, time.Hour, caching.DisableMetrics)
|
||||||
connStr, dbClose := test.PrepareDBConnectionString(t, dbType)
|
connStr, dbClose := test.PrepareDBConnectionString(t, dbType)
|
||||||
db, err := storage.NewDatabase(b, &config.DatabaseOptions{
|
db, err := storage.NewDatabase(processCtx.Context(), cm, &config.DatabaseOptions{
|
||||||
ConnectionString: config.DataSource(connStr),
|
ConnectionString: config.DataSource(connStr),
|
||||||
}, b.Caches, b.Cfg.Global.IsLocalServerName)
|
}, caches, cfg.Global.IsLocalServerName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("NewDatabase returned %s", err)
|
t.Fatalf("NewDatabase returned %s", err)
|
||||||
}
|
}
|
||||||
return db, b.ProcessContext, func() {
|
return db, processCtx, func() {
|
||||||
|
close()
|
||||||
dbClose()
|
dbClose()
|
||||||
baseClose()
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Fake Database
|
// Fake Database
|
||||||
db := test.NewInMemoryFederationDatabase()
|
db := test.NewInMemoryFederationDatabase()
|
||||||
b := struct {
|
return db, process.NewProcessContext(), func() {}
|
||||||
ProcessContext *process.ProcessContext
|
|
||||||
}{ProcessContext: process.NewProcessContext()}
|
|
||||||
return db, b.ProcessContext, func() {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -79,24 +81,24 @@ type stubFederationClient struct {
|
||||||
txRelayCount atomic.Uint32
|
txRelayCount atomic.Uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *stubFederationClient) SendTransaction(ctx context.Context, t gomatrixserverlib.Transaction) (res gomatrixserverlib.RespSend, err error) {
|
func (f *stubFederationClient) SendTransaction(ctx context.Context, t gomatrixserverlib.Transaction) (res fclient.RespSend, err error) {
|
||||||
var result error
|
var result error
|
||||||
if !f.shouldTxSucceed {
|
if !f.shouldTxSucceed {
|
||||||
result = fmt.Errorf("transaction failed")
|
result = fmt.Errorf("transaction failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
f.txCount.Add(1)
|
f.txCount.Add(1)
|
||||||
return gomatrixserverlib.RespSend{}, result
|
return fclient.RespSend{}, result
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *stubFederationClient) P2PSendTransactionToRelay(ctx context.Context, u gomatrixserverlib.UserID, t gomatrixserverlib.Transaction, forwardingServer gomatrixserverlib.ServerName) (res gomatrixserverlib.EmptyResp, err error) {
|
func (f *stubFederationClient) P2PSendTransactionToRelay(ctx context.Context, u gomatrixserverlib.UserID, t gomatrixserverlib.Transaction, forwardingServer gomatrixserverlib.ServerName) (res fclient.EmptyResp, err error) {
|
||||||
var result error
|
var result error
|
||||||
if !f.shouldTxRelaySucceed {
|
if !f.shouldTxRelaySucceed {
|
||||||
result = fmt.Errorf("relay transaction failed")
|
result = fmt.Errorf("relay transaction failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
f.txRelayCount.Add(1)
|
f.txRelayCount.Add(1)
|
||||||
return gomatrixserverlib.EmptyResp{}, result
|
return fclient.EmptyResp{}, result
|
||||||
}
|
}
|
||||||
|
|
||||||
func mustCreatePDU(t *testing.T) *gomatrixserverlib.HeaderedEvent {
|
func mustCreatePDU(t *testing.T) *gomatrixserverlib.HeaderedEvent {
|
||||||
|
|
@ -126,7 +128,7 @@ func testSetup(failuresUntilBlacklist uint32, failuresUntilAssumedOffline uint32
|
||||||
rs := &stubFederationRoomServerAPI{}
|
rs := &stubFederationRoomServerAPI{}
|
||||||
|
|
||||||
stats := statistics.NewStatistics(db, failuresUntilBlacklist, failuresUntilAssumedOffline)
|
stats := statistics.NewStatistics(db, failuresUntilBlacklist, failuresUntilAssumedOffline)
|
||||||
signingInfo := []*gomatrixserverlib.SigningIdentity{
|
signingInfo := []*fclient.SigningIdentity{
|
||||||
{
|
{
|
||||||
KeyID: "ed21019:auto",
|
KeyID: "ed21019:auto",
|
||||||
PrivateKey: test.PrivateKeyA,
|
PrivateKey: test.PrivateKeyA,
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ import (
|
||||||
"github.com/matrix-org/dendrite/clientapi/jsonerror"
|
"github.com/matrix-org/dendrite/clientapi/jsonerror"
|
||||||
"github.com/matrix-org/dendrite/userapi/api"
|
"github.com/matrix-org/dendrite/userapi/api"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib/fclient"
|
||||||
"github.com/matrix-org/util"
|
"github.com/matrix-org/util"
|
||||||
"github.com/tidwall/gjson"
|
"github.com/tidwall/gjson"
|
||||||
)
|
)
|
||||||
|
|
@ -53,10 +54,10 @@ func GetUserDevices(
|
||||||
return jsonerror.InternalAPIError(req.Context(), err)
|
return jsonerror.InternalAPIError(req.Context(), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
response := gomatrixserverlib.RespUserDevices{
|
response := fclient.RespUserDevices{
|
||||||
UserID: userID,
|
UserID: userID,
|
||||||
StreamID: res.StreamID,
|
StreamID: res.StreamID,
|
||||||
Devices: []gomatrixserverlib.RespUserDevice{},
|
Devices: []fclient.RespUserDevice{},
|
||||||
}
|
}
|
||||||
|
|
||||||
if masterKey, ok := sigRes.MasterKeys[userID]; ok {
|
if masterKey, ok := sigRes.MasterKeys[userID]; ok {
|
||||||
|
|
@ -67,7 +68,7 @@ func GetUserDevices(
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, dev := range res.Devices {
|
for _, dev := range res.Devices {
|
||||||
var key gomatrixserverlib.RespUserDeviceKeys
|
var key fclient.RespUserDeviceKeys
|
||||||
err := json.Unmarshal(dev.DeviceKeys.KeyJSON, &key)
|
err := json.Unmarshal(dev.DeviceKeys.KeyJSON, &key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
util.GetLogger(req.Context()).WithError(err).Warnf("malformed device key: %s", string(dev.DeviceKeys.KeyJSON))
|
util.GetLogger(req.Context()).WithError(err).Warnf("malformed device key: %s", string(dev.DeviceKeys.KeyJSON))
|
||||||
|
|
@ -79,7 +80,7 @@ func GetUserDevices(
|
||||||
displayName = gjson.GetBytes(dev.DeviceKeys.KeyJSON, "unsigned.device_display_name").Str
|
displayName = gjson.GetBytes(dev.DeviceKeys.KeyJSON, "unsigned.device_display_name").Str
|
||||||
}
|
}
|
||||||
|
|
||||||
device := gomatrixserverlib.RespUserDevice{
|
device := fclient.RespUserDevice{
|
||||||
DeviceID: dev.DeviceID,
|
DeviceID: dev.DeviceID,
|
||||||
DisplayName: displayName,
|
DisplayName: displayName,
|
||||||
Keys: key,
|
Keys: key,
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ import (
|
||||||
"github.com/matrix-org/dendrite/clientapi/jsonerror"
|
"github.com/matrix-org/dendrite/clientapi/jsonerror"
|
||||||
"github.com/matrix-org/dendrite/roomserver/api"
|
"github.com/matrix-org/dendrite/roomserver/api"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib/fclient"
|
||||||
"github.com/matrix-org/util"
|
"github.com/matrix-org/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -70,7 +71,7 @@ func GetEventAuth(
|
||||||
|
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusOK,
|
Code: http.StatusOK,
|
||||||
JSON: gomatrixserverlib.RespEventAuth{
|
JSON: fclient.RespEventAuth{
|
||||||
AuthEvents: gomatrixserverlib.NewEventJSONsFromHeaderedEvents(response.AuthChainEvents),
|
AuthEvents: gomatrixserverlib.NewEventJSONsFromHeaderedEvents(response.AuthChainEvents),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ import (
|
||||||
roomserverVersion "github.com/matrix-org/dendrite/roomserver/version"
|
roomserverVersion "github.com/matrix-org/dendrite/roomserver/version"
|
||||||
"github.com/matrix-org/dendrite/setup/config"
|
"github.com/matrix-org/dendrite/setup/config"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib/fclient"
|
||||||
"github.com/matrix-org/util"
|
"github.com/matrix-org/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -218,12 +219,12 @@ func processInvite(
|
||||||
if isInviteV2 {
|
if isInviteV2 {
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusOK,
|
Code: http.StatusOK,
|
||||||
JSON: gomatrixserverlib.RespInviteV2{Event: signedEvent.JSON()},
|
JSON: fclient.RespInviteV2{Event: signedEvent.JSON()},
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusOK,
|
Code: http.StatusOK,
|
||||||
JSON: gomatrixserverlib.RespInvite{Event: signedEvent.JSON()},
|
JSON: fclient.RespInvite{Event: signedEvent.JSON()},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib/fclient"
|
||||||
"github.com/matrix-org/util"
|
"github.com/matrix-org/util"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
|
@ -433,7 +434,7 @@ func SendJoin(
|
||||||
// https://matrix.org/docs/spec/server_server/latest#put-matrix-federation-v1-send-join-roomid-eventid
|
// https://matrix.org/docs/spec/server_server/latest#put-matrix-federation-v1-send-join-roomid-eventid
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusOK,
|
Code: http.StatusOK,
|
||||||
JSON: gomatrixserverlib.RespSendJoin{
|
JSON: fclient.RespSendJoin{
|
||||||
StateEvents: gomatrixserverlib.NewEventJSONsFromHeaderedEvents(stateAndAuthChainResponse.StateEvents),
|
StateEvents: gomatrixserverlib.NewEventJSONsFromHeaderedEvents(stateAndAuthChainResponse.StateEvents),
|
||||||
AuthEvents: gomatrixserverlib.NewEventJSONsFromHeaderedEvents(stateAndAuthChainResponse.AuthChainEvents),
|
AuthEvents: gomatrixserverlib.NewEventJSONsFromHeaderedEvents(stateAndAuthChainResponse.AuthChainEvents),
|
||||||
Origin: cfg.Matrix.ServerName,
|
Origin: cfg.Matrix.ServerName,
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ import (
|
||||||
"github.com/matrix-org/dendrite/setup/config"
|
"github.com/matrix-org/dendrite/setup/config"
|
||||||
"github.com/matrix-org/dendrite/userapi/api"
|
"github.com/matrix-org/dendrite/userapi/api"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib/fclient"
|
||||||
"github.com/matrix-org/util"
|
"github.com/matrix-org/util"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"golang.org/x/crypto/ed25519"
|
"golang.org/x/crypto/ed25519"
|
||||||
|
|
@ -144,7 +145,7 @@ func LocalKeys(cfg *config.FederationAPI, serverName gomatrixserverlib.ServerNam
|
||||||
|
|
||||||
func localKeys(cfg *config.FederationAPI, serverName gomatrixserverlib.ServerName) (*gomatrixserverlib.ServerKeys, error) {
|
func localKeys(cfg *config.FederationAPI, serverName gomatrixserverlib.ServerName) (*gomatrixserverlib.ServerKeys, error) {
|
||||||
var keys gomatrixserverlib.ServerKeys
|
var keys gomatrixserverlib.ServerKeys
|
||||||
var identity *gomatrixserverlib.SigningIdentity
|
var identity *fclient.SigningIdentity
|
||||||
var err error
|
var err error
|
||||||
if virtualHost := cfg.Matrix.VirtualHostForHTTPHost(serverName); virtualHost == nil {
|
if virtualHost := cfg.Matrix.VirtualHostForHTTPHost(serverName); virtualHost == nil {
|
||||||
if identity, err = cfg.Matrix.SigningIdentityFor(cfg.Matrix.ServerName); err != nil {
|
if identity, err = cfg.Matrix.SigningIdentityFor(cfg.Matrix.ServerName); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ import (
|
||||||
"github.com/matrix-org/dendrite/clientapi/jsonerror"
|
"github.com/matrix-org/dendrite/clientapi/jsonerror"
|
||||||
"github.com/matrix-org/dendrite/roomserver/api"
|
"github.com/matrix-org/dendrite/roomserver/api"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib/fclient"
|
||||||
"github.com/matrix-org/util"
|
"github.com/matrix-org/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -67,7 +68,7 @@ func GetMissingEvents(
|
||||||
|
|
||||||
eventsResponse.Events = filterEvents(eventsResponse.Events, roomID)
|
eventsResponse.Events = filterEvents(eventsResponse.Events, roomID)
|
||||||
|
|
||||||
resp := gomatrixserverlib.RespMissingEvents{
|
resp := fclient.RespMissingEvents{
|
||||||
Events: gomatrixserverlib.NewEventJSONsFromHeaderedEvents(eventsResponse.Events),
|
Events: gomatrixserverlib.NewEventJSONsFromHeaderedEvents(eventsResponse.Events),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"github.com/matrix-org/dendrite/roomserver/api"
|
"github.com/matrix-org/dendrite/roomserver/api"
|
||||||
"github.com/matrix-org/dendrite/setup/config"
|
"github.com/matrix-org/dendrite/setup/config"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib/fclient"
|
||||||
"github.com/matrix-org/util"
|
"github.com/matrix-org/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -87,7 +88,7 @@ func Peek(
|
||||||
return util.JSONResponse{Code: http.StatusNotFound, JSON: nil}
|
return util.JSONResponse{Code: http.StatusNotFound, JSON: nil}
|
||||||
}
|
}
|
||||||
|
|
||||||
respPeek := gomatrixserverlib.RespPeek{
|
respPeek := fclient.RespPeek{
|
||||||
StateEvents: gomatrixserverlib.NewEventJSONsFromHeaderedEvents(response.StateEvents),
|
StateEvents: gomatrixserverlib.NewEventJSONsFromHeaderedEvents(response.StateEvents),
|
||||||
AuthEvents: gomatrixserverlib.NewEventJSONsFromHeaderedEvents(response.AuthChainEvents),
|
AuthEvents: gomatrixserverlib.NewEventJSONsFromHeaderedEvents(response.AuthChainEvents),
|
||||||
RoomVersion: response.RoomVersion,
|
RoomVersion: response.RoomVersion,
|
||||||
|
|
|
||||||
|
|
@ -50,10 +50,7 @@ func GetProfile(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var profileRes userapi.QueryProfileResponse
|
profile, err := userAPI.QueryProfile(httpReq.Context(), userID)
|
||||||
err = userAPI.QueryProfile(httpReq.Context(), &userapi.QueryProfileRequest{
|
|
||||||
UserID: userID,
|
|
||||||
}, &profileRes)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
util.GetLogger(httpReq.Context()).WithError(err).Error("userAPI.QueryProfile failed")
|
util.GetLogger(httpReq.Context()).WithError(err).Error("userAPI.QueryProfile failed")
|
||||||
return jsonerror.InternalServerError()
|
return jsonerror.InternalServerError()
|
||||||
|
|
@ -65,21 +62,21 @@ func GetProfile(
|
||||||
if field != "" {
|
if field != "" {
|
||||||
switch field {
|
switch field {
|
||||||
case "displayname":
|
case "displayname":
|
||||||
res = eventutil.DisplayName{
|
res = eventutil.UserProfile{
|
||||||
DisplayName: profileRes.DisplayName,
|
DisplayName: profile.DisplayName,
|
||||||
}
|
}
|
||||||
case "avatar_url":
|
case "avatar_url":
|
||||||
res = eventutil.AvatarURL{
|
res = eventutil.UserProfile{
|
||||||
AvatarURL: profileRes.AvatarURL,
|
AvatarURL: profile.AvatarURL,
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
code = http.StatusBadRequest
|
code = http.StatusBadRequest
|
||||||
res = jsonerror.InvalidArgumentValue("The request body did not contain an allowed value of argument 'field'. Allowed values are either: 'avatar_url', 'displayname'.")
|
res = jsonerror.InvalidArgumentValue("The request body did not contain an allowed value of argument 'field'. Allowed values are either: 'avatar_url', 'displayname'.")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
res = eventutil.ProfileResponse{
|
res = eventutil.UserProfile{
|
||||||
AvatarURL: profileRes.AvatarURL,
|
AvatarURL: profile.AvatarURL,
|
||||||
DisplayName: profileRes.DisplayName,
|
DisplayName: profile.DisplayName,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,11 +23,15 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
|
||||||
"github.com/matrix-org/dendrite/cmd/dendrite-demo-yggdrasil/signing"
|
"github.com/matrix-org/dendrite/cmd/dendrite-demo-yggdrasil/signing"
|
||||||
fedAPI "github.com/matrix-org/dendrite/federationapi"
|
fedAPI "github.com/matrix-org/dendrite/federationapi"
|
||||||
fedInternal "github.com/matrix-org/dendrite/federationapi/internal"
|
fedInternal "github.com/matrix-org/dendrite/federationapi/internal"
|
||||||
"github.com/matrix-org/dendrite/federationapi/routing"
|
"github.com/matrix-org/dendrite/federationapi/routing"
|
||||||
|
"github.com/matrix-org/dendrite/internal/caching"
|
||||||
"github.com/matrix-org/dendrite/internal/httputil"
|
"github.com/matrix-org/dendrite/internal/httputil"
|
||||||
|
"github.com/matrix-org/dendrite/internal/sqlutil"
|
||||||
|
"github.com/matrix-org/dendrite/setup/jetstream"
|
||||||
"github.com/matrix-org/dendrite/test"
|
"github.com/matrix-org/dendrite/test"
|
||||||
"github.com/matrix-org/dendrite/test/testrig"
|
"github.com/matrix-org/dendrite/test/testrig"
|
||||||
userAPI "github.com/matrix-org/dendrite/userapi/api"
|
userAPI "github.com/matrix-org/dendrite/userapi/api"
|
||||||
|
|
@ -40,29 +44,32 @@ type fakeUserAPI struct {
|
||||||
userAPI.FederationUserAPI
|
userAPI.FederationUserAPI
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *fakeUserAPI) QueryProfile(ctx context.Context, req *userAPI.QueryProfileRequest, res *userAPI.QueryProfileResponse) error {
|
func (u *fakeUserAPI) QueryProfile(ctx context.Context, userID string) (*authtypes.Profile, error) {
|
||||||
return nil
|
return &authtypes.Profile{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHandleQueryProfile(t *testing.T) {
|
func TestHandleQueryProfile(t *testing.T) {
|
||||||
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
|
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
|
||||||
base, close := testrig.CreateBaseDendrite(t, dbType)
|
cfg, processCtx, close := testrig.CreateConfig(t, dbType)
|
||||||
|
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
|
||||||
|
routers := httputil.NewRouters()
|
||||||
defer close()
|
defer close()
|
||||||
|
|
||||||
fedMux := mux.NewRouter().SkipClean(true).PathPrefix(httputil.PublicFederationPathPrefix).Subrouter().UseEncodedPath()
|
fedMux := mux.NewRouter().SkipClean(true).PathPrefix(httputil.PublicFederationPathPrefix).Subrouter().UseEncodedPath()
|
||||||
base.PublicFederationAPIMux = fedMux
|
natsInstance := jetstream.NATSInstance{}
|
||||||
base.Cfg.FederationAPI.Matrix.SigningIdentity.ServerName = testOrigin
|
routers.Federation = fedMux
|
||||||
base.Cfg.FederationAPI.Matrix.Metrics.Enabled = false
|
cfg.FederationAPI.Matrix.SigningIdentity.ServerName = testOrigin
|
||||||
|
cfg.FederationAPI.Matrix.Metrics.Enabled = false
|
||||||
fedClient := fakeFedClient{}
|
fedClient := fakeFedClient{}
|
||||||
serverKeyAPI := &signing.YggdrasilKeys{}
|
serverKeyAPI := &signing.YggdrasilKeys{}
|
||||||
keyRing := serverKeyAPI.KeyRing()
|
keyRing := serverKeyAPI.KeyRing()
|
||||||
fedapi := fedAPI.NewInternalAPI(base, &fedClient, nil, nil, keyRing, true)
|
fedapi := fedAPI.NewInternalAPI(processCtx, cfg, cm, &natsInstance, &fedClient, nil, nil, keyRing, true)
|
||||||
userapi := fakeUserAPI{}
|
userapi := fakeUserAPI{}
|
||||||
r, ok := fedapi.(*fedInternal.FederationInternalAPI)
|
r, ok := fedapi.(*fedInternal.FederationInternalAPI)
|
||||||
if !ok {
|
if !ok {
|
||||||
panic("This is a programming error.")
|
panic("This is a programming error.")
|
||||||
}
|
}
|
||||||
routing.Setup(base, nil, r, keyRing, &fedClient, &userapi, &base.Cfg.MSCs, nil, nil)
|
routing.Setup(routers, cfg, nil, r, keyRing, &fedClient, &userapi, &cfg.MSCs, nil, nil, caching.DisableMetrics)
|
||||||
|
|
||||||
handler := fedMux.Get(routing.QueryProfileRouteName).GetHandler().ServeHTTP
|
handler := fedMux.Get(routing.QueryProfileRouteName).GetHandler().ServeHTTP
|
||||||
_, sk, _ := ed25519.GenerateKey(nil)
|
_, sk, _ := ed25519.GenerateKey(nil)
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib/fclient"
|
||||||
"github.com/matrix-org/util"
|
"github.com/matrix-org/util"
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/clientapi/httputil"
|
"github.com/matrix-org/dendrite/clientapi/httputil"
|
||||||
|
|
@ -48,9 +49,9 @@ func GetPostPublicRooms(req *http.Request, rsAPI roomserverAPI.FederationRoomser
|
||||||
|
|
||||||
func publicRooms(
|
func publicRooms(
|
||||||
ctx context.Context, request PublicRoomReq, rsAPI roomserverAPI.FederationRoomserverAPI,
|
ctx context.Context, request PublicRoomReq, rsAPI roomserverAPI.FederationRoomserverAPI,
|
||||||
) (*gomatrixserverlib.RespPublicRooms, error) {
|
) (*fclient.RespPublicRooms, error) {
|
||||||
|
|
||||||
var response gomatrixserverlib.RespPublicRooms
|
var response fclient.RespPublicRooms
|
||||||
var limit int16
|
var limit int16
|
||||||
var offset int64
|
var offset int64
|
||||||
limit = request.Limit
|
limit = request.Limit
|
||||||
|
|
@ -122,7 +123,7 @@ func fillPublicRoomsReq(httpReq *http.Request, request *PublicRoomReq) *util.JSO
|
||||||
}
|
}
|
||||||
|
|
||||||
// due to lots of switches
|
// due to lots of switches
|
||||||
func fillInRooms(ctx context.Context, roomIDs []string, rsAPI roomserverAPI.FederationRoomserverAPI) ([]gomatrixserverlib.PublicRoom, error) {
|
func fillInRooms(ctx context.Context, roomIDs []string, rsAPI roomserverAPI.FederationRoomserverAPI) ([]fclient.PublicRoom, error) {
|
||||||
avatarTuple := gomatrixserverlib.StateKeyTuple{EventType: "m.room.avatar", StateKey: ""}
|
avatarTuple := gomatrixserverlib.StateKeyTuple{EventType: "m.room.avatar", StateKey: ""}
|
||||||
nameTuple := gomatrixserverlib.StateKeyTuple{EventType: "m.room.name", StateKey: ""}
|
nameTuple := gomatrixserverlib.StateKeyTuple{EventType: "m.room.name", StateKey: ""}
|
||||||
canonicalTuple := gomatrixserverlib.StateKeyTuple{EventType: gomatrixserverlib.MRoomCanonicalAlias, StateKey: ""}
|
canonicalTuple := gomatrixserverlib.StateKeyTuple{EventType: gomatrixserverlib.MRoomCanonicalAlias, StateKey: ""}
|
||||||
|
|
@ -144,10 +145,10 @@ func fillInRooms(ctx context.Context, roomIDs []string, rsAPI roomserverAPI.Fede
|
||||||
util.GetLogger(ctx).WithError(err).Error("QueryBulkStateContent failed")
|
util.GetLogger(ctx).WithError(err).Error("QueryBulkStateContent failed")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
chunk := make([]gomatrixserverlib.PublicRoom, len(roomIDs))
|
chunk := make([]fclient.PublicRoom, len(roomIDs))
|
||||||
i := 0
|
i := 0
|
||||||
for roomID, data := range stateRes.Rooms {
|
for roomID, data := range stateRes.Rooms {
|
||||||
pub := gomatrixserverlib.PublicRoom{
|
pub := fclient.PublicRoom{
|
||||||
RoomID: roomID,
|
RoomID: roomID,
|
||||||
}
|
}
|
||||||
joinCount := 0
|
joinCount := 0
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import (
|
||||||
"github.com/matrix-org/dendrite/setup/config"
|
"github.com/matrix-org/dendrite/setup/config"
|
||||||
"github.com/matrix-org/gomatrix"
|
"github.com/matrix-org/gomatrix"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib/fclient"
|
||||||
"github.com/matrix-org/util"
|
"github.com/matrix-org/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -50,7 +51,7 @@ func RoomAliasToID(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var resp gomatrixserverlib.RespDirectory
|
var resp fclient.RespDirectory
|
||||||
|
|
||||||
if domain == cfg.Matrix.ServerName {
|
if domain == cfg.Matrix.ServerName {
|
||||||
queryReq := &roomserverAPI.GetRoomIDForAliasRequest{
|
queryReq := &roomserverAPI.GetRoomIDForAliasRequest{
|
||||||
|
|
@ -71,7 +72,7 @@ func RoomAliasToID(
|
||||||
return jsonerror.InternalServerError()
|
return jsonerror.InternalServerError()
|
||||||
}
|
}
|
||||||
|
|
||||||
resp = gomatrixserverlib.RespDirectory{
|
resp = fclient.RespDirectory{
|
||||||
RoomID: queryRes.RoomID,
|
RoomID: queryRes.RoomID,
|
||||||
Servers: serverQueryRes.ServerNames,
|
Servers: serverQueryRes.ServerNames,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,10 +28,14 @@ import (
|
||||||
fedclient "github.com/matrix-org/dendrite/federationapi/api"
|
fedclient "github.com/matrix-org/dendrite/federationapi/api"
|
||||||
fedInternal "github.com/matrix-org/dendrite/federationapi/internal"
|
fedInternal "github.com/matrix-org/dendrite/federationapi/internal"
|
||||||
"github.com/matrix-org/dendrite/federationapi/routing"
|
"github.com/matrix-org/dendrite/federationapi/routing"
|
||||||
|
"github.com/matrix-org/dendrite/internal/caching"
|
||||||
"github.com/matrix-org/dendrite/internal/httputil"
|
"github.com/matrix-org/dendrite/internal/httputil"
|
||||||
|
"github.com/matrix-org/dendrite/internal/sqlutil"
|
||||||
|
"github.com/matrix-org/dendrite/setup/jetstream"
|
||||||
"github.com/matrix-org/dendrite/test"
|
"github.com/matrix-org/dendrite/test"
|
||||||
"github.com/matrix-org/dendrite/test/testrig"
|
"github.com/matrix-org/dendrite/test/testrig"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib/fclient"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"golang.org/x/crypto/ed25519"
|
"golang.org/x/crypto/ed25519"
|
||||||
)
|
)
|
||||||
|
|
@ -40,29 +44,32 @@ type fakeFedClient struct {
|
||||||
fedclient.FederationClient
|
fedclient.FederationClient
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *fakeFedClient) LookupRoomAlias(ctx context.Context, origin, s gomatrixserverlib.ServerName, roomAlias string) (res gomatrixserverlib.RespDirectory, err error) {
|
func (f *fakeFedClient) LookupRoomAlias(ctx context.Context, origin, s gomatrixserverlib.ServerName, roomAlias string) (res fclient.RespDirectory, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHandleQueryDirectory(t *testing.T) {
|
func TestHandleQueryDirectory(t *testing.T) {
|
||||||
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
|
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
|
||||||
base, close := testrig.CreateBaseDendrite(t, dbType)
|
cfg, processCtx, close := testrig.CreateConfig(t, dbType)
|
||||||
|
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
|
||||||
|
routers := httputil.NewRouters()
|
||||||
defer close()
|
defer close()
|
||||||
|
|
||||||
fedMux := mux.NewRouter().SkipClean(true).PathPrefix(httputil.PublicFederationPathPrefix).Subrouter().UseEncodedPath()
|
fedMux := mux.NewRouter().SkipClean(true).PathPrefix(httputil.PublicFederationPathPrefix).Subrouter().UseEncodedPath()
|
||||||
base.PublicFederationAPIMux = fedMux
|
natsInstance := jetstream.NATSInstance{}
|
||||||
base.Cfg.FederationAPI.Matrix.SigningIdentity.ServerName = testOrigin
|
routers.Federation = fedMux
|
||||||
base.Cfg.FederationAPI.Matrix.Metrics.Enabled = false
|
cfg.FederationAPI.Matrix.SigningIdentity.ServerName = testOrigin
|
||||||
|
cfg.FederationAPI.Matrix.Metrics.Enabled = false
|
||||||
fedClient := fakeFedClient{}
|
fedClient := fakeFedClient{}
|
||||||
serverKeyAPI := &signing.YggdrasilKeys{}
|
serverKeyAPI := &signing.YggdrasilKeys{}
|
||||||
keyRing := serverKeyAPI.KeyRing()
|
keyRing := serverKeyAPI.KeyRing()
|
||||||
fedapi := fedAPI.NewInternalAPI(base, &fedClient, nil, nil, keyRing, true)
|
fedapi := fedAPI.NewInternalAPI(processCtx, cfg, cm, &natsInstance, &fedClient, nil, nil, keyRing, true)
|
||||||
userapi := fakeUserAPI{}
|
userapi := fakeUserAPI{}
|
||||||
r, ok := fedapi.(*fedInternal.FederationInternalAPI)
|
r, ok := fedapi.(*fedInternal.FederationInternalAPI)
|
||||||
if !ok {
|
if !ok {
|
||||||
panic("This is a programming error.")
|
panic("This is a programming error.")
|
||||||
}
|
}
|
||||||
routing.Setup(base, nil, r, keyRing, &fedClient, &userapi, &base.Cfg.MSCs, nil, nil)
|
routing.Setup(routers, cfg, nil, r, keyRing, &fedClient, &userapi, &cfg.MSCs, nil, nil, caching.DisableMetrics)
|
||||||
|
|
||||||
handler := fedMux.Get(routing.QueryDirectoryRouteName).GetHandler().ServeHTTP
|
handler := fedMux.Get(routing.QueryDirectoryRouteName).GetHandler().ServeHTTP
|
||||||
_, sk, _ := ed25519.GenerateKey(nil)
|
_, sk, _ := ed25519.GenerateKey(nil)
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,6 @@ import (
|
||||||
"github.com/matrix-org/dendrite/internal/httputil"
|
"github.com/matrix-org/dendrite/internal/httputil"
|
||||||
"github.com/matrix-org/dendrite/roomserver/api"
|
"github.com/matrix-org/dendrite/roomserver/api"
|
||||||
roomserverAPI "github.com/matrix-org/dendrite/roomserver/api"
|
roomserverAPI "github.com/matrix-org/dendrite/roomserver/api"
|
||||||
"github.com/matrix-org/dendrite/setup/base"
|
|
||||||
"github.com/matrix-org/dendrite/setup/config"
|
"github.com/matrix-org/dendrite/setup/config"
|
||||||
userapi "github.com/matrix-org/dendrite/userapi/api"
|
userapi "github.com/matrix-org/dendrite/userapi/api"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
|
@ -55,7 +54,8 @@ const (
|
||||||
// applied:
|
// applied:
|
||||||
// nolint: gocyclo
|
// nolint: gocyclo
|
||||||
func Setup(
|
func Setup(
|
||||||
base *base.BaseDendrite,
|
routers httputil.Routers,
|
||||||
|
dendriteCfg *config.Dendrite,
|
||||||
rsAPI roomserverAPI.FederationRoomserverAPI,
|
rsAPI roomserverAPI.FederationRoomserverAPI,
|
||||||
fsAPI *fedInternal.FederationInternalAPI,
|
fsAPI *fedInternal.FederationInternalAPI,
|
||||||
keys gomatrixserverlib.JSONVerifier,
|
keys gomatrixserverlib.JSONVerifier,
|
||||||
|
|
@ -63,14 +63,14 @@ func Setup(
|
||||||
userAPI userapi.FederationUserAPI,
|
userAPI userapi.FederationUserAPI,
|
||||||
mscCfg *config.MSCs,
|
mscCfg *config.MSCs,
|
||||||
servers federationAPI.ServersInRoomProvider,
|
servers federationAPI.ServersInRoomProvider,
|
||||||
producer *producers.SyncAPIProducer,
|
producer *producers.SyncAPIProducer, enableMetrics bool,
|
||||||
) {
|
) {
|
||||||
fedMux := base.PublicFederationAPIMux
|
fedMux := routers.Federation
|
||||||
keyMux := base.PublicKeyAPIMux
|
keyMux := routers.Keys
|
||||||
wkMux := base.PublicWellKnownAPIMux
|
wkMux := routers.WellKnown
|
||||||
cfg := &base.Cfg.FederationAPI
|
cfg := &dendriteCfg.FederationAPI
|
||||||
|
|
||||||
if base.EnableMetrics {
|
if enableMetrics {
|
||||||
prometheus.MustRegister(
|
prometheus.MustRegister(
|
||||||
internal.PDUCountTotal, internal.EDUCountTotal,
|
internal.PDUCountTotal, internal.EDUCountTotal,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,10 @@ import (
|
||||||
fedAPI "github.com/matrix-org/dendrite/federationapi"
|
fedAPI "github.com/matrix-org/dendrite/federationapi"
|
||||||
fedInternal "github.com/matrix-org/dendrite/federationapi/internal"
|
fedInternal "github.com/matrix-org/dendrite/federationapi/internal"
|
||||||
"github.com/matrix-org/dendrite/federationapi/routing"
|
"github.com/matrix-org/dendrite/federationapi/routing"
|
||||||
|
"github.com/matrix-org/dendrite/internal/caching"
|
||||||
"github.com/matrix-org/dendrite/internal/httputil"
|
"github.com/matrix-org/dendrite/internal/httputil"
|
||||||
|
"github.com/matrix-org/dendrite/internal/sqlutil"
|
||||||
|
"github.com/matrix-org/dendrite/setup/jetstream"
|
||||||
"github.com/matrix-org/dendrite/test"
|
"github.com/matrix-org/dendrite/test"
|
||||||
"github.com/matrix-org/dendrite/test/testrig"
|
"github.com/matrix-org/dendrite/test/testrig"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
|
@ -44,21 +47,24 @@ type sendContent struct {
|
||||||
|
|
||||||
func TestHandleSend(t *testing.T) {
|
func TestHandleSend(t *testing.T) {
|
||||||
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
|
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
|
||||||
base, close := testrig.CreateBaseDendrite(t, dbType)
|
cfg, processCtx, close := testrig.CreateConfig(t, dbType)
|
||||||
|
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
|
||||||
|
routers := httputil.NewRouters()
|
||||||
defer close()
|
defer close()
|
||||||
|
|
||||||
fedMux := mux.NewRouter().SkipClean(true).PathPrefix(httputil.PublicFederationPathPrefix).Subrouter().UseEncodedPath()
|
fedMux := mux.NewRouter().SkipClean(true).PathPrefix(httputil.PublicFederationPathPrefix).Subrouter().UseEncodedPath()
|
||||||
base.PublicFederationAPIMux = fedMux
|
natsInstance := jetstream.NATSInstance{}
|
||||||
base.Cfg.FederationAPI.Matrix.SigningIdentity.ServerName = testOrigin
|
routers.Federation = fedMux
|
||||||
base.Cfg.FederationAPI.Matrix.Metrics.Enabled = false
|
cfg.FederationAPI.Matrix.SigningIdentity.ServerName = testOrigin
|
||||||
fedapi := fedAPI.NewInternalAPI(base, nil, nil, nil, nil, true)
|
cfg.FederationAPI.Matrix.Metrics.Enabled = false
|
||||||
|
fedapi := fedAPI.NewInternalAPI(processCtx, cfg, cm, &natsInstance, nil, nil, nil, nil, true)
|
||||||
serverKeyAPI := &signing.YggdrasilKeys{}
|
serverKeyAPI := &signing.YggdrasilKeys{}
|
||||||
keyRing := serverKeyAPI.KeyRing()
|
keyRing := serverKeyAPI.KeyRing()
|
||||||
r, ok := fedapi.(*fedInternal.FederationInternalAPI)
|
r, ok := fedapi.(*fedInternal.FederationInternalAPI)
|
||||||
if !ok {
|
if !ok {
|
||||||
panic("This is a programming error.")
|
panic("This is a programming error.")
|
||||||
}
|
}
|
||||||
routing.Setup(base, nil, r, keyRing, nil, nil, &base.Cfg.MSCs, nil, nil)
|
routing.Setup(routers, cfg, nil, r, keyRing, nil, nil, &cfg.MSCs, nil, nil, caching.DisableMetrics)
|
||||||
|
|
||||||
handler := fedMux.Get(routing.SendRouteName).GetHandler().ServeHTTP
|
handler := fedMux.Get(routing.SendRouteName).GetHandler().ServeHTTP
|
||||||
_, sk, _ := ed25519.GenerateKey(nil)
|
_, sk, _ := ed25519.GenerateKey(nil)
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"github.com/matrix-org/dendrite/clientapi/jsonerror"
|
"github.com/matrix-org/dendrite/clientapi/jsonerror"
|
||||||
"github.com/matrix-org/dendrite/roomserver/api"
|
"github.com/matrix-org/dendrite/roomserver/api"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib/fclient"
|
||||||
"github.com/matrix-org/util"
|
"github.com/matrix-org/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -40,7 +41,7 @@ func GetState(
|
||||||
return *err
|
return *err
|
||||||
}
|
}
|
||||||
|
|
||||||
return util.JSONResponse{Code: http.StatusOK, JSON: &gomatrixserverlib.RespState{
|
return util.JSONResponse{Code: http.StatusOK, JSON: &fclient.RespState{
|
||||||
AuthEvents: gomatrixserverlib.NewEventJSONsFromHeaderedEvents(authChain),
|
AuthEvents: gomatrixserverlib.NewEventJSONsFromHeaderedEvents(authChain),
|
||||||
StateEvents: gomatrixserverlib.NewEventJSONsFromHeaderedEvents(stateEvents),
|
StateEvents: gomatrixserverlib.NewEventJSONsFromHeaderedEvents(stateEvents),
|
||||||
}}
|
}}
|
||||||
|
|
@ -66,7 +67,7 @@ func GetStateIDs(
|
||||||
stateEventIDs := getIDsFromEvent(stateEvents)
|
stateEventIDs := getIDsFromEvent(stateEvents)
|
||||||
authEventIDs := getIDsFromEvent(authEvents)
|
authEventIDs := getIDsFromEvent(authEvents)
|
||||||
|
|
||||||
return util.JSONResponse{Code: http.StatusOK, JSON: gomatrixserverlib.RespStateIDs{
|
return util.JSONResponse{Code: http.StatusOK, JSON: fclient.RespStateIDs{
|
||||||
StateEventIDs: stateEventIDs,
|
StateEventIDs: stateEventIDs,
|
||||||
AuthEventIDs: authEventIDs,
|
AuthEventIDs: authEventIDs,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -256,17 +256,14 @@ func createInviteFrom3PIDInvite(
|
||||||
StateKey: &inv.MXID,
|
StateKey: &inv.MXID,
|
||||||
}
|
}
|
||||||
|
|
||||||
var res userapi.QueryProfileResponse
|
profile, err := userAPI.QueryProfile(ctx, inv.MXID)
|
||||||
err = userAPI.QueryProfile(ctx, &userapi.QueryProfileRequest{
|
|
||||||
UserID: inv.MXID,
|
|
||||||
}, &res)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
content := gomatrixserverlib.MemberContent{
|
content := gomatrixserverlib.MemberContent{
|
||||||
AvatarURL: res.AvatarURL,
|
AvatarURL: profile.AvatarURL,
|
||||||
DisplayName: res.DisplayName,
|
DisplayName: profile.DisplayName,
|
||||||
Membership: gomatrixserverlib.Invite,
|
Membership: gomatrixserverlib.Invite,
|
||||||
ThirdPartyInvite: &gomatrixserverlib.MemberThirdPartyInvite{
|
ThirdPartyInvite: &gomatrixserverlib.MemberThirdPartyInvite{
|
||||||
Signed: inv.Signed,
|
Signed: inv.Signed,
|
||||||
|
|
|
||||||
|
|
@ -60,19 +60,12 @@ func NewPostgresBlacklistTable(db *sql.DB) (s *blacklistStatements, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.insertBlacklistStmt, err = db.Prepare(insertBlacklistSQL); err != nil {
|
return s, sqlutil.StatementList{
|
||||||
return
|
{&s.insertBlacklistStmt, insertBlacklistSQL},
|
||||||
}
|
{&s.selectBlacklistStmt, selectBlacklistSQL},
|
||||||
if s.selectBlacklistStmt, err = db.Prepare(selectBlacklistSQL); err != nil {
|
{&s.deleteBlacklistStmt, deleteBlacklistSQL},
|
||||||
return
|
{&s.deleteAllBlacklistStmt, deleteAllBlacklistSQL},
|
||||||
}
|
}.Prepare(db)
|
||||||
if s.deleteBlacklistStmt, err = db.Prepare(deleteBlacklistSQL); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if s.deleteAllBlacklistStmt, err = db.Prepare(deleteAllBlacklistSQL); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *blacklistStatements) InsertBlacklist(
|
func (s *blacklistStatements) InsertBlacklist(
|
||||||
|
|
|
||||||
|
|
@ -90,28 +90,15 @@ func NewPostgresJoinedHostsTable(db *sql.DB) (s *joinedHostsStatements, err erro
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if s.insertJoinedHostsStmt, err = s.db.Prepare(insertJoinedHostsSQL); err != nil {
|
return s, sqlutil.StatementList{
|
||||||
return
|
{&s.insertJoinedHostsStmt, insertJoinedHostsSQL},
|
||||||
}
|
{&s.deleteJoinedHostsStmt, deleteJoinedHostsSQL},
|
||||||
if s.deleteJoinedHostsStmt, err = s.db.Prepare(deleteJoinedHostsSQL); err != nil {
|
{&s.deleteJoinedHostsForRoomStmt, deleteJoinedHostsForRoomSQL},
|
||||||
return
|
{&s.selectJoinedHostsStmt, selectJoinedHostsSQL},
|
||||||
}
|
{&s.selectAllJoinedHostsStmt, selectAllJoinedHostsSQL},
|
||||||
if s.deleteJoinedHostsForRoomStmt, err = s.db.Prepare(deleteJoinedHostsForRoomSQL); err != nil {
|
{&s.selectJoinedHostsForRoomsStmt, selectJoinedHostsForRoomsSQL},
|
||||||
return
|
{&s.selectJoinedHostsForRoomsExcludingBlacklistedStmt, selectJoinedHostsForRoomsExcludingBlacklistedSQL},
|
||||||
}
|
}.Prepare(db)
|
||||||
if s.selectJoinedHostsStmt, err = s.db.Prepare(selectJoinedHostsSQL); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if s.selectAllJoinedHostsStmt, err = s.db.Prepare(selectAllJoinedHostsSQL); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if s.selectJoinedHostsForRoomsStmt, err = s.db.Prepare(selectJoinedHostsForRoomsSQL); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if s.selectJoinedHostsForRoomsExcludingBlacklistedStmt, err = s.db.Prepare(selectJoinedHostsForRoomsExcludingBlacklistedSQL); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *joinedHostsStatements) InsertJoinedHosts(
|
func (s *joinedHostsStatements) InsertJoinedHosts(
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/federationapi/storage/tables"
|
"github.com/matrix-org/dendrite/federationapi/storage/tables"
|
||||||
|
"github.com/matrix-org/dendrite/internal/sqlutil"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -50,10 +51,9 @@ func NewPostgresNotaryServerKeysTable(db *sql.DB) (s *notaryServerKeysStatements
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.insertServerKeysJSONStmt, err = db.Prepare(insertServerKeysJSONSQL); err != nil {
|
return s, sqlutil.StatementList{
|
||||||
return
|
{&s.insertServerKeysJSONStmt, insertServerKeysJSONSQL},
|
||||||
}
|
}.Prepare(db)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *notaryServerKeysStatements) InsertJSONResponse(
|
func (s *notaryServerKeysStatements) InsertJSONResponse(
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ import (
|
||||||
"github.com/lib/pq"
|
"github.com/lib/pq"
|
||||||
"github.com/matrix-org/dendrite/federationapi/storage/tables"
|
"github.com/matrix-org/dendrite/federationapi/storage/tables"
|
||||||
"github.com/matrix-org/dendrite/internal"
|
"github.com/matrix-org/dendrite/internal"
|
||||||
|
"github.com/matrix-org/dendrite/internal/sqlutil"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -91,22 +92,13 @@ func NewPostgresNotaryServerKeysMetadataTable(db *sql.DB) (s *notaryServerKeysMe
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.upsertServerKeysStmt, err = db.Prepare(upsertServerKeysSQL); err != nil {
|
return s, sqlutil.StatementList{
|
||||||
return
|
{&s.upsertServerKeysStmt, upsertServerKeysSQL},
|
||||||
}
|
{&s.selectNotaryKeyResponsesStmt, selectNotaryKeyResponsesSQL},
|
||||||
if s.selectNotaryKeyResponsesStmt, err = db.Prepare(selectNotaryKeyResponsesSQL); err != nil {
|
{&s.selectNotaryKeyResponsesWithKeyIDsStmt, selectNotaryKeyResponsesWithKeyIDsSQL},
|
||||||
return
|
{&s.selectNotaryKeyMetadataStmt, selectNotaryKeyMetadataSQL},
|
||||||
}
|
{&s.deleteUnusedServerKeysJSONStmt, deleteUnusedServerKeysJSONSQL},
|
||||||
if s.selectNotaryKeyResponsesWithKeyIDsStmt, err = db.Prepare(selectNotaryKeyResponsesWithKeyIDsSQL); err != nil {
|
}.Prepare(db)
|
||||||
return
|
|
||||||
}
|
|
||||||
if s.selectNotaryKeyMetadataStmt, err = db.Prepare(selectNotaryKeyMetadataSQL); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if s.deleteUnusedServerKeysJSONStmt, err = db.Prepare(deleteUnusedServerKeysJSONSQL); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *notaryServerKeysMetadataStatements) UpsertKey(
|
func (s *notaryServerKeysMetadataStatements) UpsertKey(
|
||||||
|
|
|
||||||
|
|
@ -65,16 +65,11 @@ func NewPostgresQueueJSONTable(db *sql.DB) (s *queueJSONStatements, err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if s.insertJSONStmt, err = s.db.Prepare(insertJSONSQL); err != nil {
|
return s, sqlutil.StatementList{
|
||||||
return
|
{&s.insertJSONStmt, insertJSONSQL},
|
||||||
}
|
{&s.deleteJSONStmt, deleteJSONSQL},
|
||||||
if s.deleteJSONStmt, err = s.db.Prepare(deleteJSONSQL); err != nil {
|
{&s.selectJSONStmt, selectJSONSQL},
|
||||||
return
|
}.Prepare(db)
|
||||||
}
|
|
||||||
if s.selectJSONStmt, err = s.db.Prepare(selectJSONSQL); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *queueJSONStatements) InsertQueueJSON(
|
func (s *queueJSONStatements) InsertQueueJSON(
|
||||||
|
|
|
||||||
|
|
@ -78,22 +78,13 @@ func NewPostgresQueuePDUsTable(db *sql.DB) (s *queuePDUsStatements, err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if s.insertQueuePDUStmt, err = s.db.Prepare(insertQueuePDUSQL); err != nil {
|
return s, sqlutil.StatementList{
|
||||||
return
|
{&s.insertQueuePDUStmt, insertQueuePDUSQL},
|
||||||
}
|
{&s.deleteQueuePDUsStmt, deleteQueuePDUSQL},
|
||||||
if s.deleteQueuePDUsStmt, err = s.db.Prepare(deleteQueuePDUSQL); err != nil {
|
{&s.selectQueuePDUsStmt, selectQueuePDUsSQL},
|
||||||
return
|
{&s.selectQueuePDUReferenceJSONCountStmt, selectQueuePDUReferenceJSONCountSQL},
|
||||||
}
|
{&s.selectQueuePDUServerNamesStmt, selectQueuePDUServerNamesSQL},
|
||||||
if s.selectQueuePDUsStmt, err = s.db.Prepare(selectQueuePDUsSQL); err != nil {
|
}.Prepare(db)
|
||||||
return
|
|
||||||
}
|
|
||||||
if s.selectQueuePDUReferenceJSONCountStmt, err = s.db.Prepare(selectQueuePDUReferenceJSONCountSQL); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if s.selectQueuePDUServerNamesStmt, err = s.db.Prepare(selectQueuePDUServerNamesSQL); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *queuePDUsStatements) InsertQueuePDU(
|
func (s *queuePDUsStatements) InsertQueuePDU(
|
||||||
|
|
|
||||||
|
|
@ -72,13 +72,10 @@ func NewPostgresServerSigningKeysTable(db *sql.DB) (s *serverSigningKeyStatement
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if s.bulkSelectServerKeysStmt, err = db.Prepare(bulkSelectServerSigningKeysSQL); err != nil {
|
return s, sqlutil.StatementList{
|
||||||
return
|
{&s.bulkSelectServerKeysStmt, bulkSelectServerSigningKeysSQL},
|
||||||
}
|
{&s.upsertServerKeysStmt, upsertServerSigningKeysSQL},
|
||||||
if s.upsertServerKeysStmt, err = db.Prepare(upsertServerSigningKeysSQL); err != nil {
|
}.Prepare(db)
|
||||||
return
|
|
||||||
}
|
|
||||||
return s, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *serverSigningKeyStatements) BulkSelectServerKeys(
|
func (s *serverSigningKeyStatements) BulkSelectServerKeys(
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@
|
||||||
package postgres
|
package postgres
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
|
@ -23,7 +24,6 @@ import (
|
||||||
"github.com/matrix-org/dendrite/federationapi/storage/shared"
|
"github.com/matrix-org/dendrite/federationapi/storage/shared"
|
||||||
"github.com/matrix-org/dendrite/internal/caching"
|
"github.com/matrix-org/dendrite/internal/caching"
|
||||||
"github.com/matrix-org/dendrite/internal/sqlutil"
|
"github.com/matrix-org/dendrite/internal/sqlutil"
|
||||||
"github.com/matrix-org/dendrite/setup/base"
|
|
||||||
"github.com/matrix-org/dendrite/setup/config"
|
"github.com/matrix-org/dendrite/setup/config"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
)
|
)
|
||||||
|
|
@ -36,10 +36,10 @@ type Database struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDatabase opens a new database
|
// NewDatabase opens a new database
|
||||||
func NewDatabase(base *base.BaseDendrite, dbProperties *config.DatabaseOptions, cache caching.FederationCache, isLocalServerName func(gomatrixserverlib.ServerName) bool) (*Database, error) {
|
func NewDatabase(ctx context.Context, conMan sqlutil.Connections, dbProperties *config.DatabaseOptions, cache caching.FederationCache, isLocalServerName func(gomatrixserverlib.ServerName) bool) (*Database, error) {
|
||||||
var d Database
|
var d Database
|
||||||
var err error
|
var err error
|
||||||
if d.db, d.writer, err = base.DatabaseConnection(dbProperties, sqlutil.NewDummyWriter()); err != nil {
|
if d.db, d.writer, err = conMan.Connection(dbProperties); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
blacklist, err := NewPostgresBlacklistTable(d.db)
|
blacklist, err := NewPostgresBlacklistTable(d.db)
|
||||||
|
|
@ -95,7 +95,7 @@ func NewDatabase(base *base.BaseDendrite, dbProperties *config.DatabaseOptions,
|
||||||
Version: "federationsender: drop federationsender_rooms",
|
Version: "federationsender: drop federationsender_rooms",
|
||||||
Up: deltas.UpRemoveRoomsTable,
|
Up: deltas.UpRemoveRoomsTable,
|
||||||
})
|
})
|
||||||
err = m.Up(base.Context())
|
err = m.Up(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -60,19 +60,12 @@ func NewSQLiteBlacklistTable(db *sql.DB) (s *blacklistStatements, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.insertBlacklistStmt, err = db.Prepare(insertBlacklistSQL); err != nil {
|
return s, sqlutil.StatementList{
|
||||||
return
|
{&s.insertBlacklistStmt, insertBlacklistSQL},
|
||||||
}
|
{&s.selectBlacklistStmt, selectBlacklistSQL},
|
||||||
if s.selectBlacklistStmt, err = db.Prepare(selectBlacklistSQL); err != nil {
|
{&s.deleteBlacklistStmt, deleteBlacklistSQL},
|
||||||
return
|
{&s.deleteAllBlacklistStmt, deleteAllBlacklistSQL},
|
||||||
}
|
}.Prepare(db)
|
||||||
if s.deleteBlacklistStmt, err = db.Prepare(deleteBlacklistSQL); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if s.deleteAllBlacklistStmt, err = db.Prepare(deleteAllBlacklistSQL); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *blacklistStatements) InsertBlacklist(
|
func (s *blacklistStatements) InsertBlacklist(
|
||||||
|
|
|
||||||
|
|
@ -90,22 +90,14 @@ func NewSQLiteJoinedHostsTable(db *sql.DB) (s *joinedHostsStatements, err error)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if s.insertJoinedHostsStmt, err = db.Prepare(insertJoinedHostsSQL); err != nil {
|
|
||||||
return
|
return s, sqlutil.StatementList{
|
||||||
}
|
{&s.insertJoinedHostsStmt, insertJoinedHostsSQL},
|
||||||
if s.deleteJoinedHostsStmt, err = db.Prepare(deleteJoinedHostsSQL); err != nil {
|
{&s.deleteJoinedHostsStmt, deleteJoinedHostsSQL},
|
||||||
return
|
{&s.deleteJoinedHostsForRoomStmt, deleteJoinedHostsForRoomSQL},
|
||||||
}
|
{&s.selectJoinedHostsStmt, selectJoinedHostsSQL},
|
||||||
if s.deleteJoinedHostsForRoomStmt, err = s.db.Prepare(deleteJoinedHostsForRoomSQL); err != nil {
|
{&s.selectAllJoinedHostsStmt, selectAllJoinedHostsSQL},
|
||||||
return
|
}.Prepare(db)
|
||||||
}
|
|
||||||
if s.selectJoinedHostsStmt, err = db.Prepare(selectJoinedHostsSQL); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if s.selectAllJoinedHostsStmt, err = db.Prepare(selectAllJoinedHostsSQL); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *joinedHostsStatements) InsertJoinedHosts(
|
func (s *joinedHostsStatements) InsertJoinedHosts(
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/federationapi/storage/tables"
|
"github.com/matrix-org/dendrite/federationapi/storage/tables"
|
||||||
|
"github.com/matrix-org/dendrite/internal/sqlutil"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -49,10 +50,9 @@ func NewSQLiteNotaryServerKeysTable(db *sql.DB) (s *notaryServerKeysStatements,
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.insertServerKeysJSONStmt, err = db.Prepare(insertServerKeysJSONSQL); err != nil {
|
return s, sqlutil.StatementList{
|
||||||
return
|
{&s.insertServerKeysJSONStmt, insertServerKeysJSONSQL},
|
||||||
}
|
}.Prepare(db)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *notaryServerKeysStatements) InsertJSONResponse(
|
func (s *notaryServerKeysStatements) InsertJSONResponse(
|
||||||
|
|
|
||||||
|
|
@ -92,19 +92,12 @@ func NewSQLiteNotaryServerKeysMetadataTable(db *sql.DB) (s *notaryServerKeysMeta
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.upsertServerKeysStmt, err = db.Prepare(upsertServerKeysSQL); err != nil {
|
return s, sqlutil.StatementList{
|
||||||
return
|
{&s.upsertServerKeysStmt, upsertServerKeysSQL},
|
||||||
}
|
{&s.selectNotaryKeyResponsesStmt, selectNotaryKeyResponsesSQL},
|
||||||
if s.selectNotaryKeyResponsesStmt, err = db.Prepare(selectNotaryKeyResponsesSQL); err != nil {
|
{&s.selectNotaryKeyMetadataStmt, selectNotaryKeyMetadataSQL},
|
||||||
return
|
{&s.deleteUnusedServerKeysJSONStmt, deleteUnusedServerKeysJSONSQL},
|
||||||
}
|
}.Prepare(db)
|
||||||
if s.selectNotaryKeyMetadataStmt, err = db.Prepare(selectNotaryKeyMetadataSQL); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if s.deleteUnusedServerKeysJSONStmt, err = db.Prepare(deleteUnusedServerKeysJSONSQL); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *notaryServerKeysMetadataStatements) UpsertKey(
|
func (s *notaryServerKeysMetadataStatements) UpsertKey(
|
||||||
|
|
|
||||||
|
|
@ -66,10 +66,10 @@ func NewSQLiteQueueJSONTable(db *sql.DB) (s *queueJSONStatements, err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if s.insertJSONStmt, err = db.Prepare(insertJSONSQL); err != nil {
|
|
||||||
return
|
return s, sqlutil.StatementList{
|
||||||
}
|
{&s.insertJSONStmt, insertJSONSQL},
|
||||||
return
|
}.Prepare(db)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *queueJSONStatements) InsertQueueJSON(
|
func (s *queueJSONStatements) InsertQueueJSON(
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue