[optimize] Merge user logic to service

This commit is contained in:
acite
2025-10-02 18:47:15 +08:00
parent db58091814
commit dcdd9d840e
3 changed files with 85 additions and 75 deletions

View File

@@ -11,6 +11,8 @@
<component name="ChangeListManager"> <component name="ChangeListManager">
<list default="true" id="bf317275-3039-49bb-a475-725a800a0cce" name="Changes" comment=""> <list default="true" id="bf317275-3039-49bb-a475-725a800a0cce" name="Changes" comment="">
<change beforePath="$PROJECT_DIR$/.idea/.idea.Abyss/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/.idea.Abyss/.idea/workspace.xml" afterDir="false" /> <change beforePath="$PROJECT_DIR$/.idea/.idea.Abyss/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/.idea.Abyss/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Abyss/Components/Controllers/Security/UserController.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Abyss/Components/Controllers/Security/UserController.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Abyss/Components/Services/Security/UserService.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Abyss/Components/Services/Security/UserService.cs" afterDir="false" />
</list> </list>
<option name="SHOW_DIALOG" value="false" /> <option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" /> <option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -250,6 +252,8 @@
<workItem from="1759137056827" duration="1026000" /> <workItem from="1759137056827" duration="1026000" />
<workItem from="1759150007653" duration="169000" /> <workItem from="1759150007653" duration="169000" />
<workItem from="1759314718830" duration="55000" /> <workItem from="1759314718830" duration="55000" />
<workItem from="1759315721112" duration="82000" />
<workItem from="1759398581423" duration="2195000" />
</task> </task>
<servers /> <servers />
</component> </component>

View File

@@ -20,110 +20,52 @@ public class UserController(UserService userService, ILogger<UserController> log
public async Task<IActionResult> Challenge(string user) public async Task<IActionResult> Challenge(string user)
{ {
var c = await userService.Challenge(user); var c = await userService.Challenge(user);
if (c == null) return c != null ? Ok(c): _403;
return _403;
return Ok(c);
} }
[HttpPost("{user}")] [HttpPost("{user}")]
public async Task<IActionResult> Challenge(string user, [FromBody] ChallengeResponse response) public async Task<IActionResult> Challenge(string user, [FromBody] ChallengeResponse response)
{ {
var r = await userService.Verify(user, response.Response, Ip); var r = await userService.Verify(user, response.Response, Ip);
if (r == null) if (r != null)
return _403; {
Response.Cookies.Append("token", r); Response.Cookies.Append("token", r);
return Ok(r); return Ok(r);
} }
return _403;
}
[HttpPost("validate")] [HttpPost("validate")]
public IActionResult Validate(string token) public IActionResult Validate(string token)
{ {
var u = userService.Validate(token, Ip); var u = userService.Validate(token, Ip);
if (u == -1) return u == -1 ? _401 : Ok(u);
{
return _401;
}
return Ok(u);
} }
[HttpPost("destroy")] [HttpPost("destroy")]
public IActionResult Destroy(string token) public IActionResult Destroy(string token)
{ {
var u = userService.Validate(token, Ip); var u = userService.Validate(token, Ip);
if (u == -1) if (u != -1)
{ {
return _401;
}
userService.Destroy(token); userService.Destroy(token);
return Ok("Success"); return Ok("Success");
} }
return _401;
}
[HttpPatch("{user}")] [HttpPatch("{user}")]
public async Task<IActionResult> Create(string user, [FromBody] UserCreating creating) public async Task<IActionResult> Create(string user, [FromBody] UserCreating creating)
{ {
// Valid token bool r = await userService.CreateUserAsync(user, creating, Ip);
var r = await userService.Verify(user, creating.Response, Ip); return r ? Ok("Success") : _403;
if (r == null)
return _403;
// User exists ?
var cu = await userService.QueryUser(creating.Name);
if (cu != null)
return _403;
// Valid username string
if (!IsAlphanumeric(creating.Name))
return _403;
// Valid parent && Privilege
var ou = await userService.QueryUser(userService.Validate(r, Ip));
if (creating.Privilege > ou?.Privilege || ou == null)
return _403;
await userService.CreateUser(new User
{
Username = creating.Name,
ParentId = ou.Uuid,
Privilege = creating.Privilege,
PublicKey = creating.PublicKey,
});
userService.Destroy(r);
return Ok("Success");
} }
[HttpGet("{user}/open")] [HttpGet("{user}/open")]
public async Task<IActionResult> Open(string user, [FromQuery] string token, [FromQuery] string? bindIp = null) public async Task<IActionResult> Open(string user, [FromQuery] string token, [FromQuery] string? bindIp = null)
{ {
var caller = userService.Validate(token, Ip); string? r = await userService.OpenUserAsync(user, token, bindIp, Ip);
if (caller != 1) return r != null ? Ok(r) : _403;
{
return _403;
}
var target = await userService.QueryUser(user);
if (target == null)
{
return _403;
}
var ipToBind = string.IsNullOrWhiteSpace(bindIp) ? Ip : bindIp;
var t = userService.CreateToken(target.Uuid, ipToBind, TimeSpan.FromHours(1));
logger.LogInformation("Root created 1h token for {User}, bound to {BindIp}, request from {ReqIp}", user,
ipToBind, Ip);
return Ok(new { token = t, user, boundIp = ipToBind });
}
public static bool IsAlphanumeric(string input)
{
if (string.IsNullOrEmpty(input))
return false;
return Regex.IsMatch(input, @"^[a-zA-Z0-9]+$");
} }
} }

View File

@@ -3,6 +3,7 @@
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Text; using System.Text;
using System.Text.RegularExpressions;
using Abyss.Components.Services.Misc; using Abyss.Components.Services.Misc;
using Abyss.Model.Security; using Abyss.Model.Security;
using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Caching.Memory;
@@ -17,7 +18,6 @@ public class UserService
private readonly ILogger<UserService> _logger; private readonly ILogger<UserService> _logger;
private readonly IMemoryCache _cache; private readonly IMemoryCache _cache;
private readonly SQLiteAsyncConnection _database; private readonly SQLiteAsyncConnection _database;
public UserService(ILogger<UserService> logger, ConfigureService config, IMemoryCache cache) public UserService(ILogger<UserService> logger, ConfigureService config, IMemoryCache cache)
{ {
_logger = logger; _logger = logger;
@@ -59,6 +59,62 @@ public class UserService
Console.ReadKey(); Console.ReadKey();
} }
} }
public async Task<string?> OpenUserAsync(string user, string token, string? bindIp, string ip)
{
var caller = Validate(token, ip);
if (caller != 1)
{
return null;
}
var target = await QueryUser(user);
if (target == null)
{
return null;
}
var ipToBind = string.IsNullOrWhiteSpace(bindIp) ? ip : bindIp;
var t = CreateToken(target.Uuid, ipToBind, TimeSpan.FromHours(1));
_logger.LogInformation("Root created 1h token for {User}, bound to {BindIp}, request from {ReqIp}", user,
ipToBind, ip);
return t;
}
public async Task<bool> CreateUserAsync(string user, UserCreating creating, string ip)
{
// Valid token
var r = await Verify(user, creating.Response, ip);
if (r == null)
return false;
// User exists ?
var cu = await QueryUser(creating.Name);
if (cu != null)
return false;
// Valid username string
if (!IsAlphanumeric(creating.Name))
return false;
// Valid parent && Privilege
var ou = await QueryUser(Validate(r, ip));
if (creating.Privilege > ou?.Privilege || ou == null)
return false;
await CreateUser(new User
{
Username = creating.Name,
ParentId = ou.Uuid,
Privilege = creating.Privilege,
PublicKey = creating.PublicKey,
});
Destroy(r);
return true;
}
public async Task<string?> Challenge(string user) public async Task<string?> Challenge(string user)
{ {
var u = await _database.Table<User>().Where(x => x.Username == user).FirstOrDefaultAsync(); var u = await _database.Table<User>().Where(x => x.Username == user).FirstOrDefaultAsync();
@@ -226,4 +282,12 @@ public class UserService
_logger.LogInformation($"Created token for {uid}@{ip}, valid {lifetime.TotalMinutes} minutes"); _logger.LogInformation($"Created token for {uid}@{ip}, valid {lifetime.TotalMinutes} minutes");
return token; return token;
} }
public static bool IsAlphanumeric(string input)
{
if (string.IsNullOrEmpty(input))
return false;
return Regex.IsMatch(input, @"^[a-zA-Z0-9]+$");
}
} }