mirror of
https://github.com/matrix-org/dendrite
synced 2024-11-10 20:01:15 +01:00
Merge branch 'main' of github.com:matrix-org/dendrite into gh-pages
This commit is contained in:
commit
f52d028d73
46 changed files with 467 additions and 141 deletions
2
.github/ISSUE_TEMPLATE/BUG_REPORT.md
vendored
2
.github/ISSUE_TEMPLATE/BUG_REPORT.md
vendored
|
@ -62,6 +62,6 @@ If you can identify any relevant log snippets from server logs, please include
|
||||||
those (please be careful to remove any personal or private data). Please surround them with
|
those (please be careful to remove any personal or private data). Please surround them with
|
||||||
``` (three backticks, on a line on their own), so that they are formatted legibly.
|
``` (three backticks, on a line on their own), so that they are formatted legibly.
|
||||||
|
|
||||||
Alternatively, please send logs to @kegan:matrix.org or @neilalexander:matrix.org
|
Alternatively, please send logs to @kegan:matrix.org, @s7evink:matrix.org or @devonh:one.ems.host
|
||||||
with a link to the respective Github issue, thanks!
|
with a link to the respective Github issue, thanks!
|
||||||
-->
|
-->
|
||||||
|
|
2
.github/workflows/dendrite.yml
vendored
2
.github/workflows/dendrite.yml
vendored
|
@ -440,7 +440,7 @@ jobs:
|
||||||
# Run Complement
|
# Run Complement
|
||||||
- run: |
|
- run: |
|
||||||
set -o pipefail &&
|
set -o pipefail &&
|
||||||
go test -v -json -tags dendrite_blacklist ./tests/... 2>&1 | gotestfmt -hide all
|
go test -v -json -tags dendrite_blacklist ./tests ./tests/csapi 2>&1 | gotestfmt -hide all
|
||||||
shell: bash
|
shell: bash
|
||||||
name: Run Complement Tests
|
name: Run Complement Tests
|
||||||
env:
|
env:
|
||||||
|
|
18
.github/workflows/docker.yml
vendored
18
.github/workflows/docker.yml
vendored
|
@ -32,10 +32,6 @@ jobs:
|
||||||
if: github.event_name == 'release' # Only for GitHub releases
|
if: github.event_name == 'release' # Only for GitHub releases
|
||||||
run: |
|
run: |
|
||||||
echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
|
echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
|
||||||
echo "BUILD=$(git rev-parse --short HEAD || \"\")" >> $GITHUB_ENV
|
|
||||||
BRANCH=$(git symbolic-ref --short HEAD | tr -d \/)
|
|
||||||
[ ${BRANCH} == "main" ] && BRANCH=""
|
|
||||||
echo "BRANCH=${BRANCH}" >> $GITHUB_ENV
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v1
|
uses: docker/setup-qemu-action@v1
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
|
@ -60,7 +56,6 @@ jobs:
|
||||||
cache-from: type=registry,ref=ghcr.io/${{ env.GHCR_NAMESPACE }}/dendrite-monolith:buildcache
|
cache-from: type=registry,ref=ghcr.io/${{ env.GHCR_NAMESPACE }}/dendrite-monolith:buildcache
|
||||||
cache-to: type=registry,ref=ghcr.io/${{ env.GHCR_NAMESPACE }}/dendrite-monolith:buildcache,mode=max
|
cache-to: type=registry,ref=ghcr.io/${{ env.GHCR_NAMESPACE }}/dendrite-monolith:buildcache,mode=max
|
||||||
context: .
|
context: .
|
||||||
build-args: FLAGS=-X github.com/matrix-org/dendrite/internal.branch=${{ env.BRANCH }} -X github.com/matrix-org/dendrite/internal.build=${{ env.BUILD }}
|
|
||||||
platforms: ${{ env.PLATFORMS }}
|
platforms: ${{ env.PLATFORMS }}
|
||||||
push: true
|
push: true
|
||||||
tags: |
|
tags: |
|
||||||
|
@ -75,7 +70,6 @@ jobs:
|
||||||
cache-from: type=gha
|
cache-from: type=gha
|
||||||
cache-to: type=gha,mode=max
|
cache-to: type=gha,mode=max
|
||||||
context: .
|
context: .
|
||||||
build-args: FLAGS=-X github.com/matrix-org/dendrite/internal.branch=${{ env.BRANCH }} -X github.com/matrix-org/dendrite/internal.build=${{ env.BUILD }}
|
|
||||||
platforms: ${{ env.PLATFORMS }}
|
platforms: ${{ env.PLATFORMS }}
|
||||||
push: true
|
push: true
|
||||||
tags: |
|
tags: |
|
||||||
|
@ -109,10 +103,6 @@ jobs:
|
||||||
if: github.event_name == 'release' # Only for GitHub releases
|
if: github.event_name == 'release' # Only for GitHub releases
|
||||||
run: |
|
run: |
|
||||||
echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
|
echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
|
||||||
echo "BUILD=$(git rev-parse --short HEAD || \"\")" >> $GITHUB_ENV
|
|
||||||
BRANCH=$(git symbolic-ref --short HEAD | tr -d \/)
|
|
||||||
[ ${BRANCH} == "main" ] && BRANCH=""
|
|
||||||
echo "BRANCH=${BRANCH}" >> $GITHUB_ENV
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v1
|
uses: docker/setup-qemu-action@v1
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
|
@ -137,7 +127,6 @@ jobs:
|
||||||
cache-from: type=gha
|
cache-from: type=gha
|
||||||
cache-to: type=gha,mode=max
|
cache-to: type=gha,mode=max
|
||||||
context: .
|
context: .
|
||||||
build-args: FLAGS=-X github.com/matrix-org/dendrite/internal.branch=${{ env.BRANCH }} -X github.com/matrix-org/dendrite/internal.build=${{ env.BUILD }}
|
|
||||||
file: ./build/docker/Dockerfile.demo-pinecone
|
file: ./build/docker/Dockerfile.demo-pinecone
|
||||||
platforms: ${{ env.PLATFORMS }}
|
platforms: ${{ env.PLATFORMS }}
|
||||||
push: true
|
push: true
|
||||||
|
@ -153,7 +142,6 @@ jobs:
|
||||||
cache-from: type=gha
|
cache-from: type=gha
|
||||||
cache-to: type=gha,mode=max
|
cache-to: type=gha,mode=max
|
||||||
context: .
|
context: .
|
||||||
build-args: FLAGS=-X github.com/matrix-org/dendrite/internal.branch=${{ env.BRANCH }} -X github.com/matrix-org/dendrite/internal.build=${{ env.BUILD }}
|
|
||||||
file: ./build/docker/Dockerfile.demo-pinecone
|
file: ./build/docker/Dockerfile.demo-pinecone
|
||||||
platforms: ${{ env.PLATFORMS }}
|
platforms: ${{ env.PLATFORMS }}
|
||||||
push: true
|
push: true
|
||||||
|
@ -176,10 +164,6 @@ jobs:
|
||||||
if: github.event_name == 'release' # Only for GitHub releases
|
if: github.event_name == 'release' # Only for GitHub releases
|
||||||
run: |
|
run: |
|
||||||
echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
|
echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
|
||||||
echo "BUILD=$(git rev-parse --short HEAD || \"\")" >> $GITHUB_ENV
|
|
||||||
BRANCH=$(git symbolic-ref --short HEAD | tr -d \/)
|
|
||||||
[ ${BRANCH} == "main" ] && BRANCH=""
|
|
||||||
echo "BRANCH=${BRANCH}" >> $GITHUB_ENV
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v1
|
uses: docker/setup-qemu-action@v1
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
|
@ -204,7 +188,6 @@ jobs:
|
||||||
cache-from: type=gha
|
cache-from: type=gha
|
||||||
cache-to: type=gha,mode=max
|
cache-to: type=gha,mode=max
|
||||||
context: .
|
context: .
|
||||||
build-args: FLAGS=-X github.com/matrix-org/dendrite/internal.branch=${{ env.BRANCH }} -X github.com/matrix-org/dendrite/internal.build=${{ env.BUILD }}
|
|
||||||
file: ./build/docker/Dockerfile.demo-yggdrasil
|
file: ./build/docker/Dockerfile.demo-yggdrasil
|
||||||
platforms: ${{ env.PLATFORMS }}
|
platforms: ${{ env.PLATFORMS }}
|
||||||
push: true
|
push: true
|
||||||
|
@ -220,7 +203,6 @@ jobs:
|
||||||
cache-from: type=gha
|
cache-from: type=gha
|
||||||
cache-to: type=gha,mode=max
|
cache-to: type=gha,mode=max
|
||||||
context: .
|
context: .
|
||||||
build-args: FLAGS=-X github.com/matrix-org/dendrite/internal.branch=${{ env.BRANCH }} -X github.com/matrix-org/dendrite/internal.build=${{ env.BUILD }}
|
|
||||||
file: ./build/docker/Dockerfile.demo-yggdrasil
|
file: ./build/docker/Dockerfile.demo-yggdrasil
|
||||||
platforms: ${{ env.PLATFORMS }}
|
platforms: ${{ env.PLATFORMS }}
|
||||||
push: true
|
push: true
|
||||||
|
|
|
@ -180,7 +180,6 @@ linters-settings:
|
||||||
linters:
|
linters:
|
||||||
enable:
|
enable:
|
||||||
- errcheck
|
- errcheck
|
||||||
- goconst
|
|
||||||
- gocyclo
|
- gocyclo
|
||||||
- goimports # Does everything gofmt does
|
- goimports # Does everything gofmt does
|
||||||
- gosimple
|
- gosimple
|
||||||
|
@ -211,6 +210,7 @@ linters:
|
||||||
- stylecheck
|
- stylecheck
|
||||||
- typecheck # Should turn back on soon
|
- typecheck # Should turn back on soon
|
||||||
- unconvert # Should turn back on soon
|
- unconvert # Should turn back on soon
|
||||||
|
- goconst # Slightly annoying, as it reports "issues" in SQL statements
|
||||||
disable-all: false
|
disable-all: false
|
||||||
presets:
|
presets:
|
||||||
fast: false
|
fast: false
|
||||||
|
|
18
CHANGES.md
18
CHANGES.md
|
@ -1,5 +1,23 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## Dendrite 0.13.4 (2023-10-25)
|
||||||
|
|
||||||
|
Upgrading to this version is **highly** recommended, as it fixes a long-standing bug in the state resolution
|
||||||
|
algorithm.
|
||||||
|
|
||||||
|
### Fixes:
|
||||||
|
|
||||||
|
- The "device list updater" now de-duplicates the servers to fetch devices from on startup. (This also
|
||||||
|
avoids spamming the logs when shutting down.)
|
||||||
|
- A bug in the state resolution algorithm has been fixed. This bug could result in users "being reset"
|
||||||
|
out of rooms and other missing state events due to calculating the wrong state.
|
||||||
|
- A bug when setting notifications from Element Android has been fixed by implementing MSC3987
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
- Updated dependencies
|
||||||
|
- Internal NATS Server has been updated from v2.9.19 to v2.9.23
|
||||||
|
|
||||||
## Dendrite 0.13.3 (2023-09-28)
|
## Dendrite 0.13.3 (2023-09-28)
|
||||||
|
|
||||||
### Fixes:
|
### Fixes:
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
#
|
#
|
||||||
# base installs required dependencies and runs go mod download to cache dependencies
|
# base installs required dependencies and runs go mod download to cache dependencies
|
||||||
#
|
#
|
||||||
FROM --platform=${BUILDPLATFORM} docker.io/golang:1.20-alpine AS base
|
FROM --platform=${BUILDPLATFORM} docker.io/golang:1.21-alpine AS base
|
||||||
RUN apk --update --no-cache add bash build-base curl git
|
RUN apk --update --no-cache add bash build-base curl git
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -13,7 +13,6 @@ FROM --platform=${BUILDPLATFORM} base AS build
|
||||||
WORKDIR /src
|
WORKDIR /src
|
||||||
ARG TARGETOS
|
ARG TARGETOS
|
||||||
ARG TARGETARCH
|
ARG TARGETARCH
|
||||||
ARG FLAGS
|
|
||||||
RUN --mount=target=. \
|
RUN --mount=target=. \
|
||||||
--mount=type=cache,target=/root/.cache/go-build \
|
--mount=type=cache,target=/root/.cache/go-build \
|
||||||
--mount=type=cache,target=/go/pkg/mod \
|
--mount=type=cache,target=/go/pkg/mod \
|
||||||
|
@ -21,7 +20,7 @@ RUN --mount=target=. \
|
||||||
GOARCH="$TARGETARCH" \
|
GOARCH="$TARGETARCH" \
|
||||||
GOOS="linux" \
|
GOOS="linux" \
|
||||||
CGO_ENABLED=$([ "$TARGETARCH" = "$USERARCH" ] && echo "1" || echo "0") \
|
CGO_ENABLED=$([ "$TARGETARCH" = "$USERARCH" ] && echo "1" || echo "0") \
|
||||||
go build -v -ldflags="${FLAGS}" -trimpath -o /out/ ./cmd/...
|
go build -v -trimpath -o /out/ ./cmd/...
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
FROM docker.io/golang:1.19-alpine AS base
|
FROM docker.io/golang:1.21-alpine AS base
|
||||||
|
|
||||||
#
|
#
|
||||||
# Needs to be separate from the main Dockerfile for OpenShift,
|
# Needs to be separate from the main Dockerfile for OpenShift,
|
||||||
|
|
|
@ -15,5 +15,5 @@ tar -xzf master.tar.gz
|
||||||
|
|
||||||
# Run the tests!
|
# Run the tests!
|
||||||
cd complement-master
|
cd complement-master
|
||||||
COMPLEMENT_BASE_IMAGE=complement-dendrite:latest go test -v -count=1 ./tests
|
COMPLEMENT_BASE_IMAGE=complement-dendrite:latest go test -v -count=1 ./tests ./tests/csapi
|
||||||
|
|
||||||
|
|
|
@ -1418,7 +1418,7 @@ func TestPushRules(t *testing.T) {
|
||||||
validateFunc: func(t *testing.T, respBody *bytes.Buffer) {
|
validateFunc: func(t *testing.T, respBody *bytes.Buffer) {
|
||||||
actions := gjson.GetBytes(respBody.Bytes(), "actions").Array()
|
actions := gjson.GetBytes(respBody.Bytes(), "actions").Array()
|
||||||
// only a basic check
|
// only a basic check
|
||||||
assert.Equal(t, 1, len(actions))
|
assert.Equal(t, 0, len(actions))
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -300,7 +300,7 @@ func updateProfile(
|
||||||
}, e
|
}, e
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := api.SendEvents(ctx, rsAPI, api.KindNew, events, device.UserDomain(), domain, domain, nil, true); err != nil {
|
if err := api.SendEvents(ctx, rsAPI, api.KindNew, events, device.UserDomain(), domain, domain, nil, false); err != nil {
|
||||||
util.GetLogger(ctx).WithError(err).Error("SendEvents failed")
|
util.GetLogger(ctx).WithError(err).Error("SendEvents failed")
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusInternalServerError,
|
Code: http.StatusInternalServerError,
|
||||||
|
|
|
@ -236,7 +236,7 @@ type authDict struct {
|
||||||
// TODO: Lots of custom keys depending on the type
|
// TODO: Lots of custom keys depending on the type
|
||||||
}
|
}
|
||||||
|
|
||||||
// http://matrix.org/speculator/spec/HEAD/client_server/unstable.html#user-interactive-authentication-api
|
// https://spec.matrix.org/v1.7/client-server-api/#user-interactive-authentication-api
|
||||||
type userInteractiveResponse struct {
|
type userInteractiveResponse struct {
|
||||||
Flows []authtypes.Flow `json:"flows"`
|
Flows []authtypes.Flow `json:"flows"`
|
||||||
Completed []authtypes.LoginType `json:"completed"`
|
Completed []authtypes.LoginType `json:"completed"`
|
||||||
|
@ -256,7 +256,7 @@ func newUserInteractiveResponse(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// http://matrix.org/speculator/spec/HEAD/client_server/unstable.html#post-matrix-client-unstable-register
|
// https://spec.matrix.org/v1.7/client-server-api/#post_matrixclientv3register
|
||||||
type registerResponse struct {
|
type registerResponse struct {
|
||||||
UserID string `json:"user_id"`
|
UserID string `json:"user_id"`
|
||||||
AccessToken string `json:"access_token,omitempty"`
|
AccessToken string `json:"access_token,omitempty"`
|
||||||
|
@ -462,7 +462,7 @@ func validateApplicationService(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register processes a /register request.
|
// Register processes a /register request.
|
||||||
// http://matrix.org/speculator/spec/HEAD/client_server/unstable.html#post-matrix-client-unstable-register
|
// https://spec.matrix.org/v1.7/client-server-api/#post_matrixclientv3register
|
||||||
func Register(
|
func Register(
|
||||||
req *http.Request,
|
req *http.Request,
|
||||||
userAPI userapi.ClientUserAPI,
|
userAPI userapi.ClientUserAPI,
|
||||||
|
|
|
@ -11,13 +11,11 @@ import (
|
||||||
|
|
||||||
"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/roomserver"
|
|
||||||
"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/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/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
"github.com/matrix-org/gomatrixserverlib/spec"
|
"github.com/matrix-org/gomatrixserverlib/spec"
|
||||||
|
@ -35,6 +33,19 @@ var roomVersion = flag.String("roomversion", "5", "the room version to parse eve
|
||||||
var filterType = flag.String("filtertype", "", "the event types to filter on")
|
var filterType = flag.String("filtertype", "", "the event types to filter on")
|
||||||
var difference = flag.Bool("difference", false, "whether to calculate the difference between snapshots")
|
var difference = flag.Bool("difference", false, "whether to calculate the difference between snapshots")
|
||||||
|
|
||||||
|
// dummyQuerier implements QuerySenderIDAPI. Does **NOT** do any "magic" for pseudoID rooms
|
||||||
|
// to avoid having to "start" a full roomserver API.
|
||||||
|
type dummyQuerier struct{}
|
||||||
|
|
||||||
|
func (d dummyQuerier) QuerySenderIDForUser(ctx context.Context, roomID spec.RoomID, userID spec.UserID) (*spec.SenderID, error) {
|
||||||
|
s := spec.SenderIDFromUserID(userID)
|
||||||
|
return &s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d dummyQuerier) QueryUserIDForSender(ctx context.Context, roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) {
|
||||||
|
return senderID.ToUserID(), nil
|
||||||
|
}
|
||||||
|
|
||||||
// nolint:gocyclo
|
// nolint:gocyclo
|
||||||
func main() {
|
func main() {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
@ -56,27 +67,32 @@ func main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("Fetching", len(snapshotNIDs), "snapshot NIDs")
|
|
||||||
|
|
||||||
processCtx := process.NewProcessContext()
|
processCtx := process.NewProcessContext()
|
||||||
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
|
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
|
||||||
|
|
||||||
|
dbOpts := cfg.RoomServer.Database
|
||||||
|
if dbOpts.ConnectionString == "" {
|
||||||
|
dbOpts = cfg.Global.DatabaseOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Opening database")
|
||||||
roomserverDB, err := storage.Open(
|
roomserverDB, err := storage.Open(
|
||||||
processCtx.Context(), cm, &cfg.RoomServer.Database,
|
processCtx.Context(), cm, &dbOpts,
|
||||||
caching.NewRistrettoCache(128*1024*1024, time.Hour, true),
|
caching.NewRistrettoCache(8*1024*1024, time.Minute*5, caching.DisableMetrics),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
natsInstance := &jetstream.NATSInstance{}
|
rsAPI := dummyQuerier{}
|
||||||
rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm,
|
|
||||||
natsInstance, caching.NewRistrettoCache(128*1024*1024, time.Hour, true), false)
|
|
||||||
|
|
||||||
roomInfo := &types.RoomInfo{
|
roomInfo := &types.RoomInfo{
|
||||||
RoomVersion: gomatrixserverlib.RoomVersion(*roomVersion),
|
RoomVersion: gomatrixserverlib.RoomVersion(*roomVersion),
|
||||||
}
|
}
|
||||||
stateres := state.NewStateResolution(roomserverDB, roomInfo, rsAPI)
|
stateres := state.NewStateResolution(roomserverDB, roomInfo, rsAPI)
|
||||||
|
|
||||||
|
fmt.Println("Fetching", len(snapshotNIDs), "snapshot NIDs")
|
||||||
|
|
||||||
if *difference {
|
if *difference {
|
||||||
if len(snapshotNIDs) != 2 {
|
if len(snapshotNIDs) != 2 {
|
||||||
panic("need exactly two state snapshot NIDs to calculate difference")
|
panic("need exactly two state snapshot NIDs to calculate difference")
|
||||||
|
@ -186,12 +202,25 @@ func main() {
|
||||||
authEvents[i] = authEventEntries[i].PDU
|
authEvents[i] = authEventEntries[i].PDU
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the roomNID
|
||||||
|
roomInfo, err = roomserverDB.RoomInfo(ctx, authEvents[0].RoomID().String())
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
fmt.Println("Resolving state")
|
fmt.Println("Resolving state")
|
||||||
var resolved Events
|
var resolved Events
|
||||||
resolved, err = gomatrixserverlib.ResolveConflicts(
|
resolved, err = gomatrixserverlib.ResolveConflicts(
|
||||||
gomatrixserverlib.RoomVersion(*roomVersion), events, authEvents, func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) {
|
gomatrixserverlib.RoomVersion(*roomVersion), events, authEvents, func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) {
|
||||||
return rsAPI.QueryUserIDForSender(ctx, roomID, senderID)
|
return rsAPI.QueryUserIDForSender(ctx, roomID, senderID)
|
||||||
},
|
},
|
||||||
|
func(eventID string) bool {
|
||||||
|
isRejected, rejectedErr := roomserverDB.IsEventRejected(ctx, roomInfo.RoomNID, eventID)
|
||||||
|
if rejectedErr != nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return isRejected
|
||||||
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
|
|
@ -72,6 +72,10 @@ global:
|
||||||
# The base URL to delegate client-server communications to e.g. https://localhost
|
# The base URL to delegate client-server communications to e.g. https://localhost
|
||||||
well_known_client_name: ""
|
well_known_client_name: ""
|
||||||
|
|
||||||
|
# The server name to delegate sliding sync communications to, with optional port.
|
||||||
|
# Requires `well_known_client_name` to also be configured.
|
||||||
|
well_known_sliding_sync_proxy: ""
|
||||||
|
|
||||||
# Lists of domains that the server will trust as identity servers to verify third
|
# Lists of domains that the server will trust as identity servers to verify third
|
||||||
# party identifiers such as phone numbers and email addresses.
|
# party identifiers such as phone numbers and email addresses.
|
||||||
trusted_third_party_id_servers:
|
trusted_third_party_id_servers:
|
||||||
|
|
|
@ -109,7 +109,7 @@ To configure the connection to a remote Postgres, you can use the following envi
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
POSTGRES_USER=postgres
|
POSTGRES_USER=postgres
|
||||||
POSTGERS_PASSWORD=yourPostgresPassword
|
POSTGRES_PASSWORD=yourPostgresPassword
|
||||||
POSTGRES_HOST=localhost
|
POSTGRES_HOST=localhost
|
||||||
POSTGRES_DB=postgres # the superuser database to use
|
POSTGRES_DB=postgres # the superuser database to use
|
||||||
```
|
```
|
||||||
|
|
18
go.mod
18
go.mod
|
@ -22,12 +22,12 @@ require (
|
||||||
github.com/matrix-org/dugong v0.0.0-20210921133753-66e6b1c67e2e
|
github.com/matrix-org/dugong v0.0.0-20210921133753-66e6b1c67e2e
|
||||||
github.com/matrix-org/go-sqlite3-js v0.0.0-20220419092513-28aa791a1c91
|
github.com/matrix-org/go-sqlite3-js v0.0.0-20220419092513-28aa791a1c91
|
||||||
github.com/matrix-org/gomatrix v0.0.0-20220926102614-ceba4d9f7530
|
github.com/matrix-org/gomatrix v0.0.0-20220926102614-ceba4d9f7530
|
||||||
github.com/matrix-org/gomatrixserverlib v0.0.0-20230926165653-79fcff283fc4
|
github.com/matrix-org/gomatrixserverlib v0.0.0-20231024124730-58af9a2712ca
|
||||||
github.com/matrix-org/pinecone v0.11.1-0.20230810010612-ea4c33717fd7
|
github.com/matrix-org/pinecone v0.11.1-0.20230810010612-ea4c33717fd7
|
||||||
github.com/matrix-org/util v0.0.0-20221111132719-399730281e66
|
github.com/matrix-org/util v0.0.0-20221111132719-399730281e66
|
||||||
github.com/mattn/go-sqlite3 v1.14.17
|
github.com/mattn/go-sqlite3 v1.14.17
|
||||||
github.com/nats-io/nats-server/v2 v2.9.19
|
github.com/nats-io/nats-server/v2 v2.9.23
|
||||||
github.com/nats-io/nats.go v1.27.0
|
github.com/nats-io/nats.go v1.28.0
|
||||||
github.com/neilalexander/utp v0.1.1-0.20210727203401-54ae7b1cd5f9
|
github.com/neilalexander/utp v0.1.1-0.20210727203401-54ae7b1cd5f9
|
||||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
|
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
|
||||||
github.com/opentracing/opentracing-go v1.2.0
|
github.com/opentracing/opentracing-go v1.2.0
|
||||||
|
@ -42,12 +42,12 @@ require (
|
||||||
github.com/uber/jaeger-lib v2.4.1+incompatible
|
github.com/uber/jaeger-lib v2.4.1+incompatible
|
||||||
github.com/yggdrasil-network/yggdrasil-go v0.4.6
|
github.com/yggdrasil-network/yggdrasil-go v0.4.6
|
||||||
go.uber.org/atomic v1.10.0
|
go.uber.org/atomic v1.10.0
|
||||||
golang.org/x/crypto v0.13.0
|
golang.org/x/crypto v0.14.0
|
||||||
golang.org/x/exp v0.0.0-20230809150735-7b3493d9a819
|
golang.org/x/exp v0.0.0-20230809150735-7b3493d9a819
|
||||||
golang.org/x/image v0.5.0
|
golang.org/x/image v0.5.0
|
||||||
golang.org/x/mobile v0.0.0-20221020085226-b36e6246172e
|
golang.org/x/mobile v0.0.0-20221020085226-b36e6246172e
|
||||||
golang.org/x/sync v0.3.0
|
golang.org/x/sync v0.3.0
|
||||||
golang.org/x/term v0.12.0
|
golang.org/x/term v0.13.0
|
||||||
gopkg.in/h2non/bimg.v1 v1.1.9
|
gopkg.in/h2non/bimg.v1 v1.1.9
|
||||||
gopkg.in/yaml.v2 v2.4.0
|
gopkg.in/yaml.v2 v2.4.0
|
||||||
gotest.tools/v3 v3.4.0
|
gotest.tools/v3 v3.4.0
|
||||||
|
@ -94,7 +94,7 @@ require (
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/juju/errors v1.0.0 // indirect
|
github.com/juju/errors v1.0.0 // indirect
|
||||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||||
github.com/klauspost/compress v1.16.5 // indirect
|
github.com/klauspost/compress v1.16.7 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.17 // indirect
|
github.com/mattn/go-isatty v0.0.17 // indirect
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||||
|
@ -104,7 +104,7 @@ require (
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/morikuni/aec v1.0.0 // indirect
|
github.com/morikuni/aec v1.0.0 // indirect
|
||||||
github.com/mschoch/smat v0.2.0 // indirect
|
github.com/mschoch/smat v0.2.0 // indirect
|
||||||
github.com/nats-io/jwt/v2 v2.4.1 // indirect
|
github.com/nats-io/jwt/v2 v2.5.0 // indirect
|
||||||
github.com/nats-io/nkeys v0.4.4 // indirect
|
github.com/nats-io/nkeys v0.4.4 // indirect
|
||||||
github.com/nats-io/nuid v1.0.1 // indirect
|
github.com/nats-io/nuid v1.0.1 // indirect
|
||||||
github.com/onsi/ginkgo/v2 v2.11.0 // indirect
|
github.com/onsi/ginkgo/v2 v2.11.0 // indirect
|
||||||
|
@ -123,8 +123,8 @@ require (
|
||||||
github.com/tidwall/pretty v1.2.1 // indirect
|
github.com/tidwall/pretty v1.2.1 // indirect
|
||||||
go.etcd.io/bbolt v1.3.6 // indirect
|
go.etcd.io/bbolt v1.3.6 // indirect
|
||||||
golang.org/x/mod v0.12.0 // indirect
|
golang.org/x/mod v0.12.0 // indirect
|
||||||
golang.org/x/net v0.14.0 // indirect
|
golang.org/x/net v0.17.0 // indirect
|
||||||
golang.org/x/sys v0.12.0 // indirect
|
golang.org/x/sys v0.13.0 // indirect
|
||||||
golang.org/x/text v0.13.0 // indirect
|
golang.org/x/text v0.13.0 // indirect
|
||||||
golang.org/x/time v0.3.0 // indirect
|
golang.org/x/time v0.3.0 // indirect
|
||||||
golang.org/x/tools v0.12.0 // indirect
|
golang.org/x/tools v0.12.0 // indirect
|
||||||
|
|
36
go.sum
36
go.sum
|
@ -190,8 +190,8 @@ github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:C
|
||||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||||
github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI=
|
github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I=
|
||||||
github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
|
@ -208,8 +208,8 @@ github.com/matrix-org/go-sqlite3-js v0.0.0-20220419092513-28aa791a1c91 h1:s7fexw
|
||||||
github.com/matrix-org/go-sqlite3-js v0.0.0-20220419092513-28aa791a1c91/go.mod h1:e+cg2q7C7yE5QnAXgzo512tgFh1RbQLC0+jozuegKgo=
|
github.com/matrix-org/go-sqlite3-js v0.0.0-20220419092513-28aa791a1c91/go.mod h1:e+cg2q7C7yE5QnAXgzo512tgFh1RbQLC0+jozuegKgo=
|
||||||
github.com/matrix-org/gomatrix v0.0.0-20220926102614-ceba4d9f7530 h1:kHKxCOLcHH8r4Fzarl4+Y3K5hjothkVW5z7T1dUM11U=
|
github.com/matrix-org/gomatrix v0.0.0-20220926102614-ceba4d9f7530 h1:kHKxCOLcHH8r4Fzarl4+Y3K5hjothkVW5z7T1dUM11U=
|
||||||
github.com/matrix-org/gomatrix v0.0.0-20220926102614-ceba4d9f7530/go.mod h1:/gBX06Kw0exX1HrwmoBibFA98yBk/jxKpGVeyQbff+s=
|
github.com/matrix-org/gomatrix v0.0.0-20220926102614-ceba4d9f7530/go.mod h1:/gBX06Kw0exX1HrwmoBibFA98yBk/jxKpGVeyQbff+s=
|
||||||
github.com/matrix-org/gomatrixserverlib v0.0.0-20230926165653-79fcff283fc4 h1:UuXfC7b29RBDfMdLmggeF3opu3XuGi8bNT9SKZtZc3I=
|
github.com/matrix-org/gomatrixserverlib v0.0.0-20231024124730-58af9a2712ca h1:JCP72vU4Vcmur2071RwYVOSoekR+ZjbC03wZD5lAAK0=
|
||||||
github.com/matrix-org/gomatrixserverlib v0.0.0-20230926165653-79fcff283fc4/go.mod h1:H9V9N3Uqn1bBJqYJNGK1noqtgJTaCEhtTdcH/mp50uU=
|
github.com/matrix-org/gomatrixserverlib v0.0.0-20231024124730-58af9a2712ca/go.mod h1:M8m7seOroO5ePlgxA7AFZymnG90Cnh94rYQyngSrZkk=
|
||||||
github.com/matrix-org/pinecone v0.11.1-0.20230810010612-ea4c33717fd7 h1:6t8kJr8i1/1I5nNttw6nn1ryQJgzVlBmSGgPiiaTdw4=
|
github.com/matrix-org/pinecone v0.11.1-0.20230810010612-ea4c33717fd7 h1:6t8kJr8i1/1I5nNttw6nn1ryQJgzVlBmSGgPiiaTdw4=
|
||||||
github.com/matrix-org/pinecone v0.11.1-0.20230810010612-ea4c33717fd7/go.mod h1:ReWMS/LoVnOiRAdq9sNUC2NZnd1mZkMNB52QhpTRWjg=
|
github.com/matrix-org/pinecone v0.11.1-0.20230810010612-ea4c33717fd7/go.mod h1:ReWMS/LoVnOiRAdq9sNUC2NZnd1mZkMNB52QhpTRWjg=
|
||||||
github.com/matrix-org/util v0.0.0-20221111132719-399730281e66 h1:6z4KxomXSIGWqhHcfzExgkH3Z3UkIXry4ibJS4Aqz2Y=
|
github.com/matrix-org/util v0.0.0-20221111132719-399730281e66 h1:6z4KxomXSIGWqhHcfzExgkH3Z3UkIXry4ibJS4Aqz2Y=
|
||||||
|
@ -242,12 +242,12 @@ github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7P
|
||||||
github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg=
|
github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg=
|
||||||
github.com/mschoch/smat v0.2.0 h1:8imxQsjDm8yFEAVBe7azKmKSgzSkZXDuKkSq9374khM=
|
github.com/mschoch/smat v0.2.0 h1:8imxQsjDm8yFEAVBe7azKmKSgzSkZXDuKkSq9374khM=
|
||||||
github.com/mschoch/smat v0.2.0/go.mod h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOlotKw=
|
github.com/mschoch/smat v0.2.0/go.mod h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOlotKw=
|
||||||
github.com/nats-io/jwt/v2 v2.4.1 h1:Y35W1dgbbz2SQUYDPCaclXcuqleVmpbRa7646Jf2EX4=
|
github.com/nats-io/jwt/v2 v2.5.0 h1:WQQ40AAlqqfx+f6ku+i0pOVm+ASirD4fUh+oQsiE9Ak=
|
||||||
github.com/nats-io/jwt/v2 v2.4.1/go.mod h1:24BeQtRwxRV8ruvC4CojXlx/WQ/VjuwlYiH+vu/+ibI=
|
github.com/nats-io/jwt/v2 v2.5.0/go.mod h1:24BeQtRwxRV8ruvC4CojXlx/WQ/VjuwlYiH+vu/+ibI=
|
||||||
github.com/nats-io/nats-server/v2 v2.9.19 h1:OF9jSKZGo425C/FcVVIvNgpd36CUe7aVTTXEZRJk6kA=
|
github.com/nats-io/nats-server/v2 v2.9.23 h1:6Wj6H6QpP9FMlpCyWUaNu2yeZ/qGj+mdRkZ1wbikExU=
|
||||||
github.com/nats-io/nats-server/v2 v2.9.19/go.mod h1:aTb/xtLCGKhfTFLxP591CMWfkdgBmcUUSkiSOe5A3gw=
|
github.com/nats-io/nats-server/v2 v2.9.23/go.mod h1:wEjrEy9vnqIGE4Pqz4/c75v9Pmaq7My2IgFmnykc4C0=
|
||||||
github.com/nats-io/nats.go v1.27.0 h1:3o9fsPhmoKm+yK7rekH2GtWoE+D9jFbw8N3/ayI1C00=
|
github.com/nats-io/nats.go v1.28.0 h1:Th4G6zdsz2d0OqXdfzKLClo6bOfoI/b1kInhRtFIy5c=
|
||||||
github.com/nats-io/nats.go v1.27.0/go.mod h1:XpbWUlOElGwTYbMR7imivs7jJj9GtK7ypv321Wp6pjc=
|
github.com/nats-io/nats.go v1.28.0/go.mod h1:XpbWUlOElGwTYbMR7imivs7jJj9GtK7ypv321Wp6pjc=
|
||||||
github.com/nats-io/nkeys v0.4.4 h1:xvBJ8d69TznjcQl9t6//Q5xXuVhyYiSos6RPtvQNTwA=
|
github.com/nats-io/nkeys v0.4.4 h1:xvBJ8d69TznjcQl9t6//Q5xXuVhyYiSos6RPtvQNTwA=
|
||||||
github.com/nats-io/nkeys v0.4.4/go.mod h1:XUkxdLPTufzlihbamfzQ7mw/VGx6ObUs+0bN5sNvt64=
|
github.com/nats-io/nkeys v0.4.4/go.mod h1:XUkxdLPTufzlihbamfzQ7mw/VGx6ObUs+0bN5sNvt64=
|
||||||
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
|
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
|
||||||
|
@ -354,8 +354,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=
|
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
|
||||||
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||||
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
|
@ -386,8 +386,8 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14=
|
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
||||||
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
|
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
@ -418,12 +418,12 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
|
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
||||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.12.0 h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU=
|
golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=
|
||||||
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
apiVersion: v2
|
apiVersion: v2
|
||||||
name: dendrite
|
name: dendrite
|
||||||
version: "0.13.4"
|
version: "0.13.5"
|
||||||
appVersion: "0.13.3"
|
appVersion: "0.13.4"
|
||||||
description: Dendrite Matrix Homeserver
|
description: Dendrite Matrix Homeserver
|
||||||
type: application
|
type: application
|
||||||
keywords:
|
keywords:
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
|
|
||||||
# dendrite
|
# dendrite
|
||||||
|
|
||||||
![Version: 0.13.4](https://img.shields.io/badge/Version-0.13.4-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.13.3](https://img.shields.io/badge/AppVersion-0.13.3-informational?style=flat-square)
|
![Version: 0.13.5](https://img.shields.io/badge/Version-0.13.5-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.13.4](https://img.shields.io/badge/AppVersion-0.13.4-informational?style=flat-square)
|
||||||
Dendrite Matrix Homeserver
|
Dendrite Matrix Homeserver
|
||||||
|
|
||||||
Status: **NOT PRODUCTION READY**
|
Status: **NOT PRODUCTION READY**
|
||||||
|
@ -48,16 +48,13 @@ Create a folder `appservices` and place your configurations in there. The confi
|
||||||
| signing_key.create | bool | `true` | Create a new signing key, if not exists |
|
| signing_key.create | bool | `true` | Create a new signing key, if not exists |
|
||||||
| signing_key.existingSecret | string | `""` | Use an existing secret |
|
| signing_key.existingSecret | string | `""` | Use an existing secret |
|
||||||
| resources | object | sets some sane default values | Default resource requests/limits. |
|
| resources | object | sets some sane default values | Default resource requests/limits. |
|
||||||
| persistence.storageClass | string | `""` | The storage class to use for volume claims. Used unless specified at the specific component. Defaults to the cluster default storage class. |
|
| persistence.jetstream | object | `{"capacity":"1Gi","existingClaim":""}` | The storage class to use for volume claims. Used unless specified at the specific component. Defaults to the cluster default storage class. # If defined, storageClassName: <storageClass> # If set to "-", storageClassName: "", which disables dynamic provisioning # If undefined (the default) or set to null, no storageClassName spec is # set, choosing the default provisioner. (gp2 on AWS, standard on # GKE, AWS & OpenStack) # storageClass: "" |
|
||||||
| persistence.jetstream.existingClaim | string | `""` | Use an existing volume claim for jetstream |
|
| persistence.jetstream.existingClaim | string | `""` | Use an existing volume claim for jetstream |
|
||||||
| persistence.jetstream.capacity | string | `"1Gi"` | PVC Storage Request for the jetstream volume |
|
| persistence.jetstream.capacity | string | `"1Gi"` | PVC Storage Request for the jetstream volume |
|
||||||
| persistence.jetstream.storageClass | string | `""` | The storage class to use for volume claims. Defaults to persistence.storageClass |
|
|
||||||
| persistence.media.existingClaim | string | `""` | Use an existing volume claim for media files |
|
| persistence.media.existingClaim | string | `""` | Use an existing volume claim for media files |
|
||||||
| persistence.media.capacity | string | `"1Gi"` | PVC Storage Request for the media volume |
|
| persistence.media.capacity | string | `"1Gi"` | PVC Storage Request for the media volume |
|
||||||
| persistence.media.storageClass | string | `""` | The storage class to use for volume claims. Defaults to persistence.storageClass |
|
|
||||||
| persistence.search.existingClaim | string | `""` | Use an existing volume claim for the fulltext search index |
|
| persistence.search.existingClaim | string | `""` | Use an existing volume claim for the fulltext search index |
|
||||||
| persistence.search.capacity | string | `"1Gi"` | PVC Storage Request for the search volume |
|
| persistence.search.capacity | string | `"1Gi"` | PVC Storage Request for the search volume |
|
||||||
| persistence.search.storageClass | string | `""` | The storage class to use for volume claims. Defaults to persistence.storageClass |
|
|
||||||
| extraVolumes | list | `[]` | Add additional volumes to the Dendrite Pod |
|
| extraVolumes | list | `[]` | Add additional volumes to the Dendrite Pod |
|
||||||
| extraVolumeMounts | list | `[]` | Configure additional mount points volumes in the Dendrite Pod |
|
| extraVolumeMounts | list | `[]` | Configure additional mount points volumes in the Dendrite Pod |
|
||||||
| strategy.type | string | `"RollingUpdate"` | Strategy to use for rolling updates (e.g. Recreate, RollingUpdate) If you are using ReadWriteOnce volumes, you should probably use Recreate |
|
| strategy.type | string | `"RollingUpdate"` | Strategy to use for rolling updates (e.g. Recreate, RollingUpdate) If you are using ReadWriteOnce volumes, you should probably use Recreate |
|
||||||
|
|
|
@ -12,7 +12,14 @@ spec:
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
storage: {{ .Values.persistence.media.capacity }}
|
storage: {{ .Values.persistence.media.capacity }}
|
||||||
storageClassName: {{ default .Values.persistence.storageClass .Values.persistence.media.storageClass }}
|
{{ $storageClass := .Values.persistence.media.storageClass | default .Values.persistence.storageClass }}
|
||||||
|
{{- if $storageClass }}
|
||||||
|
{{- if (eq "-" $storageClass) }}
|
||||||
|
storageClassName: ""
|
||||||
|
{{- else }}
|
||||||
|
storageClassName: "{{ $storageClass }}"
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
{{ if not .Values.persistence.jetstream.existingClaim }}
|
{{ if not .Values.persistence.jetstream.existingClaim }}
|
||||||
---
|
---
|
||||||
|
@ -28,7 +35,14 @@ spec:
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
storage: {{ .Values.persistence.jetstream.capacity }}
|
storage: {{ .Values.persistence.jetstream.capacity }}
|
||||||
storageClassName: {{ default .Values.persistence.storageClass .Values.persistence.jetstream.storageClass }}
|
{{ $storageClass := .Values.persistence.jetstream.storageClass | default .Values.persistence.storageClass }}
|
||||||
|
{{- if $storageClass }}
|
||||||
|
{{- if (eq "-" $storageClass) }}
|
||||||
|
storageClassName: ""
|
||||||
|
{{- else }}
|
||||||
|
storageClassName: "{{ $storageClass }}"
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
{{ if not .Values.persistence.search.existingClaim }}
|
{{ if not .Values.persistence.search.existingClaim }}
|
||||||
---
|
---
|
||||||
|
@ -44,5 +58,12 @@ spec:
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
storage: {{ .Values.persistence.search.capacity }}
|
storage: {{ .Values.persistence.search.capacity }}
|
||||||
storageClassName: {{ default .Values.persistence.storageClass .Values.persistence.search.storageClass }}
|
{{ $storageClass := .Values.persistence.search.storageClass | default .Values.persistence.storageClass }}
|
||||||
|
{{- if $storageClass }}
|
||||||
|
{{- if (eq "-" $storageClass) }}
|
||||||
|
storageClassName: ""
|
||||||
|
{{- else }}
|
||||||
|
storageClassName: "{{ $storageClass }}"
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
|
@ -26,7 +26,13 @@ persistence:
|
||||||
# -- The storage class to use for volume claims.
|
# -- The storage class to use for volume claims.
|
||||||
# Used unless specified at the specific component.
|
# Used unless specified at the specific component.
|
||||||
# Defaults to the cluster default storage class.
|
# Defaults to the cluster default storage class.
|
||||||
storageClass: ""
|
## If defined, storageClassName: <storageClass>
|
||||||
|
## If set to "-", storageClassName: "", which disables dynamic provisioning
|
||||||
|
## If undefined (the default) or set to null, no storageClassName spec is
|
||||||
|
## set, choosing the default provisioner. (gp2 on AWS, standard on
|
||||||
|
## GKE, AWS & OpenStack)
|
||||||
|
##
|
||||||
|
# storageClass: ""
|
||||||
jetstream:
|
jetstream:
|
||||||
# -- Use an existing volume claim for jetstream
|
# -- Use an existing volume claim for jetstream
|
||||||
existingClaim: ""
|
existingClaim: ""
|
||||||
|
@ -34,7 +40,13 @@ persistence:
|
||||||
capacity: "1Gi"
|
capacity: "1Gi"
|
||||||
# -- The storage class to use for volume claims.
|
# -- The storage class to use for volume claims.
|
||||||
# Defaults to persistence.storageClass
|
# Defaults to persistence.storageClass
|
||||||
storageClass: ""
|
## If defined, storageClassName: <storageClass>
|
||||||
|
## If set to "-", storageClassName: "", which disables dynamic provisioning
|
||||||
|
## If undefined (the default) or set to null, no storageClassName spec is
|
||||||
|
## set, choosing the default provisioner. (gp2 on AWS, standard on
|
||||||
|
## GKE, AWS & OpenStack)
|
||||||
|
##
|
||||||
|
# storageClass: ""
|
||||||
media:
|
media:
|
||||||
# -- Use an existing volume claim for media files
|
# -- Use an existing volume claim for media files
|
||||||
existingClaim: ""
|
existingClaim: ""
|
||||||
|
@ -42,7 +54,13 @@ persistence:
|
||||||
capacity: "1Gi"
|
capacity: "1Gi"
|
||||||
# -- The storage class to use for volume claims.
|
# -- The storage class to use for volume claims.
|
||||||
# Defaults to persistence.storageClass
|
# Defaults to persistence.storageClass
|
||||||
storageClass: ""
|
## If defined, storageClassName: <storageClass>
|
||||||
|
## If set to "-", storageClassName: "", which disables dynamic provisioning
|
||||||
|
## If undefined (the default) or set to null, no storageClassName spec is
|
||||||
|
## set, choosing the default provisioner. (gp2 on AWS, standard on
|
||||||
|
## GKE, AWS & OpenStack)
|
||||||
|
##
|
||||||
|
# storageClass: ""
|
||||||
search:
|
search:
|
||||||
# -- Use an existing volume claim for the fulltext search index
|
# -- Use an existing volume claim for the fulltext search index
|
||||||
existingClaim: ""
|
existingClaim: ""
|
||||||
|
@ -50,7 +68,13 @@ persistence:
|
||||||
capacity: "1Gi"
|
capacity: "1Gi"
|
||||||
# -- The storage class to use for volume claims.
|
# -- The storage class to use for volume claims.
|
||||||
# Defaults to persistence.storageClass
|
# Defaults to persistence.storageClass
|
||||||
storageClass: ""
|
## If defined, storageClassName: <storageClass>
|
||||||
|
## If set to "-", storageClassName: "", which disables dynamic provisioning
|
||||||
|
## If undefined (the default) or set to null, no storageClassName spec is
|
||||||
|
## set, choosing the default provisioner. (gp2 on AWS, standard on
|
||||||
|
## GKE, AWS & OpenStack)
|
||||||
|
##
|
||||||
|
# storageClass: ""
|
||||||
|
|
||||||
# -- Add additional volumes to the Dendrite Pod
|
# -- Add additional volumes to the Dendrite Pod
|
||||||
extraVolumes: []
|
extraVolumes: []
|
||||||
|
|
|
@ -13,8 +13,6 @@ func TestActionJSON(t *testing.T) {
|
||||||
Want Action
|
Want Action
|
||||||
}{
|
}{
|
||||||
{Action{Kind: NotifyAction}},
|
{Action{Kind: NotifyAction}},
|
||||||
{Action{Kind: DontNotifyAction}},
|
|
||||||
{Action{Kind: CoalesceAction}},
|
|
||||||
{Action{Kind: SetTweakAction}},
|
{Action{Kind: SetTweakAction}},
|
||||||
|
|
||||||
{Action{Kind: SetTweakAction, Tweak: SoundTweak, Value: "default"}},
|
{Action{Kind: SetTweakAction, Tweak: SoundTweak, Value: "default"}},
|
||||||
|
|
|
@ -10,6 +10,7 @@ func defaultOverrideRules(userID string) []*Rule {
|
||||||
&mRuleRoomNotifDefinition,
|
&mRuleRoomNotifDefinition,
|
||||||
&mRuleTombstoneDefinition,
|
&mRuleTombstoneDefinition,
|
||||||
&mRuleReactionDefinition,
|
&mRuleReactionDefinition,
|
||||||
|
&mRuleACLsDefinition,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,7 +31,7 @@ var (
|
||||||
RuleID: MRuleMaster,
|
RuleID: MRuleMaster,
|
||||||
Default: true,
|
Default: true,
|
||||||
Enabled: false,
|
Enabled: false,
|
||||||
Actions: []*Action{{Kind: DontNotifyAction}},
|
Actions: []*Action{},
|
||||||
}
|
}
|
||||||
mRuleSuppressNoticesDefinition = Rule{
|
mRuleSuppressNoticesDefinition = Rule{
|
||||||
RuleID: MRuleSuppressNotices,
|
RuleID: MRuleSuppressNotices,
|
||||||
|
@ -43,7 +44,7 @@ var (
|
||||||
Pattern: pointer("m.notice"),
|
Pattern: pointer("m.notice"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Actions: []*Action{{Kind: DontNotifyAction}},
|
Actions: []*Action{},
|
||||||
}
|
}
|
||||||
mRuleMemberEventDefinition = Rule{
|
mRuleMemberEventDefinition = Rule{
|
||||||
RuleID: MRuleMemberEvent,
|
RuleID: MRuleMemberEvent,
|
||||||
|
@ -56,7 +57,7 @@ var (
|
||||||
Pattern: pointer("m.room.member"),
|
Pattern: pointer("m.room.member"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Actions: []*Action{{Kind: DontNotifyAction}},
|
Actions: []*Action{},
|
||||||
}
|
}
|
||||||
mRuleContainsDisplayNameDefinition = Rule{
|
mRuleContainsDisplayNameDefinition = Rule{
|
||||||
RuleID: MRuleContainsDisplayName,
|
RuleID: MRuleContainsDisplayName,
|
||||||
|
@ -152,9 +153,7 @@ var (
|
||||||
Pattern: pointer("m.reaction"),
|
Pattern: pointer("m.reaction"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Actions: []*Action{
|
Actions: []*Action{},
|
||||||
{Kind: DontNotifyAction},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -21,12 +21,12 @@ func TestDefaultRules(t *testing.T) {
|
||||||
// Default override rules
|
// Default override rules
|
||||||
{
|
{
|
||||||
name: ".m.rule.master",
|
name: ".m.rule.master",
|
||||||
inputBytes: []byte(`{"rule_id":".m.rule.master","default":true,"enabled":false,"actions":["dont_notify"]}`),
|
inputBytes: []byte(`{"rule_id":".m.rule.master","default":true,"enabled":false,"actions":[]}`),
|
||||||
want: mRuleMasterDefinition,
|
want: mRuleMasterDefinition,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: ".m.rule.suppress_notices",
|
name: ".m.rule.suppress_notices",
|
||||||
inputBytes: []byte(`{"rule_id":".m.rule.suppress_notices","default":true,"enabled":true,"conditions":[{"kind":"event_match","key":"content.msgtype","pattern":"m.notice"}],"actions":["dont_notify"]}`),
|
inputBytes: []byte(`{"rule_id":".m.rule.suppress_notices","default":true,"enabled":true,"conditions":[{"kind":"event_match","key":"content.msgtype","pattern":"m.notice"}],"actions":[]}`),
|
||||||
want: mRuleSuppressNoticesDefinition,
|
want: mRuleSuppressNoticesDefinition,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -36,7 +36,7 @@ func TestDefaultRules(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: ".m.rule.member_event",
|
name: ".m.rule.member_event",
|
||||||
inputBytes: []byte(`{"rule_id":".m.rule.member_event","default":true,"enabled":true,"conditions":[{"kind":"event_match","key":"type","pattern":"m.room.member"}],"actions":["dont_notify"]}`),
|
inputBytes: []byte(`{"rule_id":".m.rule.member_event","default":true,"enabled":true,"conditions":[{"kind":"event_match","key":"type","pattern":"m.room.member"}],"actions":[]}`),
|
||||||
want: mRuleMemberEventDefinition,
|
want: mRuleMemberEventDefinition,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -16,10 +16,7 @@ func ActionsToTweaks(as []*Action) (ActionKind, map[string]interface{}, error) {
|
||||||
|
|
||||||
for _, a := range as {
|
for _, a := range as {
|
||||||
switch a.Kind {
|
switch a.Kind {
|
||||||
case DontNotifyAction:
|
case DontNotifyAction: // Ignored
|
||||||
// Don't bother processing any further
|
|
||||||
return DontNotifyAction, nil, nil
|
|
||||||
|
|
||||||
case SetTweakAction:
|
case SetTweakAction:
|
||||||
if tweaks == nil {
|
if tweaks == nil {
|
||||||
tweaks = map[string]interface{}{}
|
tweaks = map[string]interface{}{}
|
||||||
|
|
|
@ -17,17 +17,16 @@ func TestActionsToTweaks(t *testing.T) {
|
||||||
{"empty", nil, UnknownAction, nil},
|
{"empty", nil, UnknownAction, nil},
|
||||||
{"zero", []*Action{{}}, UnknownAction, nil},
|
{"zero", []*Action{{}}, UnknownAction, nil},
|
||||||
{"onlyPrimary", []*Action{{Kind: NotifyAction}}, NotifyAction, nil},
|
{"onlyPrimary", []*Action{{Kind: NotifyAction}}, NotifyAction, nil},
|
||||||
{"onlyPrimaryDontNotify", []*Action{{Kind: DontNotifyAction}}, DontNotifyAction, nil},
|
{"onlyPrimaryDontNotify", []*Action{}, UnknownAction, nil},
|
||||||
{"onlyTweak", []*Action{{Kind: SetTweakAction, Tweak: HighlightTweak}}, UnknownAction, map[string]interface{}{"highlight": nil}},
|
{"onlyTweak", []*Action{{Kind: SetTweakAction, Tweak: HighlightTweak}}, UnknownAction, map[string]interface{}{"highlight": nil}},
|
||||||
{"onlyTweakWithValue", []*Action{{Kind: SetTweakAction, Tweak: SoundTweak, Value: "default"}}, UnknownAction, map[string]interface{}{"sound": "default"}},
|
{"onlyTweakWithValue", []*Action{{Kind: SetTweakAction, Tweak: SoundTweak, Value: "default"}}, UnknownAction, map[string]interface{}{"sound": "default"}},
|
||||||
{
|
{
|
||||||
"all",
|
"all",
|
||||||
[]*Action{
|
[]*Action{
|
||||||
{Kind: CoalesceAction},
|
|
||||||
{Kind: SetTweakAction, Tweak: HighlightTweak},
|
{Kind: SetTweakAction, Tweak: HighlightTweak},
|
||||||
{Kind: SetTweakAction, Tweak: SoundTweak, Value: "default"},
|
{Kind: SetTweakAction, Tweak: SoundTweak, Value: "default"},
|
||||||
},
|
},
|
||||||
CoalesceAction,
|
UnknownAction,
|
||||||
map[string]interface{}{"highlight": nil, "sound": "default"},
|
map[string]interface{}{"highlight": nil, "sound": "default"},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ func ValidateRule(kind Kind, rule *Rule) []error {
|
||||||
errs = append(errs, fmt.Errorf("invalid rule ID: %s", rule.RuleID))
|
errs = append(errs, fmt.Errorf("invalid rule ID: %s", rule.RuleID))
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(rule.Actions) == 0 {
|
if rule.Actions == nil {
|
||||||
errs = append(errs, fmt.Errorf("missing actions"))
|
errs = append(errs, fmt.Errorf("missing actions"))
|
||||||
}
|
}
|
||||||
for _, action := range rule.Actions {
|
for _, action := range rule.Actions {
|
||||||
|
|
|
@ -25,7 +25,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
maxUsernameLength = 254 // http://matrix.org/speculator/spec/HEAD/intro.html#user-identifiers TODO account for domain
|
maxUsernameLength = 254 // https://spec.matrix.org/v1.7/appendices/#user-identifiers TODO account for domain
|
||||||
|
|
||||||
minPasswordLength = 8 // http://matrix.org/docs/spec/client_server/r0.2.0.html#password-based
|
minPasswordLength = 8 // http://matrix.org/docs/spec/client_server/r0.2.0.html#password-based
|
||||||
maxPasswordLength = 512 // https://github.com/matrix-org/synapse/blob/v0.20.0/synapse/rest/client/v2_alpha/register.py#L161
|
maxPasswordLength = 512 // https://github.com/matrix-org/synapse/blob/v0.20.0/synapse/rest/client/v2_alpha/register.py#L161
|
||||||
|
|
|
@ -18,7 +18,7 @@ var build string
|
||||||
const (
|
const (
|
||||||
VersionMajor = 0
|
VersionMajor = 0
|
||||||
VersionMinor = 13
|
VersionMinor = 13
|
||||||
VersionPatch = 3
|
VersionPatch = 4
|
||||||
VersionTag = "" // example: "rc1"
|
VersionTag = "" // example: "rc1"
|
||||||
|
|
||||||
gitRevLen = 7 // 7 matches the displayed characters on github.com
|
gitRevLen = 7 // 7 matches the displayed characters on github.com
|
||||||
|
|
|
@ -498,6 +498,13 @@ func (t *missingStateReq) resolveStatesAndCheck(ctx context.Context, roomVersion
|
||||||
roomVersion, gomatrixserverlib.ToPDUs(stateEventList), gomatrixserverlib.ToPDUs(authEventList), func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) {
|
roomVersion, gomatrixserverlib.ToPDUs(stateEventList), gomatrixserverlib.ToPDUs(authEventList), func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) {
|
||||||
return t.inputer.Queryer.QueryUserIDForSender(ctx, roomID, senderID)
|
return t.inputer.Queryer.QueryUserIDForSender(ctx, roomID, senderID)
|
||||||
},
|
},
|
||||||
|
func(eventID string) bool {
|
||||||
|
isRejected, err := t.db.IsEventRejected(ctx, t.roomInfo.RoomNID, eventID)
|
||||||
|
if err != nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return isRejected
|
||||||
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -165,6 +165,13 @@ func (r *Queryer) QueryStateAfterEvents(
|
||||||
info.RoomVersion, gomatrixserverlib.ToPDUs(stateEvents), gomatrixserverlib.ToPDUs(authEvents), func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) {
|
info.RoomVersion, gomatrixserverlib.ToPDUs(stateEvents), gomatrixserverlib.ToPDUs(authEvents), func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) {
|
||||||
return r.QueryUserIDForSender(ctx, roomID, senderID)
|
return r.QueryUserIDForSender(ctx, roomID, senderID)
|
||||||
},
|
},
|
||||||
|
func(eventID string) bool {
|
||||||
|
isRejected, rejectedErr := r.DB.IsEventRejected(ctx, info.RoomNID, eventID)
|
||||||
|
if rejectedErr != nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return isRejected
|
||||||
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("state.ResolveConflictsAdhoc: %w", err)
|
return fmt.Errorf("state.ResolveConflictsAdhoc: %w", err)
|
||||||
|
@ -676,6 +683,13 @@ func (r *Queryer) QueryStateAndAuthChain(
|
||||||
info.RoomVersion, gomatrixserverlib.ToPDUs(stateEvents), gomatrixserverlib.ToPDUs(authEvents), func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) {
|
info.RoomVersion, gomatrixserverlib.ToPDUs(stateEvents), gomatrixserverlib.ToPDUs(authEvents), func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) {
|
||||||
return r.QueryUserIDForSender(ctx, roomID, senderID)
|
return r.QueryUserIDForSender(ctx, roomID, senderID)
|
||||||
},
|
},
|
||||||
|
func(eventID string) bool {
|
||||||
|
isRejected, rejectedErr := r.DB.IsEventRejected(ctx, info.RoomNID, eventID)
|
||||||
|
if rejectedErr != nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return isRejected
|
||||||
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -407,7 +407,9 @@ type fledglingEvent struct {
|
||||||
RoomID string
|
RoomID string
|
||||||
Redacts string
|
Redacts string
|
||||||
Depth int64
|
Depth int64
|
||||||
PrevEvents []interface{}
|
PrevEvents []any
|
||||||
|
AuthEvents []any
|
||||||
|
Content map[string]any
|
||||||
}
|
}
|
||||||
|
|
||||||
func mustCreateEvent(t *testing.T, ev fledglingEvent) (result *types.HeaderedEvent) {
|
func mustCreateEvent(t *testing.T, ev fledglingEvent) (result *types.HeaderedEvent) {
|
||||||
|
@ -424,7 +426,13 @@ func mustCreateEvent(t *testing.T, ev fledglingEvent) (result *types.HeaderedEve
|
||||||
Depth: ev.Depth,
|
Depth: ev.Depth,
|
||||||
PrevEvents: ev.PrevEvents,
|
PrevEvents: ev.PrevEvents,
|
||||||
})
|
})
|
||||||
err := eb.SetContent(map[string]interface{}{})
|
if ev.Content == nil {
|
||||||
|
ev.Content = map[string]any{}
|
||||||
|
}
|
||||||
|
if ev.AuthEvents != nil {
|
||||||
|
eb.AuthEvents = ev.AuthEvents
|
||||||
|
}
|
||||||
|
err := eb.SetContent(ev.Content)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("mustCreateEvent: failed to marshal event content %v", err)
|
t.Fatalf("mustCreateEvent: failed to marshal event content %v", err)
|
||||||
}
|
}
|
||||||
|
@ -1077,3 +1085,103 @@ func TestUpgrade(t *testing.T) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestStateReset(t *testing.T) {
|
||||||
|
alice := test.NewUser(t)
|
||||||
|
bob := test.NewUser(t)
|
||||||
|
charlie := test.NewUser(t)
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
|
||||||
|
// Prepare APIs
|
||||||
|
cfg, processCtx, close := testrig.CreateConfig(t, dbType)
|
||||||
|
defer close()
|
||||||
|
|
||||||
|
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
|
||||||
|
natsInstance := jetstream.NATSInstance{}
|
||||||
|
caches := caching.NewRistrettoCache(128*1024*1024, time.Hour, caching.DisableMetrics)
|
||||||
|
rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, &natsInstance, caches, caching.DisableMetrics)
|
||||||
|
rsAPI.SetFederationAPI(nil, nil)
|
||||||
|
|
||||||
|
// create a new room
|
||||||
|
room := test.NewRoom(t, alice, test.RoomPreset(test.PresetPublicChat))
|
||||||
|
|
||||||
|
// join with Bob and Charlie
|
||||||
|
bobJoinEv := room.CreateAndInsert(t, bob, spec.MRoomMember, map[string]any{"membership": "join"}, test.WithStateKey(bob.ID))
|
||||||
|
charlieJoinEv := room.CreateAndInsert(t, charlie, spec.MRoomMember, map[string]any{"membership": "join"}, test.WithStateKey(charlie.ID))
|
||||||
|
|
||||||
|
// Send and create the room
|
||||||
|
if err := api.SendEvents(ctx, rsAPI, api.KindNew, room.Events(), "test", "test", "test", nil, false); err != nil {
|
||||||
|
t.Errorf("failed to send events: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// send a message
|
||||||
|
bobMsg := room.CreateAndInsert(t, bob, "m.room.message", map[string]any{"body": "hello world"})
|
||||||
|
charlieMsg := room.CreateAndInsert(t, charlie, "m.room.message", map[string]any{"body": "hello world"})
|
||||||
|
|
||||||
|
if err := api.SendEvents(ctx, rsAPI, api.KindNew, []*types.HeaderedEvent{bobMsg, charlieMsg}, "test", "test", "test", nil, false); err != nil {
|
||||||
|
t.Errorf("failed to send events: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bob changes his name
|
||||||
|
expectedDisplayname := "Bob!"
|
||||||
|
bobDisplayname := room.CreateAndInsert(t, bob, spec.MRoomMember, map[string]any{"membership": "join", "displayname": expectedDisplayname}, test.WithStateKey(bob.ID))
|
||||||
|
|
||||||
|
if err := api.SendEvents(ctx, rsAPI, api.KindNew, []*types.HeaderedEvent{bobDisplayname}, "test", "test", "test", nil, false); err != nil {
|
||||||
|
t.Errorf("failed to send events: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Change another state event
|
||||||
|
jrEv := room.CreateAndInsert(t, alice, spec.MRoomJoinRules, gomatrixserverlib.JoinRuleContent{JoinRule: "invite"}, test.WithStateKey(""))
|
||||||
|
if err := api.SendEvents(ctx, rsAPI, api.KindNew, []*types.HeaderedEvent{jrEv}, "test", "test", "test", nil, false); err != nil {
|
||||||
|
t.Errorf("failed to send events: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// send a message
|
||||||
|
bobMsg = room.CreateAndInsert(t, bob, "m.room.message", map[string]any{"body": "hello world"})
|
||||||
|
charlieMsg = room.CreateAndInsert(t, charlie, "m.room.message", map[string]any{"body": "hello world"})
|
||||||
|
|
||||||
|
if err := api.SendEvents(ctx, rsAPI, api.KindNew, []*types.HeaderedEvent{bobMsg, charlieMsg}, "test", "test", "test", nil, false); err != nil {
|
||||||
|
t.Errorf("failed to send events: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Craft the state reset message, which is using Bobs initial join event and the
|
||||||
|
// last message Charlie sent as the prev_events. This should trigger the recalculation
|
||||||
|
// of the "current" state, since the message event does not have state and no missing events in the DB.
|
||||||
|
stateResetMsg := mustCreateEvent(t, fledglingEvent{
|
||||||
|
Type: "m.room.message",
|
||||||
|
SenderID: charlie.ID,
|
||||||
|
RoomID: room.ID,
|
||||||
|
Depth: charlieMsg.Depth() + 1,
|
||||||
|
PrevEvents: []any{
|
||||||
|
bobJoinEv.EventID(),
|
||||||
|
charlieMsg.EventID(),
|
||||||
|
},
|
||||||
|
AuthEvents: []any{
|
||||||
|
room.Events()[0].EventID(), // create event
|
||||||
|
room.Events()[2].EventID(), // PL event
|
||||||
|
charlieJoinEv.EventID(), // Charlie join event
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// Send the state reset message
|
||||||
|
if err := api.SendEvents(ctx, rsAPI, api.KindNew, []*types.HeaderedEvent{stateResetMsg}, "test", "test", "test", nil, false); err != nil {
|
||||||
|
t.Errorf("failed to send events: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate that there is a membership event for Bob
|
||||||
|
bobMembershipEv := api.GetStateEvent(ctx, rsAPI, room.ID, gomatrixserverlib.StateKeyTuple{
|
||||||
|
EventType: spec.MRoomMember,
|
||||||
|
StateKey: bob.ID,
|
||||||
|
})
|
||||||
|
|
||||||
|
if bobMembershipEv == nil {
|
||||||
|
t.Fatalf("Membership event for Bob does not exist. State reset?")
|
||||||
|
} else {
|
||||||
|
// Validate it's the correct membership event
|
||||||
|
if dn := gjson.GetBytes(bobMembershipEv.Content(), "displayname").Str; dn != expectedDisplayname {
|
||||||
|
t.Fatalf("Expected displayname to be %q, got %q", expectedDisplayname, dn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -45,6 +45,7 @@ type StateResolutionStorage interface {
|
||||||
AddState(ctx context.Context, roomNID types.RoomNID, stateBlockNIDs []types.StateBlockNID, state []types.StateEntry) (types.StateSnapshotNID, error)
|
AddState(ctx context.Context, roomNID types.RoomNID, stateBlockNIDs []types.StateBlockNID, state []types.StateEntry) (types.StateSnapshotNID, error)
|
||||||
Events(ctx context.Context, roomVersion gomatrixserverlib.RoomVersion, eventNIDs []types.EventNID) ([]types.Event, error)
|
Events(ctx context.Context, roomVersion gomatrixserverlib.RoomVersion, eventNIDs []types.EventNID) ([]types.Event, error)
|
||||||
EventsFromIDs(ctx context.Context, roomInfo *types.RoomInfo, eventIDs []string) ([]types.Event, error)
|
EventsFromIDs(ctx context.Context, roomInfo *types.RoomInfo, eventIDs []string) ([]types.Event, error)
|
||||||
|
IsEventRejected(ctx context.Context, roomNID types.RoomNID, eventID string) (bool, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type StateResolution struct {
|
type StateResolution struct {
|
||||||
|
@ -1066,6 +1067,13 @@ func (v *StateResolution) resolveConflictsV2(
|
||||||
func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) {
|
func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) {
|
||||||
return v.Querier.QueryUserIDForSender(ctx, roomID, senderID)
|
return v.Querier.QueryUserIDForSender(ctx, roomID, senderID)
|
||||||
},
|
},
|
||||||
|
func(eventID string) bool {
|
||||||
|
isRejected, err := v.db.IsEventRejected(ctx, v.roomInfo.RoomNID, eventID)
|
||||||
|
if err != nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return isRejected
|
||||||
|
},
|
||||||
)
|
)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|
|
@ -250,3 +250,7 @@ func (u *RoomUpdater) MarkEventAsSent(eventNID types.EventNID) error {
|
||||||
func (u *RoomUpdater) MembershipUpdater(targetUserNID types.EventStateKeyNID, targetLocal bool) (*MembershipUpdater, error) {
|
func (u *RoomUpdater) MembershipUpdater(targetUserNID types.EventStateKeyNID, targetLocal bool) (*MembershipUpdater, error) {
|
||||||
return u.d.membershipUpdaterTxn(u.ctx, u.txn, u.roomInfo.RoomNID, targetUserNID, targetLocal)
|
return u.d.membershipUpdaterTxn(u.ctx, u.txn, u.roomInfo.RoomNID, targetUserNID, targetLocal)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *RoomUpdater) IsEventRejected(ctx context.Context, roomNID types.RoomNID, eventID string) (bool, error) {
|
||||||
|
return u.d.IsEventRejected(ctx, roomNID, eventID)
|
||||||
|
}
|
||||||
|
|
|
@ -93,17 +93,15 @@ func (c *ClientAPI) Verify(configErrs *ConfigErrors) {
|
||||||
checkNotEmpty(configErrs, "client_api.recaptcha_sitekey_class", c.RecaptchaSitekeyClass)
|
checkNotEmpty(configErrs, "client_api.recaptcha_sitekey_class", c.RecaptchaSitekeyClass)
|
||||||
}
|
}
|
||||||
// Ensure there is any spam counter measure when enabling registration
|
// Ensure there is any spam counter measure when enabling registration
|
||||||
if !c.RegistrationDisabled && !c.OpenRegistrationWithoutVerificationEnabled {
|
if !c.RegistrationDisabled && !c.OpenRegistrationWithoutVerificationEnabled && !c.RecaptchaEnabled {
|
||||||
if !c.RecaptchaEnabled {
|
configErrs.Add(
|
||||||
configErrs.Add(
|
"You have tried to enable open registration without any secondary verification methods " +
|
||||||
"You have tried to enable open registration without any secondary verification methods " +
|
"(such as reCAPTCHA). By enabling open registration, you are SIGNIFICANTLY " +
|
||||||
"(such as reCAPTCHA). By enabling open registration, you are SIGNIFICANTLY " +
|
"increasing the risk that your server will be used to send spam or abuse, and may result in " +
|
||||||
"increasing the risk that your server will be used to send spam or abuse, and may result in " +
|
"your server being banned from some rooms. If you are ABSOLUTELY CERTAIN you want to do this, " +
|
||||||
"your server being banned from some rooms. If you are ABSOLUTELY CERTAIN you want to do this, " +
|
"start Dendrite with the -really-enable-open-registration command line flag. Otherwise, you " +
|
||||||
"start Dendrite with the -really-enable-open-registration command line flag. Otherwise, you " +
|
"should set the registration_disabled option in your Dendrite config.",
|
||||||
"should set the registration_disabled option in your Dendrite config.",
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,7 +58,7 @@ type mockDB struct {
|
||||||
roomID string
|
roomID string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *mockDB) SelectMembershipForUser(ctx context.Context, roomID string, userID string, pos int64) (string, int, error) {
|
func (s *mockDB) SelectMembershipForUser(ctx context.Context, roomID string, userID string, pos int64) (string, int64, error) {
|
||||||
if roomID == s.roomID {
|
if roomID == s.roomID {
|
||||||
membership, ok := s.currentMembership[userID]
|
membership, ok := s.currentMembership[userID]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|
|
@ -107,7 +107,7 @@ type DatabaseTransaction interface {
|
||||||
// SelectMembershipForUser returns the membership of the user before and including the given position. If no membership can be found
|
// SelectMembershipForUser returns the membership of the user before and including the given position. If no membership can be found
|
||||||
// returns "leave", the topological position and no error. If an error occurs, other than sql.ErrNoRows, returns that and an empty
|
// returns "leave", the topological position and no error. If an error occurs, other than sql.ErrNoRows, returns that and an empty
|
||||||
// string as the membership.
|
// string as the membership.
|
||||||
SelectMembershipForUser(ctx context.Context, roomID, userID string, pos int64) (membership string, topologicalPos int, err error)
|
SelectMembershipForUser(ctx context.Context, roomID, userID string, pos int64) (membership string, topologicalPos int64, err error)
|
||||||
// getUserUnreadNotificationCountsForRooms returns the unread notifications for the given rooms
|
// getUserUnreadNotificationCountsForRooms returns the unread notifications for the given rooms
|
||||||
GetUserUnreadNotificationCountsForRooms(ctx context.Context, userID string, roomIDs map[string]string) (map[string]*eventutil.NotificationData, error)
|
GetUserUnreadNotificationCountsForRooms(ctx context.Context, userID string, roomIDs map[string]string) (map[string]*eventutil.NotificationData, error)
|
||||||
GetPresences(ctx context.Context, userID []string) ([]*types.PresenceInternal, error)
|
GetPresences(ctx context.Context, userID []string) ([]*types.PresenceInternal, error)
|
||||||
|
|
|
@ -131,7 +131,7 @@ func (s *membershipsStatements) SelectMembershipCount(
|
||||||
// string as the membership.
|
// string as the membership.
|
||||||
func (s *membershipsStatements) SelectMembershipForUser(
|
func (s *membershipsStatements) SelectMembershipForUser(
|
||||||
ctx context.Context, txn *sql.Tx, roomID, userID string, pos int64,
|
ctx context.Context, txn *sql.Tx, roomID, userID string, pos int64,
|
||||||
) (membership string, topologyPos int, err error) {
|
) (membership string, topologyPos int64, err error) {
|
||||||
stmt := sqlutil.TxStmt(txn, s.selectMembershipForUserStmt)
|
stmt := sqlutil.TxStmt(txn, s.selectMembershipForUserStmt)
|
||||||
err = stmt.QueryRowContext(ctx, roomID, userID, pos).Scan(&membership, &topologyPos)
|
err = stmt.QueryRowContext(ctx, roomID, userID, pos).Scan(&membership, &topologyPos)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -583,7 +583,7 @@ func (d *Database) GetPresences(ctx context.Context, userIDs []string) ([]*types
|
||||||
return d.Presence.GetPresenceForUsers(ctx, nil, userIDs)
|
return d.Presence.GetPresenceForUsers(ctx, nil, userIDs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Database) SelectMembershipForUser(ctx context.Context, roomID, userID string, pos int64) (membership string, topologicalPos int, err error) {
|
func (d *Database) SelectMembershipForUser(ctx context.Context, roomID, userID string, pos int64) (membership string, topologicalPos int64, err error) {
|
||||||
return d.Memberships.SelectMembershipForUser(ctx, nil, roomID, userID, pos)
|
return d.Memberships.SelectMembershipForUser(ctx, nil, roomID, userID, pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -134,7 +134,7 @@ func (s *membershipsStatements) SelectMembershipCount(
|
||||||
// string as the membership.
|
// string as the membership.
|
||||||
func (s *membershipsStatements) SelectMembershipForUser(
|
func (s *membershipsStatements) SelectMembershipForUser(
|
||||||
ctx context.Context, txn *sql.Tx, roomID, userID string, pos int64,
|
ctx context.Context, txn *sql.Tx, roomID, userID string, pos int64,
|
||||||
) (membership string, topologyPos int, err error) {
|
) (membership string, topologyPos int64, err error) {
|
||||||
stmt := sqlutil.TxStmt(txn, s.selectMembershipForUserStmt)
|
stmt := sqlutil.TxStmt(txn, s.selectMembershipForUserStmt)
|
||||||
err = stmt.QueryRowContext(ctx, roomID, userID, pos).Scan(&membership, &topologyPos)
|
err = stmt.QueryRowContext(ctx, roomID, userID, pos).Scan(&membership, &topologyPos)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -194,7 +194,7 @@ type Receipts interface {
|
||||||
type Memberships interface {
|
type Memberships interface {
|
||||||
UpsertMembership(ctx context.Context, txn *sql.Tx, event *rstypes.HeaderedEvent, streamPos, topologicalPos types.StreamPosition) error
|
UpsertMembership(ctx context.Context, txn *sql.Tx, event *rstypes.HeaderedEvent, streamPos, topologicalPos types.StreamPosition) error
|
||||||
SelectMembershipCount(ctx context.Context, txn *sql.Tx, roomID, membership string, pos types.StreamPosition) (count int, err error)
|
SelectMembershipCount(ctx context.Context, txn *sql.Tx, roomID, membership string, pos types.StreamPosition) (count int, err error)
|
||||||
SelectMembershipForUser(ctx context.Context, txn *sql.Tx, roomID, userID string, pos int64) (membership string, topologicalPos int, err error)
|
SelectMembershipForUser(ctx context.Context, txn *sql.Tx, roomID, userID string, pos int64) (membership string, topologicalPos int64, err error)
|
||||||
PurgeMemberships(ctx context.Context, txn *sql.Tx, roomID string) error
|
PurgeMemberships(ctx context.Context, txn *sql.Tx, roomID string) error
|
||||||
SelectMemberships(
|
SelectMemberships(
|
||||||
ctx context.Context, txn *sql.Tx,
|
ctx context.Context, txn *sql.Tx,
|
||||||
|
|
|
@ -124,7 +124,7 @@ func testUpsert(t *testing.T, ctx context.Context, table tables.Memberships, mem
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to select membership: %s", err)
|
t.Fatalf("failed to select membership: %s", err)
|
||||||
}
|
}
|
||||||
expectedPos := 1
|
var expectedPos int64 = 1
|
||||||
if pos != expectedPos {
|
if pos != expectedPos {
|
||||||
t.Fatalf("expected pos to be %d, got %d", expectedPos, pos)
|
t.Fatalf("expected pos to be %d, got %d", expectedPos, pos)
|
||||||
}
|
}
|
||||||
|
|
|
@ -538,8 +538,8 @@ func (s *OutputRoomEventConsumer) notifyLocal(ctx context.Context, event *rstype
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("pushrules.ActionsToTweaks: %w", err)
|
return fmt.Errorf("pushrules.ActionsToTweaks: %w", err)
|
||||||
}
|
}
|
||||||
// TODO: support coalescing.
|
|
||||||
if a != pushrules.NotifyAction && a != pushrules.CoalesceAction {
|
if a != pushrules.NotifyAction {
|
||||||
log.WithFields(log.Fields{
|
log.WithFields(log.Fields{
|
||||||
"event_id": event.EventID(),
|
"event_id": event.EventID(),
|
||||||
"room_id": event.RoomID().String(),
|
"room_id": event.RoomID().String(),
|
||||||
|
|
|
@ -81,12 +81,8 @@ func Test_evaluatePushRules(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "m.reaction doesn't notify",
|
name: "m.reaction doesn't notify",
|
||||||
eventContent: `{"type":"m.reaction","room_id":"!room:example.com"}`,
|
eventContent: `{"type":"m.reaction","room_id":"!room:example.com"}`,
|
||||||
wantAction: pushrules.DontNotifyAction,
|
wantAction: pushrules.UnknownAction,
|
||||||
wantActions: []*pushrules.Action{
|
wantActions: []*pushrules.Action{},
|
||||||
{
|
|
||||||
Kind: pushrules.DontNotifyAction,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "m.room.message notifies",
|
name: "m.room.message notifies",
|
||||||
|
@ -136,7 +132,7 @@ func Test_evaluatePushRules(t *testing.T) {
|
||||||
t.Fatalf("expected action to be '%s', got '%s'", tc.wantAction, gotAction)
|
t.Fatalf("expected action to be '%s', got '%s'", tc.wantAction, gotAction)
|
||||||
}
|
}
|
||||||
// this is taken from `notifyLocal`
|
// this is taken from `notifyLocal`
|
||||||
if tc.wantNotify && gotAction != pushrules.NotifyAction && gotAction != pushrules.CoalesceAction {
|
if tc.wantNotify && gotAction != pushrules.NotifyAction {
|
||||||
t.Fatalf("expected to notify but didn't")
|
t.Fatalf("expected to notify but didn't")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -180,11 +180,13 @@ func (u *DeviceListUpdater) Start() error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
newStaleLists := dedupeStaleLists(staleLists)
|
||||||
offset, step := time.Second*10, time.Second
|
offset, step := time.Second*10, time.Second
|
||||||
if max := len(staleLists); max > 120 {
|
if max := len(newStaleLists); max > 120 {
|
||||||
step = (time.Second * 120) / time.Duration(max)
|
step = (time.Second * 120) / time.Duration(max)
|
||||||
}
|
}
|
||||||
for _, userID := range staleLists {
|
for _, userID := range newStaleLists {
|
||||||
userID := userID // otherwise we are only sending the last entry
|
userID := userID // otherwise we are only sending the last entry
|
||||||
time.AfterFunc(offset, func() {
|
time.AfterFunc(offset, func() {
|
||||||
u.notifyWorkers(userID)
|
u.notifyWorkers(userID)
|
||||||
|
@ -416,6 +418,12 @@ func (u *DeviceListUpdater) worker(ch chan spec.ServerName) {
|
||||||
|
|
||||||
func (u *DeviceListUpdater) processServer(serverName spec.ServerName) (time.Duration, bool) {
|
func (u *DeviceListUpdater) processServer(serverName spec.ServerName) (time.Duration, bool) {
|
||||||
ctx := u.process.Context()
|
ctx := u.process.Context()
|
||||||
|
// If the process.Context is canceled, there is no need to go further.
|
||||||
|
// This avoids spamming the logs when shutting down
|
||||||
|
if errors.Is(ctx.Err(), context.Canceled) {
|
||||||
|
return defaultWaitTime, false
|
||||||
|
}
|
||||||
|
|
||||||
logger := util.GetLogger(ctx).WithField("server_name", serverName)
|
logger := util.GetLogger(ctx).WithField("server_name", serverName)
|
||||||
deviceListUpdateCount.WithLabelValues(string(serverName)).Inc()
|
deviceListUpdateCount.WithLabelValues(string(serverName)).Inc()
|
||||||
|
|
||||||
|
@ -428,13 +436,6 @@ func (u *DeviceListUpdater) processServer(serverName spec.ServerName) (time.Dura
|
||||||
return waitTime, true
|
return waitTime, true
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func() {
|
|
||||||
for _, userID := range userIDs {
|
|
||||||
// always clear the channel to unblock Update calls regardless of success/failure
|
|
||||||
u.clearChannel(userID)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
for _, userID := range userIDs {
|
for _, userID := range userIDs {
|
||||||
userWait, err := u.processServerUser(ctx, serverName, userID)
|
userWait, err := u.processServerUser(ctx, serverName, userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -461,6 +462,11 @@ func (u *DeviceListUpdater) processServer(serverName spec.ServerName) (time.Dura
|
||||||
func (u *DeviceListUpdater) processServerUser(ctx context.Context, serverName spec.ServerName, userID string) (time.Duration, error) {
|
func (u *DeviceListUpdater) processServerUser(ctx context.Context, serverName spec.ServerName, userID string) (time.Duration, error) {
|
||||||
ctx, cancel := context.WithTimeout(ctx, requestTimeout)
|
ctx, cancel := context.WithTimeout(ctx, requestTimeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
|
// If we are processing more than one user per server, this unblocks further calls to Update
|
||||||
|
// immediately instead of just after **all** users have been processed.
|
||||||
|
defer u.clearChannel(userID)
|
||||||
|
|
||||||
logger := util.GetLogger(ctx).WithFields(logrus.Fields{
|
logger := util.GetLogger(ctx).WithFields(logrus.Fields{
|
||||||
"server_name": serverName,
|
"server_name": serverName,
|
||||||
"user_id": userID,
|
"user_id": userID,
|
||||||
|
@ -579,3 +585,24 @@ func (u *DeviceListUpdater) updateDeviceList(res *fclient.RespUserDevices) error
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// dedupeStaleLists de-duplicates the stateList entries using the domain.
|
||||||
|
// This is used on startup, processServer is getting all users anyway, so
|
||||||
|
// there is no need to send every user to the workers.
|
||||||
|
func dedupeStaleLists(staleLists []string) []string {
|
||||||
|
seenDomains := make(map[spec.ServerName]struct{})
|
||||||
|
newStaleLists := make([]string, 0, len(staleLists))
|
||||||
|
for _, userID := range staleLists {
|
||||||
|
_, domain, err := gomatrixserverlib.SplitID('@', userID)
|
||||||
|
if err != nil {
|
||||||
|
// non-fatal and should not block starting up
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if _, ok := seenDomains[domain]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
newStaleLists = append(newStaleLists, userID)
|
||||||
|
seenDomains[domain] = struct{}{}
|
||||||
|
}
|
||||||
|
return newStaleLists
|
||||||
|
}
|
||||||
|
|
|
@ -428,3 +428,49 @@ func TestDeviceListUpdater_CleanUp(t *testing.T) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_dedupeStateList(t *testing.T) {
|
||||||
|
alice := "@alice:localhost"
|
||||||
|
bob := "@bob:localhost"
|
||||||
|
charlie := "@charlie:notlocalhost"
|
||||||
|
invalidUserID := "iaminvalid:localhost"
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
staleLists []string
|
||||||
|
want []string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "empty stateLists",
|
||||||
|
staleLists: []string{},
|
||||||
|
want: []string{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "single entry",
|
||||||
|
staleLists: []string{alice},
|
||||||
|
want: []string{alice},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multiple entries without dupe servers",
|
||||||
|
staleLists: []string{alice, charlie},
|
||||||
|
want: []string{alice, charlie},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multiple entries with dupe servers",
|
||||||
|
staleLists: []string{alice, bob, charlie},
|
||||||
|
want: []string{alice, charlie},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "list with invalid userID",
|
||||||
|
staleLists: []string{alice, bob, invalidUserID},
|
||||||
|
want: []string{alice},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if got := dedupeStaleLists(tt.staleLists); !reflect.DeepEqual(got, tt.want) {
|
||||||
|
t.Errorf("dedupeStaleLists() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package storage_test
|
package storage_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -758,3 +759,53 @@ func TestDeviceKeysStreamIDGeneration(t *testing.T) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestOneTimeKeys(t *testing.T) {
|
||||||
|
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
|
||||||
|
db, clean := mustCreateKeyDatabase(t, dbType)
|
||||||
|
defer clean()
|
||||||
|
userID := "@alice:localhost"
|
||||||
|
deviceID := "alice_device"
|
||||||
|
otk := api.OneTimeKeys{
|
||||||
|
UserID: userID,
|
||||||
|
DeviceID: deviceID,
|
||||||
|
KeyJSON: map[string]json.RawMessage{"curve25519:KEY1": []byte(`{"key":"v1"}`)},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a one time key to the DB
|
||||||
|
_, err := db.StoreOneTimeKeys(ctx, otk)
|
||||||
|
MustNotError(t, err)
|
||||||
|
|
||||||
|
// Check the count of one time keys is correct
|
||||||
|
count, err := db.OneTimeKeysCount(ctx, userID, deviceID)
|
||||||
|
MustNotError(t, err)
|
||||||
|
if count.KeyCount["curve25519"] != 1 {
|
||||||
|
t.Fatalf("Expected 1 key, got %d", count.KeyCount["curve25519"])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the actual key contents are correct
|
||||||
|
keysJSON, err := db.ExistingOneTimeKeys(ctx, userID, deviceID, []string{"curve25519:KEY1"})
|
||||||
|
MustNotError(t, err)
|
||||||
|
keyJSON, err := keysJSON["curve25519:KEY1"].MarshalJSON()
|
||||||
|
MustNotError(t, err)
|
||||||
|
if !bytes.Equal(keyJSON, []byte(`{"key":"v1"}`)) {
|
||||||
|
t.Fatalf("Existing keys do not match expected. Got %v", keysJSON["curve25519:KEY1"])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Claim a one time key from the database. This should remove it from the database.
|
||||||
|
claimedKeys, err := db.ClaimKeys(ctx, map[string]map[string]string{userID: {deviceID: "curve25519"}})
|
||||||
|
MustNotError(t, err)
|
||||||
|
|
||||||
|
// Check the claimed key contents are correct
|
||||||
|
if !reflect.DeepEqual(claimedKeys[0], otk) {
|
||||||
|
t.Fatalf("Expected to claim stored key %v. Got %v", otk, claimedKeys[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the count of one time keys is now zero
|
||||||
|
count, err = db.OneTimeKeysCount(ctx, userID, deviceID)
|
||||||
|
MustNotError(t, err)
|
||||||
|
if count.KeyCount["curve25519"] != 0 {
|
||||||
|
t.Fatalf("Expected 0 keys, got %d", count.KeyCount["curve25519"])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue