if location:
self.set_location(location)
+ self.log_profile_update()
+
+ def log_profile_update(self):
+ # Log that an update was performed for this profile id
+ self.db.execute("INSERT INTO fireinfo_profiles_log(public_id) \
+ VALUES(%s)", self.public_id)
+
def expired(self, when=None):
self.db.execute("UPDATE fireinfo_profiles \
SET time_valid = then_or_now(%s) WHERE id = %s", when, self.id)
return False
- def can_update_profile(self, public_id, private_id, when=None):
- # Check if the profile has been updated very recently. If so we deny
- # any new updates for some time.
- res = self.db.get("WITH profiles AS (SELECT * FROM fireinfo_profiles \
- WHERE public_id = %s AND private_id = %s AND time_valid >= then_or_now(%s) \
- ORDER BY time_updated DESC LIMIT 1) \
- SELECT 1 FROM profiles WHERE then_or_now(%s) <= \
- time_updated + INTERVAL '60 minutes'",
- public_id, private_id, when, when)
+ def profile_rate_limit_active(self, public_id, when=None):
+ # Remove all outdated entries
+ self.db.execute("DELETE FROM fireinfo_profiles_log \
+ WHERE ts <= then_or_now(%s) - INTERVAL '60 minutes'", when)
- if res:
- return False
+ res = self.db.get("SELECT COUNT(*) AS count FROM fireinfo_profiles_log \
+ WHERE public_id = %s", public_id)
+
+ if res and res.count >= 10:
+ return True
+ return False
+
+ def is_private_id_change_permitted(self, public_id, private_id, when=None):
# Check if a profile exists with a different private id that is still valid
res = self.db.get("SELECT 1 FROM fireinfo_profiles \
WHERE public_id = %s AND NOT private_id = %s \
public_id, private_id, when, when, when, valid)
if res:
- return Profile(self.backend, res.id)
+ p = Profile(self.backend, res.id)
+ p.log_profile_update()
+
+ return p
# Devices
profile = self.fireinfo.get_profile(public_id, private_id=private_id, when=when)
# Check if the update can actually be updated
- if profile and not self.fireinfo.can_update_profile(public_id, private_id, when=when):
- logging.warning("Profile not updated because private ID does not"
- " match or last update is too recent: %s" % public_id)
+ if profile and self.fireinfo.profile_rate_limit_active(public_id, when=when):
+ logging.warning("There were too many updates for this profile in the last hour: %s" % public_id)
+ return
+
+ elif not self.is_private_id_change_permitted(public_id, private_id, when=when):
+ logging.warning("Changing private id is not permitted for profile: %s" % public_id)
return
# Parse the profile