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 -->
* [ ] 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>`

View file

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

View file

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

View file

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

View file

@ -1,5 +1,23 @@
# 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)
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
import (
"context"
"net/http"
"slices"
"strings"
"time"
"github.com/sirupsen/logrus"
"github.com/element-hq/dendrite/clientapi/auth"
"github.com/element-hq/dendrite/clientapi/auth/authtypes"
"github.com/element-hq/dendrite/clientapi/httputil"
@ -29,10 +30,15 @@ type crossSigningRequest struct {
Auth newPasswordAuth `json:"auth"`
}
type UploadKeysAPI interface {
QueryKeys(ctx context.Context, req *api.QueryKeysRequest, res *api.QueryKeysResponse)
api.UploadDeviceKeysAPI
}
func UploadCrossSigningDeviceKeys(
req *http.Request, userInteractiveAuth *auth.UserInteractive,
keyserverAPI api.ClientKeyAPI, device *api.Device,
accountAPI api.ClientUserAPI, cfg *config.ClientAPI,
req *http.Request,
keyserverAPI UploadKeysAPI, device *api.Device,
accountAPI auth.GetAccountByPassword, cfg *config.ClientAPI,
) util.JSONResponse {
uploadReq := &crossSigningRequest{}
uploadRes := &api.PerformUploadDeviceKeysResponse{}
@ -41,121 +47,58 @@ func UploadCrossSigningDeviceKeys(
if resErr != nil {
return *resErr
}
sessionID := uploadReq.Auth.Session
if sessionID == "" {
sessionID = util.RandomString(sessionIDLength)
}
isCrossSigningSetup := false
masterKeyUpdatableWithoutUIA := false
{
var keysResp api.QueryMasterKeysResponse
keyserverAPI.QueryMasterKeys(req.Context(), &api.QueryMasterKeysRequest{UserID: device.UserID}, &keysResp)
if err := keysResp.Error; err != nil {
return convertKeyError(err)
}
if k := keysResp.Key; k != nil {
isCrossSigningSetup = true
if k.UpdatableWithoutUIABeforeMs != nil {
masterKeyUpdatableWithoutUIA = time.Now().UnixMilli() < *k.UpdatableWithoutUIABeforeMs
}
// Query existing keys to determine if UIA is required
keyResp := api.QueryKeysResponse{}
keyserverAPI.QueryKeys(req.Context(), &api.QueryKeysRequest{
UserID: device.UserID,
UserToDevices: map[string][]string{device.UserID: {device.ID}},
Timeout: time.Second * 10,
}, &keyResp)
if keyResp.Error != nil {
logrus.WithError(keyResp.Error).Error("Failed to query keys")
return util.JSONResponse{
Code: http.StatusBadRequest,
JSON: spec.Unknown(keyResp.Error.Error()),
}
}
{
var keysResp api.QueryKeysResponse
keyserverAPI.QueryKeys(req.Context(), &api.QueryKeysRequest{UserID: device.UserID, UserToDevices: map[string][]string{device.UserID: []string{}}}, &keysResp)
if err := keysResp.Error; err != nil {
return convertKeyError(err)
}
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
}
existingMasterKey, hasMasterKey := keyResp.MasterKeys[device.UserID]
requireUIA := false
if hasMasterKey {
// If we have a master key, check if any of the existing keys differ. If they do,
// we need to re-authenticate the user.
requireUIA = keysDiffer(existingMasterKey, keyResp, uploadReq, device.UserID)
}
if !hasDifferentKeys(device.UserID, &uploadReq.MasterKey, keysResp.MasterKeys) &&
!hasDifferentKeys(device.UserID, &uploadReq.SelfSigningKey, keysResp.SelfSigningKeys) &&
!hasDifferentKeys(device.UserID, &uploadReq.UserSigningKey, keysResp.UserSigningKeys) {
if requireUIA {
sessionID := uploadReq.Auth.Session
if sessionID == "" {
sessionID = util.RandomString(sessionIDLength)
}
if uploadReq.Auth.Type != authtypes.LoginTypePassword {
return util.JSONResponse{
Code: http.StatusOK,
JSON: map[int]interface{}{},
Code: http.StatusUnauthorized,
JSON: newUserInteractiveResponse(
sessionID,
[]authtypes.Flow{
{
Stages: []authtypes.LoginType{authtypes.LoginTypePassword},
},
},
nil,
),
}
}
}
if isCrossSigningSetup {
// 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)
typePassword := auth.LoginTypePassword{
GetAccountByPassword: accountAPI,
Config: cfg,
}
if _, authErr := typePassword.Login(req.Context(), &uploadReq.Auth.PasswordRequest); authErr != nil {
return *authErr
}
sessions.addCompletedSessionStage(sessionID, authtypes.LoginTypePassword)
}
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 {
uploadReq := &api.PerformUploadDeviceSignaturesRequest{}
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
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 {

View file

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

View file

@ -71,6 +71,10 @@ func main() {
cfg.ClientAPI.RateLimiting.Enabled = false
cfg.FederationAPI.DisableTLSValidation = false
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!!!
cfg.FederationAPI.KeyPerspectives = config.KeyPerspectives{}
cfg.MediaAPI.BasePath = config.Path(filepath.Join(*dirPath, "media"))

View file

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

View file

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

View file

@ -254,6 +254,24 @@ federation_api:
# last resort.
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.
media_api:
# 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
We require that everyone who contributes to the project signs off their contributions
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
along the lines of:
We ask that everybody who contributes to this project signs off their contributions, as explained below.
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)).
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
(claimed by legitimate usage or repute). We cannot accept sign-offs from a pseudonym or
alias and cannot accept anonymous contributions.
```
Signed-off-by: Your Name <your@email.example.org>
```
If you would prefer to sign off privately instead (so as to not reveal your full
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.
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.
## 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/go-sqlite3-js v0.0.0-20220419092513-28aa791a1c91
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/util v0.0.0-20221111132719-399730281e66
github.com/mattn/go-sqlite3 v1.14.24
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/opentracing/opentracing-go v1.2.0
github.com/patrickmn/go-cache v2.1.0+incompatible
@ -55,7 +55,7 @@ require (
gopkg.in/yaml.v2 v2.4.0
gotest.tools/v3 v3.4.0
maunium.net/go/mautrix v0.15.1
modernc.org/sqlite v1.34.2
modernc.org/sqlite v1.34.5
)
require (
@ -101,7 +101,6 @@ require (
github.com/golang/snappy v0.0.4 // indirect
github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd // 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/json-iterator/go v1.1.12 // indirect
github.com/juju/errors v1.0.0 // indirect
@ -116,7 +115,7 @@ require (
github.com/morikuni/aec v1.0.0 // indirect
github.com/mschoch/smat v0.2.0 // 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/ncruces/go-strftime v0.1.9 // 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.uber.org/mock v0.4.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/text v0.21.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/yaml.v3 v3.0.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/mathutil v1.6.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
)

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/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
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/go.mod h1:KaYt3bTw3zhBjYqnXkYywcYctk0A2nxeEFTse3rH13E=
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/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/gomatrixserverlib v0.0.0-20241215094829-e86ab16eabe8 h1:nC998SaawQwbZ16/V70Pil3pY3rSQwTaeLOpHWp7ZTo=
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 h1:c3Dkci0GDH/6cGGt8zGIiJMP+UOdtX0DPY6dxiJvtZM=
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/go.mod h1:ReWMS/LoVnOiRAdq9sNUC2NZnd1mZkMNB52QhpTRWjg=
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/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.go v1.37.0 h1:07rauXbVnnJvv1gfIyghFEo6lUcYRY0WXc3x7x0vUxE=
github.com/nats-io/nats.go v1.37.0/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8=
github.com/nats-io/nkeys v0.4.8 h1:+wee30071y3vCZAYRsnrmIPaOe47A/SkK/UBDPdIV70=
github.com/nats-io/nkeys v0.4.8/go.mod h1:kqXRgRDPlGy7nGaEDMuYzmiJCIAAWDK0IMBtDmGD0nc=
github.com/nats-io/nats.go v1.38.0 h1:A7P+g7Wjp4/NWqDOOP/K6hfhr54DvdDQUznt5JFg9XA=
github.com/nats-io/nats.go v1.38.0/go.mod h1:IGUM++TwokGnXPs82/wCuiHS02/aKrdYUQkU8If6yjw=
github.com/nats-io/nkeys v0.4.9 h1:qe9Faq2Gxwi6RZnZMXfmGMZkg3afLLOtrU+gDZJ35b0=
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/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
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-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
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.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs=
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
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-20190911185100-cd5d95a43a6e/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/gc/v2 v2.4.1 h1:9cNzOqPyMJBvrUipmynX0ZohMhcxPtMccYgGOJdOiBw=
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/go.mod h1:qFXepLhz+JjFThQ4kzwzOjA/y/artDeg+pcYnY+Q83w=
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/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc=
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.2/go.mod h1:dnR723UrTtjKpoHCAMN0Q/gZ9MT4r+iRvIBb9umWFkU=
modernc.org/sqlite v1.34.5 h1:Bb6SR13/fjp15jt70CL4f18JIN7p7dnMExd+UFnF15g=
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/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0=
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=

View file

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

View file

@ -1,7 +1,7 @@
# 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
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")
continue
}
if _, serverName, err := gomatrixserverlib.SplitID('@', typingPayload.UserID); err != nil {
_, serverName, err := gomatrixserverlib.SplitID('@', typingPayload.UserID)
if err != nil {
continue
} else if serverName == t.ourServerName {
continue
} else if serverName != t.Origin {
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 {
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)
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 {
util.GetLogger(ctx).WithError(err).WithFields(logrus.Fields{
"sender": t.Origin,

View file

@ -18,7 +18,7 @@ var build string
const (
VersionMajor = 0
VersionMinor = 14
VersionPatch = 0
VersionPatch = 1
VersionTag = "" // example: "rc1"
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.WithKeepAlives(!cfg.FederationAPI.DisableHTTPKeepalives),
fclient.WithUserAgent(fmt.Sprintf("Dendrite/%s", internal.VersionString())),
fclient.WithAllowDenyNetworks(cfg.FederationAPI.AllowNetworkCIDRs, cfg.FederationAPI.DenyNetworkCIDRs),
}
if cfg.Global.DNSCache.Enabled {
opts = append(opts, fclient.WithDNSCache(dnsCache))

View file

@ -46,6 +46,10 @@ type FederationAPI struct {
// Should we prefer direct key fetches over perspective ones?
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) {
@ -53,6 +57,20 @@ func (c *FederationAPI) Defaults(opts DefaultOpts) {
c.P2PFederationRetriesUntilAssumedOffline = 1
c.DisableTLSValidation = 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 {
c.KeyPerspectives = KeyPerspectives{
{