From 9b213c20fb5463383b9b58078b55d05f0ca928f7 Mon Sep 17 00:00:00 2001 From: Travis Ralston <travpc@gmail.com> Date: Mon, 13 Nov 2017 01:29:00 -0700 Subject: [PATCH] Implement authorization on upload --- .../matrix-media-repo/client/r0/upload.go | 12 ++++++-- .../matrix-media-repo/client/responses.go | 4 +++ .../matrix-media-repo/config/config.go | 12 ++++---- .../turt2live/matrix-media-repo/media_repo.go | 10 +++++-- .../matrix-media-repo/util/config.go | 11 +++++-- .../turt2live/matrix-media-repo/util/http.go | 15 ++++++++++ .../matrix-media-repo/util/matrix.go | 29 +++++++++++++++++++ 7 files changed, 80 insertions(+), 13 deletions(-) create mode 100644 src/github.com/turt2live/matrix-media-repo/util/http.go create mode 100644 src/github.com/turt2live/matrix-media-repo/util/matrix.go diff --git a/src/github.com/turt2live/matrix-media-repo/client/r0/upload.go b/src/github.com/turt2live/matrix-media-repo/client/r0/upload.go index 91251d29..a7a33f89 100644 --- a/src/github.com/turt2live/matrix-media-repo/client/r0/upload.go +++ b/src/github.com/turt2live/matrix-media-repo/client/r0/upload.go @@ -8,6 +8,7 @@ import ( "github.com/turt2live/matrix-media-repo/config" "github.com/turt2live/matrix-media-repo/media_handler" "github.com/turt2live/matrix-media-repo/storage" + "github.com/turt2live/matrix-media-repo/util" ) // Request: @@ -23,7 +24,14 @@ type MediaUploadedResponse struct { } func UploadMedia(w http.ResponseWriter, r *http.Request, db storage.Database, c config.MediaRepoConfig) interface{} { - // TODO: Validate access_token + if !util.IsServerOurs(r.Host, c) { + return client.AuthFailed() + } + accessToken := util.GetAccessTokenFromRequest(r) + userId, err := util.GetUserIdFromToken(r.Context(), r.Host, accessToken, c) + if err != nil || userId == "" { + return client.AuthFailed() + } filename := r.URL.Query().Get("filename") if filename == "" { @@ -42,7 +50,7 @@ func UploadMedia(w http.ResponseWriter, r *http.Request, db storage.Database, c } request := &media_handler.MediaUploadRequest{ - UploadedBy: "", + UploadedBy: userId, ContentType: contentType, DesiredFilename: filename, Host: r.Host, diff --git a/src/github.com/turt2live/matrix-media-repo/client/responses.go b/src/github.com/turt2live/matrix-media-repo/client/responses.go index d09b9995..bb3f1fc8 100644 --- a/src/github.com/turt2live/matrix-media-repo/client/responses.go +++ b/src/github.com/turt2live/matrix-media-repo/client/responses.go @@ -16,4 +16,8 @@ func NotFoundError() *ErrorResponse { func RequestTooLarge() *ErrorResponse { return &ErrorResponse{"M_UNKNOWN", "Too Large", "M_MEDIA_TOO_LARGE"} +} + +func AuthFailed() *ErrorResponse { + return &ErrorResponse{"M_UNKNOWN_TOKEN", "Authenticaton Failed", "M_UNKNOWN_TOKEN"} } \ No newline at end of file diff --git a/src/github.com/turt2live/matrix-media-repo/config/config.go b/src/github.com/turt2live/matrix-media-repo/config/config.go index 8f7961d8..5d52f4f3 100644 --- a/src/github.com/turt2live/matrix-media-repo/config/config.go +++ b/src/github.com/turt2live/matrix-media-repo/config/config.go @@ -7,12 +7,14 @@ import ( "gopkg.in/yaml.v2" ) +type HomeserverConfig struct { + Name string `yaml:"name"` + DownloadRequiresAuth bool `yaml:"downloadRequiresAuth"` + ClientServerApi string `yaml:"csApi"` +} + type MediaRepoConfig struct { - Homeservers []struct { - Name string `yaml:"name"` - DownloadRequiresAuth bool `yaml:"downloadRequiresAuth"` - ClientServerApi string `yaml:"csApi"` - } `yaml:"homeservers,flow"` + Homeservers []HomeserverConfig `yaml:"homeservers,flow"` Database struct { Postgres string `yaml:"postgres"` diff --git a/src/github.com/turt2live/matrix-media-repo/media_repo.go b/src/github.com/turt2live/matrix-media-repo/media_repo.go index c0411f4c..1d4b12ff 100644 --- a/src/github.com/turt2live/matrix-media-repo/media_repo.go +++ b/src/github.com/turt2live/matrix-media-repo/media_repo.go @@ -59,6 +59,9 @@ func main() { rtr.Handle("/_matrix/media/v1/download/{server:[a-zA-Z0-9.:-_]+}/{mediaId:[a-zA-Z0-9]+}/{filename:[a-zA-Z0-9._-]+}", downloadHandler).Methods("GET") rtr.Handle("/_matrix/media/v1/thumbnail/{server:[a-zA-Z0-9.:-_]+}/{mediaId:[a-zA-Z0-9]+}", thumbnailHandler).Methods("GET") + // TODO: Intercept 404, 500, and 400 to respond with M_NOT_FOUND and M_UNKNOWN + // TODO: Rate limiting (429 M_LIMIT_EXCEEDED) + http.Handle("/", rtr) http.ListenAndServe(":8000", nil) } @@ -88,18 +91,19 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { switch result := res.(type) { case *client.ErrorResponse: + w.Header().Set("Content-Type", "application/json") switch result.InternalCode { + case "M_UNKNOWN_TOKEN": + http.Error(w, jsonStr, http.StatusForbidden) + break case "M_NOT_FOUND": - w.Header().Set("Content-Type", "application/json") http.Error(w, jsonStr, http.StatusNotFound) break case "M_MEDIA_TOO_LARGE": - w.Header().Set("Content-Type", "application/json") http.Error(w, jsonStr, http.StatusRequestEntityTooLarge) break //case "M_UNKNOWN": default: - w.Header().Set("Content-Type", "application/json") http.Error(w, jsonStr, http.StatusInternalServerError) break } diff --git a/src/github.com/turt2live/matrix-media-repo/util/config.go b/src/github.com/turt2live/matrix-media-repo/util/config.go index 6e38a2ce..feeab340 100644 --- a/src/github.com/turt2live/matrix-media-repo/util/config.go +++ b/src/github.com/turt2live/matrix-media-repo/util/config.go @@ -3,12 +3,17 @@ package util import "github.com/turt2live/matrix-media-repo/config" func IsServerOurs(server string, c config.MediaRepoConfig) (bool) { + hs := GetHomeserverConfig(server, c) + return hs != nil +} + +func GetHomeserverConfig(server string, c config.MediaRepoConfig) (*config.HomeserverConfig) { for i := 0; i < len(c.Homeservers); i++ { hs := c.Homeservers[i] if hs.Name == server { - return true + return &hs } } - return false -} + return nil +} \ No newline at end of file diff --git a/src/github.com/turt2live/matrix-media-repo/util/http.go b/src/github.com/turt2live/matrix-media-repo/util/http.go new file mode 100644 index 00000000..1161672b --- /dev/null +++ b/src/github.com/turt2live/matrix-media-repo/util/http.go @@ -0,0 +1,15 @@ +package util + +import ( + "net/http" +) + +func GetAccessTokenFromRequest(request *http.Request) (string) { + token := request.Header.Get("Authorization") + if token != "" && len(token) > 7 { + // "Bearer <token>" + return token[7:] + } + + return request.URL.Query().Get("access_token") +} \ No newline at end of file diff --git a/src/github.com/turt2live/matrix-media-repo/util/matrix.go b/src/github.com/turt2live/matrix-media-repo/util/matrix.go new file mode 100644 index 00000000..fc47f26c --- /dev/null +++ b/src/github.com/turt2live/matrix-media-repo/util/matrix.go @@ -0,0 +1,29 @@ +package util + +import ( + "context" + + "github.com/matrix-org/gomatrix" + "github.com/turt2live/matrix-media-repo/config" +) + +type userIdResponse struct { + UserId string `json:"user_id"` +} + +func GetUserIdFromToken(ctx context.Context, serverName string, accessToken string, c config.MediaRepoConfig) (string, error) { + hs := GetHomeserverConfig(serverName, c) + mtxClient, err := gomatrix.NewClient(hs.ClientServerApi, "", accessToken) + if err != nil { + return "", err + } + + response := &userIdResponse{} + url := mtxClient.BuildURL("/account/whoami") + _, err = mtxClient.MakeRequest("GET", url, nil, response) + if err != nil { + return "", err + } + + return response.UserId, nil +} \ No newline at end of file -- GitLab