Use hashing to associate sessions
This commit is contained in:
parent
34e698e309
commit
a210e23bb3
1
.gitignore
vendored
1
.gitignore
vendored
@ -132,3 +132,4 @@ dmypy.json
|
|||||||
secrets.yml
|
secrets.yml
|
||||||
.vscode
|
.vscode
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
compiledstatic/
|
@ -33,6 +33,10 @@ SCRIPT_USE_HTTPS=True
|
|||||||
# How frequently should the monitoring script "phone home" (in ms)?
|
# How frequently should the monitoring script "phone home" (in ms)?
|
||||||
SCRIPT_HEARTBEAT_FREQUENCY=5000
|
SCRIPT_HEARTBEAT_FREQUENCY=5000
|
||||||
|
|
||||||
|
# How much time can elapse between requests from the same user before a new
|
||||||
|
# session is created, in seconds?
|
||||||
|
SESSION_MEMORY_TIMEOUT=1800
|
||||||
|
|
||||||
# Should only superusers (admins) be able to create services? This is helpful
|
# Should only superusers (admins) be able to create services? This is helpful
|
||||||
# when you'd like to invite others to your Shynet instance but don't want
|
# when you'd like to invite others to your Shynet instance but don't want
|
||||||
# them to be able to create services of their own.
|
# them to be able to create services of their own.
|
||||||
|
@ -3,6 +3,7 @@ import logging
|
|||||||
|
|
||||||
import geoip2.database
|
import geoip2.database
|
||||||
import user_agents
|
import user_agents
|
||||||
|
from hashlib import sha1
|
||||||
from celery import shared_task
|
from celery import shared_task
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
@ -59,29 +60,33 @@ def ingress_request(
|
|||||||
if dnt and service.respect_dnt:
|
if dnt and service.respect_dnt:
|
||||||
return
|
return
|
||||||
|
|
||||||
ip_data = _geoip2_lookup(ip)
|
|
||||||
log.debug(f"Found geoip2 data")
|
|
||||||
|
|
||||||
# Validate payload
|
# Validate payload
|
||||||
if payload.get("loadTime", 1) <= 0:
|
if payload.get("loadTime", 1) <= 0:
|
||||||
payload["loadTime"] = None
|
payload["loadTime"] = None
|
||||||
|
|
||||||
# Create or update session
|
association_id_hash = sha1()
|
||||||
session = (
|
association_id_hash.update(str(ip).encode("utf-8"))
|
||||||
Session.objects.filter(
|
association_id_hash.update(str(user_agent).encode("utf-8"))
|
||||||
service=service,
|
session_cache_path = (
|
||||||
last_seen__gt=timezone.now() - timezone.timedelta(minutes=10),
|
f"session_association_{service.pk}_{association_id_hash.hexdigest()}"
|
||||||
ip=ip,
|
|
||||||
user_agent=user_agent,
|
|
||||||
).first()
|
|
||||||
# We used to check for identifiers, but that can cause issues when people
|
|
||||||
# re-open the page in a new tab, for example. It's better to match sessions
|
|
||||||
# solely based on IP and user agent.
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Create or update session
|
||||||
|
session = None
|
||||||
|
if cache.get(session_cache_path) is not None:
|
||||||
|
cache.touch(session_cache_path, settings.SESSION_MEMORY_TIMEOUT)
|
||||||
|
session = Session.objects.filter(
|
||||||
|
pk=cache.get(session_cache_path), service=service
|
||||||
|
).first()
|
||||||
if session is None:
|
if session is None:
|
||||||
log.debug("Cannot link to existing session; creating a new one...")
|
|
||||||
ua = user_agents.parse(user_agent)
|
|
||||||
initial = True
|
initial = True
|
||||||
|
|
||||||
|
log.debug("Cannot link to existing session; creating a new one...")
|
||||||
|
|
||||||
|
ip_data = _geoip2_lookup(ip)
|
||||||
|
log.debug(f"Found geoip2 data...")
|
||||||
|
|
||||||
|
ua = user_agents.parse(user_agent)
|
||||||
device_type = "OTHER"
|
device_type = "OTHER"
|
||||||
if (
|
if (
|
||||||
ua.is_bot
|
ua.is_bot
|
||||||
@ -111,9 +116,14 @@ def ingress_request(
|
|||||||
latitude=ip_data.get("latitude"),
|
latitude=ip_data.get("latitude"),
|
||||||
time_zone=ip_data.get("time_zone", ""),
|
time_zone=ip_data.get("time_zone", ""),
|
||||||
)
|
)
|
||||||
|
cache.set(
|
||||||
|
session_cache_path, session.pk, timeout=settings.SESSION_MEMORY_TIMEOUT
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
log.debug("Updating old session with new data...")
|
|
||||||
initial = False
|
initial = False
|
||||||
|
|
||||||
|
log.debug("Updating old session with new data...")
|
||||||
|
|
||||||
# Update last seen time
|
# Update last seen time
|
||||||
session.last_seen = timezone.now()
|
session.last_seen = timezone.now()
|
||||||
if session.identifier == "" and identifier.strip() != "":
|
if session.identifier == "" and identifier.strip() != "":
|
||||||
@ -124,9 +134,10 @@ def ingress_request(
|
|||||||
idempotency = payload.get("idempotency")
|
idempotency = payload.get("idempotency")
|
||||||
idempotency_path = f"hit_idempotency_{idempotency}"
|
idempotency_path = f"hit_idempotency_{idempotency}"
|
||||||
hit = None
|
hit = None
|
||||||
|
|
||||||
if idempotency is not None:
|
if idempotency is not None:
|
||||||
if cache.get(idempotency_path) is not None:
|
if cache.get(idempotency_path) is not None:
|
||||||
cache.touch(idempotency_path, 10 * 60)
|
cache.touch(idempotency_path, settings.SESSION_MEMORY_TIMEOUT)
|
||||||
hit = Hit.objects.filter(
|
hit = Hit.objects.filter(
|
||||||
pk=cache.get(idempotency_path), session=session
|
pk=cache.get(idempotency_path), session=session
|
||||||
).first()
|
).first()
|
||||||
@ -137,6 +148,7 @@ def ingress_request(
|
|||||||
hit.heartbeats += 1
|
hit.heartbeats += 1
|
||||||
hit.last_seen = timezone.now()
|
hit.last_seen = timezone.now()
|
||||||
hit.save()
|
hit.save()
|
||||||
|
|
||||||
if hit is None:
|
if hit is None:
|
||||||
log.debug("Hit is a page load; creating new hit...")
|
log.debug("Hit is a page load; creating new hit...")
|
||||||
# There is no existing hit; create a new one
|
# There is no existing hit; create a new one
|
||||||
@ -153,7 +165,9 @@ def ingress_request(
|
|||||||
)
|
)
|
||||||
# Set idempotency (if applicable)
|
# Set idempotency (if applicable)
|
||||||
if idempotency is not None:
|
if idempotency is not None:
|
||||||
cache.set(idempotency_path, hit.pk, timeout=10 * 60)
|
cache.set(
|
||||||
|
idempotency_path, hit.pk, timeout=settings.SESSION_MEMORY_TIMEOUT
|
||||||
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.exception(e)
|
log.exception(e)
|
||||||
raise e
|
raise e
|
||||||
|
@ -261,3 +261,7 @@ SCRIPT_USE_HTTPS = os.getenv("SCRIPT_USE_HTTPS", "True") == "True"
|
|||||||
# How frequently should the tracking script "phone home" with a heartbeat, in
|
# How frequently should the tracking script "phone home" with a heartbeat, in
|
||||||
# milliseconds?
|
# milliseconds?
|
||||||
SCRIPT_HEARTBEAT_FREQUENCY = int(os.getenv("SCRIPT_HEARTBEAT_FREQUENCY", "5000"))
|
SCRIPT_HEARTBEAT_FREQUENCY = int(os.getenv("SCRIPT_HEARTBEAT_FREQUENCY", "5000"))
|
||||||
|
|
||||||
|
# How much time can elapse between requests from the same user before a new
|
||||||
|
# session is created, in seconds?
|
||||||
|
SESSION_MEMORY_TIMEOUT = int(os.getenv("SESSION_MEMORY_TIMEOUT", "1800"))
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
<body>
|
<body>
|
||||||
<noscript><img src="//localhost:8000/ingress/test_uuid/pixel.gif"></noscript>
|
<noscript><img src="//localhost:8000/ingress/test_uuid/pixel.gif"></noscript>
|
||||||
<script src="//localhost:8000/ingress/test_uuid/script.js"></script>
|
<script src="//localhost:8000/ingress/66015ce4-c69d-40fb-be8f-5535538d795e/script.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
Loading…
Reference in New Issue
Block a user