From 643d05b157d64f7ad37001edc3631ec259f9c050 Mon Sep 17 00:00:00 2001
From: Mark Haines <mjark@negativecurvature.net>
Date: Mon, 4 Sep 2017 13:14:01 +0100
Subject: [PATCH] Add function for making authed federation APIs (#208)

---
 .../matrix-org/dendrite/common/httpapi.go     | 27 +++++++++++++++--
 .../dendrite/federationapi/routing/routing.go | 30 ++++++++-----------
 .../dendrite/federationapi/writers/invite.go  | 16 ++++------
 .../dendrite/federationapi/writers/send.go    | 11 ++-----
 4 files changed, 44 insertions(+), 40 deletions(-)

diff --git a/src/github.com/matrix-org/dendrite/common/httpapi.go b/src/github.com/matrix-org/dendrite/common/httpapi.go
index 55f9cd1e7..8d93e58d1 100644
--- a/src/github.com/matrix-org/dendrite/common/httpapi.go
+++ b/src/github.com/matrix-org/dendrite/common/httpapi.go
@@ -2,24 +2,26 @@ package common
 
 import (
 	"net/http"
+	"time"
 
 	"github.com/gorilla/mux"
 	"github.com/matrix-org/dendrite/clientapi/auth"
 	"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
+	"github.com/matrix-org/gomatrixserverlib"
 	"github.com/matrix-org/util"
 	"github.com/prometheus/client_golang/prometheus"
 )
 
 // MakeAuthAPI turns a util.JSONRequestHandler function into an http.Handler which checks the access token in the request.
 func MakeAuthAPI(metricsName string, deviceDB auth.DeviceDatabase, f func(*http.Request, *authtypes.Device) util.JSONResponse) http.Handler {
-	h := util.NewJSONRequestHandler(func(req *http.Request) util.JSONResponse {
+	h := func(req *http.Request) util.JSONResponse {
 		device, resErr := auth.VerifyAccessToken(req, deviceDB)
 		if resErr != nil {
 			return *resErr
 		}
 		return f(req, device)
-	})
-	return prometheus.InstrumentHandler(metricsName, util.MakeJSONAPI(h))
+	}
+	return MakeAPI(metricsName, h)
 }
 
 // MakeAPI turns a util.JSONRequestHandler function into an http.Handler.
@@ -28,6 +30,25 @@ func MakeAPI(metricsName string, f func(*http.Request) util.JSONResponse) http.H
 	return prometheus.InstrumentHandler(metricsName, util.MakeJSONAPI(h))
 }
 
+// MakeFedAPI makes an http.Handler that checks matrix federation authentication.
+func MakeFedAPI(
+	metricsName string,
+	serverName gomatrixserverlib.ServerName,
+	keyRing gomatrixserverlib.KeyRing,
+	f func(*http.Request, *gomatrixserverlib.FederationRequest) util.JSONResponse,
+) http.Handler {
+	h := func(req *http.Request) util.JSONResponse {
+		fedReq, errResp := gomatrixserverlib.VerifyHTTPRequest(
+			req, time.Now(), serverName, keyRing,
+		)
+		if fedReq == nil {
+			return errResp
+		}
+		return f(req, fedReq)
+	}
+	return MakeAPI(metricsName, h)
+}
+
 // SetupHTTPAPI registers an HTTP API mux under /api and sets up a metrics
 // listener.
 func SetupHTTPAPI(servMux *http.ServeMux, apiMux *mux.Router) {
diff --git a/src/github.com/matrix-org/dendrite/federationapi/routing/routing.go b/src/github.com/matrix-org/dendrite/federationapi/routing/routing.go
index 7ed17210d..025089073 100644
--- a/src/github.com/matrix-org/dendrite/federationapi/routing/routing.go
+++ b/src/github.com/matrix-org/dendrite/federationapi/routing/routing.go
@@ -16,17 +16,16 @@ package routing
 
 import (
 	"net/http"
-	"time"
 
 	"github.com/gorilla/mux"
 	"github.com/matrix-org/dendrite/clientapi/producers"
+	"github.com/matrix-org/dendrite/common"
 	"github.com/matrix-org/dendrite/common/config"
 	"github.com/matrix-org/dendrite/federationapi/readers"
 	"github.com/matrix-org/dendrite/federationapi/writers"
 	"github.com/matrix-org/dendrite/roomserver/api"
 	"github.com/matrix-org/gomatrixserverlib"
 	"github.com/matrix-org/util"
-	"github.com/prometheus/client_golang/prometheus"
 )
 
 const (
@@ -46,7 +45,7 @@ func Setup(
 	v2keysmux := apiMux.PathPrefix(pathPrefixV2Keys).Subrouter()
 	v1fedmux := apiMux.PathPrefix(pathPrefixV1Federation).Subrouter()
 
-	localKeys := makeAPI("localkeys", func(req *http.Request) util.JSONResponse {
+	localKeys := common.MakeAPI("localkeys", func(req *http.Request) util.JSONResponse {
 		return readers.LocalKeys(req, cfg)
 	})
 
@@ -57,30 +56,25 @@ func Setup(
 	v2keysmux.Handle("/server/{keyID}", localKeys)
 	v2keysmux.Handle("/server/", localKeys)
 
-	v1fedmux.Handle("/send/{txnID}/", makeAPI("federation_send",
-		func(req *http.Request) util.JSONResponse {
-			vars := mux.Vars(req)
+	v1fedmux.Handle("/send/{txnID}/", common.MakeFedAPI(
+		"federation_send", cfg.Matrix.ServerName, keys,
+		func(httpReq *http.Request, request *gomatrixserverlib.FederationRequest) util.JSONResponse {
+			vars := mux.Vars(httpReq)
 			return writers.Send(
-				req, gomatrixserverlib.TransactionID(vars["txnID"]),
-				time.Now(),
+				httpReq, request, gomatrixserverlib.TransactionID(vars["txnID"]),
 				cfg, query, producer, keys, federation,
 			)
 		},
 	))
 
-	v1fedmux.Handle("/invite/{roomID}/{eventID}", makeAPI("federation_invite",
-		func(req *http.Request) util.JSONResponse {
-			vars := mux.Vars(req)
+	v1fedmux.Handle("/invite/{roomID}/{eventID}", common.MakeFedAPI(
+		"federation_invite", cfg.Matrix.ServerName, keys,
+		func(httpReq *http.Request, request *gomatrixserverlib.FederationRequest) util.JSONResponse {
+			vars := mux.Vars(httpReq)
 			return writers.Invite(
-				req, vars["roomID"], vars["eventID"],
-				time.Now(),
+				httpReq, request, vars["roomID"], vars["eventID"],
 				cfg, producer, keys,
 			)
 		},
 	))
 }
-
-func makeAPI(metricsName string, f func(*http.Request) util.JSONResponse) http.Handler {
-	h := util.NewJSONRequestHandler(f)
-	return prometheus.InstrumentHandler(metricsName, util.MakeJSONAPI(h))
-}
diff --git a/src/github.com/matrix-org/dendrite/federationapi/writers/invite.go b/src/github.com/matrix-org/dendrite/federationapi/writers/invite.go
index dc89f4a75..03972d361 100644
--- a/src/github.com/matrix-org/dendrite/federationapi/writers/invite.go
+++ b/src/github.com/matrix-org/dendrite/federationapi/writers/invite.go
@@ -3,31 +3,25 @@ package writers
 import (
 	"encoding/json"
 	"net/http"
-	"time"
-
-	"github.com/matrix-org/util"
 
 	"github.com/matrix-org/dendrite/clientapi/httputil"
 	"github.com/matrix-org/dendrite/clientapi/jsonerror"
 	"github.com/matrix-org/dendrite/clientapi/producers"
 	"github.com/matrix-org/dendrite/common/config"
 	"github.com/matrix-org/gomatrixserverlib"
+	"github.com/matrix-org/util"
 )
 
 // Invite implements /_matrix/federation/v1/invite/{roomID}/{eventID}
 func Invite(
-	req *http.Request,
+	httpReq *http.Request,
+	request *gomatrixserverlib.FederationRequest,
 	roomID string,
 	eventID string,
-	now time.Time,
 	cfg config.Dendrite,
 	producer *producers.RoomserverProducer,
 	keys gomatrixserverlib.KeyRing,
 ) util.JSONResponse {
-	request, errResp := gomatrixserverlib.VerifyHTTPRequest(req, now, cfg.Matrix.ServerName, keys)
-	if request == nil {
-		return errResp
-	}
 
 	// Decode the event JSON from the request.
 	var event gomatrixserverlib.Event
@@ -70,7 +64,7 @@ func Invite(
 	}}
 	verifyResults, err := keys.VerifyJSONs(verifyRequests)
 	if err != nil {
-		return httputil.LogThenError(req, err)
+		return httputil.LogThenError(httpReq, err)
 	}
 	if verifyResults[0].Error != nil {
 		return util.JSONResponse{
@@ -86,7 +80,7 @@ func Invite(
 
 	// Add the invite event to the roomserver.
 	if err = producer.SendInvite(signedEvent); err != nil {
-		return httputil.LogThenError(req, err)
+		return httputil.LogThenError(httpReq, err)
 	}
 
 	// Return the signed event to the originating server, it should then tell
diff --git a/src/github.com/matrix-org/dendrite/federationapi/writers/send.go b/src/github.com/matrix-org/dendrite/federationapi/writers/send.go
index ddae07555..f253162b5 100644
--- a/src/github.com/matrix-org/dendrite/federationapi/writers/send.go
+++ b/src/github.com/matrix-org/dendrite/federationapi/writers/send.go
@@ -4,7 +4,6 @@ import (
 	"encoding/json"
 	"fmt"
 	"net/http"
-	"time"
 
 	"github.com/matrix-org/dendrite/clientapi/httputil"
 	"github.com/matrix-org/dendrite/clientapi/jsonerror"
@@ -17,19 +16,15 @@ import (
 
 // Send implements /_matrix/federation/v1/send/{txnID}
 func Send(
-	req *http.Request,
+	httpReq *http.Request,
+	request *gomatrixserverlib.FederationRequest,
 	txnID gomatrixserverlib.TransactionID,
-	now time.Time,
 	cfg config.Dendrite,
 	query api.RoomserverQueryAPI,
 	producer *producers.RoomserverProducer,
 	keys gomatrixserverlib.KeyRing,
 	federation *gomatrixserverlib.FederationClient,
 ) util.JSONResponse {
-	request, errResp := gomatrixserverlib.VerifyHTTPRequest(req, now, cfg.Matrix.ServerName, keys)
-	if request == nil {
-		return errResp
-	}
 
 	t := txnReq{
 		query:      query,
@@ -50,7 +45,7 @@ func Send(
 
 	resp, err := t.processTransaction()
 	if err != nil {
-		return httputil.LogThenError(req, err)
+		return httputil.LogThenError(httpReq, err)
 	}
 
 	return util.JSONResponse{