Merge pull request #5276 from matrix-org/babolivier/account_validity_job_delta

Allow configuring a range for the account validity startup job
This commit is contained in:
Erik Johnston 2019-05-31 12:11:56 +01:00 committed by GitHub
commit 58cce39f3a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 39 additions and 9 deletions

1
changelog.d/5276.feature Normal file
View File

@ -0,0 +1 @@
Allow configuring a range for the account validity startup job.

View File

@ -763,7 +763,9 @@ uploads_path: "DATADIR/uploads"
# This means that, if a validity period is set, and Synapse is restarted (it will # This means that, if a validity period is set, and Synapse is restarted (it will
# then derive an expiration date from the current validity period), and some time # then derive an expiration date from the current validity period), and some time
# after that the validity period changes and Synapse is restarted, the users' # after that the validity period changes and Synapse is restarted, the users'
# expiration dates won't be updated unless their account is manually renewed. # expiration dates won't be updated unless their account is manually renewed. This
# date will be randomly selected within a range [now + period - d ; now + period],
# where d is equal to 10% of the validity period.
# #
#account_validity: #account_validity:
# enabled: True # enabled: True

View File

@ -39,6 +39,8 @@ class AccountValidityConfig(Config):
else: else:
self.renew_email_subject = "Renew your %(app)s account" self.renew_email_subject = "Renew your %(app)s account"
self.startup_job_max_delta = self.period * 10. / 100.
if self.renew_by_email_enabled and "public_baseurl" not in synapse_config: if self.renew_by_email_enabled and "public_baseurl" not in synapse_config:
raise ConfigError("Can't send renewal emails without 'public_baseurl'") raise ConfigError("Can't send renewal emails without 'public_baseurl'")
@ -129,7 +131,9 @@ class RegistrationConfig(Config):
# This means that, if a validity period is set, and Synapse is restarted (it will # This means that, if a validity period is set, and Synapse is restarted (it will
# then derive an expiration date from the current validity period), and some time # then derive an expiration date from the current validity period), and some time
# after that the validity period changes and Synapse is restarted, the users' # after that the validity period changes and Synapse is restarted, the users'
# expiration dates won't be updated unless their account is manually renewed. # expiration dates won't be updated unless their account is manually renewed. This
# date will be randomly selected within a range [now + period - d ; now + period],
# where d is equal to 10%% of the validity period.
# #
#account_validity: #account_validity:
# enabled: True # enabled: True

View File

@ -16,6 +16,7 @@
# limitations under the License. # limitations under the License.
import itertools import itertools
import logging import logging
import random
import sys import sys
import threading import threading
import time import time
@ -247,6 +248,8 @@ class SQLBaseStore(object):
self._check_safe_to_upsert, self._check_safe_to_upsert,
) )
self.rand = random.SystemRandom()
if self._account_validity.enabled: if self._account_validity.enabled:
self._clock.call_later( self._clock.call_later(
0.0, 0.0,
@ -308,21 +311,36 @@ class SQLBaseStore(object):
res = self.cursor_to_dict(txn) res = self.cursor_to_dict(txn)
if res: if res:
for user in res: for user in res:
self.set_expiration_date_for_user_txn(txn, user["name"]) self.set_expiration_date_for_user_txn(
txn,
user["name"],
use_delta=True,
)
yield self.runInteraction( yield self.runInteraction(
"get_users_with_no_expiration_date", "get_users_with_no_expiration_date",
select_users_with_no_expiration_date_txn, select_users_with_no_expiration_date_txn,
) )
def set_expiration_date_for_user_txn(self, txn, user_id): def set_expiration_date_for_user_txn(self, txn, user_id, use_delta=False):
"""Sets an expiration date to the account with the given user ID. """Sets an expiration date to the account with the given user ID.
Args: Args:
user_id (str): User ID to set an expiration date for. user_id (str): User ID to set an expiration date for.
use_delta (bool): If set to False, the expiration date for the user will be
now + validity period. If set to True, this expiration date will be a
random value in the [now + period - d ; now + period] range, d being a
delta equal to 10% of the validity period.
""" """
now_ms = self._clock.time_msec() now_ms = self._clock.time_msec()
expiration_ts = now_ms + self._account_validity.period expiration_ts = now_ms + self._account_validity.period
if use_delta:
expiration_ts = self.rand.randrange(
expiration_ts - self._account_validity.startup_job_max_delta,
expiration_ts,
)
self._simple_insert_txn( self._simple_insert_txn(
txn, txn,
"account_validity", "account_validity",

View File

@ -436,6 +436,7 @@ class AccountValidityBackgroundJobTestCase(unittest.HomeserverTestCase):
def make_homeserver(self, reactor, clock): def make_homeserver(self, reactor, clock):
self.validity_period = 10 self.validity_period = 10
self.max_delta = self.validity_period * 10. / 100.
config = self.default_config() config = self.default_config()
@ -453,14 +454,18 @@ class AccountValidityBackgroundJobTestCase(unittest.HomeserverTestCase):
def test_background_job(self): def test_background_job(self):
""" """
Tests whether the account validity startup background job does the right thing, Tests the same thing as test_background_job, except that it sets the
which is sticking an expiration date to every account that doesn't already have startup_job_max_delta parameter and checks that the expiration date is within the
one. allowed range.
""" """
user_id = self.register_user("kermit", "user") user_id = self.register_user("kermit_delta", "user")
self.hs.config.account_validity.startup_job_max_delta = self.max_delta
now_ms = self.hs.clock.time_msec() now_ms = self.hs.clock.time_msec()
self.get_success(self.store._set_expiration_date_when_missing()) self.get_success(self.store._set_expiration_date_when_missing())
res = self.get_success(self.store.get_expiration_ts_for_user(user_id)) res = self.get_success(self.store.get_expiration_ts_for_user(user_id))
self.assertEqual(res, now_ms + self.validity_period)
self.assertGreaterEqual(res, now_ms + self.validity_period - self.max_delta)
self.assertLessEqual(res, now_ms + self.validity_period)