diff --git a/eduserver/api/input.go b/eduserver/api/input.go index f8599e1c..93c3cff9 100644 --- a/eduserver/api/input.go +++ b/eduserver/api/input.go @@ -75,6 +75,18 @@ type InputReceiptEventRequest struct { // InputReceiptEventResponse is a response to InputReceiptEventRequest type InputReceiptEventResponse struct{} +type SigningKeyUpdate struct { + MasterKey gomatrixserverlib.CrossSigningKey `json:"master_key"` + SelfSigningKey gomatrixserverlib.CrossSigningKey `json:"cross_signing_key"` + UserID string `json:"user_id"` +} + +type InputSigningKeyUpdateRequest struct { + SigningKeyUpdate +} + +type InputSigningKeyUpdateResponse struct{} + // EDUServerInputAPI is used to write events to the typing server. type EDUServerInputAPI interface { InputTypingEvent( @@ -94,4 +106,10 @@ type EDUServerInputAPI interface { request *InputReceiptEventRequest, response *InputReceiptEventResponse, ) error + + InputSigningKeyUpdate( + ctx context.Context, + request *InputSigningKeyUpdateRequest, + response *InputSigningKeyUpdateResponse, + ) error } diff --git a/eduserver/api/output.go b/eduserver/api/output.go index 650458a2..89987e1e 100644 --- a/eduserver/api/output.go +++ b/eduserver/api/output.go @@ -85,3 +85,9 @@ type FederationReceiptData struct { Data ReceiptTS `json:"data"` EventIDs []string `json:"event_ids"` } + +type OutputSigningKeyUpdate struct { + SigningKeyUpdate + Type string `json:"type"` + Timestamp gomatrixserverlib.Timestamp `json:"timestamp"` +} diff --git a/eduserver/api/wrapper.go b/eduserver/api/wrapper.go index 7907f4d3..1878fde5 100644 --- a/eduserver/api/wrapper.go +++ b/eduserver/api/wrapper.go @@ -86,3 +86,20 @@ func SendReceipt( response := InputReceiptEventResponse{} return eduAPI.InputReceiptEvent(ctx, &request, &response) } + +func SendSigningKeyUpdate( + ctx context.Context, + eduAPI EDUServerInputAPI, + userID string, + masterKey, selfSigningKey gomatrixserverlib.CrossSigningKey, +) error { + request := InputSigningKeyUpdateRequest{ + SigningKeyUpdate: SigningKeyUpdate{ + MasterKey: masterKey, + SelfSigningKey: selfSigningKey, + UserID: userID, + }, + } + response := InputSigningKeyUpdateResponse{} + return eduAPI.InputSigningKeyUpdate(ctx, &request, &response) +} diff --git a/eduserver/eduserver.go b/eduserver/eduserver.go index 7cc40510..748a1260 100644 --- a/eduserver/eduserver.go +++ b/eduserver/eduserver.go @@ -52,6 +52,7 @@ func NewInternalAPI( OutputTypingEventTopic: cfg.Matrix.Kafka.TopicFor(config.TopicOutputTypingEvent), OutputSendToDeviceEventTopic: cfg.Matrix.Kafka.TopicFor(config.TopicOutputSendToDeviceEvent), OutputReceiptEventTopic: cfg.Matrix.Kafka.TopicFor(config.TopicOutputReceiptEvent), + OutputSigningKeyUpdateTopic: cfg.Matrix.Kafka.TopicFor(config), ServerName: cfg.Matrix.ServerName, } } diff --git a/eduserver/input/input.go b/eduserver/input/input.go index c54fb9de..2296a0d0 100644 --- a/eduserver/input/input.go +++ b/eduserver/input/input.go @@ -39,6 +39,8 @@ type EDUServerInputAPI struct { OutputSendToDeviceEventTopic string // The kafka topic to output new receipt events to OutputReceiptEventTopic string + // The kafka topic to output new signing key updates to + OutputSigningKeyUpdateTopic string // kafka producer Producer sarama.SyncProducer // Internal user query API @@ -203,3 +205,28 @@ func (t *EDUServerInputAPI) InputReceiptEvent( _, _, err = t.Producer.SendMessage(m) return err } + +// InputSigningKeyUpdate implements api.EDUServerInputAPI +func (t *EDUServerInputAPI) InputSigningKeyUpdate( + ctx context.Context, + request *api.InputSigningKeyUpdateRequest, + response *api.InputSigningKeyUpdateResponse, +) error { + logrus.WithFields(logrus.Fields{}).Infof("Producing to topic '%s'", t.OutputSigningKeyUpdateTopic) + output := &api.OutputSigningKeyUpdate{ + SigningKeyUpdate: request.SigningKeyUpdate, + Type: "m.signing_key_update", + Timestamp: gomatrixserverlib.AsTimestamp(time.Now()), + } + js, err := json.Marshal(output) + if err != nil { + return err + } + m := &sarama.ProducerMessage{ + Topic: t.OutputSigningKeyUpdateTopic, + Key: sarama.StringEncoder(request.UserID), + Value: sarama.ByteEncoder(js), + } + _, _, err = t.Producer.SendMessage(m) + return err +} diff --git a/eduserver/inthttp/client.go b/eduserver/inthttp/client.go index 0690ed82..70870cce 100644 --- a/eduserver/inthttp/client.go +++ b/eduserver/inthttp/client.go @@ -15,6 +15,7 @@ const ( EDUServerInputTypingEventPath = "/eduserver/input" EDUServerInputSendToDeviceEventPath = "/eduserver/sendToDevice" EDUServerInputReceiptEventPath = "/eduserver/receipt" + EDUServerInputSigningKeyUpdatePath = "/eduserver/signingKeyUpdate" ) // NewEDUServerClient creates a EDUServerInputAPI implemented by talking to a HTTP POST API. @@ -68,3 +69,16 @@ func (h *httpEDUServerInputAPI) InputReceiptEvent( apiURL := h.eduServerURL + EDUServerInputReceiptEventPath return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response) } + +// InputSigningKeyUpdate implements EDUServerInputAPI +func (h *httpEDUServerInputAPI) InputSigningKeyUpdate( + ctx context.Context, + request *api.InputSigningKeyUpdateRequest, + response *api.InputSigningKeyUpdateResponse, +) error { + span, ctx := opentracing.StartSpanFromContext(ctx, "InputSigningKeyUpdate") + defer span.Finish() + + apiURL := h.eduServerURL + EDUServerInputSigningKeyUpdatePath + return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response) +} diff --git a/eduserver/inthttp/server.go b/eduserver/inthttp/server.go index a3494375..2f811728 100644 --- a/eduserver/inthttp/server.go +++ b/eduserver/inthttp/server.go @@ -51,4 +51,17 @@ func AddRoutes(t api.EDUServerInputAPI, internalAPIMux *mux.Router) { return util.JSONResponse{Code: http.StatusOK, JSON: &response} }), ) + internalAPIMux.Handle(EDUServerInputSigningKeyUpdatePath, + httputil.MakeInternalAPI("inputSigningKeyUpdate", func(req *http.Request) util.JSONResponse { + var request api.InputSigningKeyUpdateRequest + var response api.InputSigningKeyUpdateResponse + if err := json.NewDecoder(req.Body).Decode(&request); err != nil { + return util.MessageResponse(http.StatusBadRequest, err.Error()) + } + if err := t.InputSigningKeyUpdate(req.Context(), &request, &response); err != nil { + return util.ErrorResponse(err) + } + return util.JSONResponse{Code: http.StatusOK, JSON: &response} + }), + ) } diff --git a/federationapi/routing/send_test.go b/federationapi/routing/send_test.go index 0da06aa9..e9651bcd 100644 --- a/federationapi/routing/send_test.go +++ b/federationapi/routing/send_test.go @@ -84,6 +84,14 @@ func (o *testEDUProducer) InputReceiptEvent( return nil } +func (o *testEDUProducer) InputSigningKeyUpdate( + ctx context.Context, + request *eduAPI.InputSigningKeyUpdateRequest, + response *eduAPI.InputSigningKeyUpdateResponse, +) error { + return nil +} + type testRoomserverAPI struct { api.RoomserverInternalAPITrace inputRoomEvents []api.InputRoomEvent diff --git a/setup/config/config_kafka.go b/setup/config/config_kafka.go index 36191428..15b3ad71 100644 --- a/setup/config/config_kafka.go +++ b/setup/config/config_kafka.go @@ -10,6 +10,7 @@ const ( TopicOutputRoomEvent = "OutputRoomEvent" TopicOutputClientData = "OutputClientData" TopicOutputReceiptEvent = "OutputReceiptEvent" + TopicOutputSigningKeyUpdate = "OutputSigningKeyUpdate" ) type Kafka struct {