diff options
author | Loïck Bonniot <git@lesterpig.com> | 2020-10-02 18:18:20 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-10-02 17:18:20 +0100 |
commit | 4e8c484618f5bfd5b7349cc2afd102cd5feb3861 (patch) | |
tree | 915618d3127f7ead8c5cce5a5814ae861841498a /userapi/storage | |
parent | 279044cd90722ba98b018b0aa277285113454822 (diff) |
Implement account deactivation (#1455)
* Implement account deactivation
See #610
Signed-off-by: Loïck Bonniot <git@lesterpig.com>
* Rename 'is_active' to 'is_deactivated'
Signed-off-by: Loïck Bonniot <git@lesterpig.com>
Co-authored-by: Kegsay <kegan@matrix.org>
Diffstat (limited to 'userapi/storage')
7 files changed, 94 insertions, 4 deletions
diff --git a/userapi/storage/accounts/interface.go b/userapi/storage/accounts/interface.go index 49446f11..c86b2c39 100644 --- a/userapi/storage/accounts/interface.go +++ b/userapi/storage/accounts/interface.go @@ -51,6 +51,7 @@ type Database interface { CheckAccountAvailability(ctx context.Context, localpart string) (bool, error) GetAccountByLocalpart(ctx context.Context, localpart string) (*api.Account, error) SearchProfiles(ctx context.Context, searchString string, limit int) ([]authtypes.Profile, error) + DeactivateAccount(ctx context.Context, localpart string) (err error) } // Err3PIDInUse is the error returned when trying to save an association involving diff --git a/userapi/storage/accounts/postgres/accounts_table.go b/userapi/storage/accounts/postgres/accounts_table.go index 7500e1e8..254da84c 100644 --- a/userapi/storage/accounts/postgres/accounts_table.go +++ b/userapi/storage/accounts/postgres/accounts_table.go @@ -37,7 +37,9 @@ CREATE TABLE IF NOT EXISTS account_accounts ( -- The password hash for this account. Can be NULL if this is a passwordless account. password_hash TEXT, -- Identifies which application service this account belongs to, if any. - appservice_id TEXT + appservice_id TEXT, + -- If the account is currently active + is_deactivated BOOLEAN DEFAULT FALSE -- TODO: -- is_guest, is_admin, upgraded_ts, devices, any email reset stuff? ); @@ -51,11 +53,14 @@ const insertAccountSQL = "" + const updatePasswordSQL = "" + "UPDATE account_accounts SET password_hash = $1 WHERE localpart = $2" +const deactivateAccountSQL = "" + + "UPDATE account_accounts SET is_deactivated = TRUE WHERE localpart = $1" + const selectAccountByLocalpartSQL = "" + "SELECT localpart, appservice_id FROM account_accounts WHERE localpart = $1" const selectPasswordHashSQL = "" + - "SELECT password_hash FROM account_accounts WHERE localpart = $1" + "SELECT password_hash FROM account_accounts WHERE localpart = $1 AND is_deactivated = FALSE" const selectNewNumericLocalpartSQL = "" + "SELECT nextval('numeric_username_seq')" @@ -63,6 +68,7 @@ const selectNewNumericLocalpartSQL = "" + type accountsStatements struct { insertAccountStmt *sql.Stmt updatePasswordStmt *sql.Stmt + deactivateAccountStmt *sql.Stmt selectAccountByLocalpartStmt *sql.Stmt selectPasswordHashStmt *sql.Stmt selectNewNumericLocalpartStmt *sql.Stmt @@ -80,6 +86,9 @@ func (s *accountsStatements) prepare(db *sql.DB, server gomatrixserverlib.Server if s.updatePasswordStmt, err = db.Prepare(updatePasswordSQL); err != nil { return } + if s.deactivateAccountStmt, err = db.Prepare(deactivateAccountSQL); err != nil { + return + } if s.selectAccountByLocalpartStmt, err = db.Prepare(selectAccountByLocalpartSQL); err != nil { return } @@ -127,6 +136,13 @@ func (s *accountsStatements) updatePassword( return } +func (s *accountsStatements) deactivateAccount( + ctx context.Context, localpart string, +) (err error) { + _, err = s.deactivateAccountStmt.ExecContext(ctx, localpart) + return +} + func (s *accountsStatements) selectPasswordHash( ctx context.Context, localpart string, ) (hash string, err error) { diff --git a/userapi/storage/accounts/postgres/deltas/20200929203058_is_active.sql b/userapi/storage/accounts/postgres/deltas/20200929203058_is_active.sql new file mode 100644 index 00000000..32e6e166 --- /dev/null +++ b/userapi/storage/accounts/postgres/deltas/20200929203058_is_active.sql @@ -0,0 +1,9 @@ +-- +goose Up +-- +goose StatementBegin +ALTER TABLE account_accounts ADD COLUMN IF NOT EXISTS is_deactivated BOOLEAN DEFAULT FALSE; +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin +ALTER TABLE account_accounts DROP COLUMN is_deactivated; +-- +goose StatementEnd diff --git a/userapi/storage/accounts/postgres/storage.go b/userapi/storage/accounts/postgres/storage.go index 8b9ebef8..2230f7e7 100644 --- a/userapi/storage/accounts/postgres/storage.go +++ b/userapi/storage/accounts/postgres/storage.go @@ -317,3 +317,8 @@ func (d *Database) SearchProfiles(ctx context.Context, searchString string, limi ) ([]authtypes.Profile, error) { return d.profiles.selectProfilesBySearch(ctx, searchString, limit) } + +// DeactivateAccount deactivates the user's account, removing all ability for the user to login again. +func (d *Database) DeactivateAccount(ctx context.Context, localpart string) (err error) { + return d.accounts.deactivateAccount(ctx, localpart) +} diff --git a/userapi/storage/accounts/sqlite3/accounts_table.go b/userapi/storage/accounts/sqlite3/accounts_table.go index 2d935fb6..d0ea8a8b 100644 --- a/userapi/storage/accounts/sqlite3/accounts_table.go +++ b/userapi/storage/accounts/sqlite3/accounts_table.go @@ -37,7 +37,9 @@ CREATE TABLE IF NOT EXISTS account_accounts ( -- The password hash for this account. Can be NULL if this is a passwordless account. password_hash TEXT, -- Identifies which application service this account belongs to, if any. - appservice_id TEXT + appservice_id TEXT, + -- If the account is currently active + is_deactivated BOOLEAN DEFAULT 0 -- TODO: -- is_guest, is_admin, upgraded_ts, devices, any email reset stuff? ); @@ -49,11 +51,14 @@ const insertAccountSQL = "" + const updatePasswordSQL = "" + "UPDATE account_accounts SET password_hash = $1 WHERE localpart = $2" +const deactivateAccountSQL = "" + + "UPDATE account_accounts SET is_deactivated = 1 WHERE localpart = $1" + const selectAccountByLocalpartSQL = "" + "SELECT localpart, appservice_id FROM account_accounts WHERE localpart = $1" const selectPasswordHashSQL = "" + - "SELECT password_hash FROM account_accounts WHERE localpart = $1" + "SELECT password_hash FROM account_accounts WHERE localpart = $1 AND is_deactivated = 0" const selectNewNumericLocalpartSQL = "" + "SELECT COUNT(localpart) FROM account_accounts" @@ -62,6 +67,7 @@ type accountsStatements struct { db *sql.DB insertAccountStmt *sql.Stmt updatePasswordStmt *sql.Stmt + deactivateAccountStmt *sql.Stmt selectAccountByLocalpartStmt *sql.Stmt selectPasswordHashStmt *sql.Stmt selectNewNumericLocalpartStmt *sql.Stmt @@ -81,6 +87,9 @@ func (s *accountsStatements) prepare(db *sql.DB, server gomatrixserverlib.Server if s.updatePasswordStmt, err = db.Prepare(updatePasswordSQL); err != nil { return } + if s.deactivateAccountStmt, err = db.Prepare(deactivateAccountSQL); err != nil { + return + } if s.selectAccountByLocalpartStmt, err = db.Prepare(selectAccountByLocalpartSQL); err != nil { return } @@ -128,6 +137,13 @@ func (s *accountsStatements) updatePassword( return } +func (s *accountsStatements) deactivateAccount( + ctx context.Context, localpart string, +) (err error) { + _, err = s.deactivateAccountStmt.ExecContext(ctx, localpart) + return +} + func (s *accountsStatements) selectPasswordHash( ctx context.Context, localpart string, ) (hash string, err error) { diff --git a/userapi/storage/accounts/sqlite3/deltas/20200929203058_is_active.sql b/userapi/storage/accounts/sqlite3/deltas/20200929203058_is_active.sql new file mode 100644 index 00000000..51e9bae3 --- /dev/null +++ b/userapi/storage/accounts/sqlite3/deltas/20200929203058_is_active.sql @@ -0,0 +1,38 @@ +-- +goose Up +-- +goose StatementBegin +ALTER TABLE account_accounts RENAME TO account_accounts_tmp; +CREATE TABLE account_accounts ( + localpart TEXT NOT NULL PRIMARY KEY, + created_ts BIGINT NOT NULL, + password_hash TEXT, + appservice_id TEXT, + is_deactivated BOOLEAN DEFAULT 0 +); +INSERT + INTO account_accounts ( + localpart, created_ts, password_hash, appservice_id + ) SELECT + localpart, created_ts, password_hash, appservice_id + FROM account_accounts_tmp +; +DROP TABLE account_accounts_tmp; +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin +ALTER TABLE account_accounts RENAME TO account_accounts_tmp; +CREATE TABLE account_accounts ( + localpart TEXT NOT NULL PRIMARY KEY, + created_ts BIGINT NOT NULL, + password_hash TEXT, + appservice_id TEXT +); +INSERT + INTO account_accounts ( + localpart, created_ts, password_hash, appservice_id + ) SELECT + localpart, created_ts, password_hash, appservice_id + FROM account_accounts_tmp +; +DROP TABLE account_accounts_tmp; +-- +goose StatementEnd diff --git a/userapi/storage/accounts/sqlite3/storage.go b/userapi/storage/accounts/sqlite3/storage.go index 4b66304c..7a2830a9 100644 --- a/userapi/storage/accounts/sqlite3/storage.go +++ b/userapi/storage/accounts/sqlite3/storage.go @@ -359,3 +359,8 @@ func (d *Database) SearchProfiles(ctx context.Context, searchString string, limi ) ([]authtypes.Profile, error) { return d.profiles.selectProfilesBySearch(ctx, searchString, limit) } + +// DeactivateAccount deactivates the user's account, removing all ability for the user to login again. +func (d *Database) DeactivateAccount(ctx context.Context, localpart string) (err error) { + return d.accounts.deactivateAccount(ctx, localpart) +} |