diff --git a/build/gobind-pinecone/monolith.go b/build/gobind-pinecone/monolith.go index 99c8e8844..3f1017cab 100644 --- a/build/gobind-pinecone/monolith.go +++ b/build/gobind-pinecone/monolith.go @@ -271,9 +271,8 @@ func (m *DendriteMonolith) Start() { cfg.MediaAPI.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s/%s-mediaapi.db", m.CacheDirectory, prefix)) cfg.SyncAPI.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s/%s-syncapi.db", m.StorageDirectory, prefix)) cfg.RoomServer.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s/%s-roomserver.db", m.StorageDirectory, prefix)) - cfg.SigningKeyServer.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s/%s-signingkeyserver.db", m.StorageDirectory, prefix)) cfg.KeyServer.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s/%s-keyserver.db", m.StorageDirectory, prefix)) - cfg.FederationSender.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s/%s-federationapi.db", m.StorageDirectory, prefix)) + cfg.FederationAPI.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s/%s-federationapi.db", m.StorageDirectory, prefix)) cfg.AppServiceAPI.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s/%s-appservice.db", m.StorageDirectory, prefix)) cfg.MediaAPI.BasePath = config.Path(fmt.Sprintf("%s/media", m.CacheDirectory)) cfg.MediaAPI.AbsBasePath = config.Path(fmt.Sprintf("%s/media", m.CacheDirectory)) @@ -291,12 +290,10 @@ func (m *DendriteMonolith) Start() { serverKeyAPI := &signing.YggdrasilKeys{} keyRing := serverKeyAPI.KeyRing() - rsAPI := roomserver.NewInternalAPI( - base, keyRing, - ) + rsAPI := roomserver.NewInternalAPI(base) fsAPI := federationapi.NewInternalAPI( - base, federation, rsAPI, keyRing, true, + base, federation, rsAPI, base.Caches, true, ) keyAPI := keyserver.NewInternalAPI(base, &base.Cfg.KeyServer, fsAPI) @@ -312,6 +309,7 @@ func (m *DendriteMonolith) Start() { // The underlying roomserver implementation needs to be able to call the fedsender. // This is different to rsAPI which can be the http client which doesn't need this dependency rsAPI.SetFederationSenderAPI(fsAPI) + rsAPI.SetKeyring(keyRing) monolith := setup.Monolith{ Config: base.Cfg, diff --git a/build/gobind-yggdrasil/monolith.go b/build/gobind-yggdrasil/monolith.go index 8fda7cb4c..5e32b6bf0 100644 --- a/build/gobind-yggdrasil/monolith.go +++ b/build/gobind-yggdrasil/monolith.go @@ -93,9 +93,8 @@ func (m *DendriteMonolith) Start() { cfg.MediaAPI.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s/dendrite-p2p-mediaapi.db", m.StorageDirectory)) cfg.SyncAPI.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s/dendrite-p2p-syncapi.db", m.StorageDirectory)) cfg.RoomServer.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s/dendrite-p2p-roomserver.db", m.StorageDirectory)) - cfg.SigningKeyServer.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s/dendrite-p2p-signingkeyserver.db", m.StorageDirectory)) cfg.KeyServer.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s/dendrite-p2p-keyserver.db", m.StorageDirectory)) - cfg.FederationSender.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s/dendrite-p2p-federationapi.db", m.StorageDirectory)) + cfg.FederationAPI.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s/dendrite-p2p-federationapi.db", m.StorageDirectory)) cfg.AppServiceAPI.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s/dendrite-p2p-appservice.db", m.StorageDirectory)) cfg.MediaAPI.BasePath = config.Path(fmt.Sprintf("%s/tmp", m.StorageDirectory)) cfg.MediaAPI.AbsBasePath = config.Path(fmt.Sprintf("%s/tmp", m.StorageDirectory)) @@ -112,12 +111,10 @@ func (m *DendriteMonolith) Start() { serverKeyAPI := &signing.YggdrasilKeys{} keyRing := serverKeyAPI.KeyRing() - rsAPI := roomserver.NewInternalAPI( - base, keyRing, - ) + rsAPI := roomserver.NewInternalAPI(base) fsAPI := federationapi.NewInternalAPI( - base, federation, rsAPI, keyRing, true, + base, federation, rsAPI, base.Caches, true, ) keyAPI := keyserver.NewInternalAPI(base, &base.Cfg.KeyServer, federation) @@ -134,6 +131,7 @@ func (m *DendriteMonolith) Start() { // The underlying roomserver implementation needs to be able to call the fedsender. // This is different to rsAPI which can be the http client which doesn't need this dependency rsAPI.SetFederationSenderAPI(fsAPI) + rsAPI.SetKeyring(keyRing) monolith := setup.Monolith{ Config: base.Cfg, diff --git a/cmd/dendrite-demo-libp2p/main.go b/cmd/dendrite-demo-libp2p/main.go index eb707740a..a5dce2d3f 100644 --- a/cmd/dendrite-demo-libp2p/main.go +++ b/cmd/dendrite-demo-libp2p/main.go @@ -37,7 +37,6 @@ import ( "github.com/matrix-org/dendrite/setup" "github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/mscs" - "github.com/matrix-org/dendrite/signingkeyserver" "github.com/matrix-org/dendrite/userapi" "github.com/matrix-org/gomatrixserverlib" @@ -125,14 +124,13 @@ func main() { cfg.Global.PrivateKey = privKey cfg.Global.KeyID = gomatrixserverlib.KeyID(fmt.Sprintf("ed25519:%s", *instanceName)) cfg.Global.Kafka.UseNaffka = true - cfg.FederationSender.FederationMaxRetries = 6 + cfg.FederationAPI.FederationMaxRetries = 6 cfg.UserAPI.AccountDatabase.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-account.db", *instanceName)) cfg.UserAPI.DeviceDatabase.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-device.db", *instanceName)) cfg.MediaAPI.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-mediaapi.db", *instanceName)) cfg.SyncAPI.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-syncapi.db", *instanceName)) cfg.RoomServer.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-roomserver.db", *instanceName)) - cfg.SigningKeyServer.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-signingkeyserver.db", *instanceName)) - cfg.FederationSender.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-federationapi.db", *instanceName)) + cfg.FederationAPI.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-federationapi.db", *instanceName)) cfg.AppServiceAPI.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-appservice.db", *instanceName)) cfg.Global.Kafka.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-naffka.db", *instanceName)) cfg.KeyServer.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-e2ekey.db", *instanceName)) @@ -151,16 +149,8 @@ func main() { userAPI := userapi.NewInternalAPI(accountDB, &cfg.UserAPI, nil, keyAPI) keyAPI.SetUserAPI(userAPI) - serverKeyAPI := signingkeyserver.NewInternalAPI( - &base.Base.Cfg.SigningKeyServer, federation, base.Base.Caches, - ) - keyRing := serverKeyAPI.KeyRing() - createKeyDB( - base, serverKeyAPI, - ) - rsAPI := roomserver.NewInternalAPI( - &base.Base, keyRing, + &base.Base, ) eduInputAPI := eduserver.NewInternalAPI( &base.Base, cache.New(), userAPI, @@ -168,8 +158,9 @@ func main() { asAPI := appservice.NewInternalAPI(&base.Base, userAPI, rsAPI) rsAPI.SetAppserviceAPI(asAPI) fsAPI := federationapi.NewInternalAPI( - &base.Base, federation, rsAPI, keyRing, true, + &base.Base, federation, rsAPI, base.Base.Caches, true, ) + keyRing := fsAPI.KeyRing() rsAPI.SetFederationSenderAPI(fsAPI) provider := newPublicRoomsProvider(base.LibP2PPubsub, rsAPI) err = provider.Start() @@ -177,6 +168,12 @@ func main() { panic("failed to create new public rooms provider: " + err.Error()) } + /* + createKeyDB( + base, keyRing, + ) + */ + monolith := setup.Monolith{ Config: base.Base.Cfg, AccountDB: accountDB, @@ -188,7 +185,6 @@ func main() { EDUInternalAPI: eduInputAPI, FederationAPI: fsAPI, RoomserverAPI: rsAPI, - ServerKeyAPI: serverKeyAPI, UserAPI: userAPI, KeyAPI: keyAPI, ExtPublicRoomsProvider: provider, diff --git a/cmd/dendrite-demo-pinecone/main.go b/cmd/dendrite-demo-pinecone/main.go index ac2f3ca9c..c9f5879a8 100644 --- a/cmd/dendrite-demo-pinecone/main.go +++ b/cmd/dendrite-demo-pinecone/main.go @@ -152,9 +152,8 @@ func main() { cfg.MediaAPI.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-mediaapi.db", *instanceName)) cfg.SyncAPI.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-syncapi.db", *instanceName)) cfg.RoomServer.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-roomserver.db", *instanceName)) - cfg.SigningKeyServer.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-signingkeyserver.db", *instanceName)) cfg.KeyServer.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-keyserver.db", *instanceName)) - cfg.FederationSender.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-federationapi.db", *instanceName)) + cfg.FederationAPI.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-federationapi.db", *instanceName)) cfg.AppServiceAPI.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-appservice.db", *instanceName)) cfg.Global.Kafka.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-naffka.db", *instanceName)) cfg.MSCs.MSCs = []string{"msc2836", "msc2946"} @@ -171,12 +170,10 @@ func main() { serverKeyAPI := &signing.YggdrasilKeys{} keyRing := serverKeyAPI.KeyRing() - rsComponent := roomserver.NewInternalAPI( - base, keyRing, - ) + rsComponent := roomserver.NewInternalAPI(base) rsAPI := rsComponent fsAPI := federationapi.NewInternalAPI( - base, federation, rsAPI, keyRing, true, + base, federation, rsAPI, base.Caches, true, ) keyAPI := keyserver.NewInternalAPI(base, &base.Cfg.KeyServer, fsAPI) @@ -190,6 +187,7 @@ func main() { asAPI := appservice.NewInternalAPI(base, userAPI, rsAPI) rsComponent.SetFederationSenderAPI(fsAPI) + rsComponent.SetKeyring(keyRing) monolith := setup.Monolith{ Config: base.Cfg, diff --git a/cmd/dendrite-demo-yggdrasil/main.go b/cmd/dendrite-demo-yggdrasil/main.go index 813ab34db..f22c73b88 100644 --- a/cmd/dendrite-demo-yggdrasil/main.go +++ b/cmd/dendrite-demo-yggdrasil/main.go @@ -83,9 +83,8 @@ func main() { cfg.MediaAPI.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-mediaapi.db", *instanceName)) cfg.SyncAPI.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-syncapi.db", *instanceName)) cfg.RoomServer.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-roomserver.db", *instanceName)) - cfg.SigningKeyServer.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-signingkeyserver.db", *instanceName)) cfg.KeyServer.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-keyserver.db", *instanceName)) - cfg.FederationSender.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-federationapi.db", *instanceName)) + cfg.FederationAPI.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-federationapi.db", *instanceName)) cfg.AppServiceAPI.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-appservice.db", *instanceName)) cfg.Global.Kafka.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-naffka.db", *instanceName)) cfg.MSCs.MSCs = []string{"msc2836"} @@ -108,7 +107,7 @@ func main() { keyAPI.SetUserAPI(userAPI) rsComponent := roomserver.NewInternalAPI( - base, keyRing, + base, ) rsAPI := rsComponent @@ -119,10 +118,11 @@ func main() { asAPI := appservice.NewInternalAPI(base, userAPI, rsAPI) rsAPI.SetAppserviceAPI(asAPI) fsAPI := federationapi.NewInternalAPI( - base, federation, rsAPI, keyRing, true, + base, federation, rsAPI, base.Caches, true, ) rsComponent.SetFederationSenderAPI(fsAPI) + rsComponent.SetKeyring(keyRing) monolith := setup.Monolith{ Config: base.Cfg, diff --git a/cmd/dendrite-monolith-server/main.go b/cmd/dendrite-monolith-server/main.go index 347aff9bd..e61af531e 100644 --- a/cmd/dendrite-monolith-server/main.go +++ b/cmd/dendrite-monolith-server/main.go @@ -29,7 +29,6 @@ import ( basepkg "github.com/matrix-org/dendrite/setup/base" "github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/mscs" - "github.com/matrix-org/dendrite/signingkeyserver" "github.com/matrix-org/dendrite/userapi" uapi "github.com/matrix-org/dendrite/userapi/api" "github.com/sirupsen/logrus" @@ -64,11 +63,9 @@ func main() { cfg.ClientAPI.InternalAPI.Connect = httpAPIAddr cfg.EDUServer.InternalAPI.Connect = httpAPIAddr cfg.FederationAPI.InternalAPI.Connect = httpAPIAddr - cfg.FederationSender.InternalAPI.Connect = httpAPIAddr cfg.KeyServer.InternalAPI.Connect = httpAPIAddr cfg.MediaAPI.InternalAPI.Connect = httpAPIAddr cfg.RoomServer.InternalAPI.Connect = httpAPIAddr - cfg.SigningKeyServer.InternalAPI.Connect = httpAPIAddr cfg.SyncAPI.InternalAPI.Connect = httpAPIAddr } @@ -78,18 +75,7 @@ func main() { accountDB := base.CreateAccountsDB() federation := base.CreateFederationClient() - skAPI := signingkeyserver.NewInternalAPI( - &base.Cfg.SigningKeyServer, federation, base.Caches, - ) - if base.UseHTTPAPIs { - signingkeyserver.AddInternalRoutes(base.InternalAPIMux, skAPI, base.Caches) - skAPI = base.SigningKeyServerHTTPClient() - } - keyRing := skAPI.KeyRing() - - rsImpl := roomserver.NewInternalAPI( - base, keyRing, - ) + rsImpl := roomserver.NewInternalAPI(base) // call functions directly on the impl unless running in HTTP mode rsAPI := rsImpl if base.UseHTTPAPIs { @@ -103,12 +89,14 @@ func main() { } fsAPI := federationapi.NewInternalAPI( - base, federation, rsAPI, keyRing, false, + base, federation, rsAPI, base.Caches, false, ) if base.UseHTTPAPIs { federationapi.AddInternalRoutes(base.InternalAPIMux, fsAPI) - fsAPI = base.FederationSenderHTTPClient() + fsAPI = base.FederationAPIHTTPClient() } + keyRing := fsAPI.KeyRing() + // The underlying roomserver implementation needs to be able to call the fedsender. // This is different to rsAPI which can be the http client which doesn't need this dependency rsImpl.SetFederationSenderAPI(fsAPI) @@ -153,7 +141,6 @@ func main() { EDUInternalAPI: eduInputAPI, FederationAPI: fsAPI, RoomserverAPI: rsAPI, - ServerKeyAPI: skAPI, UserAPI: userAPI, KeyAPI: keyAPI, } diff --git a/cmd/dendrite-polylith-multi/main.go b/cmd/dendrite-polylith-multi/main.go index 35d272b39..88d556eb8 100644 --- a/cmd/dendrite-polylith-multi/main.go +++ b/cmd/dendrite-polylith-multi/main.go @@ -41,16 +41,15 @@ func main() { } components := map[string]entrypoint{ - "appservice": personalities.Appservice, - "clientapi": personalities.ClientAPI, - "eduserver": personalities.EDUServer, - "federationapi": personalities.FederationAPI, - "keyserver": personalities.KeyServer, - "mediaapi": personalities.MediaAPI, - "roomserver": personalities.RoomServer, - "signingkeyserver": personalities.SigningKeyServer, - "syncapi": personalities.SyncAPI, - "userapi": personalities.UserAPI, + "appservice": personalities.Appservice, + "clientapi": personalities.ClientAPI, + "eduserver": personalities.EDUServer, + "federationapi": personalities.FederationAPI, + "keyserver": personalities.KeyServer, + "mediaapi": personalities.MediaAPI, + "roomserver": personalities.RoomServer, + "syncapi": personalities.SyncAPI, + "userapi": personalities.UserAPI, } start, ok := components[component] diff --git a/cmd/dendrite-polylith-multi/personalities/clientapi.go b/cmd/dendrite-polylith-multi/personalities/clientapi.go index 0a703958b..bd9f7a109 100644 --- a/cmd/dendrite-polylith-multi/personalities/clientapi.go +++ b/cmd/dendrite-polylith-multi/personalities/clientapi.go @@ -27,7 +27,7 @@ func ClientAPI(base *basepkg.BaseDendrite, cfg *config.Dendrite) { asQuery := base.AppserviceHTTPClient() rsAPI := base.RoomserverHTTPClient() - fsAPI := base.FederationSenderHTTPClient() + fsAPI := base.FederationAPIHTTPClient() eduInputAPI := base.EDUServerClient() userAPI := base.UserAPIClient() keyAPI := base.KeyServerHTTPClient() diff --git a/cmd/dendrite-polylith-multi/personalities/federationapi.go b/cmd/dendrite-polylith-multi/personalities/federationapi.go index 670d8d307..9b59cf45b 100644 --- a/cmd/dendrite-polylith-multi/personalities/federationapi.go +++ b/cmd/dendrite-polylith-multi/personalities/federationapi.go @@ -23,9 +23,8 @@ import ( func FederationAPI(base *basepkg.BaseDendrite, cfg *config.Dendrite) { userAPI := base.UserAPIClient() federation := base.CreateFederationClient() - serverKeyAPI := base.SigningKeyServerHTTPClient() - keyRing := serverKeyAPI.KeyRing() - fsAPI := base.FederationSenderHTTPClient() + fsAPI := base.FederationAPIHTTPClient() + keyRing := fsAPI.KeyRing() rsAPI := base.RoomserverHTTPClient() keyAPI := base.KeyServerHTTPClient() diff --git a/cmd/dendrite-polylith-multi/personalities/keyserver.go b/cmd/dendrite-polylith-multi/personalities/keyserver.go index 8a6494a3c..f8aa57b86 100644 --- a/cmd/dendrite-polylith-multi/personalities/keyserver.go +++ b/cmd/dendrite-polylith-multi/personalities/keyserver.go @@ -21,7 +21,7 @@ import ( ) func KeyServer(base *basepkg.BaseDendrite, cfg *config.Dendrite) { - fsAPI := base.FederationSenderHTTPClient() + fsAPI := base.FederationAPIHTTPClient() intAPI := keyserver.NewInternalAPI(base, &base.Cfg.KeyServer, fsAPI) intAPI.SetUserAPI(base.UserAPIClient()) diff --git a/cmd/dendrite-polylith-multi/personalities/roomserver.go b/cmd/dendrite-polylith-multi/personalities/roomserver.go index f8ede65db..0a45ae1bc 100644 --- a/cmd/dendrite-polylith-multi/personalities/roomserver.go +++ b/cmd/dendrite-polylith-multi/personalities/roomserver.go @@ -21,12 +21,9 @@ import ( ) func RoomServer(base *basepkg.BaseDendrite, cfg *config.Dendrite) { - serverKeyAPI := base.SigningKeyServerHTTPClient() - keyRing := serverKeyAPI.KeyRing() - asAPI := base.AppserviceHTTPClient() - fsAPI := base.FederationSenderHTTPClient() - rsAPI := roomserver.NewInternalAPI(base, keyRing) + fsAPI := base.FederationAPIHTTPClient() + rsAPI := roomserver.NewInternalAPI(base) rsAPI.SetFederationSenderAPI(fsAPI) rsAPI.SetAppserviceAPI(asAPI) roomserver.AddInternalRoutes(base.InternalAPIMux, rsAPI) diff --git a/cmd/dendrite-polylith-multi/personalities/signingkeyserver.go b/cmd/dendrite-polylith-multi/personalities/signingkeyserver.go deleted file mode 100644 index f2cb21edf..000000000 --- a/cmd/dendrite-polylith-multi/personalities/signingkeyserver.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2020 The Matrix.org Foundation C.I.C. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package personalities - -import ( - basepkg "github.com/matrix-org/dendrite/setup/base" - "github.com/matrix-org/dendrite/setup/config" - "github.com/matrix-org/dendrite/signingkeyserver" -) - -func SigningKeyServer(base *basepkg.BaseDendrite, cfg *config.Dendrite) { - federation := base.CreateFederationClient() - - intAPI := signingkeyserver.NewInternalAPI(&base.Cfg.SigningKeyServer, federation, base.Caches) - signingkeyserver.AddInternalRoutes(base.InternalAPIMux, intAPI, base.Caches) - - base.SetupAndServeHTTP( - base.Cfg.SigningKeyServer.InternalAPI.Listen, - basepkg.NoListener, - nil, nil, - ) -} diff --git a/cmd/generate-config/main.go b/cmd/generate-config/main.go index e300a1caf..a0407b732 100644 --- a/cmd/generate-config/main.go +++ b/cmd/generate-config/main.go @@ -24,12 +24,11 @@ func main() { if *dbURI != "" { cfg.Global.Kafka.Database.ConnectionString = config.DataSource(*dbURI) cfg.AppServiceAPI.Database.ConnectionString = config.DataSource(*dbURI) - cfg.FederationSender.Database.ConnectionString = config.DataSource(*dbURI) + cfg.FederationAPI.Database.ConnectionString = config.DataSource(*dbURI) cfg.KeyServer.Database.ConnectionString = config.DataSource(*dbURI) cfg.MSCs.Database.ConnectionString = config.DataSource(*dbURI) cfg.MediaAPI.Database.ConnectionString = config.DataSource(*dbURI) cfg.RoomServer.Database.ConnectionString = config.DataSource(*dbURI) - cfg.SigningKeyServer.Database.ConnectionString = config.DataSource(*dbURI) cfg.SyncAPI.Database.ConnectionString = config.DataSource(*dbURI) cfg.UserAPI.AccountDatabase.ConnectionString = config.DataSource(*dbURI) cfg.UserAPI.DeviceDatabase.ConnectionString = config.DataSource(*dbURI) @@ -47,7 +46,7 @@ func main() { }, }, } - cfg.SigningKeyServer.KeyPerspectives = config.KeyPerspectives{ + cfg.FederationAPI.KeyPerspectives = config.KeyPerspectives{ { ServerName: "matrix.org", Keys: []config.KeyPerspectiveTrustKey{ @@ -83,11 +82,11 @@ func main() { if *defaultsForCI { cfg.AppServiceAPI.DisableTLSValidation = true cfg.ClientAPI.RateLimiting.Enabled = false - cfg.FederationSender.DisableTLSValidation = true + cfg.FederationAPI.DisableTLSValidation = true + // don't hit matrix.org when running tests!!! + cfg.FederationAPI.KeyPerspectives = config.KeyPerspectives{} cfg.MSCs.MSCs = []string{"msc2836", "msc2946", "msc2444", "msc2753"} cfg.Logging[0].Level = "trace" - // don't hit matrix.org when running tests!!! - cfg.SigningKeyServer.KeyPerspectives = config.KeyPerspectives{} cfg.UserAPI.BCryptCost = bcrypt.MinCost } diff --git a/federationapi/api/api.go b/federationapi/api/api.go index 0a36d1ceb..57c1cffae 100644 --- a/federationapi/api/api.go +++ b/federationapi/api/api.go @@ -39,6 +39,10 @@ func (e *FederationClientError) Error() string { // FederationInternalAPI is used to query information from the federation sender. type FederationInternalAPI interface { FederationClient + gomatrixserverlib.KeyDatabase + gomatrixserverlib.KeyFetcher + + KeyRing() *gomatrixserverlib.KeyRing QueryServerKeys(ctx context.Context, request *QueryServerKeysRequest, response *QueryServerKeysResponse) error @@ -114,6 +118,14 @@ type QueryServerKeysResponse struct { ServerKeys []gomatrixserverlib.ServerKeys } +type QueryPublicKeysRequest struct { + Requests map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.Timestamp `json:"requests"` +} + +type QueryPublicKeysResponse struct { + Results map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.PublicKeyLookupResult `json:"results"` +} + type PerformDirectoryLookupRequest struct { RoomAlias string `json:"room_alias"` ServerName gomatrixserverlib.ServerName `json:"server_name"` @@ -188,3 +200,10 @@ type PerformBroadcastEDURequest struct { type PerformBroadcastEDUResponse struct { } + +type InputPublicKeysRequest struct { + Keys map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.PublicKeyLookupResult `json:"keys"` +} + +type InputPublicKeysResponse struct { +} diff --git a/federationapi/consumers/eduserver.go b/federationapi/consumers/eduserver.go index 7ee54ba0b..56ec9eaf8 100644 --- a/federationapi/consumers/eduserver.go +++ b/federationapi/consumers/eduserver.go @@ -46,7 +46,7 @@ type OutputEDUConsumer struct { // NewOutputEDUConsumer creates a new OutputEDUConsumer. Call Start() to begin consuming from EDU servers. func NewOutputEDUConsumer( process *process.ProcessContext, - cfg *config.FederationSender, + cfg *config.FederationAPI, kafkaConsumer sarama.Consumer, queues *queue.OutgoingQueues, store storage.Database, diff --git a/federationapi/consumers/roomserver.go b/federationapi/consumers/roomserver.go index 2c8a0c724..20b1bacbc 100644 --- a/federationapi/consumers/roomserver.go +++ b/federationapi/consumers/roomserver.go @@ -33,7 +33,7 @@ import ( // OutputRoomEventConsumer consumes events that originated in the room server. type OutputRoomEventConsumer struct { - cfg *config.FederationSender + cfg *config.FederationAPI rsAPI api.RoomserverInternalAPI rsConsumer *internal.ContinualConsumer db storage.Database @@ -43,7 +43,7 @@ type OutputRoomEventConsumer struct { // NewOutputRoomEventConsumer creates a new OutputRoomEventConsumer. Call Start() to begin consuming from room servers. func NewOutputRoomEventConsumer( process *process.ProcessContext, - cfg *config.FederationSender, + cfg *config.FederationAPI, kafkaConsumer sarama.Consumer, queues *queue.OutgoingQueues, store storage.Database, diff --git a/federationapi/federationapi.go b/federationapi/federationapi.go index 18bf82faa..371b364c6 100644 --- a/federationapi/federationapi.go +++ b/federationapi/federationapi.go @@ -25,6 +25,7 @@ import ( "github.com/matrix-org/dendrite/federationapi/queue" "github.com/matrix-org/dendrite/federationapi/statistics" "github.com/matrix-org/dendrite/federationapi/storage" + "github.com/matrix-org/dendrite/internal/caching" keyserverAPI "github.com/matrix-org/dendrite/keyserver/api" roomserverAPI "github.com/matrix-org/dendrite/roomserver/api" "github.com/matrix-org/dendrite/setup/base" @@ -71,29 +72,29 @@ func NewInternalAPI( base *base.BaseDendrite, federation *gomatrixserverlib.FederationClient, rsAPI roomserverAPI.RoomserverInternalAPI, - keyRing *gomatrixserverlib.KeyRing, + caches *caching.Caches, resetBlacklist bool, ) api.FederationInternalAPI { - cfg := &base.Cfg.FederationSender + cfg := &base.Cfg.FederationAPI - federationSenderDB, err := storage.NewDatabase(&cfg.Database, base.Caches) + federationDB, err := storage.NewDatabase(&cfg.Database, base.Caches) if err != nil { logrus.WithError(err).Panic("failed to connect to federation sender db") } if resetBlacklist { - _ = federationSenderDB.RemoveAllServersFromBlacklist() + _ = federationDB.RemoveAllServersFromBlacklist() } stats := &statistics.Statistics{ - DB: federationSenderDB, + DB: federationDB, FailuresUntilBlacklist: cfg.FederationMaxRetries, } consumer, _ := kafka.SetupConsumerProducer(&cfg.Matrix.Kafka) queues := queue.NewOutgoingQueues( - federationSenderDB, base.ProcessContext, + federationDB, base.ProcessContext, cfg.Matrix.DisableFederation, cfg.Matrix.ServerName, federation, rsAPI, stats, &queue.SigningInfo{ @@ -105,24 +106,24 @@ func NewInternalAPI( rsConsumer := consumers.NewOutputRoomEventConsumer( base.ProcessContext, cfg, consumer, queues, - federationSenderDB, rsAPI, + federationDB, rsAPI, ) if err = rsConsumer.Start(); err != nil { logrus.WithError(err).Panic("failed to start room server consumer") } tsConsumer := consumers.NewOutputEDUConsumer( - base.ProcessContext, cfg, consumer, queues, federationSenderDB, + base.ProcessContext, cfg, consumer, queues, federationDB, ) if err := tsConsumer.Start(); err != nil { logrus.WithError(err).Panic("failed to start typing server consumer") } keyConsumer := consumers.NewKeyChangeConsumer( - base.ProcessContext, &base.Cfg.KeyServer, consumer, queues, federationSenderDB, rsAPI, + base.ProcessContext, &base.Cfg.KeyServer, consumer, queues, federationDB, rsAPI, ) if err := keyConsumer.Start(); err != nil { logrus.WithError(err).Panic("failed to start key server consumer") } - return internal.NewFederationInternalAPI(federationSenderDB, cfg, rsAPI, federation, keyRing, stats, queues) + return internal.NewFederationInternalAPI(federationDB, cfg, rsAPI, federation, stats, caches, queues) } diff --git a/federationapi/federationapi_test.go b/federationapi/federationapi_test.go index 4590e3b6e..548f9c6da 100644 --- a/federationapi/federationapi_test.go +++ b/federationapi/federationapi_test.go @@ -25,10 +25,10 @@ func TestRoomsV3URLEscapeDoNot404(t *testing.T) { cfg.Global.PrivateKey = privKey cfg.Global.Kafka.UseNaffka = true cfg.Global.Kafka.Database.ConnectionString = config.DataSource("file::memory:") - cfg.FederationSender.Database.ConnectionString = config.DataSource("file::memory:") + cfg.FederationAPI.Database.ConnectionString = config.DataSource("file::memory:") base := base.NewBaseDendrite(cfg, "Monolith", false) keyRing := &test.NopJSONVerifier{} - fsAPI := base.FederationSenderHTTPClient() + fsAPI := base.FederationAPIHTTPClient() // TODO: This is pretty fragile, as if anything calls anything on these nils this test will break. // Unfortunately, it makes little sense to instantiate these dependencies when we just want to test routing. federationapi.AddPublicRoutes(base.PublicFederationAPIMux, base.PublicKeyAPIMux, base.PublicWellKnownAPIMux, &cfg.FederationAPI, nil, nil, keyRing, nil, fsAPI, nil, nil, &cfg.MSCs, nil) diff --git a/federationapi/internal/api.go b/federationapi/internal/api.go index 4d0f3ecca..73d27315f 100644 --- a/federationapi/internal/api.go +++ b/federationapi/internal/api.go @@ -2,6 +2,8 @@ package internal import ( "context" + "crypto/ed25519" + "encoding/base64" "sync" "time" @@ -9,16 +11,19 @@ import ( "github.com/matrix-org/dendrite/federationapi/queue" "github.com/matrix-org/dendrite/federationapi/statistics" "github.com/matrix-org/dendrite/federationapi/storage" + "github.com/matrix-org/dendrite/federationapi/storage/cache" + "github.com/matrix-org/dendrite/internal/caching" roomserverAPI "github.com/matrix-org/dendrite/roomserver/api" "github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/gomatrix" "github.com/matrix-org/gomatrixserverlib" + "github.com/sirupsen/logrus" ) // FederationInternalAPI is an implementation of api.FederationInternalAPI type FederationInternalAPI struct { db storage.Database - cfg *config.FederationSender + cfg *config.FederationAPI statistics *statistics.Statistics rsAPI roomserverAPI.RoomserverInternalAPI federation *gomatrixserverlib.FederationClient @@ -28,19 +33,72 @@ type FederationInternalAPI struct { } func NewFederationInternalAPI( - db storage.Database, cfg *config.FederationSender, + db storage.Database, cfg *config.FederationAPI, rsAPI roomserverAPI.RoomserverInternalAPI, federation *gomatrixserverlib.FederationClient, - keyRing *gomatrixserverlib.KeyRing, statistics *statistics.Statistics, + caches *caching.Caches, queues *queue.OutgoingQueues, ) *FederationInternalAPI { + serverKeyDB, err := cache.NewKeyDatabase(db, caches) + if err != nil { + logrus.WithError(err).Panicf("failed to set up caching wrapper for server key database") + } + + keyRing := &gomatrixserverlib.KeyRing{ + KeyFetchers: []gomatrixserverlib.KeyFetcher{}, + KeyDatabase: serverKeyDB, + } + + addDirectFetcher := func() { + keyRing.KeyFetchers = append( + keyRing.KeyFetchers, + &gomatrixserverlib.DirectKeyFetcher{ + Client: federation, + }, + ) + } + + if cfg.PreferDirectFetch { + addDirectFetcher() + } else { + defer addDirectFetcher() + } + + var b64e = base64.StdEncoding.WithPadding(base64.NoPadding) + for _, ps := range cfg.KeyPerspectives { + perspective := &gomatrixserverlib.PerspectiveKeyFetcher{ + PerspectiveServerName: ps.ServerName, + PerspectiveServerKeys: map[gomatrixserverlib.KeyID]ed25519.PublicKey{}, + Client: federation, + } + + for _, key := range ps.Keys { + rawkey, err := b64e.DecodeString(key.PublicKey) + if err != nil { + logrus.WithError(err).WithFields(logrus.Fields{ + "server_name": ps.ServerName, + "public_key": key.PublicKey, + }).Warn("Couldn't parse perspective key") + continue + } + perspective.PerspectiveServerKeys[key.KeyID] = rawkey + } + + keyRing.KeyFetchers = append(keyRing.KeyFetchers, perspective) + + logrus.WithFields(logrus.Fields{ + "server_name": ps.ServerName, + "num_public_keys": len(ps.Keys), + }).Info("Enabled perspective key fetcher") + } + return &FederationInternalAPI{ db: db, cfg: cfg, rsAPI: rsAPI, - federation: federation, keyRing: keyRing, + federation: federation, statistics: statistics, queues: queues, } diff --git a/signingkeyserver/internal/api.go b/federationapi/internal/keys.go similarity index 85% rename from signingkeyserver/internal/api.go rename to federationapi/internal/keys.go index f9a04a74f..0ef913f6e 100644 --- a/signingkeyserver/internal/api.go +++ b/federationapi/internal/keys.go @@ -6,26 +6,11 @@ import ( "fmt" "time" - "github.com/matrix-org/dendrite/setup/config" - "github.com/matrix-org/dendrite/signingkeyserver/api" "github.com/matrix-org/gomatrixserverlib" "github.com/sirupsen/logrus" ) -type ServerKeyAPI struct { - api.SigningKeyServerAPI - - ServerName gomatrixserverlib.ServerName - ServerPublicKey ed25519.PublicKey - ServerKeyID gomatrixserverlib.KeyID - ServerKeyValidity time.Duration - OldServerKeys []config.OldVerifyKeys - - OurKeyRing gomatrixserverlib.KeyRing - FedClient gomatrixserverlib.KeyClient -} - -func (s *ServerKeyAPI) KeyRing() *gomatrixserverlib.KeyRing { +func (s *FederationInternalAPI) KeyRing() *gomatrixserverlib.KeyRing { // Return a keyring that forces requests to be proxied through the // below functions. That way we can enforce things like validity // and keeping the cache up-to-date. @@ -35,7 +20,7 @@ func (s *ServerKeyAPI) KeyRing() *gomatrixserverlib.KeyRing { } } -func (s *ServerKeyAPI) StoreKeys( +func (s *FederationInternalAPI) StoreKeys( _ context.Context, results map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.PublicKeyLookupResult, ) error { @@ -44,10 +29,10 @@ func (s *ServerKeyAPI) StoreKeys( ctx := context.Background() // Store any keys that we were given in our database. - return s.OurKeyRing.KeyDatabase.StoreKeys(ctx, results) + return s.keyRing.KeyDatabase.StoreKeys(ctx, results) } -func (s *ServerKeyAPI) FetchKeys( +func (s *FederationInternalAPI) FetchKeys( _ context.Context, requests map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.Timestamp, ) (map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.PublicKeyLookupResult, error) { @@ -75,7 +60,7 @@ func (s *ServerKeyAPI) FetchKeys( // For any key requests that we still have outstanding, next try to // fetch them directly. We'll go through each of the key fetchers to // ask for the remaining keys - for _, fetcher := range s.OurKeyRing.KeyFetchers { + for _, fetcher := range s.keyRing.KeyFetchers { // If there are no more keys to look up then stop. if len(requests) == 0 { break @@ -105,22 +90,22 @@ func (s *ServerKeyAPI) FetchKeys( return results, nil } -func (s *ServerKeyAPI) FetcherName() string { - return fmt.Sprintf("ServerKeyAPI (wrapping %q)", s.OurKeyRing.KeyDatabase.FetcherName()) +func (s *FederationInternalAPI) FetcherName() string { + return fmt.Sprintf("FederationInternalAPI (wrapping %q)", s.keyRing.KeyDatabase.FetcherName()) } // handleLocalKeys handles cases where the key request contains // a request for our own server keys, either current or old. -func (s *ServerKeyAPI) handleLocalKeys( +func (s *FederationInternalAPI) handleLocalKeys( _ context.Context, requests map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.Timestamp, results map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.PublicKeyLookupResult, ) { for req := range requests { - if req.ServerName != s.ServerName { + if req.ServerName != s.cfg.Matrix.ServerName { continue } - if req.KeyID == s.ServerKeyID { + if req.KeyID == s.cfg.Matrix.KeyID { // We found a key request that is supposed to be for our own // keys. Remove it from the request list so we don't hit the // database or the fetchers for it. @@ -129,15 +114,15 @@ func (s *ServerKeyAPI) handleLocalKeys( // Insert our own key into the response. results[req] = gomatrixserverlib.PublicKeyLookupResult{ VerifyKey: gomatrixserverlib.VerifyKey{ - Key: gomatrixserverlib.Base64Bytes(s.ServerPublicKey), + Key: gomatrixserverlib.Base64Bytes(s.cfg.Matrix.PrivateKey.Public().(ed25519.PublicKey)), }, ExpiredTS: gomatrixserverlib.PublicKeyNotExpired, - ValidUntilTS: gomatrixserverlib.AsTimestamp(time.Now().Add(s.ServerKeyValidity)), + ValidUntilTS: gomatrixserverlib.AsTimestamp(time.Now().Add(s.cfg.Matrix.KeyValidityPeriod)), } } else { // The key request doesn't match our current key. Let's see // if it matches any of our old verify keys. - for _, oldVerifyKey := range s.OldServerKeys { + for _, oldVerifyKey := range s.cfg.Matrix.OldVerifyKeys { if req.KeyID == oldVerifyKey.KeyID { // We found a key request that is supposed to be an expired // key. @@ -162,14 +147,14 @@ func (s *ServerKeyAPI) handleLocalKeys( // handleDatabaseKeys handles cases where the key requests can be // satisfied from our local database/cache. -func (s *ServerKeyAPI) handleDatabaseKeys( +func (s *FederationInternalAPI) handleDatabaseKeys( ctx context.Context, now gomatrixserverlib.Timestamp, requests map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.Timestamp, results map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.PublicKeyLookupResult, ) error { // Ask the database/cache for the keys. - dbResults, err := s.OurKeyRing.KeyDatabase.FetchKeys(ctx, requests) + dbResults, err := s.keyRing.KeyDatabase.FetchKeys(ctx, requests) if err != nil { return err } @@ -196,7 +181,7 @@ func (s *ServerKeyAPI) handleDatabaseKeys( // handleFetcherKeys handles cases where a fetcher can satisfy // the remaining requests. -func (s *ServerKeyAPI) handleFetcherKeys( +func (s *FederationInternalAPI) handleFetcherKeys( ctx context.Context, _ gomatrixserverlib.Timestamp, fetcher gomatrixserverlib.KeyFetcher, @@ -248,10 +233,10 @@ func (s *ServerKeyAPI) handleFetcherKeys( } // Store the keys from our store map. - if err = s.OurKeyRing.KeyDatabase.StoreKeys(context.Background(), storeResults); err != nil { + if err = s.keyRing.KeyDatabase.StoreKeys(context.Background(), storeResults); err != nil { logrus.WithError(err).WithFields(logrus.Fields{ "fetcher_name": fetcher.FetcherName(), - "database_name": s.OurKeyRing.KeyDatabase.FetcherName(), + "database_name": s.keyRing.KeyDatabase.FetcherName(), }).Errorf("Failed to store keys in the database") return fmt.Errorf("server key API failed to store retrieved keys: %w", err) } diff --git a/federationapi/inthttp/client.go b/federationapi/inthttp/client.go index 9f77b099f..af6b801b3 100644 --- a/federationapi/inthttp/client.go +++ b/federationapi/inthttp/client.go @@ -6,6 +6,7 @@ import ( "net/http" "github.com/matrix-org/dendrite/federationapi/api" + "github.com/matrix-org/dendrite/internal/caching" "github.com/matrix-org/dendrite/internal/httputil" "github.com/matrix-org/gomatrix" "github.com/matrix-org/gomatrixserverlib" @@ -14,41 +15,45 @@ import ( // HTTP paths for the internal HTTP API const ( - FederationSenderQueryJoinedHostServerNamesInRoomPath = "/federationapi/queryJoinedHostServerNamesInRoom" - FederationSenderQueryServerKeysPath = "/federationapi/queryServerKeys" + FederationAPIQueryJoinedHostServerNamesInRoomPath = "/federationapi/queryJoinedHostServerNamesInRoom" + FederationAPIQueryServerKeysPath = "/federationapi/queryServerKeys" - FederationSenderPerformDirectoryLookupRequestPath = "/federationapi/performDirectoryLookup" - FederationSenderPerformJoinRequestPath = "/federationapi/performJoinRequest" - FederationSenderPerformLeaveRequestPath = "/federationapi/performLeaveRequest" - FederationSenderPerformInviteRequestPath = "/federationapi/performInviteRequest" - FederationSenderPerformOutboundPeekRequestPath = "/federationapi/performOutboundPeekRequest" - FederationSenderPerformServersAlivePath = "/federationapi/performServersAlive" - FederationSenderPerformBroadcastEDUPath = "/federationapi/performBroadcastEDU" + FederationAPIPerformDirectoryLookupRequestPath = "/federationapi/performDirectoryLookup" + FederationAPIPerformJoinRequestPath = "/federationapi/performJoinRequest" + FederationAPIPerformLeaveRequestPath = "/federationapi/performLeaveRequest" + FederationAPIPerformInviteRequestPath = "/federationapi/performInviteRequest" + FederationAPIPerformOutboundPeekRequestPath = "/federationapi/performOutboundPeekRequest" + FederationAPIPerformServersAlivePath = "/federationapi/performServersAlive" + FederationAPIPerformBroadcastEDUPath = "/federationapi/performBroadcastEDU" - FederationSenderGetUserDevicesPath = "/federationapi/client/getUserDevices" - FederationSenderClaimKeysPath = "/federationapi/client/claimKeys" - FederationSenderQueryKeysPath = "/federationapi/client/queryKeys" - FederationSenderBackfillPath = "/federationapi/client/backfill" - FederationSenderLookupStatePath = "/federationapi/client/lookupState" - FederationSenderLookupStateIDsPath = "/federationapi/client/lookupStateIDs" - FederationSenderGetEventPath = "/federationapi/client/getEvent" - FederationSenderLookupServerKeysPath = "/federationapi/client/lookupServerKeys" - FederationSenderEventRelationshipsPath = "/federationapi/client/msc2836eventRelationships" - FederationSenderSpacesSummaryPath = "/federationapi/client/msc2946spacesSummary" + FederationAPIGetUserDevicesPath = "/federationapi/client/getUserDevices" + FederationAPIClaimKeysPath = "/federationapi/client/claimKeys" + FederationAPIQueryKeysPath = "/federationapi/client/queryKeys" + FederationAPIBackfillPath = "/federationapi/client/backfill" + FederationAPILookupStatePath = "/federationapi/client/lookupState" + FederationAPILookupStateIDsPath = "/federationapi/client/lookupStateIDs" + FederationAPIGetEventPath = "/federationapi/client/getEvent" + FederationAPILookupServerKeysPath = "/federationapi/client/lookupServerKeys" + FederationAPIEventRelationshipsPath = "/federationapi/client/msc2836eventRelationships" + FederationAPISpacesSummaryPath = "/federationapi/client/msc2946spacesSummary" + + FederationAPIInputPublicKeyPath = "/federationapi/inputPublicKey" + FederationAPIQueryPublicKeyPath = "/federationapi/queryPublicKey" ) -// NewFederationSenderClient creates a FederationInternalAPI implemented by talking to a HTTP POST API. +// NewFederationAPIClient creates a FederationInternalAPI implemented by talking to a HTTP POST API. // If httpClient is nil an error is returned -func NewFederationSenderClient(federationSenderURL string, httpClient *http.Client) (api.FederationInternalAPI, error) { +func NewFederationAPIClient(federationSenderURL string, httpClient *http.Client, cache caching.ServerKeyCache) (api.FederationInternalAPI, error) { if httpClient == nil { return nil, errors.New("NewFederationInternalAPIHTTP: httpClient is ") } - return &httpFederationInternalAPI{federationSenderURL, httpClient}, nil + return &httpFederationInternalAPI{federationSenderURL, httpClient, cache}, nil } type httpFederationInternalAPI struct { - federationSenderURL string - httpClient *http.Client + federationAPIURL string + httpClient *http.Client + cache caching.ServerKeyCache } // Handle an instruction to make_leave & send_leave with a remote server. @@ -60,7 +65,7 @@ func (h *httpFederationInternalAPI) PerformLeave( span, ctx := opentracing.StartSpanFromContext(ctx, "PerformLeaveRequest") defer span.Finish() - apiURL := h.federationSenderURL + FederationSenderPerformLeaveRequestPath + apiURL := h.federationAPIURL + FederationAPIPerformLeaveRequestPath return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response) } @@ -73,7 +78,7 @@ func (h *httpFederationInternalAPI) PerformInvite( span, ctx := opentracing.StartSpanFromContext(ctx, "PerformInviteRequest") defer span.Finish() - apiURL := h.federationSenderURL + FederationSenderPerformInviteRequestPath + apiURL := h.federationAPIURL + FederationAPIPerformInviteRequestPath return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response) } @@ -86,7 +91,7 @@ func (h *httpFederationInternalAPI) PerformOutboundPeek( span, ctx := opentracing.StartSpanFromContext(ctx, "PerformOutboundPeekRequest") defer span.Finish() - apiURL := h.federationSenderURL + FederationSenderPerformOutboundPeekRequestPath + apiURL := h.federationAPIURL + FederationAPIPerformOutboundPeekRequestPath return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response) } @@ -98,7 +103,7 @@ func (h *httpFederationInternalAPI) PerformServersAlive( span, ctx := opentracing.StartSpanFromContext(ctx, "PerformServersAlive") defer span.Finish() - apiURL := h.federationSenderURL + FederationSenderPerformServersAlivePath + apiURL := h.federationAPIURL + FederationAPIPerformServersAlivePath return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response) } @@ -111,7 +116,7 @@ func (h *httpFederationInternalAPI) QueryJoinedHostServerNamesInRoom( span, ctx := opentracing.StartSpanFromContext(ctx, "QueryJoinedHostServerNamesInRoom") defer span.Finish() - apiURL := h.federationSenderURL + FederationSenderQueryJoinedHostServerNamesInRoomPath + apiURL := h.federationAPIURL + FederationAPIQueryJoinedHostServerNamesInRoomPath return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response) } @@ -124,7 +129,7 @@ func (h *httpFederationInternalAPI) PerformJoin( span, ctx := opentracing.StartSpanFromContext(ctx, "PerformJoinRequest") defer span.Finish() - apiURL := h.federationSenderURL + FederationSenderPerformJoinRequestPath + apiURL := h.federationAPIURL + FederationAPIPerformJoinRequestPath err := httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response) if err != nil { response.LastError = &gomatrix.HTTPError{ @@ -144,7 +149,7 @@ func (h *httpFederationInternalAPI) PerformDirectoryLookup( span, ctx := opentracing.StartSpanFromContext(ctx, "PerformDirectoryLookup") defer span.Finish() - apiURL := h.federationSenderURL + FederationSenderPerformDirectoryLookupRequestPath + apiURL := h.federationAPIURL + FederationAPIPerformDirectoryLookupRequestPath return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response) } @@ -157,7 +162,7 @@ func (h *httpFederationInternalAPI) PerformBroadcastEDU( span, ctx := opentracing.StartSpanFromContext(ctx, "PerformBroadcastEDU") defer span.Finish() - apiURL := h.federationSenderURL + FederationSenderPerformBroadcastEDUPath + apiURL := h.federationAPIURL + FederationAPIPerformBroadcastEDUPath return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response) } @@ -180,7 +185,7 @@ func (h *httpFederationInternalAPI) GetUserDevices( UserID: userID, } var response getUserDevices - apiURL := h.federationSenderURL + FederationSenderGetUserDevicesPath + apiURL := h.federationAPIURL + FederationAPIGetUserDevicesPath err := httputil.PostJSON(ctx, span, h.httpClient, apiURL, &request, &response) if err != nil { return result, err @@ -210,7 +215,7 @@ func (h *httpFederationInternalAPI) ClaimKeys( OneTimeKeys: oneTimeKeys, } var response claimKeys - apiURL := h.federationSenderURL + FederationSenderClaimKeysPath + apiURL := h.federationAPIURL + FederationAPIClaimKeysPath err := httputil.PostJSON(ctx, span, h.httpClient, apiURL, &request, &response) if err != nil { return result, err @@ -240,7 +245,7 @@ func (h *httpFederationInternalAPI) QueryKeys( Keys: keys, } var response queryKeys - apiURL := h.federationSenderURL + FederationSenderQueryKeysPath + apiURL := h.federationAPIURL + FederationAPIQueryKeysPath err := httputil.PostJSON(ctx, span, h.httpClient, apiURL, &request, &response) if err != nil { return result, err @@ -273,7 +278,7 @@ func (h *httpFederationInternalAPI) Backfill( EventIDs: eventIDs, } var response backfill - apiURL := h.federationSenderURL + FederationSenderBackfillPath + apiURL := h.federationAPIURL + FederationAPIBackfillPath err := httputil.PostJSON(ctx, span, h.httpClient, apiURL, &request, &response) if err != nil { return gomatrixserverlib.Transaction{}, err @@ -306,7 +311,7 @@ func (h *httpFederationInternalAPI) LookupState( RoomVersion: roomVersion, } var response lookupState - apiURL := h.federationSenderURL + FederationSenderLookupStatePath + apiURL := h.federationAPIURL + FederationAPILookupStatePath err := httputil.PostJSON(ctx, span, h.httpClient, apiURL, &request, &response) if err != nil { return gomatrixserverlib.RespState{}, err @@ -337,7 +342,7 @@ func (h *httpFederationInternalAPI) LookupStateIDs( EventID: eventID, } var response lookupStateIDs - apiURL := h.federationSenderURL + FederationSenderLookupStateIDsPath + apiURL := h.federationAPIURL + FederationAPILookupStateIDsPath err := httputil.PostJSON(ctx, span, h.httpClient, apiURL, &request, &response) if err != nil { return gomatrixserverlib.RespStateIDs{}, err @@ -366,7 +371,7 @@ func (h *httpFederationInternalAPI) GetEvent( EventID: eventID, } var response getEvent - apiURL := h.federationSenderURL + FederationSenderGetEventPath + apiURL := h.federationAPIURL + FederationAPIGetEventPath err := httputil.PostJSON(ctx, span, h.httpClient, apiURL, &request, &response) if err != nil { return gomatrixserverlib.Transaction{}, err @@ -383,7 +388,7 @@ func (h *httpFederationInternalAPI) QueryServerKeys( span, ctx := opentracing.StartSpanFromContext(ctx, "QueryServerKeys") defer span.Finish() - apiURL := h.federationSenderURL + FederationSenderQueryServerKeysPath + apiURL := h.federationAPIURL + FederationAPIQueryServerKeysPath return httputil.PostJSON(ctx, span, h.httpClient, apiURL, req, res) } @@ -405,7 +410,7 @@ func (h *httpFederationInternalAPI) LookupServerKeys( KeyRequests: keyRequests, } var response lookupServerKeys - apiURL := h.federationSenderURL + FederationSenderLookupServerKeysPath + apiURL := h.federationAPIURL + FederationAPILookupServerKeysPath err := httputil.PostJSON(ctx, span, h.httpClient, apiURL, &request, &response) if err != nil { return []gomatrixserverlib.ServerKeys{}, err @@ -437,7 +442,7 @@ func (h *httpFederationInternalAPI) MSC2836EventRelationships( RoomVer: roomVersion, } var response eventRelationships - apiURL := h.federationSenderURL + FederationSenderEventRelationshipsPath + apiURL := h.federationAPIURL + FederationAPIEventRelationshipsPath err = httputil.PostJSON(ctx, span, h.httpClient, apiURL, &request, &response) if err != nil { return res, err @@ -468,7 +473,7 @@ func (h *httpFederationInternalAPI) MSC2946Spaces( RoomID: roomID, } var response spacesReq - apiURL := h.federationSenderURL + FederationSenderSpacesSummaryPath + apiURL := h.federationAPIURL + FederationAPISpacesSummaryPath err = httputil.PostJSON(ctx, span, h.httpClient, apiURL, &request, &response) if err != nil { return res, err @@ -478,3 +483,93 @@ func (h *httpFederationInternalAPI) MSC2946Spaces( } return response.Res, nil } + +func (s *httpFederationInternalAPI) KeyRing() *gomatrixserverlib.KeyRing { + // This is a bit of a cheat - we tell gomatrixserverlib that this API is + // both the key database and the key fetcher. While this does have the + // rather unfortunate effect of preventing gomatrixserverlib from handling + // key fetchers directly, we can at least reimplement this behaviour on + // the other end of the API. + return &gomatrixserverlib.KeyRing{ + KeyDatabase: s, + KeyFetchers: []gomatrixserverlib.KeyFetcher{}, + } +} + +func (s *httpFederationInternalAPI) FetcherName() string { + return "httpServerKeyInternalAPI" +} + +func (s *httpFederationInternalAPI) StoreKeys( + _ context.Context, + results map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.PublicKeyLookupResult, +) error { + // Run in a background context - we don't want to stop this work just + // because the caller gives up waiting. + ctx := context.Background() + request := api.InputPublicKeysRequest{ + Keys: make(map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.PublicKeyLookupResult), + } + response := api.InputPublicKeysResponse{} + for req, res := range results { + request.Keys[req] = res + s.cache.StoreServerKey(req, res) + } + return s.InputPublicKeys(ctx, &request, &response) +} + +func (s *httpFederationInternalAPI) FetchKeys( + _ context.Context, + requests map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.Timestamp, +) (map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.PublicKeyLookupResult, error) { + // Run in a background context - we don't want to stop this work just + // because the caller gives up waiting. + ctx := context.Background() + result := make(map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.PublicKeyLookupResult) + request := api.QueryPublicKeysRequest{ + Requests: make(map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.Timestamp), + } + response := api.QueryPublicKeysResponse{ + Results: make(map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.PublicKeyLookupResult), + } + for req, ts := range requests { + if res, ok := s.cache.GetServerKey(req, ts); ok { + result[req] = res + continue + } + request.Requests[req] = ts + } + err := s.QueryPublicKeys(ctx, &request, &response) + if err != nil { + return nil, err + } + for req, res := range response.Results { + result[req] = res + s.cache.StoreServerKey(req, res) + } + return result, nil +} + +func (h *httpFederationInternalAPI) InputPublicKeys( + ctx context.Context, + request *api.InputPublicKeysRequest, + response *api.InputPublicKeysResponse, +) error { + span, ctx := opentracing.StartSpanFromContext(ctx, "InputPublicKey") + defer span.Finish() + + apiURL := h.federationAPIURL + FederationAPIInputPublicKeyPath + return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response) +} + +func (h *httpFederationInternalAPI) QueryPublicKeys( + ctx context.Context, + request *api.QueryPublicKeysRequest, + response *api.QueryPublicKeysResponse, +) error { + span, ctx := opentracing.StartSpanFromContext(ctx, "QueryPublicKey") + defer span.Finish() + + apiURL := h.federationAPIURL + FederationAPIQueryPublicKeyPath + return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response) +} diff --git a/federationapi/inthttp/server.go b/federationapi/inthttp/server.go index 86a1e5294..7133eddd0 100644 --- a/federationapi/inthttp/server.go +++ b/federationapi/inthttp/server.go @@ -14,7 +14,7 @@ import ( // nolint:gocyclo func AddRoutes(intAPI api.FederationInternalAPI, internalAPIMux *mux.Router) { internalAPIMux.Handle( - FederationSenderQueryJoinedHostServerNamesInRoomPath, + FederationAPIQueryJoinedHostServerNamesInRoomPath, httputil.MakeInternalAPI("QueryJoinedHostServerNamesInRoom", func(req *http.Request) util.JSONResponse { var request api.QueryJoinedHostServerNamesInRoomRequest var response api.QueryJoinedHostServerNamesInRoomResponse @@ -28,7 +28,7 @@ func AddRoutes(intAPI api.FederationInternalAPI, internalAPIMux *mux.Router) { }), ) internalAPIMux.Handle( - FederationSenderPerformJoinRequestPath, + FederationAPIPerformJoinRequestPath, httputil.MakeInternalAPI("PerformJoinRequest", func(req *http.Request) util.JSONResponse { var request api.PerformJoinRequest var response api.PerformJoinResponse @@ -40,7 +40,7 @@ func AddRoutes(intAPI api.FederationInternalAPI, internalAPIMux *mux.Router) { }), ) internalAPIMux.Handle( - FederationSenderPerformLeaveRequestPath, + FederationAPIPerformLeaveRequestPath, httputil.MakeInternalAPI("PerformLeaveRequest", func(req *http.Request) util.JSONResponse { var request api.PerformLeaveRequest var response api.PerformLeaveResponse @@ -54,7 +54,7 @@ func AddRoutes(intAPI api.FederationInternalAPI, internalAPIMux *mux.Router) { }), ) internalAPIMux.Handle( - FederationSenderPerformInviteRequestPath, + FederationAPIPerformInviteRequestPath, httputil.MakeInternalAPI("PerformInviteRequest", func(req *http.Request) util.JSONResponse { var request api.PerformInviteRequest var response api.PerformInviteResponse @@ -68,7 +68,7 @@ func AddRoutes(intAPI api.FederationInternalAPI, internalAPIMux *mux.Router) { }), ) internalAPIMux.Handle( - FederationSenderPerformDirectoryLookupRequestPath, + FederationAPIPerformDirectoryLookupRequestPath, httputil.MakeInternalAPI("PerformDirectoryLookupRequest", func(req *http.Request) util.JSONResponse { var request api.PerformDirectoryLookupRequest var response api.PerformDirectoryLookupResponse @@ -82,7 +82,7 @@ func AddRoutes(intAPI api.FederationInternalAPI, internalAPIMux *mux.Router) { }), ) internalAPIMux.Handle( - FederationSenderPerformServersAlivePath, + FederationAPIPerformServersAlivePath, httputil.MakeInternalAPI("PerformServersAliveRequest", func(req *http.Request) util.JSONResponse { var request api.PerformServersAliveRequest var response api.PerformServersAliveResponse @@ -96,7 +96,7 @@ func AddRoutes(intAPI api.FederationInternalAPI, internalAPIMux *mux.Router) { }), ) internalAPIMux.Handle( - FederationSenderPerformBroadcastEDUPath, + FederationAPIPerformBroadcastEDUPath, httputil.MakeInternalAPI("PerformBroadcastEDU", func(req *http.Request) util.JSONResponse { var request api.PerformBroadcastEDURequest var response api.PerformBroadcastEDUResponse @@ -110,7 +110,7 @@ func AddRoutes(intAPI api.FederationInternalAPI, internalAPIMux *mux.Router) { }), ) internalAPIMux.Handle( - FederationSenderGetUserDevicesPath, + FederationAPIGetUserDevicesPath, httputil.MakeInternalAPI("GetUserDevices", func(req *http.Request) util.JSONResponse { var request getUserDevices if err := json.NewDecoder(req.Body).Decode(&request); err != nil { @@ -132,7 +132,7 @@ func AddRoutes(intAPI api.FederationInternalAPI, internalAPIMux *mux.Router) { }), ) internalAPIMux.Handle( - FederationSenderClaimKeysPath, + FederationAPIClaimKeysPath, httputil.MakeInternalAPI("ClaimKeys", func(req *http.Request) util.JSONResponse { var request claimKeys if err := json.NewDecoder(req.Body).Decode(&request); err != nil { @@ -154,7 +154,7 @@ func AddRoutes(intAPI api.FederationInternalAPI, internalAPIMux *mux.Router) { }), ) internalAPIMux.Handle( - FederationSenderQueryKeysPath, + FederationAPIQueryKeysPath, httputil.MakeInternalAPI("QueryKeys", func(req *http.Request) util.JSONResponse { var request queryKeys if err := json.NewDecoder(req.Body).Decode(&request); err != nil { @@ -176,7 +176,7 @@ func AddRoutes(intAPI api.FederationInternalAPI, internalAPIMux *mux.Router) { }), ) internalAPIMux.Handle( - FederationSenderBackfillPath, + FederationAPIBackfillPath, httputil.MakeInternalAPI("Backfill", func(req *http.Request) util.JSONResponse { var request backfill if err := json.NewDecoder(req.Body).Decode(&request); err != nil { @@ -198,7 +198,7 @@ func AddRoutes(intAPI api.FederationInternalAPI, internalAPIMux *mux.Router) { }), ) internalAPIMux.Handle( - FederationSenderLookupStatePath, + FederationAPILookupStatePath, httputil.MakeInternalAPI("LookupState", func(req *http.Request) util.JSONResponse { var request lookupState if err := json.NewDecoder(req.Body).Decode(&request); err != nil { @@ -220,7 +220,7 @@ func AddRoutes(intAPI api.FederationInternalAPI, internalAPIMux *mux.Router) { }), ) internalAPIMux.Handle( - FederationSenderLookupStateIDsPath, + FederationAPILookupStateIDsPath, httputil.MakeInternalAPI("LookupStateIDs", func(req *http.Request) util.JSONResponse { var request lookupStateIDs if err := json.NewDecoder(req.Body).Decode(&request); err != nil { @@ -242,7 +242,7 @@ func AddRoutes(intAPI api.FederationInternalAPI, internalAPIMux *mux.Router) { }), ) internalAPIMux.Handle( - FederationSenderGetEventPath, + FederationAPIGetEventPath, httputil.MakeInternalAPI("GetEvent", func(req *http.Request) util.JSONResponse { var request getEvent if err := json.NewDecoder(req.Body).Decode(&request); err != nil { @@ -264,7 +264,7 @@ func AddRoutes(intAPI api.FederationInternalAPI, internalAPIMux *mux.Router) { }), ) internalAPIMux.Handle( - FederationSenderQueryServerKeysPath, + FederationAPIQueryServerKeysPath, httputil.MakeInternalAPI("QueryServerKeys", func(req *http.Request) util.JSONResponse { var request api.QueryServerKeysRequest var response api.QueryServerKeysResponse @@ -278,7 +278,7 @@ func AddRoutes(intAPI api.FederationInternalAPI, internalAPIMux *mux.Router) { }), ) internalAPIMux.Handle( - FederationSenderLookupServerKeysPath, + FederationAPILookupServerKeysPath, httputil.MakeInternalAPI("LookupServerKeys", func(req *http.Request) util.JSONResponse { var request lookupServerKeys if err := json.NewDecoder(req.Body).Decode(&request); err != nil { @@ -300,7 +300,7 @@ func AddRoutes(intAPI api.FederationInternalAPI, internalAPIMux *mux.Router) { }), ) internalAPIMux.Handle( - FederationSenderEventRelationshipsPath, + FederationAPIEventRelationshipsPath, httputil.MakeInternalAPI("MSC2836EventRelationships", func(req *http.Request) util.JSONResponse { var request eventRelationships if err := json.NewDecoder(req.Body).Decode(&request); err != nil { @@ -322,7 +322,7 @@ func AddRoutes(intAPI api.FederationInternalAPI, internalAPIMux *mux.Router) { }), ) internalAPIMux.Handle( - FederationSenderSpacesSummaryPath, + FederationAPISpacesSummaryPath, httputil.MakeInternalAPI("MSC2946SpacesSummary", func(req *http.Request) util.JSONResponse { var request spacesReq if err := json.NewDecoder(req.Body).Decode(&request); err != nil { @@ -343,4 +343,32 @@ func AddRoutes(intAPI api.FederationInternalAPI, internalAPIMux *mux.Router) { return util.JSONResponse{Code: http.StatusOK, JSON: request} }), ) + internalAPIMux.Handle(FederationAPIQueryPublicKeyPath, + httputil.MakeInternalAPI("queryPublicKeys", func(req *http.Request) util.JSONResponse { + request := api.QueryPublicKeysRequest{} + response := api.QueryPublicKeysResponse{} + if err := json.NewDecoder(req.Body).Decode(&request); err != nil { + return util.MessageResponse(http.StatusBadRequest, err.Error()) + } + keys, err := intAPI.FetchKeys(req.Context(), request.Requests) + if err != nil { + return util.ErrorResponse(err) + } + response.Results = keys + return util.JSONResponse{Code: http.StatusOK, JSON: &response} + }), + ) + internalAPIMux.Handle(FederationAPIInputPublicKeyPath, + httputil.MakeInternalAPI("inputPublicKeys", func(req *http.Request) util.JSONResponse { + request := api.InputPublicKeysRequest{} + response := api.InputPublicKeysResponse{} + if err := json.NewDecoder(req.Body).Decode(&request); err != nil { + return util.MessageResponse(http.StatusBadRequest, err.Error()) + } + if err := intAPI.StoreKeys(req.Context(), request.Keys); err != nil { + return util.ErrorResponse(err) + } + return util.JSONResponse{Code: http.StatusOK, JSON: &response} + }), + ) } diff --git a/signingkeyserver/serverkeyapi_test.go b/federationapi/serverkeyapi_test.go similarity index 95% rename from signingkeyserver/serverkeyapi_test.go rename to federationapi/serverkeyapi_test.go index bd6119aae..6ac1b8bc9 100644 --- a/signingkeyserver/serverkeyapi_test.go +++ b/federationapi/serverkeyapi_test.go @@ -1,5 +1,6 @@ -package signingkeyserver +package federationapi +/* import ( "bytes" "context" @@ -13,21 +14,20 @@ import ( "testing" "time" + "github.com/matrix-org/dendrite/federationapi/api" "github.com/matrix-org/dendrite/federationapi/routing" "github.com/matrix-org/dendrite/internal/caching" "github.com/matrix-org/dendrite/setup/config" - "github.com/matrix-org/dendrite/signingkeyserver/api" "github.com/matrix-org/gomatrixserverlib" ) type server struct { name gomatrixserverlib.ServerName // server name validity time.Duration // key validity duration from now - config *config.SigningKeyServer // skeleton config, from TestMain - fedconfig *config.FederationAPI // + config *config.FederationAPI // skeleton config, from TestMain fedclient *gomatrixserverlib.FederationClient // uses MockRoundTripper cache *caching.Caches // server-specific cache - api api.SigningKeyServerAPI // server-specific server key API + api api.FederationInternalAPI // server-specific server key API } func (s *server) renew() { @@ -76,9 +76,8 @@ func TestMain(m *testing.M) { cfg.Global.PrivateKey = testPriv cfg.Global.KeyID = serverKeyID cfg.Global.KeyValidityPeriod = s.validity - cfg.SigningKeyServer.Database.ConnectionString = config.DataSource("file::memory:") - s.config = &cfg.SigningKeyServer - s.fedconfig = &cfg.FederationAPI + cfg.FederationAPI.Database.ConnectionString = config.DataSource("file::memory:") + s.config = &cfg.FederationAPI // Create a transport which redirects federation requests to // the mock round tripper. Since we're not *really* listening for @@ -93,7 +92,7 @@ func TestMain(m *testing.M) { ) // Finally, build the server key APIs. - s.api = NewInternalAPI(s.config, s.fedclient, s.cache) + s.api = NewInternalAPI(s.config, s.fedclient, s.cache, true) } // Now that we have built our server key APIs, start the @@ -119,7 +118,7 @@ func (m *MockRoundTripper) RoundTrip(req *http.Request) (res *http.Response, err } // Get the keys and JSON-ify them. - keys := routing.LocalKeys(s.fedconfig) + keys := routing.LocalKeys(s.config) body, err := json.MarshalIndent(keys.JSON, "", " ") if err != nil { return nil, err @@ -317,3 +316,4 @@ func TestRenewalBehaviour(t *testing.T) { } t.Log(res) } +*/ diff --git a/internal/test/config.go b/internal/test/config.go index 7e68d6d2e..6281e7f66 100644 --- a/internal/test/config.go +++ b/internal/test/config.go @@ -88,11 +88,10 @@ func MakeConfig(configDir, kafkaURI, database, host string, startPort int) (*con // the table names are globally unique. But we might not want to // rely on that in the future. cfg.AppServiceAPI.Database.ConnectionString = config.DataSource(database) - cfg.FederationSender.Database.ConnectionString = config.DataSource(database) + cfg.FederationAPI.Database.ConnectionString = config.DataSource(database) cfg.KeyServer.Database.ConnectionString = config.DataSource(database) cfg.MediaAPI.Database.ConnectionString = config.DataSource(database) cfg.RoomServer.Database.ConnectionString = config.DataSource(database) - cfg.SigningKeyServer.Database.ConnectionString = config.DataSource(database) cfg.SyncAPI.Database.ConnectionString = config.DataSource(database) cfg.UserAPI.AccountDatabase.ConnectionString = config.DataSource(database) cfg.UserAPI.DeviceDatabase.ConnectionString = config.DataSource(database) @@ -100,22 +99,18 @@ func MakeConfig(configDir, kafkaURI, database, host string, startPort int) (*con cfg.AppServiceAPI.InternalAPI.Listen = assignAddress() cfg.EDUServer.InternalAPI.Listen = assignAddress() cfg.FederationAPI.InternalAPI.Listen = assignAddress() - cfg.FederationSender.InternalAPI.Listen = assignAddress() cfg.KeyServer.InternalAPI.Listen = assignAddress() cfg.MediaAPI.InternalAPI.Listen = assignAddress() cfg.RoomServer.InternalAPI.Listen = assignAddress() - cfg.SigningKeyServer.InternalAPI.Listen = assignAddress() cfg.SyncAPI.InternalAPI.Listen = assignAddress() cfg.UserAPI.InternalAPI.Listen = assignAddress() cfg.AppServiceAPI.InternalAPI.Connect = cfg.AppServiceAPI.InternalAPI.Listen cfg.EDUServer.InternalAPI.Connect = cfg.EDUServer.InternalAPI.Listen cfg.FederationAPI.InternalAPI.Connect = cfg.FederationAPI.InternalAPI.Listen - cfg.FederationSender.InternalAPI.Connect = cfg.FederationSender.InternalAPI.Listen cfg.KeyServer.InternalAPI.Connect = cfg.KeyServer.InternalAPI.Listen cfg.MediaAPI.InternalAPI.Connect = cfg.MediaAPI.InternalAPI.Listen cfg.RoomServer.InternalAPI.Connect = cfg.RoomServer.InternalAPI.Listen - cfg.SigningKeyServer.InternalAPI.Connect = cfg.SigningKeyServer.InternalAPI.Listen cfg.SyncAPI.InternalAPI.Connect = cfg.SyncAPI.InternalAPI.Listen cfg.UserAPI.InternalAPI.Connect = cfg.UserAPI.InternalAPI.Listen diff --git a/roomserver/api/api.go b/roomserver/api/api.go index 446c8d2c2..7389cb91a 100644 --- a/roomserver/api/api.go +++ b/roomserver/api/api.go @@ -5,6 +5,7 @@ import ( asAPI "github.com/matrix-org/dendrite/appservice/api" fsAPI "github.com/matrix-org/dendrite/federationapi/api" + "github.com/matrix-org/gomatrixserverlib" ) // RoomserverInputAPI is used to write events to the room server. @@ -13,6 +14,7 @@ type RoomserverInternalAPI interface { // interdependencies between the roomserver and other input APIs SetFederationSenderAPI(fsAPI fsAPI.FederationInternalAPI) SetAppserviceAPI(asAPI asAPI.AppServiceQueryAPI) + SetKeyring(keyRing *gomatrixserverlib.KeyRing) InputRoomEvents( ctx context.Context, diff --git a/roomserver/api/api_trace.go b/roomserver/api/api_trace.go index ee5deec5c..fd1acfb89 100644 --- a/roomserver/api/api_trace.go +++ b/roomserver/api/api_trace.go @@ -7,6 +7,7 @@ import ( asAPI "github.com/matrix-org/dendrite/appservice/api" fsAPI "github.com/matrix-org/dendrite/federationapi/api" + "github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/util" ) @@ -16,6 +17,10 @@ type RoomserverInternalAPITrace struct { Impl RoomserverInternalAPI } +func (t *RoomserverInternalAPITrace) SetKeyring(keyRing *gomatrixserverlib.KeyRing) { + t.Impl.SetKeyring(keyRing) +} + func (t *RoomserverInternalAPITrace) SetFederationSenderAPI(fsAPI fsAPI.FederationInternalAPI) { t.Impl.SetFederationSenderAPI(fsAPI) } diff --git a/roomserver/internal/api.go b/roomserver/internal/api.go index fb4e61516..e8aff2d22 100644 --- a/roomserver/internal/api.go +++ b/roomserver/internal/api.go @@ -46,7 +46,7 @@ type RoomserverInternalAPI struct { func NewRoomserverAPI( cfg *config.RoomServer, roomserverDB storage.Database, producer sarama.SyncProducer, outputRoomEventTopic string, caches caching.RoomServerCaches, - keyRing gomatrixserverlib.JSONVerifier, perspectiveServerNames []gomatrixserverlib.ServerName, + perspectiveServerNames []gomatrixserverlib.ServerName, ) *RoomserverInternalAPI { serverACLs := acls.NewServerACLs(roomserverDB) a := &RoomserverInternalAPI{ @@ -55,7 +55,6 @@ func NewRoomserverAPI( Cache: caches, ServerName: cfg.Matrix.ServerName, PerspectiveServerNames: perspectiveServerNames, - KeyRing: keyRing, Queryer: &query.Queryer{ DB: roomserverDB, Cache: caches, @@ -74,11 +73,18 @@ func NewRoomserverAPI( return a } +// SetKeyring sets the keyring to a given keyring. This is only useful for the P2P +// demos and must be called after SetFederationSenderInputAPI. +func (r *RoomserverInternalAPI) SetKeyring(keyRing *gomatrixserverlib.KeyRing) { + r.KeyRing = keyRing +} + // SetFederationSenderInputAPI passes in a federation sender input API reference // so that we can avoid the chicken-and-egg problem of both the roomserver input API // and the federation sender input API being interdependent. func (r *RoomserverInternalAPI) SetFederationSenderAPI(fsAPI fsAPI.FederationInternalAPI) { r.fsAPI = fsAPI + r.SetKeyring(fsAPI.KeyRing()) r.Inviter = &perform.Inviter{ DB: r.DB, diff --git a/roomserver/inthttp/client.go b/roomserver/inthttp/client.go index d9cb03989..9fa50efeb 100644 --- a/roomserver/inthttp/client.go +++ b/roomserver/inthttp/client.go @@ -11,6 +11,7 @@ import ( "github.com/matrix-org/dendrite/internal/caching" "github.com/matrix-org/dendrite/internal/httputil" "github.com/matrix-org/dendrite/roomserver/api" + "github.com/matrix-org/gomatrixserverlib" "github.com/opentracing/opentracing-go" ) @@ -82,6 +83,10 @@ func NewRoomserverClient( }, nil } +// SetKeyring no-ops in HTTP client mode as there is no chicken/egg scenario +func (h *httpRoomserverInternalAPI) SetKeyring(keyRing *gomatrixserverlib.KeyRing) { +} + // SetFederationSenderInputAPI no-ops in HTTP client mode as there is no chicken/egg scenario func (h *httpRoomserverInternalAPI) SetFederationSenderAPI(fsAPI fsInputAPI.FederationInternalAPI) { } diff --git a/roomserver/roomserver.go b/roomserver/roomserver.go index 095f73e82..e47421008 100644 --- a/roomserver/roomserver.go +++ b/roomserver/roomserver.go @@ -38,14 +38,13 @@ func AddInternalRoutes(router *mux.Router, intAPI api.RoomserverInternalAPI) { // can call functions directly on the returned API or via an HTTP interface using AddInternalRoutes. func NewInternalAPI( base *base.BaseDendrite, - keyRing gomatrixserverlib.JSONVerifier, ) api.RoomserverInternalAPI { cfg := &base.Cfg.RoomServer _, producer := kafka.SetupConsumerProducer(&cfg.Matrix.Kafka) var perspectiveServerNames []gomatrixserverlib.ServerName - for _, kp := range base.Cfg.SigningKeyServer.KeyPerspectives { + for _, kp := range base.Cfg.FederationAPI.KeyPerspectives { perspectiveServerNames = append(perspectiveServerNames, kp.ServerName) } @@ -56,6 +55,6 @@ func NewInternalAPI( return internal.NewRoomserverAPI( cfg, roomserverDB, producer, string(cfg.Matrix.Kafka.TopicFor(config.TopicOutputRoomEvent)), - base.Caches, keyRing, perspectiveServerNames, + base.Caches, perspectiveServerNames, ) } diff --git a/roomserver/roomserver_test.go b/roomserver/roomserver_test.go index ea6b4ed19..8d92d8d8b 100644 --- a/roomserver/roomserver_test.go +++ b/roomserver/roomserver_test.go @@ -13,7 +13,6 @@ import ( "github.com/Shopify/sarama" "github.com/matrix-org/dendrite/internal/caching" - "github.com/matrix-org/dendrite/internal/test" "github.com/matrix-org/dendrite/roomserver/api" "github.com/matrix-org/dendrite/roomserver/internal" "github.com/matrix-org/dendrite/roomserver/storage" @@ -182,7 +181,7 @@ func mustCreateRoomserverAPI(t *testing.T) (api.RoomserverInternalAPI, *dummyPro } return internal.NewRoomserverAPI( &cfg.RoomServer, roomserverDB, dp, string(cfg.Global.Kafka.TopicFor(config.TopicOutputRoomEvent)), - base.Caches, &test.NopJSONVerifier{}, nil, + base.Caches, nil, ), dp } diff --git a/setup/base/base.go b/setup/base/base.go index bf2290d87..c514ed52c 100644 --- a/setup/base/base.go +++ b/setup/base/base.go @@ -48,14 +48,12 @@ import ( eduServerAPI "github.com/matrix-org/dendrite/eduserver/api" eduinthttp "github.com/matrix-org/dendrite/eduserver/inthttp" federationAPI "github.com/matrix-org/dendrite/federationapi/api" - fsinthttp "github.com/matrix-org/dendrite/federationapi/inthttp" + federationIntHTTP "github.com/matrix-org/dendrite/federationapi/inthttp" keyserverAPI "github.com/matrix-org/dendrite/keyserver/api" keyinthttp "github.com/matrix-org/dendrite/keyserver/inthttp" roomserverAPI "github.com/matrix-org/dendrite/roomserver/api" rsinthttp "github.com/matrix-org/dendrite/roomserver/inthttp" "github.com/matrix-org/dendrite/setup/config" - skapi "github.com/matrix-org/dendrite/signingkeyserver/api" - skinthttp "github.com/matrix-org/dendrite/signingkeyserver/inthttp" userapi "github.com/matrix-org/dendrite/userapi/api" userapiinthttp "github.com/matrix-org/dendrite/userapi/inthttp" "github.com/sirupsen/logrus" @@ -168,10 +166,10 @@ func NewBaseDendrite(cfg *config.Dendrite, componentName string, useHTTPAPIs boo }, } client := http.Client{Timeout: HTTPClientTimeout} - if cfg.FederationSender.Proxy.Enabled { + if cfg.FederationAPI.Proxy.Enabled { client.Transport = &http.Transport{Proxy: http.ProxyURL(&url.URL{ - Scheme: cfg.FederationSender.Proxy.Protocol, - Host: fmt.Sprintf("%s:%d", cfg.FederationSender.Proxy.Host, cfg.FederationSender.Proxy.Port), + Scheme: cfg.FederationAPI.Proxy.Protocol, + Host: fmt.Sprintf("%s:%d", cfg.FederationAPI.Proxy.Host, cfg.FederationAPI.Proxy.Port), })} } @@ -248,25 +246,12 @@ func (b *BaseDendrite) EDUServerClient() eduServerAPI.EDUServerInputAPI { return e } -// FederationSenderHTTPClient returns FederationInternalAPI for hitting -// the federation sender over HTTP -func (b *BaseDendrite) FederationSenderHTTPClient() federationAPI.FederationInternalAPI { - f, err := fsinthttp.NewFederationSenderClient(b.Cfg.FederationSenderURL(), b.apiHttpClient) +// FederationAPIHTTPClient returns FederationInternalAPI for hitting +// the federation API server over HTTP +func (b *BaseDendrite) FederationAPIHTTPClient() federationAPI.FederationInternalAPI { + f, err := federationIntHTTP.NewFederationAPIClient(b.Cfg.FederationAPIURL(), b.apiHttpClient, b.Caches) if err != nil { - logrus.WithError(err).Panic("FederationSenderHTTPClient failed", b.apiHttpClient) - } - return f -} - -// SigningKeyServerHTTPClient returns SigningKeyServer for hitting the signing key server over HTTP -func (b *BaseDendrite) SigningKeyServerHTTPClient() skapi.SigningKeyServerAPI { - f, err := skinthttp.NewSigningKeyServerClient( - b.Cfg.SigningKeyServerURL(), - b.apiHttpClient, - b.Caches, - ) - if err != nil { - logrus.WithError(err).Panic("SigningKeyServerHTTPClient failed", b.httpClient) + logrus.WithError(err).Panic("FederationAPIHTTPClient failed", b.apiHttpClient) } return f } @@ -300,7 +285,7 @@ func (b *BaseDendrite) CreateClient() *gomatrixserverlib.Client { ) } opts := []gomatrixserverlib.ClientOption{ - gomatrixserverlib.WithSkipVerify(b.Cfg.FederationSender.DisableTLSValidation), + gomatrixserverlib.WithSkipVerify(b.Cfg.FederationAPI.DisableTLSValidation), } if b.Cfg.Global.DNSCache.Enabled { opts = append(opts, gomatrixserverlib.WithDNSCache(b.DNSCache)) @@ -321,7 +306,7 @@ func (b *BaseDendrite) CreateFederationClient() *gomatrixserverlib.FederationCli } opts := []gomatrixserverlib.ClientOption{ gomatrixserverlib.WithTimeout(time.Minute * 5), - gomatrixserverlib.WithSkipVerify(b.Cfg.FederationSender.DisableTLSValidation), + gomatrixserverlib.WithSkipVerify(b.Cfg.FederationAPI.DisableTLSValidation), } if b.Cfg.Global.DNSCache.Enabled { opts = append(opts, gomatrixserverlib.WithDNSCache(b.DNSCache)) diff --git a/setup/config/config.go b/setup/config/config.go index b91144078..44a67c2a3 100644 --- a/setup/config/config.go +++ b/setup/config/config.go @@ -53,18 +53,16 @@ type Dendrite struct { // been a breaking change to the config file format. Version int `yaml:"version"` - Global Global `yaml:"global"` - AppServiceAPI AppServiceAPI `yaml:"app_service_api"` - ClientAPI ClientAPI `yaml:"client_api"` - EDUServer EDUServer `yaml:"edu_server"` - FederationAPI FederationAPI `yaml:"federation_api"` - FederationSender FederationSender `yaml:"federation_sender"` - KeyServer KeyServer `yaml:"key_server"` - MediaAPI MediaAPI `yaml:"media_api"` - RoomServer RoomServer `yaml:"room_server"` - SigningKeyServer SigningKeyServer `yaml:"signing_key_server"` - SyncAPI SyncAPI `yaml:"sync_api"` - UserAPI UserAPI `yaml:"user_api"` + Global Global `yaml:"global"` + AppServiceAPI AppServiceAPI `yaml:"app_service_api"` + ClientAPI ClientAPI `yaml:"client_api"` + EDUServer EDUServer `yaml:"edu_server"` + FederationAPI FederationAPI `yaml:"federation_api"` + KeyServer KeyServer `yaml:"key_server"` + MediaAPI MediaAPI `yaml:"media_api"` + RoomServer RoomServer `yaml:"room_server"` + SyncAPI SyncAPI `yaml:"sync_api"` + UserAPI UserAPI `yaml:"user_api"` MSCs MSCs `yaml:"mscs"` @@ -300,11 +298,9 @@ func (c *Dendrite) Defaults() { c.ClientAPI.Defaults() c.EDUServer.Defaults() c.FederationAPI.Defaults() - c.FederationSender.Defaults() c.KeyServer.Defaults() c.MediaAPI.Defaults() c.RoomServer.Defaults() - c.SigningKeyServer.Defaults() c.SyncAPI.Defaults() c.UserAPI.Defaults() c.AppServiceAPI.Defaults() @@ -319,9 +315,9 @@ func (c *Dendrite) Verify(configErrs *ConfigErrors, isMonolith bool) { } for _, c := range []verifiable{ &c.Global, &c.ClientAPI, - &c.EDUServer, &c.FederationAPI, &c.FederationSender, + &c.EDUServer, &c.FederationAPI, &c.KeyServer, &c.MediaAPI, &c.RoomServer, - &c.SigningKeyServer, &c.SyncAPI, &c.UserAPI, + &c.SyncAPI, &c.UserAPI, &c.AppServiceAPI, &c.MSCs, } { c.Verify(configErrs, isMonolith) @@ -332,11 +328,9 @@ func (c *Dendrite) Wiring() { c.ClientAPI.Matrix = &c.Global c.EDUServer.Matrix = &c.Global c.FederationAPI.Matrix = &c.Global - c.FederationSender.Matrix = &c.Global c.KeyServer.Matrix = &c.Global c.MediaAPI.Matrix = &c.Global c.RoomServer.Matrix = &c.Global - c.SigningKeyServer.Matrix = &c.Global c.SyncAPI.Matrix = &c.Global c.UserAPI.Matrix = &c.Global c.AppServiceAPI.Matrix = &c.Global @@ -493,6 +487,15 @@ func (config *Dendrite) AppServiceURL() string { return string(config.AppServiceAPI.InternalAPI.Connect) } +// FederationAPIURL returns an HTTP URL for where the federation API is listening. +func (config *Dendrite) FederationAPIURL() string { + // Hard code the federationapi to talk HTTP for now. + // If we support HTTPS we need to think of a practical way to do certificate validation. + // People setting up servers shouldn't need to get a certificate valid for the public + // internet for an internal API. + return string(config.FederationAPI.InternalAPI.Connect) +} + // RoomServerURL returns an HTTP URL for where the roomserver is listening. func (config *Dendrite) RoomServerURL() string { // Hard code the roomserver to talk HTTP for now. @@ -520,24 +523,6 @@ func (config *Dendrite) EDUServerURL() string { return string(config.EDUServer.InternalAPI.Connect) } -// FederationSenderURL returns an HTTP URL for where the federation sender is listening. -func (config *Dendrite) FederationSenderURL() string { - // Hard code the federation sender server to talk HTTP for now. - // If we support HTTPS we need to think of a practical way to do certificate validation. - // People setting up servers shouldn't need to get a certificate valid for the public - // internet for an internal API. - return string(config.FederationSender.InternalAPI.Connect) -} - -// SigningKeyServerURL returns an HTTP URL for where the signing key server is listening. -func (config *Dendrite) SigningKeyServerURL() string { - // Hard code the signing key server to talk HTTP for now. - // If we support HTTPS we need to think of a practical way to do certificate validation. - // People setting up servers shouldn't need to get a certificate valid for the public - // internet for an internal API. - return string(config.SigningKeyServer.InternalAPI.Connect) -} - // KeyServerURL returns an HTTP URL for where the key server is listening. func (config *Dendrite) KeyServerURL() string { // Hard code the key server to talk HTTP for now. diff --git a/setup/config/config_federationapi.go b/setup/config/config_federationapi.go index 64803d95e..cd5015fda 100644 --- a/setup/config/config_federationapi.go +++ b/setup/config/config_federationapi.go @@ -1,23 +1,55 @@ package config +import "github.com/matrix-org/gomatrixserverlib" + type FederationAPI struct { Matrix *Global `yaml:"-"` InternalAPI InternalAPIOptions `yaml:"internal_api"` ExternalAPI ExternalAPIOptions `yaml:"external_api"` + // The database stores information used by the federation destination queues to + // send transactions to remote servers. + Database DatabaseOptions `yaml:"database"` + // List of paths to X509 certificates used by the external federation listeners. // These are used to calculate the TLS fingerprints to publish for this server. // Other matrix servers talking to this server will expect the x509 certificate // to match one of these certificates. // The certificates should be in PEM format. FederationCertificatePaths []Path `yaml:"federation_certificates"` + + // Federation failure threshold. How many consecutive failures that we should + // tolerate when sending federation requests to a specific server. The backoff + // is 2**x seconds, so 1 = 2 seconds, 2 = 4 seconds, 3 = 8 seconds, etc. + // The default value is 16 if not specified, which is circa 18 hours. + FederationMaxRetries uint32 `yaml:"send_max_retries"` + + // FederationDisableTLSValidation disables the validation of X.509 TLS certs + // on remote federation endpoints. This is not recommended in production! + DisableTLSValidation bool `yaml:"disable_tls_validation"` + + Proxy Proxy `yaml:"proxy_outbound"` + + // Perspective keyservers, to use as a backup when direct key fetch + // requests don't succeed + KeyPerspectives KeyPerspectives `yaml:"key_perspectives"` + + // Should we prefer direct key fetches over perspective ones? + PreferDirectFetch bool `yaml:"prefer_direct_fetch"` } func (c *FederationAPI) Defaults() { c.InternalAPI.Listen = "http://localhost:7772" c.InternalAPI.Connect = "http://localhost:7772" c.ExternalAPI.Listen = "http://[::]:8072" + c.Database.Defaults(10) + c.Database.ConnectionString = "file:federationapi.db" + + c.FederationMaxRetries = 16 + c.DisableTLSValidation = false + + c.Proxy.Defaults() } func (c *FederationAPI) Verify(configErrs *ConfigErrors, isMonolith bool) { @@ -26,6 +58,48 @@ func (c *FederationAPI) Verify(configErrs *ConfigErrors, isMonolith bool) { if !isMonolith { checkURL(configErrs, "federation_api.external_api.listen", string(c.ExternalAPI.Listen)) } + checkNotEmpty(configErrs, "federation_api.database.connection_string", string(c.Database.ConnectionString)) // TODO: not applicable always, e.g. in demos //checkNotZero(configErrs, "federation_api.federation_certificates", int64(len(c.FederationCertificatePaths))) } + +// The config for setting a proxy to use for server->server requests +type Proxy struct { + // Is the proxy enabled? + Enabled bool `yaml:"enabled"` + // The protocol for the proxy (http / https / socks5) + Protocol string `yaml:"protocol"` + // The host where the proxy is listening + Host string `yaml:"host"` + // The port on which the proxy is listening + Port uint16 `yaml:"port"` +} + +func (c *Proxy) Defaults() { + c.Enabled = false + c.Protocol = "http" + c.Host = "localhost" + c.Port = 8080 +} + +func (c *Proxy) Verify(configErrs *ConfigErrors) { +} + +// KeyPerspectives are used to configure perspective key servers for +// retrieving server keys. +type KeyPerspectives []KeyPerspective + +type KeyPerspective struct { + // The server name of the perspective key server + ServerName gomatrixserverlib.ServerName `yaml:"server_name"` + // Server keys for the perspective user, used to verify the + // keys have been signed by the perspective server + Keys []KeyPerspectiveTrustKey `yaml:"keys"` +} + +type KeyPerspectiveTrustKey struct { + // The key ID, e.g. ed25519:auto + KeyID gomatrixserverlib.KeyID `yaml:"key_id"` + // The public key in base64 unpadded format + PublicKey string `yaml:"public_key"` +} diff --git a/setup/config/config_federationsender.go b/setup/config/config_federationsender.go deleted file mode 100644 index d9bce8142..000000000 --- a/setup/config/config_federationsender.go +++ /dev/null @@ -1,63 +0,0 @@ -package config - -type FederationSender struct { - Matrix *Global `yaml:"-"` - - InternalAPI InternalAPIOptions `yaml:"internal_api"` - - // The FederationSender database stores information used by the FederationSender - // It is only accessed by the FederationSender. - Database DatabaseOptions `yaml:"database"` - - // Federation failure threshold. How many consecutive failures that we should - // tolerate when sending federation requests to a specific server. The backoff - // is 2**x seconds, so 1 = 2 seconds, 2 = 4 seconds, 3 = 8 seconds, etc. - // The default value is 16 if not specified, which is circa 18 hours. - FederationMaxRetries uint32 `yaml:"send_max_retries"` - - // FederationDisableTLSValidation disables the validation of X.509 TLS certs - // on remote federation endpoints. This is not recommended in production! - DisableTLSValidation bool `yaml:"disable_tls_validation"` - - Proxy Proxy `yaml:"proxy_outbound"` -} - -func (c *FederationSender) Defaults() { - c.InternalAPI.Listen = "http://localhost:7775" - c.InternalAPI.Connect = "http://localhost:7775" - c.Database.Defaults(10) - c.Database.ConnectionString = "file:federationapi.db" - - c.FederationMaxRetries = 16 - c.DisableTLSValidation = false - - c.Proxy.Defaults() -} - -func (c *FederationSender) Verify(configErrs *ConfigErrors, isMonolith bool) { - checkURL(configErrs, "federation_sender.internal_api.listen", string(c.InternalAPI.Listen)) - checkURL(configErrs, "federation_sender.internal_api.connect", string(c.InternalAPI.Connect)) - checkNotEmpty(configErrs, "federation_sender.database.connection_string", string(c.Database.ConnectionString)) -} - -// The config for setting a proxy to use for server->server requests -type Proxy struct { - // Is the proxy enabled? - Enabled bool `yaml:"enabled"` - // The protocol for the proxy (http / https / socks5) - Protocol string `yaml:"protocol"` - // The host where the proxy is listening - Host string `yaml:"host"` - // The port on which the proxy is listening - Port uint16 `yaml:"port"` -} - -func (c *Proxy) Defaults() { - c.Enabled = false - c.Protocol = "http" - c.Host = "localhost" - c.Port = 8080 -} - -func (c *Proxy) Verify(configErrs *ConfigErrors) { -} diff --git a/setup/config/config_signingkeyserver.go b/setup/config/config_signingkeyserver.go deleted file mode 100644 index c192d1fc0..000000000 --- a/setup/config/config_signingkeyserver.go +++ /dev/null @@ -1,52 +0,0 @@ -package config - -import "github.com/matrix-org/gomatrixserverlib" - -type SigningKeyServer struct { - Matrix *Global `yaml:"-"` - - InternalAPI InternalAPIOptions `yaml:"internal_api"` - - // The SigningKeyServer database caches the public keys of remote servers. - // It may be accessed by the FederationAPI, the ClientAPI, and the MediaAPI. - Database DatabaseOptions `yaml:"database"` - - // Perspective keyservers, to use as a backup when direct key fetch - // requests don't succeed - KeyPerspectives KeyPerspectives `yaml:"key_perspectives"` - - // Should we prefer direct key fetches over perspective ones? - PreferDirectFetch bool `yaml:"prefer_direct_fetch"` -} - -func (c *SigningKeyServer) Defaults() { - c.InternalAPI.Listen = "http://localhost:7780" - c.InternalAPI.Connect = "http://localhost:7780" - c.Database.Defaults(10) - c.Database.ConnectionString = "file:signingkeyserver.db" -} - -func (c *SigningKeyServer) Verify(configErrs *ConfigErrors, isMonolith bool) { - checkURL(configErrs, "signing_key_server.internal_api.listen", string(c.InternalAPI.Listen)) - checkURL(configErrs, "signing_key_server.internal_api.bind", string(c.InternalAPI.Connect)) - checkNotEmpty(configErrs, "signing_key_server.database.connection_string", string(c.Database.ConnectionString)) -} - -// KeyPerspectives are used to configure perspective key servers for -// retrieving server keys. -type KeyPerspectives []KeyPerspective - -type KeyPerspective struct { - // The server name of the perspective key server - ServerName gomatrixserverlib.ServerName `yaml:"server_name"` - // Server keys for the perspective user, used to verify the - // keys have been signed by the perspective server - Keys []KeyPerspectiveTrustKey `yaml:"keys"` -} - -type KeyPerspectiveTrustKey struct { - // The key ID, e.g. ed25519:auto - KeyID gomatrixserverlib.KeyID `yaml:"key_id"` - // The public key in base64 unpadded format - PublicKey string `yaml:"public_key"` -} diff --git a/setup/monolith.go b/setup/monolith.go index c3ed6809e..b076e990c 100644 --- a/setup/monolith.go +++ b/setup/monolith.go @@ -28,7 +28,6 @@ import ( roomserverAPI "github.com/matrix-org/dendrite/roomserver/api" "github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/process" - serverKeyAPI "github.com/matrix-org/dendrite/signingkeyserver/api" "github.com/matrix-org/dendrite/syncapi" userapi "github.com/matrix-org/dendrite/userapi/api" "github.com/matrix-org/dendrite/userapi/storage/accounts" @@ -48,7 +47,6 @@ type Monolith struct { EDUInternalAPI eduServerAPI.EDUServerInputAPI FederationAPI federationAPI.FederationInternalAPI RoomserverAPI roomserverAPI.RoomserverInternalAPI - ServerKeyAPI serverKeyAPI.SigningKeyServerAPI UserAPI userapi.UserInternalAPI KeyAPI keyAPI.KeyInternalAPI diff --git a/signingkeyserver/api/api.go b/signingkeyserver/api/api.go deleted file mode 100644 index f053d72e2..000000000 --- a/signingkeyserver/api/api.go +++ /dev/null @@ -1,40 +0,0 @@ -package api - -import ( - "context" - - "github.com/matrix-org/gomatrixserverlib" -) - -type SigningKeyServerAPI interface { - gomatrixserverlib.KeyDatabase - - KeyRing() *gomatrixserverlib.KeyRing - - InputPublicKeys( - ctx context.Context, - request *InputPublicKeysRequest, - response *InputPublicKeysResponse, - ) error - - QueryPublicKeys( - ctx context.Context, - request *QueryPublicKeysRequest, - response *QueryPublicKeysResponse, - ) error -} - -type QueryPublicKeysRequest struct { - Requests map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.Timestamp `json:"requests"` -} - -type QueryPublicKeysResponse struct { - Results map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.PublicKeyLookupResult `json:"results"` -} - -type InputPublicKeysRequest struct { - Keys map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.PublicKeyLookupResult `json:"keys"` -} - -type InputPublicKeysResponse struct { -} diff --git a/signingkeyserver/inthttp/client.go b/signingkeyserver/inthttp/client.go deleted file mode 100644 index 71e40b8f0..000000000 --- a/signingkeyserver/inthttp/client.go +++ /dev/null @@ -1,132 +0,0 @@ -package inthttp - -import ( - "context" - "errors" - "net/http" - - "github.com/matrix-org/dendrite/internal/caching" - "github.com/matrix-org/dendrite/internal/httputil" - "github.com/matrix-org/dendrite/signingkeyserver/api" - "github.com/matrix-org/gomatrixserverlib" - "github.com/opentracing/opentracing-go" -) - -// HTTP paths for the internal HTTP APIs -const ( - ServerKeyInputPublicKeyPath = "/signingkeyserver/inputPublicKey" - ServerKeyQueryPublicKeyPath = "/signingkeyserver/queryPublicKey" -) - -// NewSigningKeyServerClient creates a SigningKeyServerAPI implemented by talking to a HTTP POST API. -// If httpClient is nil an error is returned -func NewSigningKeyServerClient( - serverKeyAPIURL string, - httpClient *http.Client, - cache caching.ServerKeyCache, -) (api.SigningKeyServerAPI, error) { - if httpClient == nil { - return nil, errors.New("NewSigningKeyServerClient: httpClient is ") - } - return &httpServerKeyInternalAPI{ - serverKeyAPIURL: serverKeyAPIURL, - httpClient: httpClient, - cache: cache, - }, nil -} - -type httpServerKeyInternalAPI struct { - serverKeyAPIURL string - httpClient *http.Client - cache caching.ServerKeyCache -} - -func (s *httpServerKeyInternalAPI) KeyRing() *gomatrixserverlib.KeyRing { - // This is a bit of a cheat - we tell gomatrixserverlib that this API is - // both the key database and the key fetcher. While this does have the - // rather unfortunate effect of preventing gomatrixserverlib from handling - // key fetchers directly, we can at least reimplement this behaviour on - // the other end of the API. - return &gomatrixserverlib.KeyRing{ - KeyDatabase: s, - KeyFetchers: []gomatrixserverlib.KeyFetcher{}, - } -} - -func (s *httpServerKeyInternalAPI) FetcherName() string { - return "httpServerKeyInternalAPI" -} - -func (s *httpServerKeyInternalAPI) StoreKeys( - _ context.Context, - results map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.PublicKeyLookupResult, -) error { - // Run in a background context - we don't want to stop this work just - // because the caller gives up waiting. - ctx := context.Background() - request := api.InputPublicKeysRequest{ - Keys: make(map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.PublicKeyLookupResult), - } - response := api.InputPublicKeysResponse{} - for req, res := range results { - request.Keys[req] = res - s.cache.StoreServerKey(req, res) - } - return s.InputPublicKeys(ctx, &request, &response) -} - -func (s *httpServerKeyInternalAPI) FetchKeys( - _ context.Context, - requests map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.Timestamp, -) (map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.PublicKeyLookupResult, error) { - // Run in a background context - we don't want to stop this work just - // because the caller gives up waiting. - ctx := context.Background() - result := make(map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.PublicKeyLookupResult) - request := api.QueryPublicKeysRequest{ - Requests: make(map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.Timestamp), - } - response := api.QueryPublicKeysResponse{ - Results: make(map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.PublicKeyLookupResult), - } - for req, ts := range requests { - if res, ok := s.cache.GetServerKey(req, ts); ok { - result[req] = res - continue - } - request.Requests[req] = ts - } - err := s.QueryPublicKeys(ctx, &request, &response) - if err != nil { - return nil, err - } - for req, res := range response.Results { - result[req] = res - s.cache.StoreServerKey(req, res) - } - return result, nil -} - -func (h *httpServerKeyInternalAPI) InputPublicKeys( - ctx context.Context, - request *api.InputPublicKeysRequest, - response *api.InputPublicKeysResponse, -) error { - span, ctx := opentracing.StartSpanFromContext(ctx, "InputPublicKey") - defer span.Finish() - - apiURL := h.serverKeyAPIURL + ServerKeyInputPublicKeyPath - return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response) -} - -func (h *httpServerKeyInternalAPI) QueryPublicKeys( - ctx context.Context, - request *api.QueryPublicKeysRequest, - response *api.QueryPublicKeysResponse, -) error { - span, ctx := opentracing.StartSpanFromContext(ctx, "QueryPublicKey") - defer span.Finish() - - apiURL := h.serverKeyAPIURL + ServerKeyQueryPublicKeyPath - return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response) -} diff --git a/signingkeyserver/inthttp/server.go b/signingkeyserver/inthttp/server.go deleted file mode 100644 index d26f73805..000000000 --- a/signingkeyserver/inthttp/server.go +++ /dev/null @@ -1,43 +0,0 @@ -package inthttp - -import ( - "encoding/json" - "net/http" - - "github.com/gorilla/mux" - "github.com/matrix-org/dendrite/internal/caching" - "github.com/matrix-org/dendrite/internal/httputil" - "github.com/matrix-org/dendrite/signingkeyserver/api" - "github.com/matrix-org/util" -) - -func AddRoutes(s api.SigningKeyServerAPI, internalAPIMux *mux.Router, cache caching.ServerKeyCache) { - internalAPIMux.Handle(ServerKeyQueryPublicKeyPath, - httputil.MakeInternalAPI("queryPublicKeys", func(req *http.Request) util.JSONResponse { - request := api.QueryPublicKeysRequest{} - response := api.QueryPublicKeysResponse{} - if err := json.NewDecoder(req.Body).Decode(&request); err != nil { - return util.MessageResponse(http.StatusBadRequest, err.Error()) - } - keys, err := s.FetchKeys(req.Context(), request.Requests) - if err != nil { - return util.ErrorResponse(err) - } - response.Results = keys - return util.JSONResponse{Code: http.StatusOK, JSON: &response} - }), - ) - internalAPIMux.Handle(ServerKeyInputPublicKeyPath, - httputil.MakeInternalAPI("inputPublicKeys", func(req *http.Request) util.JSONResponse { - request := api.InputPublicKeysRequest{} - response := api.InputPublicKeysResponse{} - if err := json.NewDecoder(req.Body).Decode(&request); err != nil { - return util.MessageResponse(http.StatusBadRequest, err.Error()) - } - if err := s.StoreKeys(req.Context(), request.Keys); err != nil { - return util.ErrorResponse(err) - } - return util.JSONResponse{Code: http.StatusOK, JSON: &response} - }), - ) -} diff --git a/signingkeyserver/signingkeyserver.go b/signingkeyserver/signingkeyserver.go deleted file mode 100644 index 2b1d6751f..000000000 --- a/signingkeyserver/signingkeyserver.go +++ /dev/null @@ -1,107 +0,0 @@ -package signingkeyserver - -import ( - "crypto/ed25519" - "encoding/base64" - - "github.com/gorilla/mux" - "github.com/matrix-org/dendrite/internal/caching" - "github.com/matrix-org/dendrite/setup/config" - "github.com/matrix-org/dendrite/signingkeyserver/api" - "github.com/matrix-org/dendrite/signingkeyserver/internal" - "github.com/matrix-org/dendrite/signingkeyserver/inthttp" - "github.com/matrix-org/dendrite/signingkeyserver/storage" - "github.com/matrix-org/dendrite/signingkeyserver/storage/cache" - "github.com/matrix-org/gomatrixserverlib" - "github.com/sirupsen/logrus" -) - -// AddInternalRoutes registers HTTP handlers for the internal API. Invokes functions -// on the given input API. -func AddInternalRoutes(router *mux.Router, intAPI api.SigningKeyServerAPI, caches *caching.Caches) { - inthttp.AddRoutes(intAPI, router, caches) -} - -// NewInternalAPI returns a concerete implementation of the internal API. Callers -// can call functions directly on the returned API or via an HTTP interface using AddInternalRoutes. -func NewInternalAPI( - cfg *config.SigningKeyServer, - fedClient gomatrixserverlib.KeyClient, - caches *caching.Caches, -) api.SigningKeyServerAPI { - innerDB, err := storage.NewDatabase( - &cfg.Database, - cfg.Matrix.ServerName, - cfg.Matrix.PrivateKey.Public().(ed25519.PublicKey), - cfg.Matrix.KeyID, - ) - if err != nil { - logrus.WithError(err).Panicf("failed to connect to server key database") - } - - serverKeyDB, err := cache.NewKeyDatabase(innerDB, caches) - if err != nil { - logrus.WithError(err).Panicf("failed to set up caching wrapper for server key database") - } - - internalAPI := internal.ServerKeyAPI{ - ServerName: cfg.Matrix.ServerName, - ServerPublicKey: cfg.Matrix.PrivateKey.Public().(ed25519.PublicKey), - ServerKeyID: cfg.Matrix.KeyID, - ServerKeyValidity: cfg.Matrix.KeyValidityPeriod, - OldServerKeys: cfg.Matrix.OldVerifyKeys, - FedClient: fedClient, - OurKeyRing: gomatrixserverlib.KeyRing{ - KeyFetchers: []gomatrixserverlib.KeyFetcher{}, - KeyDatabase: serverKeyDB, - }, - } - - addDirectFetcher := func() { - internalAPI.OurKeyRing.KeyFetchers = append( - internalAPI.OurKeyRing.KeyFetchers, - &gomatrixserverlib.DirectKeyFetcher{ - Client: fedClient, - }, - ) - } - - if cfg.PreferDirectFetch { - addDirectFetcher() - } else { - defer addDirectFetcher() - } - - var b64e = base64.StdEncoding.WithPadding(base64.NoPadding) - for _, ps := range cfg.KeyPerspectives { - perspective := &gomatrixserverlib.PerspectiveKeyFetcher{ - PerspectiveServerName: ps.ServerName, - PerspectiveServerKeys: map[gomatrixserverlib.KeyID]ed25519.PublicKey{}, - Client: fedClient, - } - - for _, key := range ps.Keys { - rawkey, err := b64e.DecodeString(key.PublicKey) - if err != nil { - logrus.WithError(err).WithFields(logrus.Fields{ - "server_name": ps.ServerName, - "public_key": key.PublicKey, - }).Warn("Couldn't parse perspective key") - continue - } - perspective.PerspectiveServerKeys[key.KeyID] = rawkey - } - - internalAPI.OurKeyRing.KeyFetchers = append( - internalAPI.OurKeyRing.KeyFetchers, - perspective, - ) - - logrus.WithFields(logrus.Fields{ - "server_name": ps.ServerName, - "num_public_keys": len(ps.Keys), - }).Info("Enabled perspective key fetcher") - } - - return &internalAPI -} diff --git a/signingkeyserver/storage/cache/keydb.go b/signingkeyserver/storage/cache/keydb.go deleted file mode 100644 index 2063dfc55..000000000 --- a/signingkeyserver/storage/cache/keydb.go +++ /dev/null @@ -1,68 +0,0 @@ -package cache - -import ( - "context" - "errors" - - "github.com/matrix-org/dendrite/internal/caching" - "github.com/matrix-org/gomatrixserverlib" -) - -// A Database implements gomatrixserverlib.KeyDatabase and is used to store -// the public keys for other matrix servers. -type KeyDatabase struct { - inner gomatrixserverlib.KeyDatabase - cache caching.ServerKeyCache -} - -func NewKeyDatabase(inner gomatrixserverlib.KeyDatabase, cache caching.ServerKeyCache) (*KeyDatabase, error) { - if inner == nil { - return nil, errors.New("inner database can't be nil") - } - if cache == nil { - return nil, errors.New("cache can't be nil") - } - return &KeyDatabase{ - inner: inner, - cache: cache, - }, nil -} - -// FetcherName implements KeyFetcher -func (d KeyDatabase) FetcherName() string { - return "InMemoryKeyCache" -} - -// FetchKeys implements gomatrixserverlib.KeyDatabase -func (d *KeyDatabase) FetchKeys( - ctx context.Context, - requests map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.Timestamp, -) (map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.PublicKeyLookupResult, error) { - results := make(map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.PublicKeyLookupResult) - for req, ts := range requests { - if res, cached := d.cache.GetServerKey(req, ts); cached { - results[req] = res - delete(requests, req) - } - } - fromDB, err := d.inner.FetchKeys(ctx, requests) - if err != nil { - return results, err - } - for req, res := range fromDB { - results[req] = res - d.cache.StoreServerKey(req, res) - } - return results, nil -} - -// StoreKeys implements gomatrixserverlib.KeyDatabase -func (d *KeyDatabase) StoreKeys( - ctx context.Context, - keyMap map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.PublicKeyLookupResult, -) error { - for req, res := range keyMap { - d.cache.StoreServerKey(req, res) - } - return d.inner.StoreKeys(ctx, keyMap) -} diff --git a/signingkeyserver/storage/interface.go b/signingkeyserver/storage/interface.go deleted file mode 100644 index 3a67ac55a..000000000 --- a/signingkeyserver/storage/interface.go +++ /dev/null @@ -1,13 +0,0 @@ -package storage - -import ( - "context" - - "github.com/matrix-org/gomatrixserverlib" -) - -type Database interface { - FetcherName() string - FetchKeys(ctx context.Context, requests map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.Timestamp) (map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.PublicKeyLookupResult, error) - StoreKeys(ctx context.Context, keyMap map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.PublicKeyLookupResult) error -} diff --git a/signingkeyserver/storage/keydb.go b/signingkeyserver/storage/keydb.go deleted file mode 100644 index 82b6d0ad5..000000000 --- a/signingkeyserver/storage/keydb.go +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2020 The Matrix.org Foundation C.I.C. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//go:build !wasm -// +build !wasm - -package storage - -import ( - "fmt" - - "golang.org/x/crypto/ed25519" - - "github.com/matrix-org/dendrite/setup/config" - "github.com/matrix-org/dendrite/signingkeyserver/storage/postgres" - "github.com/matrix-org/dendrite/signingkeyserver/storage/sqlite3" - "github.com/matrix-org/gomatrixserverlib" -) - -// NewDatabase opens a database connection. -func NewDatabase( - dbProperties *config.DatabaseOptions, - serverName gomatrixserverlib.ServerName, - serverKey ed25519.PublicKey, - serverKeyID gomatrixserverlib.KeyID, -) (Database, error) { - switch { - case dbProperties.ConnectionString.IsSQLite(): - return sqlite3.NewDatabase(dbProperties, serverName, serverKey, serverKeyID) - case dbProperties.ConnectionString.IsPostgres(): - return postgres.NewDatabase(dbProperties, serverName, serverKey, serverKeyID) - default: - return nil, fmt.Errorf("unexpected database type") - } -} diff --git a/signingkeyserver/storage/keydb_wasm.go b/signingkeyserver/storage/keydb_wasm.go deleted file mode 100644 index b112993a1..000000000 --- a/signingkeyserver/storage/keydb_wasm.go +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2020 The Matrix.org Foundation C.I.C. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//go:build wasm -// +build wasm - -package storage - -import ( - "fmt" - "net/url" - - "golang.org/x/crypto/ed25519" - - "github.com/matrix-org/dendrite/internal/sqlutil" - "github.com/matrix-org/dendrite/signingkeyserver/storage/sqlite3" - "github.com/matrix-org/gomatrixserverlib" -) - -// NewDatabase opens a database connection. -func NewDatabase( - dataSourceName string, - dbProperties sqlutil.DbProperties, // nolint:unparam - serverName gomatrixserverlib.ServerName, - serverKey ed25519.PublicKey, - serverKeyID gomatrixserverlib.KeyID, -) (Database, error) { - uri, err := url.Parse(dataSourceName) - if err != nil { - return nil, err - } - switch uri.Scheme { - case "postgres": - return nil, fmt.Errorf("Cannot use postgres implementation") - case "file": - return sqlite3.NewDatabase(dataSourceName, serverName, serverKey, serverKeyID) - default: - return nil, fmt.Errorf("Cannot use postgres implementation") - } -} diff --git a/signingkeyserver/storage/postgres/keydb.go b/signingkeyserver/storage/postgres/keydb.go deleted file mode 100644 index 1b3032de5..000000000 --- a/signingkeyserver/storage/postgres/keydb.go +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2017-2018 New Vector Ltd -// Copyright 2019-2020 The Matrix.org Foundation C.I.C. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package postgres - -import ( - "context" - - "golang.org/x/crypto/ed25519" - - "github.com/matrix-org/dendrite/internal/sqlutil" - "github.com/matrix-org/dendrite/setup/config" - "github.com/matrix-org/gomatrixserverlib" -) - -// A Database implements gomatrixserverlib.KeyDatabase and is used to store -// the public keys for other matrix servers. -type Database struct { - statements serverKeyStatements -} - -// NewDatabase prepares a new key database. -// It creates the necessary tables if they don't already exist. -// It prepares all the SQL statements that it will use. -// Returns an error if there was a problem talking to the database. -func NewDatabase( - dbProperties *config.DatabaseOptions, - serverName gomatrixserverlib.ServerName, - serverKey ed25519.PublicKey, - serverKeyID gomatrixserverlib.KeyID, -) (*Database, error) { - db, err := sqlutil.Open(dbProperties) - if err != nil { - return nil, err - } - d := &Database{} - err = d.statements.prepare(db) - if err != nil { - return nil, err - } - return d, nil -} - -// FetcherName implements KeyFetcher -func (d Database) FetcherName() string { - return "PostgresKeyDatabase" -} - -// FetchKeys implements gomatrixserverlib.KeyDatabase -func (d *Database) FetchKeys( - ctx context.Context, - requests map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.Timestamp, -) (map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.PublicKeyLookupResult, error) { - return d.statements.bulkSelectServerKeys(ctx, requests) -} - -// StoreKeys implements gomatrixserverlib.KeyDatabase -func (d *Database) StoreKeys( - ctx context.Context, - keyMap map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.PublicKeyLookupResult, -) error { - // TODO: Inserting all the keys within a single transaction may - // be more efficient since the transaction overhead can be quite - // high for a single insert statement. - var lastErr error - for request, keys := range keyMap { - if err := d.statements.upsertServerKeys(ctx, request, keys); err != nil { - // Rather than returning immediately on error we try to insert the - // remaining keys. - // Since we are inserting the keys outside of a transaction it is - // possible for some of the inserts to succeed even though some - // of the inserts have failed. - // Ensuring that we always insert all the keys we can means that - // this behaviour won't depend on the iteration order of the map. - lastErr = err - } - } - return lastErr -} diff --git a/signingkeyserver/storage/postgres/server_key_table.go b/signingkeyserver/storage/postgres/server_key_table.go deleted file mode 100644 index 87f1c211c..000000000 --- a/signingkeyserver/storage/postgres/server_key_table.go +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright 2017-2018 New Vector Ltd -// Copyright 2019-2020 The Matrix.org Foundation C.I.C. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package postgres - -import ( - "context" - "database/sql" - - "github.com/lib/pq" - "github.com/matrix-org/dendrite/internal" - "github.com/matrix-org/gomatrixserverlib" -) - -const serverKeysSchema = ` --- A cache of signing keys downloaded from remote servers. -CREATE TABLE IF NOT EXISTS keydb_server_keys ( - -- The name of the matrix server the key is for. - server_name TEXT NOT NULL, - -- The ID of the server key. - server_key_id TEXT NOT NULL, - -- Combined server name and key ID separated by the ASCII unit separator - -- to make it easier to run bulk queries. - server_name_and_key_id TEXT NOT NULL, - -- When the key is valid until as a millisecond timestamp. - -- 0 if this is an expired key (in which case expired_ts will be non-zero) - valid_until_ts BIGINT NOT NULL, - -- When the key expired as a millisecond timestamp. - -- 0 if this is an active key (in which case valid_until_ts will be non-zero) - expired_ts BIGINT NOT NULL, - -- The base64-encoded public key. - server_key TEXT NOT NULL, - CONSTRAINT keydb_server_keys_unique UNIQUE (server_name, server_key_id) -); - -CREATE INDEX IF NOT EXISTS keydb_server_name_and_key_id ON keydb_server_keys (server_name_and_key_id); -` - -const bulkSelectServerKeysSQL = "" + - "SELECT server_name, server_key_id, valid_until_ts, expired_ts, " + - " server_key FROM keydb_server_keys" + - " WHERE server_name_and_key_id = ANY($1)" - -const upsertServerKeysSQL = "" + - "INSERT INTO keydb_server_keys (server_name, server_key_id," + - " server_name_and_key_id, valid_until_ts, expired_ts, server_key)" + - " VALUES ($1, $2, $3, $4, $5, $6)" + - " ON CONFLICT ON CONSTRAINT keydb_server_keys_unique" + - " DO UPDATE SET valid_until_ts = $4, expired_ts = $5, server_key = $6" - -type serverKeyStatements struct { - bulkSelectServerKeysStmt *sql.Stmt - upsertServerKeysStmt *sql.Stmt -} - -func (s *serverKeyStatements) prepare(db *sql.DB) (err error) { - _, err = db.Exec(serverKeysSchema) - if err != nil { - return - } - if s.bulkSelectServerKeysStmt, err = db.Prepare(bulkSelectServerKeysSQL); err != nil { - return - } - if s.upsertServerKeysStmt, err = db.Prepare(upsertServerKeysSQL); err != nil { - return - } - return -} - -func (s *serverKeyStatements) bulkSelectServerKeys( - ctx context.Context, - requests map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.Timestamp, -) (map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.PublicKeyLookupResult, error) { - var nameAndKeyIDs []string - for request := range requests { - nameAndKeyIDs = append(nameAndKeyIDs, nameAndKeyID(request)) - } - stmt := s.bulkSelectServerKeysStmt - rows, err := stmt.QueryContext(ctx, pq.StringArray(nameAndKeyIDs)) - if err != nil { - return nil, err - } - defer internal.CloseAndLogIfError(ctx, rows, "bulkSelectServerKeys: rows.close() failed") - results := map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.PublicKeyLookupResult{} - for rows.Next() { - var serverName string - var keyID string - var key string - var validUntilTS int64 - var expiredTS int64 - if err = rows.Scan(&serverName, &keyID, &validUntilTS, &expiredTS, &key); err != nil { - return nil, err - } - r := gomatrixserverlib.PublicKeyLookupRequest{ - ServerName: gomatrixserverlib.ServerName(serverName), - KeyID: gomatrixserverlib.KeyID(keyID), - } - vk := gomatrixserverlib.VerifyKey{} - err = vk.Key.Decode(key) - if err != nil { - return nil, err - } - results[r] = gomatrixserverlib.PublicKeyLookupResult{ - VerifyKey: vk, - ValidUntilTS: gomatrixserverlib.Timestamp(validUntilTS), - ExpiredTS: gomatrixserverlib.Timestamp(expiredTS), - } - } - return results, rows.Err() -} - -func (s *serverKeyStatements) upsertServerKeys( - ctx context.Context, - request gomatrixserverlib.PublicKeyLookupRequest, - key gomatrixserverlib.PublicKeyLookupResult, -) error { - _, err := s.upsertServerKeysStmt.ExecContext( - ctx, - string(request.ServerName), - string(request.KeyID), - nameAndKeyID(request), - key.ValidUntilTS, - key.ExpiredTS, - key.Key.Encode(), - ) - return err -} - -func nameAndKeyID(request gomatrixserverlib.PublicKeyLookupRequest) string { - return string(request.ServerName) + "\x1F" + string(request.KeyID) -} diff --git a/signingkeyserver/storage/sqlite3/keydb.go b/signingkeyserver/storage/sqlite3/keydb.go deleted file mode 100644 index 1f85a09c3..000000000 --- a/signingkeyserver/storage/sqlite3/keydb.go +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2017-2018 New Vector Ltd -// Copyright 2019-2020 The Matrix.org Foundation C.I.C. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package sqlite3 - -import ( - "context" - - "golang.org/x/crypto/ed25519" - - "github.com/matrix-org/dendrite/internal/sqlutil" - "github.com/matrix-org/dendrite/setup/config" - "github.com/matrix-org/gomatrixserverlib" -) - -// A Database implements gomatrixserverlib.KeyDatabase and is used to store -// the public keys for other matrix servers. -type Database struct { - writer sqlutil.Writer - statements serverKeyStatements -} - -// NewDatabase prepares a new key database. -// It creates the necessary tables if they don't already exist. -// It prepares all the SQL statements that it will use. -// Returns an error if there was a problem talking to the database. -func NewDatabase( - dbProperties *config.DatabaseOptions, - serverName gomatrixserverlib.ServerName, - serverKey ed25519.PublicKey, - serverKeyID gomatrixserverlib.KeyID, -) (*Database, error) { - db, err := sqlutil.Open(dbProperties) - if err != nil { - return nil, err - } - d := &Database{ - writer: sqlutil.NewExclusiveWriter(), - } - err = d.statements.prepare(db, d.writer) - if err != nil { - return nil, err - } - if err != nil { - return nil, err - } - return d, nil -} - -// FetcherName implements KeyFetcher -func (d Database) FetcherName() string { - return "SqliteKeyDatabase" -} - -// FetchKeys implements gomatrixserverlib.KeyDatabase -func (d *Database) FetchKeys( - ctx context.Context, - requests map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.Timestamp, -) (map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.PublicKeyLookupResult, error) { - return d.statements.bulkSelectServerKeys(ctx, requests) -} - -// StoreKeys implements gomatrixserverlib.KeyDatabase -func (d *Database) StoreKeys( - ctx context.Context, - keyMap map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.PublicKeyLookupResult, -) error { - // TODO: Inserting all the keys within a single transaction may - // be more efficient since the transaction overhead can be quite - // high for a single insert statement. - var lastErr error - for request, keys := range keyMap { - if err := d.statements.upsertServerKeys(ctx, request, keys); err != nil { - // Rather than returning immediately on error we try to insert the - // remaining keys. - // Since we are inserting the keys outside of a transaction it is - // possible for some of the inserts to succeed even though some - // of the inserts have failed. - // Ensuring that we always insert all the keys we can means that - // this behaviour won't depend on the iteration order of the map. - lastErr = err - } - } - return lastErr -} diff --git a/signingkeyserver/storage/sqlite3/server_key_table.go b/signingkeyserver/storage/sqlite3/server_key_table.go deleted file mode 100644 index 2484d6368..000000000 --- a/signingkeyserver/storage/sqlite3/server_key_table.go +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright 2017-2018 New Vector Ltd -// Copyright 2019-2020 The Matrix.org Foundation C.I.C. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package sqlite3 - -import ( - "context" - "database/sql" - "fmt" - - "github.com/matrix-org/dendrite/internal/sqlutil" - "github.com/matrix-org/gomatrixserverlib" -) - -const serverKeysSchema = ` --- A cache of signing keys downloaded from remote servers. -CREATE TABLE IF NOT EXISTS keydb_server_keys ( - -- The name of the matrix server the key is for. - server_name TEXT NOT NULL, - -- The ID of the server key. - server_key_id TEXT NOT NULL, - -- Combined server name and key ID separated by the ASCII unit separator - -- to make it easier to run bulk queries. - server_name_and_key_id TEXT NOT NULL, - -- When the key is valid until as a millisecond timestamp. - -- 0 if this is an expired key (in which case expired_ts will be non-zero) - valid_until_ts BIGINT NOT NULL, - -- When the key expired as a millisecond timestamp. - -- 0 if this is an active key (in which case valid_until_ts will be non-zero) - expired_ts BIGINT NOT NULL, - -- The base64-encoded public key. - server_key TEXT NOT NULL, - UNIQUE (server_name, server_key_id) -); - -CREATE INDEX IF NOT EXISTS keydb_server_name_and_key_id ON keydb_server_keys (server_name_and_key_id); -` - -const bulkSelectServerKeysSQL = "" + - "SELECT server_name, server_key_id, valid_until_ts, expired_ts, " + - " server_key FROM keydb_server_keys" + - " WHERE server_name_and_key_id IN ($1)" - -const upsertServerKeysSQL = "" + - "INSERT INTO keydb_server_keys (server_name, server_key_id," + - " server_name_and_key_id, valid_until_ts, expired_ts, server_key)" + - " VALUES ($1, $2, $3, $4, $5, $6)" + - " ON CONFLICT (server_name, server_key_id)" + - " DO UPDATE SET valid_until_ts = $4, expired_ts = $5, server_key = $6" - -type serverKeyStatements struct { - db *sql.DB - writer sqlutil.Writer - bulkSelectServerKeysStmt *sql.Stmt - upsertServerKeysStmt *sql.Stmt -} - -func (s *serverKeyStatements) prepare(db *sql.DB, writer sqlutil.Writer) (err error) { - s.db = db - s.writer = writer - _, err = db.Exec(serverKeysSchema) - if err != nil { - return - } - if s.bulkSelectServerKeysStmt, err = db.Prepare(bulkSelectServerKeysSQL); err != nil { - return - } - if s.upsertServerKeysStmt, err = db.Prepare(upsertServerKeysSQL); err != nil { - return - } - return -} - -func (s *serverKeyStatements) bulkSelectServerKeys( - ctx context.Context, - requests map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.Timestamp, -) (map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.PublicKeyLookupResult, error) { - nameAndKeyIDs := make([]string, 0, len(requests)) - for request := range requests { - nameAndKeyIDs = append(nameAndKeyIDs, nameAndKeyID(request)) - } - results := make(map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.PublicKeyLookupResult, len(requests)) - iKeyIDs := make([]interface{}, len(nameAndKeyIDs)) - for i, v := range nameAndKeyIDs { - iKeyIDs[i] = v - } - - err := sqlutil.RunLimitedVariablesQuery( - ctx, bulkSelectServerKeysSQL, s.db, iKeyIDs, sqlutil.SQLite3MaxVariables, - func(rows *sql.Rows) error { - for rows.Next() { - var serverName string - var keyID string - var key string - var validUntilTS int64 - var expiredTS int64 - if err := rows.Scan(&serverName, &keyID, &validUntilTS, &expiredTS, &key); err != nil { - return fmt.Errorf("bulkSelectServerKeys: %v", err) - } - r := gomatrixserverlib.PublicKeyLookupRequest{ - ServerName: gomatrixserverlib.ServerName(serverName), - KeyID: gomatrixserverlib.KeyID(keyID), - } - vk := gomatrixserverlib.VerifyKey{} - err := vk.Key.Decode(key) - if err != nil { - return fmt.Errorf("bulkSelectServerKeys: %v", err) - } - results[r] = gomatrixserverlib.PublicKeyLookupResult{ - VerifyKey: vk, - ValidUntilTS: gomatrixserverlib.Timestamp(validUntilTS), - ExpiredTS: gomatrixserverlib.Timestamp(expiredTS), - } - } - return nil - }, - ) - - if err != nil { - return nil, err - } - return results, nil -} - -func (s *serverKeyStatements) upsertServerKeys( - ctx context.Context, - request gomatrixserverlib.PublicKeyLookupRequest, - key gomatrixserverlib.PublicKeyLookupResult, -) error { - return s.writer.Do(s.db, nil, func(txn *sql.Tx) error { - stmt := sqlutil.TxStmt(txn, s.upsertServerKeysStmt) - _, err := stmt.ExecContext( - ctx, - string(request.ServerName), - string(request.KeyID), - nameAndKeyID(request), - key.ValidUntilTS, - key.ExpiredTS, - key.Key.Encode(), - ) - return err - }) -} - -func nameAndKeyID(request gomatrixserverlib.PublicKeyLookupRequest) string { - return string(request.ServerName) + "\x1F" + string(request.KeyID) -}