Add whitelisting and admin

This commit is contained in:
2025-11-07 23:46:48 +07:00
parent 21110cd771
commit e0795677e4
17 changed files with 2280 additions and 10 deletions

View File

@@ -1,4 +1,6 @@
using Managing.Application.Abstractions.Repositories;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace Managing.Application.Shared;
@@ -13,11 +15,16 @@ public class AdminConfigurationService : IAdminConfigurationService
{
private readonly IConfiguration _configuration;
private readonly ILogger<AdminConfigurationService> _logger;
private readonly IServiceScopeFactory _serviceScopeFactory;
public AdminConfigurationService(IConfiguration configuration, ILogger<AdminConfigurationService> logger)
public AdminConfigurationService(
IConfiguration configuration,
ILogger<AdminConfigurationService> logger,
IServiceScopeFactory serviceScopeFactory)
{
_configuration = configuration;
_logger = logger;
_serviceScopeFactory = serviceScopeFactory;
}
public bool IsUserAdmin(string userName)
@@ -27,15 +34,37 @@ public class AdminConfigurationService : IAdminConfigurationService
return false;
}
// First check configuration (for backward compatibility)
var adminUserNames = GetAdminUserNames();
var isAdmin = adminUserNames.Contains(userName, StringComparer.OrdinalIgnoreCase);
var isAdminFromConfig = adminUserNames.Contains(userName, StringComparer.OrdinalIgnoreCase);
if (isAdmin)
if (isAdminFromConfig)
{
_logger.LogInformation("User {UserName} has admin privileges", userName);
_logger.LogInformation("User {UserName} has admin privileges from configuration", userName);
return true;
}
// If not in config, check database User.IsAdmin flag
try
{
using var scope = _serviceScopeFactory.CreateScope();
var userRepository = scope.ServiceProvider.GetRequiredService<IUserRepository>();
var user = userRepository.GetUserByNameAsync(userName).GetAwaiter().GetResult();
if (user != null && user.IsAdmin)
{
_logger.LogInformation("User {UserName} has admin privileges from database", userName);
return true;
}
}
catch (Exception ex)
{
_logger.LogWarning(ex, "Error checking admin status for user {UserName} from database", userName);
// If database check fails, fall back to config-only result
}
return isAdmin;
return false;
}
public List<string> GetAdminUserNames()

View File

@@ -18,6 +18,7 @@ public class UserService : IUserService
private readonly ILogger<UserService> _logger;
private readonly ICacheService _cacheService;
private readonly IGrainFactory _grainFactory;
private readonly IWhitelistService _whitelistService;
private readonly string[] _authorizedAddresses;
public UserService(
@@ -27,6 +28,7 @@ public class UserService : IUserService
ILogger<UserService> logger,
ICacheService cacheService,
IGrainFactory grainFactory,
IWhitelistService whitelistService,
IConfiguration configuration)
{
_evmManager = evmManager;
@@ -35,6 +37,7 @@ public class UserService : IUserService
_logger = logger;
_cacheService = cacheService;
_grainFactory = grainFactory;
_whitelistService = whitelistService;
var authorizedAddressesString = configuration["AUTHORIZED_ADDRESSES"] ?? string.Empty;
_authorizedAddresses = string.IsNullOrEmpty(authorizedAddressesString)
@@ -54,9 +57,19 @@ public class UserService : IUserService
$"Message not good : {message} - Address : {address} - User : {name} - Signature : {signature}");
}
if (!_authorizedAddresses.Any(a => string.Equals(a, recoveredAddress, StringComparison.OrdinalIgnoreCase)))
// Check if address is whitelisted first (skip authorized addresses check if whitelisted)
var isWhitelisted = await _whitelistService.IsEmbeddedWalletWhitelistedAsync(recoveredAddress);
if (!isWhitelisted)
{
throw new Exception($"Address {recoveredAddress} not authorized. Please wait for team approval.");
// Only check authorized addresses if not whitelisted
var isInAuthorizedAddresses = _authorizedAddresses.Any(a => string.Equals(a, recoveredAddress, StringComparison.OrdinalIgnoreCase));
if (!isInAuthorizedAddresses)
{
_logger.LogWarning("Address {Address} is not authorized and not whitelisted", recoveredAddress);
throw new Exception($"Address {recoveredAddress} not authorized. Please wait for team approval.");
}
}

View File

@@ -66,6 +66,18 @@ public class WhitelistService : IWhitelistService
return await _whitelistRepository.GetByIdAsync(id);
}
public async Task<bool> IsEmbeddedWalletWhitelistedAsync(string embeddedWallet)
{
if (string.IsNullOrWhiteSpace(embeddedWallet))
{
return false;
}
var account = await _whitelistRepository.GetByEmbeddedWalletAsync(embeddedWallet);
return account?.IsWhitelisted ?? false;
}
public async Task<WhitelistAccount> ProcessPrivyWebhookAsync(
string privyUserId,
long privyCreatedAt,
@@ -76,8 +88,8 @@ public class WhitelistService : IWhitelistService
_logger.LogInformation("Processing Privy webhook - PrivyId: {PrivyId}, Wallet: {Wallet}, ExternalEthereum: {ExternalEthereum}, Twitter: {Twitter}",
privyUserId, walletAddress, externalEthereumAccount ?? "null", twitterAccount ?? "null");
// Convert Unix timestamp to DateTime
var privyCreationDate = DateTimeOffset.FromUnixTimeSeconds(privyCreatedAt).DateTime;
// Convert Unix timestamp to UTC DateTime (PostgreSQL requires UTC)
var privyCreationDate = DateTimeOffset.FromUnixTimeSeconds(privyCreatedAt).UtcDateTime;
// Check if account already exists
var existing = await _whitelistRepository.GetByPrivyIdAsync(privyUserId) ??