✨ Login now send a notification
This commit is contained in:
@@ -3,8 +3,14 @@ using Microsoft.AspNetCore.Mvc;
|
|||||||
using NodaTime;
|
using NodaTime;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using DysonNetwork.Pass.Account;
|
using DysonNetwork.Pass.Account;
|
||||||
|
using DysonNetwork.Pass.Localization;
|
||||||
using DysonNetwork.Shared.Data;
|
using DysonNetwork.Shared.Data;
|
||||||
using DysonNetwork.Shared.GeoIp;
|
using DysonNetwork.Shared.GeoIp;
|
||||||
|
using DysonNetwork.Shared.Proto;
|
||||||
|
using Microsoft.Extensions.Localization;
|
||||||
|
using AccountAuthFactor = DysonNetwork.Pass.Account.AccountAuthFactor;
|
||||||
|
using AccountService = DysonNetwork.Pass.Account.AccountService;
|
||||||
|
using ActionLogService = DysonNetwork.Pass.Account.ActionLogService;
|
||||||
|
|
||||||
namespace DysonNetwork.Pass.Auth;
|
namespace DysonNetwork.Pass.Auth;
|
||||||
|
|
||||||
@@ -16,7 +22,9 @@ public class AuthController(
|
|||||||
AuthService auth,
|
AuthService auth,
|
||||||
GeoIpService geo,
|
GeoIpService geo,
|
||||||
ActionLogService als,
|
ActionLogService als,
|
||||||
IConfiguration configuration
|
PusherService.PusherServiceClient pusher,
|
||||||
|
IConfiguration configuration,
|
||||||
|
IStringLocalizer<NotificationResource> localizer
|
||||||
) : ControllerBase
|
) : ControllerBase
|
||||||
{
|
{
|
||||||
private readonly string _cookieDomain = configuration["AuthToken:CookieDomain"]!;
|
private readonly string _cookieDomain = configuration["AuthToken:CookieDomain"]!;
|
||||||
@@ -24,8 +32,8 @@ public class AuthController(
|
|||||||
public class ChallengeRequest
|
public class ChallengeRequest
|
||||||
{
|
{
|
||||||
[Required] public ClientPlatform Platform { get; set; }
|
[Required] public ClientPlatform Platform { get; set; }
|
||||||
[Required][MaxLength(256)] public string Account { get; set; } = null!;
|
[Required] [MaxLength(256)] public string Account { get; set; } = null!;
|
||||||
[Required][MaxLength(512)] public string DeviceId { get; set; } = null!;
|
[Required] [MaxLength(512)] public string DeviceId { get; set; } = null!;
|
||||||
[MaxLength(1024)] public string? DeviceName { get; set; }
|
[MaxLength(1024)] public string? DeviceName { get; set; }
|
||||||
public List<string> Audiences { get; set; } = new();
|
public List<string> Audiences { get; set; } = new();
|
||||||
public List<string> Scopes { get; set; } = new();
|
public List<string> Scopes { get; set; } = new();
|
||||||
@@ -50,7 +58,8 @@ public class AuthController(
|
|||||||
|
|
||||||
request.DeviceName ??= userAgent;
|
request.DeviceName ??= userAgent;
|
||||||
|
|
||||||
var device = await auth.GetOrCreateDeviceAsync(account.Id, request.DeviceId, request.DeviceName, request.Platform);
|
var device =
|
||||||
|
await auth.GetOrCreateDeviceAsync(account.Id, request.DeviceId, request.DeviceName, request.Platform);
|
||||||
|
|
||||||
// Trying to pick up challenges from the same IP address and user agent
|
// Trying to pick up challenges from the same IP address and user agent
|
||||||
var existingChallenge = await db.AuthChallenges
|
var existingChallenge = await db.AuthChallenges
|
||||||
@@ -64,7 +73,8 @@ public class AuthController(
|
|||||||
.FirstOrDefaultAsync();
|
.FirstOrDefaultAsync();
|
||||||
if (existingChallenge is not null)
|
if (existingChallenge is not null)
|
||||||
{
|
{
|
||||||
var existingSession = await db.AuthSessions.Where(e => e.ChallengeId == existingChallenge.Id).FirstOrDefaultAsync();
|
var existingSession = await db.AuthSessions.Where(e => e.ChallengeId == existingChallenge.Id)
|
||||||
|
.FirstOrDefaultAsync();
|
||||||
if (existingSession is null) return existingChallenge;
|
if (existingSession is null) return existingChallenge;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,7 +166,10 @@ public class AuthController(
|
|||||||
[FromBody] PerformChallengeRequest request
|
[FromBody] PerformChallengeRequest request
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
var challenge = await db.AuthChallenges.Include(e => e.Account).FirstOrDefaultAsync(e => e.Id == id);
|
var challenge = await db.AuthChallenges
|
||||||
|
.Include(e => e.Account)
|
||||||
|
.Include(authChallenge => authChallenge.Client)
|
||||||
|
.FirstOrDefaultAsync(e => e.Id == id);
|
||||||
if (challenge is null) return NotFound("Auth challenge was not found.");
|
if (challenge is null) return NotFound("Auth challenge was not found.");
|
||||||
|
|
||||||
var factor = await db.AccountAuthFactors.FindAsync(request.FactorId);
|
var factor = await db.AccountAuthFactors.FindAsync(request.FactorId);
|
||||||
@@ -206,6 +219,19 @@ public class AuthController(
|
|||||||
|
|
||||||
if (challenge.StepRemain == 0)
|
if (challenge.StepRemain == 0)
|
||||||
{
|
{
|
||||||
|
AccountService.SetCultureInfo(challenge.Account);
|
||||||
|
await pusher.SendPushNotificationToUserAsync(new SendPushNotificationToUserRequest
|
||||||
|
{
|
||||||
|
Notification = new PushNotification()
|
||||||
|
{
|
||||||
|
Topic = "auth.login",
|
||||||
|
Title = localizer["NewLoginTitle"],
|
||||||
|
Body = localizer["NewLoginBody", challenge.Client?.DeviceName ?? "unknown",
|
||||||
|
challenge.IpAddress ?? "unknown"],
|
||||||
|
IsSavable = true
|
||||||
|
},
|
||||||
|
UserId = challenge.AccountId.ToString()
|
||||||
|
});
|
||||||
als.CreateActionLogFromRequest(ActionLogType.NewLogin,
|
als.CreateActionLogFromRequest(ActionLogType.NewLogin,
|
||||||
new Dictionary<string, object>
|
new Dictionary<string, object>
|
||||||
{
|
{
|
||||||
@@ -303,4 +329,4 @@ public class AuthController(
|
|||||||
});
|
});
|
||||||
return Ok();
|
return Ok();
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -28,7 +28,7 @@ namespace DysonNetwork.Sphere.Resources.Localization {
|
|||||||
internal static System.Resources.ResourceManager ResourceManager {
|
internal static System.Resources.ResourceManager ResourceManager {
|
||||||
get {
|
get {
|
||||||
if (object.Equals(null, resourceMan)) {
|
if (object.Equals(null, resourceMan)) {
|
||||||
System.Resources.ResourceManager temp = new System.Resources.ResourceManager("DysonNetwork.Sphere.Resources.Localization.NotificationResource", typeof(NotificationResource).Assembly);
|
System.Resources.ResourceManager temp = new System.Resources.ResourceManager("DysonNetwork.Pass.Resources.Localization.NotificationResource", typeof(NotificationResource).Assembly);
|
||||||
resourceMan = temp;
|
resourceMan = temp;
|
||||||
}
|
}
|
||||||
return resourceMan;
|
return resourceMan;
|
||||||
@@ -158,5 +158,17 @@ namespace DysonNetwork.Sphere.Resources.Localization {
|
|||||||
return ResourceManager.GetString("OrderPaidBody", resourceCulture);
|
return ResourceManager.GetString("OrderPaidBody", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static string NewLoginTitle {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("NewLoginTitle", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static string NewLoginBody {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("NewLoginBody", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -80,4 +80,10 @@
|
|||||||
<data name="OrderPaidBody" xml:space="preserve">
|
<data name="OrderPaidBody" xml:space="preserve">
|
||||||
<value>{0} {1} was removed from your wallet to pay {2}</value>
|
<value>{0} {1} was removed from your wallet to pay {2}</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="NewLoginTitle" xml:space="preserve">
|
||||||
|
<value>New login detected</value>
|
||||||
|
</data>
|
||||||
|
<data name="NewLoginBody" xml:space="preserve">
|
||||||
|
<value>Your account logged on to a device named {0} at {1}</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@@ -72,4 +72,10 @@
|
|||||||
<data name="OrderPaidBody" xml:space="preserve">
|
<data name="OrderPaidBody" xml:space="preserve">
|
||||||
<value>{0} {1} 已从你的帐户中扣除来支付 {2}</value>
|
<value>{0} {1} 已从你的帐户中扣除来支付 {2}</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="NewLoginTitle" xml:space="preserve">
|
||||||
|
<value>检测到新登陆</value>
|
||||||
|
</data>
|
||||||
|
<data name="NewLoginBody" xml:space="preserve">
|
||||||
|
<value>您的帐号在位于 {1} 的设备 {0} 上刚刚登陆了</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@@ -148,6 +148,7 @@
|
|||||||
<Assembly Path="/opt/homebrew/Cellar/dotnet/9.0.6/libexec/packs/Microsoft.AspNetCore.App.Ref/9.0.6/ref/net9.0/Microsoft.AspNetCore.RateLimiting.dll" />
|
<Assembly Path="/opt/homebrew/Cellar/dotnet/9.0.6/libexec/packs/Microsoft.AspNetCore.App.Ref/9.0.6/ref/net9.0/Microsoft.AspNetCore.RateLimiting.dll" />
|
||||||
</AssemblyExplorer></s:String>
|
</AssemblyExplorer></s:String>
|
||||||
<s:Boolean x:Key="/Default/ResxEditorPersonal/CheckedGroups/=DysonNetwork_002EPass_002FResources_002FLocalization_002FAccountEventResource/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/ResxEditorPersonal/CheckedGroups/=DysonNetwork_002EPass_002FResources_002FLocalization_002FAccountEventResource/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/ResxEditorPersonal/CheckedGroups/=DysonNetwork_002EPass_002FResources_002FLocalization_002FNotificationResource/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/ResxEditorPersonal/CheckedGroups/=DysonNetwork_002ESphere_002FLocalization_002FResources_002FAccountEventResource/@EntryIndexedValue">False</s:Boolean>
|
<s:Boolean x:Key="/Default/ResxEditorPersonal/CheckedGroups/=DysonNetwork_002ESphere_002FLocalization_002FResources_002FAccountEventResource/@EntryIndexedValue">False</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/ResxEditorPersonal/CheckedGroups/=DysonNetwork_002ESphere_002FLocalization_002FResources_002FAccountEventResource/@EntryIndexRemoved">True</s:Boolean>
|
<s:Boolean x:Key="/Default/ResxEditorPersonal/CheckedGroups/=DysonNetwork_002ESphere_002FLocalization_002FResources_002FAccountEventResource/@EntryIndexRemoved">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/ResxEditorPersonal/CheckedGroups/=DysonNetwork_002ESphere_002FLocalization_002FResources_002FSharedResource/@EntryIndexedValue">False</s:Boolean>
|
<s:Boolean x:Key="/Default/ResxEditorPersonal/CheckedGroups/=DysonNetwork_002ESphere_002FLocalization_002FResources_002FSharedResource/@EntryIndexedValue">False</s:Boolean>
|
||||||
|
Reference in New Issue
Block a user