mirror of
https://github.com/element-hq/dendrite.git
synced 2025-09-14 05:12:26 +03:00
mas: added localpart_external_ids table
This commit is contained in:
parent
e1dfe62b20
commit
150be588f5
8 changed files with 242 additions and 0 deletions
|
@ -471,6 +471,14 @@ type OpenIDTokenAttributes struct {
|
||||||
ExpiresAtMS int64
|
ExpiresAtMS int64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LocalpartExternalID represents a connection between Matrix account and OpenID Connect provider
|
||||||
|
type LocalpartExternalID struct {
|
||||||
|
Localpart string
|
||||||
|
ExternalID string
|
||||||
|
AuthProvider string
|
||||||
|
CreatedTs int64
|
||||||
|
}
|
||||||
|
|
||||||
// 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
|
||||||
type UserInfo struct {
|
type UserInfo struct {
|
||||||
Sub string // The Matrix user's ID who generated the token
|
Sub string // The Matrix user's ID who generated the token
|
||||||
|
|
|
@ -134,6 +134,12 @@ type Notification interface {
|
||||||
DeleteOldNotifications(ctx context.Context) error
|
DeleteOldNotifications(ctx context.Context) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type LocalpartExternalID interface {
|
||||||
|
CreateLocalpartExternalID(ctx context.Context, localpart, externalID, authProvider string) error
|
||||||
|
GetLocalpartForExternalID(ctx context.Context, externalID, authProvider string) (*api.LocalpartExternalID, error)
|
||||||
|
DeleteLocalpartExternalID(ctx context.Context, externalID, authProvider string) error
|
||||||
|
}
|
||||||
|
|
||||||
type UserDatabase interface {
|
type UserDatabase interface {
|
||||||
Account
|
Account
|
||||||
AccountData
|
AccountData
|
||||||
|
@ -147,6 +153,7 @@ type UserDatabase interface {
|
||||||
Statistics
|
Statistics
|
||||||
ThreePID
|
ThreePID
|
||||||
RegistrationTokens
|
RegistrationTokens
|
||||||
|
LocalpartExternalID
|
||||||
}
|
}
|
||||||
|
|
||||||
type KeyChangeDatabase interface {
|
type KeyChangeDatabase interface {
|
||||||
|
|
97
userapi/storage/postgres/localpart_external_ids_table.go
Normal file
97
userapi/storage/postgres/localpart_external_ids_table.go
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
package postgres
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/element-hq/dendrite/internal/sqlutil"
|
||||||
|
"github.com/element-hq/dendrite/userapi/api"
|
||||||
|
"github.com/element-hq/dendrite/userapi/storage/tables"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
const localpartExternalIDsSchema = `
|
||||||
|
-- Stores data about connections between accounts and third-party auth providers
|
||||||
|
CREATE TABLE IF NOT EXISTS userapi_localpart_external_ids (
|
||||||
|
-- The Matrix user ID for this account
|
||||||
|
localpart TEXT NOT NULL,
|
||||||
|
-- The external ID
|
||||||
|
external_id TEXT NOT NULL,
|
||||||
|
-- Auth provider ID (see OIDCProvider.IDPID)
|
||||||
|
auth_provider TEXT NOT NULL,
|
||||||
|
-- When this connection was created, as a unix timestamp.
|
||||||
|
created_ts BIGINT NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT userapi_localpart_external_ids_external_id_auth_provider_unique UNIQUE(external_id, auth_provider),
|
||||||
|
CONSTRAINT userapi_localpart_external_ids_localpart_external_id_auth_provider_unique UNIQUE(localpart, external_id, auth_provider)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- This index allows efficient lookup of the local user by the external ID
|
||||||
|
CREATE INDEX IF NOT EXISTS userapi_external_id_auth_provider_idx ON userapi_localpart_external_ids(external_id, auth_provider);
|
||||||
|
`
|
||||||
|
|
||||||
|
const insertUserExternalIDSQL = "" +
|
||||||
|
"INSERT INTO userapi_localpart_external_ids(localpart, external_id, auth_provider, created_ts) VALUES ($1, $2, $3, $4)"
|
||||||
|
|
||||||
|
const selectUserExternalIDSQL = "" +
|
||||||
|
"SELECT localpart, created_ts FROM userapi_localpart_external_ids WHERE external_id = $1 AND auth_provider = $2"
|
||||||
|
|
||||||
|
const deleteUserExternalIDSQL = "" +
|
||||||
|
"SELECT localpart, external_id, auth_provider, created_ts FROM userapi_localpart_external_ids WHERE external_id = $1 AND auth_provider = $2"
|
||||||
|
|
||||||
|
type localpartExternalIDStatements struct {
|
||||||
|
db *sql.DB
|
||||||
|
insertUserExternalIDStmt *sql.Stmt
|
||||||
|
selectUserExternalIDStmt *sql.Stmt
|
||||||
|
deleteUserExternalIDStmt *sql.Stmt
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPostgresLocalpartExternalIDsTable(db *sql.DB) (tables.LocalpartExternalIDsTable, error) {
|
||||||
|
s := &localpartExternalIDStatements{
|
||||||
|
db: db,
|
||||||
|
}
|
||||||
|
_, err := db.Exec(localpartExternalIDsSchema)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return s, sqlutil.StatementList{
|
||||||
|
{&s.insertUserExternalIDStmt, insertUserExternalIDSQL},
|
||||||
|
{&s.selectUserExternalIDStmt, selectUserExternalIDSQL},
|
||||||
|
{&s.deleteUserExternalIDStmt, deleteUserExternalIDSQL},
|
||||||
|
}.Prepare(db)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select selects an existing OpenID Connect connection from the database
|
||||||
|
func (u *localpartExternalIDStatements) Select(ctx context.Context, txn *sql.Tx, externalID, authProvider string) (*api.LocalpartExternalID, error) {
|
||||||
|
ret := api.LocalpartExternalID{
|
||||||
|
ExternalID: externalID,
|
||||||
|
AuthProvider: authProvider,
|
||||||
|
}
|
||||||
|
err := u.selectUserExternalIDStmt.QueryRowContext(ctx, externalID, authProvider).Scan(
|
||||||
|
&ret.Localpart, &ret.CreatedTs,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
log.WithError(err).Error("Unable to retrieve localpart from the db")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert creates a new record representing an OpenID Connect connection between Matrix and external accounts.
|
||||||
|
func (u *localpartExternalIDStatements) Insert(ctx context.Context, txn *sql.Tx, localpart, externalID, authProvider string) error {
|
||||||
|
stmt := sqlutil.TxStmt(txn, u.insertUserExternalIDStmt)
|
||||||
|
_, err := stmt.ExecContext(ctx, localpart, externalID, authProvider, time.Now().Unix())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete deletes the existing OpenID Connect connection. After this method is called, the Matrix account will no longer be associated with the external account.
|
||||||
|
func (u *localpartExternalIDStatements) Delete(ctx context.Context, txn *sql.Tx, externalID, authProvider string) error {
|
||||||
|
stmt := sqlutil.TxStmt(txn, u.deleteUserExternalIDStmt)
|
||||||
|
_, err := stmt.ExecContext(ctx, externalID, authProvider)
|
||||||
|
return err
|
||||||
|
}
|
|
@ -97,6 +97,10 @@ func NewDatabase(ctx context.Context, conMan *sqlutil.Connections, dbProperties
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("NewPostgresStatsTable: %w", err)
|
return nil, fmt.Errorf("NewPostgresStatsTable: %w", err)
|
||||||
}
|
}
|
||||||
|
localpartExternalIDsTable, err := NewPostgresLocalpartExternalIDsTable(db)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("NewSQLiteLocalpartExternalIDsTable: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
m = sqlutil.NewMigrator(db)
|
m = sqlutil.NewMigrator(db)
|
||||||
m.AddMigrations(sqlutil.Migration{
|
m.AddMigrations(sqlutil.Migration{
|
||||||
|
@ -123,6 +127,7 @@ func NewDatabase(ctx context.Context, conMan *sqlutil.Connections, dbProperties
|
||||||
Notifications: notificationsTable,
|
Notifications: notificationsTable,
|
||||||
RegistrationTokens: registationTokensTable,
|
RegistrationTokens: registationTokensTable,
|
||||||
Stats: statsTable,
|
Stats: statsTable,
|
||||||
|
LocalpartExternalIDs: localpartExternalIDsTable,
|
||||||
ServerName: serverName,
|
ServerName: serverName,
|
||||||
DB: db,
|
DB: db,
|
||||||
Writer: writer,
|
Writer: writer,
|
||||||
|
|
|
@ -49,6 +49,7 @@ type Database struct {
|
||||||
Notifications tables.NotificationTable
|
Notifications tables.NotificationTable
|
||||||
Pushers tables.PusherTable
|
Pushers tables.PusherTable
|
||||||
Stats tables.StatsTable
|
Stats tables.StatsTable
|
||||||
|
LocalpartExternalIDs tables.LocalpartExternalIDsTable
|
||||||
LoginTokenLifetime time.Duration
|
LoginTokenLifetime time.Duration
|
||||||
ServerName spec.ServerName
|
ServerName spec.ServerName
|
||||||
BcryptCost int
|
BcryptCost int
|
||||||
|
@ -870,6 +871,18 @@ func (d *Database) UpsertPusher(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *Database) CreateLocalpartExternalID(ctx context.Context, localpart, externalID, authProvider string) error {
|
||||||
|
return d.LocalpartExternalIDs.Insert(ctx, nil, localpart, externalID, authProvider)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Database) GetLocalpartForExternalID(ctx context.Context, externalID, authProvider string) (*api.LocalpartExternalID, error) {
|
||||||
|
return d.LocalpartExternalIDs.Select(ctx, nil, externalID, authProvider)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Database) DeleteLocalpartExternalID(ctx context.Context, externalID, authProvider string) error {
|
||||||
|
return d.LocalpartExternalIDs.Delete(ctx, nil, externalID, authProvider)
|
||||||
|
}
|
||||||
|
|
||||||
// GetPushers returns the pushers matching the given localpart.
|
// GetPushers returns the pushers matching the given localpart.
|
||||||
func (d *Database) GetPushers(
|
func (d *Database) GetPushers(
|
||||||
ctx context.Context, localpart string, serverName spec.ServerName,
|
ctx context.Context, localpart string, serverName spec.ServerName,
|
||||||
|
|
97
userapi/storage/sqlite3/localpart_external_ids_table.go
Normal file
97
userapi/storage/sqlite3/localpart_external_ids_table.go
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
package sqlite3
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/element-hq/dendrite/internal/sqlutil"
|
||||||
|
"github.com/element-hq/dendrite/userapi/api"
|
||||||
|
"github.com/element-hq/dendrite/userapi/storage/tables"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
const localpartExternalIDsSchema = `
|
||||||
|
-- Stores data about connections between accounts and third-party auth providers
|
||||||
|
CREATE TABLE IF NOT EXISTS userapi_localpart_external_ids (
|
||||||
|
-- The Matrix user ID for this account
|
||||||
|
localpart TEXT NOT NULL,
|
||||||
|
-- The external ID
|
||||||
|
external_id TEXT NOT NULL,
|
||||||
|
-- Auth provider ID (see OIDCProvider.IDPID)
|
||||||
|
auth_provider TEXT NOT NULL,
|
||||||
|
-- When this connection was created, as a unix timestamp.
|
||||||
|
created_ts BIGINT NOT NULL,
|
||||||
|
|
||||||
|
UNIQUE(external_id, auth_provider),
|
||||||
|
UNIQUE(localpart, external_id, auth_provider)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- This index allows efficient lookup of the local user by the external ID
|
||||||
|
CREATE INDEX IF NOT EXISTS userapi_external_id_auth_provider_idx ON userapi_localpart_external_ids(external_id, auth_provider);
|
||||||
|
`
|
||||||
|
|
||||||
|
const insertLocalpartExternalIDSQL = "" +
|
||||||
|
"INSERT INTO userapi_localpart_external_ids(localpart, external_id, auth_provider, created_ts) VALUES ($1, $2, $3, $4)"
|
||||||
|
|
||||||
|
const selectLocalpartExternalIDSQL = "" +
|
||||||
|
"SELECT localpart, created_ts FROM userapi_localpart_external_ids WHERE external_id = $1 AND auth_provider = $2"
|
||||||
|
|
||||||
|
const deleteLocalpartExternalIDSQL = "" +
|
||||||
|
"SELECT localpart, external_id, auth_provider, created_ts FROM userapi_localpart_external_ids WHERE external_id = $1 AND auth_provider = $2"
|
||||||
|
|
||||||
|
type localpartExternalIDStatements struct {
|
||||||
|
db *sql.DB
|
||||||
|
insertUserExternalIDStmt *sql.Stmt
|
||||||
|
selectUserExternalIDStmt *sql.Stmt
|
||||||
|
deleteUserExternalIDStmt *sql.Stmt
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSQLiteLocalpartExternalIDsTable(db *sql.DB) (tables.LocalpartExternalIDsTable, error) {
|
||||||
|
s := &localpartExternalIDStatements{
|
||||||
|
db: db,
|
||||||
|
}
|
||||||
|
_, err := db.Exec(localpartExternalIDsSchema)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return s, sqlutil.StatementList{
|
||||||
|
{&s.insertUserExternalIDStmt, insertLocalpartExternalIDSQL},
|
||||||
|
{&s.selectUserExternalIDStmt, selectLocalpartExternalIDSQL},
|
||||||
|
{&s.deleteUserExternalIDStmt, deleteLocalpartExternalIDSQL},
|
||||||
|
}.Prepare(db)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select selects an existing OpenID Connect connection from the database
|
||||||
|
func (u *localpartExternalIDStatements) Select(ctx context.Context, txn *sql.Tx, externalID, authProvider string) (*api.LocalpartExternalID, error) {
|
||||||
|
ret := api.LocalpartExternalID{
|
||||||
|
ExternalID: externalID,
|
||||||
|
AuthProvider: authProvider,
|
||||||
|
}
|
||||||
|
err := u.selectUserExternalIDStmt.QueryRowContext(ctx, externalID, authProvider).Scan(
|
||||||
|
&ret.Localpart, &ret.CreatedTs,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
log.WithError(err).Error("Unable to retrieve localpart from the db")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert creates a new record representing an OpenID Connect connection between Matrix and external accounts.
|
||||||
|
func (u *localpartExternalIDStatements) Insert(ctx context.Context, txn *sql.Tx, localpart, externalID, authProvider string) error {
|
||||||
|
stmt := sqlutil.TxStmt(txn, u.insertUserExternalIDStmt)
|
||||||
|
_, err := stmt.ExecContext(ctx, localpart, externalID, authProvider, time.Now().Unix())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete deletes the existing OpenID Connect connection. After this method is called, the Matrix account will no longer be associated with the external account.
|
||||||
|
func (u *localpartExternalIDStatements) Delete(ctx context.Context, txn *sql.Tx, externalID, authProvider string) error {
|
||||||
|
stmt := sqlutil.TxStmt(txn, u.deleteUserExternalIDStmt)
|
||||||
|
_, err := stmt.ExecContext(ctx, externalID, authProvider)
|
||||||
|
return err
|
||||||
|
}
|
|
@ -94,6 +94,10 @@ func NewUserDatabase(ctx context.Context, conMan *sqlutil.Connections, dbPropert
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("NewSQLiteStatsTable: %w", err)
|
return nil, fmt.Errorf("NewSQLiteStatsTable: %w", err)
|
||||||
}
|
}
|
||||||
|
localpartExternalIDsTable, err := NewSQLiteLocalpartExternalIDsTable(db)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("NewSQLiteUserExternalIDsTable: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
m = sqlutil.NewMigrator(db)
|
m = sqlutil.NewMigrator(db)
|
||||||
m.AddMigrations(sqlutil.Migration{
|
m.AddMigrations(sqlutil.Migration{
|
||||||
|
@ -119,6 +123,7 @@ func NewUserDatabase(ctx context.Context, conMan *sqlutil.Connections, dbPropert
|
||||||
Pushers: pusherTable,
|
Pushers: pusherTable,
|
||||||
Notifications: notificationsTable,
|
Notifications: notificationsTable,
|
||||||
Stats: statsTable,
|
Stats: statsTable,
|
||||||
|
LocalpartExternalIDs: localpartExternalIDsTable,
|
||||||
ServerName: serverName,
|
ServerName: serverName,
|
||||||
DB: db,
|
DB: db,
|
||||||
Writer: writer,
|
Writer: writer,
|
||||||
|
|
|
@ -127,6 +127,16 @@ type StatsTable interface {
|
||||||
UpsertDailyStats(ctx context.Context, txn *sql.Tx, serverName spec.ServerName, stats types.MessageStats, activeRooms, activeE2EERooms int64) error
|
UpsertDailyStats(ctx context.Context, txn *sql.Tx, serverName spec.ServerName, stats types.MessageStats, activeRooms, activeE2EERooms int64) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type LocalpartExternalIDsTable interface {
|
||||||
|
Select(ctx context.Context, txn *sql.Tx, externalID, authProvider string) (*api.LocalpartExternalID, error)
|
||||||
|
Insert(ctx context.Context, txn *sql.Tx, localpart, externalID, authProvider string) error
|
||||||
|
Delete(ctx context.Context, txn *sql.Tx, externalID, authProvider string) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type UIAuthSessionsTable interface {
|
||||||
|
SelectByID(ctx context.Context, txn *sql.Tx, sessionID int) (*api.UIAuthSession, error)
|
||||||
|
}
|
||||||
|
|
||||||
type NotificationFilter uint32
|
type NotificationFilter uint32
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue