♻️ Refactored the authorized device (now client)
This commit is contained in:
@@ -68,7 +68,7 @@ public class AuthController(
|
||||
IpAddress = ipAddress,
|
||||
UserAgent = userAgent,
|
||||
Location = geo.GetPointFromIp(ipAddress),
|
||||
DeviceId = device.Id,
|
||||
ClientId = device.Id,
|
||||
AccountId = account.Id
|
||||
}.Normalize();
|
||||
|
||||
|
@@ -1,17 +0,0 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Text.Json.Serialization;
|
||||
using DysonNetwork.Shared.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace DysonNetwork.Pass.Auth;
|
||||
|
||||
[Index(nameof(DeviceId), IsUnique = true)]
|
||||
public class AuthDevice : ModelBase
|
||||
{
|
||||
public Guid Id { get; set; } = Guid.NewGuid();
|
||||
[MaxLength(1024)] public string DeviceName { get; set; } = string.Empty;
|
||||
[MaxLength(1024)] public string DeviceId { get; set; } = string.Empty;
|
||||
|
||||
public Guid AccountId { get; set; }
|
||||
[JsonIgnore] public Account.Account Account { get; set; } = null!;
|
||||
}
|
@@ -100,17 +100,17 @@ public class AuthService(
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
public async Task<AuthDevice> GetOrCreateDeviceAsync(Guid accountId, string deviceId)
|
||||
|
||||
public async Task<AuthClient> GetOrCreateDeviceAsync(Guid accountId, string deviceId)
|
||||
{
|
||||
var device = await db.AuthDevices.FirstOrDefaultAsync(d => d.DeviceId == deviceId && d.AccountId == accountId);
|
||||
var device = await db.AuthClients.FirstOrDefaultAsync(d => d.DeviceId == deviceId && d.AccountId == accountId);
|
||||
if (device is not null) return device;
|
||||
device = new AuthDevice
|
||||
device = new AuthClient
|
||||
{
|
||||
DeviceId = deviceId,
|
||||
AccountId = accountId
|
||||
};
|
||||
db.AuthDevices.Add(device);
|
||||
db.AuthClients.Add(device);
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
return device;
|
||||
@@ -203,43 +203,43 @@ public class AuthService(
|
||||
// Check if the session is already in sudo mode (cached)
|
||||
var sudoModeKey = $"accounts:{session.Id}:sudo";
|
||||
var (found, _) = await cache.GetAsyncWithStatus<bool>(sudoModeKey);
|
||||
|
||||
|
||||
if (found)
|
||||
{
|
||||
// Session is already in sudo mode
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Check if the user has a pin code
|
||||
var hasPinCode = await db.AccountAuthFactors
|
||||
.Where(f => f.AccountId == session.AccountId)
|
||||
.Where(f => f.EnabledAt != null)
|
||||
.Where(f => f.Type == AccountAuthFactorType.PinCode)
|
||||
.AnyAsync();
|
||||
|
||||
|
||||
if (!hasPinCode)
|
||||
{
|
||||
// User doesn't have a pin code, no validation needed
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// If pin code is not provided, we can't validate
|
||||
if (string.IsNullOrEmpty(pinCode))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
// Validate the pin code
|
||||
var isValid = await ValidatePinCode(session.AccountId, pinCode);
|
||||
|
||||
|
||||
if (isValid)
|
||||
{
|
||||
// Set session in sudo mode for 5 minutes
|
||||
await cache.SetAsync(sudoModeKey, true, TimeSpan.FromMinutes(5));
|
||||
}
|
||||
|
||||
|
||||
return isValid;
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
@@ -316,4 +316,4 @@ public class AuthService(
|
||||
|
||||
return Convert.FromBase64String(padded);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -2,6 +2,7 @@ using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Text.Json.Serialization;
|
||||
using DysonNetwork.Shared.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NodaTime;
|
||||
using NodaTime.Serialization.Protobuf;
|
||||
using Point = NetTopologySuite.Geometries.Point;
|
||||
@@ -68,12 +69,13 @@ public class AuthChallenge : ModelBase
|
||||
[MaxLength(128)] public string? IpAddress { get; set; }
|
||||
[MaxLength(512)] public string? UserAgent { get; set; }
|
||||
[MaxLength(1024)] public string? Nonce { get; set; }
|
||||
[MaxLength(1024)] public string? DeviceId { get; set; } = string.Empty;
|
||||
public Point? Location { get; set; }
|
||||
|
||||
public Guid AccountId { get; set; }
|
||||
[JsonIgnore] public Account.Account Account { get; set; } = null!;
|
||||
public Guid DeviceId { get; set; }
|
||||
public AuthDevice Device { get; set; } = null!;
|
||||
public Guid? ClientId { get; set; }
|
||||
public AuthClient? Client { get; set; } = null!;
|
||||
|
||||
public AuthChallenge Normalize()
|
||||
{
|
||||
@@ -95,8 +97,20 @@ public class AuthChallenge : ModelBase
|
||||
Scopes = { Scopes },
|
||||
IpAddress = IpAddress,
|
||||
UserAgent = UserAgent,
|
||||
DeviceId = DeviceId.ToString(),
|
||||
DeviceId = Client.DeviceId.ToString(),
|
||||
Nonce = Nonce,
|
||||
AccountId = AccountId.ToString()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[Index(nameof(DeviceId), IsUnique = true)]
|
||||
public class AuthClient : ModelBase
|
||||
{
|
||||
public Guid Id { get; set; } = Guid.NewGuid();
|
||||
[MaxLength(1024)] public string DeviceName { get; set; } = string.Empty;
|
||||
[MaxLength(1024)] public string? DeviceLabel { get; set; }
|
||||
[MaxLength(1024)] public string DeviceId { get; set; } = string.Empty;
|
||||
|
||||
public Guid AccountId { get; set; }
|
||||
[JsonIgnore] public Account.Account Account { get; set; } = null!;
|
||||
}
|
@@ -227,7 +227,7 @@ public abstract class OidcService(
|
||||
Audiences = [ProviderName],
|
||||
Scopes = ["*"],
|
||||
AccountId = account.Id,
|
||||
DeviceId = device.Id,
|
||||
ClientId = device.Id,
|
||||
IpAddress = request.Connection.RemoteIpAddress?.ToString() ?? null,
|
||||
UserAgent = request.Request.Headers.UserAgent,
|
||||
};
|
||||
|
Reference in New Issue
Block a user