From daf35ebf04fb8812aa5b4d690484ca4f1c9159fd Mon Sep 17 00:00:00 2001
From: "jozsef.b@aycode.com" <9Rj@D}fVwBaN>
Date: Mon, 22 Apr 2024 17:29:35 +0200
Subject: [PATCH] =?UTF-8?q?Login,=20Register,=20ProjectSalt,=20PasswordHas?=
=?UTF-8?q?h,=20meg=20a=20faszom=20sem=20tudja=20m=C3=A1r...?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
AyCode.Core.Tests/AyCode.Core.Tests.csproj | 4 +-
AyCode.Core.sln | 14 +-
AyCode.Core/AyCode.Core.csproj | 4 +
AyCode.Core/Consts/AcConst.cs | 44 ++++-
AyCode.Core/Consts/AcErrorCode.cs | 1 +
AyCode.Core/Consts/AcRegExpression.cs | 15 ++
AyCode.Core/Consts/AcValidate.cs | 19 +-
.../AyCode.Database.Tests.csproj | 4 +-
AyCode.Database/AyCode.Database.csproj | 4 +-
AyCode.Database/DataLayers/AcDalBase.cs | 1 +
.../DataLayers/Users/AcUserDalBase.cs | 51 +++--
AyCode.Entities/Addresses/AcAddress.cs | 4 +-
AyCode.Entities/Profiles/AcProfile.cs | 1 +
AyCode.Entities/Users/AcUser.cs | 2 +-
.../AyCode.Interfaces.Server.csproj | 12 ++
.../Logins/IAcLoginServiceServer.cs | 20 ++
.../Addresses/Dtos/IAcAddressDtoBase.cs | 4 +-
.../Logins/IAcLoginServiceBase.cs | 15 ++
.../Logins/IAcLoginServiceClient.cs | 15 ++
.../Logins/IAcLoginServiceCommon.cs | 25 +++
AyCode.Interfaces/Users/IAcUserBase.cs | 2 +-
.../Logins/AcLoggedInModelServer.cs | 17 ++
AyCode.Models/AyCode.Models.csproj | 4 -
AyCode.Models/Logins/IAcLoggedInModelBase.cs | 18 ++
AyCode.Models/Logins/IAcLoginDtoBase.cs | 2 +-
.../AyCode.Services.Server.Tests.csproj | 42 ++++
.../AcLoginServiceServerTestBase.cs | 30 +++
.../AyCode.Services.Server.csproj | 2 +-
.../Logins/AcLoginServiceServer.cs | 179 ++++++++++++++++++
AyCode.Services/AyCode.Services.csproj | 4 +
AyCode.Services/Logins/AcLoginServiceBase.cs | 17 ++
.../Logins/AcLoginServiceClient.cs | 58 ++++++
AyCode.Utils/AyCode.Utils.csproj | 2 +-
AyCode.Utils/Extensions/StringExtensions.cs | 39 +++-
AyCode.Utils/Helpers/PasswordHasher.cs | 45 +++--
35 files changed, 650 insertions(+), 70 deletions(-)
create mode 100644 AyCode.Core/Consts/AcRegExpression.cs
create mode 100644 AyCode.Interfaces.Server/Logins/IAcLoginServiceServer.cs
create mode 100644 AyCode.Interfaces/Logins/IAcLoginServiceBase.cs
create mode 100644 AyCode.Interfaces/Logins/IAcLoginServiceClient.cs
create mode 100644 AyCode.Interfaces/Logins/IAcLoginServiceCommon.cs
create mode 100644 AyCode.Models.Server/Logins/AcLoggedInModelServer.cs
create mode 100644 AyCode.Models/Logins/IAcLoggedInModelBase.cs
create mode 100644 AyCode.Services.Server.Tests/AyCode.Services.Server.Tests.csproj
create mode 100644 AyCode.Services.Server.Tests/LoginServices/AcLoginServiceServerTestBase.cs
create mode 100644 AyCode.Services.Server/Logins/AcLoginServiceServer.cs
create mode 100644 AyCode.Services/Logins/AcLoginServiceBase.cs
create mode 100644 AyCode.Services/Logins/AcLoginServiceClient.cs
diff --git a/AyCode.Core.Tests/AyCode.Core.Tests.csproj b/AyCode.Core.Tests/AyCode.Core.Tests.csproj
index 471fb92..2c5868e 100644
--- a/AyCode.Core.Tests/AyCode.Core.Tests.csproj
+++ b/AyCode.Core.Tests/AyCode.Core.Tests.csproj
@@ -11,8 +11,8 @@
-
-
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/AyCode.Core.sln b/AyCode.Core.sln
index 3ed7ba3..7ef3cbf 100644
--- a/AyCode.Core.sln
+++ b/AyCode.Core.sln
@@ -25,13 +25,15 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AyCode.Database.Tests", "Ay
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AyCode.Core.Tests", "AyCode.Core.Tests\AyCode.Core.Tests.csproj", "{320A245F-6731-476D-A9D8-77888E6B5D9C}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AyCode.Models", "AyCode.Models\AyCode.Models.csproj", "{21392620-7D0E-44B6-9485-93C57F944C20}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AyCode.Models", "AyCode.Models\AyCode.Models.csproj", "{21392620-7D0E-44B6-9485-93C57F944C20}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AyCode.Services", "AyCode.Services\AyCode.Services.csproj", "{58C8A6A7-D624-4E32-93B9-16B879405CAA}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AyCode.Services", "AyCode.Services\AyCode.Services.csproj", "{58C8A6A7-D624-4E32-93B9-16B879405CAA}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AyCode.Models.Server", "AyCode.Models.Server\AyCode.Models.Server.csproj", "{44CF90C8-76E4-4BD6-A957-E8F7AE019B06}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AyCode.Models.Server", "AyCode.Models.Server\AyCode.Models.Server.csproj", "{44CF90C8-76E4-4BD6-A957-E8F7AE019B06}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AyCode.Services.Server", "AyCode.Services.Server\AyCode.Services.Server.csproj", "{3C74C94F-2FEB-47F7-ABB3-B0C9CBCCC876}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AyCode.Services.Server", "AyCode.Services.Server\AyCode.Services.Server.csproj", "{3C74C94F-2FEB-47F7-ABB3-B0C9CBCCC876}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AyCode.Services.Server.Tests", "AyCode.Services.Server.Tests\AyCode.Services.Server.Tests.csproj", "{9AC9AF60-280A-4871-A7FA-69AB4D0C858A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -99,6 +101,10 @@ Global
{3C74C94F-2FEB-47F7-ABB3-B0C9CBCCC876}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3C74C94F-2FEB-47F7-ABB3-B0C9CBCCC876}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3C74C94F-2FEB-47F7-ABB3-B0C9CBCCC876}.Release|Any CPU.Build.0 = Release|Any CPU
+ {9AC9AF60-280A-4871-A7FA-69AB4D0C858A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {9AC9AF60-280A-4871-A7FA-69AB4D0C858A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {9AC9AF60-280A-4871-A7FA-69AB4D0C858A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {9AC9AF60-280A-4871-A7FA-69AB4D0C858A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/AyCode.Core/AyCode.Core.csproj b/AyCode.Core/AyCode.Core.csproj
index 46fad1b..213344f 100644
--- a/AyCode.Core/AyCode.Core.csproj
+++ b/AyCode.Core/AyCode.Core.csproj
@@ -10,4 +10,8 @@
+
+
+
+
diff --git a/AyCode.Core/Consts/AcConst.cs b/AyCode.Core/Consts/AcConst.cs
index 2f9afd7..02c89ab 100644
--- a/AyCode.Core/Consts/AcConst.cs
+++ b/AyCode.Core/Consts/AcConst.cs
@@ -1,7 +1,15 @@
-namespace AyCode.Core.Consts
+using System.Runtime.InteropServices;
+using System.Security;
+using System.Text;
+using AyCode.Core.Extensions;
+
+namespace AyCode.Core.Consts
{
- public static class AcConst
+ public abstract class AcConst
{
+ public static Guid ProjectId;
+ public static string ProjectSalt;
+
public const int ImageUploadLimit = 4096 * 1024;
public static int ConsentCount = 1;
@@ -47,6 +55,7 @@
/// MainScene, Lobby
///
public static readonly Guid AnataCity;
+
public static readonly Guid PlayerGarage;
public static readonly Guid PlayerWardrobe;
public static readonly Guid LoadingId;
@@ -56,6 +65,7 @@
/// RegionAdmin
///
public static readonly Guid RegionAdminUserId;
+
public static readonly Guid RegionAdminPlayerId;
public static readonly Guid GamePlayer;
@@ -67,8 +77,13 @@
public static string[] AvailableDomainSuffixes = new string[] { "3d", "anata", "app", "art", "club", "game", "blog", "shop", "biz", "chat", "conf", "city", "com", "net", "cool", "dance", "date", "fun", "design", "digital", "estate", "metaverse", "mv", "events", "fans", "fashion", "makeup", "fin", "fm", "sport", "gallery", "io", "info", "job", "mev", "land", "world", "life", "live", "lol", "love", "market", "media", "museum", "news", "ngo", "ninja", "kiwi", "one", "org", "party", "pink", "press", "slide", "property", "pub", "race", "sale", "school", "science", "social", "study", "style", "support", "tattoo", "team", "tech", "theatre", "town", "trade", "travel", "tv", "university", "education", "video", "vip", "vision", "wiki", "work", "xxx", "yeti", "ac", "ad", "ae", "af", "ag", "ai", "al", "am", "ao", "aq", "ar", "as", "at", "au", "aw", "ax", "az", "ba", "bb", "bd", "be", "bf", "bg", "bh", "bi", "bj", "bm", "bn", "bo", "bq", "br", "bs", "bt", "bw", "by", "bz", "ca", "cc", "cd", "cf", "cg", "ch", "ci", "ck", "cl", "cm", "cn", "co", "cr", "cu", "cv", "cw", "cx", "cy", "cz", "de", "dj", "dk", "dm", "do", "dz", "ec", "ee", "eg", "eh", "er", "es", "et", "eu", "fi", "fj", "fk", "fm", "fo", "fr", "ga", "gd", "ge", "gf", "gg", "gh", "gi", "gl", "gm", "gn", "gp", "gq", "gr", "gs", "gt", "gu", "gw", "gy", "hk", "hm", "hn", "hr", "ht", "hu", "id", "ie", "il", "im", "in", "io", "iq", "ir", "is", "it", "je", "jm", "jo", "jp", "ke", "kg", "kh", "ki", "km", "kn", "kp", "kr", "kw", "ky", "kz", "la", "lb", "lc", "li", "lk", "lr", "ls", "lt", "lu", "lv", "ly", "ma", "mc", "md", "me", "mg", "mh", "mk", "ml", "mm", "mn", "mo", "mp", "mq", "mr", "ms", "mt", "mu", "mv", "mw", "mx", "my", "mz", "na", "nc", "ne", "nf", "ng", "ni", "nl", "no", "np", "nr", "nu", "nz", "om", "pa", "pe", "pf", "pg", "ph", "pk", "pl", "pm", "pn", "pr", "ps", "pt", "pw", "py", "qa", "re", "ro", "rs", "ru", "rw", "sa", "sb", "sc", "sd", "se", "sg", "sh", "si", "sk", "sl", "sm", "sn", "so", "sr", "ss", "st", "su", "sv", "sx", "sy", "sz", "tc", "td", "tf", "tg", "th", "tj", "tk", "tl", "tm", "tn", "to", "tr", "tt", "tv", "tw", "tz", "ua", "ug", "uk", "us", "uy", "uz", "va", "vc", "ve", "vg", "vi", "vn", "vu", "wf", "ws", "ye", "yt", "za", "zm", "zw" };
+ //TODO: kitörölni és DB-ből kiszedni! - J.
+ private static string _tiamProjectIdString = "684f34d1-163a-4077-918f-a9d9df5ce789";
static AcConst()
{
+ ProjectId = Guid.Parse(_tiamProjectIdString);
+ ProjectSalt = GenerateProjectSalt(ProjectId.ToString("N"));
+
//var anataFolder = AcDomain.IsProductVersion ? "Anata" : "AnataDev";
//AnataRootCacheFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "AyCode", anataFolder);
@@ -100,5 +115,30 @@
//AnataWorldDomainId = Guid.Parse("8EFA53B3-7114-41E2-98F1-D690ECF509D2");
//AnataWorldBrandId = Guid.Parse("99265775-4B19-4975-B338-EB0F2F890806");
}
+
+ //SEMMILYEN KÖRÜLMÉNYEK KÖZÖTT SE VÁLTOZTASD MEG METÓDUS LOGIKÁJÁT!!! Különben senki sem fog tudni Login-olni! - J.
+ public static string GenerateProjectSalt(string projectIdString)
+ {
+ if (projectIdString.IsNullOrWhiteSpace()) return string.Empty;
+
+ var projectSalt = new StringBuilder();
+
+ var projectIdChars = projectIdString.ToCharArray();
+ var mid = (projectIdChars.Length + 1) / 2;
+
+ var firstHalf = projectIdChars.Take(mid).Reverse();
+ var secondHalf = projectIdChars.Skip(mid).Reverse();
+ var mixedChars = firstHalf.MixCharacters(secondHalf).ToArray();
+
+ for (var i = mixedChars.Length - 1; i >= 0; i--)
+ {
+ projectSalt.Append(mixedChars[i]);
+
+ mixedChars[i] = ' ';
+ projectIdChars[i] = ' ';
+ }
+
+ return projectSalt.ToString();
+ }
}
}
diff --git a/AyCode.Core/Consts/AcErrorCode.cs b/AyCode.Core/Consts/AcErrorCode.cs
index f8dda75..c414fa0 100644
--- a/AyCode.Core/Consts/AcErrorCode.cs
+++ b/AyCode.Core/Consts/AcErrorCode.cs
@@ -53,5 +53,6 @@
DomainIdNotFound = 43,
DisableAddUser = 44,
+ PhoneNumberFormatIsNotValid = 45,
}
}
diff --git a/AyCode.Core/Consts/AcRegExpression.cs b/AyCode.Core/Consts/AcRegExpression.cs
new file mode 100644
index 0000000..c6a68a9
--- /dev/null
+++ b/AyCode.Core/Consts/AcRegExpression.cs
@@ -0,0 +1,15 @@
+using System.Text.RegularExpressions;
+
+namespace AyCode.Core.Consts;
+
+public static partial class AcRegExpression
+{
+ public const string EmailMask = @"(\w|[.-])+@(\w|-)+\.(\w|-){2,4}";
+ public const string PhoneNumberMask = @"\+(9[976]\d|8[987530]\d|6[987]\d|5[90]\d|42\d|3[875]\d|2[98654321]\d|9[8543210]|8[6421]|6[6543210]|5[87654321]|4[987654310]|3[9643210]|2[70]|7|1)\W*\d\W*\d\W*\d\W*\d\W*\d\W*\d\W*\d\W*\d\W*(\d{1,2})";
+
+ [GeneratedRegex(AcRegExpression.EmailMask)]
+ public static partial Regex EmailRegex();
+
+ [GeneratedRegex(AcRegExpression.PhoneNumberMask)]
+ public static partial Regex PhoneNumberRegex();
+}
\ No newline at end of file
diff --git a/AyCode.Core/Consts/AcValidate.cs b/AyCode.Core/Consts/AcValidate.cs
index cd69019..d3ba4ea 100644
--- a/AyCode.Core/Consts/AcValidate.cs
+++ b/AyCode.Core/Consts/AcValidate.cs
@@ -1,10 +1,16 @@
using AyCode.Utils.Extensions;
using System.Text.RegularExpressions;
+using AyCode.Core.Extensions;
namespace AyCode.Core.Consts
{
public static class AcValidate
{
+ public static bool IsValidEmailAndPasswordFormat(string email, string password, out AcErrorCode acErrorCode)
+ {
+ return IsValidEmailFormat(email, out acErrorCode) && IsValidPasswordFormat(password, out acErrorCode);
+ }
+
public static bool IsValidUserNameAndPasswordFormat(string username, string password, out AcErrorCode acErrorCode)
{
return IsValidUserNameFormat(username, out acErrorCode) && IsValidPasswordFormat(password, out acErrorCode);
@@ -45,12 +51,23 @@ namespace AyCode.Core.Consts
acErrorCode = AcErrorCode.Unset;
//a@a.a -> length == 5
- var isValid = !email.IsNullOrWhiteSpace() && email.Length >= 5 && email.Contains('@') && email.Contains('.') && !email.Contains(' ');
+ //var isValid = !email.IsNullOrWhiteSpace() && email.Length >= 5 && email.Contains('@') && email.Contains('.') && !email.Contains(' ');
+ var isValid = AcRegExpression.EmailRegex().IsMatch(email);
if (!isValid) acErrorCode = AcErrorCode.EmailFormatIsNotValid;
return isValid;
}
+ public static bool IsValidPhoneNumberFormat(string phoneNumber, out AcErrorCode acErrorCode)
+ {
+ acErrorCode = AcErrorCode.Unset;
+
+ var isValid = AcRegExpression.PhoneNumberRegex().IsMatch(phoneNumber);
+
+ if (!isValid) acErrorCode = AcErrorCode.PhoneNumberFormatIsNotValid;
+ return isValid;
+ }
+
public static bool IsValidUserTokenFormat(string verificationToken, out AcErrorCode acErrorCode)
{
acErrorCode = AcErrorCode.Unset;
diff --git a/AyCode.Database.Tests/AyCode.Database.Tests.csproj b/AyCode.Database.Tests/AyCode.Database.Tests.csproj
index b4336aa..db41b0b 100644
--- a/AyCode.Database.Tests/AyCode.Database.Tests.csproj
+++ b/AyCode.Database.Tests/AyCode.Database.Tests.csproj
@@ -11,8 +11,8 @@
-
-
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/AyCode.Database/AyCode.Database.csproj b/AyCode.Database/AyCode.Database.csproj
index be6b751..d6334d3 100644
--- a/AyCode.Database/AyCode.Database.csproj
+++ b/AyCode.Database/AyCode.Database.csproj
@@ -7,8 +7,8 @@
-
-
+
+
diff --git a/AyCode.Database/DataLayers/AcDalBase.cs b/AyCode.Database/DataLayers/AcDalBase.cs
index 4691581..d02bb95 100644
--- a/AyCode.Database/DataLayers/AcDalBase.cs
+++ b/AyCode.Database/DataLayers/AcDalBase.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
+using AyCode.Core.Extensions;
using AyCode.Core.Helpers;
using AyCode.Database.DbContexts;
using AyCode.Database.Extensions;
diff --git a/AyCode.Database/DataLayers/Users/AcUserDalBase.cs b/AyCode.Database/DataLayers/Users/AcUserDalBase.cs
index 64675fe..d58903c 100644
--- a/AyCode.Database/DataLayers/Users/AcUserDalBase.cs
+++ b/AyCode.Database/DataLayers/Users/AcUserDalBase.cs
@@ -32,40 +32,51 @@ namespace AyCode.Database.DataLayers.Users
public TUser? GetUserByEmail(string email) => Session(x => x.GetUserByEmail(email));
public Task GetUserByEmailAsync(string email) => SessionAsync(x => x.GetUserByEmail(email));
- public Task AddUser(TUser user, string profileName, TProfileAddress address, string? firstName = null, string? lastName = null)
+ public Task AddUserAsync(TUser user)
+ {
+ return TransactionAsync(ctx => ctx.AddUser(user));
+ }
+
+ public Task AddUserAsync(TUser user, string profileName, TProfileAddress address, string? firstName = null, string? lastName = null)
{
return TransactionAsync(ctx =>
{
- var profile = Activator.CreateInstance();
-
- profile.Id = Guid.NewGuid();
- profile.Name = profileName;
- profile.FirstName = firstName;
- profile.LastName = lastName;
- profile.Address = address;
-
+ var profile = CreateProfile(profileName, address, firstName, lastName);
user.Profile= profile;
- if (ctx.AddUser(user)) return false;
-
- ctx.SaveChanges();
-
- return true;
+ return ctx.AddUser(user);
});
}
- public Task AddUser(TUser user)
+ public bool AddUser(TUser user, string profileName, TProfileAddress address, string? firstName = null, string? lastName = null)
{
- return TransactionAsync(ctx =>
+ return Transaction(ctx =>
{
- if (ctx.AddUser(user)) return false;
-
- ctx.SaveChanges();
+ var profile = CreateProfile(profileName, address, firstName, lastName);
- return true;
+ user.Profile = profile;
+
+ return ctx.AddUser(user);
});
}
+ private static TProfile CreateProfile(string profileName, TProfileAddress address, string? firstName, string? lastName)
+ {
+ var profile = Activator.CreateInstance();
+
+ profile.Id = Guid.NewGuid();
+ profile.Name = profileName;
+ profile.FirstName = firstName;
+ profile.LastName = lastName;
+
+ profile.Address = address;
+ profile.AddressId = address.Id;
+ return profile;
+ }
+
+ public Task RemoveUserAsync(TUser user) => TransactionAsync(ctx => ctx.RemoveUserAsync(user));
+ public Task RemoveUserAsync(Guid userId) => TransactionAsync(ctx => ctx.RemoveUserAsync(userId));
+
//public UserToken CreateUserToken(Guid userId, string verificationToken)
//{
// UserToken userToken = null;
diff --git a/AyCode.Entities/Addresses/AcAddress.cs b/AyCode.Entities/Addresses/AcAddress.cs
index 852c28e..27e871e 100644
--- a/AyCode.Entities/Addresses/AcAddress.cs
+++ b/AyCode.Entities/Addresses/AcAddress.cs
@@ -13,8 +13,8 @@ public abstract class AcAddress : IAcAddress
public bool IsValid { get; set; }
public bool IsHelper { get; set; }
- public double Latitude { get; set; }
- public double Longitude { get; set; }
+ public double? Latitude { get; set; }
+ public double? Longitude { get; set; }
public string? AddressText { get; set; }
diff --git a/AyCode.Entities/Profiles/AcProfile.cs b/AyCode.Entities/Profiles/AcProfile.cs
index 138b1c6..8ab4b23 100644
--- a/AyCode.Entities/Profiles/AcProfile.cs
+++ b/AyCode.Entities/Profiles/AcProfile.cs
@@ -1,6 +1,7 @@
using AyCode.Interfaces.Profiles;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
+using AyCode.Core.Extensions;
using AyCode.Interfaces.Addresses;
using AyCode.Utils.Extensions;
diff --git a/AyCode.Entities/Users/AcUser.cs b/AyCode.Entities/Users/AcUser.cs
index 515d252..a71e947 100644
--- a/AyCode.Entities/Users/AcUser.cs
+++ b/AyCode.Entities/Users/AcUser.cs
@@ -23,7 +23,7 @@ namespace AyCode.Entities.Users
[Required, Column("Email")]
public string EmailAddress { get; set; }
//public string NormalizedEmail { get; set; }
- public string PhoneNumber { get; set; }
+ public string? PhoneNumber { get; set; }
public string Password { get; set; }
public string? RefreshToken { get; set; }
diff --git a/AyCode.Interfaces.Server/AyCode.Interfaces.Server.csproj b/AyCode.Interfaces.Server/AyCode.Interfaces.Server.csproj
index 30402ac..f7f8798 100644
--- a/AyCode.Interfaces.Server/AyCode.Interfaces.Server.csproj
+++ b/AyCode.Interfaces.Server/AyCode.Interfaces.Server.csproj
@@ -6,4 +6,16 @@
enable
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/AyCode.Interfaces.Server/Logins/IAcLoginServiceServer.cs b/AyCode.Interfaces.Server/Logins/IAcLoginServiceServer.cs
new file mode 100644
index 0000000..946545d
--- /dev/null
+++ b/AyCode.Interfaces.Server/Logins/IAcLoginServiceServer.cs
@@ -0,0 +1,20 @@
+using System.Net;
+using AyCode.Interfaces.Addresses;
+using AyCode.Interfaces.Logins;
+using AyCode.Interfaces.Profiles;
+using AyCode.Interfaces.ServiceProviders;
+using AyCode.Interfaces.Users;
+
+namespace AyCode.Interfaces.Server.Logins;
+
+public interface IAcLoginServiceServer : IAcLoginServiceCommon
+
+ where TUser : class, IAcUser
+ where TUserToken : class, IAcUserTokenBase
+ where TProfile : class, IAcProfile
+ where TServiceProvider : class, IAcServiceProviderBase
+ where TUserToServiceProvider : class, IAcUserToServiceProviderBase
+ where TProfileAddress : class, IAcAddress
+{
+ protected string GenerateDynamicSalt(Guid userId);
+}
\ No newline at end of file
diff --git a/AyCode.Interfaces/Addresses/Dtos/IAcAddressDtoBase.cs b/AyCode.Interfaces/Addresses/Dtos/IAcAddressDtoBase.cs
index 967d007..d4be114 100644
--- a/AyCode.Interfaces/Addresses/Dtos/IAcAddressDtoBase.cs
+++ b/AyCode.Interfaces/Addresses/Dtos/IAcAddressDtoBase.cs
@@ -8,7 +8,7 @@ public interface IAcAddressDtoBase : IEntityGuid
public bool IsValid { get; set; }
public bool IsHelper { get; set; }
- public double Latitude { get; set; }
- public double Longitude { get; set; }
+ public double? Latitude { get; set; }
+ public double? Longitude { get; set; }
public string? AddressText { get; set; }
}
\ No newline at end of file
diff --git a/AyCode.Interfaces/Logins/IAcLoginServiceBase.cs b/AyCode.Interfaces/Logins/IAcLoginServiceBase.cs
new file mode 100644
index 0000000..dc7ab32
--- /dev/null
+++ b/AyCode.Interfaces/Logins/IAcLoginServiceBase.cs
@@ -0,0 +1,15 @@
+using AyCode.Interfaces.Addresses;
+using AyCode.Interfaces.Profiles;
+using AyCode.Interfaces.ServiceProviders;
+using AyCode.Interfaces.Users;
+
+namespace AyCode.Interfaces.Logins;
+
+public interface IAcLoginServiceBase where TUser : class, IAcUser
+ where TProfile : class, IAcProfile
+ where TServiceProvider : class, IAcServiceProviderBase
+ where TUserToServiceProvider : class, IAcUserToServiceProviderBase
+ where TProfileAddress : class, IAcAddress
+{
+ public TUser? LoggedInUser { get; }
+}
\ No newline at end of file
diff --git a/AyCode.Interfaces/Logins/IAcLoginServiceClient.cs b/AyCode.Interfaces/Logins/IAcLoginServiceClient.cs
new file mode 100644
index 0000000..a2e31ab
--- /dev/null
+++ b/AyCode.Interfaces/Logins/IAcLoginServiceClient.cs
@@ -0,0 +1,15 @@
+using AyCode.Interfaces.Addresses;
+using AyCode.Interfaces.Profiles;
+using AyCode.Interfaces.ServiceProviders;
+using AyCode.Interfaces.Users;
+
+namespace AyCode.Interfaces.Logins;
+
+public interface IAcLoginServiceClient : IAcLoginServiceCommon
+ where TUser : class, IAcUser
+ where TProfile : class, IAcProfile
+ where TServiceProvider : class, IAcServiceProviderBase
+ where TUserToServiceProvider : class, IAcUserToServiceProviderBase
+ where TProfileAddress : class, IAcAddress
+{
+}
\ No newline at end of file
diff --git a/AyCode.Interfaces/Logins/IAcLoginServiceCommon.cs b/AyCode.Interfaces/Logins/IAcLoginServiceCommon.cs
new file mode 100644
index 0000000..ff889f0
--- /dev/null
+++ b/AyCode.Interfaces/Logins/IAcLoginServiceCommon.cs
@@ -0,0 +1,25 @@
+using AyCode.Interfaces.Addresses;
+using AyCode.Interfaces.Profiles;
+using AyCode.Interfaces.ServiceProviders;
+using AyCode.Interfaces.Users;
+
+namespace AyCode.Interfaces.Logins;
+
+public interface IAcLoginServiceCommon : IAcLoginServiceBase
+ where TUser : class, IAcUser
+ where TProfile : class, IAcProfile
+ where TServiceProvider : class, IAcServiceProviderBase
+ where TUserToServiceProvider : class, IAcUserToServiceProviderBase
+ where TProfileAddress : class, IAcAddress
+{
+ public TUser? Login(string email, string password, out string accessToken);
+ public Task LoginAsync(string email, string password);
+
+ public bool Logout();
+ public Task LogoutAsync();
+
+ public TUser? Registration(string email, string password, string? phoneNumber = null);
+ public TUser? Registration(Guid userId, string email, string password, string? phoneNumber = null);
+ public Task RegistrationAsync(string email, string password, string? phoneNumber = null);
+ public Task RegistrationAsync(Guid userId, string email, string password, string? phoneNumber = null);
+}
\ No newline at end of file
diff --git a/AyCode.Interfaces/Users/IAcUserBase.cs b/AyCode.Interfaces/Users/IAcUserBase.cs
index e50f92b..4cd9d96 100644
--- a/AyCode.Interfaces/Users/IAcUserBase.cs
+++ b/AyCode.Interfaces/Users/IAcUserBase.cs
@@ -6,7 +6,7 @@ namespace AyCode.Interfaces.Users;
public interface IAcUserBase : IEntityGuid, IAcProfileForeignKey, IEmailAddress, IEmailConfirmed, IPassword, ITimeStampInfo
{
- public string PhoneNumber { get; set; }
+ public string? PhoneNumber { get; set; }
public string? RefreshToken { get; set; }
public Guid? RefferalId { get; set; }
diff --git a/AyCode.Models.Server/Logins/AcLoggedInModelServer.cs b/AyCode.Models.Server/Logins/AcLoggedInModelServer.cs
new file mode 100644
index 0000000..cab634a
--- /dev/null
+++ b/AyCode.Models.Server/Logins/AcLoggedInModelServer.cs
@@ -0,0 +1,17 @@
+using AyCode.Interfaces.Addresses;
+using AyCode.Interfaces.Profiles;
+using AyCode.Interfaces.ServiceProviders;
+using AyCode.Interfaces.Users;
+using AyCode.Models.Logins;
+
+namespace AyCode.Models.Server.Logins;
+
+public class AcLoggedInModelServer : IAcLoggedInModelBase
+ where TUser : class, IAcUser
+ where TProfile : class, IAcProfile
+ where TServiceProvider : class, IAcServiceProviderBase
+ where TUserToServiceProvider : class, IAcUserToServiceProviderBase
+ where TProfileAddress : class, IAcAddress
+{
+ public TUser? LoggedInUser { get; set; }
+}
\ No newline at end of file
diff --git a/AyCode.Models/AyCode.Models.csproj b/AyCode.Models/AyCode.Models.csproj
index 4362a07..086bd2b 100644
--- a/AyCode.Models/AyCode.Models.csproj
+++ b/AyCode.Models/AyCode.Models.csproj
@@ -6,10 +6,6 @@
enable
-
-
-
-
diff --git a/AyCode.Models/Logins/IAcLoggedInModelBase.cs b/AyCode.Models/Logins/IAcLoggedInModelBase.cs
new file mode 100644
index 0000000..2dd9bea
--- /dev/null
+++ b/AyCode.Models/Logins/IAcLoggedInModelBase.cs
@@ -0,0 +1,18 @@
+using AyCode.Interfaces.Addresses;
+using AyCode.Interfaces.Logins;
+using AyCode.Interfaces.Profiles;
+using AyCode.Interfaces.ServiceProviders;
+using AyCode.Interfaces.TimeStampInfo;
+using AyCode.Interfaces.Users;
+
+namespace AyCode.Models.Logins;
+
+public interface IAcLoggedInModelBase : IAcLoginDtoBase
+ where TUser : class, IAcUser
+ where TProfile : class, IAcProfile
+ where TServiceProvider : class, IAcServiceProviderBase
+ where TUserToServiceProvider : class, IAcUserToServiceProviderBase
+ where TProfileAddress : class, IAcAddress
+{
+ TUser? LoggedInUser { get; set; }
+}
\ No newline at end of file
diff --git a/AyCode.Models/Logins/IAcLoginDtoBase.cs b/AyCode.Models/Logins/IAcLoginDtoBase.cs
index 805ae70..d1d901b 100644
--- a/AyCode.Models/Logins/IAcLoginDtoBase.cs
+++ b/AyCode.Models/Logins/IAcLoginDtoBase.cs
@@ -2,7 +2,7 @@
namespace AyCode.Models.Logins;
-public interface IAcLoginDtoBase : IEntityGuid
+public interface IAcLoginDtoBase
{
}
\ No newline at end of file
diff --git a/AyCode.Services.Server.Tests/AyCode.Services.Server.Tests.csproj b/AyCode.Services.Server.Tests/AyCode.Services.Server.Tests.csproj
new file mode 100644
index 0000000..482e437
--- /dev/null
+++ b/AyCode.Services.Server.Tests/AyCode.Services.Server.Tests.csproj
@@ -0,0 +1,42 @@
+
+
+
+ net8.0
+ enable
+ enable
+
+ false
+ true
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/AyCode.Services.Server.Tests/LoginServices/AcLoginServiceServerTestBase.cs b/AyCode.Services.Server.Tests/LoginServices/AcLoginServiceServerTestBase.cs
new file mode 100644
index 0000000..1e63548
--- /dev/null
+++ b/AyCode.Services.Server.Tests/LoginServices/AcLoginServiceServerTestBase.cs
@@ -0,0 +1,30 @@
+using AyCode.Database.DataLayers.Users;
+using AyCode.Database.DbContexts.Users;
+using AyCode.Database.DbContexts;
+using AyCode.Database.Tests;
+using AyCode.Interfaces.Addresses;
+using AyCode.Interfaces.Profiles;
+using AyCode.Interfaces.Server.Logins;
+using AyCode.Interfaces.ServiceProviders;
+using AyCode.Interfaces.Users;
+
+namespace AyCode.Services.Server.Tests.LoginServices
+{
+ public abstract class AcLoginServiceServerTestBase : AcDatabaseTestModelBase
+ where TDal : AcUserDalBase
+ where TDbContext : AcDbContextBase, IAcUserDbContextBase
+ where TLoginServiceServer : class, IAcLoginServiceServer
+ where TUser : class, IAcUser
+ where TProfile : class, IAcProfile
+ where TProfileAddress : class, IAcAddress
+ where TUserToken : class, IAcUserTokenBase
+ where TServiceProvider : class, IAcServiceProviderBase
+ where TUserToServiceProvider : class, IAcUserToServiceProviderBase
+ {
+ public TUser RegisterUserTest()
+ {
+ //Activator.CreateInstance(typeof(TLoginServiceServer), )
+ throw new NotImplementedException();
+ }
+ }
+}
\ No newline at end of file
diff --git a/AyCode.Services.Server/AyCode.Services.Server.csproj b/AyCode.Services.Server/AyCode.Services.Server.csproj
index 945146c..20fdac1 100644
--- a/AyCode.Services.Server/AyCode.Services.Server.csproj
+++ b/AyCode.Services.Server/AyCode.Services.Server.csproj
@@ -8,7 +8,7 @@
-
+
diff --git a/AyCode.Services.Server/Logins/AcLoginServiceServer.cs b/AyCode.Services.Server/Logins/AcLoginServiceServer.cs
new file mode 100644
index 0000000..16d8c8a
--- /dev/null
+++ b/AyCode.Services.Server/Logins/AcLoginServiceServer.cs
@@ -0,0 +1,179 @@
+using System.IdentityModel.Tokens.Jwt;
+using AyCode.Core.Helpers;
+using AyCode.Interfaces.Addresses;
+using AyCode.Interfaces.Logins;
+using AyCode.Interfaces.Profiles;
+using AyCode.Interfaces.Server.Logins;
+using AyCode.Interfaces.ServiceProviders;
+using AyCode.Interfaces.Users;
+using AyCode.Services.Logins;
+using System.Runtime.InteropServices;
+using System.Security;
+using System.Security.Claims;
+using System.Security.Cryptography;
+using System.Text;
+using Microsoft.IdentityModel.Tokens;
+using AyCode.Database.DataLayers;
+using Microsoft.EntityFrameworkCore;
+using AyCode.Database.DbContexts;
+using AyCode.Core.Consts;
+using AyCode.Core.Extensions;
+using AyCode.Database.DataLayers.Users;
+using AyCode.Database.DbContexts.Users;
+using AyCode.Models.Logins;
+using AyCode.Models.Server.Logins;
+using AyCode.Utils.Extensions;
+using AyCode.Utils.Helpers;
+using Microsoft.Extensions.Configuration;
+
+namespace AyCode.Services.Server.Logins;
+
+public class AcLoginServiceServer(TDal userDal, IConfiguration configuration)
+ : AcLoginServiceBase, IAcLoginServiceServer
+
+ where TResultLoggedInModel: class, IAcLoggedInModelBase
+ where TDal : AcUserDalBase
+ where TDbContext : AcDbContextBase, IAcUserDbContextBase
+ where TUser : class, IAcUser
+ where TUserToken : class, IAcUserTokenBase
+ where TProfile : class, IAcProfile
+ where TServiceProvider : class, IAcServiceProviderBase
+ where TUserToServiceProvider : class, IAcUserToServiceProviderBase
+ where TProfileAddress : class, IAcAddress
+{
+ public virtual TUser? Login(string email, string password, out string accessToken)
+ {
+ accessToken = string.Empty;
+ //var loginModel = Activator.CreateInstance();
+
+ if (!AcValidate.IsValidEmailAndPasswordFormat(email, password, out var errorCode)) return null;//return loginModel;
+
+ var user = userDal.GetUserByEmail(email);
+ if (user is not { EmailConfirmed: true } || !string.Equals(user.EmailAddress, email, StringComparison.CurrentCultureIgnoreCase)
+ || !PasswordHasher.VerifyPassword(password, user.Password, GenerateDynamicSalt(user.Id))) return null;
+
+
+ //loginModel.LoggedInUser = user;
+ return LoggedInUser = user;
+ }
+
+ public virtual Task LoginAsync(string email, string password)
+ {
+ return TaskHelper.ToThreadPoolTask(() => Login(email, password, out _));
+ }
+
+ public virtual bool Logout()
+ {
+ LoggedInUser = null;
+
+ return true;
+ }
+
+ public virtual Task LogoutAsync()
+ {
+ return TaskHelper.ToThreadPoolTask(Logout);
+ }
+
+ public virtual TUser? Registration(string email, string password, string? phoneNumber = null)
+ => Registration(Guid.NewGuid(), email, password, phoneNumber);
+
+ public virtual TUser? Registration(Guid userId, string email, string password, string? phoneNumber = null)
+ {
+ if ((phoneNumber != null && !AcValidate.IsValidPhoneNumberFormat(phoneNumber, out var errorCode)) ||
+ !AcValidate.IsValidEmailAndPasswordFormat(email, password, out errorCode)) return null;
+
+ var user = Activator.CreateInstance();
+ user.Id = userId;
+ user.EmailAddress = email;
+ user.EmailConfirmed = true;
+ user.Password = PasswordHasher.HashPassword(password, GenerateDynamicSalt(userId));
+
+ var address = Activator.CreateInstance();
+ address.Id = Guid.NewGuid();
+
+ var userName = email.Split('@')[0]; //TODO: generálni egy nevet... - J.
+ return userDal.AddUser(user, userName, address) ? null : userDal.GetUserById(userId);
+ }
+
+ public virtual Task RegistrationAsync(string email, string password, string? phoneNumber = null)
+ => RegistrationAsync(Guid.NewGuid(), email, password, phoneNumber);
+ public virtual Task RegistrationAsync(Guid userId, string email, string password, string? phoneNumber = null)
+ {
+ return TaskHelper.ToThreadPoolTask(() => Registration(userId, email, password, phoneNumber));
+ }
+
+ //SEMMILYEN KÖRÜLMÉNYEK KÖZÖTT SE VÁLTOZTASD MEG METÓDUS LOGIKÁJÁT!!! Különben senki sem fog tudni Login-olni! - J.
+ public virtual string GenerateDynamicSalt(Guid userId)
+ => userId.ToString("N").ToLower().Reverse().MixCharacters(AcConst.ProjectSalt);
+
+ private string GenerateAccessToken(TUser user)
+ {
+ var tokenHandler = new JwtSecurityTokenHandler();
+ Console.WriteLine("----------------------------------------------------------");
+
+ if (configuration["JWT:Key"] == null)
+ throw new SecurityTokenException("Token is null");
+
+ var keyDetail = Encoding.UTF8.GetBytes(configuration["JWT:Key"] ?? string.Empty);
+ Console.WriteLine(configuration["JWT:Key"]);
+
+ var claims = new List
+ {
+ new(ClaimTypes.NameIdentifier, user.Id.ToString()),
+ new(ClaimTypes.Email, user.EmailAddress)
+ };
+
+ var tokenDescriptor = new SecurityTokenDescriptor
+ {
+ Audience = configuration["JWT:Audience"],
+ Issuer = configuration["JWT:Issuer"],
+ Expires = DateTime.UtcNow.AddMinutes(30),
+ Subject = new ClaimsIdentity(claims),
+ SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(keyDetail), SecurityAlgorithms.HmacSha256Signature)
+ };
+
+ var token = tokenHandler.CreateToken(tokenDescriptor) as JwtSecurityToken;
+ var writtenToken = tokenHandler.WriteToken(token);
+ Console.WriteLine(writtenToken);
+
+ return writtenToken;
+ }
+
+ private ClaimsPrincipal GetPrincipalFromExpiredToken(string token)
+ {
+ var tokenHandler = new JwtSecurityTokenHandler();
+
+ if (configuration["JWT:Key"] == null)
+ throw new SecurityTokenException("Token is null");
+
+ var keyDetail = Encoding.UTF8.GetBytes(configuration["JWT:Key"] ?? string.Empty);
+
+ var tokenValidationParameter = new TokenValidationParameters
+ {
+ ValidateIssuer = false,
+ ValidateAudience = false,
+ ValidateLifetime = false,
+ ValidateIssuerSigningKey = true,
+ ValidIssuer = configuration["JWT:Issuer"],
+ ValidAudience = configuration["JWT:Audience"],
+ IssuerSigningKey = new SymmetricSecurityKey(keyDetail),
+ };
+
+ var principal = tokenHandler.ValidateToken(token, tokenValidationParameter, out var securityToken);
+
+ if (securityToken is not JwtSecurityToken jwtSecurityToken || !jwtSecurityToken.Header.Alg.Equals(SecurityAlgorithms.HmacSha256, StringComparison.InvariantCultureIgnoreCase))
+ throw new SecurityTokenException("Invalid token");
+
+ return principal;
+ }
+
+ private string GenerateRefreshToken()
+ {
+ var randomNumber = new byte[32];
+ using (var rng = RandomNumberGenerator.Create())
+ {
+ rng.GetBytes(randomNumber);
+ return Convert.ToBase64String(randomNumber);
+ }
+ }
+}
\ No newline at end of file
diff --git a/AyCode.Services/AyCode.Services.csproj b/AyCode.Services/AyCode.Services.csproj
index c68d0c6..96f7971 100644
--- a/AyCode.Services/AyCode.Services.csproj
+++ b/AyCode.Services/AyCode.Services.csproj
@@ -6,6 +6,10 @@
enable
+
+
+
+
diff --git a/AyCode.Services/Logins/AcLoginServiceBase.cs b/AyCode.Services/Logins/AcLoginServiceBase.cs
new file mode 100644
index 0000000..e9e1ce9
--- /dev/null
+++ b/AyCode.Services/Logins/AcLoginServiceBase.cs
@@ -0,0 +1,17 @@
+using AyCode.Interfaces.Addresses;
+using AyCode.Interfaces.Logins;
+using AyCode.Interfaces.Profiles;
+using AyCode.Interfaces.ServiceProviders;
+using AyCode.Interfaces.Users;
+
+namespace AyCode.Services.Logins;
+
+public abstract class AcLoginServiceBase : IAcLoginServiceBase
+ where TUser : class, IAcUser
+ where TProfile : class, IAcProfile
+ where TServiceProvider : class, IAcServiceProviderBase
+ where TUserToServiceProvider : class, IAcUserToServiceProviderBase
+ where TProfileAddress : class, IAcAddress
+{
+ public TUser? LoggedInUser { get; protected set; }
+}
\ No newline at end of file
diff --git a/AyCode.Services/Logins/AcLoginServiceClient.cs b/AyCode.Services/Logins/AcLoginServiceClient.cs
new file mode 100644
index 0000000..4de231a
--- /dev/null
+++ b/AyCode.Services/Logins/AcLoginServiceClient.cs
@@ -0,0 +1,58 @@
+using AyCode.Core.Helpers;
+using AyCode.Interfaces.Addresses;
+using AyCode.Interfaces.Logins;
+using AyCode.Interfaces.Profiles;
+using AyCode.Interfaces.ServiceProviders;
+using AyCode.Interfaces.Users;
+
+namespace AyCode.Services.Logins;
+
+public class AcLoginServiceClient
+ : AcLoginServiceBase, IAcLoginServiceClient
+
+ where TUser : class, IAcUser
+ where TProfile : class, IAcProfile
+ where TServiceProvider : class, IAcServiceProviderBase
+ where TUserToServiceProvider : class, IAcUserToServiceProviderBase
+ where TProfileAddress : class, IAcAddress
+{
+ public virtual TUser? Login(string email, string password, out string accessToken)
+ {
+ throw new NotImplementedException();
+ }
+
+ public virtual Task LoginAsync(string email, string password)
+ {
+ return TaskHelper.ToThreadPoolTask(() => Login(email, password, out _));
+ }
+
+ public virtual bool Logout()
+ {
+ throw new NotImplementedException();
+ }
+
+ public virtual Task LogoutAsync()
+ {
+ return TaskHelper.ToThreadPoolTask(Logout);
+ }
+
+ public virtual TUser? Registration(string email, string password, string? phoneNumber = null)
+ {
+ throw new NotImplementedException();
+ }
+
+ public TUser? Registration(Guid userId, string email, string password, string? phoneNumber = null)
+ {
+ throw new NotImplementedException();
+ }
+
+ public virtual Task RegistrationAsync(string email, string password, string? phoneNumber = null)
+ {
+ return TaskHelper.ToThreadPoolTask(() => Registration(email, password, phoneNumber));
+ }
+
+ public Task RegistrationAsync(Guid userId, string email, string password, string? phoneNumber = null)
+ {
+ throw new NotImplementedException();
+ }
+}
\ No newline at end of file
diff --git a/AyCode.Utils/AyCode.Utils.csproj b/AyCode.Utils/AyCode.Utils.csproj
index eb7c41d..115ed45 100644
--- a/AyCode.Utils/AyCode.Utils.csproj
+++ b/AyCode.Utils/AyCode.Utils.csproj
@@ -8,7 +8,7 @@
-
+
diff --git a/AyCode.Utils/Extensions/StringExtensions.cs b/AyCode.Utils/Extensions/StringExtensions.cs
index 48c0174..88bd5ae 100644
--- a/AyCode.Utils/Extensions/StringExtensions.cs
+++ b/AyCode.Utils/Extensions/StringExtensions.cs
@@ -1,7 +1,8 @@
using System.Diagnostics.CodeAnalysis;
+using System.Text;
using JetBrains.Annotations;
-namespace AyCode.Utils.Extensions
+namespace AyCode.Core.Extensions
{
public static class StringExtensions
{
@@ -36,5 +37,41 @@ namespace AyCode.Utils.Extensions
return char.ToUpper(str[0]) + str[1..];
}
+
+
+ //public static string MixCharacters(this string str1, string str2)
+ // => MixCharacters(str1?.ToCharArray(), str2?.ToCharArray());
+
+ //public static string MixCharacters(this char[] chars1, string str2)
+ // => MixCharacters(chars1, str2?.ToCharArray());
+
+ //public static string MixCharacters(this string str1, char[] chars2)
+ // => MixCharacters(str1?.ToCharArray(), chars2);
+
+ ///
+ /// Example : chars1=ABC, chars2=DEF ==> ADBECF
+ ///
+ ///
+ ///
+ ///
+ public static string MixCharacters(this IEnumerable firstChars, IEnumerable secondChars)
+ {
+ var chars1 = firstChars as char[] ?? firstChars.ToArray();
+ var chars2 = secondChars as char[] ?? secondChars.ToArray();
+
+ if (chars1 is not { Length: > 0 }) return chars2.ToString() ?? string.Empty;
+ if (chars2 is not { Length: > 0 }) return chars1.ToString() ?? string.Empty;
+
+ var length = chars1.Length < chars2.Length ? chars1.Length : chars2.Length;
+ var builder = new StringBuilder(length * 2);
+
+ for (var i = 0; i < length; i++)
+ {
+ builder.Append(chars1[i]);
+ builder.Append(chars2[i]);
+ }
+
+ return builder.ToString();
+ }
}
}
diff --git a/AyCode.Utils/Helpers/PasswordHasher.cs b/AyCode.Utils/Helpers/PasswordHasher.cs
index 44433f3..71a5924 100644
--- a/AyCode.Utils/Helpers/PasswordHasher.cs
+++ b/AyCode.Utils/Helpers/PasswordHasher.cs
@@ -1,51 +1,50 @@
using Microsoft.AspNetCore.Cryptography.KeyDerivation;
using System.Security.Cryptography;
+using System.Text;
+using AyCode.Core.Extensions;
+using AyCode.Utils.Extensions;
namespace AyCode.Utils.Helpers
{
public class PasswordHasher
{
- public string HashPassword(string password)
+ public static string HashPassword(string password, string? dynamicSalt = null)
{
// Generate a random salt
- byte[] salt = new byte[16];
- using (var rng = RandomNumberGenerator.Create())
- {
- rng.GetBytes(salt);
- }
+ var salt = new byte[16];
+ using (var rng = RandomNumberGenerator.Create()) rng.GetBytes(salt);
// Hash the password with the salt
- string hashedPassword = Convert.ToBase64String(KeyDerivation.Pbkdf2(
- password: password,
- salt: salt,
- prf: KeyDerivationPrf.HMACSHA512,
- iterationCount: 10000,
- numBytesRequested: 32));
+ var hashedPassword = GenerateHashedPassword(password, salt, dynamicSalt);
// Combine the salt and hashed password
- string combinedHash = $"$bcrypt$v=1$salt={Convert.ToBase64String(salt)}$hash={hashedPassword}";
+ var combinedHash = $"$bcrypt$v=1$salt={Convert.ToBase64String(salt)}$hash={hashedPassword}";
return combinedHash;
}
- public bool VerifyPassword(string password, string hashedPassword)
+ public static bool VerifyPassword(string password, string hashedPassword, string? dynamicSalt = null)
{
// Extract the salt and hashed password from the combined hash
- string[] parts = hashedPassword.Split('$');
- byte[] salt = Convert.FromBase64String(parts[3]);
- string storedHash = parts[5];
+ var parts = hashedPassword.Split('$');
+ var salt = Convert.FromBase64String(parts[3].Replace("salt=", string.Empty));
+ var storedHash = parts[4].Replace("hash=", string.Empty);
- // Hash the provided password with the extracted salt
- string hashedProvidedPassword = Convert.ToBase64String(KeyDerivation.Pbkdf2(
+ return storedHash == GenerateHashedPassword(password, salt, dynamicSalt);
+ }
+
+ private static string GenerateHashedPassword(string password, byte[] salt, string? dynamicSalt)
+ => Convert.ToBase64String(KeyDerivation.Pbkdf2(
password: password,
- salt: salt,
+ salt: GenerateFinallySalt(salt, dynamicSalt),
prf: KeyDerivationPrf.HMACSHA512,
iterationCount: 10000,
numBytesRequested: 32));
- // Compare the hashed passwords
- return storedHash == hashedProvidedPassword;
- }
+ //SEMMILYEN KÖRÜLMÉNYEK KÖZÖTT SE VÁLTOZTASD MEG METÓDUS LOGIKÁJÁT!!! Különben senki sem fog tudni Login-olni! - J.
+ private static byte[] GenerateFinallySalt(byte[] salt, string? dynamicSalt)
+ => SHA256.HashData(string.IsNullOrWhiteSpace(dynamicSalt) ? salt : Encoding.ASCII.GetBytes(Convert.ToBase64String(salt).Reverse().MixCharacters(dynamicSalt))).Take(16).ToArray();
+
}
}