1
0
mirror of https://github.com/bitwarden/server.git synced 2024-11-26 12:55:17 +01:00

new device logged in email notification

This commit is contained in:
Kyle Spearrin 2019-01-24 22:37:49 -05:00
parent 43967ebbc1
commit b19628c6f8
9 changed files with 110 additions and 1 deletions

View File

@ -11,6 +11,11 @@
<EmbeddedResource Include="MailTemplates\Handlebars\**\*.hbs" />
</ItemGroup>
<ItemGroup>
<None Remove="MailTemplates\Handlebars\NewDeviceLoggedIn.html.hbs" />
<None Remove="MailTemplates\Handlebars\NewDeviceLoggedIn.text.hbs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Handlebars.Net" Version="1.9.5" />
<PackageReference Include="IdentityServer4.AccessTokenValidation" Version="2.6.0" />

View File

@ -1,27 +1,50 @@
namespace Bit.Core.Enums
using System.ComponentModel.DataAnnotations;
namespace Bit.Core.Enums
{
public enum DeviceType : byte
{
[Display(Name = "Android")]
Android = 0,
[Display(Name = "iOS")]
iOS = 1,
[Display(Name = "Chrome Extension")]
ChromeExtension = 2,
[Display(Name = "Firefox Extension")]
FirefoxExtension = 3,
[Display(Name = "Opera Extension")]
OperaExtension = 4,
[Display(Name = "Edge Extension")]
EdgeExtension = 5,
[Display(Name = "Windows")]
WindowsDesktop = 6,
[Display(Name = "macOS")]
MacOsDesktop = 7,
[Display(Name = "Linux")]
LinuxDesktop = 8,
[Display(Name = "Chrome")]
ChromeBrowser = 9,
[Display(Name = "Firefox")]
FirefoxBrowser = 10,
[Display(Name = "Opera")]
OperaBrowser = 11,
[Display(Name = "Edge")]
EdgeBrowser = 12,
[Display(Name = "Internet Explorer")]
IEBrowser = 13,
[Display(Name = "Unknown Browser")]
UnknownBrowser = 14,
[Display(Name = "Android")]
AndroidAmazon = 15,
[Display(Name = "UWP")]
UWP = 16,
[Display(Name = "Safari")]
SafariBrowser = 17,
[Display(Name = "Vivaldi")]
VivaldiBrowser = 18,
[Display(Name = "Vivaldi Extension")]
VivaldiExtension = 19,
[Display(Name = "Safari Extension")]
SafariExtension = 20
}
}

View File

@ -15,6 +15,8 @@ using Bit.Core.Models;
using Bit.Core.Identity;
using Bit.Core.Models.Data;
using Bit.Core.Utilities;
using System.ComponentModel.DataAnnotations;
using System.Reflection;
namespace Bit.Core.IdentityServer
{
@ -29,6 +31,7 @@ namespace Bit.Core.IdentityServer
private readonly IOrganizationRepository _organizationRepository;
private readonly IOrganizationUserRepository _organizationUserRepository;
private readonly IApplicationCacheService _applicationCacheService;
private readonly IMailService _mailService;
private readonly CurrentContext _currentContext;
public ResourceOwnerPasswordValidator(
@ -41,6 +44,7 @@ namespace Bit.Core.IdentityServer
IOrganizationRepository organizationRepository,
IOrganizationUserRepository organizationUserRepository,
IApplicationCacheService applicationCacheService,
IMailService mailService,
CurrentContext currentContext)
{
_userManager = userManager;
@ -52,6 +56,7 @@ namespace Bit.Core.IdentityServer
_organizationRepository = organizationRepository;
_organizationUserRepository = organizationUserRepository;
_applicationCacheService = applicationCacheService;
_mailService = mailService;
_currentContext = currentContext;
}
@ -373,6 +378,16 @@ namespace Bit.Core.IdentityServer
{
device.UserId = user.Id;
await _deviceService.SaveAsync(device);
var now = DateTime.UtcNow;
if(now - user.CreationDate > TimeSpan.FromMinutes(10))
{
var deviceType = device.Type.GetType().GetMember(device.Type.ToString())
.FirstOrDefault()?.GetCustomAttribute<DisplayAttribute>()?.GetName();
await _mailService.SendNewDeviceLoggedInEmail(user.Email, deviceType, now,
_currentContext.IpAddress);
}
return device;
}

View File

@ -0,0 +1,21 @@
{{#>FullHtmlLayout}}
<table width="100%" cellpadding="0" cellspacing="0" style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">
<tr style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">
<td class="content-block" style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; margin: 0; -webkit-font-smoothing: antialiased; padding: 0 0 10px; -webkit-text-size-adjust: none;" valign="top">
Your Bitwarden account was just logged into from a new device.
</td>
</tr>
<tr style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">
<td class="content-block" style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; margin: 0; -webkit-font-smoothing: antialiased; padding: 0 0 10px; -webkit-text-size-adjust: none;" valign="top">
<b style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">Date:</b> {{TheDate}} at {{TheTime}} {{TimeZone}}<br style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;" />
<b style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">IP Address:</b> {{IpAddress}}<br style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;" />
<b style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">Device Type:</b> {{DeviceType}}
</td>
</tr>
<tr style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">
<td class="content-block last" style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; margin: 0; -webkit-font-smoothing: antialiased; padding: 0; -webkit-text-size-adjust: none;" valign="top">
You can deauthorize all devices that have access to your account from the <a target="_blank" clicktracking=off href="{{{WebVaultUrl}}}" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #3c8dbc; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0; text-decoration: underline;">web vault</a> under Settings &rarr; My Account &rarr; Deauthorize Sessions.
</td>
</tr>
</table>
{{/FullHtmlLayout}}

View File

@ -0,0 +1,10 @@
{{#>BasicTextLayout}}
Your Bitwarden account was just logged into from a new device.
Date: {{TheDate}} at {{TheTime}} {{TimeZone}}
IP Address: {{IpAddress}}
Device Type: {{DeviceType}}
You can deauthorize all devices that have access to your account from the
web vault under Settings > My Account > Deauthorize Sessions.
{{/BasicTextLayout}}

View File

@ -0,0 +1,11 @@
namespace Bit.Core.Models.Mail
{
public class NewDeviceLoggedInModel : BaseMailModel
{
public string TheDate { get; set; }
public string TheTime { get; set; }
public string TimeZone { get; set; }
public string IpAddress { get; set; }
public string DeviceType { get; set; }
}
}

View File

@ -20,5 +20,6 @@ namespace Bit.Core.Services
Task SendOrganizationConfirmedEmailAsync(string organizationName, string email);
Task SendPasswordlessSignInAsync(string returnUrl, string token, string email);
Task SendInvoiceUpcomingAsync(string email, decimal amount, DateTime dueDate, List<string> items, bool mentionInvoices);
Task SendNewDeviceLoggedInEmail(string email, string deviceType, DateTime timestamp, string ip);
}
}

View File

@ -236,6 +236,24 @@ namespace Bit.Core.Services
await _mailDeliveryService.SendEmailAsync(message);
}
public async Task SendNewDeviceLoggedInEmail(string email, string deviceType, DateTime timestamp, string ip)
{
var message = CreateDefaultMessage($"New Device Logged In From {deviceType}", email);
var model = new NewDeviceLoggedInModel
{
WebVaultUrl = _globalSettings.BaseServiceUri.VaultWithHash,
SiteName = _globalSettings.SiteName,
DeviceType = deviceType,
TheDate = timestamp.ToLongDateString(),
TheTime = timestamp.ToShortTimeString(),
TimeZone = "UTC",
IpAddress = ip
};
await AddMessageContentAsync(message, "NewDeviceLoggedIn", model);
message.MetaData.Add("SendGridCategories", new List<string> { "NewDeviceLoggedIn" });
await _mailDeliveryService.SendEmailAsync(message);
}
private MailMessage CreateDefaultMessage(string subject, string toEmail)
{
return CreateDefaultMessage(subject, new List<string> { toEmail });

View File

@ -72,5 +72,10 @@ namespace Bit.Core.Services
{
return Task.FromResult(0);
}
public Task SendNewDeviceLoggedInEmail(string email, string deviceType, DateTime timestamp, string ip)
{
return Task.FromResult(0);
}
}
}