diff --git a/src/github.com/matrix-org/dendrite/clientapi/readers/login.go b/src/github.com/matrix-org/dendrite/clientapi/readers/login.go new file mode 100644 index 00000000..e4d2e4ee --- /dev/null +++ b/src/github.com/matrix-org/dendrite/clientapi/readers/login.go @@ -0,0 +1,76 @@ +package readers + +import ( + "fmt" + "github.com/matrix-org/dendrite/clientapi/config" + "github.com/matrix-org/dendrite/clientapi/httputil" + "github.com/matrix-org/dendrite/clientapi/jsonerror" + "github.com/matrix-org/util" + "net/http" +) + +type loginFlows struct { + Flows []flow `json:"flows"` +} + +type flow struct { + Type string `json:"type"` + Stages []string `json:"stages"` +} + +type passwordRequest struct { + User string `json:"user"` + Password string `json:"password"` +} + +type loginResponse struct { + UserID string `json:"user_id"` + AccessToken string `json:"access_token"` + HomeServer string `json:"home_server"` +} + +func passwordLogin() loginFlows { + f := loginFlows{} + s := flow{"m.login.password", []string{"m.login.password"}} + f.Flows = append(f.Flows, s) + return f +} + +// Login implements GET and POST /login +func Login(req *http.Request, cfg config.ClientAPI) util.JSONResponse { + if req.Method == "GET" { // TODO: support other forms of login other than password, depending on config options + return util.JSONResponse{ + Code: 200, + JSON: passwordLogin(), + } + } else if req.Method == "POST" { + var r passwordRequest + resErr := httputil.UnmarshalJSONRequest(req, &r) + if resErr != nil { + return *resErr + } + if r.User == "" { + return util.JSONResponse{ + Code: 400, + JSON: jsonerror.BadJSON("'user' must be supplied."), + } + } + // TODO: Check username and password properly + return util.JSONResponse{ + Code: 200, + JSON: loginResponse{ + UserID: makeUserID(r.User, cfg.ServerName), + AccessToken: makeUserID(r.User, cfg.ServerName), // FIXME: token is the user ID for now + HomeServer: cfg.ServerName, + }, + } + } + return util.JSONResponse{ + Code: 405, + JSON: jsonerror.NotFound("Bad method"), + } +} + +func makeUserID(localpart, domain string) string { + return fmt.Sprintf("@%s:%s", localpart, domain) +} 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 29595399..ab6296ba 100644 --- a/src/github.com/matrix-org/dendrite/clientapi/routing/routing.go +++ b/src/github.com/matrix-org/dendrite/clientapi/routing/routing.go @@ -1,11 +1,13 @@ package routing import ( + "encoding/json" "net/http" "github.com/gorilla/mux" "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/roomserver/api" "github.com/matrix-org/util" @@ -43,6 +45,87 @@ func Setup(servMux *http.ServeMux, httpClient *http.Client, cfg config.ClientAPI })), ) + // Stub endpoints required by Riot + + r0mux.Handle("/login", + make("login", util.NewJSONRequestHandler(func(req *http.Request) util.JSONResponse { + return readers.Login(req, cfg) + })), + ) + + r0mux.Handle("/pushrules/", + make("push_rules", util.NewJSONRequestHandler(func(req *http.Request) util.JSONResponse { + // TODO: Implement push rules API + res := json.RawMessage(`{ + "global": { + "content": [], + "override": [], + "room": [], + "sender": [], + "underride": [] + } + }`) + return util.JSONResponse{ + Code: 200, + JSON: &res, + } + })), + ) + + r0mux.Handle("/user/{userID}/filter", + make("make_filter", util.NewJSONRequestHandler(func(req *http.Request) util.JSONResponse { + // TODO: Persist filter and return filter ID + return util.JSONResponse{ + Code: 200, + JSON: struct{}{}, + } + })), + ) + + r0mux.Handle("/user/{userID}/filter/{filterID}", + make("filter", util.NewJSONRequestHandler(func(req *http.Request) util.JSONResponse { + // TODO: Retrieve filter based on ID + return util.JSONResponse{ + Code: 200, + JSON: struct{}{}, + } + })), + ) + + // Riot user settings + + r0mux.Handle("/profile/{userID}", + make("profile", util.NewJSONRequestHandler(func(req *http.Request) util.JSONResponse { + // TODO: Get profile data for user ID + return util.JSONResponse{ + Code: 200, + JSON: struct{}{}, + } + })), + ) + + r0mux.Handle("/account/3pid", + make("account_3pid", util.NewJSONRequestHandler(func(req *http.Request) util.JSONResponse { + // TODO: Get 3pid data for user ID + res := json.RawMessage(`{"threepids":[]}`) + return util.JSONResponse{ + Code: 200, + JSON: &res, + } + })), + ) + + // Riot logs get flooded unless this is handled + r0mux.Handle("/presence/{userID}/status", + make("presence", util.NewJSONRequestHandler(func(req *http.Request) util.JSONResponse { + // TODO: Set presence (probably the responsibility of a presence server not clientapi) + return util.JSONResponse{ + Code: 200, + JSON: struct{}{}, + } + })), + ) + servMux.Handle("/metrics", prometheus.Handler()) servMux.Handle("/api/", http.StripPrefix("/api", apiMux)) } diff --git a/vendor/manifest b/vendor/manifest index dceb7916..2cc75e57 100644 --- a/vendor/manifest +++ b/vendor/manifest @@ -98,7 +98,7 @@ { "importpath": "github.com/matrix-org/util", "repository": "https://github.com/matrix-org/util", - "revision": "ec8896cd7d9ba6de6143c5f123d1e45413657e7d", + "revision": "bc9d5e2d2f68a2ca279fce0fa2f28a91ecf301ed", "branch": "master" }, { diff --git a/vendor/src/github.com/matrix-org/util/json.go b/vendor/src/github.com/matrix-org/util/json.go index 3323b526..a30d73f8 100644 --- a/vendor/src/github.com/matrix-org/util/json.go +++ b/vendor/src/github.com/matrix-org/util/json.go @@ -111,6 +111,11 @@ func MakeJSONAPI(handler JSONRequestHandler) http.HandlerFunc { logger := GetLogger(req.Context()) logger.Print("Incoming request") + if req.Method == "OPTIONS" { + SetCORSHeaders(w) + w.WriteHeader(200) + return + } res := handler.OnIncomingRequest(req) // Set common headers returned regardless of the outcome of the request