client_ips.py 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. # -*- coding: utf-8 -*-
  2. # Copyright 2016 OpenMarket Ltd
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. from ._base import SQLBaseStore, Cache
  16. from twisted.internet import defer
  17. # Number of msec of granularity to store the user IP 'last seen' time. Smaller
  18. # times give more inserts into the database even for readonly API hits
  19. # 120 seconds == 2 minutes
  20. LAST_SEEN_GRANULARITY = 120 * 1000
  21. class ClientIpStore(SQLBaseStore):
  22. def __init__(self, hs):
  23. self.client_ip_last_seen = Cache(
  24. name="client_ip_last_seen",
  25. keylen=4,
  26. )
  27. super(ClientIpStore, self).__init__(hs)
  28. @defer.inlineCallbacks
  29. def insert_client_ip(self, user, access_token, ip, user_agent):
  30. now = int(self._clock.time_msec())
  31. key = (user.to_string(), access_token, ip)
  32. try:
  33. last_seen = self.client_ip_last_seen.get(key)
  34. except KeyError:
  35. last_seen = None
  36. # Rate-limited inserts
  37. if last_seen is not None and (now - last_seen) < LAST_SEEN_GRANULARITY:
  38. defer.returnValue(None)
  39. self.client_ip_last_seen.prefill(key, now)
  40. # It's safe not to lock here: a) no unique constraint,
  41. # b) LAST_SEEN_GRANULARITY makes concurrent updates incredibly unlikely
  42. yield self._simple_upsert(
  43. "user_ips",
  44. keyvalues={
  45. "user_id": user.to_string(),
  46. "access_token": access_token,
  47. "ip": ip,
  48. "user_agent": user_agent,
  49. },
  50. values={
  51. "last_seen": now,
  52. },
  53. desc="insert_client_ip",
  54. lock=False,
  55. )