From 3b9222e8f74e97081743fbbe264743a3c4e89566 Mon Sep 17 00:00:00 2001 From: Kegsay Date: Tue, 23 May 2017 17:43:05 +0100 Subject: [PATCH] Glue together devices and auth with the current HTTP code (#117) - Renamed `clientapi/auth/types` to `clientapi/auth/authtypes` for the same horrible namespace clashing reasons as `storage`. - Factored out `makeAPI` to `common`. - Added in `makeAuthAPI`. --- .../dendrite/clientapi/auth/auth.go | 24 +++++----- .../auth/{types => authtypes}/account.go | 2 +- .../auth/{types => authtypes}/device.go | 2 +- .../auth/{types => authtypes}/logintypes.go | 2 +- .../auth/storage/accounts/accounts_table.go | 10 ++--- .../auth/storage/accounts/storage.go | 6 +-- .../clientapi/auth/storage/devices/storage.go | 16 ++++++- .../dendrite/clientapi/routing/routing.go | 44 +++++++++---------- .../dendrite/clientapi/writers/createroom.go | 15 +++---- .../dendrite/clientapi/writers/register.go | 16 +++---- .../dendrite/clientapi/writers/sendevent.go | 11 ++--- .../cmd/dendrite-client-api-server/main.go | 7 ++- .../cmd/dendrite-sync-api-server/main.go | 9 +++- .../matrix-org/dendrite/common/httpapi.go | 28 ++++++++++++ .../dendrite/syncapi/routing/routing.go | 16 +++---- .../dendrite/syncapi/sync/requestpool.go | 9 ++-- 16 files changed, 130 insertions(+), 87 deletions(-) rename src/github.com/matrix-org/dendrite/clientapi/auth/{types => authtypes}/account.go (98%) rename src/github.com/matrix-org/dendrite/clientapi/auth/{types => authtypes}/device.go (97%) rename src/github.com/matrix-org/dendrite/clientapi/auth/{types => authtypes}/logintypes.go (92%) create mode 100644 src/github.com/matrix-org/dendrite/common/httpapi.go diff --git a/src/github.com/matrix-org/dendrite/clientapi/auth/auth.go b/src/github.com/matrix-org/dendrite/clientapi/auth/auth.go index c6c54d78..4e8c5a57 100644 --- a/src/github.com/matrix-org/dendrite/clientapi/auth/auth.go +++ b/src/github.com/matrix-org/dendrite/clientapi/auth/auth.go @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +// Package auth implements authentication checks and storage. package auth import ( @@ -19,28 +20,31 @@ import ( "net/http" "strings" + "github.com/matrix-org/dendrite/clientapi/auth/authtypes" + "github.com/matrix-org/dendrite/clientapi/auth/storage/devices" "github.com/matrix-org/dendrite/clientapi/jsonerror" "github.com/matrix-org/util" ) // VerifyAccessToken verifies that an access token was supplied in the given HTTP request -// and returns the user ID it corresponds to. Returns resErr (an error response which can be +// and returns the device it corresponds to. Returns resErr (an error response which can be // sent to the client) if the token is invalid or there was a problem querying the database. -func VerifyAccessToken(req *http.Request) (userID string, resErr *util.JSONResponse) { - token, tokenErr := extractAccessToken(req) - if tokenErr != nil { +func VerifyAccessToken(req *http.Request, deviceDB *devices.Database) (device *authtypes.Device, resErr *util.JSONResponse) { + token, err := extractAccessToken(req) + if err != nil { resErr = &util.JSONResponse{ Code: 401, - JSON: jsonerror.MissingToken(tokenErr.Error()), + JSON: jsonerror.MissingToken(err.Error()), } return } - if token == "fail" { - res := util.ErrorResponse(fmt.Errorf("Fatal error")) - resErr = &res + device, err = deviceDB.GetDeviceByAccessToken(token) + if err != nil { + resErr = &util.JSONResponse{ + Code: 500, + JSON: jsonerror.Unknown("Failed to check access token"), + } } - // TODO: Check the token against the database - userID = token return } diff --git a/src/github.com/matrix-org/dendrite/clientapi/auth/types/account.go b/src/github.com/matrix-org/dendrite/clientapi/auth/authtypes/account.go similarity index 98% rename from src/github.com/matrix-org/dendrite/clientapi/auth/types/account.go rename to src/github.com/matrix-org/dendrite/clientapi/auth/authtypes/account.go index 21b10e03..ed33d0b5 100644 --- a/src/github.com/matrix-org/dendrite/clientapi/auth/types/account.go +++ b/src/github.com/matrix-org/dendrite/clientapi/auth/authtypes/account.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package types +package authtypes import ( "github.com/matrix-org/gomatrixserverlib" diff --git a/src/github.com/matrix-org/dendrite/clientapi/auth/types/device.go b/src/github.com/matrix-org/dendrite/clientapi/auth/authtypes/device.go similarity index 97% rename from src/github.com/matrix-org/dendrite/clientapi/auth/types/device.go rename to src/github.com/matrix-org/dendrite/clientapi/auth/authtypes/device.go index 72352cde..4feceada 100644 --- a/src/github.com/matrix-org/dendrite/clientapi/auth/types/device.go +++ b/src/github.com/matrix-org/dendrite/clientapi/auth/authtypes/device.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package types +package authtypes // Device represents a client's device (mobile, web, etc) type Device struct { diff --git a/src/github.com/matrix-org/dendrite/clientapi/auth/types/logintypes.go b/src/github.com/matrix-org/dendrite/clientapi/auth/authtypes/logintypes.go similarity index 92% rename from src/github.com/matrix-org/dendrite/clientapi/auth/types/logintypes.go rename to src/github.com/matrix-org/dendrite/clientapi/auth/authtypes/logintypes.go index 42cb477a..6a90b295 100644 --- a/src/github.com/matrix-org/dendrite/clientapi/auth/types/logintypes.go +++ b/src/github.com/matrix-org/dendrite/clientapi/auth/authtypes/logintypes.go @@ -1,4 +1,4 @@ -package types +package authtypes // LoginType are specified by http://matrix.org/docs/spec/client_server/r0.2.0.html#login-types type LoginType string diff --git a/src/github.com/matrix-org/dendrite/clientapi/auth/storage/accounts/accounts_table.go b/src/github.com/matrix-org/dendrite/clientapi/auth/storage/accounts/accounts_table.go index dc5b5196..ad34a400 100644 --- a/src/github.com/matrix-org/dendrite/clientapi/auth/storage/accounts/accounts_table.go +++ b/src/github.com/matrix-org/dendrite/clientapi/auth/storage/accounts/accounts_table.go @@ -19,7 +19,7 @@ import ( "fmt" "time" - "github.com/matrix-org/dendrite/clientapi/auth/types" + "github.com/matrix-org/dendrite/clientapi/auth/authtypes" "github.com/matrix-org/gomatrixserverlib" ) @@ -76,10 +76,10 @@ func (s *accountsStatements) prepare(db *sql.DB, server gomatrixserverlib.Server // insertAccount creates a new account. 'hash' should be the password hash for this account. If it is missing, // this account will be passwordless. Returns an error if this account already exists. Returns the account // on success. -func (s *accountsStatements) insertAccount(localpart, hash string) (acc *types.Account, err error) { +func (s *accountsStatements) insertAccount(localpart, hash string) (acc *authtypes.Account, err error) { createdTimeMS := time.Now().UnixNano() / 1000000 if _, err = s.insertAccountStmt.Exec(localpart, createdTimeMS, hash); err == nil { - acc = &types.Account{ + acc = &authtypes.Account{ Localpart: localpart, UserID: makeUserID(localpart, s.serverName), ServerName: s.serverName, @@ -93,8 +93,8 @@ func (s *accountsStatements) selectPasswordHash(localpart string) (hash string, return } -func (s *accountsStatements) selectAccountByLocalpart(localpart string) (*types.Account, error) { - var acc types.Account +func (s *accountsStatements) selectAccountByLocalpart(localpart string) (*authtypes.Account, error) { + var acc authtypes.Account err := s.selectAccountByLocalpartStmt.QueryRow(localpart).Scan(&acc.Localpart) if err != nil { acc.UserID = makeUserID(localpart, s.serverName) diff --git a/src/github.com/matrix-org/dendrite/clientapi/auth/storage/accounts/storage.go b/src/github.com/matrix-org/dendrite/clientapi/auth/storage/accounts/storage.go index bb08870c..5dbd4943 100644 --- a/src/github.com/matrix-org/dendrite/clientapi/auth/storage/accounts/storage.go +++ b/src/github.com/matrix-org/dendrite/clientapi/auth/storage/accounts/storage.go @@ -16,7 +16,7 @@ package accounts import ( "database/sql" - "github.com/matrix-org/dendrite/clientapi/auth/types" + "github.com/matrix-org/dendrite/clientapi/auth/authtypes" "github.com/matrix-org/gomatrixserverlib" "golang.org/x/crypto/bcrypt" // Import the postgres database driver. @@ -45,7 +45,7 @@ func NewDatabase(dataSourceName string, serverName gomatrixserverlib.ServerName) // GetAccountByPassword returns the account associated with the given localpart and password. // Returns sql.ErrNoRows if no account exists which matches the given credentials. -func (d *Database) GetAccountByPassword(localpart, plaintextPassword string) (*types.Account, error) { +func (d *Database) GetAccountByPassword(localpart, plaintextPassword string) (*authtypes.Account, error) { hash, err := d.accounts.selectPasswordHash(localpart) if err != nil { return nil, err @@ -58,7 +58,7 @@ func (d *Database) GetAccountByPassword(localpart, plaintextPassword string) (*t // CreateAccount makes a new account with the given login name and password. If no password is supplied, // the account will be a passwordless account. -func (d *Database) CreateAccount(localpart, plaintextPassword string) (*types.Account, error) { +func (d *Database) CreateAccount(localpart, plaintextPassword string) (*authtypes.Account, error) { hash, err := hashPassword(plaintextPassword) if err != nil { return nil, err diff --git a/src/github.com/matrix-org/dendrite/clientapi/auth/storage/devices/storage.go b/src/github.com/matrix-org/dendrite/clientapi/auth/storage/devices/storage.go index 842d6bbe..ef5fe495 100644 --- a/src/github.com/matrix-org/dendrite/clientapi/auth/storage/devices/storage.go +++ b/src/github.com/matrix-org/dendrite/clientapi/auth/storage/devices/storage.go @@ -14,12 +14,24 @@ package devices +import ( + "github.com/matrix-org/dendrite/clientapi/auth/authtypes" +) + // Database represents a device database. type Database struct { // TODO } // NewDatabase creates a new device database -func NewDatabase() *Database { - return &Database{} +func NewDatabase(dataSource string) (*Database, error) { + return &Database{}, nil +} + +// GetDeviceByAccessToken returns the device matching the given access token. +func (d *Database) GetDeviceByAccessToken(token string) (*authtypes.Device, error) { + // TODO: Actual implementation + return &authtypes.Device{ + UserID: token, + }, nil } diff --git a/src/github.com/matrix-org/dendrite/clientapi/routing/routing.go b/src/github.com/matrix-org/dendrite/clientapi/routing/routing.go index a1921c0c..a7d47c49 100644 --- a/src/github.com/matrix-org/dendrite/clientapi/routing/routing.go +++ b/src/github.com/matrix-org/dendrite/clientapi/routing/routing.go @@ -19,11 +19,14 @@ import ( "net/http" "github.com/gorilla/mux" + "github.com/matrix-org/dendrite/clientapi/auth/authtypes" "github.com/matrix-org/dendrite/clientapi/auth/storage/accounts" + "github.com/matrix-org/dendrite/clientapi/auth/storage/devices" "github.com/matrix-org/dendrite/clientapi/config" "github.com/matrix-org/dendrite/clientapi/producers" "github.com/matrix-org/dendrite/clientapi/readers" "github.com/matrix-org/dendrite/clientapi/writers" + "github.com/matrix-org/dendrite/common" "github.com/matrix-org/dendrite/roomserver/api" "github.com/matrix-org/util" "github.com/prometheus/client_golang/prometheus" @@ -33,49 +36,50 @@ const pathPrefixR0 = "/_matrix/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. -func Setup(servMux *http.ServeMux, httpClient *http.Client, cfg config.ClientAPI, producer *producers.RoomserverProducer, queryAPI api.RoomserverQueryAPI, accountDB *accounts.Database) { +func Setup(servMux *http.ServeMux, httpClient *http.Client, cfg config.ClientAPI, producer *producers.RoomserverProducer, + queryAPI api.RoomserverQueryAPI, accountDB *accounts.Database, deviceDB *devices.Database) { apiMux := mux.NewRouter() r0mux := apiMux.PathPrefix(pathPrefixR0).Subrouter() r0mux.Handle("/createRoom", - makeAPI("createRoom", func(req *http.Request) util.JSONResponse { - return writers.CreateRoom(req, cfg, producer) + common.MakeAuthAPI("createRoom", deviceDB, func(req *http.Request, device *authtypes.Device) util.JSONResponse { + return writers.CreateRoom(req, device, cfg, producer) }), ) r0mux.Handle("/rooms/{roomID}/send/{eventType}/{txnID}", - makeAPI("send_message", func(req *http.Request) util.JSONResponse { + common.MakeAuthAPI("send_message", deviceDB, func(req *http.Request, device *authtypes.Device) util.JSONResponse { vars := mux.Vars(req) - return writers.SendEvent(req, vars["roomID"], vars["eventType"], vars["txnID"], nil, cfg, queryAPI, producer) + return writers.SendEvent(req, device, vars["roomID"], vars["eventType"], vars["txnID"], nil, cfg, queryAPI, producer) }), ) r0mux.Handle("/rooms/{roomID}/state/{eventType}", - makeAPI("send_message", func(req *http.Request) util.JSONResponse { + common.MakeAuthAPI("send_message", deviceDB, func(req *http.Request, device *authtypes.Device) util.JSONResponse { vars := mux.Vars(req) emptyString := "" - return writers.SendEvent(req, vars["roomID"], vars["eventType"], vars["txnID"], &emptyString, cfg, queryAPI, producer) + return writers.SendEvent(req, device, vars["roomID"], vars["eventType"], vars["txnID"], &emptyString, cfg, queryAPI, producer) }), ) r0mux.Handle("/rooms/{roomID}/state/{eventType}/{stateKey}", - makeAPI("send_message", func(req *http.Request) util.JSONResponse { + common.MakeAuthAPI("send_message", deviceDB, func(req *http.Request, device *authtypes.Device) util.JSONResponse { vars := mux.Vars(req) stateKey := vars["stateKey"] - return writers.SendEvent(req, vars["roomID"], vars["eventType"], vars["txnID"], &stateKey, cfg, queryAPI, producer) + return writers.SendEvent(req, device, vars["roomID"], vars["eventType"], vars["txnID"], &stateKey, cfg, queryAPI, producer) }), ) - r0mux.Handle("/register", makeAPI("register", func(req *http.Request) util.JSONResponse { + r0mux.Handle("/register", common.MakeAPI("register", func(req *http.Request) util.JSONResponse { return writers.Register(req, accountDB) })) // Stub endpoints required by Riot r0mux.Handle("/login", - makeAPI("login", func(req *http.Request) util.JSONResponse { + common.MakeAPI("login", func(req *http.Request) util.JSONResponse { return readers.Login(req, cfg) }), ) r0mux.Handle("/pushrules/", - makeAPI("push_rules", func(req *http.Request) util.JSONResponse { + common.MakeAPI("push_rules", func(req *http.Request) util.JSONResponse { // TODO: Implement push rules API res := json.RawMessage(`{ "global": { @@ -94,7 +98,7 @@ func Setup(servMux *http.ServeMux, httpClient *http.Client, cfg config.ClientAPI ) r0mux.Handle("/user/{userID}/filter", - makeAPI("make_filter", func(req *http.Request) util.JSONResponse { + common.MakeAPI("make_filter", func(req *http.Request) util.JSONResponse { // TODO: Persist filter and return filter ID return util.JSONResponse{ Code: 200, @@ -104,7 +108,7 @@ func Setup(servMux *http.ServeMux, httpClient *http.Client, cfg config.ClientAPI ) r0mux.Handle("/user/{userID}/filter/{filterID}", - makeAPI("filter", func(req *http.Request) util.JSONResponse { + common.MakeAPI("filter", func(req *http.Request) util.JSONResponse { // TODO: Retrieve filter based on ID return util.JSONResponse{ Code: 200, @@ -116,7 +120,7 @@ func Setup(servMux *http.ServeMux, httpClient *http.Client, cfg config.ClientAPI // Riot user settings r0mux.Handle("/profile/{userID}", - makeAPI("profile", func(req *http.Request) util.JSONResponse { + common.MakeAPI("profile", func(req *http.Request) util.JSONResponse { // TODO: Get profile data for user ID return util.JSONResponse{ Code: 200, @@ -126,7 +130,7 @@ func Setup(servMux *http.ServeMux, httpClient *http.Client, cfg config.ClientAPI ) r0mux.Handle("/account/3pid", - makeAPI("account_3pid", func(req *http.Request) util.JSONResponse { + common.MakeAPI("account_3pid", func(req *http.Request) util.JSONResponse { // TODO: Get 3pid data for user ID res := json.RawMessage(`{"threepids":[]}`) return util.JSONResponse{ @@ -138,7 +142,7 @@ func Setup(servMux *http.ServeMux, httpClient *http.Client, cfg config.ClientAPI // Riot logs get flooded unless this is handled r0mux.Handle("/presence/{userID}/status", - makeAPI("presence", func(req *http.Request) util.JSONResponse { + common.MakeAPI("presence", func(req *http.Request) util.JSONResponse { // TODO: Set presence (probably the responsibility of a presence server not clientapi) return util.JSONResponse{ Code: 200, @@ -150,9 +154,3 @@ func Setup(servMux *http.ServeMux, httpClient *http.Client, cfg config.ClientAPI servMux.Handle("/metrics", prometheus.Handler()) servMux.Handle("/api/", http.StripPrefix("/api", apiMux)) } - -// make a util.JSONRequestHandler function into an http.Handler. -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/clientapi/writers/createroom.go b/src/github.com/matrix-org/dendrite/clientapi/writers/createroom.go index e14c56fb..a2501700 100644 --- a/src/github.com/matrix-org/dendrite/clientapi/writers/createroom.go +++ b/src/github.com/matrix-org/dendrite/clientapi/writers/createroom.go @@ -22,7 +22,7 @@ import ( "time" log "github.com/Sirupsen/logrus" - "github.com/matrix-org/dendrite/clientapi/auth" + "github.com/matrix-org/dendrite/clientapi/auth/authtypes" "github.com/matrix-org/dendrite/clientapi/config" "github.com/matrix-org/dendrite/clientapi/events" "github.com/matrix-org/dendrite/clientapi/httputil" @@ -91,22 +91,19 @@ type fledglingEvent struct { } // CreateRoom implements /createRoom -func CreateRoom(req *http.Request, cfg config.ClientAPI, producer *producers.RoomserverProducer) util.JSONResponse { +func CreateRoom(req *http.Request, device *authtypes.Device, cfg config.ClientAPI, producer *producers.RoomserverProducer) util.JSONResponse { // TODO: Check room ID doesn't clash with an existing one, and we // probably shouldn't be using pseudo-random strings, maybe GUIDs? roomID := fmt.Sprintf("!%s:%s", util.RandomString(16), cfg.ServerName) - return createRoom(req, cfg, roomID, producer) + return createRoom(req, device, cfg, roomID, producer) } // createRoom implements /createRoom -func createRoom(req *http.Request, cfg config.ClientAPI, roomID string, producer *producers.RoomserverProducer) util.JSONResponse { +func createRoom(req *http.Request, device *authtypes.Device, cfg config.ClientAPI, roomID string, producer *producers.RoomserverProducer) util.JSONResponse { logger := util.GetLogger(req.Context()) - userID, resErr := auth.VerifyAccessToken(req) - if resErr != nil { - return *resErr - } + userID := device.UserID var r createRoomRequest - resErr = httputil.UnmarshalJSONRequest(req, &r) + resErr := httputil.UnmarshalJSONRequest(req, &r) if resErr != nil { return *resErr } diff --git a/src/github.com/matrix-org/dendrite/clientapi/writers/register.go b/src/github.com/matrix-org/dendrite/clientapi/writers/register.go index 753fb1a0..5191a719 100644 --- a/src/github.com/matrix-org/dendrite/clientapi/writers/register.go +++ b/src/github.com/matrix-org/dendrite/clientapi/writers/register.go @@ -5,8 +5,8 @@ import ( "net/http" log "github.com/Sirupsen/logrus" + "github.com/matrix-org/dendrite/clientapi/auth/authtypes" "github.com/matrix-org/dendrite/clientapi/auth/storage/accounts" - "github.com/matrix-org/dendrite/clientapi/auth/types" "github.com/matrix-org/dendrite/clientapi/httputil" "github.com/matrix-org/dendrite/clientapi/jsonerror" "github.com/matrix-org/gomatrixserverlib" @@ -34,15 +34,15 @@ type registerRequest struct { } type authDict struct { - Type types.LoginType `json:"type"` - Session string `json:"session"` + Type authtypes.LoginType `json:"type"` + Session string `json:"session"` // TODO: Lots of custom keys depending on the type } // http://matrix.org/speculator/spec/HEAD/client_server/unstable.html#user-interactive-authentication-api type userInteractiveResponse struct { Flows []authFlow `json:"flows"` - Completed []types.LoginType `json:"completed"` + Completed []authtypes.LoginType `json:"completed"` Params map[string]interface{} `json:"params"` Session string `json:"session"` } @@ -50,12 +50,12 @@ type userInteractiveResponse struct { // authFlow represents one possible way that the client can authenticate a request. // http://matrix.org/speculator/spec/HEAD/client_server/unstable.html#user-interactive-authentication-api type authFlow struct { - Stages []types.LoginType `json:"stages"` + Stages []authtypes.LoginType `json:"stages"` } func newUserInteractiveResponse(sessionID string, fs []authFlow) userInteractiveResponse { return userInteractiveResponse{ - fs, []types.LoginType{}, make(map[string]interface{}), sessionID, + fs, []authtypes.LoginType{}, make(map[string]interface{}), sessionID, } } @@ -119,7 +119,7 @@ func Register(req *http.Request, accountDB *accounts.Database) util.JSONResponse // TODO: Hard-coded 'dummy' auth for now with a bogus session ID. // Server admins should be able to change things around (eg enable captcha) JSON: newUserInteractiveResponse("totallyuniquesessionid", []authFlow{ - {[]types.LoginType{types.LoginTypeDummy}}, + {[]authtypes.LoginType{authtypes.LoginTypeDummy}}, }), } } @@ -129,7 +129,7 @@ func Register(req *http.Request, accountDB *accounts.Database) util.JSONResponse // TODO: email / msisdn / recaptcha auth types. switch r.Auth.Type { - case types.LoginTypeDummy: + case authtypes.LoginTypeDummy: // there is nothing to do return completeRegistration(accountDB, r.Username, r.Password) default: diff --git a/src/github.com/matrix-org/dendrite/clientapi/writers/sendevent.go b/src/github.com/matrix-org/dendrite/clientapi/writers/sendevent.go index e4cd3e0d..ec65fadb 100644 --- a/src/github.com/matrix-org/dendrite/clientapi/writers/sendevent.go +++ b/src/github.com/matrix-org/dendrite/clientapi/writers/sendevent.go @@ -20,7 +20,7 @@ import ( "fmt" "time" - "github.com/matrix-org/dendrite/clientapi/auth" + "github.com/matrix-org/dendrite/clientapi/auth/authtypes" "github.com/matrix-org/dendrite/clientapi/config" "github.com/matrix-org/dendrite/clientapi/httputil" "github.com/matrix-org/dendrite/clientapi/jsonerror" @@ -39,14 +39,11 @@ type sendEventResponse struct { // SendEvent implements: // /rooms/{roomID}/send/{eventType}/{txnID} // /rooms/{roomID}/state/{eventType}/{stateKey} -func SendEvent(req *http.Request, roomID, eventType, txnID string, stateKey *string, cfg config.ClientAPI, queryAPI api.RoomserverQueryAPI, producer *producers.RoomserverProducer) util.JSONResponse { +func SendEvent(req *http.Request, device *authtypes.Device, roomID, eventType, txnID string, stateKey *string, cfg config.ClientAPI, queryAPI api.RoomserverQueryAPI, producer *producers.RoomserverProducer) util.JSONResponse { // parse the incoming http request - userID, resErr := auth.VerifyAccessToken(req) - if resErr != nil { - return *resErr - } + userID := device.UserID var r map[string]interface{} // must be a JSON object - resErr = httputil.UnmarshalJSONRequest(req, &r) + resErr := httputil.UnmarshalJSONRequest(req, &r) if resErr != nil { return *resErr } diff --git a/src/github.com/matrix-org/dendrite/cmd/dendrite-client-api-server/main.go b/src/github.com/matrix-org/dendrite/cmd/dendrite-client-api-server/main.go index a2b9c31d..c75ca323 100644 --- a/src/github.com/matrix-org/dendrite/cmd/dendrite-client-api-server/main.go +++ b/src/github.com/matrix-org/dendrite/cmd/dendrite-client-api-server/main.go @@ -20,6 +20,7 @@ import ( "strings" "github.com/matrix-org/dendrite/clientapi/auth/storage/accounts" + "github.com/matrix-org/dendrite/clientapi/auth/storage/devices" "github.com/matrix-org/dendrite/clientapi/config" "github.com/matrix-org/dendrite/clientapi/producers" "github.com/matrix-org/dendrite/clientapi/routing" @@ -85,7 +86,11 @@ func main() { if err != nil { log.Panicf("Failed to setup account database(%s): %s", accountDataSource, err.Error()) } + deviceDB, err := devices.NewDatabase(accountDataSource) + if err != nil { + log.Panicf("Failed to setup device database(%s): %s", accountDataSource, err.Error()) + } - routing.Setup(http.DefaultServeMux, http.DefaultClient, cfg, roomserverProducer, queryAPI, accountDB) + routing.Setup(http.DefaultServeMux, http.DefaultClient, cfg, roomserverProducer, queryAPI, accountDB, deviceDB) log.Fatal(http.ListenAndServe(bindAddr, nil)) } diff --git a/src/github.com/matrix-org/dendrite/cmd/dendrite-sync-api-server/main.go b/src/github.com/matrix-org/dendrite/cmd/dendrite-sync-api-server/main.go index 5d1bf8e2..090c0d88 100644 --- a/src/github.com/matrix-org/dendrite/cmd/dendrite-sync-api-server/main.go +++ b/src/github.com/matrix-org/dendrite/cmd/dendrite-sync-api-server/main.go @@ -20,6 +20,7 @@ import ( "net/http" "os" + "github.com/matrix-org/dendrite/clientapi/auth/storage/devices" "github.com/matrix-org/dendrite/common" "github.com/matrix-org/dendrite/syncapi/config" "github.com/matrix-org/dendrite/syncapi/consumers" @@ -72,6 +73,12 @@ func main() { log.Panicf("startup: failed to create sync server database with data source %s : %s", cfg.DataSource, err) } + // TODO: DO NOT USE THIS DATA SOURCE (it's the sync one, not devices!) + deviceDB, err := devices.NewDatabase(cfg.DataSource) + if err != nil { + log.Panicf("startup: failed to create device database with data source %s : %s", cfg.DataSource, err) + } + pos, err := db.SyncStreamPosition() if err != nil { log.Panicf("startup: failed to get latest sync stream position : %s", err) @@ -90,6 +97,6 @@ func main() { } log.Info("Starting sync server on ", *bindAddr) - routing.SetupSyncServerListeners(http.DefaultServeMux, http.DefaultClient, *cfg, sync.NewRequestPool(db, n)) + routing.SetupSyncServerListeners(http.DefaultServeMux, http.DefaultClient, *cfg, sync.NewRequestPool(db, n), deviceDB) log.Fatal(http.ListenAndServe(*bindAddr, nil)) } diff --git a/src/github.com/matrix-org/dendrite/common/httpapi.go b/src/github.com/matrix-org/dendrite/common/httpapi.go new file mode 100644 index 00000000..0ab33925 --- /dev/null +++ b/src/github.com/matrix-org/dendrite/common/httpapi.go @@ -0,0 +1,28 @@ +package common + +import ( + "github.com/matrix-org/dendrite/clientapi/auth" + "github.com/matrix-org/dendrite/clientapi/auth/authtypes" + "github.com/matrix-org/dendrite/clientapi/auth/storage/devices" + "github.com/matrix-org/util" + "github.com/prometheus/client_golang/prometheus" + "net/http" +) + +// MakeAuthAPI turns a util.JSONRequestHandler function into an http.Handler which checks the access token in the request. +func MakeAuthAPI(metricsName string, deviceDB *devices.Database, f func(*http.Request, *authtypes.Device) util.JSONResponse) http.Handler { + h := util.NewJSONRequestHandler(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)) +} + +// MakeAPI turns a util.JSONRequestHandler function into an http.Handler. +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/syncapi/routing/routing.go b/src/github.com/matrix-org/dendrite/syncapi/routing/routing.go index 7c7be983..ad09cd17 100644 --- a/src/github.com/matrix-org/dendrite/syncapi/routing/routing.go +++ b/src/github.com/matrix-org/dendrite/syncapi/routing/routing.go @@ -18,6 +18,9 @@ import ( "net/http" "github.com/gorilla/mux" + "github.com/matrix-org/dendrite/clientapi/auth/authtypes" + "github.com/matrix-org/dendrite/clientapi/auth/storage/devices" + "github.com/matrix-org/dendrite/common" "github.com/matrix-org/dendrite/syncapi/config" "github.com/matrix-org/dendrite/syncapi/sync" "github.com/matrix-org/util" @@ -27,17 +30,12 @@ import ( const pathPrefixR0 = "/_matrix/client/r0" // SetupSyncServerListeners configures the given mux with sync-server listeners -func SetupSyncServerListeners(servMux *http.ServeMux, httpClient *http.Client, cfg config.Sync, srp *sync.RequestPool) { +func SetupSyncServerListeners(servMux *http.ServeMux, httpClient *http.Client, cfg config.Sync, srp *sync.RequestPool, deviceDB *devices.Database) { apiMux := mux.NewRouter() r0mux := apiMux.PathPrefix(pathPrefixR0).Subrouter() - r0mux.Handle("/sync", make("sync", util.NewJSONRequestHandler(func(req *http.Request) util.JSONResponse { - return srp.OnIncomingSyncRequest(req) - }))) + r0mux.Handle("/sync", common.MakeAuthAPI("sync", deviceDB, func(req *http.Request, device *authtypes.Device) util.JSONResponse { + return srp.OnIncomingSyncRequest(req, device) + })) servMux.Handle("/metrics", prometheus.Handler()) servMux.Handle("/api/", http.StripPrefix("/api", apiMux)) } - -// make a util.JSONRequestHandler into an http.Handler -func make(metricsName string, h util.JSONRequestHandler) http.Handler { - return prometheus.InstrumentHandler(metricsName, util.MakeJSONAPI(h)) -} diff --git a/src/github.com/matrix-org/dendrite/syncapi/sync/requestpool.go b/src/github.com/matrix-org/dendrite/syncapi/sync/requestpool.go index 8e9affb6..08bad334 100644 --- a/src/github.com/matrix-org/dendrite/syncapi/sync/requestpool.go +++ b/src/github.com/matrix-org/dendrite/syncapi/sync/requestpool.go @@ -19,7 +19,7 @@ import ( "time" log "github.com/Sirupsen/logrus" - "github.com/matrix-org/dendrite/clientapi/auth" + "github.com/matrix-org/dendrite/clientapi/auth/authtypes" "github.com/matrix-org/dendrite/clientapi/httputil" "github.com/matrix-org/dendrite/clientapi/jsonerror" "github.com/matrix-org/dendrite/syncapi/storage" @@ -41,13 +41,10 @@ func NewRequestPool(db *storage.SyncServerDatabase, n *Notifier) *RequestPool { // OnIncomingSyncRequest is called when a client makes a /sync request. This function MUST be // called in a dedicated goroutine for this request. This function will block the goroutine // until a response is ready, or it times out. -func (rp *RequestPool) OnIncomingSyncRequest(req *http.Request) util.JSONResponse { +func (rp *RequestPool) OnIncomingSyncRequest(req *http.Request, device *authtypes.Device) util.JSONResponse { // Extract values from request logger := util.GetLogger(req.Context()) - userID, resErr := auth.VerifyAccessToken(req) - if resErr != nil { - return *resErr - } + userID := device.UserID syncReq, err := newSyncRequest(req, userID) if err != nil { return util.JSONResponse{