BTCPay-infrastructure-recovery

This commit is contained in:
sysadmin
2025-09-04 21:28:47 +01:00
parent b4cee007c4
commit be4d797c6c
22 changed files with 1552 additions and 101 deletions

View File

@@ -38,20 +38,29 @@ public class AccountController : Controller
return View();
}
if (username == "admin" && password == "admin")
// Use AuthService to validate against database users
var loginDto = new LoginDto { Username = username, Password = password };
var authResponse = await _authService.LoginAsync(loginDto);
if (authResponse != null)
{
var claims = new List<Claim>
// Get the actual user from database to get correct ID
var user = await _authService.GetUserByUsernameAsync(username);
if (user != null)
{
new(ClaimTypes.Name, "admin"),
new(ClaimTypes.NameIdentifier, Guid.NewGuid().ToString()),
new(ClaimTypes.Role, "Admin")
};
var claims = new List<Claim>
{
new(ClaimTypes.Name, user.Username),
new(ClaimTypes.NameIdentifier, user.Id.ToString()), // Use real database ID
new(ClaimTypes.Role, "Admin") // All users in admin system are admins
};
var identity = new ClaimsIdentity(claims, "Cookies");
var principal = new ClaimsPrincipal(identity);
var identity = new ClaimsIdentity(claims, "Cookies");
var principal = new ClaimsPrincipal(identity);
await HttpContext.SignInAsync("Cookies", principal);
return RedirectToAction("Index", "Dashboard");
await HttpContext.SignInAsync("Cookies", principal);
return RedirectToAction("Index", "Dashboard");
}
}
ModelState.AddModelError("", "Invalid username or password");

View File

@@ -30,19 +30,28 @@ public class UsersController : Controller
[HttpPost]
public async Task<IActionResult> Create(CreateUserDto model)
{
if (!ModelState.IsValid)
try
{
if (!ModelState.IsValid)
{
return View(model);
}
var user = await _authService.CreateUserAsync(model);
if (user == null)
{
ModelState.AddModelError("Username", "User with this username already exists");
return View(model);
}
TempData["SuccessMessage"] = $"User '{user.Username}' created successfully";
return RedirectToAction(nameof(Index));
}
catch (Exception ex)
{
ModelState.AddModelError("", "An error occurred while creating the user: " + ex.Message);
return View(model);
}
var user = await _authService.CreateUserAsync(model);
if (user == null)
{
ModelState.AddModelError("", "User with this username already exists");
return View(model);
}
return RedirectToAction(nameof(Index));
}
public async Task<IActionResult> Edit(Guid id)
@@ -66,25 +75,89 @@ public class UsersController : Controller
[HttpPost]
public async Task<IActionResult> Edit(Guid id, UpdateUserDto model)
{
if (!ModelState.IsValid)
try
{
// Additional validation for required username
if (string.IsNullOrWhiteSpace(model.Username))
{
ModelState.AddModelError("Username", "Username is required");
}
// Validate password if provided
if (!string.IsNullOrEmpty(model.Password) && model.Password.Length < 3)
{
ModelState.AddModelError("Password", "Password must be at least 3 characters if changing");
}
if (!ModelState.IsValid)
{
ViewData["UserId"] = id;
return View(model);
}
var success = await _authService.UpdateUserAsync(id, model);
if (!success)
{
// Check if it's because of duplicate username
var existingUser = await _authService.GetUserByIdAsync(id);
if (existingUser == null)
{
return NotFound();
}
ModelState.AddModelError("Username", "Username is already taken by another user");
ViewData["UserId"] = id;
return View(model);
}
TempData["SuccessMessage"] = "User updated successfully";
return RedirectToAction(nameof(Index));
}
catch (Exception ex)
{
ModelState.AddModelError("", "An error occurred while updating the user: " + ex.Message);
ViewData["UserId"] = id;
return View(model);
}
var success = await _authService.UpdateUserAsync(id, model);
if (!success)
{
return NotFound();
}
return RedirectToAction(nameof(Index));
}
[HttpPost]
public async Task<IActionResult> Delete(Guid id)
{
await _authService.DeleteUserAsync(id);
return RedirectToAction(nameof(Index));
try
{
// Prevent admin user from deleting themselves
var currentUserIdClaim = User.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value;
if (Guid.TryParse(currentUserIdClaim, out Guid currentUserId) && currentUserId == id)
{
TempData["ErrorMessage"] = "You cannot delete your own account";
return RedirectToAction(nameof(Index));
}
// Get user info for confirmation message
var user = await _authService.GetUserByIdAsync(id);
if (user == null)
{
TempData["ErrorMessage"] = "User not found";
return RedirectToAction(nameof(Index));
}
var success = await _authService.DeleteUserAsync(id);
if (success)
{
TempData["SuccessMessage"] = $"User '{user.Username}' has been deactivated";
}
else
{
TempData["ErrorMessage"] = "Failed to delete user";
}
return RedirectToAction(nameof(Index));
}
catch (Exception ex)
{
TempData["ErrorMessage"] = "An error occurred while deleting the user: " + ex.Message;
return RedirectToAction(nameof(Index));
}
}
}

View File

@@ -0,0 +1,82 @@
@model LittleShop.DTOs.UpdateUserDto
@{
ViewData["Title"] = "Edit User";
var userId = ViewData["UserId"] as Guid?;
}
<div class="row mb-4">
<div class="col">
<h1><i class="fas fa-user-edit"></i> Edit User</h1>
</div>
</div>
<div class="row">
<div class="col-md-8">
<div class="card">
<div class="card-body">
<form method="post" asp-area="Admin" asp-controller="Users" asp-action="Edit" asp-route-id="@userId">
@Html.AntiForgeryToken()
@if (ViewData.ModelState[""] != null && ViewData.ModelState[""].Errors.Count > 0)
{
<div class="alert alert-danger" role="alert">
@foreach (var error in ViewData.ModelState[""].Errors)
{
<div>@error.ErrorMessage</div>
}
</div>
}
<div class="mb-3">
<label for="Username" class="form-label">Username</label>
<input name="Username" id="Username" class="form-control" value="@Model?.Username" required />
<div class="form-text">Must be unique across all users</div>
</div>
<div class="mb-3">
<label for="Password" class="form-label">New Password</label>
<input name="Password" id="Password" type="password" class="form-control" />
<div class="form-text">Leave blank to keep current password. Minimum 3 characters if changing.</div>
</div>
<div class="mb-3 form-check">
<input name="IsActive" id="IsActive" type="checkbox" class="form-check-input" value="true" @(Model?.IsActive == true ? "checked" : "") />
<input name="IsActive" type="hidden" value="false" />
<label for="IsActive" class="form-check-label">
User is active (can log in)
</label>
</div>
<div class="d-flex justify-content-between">
<a href="@Url.Action("Index")" class="btn btn-secondary">
<i class="fas fa-arrow-left"></i> Back to Users
</a>
<button type="submit" class="btn btn-primary">
<i class="fas fa-save"></i> Update User
</button>
</div>
</form>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card">
<div class="card-header">
<h5><i class="fas fa-info-circle"></i> Edit Information</h5>
</div>
<div class="card-body">
<ul class="list-unstyled">
<li><strong>Username:</strong> Can be changed if unique</li>
<li><strong>Password:</strong> Optional - leave blank to keep current</li>
<li><strong>Status:</strong> Inactive users cannot log in</li>
</ul>
<div class="alert alert-warning mt-3">
<i class="fas fa-exclamation-triangle"></i>
<strong>Warning:</strong> Deactivating your own account will lock you out.
</div>
</div>
</div>
</div>
</div>

View File

@@ -15,6 +15,22 @@
</div>
</div>
@if (TempData["SuccessMessage"] != null)
{
<div class="alert alert-success alert-dismissible fade show" role="alert">
<i class="fas fa-check-circle"></i> @TempData["SuccessMessage"]
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
}
@if (TempData["ErrorMessage"] != null)
{
<div class="alert alert-danger alert-dismissible fade show" role="alert">
<i class="fas fa-exclamation-circle"></i> @TempData["ErrorMessage"]
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
}
<div class="card">
<div class="card-body">
@if (Model.Any())