aboutsummaryrefslogtreecommitdiff
path: root/keyserver
diff options
context:
space:
mode:
authorKegsay <kegan@matrix.org>2020-07-13 16:02:35 +0100
committerGitHub <noreply@github.com>2020-07-13 16:02:35 +0100
commit396219ef534093b45ad02cccc8ca9cf0f9742c40 (patch)
tree4cf4eaf0a31cc2a3e42a9bb8be7f7e4d4a17e982 /keyserver
parent3178afde2c432d5886fa51e1eacfb1e770da39a6 (diff)
Add boilerplate for key server APIs (#1196)
Also add a README which outilnes how things will work.
Diffstat (limited to 'keyserver')
-rw-r--r--keyserver/README.md19
-rw-r--r--keyserver/api/api.go49
-rw-r--r--keyserver/internal/internal.go19
-rw-r--r--keyserver/inthttp/client.go103
-rw-r--r--keyserver/inthttp/server.go61
-rw-r--r--keyserver/keyserver.go21
-rw-r--r--keyserver/routing/keys.go33
-rw-r--r--keyserver/routing/routing.go54
8 files changed, 264 insertions, 95 deletions
diff --git a/keyserver/README.md b/keyserver/README.md
new file mode 100644
index 00000000..fd9f37d2
--- /dev/null
+++ b/keyserver/README.md
@@ -0,0 +1,19 @@
+## Key Server
+
+This is an internal component which manages E2E keys from clients. It handles all the [Key Management APIs](https://matrix.org/docs/spec/client_server/r0.6.1#key-management-api) with the exception of `/keys/changes` which is handled by Sync API. This component is designed to shard by user ID.
+
+Keys are uploaded and stored in this component, and key changes are emitted to a Kafka topic for downstream components such as Sync API.
+
+### Internal APIs
+- `PerformUploadKeys` stores identity keys and one-time public keys for given user(s).
+- `PerformClaimKeys` acquires one-time public keys for given user(s). This may involve outbound federation calls.
+- `QueryKeys` returns identity keys for given user(s). This may involve outbound federation calls. This component may then cache federated identity keys to avoid repeatedly hitting remote servers.
+- A topic which emits identity keys every time there is a change (addition or deletion).
+
+### Endpoint mappings
+- Client API maps `/keys/upload` to `PerformUploadKeys`.
+- Client API maps `/keys/query` to `QueryKeys`.
+- Client API maps `/keys/claim` to `PerformClaimKeys`.
+- Federation API maps `/user/keys/query` to `QueryKeys`.
+- Federation API maps `/user/keys/claim` to `PerformClaimKeys`.
+- Sync API maps `/keys/changes` to consuming from the Kafka topic.
diff --git a/keyserver/api/api.go b/keyserver/api/api.go
new file mode 100644
index 00000000..d8b866f3
--- /dev/null
+++ b/keyserver/api/api.go
@@ -0,0 +1,49 @@
+// 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 api
+
+import "context"
+
+type KeyInternalAPI interface {
+ PerformUploadKeys(ctx context.Context, req *PerformUploadKeysRequest, res *PerformUploadKeysResponse)
+ PerformClaimKeys(ctx context.Context, req *PerformClaimKeysRequest, res *PerformClaimKeysResponse)
+ QueryKeys(ctx context.Context, req *QueryKeysRequest, res *QueryKeysResponse)
+}
+
+// KeyError is returned if there was a problem performing/querying the server
+type KeyError struct {
+ Error string
+}
+
+type PerformUploadKeysRequest struct {
+}
+
+type PerformUploadKeysResponse struct {
+ Error *KeyError
+}
+
+type PerformClaimKeysRequest struct {
+}
+
+type PerformClaimKeysResponse struct {
+ Error *KeyError
+}
+
+type QueryKeysRequest struct {
+}
+
+type QueryKeysResponse struct {
+ Error *KeyError
+}
diff --git a/keyserver/internal/internal.go b/keyserver/internal/internal.go
new file mode 100644
index 00000000..40883cdd
--- /dev/null
+++ b/keyserver/internal/internal.go
@@ -0,0 +1,19 @@
+package internal
+
+import (
+ "context"
+
+ "github.com/matrix-org/dendrite/keyserver/api"
+)
+
+type KeyInternalAPI struct{}
+
+func (a *KeyInternalAPI) PerformUploadKeys(ctx context.Context, req *api.PerformUploadKeysRequest, res *api.PerformUploadKeysResponse) {
+
+}
+func (a *KeyInternalAPI) PerformClaimKeys(ctx context.Context, req *api.PerformClaimKeysRequest, res *api.PerformClaimKeysResponse) {
+
+}
+func (a *KeyInternalAPI) QueryKeys(ctx context.Context, req *api.QueryKeysRequest, res *api.QueryKeysResponse) {
+
+}
diff --git a/keyserver/inthttp/client.go b/keyserver/inthttp/client.go
new file mode 100644
index 00000000..f2d00c70
--- /dev/null
+++ b/keyserver/inthttp/client.go
@@ -0,0 +1,103 @@
+// 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 inthttp
+
+import (
+ "context"
+ "errors"
+ "net/http"
+
+ "github.com/matrix-org/dendrite/internal/httputil"
+ "github.com/matrix-org/dendrite/keyserver/api"
+ "github.com/opentracing/opentracing-go"
+)
+
+// HTTP paths for the internal HTTP APIs
+const (
+ PerformUploadKeysPath = "/keyserver/performUploadKeys"
+ PerformClaimKeysPath = "/keyserver/performClaimKeys"
+ QueryKeysPath = "/keyserver/queryKeys"
+)
+
+// NewKeyServerClient creates a KeyInternalAPI implemented by talking to a HTTP POST API.
+// If httpClient is nil an error is returned
+func NewKeyServerClient(
+ apiURL string,
+ httpClient *http.Client,
+) (api.KeyInternalAPI, error) {
+ if httpClient == nil {
+ return nil, errors.New("NewKeyServerClient: httpClient is <nil>")
+ }
+ return &httpKeyInternalAPI{
+ apiURL: apiURL,
+ httpClient: httpClient,
+ }, nil
+}
+
+type httpKeyInternalAPI struct {
+ apiURL string
+ httpClient *http.Client
+}
+
+func (h *httpKeyInternalAPI) PerformClaimKeys(
+ ctx context.Context,
+ request *api.PerformClaimKeysRequest,
+ response *api.PerformClaimKeysResponse,
+) {
+ span, ctx := opentracing.StartSpanFromContext(ctx, "PerformClaimKeys")
+ defer span.Finish()
+
+ apiURL := h.apiURL + PerformClaimKeysPath
+ err := httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response)
+ if err != nil {
+ response.Error = &api.KeyError{
+ Error: err.Error(),
+ }
+ }
+}
+
+func (h *httpKeyInternalAPI) PerformUploadKeys(
+ ctx context.Context,
+ request *api.PerformUploadKeysRequest,
+ response *api.PerformUploadKeysResponse,
+) {
+ span, ctx := opentracing.StartSpanFromContext(ctx, "PerformUploadKeys")
+ defer span.Finish()
+
+ apiURL := h.apiURL + PerformUploadKeysPath
+ err := httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response)
+ if err != nil {
+ response.Error = &api.KeyError{
+ Error: err.Error(),
+ }
+ }
+}
+
+func (h *httpKeyInternalAPI) QueryKeys(
+ ctx context.Context,
+ request *api.QueryKeysRequest,
+ response *api.QueryKeysResponse,
+) {
+ span, ctx := opentracing.StartSpanFromContext(ctx, "QueryKeys")
+ defer span.Finish()
+
+ apiURL := h.apiURL + QueryKeysPath
+ err := httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response)
+ if err != nil {
+ response.Error = &api.KeyError{
+ Error: err.Error(),
+ }
+ }
+}
diff --git a/keyserver/inthttp/server.go b/keyserver/inthttp/server.go
new file mode 100644
index 00000000..ec78b613
--- /dev/null
+++ b/keyserver/inthttp/server.go
@@ -0,0 +1,61 @@
+// 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 inthttp
+
+import (
+ "encoding/json"
+ "net/http"
+
+ "github.com/gorilla/mux"
+ "github.com/matrix-org/dendrite/internal/httputil"
+ "github.com/matrix-org/dendrite/keyserver/api"
+ "github.com/matrix-org/util"
+)
+
+func AddRoutes(internalAPIMux *mux.Router, s api.KeyInternalAPI) {
+ internalAPIMux.Handle(PerformClaimKeysPath,
+ httputil.MakeInternalAPI("performClaimKeys", func(req *http.Request) util.JSONResponse {
+ request := api.PerformClaimKeysRequest{}
+ response := api.PerformClaimKeysResponse{}
+ if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
+ return util.MessageResponse(http.StatusBadRequest, err.Error())
+ }
+ s.PerformClaimKeys(req.Context(), &request, &response)
+ return util.JSONResponse{Code: http.StatusOK, JSON: &response}
+ }),
+ )
+ internalAPIMux.Handle(PerformUploadKeysPath,
+ httputil.MakeInternalAPI("performUploadKeys", func(req *http.Request) util.JSONResponse {
+ request := api.PerformUploadKeysRequest{}
+ response := api.PerformUploadKeysResponse{}
+ if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
+ return util.MessageResponse(http.StatusBadRequest, err.Error())
+ }
+ s.PerformUploadKeys(req.Context(), &request, &response)
+ return util.JSONResponse{Code: http.StatusOK, JSON: &response}
+ }),
+ )
+ internalAPIMux.Handle(QueryKeysPath,
+ httputil.MakeInternalAPI("queryKeys", func(req *http.Request) util.JSONResponse {
+ request := api.QueryKeysRequest{}
+ response := api.QueryKeysResponse{}
+ if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
+ return util.MessageResponse(http.StatusBadRequest, err.Error())
+ }
+ s.QueryKeys(req.Context(), &request, &response)
+ return util.JSONResponse{Code: http.StatusOK, JSON: &response}
+ }),
+ )
+}
diff --git a/keyserver/keyserver.go b/keyserver/keyserver.go
index bedc4dfb..3bb0e462 100644
--- a/keyserver/keyserver.go
+++ b/keyserver/keyserver.go
@@ -16,14 +16,19 @@ package keyserver
import (
"github.com/gorilla/mux"
- "github.com/matrix-org/dendrite/internal/config"
- "github.com/matrix-org/dendrite/keyserver/routing"
- userapi "github.com/matrix-org/dendrite/userapi/api"
+ "github.com/matrix-org/dendrite/keyserver/api"
+ "github.com/matrix-org/dendrite/keyserver/internal"
+ "github.com/matrix-org/dendrite/keyserver/inthttp"
)
-// AddPublicRoutes registers HTTP handlers for CS API calls
-func AddPublicRoutes(
- router *mux.Router, cfg *config.Dendrite, userAPI userapi.UserInternalAPI,
-) {
- routing.Setup(router, cfg, userAPI)
+// AddInternalRoutes registers HTTP handlers for the internal API. Invokes functions
+// on the given input API.
+func AddInternalRoutes(router *mux.Router, intAPI api.KeyInternalAPI) {
+ inthttp.AddRoutes(router, intAPI)
+}
+
+// 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() api.KeyInternalAPI {
+ return &internal.KeyInternalAPI{}
}
diff --git a/keyserver/routing/keys.go b/keyserver/routing/keys.go
deleted file mode 100644
index a279a747..00000000
--- a/keyserver/routing/keys.go
+++ /dev/null
@@ -1,33 +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 routing
-
-import (
- "net/http"
-
- "github.com/matrix-org/util"
-)
-
-func QueryKeys(
- req *http.Request,
-) util.JSONResponse {
- return util.JSONResponse{
- Code: http.StatusOK,
- JSON: map[string]interface{}{
- "failures": map[string]interface{}{},
- "device_keys": map[string]interface{}{},
- },
- }
-}
diff --git a/keyserver/routing/routing.go b/keyserver/routing/routing.go
deleted file mode 100644
index dba43528..00000000
--- a/keyserver/routing/routing.go
+++ /dev/null
@@ -1,54 +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 routing
-
-import (
- "net/http"
-
- "github.com/gorilla/mux"
- "github.com/matrix-org/dendrite/internal/config"
- "github.com/matrix-org/dendrite/internal/httputil"
- userapi "github.com/matrix-org/dendrite/userapi/api"
- "github.com/matrix-org/util"
-)
-
-const pathPrefixR0 = "/client/r0"
-
-// Setup registers HTTP handlers with the given ServeMux. It also supplies the given http.Client
-// to clients which need to make outbound HTTP requests.
-//
-// Due to Setup being used to call many other functions, a gocyclo nolint is
-// applied:
-// nolint: gocyclo
-func Setup(
- publicAPIMux *mux.Router, cfg *config.Dendrite, userAPI userapi.UserInternalAPI,
-) {
- r0mux := publicAPIMux.PathPrefix(pathPrefixR0).Subrouter()
-
- r0mux.Handle("/keys/query",
- httputil.MakeAuthAPI("queryKeys", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
- return QueryKeys(req)
- }),
- ).Methods(http.MethodPost, http.MethodOptions)
-
- r0mux.Handle("/keys/upload/{keyID}",
- httputil.MakeAuthAPI("keys_upload", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
- return util.JSONResponse{
- Code: 200,
- JSON: map[string]interface{}{},
- }
- }),
- ).Methods(http.MethodPost, http.MethodOptions)
-}