Implement profile retrieval over federation (#726)
parent
66bf615360
commit
324ca22b35
|
@ -20,13 +20,13 @@ package api
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"errors"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
|
"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/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
|
||||||
|
"github.com/matrix-org/dendrite/common"
|
||||||
commonHTTP "github.com/matrix-org/dendrite/common/http"
|
commonHTTP "github.com/matrix-org/dendrite/common/http"
|
||||||
opentracing "github.com/opentracing/opentracing-go"
|
opentracing "github.com/opentracing/opentracing-go"
|
||||||
)
|
)
|
||||||
|
@ -164,7 +164,7 @@ func RetrieveUserProfile(
|
||||||
|
|
||||||
// If no user exists, return
|
// If no user exists, return
|
||||||
if !userResp.UserIDExists {
|
if !userResp.UserIDExists {
|
||||||
return nil, errors.New("no known profile for given user ID")
|
return nil, common.ErrProfileNoExists
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to query the user from the local database again
|
// Try to query the user from the local database again
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
package authtypes
|
package authtypes
|
||||||
|
|
||||||
// Profile represents the profile for a Matrix account on this home server.
|
// Profile represents the profile for a Matrix account.
|
||||||
type Profile struct {
|
type Profile struct {
|
||||||
Localpart string
|
Localpart string
|
||||||
DisplayName string
|
DisplayName string
|
||||||
|
|
|
@ -30,43 +30,61 @@ import (
|
||||||
"github.com/matrix-org/dendrite/roomserver/api"
|
"github.com/matrix-org/dendrite/roomserver/api"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
|
||||||
|
"github.com/matrix-org/gomatrix"
|
||||||
"github.com/matrix-org/util"
|
"github.com/matrix-org/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetProfile implements GET /profile/{userID}
|
// GetProfile implements GET /profile/{userID}
|
||||||
func GetProfile(
|
func GetProfile(
|
||||||
req *http.Request, accountDB *accounts.Database, userID string, asAPI appserviceAPI.AppServiceQueryAPI,
|
req *http.Request, accountDB *accounts.Database, cfg *config.Dendrite,
|
||||||
|
userID string,
|
||||||
|
asAPI appserviceAPI.AppServiceQueryAPI,
|
||||||
|
federation *gomatrixserverlib.FederationClient,
|
||||||
) util.JSONResponse {
|
) util.JSONResponse {
|
||||||
profile, err := appserviceAPI.RetrieveUserProfile(req.Context(), userID, asAPI, accountDB)
|
profile, err := getProfile(req.Context(), accountDB, cfg, userID, asAPI, federation)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if err == common.ErrProfileNoExists {
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusNotFound,
|
||||||
|
JSON: jsonerror.NotFound("The user does not exist or does not have a profile"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return httputil.LogThenError(req, err)
|
return httputil.LogThenError(req, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
res := common.ProfileResponse{
|
|
||||||
AvatarURL: profile.AvatarURL,
|
|
||||||
DisplayName: profile.DisplayName,
|
|
||||||
}
|
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusOK,
|
Code: http.StatusOK,
|
||||||
JSON: res,
|
JSON: common.ProfileResponse{
|
||||||
|
AvatarURL: profile.AvatarURL,
|
||||||
|
DisplayName: profile.DisplayName,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAvatarURL implements GET /profile/{userID}/avatar_url
|
// GetAvatarURL implements GET /profile/{userID}/avatar_url
|
||||||
func GetAvatarURL(
|
func GetAvatarURL(
|
||||||
req *http.Request, accountDB *accounts.Database, userID string, asAPI appserviceAPI.AppServiceQueryAPI,
|
req *http.Request, accountDB *accounts.Database, cfg *config.Dendrite,
|
||||||
|
userID string, asAPI appserviceAPI.AppServiceQueryAPI,
|
||||||
|
federation *gomatrixserverlib.FederationClient,
|
||||||
) util.JSONResponse {
|
) util.JSONResponse {
|
||||||
profile, err := appserviceAPI.RetrieveUserProfile(req.Context(), userID, asAPI, accountDB)
|
profile, err := getProfile(req.Context(), accountDB, cfg, userID, asAPI, federation)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if err == common.ErrProfileNoExists {
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusNotFound,
|
||||||
|
JSON: jsonerror.NotFound("The user does not exist or does not have a profile"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return httputil.LogThenError(req, err)
|
return httputil.LogThenError(req, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
res := common.AvatarURL{
|
|
||||||
AvatarURL: profile.AvatarURL,
|
|
||||||
}
|
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusOK,
|
Code: http.StatusOK,
|
||||||
JSON: res,
|
JSON: common.AvatarURL{
|
||||||
|
AvatarURL: profile.AvatarURL,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,18 +170,27 @@ func SetAvatarURL(
|
||||||
|
|
||||||
// GetDisplayName implements GET /profile/{userID}/displayname
|
// GetDisplayName implements GET /profile/{userID}/displayname
|
||||||
func GetDisplayName(
|
func GetDisplayName(
|
||||||
req *http.Request, accountDB *accounts.Database, userID string, asAPI appserviceAPI.AppServiceQueryAPI,
|
req *http.Request, accountDB *accounts.Database, cfg *config.Dendrite,
|
||||||
|
userID string, asAPI appserviceAPI.AppServiceQueryAPI,
|
||||||
|
federation *gomatrixserverlib.FederationClient,
|
||||||
) util.JSONResponse {
|
) util.JSONResponse {
|
||||||
profile, err := appserviceAPI.RetrieveUserProfile(req.Context(), userID, asAPI, accountDB)
|
profile, err := getProfile(req.Context(), accountDB, cfg, userID, asAPI, federation)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if err == common.ErrProfileNoExists {
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusNotFound,
|
||||||
|
JSON: jsonerror.NotFound("The user does not exist or does not have a profile"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return httputil.LogThenError(req, err)
|
return httputil.LogThenError(req, err)
|
||||||
}
|
}
|
||||||
res := common.DisplayName{
|
|
||||||
DisplayName: profile.DisplayName,
|
|
||||||
}
|
|
||||||
return util.JSONResponse{
|
return util.JSONResponse{
|
||||||
Code: http.StatusOK,
|
Code: http.StatusOK,
|
||||||
JSON: res,
|
JSON: common.DisplayName{
|
||||||
|
DisplayName: profile.DisplayName,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -247,6 +274,48 @@ func SetDisplayName(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getProfile gets the full profile of a user by querying the database or a
|
||||||
|
// remote homeserver.
|
||||||
|
// Returns an error when something goes wrong or specifically
|
||||||
|
// common.ErrProfileNoExists when the profile doesn't exist.
|
||||||
|
func getProfile(
|
||||||
|
ctx context.Context, accountDB *accounts.Database, cfg *config.Dendrite,
|
||||||
|
userID string,
|
||||||
|
asAPI appserviceAPI.AppServiceQueryAPI,
|
||||||
|
federation *gomatrixserverlib.FederationClient,
|
||||||
|
) (*authtypes.Profile, error) {
|
||||||
|
localpart, domain, err := gomatrixserverlib.SplitID('@', userID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if domain != cfg.Matrix.ServerName {
|
||||||
|
profile, fedErr := federation.LookupProfile(ctx, domain, userID, "")
|
||||||
|
if fedErr != nil {
|
||||||
|
if x, ok := fedErr.(gomatrix.HTTPError); ok {
|
||||||
|
if x.Code == http.StatusNotFound {
|
||||||
|
return nil, common.ErrProfileNoExists
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fedErr
|
||||||
|
}
|
||||||
|
|
||||||
|
return &authtypes.Profile{
|
||||||
|
Localpart: localpart,
|
||||||
|
DisplayName: profile.DisplayName,
|
||||||
|
AvatarURL: profile.AvatarURL,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
profile, err := appserviceAPI.RetrieveUserProfile(ctx, userID, asAPI, accountDB)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return profile, nil
|
||||||
|
}
|
||||||
|
|
||||||
func buildMembershipEvents(
|
func buildMembershipEvents(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
memberships []authtypes.Membership,
|
memberships []authtypes.Membership,
|
||||||
|
|
|
@ -283,7 +283,7 @@ func Setup(
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
}
|
}
|
||||||
return GetProfile(req, accountDB, vars["userID"], asAPI)
|
return GetProfile(req, accountDB, &cfg, vars["userID"], asAPI, federation)
|
||||||
}),
|
}),
|
||||||
).Methods(http.MethodGet, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
|
@ -293,7 +293,7 @@ func Setup(
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
}
|
}
|
||||||
return GetAvatarURL(req, accountDB, vars["userID"], asAPI)
|
return GetAvatarURL(req, accountDB, &cfg, vars["userID"], asAPI, federation)
|
||||||
}),
|
}),
|
||||||
).Methods(http.MethodGet, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
|
@ -315,7 +315,7 @@ func Setup(
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.ErrorResponse(err)
|
return util.ErrorResponse(err)
|
||||||
}
|
}
|
||||||
return GetDisplayName(req, accountDB, vars["userID"], asAPI)
|
return GetDisplayName(req, accountDB, &cfg, vars["userID"], asAPI, federation)
|
||||||
}),
|
}),
|
||||||
).Methods(http.MethodGet, http.MethodOptions)
|
).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
|
|
|
@ -15,9 +15,14 @@
|
||||||
package common
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ErrProfileNoExists is returned when trying to lookup a user's profile that
|
||||||
|
// doesn't exist locally.
|
||||||
|
var ErrProfileNoExists = errors.New("no known profile for given user ID")
|
||||||
|
|
||||||
// AccountData represents account data sent from the client API server to the
|
// AccountData represents account data sent from the client API server to the
|
||||||
// sync API server
|
// sync API server
|
||||||
type AccountData struct {
|
type AccountData struct {
|
||||||
|
|
1
testfile
1
testfile
|
@ -167,3 +167,4 @@ Tags appear in an initial v2 /sync
|
||||||
Newly updated tags appear in an incremental v2 /sync
|
Newly updated tags appear in an incremental v2 /sync
|
||||||
Deleted tags appear in an incremental v2 /sync
|
Deleted tags appear in an incremental v2 /sync
|
||||||
/event/ on non world readable room does not work
|
/event/ on non world readable room does not work
|
||||||
|
Outbound federation can query profile data
|
||||||
|
|
Loading…
Reference in New Issue