Finished. Have at it.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
namespace RelayServer.Services;
|
||||
namespace RelayServer.Services.Core;
|
||||
|
||||
public sealed class CoreClientService
|
||||
{
|
||||
|
||||
@@ -1,6 +1,195 @@
|
||||
namespace RelayServer.Services;
|
||||
using System.Text.Json;
|
||||
using RelayServer.Models;
|
||||
using RelayServer.Services.Chat;
|
||||
using RelayServer.Services.Crypto;
|
||||
using SurrealDb.Net;
|
||||
|
||||
public class ServerBootstrapService
|
||||
namespace RelayServer.Services.Core;
|
||||
|
||||
public sealed class ServerBootstrapService
|
||||
{
|
||||
// TODO: Make channels dynamically addable
|
||||
// TODO: Add logic for channel types (ENUM)
|
||||
// TODO: Add logic for channel groups for future UI use
|
||||
|
||||
private readonly SurrealDbClient _db;
|
||||
private readonly CoreClientService _coreClient;
|
||||
private readonly ChannelCryptoService _cryptoService;
|
||||
|
||||
public ServerBootstrapService(
|
||||
SurrealDbClient db,
|
||||
CoreClientService coreClient,
|
||||
ChannelCryptoService cryptoService)
|
||||
{
|
||||
_db = db;
|
||||
_coreClient = coreClient;
|
||||
_cryptoService = cryptoService;
|
||||
}
|
||||
|
||||
public async Task InitializeAsync()
|
||||
{
|
||||
var keeper = await _coreClient.GetUserByUsernameAsync("Keeper317");
|
||||
var kira = await _coreClient.GetUserByUsernameAsync("Ru_Kira");
|
||||
var test = await _coreClient.GetUserByUsernameAsync("Test");
|
||||
|
||||
if (keeper is null || kira is null || test is null)
|
||||
throw new InvalidOperationException("One or more required users do not exist in RelayCore.");
|
||||
|
||||
if (!keeper.Licensed || !kira.Licensed || !test.Licensed)
|
||||
throw new InvalidOperationException("One or more required users are not licensed.");
|
||||
|
||||
Console.WriteLine($"Core verified user: {keeper.Username}");
|
||||
Console.WriteLine($"Core verified user: {kira.Username}");
|
||||
Console.WriteLine($"Core verified user: {test.Username}");
|
||||
|
||||
var server = await GetServerByNameAsync("Test Server");
|
||||
|
||||
if (server is null)
|
||||
{
|
||||
server = await _db.Create("servers", new Servers
|
||||
{
|
||||
Name = "Test Server",
|
||||
OwnerUserId = keeper.Id,
|
||||
CreatedAt = DateTime.UtcNow
|
||||
});
|
||||
|
||||
Console.WriteLine($"Server created: {ToJsonString(server)}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"Server already exists: {ToJsonString(server)}");
|
||||
}
|
||||
|
||||
await EnsureServerMemberAsync(keeper.Id, true);
|
||||
await EnsureServerMemberAsync(kira.Id, false);
|
||||
await EnsureServerMemberAsync(test.Id, false);
|
||||
|
||||
Console.WriteLine("Server members ensured.");
|
||||
|
||||
var channel = await EnsureChannelAsync("general", DateTime.UtcNow);
|
||||
var channel2 = await EnsureChannelAsync("files", DateTime.UtcNow.Subtract(new TimeSpan(0, 4, 0, 0)));
|
||||
var channel3 = await EnsureChannelAsync("welcome", DateTime.UtcNow.Subtract(new TimeSpan(1, 4, 4, 4)));
|
||||
var channel4 = await EnsureChannelAsync("voice-general", DateTime.UtcNow.Subtract(new TimeSpan(0, 2, 0, 0)));
|
||||
|
||||
Console.WriteLine($"Resolved channelId: {GetRecordId(channel.Id)}");
|
||||
Console.WriteLine($"Resolved channelId: {GetRecordId(channel2.Id)}");
|
||||
Console.WriteLine($"Resolved channelId: {GetRecordId(channel3.Id)}");
|
||||
Console.WriteLine($"Resolved channelId: {GetRecordId(channel4.Id)}");
|
||||
|
||||
var existingKey = await GetLatestServerEncryptionKeyAsync();
|
||||
|
||||
if (existingKey is null)
|
||||
{
|
||||
var keyBase64 = _cryptoService.GenerateKey();
|
||||
var serverKeys = E2EeHelper.GenerateRsaKeyPair();
|
||||
|
||||
existingKey = await _db.Create("server_encryption_keys", new ServerEncryptionKeys
|
||||
{
|
||||
KeyBase64 = keyBase64,
|
||||
PublicKey = serverKeys.publicKey,
|
||||
PrivateKey = serverKeys.privateKey,
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
UpdatedAt = DateTime.UtcNow
|
||||
});
|
||||
|
||||
Console.WriteLine("Server encryption key created.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Server encryption key already exists.");
|
||||
}
|
||||
|
||||
ChatSocketBehavior.ServerPublicKey = existingKey.PublicKey;
|
||||
ChatSocketBehavior.ServerPrivateKey = existingKey.PrivateKey;
|
||||
ChatSocketBehavior.ChannelDbKey = existingKey.KeyBase64;
|
||||
}
|
||||
|
||||
private static string ToJsonString(object? obj)
|
||||
{
|
||||
return JsonSerializer.Serialize(obj, new JsonSerializerOptions
|
||||
{
|
||||
WriteIndented = true,
|
||||
Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping
|
||||
});
|
||||
}
|
||||
|
||||
private static string GetRecordId(object? id)
|
||||
{
|
||||
if (id is null)
|
||||
return string.Empty;
|
||||
|
||||
var json = JsonSerializer.Serialize(id);
|
||||
|
||||
using var doc = JsonDocument.Parse(json);
|
||||
var root = doc.RootElement;
|
||||
|
||||
var recordId = root.GetProperty("Id").GetString() ?? string.Empty;
|
||||
var table = root.GetProperty("Table").GetString() ?? string.Empty;
|
||||
|
||||
return $"{table}:{recordId}";
|
||||
}
|
||||
|
||||
private async Task<Servers?> GetServerByNameAsync(string name)
|
||||
{
|
||||
var servers = await _db.Select<Servers>("servers");
|
||||
return servers.FirstOrDefault(x => x.Name == name);
|
||||
}
|
||||
|
||||
private async Task<ServerMembers?> GetServerMemberByUserIdAsync(string userId)
|
||||
{
|
||||
var members = await _db.Select<ServerMembers>("server_members");
|
||||
return members.FirstOrDefault(x => x.UserId == userId);
|
||||
}
|
||||
|
||||
private async Task<Channels?> GetChannelByNameAsync(string name)
|
||||
{
|
||||
var channels = await _db.Select<Channels>("channels");
|
||||
return channels.FirstOrDefault(x => x.Name == name);
|
||||
}
|
||||
|
||||
private async Task<ServerEncryptionKeys?> GetLatestServerEncryptionKeyAsync()
|
||||
{
|
||||
var keys = await _db.Select<ServerEncryptionKeys>("server_encryption_keys");
|
||||
return keys
|
||||
.OrderByDescending(x => x.CreatedAt)
|
||||
.FirstOrDefault();
|
||||
}
|
||||
|
||||
private async Task EnsureServerMemberAsync(string userId, bool isOwner)
|
||||
{
|
||||
var existing = await GetServerMemberByUserIdAsync(userId);
|
||||
if (existing is not null)
|
||||
{
|
||||
Console.WriteLine($"Server member already exists for {userId}");
|
||||
return;
|
||||
}
|
||||
|
||||
await _db.Create("server_members", new ServerMembers
|
||||
{
|
||||
UserId = userId,
|
||||
JoinedAt = DateTime.UtcNow,
|
||||
IsOwner = isOwner
|
||||
});
|
||||
|
||||
Console.WriteLine($"Server member created for {userId}");
|
||||
}
|
||||
|
||||
private async Task<Channels> EnsureChannelAsync(string name, DateTime createdAt)
|
||||
{
|
||||
var existing = await GetChannelByNameAsync(name);
|
||||
if (existing is not null)
|
||||
{
|
||||
Console.WriteLine($"Channel already exists: {name}");
|
||||
return existing;
|
||||
}
|
||||
|
||||
var channel = await _db.Create("channels", new Channels
|
||||
{
|
||||
Name = name,
|
||||
CreatedAt = createdAt
|
||||
});
|
||||
|
||||
Console.WriteLine($"Channel created: {ToJsonString(channel)}");
|
||||
return channel;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user