@@ -23,6 +23,7 @@ import { E164_NUMBER } from './validators';
2323import AppError from '../error' ;
2424import Localizer from '../l10n' ;
2525import NodeRendererBindings from '../senders/renderer/bindings-node' ;
26+ import { AccountEventsManager } from '../account-events' ;
2627
2728const { Container } = require ( 'typedi' ) ;
2829
@@ -43,6 +44,7 @@ export type Customs = {
4344class RecoveryPhoneHandler {
4445 private readonly recoveryPhoneService : RecoveryPhoneService ;
4546 private readonly accountManager : AccountManager ;
47+ private readonly accountEventsManager : AccountEventsManager ;
4648 private readonly localizer : Localizer ;
4749
4850 constructor (
@@ -54,6 +56,7 @@ class RecoveryPhoneHandler {
5456 ) {
5557 this . recoveryPhoneService = Container . get ( RecoveryPhoneService ) ;
5658 this . accountManager = Container . get ( AccountManager ) ;
59+ this . accountEventsManager = Container . get ( AccountEventsManager ) ;
5760 this . localizer = new Localizer ( new NodeRendererBindings ( ) ) ;
5861 }
5962
@@ -86,8 +89,11 @@ class RecoveryPhoneHandler {
8689 } ;
8790
8891 async sendCode ( request : AuthRequest ) {
89- const { uid, email } = request . auth
90- . credentials as SessionTokenAuthCredential ;
92+ const {
93+ uid,
94+ email,
95+ id : sessionTokenId ,
96+ } = request . auth . credentials as SessionTokenAuthCredential ;
9197
9298 if ( ! email ) {
9399 throw AppError . invalidToken ( ) ;
@@ -134,6 +140,14 @@ class RecoveryPhoneHandler {
134140 if ( success ) {
135141 this . log . info ( 'account.recoveryPhone.signinSendCode.success' , { uid } ) ;
136142 await this . glean . twoStepAuthPhoneCode . sent ( request ) ;
143+
144+ this . accountEventsManager . recordSecurityEvent ( this . db , {
145+ name : 'account.recovery_phone_send_code' ,
146+ uid,
147+ ipAddr : request . app . clientAddress ,
148+ tokenId : sessionTokenId ,
149+ } ) ;
150+
137151 return { status : RecoveryPhoneStatus . SUCCESS } ;
138152 }
139153
@@ -308,6 +322,14 @@ class RecoveryPhoneHandler {
308322 uid,
309323 }
310324 ) ;
325+
326+ this . accountEventsManager . recordSecurityEvent ( this . db , {
327+ name : 'account.recovery_phone_setup_complete' ,
328+ uid,
329+ ipAddr : request . app . clientAddress ,
330+ tokenId : sessionTokenId ,
331+ } ) ;
332+
311333 return {
312334 phoneNumber,
313335 nationalFormat,
@@ -324,6 +346,13 @@ class RecoveryPhoneHandler {
324346 } else {
325347 this . log . info ( 'account.recoveryPhone.phoneSignin.success' , { uid } ) ;
326348
349+ this . accountEventsManager . recordSecurityEvent ( this . db , {
350+ name : 'account.recovery_phone_signin_complete' ,
351+ uid,
352+ ipAddr : request . app . clientAddress ,
353+ tokenId : sessionTokenId ,
354+ } ) ;
355+
327356 try {
328357 await this . mailer . sendPostSigninRecoveryPhoneEmail (
329358 account . emails ,
@@ -354,11 +383,19 @@ class RecoveryPhoneHandler {
354383 return { status : RecoveryPhoneStatus . SUCCESS } ;
355384 }
356385
386+ this . accountEventsManager . recordSecurityEvent ( this . db , {
387+ name : 'account.recovery_phone_signin_failed' ,
388+ uid,
389+ ipAddr : request . app . clientAddress ,
390+ tokenId : sessionTokenId ,
391+ } ) ;
392+
357393 throw AppError . invalidOrExpiredOtpCode ( ) ;
358394 }
359395
360396 async destroy ( request : AuthRequest ) {
361- const { uid } = request . auth . credentials as unknown as { uid : string } ;
397+ const sessionToken = request . auth . credentials as SessionTokenAuthCredential ;
398+ const { uid } = sessionToken ;
362399
363400 let success = false ;
364401 try {
@@ -392,6 +429,13 @@ class RecoveryPhoneHandler {
392429 const { acceptLanguage, geo, ua } = request . app ;
393430
394431 try {
432+ this . accountEventsManager . recordSecurityEvent ( this . db , {
433+ name : 'account.recovery_phone_removed' ,
434+ uid,
435+ ipAddr : request . app . clientAddress ,
436+ tokenId : sessionToken . id ,
437+ } ) ;
438+
395439 await this . mailer . sendPostRemoveRecoveryPhoneEmail (
396440 account . emails ,
397441 account ,
0 commit comments