From 50bc29ccfd91c27e7c238083621f294555cc8322 Mon Sep 17 00:00:00 2001 From: Maksim Mrug <80621719+kruzhambus@users.noreply.github.com> Date: Tue, 18 Jul 2023 12:24:38 +0300 Subject: [PATCH 1/5] (add) telegram notification on logout-all --- apps/production/src/auth/auth.controller.ts | 14 ++++++++- apps/production/src/auth/auth.service.ts | 33 +++++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/apps/production/src/auth/auth.controller.ts b/apps/production/src/auth/auth.controller.ts index 440ebd7d..334eaa55 100644 --- a/apps/production/src/auth/auth.controller.ts +++ b/apps/production/src/auth/auth.controller.ts @@ -428,13 +428,25 @@ export class AuthController { @UseGuards(JwtRefreshTokenGuard) @Post('logout-all') @HttpCode(200) - public async logoutAll(@CurrentUserId() userId: string): Promise { + public async logoutAll( + @CurrentUserId() userId: string, + @Headers() headers: unknown, + @Ip() requestIp: string, + ): Promise { const user = await this.userService.findUserById(userId) + const ip = + headers['x-forwarded-for'] || headers['cf-connecting-ip'] || requestIp if (!user) { throw new UnauthorizedException() } + await this.authService.sendTelegramNotificationForLogoutAllDevices( + user.id, + headers, + ip, + ) + await this.authService.logoutAll(user.id) } diff --git a/apps/production/src/auth/auth.service.ts b/apps/production/src/auth/auth.service.ts index 946d6bab..69045a8c 100644 --- a/apps/production/src/auth/auth.service.ts +++ b/apps/production/src/auth/auth.service.ts @@ -249,6 +249,39 @@ export class AuthService { } } + public async sendTelegramNotificationForLogoutAllDevices( + userId: string, + headers: unknown, + ip: string, + ) { + const user = await this.userService.findUserById(userId) + + if (!user.telegramChatId || !user.receiveLoginNotifications) { + return + } + + const headersInfo = await this.getHeadersInfo(headers) + const logoutDate = dayjs().utc().format('YYYY-MM-DD HH:mm:ss') + const message = + '🚨 *Someone has logged out of all devices!*\n\n' + + `*Browser:* ${headersInfo.browser}\n` + + `*Device:* ${headersInfo.device}\n` + + `*OS:* ${headersInfo.os}\n` + + `*Country:* ${headersInfo.country}\n` + + `*IP:* ${ip}\n` + + `*Date:* ${logoutDate} (UTC)\n\n` + + 'If it was not you, please change your password immediately.' + if (user && user.isTelegramChatIdConfirmed) { + await this.telegramService.sendMessage( + Number(user.telegramChatId), + message, + { + parse_mode: 'Markdown', + }, + ) + } + } + private async getHeadersInfo(headers: unknown) { const ua = UAParser(headers['user-agent']) const browser = ua.browser.name || 'Unknown' From ae7e17af75cd71912aeb386b7a19afe21cf6e925 Mon Sep 17 00:00:00 2001 From: Maksim Mrug <80621719+kruzhambus@users.noreply.github.com> Date: Tue, 18 Jul 2023 12:31:53 +0300 Subject: [PATCH 2/5] (add) telegram notification on reset-password --- apps/production/src/auth/auth.controller.ts | 6 ++++ apps/production/src/auth/auth.service.ts | 33 +++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/apps/production/src/auth/auth.controller.ts b/apps/production/src/auth/auth.controller.ts index 334eaa55..bd26afff 100644 --- a/apps/production/src/auth/auth.controller.ts +++ b/apps/production/src/auth/auth.controller.ts @@ -210,6 +210,12 @@ export class AuthController { throw new ConflictException(i18n.t('auth.accountNotExists')) } + await this.authService.sendTelegramNotificationForPasswordReset( + user.id, + headers, + ip, + ) + await this.authService.sendResetPasswordEmail(user.id, user.email) } diff --git a/apps/production/src/auth/auth.service.ts b/apps/production/src/auth/auth.service.ts index 69045a8c..dc4dc63e 100644 --- a/apps/production/src/auth/auth.service.ts +++ b/apps/production/src/auth/auth.service.ts @@ -282,6 +282,39 @@ export class AuthService { } } + public async sendTelegramNotificationForPasswordReset( + userId: string, + headers: unknown, + ip: string, + ) { + const user = await this.userService.findUserById(userId) + + if (!user.telegramChatId || !user.receiveLoginNotifications) { + return + } + + const headersInfo = await this.getHeadersInfo(headers) + const resetDate = dayjs().utc().format('YYYY-MM-DD HH:mm:ss') + const message = + '🚨 *Someone has reset your password!*\n\n' + + `*Browser:* ${headersInfo.browser}\n` + + `*Device:* ${headersInfo.device}\n` + + `*OS:* ${headersInfo.os}\n` + + `*Country:* ${headersInfo.country}\n` + + `*IP:* ${ip}\n` + + `*Date:* ${resetDate} (UTC)\n\n` + + 'If it was not you, please change your password immediately.' + if (user && user.isTelegramChatIdConfirmed) { + await this.telegramService.sendMessage( + Number(user.telegramChatId), + message, + { + parse_mode: 'Markdown', + }, + ) + } + } + private async getHeadersInfo(headers: unknown) { const ua = UAParser(headers['user-agent']) const browser = ua.browser.name || 'Unknown' From f769c88b2903e83f8d827814b3b81a6b1b7eb9d2 Mon Sep 17 00:00:00 2001 From: Maksim Mrug <80621719+kruzhambus@users.noreply.github.com> Date: Tue, 18 Jul 2023 12:40:26 +0300 Subject: [PATCH 3/5] some improvments --- apps/production/src/auth/auth.controller.ts | 13 +++- apps/production/src/auth/auth.service.ts | 83 ++++----------------- 2 files changed, 24 insertions(+), 72 deletions(-) diff --git a/apps/production/src/auth/auth.controller.ts b/apps/production/src/auth/auth.controller.ts index bd26afff..cbf10a6e 100644 --- a/apps/production/src/auth/auth.controller.ts +++ b/apps/production/src/auth/auth.controller.ts @@ -151,7 +151,12 @@ export class AuthController { !user.isTwoFactorAuthenticationEnabled, ) - await this.authService.sendTelegramNotification(user.id, headers, ip) + await this.authService.sendTelegramNotification( + 'Someone has logged into your account!', + user.id, + headers, + ip, + ) if (user.isTwoFactorAuthenticationEnabled) { user = _pick(user, ['isTwoFactorAuthenticationEnabled', 'email']) @@ -210,7 +215,8 @@ export class AuthController { throw new ConflictException(i18n.t('auth.accountNotExists')) } - await this.authService.sendTelegramNotificationForPasswordReset( + await this.authService.sendTelegramNotification( + 'Someone has requested a password reset!', user.id, headers, ip, @@ -447,7 +453,8 @@ export class AuthController { throw new UnauthorizedException() } - await this.authService.sendTelegramNotificationForLogoutAllDevices( + await this.authService.sendTelegramNotification( + 'Someone has logged out of all devices!', user.id, headers, ip, diff --git a/apps/production/src/auth/auth.service.ts b/apps/production/src/auth/auth.service.ts index dc4dc63e..6dad6d89 100644 --- a/apps/production/src/auth/auth.service.ts +++ b/apps/production/src/auth/auth.service.ts @@ -217,6 +217,7 @@ export class AuthService { } public async sendTelegramNotification( + messageTitle: string, userId: string, headers: unknown, ip: string, @@ -230,7 +231,7 @@ export class AuthService { const headersInfo = await this.getHeadersInfo(headers) const loginDate = dayjs().utc().format('YYYY-MM-DD HH:mm:ss') const message = - '🚨 *Someone has logged into your account!*\n\n' + + `🚨 *${messageTitle}*\n\n` + `*Browser:* ${headersInfo.browser}\n` + `*Device:* ${headersInfo.device}\n` + `*OS:* ${headersInfo.os}\n` + @@ -249,72 +250,6 @@ export class AuthService { } } - public async sendTelegramNotificationForLogoutAllDevices( - userId: string, - headers: unknown, - ip: string, - ) { - const user = await this.userService.findUserById(userId) - - if (!user.telegramChatId || !user.receiveLoginNotifications) { - return - } - - const headersInfo = await this.getHeadersInfo(headers) - const logoutDate = dayjs().utc().format('YYYY-MM-DD HH:mm:ss') - const message = - '🚨 *Someone has logged out of all devices!*\n\n' + - `*Browser:* ${headersInfo.browser}\n` + - `*Device:* ${headersInfo.device}\n` + - `*OS:* ${headersInfo.os}\n` + - `*Country:* ${headersInfo.country}\n` + - `*IP:* ${ip}\n` + - `*Date:* ${logoutDate} (UTC)\n\n` + - 'If it was not you, please change your password immediately.' - if (user && user.isTelegramChatIdConfirmed) { - await this.telegramService.sendMessage( - Number(user.telegramChatId), - message, - { - parse_mode: 'Markdown', - }, - ) - } - } - - public async sendTelegramNotificationForPasswordReset( - userId: string, - headers: unknown, - ip: string, - ) { - const user = await this.userService.findUserById(userId) - - if (!user.telegramChatId || !user.receiveLoginNotifications) { - return - } - - const headersInfo = await this.getHeadersInfo(headers) - const resetDate = dayjs().utc().format('YYYY-MM-DD HH:mm:ss') - const message = - '🚨 *Someone has reset your password!*\n\n' + - `*Browser:* ${headersInfo.browser}\n` + - `*Device:* ${headersInfo.device}\n` + - `*OS:* ${headersInfo.os}\n` + - `*Country:* ${headersInfo.country}\n` + - `*IP:* ${ip}\n` + - `*Date:* ${resetDate} (UTC)\n\n` + - 'If it was not you, please change your password immediately.' - if (user && user.isTelegramChatIdConfirmed) { - await this.telegramService.sendMessage( - Number(user.telegramChatId), - message, - { - parse_mode: 'Markdown', - }, - ) - } - } - private async getHeadersInfo(headers: unknown) { const ua = UAParser(headers['user-agent']) const browser = ua.browser.name || 'Unknown' @@ -547,7 +482,12 @@ export class AuthService { throw new BadRequestException() } - await this.sendTelegramNotification(user.id, headers, ip) + await this.sendTelegramNotification( + 'Someone has logged in to their account with Google', + user.id, + headers, + ip, + ) const jwtTokens = await this.generateJwtTokens( user.id, @@ -958,7 +898,12 @@ export class AuthService { throw new BadRequestException() } - await this.sendTelegramNotification(user.id, headers, ip) + await this.sendTelegramNotification( + 'Someone has logged in to their account with Github', + user.id, + headers, + ip, + ) const jwtTokens = await this.generateJwtTokens( user.id, From 27817511dfed0f8a5b2d0981983897f47b8b1d06 Mon Sep 17 00:00:00 2001 From: Maksim Mrug <80621719+kruzhambus@users.noreply.github.com> Date: Tue, 18 Jul 2023 12:47:53 +0300 Subject: [PATCH 4/5] (add) telegram notification on change-password --- apps/production/src/auth/auth.controller.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/apps/production/src/auth/auth.controller.ts b/apps/production/src/auth/auth.controller.ts index cbf10a6e..42f2ee56 100644 --- a/apps/production/src/auth/auth.controller.ts +++ b/apps/production/src/auth/auth.controller.ts @@ -259,8 +259,12 @@ export class AuthController { @Body() body: ChangePasswordDto, @CurrentUserId() userId: string, @I18n() i18n: I18nContext, + @Headers() headers: unknown, + @Ip() requestIp: string, ): Promise { const user = await this.userService.findUserById(userId) + const ip = + headers['x-forwarded-for'] || headers['cf-connecting-ip'] || requestIp if (!user) { throw new UnauthorizedException() @@ -275,6 +279,13 @@ export class AuthController { throw new ConflictException(i18n.t('auth.invalidPassword')) } + await this.authService.sendTelegramNotification( + 'Someone has changed their password!', + user.id, + headers, + ip, + ) + await this.authService.changePassword(user.id, body.newPassword) } From 62bef26afacf8bbfd73c200334b580b4e3f0400c Mon Sep 17 00:00:00 2001 From: Maksim Mrug <80621719+kruzhambus@users.noreply.github.com> Date: Tue, 18 Jul 2023 12:48:49 +0300 Subject: [PATCH 5/5] (add) telegram notification on change-email --- apps/production/src/auth/auth.controller.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/apps/production/src/auth/auth.controller.ts b/apps/production/src/auth/auth.controller.ts index 42f2ee56..966c2657 100644 --- a/apps/production/src/auth/auth.controller.ts +++ b/apps/production/src/auth/auth.controller.ts @@ -331,8 +331,12 @@ export class AuthController { @Body() body: RequestChangeEmailDto, @CurrentUserId() userId: string, @I18n() i18n: I18nContext, + @Headers() headers: unknown, + @Ip() requestIp: string, ): Promise { const user = await this.userService.findUserById(userId) + const ip = + headers['x-forwarded-for'] || headers['cf-connecting-ip'] || requestIp if (!user) { throw new UnauthorizedException() @@ -353,6 +357,13 @@ export class AuthController { throw new ConflictException(i18n.t('auth.emailAlreadyTaken')) } + await this.authService.sendTelegramNotification( + 'Someone has changed their email!', + user.id, + headers, + ip, + ) + await this.authService.changeEmail(user.id, user.email, body.newEmail) }