2020-08-10 14:18:04 +01:00
package config
import (
2022-11-15 15:05:23 +00:00
"fmt"
2020-08-10 14:18:04 +01:00
"math/rand"
2022-07-11 14:31:31 +01:00
"strconv"
"strings"
2020-08-10 14:18:04 +01:00
"time"
"github.com/matrix-org/gomatrixserverlib"
2023-04-06 09:55:01 +01:00
"github.com/matrix-org/gomatrixserverlib/fclient"
2023-04-19 15:50:33 +01:00
"github.com/matrix-org/gomatrixserverlib/spec"
2020-08-10 14:18:04 +01:00
"golang.org/x/crypto/ed25519"
)
type Global struct {
2022-11-18 13:24:02 +00:00
// Signing identity contains the server name, private key and key ID of
// the deployment.
2023-04-06 09:55:01 +01:00
fclient . SigningIdentity ` yaml:",inline" `
2020-08-10 14:18:04 +01:00
2022-10-26 12:59:19 +01:00
// The secondary server names, used for virtual hosting.
2022-11-29 11:11:08 +00:00
VirtualHosts [ ] * VirtualHost ` yaml:"-" `
2022-10-26 12:59:19 +01:00
2020-08-10 14:18:04 +01:00
// Path to the private key which will be used to sign requests and events.
PrivateKeyPath Path ` yaml:"private_key" `
2020-09-25 10:58:53 +01:00
// Information about old private keys that used to be used to sign requests and
// events on this domain. They will not be used but will be advertised to other
// servers that ask for them to help verify old events.
2022-10-06 11:56:00 +01:00
OldVerifyKeys [ ] * OldVerifyKeys ` yaml:"old_private_keys" `
2020-09-25 10:58:53 +01:00
2020-08-10 14:18:04 +01:00
// How long a remote server can cache our server key for before requesting it again.
// Increasing this number will reduce the number of requests made by remote servers
// for our key, but increases the period a compromised key will be considered valid
// by remote servers.
// Defaults to 24 hours.
KeyValidityPeriod time . Duration ` yaml:"key_validity_period" `
2022-05-03 16:35:06 +01:00
// Global pool of database connections, which is used only in monolith mode. If a
// component does not specify any database options of its own, then this pool of
// connections will be used instead. This way we don't have to manage connection
// counts on a per-component basis, but can instead do it for the entire monolith.
2022-09-01 14:15:41 +01:00
DatabaseOptions DatabaseOptions ` yaml:"database,omitempty" `
2022-05-03 16:35:06 +01:00
2021-09-10 10:05:31 +01:00
// The server name to delegate server-server communications to, with optional port
WellKnownServerName string ` yaml:"well_known_server_name" `
2022-07-25 10:39:57 +01:00
// The server name to delegate client-server communications to, with optional port
WellKnownClientName string ` yaml:"well_known_client_name" `
2023-08-24 22:08:40 +01:00
// The server name to delegate sliding sync communications to, with optional port.
// Requires `well_known_client_name` to also be configured.
WellKnownSlidingSyncProxy string ` yaml:"well_known_sliding_sync_proxy" `
2020-12-02 15:10:03 +00:00
// Disables federation. Dendrite will not be able to make any outbound HTTP requests
// to other servers and the federation API will not be exposed.
DisableFederation bool ` yaml:"disable_federation" `
2022-04-06 12:11:19 +01:00
// Configures the handling of presence events.
Presence PresenceOptions ` yaml:"presence" `
2020-08-10 14:18:04 +01:00
// List of domains that the server will trust as identity servers to
// verify third-party identifiers.
// Defaults to an empty array.
TrustedIDServers [ ] string ` yaml:"trusted_third_party_id_servers" `
2022-01-05 17:44:49 +00:00
// JetStream configuration
JetStream JetStream ` yaml:"jetstream" `
2020-08-10 14:18:04 +01:00
// Metrics configuration
Metrics Metrics ` yaml:"metrics" `
2021-01-22 14:16:59 +00:00
2021-03-24 10:25:24 +00:00
// Sentry configuration
Sentry Sentry ` yaml:"sentry" `
2021-01-22 14:16:59 +00:00
// DNS caching options for all outbound HTTP requests
DNSCache DNSCacheOptions ` yaml:"dns_cache" `
2022-02-18 15:05:03 +00:00
// ServerNotices configuration used for sending server notices
ServerNotices ServerNotices ` yaml:"server_notices" `
2022-05-04 18:04:28 +01:00
2022-07-19 11:51:46 +01:00
// ReportStats configures opt-in phone-home statistics reporting.
2022-05-04 18:04:28 +01:00
ReportStats ReportStats ` yaml:"report_stats" `
2022-07-11 14:31:31 +01:00
// Configuration for the caches.
Cache Cache ` yaml:"cache" `
2020-08-10 14:18:04 +01:00
}
2022-09-01 14:15:41 +01:00
func ( c * Global ) Defaults ( opts DefaultOpts ) {
if opts . Generate {
2021-11-24 11:57:39 +00:00
c . ServerName = "localhost"
c . PrivateKeyPath = "matrix_key.pem"
_ , c . PrivateKey , _ = ed25519 . GenerateKey ( rand . New ( rand . NewSource ( 0 ) ) )
c . KeyID = "ed25519:auto"
2022-09-01 14:15:41 +01:00
c . TrustedIDServers = [ ] string {
"matrix.org" ,
"vector.im" ,
}
2021-11-24 11:57:39 +00:00
}
2020-08-10 14:18:04 +01:00
c . KeyValidityPeriod = time . Hour * 24 * 7
2023-02-14 11:47:47 +00:00
if opts . SingleDatabase {
2022-09-01 14:15:41 +01:00
c . DatabaseOptions . Defaults ( 90 )
}
c . JetStream . Defaults ( opts )
c . Metrics . Defaults ( opts )
2021-01-22 14:16:59 +00:00
c . DNSCache . Defaults ( )
2021-03-24 10:25:24 +00:00
c . Sentry . Defaults ( )
2022-09-01 14:15:41 +01:00
c . ServerNotices . Defaults ( opts )
2022-05-04 18:04:28 +01:00
c . ReportStats . Defaults ( )
2022-09-01 14:15:41 +01:00
c . Cache . Defaults ( )
2020-08-10 14:18:04 +01:00
}
2023-02-14 11:47:47 +00:00
func ( c * Global ) Verify ( configErrs * ConfigErrors ) {
2020-08-10 14:18:04 +01:00
checkNotEmpty ( configErrs , "global.server_name" , string ( c . ServerName ) )
checkNotEmpty ( configErrs , "global.private_key" , string ( c . PrivateKeyPath ) )
2023-11-25 21:19:22 +00:00
// Check that client well-known has a proper format
if c . WellKnownClientName != "" && ! strings . HasPrefix ( c . WellKnownClientName , "http://" ) && ! strings . HasPrefix ( c . WellKnownClientName , "https://" ) {
configErrs . Add ( "The configuration for well_known_client_name does not have a proper format, consider adding http:// or https://. Some clients may fail to connect." )
}
2022-11-15 15:05:23 +00:00
for _ , v := range c . VirtualHosts {
v . Verify ( configErrs )
}
2023-02-14 11:47:47 +00:00
c . JetStream . Verify ( configErrs )
c . Metrics . Verify ( configErrs )
c . Sentry . Verify ( configErrs )
c . DNSCache . Verify ( configErrs )
c . ServerNotices . Verify ( configErrs )
c . ReportStats . Verify ( configErrs )
c . Cache . Verify ( configErrs )
2020-08-10 14:18:04 +01:00
}
2023-04-19 15:50:33 +01:00
func ( c * Global ) IsLocalServerName ( serverName spec . ServerName ) bool {
2022-10-26 12:59:19 +01:00
if c . ServerName == serverName {
return true
}
2022-11-15 15:05:23 +00:00
for _ , v := range c . VirtualHosts {
if v . ServerName == serverName {
2022-10-26 12:59:19 +01:00
return true
}
}
return false
}
2023-04-19 15:50:33 +01:00
func ( c * Global ) SplitLocalID ( sigil byte , id string ) ( string , spec . ServerName , error ) {
2022-11-15 15:05:23 +00:00
u , s , err := gomatrixserverlib . SplitID ( sigil , id )
if err != nil {
return u , s , err
}
if ! c . IsLocalServerName ( s ) {
return u , s , fmt . Errorf ( "server name %q not known" , s )
}
return u , s , nil
}
2023-04-19 15:50:33 +01:00
func ( c * Global ) VirtualHost ( serverName spec . ServerName ) * VirtualHost {
2022-11-18 13:24:02 +00:00
for _ , v := range c . VirtualHosts {
if v . ServerName == serverName {
return v
}
}
return nil
}
2023-04-19 15:50:33 +01:00
func ( c * Global ) VirtualHostForHTTPHost ( serverName spec . ServerName ) * VirtualHost {
2022-11-18 13:24:02 +00:00
for _ , v := range c . VirtualHosts {
if v . ServerName == serverName {
return v
}
for _ , h := range v . MatchHTTPHosts {
if h == serverName {
return v
}
}
}
return nil
}
2023-04-19 15:50:33 +01:00
func ( c * Global ) SigningIdentityFor ( serverName spec . ServerName ) ( * fclient . SigningIdentity , error ) {
2022-11-15 15:05:23 +00:00
for _ , id := range c . SigningIdentities ( ) {
if id . ServerName == serverName {
return id , nil
}
}
2022-12-22 12:05:59 +00:00
return nil , fmt . Errorf ( "no signing identity for %q" , serverName )
2022-11-15 15:05:23 +00:00
}
2023-04-06 09:55:01 +01:00
func ( c * Global ) SigningIdentities ( ) [ ] * fclient . SigningIdentity {
identities := make ( [ ] * fclient . SigningIdentity , 0 , len ( c . VirtualHosts ) + 1 )
2022-11-18 13:24:02 +00:00
identities = append ( identities , & c . SigningIdentity )
2022-11-15 15:05:23 +00:00
for _ , v := range c . VirtualHosts {
2022-11-18 13:24:02 +00:00
identities = append ( identities , & v . SigningIdentity )
2022-11-15 15:05:23 +00:00
}
return identities
}
type VirtualHost struct {
2022-11-18 13:24:02 +00:00
// Signing identity contains the server name, private key and key ID of
// the virtual host.
2023-04-06 09:55:01 +01:00
fclient . SigningIdentity ` yaml:",inline" `
2022-11-15 15:05:23 +00:00
// Path to the private key. If not specified, the default global private key
// will be used instead.
PrivateKeyPath Path ` yaml:"private_key" `
// How long a remote server can cache our server key for before requesting it again.
// Increasing this number will reduce the number of requests made by remote servers
// for our key, but increases the period a compromised key will be considered valid
// by remote servers.
// Defaults to 24 hours.
KeyValidityPeriod time . Duration ` yaml:"key_validity_period" `
2022-11-17 09:26:56 +00:00
// Match these HTTP Host headers on the `/key/v2/server` endpoint, this needs
// to match all delegated names, likely including the port number too if
// the well-known delegation includes that also.
2023-04-19 15:50:33 +01:00
MatchHTTPHosts [ ] spec . ServerName ` yaml:"match_http_hosts" `
2022-11-17 09:26:56 +00:00
2022-11-15 15:05:23 +00:00
// Is registration enabled on this virtual host?
2022-11-18 13:24:02 +00:00
AllowRegistration bool ` yaml:"allow_registration" `
// Is guest registration enabled on this virtual host?
AllowGuests bool ` yaml:"allow_guests" `
2022-11-15 15:05:23 +00:00
}
func ( v * VirtualHost ) Verify ( configErrs * ConfigErrors ) {
checkNotEmpty ( configErrs , "virtual_host.*.server_name" , string ( v . ServerName ) )
}
2022-11-18 13:24:02 +00:00
// RegistrationAllowed returns two bools, the first states whether registration
// is allowed for this virtual host and the second states whether guests are
// allowed for this virtual host.
func ( v * VirtualHost ) RegistrationAllowed ( ) ( bool , bool ) {
if v == nil {
return false , false
2022-11-15 15:05:23 +00:00
}
2022-11-18 13:24:02 +00:00
return v . AllowRegistration , v . AllowGuests
2022-11-15 15:05:23 +00:00
}
2020-09-25 10:58:53 +01:00
type OldVerifyKeys struct {
// Path to the private key.
PrivateKeyPath Path ` yaml:"private_key" `
// The private key itself.
PrivateKey ed25519 . PrivateKey ` yaml:"-" `
2022-10-06 11:56:00 +01:00
// The public key, in case only that part is known.
2023-04-19 15:50:33 +01:00
PublicKey spec . Base64Bytes ` yaml:"public_key" `
2022-10-06 11:56:00 +01:00
2020-09-25 10:58:53 +01:00
// The key ID of the private key.
2022-10-06 11:56:00 +01:00
KeyID gomatrixserverlib . KeyID ` yaml:"key_id" `
2020-09-25 10:58:53 +01:00
// When the private key was designed as "expired", as a UNIX timestamp
// in millisecond precision.
2023-04-19 15:50:33 +01:00
ExpiredAt spec . Timestamp ` yaml:"expired_at" `
2020-09-25 10:58:53 +01:00
}
2020-08-10 14:18:04 +01:00
// The configuration to use for Prometheus metrics
type Metrics struct {
// Whether or not the metrics are enabled
Enabled bool ` yaml:"enabled" `
// Use BasicAuth for Authorization
BasicAuth struct {
// Authorization via Static Username & Password
// Hardcoded Username and Password
Username string ` yaml:"username" `
Password string ` yaml:"password" `
} ` yaml:"basic_auth" `
}
2022-09-01 14:15:41 +01:00
func ( c * Metrics ) Defaults ( opts DefaultOpts ) {
2020-08-10 14:18:04 +01:00
c . Enabled = false
2022-09-01 14:15:41 +01:00
if opts . Generate {
2021-11-24 11:57:39 +00:00
c . BasicAuth . Username = "metrics"
c . BasicAuth . Password = "metrics"
}
2020-08-10 14:18:04 +01:00
}
2023-02-14 11:47:47 +00:00
func ( c * Metrics ) Verify ( configErrs * ConfigErrors ) {
2020-08-10 14:18:04 +01:00
}
2022-02-18 15:05:03 +00:00
// ServerNotices defines the configuration used for sending server notices
type ServerNotices struct {
Enabled bool ` yaml:"enabled" `
// The localpart to be used when sending notices
LocalPart string ` yaml:"local_part" `
// The displayname to be used when sending notices
DisplayName string ` yaml:"display_name" `
// The avatar of this user
2022-10-24 06:10:50 +01:00
AvatarURL string ` yaml:"avatar_url" `
2022-02-18 15:05:03 +00:00
// The roomname to be used when creating messages
RoomName string ` yaml:"room_name" `
}
2022-09-01 14:15:41 +01:00
func ( c * ServerNotices ) Defaults ( opts DefaultOpts ) {
if opts . Generate {
2022-02-18 15:05:03 +00:00
c . Enabled = true
c . LocalPart = "_server"
c . DisplayName = "Server Alert"
c . RoomName = "Server Alert"
c . AvatarURL = ""
}
}
2023-02-14 11:47:47 +00:00
func ( c * ServerNotices ) Verify ( errors * ConfigErrors ) { }
2022-02-18 15:05:03 +00:00
2022-07-11 14:31:31 +01:00
type Cache struct {
EstimatedMaxSize DataUnit ` yaml:"max_size_estimated" `
MaxAge time . Duration ` yaml:"max_age" `
}
2022-09-01 14:15:41 +01:00
func ( c * Cache ) Defaults ( ) {
2022-07-11 14:31:31 +01:00
c . EstimatedMaxSize = 1024 * 1024 * 1024 // 1GB
c . MaxAge = time . Hour
}
2023-02-14 11:47:47 +00:00
func ( c * Cache ) Verify ( errors * ConfigErrors ) {
2022-07-11 14:31:31 +01:00
checkPositive ( errors , "max_size_estimated" , int64 ( c . EstimatedMaxSize ) )
}
2022-07-19 11:51:46 +01:00
// ReportStats configures opt-in phone-home statistics reporting.
2022-05-04 18:04:28 +01:00
type ReportStats struct {
2022-07-19 11:51:46 +01:00
// Enabled configures phone-home statistics of the server
2022-05-04 18:04:28 +01:00
Enabled bool ` yaml:"enabled" `
// Endpoint the endpoint to report stats to
Endpoint string ` yaml:"endpoint" `
}
func ( c * ReportStats ) Defaults ( ) {
c . Enabled = false
2023-03-10 11:27:08 +00:00
c . Endpoint = "https://panopticon.matrix.org/push"
2022-05-04 18:04:28 +01:00
}
2023-02-14 11:47:47 +00:00
func ( c * ReportStats ) Verify ( configErrs * ConfigErrors ) {
2023-03-10 11:27:08 +00:00
// We prefer to hit panopticon (https://github.com/matrix-org/panopticon) directly over
// the "old" matrix.org endpoint.
if c . Endpoint == "https://matrix.org/report-usage-stats/push" {
c . Endpoint = "https://panopticon.matrix.org/push"
}
2022-05-04 18:04:28 +01:00
if c . Enabled {
checkNotEmpty ( configErrs , "global.report_stats.endpoint" , c . Endpoint )
}
}
2021-03-24 10:25:24 +00:00
// The configuration to use for Sentry error reporting
type Sentry struct {
Enabled bool ` yaml:"enabled" `
// The DSN to connect to e.g "https://examplePublicKey@o0.ingest.sentry.io/0"
// See https://docs.sentry.io/platforms/go/configuration/options/
DSN string ` yaml:"dsn" `
// The environment e.g "production"
// See https://docs.sentry.io/platforms/go/configuration/environments/
Environment string ` yaml:"environment" `
}
func ( c * Sentry ) Defaults ( ) {
c . Enabled = false
}
2023-02-14 11:47:47 +00:00
func ( c * Sentry ) Verify ( configErrs * ConfigErrors ) {
2021-03-24 10:25:24 +00:00
}
2020-08-10 14:18:04 +01:00
type DatabaseOptions struct {
// The connection string, file:filename.db or postgres://server....
ConnectionString DataSource ` yaml:"connection_string" `
// Maximum open connections to the DB (0 = use default, negative means unlimited)
MaxOpenConnections int ` yaml:"max_open_conns" `
// Maximum idle connections to the DB (0 = use default, negative means unlimited)
MaxIdleConnections int ` yaml:"max_idle_conns" `
// maximum amount of time (in seconds) a connection may be reused (<= 0 means unlimited)
ConnMaxLifetimeSeconds int ` yaml:"conn_max_lifetime" `
}
2021-03-08 13:18:29 +00:00
func ( c * DatabaseOptions ) Defaults ( conns int ) {
c . MaxOpenConnections = conns
2020-08-10 14:18:04 +01:00
c . MaxIdleConnections = 2
c . ConnMaxLifetimeSeconds = - 1
}
2023-02-14 11:47:47 +00:00
func ( c * DatabaseOptions ) Verify ( configErrs * ConfigErrors ) { }
2020-08-10 14:18:04 +01:00
// MaxIdleConns returns maximum idle connections to the DB
func ( c DatabaseOptions ) MaxIdleConns ( ) int {
return c . MaxIdleConnections
}
// MaxOpenConns returns maximum open connections to the DB
func ( c DatabaseOptions ) MaxOpenConns ( ) int {
return c . MaxOpenConnections
}
// ConnMaxLifetime returns maximum amount of time a connection may be reused
func ( c DatabaseOptions ) ConnMaxLifetime ( ) time . Duration {
return time . Duration ( c . ConnMaxLifetimeSeconds ) * time . Second
}
2021-01-22 14:16:59 +00:00
type DNSCacheOptions struct {
// Whether the DNS cache is enabled or not
Enabled bool ` yaml:"enabled" `
// How many entries to store in the DNS cache at a given time
CacheSize int ` yaml:"cache_size" `
// How long a cache entry should be considered valid for
CacheLifetime time . Duration ` yaml:"cache_lifetime" `
}
func ( c * DNSCacheOptions ) Defaults ( ) {
c . Enabled = false
c . CacheSize = 256
c . CacheLifetime = time . Minute * 5
}
2023-02-14 11:47:47 +00:00
func ( c * DNSCacheOptions ) Verify ( configErrs * ConfigErrors ) {
2021-01-22 14:16:59 +00:00
checkPositive ( configErrs , "cache_size" , int64 ( c . CacheSize ) )
checkPositive ( configErrs , "cache_lifetime" , int64 ( c . CacheLifetime ) )
}
2022-04-06 12:11:19 +01:00
// PresenceOptions defines possible configurations for presence events.
type PresenceOptions struct {
// Whether inbound presence events are allowed
EnableInbound bool ` yaml:"enable_inbound" `
// Whether outbound presence events are allowed
EnableOutbound bool ` yaml:"enable_outbound" `
}
2022-07-11 14:31:31 +01:00
type DataUnit int64
func ( d * DataUnit ) UnmarshalText ( text [ ] byte ) error {
var magnitude float64
s := strings . ToLower ( string ( text ) )
switch {
case strings . HasSuffix ( s , "tb" ) :
s , magnitude = s [ : len ( s ) - 2 ] , 1024 * 1024 * 1024 * 1024
case strings . HasSuffix ( s , "gb" ) :
s , magnitude = s [ : len ( s ) - 2 ] , 1024 * 1024 * 1024
case strings . HasSuffix ( s , "mb" ) :
s , magnitude = s [ : len ( s ) - 2 ] , 1024 * 1024
case strings . HasSuffix ( s , "kb" ) :
s , magnitude = s [ : len ( s ) - 2 ] , 1024
default :
magnitude = 1
}
v , err := strconv . ParseFloat ( s , 64 )
if err != nil {
return err
}
* d = DataUnit ( v * magnitude )
return nil
}