mirror of
https://github.com/matrix-org/dendrite.git
synced 2024-11-29 17:51:56 -06:00
8c6cf51b8f
This is meant to cache client presence for a moment so that it doesn't oscillate. Currently Dendrite just federates out whatever presence it gets from the sync loop, which means if theres any clients attempting to sync without setting the user online, and there is an online client, it will just flip back and forth each time one of the clients polls /sync. This pull request essentially stores in a map when the client last set online ideally to allow the online client to sync again and set an online presence before setting idle or offline. I am not great at programming nor am I familiar with this codebase so if this pr is just shitwater feel free to discard, just trying to fix an issue that severely bothers me. If it is easier you can also steal the code and write it in yourself. I ran the linter, not sure that it did anything, the vscode go extension seems to format and lint anyways. I tried to run unit tests but I have no idea any of this thing. it errors on `TestRequestPool_updatePresence/same_presence_is_not_published_dummy2 (10m0s)` which I think making this change broke. I am unsure how to comply, if y'all point me in the right direction ill try to fix it. I have tested it with all the situations I can think of on my personal instance pain.agency, and this seems to stand up under all the previously bugged situations. ~~My go also decided to update a bunch of the dependencies, I hate git and github and have no idea how to fix that, it was not intentional.~~ i just overwrote them with the ones from the main repo and committed it, seems to have done what was needed. ### Pull Request Checklist <!-- Please read https://matrix-org.github.io/dendrite/development/contributing before submitting your pull request --> * [x] I have added Go unit tests or [Complement integration tests](https://github.com/matrix-org/complement) for this PR _or_ I have justified why this PR doesn't need tests * [x] Pull request includes a [sign off below using a legally identifiable name](https://matrix-org.github.io/dendrite/development/contributing#sign-off) _or_ I have already signed off privately Signed-off-by: `Joseph Winkie <jjj333.p.1325@gmail.com>` --------- Co-authored-by: Till Faelligen <2353100+S7evinK@users.noreply.github.com>
193 lines
6.2 KiB
Go
193 lines
6.2 KiB
Go
// Copyright 2017 Vector Creations 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 threepid
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"net/http"
|
|
"net/url"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/matrix-org/dendrite/setup/config"
|
|
"github.com/matrix-org/gomatrixserverlib/fclient"
|
|
"github.com/matrix-org/gomatrixserverlib/spec"
|
|
)
|
|
|
|
// EmailAssociationRequest represents the request defined at https://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-register-email-requesttoken
|
|
type EmailAssociationRequest struct {
|
|
IDServer string `json:"id_server"`
|
|
Secret string `json:"client_secret"`
|
|
Email string `json:"email"`
|
|
SendAttempt int `json:"send_attempt"`
|
|
}
|
|
|
|
// EmailAssociationCheckRequest represents the request defined at https://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-account-3pid
|
|
type EmailAssociationCheckRequest struct {
|
|
Creds Credentials `json:"three_pid_creds"`
|
|
Bind bool `json:"bind"`
|
|
}
|
|
|
|
// Credentials represents the "ThreePidCredentials" structure defined at https://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-account-3pid
|
|
type Credentials struct {
|
|
SID string `json:"sid"`
|
|
IDServer string `json:"id_server"`
|
|
Secret string `json:"client_secret"`
|
|
}
|
|
|
|
type SID struct {
|
|
SID string `json:"sid"`
|
|
}
|
|
|
|
// CreateSession creates a session on an identity server.
|
|
// Returns the session's ID.
|
|
// Returns an error if there was a problem sending the request or decoding the
|
|
// response, or if the identity server responded with a non-OK status.
|
|
func CreateSession(
|
|
ctx context.Context, req EmailAssociationRequest, cfg *config.ClientAPI, client *fclient.Client,
|
|
) (string, error) {
|
|
if err := isTrusted(req.IDServer, cfg); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
// Create a session on the ID server
|
|
postURL := fmt.Sprintf("https://%s/_matrix/identity/api/v1/validate/email/requestToken", req.IDServer)
|
|
|
|
data := url.Values{}
|
|
data.Add("client_secret", req.Secret)
|
|
data.Add("email", req.Email)
|
|
data.Add("send_attempt", strconv.Itoa(req.SendAttempt))
|
|
|
|
request, err := http.NewRequest(http.MethodPost, postURL, strings.NewReader(data.Encode()))
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
request.Header.Add("Content-Type", "application/x-www-form-urlencoded")
|
|
|
|
resp, err := client.DoHTTPRequest(ctx, request)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
defer resp.Body.Close() // nolint: errcheck
|
|
|
|
// Error if the status isn't OK
|
|
if resp.StatusCode != http.StatusOK {
|
|
return "", fmt.Errorf("could not create a session on the server %s", req.IDServer)
|
|
}
|
|
|
|
// Extract the SID from the response and return it
|
|
var sid SID
|
|
err = json.NewDecoder(resp.Body).Decode(&sid)
|
|
|
|
return sid.SID, err
|
|
}
|
|
|
|
type GetValidatedResponse struct {
|
|
Medium string `json:"medium"`
|
|
ValidatedAt int64 `json:"validated_at"`
|
|
Address string `json:"address"`
|
|
ErrCode string `json:"errcode"`
|
|
Error string `json:"error"`
|
|
}
|
|
|
|
// CheckAssociation checks the status of an ongoing association validation on an
|
|
// identity server.
|
|
// Returns a boolean set to true if the association has been validated, false if not.
|
|
// If the association has been validated, also returns the related third-party
|
|
// identifier and its medium.
|
|
// Returns an error if there was a problem sending the request or decoding the
|
|
// response, or if the identity server responded with a non-OK status.
|
|
func CheckAssociation(
|
|
ctx context.Context, creds Credentials, cfg *config.ClientAPI,
|
|
client *fclient.Client,
|
|
) (bool, string, string, error) {
|
|
if err := isTrusted(creds.IDServer, cfg); err != nil {
|
|
return false, "", "", err
|
|
}
|
|
|
|
requestURL := fmt.Sprintf("https://%s/_matrix/identity/api/v1/3pid/getValidated3pid?sid=%s&client_secret=%s", creds.IDServer, creds.SID, creds.Secret)
|
|
req, err := http.NewRequest(http.MethodGet, requestURL, nil)
|
|
if err != nil {
|
|
return false, "", "", err
|
|
}
|
|
resp, err := client.DoHTTPRequest(ctx, req)
|
|
if err != nil {
|
|
return false, "", "", err
|
|
}
|
|
|
|
var respBody GetValidatedResponse
|
|
if err = json.NewDecoder(resp.Body).Decode(&respBody); err != nil {
|
|
return false, "", "", err
|
|
}
|
|
|
|
if respBody.ErrCode == string(spec.ErrorSessionNotValidated) {
|
|
return false, "", "", nil
|
|
} else if len(respBody.ErrCode) > 0 {
|
|
return false, "", "", errors.New(respBody.Error)
|
|
}
|
|
|
|
return true, respBody.Address, respBody.Medium, nil
|
|
}
|
|
|
|
// PublishAssociation publishes a validated association between a third-party
|
|
// identifier and a Matrix ID.
|
|
// Returns an error if there was a problem sending the request or decoding the
|
|
// response, or if the identity server responded with a non-OK status.
|
|
func PublishAssociation(ctx context.Context, creds Credentials, userID string, cfg *config.ClientAPI, client *fclient.Client) error {
|
|
if err := isTrusted(creds.IDServer, cfg); err != nil {
|
|
return err
|
|
}
|
|
|
|
postURL := fmt.Sprintf("https://%s/_matrix/identity/api/v1/3pid/bind", creds.IDServer)
|
|
|
|
data := url.Values{}
|
|
data.Add("sid", creds.SID)
|
|
data.Add("client_secret", creds.Secret)
|
|
data.Add("mxid", userID)
|
|
|
|
request, err := http.NewRequest(http.MethodPost, postURL, strings.NewReader(data.Encode()))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
request.Header.Add("Content-Type", "application/x-www-form-urlencoded")
|
|
|
|
resp, err := client.DoHTTPRequest(ctx, request)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Error if the status isn't OK
|
|
if resp.StatusCode != http.StatusOK {
|
|
return fmt.Errorf("could not publish the association on the server %s", creds.IDServer)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// isTrusted checks if a given identity server is part of the list of trusted
|
|
// identity servers in the configuration file.
|
|
// Returns an error if the server isn't trusted.
|
|
func isTrusted(idServer string, cfg *config.ClientAPI) error {
|
|
for _, server := range cfg.Matrix.TrustedIDServers {
|
|
if idServer == server {
|
|
return nil
|
|
}
|
|
}
|
|
return ErrNotTrusted{}
|
|
}
|