diff --git a/RelayCore/E2EeHelper.cs b/RelayClient/Crypto/E2EeHelper.cs similarity index 98% rename from RelayCore/E2EeHelper.cs rename to RelayClient/Crypto/E2EeHelper.cs index c4d5578..c17a0be 100644 --- a/RelayCore/E2EeHelper.cs +++ b/RelayClient/Crypto/E2EeHelper.cs @@ -1,7 +1,7 @@ using System.Security.Cryptography; using System.Text; -namespace RelayCore; +namespace RelayClient.Crypto; public static class E2EeHelper { diff --git a/RelayClient/Crypto/KeyStorage.cs b/RelayClient/Crypto/KeyStorage.cs new file mode 100644 index 0000000..d55cbc3 --- /dev/null +++ b/RelayClient/Crypto/KeyStorage.cs @@ -0,0 +1,20 @@ +namespace RelayClient.Crypto; + +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")); + } +} \ No newline at end of file diff --git a/RelayClient/RelayClient.csproj b/RelayClient/RelayClient.csproj index b536a2d..39a8d37 100644 --- a/RelayClient/RelayClient.csproj +++ b/RelayClient/RelayClient.csproj @@ -41,6 +41,7 @@ + diff --git a/RelayCore/keys/.gitkeep b/RelayClient/keys/.gitkeep similarity index 100% rename from RelayCore/keys/.gitkeep rename to RelayClient/keys/.gitkeep diff --git a/RelayCore/Models/AuthAudits.cs b/RelayCore/Models/AuthAudits.cs new file mode 100644 index 0000000..1bdacd2 --- /dev/null +++ b/RelayCore/Models/AuthAudits.cs @@ -0,0 +1,14 @@ +using SurrealDb.Net.Models; + +namespace RelayCore.Models; + +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; } +} \ No newline at end of file diff --git a/RelayCore/Models/Licenses.cs b/RelayCore/Models/Licenses.cs new file mode 100644 index 0000000..47657a4 --- /dev/null +++ b/RelayCore/Models/Licenses.cs @@ -0,0 +1,15 @@ +using SurrealDb.Net.Models; + +namespace RelayCore.Models; + +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; } + +} \ No newline at end of file diff --git a/RelayCore/Models/PasswordHash.cs b/RelayCore/Models/PasswordHash.cs new file mode 100644 index 0000000..2e58139 --- /dev/null +++ b/RelayCore/Models/PasswordHash.cs @@ -0,0 +1,8 @@ +using SurrealDb.Net.Models; + +namespace RelayCore.Models; + +public class PasswordHash : Record +{ + public string? Password { get; set; } +} \ No newline at end of file diff --git a/RelayCore/Models/PasswordHasher.cs b/RelayCore/Models/PasswordHasher.cs index d8fbae5..425d50b 100644 --- a/RelayCore/Models/PasswordHasher.cs +++ b/RelayCore/Models/PasswordHasher.cs @@ -1,9 +1,8 @@ -using System; -using System.Security.Cryptography; +using System.Security.Cryptography; using System.Text; using Konscious.Security.Cryptography; -namespace PasswordHasher +namespace RelayCore.Models { /// /// Provides secure password hashing functionality using Argon2id algorithm diff --git a/RelayCore/Models/PasswordReset.cs b/RelayCore/Models/PasswordReset.cs new file mode 100644 index 0000000..acd03cc --- /dev/null +++ b/RelayCore/Models/PasswordReset.cs @@ -0,0 +1,12 @@ +using SurrealDb.Net.Models; + +namespace RelayCore.Models; + +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; } +} \ No newline at end of file diff --git a/RelayCore/Models/Sessions.cs b/RelayCore/Models/Sessions.cs new file mode 100644 index 0000000..cefd0b8 --- /dev/null +++ b/RelayCore/Models/Sessions.cs @@ -0,0 +1,16 @@ +using SurrealDb.Net.Models; + +namespace RelayCore.Models; + +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; } +} \ No newline at end of file diff --git a/RelayCore/Models/Users.cs b/RelayCore/Models/Users.cs new file mode 100644 index 0000000..1b3e20b --- /dev/null +++ b/RelayCore/Models/Users.cs @@ -0,0 +1,17 @@ +using SurrealDb.Net.Models; + +namespace RelayCore.Models; + +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; } +} \ No newline at end of file diff --git a/RelayCore/Program.cs b/RelayCore/Program.cs index 4b45823..649a2ef 100644 --- a/RelayCore/Program.cs +++ b/RelayCore/Program.cs @@ -2,10 +2,11 @@ using SurrealDb.Net.Models; using SurrealDb.Net.Models.Auth; using System.Text.Json; -using PasswordHasher; using RelayCore; +using RelayCore.Enums; +using RelayCore.Models; -using var db = new SurrealDbClient("ws://127.0.0.1:8000/rpc"); +await 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"); @@ -16,76 +17,6 @@ var kira = await CreateUserAsync(db, "Ru_Kira", "jduesling13@gmail.com", "passwo 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) @@ -112,7 +43,7 @@ static async Task CreateUserAsync(SurrealDbClient db, string username, st var created = await db.Create("users", user); - var hasher = new PasswordHasher.PasswordHasher(); + var hasher = new PasswordHasher(); var passwordHash = hasher.HashPassword(created.Id.ToString() + rawPassword); var updated = await db.Merge(new PasswordHash @@ -122,177 +53,4 @@ static async Task CreateUserAsync(SurrealDbClient db, string username, st }); 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/RelayServer/Models/ConversationMembers.cs b/RelayServer/Models/ConversationMembers.cs new file mode 100644 index 0000000..27dd399 --- /dev/null +++ b/RelayServer/Models/ConversationMembers.cs @@ -0,0 +1,10 @@ +using SurrealDb.Net.Models; + +namespace RelayServer.Models; + +public class ConversationMembers : Record +{ + public required string ConversationId { get; set; } + public required string UserId { get; set; } + public required DateTime JoinedAt { get; set; } +} \ No newline at end of file diff --git a/RelayServer/Models/Conversations.cs b/RelayServer/Models/Conversations.cs new file mode 100644 index 0000000..9788ea2 --- /dev/null +++ b/RelayServer/Models/Conversations.cs @@ -0,0 +1,12 @@ +using SurrealDb.Net.Models; + +namespace RelayServer.Models; + +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; } +} \ No newline at end of file diff --git a/RelayServer/Models/Messages.cs b/RelayServer/Models/Messages.cs new file mode 100644 index 0000000..1a91e52 --- /dev/null +++ b/RelayServer/Models/Messages.cs @@ -0,0 +1,15 @@ +using SurrealDb.Net.Models; + +namespace RelayServer.Models; + +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; } +} \ No newline at end of file diff --git a/RelayServer/Models/UserKeys.cs b/RelayServer/Models/UserKeys.cs new file mode 100644 index 0000000..0dbf6fd --- /dev/null +++ b/RelayServer/Models/UserKeys.cs @@ -0,0 +1,11 @@ +using SurrealDb.Net.Models; + +namespace RelayServer.Models; + +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; } +} \ No newline at end of file diff --git a/RelayServer/RelayServer.csproj b/RelayServer/RelayServer.csproj index 6c1dc92..11711eb 100644 --- a/RelayServer/RelayServer.csproj +++ b/RelayServer/RelayServer.csproj @@ -7,4 +7,8 @@ enable + + + +