mirror of
https://github.com/hoernschen/dendrite.git
synced 2024-12-26 15:08:28 +00:00
Merge branch 'master' into neilalexander/rsconcurrency
This commit is contained in:
commit
5fe9872290
68 changed files with 251 additions and 158 deletions
|
@ -102,7 +102,7 @@ linters-settings:
|
|||
#local-prefixes: github.com/org/project
|
||||
gocyclo:
|
||||
# minimal code complexity to report, 30 by default (but we recommend 10-20)
|
||||
min-complexity: 13
|
||||
min-complexity: 25
|
||||
maligned:
|
||||
# print struct with more effective memory layout or not, false by default
|
||||
suggest-new: true
|
||||
|
|
|
@ -16,6 +16,7 @@ package appservice
|
|||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
|
@ -48,6 +49,15 @@ func NewInternalAPI(
|
|||
userAPI userapi.UserInternalAPI,
|
||||
rsAPI roomserverAPI.RoomserverInternalAPI,
|
||||
) appserviceAPI.AppServiceQueryAPI {
|
||||
client := &http.Client{
|
||||
Timeout: time.Second * 30,
|
||||
Transport: &http.Transport{
|
||||
DisableKeepAlives: true,
|
||||
TLSClientConfig: &tls.Config{
|
||||
InsecureSkipVerify: base.Cfg.AppServiceAPI.DisableTLSValidation,
|
||||
},
|
||||
},
|
||||
}
|
||||
consumer, _ := kafka.SetupConsumerProducer(&base.Cfg.Global.Kafka)
|
||||
|
||||
// Create a connection to the appservice postgres DB
|
||||
|
@ -79,10 +89,8 @@ func NewInternalAPI(
|
|||
// Create appserivce query API with an HTTP client that will be used for all
|
||||
// outbound and inbound requests (inbound only for the internal API)
|
||||
appserviceQueryAPI := &query.AppServiceQueryAPI{
|
||||
HTTPClient: &http.Client{
|
||||
Timeout: time.Second * 30,
|
||||
},
|
||||
Cfg: base.Cfg,
|
||||
HTTPClient: client,
|
||||
Cfg: base.Cfg,
|
||||
}
|
||||
|
||||
// Only consume if we actually have ASes to track, else we'll just chew cycles needlessly.
|
||||
|
@ -98,7 +106,7 @@ func NewInternalAPI(
|
|||
}
|
||||
|
||||
// Create application service transaction workers
|
||||
if err := workers.SetupTransactionWorkers(appserviceDB, workerStates); err != nil {
|
||||
if err := workers.SetupTransactionWorkers(client, appserviceDB, workerStates); err != nil {
|
||||
logrus.WithError(err).Panicf("failed to start app service transaction workers")
|
||||
}
|
||||
return appserviceQueryAPI
|
||||
|
|
|
@ -85,9 +85,6 @@ func (s *OutputRoomEventConsumer) onMessage(msg *sarama.ConsumerMessage) error {
|
|||
}
|
||||
|
||||
if output.Type != api.OutputTypeNewRoomEvent {
|
||||
log.WithField("type", output.Type).Debug(
|
||||
"roomserver output log: ignoring unknown output type",
|
||||
)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -114,6 +111,7 @@ func (s *OutputRoomEventConsumer) filterRoomserverEvents(
|
|||
// Queue this event to be sent off to the application service
|
||||
if err := s.asDB.StoreEvent(ctx, ws.AppService.ID, event); err != nil {
|
||||
log.WithError(err).Warn("failed to insert incoming event into appservices database")
|
||||
return err
|
||||
} else {
|
||||
// Tell our worker to send out new messages by updating remaining message
|
||||
// count and waking them up with a broadcast
|
||||
|
@ -126,8 +124,43 @@ func (s *OutputRoomEventConsumer) filterRoomserverEvents(
|
|||
return nil
|
||||
}
|
||||
|
||||
// appserviceJoinedAtEvent returns a boolean depending on whether a given
|
||||
// appservice has membership at the time a given event was created.
|
||||
func (s *OutputRoomEventConsumer) appserviceJoinedAtEvent(ctx context.Context, event *gomatrixserverlib.HeaderedEvent, appservice config.ApplicationService) bool {
|
||||
// TODO: This is only checking the current room state, not the state at
|
||||
// the event in question. Pretty sure this is what Synapse does too, but
|
||||
// until we have a lighter way of checking the state before the event that
|
||||
// doesn't involve state res, then this is probably OK.
|
||||
membershipReq := &api.QueryMembershipsForRoomRequest{
|
||||
RoomID: event.RoomID(),
|
||||
JoinedOnly: true,
|
||||
}
|
||||
membershipRes := &api.QueryMembershipsForRoomResponse{}
|
||||
|
||||
// XXX: This could potentially race if the state for the event is not known yet
|
||||
// e.g. the event came over federation but we do not have the full state persisted.
|
||||
if err := s.rsAPI.QueryMembershipsForRoom(ctx, membershipReq, membershipRes); err == nil {
|
||||
for _, ev := range membershipRes.JoinEvents {
|
||||
var membership gomatrixserverlib.MemberContent
|
||||
if err = json.Unmarshal(ev.Content, &membership); err != nil || ev.StateKey == nil {
|
||||
continue
|
||||
}
|
||||
if appservice.IsInterestedInUserID(*ev.StateKey) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.WithFields(log.Fields{
|
||||
"room_id": event.RoomID(),
|
||||
}).WithError(err).Errorf("Unable to get membership for room")
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// appserviceIsInterestedInEvent returns a boolean depending on whether a given
|
||||
// event falls within one of a given application service's namespaces.
|
||||
//
|
||||
// TODO: This should be cached, see https://github.com/matrix-org/dendrite/issues/1682
|
||||
func (s *OutputRoomEventConsumer) appserviceIsInterestedInEvent(ctx context.Context, event *gomatrixserverlib.HeaderedEvent, appservice config.ApplicationService) bool {
|
||||
// No reason to queue events if they'll never be sent to the application
|
||||
// service
|
||||
|
@ -162,5 +195,6 @@ func (s *OutputRoomEventConsumer) appserviceIsInterestedInEvent(ctx context.Cont
|
|||
}).WithError(err).Errorf("Unable to get aliases for room")
|
||||
}
|
||||
|
||||
return false
|
||||
// Check if any of the members in the room match the appservice
|
||||
return s.appserviceJoinedAtEvent(ctx, event, appservice)
|
||||
}
|
||||
|
|
|
@ -20,7 +20,6 @@ import (
|
|||
"context"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/matrix-org/dendrite/appservice/api"
|
||||
"github.com/matrix-org/dendrite/setup/config"
|
||||
|
@ -47,11 +46,6 @@ func (a *AppServiceQueryAPI) RoomAliasExists(
|
|||
span, ctx := opentracing.StartSpanFromContext(ctx, "ApplicationServiceRoomAlias")
|
||||
defer span.Finish()
|
||||
|
||||
// Create an HTTP client if one does not already exist
|
||||
if a.HTTPClient == nil {
|
||||
a.HTTPClient = makeHTTPClient()
|
||||
}
|
||||
|
||||
// Determine which application service should handle this request
|
||||
for _, appservice := range a.Cfg.Derived.ApplicationServices {
|
||||
if appservice.URL != "" && appservice.IsInterestedInRoomAlias(request.Alias) {
|
||||
|
@ -115,11 +109,6 @@ func (a *AppServiceQueryAPI) UserIDExists(
|
|||
span, ctx := opentracing.StartSpanFromContext(ctx, "ApplicationServiceUserID")
|
||||
defer span.Finish()
|
||||
|
||||
// Create an HTTP client if one does not already exist
|
||||
if a.HTTPClient == nil {
|
||||
a.HTTPClient = makeHTTPClient()
|
||||
}
|
||||
|
||||
// Determine which application service should handle this request
|
||||
for _, appservice := range a.Cfg.Derived.ApplicationServices {
|
||||
if appservice.URL != "" && appservice.IsInterestedInUserID(request.UserID) {
|
||||
|
@ -169,10 +158,3 @@ func (a *AppServiceQueryAPI) UserIDExists(
|
|||
response.UserIDExists = false
|
||||
return nil
|
||||
}
|
||||
|
||||
// makeHTTPClient creates an HTTP client with certain options that will be used for all query requests to application services
|
||||
func makeHTTPClient() *http.Client {
|
||||
return &http.Client{
|
||||
Timeout: time.Second * 30,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,8 +34,6 @@ import (
|
|||
var (
|
||||
// Maximum size of events sent in each transaction.
|
||||
transactionBatchSize = 50
|
||||
// Timeout for sending a single transaction to an application service.
|
||||
transactionTimeout = time.Second * 60
|
||||
)
|
||||
|
||||
// SetupTransactionWorkers spawns a separate goroutine for each application
|
||||
|
@ -44,6 +42,7 @@ var (
|
|||
// size), then send that off to the AS's /transactions/{txnID} endpoint. It also
|
||||
// handles exponentially backing off in case the AS isn't currently available.
|
||||
func SetupTransactionWorkers(
|
||||
client *http.Client,
|
||||
appserviceDB storage.Database,
|
||||
workerStates []types.ApplicationServiceWorkerState,
|
||||
) error {
|
||||
|
@ -51,7 +50,7 @@ func SetupTransactionWorkers(
|
|||
for _, workerState := range workerStates {
|
||||
// Don't create a worker if this AS doesn't want to receive events
|
||||
if workerState.AppService.URL != "" {
|
||||
go worker(appserviceDB, workerState)
|
||||
go worker(client, appserviceDB, workerState)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
@ -59,17 +58,12 @@ func SetupTransactionWorkers(
|
|||
|
||||
// worker is a goroutine that sends any queued events to the application service
|
||||
// it is given.
|
||||
func worker(db storage.Database, ws types.ApplicationServiceWorkerState) {
|
||||
func worker(client *http.Client, db storage.Database, ws types.ApplicationServiceWorkerState) {
|
||||
log.WithFields(log.Fields{
|
||||
"appservice": ws.AppService.ID,
|
||||
}).Info("starting application service")
|
||||
}).Info("Starting application service")
|
||||
ctx := context.Background()
|
||||
|
||||
// Create a HTTP client for sending requests to app services
|
||||
client := &http.Client{
|
||||
Timeout: transactionTimeout,
|
||||
}
|
||||
|
||||
// Initial check for any leftover events to send from last time
|
||||
eventCount, err := db.CountEventsWithAppServiceID(ctx, ws.AppService.ID)
|
||||
if err != nil {
|
||||
|
|
|
@ -217,7 +217,8 @@ func createRoom(
|
|||
roomAlias = fmt.Sprintf("#%s:%s", r.RoomAliasName, cfg.Matrix.ServerName)
|
||||
// check it's free TODO: This races but is better than nothing
|
||||
hasAliasReq := roomserverAPI.GetRoomIDForAliasRequest{
|
||||
Alias: roomAlias,
|
||||
Alias: roomAlias,
|
||||
IncludeAppservices: false,
|
||||
}
|
||||
|
||||
var aliasResp roomserverAPI.GetRoomIDForAliasResponse
|
||||
|
|
|
@ -61,9 +61,12 @@ func DirectoryRoom(
|
|||
var res roomDirectoryResponse
|
||||
|
||||
// Query the roomserver API to check if the alias exists locally.
|
||||
queryReq := roomserverAPI.GetRoomIDForAliasRequest{Alias: roomAlias}
|
||||
var queryRes roomserverAPI.GetRoomIDForAliasResponse
|
||||
if err = rsAPI.GetRoomIDForAlias(req.Context(), &queryReq, &queryRes); err != nil {
|
||||
queryReq := &roomserverAPI.GetRoomIDForAliasRequest{
|
||||
Alias: roomAlias,
|
||||
IncludeAppservices: true,
|
||||
}
|
||||
queryRes := &roomserverAPI.GetRoomIDForAliasResponse{}
|
||||
if err = rsAPI.GetRoomIDForAlias(req.Context(), queryReq, queryRes); err != nil {
|
||||
util.GetLogger(req.Context()).WithError(err).Error("rsAPI.GetRoomIDForAlias failed")
|
||||
return jsonerror.InternalServerError()
|
||||
}
|
||||
|
|
|
@ -103,8 +103,22 @@ func GetEvent(
|
|||
}
|
||||
}
|
||||
|
||||
var appService *config.ApplicationService
|
||||
if device.AppserviceID != "" {
|
||||
for _, as := range cfg.Derived.ApplicationServices {
|
||||
if as.ID == device.AppserviceID {
|
||||
appService = &as
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, stateEvent := range stateResp.StateEvents {
|
||||
if !stateEvent.StateKeyEquals(device.UserID) {
|
||||
if appService != nil {
|
||||
if !appService.IsInterestedInUserID(*stateEvent.StateKey()) {
|
||||
continue
|
||||
}
|
||||
} else if !stateEvent.StateKeyEquals(device.UserID) {
|
||||
continue
|
||||
}
|
||||
membership, err := stateEvent.Membership()
|
||||
|
|
|
@ -91,7 +91,6 @@ func GetAvatarURL(
|
|||
}
|
||||
|
||||
// SetAvatarURL implements PUT /profile/{userID}/avatar_url
|
||||
// nolint:gocyclo
|
||||
func SetAvatarURL(
|
||||
req *http.Request, accountDB accounts.Database,
|
||||
device *userapi.Device, userID string, cfg *config.ClientAPI, rsAPI api.RoomserverInternalAPI,
|
||||
|
@ -209,7 +208,6 @@ func GetDisplayName(
|
|||
}
|
||||
|
||||
// SetDisplayName implements PUT /profile/{userID}/displayname
|
||||
// nolint:gocyclo
|
||||
func SetDisplayName(
|
||||
req *http.Request, accountDB accounts.Database,
|
||||
device *userapi.Device, userID string, cfg *config.ClientAPI, rsAPI api.RoomserverInternalAPI,
|
||||
|
|
|
@ -496,11 +496,20 @@ func Register(
|
|||
r.Username = strconv.FormatInt(id, 10)
|
||||
}
|
||||
|
||||
// Is this an appservice registration? It will be if the access
|
||||
// token is supplied
|
||||
accessToken, accessTokenErr := auth.ExtractAccessToken(req)
|
||||
|
||||
// Squash username to all lowercase letters
|
||||
r.Username = strings.ToLower(r.Username)
|
||||
|
||||
if resErr = validateUsername(r.Username); resErr != nil {
|
||||
return *resErr
|
||||
if r.Type == authtypes.LoginTypeApplicationService && accessTokenErr == nil {
|
||||
if resErr = validateApplicationServiceUsername(r.Username); resErr != nil {
|
||||
return *resErr
|
||||
}
|
||||
} else {
|
||||
if resErr = validateUsername(r.Username); resErr != nil {
|
||||
return *resErr
|
||||
}
|
||||
}
|
||||
if resErr = validatePassword(r.Password); resErr != nil {
|
||||
return *resErr
|
||||
|
@ -513,7 +522,7 @@ func Register(
|
|||
"session_id": r.Auth.Session,
|
||||
}).Info("Processing registration request")
|
||||
|
||||
return handleRegistrationFlow(req, r, sessionID, cfg, userAPI)
|
||||
return handleRegistrationFlow(req, r, sessionID, cfg, userAPI, accessToken, accessTokenErr)
|
||||
}
|
||||
|
||||
func handleGuestRegistration(
|
||||
|
@ -579,6 +588,8 @@ func handleRegistrationFlow(
|
|||
sessionID string,
|
||||
cfg *config.ClientAPI,
|
||||
userAPI userapi.UserInternalAPI,
|
||||
accessToken string,
|
||||
accessTokenErr error,
|
||||
) util.JSONResponse {
|
||||
// TODO: Shared secret registration (create new user scripts)
|
||||
// TODO: Enable registration config flag
|
||||
|
@ -588,12 +599,12 @@ func handleRegistrationFlow(
|
|||
// TODO: Handle mapping registrationRequest parameters into session parameters
|
||||
|
||||
// TODO: email / msisdn auth types.
|
||||
accessToken, accessTokenErr := auth.ExtractAccessToken(req)
|
||||
|
||||
// Appservices are special and are not affected by disabled
|
||||
// registration or user exclusivity.
|
||||
if r.Auth.Type == authtypes.LoginTypeApplicationService ||
|
||||
(r.Auth.Type == "" && accessTokenErr == nil) {
|
||||
// registration or user exclusivity. We'll go onto the appservice
|
||||
// registration flow if a valid access token was provided or if
|
||||
// the login type specifically requests it.
|
||||
if r.Type == authtypes.LoginTypeApplicationService && accessTokenErr == nil {
|
||||
return handleApplicationServiceRegistration(
|
||||
accessToken, accessTokenErr, req, r, cfg, userAPI,
|
||||
)
|
||||
|
|
|
@ -161,7 +161,6 @@ func OnIncomingStateRequest(ctx context.Context, device *userapi.Device, rsAPI a
|
|||
// state to see if there is an event with that type and state key, if there
|
||||
// is then (by default) we return the content, otherwise a 404.
|
||||
// If eventFormat=true, sends the whole event else just the content.
|
||||
// nolint:gocyclo
|
||||
func OnIncomingStateTypeRequest(
|
||||
ctx context.Context, device *userapi.Device, rsAPI api.RoomserverInternalAPI,
|
||||
roomID, evType, stateKey string, eventFormat bool,
|
||||
|
|
|
@ -24,6 +24,7 @@ import (
|
|||
"github.com/matrix-org/dendrite/setup/config"
|
||||
"github.com/matrix-org/dendrite/userapi/storage/accounts"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
const usage = `Usage: %s
|
||||
|
@ -57,7 +58,7 @@ func main() {
|
|||
|
||||
accountDB, err := accounts.NewDatabase(&config.DatabaseOptions{
|
||||
ConnectionString: cfg.UserAPI.AccountDatabase.ConnectionString,
|
||||
}, cfg.Global.ServerName)
|
||||
}, cfg.Global.ServerName, bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
logrus.Fatalln("Failed to connect to the database:", err.Error())
|
||||
}
|
||||
|
|
|
@ -52,7 +52,6 @@ var (
|
|||
instancePeer = flag.String("peer", "", "an internet Yggdrasil peer to connect to")
|
||||
)
|
||||
|
||||
// nolint:gocyclo
|
||||
func main() {
|
||||
flag.Parse()
|
||||
internal.SetupPprof()
|
||||
|
|
|
@ -73,7 +73,6 @@ func (n *Node) DialerContext(ctx context.Context, network, address string) (net.
|
|||
return n.Dialer(network, address)
|
||||
}
|
||||
|
||||
// nolint:gocyclo
|
||||
func Setup(instanceName, storageDirectory string) (*Node, error) {
|
||||
n := &Node{
|
||||
core: &yggdrasil.Core{},
|
||||
|
|
|
@ -128,7 +128,6 @@ func (n *Node) Dial(network, address string) (net.Conn, error) {
|
|||
}
|
||||
|
||||
// Implements http.Transport.DialContext
|
||||
// nolint:gocyclo
|
||||
func (n *Node) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
|
||||
s, ok1 := n.sessions.Load(address)
|
||||
session, ok2 := s.(*session)
|
||||
|
|
|
@ -20,7 +20,6 @@ var requestFrom = flag.String("from", "", "the server name that the request shou
|
|||
var requestKey = flag.String("key", "matrix_key.pem", "the private key to use when signing the request")
|
||||
var requestPost = flag.Bool("post", false, "send a POST request instead of GET (pipe input into stdin or type followed by Ctrl-D)")
|
||||
|
||||
// nolint:gocyclo
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"fmt"
|
||||
|
||||
"github.com/matrix-org/dendrite/setup/config"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
|
@ -61,12 +62,14 @@ func main() {
|
|||
}
|
||||
|
||||
if *defaultsForCI {
|
||||
cfg.AppServiceAPI.DisableTLSValidation = true
|
||||
cfg.ClientAPI.RateLimiting.Enabled = false
|
||||
cfg.FederationSender.DisableTLSValidation = true
|
||||
cfg.MSCs.MSCs = []string{"msc2836", "msc2946", "msc2444", "msc2753"}
|
||||
cfg.Logging[0].Level = "trace"
|
||||
// don't hit matrix.org when running tests!!!
|
||||
cfg.SigningKeyServer.KeyPerspectives = config.KeyPerspectives{}
|
||||
cfg.UserAPI.BCryptCost = bcrypt.MinCost
|
||||
}
|
||||
|
||||
j, err := yaml.Marshal(cfg)
|
||||
|
|
|
@ -24,7 +24,6 @@ import (
|
|||
|
||||
var roomVersion = flag.String("roomversion", "5", "the room version to parse events as")
|
||||
|
||||
// nolint:gocyclo
|
||||
func main() {
|
||||
ctx := context.Background()
|
||||
cfg := setup.ParseFlags(true)
|
||||
|
|
|
@ -125,6 +125,11 @@ app_service_api:
|
|||
max_idle_conns: 2
|
||||
conn_max_lifetime: -1
|
||||
|
||||
# Disable the validation of TLS certificates of appservices. This is
|
||||
# not recommended in production since it may allow appservice traffic
|
||||
# to be sent to an unverified endpoint.
|
||||
disable_tls_validation: false
|
||||
|
||||
# Appservice configuration files to load into this homeserver.
|
||||
config_files: []
|
||||
|
||||
|
@ -235,7 +240,7 @@ media_api:
|
|||
listen: http://[::]:8074
|
||||
database:
|
||||
connection_string: file:mediaapi.db
|
||||
max_open_conns: 10
|
||||
max_open_conns: 5
|
||||
max_idle_conns: 2
|
||||
conn_max_lifetime: -1
|
||||
|
||||
|
@ -273,7 +278,7 @@ mscs:
|
|||
mscs: []
|
||||
database:
|
||||
connection_string: file:mscs.db
|
||||
max_open_conns: 10
|
||||
max_open_conns: 5
|
||||
max_idle_conns: 2
|
||||
conn_max_lifetime: -1
|
||||
|
||||
|
@ -335,6 +340,13 @@ sync_api:
|
|||
|
||||
# Configuration for the User API.
|
||||
user_api:
|
||||
# The cost when hashing passwords on registration/login. Default: 10. Min: 4, Max: 31
|
||||
# See https://pkg.go.dev/golang.org/x/crypto/bcrypt for more information.
|
||||
# Setting this lower makes registration/login consume less CPU resources at the cost of security
|
||||
# should the database be compromised. Setting this higher makes registration/login consume more
|
||||
# CPU resources but makes it harder to brute force password hashes.
|
||||
# This value can be low if performing tests or on embedded Dendrite instances (e.g WASM builds)
|
||||
# bcrypt_cost: 10
|
||||
internal_api:
|
||||
listen: http://localhost:7781
|
||||
connect: http://localhost:7781
|
||||
|
|
|
@ -29,7 +29,6 @@ import (
|
|||
)
|
||||
|
||||
// MakeJoin implements the /make_join API
|
||||
// nolint:gocyclo
|
||||
func MakeJoin(
|
||||
httpReq *http.Request,
|
||||
request *gomatrixserverlib.FederationRequest,
|
||||
|
@ -161,7 +160,6 @@ func MakeJoin(
|
|||
// SendJoin implements the /send_join API
|
||||
// The make-join send-join dance makes much more sense as a single
|
||||
// flow so the cyclomatic complexity is high:
|
||||
// nolint:gocyclo
|
||||
func SendJoin(
|
||||
httpReq *http.Request,
|
||||
request *gomatrixserverlib.FederationRequest,
|
||||
|
|
|
@ -25,7 +25,6 @@ import (
|
|||
)
|
||||
|
||||
// MakeLeave implements the /make_leave API
|
||||
// nolint:gocyclo
|
||||
func MakeLeave(
|
||||
httpReq *http.Request,
|
||||
request *gomatrixserverlib.FederationRequest,
|
||||
|
@ -118,7 +117,6 @@ func MakeLeave(
|
|||
}
|
||||
|
||||
// SendLeave implements the /send_leave API
|
||||
// nolint:gocyclo
|
||||
func SendLeave(
|
||||
httpReq *http.Request,
|
||||
request *gomatrixserverlib.FederationRequest,
|
||||
|
|
|
@ -111,7 +111,6 @@ func fillPublicRoomsReq(httpReq *http.Request, request *PublicRoomReq) *util.JSO
|
|||
}
|
||||
|
||||
// due to lots of switches
|
||||
// nolint:gocyclo
|
||||
func fillInRooms(ctx context.Context, roomIDs []string, rsAPI roomserverAPI.RoomserverInternalAPI) ([]gomatrixserverlib.PublicRoom, error) {
|
||||
avatarTuple := gomatrixserverlib.StateKeyTuple{EventType: "m.room.avatar", StateKey: ""}
|
||||
nameTuple := gomatrixserverlib.StateKeyTuple{EventType: "m.room.name", StateKey: ""}
|
||||
|
|
|
@ -53,9 +53,12 @@ func RoomAliasToID(
|
|||
var resp gomatrixserverlib.RespDirectory
|
||||
|
||||
if domain == cfg.Matrix.ServerName {
|
||||
queryReq := roomserverAPI.GetRoomIDForAliasRequest{Alias: roomAlias}
|
||||
var queryRes roomserverAPI.GetRoomIDForAliasResponse
|
||||
if err = rsAPI.GetRoomIDForAlias(httpReq.Context(), &queryReq, &queryRes); err != nil {
|
||||
queryReq := &roomserverAPI.GetRoomIDForAliasRequest{
|
||||
Alias: roomAlias,
|
||||
IncludeAppservices: true,
|
||||
}
|
||||
queryRes := &roomserverAPI.GetRoomIDForAliasResponse{}
|
||||
if err = rsAPI.GetRoomIDForAlias(httpReq.Context(), queryReq, queryRes); err != nil {
|
||||
util.GetLogger(httpReq.Context()).WithError(err).Error("aliasAPI.GetRoomIDForAlias failed")
|
||||
return jsonerror.InternalServerError()
|
||||
}
|
||||
|
|
|
@ -279,7 +279,6 @@ func (t *txnReq) haveEventIDs() map[string]bool {
|
|||
return result
|
||||
}
|
||||
|
||||
// nolint:gocyclo
|
||||
func (t *txnReq) processEDUs(ctx context.Context) {
|
||||
for _, e := range t.EDUs {
|
||||
switch e.Type {
|
||||
|
@ -540,7 +539,6 @@ func checkAllowedByState(e *gomatrixserverlib.Event, stateEvents []*gomatrixserv
|
|||
return gomatrixserverlib.Allowed(e, &authUsingState)
|
||||
}
|
||||
|
||||
// nolint:gocyclo
|
||||
func (t *txnReq) processEventWithMissingState(ctx context.Context, e *gomatrixserverlib.Event, roomVersion gomatrixserverlib.RoomVersion) error {
|
||||
// Do this with a fresh context, so that we keep working even if the
|
||||
// original request times out. With any luck, by the time the remote
|
||||
|
@ -832,7 +830,6 @@ retryAllowedState:
|
|||
// begin from. Returns an error only if we should terminate the transaction which initiated /get_missing_events
|
||||
// This function recursively calls txnReq.processEvent with the missing events, which will be processed before this function returns.
|
||||
// This means that we may recursively call this function, as we spider back up prev_events.
|
||||
// nolint:gocyclo
|
||||
func (t *txnReq) getMissingEvents(ctx context.Context, e *gomatrixserverlib.Event, roomVersion gomatrixserverlib.RoomVersion) (newEvents []*gomatrixserverlib.Event, err error) {
|
||||
logger := util.GetLogger(ctx).WithField("event_id", e.EventID()).WithField("room_id", e.RoomID())
|
||||
needed := gomatrixserverlib.StateNeededForAuth([]*gomatrixserverlib.Event{e})
|
||||
|
@ -935,7 +932,6 @@ func (t *txnReq) lookupMissingStateViaState(ctx context.Context, roomID, eventID
|
|||
return &state, nil
|
||||
}
|
||||
|
||||
// nolint:gocyclo
|
||||
func (t *txnReq) lookupMissingStateViaStateIDs(ctx context.Context, roomID, eventID string, roomVersion gomatrixserverlib.RoomVersion) (
|
||||
*gomatrixserverlib.RespState, error) {
|
||||
util.GetLogger(ctx).Infof("lookupMissingStateViaStateIDs %s", eventID)
|
||||
|
|
|
@ -173,7 +173,6 @@ func (oq *destinationQueue) wakeQueueIfNeeded() {
|
|||
// getPendingFromDatabase will look at the database and see if
|
||||
// there are any persisted events that haven't been sent to this
|
||||
// destination yet. If so, they will be queued up.
|
||||
// nolint:gocyclo
|
||||
func (oq *destinationQueue) getPendingFromDatabase() {
|
||||
// Check to see if there's anything to do for this server
|
||||
// in the database.
|
||||
|
@ -238,7 +237,6 @@ func (oq *destinationQueue) getPendingFromDatabase() {
|
|||
}
|
||||
|
||||
// backgroundSend is the worker goroutine for sending events.
|
||||
// nolint:gocyclo
|
||||
func (oq *destinationQueue) backgroundSend() {
|
||||
// Check if a worker is already running, and if it isn't, then
|
||||
// mark it as started.
|
||||
|
@ -353,7 +351,6 @@ func (oq *destinationQueue) backgroundSend() {
|
|||
// nextTransaction creates a new transaction from the pending event
|
||||
// queue and sends it. Returns true if a transaction was sent or
|
||||
// false otherwise.
|
||||
// nolint:gocyclo
|
||||
func (oq *destinationQueue) nextTransaction(
|
||||
pdus []*queuedPDU,
|
||||
edus []*queuedEDU,
|
||||
|
|
2
go.sum
2
go.sum
|
@ -866,8 +866,6 @@ github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5k
|
|||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.8.0 h1:nfhvjKcUMhBMVqbKHJlk5RPrrfYr/NMo3692g0dwfWU=
|
||||
github.com/sirupsen/logrus v1.8.0/go.mod h1:4GuYW9TZmE769R5STWrRakJc4UqQ3+QQ95fyz7ENv1A=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
|
|
|
@ -34,6 +34,9 @@ type SetRoomAliasResponse struct {
|
|||
type GetRoomIDForAliasRequest struct {
|
||||
// Alias we want to lookup
|
||||
Alias string `json:"alias"`
|
||||
// Should we ask appservices for their aliases as a part of
|
||||
// the request?
|
||||
IncludeAppservices bool `json:"include_appservices"`
|
||||
}
|
||||
|
||||
// GetRoomIDForAliasResponse is a response to GetRoomIDForAlias
|
||||
|
|
|
@ -151,7 +151,9 @@ type QueryMembershipsForRoomRequest struct {
|
|||
JoinedOnly bool `json:"joined_only"`
|
||||
// ID of the room to fetch memberships from
|
||||
RoomID string `json:"room_id"`
|
||||
// ID of the user sending the request
|
||||
// Optional - ID of the user sending the request, for checking if the
|
||||
// user is allowed to see the memberships. If not specified then all
|
||||
// room memberships will be returned.
|
||||
Sender string `json:"sender"`
|
||||
}
|
||||
|
||||
|
|
|
@ -172,7 +172,6 @@ func IsServerBannedFromRoom(ctx context.Context, rsAPI RoomserverInternalAPI, ro
|
|||
// PopulatePublicRooms extracts PublicRoom information for all the provided room IDs. The IDs are not checked to see if they are visible in the
|
||||
// published room directory.
|
||||
// due to lots of switches
|
||||
// nolint:gocyclo
|
||||
func PopulatePublicRooms(ctx context.Context, roomIDs []string, rsAPI RoomserverInternalAPI) ([]gomatrixserverlib.PublicRoom, error) {
|
||||
avatarTuple := gomatrixserverlib.StateKeyTuple{EventType: "m.room.avatar", StateKey: ""}
|
||||
nameTuple := gomatrixserverlib.StateKeyTuple{EventType: "m.room.name", StateKey: ""}
|
||||
|
|
|
@ -88,31 +88,35 @@ func (r *RoomserverInternalAPI) GetRoomIDForAlias(
|
|||
) error {
|
||||
// Look up the room ID in the database
|
||||
roomID, err := r.DB.GetRoomIDForAlias(ctx, request.Alias)
|
||||
if err != nil {
|
||||
return err
|
||||
if err == nil && roomID != "" {
|
||||
response.RoomID = roomID
|
||||
return nil
|
||||
}
|
||||
|
||||
if r.asAPI != nil { // appservice component is wired in
|
||||
if roomID == "" {
|
||||
// No room found locally, try our application services by making a call to
|
||||
// the appservice component
|
||||
aliasReq := asAPI.RoomAliasExistsRequest{Alias: request.Alias}
|
||||
var aliasResp asAPI.RoomAliasExistsResponse
|
||||
if err = r.asAPI.RoomAliasExists(ctx, &aliasReq, &aliasResp); err != nil {
|
||||
// Check appservice on err, but only if the appservice API is
|
||||
// wired in and no room ID was found.
|
||||
if r.asAPI != nil && request.IncludeAppservices && roomID == "" {
|
||||
// No room found locally, try our application services by making a call to
|
||||
// the appservice component
|
||||
aliasReq := &asAPI.RoomAliasExistsRequest{
|
||||
Alias: request.Alias,
|
||||
}
|
||||
aliasRes := &asAPI.RoomAliasExistsResponse{}
|
||||
if err = r.asAPI.RoomAliasExists(ctx, aliasReq, aliasRes); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if aliasRes.AliasExists {
|
||||
roomID, err = r.DB.GetRoomIDForAlias(ctx, request.Alias)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if aliasResp.AliasExists {
|
||||
roomID, err = r.DB.GetRoomIDForAlias(ctx, request.Alias)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
response.RoomID = roomID
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
response.RoomID = roomID
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
|
||||
// GetAliasesForRoomID implements alias.RoomserverInternalAPI
|
||||
|
|
|
@ -89,6 +89,7 @@ func (r *RoomserverInternalAPI) SetFederationSenderAPI(fsAPI fsAPI.FederationSen
|
|||
Cfg: r.Cfg,
|
||||
DB: r.DB,
|
||||
FSAPI: r.fsAPI,
|
||||
RSAPI: r,
|
||||
Inputer: r.Inputer,
|
||||
}
|
||||
r.Peeker = &perform.Peeker{
|
||||
|
|
|
@ -270,7 +270,6 @@ func CheckServerAllowedToSeeEvent(
|
|||
}
|
||||
|
||||
// TODO: Remove this when we have tests to assert correctness of this function
|
||||
// nolint:gocyclo
|
||||
func ScanEventTree(
|
||||
ctx context.Context, db storage.Database, info types.RoomInfo, front []string, visited map[string]bool, limit int,
|
||||
serverName gomatrixserverlib.ServerName,
|
||||
|
|
|
@ -381,7 +381,6 @@ func (b *backfillRequester) StateBeforeEvent(ctx context.Context, roomVer gomatr
|
|||
// It returns a list of servers which can be queried for backfill requests. These servers
|
||||
// will be servers that are in the room already. The entries at the beginning are preferred servers
|
||||
// and will be tried first. An empty list will fail the request.
|
||||
// nolint:gocyclo
|
||||
func (b *backfillRequester) ServersAtEvent(ctx context.Context, roomID, eventID string) []gomatrixserverlib.ServerName {
|
||||
// eventID will be a prev_event ID of a backwards extremity, meaning we will not have a database entry for it. Instead, use
|
||||
// its successor, so look it up.
|
||||
|
|
|
@ -37,7 +37,6 @@ type Inviter struct {
|
|||
Inputer *input.Inputer
|
||||
}
|
||||
|
||||
// nolint:gocyclo
|
||||
func (r *Inviter) PerformInvite(
|
||||
ctx context.Context,
|
||||
req *api.PerformInviteRequest,
|
||||
|
|
|
@ -24,6 +24,7 @@ import (
|
|||
fsAPI "github.com/matrix-org/dendrite/federationsender/api"
|
||||
"github.com/matrix-org/dendrite/internal/eventutil"
|
||||
"github.com/matrix-org/dendrite/roomserver/api"
|
||||
rsAPI "github.com/matrix-org/dendrite/roomserver/api"
|
||||
"github.com/matrix-org/dendrite/roomserver/internal/helpers"
|
||||
"github.com/matrix-org/dendrite/roomserver/internal/input"
|
||||
"github.com/matrix-org/dendrite/roomserver/storage"
|
||||
|
@ -36,6 +37,7 @@ type Joiner struct {
|
|||
ServerName gomatrixserverlib.ServerName
|
||||
Cfg *config.RoomServer
|
||||
FSAPI fsAPI.FederationSenderInternalAPI
|
||||
RSAPI rsAPI.RoomserverInternalAPI
|
||||
DB storage.Database
|
||||
|
||||
Inputer *input.Inputer
|
||||
|
@ -121,11 +123,17 @@ func (r *Joiner) performJoinRoomByAlias(
|
|||
roomID = dirRes.RoomID
|
||||
req.ServerNames = append(req.ServerNames, dirRes.ServerNames...)
|
||||
} else {
|
||||
var getRoomReq = rsAPI.GetRoomIDForAliasRequest{
|
||||
Alias: req.RoomIDOrAlias,
|
||||
IncludeAppservices: true,
|
||||
}
|
||||
var getRoomRes = rsAPI.GetRoomIDForAliasResponse{}
|
||||
// Otherwise, look up if we know this room alias locally.
|
||||
roomID, err = r.DB.GetRoomIDForAlias(ctx, req.RoomIDOrAlias)
|
||||
err = r.RSAPI.GetRoomIDForAlias(ctx, &getRoomReq, &getRoomRes)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("Lookup room alias %q failed: %w", req.RoomIDOrAlias, err)
|
||||
}
|
||||
roomID = getRoomRes.RoomID
|
||||
}
|
||||
|
||||
// If the room ID is empty then we failed to look up the alias.
|
||||
|
@ -139,7 +147,6 @@ func (r *Joiner) performJoinRoomByAlias(
|
|||
}
|
||||
|
||||
// TODO: Break this function up a bit
|
||||
// nolint:gocyclo
|
||||
func (r *Joiner) performJoinRoomByID(
|
||||
ctx context.Context,
|
||||
req *api.PerformJoinRequest,
|
||||
|
|
|
@ -49,7 +49,6 @@ func (r *Queryer) QueryLatestEventsAndState(
|
|||
}
|
||||
|
||||
// QueryStateAfterEvents implements api.RoomserverInternalAPI
|
||||
// nolint:gocyclo
|
||||
func (r *Queryer) QueryStateAfterEvents(
|
||||
ctx context.Context,
|
||||
request *api.QueryStateAfterEventsRequest,
|
||||
|
@ -243,6 +242,27 @@ func (r *Queryer) QueryMembershipsForRoom(
|
|||
return err
|
||||
}
|
||||
|
||||
// If no sender is specified then we will just return the entire
|
||||
// set of memberships for the room, regardless of whether a specific
|
||||
// user is allowed to see them or not.
|
||||
if request.Sender == "" {
|
||||
var events []types.Event
|
||||
var eventNIDs []types.EventNID
|
||||
eventNIDs, err = r.DB.GetMembershipEventNIDsForRoom(ctx, info.RoomNID, request.JoinedOnly, false)
|
||||
if err != nil {
|
||||
return fmt.Errorf("r.DB.GetMembershipEventNIDsForRoom: %w", err)
|
||||
}
|
||||
events, err = r.DB.Events(ctx, eventNIDs)
|
||||
if err != nil {
|
||||
return fmt.Errorf("r.DB.Events: %w", err)
|
||||
}
|
||||
for _, event := range events {
|
||||
clientEvent := gomatrixserverlib.ToClientEvent(event.Event, gomatrixserverlib.FormatAll)
|
||||
response.JoinEvents = append(response.JoinEvents, clientEvent)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
membershipEventNID, stillInRoom, isRoomforgotten, err := r.DB.GetMembership(ctx, info.RoomNID, request.Sender)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -372,7 +392,6 @@ func (r *Queryer) QueryServerAllowedToSeeEvent(
|
|||
}
|
||||
|
||||
// QueryMissingEvents implements api.RoomserverInternalAPI
|
||||
// nolint:gocyclo
|
||||
func (r *Queryer) QueryMissingEvents(
|
||||
ctx context.Context,
|
||||
request *api.QueryMissingEventsRequest,
|
||||
|
|
|
@ -770,7 +770,6 @@ func (v *StateResolution) resolveConflictsV1(
|
|||
// Returns a list that combines the entries without conflicts with the result of state resolution for the entries with conflicts.
|
||||
// The returned list is sorted by state key tuple.
|
||||
// Returns an error if there was a problem talking to the database.
|
||||
// nolint:gocyclo
|
||||
func (v *StateResolution) resolveConflictsV2(
|
||||
ctx context.Context,
|
||||
notConflicted, conflicted []types.StateEntry,
|
||||
|
|
|
@ -412,7 +412,6 @@ func (d *Database) GetLatestEventsForUpdate(
|
|||
return updater, err
|
||||
}
|
||||
|
||||
// nolint:gocyclo
|
||||
func (d *Database) StoreEvent(
|
||||
ctx context.Context, event *gomatrixserverlib.Event,
|
||||
txnAndSessionID *api.TransactionID, authEventNIDs []types.EventNID, isRejected bool,
|
||||
|
@ -672,7 +671,6 @@ func extractRoomVersionFromCreateEvent(event *gomatrixserverlib.Event) (
|
|||
// to cross-reference with other tables when loading.
|
||||
//
|
||||
// Returns the redaction event and the event ID of the redacted event if this call resulted in a redaction.
|
||||
// nolint:gocyclo
|
||||
func (d *Database) handleRedactions(
|
||||
ctx context.Context, txn *sql.Tx, eventNID types.EventNID, event *gomatrixserverlib.Event,
|
||||
) (*gomatrixserverlib.Event, string, error) {
|
||||
|
@ -802,7 +800,6 @@ func (d *Database) loadEvent(ctx context.Context, eventID string) *types.Event {
|
|||
// GetStateEvent returns the current state event of a given type for a given room with a given state key
|
||||
// If no event could be found, returns nil
|
||||
// If there was an issue during the retrieval, returns an error
|
||||
// nolint:gocyclo
|
||||
func (d *Database) GetStateEvent(ctx context.Context, roomID, evType, stateKey string) (*gomatrixserverlib.HeaderedEvent, error) {
|
||||
roomInfo, err := d.RoomInfo(ctx, roomID)
|
||||
if err != nil {
|
||||
|
@ -893,7 +890,6 @@ func (d *Database) GetRoomsByMembership(ctx context.Context, userID, membership
|
|||
|
||||
// GetBulkStateContent returns all state events which match a given room ID and a given state key tuple. Both must be satisfied for a match.
|
||||
// If a tuple has the StateKey of '*' and allowWildcards=true then all state events with the EventType should be returned.
|
||||
// nolint:gocyclo
|
||||
func (d *Database) GetBulkStateContent(ctx context.Context, roomIDs []string, tuples []gomatrixserverlib.StateKeyTuple, allowWildcards bool) ([]tables.StrippedEvent, error) {
|
||||
eventTypes := make([]string, 0, len(tuples))
|
||||
for _, tuple := range tuples {
|
||||
|
|
|
@ -263,7 +263,7 @@ func (b *BaseDendrite) KeyServerHTTPClient() keyserverAPI.KeyInternalAPI {
|
|||
// CreateAccountsDB creates a new instance of the accounts database. Should only
|
||||
// be called once per component.
|
||||
func (b *BaseDendrite) CreateAccountsDB() accounts.Database {
|
||||
db, err := accounts.NewDatabase(&b.Cfg.UserAPI.AccountDatabase, b.Cfg.Global.ServerName)
|
||||
db, err := accounts.NewDatabase(&b.Cfg.UserAPI.AccountDatabase, b.Cfg.Global.ServerName, b.Cfg.UserAPI.BCryptCost)
|
||||
if err != nil {
|
||||
logrus.WithError(err).Panicf("failed to connect to accounts db")
|
||||
}
|
||||
|
@ -316,7 +316,6 @@ func (b *BaseDendrite) CreateFederationClient() *gomatrixserverlib.FederationCli
|
|||
|
||||
// SetupAndServeHTTP sets up the HTTP server to serve endpoints registered on
|
||||
// ApiMux under /api/ and adds a prometheus handler under /metrics.
|
||||
// nolint:gocyclo
|
||||
func (b *BaseDendrite) SetupAndServeHTTP(
|
||||
internalHTTPAddr, externalHTTPAddr config.HTTPAddress,
|
||||
certFile, keyFile *string,
|
||||
|
|
|
@ -33,13 +33,17 @@ type AppServiceAPI struct {
|
|||
|
||||
Database DatabaseOptions `yaml:"database"`
|
||||
|
||||
// DisableTLSValidation disables the validation of X.509 TLS certs
|
||||
// on appservice endpoints. This is not recommended in production!
|
||||
DisableTLSValidation bool `yaml:"disable_tls_validation"`
|
||||
|
||||
ConfigFiles []string `yaml:"config_files"`
|
||||
}
|
||||
|
||||
func (c *AppServiceAPI) Defaults() {
|
||||
c.InternalAPI.Listen = "http://localhost:7777"
|
||||
c.InternalAPI.Connect = "http://localhost:7777"
|
||||
c.Database.Defaults()
|
||||
c.Database.Defaults(10)
|
||||
c.Database.ConnectionString = "file:appservice.db"
|
||||
}
|
||||
|
||||
|
@ -193,7 +197,7 @@ func loadAppServices(config *AppServiceAPI, derived *Derived) error {
|
|||
// setupRegexps will create regex objects for exclusive and non-exclusive
|
||||
// usernames, aliases and rooms of all application services, so that other
|
||||
// methods can quickly check if a particular string matches any of them.
|
||||
func setupRegexps(_ *AppServiceAPI, derived *Derived) (err error) {
|
||||
func setupRegexps(asAPI *AppServiceAPI, derived *Derived) (err error) {
|
||||
// Combine all exclusive namespaces for later string checking
|
||||
var exclusiveUsernameStrings, exclusiveAliasStrings []string
|
||||
|
||||
|
@ -201,6 +205,16 @@ func setupRegexps(_ *AppServiceAPI, derived *Derived) (err error) {
|
|||
// its contents to the overall exlusive regex string. Room regex
|
||||
// not necessary as we aren't denying exclusive room ID creation
|
||||
for _, appservice := range derived.ApplicationServices {
|
||||
// The sender_localpart can be considered an exclusive regex for a single user, so let's do that
|
||||
// to simplify the code
|
||||
var senderUserIDSlice = []string{fmt.Sprintf("@%s:%s", appservice.SenderLocalpart, asAPI.Matrix.ServerName)}
|
||||
usersSlice, found := appservice.NamespaceMap["users"]
|
||||
if !found {
|
||||
usersSlice = []ApplicationServiceNamespace{}
|
||||
appservice.NamespaceMap["users"] = usersSlice
|
||||
}
|
||||
appendExclusiveNamespaceRegexs(&senderUserIDSlice, usersSlice)
|
||||
|
||||
for key, namespaceSlice := range appservice.NamespaceMap {
|
||||
switch key {
|
||||
case "users":
|
||||
|
|
|
@ -25,7 +25,7 @@ type FederationSender struct {
|
|||
func (c *FederationSender) Defaults() {
|
||||
c.InternalAPI.Listen = "http://localhost:7775"
|
||||
c.InternalAPI.Connect = "http://localhost:7775"
|
||||
c.Database.Defaults()
|
||||
c.Database.Defaults(10)
|
||||
c.Database.ConnectionString = "file:federationsender.db"
|
||||
|
||||
c.FederationMaxRetries = 16
|
||||
|
|
|
@ -122,8 +122,8 @@ type DatabaseOptions struct {
|
|||
ConnMaxLifetimeSeconds int `yaml:"conn_max_lifetime"`
|
||||
}
|
||||
|
||||
func (c *DatabaseOptions) Defaults() {
|
||||
c.MaxOpenConnections = 100
|
||||
func (c *DatabaseOptions) Defaults(conns int) {
|
||||
c.MaxOpenConnections = conns
|
||||
c.MaxIdleConnections = 2
|
||||
c.ConnMaxLifetimeSeconds = -1
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ func (k *Kafka) TopicFor(name string) string {
|
|||
|
||||
func (c *Kafka) Defaults() {
|
||||
c.UseNaffka = true
|
||||
c.Database.Defaults()
|
||||
c.Database.Defaults(10)
|
||||
c.Addresses = []string{"localhost:2181"}
|
||||
c.Database.ConnectionString = DataSource("file:naffka.db")
|
||||
c.TopicPrefix = "Dendrite"
|
||||
|
|
|
@ -11,7 +11,7 @@ type KeyServer struct {
|
|||
func (c *KeyServer) Defaults() {
|
||||
c.InternalAPI.Listen = "http://localhost:7779"
|
||||
c.InternalAPI.Connect = "http://localhost:7779"
|
||||
c.Database.Defaults()
|
||||
c.Database.Defaults(10)
|
||||
c.Database.ConnectionString = "file:keyserver.db"
|
||||
}
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ func (c *MediaAPI) Defaults() {
|
|||
c.InternalAPI.Listen = "http://localhost:7774"
|
||||
c.InternalAPI.Connect = "http://localhost:7774"
|
||||
c.ExternalAPI.Listen = "http://[::]:8074"
|
||||
c.Database.Defaults()
|
||||
c.Database.Defaults(5)
|
||||
c.Database.ConnectionString = "file:mediaapi.db"
|
||||
|
||||
defaultMaxFileSizeBytes := FileSizeBytes(10485760)
|
||||
|
|
|
@ -14,7 +14,7 @@ type MSCs struct {
|
|||
}
|
||||
|
||||
func (c *MSCs) Defaults() {
|
||||
c.Database.Defaults()
|
||||
c.Database.Defaults(5)
|
||||
c.Database.ConnectionString = "file:mscs.db"
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ type RoomServer struct {
|
|||
func (c *RoomServer) Defaults() {
|
||||
c.InternalAPI.Listen = "http://localhost:7770"
|
||||
c.InternalAPI.Connect = "http://localhost:7770"
|
||||
c.Database.Defaults()
|
||||
c.Database.Defaults(10)
|
||||
c.Database.ConnectionString = "file:roomserver.db"
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ type SigningKeyServer struct {
|
|||
func (c *SigningKeyServer) Defaults() {
|
||||
c.InternalAPI.Listen = "http://localhost:7780"
|
||||
c.InternalAPI.Connect = "http://localhost:7780"
|
||||
c.Database.Defaults()
|
||||
c.Database.Defaults(10)
|
||||
c.Database.ConnectionString = "file:signingkeyserver.db"
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ func (c *SyncAPI) Defaults() {
|
|||
c.InternalAPI.Listen = "http://localhost:7773"
|
||||
c.InternalAPI.Connect = "http://localhost:7773"
|
||||
c.ExternalAPI.Listen = "http://localhost:8073"
|
||||
c.Database.Defaults()
|
||||
c.Database.Defaults(10)
|
||||
c.Database.ConnectionString = "file:syncapi.db"
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,15 @@
|
|||
package config
|
||||
|
||||
import "golang.org/x/crypto/bcrypt"
|
||||
|
||||
type UserAPI struct {
|
||||
Matrix *Global `yaml:"-"`
|
||||
|
||||
InternalAPI InternalAPIOptions `yaml:"internal_api"`
|
||||
|
||||
// The cost when hashing passwords.
|
||||
BCryptCost int `yaml:"bcrypt_cost"`
|
||||
|
||||
// The Account database stores the login details and account information
|
||||
// for local users. It is accessed by the UserAPI.
|
||||
AccountDatabase DatabaseOptions `yaml:"account_database"`
|
||||
|
@ -16,10 +21,11 @@ type UserAPI struct {
|
|||
func (c *UserAPI) Defaults() {
|
||||
c.InternalAPI.Listen = "http://localhost:7781"
|
||||
c.InternalAPI.Connect = "http://localhost:7781"
|
||||
c.AccountDatabase.Defaults()
|
||||
c.DeviceDatabase.Defaults()
|
||||
c.AccountDatabase.Defaults(10)
|
||||
c.DeviceDatabase.Defaults(10)
|
||||
c.AccountDatabase.ConnectionString = "file:userapi_accounts.db"
|
||||
c.DeviceDatabase.ConnectionString = "file:userapi_devices.db"
|
||||
c.BCryptCost = bcrypt.DefaultCost
|
||||
}
|
||||
|
||||
func (c *UserAPI) Verify(configErrs *ConfigErrors, isMonolith bool) {
|
||||
|
|
|
@ -238,7 +238,6 @@ func federatedEventRelationship(
|
|||
}
|
||||
}
|
||||
|
||||
// nolint:gocyclo
|
||||
func (rc *reqCtx) process() (*gomatrixserverlib.MSC2836EventRelationshipsResponse, *util.JSONResponse) {
|
||||
var res gomatrixserverlib.MSC2836EventRelationshipsResponse
|
||||
var returnEvents []*gomatrixserverlib.HeaderedEvent
|
||||
|
|
|
@ -217,7 +217,6 @@ func (w *walker) markSent(id string) {
|
|||
w.inMemoryBatchCache[w.callerID()] = m
|
||||
}
|
||||
|
||||
// nolint:gocyclo
|
||||
func (w *walker) walk() *gomatrixserverlib.MSC2946SpacesResponse {
|
||||
var res gomatrixserverlib.MSC2946SpacesResponse
|
||||
// Begin walking the graph starting with the room ID in the request in a queue of unvisited rooms
|
||||
|
|
|
@ -46,7 +46,6 @@ func DeviceOTKCounts(ctx context.Context, keyAPI keyapi.KeyInternalAPI, userID,
|
|||
// DeviceListCatchup fills in the given response for the given user ID to bring it up-to-date with device lists. hasNew=true if the response
|
||||
// was filled in, else false if there are no new device list changes because there is nothing to catch up on. The response MUST
|
||||
// be already filled in with join/leave information.
|
||||
// nolint:gocyclo
|
||||
func DeviceListCatchup(
|
||||
ctx context.Context, keyAPI keyapi.KeyInternalAPI, rsAPI roomserverAPI.RoomserverInternalAPI,
|
||||
userID string, res *types.Response, from, to types.LogPosition,
|
||||
|
@ -137,7 +136,6 @@ func DeviceListCatchup(
|
|||
}
|
||||
|
||||
// TrackChangedUsers calculates the values of device_lists.changed|left in the /sync response.
|
||||
// nolint:gocyclo
|
||||
func TrackChangedUsers(
|
||||
ctx context.Context, rsAPI roomserverAPI.RoomserverInternalAPI, userID string, newlyJoinedRooms, newlyLeftRooms []string,
|
||||
) (changed, left []string, err error) {
|
||||
|
|
|
@ -61,7 +61,6 @@ const defaultMessagesLimit = 10
|
|||
// OnIncomingMessagesRequest implements the /messages endpoint from the
|
||||
// client-server API.
|
||||
// See: https://matrix.org/docs/spec/client_server/latest.html#get-matrix-client-r0-rooms-roomid-messages
|
||||
// nolint:gocyclo
|
||||
func OnIncomingMessagesRequest(
|
||||
req *http.Request, db storage.Database, roomID string, device *userapi.Device,
|
||||
federation *gomatrixserverlib.FederationClient,
|
||||
|
@ -306,7 +305,6 @@ func (r *messagesReq) retrieveEvents() (
|
|||
return clientEvents, start, end, err
|
||||
}
|
||||
|
||||
// nolint:gocyclo
|
||||
func (r *messagesReq) filterHistoryVisible(events []*gomatrixserverlib.HeaderedEvent) []*gomatrixserverlib.HeaderedEvent {
|
||||
// TODO FIXME: We don't fully implement history visibility yet. To avoid leaking events which the
|
||||
// user shouldn't see, we check the recent events and remove any prior to the join event of the user
|
||||
|
|
|
@ -36,7 +36,6 @@ type SyncServerDatasource struct {
|
|||
}
|
||||
|
||||
// NewDatabase creates a new sync server database
|
||||
// nolint:gocyclo
|
||||
func NewDatabase(dbProperties *config.DatabaseOptions) (*SyncServerDatasource, error) {
|
||||
var d SyncServerDatasource
|
||||
var err error
|
||||
|
|
|
@ -661,7 +661,6 @@ func (d *Database) fetchMissingStateEvents(
|
|||
// exclusive of oldPos, inclusive of newPos, for the rooms in which
|
||||
// the user has new membership events.
|
||||
// A list of joined room IDs is also returned in case the caller needs it.
|
||||
// nolint:gocyclo
|
||||
func (d *Database) GetStateDeltas(
|
||||
ctx context.Context, device *userapi.Device,
|
||||
r types.Range, userID string,
|
||||
|
@ -773,7 +772,6 @@ func (d *Database) GetStateDeltas(
|
|||
// requests with full_state=true.
|
||||
// Fetches full state for all joined rooms and uses selectStateInRange to get
|
||||
// updates for other rooms.
|
||||
// nolint:gocyclo
|
||||
func (d *Database) GetStateDeltasForFullStateSync(
|
||||
ctx context.Context, device *userapi.Device,
|
||||
r types.Range, userID string,
|
||||
|
|
|
@ -23,7 +23,6 @@ const (
|
|||
// fields might come from either a StateFilter or an EventFilter,
|
||||
// and it's easier just to have the caller extract the relevant
|
||||
// parts.
|
||||
// nolint:gocyclo
|
||||
func prepareWithFilters(
|
||||
db *sql.DB, txn *sql.Tx, query string, params []interface{},
|
||||
senders, notsenders, types, nottypes []string, excludeEventIDs []string,
|
||||
|
|
|
@ -52,7 +52,6 @@ func NewDatabase(dbProperties *config.DatabaseOptions) (*SyncServerDatasource, e
|
|||
return &d, nil
|
||||
}
|
||||
|
||||
// nolint:gocyclo
|
||||
func (d *SyncServerDatasource) prepare(dbProperties *config.DatabaseOptions) (err error) {
|
||||
if err = d.PartitionOffsetStatements.Prepare(d.db, d.writer, "syncapi"); err != nil {
|
||||
return err
|
||||
|
|
|
@ -137,7 +137,6 @@ func (p *PDUStreamProvider) CompleteSync(
|
|||
return to
|
||||
}
|
||||
|
||||
// nolint:gocyclo
|
||||
func (p *PDUStreamProvider) IncrementalSync(
|
||||
ctx context.Context,
|
||||
req *types.SyncRequest,
|
||||
|
@ -254,7 +253,6 @@ func (p *PDUStreamProvider) addRoomDeltaToResponse(
|
|||
return nil
|
||||
}
|
||||
|
||||
// nolint:gocyclo
|
||||
func (p *PDUStreamProvider) getJoinResponseForCompleteSync(
|
||||
ctx context.Context,
|
||||
roomID string,
|
||||
|
|
|
@ -510,3 +510,10 @@ Can pass a JSON filter as a query parameter
|
|||
Local room members can get room messages
|
||||
Remote room members can get room messages
|
||||
Guest users can send messages to guest_access rooms if joined
|
||||
AS can create a user
|
||||
AS can create a user with an underscore
|
||||
AS can create a user with inhibit_login
|
||||
AS can set avatar for ghosted users
|
||||
AS can set displayname for ghosted users
|
||||
Ghost user must register before joining room
|
||||
Inviting an AS-hosted user asks the AS server
|
||||
|
|
|
@ -241,6 +241,9 @@ type Device struct {
|
|||
LastSeenTS int64
|
||||
LastSeenIP string
|
||||
UserAgent string
|
||||
// If the device is for an appservice user,
|
||||
// this is the appservice ID.
|
||||
AppserviceID string
|
||||
}
|
||||
|
||||
// Account represents a Matrix account on this home server.
|
||||
|
|
|
@ -87,7 +87,7 @@ func (a *UserInternalAPI) PerformAccountCreation(ctx context.Context, req *api.P
|
|||
ServerName: a.ServerName,
|
||||
UserID: fmt.Sprintf("@%s:%s", req.Localpart, a.ServerName),
|
||||
}
|
||||
return err
|
||||
return nil
|
||||
}
|
||||
|
||||
if err = a.AccountDB.SetDisplayName(ctx, req.Localpart, req.Localpart); err != nil {
|
||||
|
@ -381,7 +381,8 @@ func (a *UserInternalAPI) queryAppServiceToken(ctx context.Context, token, appSe
|
|||
// Use AS dummy device ID
|
||||
ID: types.AppServiceDeviceID,
|
||||
// AS dummy device has AS's token.
|
||||
AccessToken: token,
|
||||
AccessToken: token,
|
||||
AppserviceID: appService.ID,
|
||||
}
|
||||
|
||||
localpart, err := userutil.ParseUsernameParam(appServiceUserID, &a.ServerName)
|
||||
|
|
|
@ -44,10 +44,11 @@ type Database struct {
|
|||
accountDatas accountDataStatements
|
||||
threepids threepidStatements
|
||||
serverName gomatrixserverlib.ServerName
|
||||
bcryptCost int
|
||||
}
|
||||
|
||||
// NewDatabase creates a new accounts and profiles database
|
||||
func NewDatabase(dbProperties *config.DatabaseOptions, serverName gomatrixserverlib.ServerName) (*Database, error) {
|
||||
func NewDatabase(dbProperties *config.DatabaseOptions, serverName gomatrixserverlib.ServerName, bcryptCost int) (*Database, error) {
|
||||
db, err := sqlutil.Open(dbProperties)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -56,6 +57,7 @@ func NewDatabase(dbProperties *config.DatabaseOptions, serverName gomatrixserver
|
|||
serverName: serverName,
|
||||
db: db,
|
||||
writer: sqlutil.NewDummyWriter(),
|
||||
bcryptCost: bcryptCost,
|
||||
}
|
||||
|
||||
// Create tables before executing migrations so we don't fail if the table is missing,
|
||||
|
@ -131,7 +133,7 @@ func (d *Database) SetDisplayName(
|
|||
func (d *Database) SetPassword(
|
||||
ctx context.Context, localpart, plaintextPassword string,
|
||||
) error {
|
||||
hash, err := hashPassword(plaintextPassword)
|
||||
hash, err := d.hashPassword(plaintextPassword)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -175,7 +177,7 @@ func (d *Database) createAccount(
|
|||
// Generate a password hash if this is not a password-less user
|
||||
hash := ""
|
||||
if plaintextPassword != "" {
|
||||
hash, err = hashPassword(plaintextPassword)
|
||||
hash, err = d.hashPassword(plaintextPassword)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -246,8 +248,8 @@ func (d *Database) GetNewNumericLocalpart(
|
|||
return d.accounts.selectNewNumericLocalpart(ctx, nil)
|
||||
}
|
||||
|
||||
func hashPassword(plaintext string) (hash string, err error) {
|
||||
hashBytes, err := bcrypt.GenerateFromPassword([]byte(plaintext), bcrypt.DefaultCost)
|
||||
func (d *Database) hashPassword(plaintext string) (hash string, err error) {
|
||||
hashBytes, err := bcrypt.GenerateFromPassword([]byte(plaintext), d.bcryptCost)
|
||||
return string(hashBytes), err
|
||||
}
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@ type Database struct {
|
|||
accountDatas accountDataStatements
|
||||
threepids threepidStatements
|
||||
serverName gomatrixserverlib.ServerName
|
||||
bcryptCost int
|
||||
|
||||
accountsMu sync.Mutex
|
||||
profilesMu sync.Mutex
|
||||
|
@ -50,7 +51,7 @@ type Database struct {
|
|||
}
|
||||
|
||||
// NewDatabase creates a new accounts and profiles database
|
||||
func NewDatabase(dbProperties *config.DatabaseOptions, serverName gomatrixserverlib.ServerName) (*Database, error) {
|
||||
func NewDatabase(dbProperties *config.DatabaseOptions, serverName gomatrixserverlib.ServerName, bcryptCost int) (*Database, error) {
|
||||
db, err := sqlutil.Open(dbProperties)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -59,6 +60,7 @@ func NewDatabase(dbProperties *config.DatabaseOptions, serverName gomatrixserver
|
|||
serverName: serverName,
|
||||
db: db,
|
||||
writer: sqlutil.NewExclusiveWriter(),
|
||||
bcryptCost: bcryptCost,
|
||||
}
|
||||
|
||||
// Create tables before executing migrations so we don't fail if the table is missing,
|
||||
|
@ -143,7 +145,7 @@ func (d *Database) SetDisplayName(
|
|||
func (d *Database) SetPassword(
|
||||
ctx context.Context, localpart, plaintextPassword string,
|
||||
) error {
|
||||
hash, err := hashPassword(plaintextPassword)
|
||||
hash, err := d.hashPassword(plaintextPassword)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -208,7 +210,7 @@ func (d *Database) createAccount(
|
|||
// Generate a password hash if this is not a password-less user
|
||||
hash := ""
|
||||
if plaintextPassword != "" {
|
||||
hash, err = hashPassword(plaintextPassword)
|
||||
hash, err = d.hashPassword(plaintextPassword)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -278,8 +280,8 @@ func (d *Database) GetNewNumericLocalpart(
|
|||
return d.accounts.selectNewNumericLocalpart(ctx, nil)
|
||||
}
|
||||
|
||||
func hashPassword(plaintext string) (hash string, err error) {
|
||||
hashBytes, err := bcrypt.GenerateFromPassword([]byte(plaintext), bcrypt.DefaultCost)
|
||||
func (d *Database) hashPassword(plaintext string) (hash string, err error) {
|
||||
hashBytes, err := bcrypt.GenerateFromPassword([]byte(plaintext), d.bcryptCost)
|
||||
return string(hashBytes), err
|
||||
}
|
||||
|
||||
|
|
|
@ -27,12 +27,12 @@ import (
|
|||
|
||||
// NewDatabase opens a new Postgres or Sqlite database (based on dataSourceName scheme)
|
||||
// and sets postgres connection parameters
|
||||
func NewDatabase(dbProperties *config.DatabaseOptions, serverName gomatrixserverlib.ServerName) (Database, error) {
|
||||
func NewDatabase(dbProperties *config.DatabaseOptions, serverName gomatrixserverlib.ServerName, bcryptCost int) (Database, error) {
|
||||
switch {
|
||||
case dbProperties.ConnectionString.IsSQLite():
|
||||
return sqlite3.NewDatabase(dbProperties, serverName)
|
||||
return sqlite3.NewDatabase(dbProperties, serverName, bcryptCost)
|
||||
case dbProperties.ConnectionString.IsPostgres():
|
||||
return postgres.NewDatabase(dbProperties, serverName)
|
||||
return postgres.NewDatabase(dbProperties, serverName, bcryptCost)
|
||||
default:
|
||||
return nil, fmt.Errorf("unexpected database type")
|
||||
}
|
||||
|
|
|
@ -25,10 +25,11 @@ import (
|
|||
func NewDatabase(
|
||||
dbProperties *config.DatabaseOptions,
|
||||
serverName gomatrixserverlib.ServerName,
|
||||
bcryptCost int,
|
||||
) (Database, error) {
|
||||
switch {
|
||||
case dbProperties.ConnectionString.IsSQLite():
|
||||
return sqlite3.NewDatabase(dbProperties, serverName)
|
||||
return sqlite3.NewDatabase(dbProperties, serverName, bcryptCost)
|
||||
case dbProperties.ConnectionString.IsPostgres():
|
||||
return nil, fmt.Errorf("can't use Postgres implementation")
|
||||
default:
|
||||
|
|
|
@ -37,7 +37,6 @@ func AddInternalRoutes(router *mux.Router, intAPI api.UserInternalAPI) {
|
|||
func NewInternalAPI(
|
||||
accountDB accounts.Database, cfg *config.UserAPI, appServices []config.ApplicationService, keyAPI keyapi.KeyInternalAPI,
|
||||
) api.UserInternalAPI {
|
||||
|
||||
deviceDB, err := devices.NewDatabase(&cfg.DeviceDatabase, cfg.Matrix.ServerName)
|
||||
if err != nil {
|
||||
logrus.WithError(err).Panicf("failed to connect to device db")
|
||||
|
|
|
@ -16,6 +16,7 @@ import (
|
|||
"github.com/matrix-org/dendrite/userapi/inthttp"
|
||||
"github.com/matrix-org/dendrite/userapi/storage/accounts"
|
||||
"github.com/matrix-org/gomatrixserverlib"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -25,7 +26,7 @@ const (
|
|||
func MustMakeInternalAPI(t *testing.T) (api.UserInternalAPI, accounts.Database) {
|
||||
accountDB, err := accounts.NewDatabase(&config.DatabaseOptions{
|
||||
ConnectionString: "file::memory:",
|
||||
}, serverName)
|
||||
}, serverName, bcrypt.MinCost)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create account DB: %s", err)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue