You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

265 lines
9.1 KiB

  1. # Copyright 2018 New Vector Ltd
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. """Tests REST events for /rooms paths."""
  15. from synapse.api.constants import APP_SERVICE_REGISTRATION_TYPE, LoginType
  16. from synapse.api.errors import Codes, HttpResponseException, SynapseError
  17. from synapse.appservice import ApplicationService
  18. from synapse.rest.client import register, sync
  19. from tests import unittest
  20. from tests.unittest import override_config
  21. from tests.utils import default_config
  22. class TestMauLimit(unittest.HomeserverTestCase):
  23. servlets = [register.register_servlets, sync.register_servlets]
  24. def default_config(self):
  25. config = default_config("test")
  26. config.update(
  27. {
  28. "registrations_require_3pid": [],
  29. "limit_usage_by_mau": True,
  30. "max_mau_value": 2,
  31. "mau_trial_days": 0,
  32. "server_notices": {
  33. "system_mxid_localpart": "server",
  34. "room_name": "Test Server Notice Room",
  35. },
  36. }
  37. )
  38. # apply any additional config which was specified via the override_config
  39. # decorator.
  40. if self._extra_config is not None:
  41. config.update(self._extra_config)
  42. return config
  43. def prepare(self, reactor, clock, homeserver):
  44. self.store = homeserver.get_datastore()
  45. def test_simple_deny_mau(self):
  46. # Create and sync so that the MAU counts get updated
  47. token1 = self.create_user("kermit1")
  48. self.do_sync_for_user(token1)
  49. token2 = self.create_user("kermit2")
  50. self.do_sync_for_user(token2)
  51. # check we're testing what we think we are: there should be two active users
  52. self.assertEqual(self.get_success(self.store.get_monthly_active_count()), 2)
  53. # We've created and activated two users, we shouldn't be able to
  54. # register new users
  55. with self.assertRaises(SynapseError) as cm:
  56. self.create_user("kermit3")
  57. e = cm.exception
  58. self.assertEqual(e.code, 403)
  59. self.assertEqual(e.errcode, Codes.RESOURCE_LIMIT_EXCEEDED)
  60. def test_as_ignores_mau(self):
  61. """Test that application services can still create users when the MAU
  62. limit has been reached. This only works when application service
  63. user ip tracking is disabled.
  64. """
  65. # Create and sync so that the MAU counts get updated
  66. token1 = self.create_user("kermit1")
  67. self.do_sync_for_user(token1)
  68. token2 = self.create_user("kermit2")
  69. self.do_sync_for_user(token2)
  70. # check we're testing what we think we are: there should be two active users
  71. self.assertEqual(self.get_success(self.store.get_monthly_active_count()), 2)
  72. # We've created and activated two users, we shouldn't be able to
  73. # register new users
  74. with self.assertRaises(SynapseError) as cm:
  75. self.create_user("kermit3")
  76. e = cm.exception
  77. self.assertEqual(e.code, 403)
  78. self.assertEqual(e.errcode, Codes.RESOURCE_LIMIT_EXCEEDED)
  79. # Cheekily add an application service that we use to register a new user
  80. # with.
  81. as_token = "foobartoken"
  82. self.store.services_cache.append(
  83. ApplicationService(
  84. token=as_token,
  85. hostname=self.hs.hostname,
  86. id="SomeASID",
  87. sender="@as_sender:test",
  88. namespaces={"users": [{"regex": "@as_*", "exclusive": True}]},
  89. )
  90. )
  91. self.create_user("as_kermit4", token=as_token, appservice=True)
  92. def test_allowed_after_a_month_mau(self):
  93. # Create and sync so that the MAU counts get updated
  94. token1 = self.create_user("kermit1")
  95. self.do_sync_for_user(token1)
  96. token2 = self.create_user("kermit2")
  97. self.do_sync_for_user(token2)
  98. # Advance time by 31 days
  99. self.reactor.advance(31 * 24 * 60 * 60)
  100. self.get_success(self.store.reap_monthly_active_users())
  101. self.reactor.advance(0)
  102. # We should be able to register more users
  103. token3 = self.create_user("kermit3")
  104. self.do_sync_for_user(token3)
  105. @override_config({"mau_trial_days": 1})
  106. def test_trial_delay(self):
  107. # We should be able to register more than the limit initially
  108. token1 = self.create_user("kermit1")
  109. self.do_sync_for_user(token1)
  110. token2 = self.create_user("kermit2")
  111. self.do_sync_for_user(token2)
  112. token3 = self.create_user("kermit3")
  113. self.do_sync_for_user(token3)
  114. # Advance time by 2 days
  115. self.reactor.advance(2 * 24 * 60 * 60)
  116. # Two users should be able to sync
  117. self.do_sync_for_user(token1)
  118. self.do_sync_for_user(token2)
  119. # But the third should fail
  120. with self.assertRaises(SynapseError) as cm:
  121. self.do_sync_for_user(token3)
  122. e = cm.exception
  123. self.assertEqual(e.code, 403)
  124. self.assertEqual(e.errcode, Codes.RESOURCE_LIMIT_EXCEEDED)
  125. # And new registrations are now denied too
  126. with self.assertRaises(SynapseError) as cm:
  127. self.create_user("kermit4")
  128. e = cm.exception
  129. self.assertEqual(e.code, 403)
  130. self.assertEqual(e.errcode, Codes.RESOURCE_LIMIT_EXCEEDED)
  131. @override_config({"mau_trial_days": 1})
  132. def test_trial_users_cant_come_back(self):
  133. self.hs.config.mau_trial_days = 1
  134. # We should be able to register more than the limit initially
  135. token1 = self.create_user("kermit1")
  136. self.do_sync_for_user(token1)
  137. token2 = self.create_user("kermit2")
  138. self.do_sync_for_user(token2)
  139. token3 = self.create_user("kermit3")
  140. self.do_sync_for_user(token3)
  141. # Advance time by 2 days
  142. self.reactor.advance(2 * 24 * 60 * 60)
  143. # Two users should be able to sync
  144. self.do_sync_for_user(token1)
  145. self.do_sync_for_user(token2)
  146. # Advance by 2 months so everyone falls out of MAU
  147. self.reactor.advance(60 * 24 * 60 * 60)
  148. self.get_success(self.store.reap_monthly_active_users())
  149. # We can create as many new users as we want
  150. token4 = self.create_user("kermit4")
  151. self.do_sync_for_user(token4)
  152. token5 = self.create_user("kermit5")
  153. self.do_sync_for_user(token5)
  154. token6 = self.create_user("kermit6")
  155. self.do_sync_for_user(token6)
  156. # users 2 and 3 can come back to bring us back up to MAU limit
  157. self.do_sync_for_user(token2)
  158. self.do_sync_for_user(token3)
  159. # New trial users can still sync
  160. self.do_sync_for_user(token4)
  161. self.do_sync_for_user(token5)
  162. self.do_sync_for_user(token6)
  163. # But old user can't
  164. with self.assertRaises(SynapseError) as cm:
  165. self.do_sync_for_user(token1)
  166. e = cm.exception
  167. self.assertEqual(e.code, 403)
  168. self.assertEqual(e.errcode, Codes.RESOURCE_LIMIT_EXCEEDED)
  169. @override_config(
  170. # max_mau_value should not matter
  171. {"max_mau_value": 1, "limit_usage_by_mau": False, "mau_stats_only": True}
  172. )
  173. def test_tracked_but_not_limited(self):
  174. # Simply being able to create 2 users indicates that the
  175. # limit was not reached.
  176. token1 = self.create_user("kermit1")
  177. self.do_sync_for_user(token1)
  178. token2 = self.create_user("kermit2")
  179. self.do_sync_for_user(token2)
  180. # We do want to verify that the number of tracked users
  181. # matches what we want though
  182. count = self.store.get_monthly_active_count()
  183. self.reactor.advance(100)
  184. self.assertEqual(2, self.successResultOf(count))
  185. def create_user(self, localpart, token=None, appservice=False):
  186. request_data = {
  187. "username": localpart,
  188. "password": "monkey",
  189. "auth": {"type": LoginType.DUMMY},
  190. }
  191. if appservice:
  192. request_data["type"] = APP_SERVICE_REGISTRATION_TYPE
  193. channel = self.make_request(
  194. "POST",
  195. "/register",
  196. request_data,
  197. access_token=token,
  198. )
  199. if channel.code != 200:
  200. raise HttpResponseException(
  201. channel.code, channel.result["reason"], channel.result["body"]
  202. ).to_synapse_error()
  203. access_token = channel.json_body["access_token"]
  204. return access_token
  205. def do_sync_for_user(self, token):
  206. channel = self.make_request("GET", "/sync", access_token=token)
  207. if channel.code != 200:
  208. raise HttpResponseException(
  209. channel.code, channel.result["reason"], channel.result["body"]
  210. ).to_synapse_error()