♻️ Extract the Storage service to DysonNetwork.Drive microservice
This commit is contained in:
@ -1,7 +1,7 @@
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using DysonNetwork.Common.Models;
|
||||
using DysonNetwork.Pass.Permission;
|
||||
using DysonNetwork.Sphere.Permission;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Design;
|
||||
using NodaTime;
|
||||
|
@ -21,8 +21,8 @@
|
||||
<PackageReference Include="EFCore.BulkExtensions" Version="9.0.1" />
|
||||
<PackageReference Include="Quartz.Extensions.Hosting" Version="3.14.0" />
|
||||
<PackageReference Include="Quartz.Extensions.DependencyInjection" Version="3.14.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.4" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="8.1.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.6" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="9.0.1" />
|
||||
|
||||
|
||||
|
||||
@ -44,6 +44,8 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\DysonNetwork.Common\DysonNetwork.Common.csproj" />
|
||||
<ProjectReference Include="..\DysonNetwork.Drive\DysonNetwork.Drive.csproj" />
|
||||
<ProjectReference Include="..\DysonNetwork.Sphere\DysonNetwork.Sphere.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -46,7 +46,7 @@ public class AccountCurrentController(
|
||||
[HttpPatch]
|
||||
public async Task<ActionResult<Account>> UpdateBasicInfo([FromBody] BasicInfoRequest request)
|
||||
{
|
||||
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||
if (HttpContext.Items["CurrentUser"] is not Common.Models.Account currentUser) return Unauthorized();
|
||||
|
||||
var account = await db.Accounts.FirstAsync(a => a.Id == currentUser.Id);
|
||||
|
||||
@ -77,7 +77,7 @@ public class AccountCurrentController(
|
||||
[HttpPatch("profile")]
|
||||
public async Task<ActionResult<Profile>> UpdateProfile([FromBody] ProfileRequest request)
|
||||
{
|
||||
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||
if (HttpContext.Items["CurrentUser"] is not Common.Models.Account currentUser) return Unauthorized();
|
||||
var userId = currentUser.Id;
|
||||
|
||||
var profile = await db.AccountProfiles
|
||||
@ -162,7 +162,7 @@ public class AccountCurrentController(
|
||||
[HttpDelete]
|
||||
public async Task<ActionResult> RequestDeleteAccount()
|
||||
{
|
||||
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||
if (HttpContext.Items["CurrentUser"] is not Common.Models.Account currentUser) return Unauthorized();
|
||||
|
||||
try
|
||||
{
|
||||
@ -179,7 +179,7 @@ public class AccountCurrentController(
|
||||
[HttpGet("statuses")]
|
||||
public async Task<ActionResult<Status>> GetCurrentStatus()
|
||||
{
|
||||
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||
if (HttpContext.Items["CurrentUser"] is not Common.Models.Account currentUser) return Unauthorized();
|
||||
var status = await events.GetStatus(currentUser.Id);
|
||||
return Ok(status);
|
||||
}
|
||||
@ -188,7 +188,7 @@ public class AccountCurrentController(
|
||||
[RequiredPermission("global", "accounts.statuses.update")]
|
||||
public async Task<ActionResult<Status>> UpdateStatus([FromBody] AccountController.StatusRequest request)
|
||||
{
|
||||
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||
if (HttpContext.Items["CurrentUser"] is not Common.Models.Account currentUser) return Unauthorized();
|
||||
|
||||
var now = SystemClock.Instance.GetCurrentInstant();
|
||||
var status = await db.AccountStatuses
|
||||
@ -212,10 +212,10 @@ public class AccountCurrentController(
|
||||
}
|
||||
|
||||
[HttpPost("statuses")]
|
||||
[RequiredPermission("global", "accounts.statuses.create")]
|
||||
[DysonNetwork.Sphere.Permission.RequiredPermission("global", "accounts.statuses.create")]
|
||||
public async Task<ActionResult<Status>> CreateStatus([FromBody] AccountController.StatusRequest request)
|
||||
{
|
||||
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||
if (HttpContext.Items["CurrentUser"] is not Common.Models.Account currentUser) return Unauthorized();
|
||||
|
||||
var status = new Status
|
||||
{
|
||||
@ -233,7 +233,7 @@ public class AccountCurrentController(
|
||||
[HttpDelete("me/statuses")]
|
||||
public async Task<ActionResult> DeleteStatus()
|
||||
{
|
||||
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||
if (HttpContext.Items["CurrentUser"] is not Common.Models.Account currentUser) return Unauthorized();
|
||||
|
||||
var now = SystemClock.Instance.GetCurrentInstant();
|
||||
var status = await db.AccountStatuses
|
||||
@ -250,7 +250,7 @@ public class AccountCurrentController(
|
||||
[HttpGet("check-in")]
|
||||
public async Task<ActionResult<CheckInResult>> GetCheckInResult()
|
||||
{
|
||||
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||
if (HttpContext.Items["CurrentUser"] is not Common.Models.Account currentUser) return Unauthorized();
|
||||
var userId = currentUser.Id;
|
||||
|
||||
var now = SystemClock.Instance.GetCurrentInstant();
|
||||
@ -270,7 +270,7 @@ public class AccountCurrentController(
|
||||
[HttpPost("check-in")]
|
||||
public async Task<ActionResult<CheckInResult>> DoCheckIn([FromBody] string? captchaToken)
|
||||
{
|
||||
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||
if (HttpContext.Items["CurrentUser"] is not Common.Models.Account currentUser) return Unauthorized();
|
||||
|
||||
var isAvailable = await events.CheckInDailyIsAvailable(currentUser);
|
||||
if (!isAvailable)
|
||||
@ -297,7 +297,7 @@ public class AccountCurrentController(
|
||||
public async Task<ActionResult<List<DailyEventResponse>>> GetEventCalendar([FromQuery] int? month,
|
||||
[FromQuery] int? year)
|
||||
{
|
||||
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||
if (HttpContext.Items["CurrentUser"] is not Common.Models.Account currentUser) return Unauthorized();
|
||||
|
||||
var currentDate = SystemClock.Instance.GetCurrentInstant().InUtc().Date;
|
||||
month ??= currentDate.Month;
|
||||
@ -318,7 +318,7 @@ public class AccountCurrentController(
|
||||
[FromQuery] int offset = 0
|
||||
)
|
||||
{
|
||||
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||
if (HttpContext.Items["CurrentUser"] is not Common.Models.Account currentUser) return Unauthorized();
|
||||
|
||||
var query = db.ActionLogs
|
||||
.Where(log => log.AccountId == currentUser.Id)
|
||||
@ -338,7 +338,7 @@ public class AccountCurrentController(
|
||||
[HttpGet("factors")]
|
||||
public async Task<ActionResult<List<AccountAuthFactor>>> GetAuthFactors()
|
||||
{
|
||||
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||
if (HttpContext.Items["CurrentUser"] is not Common.Models.Account currentUser) return Unauthorized();
|
||||
|
||||
var factors = await db.AccountAuthFactors
|
||||
.Include(f => f.Account)
|
||||
@ -358,7 +358,7 @@ public class AccountCurrentController(
|
||||
[Authorize]
|
||||
public async Task<ActionResult<AccountAuthFactor>> CreateAuthFactor([FromBody] AuthFactorRequest request)
|
||||
{
|
||||
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||
if (HttpContext.Items["CurrentUser"] is not Common.Models.Account currentUser) return Unauthorized();
|
||||
if (await accounts.CheckAuthFactorExists(currentUser, request.Type))
|
||||
return BadRequest($"Auth factor with type {request.Type} is already exists.");
|
||||
|
||||
@ -370,7 +370,7 @@ public class AccountCurrentController(
|
||||
[Authorize]
|
||||
public async Task<ActionResult<AccountAuthFactor>> EnableAuthFactor(Guid id, [FromBody] string? code)
|
||||
{
|
||||
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||
if (HttpContext.Items["CurrentUser"] is not Common.Models.Account currentUser) return Unauthorized();
|
||||
|
||||
var factor = await db.AccountAuthFactors
|
||||
.Where(f => f.AccountId == currentUser.Id && f.Id == id)
|
||||
@ -392,7 +392,7 @@ public class AccountCurrentController(
|
||||
[Authorize]
|
||||
public async Task<ActionResult<AccountAuthFactor>> DisableAuthFactor(Guid id)
|
||||
{
|
||||
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||
if (HttpContext.Items["CurrentUser"] is not Common.Models.Account currentUser) return Unauthorized();
|
||||
|
||||
var factor = await db.AccountAuthFactors
|
||||
.Where(f => f.AccountId == currentUser.Id && f.Id == id)
|
||||
@ -414,7 +414,7 @@ public class AccountCurrentController(
|
||||
[Authorize]
|
||||
public async Task<ActionResult<AccountAuthFactor>> DeleteAuthFactor(Guid id)
|
||||
{
|
||||
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||
if (HttpContext.Items["CurrentUser"] is not Common.Models.Account currentUser) return Unauthorized();
|
||||
|
||||
var factor = await db.AccountAuthFactors
|
||||
.Where(f => f.AccountId == currentUser.Id && f.Id == id)
|
||||
@ -445,7 +445,7 @@ public class AccountCurrentController(
|
||||
[Authorize]
|
||||
public async Task<ActionResult<List<AuthorizedDevice>>> GetDevices()
|
||||
{
|
||||
if (HttpContext.Items["CurrentUser"] is not Account currentUser ||
|
||||
if (HttpContext.Items["CurrentUser"] is not Common.Models.Account currentUser ||
|
||||
HttpContext.Items["CurrentSession"] is not Session currentSession) return Unauthorized();
|
||||
|
||||
Response.Headers.Append("X-Auth-Session", currentSession.Id.ToString());
|
||||
@ -475,13 +475,13 @@ public class AccountCurrentController(
|
||||
|
||||
[HttpGet("sessions")]
|
||||
[Authorize]
|
||||
public async Task<ActionResult<List<Session>>> GetSessions(
|
||||
public async Task<ActionResult<List<AuthSession>>> GetSessions(
|
||||
[FromQuery] int take = 20,
|
||||
[FromQuery] int offset = 0
|
||||
)
|
||||
{
|
||||
if (HttpContext.Items["CurrentUser"] is not Account currentUser ||
|
||||
HttpContext.Items["CurrentSession"] is not Session currentSession) return Unauthorized();
|
||||
if (HttpContext.Items["CurrentUser"] is not Common.Models.Account currentUser ||
|
||||
HttpContext.Items["CurrentSession"] is not AuthSession currentSession) return Unauthorized();
|
||||
|
||||
var query = db.AuthSessions
|
||||
.Include(session => session.Account)
|
||||
@ -505,7 +505,7 @@ public class AccountCurrentController(
|
||||
[Authorize]
|
||||
public async Task<ActionResult<Session>> DeleteSession(Guid id)
|
||||
{
|
||||
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||
if (HttpContext.Items["CurrentUser"] is not Common.Models.Account currentUser) return Unauthorized();
|
||||
|
||||
try
|
||||
{
|
||||
@ -522,7 +522,7 @@ public class AccountCurrentController(
|
||||
[Authorize]
|
||||
public async Task<ActionResult<Session>> DeleteCurrentSession()
|
||||
{
|
||||
if (HttpContext.Items["CurrentUser"] is not Account currentUser ||
|
||||
if (HttpContext.Items["CurrentUser"] is not Common.Models.Account currentUser ||
|
||||
HttpContext.Items["CurrentSession"] is not Session currentSession) return Unauthorized();
|
||||
|
||||
try
|
||||
@ -537,9 +537,9 @@ public class AccountCurrentController(
|
||||
}
|
||||
|
||||
[HttpPatch("sessions/{id:guid}/label")]
|
||||
public async Task<ActionResult<Session>> UpdateSessionLabel(Guid id, [FromBody] string label)
|
||||
public async Task<ActionResult<AuthSession>> UpdateSessionLabel(Guid id, [FromBody] string label)
|
||||
{
|
||||
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||
if (HttpContext.Items["CurrentUser"] is not Common.Models.Account currentUser) return Unauthorized();
|
||||
|
||||
try
|
||||
{
|
||||
@ -553,9 +553,9 @@ public class AccountCurrentController(
|
||||
}
|
||||
|
||||
[HttpPatch("sessions/current/label")]
|
||||
public async Task<ActionResult<Session>> UpdateCurrentSessionLabel([FromBody] string label)
|
||||
public async Task<ActionResult<AuthSession>> UpdateCurrentSessionLabel([FromBody] string label)
|
||||
{
|
||||
if (HttpContext.Items["CurrentUser"] is not Account currentUser ||
|
||||
if (HttpContext.Items["CurrentUser"] is not Common.Models.Account currentUser ||
|
||||
HttpContext.Items["CurrentSession"] is not Session currentSession) return Unauthorized();
|
||||
|
||||
try
|
||||
@ -573,7 +573,7 @@ public class AccountCurrentController(
|
||||
[Authorize]
|
||||
public async Task<ActionResult<List<AccountContact>>> GetContacts()
|
||||
{
|
||||
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||
if (HttpContext.Items["CurrentUser"] is not Common.Models.Account currentUser) return Unauthorized();
|
||||
|
||||
var contacts = await db.AccountContacts
|
||||
.Where(c => c.AccountId == currentUser.Id)
|
||||
@ -592,7 +592,7 @@ public class AccountCurrentController(
|
||||
[Authorize]
|
||||
public async Task<ActionResult<AccountContact>> CreateContact([FromBody] AccountContactRequest request)
|
||||
{
|
||||
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||
if (HttpContext.Items["CurrentUser"] is not Common.Models.Account currentUser) return Unauthorized();
|
||||
|
||||
try
|
||||
{
|
||||
@ -609,7 +609,7 @@ public class AccountCurrentController(
|
||||
[Authorize]
|
||||
public async Task<ActionResult<AccountContact>> VerifyContact(Guid id)
|
||||
{
|
||||
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||
if (HttpContext.Items["CurrentUser"] is not Common.Models.Account currentUser) return Unauthorized();
|
||||
|
||||
var contact = await db.AccountContacts
|
||||
.Where(c => c.AccountId == currentUser.Id && c.Id == id)
|
||||
@ -631,7 +631,7 @@ public class AccountCurrentController(
|
||||
[Authorize]
|
||||
public async Task<ActionResult<AccountContact>> SetPrimaryContact(Guid id)
|
||||
{
|
||||
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||
if (HttpContext.Items["CurrentUser"] is not Common.Models.Account currentUser) return Unauthorized();
|
||||
|
||||
var contact = await db.AccountContacts
|
||||
.Where(c => c.AccountId == currentUser.Id && c.Id == id)
|
||||
@ -653,7 +653,7 @@ public class AccountCurrentController(
|
||||
[Authorize]
|
||||
public async Task<ActionResult<AccountContact>> DeleteContact(Guid id)
|
||||
{
|
||||
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||
if (HttpContext.Items["CurrentUser"] is not Common.Models.Account currentUser) return Unauthorized();
|
||||
|
||||
var contact = await db.AccountContacts
|
||||
.Where(c => c.AccountId == currentUser.Id && c.Id == id)
|
||||
@ -676,7 +676,7 @@ public class AccountCurrentController(
|
||||
[Authorize]
|
||||
public async Task<ActionResult<List<Badge>>> GetBadges()
|
||||
{
|
||||
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||
if (HttpContext.Items["CurrentUser"] is not Common.Models.Account currentUser) return Unauthorized();
|
||||
|
||||
var badges = await db.Badges
|
||||
.Where(b => b.AccountId == currentUser.Id)
|
||||
@ -688,7 +688,7 @@ public class AccountCurrentController(
|
||||
[Authorize]
|
||||
public async Task<ActionResult<Badge>> ActivateBadge(Guid id)
|
||||
{
|
||||
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
||||
if (HttpContext.Items["CurrentUser"] is not Common.Models.Account currentUser) return Unauthorized();
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -140,7 +140,7 @@ public class NotificationController(PassDatabase db, NotificationService nty) :
|
||||
|
||||
[HttpPost("send")]
|
||||
[Authorize]
|
||||
[RequiredPermission("global", "notifications.send")]
|
||||
[DysonNetwork.Sphere.Permission.RequiredPermission("global", "notifications.send")]
|
||||
public async Task<ActionResult> SendNotification(
|
||||
[FromBody] NotificationWithAimRequest request,
|
||||
[FromQuery] bool save = false
|
||||
|
@ -3,7 +3,7 @@ using DysonNetwork.Pass.Features.Auth;
|
||||
using DysonNetwork.Pass.Features.Auth.OpenId;
|
||||
using DysonNetwork.Pass.Email;
|
||||
using DysonNetwork.Pass.Localization;
|
||||
using DysonNetwork.Pass.Permission;
|
||||
using DysonNetwork.Sphere.Permission;
|
||||
using DysonNetwork.Pass.Storage;
|
||||
using EFCore.BulkExtensions;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
@ -3,7 +3,7 @@ using DysonNetwork.Pass.Storage;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NodaTime;
|
||||
using DysonNetwork.Common.Models;
|
||||
using DysonNetwork.Pass.Permission;
|
||||
using DysonNetwork.Sphere.Permission;
|
||||
|
||||
namespace DysonNetwork.Pass.Features.Account;
|
||||
|
||||
|
@ -218,7 +218,7 @@ public class AuthController(
|
||||
if (session is not null)
|
||||
return BadRequest("Session already exists for this challenge.");
|
||||
|
||||
session = new Session
|
||||
var session = new AuthSession
|
||||
{
|
||||
LastGrantedAt = Instant.FromDateTimeUtc(DateTime.UtcNow),
|
||||
ExpiredAt = Instant.FromDateTimeUtc(DateTime.UtcNow.AddDays(30)),
|
||||
|
@ -3,11 +3,14 @@ using System.Security.Cryptography;
|
||||
using System.Text.Encodings.Web;
|
||||
using DysonNetwork.Pass.Features.Account;
|
||||
using DysonNetwork.Pass.Features.Auth.OidcProvider.Services;
|
||||
using DysonNetwork.Pass.Storage;
|
||||
using DysonNetwork.Pass.Storage.Handlers;
|
||||
using DysonNetwork.Common.Services;
|
||||
using DysonNetwork.Drive.Handlers;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.Extensions.Options;
|
||||
using SystemClock = NodaTime.SystemClock;
|
||||
using NodaTime;
|
||||
using DysonNetwork.Pass.Data;
|
||||
using DysonNetwork.Common.Models;
|
||||
using DysonNetwork.Drive;
|
||||
|
||||
namespace DysonNetwork.Pass.Features.Auth.Services;
|
||||
|
||||
@ -57,14 +60,14 @@ public class DysonTokenAuthHandler(
|
||||
|
||||
try
|
||||
{
|
||||
var now = SystemClock.Instance.GetCurrentInstant();
|
||||
var now = NodaTime.SystemClock.Instance.GetCurrentInstant();
|
||||
|
||||
// Validate token and extract session ID
|
||||
if (!ValidateToken(tokenInfo.Token, out var sessionId))
|
||||
return AuthenticateResult.Fail("Invalid token.");
|
||||
|
||||
// Try to get session from cache first
|
||||
var session = await cache.GetAsync<Session>($"{AuthCachePrefix}{sessionId}");
|
||||
var session = await cache.GetAsync<AuthSession>($"{AuthCachePrefix}{sessionId}");
|
||||
|
||||
// If not in cache, load from database
|
||||
if (session is null)
|
||||
@ -126,7 +129,7 @@ public class DysonTokenAuthHandler(
|
||||
{
|
||||
Account = session.Account,
|
||||
Session = session,
|
||||
SeenAt = SystemClock.Instance.GetCurrentInstant(),
|
||||
SeenAt = NodaTime.SystemClock.Instance.GetCurrentInstant(),
|
||||
};
|
||||
fbs.Enqueue(lastInfo);
|
||||
|
||||
|
@ -5,6 +5,7 @@ using DysonNetwork.Pass.Storage;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NodaTime;
|
||||
using DysonNetwork.Pass.Data;
|
||||
using DysonNetwork.Common.Models;
|
||||
|
||||
namespace DysonNetwork.Pass.Features.Auth;
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System.Security.Cryptography;
|
||||
using DysonNetwork.Common.Models;
|
||||
|
||||
namespace DysonNetwork.Pass.Features.Auth;
|
||||
|
||||
@ -7,7 +8,7 @@ public class CompactTokenService(IConfiguration config)
|
||||
private readonly string _privateKeyPath = config["AuthToken:PrivateKeyPath"]
|
||||
?? throw new InvalidOperationException("AuthToken:PrivateKeyPath configuration is missing");
|
||||
|
||||
public string CreateToken(Session session)
|
||||
public string CreateToken(AuthSession session)
|
||||
{
|
||||
// Load the private key for signing
|
||||
var privateKeyPem = File.ReadAllText(_privateKeyPath);
|
||||
|
@ -5,6 +5,8 @@ using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using DysonNetwork.Common.Services;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using DysonNetwork.Pass.Data;
|
||||
using DysonNetwork.Sphere;
|
||||
|
||||
namespace DysonNetwork.Pass.Features.Auth.OpenId;
|
||||
|
||||
@ -14,11 +16,12 @@ namespace DysonNetwork.Pass.Features.Auth.OpenId;
|
||||
public class AppleOidcService(
|
||||
IConfiguration configuration,
|
||||
IHttpClientFactory httpClientFactory,
|
||||
PassDatabase db,
|
||||
PassDatabase passDb,
|
||||
AppDatabase sphereDb,
|
||||
AuthService auth,
|
||||
ICacheService cache
|
||||
)
|
||||
: OidcService(configuration, httpClientFactory, db, auth, cache)
|
||||
: OidcService(configuration, httpClientFactory, passDb, sphereDb, auth, cache)
|
||||
{
|
||||
private readonly IConfiguration _configuration = configuration;
|
||||
private readonly IHttpClientFactory _httpClientFactory = httpClientFactory;
|
||||
|
@ -1,17 +1,20 @@
|
||||
using System.Net.Http.Json;
|
||||
using System.Text.Json;
|
||||
using DysonNetwork.Pass.Storage;
|
||||
using DysonNetwork.Common.Services;
|
||||
using DysonNetwork.Pass.Data;
|
||||
using DysonNetwork.Sphere;
|
||||
|
||||
namespace DysonNetwork.Pass.Features.Auth.OpenId;
|
||||
|
||||
public class DiscordOidcService(
|
||||
IConfiguration configuration,
|
||||
IHttpClientFactory httpClientFactory,
|
||||
PassDatabase db,
|
||||
PassDatabase passDb,
|
||||
AppDatabase sphereDb,
|
||||
AuthService auth,
|
||||
ICacheService cache
|
||||
)
|
||||
: OidcService(configuration, httpClientFactory, db, auth, cache)
|
||||
: OidcService(configuration, httpClientFactory, passDb, sphereDb, auth, cache)
|
||||
{
|
||||
public override string ProviderName => "Discord";
|
||||
protected override string DiscoveryEndpoint => ""; // Discord doesn't have a standard OIDC discovery endpoint
|
||||
|
@ -1,17 +1,20 @@
|
||||
using System.Net.Http.Json;
|
||||
using System.Text.Json;
|
||||
using DysonNetwork.Pass.Storage;
|
||||
using DysonNetwork.Common.Services;
|
||||
using DysonNetwork.Pass.Data;
|
||||
using DysonNetwork.Sphere;
|
||||
|
||||
namespace DysonNetwork.Pass.Features.Auth.OpenId;
|
||||
|
||||
public class GitHubOidcService(
|
||||
IConfiguration configuration,
|
||||
IHttpClientFactory httpClientFactory,
|
||||
PassDatabase db,
|
||||
PassDatabase passDb,
|
||||
AppDatabase sphereDb,
|
||||
AuthService auth,
|
||||
ICacheService cache
|
||||
)
|
||||
: OidcService(configuration, httpClientFactory, db, auth, cache)
|
||||
: OidcService(configuration, httpClientFactory, passDb, sphereDb, auth, cache)
|
||||
{
|
||||
public override string ProviderName => "GitHub";
|
||||
protected override string DiscoveryEndpoint => ""; // GitHub doesn't have a standard OIDC discovery endpoint
|
||||
@ -77,7 +80,7 @@ public class GitHubOidcService(
|
||||
var client = HttpClientFactory.CreateClient();
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, "https://api.github.com/user");
|
||||
request.Headers.Add("Authorization", $"Bearer {accessToken}");
|
||||
request.Headers.Add("User-Agent", "DysonNetwork.Sphere");
|
||||
request.Headers.Add("User-Agent", "DysonNetwork.Drive");
|
||||
|
||||
var response = await client.SendAsync(request);
|
||||
response.EnsureSuccessStatusCode();
|
||||
@ -109,7 +112,7 @@ public class GitHubOidcService(
|
||||
var client = HttpClientFactory.CreateClient();
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, "https://api.github.com/user/emails");
|
||||
request.Headers.Add("Authorization", $"Bearer {accessToken}");
|
||||
request.Headers.Add("User-Agent", "DysonNetwork.Sphere");
|
||||
request.Headers.Add("User-Agent", "DysonNetwork.Drive");
|
||||
|
||||
var response = await client.SendAsync(request);
|
||||
if (!response.IsSuccessStatusCode) return null;
|
||||
|
@ -4,17 +4,20 @@ using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using DysonNetwork.Common.Services;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using DysonNetwork.Pass.Data;
|
||||
using DysonNetwork.Sphere;
|
||||
|
||||
namespace DysonNetwork.Pass.Features.Auth.OpenId;
|
||||
|
||||
public class GoogleOidcService(
|
||||
IConfiguration configuration,
|
||||
IHttpClientFactory httpClientFactory,
|
||||
PassDatabase db,
|
||||
PassDatabase passDb,
|
||||
AppDatabase sphereDb,
|
||||
AuthService auth,
|
||||
ICacheService cache
|
||||
)
|
||||
: OidcService(configuration, httpClientFactory, db, auth, cache)
|
||||
: OidcService(configuration, httpClientFactory, passDb, sphereDb, auth, cache)
|
||||
{
|
||||
private readonly IHttpClientFactory _httpClientFactory = httpClientFactory;
|
||||
|
||||
|
@ -1,17 +1,20 @@
|
||||
using System.Net.Http.Json;
|
||||
using System.Text.Json;
|
||||
using DysonNetwork.Pass.Storage;
|
||||
using DysonNetwork.Common.Services;
|
||||
using DysonNetwork.Pass.Data;
|
||||
using DysonNetwork.Sphere;
|
||||
|
||||
namespace DysonNetwork.Pass.Features.Auth.OpenId;
|
||||
|
||||
public class MicrosoftOidcService(
|
||||
IConfiguration configuration,
|
||||
IHttpClientFactory httpClientFactory,
|
||||
PassDatabase db,
|
||||
PassDatabase passDb,
|
||||
AppDatabase sphereDb,
|
||||
AuthService auth,
|
||||
ICacheService cache
|
||||
)
|
||||
: OidcService(configuration, httpClientFactory, db, auth, cache)
|
||||
: OidcService(configuration, httpClientFactory, passDb, sphereDb, auth, cache)
|
||||
{
|
||||
public override string ProviderName => "Microsoft";
|
||||
|
||||
|
@ -1,8 +1,10 @@
|
||||
using DysonNetwork.Common.Services;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using NodaTime;
|
||||
using DysonNetwork.Common.Models;
|
||||
using DysonNetwork.Pass.Data;
|
||||
using DysonNetwork.Sphere;
|
||||
|
||||
namespace DysonNetwork.Pass.Features.Auth.OpenId;
|
||||
|
||||
@ -10,7 +12,8 @@ namespace DysonNetwork.Pass.Features.Auth.OpenId;
|
||||
[Route("/auth/login")]
|
||||
public class OidcController(
|
||||
IServiceProvider serviceProvider,
|
||||
PassDatabase db,
|
||||
PassDatabase passDb,
|
||||
AppDatabase sphereDb,
|
||||
AccountService accounts,
|
||||
ICacheService cache
|
||||
)
|
||||
@ -31,7 +34,7 @@ public class OidcController(
|
||||
var oidcService = GetOidcService(provider);
|
||||
|
||||
// If the user is already authenticated, treat as an account connection request
|
||||
if (HttpContext.Items["CurrentUser"] is Models.Account currentUser)
|
||||
if (HttpContext.Items["CurrentUser"] is Account currentUser)
|
||||
{
|
||||
var state = Guid.NewGuid().ToString();
|
||||
var nonce = Guid.NewGuid().ToString();
|
||||
@ -67,7 +70,7 @@ public class OidcController(
|
||||
/// Handles Apple authentication directly from mobile apps
|
||||
/// </summary>
|
||||
[HttpPost("apple/mobile")]
|
||||
public async Task<ActionResult<Challenge>> AppleMobileLogin(
|
||||
public async Task<ActionResult<AuthChallenge>> AppleMobileSignIn(
|
||||
[FromBody] AppleMobileSignInRequest request)
|
||||
{
|
||||
try
|
||||
@ -124,7 +127,7 @@ public class OidcController(
|
||||
};
|
||||
}
|
||||
|
||||
private async Task<Models.Account> FindOrCreateAccount(OidcUserInfo userInfo, string provider)
|
||||
private async Task<Account> FindOrCreateAccount(OidcUserInfo userInfo, string provider)
|
||||
{
|
||||
if (string.IsNullOrEmpty(userInfo.Email))
|
||||
throw new ArgumentException("Email is required for account creation");
|
||||
@ -134,15 +137,16 @@ public class OidcController(
|
||||
if (existingAccount != null)
|
||||
{
|
||||
// Check if this provider connection already exists
|
||||
var existingConnection = await db.AccountConnections
|
||||
.FirstOrDefaultAsync(c => c.AccountId == existingAccount.Id &&
|
||||
c.Provider == provider &&
|
||||
c.ProvidedIdentifier == userInfo.UserId);
|
||||
var existingConnection = await passDb.AccountConnections
|
||||
.FirstOrDefaultAsync(c => c.Provider == provider &&
|
||||
c.ProvidedIdentifier == userInfo.UserId &&
|
||||
c.AccountId == existingAccount.Id
|
||||
);
|
||||
|
||||
// If no connection exists, create one
|
||||
if (existingConnection != null)
|
||||
{
|
||||
await db.AccountConnections
|
||||
await passDb.AccountConnections
|
||||
.Where(c => c.AccountId == existingAccount.Id &&
|
||||
c.Provider == provider &&
|
||||
c.ProvidedIdentifier == userInfo.UserId)
|
||||
@ -164,8 +168,8 @@ public class OidcController(
|
||||
Meta = userInfo.ToMetadata()
|
||||
};
|
||||
|
||||
await db.AccountConnections.AddAsync(connection);
|
||||
await db.SaveChangesAsync();
|
||||
await passDb.AccountConnections.AddAsync(connection);
|
||||
await passDb.SaveChangesAsync();
|
||||
|
||||
return existingAccount;
|
||||
}
|
||||
@ -185,8 +189,8 @@ public class OidcController(
|
||||
Meta = userInfo.ToMetadata()
|
||||
};
|
||||
|
||||
db.AccountConnections.Add(newConnection);
|
||||
await db.SaveChangesAsync();
|
||||
await passDb.AccountConnections.Add(newConnection);
|
||||
await passDb.SaveChangesAsync();
|
||||
|
||||
return newAccount;
|
||||
}
|
||||
|
@ -5,6 +5,8 @@ using DysonNetwork.Common.Services;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using NodaTime;
|
||||
using DysonNetwork.Common.Models;
|
||||
using DysonNetwork.Pass.Data;
|
||||
|
||||
namespace DysonNetwork.Pass.Features.Auth.OpenId;
|
||||
|
||||
@ -21,7 +23,7 @@ public abstract class OidcService(
|
||||
{
|
||||
protected readonly IConfiguration Configuration = configuration;
|
||||
protected readonly IHttpClientFactory HttpClientFactory = httpClientFactory;
|
||||
protected readonly AppDatabase Db = db;
|
||||
protected readonly PassDatabase Db = db;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the unique identifier for this provider
|
||||
|
@ -14,7 +14,7 @@ using NodaTime.Serialization.SystemTextJson;
|
||||
using System.Text;
|
||||
using DysonNetwork.Pass.Email;
|
||||
using DysonNetwork.Pass.Developer;
|
||||
using DysonNetwork.Pass.Features.Account.DysonNetwork.Pass.Features.Account;
|
||||
using DysonNetwork.Pass.Features.Account;
|
||||
using DysonNetwork.Pass.Features.Account.Services;
|
||||
using DysonNetwork.Pass.Permission;
|
||||
using Quartz;
|
||||
|
Reference in New Issue
Block a user