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.
This commit is contained in:
parent
49c040c89f
commit
b7cfc2e057
5 changed files with 129 additions and 18 deletions
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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"`
|
||||
}
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
// 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,
|
||||
}
|
||||
}
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in a new issue