mirror of
https://github.com/RedWizardsLab/EchoHub.git
synced 2026-09-04 08:36:11 +02:00
feat: implement user registration and update SASL authentication handling
This commit is contained in:
@@ -4,6 +4,9 @@ Release history for EchoHub.
|
|||||||
|
|
||||||
## Releases
|
## Releases
|
||||||
|
|
||||||
|
- [v0.2.8](v0.2.8.md) - Docker Support, IRC Account Creation & BOM Fix
|
||||||
|
- [v0.2.7](v0.2.7.md) - User List Fix & Terminal.Gui NuGet Migration
|
||||||
|
- [v0.2.6](v0.2.6.md) - Major Refactoring & Code Organization
|
||||||
- [v0.2.5](v0.2.5.md) - Session Persistence, Auto-Updates, Audio & Transparent Theme
|
- [v0.2.5](v0.2.5.md) - Session Persistence, Auto-Updates, Audio & Transparent Theme
|
||||||
- [v0.2.4](v0.2.4.md) - E2E Message Encryption
|
- [v0.2.4](v0.2.4.md) - E2E Message Encryption
|
||||||
- [v0.2.3](v0.2.3.md) - Moderation, Embeds & UI Overhaul
|
- [v0.2.3](v0.2.3.md) - Moderation, Embeds & UI Overhaul
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
- name: Overview
|
- name: Overview
|
||||||
href: index.md
|
href: index.md
|
||||||
|
- name: v0.2.8
|
||||||
|
href: v0.2.8.md
|
||||||
- name: v0.2.7
|
- name: v0.2.7
|
||||||
href: v0.2.7.md
|
href: v0.2.7.md
|
||||||
- name: v0.2.6
|
- name: v0.2.6
|
||||||
|
|||||||
@@ -4,14 +4,6 @@
|
|||||||
|
|
||||||
- Fix user list empty on initial connect — `FetchAndUpdateOnlineUsers` was called before `InvokeUI` set the current channel, causing an early return
|
- Fix user list empty on initial connect — `FetchAndUpdateOnlineUsers` was called before `InvokeUI` set the current channel, causing an early return
|
||||||
|
|
||||||
## New Features
|
|
||||||
|
|
||||||
- Add Docker support for EchoHub.Server — `docker compose up -d` for easy self-hosting with persistent volume for database, uploads, and logs
|
|
||||||
|
|
||||||
## CI
|
|
||||||
|
|
||||||
- Add Docker workflow — builds and pushes multi-arch (`amd64`/`arm64`) server image to GHCR on release
|
|
||||||
|
|
||||||
## Infrastructure
|
## Infrastructure
|
||||||
|
|
||||||
- Switch Terminal.Gui from local fork submodule back to NuGet package (`2.0.0-develop.5039`) — transparent color PR merged upstream
|
- Switch Terminal.Gui from local fork submodule back to NuGet package (`2.0.0-develop.5039`) — transparent color PR merged upstream
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
# v0.2.8
|
||||||
|
|
||||||
|
## Bug Fixes
|
||||||
|
|
||||||
|
- Fix IRC gateway sending UTF-8 BOM on first message, breaking CAP negotiation and SASL auth for all clients
|
||||||
|
- Handle `AUTHENTICATE *` (SASL abort) instead of crashing on invalid base64
|
||||||
|
|
||||||
|
## New Features
|
||||||
|
|
||||||
|
- Add Docker support for EchoHub.Server — `docker compose up -d` for easy self-hosting with persistent volume for database, uploads, and logs
|
||||||
|
- IRC account creation — connecting with a new username auto-registers the account (PASS and SASL PLAIN)
|
||||||
|
|
||||||
|
## CI
|
||||||
|
|
||||||
|
- Add Docker workflow — builds and pushes multi-arch (`amd64`/`arm64`) server image to GHCR on release
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<Project>
|
<Project>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Version>0.2.7</Version>
|
<Version>0.2.8</Version>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
<NoWarn>$(NoWarn);CS1591</NoWarn>
|
<NoWarn>$(NoWarn);CS1591</NoWarn>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
@@ -29,4 +29,5 @@ public interface IChatService
|
|||||||
Task<UserProfileDto?> GetUserProfileAsync(string username);
|
Task<UserProfileDto?> GetUserProfileAsync(string username);
|
||||||
Task<List<string>> GetChannelsForUserAsync(string username);
|
Task<List<string>> GetChannelsForUserAsync(string username);
|
||||||
Task<(Guid UserId, string Username)?> AuthenticateUserAsync(string username, string password);
|
Task<(Guid UserId, string Username)?> AuthenticateUserAsync(string username, string password);
|
||||||
|
Task<(Guid UserId, string Username)?> RegisterUserAsync(string username, string password);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -170,9 +170,13 @@ public sealed class IrcCommandHandler
|
|||||||
|
|
||||||
var result = await _chatService.AuthenticateUserAsync(username, password);
|
var result = await _chatService.AuthenticateUserAsync(username, password);
|
||||||
|
|
||||||
|
// Auth failed — try registering a new account
|
||||||
|
if (result is null)
|
||||||
|
result = await _chatService.RegisterUserAsync(username, password);
|
||||||
|
|
||||||
if (result is null)
|
if (result is null)
|
||||||
{
|
{
|
||||||
_logger.LogWarning("SASL auth failed for user '{Username}' (connection {Id})",
|
_logger.LogWarning("SASL auth/register failed for user '{Username}' (connection {Id})",
|
||||||
username, _conn.ConnectionId);
|
username, _conn.ConnectionId);
|
||||||
await _conn.SendNumericAsync(ServerName, IrcNumericReply.ERR_SASLFAIL,
|
await _conn.SendNumericAsync(ServerName, IrcNumericReply.ERR_SASLFAIL,
|
||||||
":SASL authentication failed");
|
":SASL authentication failed");
|
||||||
@@ -286,10 +290,14 @@ public sealed class IrcCommandHandler
|
|||||||
|
|
||||||
var result = await _chatService.AuthenticateUserAsync(_conn.Nickname!, _conn.Password);
|
var result = await _chatService.AuthenticateUserAsync(_conn.Nickname!, _conn.Password);
|
||||||
|
|
||||||
|
// Auth failed — try registering a new account
|
||||||
|
if (result is null)
|
||||||
|
result = await _chatService.RegisterUserAsync(_conn.Nickname!, _conn.Password);
|
||||||
|
|
||||||
if (result is null)
|
if (result is null)
|
||||||
{
|
{
|
||||||
await _conn.SendNumericAsync(ServerName, IrcNumericReply.ERR_PASSWDMISMATCH,
|
await _conn.SendNumericAsync(ServerName, IrcNumericReply.ERR_PASSWDMISMATCH,
|
||||||
":Password incorrect or account not found. Register via the EchoHub client first.");
|
":Password incorrect.");
|
||||||
await _conn.SendAsync("ERROR :Authentication failed");
|
await _conn.SendAsync("ERROR :Authentication failed");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -339,6 +339,38 @@ public class ChatService : IChatService
|
|||||||
return (user.Id, user.Username);
|
return (user.Id, user.Username);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<(Guid UserId, string Username)?> RegisterUserAsync(string username, string password)
|
||||||
|
{
|
||||||
|
username = username.ToLowerInvariant().Trim();
|
||||||
|
|
||||||
|
if (!ValidationConstants.UsernameRegex().IsMatch(username))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
if (password.Length < 6 || password.Length > ValidationConstants.MaxPasswordLength)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
using var scope = _scopeFactory.CreateScope();
|
||||||
|
var db = scope.ServiceProvider.GetRequiredService<EchoHubDbContext>();
|
||||||
|
|
||||||
|
if (await db.Users.AnyAsync(u => u.Username == username))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var isFirstUser = !await db.Users.AnyAsync();
|
||||||
|
|
||||||
|
var user = new User
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
Username = username,
|
||||||
|
PasswordHash = BCrypt.Net.BCrypt.HashPassword(password),
|
||||||
|
Role = isFirstUser ? ServerRole.Owner : ServerRole.Member,
|
||||||
|
};
|
||||||
|
|
||||||
|
db.Users.Add(user);
|
||||||
|
await db.SaveChangesAsync();
|
||||||
|
|
||||||
|
return (user.Id, user.Username);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Collapse consecutive newlines and cap total line count to prevent newline spam.
|
/// Collapse consecutive newlines and cap total line count to prevent newline spam.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
Reference in New Issue
Block a user