Federation: Implement Query Profile API
* Federation: Implement Query Profile API
Implements the server portion of: `GET
/_matrix/federation/v1/query/profile?user_id=...&field=...`
Closes
* Properly export profile-related structs and fix wording
* Check provided user's domain matches our own.
MODIFY
src/github.com/matrix-org/dendrite/clientapi/jsonerror/jsonerror.go
src/github.com/matrix-org/dendrite/clientapi/jsonerror/jsonerror.go
@@ -67,6 +67,18 @@ func NotFound(msg string) *MatrixError {
return &MatrixError{"M_NOT_FOUND", msg}
}
+// MissingArgument is an error when the client tries to access a resource
+// without providing an argument that is required.
+func MissingArgument(msg string) *MatrixError {
+ return &MatrixError{"M_MISSING_ARGUMENT", msg}
+}
+
+// InvalidArgumentValue is an error when the client tries to provide an
+// invalid value for a valid argument
+func InvalidArgumentValue(msg string) *MatrixError {
+ return &MatrixError{"M_INVALID_ARGUMENT_VALUE", msg}
+}
+
// MissingToken is an error when the client tries to access a resource which
// requires authentication without supplying credentials.
func MissingToken(msg string) *MatrixError {

MODIFY
src/github.com/matrix-org/dendrite/clientapi/routing/profile.go
src/github.com/matrix-org/dendrite/clientapi/routing/profile.go
@@ -31,19 +31,6 @@ import (
"github.com/matrix-org/util"
)
-type profileResponse struct {
- AvatarURL string `json:"avatar_url"`
- DisplayName string `json:"displayname"`
-}
-
-type avatarURL struct {
- AvatarURL string `json:"avatar_url"`
-}
-
-type displayName struct {
- DisplayName string `json:"displayname"`
-}
-
// GetProfile implements GET /profile/{userID}
func GetProfile(
req *http.Request, accountDB *accounts.Database, userID string,
@@ -63,7 +50,7 @@ func GetProfile(
if err != nil {
return httputil.LogThenError(req, err)
}
- res := profileResponse{
+ res := common.ProfileResponse{
AvatarURL: profile.AvatarURL,
DisplayName: profile.DisplayName,
}
@@ -86,7 +73,7 @@ func GetAvatarURL(
if err != nil {
return httputil.LogThenError(req, err)
}
- res := avatarURL{
+ res := common.AvatarURL{
AvatarURL: profile.AvatarURL,
}
return util.JSONResponse{
@@ -110,7 +97,7 @@ func SetAvatarURL(
changedKey := "avatar_url"
- var r avatarURL
+ var r common.AvatarURL
if resErr := httputil.UnmarshalJSONRequest(req, &r); resErr != nil {
return *resErr
}
@@ -178,7 +165,7 @@ func GetDisplayName(
if err != nil {
return httputil.LogThenError(req, err)
}
- res := displayName{
+ res := common.DisplayName{
DisplayName: profile.DisplayName,
}
return util.JSONResponse{
@@ -202,7 +189,7 @@ func SetDisplayName(
changedKey := "displayname"
- var r displayName
+ var r common.DisplayName
if resErr := httputil.UnmarshalJSONRequest(req, &r); resErr != nil {
return *resErr
}

MODIFY
src/github.com/matrix-org/dendrite/common/types.go
src/github.com/matrix-org/dendrite/common/types.go
@@ -20,3 +20,19 @@ type AccountData struct {
RoomID string `json:"room_id"`
Type string `json:"type"`
}
+
+// ProfileResponse is a struct containing all known user profile data
+type ProfileResponse struct {
+ AvatarURL string `json:"avatar_url"`
+ DisplayName string `json:"displayname"`
+}
+
+// AvatarURL is a struct containing only the URL to a user's avatar
+type AvatarURL struct {
+ AvatarURL string `json:"avatar_url"`
+}
+
+// DisplayName is a struct containing only a user's display name
+type DisplayName struct {
+ DisplayName string `json:"displayname"`
+}

ADD
src/github.com/matrix-org/dendrite/federationapi/routing/profile.go
+// Copyright 2017 New Vector Ltd
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package routing
+
+import (
+ "net/http"
+
+ "github.com/matrix-org/dendrite/clientapi/auth/storage/accounts"
+ "github.com/matrix-org/dendrite/clientapi/httputil"
+ "github.com/matrix-org/dendrite/clientapi/jsonerror"
+ "github.com/matrix-org/dendrite/common"
+ "github.com/matrix-org/dendrite/common/config"
+ "github.com/matrix-org/gomatrixserverlib"
+ "github.com/matrix-org/util"
+)
+
+// GetProfile implements GET /_matrix/federation/v1/query/profile
+func GetProfile(
+ httpReq *http.Request,
+ accountDB *accounts.Database,
+ cfg config.Dendrite,
+) util.JSONResponse {
+ userID, field := httpReq.FormValue("user_id"), httpReq.FormValue("field")
+
+ // httpReq.FormValue will return an empty string if value is not found
+ if userID == "" {
+ return util.JSONResponse{
+ Code: 400,
+ JSON: jsonerror.MissingArgument("The request body did not contain required argument 'user_id'."),
+ }
+ }
+
+ localpart, domain, err := gomatrixserverlib.SplitID('@', userID)
+ if err != nil {
+ return httputil.LogThenError(httpReq, err)
+ }
+
+ if domain != cfg.Matrix.ServerName {
+ return httputil.LogThenError(httpReq, err)
+ }
+
+ profile, err := accountDB.GetProfileByLocalpart(httpReq.Context(), localpart)
+ if err != nil {
+ return httputil.LogThenError(httpReq, err)
+ }
+
+ var res interface{}
+ code := 200
+
+ if field != "" {
+ switch field {
+ case "displayname":
+ res = common.DisplayName{
+ profile.DisplayName,
+ }
+ case "avatar_url":
+ res = common.AvatarURL{
+ profile.AvatarURL,
+ }
+ default:
+ code = 400
+ res = jsonerror.InvalidArgumentValue("The request body did not contain an allowed value of argument 'field'. Allowed values are either: 'avatar_url', 'displayname'.")
+ }
+ } else {
+ res = common.ProfileResponse{
+ profile.AvatarURL,
+ profile.DisplayName,
+ }
+ }
+
+ return util.JSONResponse{
+ Code: code,
+ JSON: res,
+ }
+}

MODIFY
src/github.com/matrix-org/dendrite/federationapi/routing/routing.go
src/github.com/matrix-org/dendrite/federationapi/routing/routing.go
@@ -105,6 +105,15 @@ func Setup(
},
)).Methods("GET")
+ v1fedmux.Handle("/query/profile", common.MakeFedAPI(
+ "federation_query_profile", cfg.Matrix.ServerName, keys,
+ func(httpReq *http.Request, request *gomatrixserverlib.FederationRequest) util.JSONResponse {
+ return GetProfile(
+ httpReq, accountDB, cfg,
+ )
+ },
+ )).Methods("GET")
+
v1fedmux.Handle("/version", common.MakeExternalAPI(
"federation_version",
func(httpReq *http.Request) util.JSONResponse {

Federation: Implement Query Profile API (#317)

* Federation: Implement Query Profile API

Implements the server portion of: `GET
/_matrix/federation/v1/query/profile?user_id=...&field=...`

Closes #278

Signed-off-by: Andrew (anoa) <anoa@openmailbox.org>

* Properly export profile-related structs and fix wording

Signed-off-by: Andrew (anoa) <anoa@openmailbox.org>

* Check provided user's domain matches our own.