mirror of
https://github.com/matrix-org/dendrite.git
synced 2026-01-03 04:03:09 -06:00
Merge branch 'matrix-org:main' into main
This commit is contained in:
commit
42e50a44fa
|
|
@ -74,6 +74,10 @@ $ cp dendrite-config.yaml dendrite.yaml
|
||||||
|
|
||||||
# Build and run the server:
|
# Build and run the server:
|
||||||
$ ./bin/dendrite-monolith-server --tls-cert server.crt --tls-key server.key --config dendrite.yaml
|
$ ./bin/dendrite-monolith-server --tls-cert server.crt --tls-key server.key --config dendrite.yaml
|
||||||
|
|
||||||
|
# Create an user account (add -admin for an admin user).
|
||||||
|
# Specify the localpart only, e.g. 'alice' for '@alice:domain.com'
|
||||||
|
$ ./bin/create-account --config dendrite.yaml -username alice
|
||||||
```
|
```
|
||||||
|
|
||||||
Then point your favourite Matrix client at `http://localhost:8008` or `https://localhost:8448`.
|
Then point your favourite Matrix client at `http://localhost:8008` or `https://localhost:8448`.
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ echo "Installing golangci-lint..."
|
||||||
|
|
||||||
# Make a backup of go.{mod,sum} first
|
# Make a backup of go.{mod,sum} first
|
||||||
cp go.mod go.mod.bak && cp go.sum go.sum.bak
|
cp go.mod go.mod.bak && cp go.sum go.sum.bak
|
||||||
go get github.com/golangci/golangci-lint/cmd/golangci-lint@v1.41.1
|
go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.45.2
|
||||||
|
|
||||||
# Run linting
|
# Run linting
|
||||||
echo "Looking for lint..."
|
echo "Looking for lint..."
|
||||||
|
|
@ -33,7 +33,7 @@ echo "Looking for lint..."
|
||||||
# Capture exit code to ensure go.{mod,sum} is restored before exiting
|
# Capture exit code to ensure go.{mod,sum} is restored before exiting
|
||||||
exit_code=0
|
exit_code=0
|
||||||
|
|
||||||
PATH="$PATH:${GOPATH:-~/go}/bin" golangci-lint run $args || exit_code=1
|
PATH="$PATH:$(go env GOPATH)/bin" golangci-lint run $args || exit_code=1
|
||||||
|
|
||||||
# Restore go.{mod,sum}
|
# Restore go.{mod,sum}
|
||||||
mv go.mod.bak go.mod && mv go.sum.bak go.sum
|
mv go.mod.bak go.mod && mv go.sum.bak go.sum
|
||||||
|
|
|
||||||
49
clientapi/routing/admin.go
Normal file
49
clientapi/routing/admin.go
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
package routing
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
"github.com/matrix-org/dendrite/clientapi/jsonerror"
|
||||||
|
"github.com/matrix-org/dendrite/internal/httputil"
|
||||||
|
roomserverAPI "github.com/matrix-org/dendrite/roomserver/api"
|
||||||
|
userapi "github.com/matrix-org/dendrite/userapi/api"
|
||||||
|
"github.com/matrix-org/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
func AdminEvacuateRoom(req *http.Request, device *userapi.Device, rsAPI roomserverAPI.RoomserverInternalAPI) util.JSONResponse {
|
||||||
|
if device.AccountType != userapi.AccountTypeAdmin {
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusForbidden,
|
||||||
|
JSON: jsonerror.Forbidden("This API can only be used by admin users."),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||||
|
if err != nil {
|
||||||
|
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{}
|
||||||
|
rsAPI.PerformAdminEvacuateRoom(
|
||||||
|
req.Context(),
|
||||||
|
&roomserverAPI.PerformAdminEvacuateRoomRequest{
|
||||||
|
RoomID: roomID,
|
||||||
|
},
|
||||||
|
res,
|
||||||
|
)
|
||||||
|
if err := res.Error; err != nil {
|
||||||
|
return err.JSONResponse()
|
||||||
|
}
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: 200,
|
||||||
|
JSON: map[string]interface{}{
|
||||||
|
"affected": res.Affected,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -122,40 +122,7 @@ func Setup(
|
||||||
|
|
||||||
dendriteAdminRouter.Handle("/admin/evacuateRoom/{roomID}",
|
dendriteAdminRouter.Handle("/admin/evacuateRoom/{roomID}",
|
||||||
httputil.MakeAuthAPI("admin_evacuate_room", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
httputil.MakeAuthAPI("admin_evacuate_room", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||||
if device.AccountType != userapi.AccountTypeAdmin {
|
return AdminEvacuateRoom(req, device, rsAPI)
|
||||||
return util.JSONResponse{
|
|
||||||
Code: http.StatusForbidden,
|
|
||||||
JSON: jsonerror.Forbidden("This API can only be used by admin users."),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
|
||||||
if err != nil {
|
|
||||||
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{}
|
|
||||||
rsAPI.PerformAdminEvacuateRoom(
|
|
||||||
req.Context(),
|
|
||||||
&roomserverAPI.PerformAdminEvacuateRoomRequest{
|
|
||||||
RoomID: roomID,
|
|
||||||
},
|
|
||||||
res,
|
|
||||||
)
|
|
||||||
if err := res.Error; err != nil {
|
|
||||||
return err.JSONResponse()
|
|
||||||
}
|
|
||||||
return util.JSONResponse{
|
|
||||||
Code: 200,
|
|
||||||
JSON: map[string]interface{}{
|
|
||||||
"affected": res.Affected,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}),
|
}),
|
||||||
).Methods(http.MethodGet, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import (
|
||||||
keyapi "github.com/matrix-org/dendrite/keyserver/api"
|
keyapi "github.com/matrix-org/dendrite/keyserver/api"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
"github.com/matrix-org/util"
|
"github.com/matrix-org/util"
|
||||||
|
"github.com/tidwall/gjson"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetUserDevices for the given user id
|
// GetUserDevices for the given user id
|
||||||
|
|
@ -69,9 +70,14 @@ func GetUserDevices(
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
displayName := dev.DisplayName
|
||||||
|
if displayName == "" {
|
||||||
|
displayName = gjson.GetBytes(dev.DeviceKeys.KeyJSON, "unsigned.device_display_name").Str
|
||||||
|
}
|
||||||
|
|
||||||
device := gomatrixserverlib.RespUserDevice{
|
device := gomatrixserverlib.RespUserDevice{
|
||||||
DeviceID: dev.DeviceID,
|
DeviceID: dev.DeviceID,
|
||||||
DisplayName: dev.DisplayName,
|
DisplayName: displayName,
|
||||||
Keys: key,
|
Keys: key,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -632,43 +632,55 @@ func (a *KeyInternalAPI) uploadLocalDeviceKeys(ctx context.Context, req *api.Per
|
||||||
}
|
}
|
||||||
|
|
||||||
var keysToStore []api.DeviceMessage
|
var keysToStore []api.DeviceMessage
|
||||||
// assert that the user ID / device ID are not lying for each key
|
|
||||||
for _, key := range req.DeviceKeys {
|
|
||||||
var serverName gomatrixserverlib.ServerName
|
|
||||||
_, serverName, err = gomatrixserverlib.SplitID('@', key.UserID)
|
|
||||||
if err != nil {
|
|
||||||
continue // ignore invalid users
|
|
||||||
}
|
|
||||||
if serverName != a.ThisServer {
|
|
||||||
continue // ignore remote users
|
|
||||||
}
|
|
||||||
if len(key.KeyJSON) == 0 {
|
|
||||||
keysToStore = append(keysToStore, key.WithStreamID(0))
|
|
||||||
continue // deleted keys don't need sanity checking
|
|
||||||
}
|
|
||||||
// check that the device in question actually exists in the user
|
|
||||||
// API before we try and store a key for it
|
|
||||||
if _, ok := existingDeviceMap[key.DeviceID]; !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
gotUserID := gjson.GetBytes(key.KeyJSON, "user_id").Str
|
|
||||||
gotDeviceID := gjson.GetBytes(key.KeyJSON, "device_id").Str
|
|
||||||
if gotUserID == key.UserID && gotDeviceID == key.DeviceID {
|
|
||||||
keysToStore = append(keysToStore, key.WithStreamID(0))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
res.KeyError(key.UserID, key.DeviceID, &api.KeyError{
|
|
||||||
Err: fmt.Sprintf(
|
|
||||||
"user_id or device_id mismatch: users: %s - %s, devices: %s - %s",
|
|
||||||
gotUserID, key.UserID, gotDeviceID, key.DeviceID,
|
|
||||||
),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if req.OnlyDisplayNameUpdates {
|
if req.OnlyDisplayNameUpdates {
|
||||||
// add the display name field from keysToStore into existingKeys
|
for _, existingKey := range existingKeys {
|
||||||
keysToStore = appendDisplayNames(existingKeys, keysToStore)
|
for _, newKey := range req.DeviceKeys {
|
||||||
|
switch {
|
||||||
|
case existingKey.UserID != newKey.UserID:
|
||||||
|
continue
|
||||||
|
case existingKey.DeviceID != newKey.DeviceID:
|
||||||
|
continue
|
||||||
|
case existingKey.DisplayName != newKey.DisplayName:
|
||||||
|
existingKey.DisplayName = newKey.DisplayName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
keysToStore = append(keysToStore, existingKey)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// assert that the user ID / device ID are not lying for each key
|
||||||
|
for _, key := range req.DeviceKeys {
|
||||||
|
var serverName gomatrixserverlib.ServerName
|
||||||
|
_, serverName, err = gomatrixserverlib.SplitID('@', key.UserID)
|
||||||
|
if err != nil {
|
||||||
|
continue // ignore invalid users
|
||||||
|
}
|
||||||
|
if serverName != a.ThisServer {
|
||||||
|
continue // ignore remote users
|
||||||
|
}
|
||||||
|
if len(key.KeyJSON) == 0 {
|
||||||
|
keysToStore = append(keysToStore, key.WithStreamID(0))
|
||||||
|
continue // deleted keys don't need sanity checking
|
||||||
|
}
|
||||||
|
// check that the device in question actually exists in the user
|
||||||
|
// API before we try and store a key for it
|
||||||
|
if _, ok := existingDeviceMap[key.DeviceID]; !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
gotUserID := gjson.GetBytes(key.KeyJSON, "user_id").Str
|
||||||
|
gotDeviceID := gjson.GetBytes(key.KeyJSON, "device_id").Str
|
||||||
|
if gotUserID == key.UserID && gotDeviceID == key.DeviceID {
|
||||||
|
keysToStore = append(keysToStore, key.WithStreamID(0))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
res.KeyError(key.UserID, key.DeviceID, &api.KeyError{
|
||||||
|
Err: fmt.Sprintf(
|
||||||
|
"user_id or device_id mismatch: users: %s - %s, devices: %s - %s",
|
||||||
|
gotUserID, key.UserID, gotDeviceID, key.DeviceID,
|
||||||
|
),
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// store the device keys and emit changes
|
// store the device keys and emit changes
|
||||||
|
|
@ -764,16 +776,3 @@ func emitDeviceKeyChanges(producer KeyChangeProducer, existing, new []api.Device
|
||||||
}
|
}
|
||||||
return producer.ProduceKeyChanges(keysAdded)
|
return producer.ProduceKeyChanges(keysAdded)
|
||||||
}
|
}
|
||||||
|
|
||||||
func appendDisplayNames(existing, new []api.DeviceMessage) []api.DeviceMessage {
|
|
||||||
for i, existingDevice := range existing {
|
|
||||||
for _, newDevice := range new {
|
|
||||||
if existingDevice.DeviceID != newDevice.DeviceID {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
existingDevice.DisplayName = newDevice.DisplayName
|
|
||||||
existing[i] = existingDevice
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return existing
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -123,11 +123,19 @@ func TestThumbnailsStorage(t *testing.T) {
|
||||||
t.Fatalf("expected %d stored thumbnail metadata, got %d", len(thumbnails), len(gotMediadatas))
|
t.Fatalf("expected %d stored thumbnail metadata, got %d", len(thumbnails), len(gotMediadatas))
|
||||||
}
|
}
|
||||||
for i := range gotMediadatas {
|
for i := range gotMediadatas {
|
||||||
if !reflect.DeepEqual(thumbnails[i].MediaMetadata, gotMediadatas[i].MediaMetadata) {
|
// metadata may be returned in a different order than it was stored, perform a search
|
||||||
t.Fatalf("expected metadata %+v, got %v", thumbnails[i].MediaMetadata, gotMediadatas[i].MediaMetadata)
|
metaDataMatches := func() bool {
|
||||||
|
for _, t := range thumbnails {
|
||||||
|
if reflect.DeepEqual(t.MediaMetadata, gotMediadatas[i].MediaMetadata) && reflect.DeepEqual(t.ThumbnailSize, gotMediadatas[i].ThumbnailSize) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(thumbnails[i].ThumbnailSize, gotMediadatas[i].ThumbnailSize) {
|
|
||||||
t.Fatalf("expected metadata %+v, got %v", thumbnails[i].ThumbnailSize, gotMediadatas[i].ThumbnailSize)
|
if !metaDataMatches() {
|
||||||
|
t.Fatalf("expected metadata %+v, got %+v", thumbnails[i].MediaMetadata, gotMediadatas[i].MediaMetadata)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -145,6 +145,10 @@ func (p *PresenceStreamProvider) IncrementalSync(
|
||||||
p.cache.Store(cacheKey, presence)
|
p.cache.Store(cacheKey, presence)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(req.Response.Presence.Events) == 0 {
|
||||||
|
return to
|
||||||
|
}
|
||||||
|
|
||||||
return lastPos
|
return lastPos
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -168,7 +168,7 @@ func Test_Devices(t *testing.T) {
|
||||||
|
|
||||||
devices2, err := db.GetDevicesByID(ctx, deviceIDs)
|
devices2, err := db.GetDevicesByID(ctx, deviceIDs)
|
||||||
assert.NoError(t, err, "unable to get devices by id")
|
assert.NoError(t, err, "unable to get devices by id")
|
||||||
assert.Equal(t, devices, devices2)
|
assert.ElementsMatch(t, devices, devices2)
|
||||||
|
|
||||||
// Update device
|
// Update device
|
||||||
newName := "new display name"
|
newName := "new display name"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue