More config cleanup

This commit is contained in:
Till Faelligen 2022-05-02 13:24:59 +02:00
parent e5773a695f
commit 7f520fc053
25 changed files with 145 additions and 150 deletions

View file

@ -114,10 +114,10 @@ global:
# Maximum number of entries to hold in the DNS cache, and # Maximum number of entries to hold in the DNS cache, and
# for how long those items should be considered valid in seconds. # for how long those items should be considered valid in seconds.
cache_size: 256 cache_size: 256
cache_lifetime: 300 cache_lifetime: "5m" # 5minutes; see https://pkg.go.dev/time@master#ParseDuration for more
# Configuration for the Appservice API. # Configuration for the Appservice API.
app_service_api: appservice_api:
internal_api: internal_api:
listen: http://0.0.0.0:7777 listen: http://0.0.0.0:7777
connect: http://appservice_api:7777 connect: http://appservice_api:7777
@ -311,17 +311,18 @@ user_api:
max_open_conns: 10 max_open_conns: 10
max_idle_conns: 2 max_idle_conns: 2
conn_max_lifetime: -1 conn_max_lifetime: -1
# The cost when hashing passwords on registration/login. Default: 10. Min: 4, Max: 31
# Configuration for the Push Server API. # See https://pkg.go.dev/golang.org/x/crypto/bcrypt for more information.
push_server: # Setting this lower makes registration/login consume less CPU resources at the cost of security
internal_api: # should the database be compromised. Setting this higher makes registration/login consume more
listen: http://localhost:7782 # CPU resources but makes it harder to brute force password hashes.
connect: http://localhost:7782 # This value can be low if performing tests or on embedded Dendrite instances (e.g WASM builds)
database: # bcrypt_cost: 10
connection_string: postgresql://dendrite:itsasecret@postgres/dendrite_pushserver?sslmode=disable # The length of time that a token issued for a relying party from
max_open_conns: 10 # /_matrix/client/r0/user/{userId}/openid/request_token endpoint
max_idle_conns: 2 # is considered to be valid.
conn_max_lifetime: -1 # The default lifetime is 60 minutes.
# openid_token_lifetime: "1h" # One hour; see https://pkg.go.dev/time@master#ParseDuration for more
# Configuration for Opentracing. # Configuration for Opentracing.
# See https://github.com/matrix-org/dendrite/tree/master/docs/tracing for information on # See https://github.com/matrix-org/dendrite/tree/master/docs/tracing for information on

View file

@ -16,6 +16,7 @@ package routing
import ( import (
"net/http" "net/http"
"time"
"github.com/matrix-org/dendrite/clientapi/jsonerror" "github.com/matrix-org/dendrite/clientapi/jsonerror"
"github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/config"
@ -64,7 +65,7 @@ func CreateOpenIDToken(
AccessToken: response.Token.Token, AccessToken: response.Token.Token,
TokenType: "Bearer", TokenType: "Bearer",
MatrixServerName: string(cfg.Matrix.ServerName), MatrixServerName: string(cfg.Matrix.ServerName),
ExpiresIn: response.Token.ExpiresAtMS / 1000, // convert ms to s ExpiresIn: int64(time.Until(response.Token.ExpiresAt.Time()).Seconds()),
}, },
} }
} }

View file

@ -35,23 +35,20 @@ func RequestTurnServer(req *http.Request, device *api.Device, cfg *config.Client
turnConfig := cfg.TURN turnConfig := cfg.TURN
// TODO Guest Support // TODO Guest Support
if len(turnConfig.URIs) == 0 || turnConfig.UserLifetime == "" { if len(turnConfig.URIs) == 0 || turnConfig.UserLifetime.Seconds() == 0 {
return util.JSONResponse{ return util.JSONResponse{
Code: http.StatusOK, Code: http.StatusOK,
JSON: struct{}{}, JSON: struct{}{},
} }
} }
// Duration checked at startup, err not possible
duration, _ := time.ParseDuration(turnConfig.UserLifetime)
resp := gomatrix.RespTurnServer{ resp := gomatrix.RespTurnServer{
URIs: turnConfig.URIs, URIs: turnConfig.URIs,
TTL: int(duration.Seconds()), TTL: int(turnConfig.UserLifetime.Seconds()),
} }
if turnConfig.SharedSecret != "" { if turnConfig.SharedSecret != "" {
expiry := time.Now().Add(duration).Unix() expiry := time.Now().Add(turnConfig.UserLifetime).Unix()
resp.Username = fmt.Sprintf("%d:%s", expiry, device.UserID) resp.Username = fmt.Sprintf("%d:%s", expiry, device.UserID)
mac := hmac.New(sha1.New, []byte(turnConfig.SharedSecret)) mac := hmac.New(sha1.New, []byte(turnConfig.SharedSecret))
_, err := mac.Write([]byte(resp.Username)) _, err := mac.Write([]byte(resp.Username))

View file

@ -140,7 +140,7 @@ global:
cache_lifetime: "5m" # 5minutes; see https://pkg.go.dev/time@master#ParseDuration for more cache_lifetime: "5m" # 5minutes; see https://pkg.go.dev/time@master#ParseDuration for more
# Configuration for the Appservice API. # Configuration for the Appservice API.
app_service_api: appservice_api:
# Disable the validation of TLS certificates of appservices. This is # Disable the validation of TLS certificates of appservices. This is
# not recommended in production since it may allow appservice traffic # not recommended in production since it may allow appservice traffic
# to be sent to an unverified endpoint. # to be sent to an unverified endpoint.
@ -174,7 +174,7 @@ client_api:
# TURN server information that this homeserver should send to clients. # TURN server information that this homeserver should send to clients.
turn: turn:
turn_user_lifetime: "" turn_user_lifetime: "24h" # 24 hours; see https://pkg.go.dev/time@master#ParseDuration for more
turn_uris: [] turn_uris: []
turn_shared_secret: "" turn_shared_secret: ""
turn_username: "" turn_username: ""
@ -268,9 +268,9 @@ user_api:
# bcrypt_cost: 10 # bcrypt_cost: 10
# The length of time that a token issued for a relying party from # The length of time that a token issued for a relying party from
# /_matrix/client/r0/user/{userId}/openid/request_token endpoint # /_matrix/client/r0/user/{userId}/openid/request_token endpoint
# is considered to be valid in milliseconds. # is considered to be valid.
# The default lifetime is 3600000ms (60 minutes). # The default lifetime is 60 minutes.
# openid_token_lifetime_ms: 3600000 # openid_token_lifetime: "1h" # One hour; see https://pkg.go.dev/time@master#ParseDuration for more
# Configuration for Opentracing. # Configuration for Opentracing.
# See https://github.com/matrix-org/dendrite/tree/master/docs/tracing for information on # See https://github.com/matrix-org/dendrite/tree/master/docs/tracing for information on

View file

@ -131,7 +131,7 @@ global:
cache_lifetime: "5m" # 5minutes; see https://pkg.go.dev/time@master#ParseDuration for more cache_lifetime: "5m" # 5minutes; see https://pkg.go.dev/time@master#ParseDuration for more
# Configuration for the Appservice API. # Configuration for the Appservice API.
app_service_api: appservice_api:
internal_api: internal_api:
listen: http://localhost:7777 # Only used in polylith deployments listen: http://localhost:7777 # Only used in polylith deployments
connect: http://localhost:7777 # Only used in polylith deployments connect: http://localhost:7777 # Only used in polylith deployments
@ -180,7 +180,7 @@ client_api:
# TURN server information that this homeserver should send to clients. # TURN server information that this homeserver should send to clients.
turn: turn:
turn_user_lifetime: "" turn_user_lifetime: "24h" # 24 hours; see https://pkg.go.dev/time@master#ParseDuration for more
turn_uris: [] turn_uris: []
turn_shared_secret: "" turn_shared_secret: ""
turn_username: "" turn_username: ""
@ -342,9 +342,9 @@ user_api:
conn_max_lifetime: -1 conn_max_lifetime: -1
# The length of time that a token issued for a relying party from # The length of time that a token issued for a relying party from
# /_matrix/client/r0/user/{userId}/openid/request_token endpoint # /_matrix/client/r0/user/{userId}/openid/request_token endpoint
# is considered to be valid in milliseconds. # is considered to be valid.
# The default lifetime is 3600000ms (60 minutes). # The default lifetime is 60 minutes.
# openid_token_lifetime_ms: 3600000 # openid_token_lifetime: "1h" # One hour; see https://pkg.go.dev/time@master#ParseDuration for more
# Configuration for Opentracing. # Configuration for Opentracing.
# See https://github.com/matrix-org/dendrite/tree/master/docs/tracing for information on # See https://github.com/matrix-org/dendrite/tree/master/docs/tracing for information on

View file

@ -52,8 +52,7 @@ func GetOpenIDUserInfo(
var res interface{} = openIDUserInfoResponse{Sub: openIDTokenAttrResponse.Sub} var res interface{} = openIDUserInfoResponse{Sub: openIDTokenAttrResponse.Sub}
code := http.StatusOK code := http.StatusOK
nowMS := time.Now().UnixNano() / int64(time.Millisecond) if openIDTokenAttrResponse.Sub == "" || time.Now().After(openIDTokenAttrResponse.ExpiresAt.Time()) {
if openIDTokenAttrResponse.Sub == "" || nowMS > openIDTokenAttrResponse.ExpiresAtMS {
code = http.StatusUnauthorized code = http.StatusUnauthorized
res = jsonerror.UnknownToken("Access Token unknown or expired") res = jsonerror.UnknownToken("Access Token unknown or expired")
} }

View file

@ -280,7 +280,7 @@ func (b *BaseDendrite) CreateAccountsDB() userdb.Database {
&b.Cfg.UserAPI.AccountDatabase, &b.Cfg.UserAPI.AccountDatabase,
b.Cfg.Global.ServerName, b.Cfg.Global.ServerName,
b.Cfg.UserAPI.BCryptCost, b.Cfg.UserAPI.BCryptCost,
b.Cfg.UserAPI.OpenIDTokenLifetimeMS, b.Cfg.UserAPI.OpenIDTokenLifetime,
userapi.DefaultLoginTokenLifetime, userapi.DefaultLoginTokenLifetime,
b.Cfg.Global.ServerNotices.LocalPart, b.Cfg.Global.ServerNotices.LocalPart,
) )

View file

@ -29,7 +29,7 @@ import (
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"golang.org/x/crypto/ed25519" "golang.org/x/crypto/ed25519"
yaml "gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
jaegerconfig "github.com/uber/jaeger-client-go/config" jaegerconfig "github.com/uber/jaeger-client-go/config"
jaegermetrics "github.com/uber/jaeger-lib/metrics" jaegermetrics "github.com/uber/jaeger-lib/metrics"
@ -54,7 +54,7 @@ type Dendrite struct {
Version int `yaml:"version"` Version int `yaml:"version"`
Global Global `yaml:"global"` Global Global `yaml:"global"`
AppServiceAPI AppServiceAPI `yaml:"app_service_api"` AppServiceAPI AppServiceAPI `yaml:"appservice_api"`
ClientAPI ClientAPI `yaml:"client_api"` ClientAPI ClientAPI `yaml:"client_api"`
FederationAPI FederationAPI `yaml:"federation_api"` FederationAPI FederationAPI `yaml:"federation_api"`
KeyServer KeyServer `yaml:"key_server"` KeyServer KeyServer `yaml:"key_server"`

View file

@ -50,10 +50,10 @@ func (c *AppServiceAPI) Defaults(generate bool) {
} }
func (c *AppServiceAPI) Verify(configErrs *ConfigErrors, isMonolith bool) { func (c *AppServiceAPI) Verify(configErrs *ConfigErrors, isMonolith bool) {
checkURL(configErrs, "app_service_api.internal_api.listen", string(c.InternalAPI.Listen)) checkURL(configErrs, "appservice_api.internal_api.listen", string(c.InternalAPI.Listen))
checkURL(configErrs, "app_service_api.internal_api.bind", string(c.InternalAPI.Connect)) checkURL(configErrs, "appservice_api.internal_api.bind", string(c.InternalAPI.Connect))
setDatabase(c.Matrix.GlobalDatabaseOptions, &c.Database, "appservice.db") setDatabase(c.Matrix.GlobalDatabaseOptions, &c.Database, "appservice.db")
checkNotEmpty(configErrs, "app_service_api.database.connection_string", string(c.Database.ConnectionString)) checkNotEmpty(configErrs, "appservice_api.database.connection_string", string(c.Database.ConnectionString))
} }
// ApplicationServiceNamespace is the namespace that a specific application // ApplicationServiceNamespace is the namespace that a specific application

View file

@ -1,7 +1,6 @@
package config package config
import ( import (
"fmt"
"time" "time"
) )
@ -64,6 +63,7 @@ func (c *ClientAPI) Defaults(generate bool) {
c.RegistrationDisabled = true c.RegistrationDisabled = true
c.OpenRegistrationWithoutVerificationEnabled = false c.OpenRegistrationWithoutVerificationEnabled = false
c.RateLimiting.Defaults() c.RateLimiting.Defaults()
c.TURN.Defaults()
} }
func (c *ClientAPI) Verify(configErrs *ConfigErrors, isMonolith bool) { func (c *ClientAPI) Verify(configErrs *ConfigErrors, isMonolith bool) {
@ -100,7 +100,7 @@ type TURN struct {
// Whether or not guests can request TURN credentials // Whether or not guests can request TURN credentials
// AllowGuests bool `yaml:"turn_allow_guests"` // AllowGuests bool `yaml:"turn_allow_guests"`
// How long the authorization should last // How long the authorization should last
UserLifetime string `yaml:"turn_user_lifetime"` UserLifetime time.Duration `yaml:"turn_user_lifetime"`
// The list of TURN URIs to pass to clients // The list of TURN URIs to pass to clients
URIs []string `yaml:"turn_uris"` URIs []string `yaml:"turn_uris"`
@ -115,12 +115,11 @@ type TURN struct {
} }
func (c *TURN) Verify(configErrs *ConfigErrors) { func (c *TURN) Verify(configErrs *ConfigErrors) {
value := c.UserLifetime checkPositive(configErrs, "cache_lifetime", int64(c.UserLifetime))
if value != "" { }
if _, err := time.ParseDuration(value); err != nil {
configErrs.Add(fmt.Sprintf("invalid duration for config key %q: %s", "client_api.turn.turn_user_lifetime", value)) func (c *TURN) Defaults() {
} c.UserLifetime = time.Hour * 24
}
} }
type RateLimiting struct { type RateLimiting struct {

View file

@ -63,7 +63,7 @@ global:
display_name: "Server alerts" display_name: "Server alerts"
avatar: "" avatar: ""
room_name: "Server Alerts" room_name: "Server Alerts"
app_service_api: appservice_api:
internal_api: internal_api:
listen: http://localhost:7777 listen: http://localhost:7777
connect: http://localhost:7777 connect: http://localhost:7777
@ -87,20 +87,11 @@ client_api:
recaptcha_bypass_secret: "" recaptcha_bypass_secret: ""
recaptcha_siteverify_api: "" recaptcha_siteverify_api: ""
turn: turn:
turn_user_lifetime: "" turn_user_lifetime: "1h"
turn_uris: [] turn_uris: []
turn_shared_secret: "" turn_shared_secret: ""
turn_username: "" turn_username: ""
turn_password: "" turn_password: ""
current_state_server:
internal_api:
listen: http://localhost:7782
connect: http://localhost:7782
database:
connection_string: file:currentstate.db
max_open_conns: 100
max_idle_conns: 2
conn_max_lifetime: -1
federation_api: federation_api:
internal_api: internal_api:
listen: http://localhost:7772 listen: http://localhost:7772

View file

@ -1,6 +1,10 @@
package config package config
import "golang.org/x/crypto/bcrypt" import (
"time"
"golang.org/x/crypto/bcrypt"
)
type UserAPI struct { type UserAPI struct {
Matrix *Global `yaml:"-"` Matrix *Global `yaml:"-"`
@ -11,7 +15,7 @@ type UserAPI struct {
BCryptCost int `yaml:"bcrypt_cost"` BCryptCost int `yaml:"bcrypt_cost"`
// The length of time an OpenID token is condidered valid in milliseconds // The length of time an OpenID token is condidered valid in milliseconds
OpenIDTokenLifetimeMS int64 `yaml:"openid_token_lifetime_ms"` OpenIDTokenLifetime time.Duration `yaml:"openid_token_lifetime"`
// Disable TLS validation on HTTPS calls to push gatways. NOT RECOMMENDED! // Disable TLS validation on HTTPS calls to push gatways. NOT RECOMMENDED!
PushGatewayDisableTLSValidation bool `yaml:"push_gateway_disable_tls_validation"` PushGatewayDisableTLSValidation bool `yaml:"push_gateway_disable_tls_validation"`
@ -21,7 +25,7 @@ type UserAPI struct {
AccountDatabase DatabaseOptions `yaml:"account_database"` AccountDatabase DatabaseOptions `yaml:"account_database"`
} }
const DefaultOpenIDTokenLifetimeMS = 3600000 // 60 minutes var DefaultOpenIDTokenLifetime = time.Hour
func (c *UserAPI) Defaults(generate bool) { func (c *UserAPI) Defaults(generate bool) {
c.InternalAPI.Listen = "http://localhost:7781" c.InternalAPI.Listen = "http://localhost:7781"
@ -31,7 +35,7 @@ func (c *UserAPI) Defaults(generate bool) {
c.AccountDatabase.ConnectionString = "file:userapi_accounts.db" c.AccountDatabase.ConnectionString = "file:userapi_accounts.db"
} }
c.BCryptCost = bcrypt.DefaultCost c.BCryptCost = bcrypt.DefaultCost
c.OpenIDTokenLifetimeMS = DefaultOpenIDTokenLifetimeMS c.OpenIDTokenLifetime = DefaultOpenIDTokenLifetime
} }
func (c *UserAPI) Verify(configErrs *ConfigErrors, isMonolith bool) { func (c *UserAPI) Verify(configErrs *ConfigErrors, isMonolith bool) {
@ -39,5 +43,5 @@ func (c *UserAPI) Verify(configErrs *ConfigErrors, isMonolith bool) {
checkURL(configErrs, "user_api.internal_api.connect", string(c.InternalAPI.Connect)) checkURL(configErrs, "user_api.internal_api.connect", string(c.InternalAPI.Connect))
setDatabase(c.Matrix.GlobalDatabaseOptions, &c.AccountDatabase, "userapi.db") setDatabase(c.Matrix.GlobalDatabaseOptions, &c.AccountDatabase, "userapi.db")
checkNotEmpty(configErrs, "user_api.account_database.connection_string", string(c.AccountDatabase.ConnectionString)) checkNotEmpty(configErrs, "user_api.account_database.connection_string", string(c.AccountDatabase.ConnectionString))
checkPositive(configErrs, "user_api.openid_token_lifetime_ms", c.OpenIDTokenLifetimeMS) checkPositive(configErrs, "user_api.openid_token_lifetime", c.OpenIDTokenLifetime.Milliseconds())
} }

View file

@ -378,8 +378,8 @@ type QueryOpenIDTokenRequest struct {
// QueryOpenIDTokenResponse is the response for QueryOpenIDToken // QueryOpenIDTokenResponse is the response for QueryOpenIDToken
type QueryOpenIDTokenResponse struct { type QueryOpenIDTokenResponse struct {
Sub string // The Matrix User ID that generated the token Sub string // The Matrix User ID that generated the token
ExpiresAtMS int64 ExpiresAt gomatrixserverlib.Timestamp
} }
// Device represents a client's device (mobile, web, etc) // Device represents a client's device (mobile, web, etc)
@ -415,15 +415,15 @@ type Account struct {
// OpenIDToken represents an OpenID token // OpenIDToken represents an OpenID token
type OpenIDToken struct { type OpenIDToken struct {
Token string Token string
UserID string UserID string
ExpiresAtMS int64 ExpiresAt gomatrixserverlib.Timestamp
} }
// OpenIDTokenInfo represents the attributes associated with an issued OpenID token // OpenIDTokenInfo represents the attributes associated with an issued OpenID token
type OpenIDTokenAttributes struct { type OpenIDTokenAttributes struct {
UserID string UserID string
ExpiresAtMS int64 ExpiresAt gomatrixserverlib.Timestamp
} }
// UserInfo is for returning information about the user an OpenID token was issued for // UserInfo is for returning information about the user an OpenID token was issued for

View file

@ -464,9 +464,9 @@ func (a *UserInternalAPI) PerformOpenIDTokenCreation(ctx context.Context, req *a
exp, err := a.DB.CreateOpenIDToken(ctx, token, req.UserID) exp, err := a.DB.CreateOpenIDToken(ctx, token, req.UserID)
res.Token = api.OpenIDToken{ res.Token = api.OpenIDToken{
Token: token, Token: token,
UserID: req.UserID, UserID: req.UserID,
ExpiresAtMS: exp, ExpiresAt: exp,
} }
return err return err
@ -480,7 +480,7 @@ func (a *UserInternalAPI) QueryOpenIDToken(ctx context.Context, req *api.QueryOp
} }
res.Sub = openIDTokenAttrs.UserID res.Sub = openIDTokenAttrs.UserID
res.ExpiresAtMS = openIDTokenAttrs.ExpiresAtMS res.ExpiresAt = openIDTokenAttrs.ExpiresAt
return nil return nil
} }

View file

@ -22,6 +22,7 @@ import (
"github.com/matrix-org/dendrite/clientapi/auth/authtypes" "github.com/matrix-org/dendrite/clientapi/auth/authtypes"
"github.com/matrix-org/dendrite/userapi/api" "github.com/matrix-org/dendrite/userapi/api"
"github.com/matrix-org/dendrite/userapi/storage/tables" "github.com/matrix-org/dendrite/userapi/storage/tables"
"github.com/matrix-org/gomatrixserverlib"
) )
type Profile interface { type Profile interface {
@ -97,7 +98,7 @@ type LoginToken interface {
} }
type OpenID interface { type OpenID interface {
CreateOpenIDToken(ctx context.Context, token, userID string) (exp int64, err error) CreateOpenIDToken(ctx context.Context, token, userID string) (exp gomatrixserverlib.Timestamp, err error)
GetOpenIDTokenAttributes(ctx context.Context, token string) (*api.OpenIDTokenAttributes, error) GetOpenIDTokenAttributes(ctx context.Context, token string) (*api.OpenIDTokenAttributes, error)
} }

View file

@ -55,7 +55,7 @@ func (s *openIDTokenStatements) InsertOpenIDToken(
ctx context.Context, ctx context.Context,
txn *sql.Tx, txn *sql.Tx,
token, localpart string, token, localpart string,
expiresAtMS int64, expiresAtMS gomatrixserverlib.Timestamp,
) (err error) { ) (err error) {
stmt := sqlutil.TxStmt(txn, s.insertTokenStmt) stmt := sqlutil.TxStmt(txn, s.insertTokenStmt)
_, err = stmt.ExecContext(ctx, token, localpart, expiresAtMS) _, err = stmt.ExecContext(ctx, token, localpart, expiresAtMS)
@ -71,7 +71,7 @@ func (s *openIDTokenStatements) SelectOpenIDTokenAtrributes(
var openIDTokenAttrs api.OpenIDTokenAttributes var openIDTokenAttrs api.OpenIDTokenAttributes
err := s.selectTokenStmt.QueryRowContext(ctx, token).Scan( err := s.selectTokenStmt.QueryRowContext(ctx, token).Scan(
&openIDTokenAttrs.UserID, &openIDTokenAttrs.UserID,
&openIDTokenAttrs.ExpiresAtMS, &openIDTokenAttrs.ExpiresAt,
) )
if err != nil { if err != nil {
if err != sql.ErrNoRows { if err != sql.ErrNoRows {

View file

@ -30,7 +30,7 @@ import (
) )
// NewDatabase creates a new accounts and profiles database // NewDatabase creates a new accounts and profiles database
func NewDatabase(dbProperties *config.DatabaseOptions, serverName gomatrixserverlib.ServerName, bcryptCost int, openIDTokenLifetimeMS int64, loginTokenLifetime time.Duration, serverNoticesLocalpart string) (*shared.Database, error) { func NewDatabase(dbProperties *config.DatabaseOptions, serverName gomatrixserverlib.ServerName, bcryptCost int, openIDTokenLifetimeMS, loginTokenLifetime time.Duration, serverNoticesLocalpart string) (*shared.Database, error) {
db, err := sqlutil.Open(dbProperties) db, err := sqlutil.Open(dbProperties)
if err != nil { if err != nil {
return nil, err return nil, err
@ -94,22 +94,22 @@ func NewDatabase(dbProperties *config.DatabaseOptions, serverName gomatrixserver
return nil, fmt.Errorf("NewPostgresNotificationTable: %w", err) return nil, fmt.Errorf("NewPostgresNotificationTable: %w", err)
} }
return &shared.Database{ return &shared.Database{
AccountDatas: accountDataTable, AccountDatas: accountDataTable,
Accounts: accountsTable, Accounts: accountsTable,
Devices: devicesTable, Devices: devicesTable,
KeyBackups: keyBackupTable, KeyBackups: keyBackupTable,
KeyBackupVersions: keyBackupVersionTable, KeyBackupVersions: keyBackupVersionTable,
LoginTokens: loginTokenTable, LoginTokens: loginTokenTable,
OpenIDTokens: openIDTable, OpenIDTokens: openIDTable,
Profiles: profilesTable, Profiles: profilesTable,
ThreePIDs: threePIDTable, ThreePIDs: threePIDTable,
Pushers: pusherTable, Pushers: pusherTable,
Notifications: notificationsTable, Notifications: notificationsTable,
ServerName: serverName, ServerName: serverName,
DB: db, DB: db,
Writer: sqlutil.NewDummyWriter(), Writer: sqlutil.NewDummyWriter(),
LoginTokenLifetime: loginTokenLifetime, LoginTokenLifetime: loginTokenLifetime,
BcryptCost: bcryptCost, BcryptCost: bcryptCost,
OpenIDTokenLifetimeMS: openIDTokenLifetimeMS, OpenIDTokenLifetime: openIDTokenLifetimeMS,
}, nil }, nil
} }

View file

@ -38,23 +38,23 @@ import (
// Database represents an account database // Database represents an account database
type Database struct { type Database struct {
DB *sql.DB DB *sql.DB
Writer sqlutil.Writer Writer sqlutil.Writer
Accounts tables.AccountsTable Accounts tables.AccountsTable
Profiles tables.ProfileTable Profiles tables.ProfileTable
AccountDatas tables.AccountDataTable AccountDatas tables.AccountDataTable
ThreePIDs tables.ThreePIDTable ThreePIDs tables.ThreePIDTable
OpenIDTokens tables.OpenIDTable OpenIDTokens tables.OpenIDTable
KeyBackups tables.KeyBackupTable KeyBackups tables.KeyBackupTable
KeyBackupVersions tables.KeyBackupVersionTable KeyBackupVersions tables.KeyBackupVersionTable
Devices tables.DevicesTable Devices tables.DevicesTable
LoginTokens tables.LoginTokenTable LoginTokens tables.LoginTokenTable
Notifications tables.NotificationTable Notifications tables.NotificationTable
Pushers tables.PusherTable Pushers tables.PusherTable
LoginTokenLifetime time.Duration LoginTokenLifetime time.Duration
ServerName gomatrixserverlib.ServerName ServerName gomatrixserverlib.ServerName
BcryptCost int BcryptCost int
OpenIDTokenLifetimeMS int64 OpenIDTokenLifetime time.Duration
} }
const ( const (
@ -325,12 +325,12 @@ func (d *Database) DeactivateAccount(ctx context.Context, localpart string) (err
func (d *Database) CreateOpenIDToken( func (d *Database) CreateOpenIDToken(
ctx context.Context, ctx context.Context,
token, localpart string, token, localpart string,
) (int64, error) { ) (gomatrixserverlib.Timestamp, error) {
expiresAtMS := time.Now().UnixNano()/int64(time.Millisecond) + d.OpenIDTokenLifetimeMS expiresAt := gomatrixserverlib.AsTimestamp(time.Now().Add(d.OpenIDTokenLifetime))
err := d.Writer.Do(d.DB, nil, func(txn *sql.Tx) error { err := d.Writer.Do(d.DB, nil, func(txn *sql.Tx) error {
return d.OpenIDTokens.InsertOpenIDToken(ctx, txn, token, localpart, expiresAtMS) return d.OpenIDTokens.InsertOpenIDToken(ctx, txn, token, localpart, expiresAt)
}) })
return expiresAtMS, err return expiresAt, err
} }
// GetOpenIDTokenAttributes gets the attributes of issued an OIDC auth token // GetOpenIDTokenAttributes gets the attributes of issued an OIDC auth token

View file

@ -57,7 +57,7 @@ func (s *openIDTokenStatements) InsertOpenIDToken(
ctx context.Context, ctx context.Context,
txn *sql.Tx, txn *sql.Tx,
token, localpart string, token, localpart string,
expiresAtMS int64, expiresAtMS gomatrixserverlib.Timestamp,
) (err error) { ) (err error) {
stmt := sqlutil.TxStmt(txn, s.insertTokenStmt) stmt := sqlutil.TxStmt(txn, s.insertTokenStmt)
_, err = stmt.ExecContext(ctx, token, localpart, expiresAtMS) _, err = stmt.ExecContext(ctx, token, localpart, expiresAtMS)
@ -73,7 +73,7 @@ func (s *openIDTokenStatements) SelectOpenIDTokenAtrributes(
var openIDTokenAttrs api.OpenIDTokenAttributes var openIDTokenAttrs api.OpenIDTokenAttributes
err := s.selectTokenStmt.QueryRowContext(ctx, token).Scan( err := s.selectTokenStmt.QueryRowContext(ctx, token).Scan(
&openIDTokenAttrs.UserID, &openIDTokenAttrs.UserID,
&openIDTokenAttrs.ExpiresAtMS, &openIDTokenAttrs.ExpiresAt,
) )
if err != nil { if err != nil {
if err != sql.ErrNoRows { if err != sql.ErrNoRows {

View file

@ -31,7 +31,7 @@ import (
) )
// NewDatabase creates a new accounts and profiles database // NewDatabase creates a new accounts and profiles database
func NewDatabase(dbProperties *config.DatabaseOptions, serverName gomatrixserverlib.ServerName, bcryptCost int, openIDTokenLifetimeMS int64, loginTokenLifetime time.Duration, serverNoticesLocalpart string) (*shared.Database, error) { func NewDatabase(dbProperties *config.DatabaseOptions, serverName gomatrixserverlib.ServerName, bcryptCost int, openIDTokenLifetimeMS, loginTokenLifetime time.Duration, serverNoticesLocalpart string) (*shared.Database, error) {
db, err := sqlutil.Open(dbProperties) db, err := sqlutil.Open(dbProperties)
if err != nil { if err != nil {
return nil, err return nil, err
@ -95,22 +95,22 @@ func NewDatabase(dbProperties *config.DatabaseOptions, serverName gomatrixserver
return nil, fmt.Errorf("NewPostgresNotificationTable: %w", err) return nil, fmt.Errorf("NewPostgresNotificationTable: %w", err)
} }
return &shared.Database{ return &shared.Database{
AccountDatas: accountDataTable, AccountDatas: accountDataTable,
Accounts: accountsTable, Accounts: accountsTable,
Devices: devicesTable, Devices: devicesTable,
KeyBackups: keyBackupTable, KeyBackups: keyBackupTable,
KeyBackupVersions: keyBackupVersionTable, KeyBackupVersions: keyBackupVersionTable,
LoginTokens: loginTokenTable, LoginTokens: loginTokenTable,
OpenIDTokens: openIDTable, OpenIDTokens: openIDTable,
Profiles: profilesTable, Profiles: profilesTable,
ThreePIDs: threePIDTable, ThreePIDs: threePIDTable,
Pushers: pusherTable, Pushers: pusherTable,
Notifications: notificationsTable, Notifications: notificationsTable,
ServerName: serverName, ServerName: serverName,
DB: db, DB: db,
Writer: sqlutil.NewExclusiveWriter(), Writer: sqlutil.NewExclusiveWriter(),
LoginTokenLifetime: loginTokenLifetime, LoginTokenLifetime: loginTokenLifetime,
BcryptCost: bcryptCost, BcryptCost: bcryptCost,
OpenIDTokenLifetimeMS: openIDTokenLifetimeMS, OpenIDTokenLifetime: openIDTokenLifetimeMS,
}, nil }, nil
} }

View file

@ -30,12 +30,12 @@ import (
// NewUserAPIDatabase opens a new Postgres or Sqlite database (based on dataSourceName scheme) // NewUserAPIDatabase opens a new Postgres or Sqlite database (based on dataSourceName scheme)
// and sets postgres connection parameters // and sets postgres connection parameters
func NewUserAPIDatabase(dbProperties *config.DatabaseOptions, serverName gomatrixserverlib.ServerName, bcryptCost int, openIDTokenLifetimeMS int64, loginTokenLifetime time.Duration, serverNoticesLocalpart string) (Database, error) { func NewUserAPIDatabase(dbProperties *config.DatabaseOptions, serverName gomatrixserverlib.ServerName, bcryptCost int, openIDTokenLifetime, loginTokenLifetime time.Duration, serverNoticesLocalpart string) (Database, error) {
switch { switch {
case dbProperties.ConnectionString.IsSQLite(): case dbProperties.ConnectionString.IsSQLite():
return sqlite3.NewDatabase(dbProperties, serverName, bcryptCost, openIDTokenLifetimeMS, loginTokenLifetime, serverNoticesLocalpart) return sqlite3.NewDatabase(dbProperties, serverName, bcryptCost, openIDTokenLifetime, loginTokenLifetime, serverNoticesLocalpart)
case dbProperties.ConnectionString.IsPostgres(): case dbProperties.ConnectionString.IsPostgres():
return postgres.NewDatabase(dbProperties, serverName, bcryptCost, openIDTokenLifetimeMS, loginTokenLifetime, serverNoticesLocalpart) return postgres.NewDatabase(dbProperties, serverName, bcryptCost, openIDTokenLifetime, loginTokenLifetime, serverNoticesLocalpart)
default: default:
return nil, fmt.Errorf("unexpected database type") return nil, fmt.Errorf("unexpected database type")
} }

View file

@ -20,18 +20,20 @@ import (
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
) )
const loginTokenLifetime = time.Minute const (
loginTokenLifetime = time.Minute
openIDLifetime = time.Minute
)
var ( var (
openIDLifetimeMS = time.Minute.Milliseconds() ctx = context.Background()
ctx = context.Background()
) )
func mustCreateDatabase(t *testing.T, dbType test.DBType) (storage.Database, func()) { func mustCreateDatabase(t *testing.T, dbType test.DBType) (storage.Database, func()) {
connStr, close := test.PrepareDBConnectionString(t, dbType) connStr, close := test.PrepareDBConnectionString(t, dbType)
db, err := storage.NewUserAPIDatabase(&config.DatabaseOptions{ db, err := storage.NewUserAPIDatabase(&config.DatabaseOptions{
ConnectionString: config.DataSource(connStr), ConnectionString: config.DataSource(connStr),
}, "localhost", bcrypt.MinCost, openIDLifetimeMS, loginTokenLifetime, "_server") }, "localhost", bcrypt.MinCost, openIDLifetime, loginTokenLifetime, "_server")
if err != nil { if err != nil {
t.Fatalf("NewUserAPIDatabase returned %s", err) t.Fatalf("NewUserAPIDatabase returned %s", err)
} }
@ -328,15 +330,15 @@ func Test_OpenID(t *testing.T) {
db, close := mustCreateDatabase(t, dbType) db, close := mustCreateDatabase(t, dbType)
defer close() defer close()
expiresAtMS := time.Now().UnixNano()/int64(time.Millisecond) + openIDLifetimeMS expiresAt := gomatrixserverlib.AsTimestamp(time.Now().Add(openIDLifetime))
expires, err := db.CreateOpenIDToken(ctx, token, alice.ID) expires, err := db.CreateOpenIDToken(ctx, token, alice.ID)
assert.NoError(t, err, "unable to create OpenID token") assert.NoError(t, err, "unable to create OpenID token")
assert.Equal(t, expiresAtMS, expires) assert.Equal(t, expiresAt, expires)
attributes, err := db.GetOpenIDTokenAttributes(ctx, token) attributes, err := db.GetOpenIDTokenAttributes(ctx, token)
assert.NoError(t, err, "unable to get OpenID token attributes") assert.NoError(t, err, "unable to get OpenID token attributes")
assert.Equal(t, alice.ID, attributes.UserID) assert.Equal(t, alice.ID, attributes.UserID)
assert.Equal(t, expiresAtMS, attributes.ExpiresAtMS) assert.Equal(t, expiresAt, attributes.ExpiresAt)
}) })
} }

View file

@ -27,13 +27,12 @@ func NewUserAPIDatabase(
dbProperties *config.DatabaseOptions, dbProperties *config.DatabaseOptions,
serverName gomatrixserverlib.ServerName, serverName gomatrixserverlib.ServerName,
bcryptCost int, bcryptCost int,
openIDTokenLifetimeMS int64, openIDTokenLifetime, loginTokenLifetime time.Duration,
loginTokenLifetime time.Duration,
serverNoticesLocalpart string, serverNoticesLocalpart string,
) (Database, error) { ) (Database, error) {
switch { switch {
case dbProperties.ConnectionString.IsSQLite(): case dbProperties.ConnectionString.IsSQLite():
return sqlite3.NewDatabase(dbProperties, serverName, bcryptCost, openIDTokenLifetimeMS, loginTokenLifetime, serverNoticesLocalpart) return sqlite3.NewDatabase(dbProperties, serverName, bcryptCost, openIDTokenLifetime, loginTokenLifetime, serverNoticesLocalpart)
case dbProperties.ConnectionString.IsPostgres(): case dbProperties.ConnectionString.IsPostgres():
return nil, fmt.Errorf("can't use Postgres implementation") return nil, fmt.Errorf("can't use Postgres implementation")
default: default:

View file

@ -21,6 +21,7 @@ import (
"github.com/matrix-org/dendrite/clientapi/auth/authtypes" "github.com/matrix-org/dendrite/clientapi/auth/authtypes"
"github.com/matrix-org/dendrite/userapi/api" "github.com/matrix-org/dendrite/userapi/api"
"github.com/matrix-org/gomatrixserverlib"
) )
type AccountDataTable interface { type AccountDataTable interface {
@ -75,7 +76,7 @@ type LoginTokenTable interface {
} }
type OpenIDTable interface { type OpenIDTable interface {
InsertOpenIDToken(ctx context.Context, txn *sql.Tx, token, localpart string, expiresAtMS int64) (err error) InsertOpenIDToken(ctx context.Context, txn *sql.Tx, token, localpart string, expiresAtMS gomatrixserverlib.Timestamp) (err error)
SelectOpenIDTokenAtrributes(ctx context.Context, token string) (*api.OpenIDTokenAttributes, error) SelectOpenIDTokenAtrributes(ctx context.Context, token string) (*api.OpenIDTokenAttributes, error)
} }

View file

@ -52,7 +52,7 @@ func MustMakeInternalAPI(t *testing.T, opts apiTestOpts) (api.UserInternalAPI, s
MaxOpenConnections: 1, MaxOpenConnections: 1,
MaxIdleConnections: 1, MaxIdleConnections: 1,
} }
accountDB, err := storage.NewUserAPIDatabase(dbopts, serverName, bcrypt.MinCost, config.DefaultOpenIDTokenLifetimeMS, opts.loginTokenLifetime, "") accountDB, err := storage.NewUserAPIDatabase(dbopts, serverName, bcrypt.MinCost, config.DefaultOpenIDTokenLifetime, opts.loginTokenLifetime, "")
if err != nil { if err != nil {
t.Fatalf("failed to create account DB: %s", err) t.Fatalf("failed to create account DB: %s", err)
} }