Also track login and register events from the api routes

This commit is contained in:
Adrià Casajús 2022-04-11 16:11:01 +02:00
parent 8da4293305
commit 2b149747f5
No known key found for this signature in database
GPG Key ID: F0033226A5AFC9B9
2 changed files with 34 additions and 7 deletions

View File

@ -19,6 +19,7 @@ from app.email_utils import (
send_email, send_email,
render, render,
) )
from app.events.auth_event import LoginEvent, RegisterEvent
from app.extensions import limiter from app.extensions import limiter
from app.log import LOG from app.log import LOG
from app.models import User, ApiKey, SocialAuth, AccountActivation from app.models import User, ApiKey, SocialAuth, AccountActivation
@ -55,16 +56,20 @@ def auth_login():
user = User.filter_by(email=email).first() user = User.filter_by(email=email).first()
if not user or not user.check_password(password): if not user or not user.check_password(password):
LoginEvent(LoginEvent.ActionType.failed, LoginEvent.Source.api).send()
return jsonify(error="Email or password incorrect"), 400 return jsonify(error="Email or password incorrect"), 400
elif user.disabled: elif user.disabled:
LoginEvent(LoginEvent.ActionType.disabled_login, LoginEvent.Source.api).send()
return jsonify(error="Account disabled"), 400 return jsonify(error="Account disabled"), 400
elif not user.activated: elif not user.activated:
LoginEvent(LoginEvent.ActionType.not_activated, LoginEvent.Source.api).send()
return jsonify(error="Account not activated"), 422 return jsonify(error="Account not activated"), 422
elif user.fido_enabled(): elif user.fido_enabled():
# allow user who has TOTP enabled to continue using the mobile app # allow user who has TOTP enabled to continue using the mobile app
if not user.enable_otp: if not user.enable_otp:
return jsonify(error="Currently we don't support FIDO on mobile yet"), 403 return jsonify(error="Currently we don't support FIDO on mobile yet"), 403
LoginEvent(LoginEvent.ActionType.success, LoginEvent.Source.api).send()
return jsonify(**auth_payload(user, device)), 200 return jsonify(**auth_payload(user, device)), 200
@ -88,14 +93,20 @@ def auth_register():
password = data.get("password") password = data.get("password")
if DISABLE_REGISTRATION: if DISABLE_REGISTRATION:
RegisterEvent(RegisterEvent.ActionType.failed, RegisterEvent.Source.api).send()
return jsonify(error="registration is closed"), 400 return jsonify(error="registration is closed"), 400
if not email_can_be_used_as_mailbox(email) or personal_email_already_used(email): if not email_can_be_used_as_mailbox(email) or personal_email_already_used(email):
RegisterEvent(
RegisterEvent.ActionType.invalid_email, RegisterEvent.Source.api
).send()
return jsonify(error=f"cannot use {email} as personal inbox"), 400 return jsonify(error=f"cannot use {email} as personal inbox"), 400
if not password or len(password) < 8: if not password or len(password) < 8:
RegisterEvent(RegisterEvent.ActionType.failed, RegisterEvent.Source.api).send()
return jsonify(error="password too short"), 400 return jsonify(error="password too short"), 400
if len(password) > 100: if len(password) > 100:
RegisterEvent(RegisterEvent.ActionType.failed, RegisterEvent.Source.api).send()
return jsonify(error="password too long"), 400 return jsonify(error="password too long"), 400
LOG.d("create user %s", email) LOG.d("create user %s", email)
@ -114,6 +125,7 @@ def auth_register():
render("transactional/code-activation.html", code=code), render("transactional/code-activation.html", code=code),
) )
RegisterEvent(RegisterEvent.ActionType.success, RegisterEvent.Source.api).send()
return jsonify(msg="User needs to confirm their account"), 200 return jsonify(msg="User needs to confirm their account"), 200

View File

@ -10,22 +10,37 @@ class LoginEvent:
disabled_login = 2 disabled_login = 2
not_activated = 3 not_activated = 3
def __init__(self, action: ActionType): class Source(EnumE):
web = 0
api = 1
def __init__(self, action: ActionType, source: Source = Source.web):
self.action = action self.action = action
self.source = source
def send(self): def send(self):
newrelic.agent.record_custom_event("LoginEvent", {"action": self.action}) newrelic.agent.record_custom_event(
"LoginEvent", {"action": self.action, "source": self.source}
)
class RegisterEvent: class RegisterEvent:
class ActionType(EnumE): class ActionType(EnumE):
success = 0 success = 0
catpcha_failed = 1 failed = 1
email_in_use = 2 catpcha_failed = 2
invalid_email = 3 email_in_use = 3
invalid_email = 4
def __init__(self, action: ActionType): class Source(EnumE):
web = 0
api = 1
def __init__(self, action: ActionType, source: Source = Source.web):
self.action = action self.action = action
self.source = source
def send(self): def send(self):
newrelic.agent.record_custom_event("RegisterEvent", {"action": self.action}) newrelic.agent.record_custom_event(
"RegisterEvent", {"action": self.action, "source": self.source}
)