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`.
This commit is contained in:
parent
309300a744
commit
3b9222e8f7
|
@ -12,6 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
// Package auth implements authentication checks and storage.
|
||||||
package auth
|
package auth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -19,28 +20,31 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"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/dendrite/clientapi/jsonerror"
|
||||||
"github.com/matrix-org/util"
|
"github.com/matrix-org/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// VerifyAccessToken verifies that an access token was supplied in the given HTTP request
|
// 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.
|
// 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) {
|
func VerifyAccessToken(req *http.Request, deviceDB *devices.Database) (device *authtypes.Device, resErr *util.JSONResponse) {
|
||||||
token, tokenErr := extractAccessToken(req)
|
token, err := extractAccessToken(req)
|
||||||
if tokenErr != nil {
|
if err != nil {
|
||||||
resErr = &util.JSONResponse{
|
resErr = &util.JSONResponse{
|
||||||
Code: 401,
|
Code: 401,
|
||||||
JSON: jsonerror.MissingToken(tokenErr.Error()),
|
JSON: jsonerror.MissingToken(err.Error()),
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if token == "fail" {
|
device, err = deviceDB.GetDeviceByAccessToken(token)
|
||||||
res := util.ErrorResponse(fmt.Errorf("Fatal error"))
|
if err != nil {
|
||||||
resErr = &res
|
resErr = &util.JSONResponse{
|
||||||
|
Code: 500,
|
||||||
|
JSON: jsonerror.Unknown("Failed to check access token"),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// TODO: Check the token against the database
|
|
||||||
userID = token
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
package types
|
package authtypes
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
|
@ -12,7 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
package types
|
package authtypes
|
||||||
|
|
||||||
// Device represents a client's device (mobile, web, etc)
|
// Device represents a client's device (mobile, web, etc)
|
||||||
type Device struct {
|
type Device struct {
|
|
@ -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
|
// LoginType are specified by http://matrix.org/docs/spec/client_server/r0.2.0.html#login-types
|
||||||
type LoginType string
|
type LoginType string
|
|
@ -19,7 +19,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/clientapi/auth/types"
|
"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"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,
|
// 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
|
// this account will be passwordless. Returns an error if this account already exists. Returns the account
|
||||||
// on success.
|
// 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
|
createdTimeMS := time.Now().UnixNano() / 1000000
|
||||||
if _, err = s.insertAccountStmt.Exec(localpart, createdTimeMS, hash); err == nil {
|
if _, err = s.insertAccountStmt.Exec(localpart, createdTimeMS, hash); err == nil {
|
||||||
acc = &types.Account{
|
acc = &authtypes.Account{
|
||||||
Localpart: localpart,
|
Localpart: localpart,
|
||||||
UserID: makeUserID(localpart, s.serverName),
|
UserID: makeUserID(localpart, s.serverName),
|
||||||
ServerName: s.serverName,
|
ServerName: s.serverName,
|
||||||
|
@ -93,8 +93,8 @@ func (s *accountsStatements) selectPasswordHash(localpart string) (hash string,
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *accountsStatements) selectAccountByLocalpart(localpart string) (*types.Account, error) {
|
func (s *accountsStatements) selectAccountByLocalpart(localpart string) (*authtypes.Account, error) {
|
||||||
var acc types.Account
|
var acc authtypes.Account
|
||||||
err := s.selectAccountByLocalpartStmt.QueryRow(localpart).Scan(&acc.Localpart)
|
err := s.selectAccountByLocalpartStmt.QueryRow(localpart).Scan(&acc.Localpart)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
acc.UserID = makeUserID(localpart, s.serverName)
|
acc.UserID = makeUserID(localpart, s.serverName)
|
||||||
|
|
|
@ -16,7 +16,7 @@ package accounts
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"github.com/matrix-org/dendrite/clientapi/auth/types"
|
"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
// Import the postgres database driver.
|
// 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.
|
// GetAccountByPassword returns the account associated with the given localpart and password.
|
||||||
// Returns sql.ErrNoRows if no account exists which matches the given credentials.
|
// 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)
|
hash, err := d.accounts.selectPasswordHash(localpart)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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,
|
// CreateAccount makes a new account with the given login name and password. If no password is supplied,
|
||||||
// the account will be a passwordless account.
|
// 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)
|
hash, err := hashPassword(plaintextPassword)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -14,12 +14,24 @@
|
||||||
|
|
||||||
package devices
|
package devices
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
|
||||||
|
)
|
||||||
|
|
||||||
// Database represents a device database.
|
// Database represents a device database.
|
||||||
type Database struct {
|
type Database struct {
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDatabase creates a new device database
|
// NewDatabase creates a new device database
|
||||||
func NewDatabase() *Database {
|
func NewDatabase(dataSource string) (*Database, error) {
|
||||||
return &Database{}
|
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
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,11 +19,14 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"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/accounts"
|
||||||
|
"github.com/matrix-org/dendrite/clientapi/auth/storage/devices"
|
||||||
"github.com/matrix-org/dendrite/clientapi/config"
|
"github.com/matrix-org/dendrite/clientapi/config"
|
||||||
"github.com/matrix-org/dendrite/clientapi/producers"
|
"github.com/matrix-org/dendrite/clientapi/producers"
|
||||||
"github.com/matrix-org/dendrite/clientapi/readers"
|
"github.com/matrix-org/dendrite/clientapi/readers"
|
||||||
"github.com/matrix-org/dendrite/clientapi/writers"
|
"github.com/matrix-org/dendrite/clientapi/writers"
|
||||||
|
"github.com/matrix-org/dendrite/common"
|
||||||
"github.com/matrix-org/dendrite/roomserver/api"
|
"github.com/matrix-org/dendrite/roomserver/api"
|
||||||
"github.com/matrix-org/util"
|
"github.com/matrix-org/util"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"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
|
// Setup registers HTTP handlers with the given ServeMux. It also supplies the given http.Client
|
||||||
// to clients which need to make outbound HTTP requests.
|
// 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()
|
apiMux := mux.NewRouter()
|
||||||
r0mux := apiMux.PathPrefix(pathPrefixR0).Subrouter()
|
r0mux := apiMux.PathPrefix(pathPrefixR0).Subrouter()
|
||||||
r0mux.Handle("/createRoom",
|
r0mux.Handle("/createRoom",
|
||||||
makeAPI("createRoom", func(req *http.Request) util.JSONResponse {
|
common.MakeAuthAPI("createRoom", deviceDB, func(req *http.Request, device *authtypes.Device) util.JSONResponse {
|
||||||
return writers.CreateRoom(req, cfg, producer)
|
return writers.CreateRoom(req, device, cfg, producer)
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
r0mux.Handle("/rooms/{roomID}/send/{eventType}/{txnID}",
|
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)
|
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}",
|
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)
|
vars := mux.Vars(req)
|
||||||
emptyString := ""
|
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}",
|
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)
|
vars := mux.Vars(req)
|
||||||
stateKey := vars["stateKey"]
|
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)
|
return writers.Register(req, accountDB)
|
||||||
}))
|
}))
|
||||||
|
|
||||||
// Stub endpoints required by Riot
|
// Stub endpoints required by Riot
|
||||||
|
|
||||||
r0mux.Handle("/login",
|
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)
|
return readers.Login(req, cfg)
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
r0mux.Handle("/pushrules/",
|
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
|
// TODO: Implement push rules API
|
||||||
res := json.RawMessage(`{
|
res := json.RawMessage(`{
|
||||||
"global": {
|
"global": {
|
||||||
|
@ -94,7 +98,7 @@ func Setup(servMux *http.ServeMux, httpClient *http.Client, cfg config.ClientAPI
|
||||||
)
|
)
|
||||||
|
|
||||||
r0mux.Handle("/user/{userID}/filter",
|
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
|
// TODO: Persist filter and return filter ID
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: 200,
|
Code: 200,
|
||||||
|
@ -104,7 +108,7 @@ func Setup(servMux *http.ServeMux, httpClient *http.Client, cfg config.ClientAPI
|
||||||
)
|
)
|
||||||
|
|
||||||
r0mux.Handle("/user/{userID}/filter/{filterID}",
|
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
|
// TODO: Retrieve filter based on ID
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: 200,
|
Code: 200,
|
||||||
|
@ -116,7 +120,7 @@ func Setup(servMux *http.ServeMux, httpClient *http.Client, cfg config.ClientAPI
|
||||||
// Riot user settings
|
// Riot user settings
|
||||||
|
|
||||||
r0mux.Handle("/profile/{userID}",
|
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
|
// TODO: Get profile data for user ID
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: 200,
|
Code: 200,
|
||||||
|
@ -126,7 +130,7 @@ func Setup(servMux *http.ServeMux, httpClient *http.Client, cfg config.ClientAPI
|
||||||
)
|
)
|
||||||
|
|
||||||
r0mux.Handle("/account/3pid",
|
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
|
// TODO: Get 3pid data for user ID
|
||||||
res := json.RawMessage(`{"threepids":[]}`)
|
res := json.RawMessage(`{"threepids":[]}`)
|
||||||
return util.JSONResponse{
|
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
|
// Riot logs get flooded unless this is handled
|
||||||
r0mux.Handle("/presence/{userID}/status",
|
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)
|
// TODO: Set presence (probably the responsibility of a presence server not clientapi)
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: 200,
|
Code: 200,
|
||||||
|
@ -150,9 +154,3 @@ func Setup(servMux *http.ServeMux, httpClient *http.Client, cfg config.ClientAPI
|
||||||
servMux.Handle("/metrics", prometheus.Handler())
|
servMux.Handle("/metrics", prometheus.Handler())
|
||||||
servMux.Handle("/api/", http.StripPrefix("/api", apiMux))
|
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))
|
|
||||||
}
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
log "github.com/Sirupsen/logrus"
|
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/config"
|
||||||
"github.com/matrix-org/dendrite/clientapi/events"
|
"github.com/matrix-org/dendrite/clientapi/events"
|
||||||
"github.com/matrix-org/dendrite/clientapi/httputil"
|
"github.com/matrix-org/dendrite/clientapi/httputil"
|
||||||
|
@ -91,22 +91,19 @@ type fledglingEvent struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateRoom implements /createRoom
|
// 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
|
// TODO: Check room ID doesn't clash with an existing one, and we
|
||||||
// probably shouldn't be using pseudo-random strings, maybe GUIDs?
|
// probably shouldn't be using pseudo-random strings, maybe GUIDs?
|
||||||
roomID := fmt.Sprintf("!%s:%s", util.RandomString(16), cfg.ServerName)
|
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
|
// 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())
|
logger := util.GetLogger(req.Context())
|
||||||
userID, resErr := auth.VerifyAccessToken(req)
|
userID := device.UserID
|
||||||
if resErr != nil {
|
|
||||||
return *resErr
|
|
||||||
}
|
|
||||||
var r createRoomRequest
|
var r createRoomRequest
|
||||||
resErr = httputil.UnmarshalJSONRequest(req, &r)
|
resErr := httputil.UnmarshalJSONRequest(req, &r)
|
||||||
if resErr != nil {
|
if resErr != nil {
|
||||||
return *resErr
|
return *resErr
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,8 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
log "github.com/Sirupsen/logrus"
|
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/storage/accounts"
|
||||||
"github.com/matrix-org/dendrite/clientapi/auth/types"
|
|
||||||
"github.com/matrix-org/dendrite/clientapi/httputil"
|
"github.com/matrix-org/dendrite/clientapi/httputil"
|
||||||
"github.com/matrix-org/dendrite/clientapi/jsonerror"
|
"github.com/matrix-org/dendrite/clientapi/jsonerror"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
@ -34,15 +34,15 @@ type registerRequest struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type authDict struct {
|
type authDict struct {
|
||||||
Type types.LoginType `json:"type"`
|
Type authtypes.LoginType `json:"type"`
|
||||||
Session string `json:"session"`
|
Session string `json:"session"`
|
||||||
// TODO: Lots of custom keys depending on the type
|
// TODO: Lots of custom keys depending on the type
|
||||||
}
|
}
|
||||||
|
|
||||||
// http://matrix.org/speculator/spec/HEAD/client_server/unstable.html#user-interactive-authentication-api
|
// http://matrix.org/speculator/spec/HEAD/client_server/unstable.html#user-interactive-authentication-api
|
||||||
type userInteractiveResponse struct {
|
type userInteractiveResponse struct {
|
||||||
Flows []authFlow `json:"flows"`
|
Flows []authFlow `json:"flows"`
|
||||||
Completed []types.LoginType `json:"completed"`
|
Completed []authtypes.LoginType `json:"completed"`
|
||||||
Params map[string]interface{} `json:"params"`
|
Params map[string]interface{} `json:"params"`
|
||||||
Session string `json:"session"`
|
Session string `json:"session"`
|
||||||
}
|
}
|
||||||
|
@ -50,12 +50,12 @@ type userInteractiveResponse struct {
|
||||||
// authFlow represents one possible way that the client can authenticate a request.
|
// 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
|
// http://matrix.org/speculator/spec/HEAD/client_server/unstable.html#user-interactive-authentication-api
|
||||||
type authFlow struct {
|
type authFlow struct {
|
||||||
Stages []types.LoginType `json:"stages"`
|
Stages []authtypes.LoginType `json:"stages"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func newUserInteractiveResponse(sessionID string, fs []authFlow) userInteractiveResponse {
|
func newUserInteractiveResponse(sessionID string, fs []authFlow) userInteractiveResponse {
|
||||||
return 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.
|
// TODO: Hard-coded 'dummy' auth for now with a bogus session ID.
|
||||||
// Server admins should be able to change things around (eg enable captcha)
|
// Server admins should be able to change things around (eg enable captcha)
|
||||||
JSON: newUserInteractiveResponse("totallyuniquesessionid", []authFlow{
|
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.
|
// TODO: email / msisdn / recaptcha auth types.
|
||||||
switch r.Auth.Type {
|
switch r.Auth.Type {
|
||||||
case types.LoginTypeDummy:
|
case authtypes.LoginTypeDummy:
|
||||||
// there is nothing to do
|
// there is nothing to do
|
||||||
return completeRegistration(accountDB, r.Username, r.Password)
|
return completeRegistration(accountDB, r.Username, r.Password)
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -20,7 +20,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"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/config"
|
||||||
"github.com/matrix-org/dendrite/clientapi/httputil"
|
"github.com/matrix-org/dendrite/clientapi/httputil"
|
||||||
"github.com/matrix-org/dendrite/clientapi/jsonerror"
|
"github.com/matrix-org/dendrite/clientapi/jsonerror"
|
||||||
|
@ -39,14 +39,11 @@ type sendEventResponse struct {
|
||||||
// SendEvent implements:
|
// SendEvent implements:
|
||||||
// /rooms/{roomID}/send/{eventType}/{txnID}
|
// /rooms/{roomID}/send/{eventType}/{txnID}
|
||||||
// /rooms/{roomID}/state/{eventType}/{stateKey}
|
// /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
|
// parse the incoming http request
|
||||||
userID, resErr := auth.VerifyAccessToken(req)
|
userID := device.UserID
|
||||||
if resErr != nil {
|
|
||||||
return *resErr
|
|
||||||
}
|
|
||||||
var r map[string]interface{} // must be a JSON object
|
var r map[string]interface{} // must be a JSON object
|
||||||
resErr = httputil.UnmarshalJSONRequest(req, &r)
|
resErr := httputil.UnmarshalJSONRequest(req, &r)
|
||||||
if resErr != nil {
|
if resErr != nil {
|
||||||
return *resErr
|
return *resErr
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/clientapi/auth/storage/accounts"
|
"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/config"
|
||||||
"github.com/matrix-org/dendrite/clientapi/producers"
|
"github.com/matrix-org/dendrite/clientapi/producers"
|
||||||
"github.com/matrix-org/dendrite/clientapi/routing"
|
"github.com/matrix-org/dendrite/clientapi/routing"
|
||||||
|
@ -85,7 +86,11 @@ func main() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Panicf("Failed to setup account database(%s): %s", accountDataSource, err.Error())
|
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))
|
log.Fatal(http.ListenAndServe(bindAddr, nil))
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/matrix-org/dendrite/clientapi/auth/storage/devices"
|
||||||
"github.com/matrix-org/dendrite/common"
|
"github.com/matrix-org/dendrite/common"
|
||||||
"github.com/matrix-org/dendrite/syncapi/config"
|
"github.com/matrix-org/dendrite/syncapi/config"
|
||||||
"github.com/matrix-org/dendrite/syncapi/consumers"
|
"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)
|
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()
|
pos, err := db.SyncStreamPosition()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Panicf("startup: failed to get latest sync stream position : %s", err)
|
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)
|
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))
|
log.Fatal(http.ListenAndServe(*bindAddr, nil))
|
||||||
}
|
}
|
||||||
|
|
28
src/github.com/matrix-org/dendrite/common/httpapi.go
Normal file
28
src/github.com/matrix-org/dendrite/common/httpapi.go
Normal file
|
@ -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))
|
||||||
|
}
|
|
@ -18,6 +18,9 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"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/config"
|
||||||
"github.com/matrix-org/dendrite/syncapi/sync"
|
"github.com/matrix-org/dendrite/syncapi/sync"
|
||||||
"github.com/matrix-org/util"
|
"github.com/matrix-org/util"
|
||||||
|
@ -27,17 +30,12 @@ import (
|
||||||
const pathPrefixR0 = "/_matrix/client/r0"
|
const pathPrefixR0 = "/_matrix/client/r0"
|
||||||
|
|
||||||
// SetupSyncServerListeners configures the given mux with sync-server listeners
|
// 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()
|
apiMux := mux.NewRouter()
|
||||||
r0mux := apiMux.PathPrefix(pathPrefixR0).Subrouter()
|
r0mux := apiMux.PathPrefix(pathPrefixR0).Subrouter()
|
||||||
r0mux.Handle("/sync", make("sync", util.NewJSONRequestHandler(func(req *http.Request) util.JSONResponse {
|
r0mux.Handle("/sync", common.MakeAuthAPI("sync", deviceDB, func(req *http.Request, device *authtypes.Device) util.JSONResponse {
|
||||||
return srp.OnIncomingSyncRequest(req)
|
return srp.OnIncomingSyncRequest(req, device)
|
||||||
})))
|
}))
|
||||||
servMux.Handle("/metrics", prometheus.Handler())
|
servMux.Handle("/metrics", prometheus.Handler())
|
||||||
servMux.Handle("/api/", http.StripPrefix("/api", apiMux))
|
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))
|
|
||||||
}
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
log "github.com/Sirupsen/logrus"
|
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/httputil"
|
||||||
"github.com/matrix-org/dendrite/clientapi/jsonerror"
|
"github.com/matrix-org/dendrite/clientapi/jsonerror"
|
||||||
"github.com/matrix-org/dendrite/syncapi/storage"
|
"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
|
// 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
|
// called in a dedicated goroutine for this request. This function will block the goroutine
|
||||||
// until a response is ready, or it times out.
|
// 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
|
// Extract values from request
|
||||||
logger := util.GetLogger(req.Context())
|
logger := util.GetLogger(req.Context())
|
||||||
userID, resErr := auth.VerifyAccessToken(req)
|
userID := device.UserID
|
||||||
if resErr != nil {
|
|
||||||
return *resErr
|
|
||||||
}
|
|
||||||
syncReq, err := newSyncRequest(req, userID)
|
syncReq, err := newSyncRequest(req, userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
|
|
Loading…
Reference in a new issue