diff --git a/.dockerignore b/.dockerignore
deleted file mode 100644
index cd967fc..0000000
--- a/.dockerignore
+++ /dev/null
@@ -1,25 +0,0 @@
-**/.dockerignore
-**/.env
-**/.git
-**/.gitignore
-**/.project
-**/.settings
-**/.toolstarget
-**/.vs
-**/.vscode
-**/.idea
-**/*.*proj.user
-**/*.dbmdl
-**/*.jfm
-**/azds.yaml
-**/bin
-**/charts
-**/docker-compose*
-**/Dockerfile*
-**/node_modules
-**/npm-debug.log
-**/obj
-**/secrets.dev.yaml
-**/values.dev.yaml
-LICENSE
-README.md
\ No newline at end of file
diff --git a/Dockerfile b/Dockerfile
deleted file mode 100644
index d6dc02a..0000000
--- a/Dockerfile
+++ /dev/null
@@ -1,21 +0,0 @@
-FROM mcr.microsoft.com/dotnet/runtime:9.0 AS base
-USER $APP_UID
-WORKDIR /app
-
-FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
-ARG BUILD_CONFIGURATION=Release
-WORKDIR /src
-COPY ["RelayCore.csproj", "./"]
-RUN dotnet restore "RelayCore.csproj"
-COPY . .
-WORKDIR "/src/"
-RUN dotnet build "./RelayCore.csproj" -c $BUILD_CONFIGURATION -o /app/build
-
-FROM build AS publish
-ARG BUILD_CONFIGURATION=Release
-RUN dotnet publish "./RelayCore.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
-
-FROM base AS final
-WORKDIR /app
-COPY --from=publish /app/publish .
-ENTRYPOINT ["dotnet", "RelayCore.dll"]
diff --git a/E2EeHelper.cs b/E2EeHelper.cs
deleted file mode 100644
index c4d5578..0000000
--- a/E2EeHelper.cs
+++ /dev/null
@@ -1,82 +0,0 @@
-using System.Security.Cryptography;
-using System.Text;
-
-namespace RelayCore;
-
-public static class E2EeHelper
-{
- public static (string publicKey, string privateKey) GenerateRsaKeyPair()
- {
- using var rsa = RSA.Create(2048);
-
- var publicKey = Convert.ToBase64String(rsa.ExportSubjectPublicKeyInfo());
- var privateKey = Convert.ToBase64String(rsa.ExportPkcs8PrivateKey());
-
- return (publicKey, privateKey);
- }
-
- public static EncryptedMessagePayload EncryptForRecipient(string plainText, string recipientPublicKeyBase64)
- {
- var aesKey = RandomNumberGenerator.GetBytes(32);
- var nonce = RandomNumberGenerator.GetBytes(12);
- var plainBytes = Encoding.UTF8.GetBytes(plainText);
- var cipherBytes = new byte[plainBytes.Length];
- var tag = new byte[16];
-
- using (var aes = new AesGcm(aesKey, 16))
- {
- aes.Encrypt(nonce, plainBytes, cipherBytes, tag);
- }
-
- var recipientPublicKey = Convert.FromBase64String(recipientPublicKeyBase64);
- byte[] encryptedKey;
-
- using (var rsa = RSA.Create())
- {
- rsa.ImportSubjectPublicKeyInfo(recipientPublicKey, out _);
- encryptedKey = rsa.Encrypt(aesKey, RSAEncryptionPadding.OaepSHA256);
- }
-
- return new EncryptedMessagePayload
- {
- CipherText = Convert.ToBase64String(cipherBytes),
- Nonce = Convert.ToBase64String(nonce),
- Tag = Convert.ToBase64String(tag),
- EncryptedKey = Convert.ToBase64String(encryptedKey)
- };
- }
-
- public static string DecryptForRecipient(EncryptedMessagePayload payload, string recipientPrivateKeyBase64)
- {
- var encryptedKey = Convert.FromBase64String(payload.EncryptedKey);
- var privateKey = Convert.FromBase64String(recipientPrivateKeyBase64);
-
- byte[] aesKey;
-
- using (var rsa = RSA.Create())
- {
- rsa.ImportPkcs8PrivateKey(privateKey, out _);
- aesKey = rsa.Decrypt(encryptedKey, RSAEncryptionPadding.OaepSHA256);
- }
-
- var nonce = Convert.FromBase64String(payload.Nonce);
- var tag = Convert.FromBase64String(payload.Tag);
- var cipherBytes = Convert.FromBase64String(payload.CipherText);
- var plainBytes = new byte[cipherBytes.Length];
-
- using (var aes = new AesGcm(aesKey, 16))
- {
- aes.Decrypt(nonce, cipherBytes, tag, plainBytes);
- }
-
- return Encoding.UTF8.GetString(plainBytes);
- }
-}
-
-public class EncryptedMessagePayload
-{
- public required string CipherText { get; set; }
- public required string Nonce { get; set; }
- public required string Tag { get; set; }
- public required string EncryptedKey { get; set; }
-}
\ No newline at end of file
diff --git a/PasswordHasher.cs b/PasswordHasher.cs
deleted file mode 100644
index d8fbae5..0000000
--- a/PasswordHasher.cs
+++ /dev/null
@@ -1,109 +0,0 @@
-using System;
-using System.Security.Cryptography;
-using System.Text;
-using Konscious.Security.Cryptography;
-
-namespace PasswordHasher
-{
- ///
- /// Provides secure password hashing functionality using Argon2id algorithm
- ///
- public class PasswordHasher
- {
- ///
- /// Size of the salt in bytes
- ///
- private const int SaltSize = 16;
-
- ///
- /// Size of the hash in bytes
- ///
- private const int HashSize = 32;
-
- ///
- /// Number of threads to use for parallel computation
- ///
- private const int DegreeOfParallelism = 1;
-
- ///
- /// Number of iterations for the Argon2id algorithm
- ///
- private const int Iterations = 2;
-
- ///
- /// Memory size in KB to use
- ///
- private const int MemorySize = 19456; // 19 MB
-
- ///
- /// Generates a secure hash of a password using Argon2id with a random salt
- ///
- /// The plain text password to hash
- /// A Base64 string containing the combined salt and hash
- /// Thrown when password is null
- public string HashPassword(string password)
- {
- // Generate a random salt
- byte[] salt = new byte[SaltSize];
- using (RandomNumberGenerator rng = RandomNumberGenerator.Create())
- {
- rng.GetBytes(salt);
- }
-
- // Create hash
- byte[] hash = HashPassword(password, salt);
-
- // Combine salt and hash
- var combinedBytes = new byte[salt.Length + hash.Length];
- Array.Copy(salt, 0, combinedBytes, 0, salt.Length);
- Array.Copy(hash, 0, combinedBytes, salt.Length, hash.Length);
-
- // Convert to base64 for storage
- return Convert.ToBase64String(combinedBytes);
- }
-
- ///
- /// Generates a password hash using Argon2id with a specific salt
- ///
- /// The plain text password
- /// The salt to use for hashing
- /// A byte array containing the password hash
- private byte[] HashPassword(string password, byte[] salt)
- {
- var argon2 = new Argon2id(Encoding.UTF8.GetBytes(password))
- {
- Salt = salt,
- DegreeOfParallelism = DegreeOfParallelism,
- Iterations = Iterations,
- MemorySize = MemorySize
- };
- return argon2.GetBytes(HashSize);
- }
-
- ///
- /// Verifies if a password matches a stored hash
- ///
- /// The plain text password to verify
- /// The stored hash in Base64 format
- /// True if the password matches the hash, false otherwise
- /// Thrown when password or hashedPassword are null
- /// Thrown when hashedPassword is not in valid Base64 format
- public bool VerifyPassword(string password, string hashedPassword)
- {
- // Decode the stored hash
- byte[] combinedBytes = Convert.FromBase64String(hashedPassword);
-
- // Extract salt and hash
- byte[] salt = new byte[SaltSize];
- byte[] hash = new byte[HashSize];
- Array.Copy(combinedBytes, 0, salt, 0, SaltSize);
- Array.Copy(combinedBytes, SaltSize, hash, 0, HashSize);
-
- // Compute hash for the input password
- byte[] newHash = HashPassword(password, salt);
-
- // Compare the hashes
- return CryptographicOperations.FixedTimeEquals(hash, newHash);
- }
- }
-}
\ No newline at end of file
diff --git a/Program.cs b/Program.cs
deleted file mode 100644
index 4b45823..0000000
--- a/Program.cs
+++ /dev/null
@@ -1,298 +0,0 @@
-using SurrealDb.Net;
-using SurrealDb.Net.Models;
-using SurrealDb.Net.Models.Auth;
-using System.Text.Json;
-using PasswordHasher;
-using RelayCore;
-
-using var db = new SurrealDbClient("ws://127.0.0.1:8000/rpc");
-
-await db.SignIn(new RootAuth { Username = "root", Password = "secret" });
-await db.Use("test", "test");
-
-var keeper = await CreateUserAsync(db, "Keeper317", "Keeper317@gmail.com", "password");
-var kira = await CreateUserAsync(db, "Ru_Kira", "jduesling13@gmail.com", "password");
-
-Console.WriteLine($"Keeper created: {ToJsonString(keeper)}");
-Console.WriteLine($"Kira created: {ToJsonString(kira)}");
-
-var keeperKeys = E2EeHelper.GenerateRsaKeyPair();
-var kiraKeys = E2EeHelper.GenerateRsaKeyPair();
-
-KeyStorage.SavePrivateKey("Keeper317", keeperKeys.privateKey);
-KeyStorage.SavePrivateKey("Ru_Kira", kiraKeys.privateKey);
-
-await db.Create("user_keys", new UserKeys
-{
- UserId = keeper.Id.ToString(),
- PublicKey = keeperKeys.publicKey,
- CreatedAt = DateTime.UtcNow,
- UpdatedAt = DateTime.UtcNow
-});
-
-await db.Create("user_keys", new UserKeys
-{
- UserId = kira.Id.ToString(),
- PublicKey = kiraKeys.publicKey,
- CreatedAt = DateTime.UtcNow,
- UpdatedAt = DateTime.UtcNow
-});
-
-Console.WriteLine("Public keys stored for both users.");
-
-var conversation = await db.Create("conversations", new Conversations
-{
- CreatedByUserId = keeper.Id.ToString(),
- CreatedAt = DateTime.UtcNow,
- UpdatedAt = DateTime.UtcNow,
- Title = "Keeper317 + Ru_Kira",
- IsDirectMessage = true
-});
-
-Console.WriteLine($"Conversation created: {ToJsonString(conversation)}");
-
-await db.Create("conversation_members", new ConversationMembers
-{
- ConversationId = conversation.Id.ToString(),
- UserId = keeper.Id.ToString(),
- JoinedAt = DateTime.UtcNow
-});
-
-await db.Create("conversation_members", new ConversationMembers
-{
- ConversationId = conversation.Id.ToString(),
- UserId = kira.Id.ToString(),
- JoinedAt = DateTime.UtcNow
-});
-
-Console.WriteLine("Conversation members added.");
-
-var encrypted = E2EeHelper.EncryptForRecipient("hello from Keeper317", kiraKeys.publicKey);
-
-var savedMessage = await db.Create("messages", new Messages
-{
- ConversationId = conversation.Id.ToString(),
- SenderUserId = keeper.Id.ToString(),
- RecipientUserId = kira.Id.ToString(),
- CipherText = encrypted.CipherText,
- Nonce = encrypted.Nonce,
- Tag = encrypted.Tag,
- EncryptedKey = encrypted.EncryptedKey,
- CreatedAt = DateTime.UtcNow
-});
-
-Console.WriteLine($"Encrypted message saved: {ToJsonString(savedMessage)}");
-
-var decrypted = E2EeHelper.DecryptForRecipient(encrypted, kiraKeys.privateKey);
-Console.WriteLine($"Decrypted for Ru_Kira: {decrypted}");
-
-return;
-
-static string ToJsonString(object? o)
-{
- return JsonSerializer.Serialize(o, new JsonSerializerOptions { WriteIndented = true });
-}
-
-static async Task CreateUserAsync(SurrealDbClient db, string username, string email, string rawPassword)
-{
- var now = DateTime.UtcNow;
-
- var user = new Users
- {
- Username = username,
- Email = email,
- CreatedAt = now,
- UpdatedAt = now,
- LastLogin = now,
- TwoFactorEnabled = false,
- EmailVerified = false,
- AccountStatus = (int)AccountStatuses.Active,
- OnlineStatus = (int)OnlineStatuses.Online,
- };
-
- var created = await db.Create("users", user);
-
- var hasher = new PasswordHasher.PasswordHasher();
- var passwordHash = hasher.HashPassword(created.Id.ToString() + rawPassword);
-
- var updated = await db.Merge(new PasswordHash
- {
- Id = created.Id,
- Password = passwordHash
- });
-
- return updated;
-}
-
-public static class KeyStorage
-{
- public static void SavePrivateKey(string username, string privateKey)
- {
- Directory.CreateDirectory("keys");
- File.WriteAllText(Path.Combine("keys", $"{username}.private.key"), privateKey);
- }
-
- public static string LoadPrivateKey(string username)
- {
- return File.ReadAllText(Path.Combine("keys", $"{username}.private.key"));
- }
-
- public static bool PrivateKeyExists(string username)
- {
- return File.Exists(Path.Combine("keys", $"{username}.private.key"));
- }
-}
-
-public class ResponsibilityMerge : Record
-{
- public bool Marketing { get; set; }
-}
-public class Group
-{
- public bool Marketing { get; set; }
- public int Count { get; set; }
-}
-
-public class Users : Record
-{
- public required string Username { get; set; }
- public string? Password { get; set; }
- public required string Email { get; set; }
- public required DateTime CreatedAt { get; set; }
- public required DateTime UpdatedAt { get; set; }
- public required DateTime LastLogin { get; set; }
- public bool TwoFactorEnabled { get; set; }
- public bool EmailVerified { get; set; }
- public required int AccountStatus { get; set; }
- public required int OnlineStatus { get; set; }
-}
-
-public class PasswordHash : Record
-{
- public string? Password { get; set; }
-}
-
-public class Sessions : Record
-{
- public required string UserId { get; set; }
- public required string TokenHash { get; set; }
- public required DateTime IssuedAt { get; set; }
- public required DateTime ExpiresAt { get; set; }
- public DateTime? LastUsedAt { get; set; }
- public bool Revoked { get; set; }
- public required string DeviceName { get; set; }
- public required string IpAddress { get; set; }
- public required string UserAgent { get; set; }
-}
-
-public class PasswordReset : Record
-{
- public required string UserId { get; set; }
- public required string TokenHash { get; set; }
- public required DateTime CreatedAt { get; set; }
- public required DateTime ExpiresAt { get; set; }
- public bool Revoked { get; set; }
-}
-
-public class Licenses : Record
-{
- public required string UserId { get; set; }
- public required int LicenseType { get; set; }
- public required int Status { get; set; }
- public required DateTime CreatedAt { get; set; }
- public required DateTime StartsAt { get; set; }
- public required DateTime UpdatedAt { get; set; }
- public required DateTime ExpiresAt { get; set; }
-
-}
-
-public class AuthAudits : Record
-{
- public required string UserId { get; set; }
- public required int EventType { get; set; }
- public bool Success { get; set; }
- public required string IpAddress { get; set; }
- public required string UserAgent { get; set; }
- public required string Details { get; set; }
- public required DateTime CreatedAt { get; set; }
-}
-
-public class UserKeys : Record
-{
- public required string UserId { get; set; }
- public required string PublicKey { get; set; }
- public required DateTime CreatedAt { get; set; }
- public required DateTime UpdatedAt { get; set; }
-}
-
-public class Conversations : Record
-{
- public required string CreatedByUserId { get; set; }
- public required DateTime CreatedAt { get; set; }
- public required DateTime UpdatedAt { get; set; }
- public string? Title { get; set; }
- public bool IsDirectMessage { get; set; }
-}
-
-public class ConversationMembers : Record
-{
- public required string ConversationId { get; set; }
- public required string UserId { get; set; }
- public required DateTime JoinedAt { get; set; }
-}
-
-public class Messages : Record
-{
- public required string ConversationId { get; set; }
- public required string SenderUserId { get; set; }
- public required string RecipientUserId { get; set; }
- public required string CipherText { get; set; }
- public required string Nonce { get; set; }
- public required string Tag { get; set; }
- public required string EncryptedKey { get; set; }
- public required DateTime CreatedAt { get; set; }
-}
-
-enum AccountStatuses
-{
- Active,
- Suspended,
- Banned,
- Deleted
-}
-
-enum OnlineStatuses
-{
- Online,
- Busy,
- DND,
- Invisible,
- Offline
-}
-
-enum LicenseStatuses
-{
- Active,
- Expired,
- Renewable,
- Revoked
-}
-
-enum LicenseType
-{
- Free,
- Basic,
- Advanced,
- Pro,
- Enterprise
-}
-
-enum LogEvents
-{
- LoginSuccess,
- LoginFailure,
- LogoutSuccess,
- LogoutFailure,
- PasswordResetSuccess,
- PasswordResetFailure,
-}
\ No newline at end of file
diff --git a/Relay.sln b/Relay.sln
new file mode 100644
index 0000000..add378e
--- /dev/null
+++ b/Relay.sln
@@ -0,0 +1,62 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.0.31903.59
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RelayCore", "RelayCore\RelayCore.csproj", "{346BE501-DE74-4E88-9787-4722FBC8BD0D}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RelayClient", "RelayClient\RelayClient.csproj", "{AB9DA5AB-55DC-4DE4-834C-E1E1BCD0C3CD}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RelayServer", "RelayServer\RelayServer.csproj", "{38995780-E9AA-44D6-B62D-07CCA45E4E4C}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|Any CPU = Release|Any CPU
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {346BE501-DE74-4E88-9787-4722FBC8BD0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {346BE501-DE74-4E88-9787-4722FBC8BD0D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {346BE501-DE74-4E88-9787-4722FBC8BD0D}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {346BE501-DE74-4E88-9787-4722FBC8BD0D}.Debug|x64.Build.0 = Debug|Any CPU
+ {346BE501-DE74-4E88-9787-4722FBC8BD0D}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {346BE501-DE74-4E88-9787-4722FBC8BD0D}.Debug|x86.Build.0 = Debug|Any CPU
+ {346BE501-DE74-4E88-9787-4722FBC8BD0D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {346BE501-DE74-4E88-9787-4722FBC8BD0D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {346BE501-DE74-4E88-9787-4722FBC8BD0D}.Release|x64.ActiveCfg = Release|Any CPU
+ {346BE501-DE74-4E88-9787-4722FBC8BD0D}.Release|x64.Build.0 = Release|Any CPU
+ {346BE501-DE74-4E88-9787-4722FBC8BD0D}.Release|x86.ActiveCfg = Release|Any CPU
+ {346BE501-DE74-4E88-9787-4722FBC8BD0D}.Release|x86.Build.0 = Release|Any CPU
+ {AB9DA5AB-55DC-4DE4-834C-E1E1BCD0C3CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AB9DA5AB-55DC-4DE4-834C-E1E1BCD0C3CD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AB9DA5AB-55DC-4DE4-834C-E1E1BCD0C3CD}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {AB9DA5AB-55DC-4DE4-834C-E1E1BCD0C3CD}.Debug|x64.Build.0 = Debug|Any CPU
+ {AB9DA5AB-55DC-4DE4-834C-E1E1BCD0C3CD}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {AB9DA5AB-55DC-4DE4-834C-E1E1BCD0C3CD}.Debug|x86.Build.0 = Debug|Any CPU
+ {AB9DA5AB-55DC-4DE4-834C-E1E1BCD0C3CD}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AB9DA5AB-55DC-4DE4-834C-E1E1BCD0C3CD}.Release|Any CPU.Build.0 = Release|Any CPU
+ {AB9DA5AB-55DC-4DE4-834C-E1E1BCD0C3CD}.Release|x64.ActiveCfg = Release|Any CPU
+ {AB9DA5AB-55DC-4DE4-834C-E1E1BCD0C3CD}.Release|x64.Build.0 = Release|Any CPU
+ {AB9DA5AB-55DC-4DE4-834C-E1E1BCD0C3CD}.Release|x86.ActiveCfg = Release|Any CPU
+ {AB9DA5AB-55DC-4DE4-834C-E1E1BCD0C3CD}.Release|x86.Build.0 = Release|Any CPU
+ {38995780-E9AA-44D6-B62D-07CCA45E4E4C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {38995780-E9AA-44D6-B62D-07CCA45E4E4C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {38995780-E9AA-44D6-B62D-07CCA45E4E4C}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {38995780-E9AA-44D6-B62D-07CCA45E4E4C}.Debug|x64.Build.0 = Debug|Any CPU
+ {38995780-E9AA-44D6-B62D-07CCA45E4E4C}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {38995780-E9AA-44D6-B62D-07CCA45E4E4C}.Debug|x86.Build.0 = Debug|Any CPU
+ {38995780-E9AA-44D6-B62D-07CCA45E4E4C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {38995780-E9AA-44D6-B62D-07CCA45E4E4C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {38995780-E9AA-44D6-B62D-07CCA45E4E4C}.Release|x64.ActiveCfg = Release|Any CPU
+ {38995780-E9AA-44D6-B62D-07CCA45E4E4C}.Release|x64.Build.0 = Release|Any CPU
+ {38995780-E9AA-44D6-B62D-07CCA45E4E4C}.Release|x86.ActiveCfg = Release|Any CPU
+ {38995780-E9AA-44D6-B62D-07CCA45E4E4C}.Release|x86.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/RelayClient/.gitignore b/RelayClient/.gitignore
new file mode 100644
index 0000000..b59e83d
--- /dev/null
+++ b/RelayClient/.gitignore
@@ -0,0 +1,93 @@
+############################################
+# .NET Build
+############################################
+
+bin/
+obj/
+out/
+publish/
+
+############################################
+# Visual Studio
+############################################
+
+.vs/
+*.user
+*.suo
+*.userprefs
+*.csproj.user
+*.dbmdl
+*.cache
+*.pdb
+*.opendb
+
+############################################
+# Rider / JetBrains
+############################################
+
+.idea/
+*.sln.iml
+
+############################################
+# VSCode
+############################################
+
+.vscode/
+
+############################################
+# NuGet
+############################################
+
+*.nupkg
+*.snupkg
+packages/
+.nuget/
+.nuget/packages/
+
+############################################
+# Logs
+############################################
+
+*.log
+logs/
+
+############################################
+# OS files
+############################################
+
+.DS_Store
+Thumbs.db
+
+############################################
+# Local secrets / environment
+############################################
+
+.env
+.env.*
+secrets.json
+appsettings.Development.json
+
+############################################
+# E2EE private keys
+############################################
+
+keys/*
+!keys/.gitkeep
+
+############################################
+# Local test databases / data folders
+############################################
+
+data/
+*.db
+*.sqlite
+*.sqlite3
+
+############################################
+# Temporary files
+############################################
+
+*.tmp
+*.temp
+*.bak
+*.swp
\ No newline at end of file
diff --git a/RelayClient/App.xaml b/RelayClient/App.xaml
new file mode 100644
index 0000000..0485623
--- /dev/null
+++ b/RelayClient/App.xaml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/RelayClient/App.xaml.cs b/RelayClient/App.xaml.cs
new file mode 100644
index 0000000..3da581d
--- /dev/null
+++ b/RelayClient/App.xaml.cs
@@ -0,0 +1,16 @@
+using Microsoft.Extensions.DependencyInjection;
+
+namespace RelayClient;
+
+public partial class App : Application
+{
+ public App()
+ {
+ InitializeComponent();
+ }
+
+ protected override Window CreateWindow(IActivationState? activationState)
+ {
+ return new Window(new AppShell());
+ }
+}
\ No newline at end of file
diff --git a/RelayClient/AppShell.xaml b/RelayClient/AppShell.xaml
new file mode 100644
index 0000000..b205bde
--- /dev/null
+++ b/RelayClient/AppShell.xaml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
diff --git a/RelayClient/AppShell.xaml.cs b/RelayClient/AppShell.xaml.cs
new file mode 100644
index 0000000..b751b95
--- /dev/null
+++ b/RelayClient/AppShell.xaml.cs
@@ -0,0 +1,9 @@
+namespace RelayClient;
+
+public partial class AppShell : Shell
+{
+ public AppShell()
+ {
+ InitializeComponent();
+ }
+}
\ No newline at end of file
diff --git a/RelayClient/MainPage.xaml b/RelayClient/MainPage.xaml
new file mode 100644
index 0000000..f8b87d0
--- /dev/null
+++ b/RelayClient/MainPage.xaml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/RelayClient/MainPage.xaml.cs b/RelayClient/MainPage.xaml.cs
new file mode 100644
index 0000000..f10d86c
--- /dev/null
+++ b/RelayClient/MainPage.xaml.cs
@@ -0,0 +1,23 @@
+namespace RelayClient;
+
+public partial class MainPage : ContentPage
+{
+ int count = 0;
+
+ public MainPage()
+ {
+ InitializeComponent();
+ }
+
+ private void OnCounterClicked(object? sender, EventArgs e)
+ {
+ count++;
+
+ if (count == 1)
+ CounterBtn.Text = $"Clicked {count} time";
+ else
+ CounterBtn.Text = $"Clicked {count} times";
+
+ SemanticScreenReader.Announce(CounterBtn.Text);
+ }
+}
\ No newline at end of file
diff --git a/RelayClient/MauiProgram.cs b/RelayClient/MauiProgram.cs
new file mode 100644
index 0000000..50927fe
--- /dev/null
+++ b/RelayClient/MauiProgram.cs
@@ -0,0 +1,25 @@
+using Microsoft.Extensions.Logging;
+using Microsoft.Maui.Hosting;
+
+namespace RelayClient;
+
+public static class MauiProgram
+{
+ public static MauiApp CreateMauiApp()
+ {
+ var builder = MauiApp.CreateBuilder();
+ builder
+ .UseMauiApp()
+ .ConfigureFonts(fonts =>
+ {
+ fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
+ fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
+ });
+
+#if DEBUG
+ builder.Logging.AddDebug();
+#endif
+
+ return builder.Build();
+ }
+}
\ No newline at end of file
diff --git a/RelayClient/Platforms/Android/AndroidManifest.xml b/RelayClient/Platforms/Android/AndroidManifest.xml
new file mode 100644
index 0000000..e9937ad
--- /dev/null
+++ b/RelayClient/Platforms/Android/AndroidManifest.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/RelayClient/Platforms/Android/MainActivity.cs b/RelayClient/Platforms/Android/MainActivity.cs
new file mode 100644
index 0000000..e368a02
--- /dev/null
+++ b/RelayClient/Platforms/Android/MainActivity.cs
@@ -0,0 +1,12 @@
+using Android.App;
+using Android.Content.PM;
+using Android.OS;
+
+namespace RelayClient;
+
+[Activity(Theme = "@style/Maui.SplashTheme", MainLauncher = true, LaunchMode = LaunchMode.SingleTop,
+ ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode |
+ ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize | ConfigChanges.Density)]
+public class MainActivity : MauiAppCompatActivity
+{
+}
\ No newline at end of file
diff --git a/RelayClient/Platforms/Android/MainApplication.cs b/RelayClient/Platforms/Android/MainApplication.cs
new file mode 100644
index 0000000..ea67751
--- /dev/null
+++ b/RelayClient/Platforms/Android/MainApplication.cs
@@ -0,0 +1,15 @@
+using Android.App;
+using Android.Runtime;
+
+namespace RelayClient;
+
+[Application]
+public class MainApplication : MauiApplication
+{
+ public MainApplication(IntPtr handle, JniHandleOwnership ownership)
+ : base(handle, ownership)
+ {
+ }
+
+ protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
+}
\ No newline at end of file
diff --git a/RelayClient/Platforms/Android/Resources/values/colors.xml b/RelayClient/Platforms/Android/Resources/values/colors.xml
new file mode 100644
index 0000000..c04d749
--- /dev/null
+++ b/RelayClient/Platforms/Android/Resources/values/colors.xml
@@ -0,0 +1,6 @@
+
+
+ #512BD4
+ #2B0B98
+ #2B0B98
+
\ No newline at end of file
diff --git a/RelayClient/Platforms/MacCatalyst/AppDelegate.cs b/RelayClient/Platforms/MacCatalyst/AppDelegate.cs
new file mode 100644
index 0000000..ec9f816
--- /dev/null
+++ b/RelayClient/Platforms/MacCatalyst/AppDelegate.cs
@@ -0,0 +1,9 @@
+using Foundation;
+
+namespace RelayClient;
+
+[Register("AppDelegate")]
+public class AppDelegate : MauiUIApplicationDelegate
+{
+ protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
+}
\ No newline at end of file
diff --git a/RelayClient/Platforms/MacCatalyst/Entitlements.plist b/RelayClient/Platforms/MacCatalyst/Entitlements.plist
new file mode 100644
index 0000000..de4adc9
--- /dev/null
+++ b/RelayClient/Platforms/MacCatalyst/Entitlements.plist
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+ com.apple.security.app-sandbox
+
+
+ com.apple.security.network.client
+
+
+
+
diff --git a/RelayClient/Platforms/MacCatalyst/Info.plist b/RelayClient/Platforms/MacCatalyst/Info.plist
new file mode 100644
index 0000000..f2e0987
--- /dev/null
+++ b/RelayClient/Platforms/MacCatalyst/Info.plist
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ UIDeviceFamily
+
+ 2
+
+ LSApplicationCategoryType
+ public.app-category.lifestyle
+ UIRequiredDeviceCapabilities
+
+ arm64
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UISupportedInterfaceOrientations~ipad
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationPortraitUpsideDown
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ XSAppIconAssets
+ Assets.xcassets/appicon.appiconset
+
+
diff --git a/RelayClient/Platforms/MacCatalyst/Program.cs b/RelayClient/Platforms/MacCatalyst/Program.cs
new file mode 100644
index 0000000..9ee92fa
--- /dev/null
+++ b/RelayClient/Platforms/MacCatalyst/Program.cs
@@ -0,0 +1,15 @@
+using ObjCRuntime;
+using UIKit;
+
+namespace RelayClient;
+
+public class Program
+{
+ // This is the main entry point of the application.
+ static void Main(string[] args)
+ {
+ // if you want to use a different Application Delegate class from "AppDelegate"
+ // you can specify it here.
+ UIApplication.Main(args, null, typeof(AppDelegate));
+ }
+}
\ No newline at end of file
diff --git a/RelayClient/Platforms/Windows/App.xaml b/RelayClient/Platforms/Windows/App.xaml
new file mode 100644
index 0000000..6527f81
--- /dev/null
+++ b/RelayClient/Platforms/Windows/App.xaml
@@ -0,0 +1,8 @@
+
+
+
diff --git a/RelayClient/Platforms/Windows/App.xaml.cs b/RelayClient/Platforms/Windows/App.xaml.cs
new file mode 100644
index 0000000..74d15ee
--- /dev/null
+++ b/RelayClient/Platforms/Windows/App.xaml.cs
@@ -0,0 +1,23 @@
+using Microsoft.UI.Xaml;
+
+// To learn more about WinUI, the WinUI project structure,
+// and more about our project templates, see: http://aka.ms/winui-project-info.
+
+namespace RelayClient.WinUI;
+
+///
+/// Provides application-specific behavior to supplement the default Application class.
+///
+public partial class App : MauiWinUIApplication
+{
+ ///
+ /// Initializes the singleton application object. This is the first line of authored code
+ /// executed, and as such is the logical equivalent of main() or WinMain().
+ ///
+ public App()
+ {
+ this.InitializeComponent();
+ }
+
+ protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
+}
\ No newline at end of file
diff --git a/RelayClient/Platforms/Windows/Package.appxmanifest b/RelayClient/Platforms/Windows/Package.appxmanifest
new file mode 100644
index 0000000..b3c21e1
--- /dev/null
+++ b/RelayClient/Platforms/Windows/Package.appxmanifest
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+ $placeholder$
+ User Name
+ $placeholder$.png
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/RelayClient/Platforms/Windows/app.manifest b/RelayClient/Platforms/Windows/app.manifest
new file mode 100644
index 0000000..439c31c
--- /dev/null
+++ b/RelayClient/Platforms/Windows/app.manifest
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+ true/PM
+ PerMonitorV2, PerMonitor
+
+ true
+
+
+
diff --git a/RelayClient/Platforms/iOS/AppDelegate.cs b/RelayClient/Platforms/iOS/AppDelegate.cs
new file mode 100644
index 0000000..ec9f816
--- /dev/null
+++ b/RelayClient/Platforms/iOS/AppDelegate.cs
@@ -0,0 +1,9 @@
+using Foundation;
+
+namespace RelayClient;
+
+[Register("AppDelegate")]
+public class AppDelegate : MauiUIApplicationDelegate
+{
+ protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
+}
\ No newline at end of file
diff --git a/RelayClient/Platforms/iOS/Info.plist b/RelayClient/Platforms/iOS/Info.plist
new file mode 100644
index 0000000..0004a4f
--- /dev/null
+++ b/RelayClient/Platforms/iOS/Info.plist
@@ -0,0 +1,32 @@
+
+
+
+
+ LSRequiresIPhoneOS
+
+ UIDeviceFamily
+
+ 1
+ 2
+
+ UIRequiredDeviceCapabilities
+
+ arm64
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UISupportedInterfaceOrientations~ipad
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationPortraitUpsideDown
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ XSAppIconAssets
+ Assets.xcassets/appicon.appiconset
+
+
diff --git a/RelayClient/Platforms/iOS/Program.cs b/RelayClient/Platforms/iOS/Program.cs
new file mode 100644
index 0000000..9ee92fa
--- /dev/null
+++ b/RelayClient/Platforms/iOS/Program.cs
@@ -0,0 +1,15 @@
+using ObjCRuntime;
+using UIKit;
+
+namespace RelayClient;
+
+public class Program
+{
+ // This is the main entry point of the application.
+ static void Main(string[] args)
+ {
+ // if you want to use a different Application Delegate class from "AppDelegate"
+ // you can specify it here.
+ UIApplication.Main(args, null, typeof(AppDelegate));
+ }
+}
\ No newline at end of file
diff --git a/RelayClient/Platforms/iOS/Resources/PrivacyInfo.xcprivacy b/RelayClient/Platforms/iOS/Resources/PrivacyInfo.xcprivacy
new file mode 100644
index 0000000..24ab3b4
--- /dev/null
+++ b/RelayClient/Platforms/iOS/Resources/PrivacyInfo.xcprivacy
@@ -0,0 +1,51 @@
+
+
+
+
+
+ NSPrivacyAccessedAPITypes
+
+
+ NSPrivacyAccessedAPIType
+ NSPrivacyAccessedAPICategoryFileTimestamp
+ NSPrivacyAccessedAPITypeReasons
+
+ C617.1
+
+
+
+ NSPrivacyAccessedAPIType
+ NSPrivacyAccessedAPICategorySystemBootTime
+ NSPrivacyAccessedAPITypeReasons
+
+ 35F9.1
+
+
+
+ NSPrivacyAccessedAPIType
+ NSPrivacyAccessedAPICategoryDiskSpace
+ NSPrivacyAccessedAPITypeReasons
+
+ E174.1
+
+
+
+
+
+
diff --git a/RelayClient/Properties/launchSettings.json b/RelayClient/Properties/launchSettings.json
new file mode 100644
index 0000000..4f85793
--- /dev/null
+++ b/RelayClient/Properties/launchSettings.json
@@ -0,0 +1,8 @@
+{
+ "profiles": {
+ "Windows Machine": {
+ "commandName": "Project",
+ "nativeDebugging": false
+ }
+ }
+}
\ No newline at end of file
diff --git a/RelayClient/README.md b/RelayClient/README.md
new file mode 100644
index 0000000..f31753a
--- /dev/null
+++ b/RelayClient/README.md
@@ -0,0 +1 @@
+# RelayClient
diff --git a/RelayClient/RelayClient.csproj b/RelayClient/RelayClient.csproj
new file mode 100644
index 0000000..b536a2d
--- /dev/null
+++ b/RelayClient/RelayClient.csproj
@@ -0,0 +1,46 @@
+
+
+
+ net10.0-android;net10.0-ios;net10.0-maccatalyst
+
+ $(TargetFrameworks);net10.0-windows10.0.19041.0
+
+
+ Exe
+ RelayClient
+ true
+ true
+ enable
+ enable
+
+ SourceGen
+
+ RelayClient
+ com.companyname.relayclient
+ 1.0
+ 1
+
+ None
+
+ 15.0
+ 15.0
+ 21.0
+ 10.0.17763.0
+ 10.0.17763.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/RelayClient/Resources/AppIcon/appicon.svg b/RelayClient/Resources/AppIcon/appicon.svg
new file mode 100644
index 0000000..9d63b65
--- /dev/null
+++ b/RelayClient/Resources/AppIcon/appicon.svg
@@ -0,0 +1,4 @@
+
+
\ No newline at end of file
diff --git a/RelayClient/Resources/AppIcon/appiconfg.svg b/RelayClient/Resources/AppIcon/appiconfg.svg
new file mode 100644
index 0000000..21dfb25
--- /dev/null
+++ b/RelayClient/Resources/AppIcon/appiconfg.svg
@@ -0,0 +1,8 @@
+
+
+
\ No newline at end of file
diff --git a/RelayClient/Resources/Fonts/OpenSans-Regular.ttf b/RelayClient/Resources/Fonts/OpenSans-Regular.ttf
new file mode 100644
index 0000000..2cc82d2
Binary files /dev/null and b/RelayClient/Resources/Fonts/OpenSans-Regular.ttf differ
diff --git a/RelayClient/Resources/Fonts/OpenSans-Semibold.ttf b/RelayClient/Resources/Fonts/OpenSans-Semibold.ttf
new file mode 100644
index 0000000..fcb5284
Binary files /dev/null and b/RelayClient/Resources/Fonts/OpenSans-Semibold.ttf differ
diff --git a/RelayClient/Resources/Images/dotnet_bot.png b/RelayClient/Resources/Images/dotnet_bot.png
new file mode 100644
index 0000000..054167e
Binary files /dev/null and b/RelayClient/Resources/Images/dotnet_bot.png differ
diff --git a/RelayClient/Resources/Raw/AboutAssets.txt b/RelayClient/Resources/Raw/AboutAssets.txt
new file mode 100644
index 0000000..89dc758
--- /dev/null
+++ b/RelayClient/Resources/Raw/AboutAssets.txt
@@ -0,0 +1,15 @@
+Any raw assets you want to be deployed with your application can be placed in
+this directory (and child directories). Deployment of the asset to your application
+is automatically handled by the following `MauiAsset` Build Action within your `.csproj`.
+
+
+
+These files will be deployed with your package and will be accessible using Essentials:
+
+ async Task LoadMauiAsset()
+ {
+ using var stream = await FileSystem.OpenAppPackageFileAsync("AboutAssets.txt");
+ using var reader = new StreamReader(stream);
+
+ var contents = reader.ReadToEnd();
+ }
diff --git a/RelayClient/Resources/Splash/splash.svg b/RelayClient/Resources/Splash/splash.svg
new file mode 100644
index 0000000..21dfb25
--- /dev/null
+++ b/RelayClient/Resources/Splash/splash.svg
@@ -0,0 +1,8 @@
+
+
+
\ No newline at end of file
diff --git a/RelayClient/Resources/Styles/Colors.xaml b/RelayClient/Resources/Styles/Colors.xaml
new file mode 100644
index 0000000..d57fcc6
--- /dev/null
+++ b/RelayClient/Resources/Styles/Colors.xaml
@@ -0,0 +1,44 @@
+
+
+
+
+
+ #512BD4
+ #ac99ea
+ #242424
+ #DFD8F7
+ #9880e5
+ #2B0B98
+
+ White
+ Black
+ #D600AA
+ #190649
+ #1f1f1f
+
+ #E1E1E1
+ #C8C8C8
+ #ACACAC
+ #919191
+ #6E6E6E
+ #404040
+ #212121
+ #141414
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/RelayClient/Resources/Styles/Styles.xaml b/RelayClient/Resources/Styles/Styles.xaml
new file mode 100644
index 0000000..5fef12a
--- /dev/null
+++ b/RelayClient/Resources/Styles/Styles.xaml
@@ -0,0 +1,434 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/RelayCore.csproj b/RelayCore.csproj
deleted file mode 100644
index fc62708..0000000
--- a/RelayCore.csproj
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
- Exe
- net9.0
- enable
- enable
- Linux
-
-
-
-
-
-
-
-
diff --git a/RelayCore.sln b/RelayCore.sln
deleted file mode 100644
index 1a0a0ee..0000000
--- a/RelayCore.sln
+++ /dev/null
@@ -1,21 +0,0 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RelayCore", "RelayCore.csproj", "{E918B36B-F762-4D75-BFF6-3566400F36CD}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{6BE28511-369E-4D50-BDAF-3258D32FA7B9}"
- ProjectSection(SolutionItems) = preProject
- compose.yaml = compose.yaml
- EndProjectSection
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Any CPU = Debug|Any CPU
- Release|Any CPU = Release|Any CPU
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {E918B36B-F762-4D75-BFF6-3566400F36CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {E918B36B-F762-4D75-BFF6-3566400F36CD}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {E918B36B-F762-4D75-BFF6-3566400F36CD}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {E918B36B-F762-4D75-BFF6-3566400F36CD}.Release|Any CPU.Build.0 = Release|Any CPU
- EndGlobalSection
-EndGlobal
diff --git a/RelayServer/.gitignore b/RelayServer/.gitignore
new file mode 100644
index 0000000..b59e83d
--- /dev/null
+++ b/RelayServer/.gitignore
@@ -0,0 +1,93 @@
+############################################
+# .NET Build
+############################################
+
+bin/
+obj/
+out/
+publish/
+
+############################################
+# Visual Studio
+############################################
+
+.vs/
+*.user
+*.suo
+*.userprefs
+*.csproj.user
+*.dbmdl
+*.cache
+*.pdb
+*.opendb
+
+############################################
+# Rider / JetBrains
+############################################
+
+.idea/
+*.sln.iml
+
+############################################
+# VSCode
+############################################
+
+.vscode/
+
+############################################
+# NuGet
+############################################
+
+*.nupkg
+*.snupkg
+packages/
+.nuget/
+.nuget/packages/
+
+############################################
+# Logs
+############################################
+
+*.log
+logs/
+
+############################################
+# OS files
+############################################
+
+.DS_Store
+Thumbs.db
+
+############################################
+# Local secrets / environment
+############################################
+
+.env
+.env.*
+secrets.json
+appsettings.Development.json
+
+############################################
+# E2EE private keys
+############################################
+
+keys/*
+!keys/.gitkeep
+
+############################################
+# Local test databases / data folders
+############################################
+
+data/
+*.db
+*.sqlite
+*.sqlite3
+
+############################################
+# Temporary files
+############################################
+
+*.tmp
+*.temp
+*.bak
+*.swp
\ No newline at end of file
diff --git a/RelayServer/Program.cs b/RelayServer/Program.cs
new file mode 100644
index 0000000..837131c
--- /dev/null
+++ b/RelayServer/Program.cs
@@ -0,0 +1 @@
+Console.WriteLine("Hello, World!");
\ No newline at end of file
diff --git a/RelayServer/README.md b/RelayServer/README.md
new file mode 100644
index 0000000..2cd21e5
--- /dev/null
+++ b/RelayServer/README.md
@@ -0,0 +1 @@
+# RelayServer
diff --git a/RelayServer/RelayServer.csproj b/RelayServer/RelayServer.csproj
new file mode 100644
index 0000000..6c1dc92
--- /dev/null
+++ b/RelayServer/RelayServer.csproj
@@ -0,0 +1,10 @@
+
+
+
+ Exe
+ net10.0
+ enable
+ enable
+
+
+
diff --git a/compose.yaml b/compose.yaml
deleted file mode 100644
index eed92af..0000000
--- a/compose.yaml
+++ /dev/null
@@ -1,7 +0,0 @@
-services:
- relaycore:
- image: relaycore
- build:
- context: .
- dockerfile: Dockerfile
-
diff --git a/keys/.gitkeep b/keys/.gitkeep
deleted file mode 100644
index e69de29..0000000