Merge branch 'main' of github.com:element-hq/dendrite into msc3861

This commit is contained in:
Roman Isaev 2025-01-17 02:55:30 +00:00
commit 6833e99558
No known key found for this signature in database
GPG key ID: 7BE2B6A6C89AEC7F
22 changed files with 519 additions and 159 deletions

View file

@ -3,6 +3,6 @@
<!-- Please read https://matrix-org.github.io/dendrite/development/contributing before submitting your pull request --> <!-- Please read https://matrix-org.github.io/dendrite/development/contributing before submitting your pull request -->
* [ ] I have added Go unit tests or [Complement integration tests](https://github.com/matrix-org/complement) for this PR _or_ I have justified why this PR doesn't need tests * [ ] I have added Go unit tests or [Complement integration tests](https://github.com/matrix-org/complement) for this PR _or_ I have justified why this PR doesn't need tests
* [ ] Pull request includes a [sign off below using a legally identifiable name](https://matrix-org.github.io/dendrite/development/contributing#sign-off) _or_ I have already signed off privately * [ ] Pull request includes a [sign off below](https://element-hq.github.io/dendrite/development/contributing#sign-off) _or_ I have already signed off privately
Signed-off-by: `Your Name <your@email.example.org>` Signed-off-by: `Your Name <your@email.example.org>`

View file

@ -98,7 +98,7 @@ jobs:
output: "trivy-results.sarif" output: "trivy-results.sarif"
- name: Upload Trivy scan results to GitHub Security tab - name: Upload Trivy scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v2 uses: github/codeql-action/upload-sarif@v3
with: with:
sarif_file: "trivy-results.sarif" sarif_file: "trivy-results.sarif"

View file

@ -27,7 +27,7 @@ jobs:
git config user.email "$GITHUB_ACTOR@users.noreply.github.com" git config user.email "$GITHUB_ACTOR@users.noreply.github.com"
- name: Install Helm - name: Install Helm
uses: azure/setup-helm@v3 uses: azure/setup-helm@v4
with: with:
version: v3.10.0 version: v3.10.0

View file

@ -20,7 +20,7 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: with:
fetch-depth: 0 fetch-depth: 0
- uses: azure/setup-helm@v3 - uses: azure/setup-helm@v4
with: with:
version: v3.10.0 version: v3.10.0
- uses: actions/setup-python@v5 - uses: actions/setup-python@v5

View file

@ -1,5 +1,23 @@
# Changelog # Changelog
## Dendrite 0.14.1 (2025-01-16)
### ⚠ Important
This is a security release, [gomatrixserverlib](https://github.com/matrix-org/gomatrixserverlib) was vulnerable to
server-side request forgery, serving content from a private network it can access, under certain conditions.
Upgrading to this version is **highly** recommended.
### Security
- Support for blocking access to certain networks, fixing [CVE-2024-52594](https://www.cve.org/CVERecord?id=CVE-2024-52594) and
[GHSA-4ff6-858j-r822](https://github.com/matrix-org/gomatrixserverlib/security/advisories/GHSA-4ff6-858j-r822)
### Fixes
- Speed-up loading server ACLs on startup, this is mostly noticeable on larger instances with many rooms.
## Dendrite 0.14.0 (2024-12-18) ## Dendrite 0.14.0 (2024-12-18)
This is the first release after forking matrix-org/dendrite, this repository is now licensed under AGPLv3.0. This is the first release after forking matrix-org/dendrite, this repository is now licensed under AGPLv3.0.

View file

@ -7,11 +7,12 @@
package routing package routing
import ( import (
"context"
"net/http" "net/http"
"slices"
"strings"
"time" "time"
"github.com/sirupsen/logrus"
"github.com/element-hq/dendrite/clientapi/auth" "github.com/element-hq/dendrite/clientapi/auth"
"github.com/element-hq/dendrite/clientapi/auth/authtypes" "github.com/element-hq/dendrite/clientapi/auth/authtypes"
"github.com/element-hq/dendrite/clientapi/httputil" "github.com/element-hq/dendrite/clientapi/httputil"
@ -29,10 +30,15 @@ type crossSigningRequest struct {
Auth newPasswordAuth `json:"auth"` Auth newPasswordAuth `json:"auth"`
} }
type UploadKeysAPI interface {
QueryKeys(ctx context.Context, req *api.QueryKeysRequest, res *api.QueryKeysResponse)
api.UploadDeviceKeysAPI
}
func UploadCrossSigningDeviceKeys( func UploadCrossSigningDeviceKeys(
req *http.Request, userInteractiveAuth *auth.UserInteractive, req *http.Request,
keyserverAPI api.ClientKeyAPI, device *api.Device, keyserverAPI UploadKeysAPI, device *api.Device,
accountAPI api.ClientUserAPI, cfg *config.ClientAPI, accountAPI auth.GetAccountByPassword, cfg *config.ClientAPI,
) util.JSONResponse { ) util.JSONResponse {
uploadReq := &crossSigningRequest{} uploadReq := &crossSigningRequest{}
uploadRes := &api.PerformUploadDeviceKeysResponse{} uploadRes := &api.PerformUploadDeviceKeysResponse{}
@ -41,121 +47,58 @@ func UploadCrossSigningDeviceKeys(
if resErr != nil { if resErr != nil {
return *resErr return *resErr
} }
sessionID := uploadReq.Auth.Session
if sessionID == "" {
sessionID = util.RandomString(sessionIDLength)
}
isCrossSigningSetup := false // Query existing keys to determine if UIA is required
masterKeyUpdatableWithoutUIA := false keyResp := api.QueryKeysResponse{}
{ keyserverAPI.QueryKeys(req.Context(), &api.QueryKeysRequest{
var keysResp api.QueryMasterKeysResponse UserID: device.UserID,
keyserverAPI.QueryMasterKeys(req.Context(), &api.QueryMasterKeysRequest{UserID: device.UserID}, &keysResp) UserToDevices: map[string][]string{device.UserID: {device.ID}},
if err := keysResp.Error; err != nil { Timeout: time.Second * 10,
return convertKeyError(err) }, &keyResp)
}
if k := keysResp.Key; k != nil { if keyResp.Error != nil {
isCrossSigningSetup = true logrus.WithError(keyResp.Error).Error("Failed to query keys")
if k.UpdatableWithoutUIABeforeMs != nil { return util.JSONResponse{
masterKeyUpdatableWithoutUIA = time.Now().UnixMilli() < *k.UpdatableWithoutUIABeforeMs Code: http.StatusBadRequest,
} JSON: spec.Unknown(keyResp.Error.Error()),
} }
} }
{ existingMasterKey, hasMasterKey := keyResp.MasterKeys[device.UserID]
var keysResp api.QueryKeysResponse requireUIA := false
keyserverAPI.QueryKeys(req.Context(), &api.QueryKeysRequest{UserID: device.UserID, UserToDevices: map[string][]string{device.UserID: []string{}}}, &keysResp) if hasMasterKey {
if err := keysResp.Error; err != nil { // If we have a master key, check if any of the existing keys differ. If they do,
return convertKeyError(err) // we need to re-authenticate the user.
} requireUIA = keysDiffer(existingMasterKey, keyResp, uploadReq, device.UserID)
hasDifferentKeys := func(userID string, uploadReqCSKey *fclient.CrossSigningKey, dbCSKeys map[string]fclient.CrossSigningKey) bool { }
dbCSKey, ok := dbCSKeys[userID]
if !ok {
return true
}
dbKeysExist := len(dbCSKey.Keys) > 0
for keyID, key := range uploadReqCSKey.Keys {
// If dbKeysExist is false and we enter the loop, it means we have received at least one key that is not in the DB, and we want to persist it.
if !dbKeysExist {
return true
}
dbKey, ok := dbCSKey.Keys[keyID]
if !ok || !slices.Equal(dbKey, key) {
return true
}
}
return false
}
if !hasDifferentKeys(device.UserID, &uploadReq.MasterKey, keysResp.MasterKeys) && if requireUIA {
!hasDifferentKeys(device.UserID, &uploadReq.SelfSigningKey, keysResp.SelfSigningKeys) && sessionID := uploadReq.Auth.Session
!hasDifferentKeys(device.UserID, &uploadReq.UserSigningKey, keysResp.UserSigningKeys) { if sessionID == "" {
sessionID = util.RandomString(sessionIDLength)
}
if uploadReq.Auth.Type != authtypes.LoginTypePassword {
return util.JSONResponse{ return util.JSONResponse{
Code: http.StatusOK, Code: http.StatusUnauthorized,
JSON: map[int]interface{}{}, JSON: newUserInteractiveResponse(
sessionID,
[]authtypes.Flow{
{
Stages: []authtypes.LoginType{authtypes.LoginTypePassword},
},
},
nil,
),
} }
} }
} typePassword := auth.LoginTypePassword{
GetAccountByPassword: accountAPI,
if isCrossSigningSetup { Config: cfg,
// With MSC3861, UIA is not possible. Instead, the auth service has to explicitly mark the master key as replaceable.
if cfg.MSCs.MSC3861Enabled() {
if !masterKeyUpdatableWithoutUIA {
url := ""
if m := cfg.MSCs.MSC3861; m.AccountManagementURL != "" {
url = strings.Join([]string{m.AccountManagementURL, "?action=", CrossSigningResetStage}, "")
} else {
url = m.Issuer
}
return util.JSONResponse{
Code: http.StatusUnauthorized,
JSON: newUserInteractiveResponse(
"dummy",
[]authtypes.Flow{
{
Stages: []authtypes.LoginType{CrossSigningResetStage},
},
},
map[string]interface{}{
CrossSigningResetStage: map[string]string{
"url": url,
},
},
strings.Join([]string{
"To reset your end-to-end encryption cross-signing identity, you first need to approve it at",
url,
"and then try again.",
}, " "),
),
}
}
// XXX: is it necessary?
sessions.addCompletedSessionStage(sessionID, CrossSigningResetStage)
} else {
if uploadReq.Auth.Type != authtypes.LoginTypePassword {
return util.JSONResponse{
Code: http.StatusUnauthorized,
JSON: newUserInteractiveResponse(
sessionID,
[]authtypes.Flow{
{
Stages: []authtypes.LoginType{authtypes.LoginTypePassword},
},
},
nil,
"",
),
}
}
typePassword := auth.LoginTypePassword{
GetAccountByPassword: accountAPI.QueryAccountByPassword,
Config: cfg,
}
if _, authErr := typePassword.Login(req.Context(), &uploadReq.Auth.PasswordRequest); authErr != nil {
return *authErr
}
sessions.addCompletedSessionStage(sessionID, authtypes.LoginTypePassword)
} }
if _, authErr := typePassword.Login(req.Context(), &uploadReq.Auth.PasswordRequest); authErr != nil {
return *authErr
}
sessions.addCompletedSessionStage(sessionID, authtypes.LoginTypePassword)
} }
uploadReq.UserID = device.UserID uploadReq.UserID = device.UserID
@ -192,6 +135,21 @@ func UploadCrossSigningDeviceKeys(
} }
} }
func keysDiffer(existingMasterKey fclient.CrossSigningKey, keyResp api.QueryKeysResponse, uploadReq *crossSigningRequest, userID string) bool {
masterKeyEqual := existingMasterKey.Equal(&uploadReq.MasterKey)
if !masterKeyEqual {
return true
}
existingSelfSigningKey := keyResp.SelfSigningKeys[userID]
selfSigningEqual := existingSelfSigningKey.Equal(&uploadReq.SelfSigningKey)
if !selfSigningEqual {
return true
}
existingUserSigningKey := keyResp.UserSigningKeys[userID]
userSigningEqual := existingUserSigningKey.Equal(&uploadReq.UserSigningKey)
return !userSigningEqual
}
func UploadCrossSigningDeviceSignatures(req *http.Request, keyserverAPI api.ClientKeyAPI, device *api.Device) util.JSONResponse { func UploadCrossSigningDeviceSignatures(req *http.Request, keyserverAPI api.ClientKeyAPI, device *api.Device) util.JSONResponse {
uploadReq := &api.PerformUploadDeviceSignaturesRequest{} uploadReq := &api.PerformUploadDeviceSignaturesRequest{}
uploadRes := &api.PerformUploadDeviceSignaturesResponse{} uploadRes := &api.PerformUploadDeviceSignaturesResponse{}

View file

@ -0,0 +1,316 @@
package routing
import (
"bytes"
"context"
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"strings"
"testing"
"github.com/element-hq/dendrite/setup/config"
"github.com/element-hq/dendrite/test"
"github.com/element-hq/dendrite/test/testrig"
"github.com/element-hq/dendrite/userapi/api"
"github.com/matrix-org/gomatrixserverlib"
"github.com/matrix-org/gomatrixserverlib/fclient"
"github.com/matrix-org/gomatrixserverlib/spec"
)
type mockKeyAPI struct {
t *testing.T
userResponses map[string]api.QueryKeysResponse
}
func (m mockKeyAPI) QueryKeys(ctx context.Context, req *api.QueryKeysRequest, res *api.QueryKeysResponse) {
res.MasterKeys = m.userResponses[req.UserID].MasterKeys
res.SelfSigningKeys = m.userResponses[req.UserID].SelfSigningKeys
res.UserSigningKeys = m.userResponses[req.UserID].UserSigningKeys
if m.t != nil {
m.t.Logf("QueryKeys: %+v => %+v", req, res)
}
}
func (m mockKeyAPI) PerformUploadDeviceKeys(ctx context.Context, req *api.PerformUploadDeviceKeysRequest, res *api.PerformUploadDeviceKeysResponse) {
// Just a dummy upload which always succeeds
}
func getAccountByPassword(ctx context.Context, req *api.QueryAccountByPasswordRequest, res *api.QueryAccountByPasswordResponse) error {
res.Exists = true
res.Account = &api.Account{UserID: fmt.Sprintf("@%s:%s", req.Localpart, req.ServerName)}
return nil
}
// Tests that if there is no existing master key for the user, the request is allowed
func Test_UploadCrossSigningDeviceKeys_ValidRequest(t *testing.T) {
req := httptest.NewRequest(http.MethodPost, "/", strings.NewReader(`{
"master_key": {"user_id": "@user:example.com", "usage": ["master"], "keys": {"ed25519:1": "key1"}},
"self_signing_key": {"user_id": "@user:example.com", "usage": ["self_signing"], "keys": {"ed25519:2": "key2"}},
"user_signing_key": {"user_id": "@user:example.com", "usage": ["user_signing"], "keys": {"ed25519:3": "key3"}}
}`))
req.Header.Set("Content-Type", "application/json")
keyserverAPI := &mockKeyAPI{
userResponses: map[string]api.QueryKeysResponse{
"@user:example.com": {},
},
}
device := &api.Device{UserID: "@user:example.com", ID: "device"}
cfg := &config.ClientAPI{}
res := UploadCrossSigningDeviceKeys(req, keyserverAPI, device, getAccountByPassword, cfg)
if res.Code != http.StatusOK {
t.Fatalf("expected status %d, got %d", http.StatusOK, res.Code)
}
}
// Require UIA if there is an existing master key and there is no auth provided.
func Test_UploadCrossSigningDeviceKeys_Unauthorised(t *testing.T) {
userID := "@user:example.com"
// Note that there is no auth field.
request := fclient.CrossSigningKeys{
MasterKey: fclient.CrossSigningKey{
Keys: map[gomatrixserverlib.KeyID]spec.Base64Bytes{"ed25519:1": spec.Base64Bytes("key1")},
Usage: []fclient.CrossSigningKeyPurpose{fclient.CrossSigningKeyPurposeMaster},
UserID: userID,
},
SelfSigningKey: fclient.CrossSigningKey{
Keys: map[gomatrixserverlib.KeyID]spec.Base64Bytes{"ed25519:1": spec.Base64Bytes("key2")},
Usage: []fclient.CrossSigningKeyPurpose{fclient.CrossSigningKeyPurposeSelfSigning},
UserID: userID,
},
UserSigningKey: fclient.CrossSigningKey{
Keys: map[gomatrixserverlib.KeyID]spec.Base64Bytes{"ed25519:1": spec.Base64Bytes("key3")},
Usage: []fclient.CrossSigningKeyPurpose{fclient.CrossSigningKeyPurposeUserSigning},
UserID: userID,
},
}
b := bytes.Buffer{}
m := json.NewEncoder(&b)
err := m.Encode(request)
if err != nil {
t.Fatal(err)
}
req := httptest.NewRequest(http.MethodPost, "/", &b)
req.Header.Set("Content-Type", "application/json")
keyserverAPI := &mockKeyAPI{
t: t,
userResponses: map[string]api.QueryKeysResponse{
"@user:example.com": {
MasterKeys: map[string]fclient.CrossSigningKey{
"@user:example.com": {UserID: "@user:example.com", Usage: []fclient.CrossSigningKeyPurpose{"master"}, Keys: map[gomatrixserverlib.KeyID]spec.Base64Bytes{"ed25519:1": spec.Base64Bytes("key1")}},
},
SelfSigningKeys: nil,
UserSigningKeys: nil,
},
},
}
device := &api.Device{UserID: "@user:example.com", ID: "device"}
cfg := &config.ClientAPI{}
res := UploadCrossSigningDeviceKeys(req, keyserverAPI, device, getAccountByPassword, cfg)
if res.Code != http.StatusUnauthorized {
t.Fatalf("expected status %d, got %d", http.StatusUnauthorized, res.Code)
}
}
// Invalid JSON is rejected
func Test_UploadCrossSigningDeviceKeys_InvalidJSON(t *testing.T) {
req := httptest.NewRequest(http.MethodPost, "/", strings.NewReader(`{
"auth": {"type": "m.login.password", "session": "session", "user": "user", "password": "password"},
"master_key": {"user_id": "@user:example.com", "usage": ["master"], "keys": {"ed25519:1": "key1"}},
"self_signing_key": {"user_id": "@user:example.com", "usage": ["self_signing"], "keys": {"ed25519:2": "key2"}},
"user_signing_key": {"user_id": "@user:example.com", "usage": ["user_signing"], "keys": {"ed25519:3": "key3"}
}`)) // Missing closing brace
req.Header.Set("Content-Type", "application/json")
keyserverAPI := &mockKeyAPI{}
device := &api.Device{UserID: "@user:example.com", ID: "device"}
cfg := &config.ClientAPI{}
res := UploadCrossSigningDeviceKeys(req, keyserverAPI, device, getAccountByPassword, cfg)
if res.Code != http.StatusBadRequest {
t.Fatalf("expected status %d, got %d", http.StatusBadRequest, res.Code)
}
}
// Require UIA if an existing master key is present and the keys differ.
func Test_UploadCrossSigningDeviceKeys_ExistingKeysMismatch(t *testing.T) {
// Again, no auth provided
req := httptest.NewRequest(http.MethodPost, "/", strings.NewReader(`{
"master_key": {"user_id": "@user:example.com", "usage": ["master"], "keys": {"ed25519:1": "key1"}},
"self_signing_key": {"user_id": "@user:example.com", "usage": ["self_signing"], "keys": {"ed25519:2": "key2"}},
"user_signing_key": {"user_id": "@user:example.com", "usage": ["user_signing"], "keys": {"ed25519:3": "key3"}}
}`))
req.Header.Set("Content-Type", "application/json")
keyserverAPI := &mockKeyAPI{
userResponses: map[string]api.QueryKeysResponse{
"@user:example.com": {
MasterKeys: map[string]fclient.CrossSigningKey{
"@user:example.com": {UserID: "@user:example.com", Usage: []fclient.CrossSigningKeyPurpose{"master"}, Keys: map[gomatrixserverlib.KeyID]spec.Base64Bytes{"ed25519:1": spec.Base64Bytes("different_key")}},
},
},
},
}
device := &api.Device{UserID: "@user:example.com", ID: "device"}
cfg, _, _ := testrig.CreateConfig(t, test.DBTypeSQLite)
cfg.Global.ServerName = "example.com"
res := UploadCrossSigningDeviceKeys(req, keyserverAPI, device, getAccountByPassword, &cfg.ClientAPI)
if res.Code != http.StatusUnauthorized {
t.Fatalf("expected status %d, got %d", http.StatusUnauthorized, res.Code)
}
}
func Test_KeysDiffer_MasterKeyMismatch(t *testing.T) {
existingMasterKey := fclient.CrossSigningKey{
UserID: "@user:example.com",
Usage: []fclient.CrossSigningKeyPurpose{fclient.CrossSigningKeyPurposeMaster},
Keys: map[gomatrixserverlib.KeyID]spec.Base64Bytes{"ed25519:1": spec.Base64Bytes("existing_key")},
}
keyResp := api.QueryKeysResponse{}
uploadReq := &crossSigningRequest{
PerformUploadDeviceKeysRequest: api.PerformUploadDeviceKeysRequest{
CrossSigningKeys: fclient.CrossSigningKeys{
MasterKey: fclient.CrossSigningKey{
UserID: "@user:example.com",
Usage: []fclient.CrossSigningKeyPurpose{fclient.CrossSigningKeyPurposeMaster},
Keys: map[gomatrixserverlib.KeyID]spec.Base64Bytes{"ed25519:1": spec.Base64Bytes("new_key")},
},
},
},
}
userID := "@user:example.com"
result := keysDiffer(existingMasterKey, keyResp, uploadReq, userID)
if !result {
t.Fatalf("expected keys to differ, but they did not")
}
}
func Test_KeysDiffer_SelfSigningKeyMismatch(t *testing.T) {
existingMasterKey := fclient.CrossSigningKey{
UserID: "@user:example.com",
Usage: []fclient.CrossSigningKeyPurpose{fclient.CrossSigningKeyPurposeMaster},
Keys: map[gomatrixserverlib.KeyID]spec.Base64Bytes{"ed25519:1": spec.Base64Bytes("key")},
}
keyResp := api.QueryKeysResponse{
SelfSigningKeys: map[string]fclient.CrossSigningKey{
"@user:example.com": {
UserID: "@user:example.com",
Usage: []fclient.CrossSigningKeyPurpose{fclient.CrossSigningKeyPurposeSelfSigning},
Keys: map[gomatrixserverlib.KeyID]spec.Base64Bytes{"ed25519:2": spec.Base64Bytes("existing_key")},
},
},
}
uploadReq := &crossSigningRequest{
PerformUploadDeviceKeysRequest: api.PerformUploadDeviceKeysRequest{
CrossSigningKeys: fclient.CrossSigningKeys{
SelfSigningKey: fclient.CrossSigningKey{
UserID: "@user:example.com",
Usage: []fclient.CrossSigningKeyPurpose{fclient.CrossSigningKeyPurposeSelfSigning},
Keys: map[gomatrixserverlib.KeyID]spec.Base64Bytes{"ed25519:2": spec.Base64Bytes("new_key")},
},
},
},
}
userID := "@user:example.com"
result := keysDiffer(existingMasterKey, keyResp, uploadReq, userID)
if !result {
t.Fatalf("expected keys to differ, but they did not")
}
}
func Test_KeysDiffer_UserSigningKeyMismatch(t *testing.T) {
existingMasterKey := fclient.CrossSigningKey{
UserID: "@user:example.com",
Usage: []fclient.CrossSigningKeyPurpose{fclient.CrossSigningKeyPurposeMaster},
Keys: map[gomatrixserverlib.KeyID]spec.Base64Bytes{"ed25519:1": spec.Base64Bytes("key")},
}
keyResp := api.QueryKeysResponse{
UserSigningKeys: map[string]fclient.CrossSigningKey{
"@user:example.com": {
UserID: "@user:example.com",
Usage: []fclient.CrossSigningKeyPurpose{fclient.CrossSigningKeyPurposeUserSigning},
Keys: map[gomatrixserverlib.KeyID]spec.Base64Bytes{"ed25519:3": spec.Base64Bytes("existing_key")},
},
},
}
uploadReq := &crossSigningRequest{
PerformUploadDeviceKeysRequest: api.PerformUploadDeviceKeysRequest{
CrossSigningKeys: fclient.CrossSigningKeys{
UserSigningKey: fclient.CrossSigningKey{
UserID: "@user:example.com",
Usage: []fclient.CrossSigningKeyPurpose{fclient.CrossSigningKeyPurposeUserSigning},
Keys: map[gomatrixserverlib.KeyID]spec.Base64Bytes{"ed25519:3": spec.Base64Bytes("new_key")},
},
},
},
}
userID := "@user:example.com"
result := keysDiffer(existingMasterKey, keyResp, uploadReq, userID)
if !result {
t.Fatalf("expected keys to differ, but they did not")
}
}
func Test_KeysDiffer_AllKeysMatch(t *testing.T) {
existingMasterKey := fclient.CrossSigningKey{
UserID: "@user:example.com",
Usage: []fclient.CrossSigningKeyPurpose{fclient.CrossSigningKeyPurposeMaster},
Keys: map[gomatrixserverlib.KeyID]spec.Base64Bytes{"ed25519:1": spec.Base64Bytes("key")},
}
keyResp := api.QueryKeysResponse{
SelfSigningKeys: map[string]fclient.CrossSigningKey{
"@user:example.com": {
UserID: "@user:example.com",
Usage: []fclient.CrossSigningKeyPurpose{fclient.CrossSigningKeyPurposeSelfSigning},
Keys: map[gomatrixserverlib.KeyID]spec.Base64Bytes{"ed25519:2": spec.Base64Bytes("key")},
},
},
UserSigningKeys: map[string]fclient.CrossSigningKey{
"@user:example.com": {
UserID: "@user:example.com",
Usage: []fclient.CrossSigningKeyPurpose{fclient.CrossSigningKeyPurposeUserSigning},
Keys: map[gomatrixserverlib.KeyID]spec.Base64Bytes{"ed25519:3": spec.Base64Bytes("key")},
},
},
}
uploadReq := &crossSigningRequest{
PerformUploadDeviceKeysRequest: api.PerformUploadDeviceKeysRequest{
CrossSigningKeys: fclient.CrossSigningKeys{
MasterKey: fclient.CrossSigningKey{
UserID: "@user:example.com",
Usage: []fclient.CrossSigningKeyPurpose{fclient.CrossSigningKeyPurposeMaster},
Keys: map[gomatrixserverlib.KeyID]spec.Base64Bytes{"ed25519:1": spec.Base64Bytes("key")},
},
SelfSigningKey: fclient.CrossSigningKey{
UserID: "@user:example.com",
Usage: []fclient.CrossSigningKeyPurpose{fclient.CrossSigningKeyPurposeSelfSigning},
Keys: map[gomatrixserverlib.KeyID]spec.Base64Bytes{"ed25519:2": spec.Base64Bytes("key")},
},
UserSigningKey: fclient.CrossSigningKey{
UserID: "@user:example.com",
Usage: []fclient.CrossSigningKeyPurpose{fclient.CrossSigningKeyPurposeUserSigning},
Keys: map[gomatrixserverlib.KeyID]spec.Base64Bytes{"ed25519:3": spec.Base64Bytes("key")},
},
},
},
}
userID := "@user:example.com"
result := keysDiffer(existingMasterKey, keyResp, uploadReq, userID)
if result {
t.Fatalf("expected keys to match, but they did not")
}
}

View file

@ -1492,7 +1492,7 @@ func Setup(
// Cross-signing device keys // Cross-signing device keys
postDeviceSigningKeys := httputil.MakeAuthAPI("post_device_signing_keys", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse { postDeviceSigningKeys := httputil.MakeAuthAPI("post_device_signing_keys", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {
return UploadCrossSigningDeviceKeys(req, userInteractiveAuth, userAPI, device, userAPI, cfg) return UploadCrossSigningDeviceKeys(req, userAPI, device, userAPI.QueryAccountByPassword, cfg)
}) })
postDeviceSigningSignatures := httputil.MakeAuthAPI("post_device_signing_signatures", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse { postDeviceSigningSignatures := httputil.MakeAuthAPI("post_device_signing_signatures", userVerifier, func(req *http.Request, device *userapi.Device) util.JSONResponse {

View file

@ -94,6 +94,8 @@ func main() {
dnsCache = fclient.NewDNSCache( dnsCache = fclient.NewDNSCache(
cfg.Global.DNSCache.CacheSize, cfg.Global.DNSCache.CacheSize,
cfg.Global.DNSCache.CacheLifetime, cfg.Global.DNSCache.CacheLifetime,
cfg.FederationAPI.AllowNetworkCIDRs,
cfg.FederationAPI.DenyNetworkCIDRs,
) )
logrus.Infof( logrus.Infof(
"DNS cache enabled (size %d, lifetime %s)", "DNS cache enabled (size %d, lifetime %s)",

View file

@ -71,6 +71,10 @@ func main() {
cfg.ClientAPI.RateLimiting.Enabled = false cfg.ClientAPI.RateLimiting.Enabled = false
cfg.FederationAPI.DisableTLSValidation = false cfg.FederationAPI.DisableTLSValidation = false
cfg.FederationAPI.DisableHTTPKeepalives = true cfg.FederationAPI.DisableHTTPKeepalives = true
// Allow allow networks when running in CI, as otherwise connections
// to other servers might be blocked when running Complement/Sytest.
cfg.FederationAPI.DenyNetworkCIDRs = []string{}
cfg.FederationAPI.AllowNetworkCIDRs = []string{}
// don't hit matrix.org when running tests!!! // don't hit matrix.org when running tests!!!
cfg.FederationAPI.KeyPerspectives = config.KeyPerspectives{} cfg.FederationAPI.KeyPerspectives = config.KeyPerspectives{}
cfg.MediaAPI.BasePath = config.Path(filepath.Join(*dirPath, "media")) cfg.MediaAPI.BasePath = config.Path(filepath.Join(*dirPath, "media"))

View file

@ -70,6 +70,8 @@ func main() {
dnsCache = fclient.NewDNSCache( dnsCache = fclient.NewDNSCache(
cfg.Global.DNSCache.CacheSize, cfg.Global.DNSCache.CacheSize,
cfg.Global.DNSCache.CacheLifetime, cfg.Global.DNSCache.CacheLifetime,
cfg.FederationAPI.AllowNetworkCIDRs,
cfg.FederationAPI.DenyNetworkCIDRs,
) )
logrus.Infof( logrus.Infof(
"DNS cache enabled (size %d, lifetime %s)", "DNS cache enabled (size %d, lifetime %s)",

View file

@ -65,6 +65,8 @@ func main() {
dnsCache = fclient.NewDNSCache( dnsCache = fclient.NewDNSCache(
cfg.Global.DNSCache.CacheSize, cfg.Global.DNSCache.CacheSize,
cfg.Global.DNSCache.CacheLifetime, cfg.Global.DNSCache.CacheLifetime,
cfg.FederationAPI.AllowNetworkCIDRs,
cfg.FederationAPI.DenyNetworkCIDRs,
) )
logrus.Infof( logrus.Infof(
"DNS cache enabled (size %d, lifetime %s)", "DNS cache enabled (size %d, lifetime %s)",

View file

@ -254,6 +254,24 @@ federation_api:
# last resort. # last resort.
prefer_direct_fetch: false prefer_direct_fetch: false
# deny_networks and allow_networks are the CIDR ranges used to prevent requests
# from accessing private IPs. If your system has specific IPs it should never
# contact, add them here with CIDR notation.
#
# The deny list is checked before the allow list.
deny_networks:
- "127.0.0.1/8"
- "10.0.0.0/8"
- "172.16.0.0/12"
- "192.168.0.0/16"
- "100.64.0.0/10"
- "169.254.0.0/16"
- "::1/128"
- "fe80::/64"
- "fc00::/7"
allow_networks:
- "0.0.0.0/0" # "Everything". The deny list will help limit this.
# Configuration for the Media API. # Configuration for the Media API.
media_api: media_api:
# Storage path for uploaded media. May be relative or absolute. # Storage path for uploaded media. May be relative or absolute.

View file

@ -34,27 +34,49 @@ The following items are unlikely to be accepted into a main Dendrite release for
## Sign off ## Sign off
We require that everyone who contributes to the project signs off their contributions We ask that everybody who contributes to this project signs off their contributions, as explained below.
in accordance with the [Developer Certificate of Origin](https://github.com/matrix-org/matrix-spec/blob/main/CONTRIBUTING.rst#sign-off).
In effect, this means adding a statement to your pull requests or commit messages We follow a simple 'inbound=outbound' model for contributions: the act of submitting an 'inbound' contribution means that the contributor agrees to license their contribution under the same terms as the project's overall 'outbound' license - in our case, this is Apache Software License v2 (see [LICENSE](../..//LICENSE)).
along the lines of:
In order to have a concrete record that your contribution is intentional and you agree to license it under the same terms as the project's license, we've adopted the same lightweight approach used by the [Linux Kernel](https://www.kernel.org/doc/html/latest/process/submitting-patches.html), [Docker](https://github.com/docker/docker/blob/master/CONTRIBUTING.md), and many other projects: the [Developer Certificate of Origin](https://developercertificate.org/) (DCO). This is a simple declaration that you wrote the contribution or otherwise have the right to contribute it to Matrix:
``` ```
Signed-off-by: Full Name <email address> Developer Certificate of Origin
Version 1.1
Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
660 York Street, Suite 102,
San Francisco, CA 94110 USA
Everyone is permitted to copy and distribute verbatim copies of this
license document, but changing it is not allowed.
Developer's Certificate of Origin 1.1
By making a contribution to this project, I certify that:
(a) The contribution was created in whole or in part by me and I
have the right to submit it under the open source license
indicated in the file; or
(b) The contribution is based upon previous work that, to the best
of my knowledge, is covered under an appropriate open source
license and I have the right under that license to submit that
work with modifications, whether created in whole or in part
by me, under the same open source license (unless I am
permitted to submit under a different license), as indicated
in the file; or
(c) The contribution was provided directly to me by some other
person who certified (a), (b) or (c) and I have not modified
it.
(d) I understand and agree that this project and the contribution
are public and that a record of the contribution (including all
personal information I submit with it, including my sign-off) is
maintained indefinitely and may be redistributed consistent with
this project or the open source license(s) involved.
``` ```
Unfortunately we can't accept contributions without a sign-off. If you agree to this for your contribution, then all that's needed is to include the line in your commit or pull request comment:
Please note that we can only accept contributions under a legally identifiable name, ```
such as your name as it appears on government-issued documentation or common-law names Signed-off-by: Your Name <your@email.example.org>
(claimed by legitimate usage or repute). We cannot accept sign-offs from a pseudonym or ```
alias and cannot accept anonymous contributions.
If you would prefer to sign off privately instead (so as to not reveal your full Git allows you to add this signoff automatically when using the `-s` flag to `git commit`, which uses the name and email set in your `user.name` and `user.email` git configs.
name on a public pull request), you can do so by emailing a sign-off declaration
and a link to your pull request directly to the [Matrix.org Foundation](https://matrix.org/foundation/)
at `dco@matrix.org`. Once a private sign-off has been made, you will not be required
to do so for future contributions.
## Getting up and running ## Getting up and running

14
go.mod
View file

@ -25,12 +25,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-20241215094829-e86ab16eabe8 github.com/matrix-org/gomatrixserverlib v0.0.0-20250116181547-c4f1e01eab0d
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.24 github.com/mattn/go-sqlite3 v1.14.24
github.com/nats-io/nats-server/v2 v2.10.23 github.com/nats-io/nats-server/v2 v2.10.23
github.com/nats-io/nats.go v1.37.0 github.com/nats-io/nats.go v1.38.0
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
github.com/patrickmn/go-cache v2.1.0+incompatible github.com/patrickmn/go-cache v2.1.0+incompatible
@ -55,7 +55,7 @@ require (
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
maunium.net/go/mautrix v0.15.1 maunium.net/go/mautrix v0.15.1
modernc.org/sqlite v1.34.2 modernc.org/sqlite v1.34.5
) )
require ( require (
@ -101,7 +101,6 @@ require (
github.com/golang/snappy v0.0.4 // indirect github.com/golang/snappy v0.0.4 // indirect
github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd // indirect github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd // indirect
github.com/h2non/filetype v1.1.3 // indirect github.com/h2non/filetype v1.1.3 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/hjson/hjson-go/v4 v4.4.0 // indirect github.com/hjson/hjson-go/v4 v4.4.0 // indirect
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
@ -116,7 +115,7 @@ require (
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.5.8 // indirect github.com/nats-io/jwt/v2 v2.5.8 // indirect
github.com/nats-io/nkeys v0.4.8 // indirect github.com/nats-io/nkeys v0.4.9 // indirect
github.com/nats-io/nuid v1.0.1 // indirect github.com/nats-io/nuid v1.0.1 // indirect
github.com/ncruces/go-strftime v0.1.9 // indirect github.com/ncruces/go-strftime v0.1.9 // indirect
github.com/onsi/ginkgo/v2 v2.11.0 // indirect github.com/onsi/ginkgo/v2 v2.11.0 // indirect
@ -142,7 +141,7 @@ require (
go.opentelemetry.io/otel/trace v1.32.0 // indirect go.opentelemetry.io/otel/trace v1.32.0 // indirect
go.uber.org/mock v0.4.0 // indirect go.uber.org/mock v0.4.0 // indirect
golang.org/x/mod v0.19.0 // indirect golang.org/x/mod v0.19.0 // indirect
golang.org/x/net v0.32.0 // indirect golang.org/x/net v0.33.0 // indirect
golang.org/x/sys v0.28.0 // indirect golang.org/x/sys v0.28.0 // indirect
golang.org/x/text v0.21.0 // indirect golang.org/x/text v0.21.0 // indirect
golang.org/x/time v0.8.0 // indirect golang.org/x/time v0.8.0 // indirect
@ -151,12 +150,9 @@ require (
gopkg.in/macaroon.v2 v2.1.0 // indirect gopkg.in/macaroon.v2 v2.1.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
maunium.net/go/maulogger/v2 v2.4.1 // indirect maunium.net/go/maulogger/v2 v2.4.1 // indirect
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 // indirect
modernc.org/libc v1.55.3 // indirect modernc.org/libc v1.55.3 // indirect
modernc.org/mathutil v1.6.0 // indirect modernc.org/mathutil v1.6.0 // indirect
modernc.org/memory v1.8.0 // indirect modernc.org/memory v1.8.0 // indirect
modernc.org/strutil v1.2.0 // indirect
modernc.org/token v1.1.0 // indirect
nhooyr.io/websocket v1.8.7 // indirect nhooyr.io/websocket v1.8.7 // indirect
) )

24
go.sum
View file

@ -197,8 +197,6 @@ github.com/h2non/filetype v1.1.3 h1:FKkx9QbD7HR/zjK1Ia5XiBsq9zdLi5Kf3zGyFTAFkGg=
github.com/h2non/filetype v1.1.3/go.mod h1:319b3zT68BvV+WRj7cwy856M2ehB3HqNOt6sy1HndBY= github.com/h2non/filetype v1.1.3/go.mod h1:319b3zT68BvV+WRj7cwy856M2ehB3HqNOt6sy1HndBY=
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw= github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI= github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
github.com/hjson/hjson-go/v4 v4.4.0 h1:D/NPvqOCH6/eisTb5/ztuIS8GUvmpHaLOcNk1Bjr298= github.com/hjson/hjson-go/v4 v4.4.0 h1:D/NPvqOCH6/eisTb5/ztuIS8GUvmpHaLOcNk1Bjr298=
github.com/hjson/hjson-go/v4 v4.4.0/go.mod h1:KaYt3bTw3zhBjYqnXkYywcYctk0A2nxeEFTse3rH13E= github.com/hjson/hjson-go/v4 v4.4.0/go.mod h1:KaYt3bTw3zhBjYqnXkYywcYctk0A2nxeEFTse3rH13E=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
@ -232,8 +230,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-20241215094829-e86ab16eabe8 h1:nC998SaawQwbZ16/V70Pil3pY3rSQwTaeLOpHWp7ZTo= github.com/matrix-org/gomatrixserverlib v0.0.0-20250116181547-c4f1e01eab0d h1:c3Dkci0GDH/6cGGt8zGIiJMP+UOdtX0DPY6dxiJvtZM=
github.com/matrix-org/gomatrixserverlib v0.0.0-20241215094829-e86ab16eabe8/go.mod h1:qil34SWn6VB6gO5312rzziCUcZtgROPjrLE+4ly/0os= github.com/matrix-org/gomatrixserverlib v0.0.0-20250116181547-c4f1e01eab0d/go.mod h1:qil34SWn6VB6gO5312rzziCUcZtgROPjrLE+4ly/0os=
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=
@ -270,10 +268,10 @@ github.com/nats-io/jwt/v2 v2.5.8 h1:uvdSzwWiEGWGXf+0Q+70qv6AQdvcvxrv9hPM0RiPamE=
github.com/nats-io/jwt/v2 v2.5.8/go.mod h1:ZdWS1nZa6WMZfFwwgpEaqBV8EPGVgOTDHN/wTbz0Y5A= github.com/nats-io/jwt/v2 v2.5.8/go.mod h1:ZdWS1nZa6WMZfFwwgpEaqBV8EPGVgOTDHN/wTbz0Y5A=
github.com/nats-io/nats-server/v2 v2.10.23 h1:jvfb9cEi5h8UG6HkZgJGdn9f1UPaX3Dohk0PohEekJI= github.com/nats-io/nats-server/v2 v2.10.23 h1:jvfb9cEi5h8UG6HkZgJGdn9f1UPaX3Dohk0PohEekJI=
github.com/nats-io/nats-server/v2 v2.10.23/go.mod h1:hMFnpDT2XUXsvHglABlFl/uroQCCOcW6X/0esW6GpBk= github.com/nats-io/nats-server/v2 v2.10.23/go.mod h1:hMFnpDT2XUXsvHglABlFl/uroQCCOcW6X/0esW6GpBk=
github.com/nats-io/nats.go v1.37.0 h1:07rauXbVnnJvv1gfIyghFEo6lUcYRY0WXc3x7x0vUxE= github.com/nats-io/nats.go v1.38.0 h1:A7P+g7Wjp4/NWqDOOP/K6hfhr54DvdDQUznt5JFg9XA=
github.com/nats-io/nats.go v1.37.0/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8= github.com/nats-io/nats.go v1.38.0/go.mod h1:IGUM++TwokGnXPs82/wCuiHS02/aKrdYUQkU8If6yjw=
github.com/nats-io/nkeys v0.4.8 h1:+wee30071y3vCZAYRsnrmIPaOe47A/SkK/UBDPdIV70= github.com/nats-io/nkeys v0.4.9 h1:qe9Faq2Gxwi6RZnZMXfmGMZkg3afLLOtrU+gDZJ35b0=
github.com/nats-io/nkeys v0.4.8/go.mod h1:kqXRgRDPlGy7nGaEDMuYzmiJCIAAWDK0IMBtDmGD0nc= github.com/nats-io/nkeys v0.4.9/go.mod h1:jcMqs+FLG+W5YO36OX6wFIFcmpdAns+w1Wm6D3I/evE=
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
@ -418,8 +416,8 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
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-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI= golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs= golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
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=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -515,8 +513,6 @@ modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE=
modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ= modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ=
modernc.org/gc/v2 v2.4.1 h1:9cNzOqPyMJBvrUipmynX0ZohMhcxPtMccYgGOJdOiBw= modernc.org/gc/v2 v2.4.1 h1:9cNzOqPyMJBvrUipmynX0ZohMhcxPtMccYgGOJdOiBw=
modernc.org/gc/v2 v2.4.1/go.mod h1:wzN5dK1AzVGoH6XOzc3YZ+ey/jPgYHLuVckd62P0GYU= modernc.org/gc/v2 v2.4.1/go.mod h1:wzN5dK1AzVGoH6XOzc3YZ+ey/jPgYHLuVckd62P0GYU=
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 h1:5D53IMaUuA5InSeMu9eJtlQXS2NxAhyWQvkKEgXZhHI=
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4=
modernc.org/libc v1.55.3 h1:AzcW1mhlPNrRtjS5sS+eW2ISCgSOLLNyFzRh/V3Qj/U= modernc.org/libc v1.55.3 h1:AzcW1mhlPNrRtjS5sS+eW2ISCgSOLLNyFzRh/V3Qj/U=
modernc.org/libc v1.55.3/go.mod h1:qFXepLhz+JjFThQ4kzwzOjA/y/artDeg+pcYnY+Q83w= modernc.org/libc v1.55.3/go.mod h1:qFXepLhz+JjFThQ4kzwzOjA/y/artDeg+pcYnY+Q83w=
modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
@ -527,8 +523,8 @@ modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc= modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc=
modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss= modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss=
modernc.org/sqlite v1.34.2 h1:J9n76TPsfYYkFkZ9Uy1QphILYifiVEwwOT7yP5b++2Y= modernc.org/sqlite v1.34.5 h1:Bb6SR13/fjp15jt70CL4f18JIN7p7dnMExd+UFnF15g=
modernc.org/sqlite v1.34.2/go.mod h1:dnR723UrTtjKpoHCAMN0Q/gZ9MT4r+iRvIBb9umWFkU= modernc.org/sqlite v1.34.5/go.mod h1:YLuNmX9NKs8wRNK2ko1LW1NGYcc9FkBO69JOt1AR9JE=
modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA=
modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0=
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=

View file

@ -1,7 +1,7 @@
apiVersion: v2 apiVersion: v2
name: dendrite name: dendrite
version: "0.15.0" version: "0.15.1"
appVersion: "0.14.0" appVersion: "0.14.1"
description: Dendrite Matrix Homeserver description: Dendrite Matrix Homeserver
type: application type: application
icon: https://avatars.githubusercontent.com/u/8418310?s=48&v=4 icon: https://avatars.githubusercontent.com/u/8418310?s=48&v=4

View file

@ -1,7 +1,7 @@
# dendrite # dendrite
![Version: 0.15.0](https://img.shields.io/badge/Version-0.15.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.14.0](https://img.shields.io/badge/AppVersion-0.14.0-informational?style=flat-square) ![Version: 0.15.1](https://img.shields.io/badge/Version-0.15.1-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.14.1](https://img.shields.io/badge/AppVersion-0.14.1-informational?style=flat-square)
Dendrite Matrix Homeserver Dendrite Matrix Homeserver
Status: **NOT PRODUCTION READY** Status: **NOT PRODUCTION READY**

View file

@ -216,13 +216,17 @@ func (t *TxnReq) processEDUs(ctx context.Context) {
util.GetLogger(ctx).WithError(err).Debug("Failed to unmarshal typing event") util.GetLogger(ctx).WithError(err).Debug("Failed to unmarshal typing event")
continue continue
} }
if _, serverName, err := gomatrixserverlib.SplitID('@', typingPayload.UserID); err != nil { _, serverName, err := gomatrixserverlib.SplitID('@', typingPayload.UserID)
if err != nil {
continue continue
} else if serverName == t.ourServerName { } else if serverName == t.ourServerName {
continue continue
} else if serverName != t.Origin { } else if serverName != t.Origin {
continue continue
} }
if api.IsServerBannedFromRoom(ctx, t.rsAPI, typingPayload.RoomID, serverName) {
continue
}
if err := t.producer.SendTyping(ctx, typingPayload.UserID, typingPayload.RoomID, typingPayload.Typing, 30*1000); err != nil { if err := t.producer.SendTyping(ctx, typingPayload.UserID, typingPayload.RoomID, typingPayload.Typing, 30*1000); err != nil {
util.GetLogger(ctx).WithError(err).Error("Failed to send typing event to JetStream") util.GetLogger(ctx).WithError(err).Error("Failed to send typing event to JetStream")
} }
@ -278,6 +282,9 @@ func (t *TxnReq) processEDUs(ctx context.Context) {
util.GetLogger(ctx).Debugf("Dropping receipt event where sender domain (%q) doesn't match origin (%q)", domain, t.Origin) util.GetLogger(ctx).Debugf("Dropping receipt event where sender domain (%q) doesn't match origin (%q)", domain, t.Origin)
continue continue
} }
if api.IsServerBannedFromRoom(ctx, t.rsAPI, roomID, domain) {
continue
}
if err := t.processReceiptEvent(ctx, userID, roomID, "m.read", mread.Data.TS, mread.EventIDs); err != nil { if err := t.processReceiptEvent(ctx, userID, roomID, "m.read", mread.Data.TS, mread.EventIDs); err != nil {
util.GetLogger(ctx).WithError(err).WithFields(logrus.Fields{ util.GetLogger(ctx).WithError(err).WithFields(logrus.Fields{
"sender": t.Origin, "sender": t.Origin,

View file

@ -18,7 +18,7 @@ var build string
const ( const (
VersionMajor = 0 VersionMajor = 0
VersionMinor = 14 VersionMinor = 14
VersionPatch = 0 VersionPatch = 1
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

View file

@ -82,6 +82,7 @@ func CreateFederationClient(cfg *config.Dendrite, dnsCache *fclient.DNSCache) fc
fclient.WithSkipVerify(cfg.FederationAPI.DisableTLSValidation), fclient.WithSkipVerify(cfg.FederationAPI.DisableTLSValidation),
fclient.WithKeepAlives(!cfg.FederationAPI.DisableHTTPKeepalives), fclient.WithKeepAlives(!cfg.FederationAPI.DisableHTTPKeepalives),
fclient.WithUserAgent(fmt.Sprintf("Dendrite/%s", internal.VersionString())), fclient.WithUserAgent(fmt.Sprintf("Dendrite/%s", internal.VersionString())),
fclient.WithAllowDenyNetworks(cfg.FederationAPI.AllowNetworkCIDRs, cfg.FederationAPI.DenyNetworkCIDRs),
} }
if cfg.Global.DNSCache.Enabled { if cfg.Global.DNSCache.Enabled {
opts = append(opts, fclient.WithDNSCache(dnsCache)) opts = append(opts, fclient.WithDNSCache(dnsCache))

View file

@ -46,6 +46,10 @@ type FederationAPI struct {
// Should we prefer direct key fetches over perspective ones? // Should we prefer direct key fetches over perspective ones?
PreferDirectFetch bool `yaml:"prefer_direct_fetch"` PreferDirectFetch bool `yaml:"prefer_direct_fetch"`
// Deny/Allow lists used for restricting request scopes.
DenyNetworkCIDRs []string `yaml:"deny_networks"`
AllowNetworkCIDRs []string `yaml:"allow_networks"`
} }
func (c *FederationAPI) Defaults(opts DefaultOpts) { func (c *FederationAPI) Defaults(opts DefaultOpts) {
@ -53,6 +57,20 @@ func (c *FederationAPI) Defaults(opts DefaultOpts) {
c.P2PFederationRetriesUntilAssumedOffline = 1 c.P2PFederationRetriesUntilAssumedOffline = 1
c.DisableTLSValidation = false c.DisableTLSValidation = false
c.DisableHTTPKeepalives = false c.DisableHTTPKeepalives = false
c.DenyNetworkCIDRs = []string{
"127.0.0.1/8",
"10.0.0.0/8",
"172.16.0.0/12",
"192.168.0.0/16",
"100.64.0.0/10",
"169.254.0.0/16",
"::1/128",
"fe80::/64",
"fc00::/7",
}
c.AllowNetworkCIDRs = []string{
"0.0.0.0/0",
}
if opts.Generate { if opts.Generate {
c.KeyPerspectives = KeyPerspectives{ c.KeyPerspectives = KeyPerspectives{
{ {