From 2761abf405c262998f8e99620537cdf8cb525cf7 Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Sun, 17 Aug 2025 23:43:13 +0800 Subject: [PATCH] :sparkles: Login now send a notification --- DysonNetwork.Pass/Auth/AuthController.cs | 40 +++++++++++++++---- .../NotificationResource.Designer.cs | 14 ++++++- .../Localization/NotificationResource.resx | 6 +++ .../NotificationResource.zh-hans.resx | 6 +++ DysonNetwork.sln.DotSettings.user | 1 + 5 files changed, 59 insertions(+), 8 deletions(-) diff --git a/DysonNetwork.Pass/Auth/AuthController.cs b/DysonNetwork.Pass/Auth/AuthController.cs index fb8e8c6..c58a8e2 100644 --- a/DysonNetwork.Pass/Auth/AuthController.cs +++ b/DysonNetwork.Pass/Auth/AuthController.cs @@ -3,8 +3,14 @@ using Microsoft.AspNetCore.Mvc; using NodaTime; using Microsoft.EntityFrameworkCore; using DysonNetwork.Pass.Account; +using DysonNetwork.Pass.Localization; using DysonNetwork.Shared.Data; 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; @@ -16,7 +22,9 @@ public class AuthController( AuthService auth, GeoIpService geo, ActionLogService als, - IConfiguration configuration + PusherService.PusherServiceClient pusher, + IConfiguration configuration, + IStringLocalizer localizer ) : ControllerBase { private readonly string _cookieDomain = configuration["AuthToken:CookieDomain"]!; @@ -24,8 +32,8 @@ public class AuthController( public class ChallengeRequest { [Required] public ClientPlatform Platform { get; set; } - [Required][MaxLength(256)] public string Account { get; set; } = null!; - [Required][MaxLength(512)] public string DeviceId { get; set; } = null!; + [Required] [MaxLength(256)] public string Account { get; set; } = null!; + [Required] [MaxLength(512)] public string DeviceId { get; set; } = null!; [MaxLength(1024)] public string? DeviceName { get; set; } public List Audiences { get; set; } = new(); public List Scopes { get; set; } = new(); @@ -50,7 +58,8 @@ public class AuthController( 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 var existingChallenge = await db.AuthChallenges @@ -64,7 +73,8 @@ public class AuthController( .FirstOrDefaultAsync(); 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; } @@ -156,7 +166,10 @@ public class AuthController( [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."); var factor = await db.AccountAuthFactors.FindAsync(request.FactorId); @@ -206,6 +219,19 @@ public class AuthController( 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, new Dictionary { @@ -303,4 +329,4 @@ public class AuthController( }); return Ok(); } -} +} \ No newline at end of file diff --git a/DysonNetwork.Pass/Resources/Localization/NotificationResource.Designer.cs b/DysonNetwork.Pass/Resources/Localization/NotificationResource.Designer.cs index c604395..75bfdf4 100644 --- a/DysonNetwork.Pass/Resources/Localization/NotificationResource.Designer.cs +++ b/DysonNetwork.Pass/Resources/Localization/NotificationResource.Designer.cs @@ -28,7 +28,7 @@ namespace DysonNetwork.Sphere.Resources.Localization { internal static System.Resources.ResourceManager ResourceManager { get { 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; } return resourceMan; @@ -158,5 +158,17 @@ namespace DysonNetwork.Sphere.Resources.Localization { 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); + } + } } } diff --git a/DysonNetwork.Pass/Resources/Localization/NotificationResource.resx b/DysonNetwork.Pass/Resources/Localization/NotificationResource.resx index 283612a..218a4d5 100644 --- a/DysonNetwork.Pass/Resources/Localization/NotificationResource.resx +++ b/DysonNetwork.Pass/Resources/Localization/NotificationResource.resx @@ -80,4 +80,10 @@ {0} {1} was removed from your wallet to pay {2} + + New login detected + + + Your account logged on to a device named {0} at {1} + \ No newline at end of file diff --git a/DysonNetwork.Pass/Resources/Localization/NotificationResource.zh-hans.resx b/DysonNetwork.Pass/Resources/Localization/NotificationResource.zh-hans.resx index 4cf16b1..d6346f7 100644 --- a/DysonNetwork.Pass/Resources/Localization/NotificationResource.zh-hans.resx +++ b/DysonNetwork.Pass/Resources/Localization/NotificationResource.zh-hans.resx @@ -72,4 +72,10 @@ {0} {1} 已从你的帐户中扣除来支付 {2} + + 检测到新登陆 + + + 您的帐号在位于 {1} 的设备 {0} 上刚刚登陆了 + \ No newline at end of file diff --git a/DysonNetwork.sln.DotSettings.user b/DysonNetwork.sln.DotSettings.user index 0c61107..2eace75 100644 --- a/DysonNetwork.sln.DotSettings.user +++ b/DysonNetwork.sln.DotSettings.user @@ -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" /> </AssemblyExplorer> True + True False True False