Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

Remove pushers when deleting 3pid from account #10581

Merged
merged 16 commits into from
Aug 26, 2021
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
Users will stop receiving message updates via email for addresses that were once, but not still, linked to their account
Azrenbeth marked this conversation as resolved.
Show resolved Hide resolved

Synapse 1.41.0rc1 (2021-08-18)
==============================

Expand Down
1 change: 1 addition & 0 deletions changelog.d/10581.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Remove pushers when deleting 3pid from account. Pushers for old unlinked emails will also be deleted.
Azrenbeth marked this conversation as resolved.
Show resolved Hide resolved
5 changes: 5 additions & 0 deletions docs/upgrade.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,11 @@ This may affect you if you make use of custom HTML templates for the
The template is now provided an `error` variable if the authentication
process failed. See the default templates linked above for an example.

# Upgrading to v1.42.0

## Removal of out-of-date email pushers
Users will stop receiving message updates via email for addresses that were
once, but not still, linked to their account.

# Upgrading to v1.41.0

Expand Down
5 changes: 4 additions & 1 deletion synapse/handlers/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -1464,6 +1464,10 @@ async def delete_threepid(
)

await self.store.user_delete_threepid(user_id, medium, address)
if medium == "email":
await self.store.delete_pusher_by_app_id_pushkey_user_id(
app_id="m.email", pushkey=address, user_id=user_id
)
return result

async def hash(self, password: str) -> str:
Expand Down Expand Up @@ -1732,7 +1736,6 @@ def add_query_param_to_url(url: str, param_name: str, param: Any):

@attr.s(slots=True)
class MacaroonGenerator:

hs = attr.ib()

def generate_guest_access_token(self, user_id: str) -> str:
Expand Down
71 changes: 71 additions & 0 deletions synapse/storage/databases/main/pusher.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ def __init__(self, database: DatabasePool, db_conn: Connection, hs: "HomeServer"
self._remove_stale_pushers,
)

self.db_pool.updates.register_background_update_handler(
"remove_deleted_email_pushers",
self._remove_deleted_email_pushers,
)

def _decode_pushers_rows(self, rows: Iterable[dict]) -> Iterator[PusherConfig]:
"""JSON-decode the data in the rows returned from the `pushers` table

Expand Down Expand Up @@ -388,6 +393,72 @@ def _delete_pushers(txn) -> int:

return number_deleted

async def _remove_deleted_email_pushers(
self, progress: dict, batch_size: int
) -> int:
"""A background update that deletes all pushers for deleted email addresses.

In previous versions of synapse, when users deleted their email address, it didn't
also delete all the pushers for that email address. This background update removes
those to prevent unwanted emails
Azrenbeth marked this conversation as resolved.
Show resolved Hide resolved

Args:
progress: dict used to store progress of this background update
batch_size: the maximum number of rows to retrieve in a single select query

Returns:
The number of deleted rows
"""

last_pusher = progress.get("last_pusher", 0)

def _delete_pushers(txn) -> int:

sql = """
SELECT p.id, p.user_name, p.app_id, p.pushkey
FROM pushers AS p
LEFT JOIN user_threepids AS t
ON t.user_id=p.user_name
Azrenbeth marked this conversation as resolved.
Show resolved Hide resolved
AND t.medium = 'email'
AND t.address = p.pushkey
WHERE t.user_id is NULL
AND p.app_id = 'm.email'
AND p.id > ?
ORDER BY p.id ASC
LIMIT ?
"""

txn.execute(sql, (last_pusher, batch_size))

last = None
num_deleted = 0
for row in txn:
last = row[0]
num_deleted += 1
self.db_pool.simple_delete_txn(
txn,
"pushers",
{"user_name": row[1], "app_id": row[2], "pushkey": row[3]},
)

if last is not None:
self.db_pool.updates._background_update_progress_txn(
txn, "remove_deleted_email_pushers", {"last_pusher": last}
)

return num_deleted

number_deleted = await self.db_pool.runInteraction(
"_remove_deleted_email_pushers", _delete_pushers
)

if number_deleted < batch_size:
await self.db_pool.updates._end_background_update(
"remove_deleted_email_pushers"
)

return number_deleted


class PusherStore(PusherWorkerStore):
def get_pushers_stream_token(self) -> int:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/* Copyright 2021 The Matrix.org Foundation C.I.C
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/


-- We may not have deleted all pushers for emails that are no longer linked
-- to an account, so we set up a background job to delete them.
INSERT INTO background_updates (ordering, update_name, progress_json) VALUES
(6302, 'remove_deleted_email_pushers', '{}');