Compare commits
No commits in common. "cba3b9f8d6487fdaabd74c0e6b85acf22f97137a" and "a11c4e76448f0b31b8ea42a258b44b71e9042c3f" have entirely different histories.
cba3b9f8d6
...
a11c4e7644
|
|
@ -10,11 +10,9 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="8.0.0" />
|
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" />
|
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
|
||||||
<PackageReference Include="MSTest.TestAdapter" Version="3.3.1" />
|
<PackageReference Include="MSTest.TestAdapter" Version="3.2.2" />
|
||||||
<PackageReference Include="MSTest.TestFramework" Version="3.3.1" />
|
<PackageReference Include="MSTest.TestFramework" Version="3.2.2" />
|
||||||
<PackageReference Include="coverlet.collector" Version="6.0.2">
|
<PackageReference Include="coverlet.collector" Version="6.0.2">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,9 @@
|
||||||
using Microsoft.Extensions.Configuration;
|
namespace AyCode.Core.Tests;
|
||||||
|
|
||||||
namespace AyCode.Core.Tests;
|
|
||||||
|
|
||||||
public abstract class TestModelBase
|
public abstract class TestModelBase
|
||||||
{
|
{
|
||||||
protected IConfiguration AppSettingsConfiguration;
|
|
||||||
|
|
||||||
protected TestModelBase()
|
protected TestModelBase()
|
||||||
{
|
{
|
||||||
//if (IsProductVersion) throw new Exception("IsProductVersion!!!!!");
|
//if (IsProductVersion) throw new Exception("IsProductVersion!!!!!");
|
||||||
|
|
||||||
AppSettingsConfiguration = InitAppSettingsConfiguration();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected IConfiguration InitAppSettingsConfiguration(string appSettingsFileName = "appsettings.json")
|
|
||||||
{
|
|
||||||
var config = new ConfigurationBuilder()
|
|
||||||
.AddJsonFile(appSettingsFileName)
|
|
||||||
.AddEnvironmentVariables()
|
|
||||||
.Build();
|
|
||||||
return config;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -25,15 +25,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AyCode.Database.Tests", "Ay
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AyCode.Core.Tests", "AyCode.Core.Tests\AyCode.Core.Tests.csproj", "{320A245F-6731-476D-A9D8-77888E6B5D9C}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AyCode.Core.Tests", "AyCode.Core.Tests\AyCode.Core.Tests.csproj", "{320A245F-6731-476D-A9D8-77888E6B5D9C}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AyCode.Models", "AyCode.Models\AyCode.Models.csproj", "{21392620-7D0E-44B6-9485-93C57F944C20}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AyCode.Models", "AyCode.Models\AyCode.Models.csproj", "{21392620-7D0E-44B6-9485-93C57F944C20}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AyCode.Services", "AyCode.Services\AyCode.Services.csproj", "{58C8A6A7-D624-4E32-93B9-16B879405CAA}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AyCode.Services", "AyCode.Services\AyCode.Services.csproj", "{58C8A6A7-D624-4E32-93B9-16B879405CAA}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AyCode.Models.Server", "AyCode.Models.Server\AyCode.Models.Server.csproj", "{44CF90C8-76E4-4BD6-A957-E8F7AE019B06}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AyCode.Models.Server", "AyCode.Models.Server\AyCode.Models.Server.csproj", "{44CF90C8-76E4-4BD6-A957-E8F7AE019B06}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AyCode.Services.Server", "AyCode.Services.Server\AyCode.Services.Server.csproj", "{3C74C94F-2FEB-47F7-ABB3-B0C9CBCCC876}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AyCode.Services.Server", "AyCode.Services.Server\AyCode.Services.Server.csproj", "{3C74C94F-2FEB-47F7-ABB3-B0C9CBCCC876}"
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AyCode.Services.Server.Tests", "AyCode.Services.Server.Tests\AyCode.Services.Server.Tests.csproj", "{9AC9AF60-280A-4871-A7FA-69AB4D0C858A}"
|
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
|
@ -80,9 +78,11 @@ Global
|
||||||
{15272F57-771E-47BE-A960-AD75935254D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{15272F57-771E-47BE-A960-AD75935254D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{15272F57-771E-47BE-A960-AD75935254D0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{15272F57-771E-47BE-A960-AD75935254D0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{15272F57-771E-47BE-A960-AD75935254D0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{15272F57-771E-47BE-A960-AD75935254D0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{15272F57-771E-47BE-A960-AD75935254D0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{320A245F-6731-476D-A9D8-77888E6B5D9C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{320A245F-6731-476D-A9D8-77888E6B5D9C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{320A245F-6731-476D-A9D8-77888E6B5D9C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{320A245F-6731-476D-A9D8-77888E6B5D9C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{320A245F-6731-476D-A9D8-77888E6B5D9C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{320A245F-6731-476D-A9D8-77888E6B5D9C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{320A245F-6731-476D-A9D8-77888E6B5D9C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{21392620-7D0E-44B6-9485-93C57F944C20}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{21392620-7D0E-44B6-9485-93C57F944C20}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{21392620-7D0E-44B6-9485-93C57F944C20}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{21392620-7D0E-44B6-9485-93C57F944C20}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{21392620-7D0E-44B6-9485-93C57F944C20}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{21392620-7D0E-44B6-9485-93C57F944C20}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
|
@ -99,9 +99,6 @@ Global
|
||||||
{3C74C94F-2FEB-47F7-ABB3-B0C9CBCCC876}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{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.ActiveCfg = Release|Any CPU
|
||||||
{3C74C94F-2FEB-47F7-ABB3-B0C9CBCCC876}.Release|Any CPU.Build.0 = 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
|
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,4 @@
|
||||||
<ProjectReference Include="..\AyCode.Utils\AyCode.Utils.csproj" />
|
<ProjectReference Include="..\AyCode.Utils\AyCode.Utils.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Folder Include="Extensions\" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -53,7 +53,5 @@
|
||||||
DomainIdNotFound = 43,
|
DomainIdNotFound = 43,
|
||||||
|
|
||||||
DisableAddUser = 44,
|
DisableAddUser = 44,
|
||||||
PhoneNumberFormatIsNotValid = 45,
|
|
||||||
RefreshTokenUpdateError = 50,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
@ -1,16 +1,10 @@
|
||||||
using AyCode.Utils.Extensions;
|
using AyCode.Utils.Extensions;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using AyCode.Core.Extensions;
|
|
||||||
|
|
||||||
namespace AyCode.Core.Consts
|
namespace AyCode.Core.Consts
|
||||||
{
|
{
|
||||||
public static class AcValidate
|
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)
|
public static bool IsValidUserNameAndPasswordFormat(string username, string password, out AcErrorCode acErrorCode)
|
||||||
{
|
{
|
||||||
return IsValidUserNameFormat(username, out acErrorCode) && IsValidPasswordFormat(password, out acErrorCode);
|
return IsValidUserNameFormat(username, out acErrorCode) && IsValidPasswordFormat(password, out acErrorCode);
|
||||||
|
|
@ -36,38 +30,27 @@ namespace AyCode.Core.Consts
|
||||||
return isValid;
|
return isValid;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsValidPasswordFormat(string? password, out AcErrorCode acErrorCode)
|
public static bool IsValidPasswordFormat(string password, out AcErrorCode acErrorCode)
|
||||||
{
|
{
|
||||||
acErrorCode = AcErrorCode.Unset;
|
acErrorCode = AcErrorCode.Unset;
|
||||||
|
|
||||||
var isValid = !string.IsNullOrWhiteSpace(password) && password.Length is >= AcConst.MinPasswordLength and <= AcConst.MaxPasswordLength;
|
var isValid = !password.IsNullOrWhiteSpace() && password.Length is >= AcConst.MinPasswordLength and <= AcConst.MaxPasswordLength;
|
||||||
|
|
||||||
if (!isValid) acErrorCode = AcErrorCode.PasswordIsTooShort;
|
if (!isValid) acErrorCode = AcErrorCode.PasswordIsTooShort;
|
||||||
return isValid;
|
return isValid;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsValidEmailFormat(string? email, out AcErrorCode acErrorCode)
|
public static bool IsValidEmailFormat(string email, out AcErrorCode acErrorCode)
|
||||||
{
|
{
|
||||||
acErrorCode = AcErrorCode.Unset;
|
acErrorCode = AcErrorCode.Unset;
|
||||||
|
|
||||||
//a@a.a -> length == 5
|
//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 = !string.IsNullOrWhiteSpace(email) && AcRegExpression.EmailRegex().IsMatch(email);
|
|
||||||
|
|
||||||
if (!isValid) acErrorCode = AcErrorCode.EmailFormatIsNotValid;
|
if (!isValid) acErrorCode = AcErrorCode.EmailFormatIsNotValid;
|
||||||
return isValid;
|
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)
|
public static bool IsValidUserTokenFormat(string verificationToken, out AcErrorCode acErrorCode)
|
||||||
{
|
{
|
||||||
acErrorCode = AcErrorCode.Unset;
|
acErrorCode = AcErrorCode.Unset;
|
||||||
|
|
|
||||||
|
|
@ -1,62 +0,0 @@
|
||||||
using System.Security.Cryptography;
|
|
||||||
using System.Text;
|
|
||||||
using AyCode.Core.Consts;
|
|
||||||
using AyCode.Core.Extensions;
|
|
||||||
using Microsoft.AspNetCore.Cryptography.KeyDerivation;
|
|
||||||
|
|
||||||
namespace AyCode.Core.Helpers
|
|
||||||
{
|
|
||||||
public class PasswordHasher
|
|
||||||
{
|
|
||||||
public static string HashPassword(string? password, string? dynamicSalt = null)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(password)) throw new ArgumentNullException(nameof(password));
|
|
||||||
|
|
||||||
// Generate a random salt
|
|
||||||
var salt = new byte[16];
|
|
||||||
using (var rng = RandomNumberGenerator.Create()) rng.GetBytes(salt);
|
|
||||||
|
|
||||||
// Hash the password with the salt
|
|
||||||
var hashedPassword = GenerateHashedPassword(password, salt, dynamicSalt);
|
|
||||||
|
|
||||||
// Combine the salt and hashed password
|
|
||||||
var combinedHash = $"$bcrypt$v=1$salt={Convert.ToBase64String(salt)}$hash={hashedPassword}";
|
|
||||||
|
|
||||||
return combinedHash;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool VerifyPassword(string? password, string hashedPassword, string? dynamicSalt = null)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(password)) return false;
|
|
||||||
|
|
||||||
// Extract the salt and hashed password from the combined hash
|
|
||||||
var parts = hashedPassword.Split('$');
|
|
||||||
|
|
||||||
if (parts.Length != 5) return false;
|
|
||||||
|
|
||||||
var salt = Convert.FromBase64String(parts[3].Replace("salt=", string.Empty));
|
|
||||||
var storedHash = parts[4].Replace("hash=", string.Empty);
|
|
||||||
|
|
||||||
return storedHash == GenerateHashedPassword(password, salt, dynamicSalt);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GenerateHashedPassword(string password, byte[] salt, string? dynamicSalt)
|
|
||||||
=> Convert.ToBase64String(KeyDerivation.Pbkdf2(
|
|
||||||
password: password,
|
|
||||||
salt: GenerateFinallySalt(salt, dynamicSalt),
|
|
||||||
prf: KeyDerivationPrf.HMACSHA512,
|
|
||||||
iterationCount: 10000,
|
|
||||||
numBytesRequested: 32));
|
|
||||||
|
|
||||||
//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 GenerateDynamicSalt(Guid userId)
|
|
||||||
=> userId.ToString("N").ToLower().Reverse().MixCharacters(AcConst.ProjectSalt);
|
|
||||||
|
|
||||||
//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();
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -6,10 +6,18 @@ namespace AyCode.Database.Tests;
|
||||||
|
|
||||||
public abstract class AcDatabaseTestModelBase<TDal, TDbContext> : TestModelBase where TDal : IAcDalBase<TDbContext> where TDbContext : AcDbContextBase
|
public abstract class AcDatabaseTestModelBase<TDal, TDbContext> : TestModelBase where TDal : IAcDalBase<TDbContext> where TDbContext : AcDbContextBase
|
||||||
{
|
{
|
||||||
protected readonly TDal Dal = PooledDal.CreateDal<TDal>();
|
protected TDal Dal;
|
||||||
|
protected AcDatabaseTestModelBase()
|
||||||
|
{
|
||||||
|
Dal = PooledDal.CreateDal<TDal>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract class AcDatabaseTestModelBase<TDbContext> : TestModelBase where TDbContext : AcDbContextBase
|
public abstract class AcDatabaseTestModelBase<TDbContext> : TestModelBase where TDbContext : AcDbContextBase
|
||||||
{
|
{
|
||||||
protected readonly TDbContext Context = Activator.CreateInstance<TDbContext>();
|
protected TDbContext Context;
|
||||||
|
protected AcDatabaseTestModelBase()
|
||||||
|
{
|
||||||
|
Context = Activator.CreateInstance<TDbContext>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -10,11 +10,9 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="8.0.0" />
|
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" />
|
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
|
||||||
<PackageReference Include="MSTest.TestAdapter" Version="3.3.1" />
|
<PackageReference Include="MSTest.TestAdapter" Version="3.2.2" />
|
||||||
<PackageReference Include="MSTest.TestFramework" Version="3.3.1" />
|
<PackageReference Include="MSTest.TestFramework" Version="3.2.2" />
|
||||||
<PackageReference Include="coverlet.collector" Version="6.0.2">
|
<PackageReference Include="coverlet.collector" Version="6.0.2">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ namespace AyCode.Database.Tests.Users
|
||||||
protected TUser AcBase_GetUserById_ReturnsUser_WhenUserExists(string userIdString)
|
protected TUser AcBase_GetUserById_ReturnsUser_WhenUserExists(string userIdString)
|
||||||
{
|
{
|
||||||
var userId = Guid.Parse(userIdString);
|
var userId = Guid.Parse(userIdString);
|
||||||
var user = Dal.GetUserById(userId, false);
|
var user = Dal.GetUserById(userId);
|
||||||
|
|
||||||
Assert.IsNotNull(user, "User is null");
|
Assert.IsNotNull(user, "User is null");
|
||||||
Assert.IsNotNull(user.Profile, "Profile is null");
|
Assert.IsNotNull(user.Profile, "Profile is null");
|
||||||
|
|
@ -34,7 +34,7 @@ namespace AyCode.Database.Tests.Users
|
||||||
|
|
||||||
protected TUser AcBase_GetUserByEmail_ReturnsUser_WhenUserExists(string email)
|
protected TUser AcBase_GetUserByEmail_ReturnsUser_WhenUserExists(string email)
|
||||||
{
|
{
|
||||||
var user = Dal.GetUserByEmail(email, false);
|
var user = Dal.GetUserByEmail(email);
|
||||||
|
|
||||||
Assert.IsNotNull(user, "User is null");
|
Assert.IsNotNull(user, "User is null");
|
||||||
Assert.IsNotNull(user.Profile, "Profile is null");
|
Assert.IsNotNull(user.Profile, "Profile is null");
|
||||||
|
|
@ -49,7 +49,7 @@ namespace AyCode.Database.Tests.Users
|
||||||
{
|
{
|
||||||
TUser? user = null;
|
TUser? user = null;
|
||||||
|
|
||||||
user = await Dal.GetUserByEmailAsync(email, false).ConfigureAwait(false);
|
user = await Dal.GetUserByEmailAsync(email).ConfigureAwait(false);
|
||||||
|
|
||||||
//user = await Dal.SessionAsync(ctx => ctx.Users.FirstOrDefault(x => x.EmailAddress == email)).ConfigureAwait(false);
|
//user = await Dal.SessionAsync(ctx => ctx.Users.FirstOrDefault(x => x.EmailAddress == email)).ConfigureAwait(false);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.4" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.3" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="8.0.4" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="8.0.3" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using AyCode.Core.Extensions;
|
|
||||||
using AyCode.Core.Helpers;
|
using AyCode.Core.Helpers;
|
||||||
using AyCode.Database.DbContexts;
|
using AyCode.Database.DbContexts;
|
||||||
using AyCode.Database.Extensions;
|
using AyCode.Database.Extensions;
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@ using AyCode.Interfaces.Users;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using AyCode.Database.Extensions;
|
using AyCode.Database.Extensions;
|
||||||
using AyCode.Core.Consts;
|
using AyCode.Core.Consts;
|
||||||
using AyCode.Core.Helpers;
|
|
||||||
using AyCode.Database.DbSets.Users;
|
using AyCode.Database.DbSets.Users;
|
||||||
using AyCode.Interfaces.Addresses;
|
using AyCode.Interfaces.Addresses;
|
||||||
using AyCode.Interfaces.Profiles;
|
using AyCode.Interfaces.Profiles;
|
||||||
|
|
@ -27,41 +26,15 @@ namespace AyCode.Database.DataLayers.Users
|
||||||
where TUserToServiceProvider : class, IAcUserToServiceProviderBase
|
where TUserToServiceProvider : class, IAcUserToServiceProviderBase
|
||||||
where TProfileAddress : class, IAcAddress
|
where TProfileAddress : class, IAcAddress
|
||||||
{
|
{
|
||||||
public TUser? GetUserById(Guid userId, bool onlyConfirmed) => Session(x => x.GetUserById(userId, onlyConfirmed));
|
public TUser? GetUserById(Guid userId) => Session(x => x.GetUserById(userId));
|
||||||
public Task<TUser?> GetUserByIdAsync(Guid userId, bool onlyConfirmed) => SessionAsync(x => x.GetUserById(userId, onlyConfirmed));
|
public Task<TUser?> GetUserByIdAsync(Guid userId) => SessionAsync(x => x.GetUserById(userId));
|
||||||
|
|
||||||
public TUser? GetUserByEmail(string? email, bool onlyConfirmed) => Session(x => x.GetUserByEmail(email, onlyConfirmed));
|
public TUser? GetUserByEmail(string email) => Session(x => x.GetUserByEmail(email));
|
||||||
public Task<TUser?> GetUserByEmailAsync(string? email, bool onlyConfirmed) => SessionAsync(x => x.GetUserByEmail(email, onlyConfirmed));
|
public Task<TUser?> GetUserByEmailAsync(string email) => SessionAsync(x => x.GetUserByEmail(email));
|
||||||
|
|
||||||
public Task<bool> AddUserAsync(TUser user)
|
public Task<bool> AddUser(TUser user, string profileName, TProfileAddress address, string? firstName = null, string? lastName = null)
|
||||||
{
|
|
||||||
return TransactionAsync(ctx => ctx.AddUser(user));
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<bool> AddUserAsync(TUser user, string profileName, TProfileAddress address, string? firstName = null, string? lastName = null)
|
|
||||||
{
|
{
|
||||||
return TransactionAsync(ctx =>
|
return TransactionAsync(ctx =>
|
||||||
{
|
|
||||||
var profile = CreateProfile(profileName, address, firstName, lastName);
|
|
||||||
user.Profile= profile;
|
|
||||||
|
|
||||||
return ctx.AddUser(user);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool AddUser(TUser user, string profileName, TProfileAddress address, string? firstName = null, string? lastName = null)
|
|
||||||
{
|
|
||||||
return Transaction(ctx =>
|
|
||||||
{
|
|
||||||
var profile = CreateProfile(profileName, address, firstName, lastName);
|
|
||||||
|
|
||||||
user.Profile = profile;
|
|
||||||
|
|
||||||
return ctx.AddUser(user);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private static TProfile CreateProfile(string profileName, TProfileAddress address, string? firstName, string? lastName)
|
|
||||||
{
|
{
|
||||||
var profile = Activator.CreateInstance<TProfile>();
|
var profile = Activator.CreateInstance<TProfile>();
|
||||||
|
|
||||||
|
|
@ -69,83 +42,28 @@ namespace AyCode.Database.DataLayers.Users
|
||||||
profile.Name = profileName;
|
profile.Name = profileName;
|
||||||
profile.FirstName = firstName;
|
profile.FirstName = firstName;
|
||||||
profile.LastName = lastName;
|
profile.LastName = lastName;
|
||||||
|
|
||||||
profile.Address = address;
|
profile.Address = address;
|
||||||
profile.AddressId = address.Id;
|
|
||||||
|
|
||||||
return profile;
|
user.Profile= profile;
|
||||||
}
|
|
||||||
|
|
||||||
public Task<bool> RemoveUserAsync(TUser? user) => TransactionAsync(ctx => RemoveUserTransactionBody(user, ctx));
|
if (ctx.AddUser(user)) return false;
|
||||||
public Task<bool> RemoveUserAsync(Guid userId) => TransactionAsync(ctx =>
|
|
||||||
{
|
|
||||||
var user = ctx.GetUserById(userId, false);
|
|
||||||
|
|
||||||
return RemoveUserTransactionBody(user, ctx);
|
ctx.SaveChanges();
|
||||||
|
|
||||||
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
protected virtual bool RemoveUserTransactionBody(TUser? user, TDbContext ctx)
|
|
||||||
{
|
|
||||||
if (user == null) return false;
|
|
||||||
|
|
||||||
var profile = ctx.Profiles.FirstOrDefault(x => x.Id == user.ProfileId);
|
|
||||||
if (profile != null)
|
|
||||||
{
|
|
||||||
var address = ctx.Addresses.FirstOrDefault(x => x.Id == profile.AddressId);
|
|
||||||
if (address != null) ctx.Addresses.Remove(address);
|
|
||||||
|
|
||||||
ctx.Profiles.Remove(profile);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ctx.RemoveUser(user);
|
public Task<bool> AddUser(TUser user)
|
||||||
}
|
|
||||||
|
|
||||||
public TUser? AuthenticateUser(string? email, string? password, string refreshToken, out AcErrorCode errorCode)
|
|
||||||
{
|
{
|
||||||
TUser? user = null;
|
return TransactionAsync(ctx =>
|
||||||
var errorCodeInner = AcErrorCode.Unset;
|
|
||||||
|
|
||||||
var result = Transaction(ctx =>
|
|
||||||
{
|
{
|
||||||
try
|
if (ctx.AddUser(user)) return false;
|
||||||
{
|
|
||||||
//var passwordHash = PasswordHasher.HashPassword(password, PasswordHasher.GenerateDynamicSalt(userId));
|
|
||||||
|
|
||||||
user = ctx.GetUserByEmail(email, true);
|
ctx.SaveChanges();
|
||||||
if (user is { EmailConfirmed: true } && string.Equals(user.EmailAddress, email, StringComparison.CurrentCultureIgnoreCase)
|
|
||||||
&& PasswordHasher.VerifyPassword(password, user.Password, PasswordHasher.GenerateDynamicSalt(user.Id)))
|
|
||||||
{
|
|
||||||
if (ctx.UpdateJwtRefreshToken(user, refreshToken)) return true;
|
|
||||||
|
|
||||||
errorCodeInner = AcErrorCode.RefreshTokenUpdateError;
|
return true;
|
||||||
}
|
|
||||||
else errorCodeInner = AcErrorCode.WrongLoginData;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
errorCodeInner = AcErrorCode.UnknownError;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
errorCode = errorCodeInner;
|
|
||||||
|
|
||||||
return result ? user : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<TUser?> UpdateJwtRefreshTokenAsync(string email, string refreshToken)
|
|
||||||
{
|
|
||||||
TUser? user = null;
|
|
||||||
|
|
||||||
return await TransactionAsync(ctx => (user = ctx.UpdateJwtRefreshToken(email, refreshToken)) != null) ? user : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TUser? UpdateJwtRefreshToken(string email, string refreshToken)
|
|
||||||
{
|
|
||||||
TUser? user = null;
|
|
||||||
|
|
||||||
return Transaction(ctx => (user = ctx.UpdateJwtRefreshToken(email, refreshToken)) != null) ? user : null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//public UserToken CreateUserToken(Guid userId, string verificationToken)
|
//public UserToken CreateUserToken(Guid userId, string verificationToken)
|
||||||
|
|
|
||||||
|
|
@ -16,9 +16,6 @@ namespace AyCode.Database.DbContexts.Users
|
||||||
{
|
{
|
||||||
public required DbSet<TUser> Users { get; set; }
|
public required DbSet<TUser> Users { get; set; }
|
||||||
public required DbSet<TUserToken> UserTokens { get; set; }
|
public required DbSet<TUserToken> UserTokens { get; set; }
|
||||||
public DbSet<TProfileAddress> Addresses { get; set; }
|
|
||||||
public DbSet<TProfile> Profiles { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
protected AcUserDbContextBase() : this(string.Empty)
|
protected AcUserDbContextBase() : this(string.Empty)
|
||||||
{ }
|
{ }
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,4 @@
|
||||||
using AyCode.Database.DbSets.Addresses;
|
using AyCode.Database.DbSets.Users;
|
||||||
using AyCode.Database.DbSets.Profiles;
|
|
||||||
using AyCode.Database.DbSets.Users;
|
|
||||||
using AyCode.Interfaces.Addresses;
|
using AyCode.Interfaces.Addresses;
|
||||||
using AyCode.Interfaces.Profiles;
|
using AyCode.Interfaces.Profiles;
|
||||||
using AyCode.Interfaces.ServiceProviders;
|
using AyCode.Interfaces.ServiceProviders;
|
||||||
|
|
@ -8,9 +6,7 @@ using AyCode.Interfaces.Users;
|
||||||
|
|
||||||
namespace AyCode.Database.DbContexts.Users;
|
namespace AyCode.Database.DbContexts.Users;
|
||||||
|
|
||||||
public interface IAcUserDbContextBase<TUser, TProfile, TUserToken, TServiceProvider, TUserToServiceProvider, TProfileAddress>
|
public interface IAcUserDbContextBase<TUser, TProfile, TUserToken, TServiceProvider, TUserToServiceProvider, TProfileAddress> : IAcUserDbSet<TUser, TProfile, TServiceProvider, TUserToServiceProvider, TProfileAddress>, IAcUserTokenDbSet<TUserToken>
|
||||||
: IAcUserDbSet<TUser, TProfile, TServiceProvider, TUserToServiceProvider, TProfileAddress>, IAcUserTokenDbSet<TUserToken>, IAcAddressDbSetBase<TProfileAddress>, IAcProfileDbSetBase<TProfile>
|
|
||||||
|
|
||||||
where TUser : class, IAcUser<TProfile, TServiceProvider, TUserToServiceProvider, TProfileAddress>
|
where TUser : class, IAcUser<TProfile, TServiceProvider, TUserToServiceProvider, TProfileAddress>
|
||||||
where TProfile : class, IAcProfile<TProfileAddress>
|
where TProfile : class, IAcProfile<TProfileAddress>
|
||||||
where TUserToken : class, IAcUserTokenBase
|
where TUserToken : class, IAcUserTokenBase
|
||||||
|
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
using AyCode.Interfaces.Profiles.Dtos;
|
|
||||||
using AyCode.Interfaces.Users;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
|
|
||||||
namespace AyCode.Database.DbSets.Profiles;
|
|
||||||
|
|
||||||
public interface IAcProfileDbSetBase<TProfile> where TProfile : class, IAcProfileDtoBase
|
|
||||||
{
|
|
||||||
DbSet<TProfile> Profiles { get; set; }
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
using AyCode.Core.Extensions;
|
using AyCode.Core.Logger;
|
||||||
using AyCode.Core.Logger;
|
|
||||||
using AyCode.Entities.Users;
|
using AyCode.Entities.Users;
|
||||||
using AyCode.Interfaces.Entities;
|
using AyCode.Interfaces.Entities;
|
||||||
using AyCode.Interfaces.Profiles;
|
using AyCode.Interfaces.Profiles;
|
||||||
|
|
@ -9,31 +8,21 @@ namespace AyCode.Database.DbSets.Users;
|
||||||
|
|
||||||
public static class AcUserDbSetExtensions
|
public static class AcUserDbSetExtensions
|
||||||
{
|
{
|
||||||
public static TUser? AuthenticateUser<TUser>(this IAcUserDbSetBase<TUser> ctx, string? email, string? passwordHash, bool onlyConfirmed) where TUser : class, IAcUserBase
|
public static TUser? GetUserById<TUser>(this IAcUserDbSetBase<TUser> ctx, Guid userId) where TUser : class, IAcUserBase
|
||||||
{
|
=> ctx.GetUsersById(userId).FirstOrDefault();
|
||||||
if (string.IsNullOrWhiteSpace(email) || string.IsNullOrWhiteSpace(passwordHash))
|
|
||||||
return null;
|
|
||||||
|
|
||||||
return ctx.GetUsersByEmail(email, onlyConfirmed).SingleOrDefault(u => u.Password == passwordHash);
|
public static TUser? GetUserByEmail<TUser>(this IAcUserDbSetBase<TUser> ctx, string email) where TUser : class, IAcUserBase
|
||||||
}
|
=> ctx.GetUsersByEmail(email).FirstOrDefault();
|
||||||
|
|
||||||
public static TUser? GetUserById<TUser>(this IAcUserDbSetBase<TUser> ctx, Guid userId, bool onlyConfirmed) where TUser : class, IAcUserBase
|
public static IQueryable<TUser> GetUsersById<TUser>(this IAcUserDbSetBase<TUser> ctx, Guid userId) where TUser : class, IAcUserBase
|
||||||
=> ctx.GetUsersById(userId, onlyConfirmed).FirstOrDefault();
|
=> ctx.Users.Where(u => u.Id == userId);
|
||||||
|
|
||||||
public static TUser? GetUserByEmail<TUser>(this IAcUserDbSetBase<TUser> ctx, string? email, bool onlyConfirmed) where TUser : class, IAcUserBase
|
public static IQueryable<TUser> GetUsersByEmail<TUser>(this IAcUserDbSetBase<TUser> ctx, string email) where TUser : class, IAcUserBase
|
||||||
{
|
|
||||||
return string.IsNullOrWhiteSpace(email) ? null : ctx.GetUsersByEmail(email, onlyConfirmed).FirstOrDefault();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IQueryable<TUser> GetUsersById<TUser>(this IAcUserDbSetBase<TUser> ctx, Guid userId, bool onlyConfirmed) where TUser : class, IAcUserBase
|
|
||||||
=> ctx.Users.Where(u => u.Id == userId && (!onlyConfirmed || u.EmailConfirmed));
|
|
||||||
|
|
||||||
public static IQueryable<TUser> GetUsersByEmail<TUser>(this IAcUserDbSetBase<TUser> ctx, string email, bool onlyConfirmed) where TUser : class, IAcUserBase
|
|
||||||
{
|
{
|
||||||
Logger.Info($"GetUserByEmail: {email}");
|
Logger.Info($"GetUserByEmail: {email}");
|
||||||
|
|
||||||
var emailLower = email.ToLower();
|
var emailLower = email.ToLower();
|
||||||
return ctx.Users.Where(u => u.EmailAddress == emailLower && (!onlyConfirmed || u.EmailConfirmed));
|
return ctx.Users.Where(u => u.EmailAddress == emailLower);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool AddUser<TUser>(this IAcUserDbSetBase<TUser> ctx, TUser user) where TUser : class, IAcUserBase
|
public static bool AddUser<TUser>(this IAcUserDbSetBase<TUser> ctx, TUser user) where TUser : class, IAcUserBase
|
||||||
|
|
@ -45,40 +34,15 @@ public static class AcUserDbSetExtensions
|
||||||
return ctx.Users.Add(user).State == Microsoft.EntityFrameworkCore.EntityState.Added;
|
return ctx.Users.Add(user).State == Microsoft.EntityFrameworkCore.EntityState.Added;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool RemoveUser<TUser>(this IAcUserDbSetBase<TUser> ctx, TUser user) where TUser : class, IAcUserBase
|
public static bool RemoveUserAsync<TUser>(this IAcUserDbSetBase<TUser> ctx, TUser user) where TUser : class, IAcUserBase
|
||||||
=> ctx.Users.Remove(user).State == Microsoft.EntityFrameworkCore.EntityState.Deleted;
|
=> ctx.Users.Remove(user).State == Microsoft.EntityFrameworkCore.EntityState.Deleted;
|
||||||
|
|
||||||
public static bool RemoveUser<TUser>(this IAcUserDbSetBase<TUser> ctx, Guid userId) where TUser : class, IAcUserBase
|
public static bool RemoveUserAsync<TUser>(this IAcUserDbSetBase<TUser> ctx, Guid userId) where TUser : class, IAcUserBase
|
||||||
{
|
{
|
||||||
var user = ctx.GetUserById(userId, false);
|
var user = ctx.GetUserById(userId);
|
||||||
|
|
||||||
if (user == null) return false;
|
if (user == null) return false;
|
||||||
|
|
||||||
return ctx.RemoveUser(user);
|
return ctx.RemoveUserAsync(user);
|
||||||
}
|
|
||||||
|
|
||||||
public static bool UpdateJwtRefreshToken<TUser>(this IAcUserDbSetBase<TUser> ctx, TUser user, string refreshToken) where TUser : class, IAcUserBase
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(refreshToken)) return false;
|
|
||||||
|
|
||||||
user.RefreshToken = refreshToken;
|
|
||||||
ctx.Users.Update(user);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static TUser? UpdateJwtRefreshToken<TUser>(this IAcUserDbSetBase<TUser> ctx, string email, string refreshToken) where TUser : class, IAcUserBase
|
|
||||||
{
|
|
||||||
Console.WriteLine(@"UserDal Update refresh token");
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(refreshToken)) return null;
|
|
||||||
|
|
||||||
var existingUser = ctx.GetUserByEmail(email, true);
|
|
||||||
if (existingUser == null) return null;
|
|
||||||
|
|
||||||
existingUser.RefreshToken = refreshToken;
|
|
||||||
ctx.Users.Update(existingUser);
|
|
||||||
|
|
||||||
return existingUser;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -13,8 +13,8 @@ public abstract class AcAddress : IAcAddress
|
||||||
public bool IsValid { get; set; }
|
public bool IsValid { get; set; }
|
||||||
public bool IsHelper { get; set; }
|
public bool IsHelper { get; set; }
|
||||||
|
|
||||||
public double? Latitude { get; set; }
|
public double Latitude { get; set; }
|
||||||
public double? Longitude { get; set; }
|
public double Longitude { get; set; }
|
||||||
|
|
||||||
public string? AddressText { get; set; }
|
public string? AddressText { get; set; }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
using AyCode.Interfaces.Profiles;
|
using AyCode.Interfaces.Profiles;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using AyCode.Core.Extensions;
|
|
||||||
using AyCode.Interfaces.Addresses;
|
using AyCode.Interfaces.Addresses;
|
||||||
using AyCode.Utils.Extensions;
|
using AyCode.Utils.Extensions;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ namespace AyCode.Entities.Users
|
||||||
[Required, Column("Email")]
|
[Required, Column("Email")]
|
||||||
public string EmailAddress { get; set; }
|
public string EmailAddress { get; set; }
|
||||||
//public string NormalizedEmail { get; set; }
|
//public string NormalizedEmail { get; set; }
|
||||||
public string? PhoneNumber { get; set; }
|
public string PhoneNumber { get; set; }
|
||||||
public string Password { get; set; }
|
public string Password { get; set; }
|
||||||
public string? RefreshToken { get; set; }
|
public string? RefreshToken { get; set; }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,12 +6,4 @@
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\AyCode.Core.Server\AyCode.Core.Server.csproj" />
|
|
||||||
<ProjectReference Include="..\AyCode.Core\AyCode.Core.csproj" />
|
|
||||||
<ProjectReference Include="..\AyCode.Entities.Server\AyCode.Entities.Server.csproj" />
|
|
||||||
<ProjectReference Include="..\AyCode.Entities\AyCode.Entities.csproj" />
|
|
||||||
<ProjectReference Include="..\AyCode.Interfaces\AyCode.Interfaces.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
using AyCode.Core.Consts;
|
|
||||||
using AyCode.Interfaces.Addresses;
|
|
||||||
using AyCode.Interfaces.Profiles;
|
|
||||||
using AyCode.Interfaces.ServiceProviders;
|
|
||||||
using AyCode.Interfaces.Users;
|
|
||||||
|
|
||||||
namespace AyCode.Interfaces.Server.Logins;
|
|
||||||
|
|
||||||
public interface IAcLoggedInModelBase<TUser, TUserToken, TProfile, TServiceProvider, TUserToServiceProvider, TProfileAddress> : IAcLoginDtoBase
|
|
||||||
|
|
||||||
where TUser : class, IAcUser<TProfile, TServiceProvider, TUserToServiceProvider, TProfileAddress>
|
|
||||||
where TUserToken : class, IAcUserTokenBase
|
|
||||||
where TProfile : class, IAcProfile<TProfileAddress>
|
|
||||||
where TServiceProvider : class, IAcServiceProviderBase
|
|
||||||
where TUserToServiceProvider : class, IAcUserToServiceProviderBase
|
|
||||||
where TProfileAddress : class, IAcAddress
|
|
||||||
{
|
|
||||||
bool IsLoggedIn { get; }
|
|
||||||
TUser LoggedInUser { get; }
|
|
||||||
string AccessToken { get; }
|
|
||||||
AcErrorCode LoginErrorCode { get; set; }
|
|
||||||
|
|
||||||
void AddLoggedInUser(TUser user, string accessToken);
|
|
||||||
void Logout();
|
|
||||||
}
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
namespace AyCode.Interfaces.Server.Logins;
|
|
||||||
|
|
||||||
public interface IAcLoginDtoBase
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
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<TResultLoggedInModel, TUser, TUserToken, TProfile, TServiceProvider, TUserToServiceProvider, TProfileAddress> : IAcLoginServiceCommon<TUser, TProfile, TServiceProvider, TUserToServiceProvider, TProfileAddress>
|
|
||||||
where TResultLoggedInModel: class, IAcLoggedInModelBase<TUser, TUserToken, TProfile, TServiceProvider, TUserToServiceProvider, TProfileAddress>
|
|
||||||
|
|
||||||
where TUser : class, IAcUser<TProfile, TServiceProvider, TUserToServiceProvider, TProfileAddress>
|
|
||||||
where TUserToken : class, IAcUserTokenBase
|
|
||||||
where TProfile : class, IAcProfile<TProfileAddress>
|
|
||||||
where TServiceProvider : class, IAcServiceProviderBase
|
|
||||||
where TUserToServiceProvider : class, IAcUserToServiceProviderBase
|
|
||||||
where TProfileAddress : class, IAcAddress
|
|
||||||
{
|
|
||||||
public TResultLoggedInModel? LoggedInModel { get; }
|
|
||||||
|
|
||||||
public TResultLoggedInModel Login(string? email, string password);
|
|
||||||
public Task<TResultLoggedInModel> LoginAsync(string? email, string password);
|
|
||||||
}
|
|
||||||
|
|
@ -8,7 +8,7 @@ public interface IAcAddressDtoBase : IEntityGuid
|
||||||
public bool IsValid { get; set; }
|
public bool IsValid { get; set; }
|
||||||
public bool IsHelper { get; set; }
|
public bool IsHelper { get; set; }
|
||||||
|
|
||||||
public double? Latitude { get; set; }
|
public double Latitude { get; set; }
|
||||||
public double? Longitude { get; set; }
|
public double Longitude { get; set; }
|
||||||
public string? AddressText { get; set; }
|
public string? AddressText { get; set; }
|
||||||
}
|
}
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
using AyCode.Interfaces.Addresses;
|
|
||||||
using AyCode.Interfaces.Profiles;
|
|
||||||
using AyCode.Interfaces.ServiceProviders;
|
|
||||||
using AyCode.Interfaces.Users;
|
|
||||||
|
|
||||||
namespace AyCode.Interfaces.Logins;
|
|
||||||
|
|
||||||
public interface IAcLoginServiceBase<TUser, TProfile, TServiceProvider, TUserToServiceProvider, TProfileAddress> where TUser : class, IAcUser<TProfile, TServiceProvider, TUserToServiceProvider, TProfileAddress>
|
|
||||||
where TProfile : class, IAcProfile<TProfileAddress>
|
|
||||||
where TServiceProvider : class, IAcServiceProviderBase
|
|
||||||
where TUserToServiceProvider : class, IAcUserToServiceProviderBase
|
|
||||||
where TProfileAddress : class, IAcAddress
|
|
||||||
{
|
|
||||||
public bool IsLoggedIn { get; }
|
|
||||||
public TUser? LoggedInUser { get; }
|
|
||||||
}
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
using AyCode.Interfaces.Addresses;
|
|
||||||
using AyCode.Interfaces.Profiles;
|
|
||||||
using AyCode.Interfaces.ServiceProviders;
|
|
||||||
using AyCode.Interfaces.Users;
|
|
||||||
|
|
||||||
namespace AyCode.Interfaces.Logins;
|
|
||||||
|
|
||||||
public interface IAcLoginServiceClient<TUser, TProfile, TServiceProvider, TUserToServiceProvider, TProfileAddress> : IAcLoginServiceCommon<TUser, TProfile, TServiceProvider, TUserToServiceProvider, TProfileAddress>
|
|
||||||
where TUser : class, IAcUser<TProfile, TServiceProvider, TUserToServiceProvider, TProfileAddress>
|
|
||||||
where TProfile : class, IAcProfile<TProfileAddress>
|
|
||||||
where TServiceProvider : class, IAcServiceProviderBase
|
|
||||||
where TUserToServiceProvider : class, IAcUserToServiceProviderBase
|
|
||||||
where TProfileAddress : class, IAcAddress
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
using AyCode.Core.Consts;
|
|
||||||
using AyCode.Interfaces.Addresses;
|
|
||||||
using AyCode.Interfaces.Profiles;
|
|
||||||
using AyCode.Interfaces.ServiceProviders;
|
|
||||||
using AyCode.Interfaces.Users;
|
|
||||||
|
|
||||||
namespace AyCode.Interfaces.Logins;
|
|
||||||
|
|
||||||
public interface IAcLoginServiceCommon<TUser, TProfile, TServiceProvider, TUserToServiceProvider, TProfileAddress> : IAcLoginServiceBase<TUser, TProfile, TServiceProvider, TUserToServiceProvider, TProfileAddress>
|
|
||||||
where TUser : class, IAcUser<TProfile, TServiceProvider, TUserToServiceProvider, TProfileAddress>
|
|
||||||
where TProfile : class, IAcProfile<TProfileAddress>
|
|
||||||
where TServiceProvider : class, IAcServiceProviderBase
|
|
||||||
where TUserToServiceProvider : class, IAcUserToServiceProviderBase
|
|
||||||
where TProfileAddress : class, IAcAddress
|
|
||||||
{
|
|
||||||
public bool Logout();
|
|
||||||
public Task<bool> LogoutAsync();
|
|
||||||
|
|
||||||
public AcErrorCode Registration(string email, string password, string? phoneNumber = null);
|
|
||||||
public AcErrorCode Registration(Guid userId, string email, string password, string? phoneNumber = null);
|
|
||||||
public Task<AcErrorCode> RegistrationAsync(string email, string password, string? phoneNumber = null);
|
|
||||||
public Task<AcErrorCode> RegistrationAsync(Guid userId, string email, string password, string? phoneNumber = null);
|
|
||||||
}
|
|
||||||
|
|
@ -6,7 +6,7 @@ namespace AyCode.Interfaces.Users;
|
||||||
|
|
||||||
public interface IAcUserBase : IEntityGuid, IAcProfileForeignKey, IEmailAddress, IEmailConfirmed, IPassword, ITimeStampInfo
|
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 string? RefreshToken { get; set; }
|
||||||
|
|
||||||
public Guid? RefferalId { get; set; }
|
public Guid? RefferalId { get; set; }
|
||||||
|
|
|
||||||
|
|
@ -1,38 +0,0 @@
|
||||||
using AyCode.Core.Consts;
|
|
||||||
using AyCode.Interfaces.Addresses;
|
|
||||||
using AyCode.Interfaces.Profiles;
|
|
||||||
using AyCode.Interfaces.ServiceProviders;
|
|
||||||
using AyCode.Interfaces.Users;
|
|
||||||
using AyCode.Interfaces.Server.Logins;
|
|
||||||
|
|
||||||
namespace AyCode.Models.Server.Logins;
|
|
||||||
|
|
||||||
public class AcLoggedInModelServer<TResultLoggedInModel, TUser, TUserToken, TProfile, TServiceProvider, TUserToServiceProvider, TProfileAddress> : IAcLoggedInModelBase<TUser, TUserToken, TProfile, TServiceProvider, TUserToServiceProvider, TProfileAddress>
|
|
||||||
|
|
||||||
where TUser : class, IAcUser<TProfile, TServiceProvider, TUserToServiceProvider, TProfileAddress>
|
|
||||||
where TUserToken : class, IAcUserTokenBase
|
|
||||||
where TProfile : class, IAcProfile<TProfileAddress>
|
|
||||||
where TServiceProvider : class, IAcServiceProviderBase
|
|
||||||
where TUserToServiceProvider : class, IAcUserToServiceProviderBase
|
|
||||||
where TProfileAddress : class, IAcAddress
|
|
||||||
{
|
|
||||||
public bool IsLoggedIn => LoggedInUser != null;
|
|
||||||
|
|
||||||
public TUser LoggedInUser { get; private set; }
|
|
||||||
public string AccessToken { get; private set; }
|
|
||||||
public AcErrorCode LoginErrorCode { get; set; }
|
|
||||||
|
|
||||||
public void AddLoggedInUser(TUser user, string accessToken)
|
|
||||||
{
|
|
||||||
LoggedInUser = user;
|
|
||||||
AccessToken = accessToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Logout()
|
|
||||||
{
|
|
||||||
AccessToken = string.Empty;
|
|
||||||
LoggedInUser = null;
|
|
||||||
|
|
||||||
LoginErrorCode = AcErrorCode.Unset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -6,14 +6,14 @@
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Folder Include="Logins\" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\AyCode.Core\AyCode.Core.csproj" />
|
<ProjectReference Include="..\AyCode.Core\AyCode.Core.csproj" />
|
||||||
<ProjectReference Include="..\AyCode.Entities\AyCode.Entities.csproj" />
|
<ProjectReference Include="..\AyCode.Entities\AyCode.Entities.csproj" />
|
||||||
<ProjectReference Include="..\AyCode.Interfaces\AyCode.Interfaces.csproj" />
|
<ProjectReference Include="..\AyCode.Interfaces\AyCode.Interfaces.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Folder Include="Logins\" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
using AyCode.Interfaces.Entities;
|
||||||
|
|
||||||
|
namespace AyCode.Models.Logins;
|
||||||
|
|
||||||
|
public interface IAcLoginDtoBase : IEntityGuid
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
|
|
||||||
<IsPackable>false</IsPackable>
|
|
||||||
<IsTestProject>true</IsTestProject>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="coverlet.collector" Version="6.0.2">
|
|
||||||
<PrivateAssets>all</PrivateAssets>
|
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
|
||||||
</PackageReference>
|
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="8.0.0" />
|
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" />
|
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
|
|
||||||
<PackageReference Include="MSTest.TestAdapter" Version="3.3.1" />
|
|
||||||
<PackageReference Include="MSTest.TestFramework" Version="3.3.1" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\AyCode.Core.Server\AyCode.Core.Server.csproj" />
|
|
||||||
<ProjectReference Include="..\AyCode.Core\AyCode.Core.csproj" />
|
|
||||||
<ProjectReference Include="..\AyCode.Database.Tests\AyCode.Database.Tests.csproj" />
|
|
||||||
<ProjectReference Include="..\AyCode.Database\AyCode.Database.csproj" />
|
|
||||||
<ProjectReference Include="..\AyCode.Entities.Server\AyCode.Entities.Server.csproj" />
|
|
||||||
<ProjectReference Include="..\AyCode.Entities\AyCode.Entities.csproj" />
|
|
||||||
<ProjectReference Include="..\AyCode.Interfaces.Server\AyCode.Interfaces.Server.csproj" />
|
|
||||||
<ProjectReference Include="..\AyCode.Interfaces\AyCode.Interfaces.csproj" />
|
|
||||||
<ProjectReference Include="..\AyCode.Models.Server\AyCode.Models.Server.csproj" />
|
|
||||||
<ProjectReference Include="..\AyCode.Models\AyCode.Models.csproj" />
|
|
||||||
<ProjectReference Include="..\AyCode.Services\AyCode.Services.csproj" />
|
|
||||||
<ProjectReference Include="..\AyCode.Utils.Server\AyCode.Utils.Server.csproj" />
|
|
||||||
<ProjectReference Include="..\AyCode.Utils\AyCode.Utils.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Using Include="Microsoft.VisualStudio.TestTools.UnitTesting" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
|
|
@ -1,31 +0,0 @@
|
||||||
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<TDal, TDbContext, TLoginServiceServer, TResultLoggedInModel, TUser, TProfile, TUserToken, TServiceProvider, TUserToServiceProvider, TProfileAddress> : AcDatabaseTestModelBase<TDal, TDbContext>
|
|
||||||
where TDal : AcUserDalBase<TDbContext, TUser, TProfile, TUserToken, TServiceProvider, TUserToServiceProvider, TProfileAddress>
|
|
||||||
where TDbContext : AcDbContextBase, IAcUserDbContextBase<TUser, TProfile, TUserToken,TServiceProvider, TUserToServiceProvider, TProfileAddress>
|
|
||||||
where TLoginServiceServer : class, IAcLoginServiceServer<TResultLoggedInModel, TUser, TUserToken, TProfile, TServiceProvider, TUserToServiceProvider, TProfileAddress>
|
|
||||||
where TResultLoggedInModel: class, IAcLoggedInModelBase<TUser, TUserToken, TProfile, TServiceProvider, TUserToServiceProvider, TProfileAddress>
|
|
||||||
where TUser : class, IAcUser<TProfile, TServiceProvider, TUserToServiceProvider, TProfileAddress>
|
|
||||||
where TProfile : class, IAcProfile<TProfileAddress>
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Configuration" Version="8.0.0" />
|
||||||
<PackageReference Include="SendGrid" Version="9.29.3" />
|
<PackageReference Include="SendGrid" Version="9.29.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
@ -26,7 +26,6 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Folder Include="Messages\" />
|
<Folder Include="Messages\" />
|
||||||
<Folder Include="Emails\" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
||||||
|
|
@ -1,50 +0,0 @@
|
||||||
using AyCode.Core.Consts;
|
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
using SendGrid.Helpers.Mail;
|
|
||||||
using SendGrid;
|
|
||||||
|
|
||||||
namespace AyCode.Services.Server.Emails;
|
|
||||||
|
|
||||||
public interface IAcEmailServiceServer
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
public class AcEmailServiceServer() : IAcEmailServiceServer
|
|
||||||
{
|
|
||||||
private IConfiguration _configuration;
|
|
||||||
private readonly SendGridClient _sendGridClient;
|
|
||||||
private readonly EmailAddress _fromEmailAddress;
|
|
||||||
|
|
||||||
public AcEmailServiceServer(IConfiguration configuration) : this()
|
|
||||||
{
|
|
||||||
_configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
|
|
||||||
//_sendGridClient = new SendGridClient(_configuration.ServerUserName);
|
|
||||||
//_fromEmailAddress = new EmailAddress(_configuration.FromEmail, _configuration.FromName);
|
|
||||||
|
|
||||||
//Console.WriteLine($"{config.ServerUserName}; {config.FromEmail}; {config.FromName}");
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<Response> SendLostPasswordEmailAsync(string addressEmail, string verificationToken)
|
|
||||||
{
|
|
||||||
const string subject = "Lost password";
|
|
||||||
var toEmailAddress = new EmailAddress(addressEmail);
|
|
||||||
|
|
||||||
var plainTextContent = $"{verificationToken}";
|
|
||||||
var htmlContent = $"<strong>{verificationToken}</strong>";
|
|
||||||
|
|
||||||
var msg = MailHelper.CreateSingleEmail(_fromEmailAddress, toEmailAddress, subject, plainTextContent, htmlContent);
|
|
||||||
return await _sendGridClient.SendEmailAsync(msg).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<Response> SendRegistrationEmailAsync(string addressEmail, string verificationToken, string userName)
|
|
||||||
{
|
|
||||||
const string subject = "Registration";
|
|
||||||
var toEmailAddress = new EmailAddress(addressEmail);
|
|
||||||
|
|
||||||
var plainTextContent = $"User name: {userName}{AcEnv.NL}Confirmation token: {verificationToken}";
|
|
||||||
var htmlContent = $"User name: <strong>{userName}</strong></br>Confirmation token: <strong>{verificationToken}</strong>";
|
|
||||||
|
|
||||||
var msg = MailHelper.CreateSingleEmail(_fromEmailAddress, toEmailAddress, subject, plainTextContent, htmlContent);
|
|
||||||
return await _sendGridClient.SendEmailAsync(msg).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,192 +0,0 @@
|
||||||
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.Server.Logins;
|
|
||||||
using AyCode.Utils.Extensions;
|
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
|
|
||||||
namespace AyCode.Services.Server.Logins;
|
|
||||||
|
|
||||||
public class AcLoginServiceServer<TResultLoggedInModel, TDal, TDbContext, TUser, TUserToken, TProfile, TServiceProvider, TUserToServiceProvider, TProfileAddress>(TDal userDal, IConfiguration configuration)
|
|
||||||
: AcLoginServiceBase<TUser, TProfile, TServiceProvider, TUserToServiceProvider, TProfileAddress>, IAcLoginServiceServer<TResultLoggedInModel, TUser, TUserToken, TProfile, TServiceProvider, TUserToServiceProvider, TProfileAddress>
|
|
||||||
|
|
||||||
where TResultLoggedInModel : class, IAcLoggedInModelBase<TUser, TUserToken, TProfile, TServiceProvider, TUserToServiceProvider, TProfileAddress>
|
|
||||||
where TDal : AcUserDalBase<TDbContext, TUser, TProfile, TUserToken, TServiceProvider, TUserToServiceProvider, TProfileAddress>
|
|
||||||
where TDbContext : AcDbContextBase, IAcUserDbContextBase<TUser, TProfile, TUserToken, TServiceProvider, TUserToServiceProvider, TProfileAddress>
|
|
||||||
where TUser : class, IAcUser<TProfile, TServiceProvider, TUserToServiceProvider, TProfileAddress>
|
|
||||||
where TUserToken : class, IAcUserTokenBase
|
|
||||||
where TProfile : class, IAcProfile<TProfileAddress>
|
|
||||||
where TServiceProvider : class, IAcServiceProviderBase
|
|
||||||
where TUserToServiceProvider : class, IAcUserToServiceProviderBase
|
|
||||||
where TProfileAddress : class, IAcAddress
|
|
||||||
{
|
|
||||||
public TResultLoggedInModel? LoggedInModel { get; private set; }
|
|
||||||
public override TUser? LoggedInUser => LoggedInModel?.LoggedInUser;
|
|
||||||
public override bool IsLoggedIn => LoggedInModel?.IsLoggedIn ?? false;
|
|
||||||
|
|
||||||
public virtual TResultLoggedInModel Login(string? email, string? password)
|
|
||||||
{
|
|
||||||
if (LoggedInModel != null) Logout();
|
|
||||||
|
|
||||||
LoggedInModel = Activator.CreateInstance<TResultLoggedInModel>();
|
|
||||||
|
|
||||||
if (AcValidate.IsValidEmailAndPasswordFormat(email, password, out var errorCode))
|
|
||||||
{
|
|
||||||
var user = userDal.AuthenticateUser(email, password, GenerateRefreshToken(), out errorCode);
|
|
||||||
|
|
||||||
if (user != null) LoggedInModel.AddLoggedInUser(user, GenerateAccessToken(user));
|
|
||||||
}
|
|
||||||
|
|
||||||
LoggedInModel.LoginErrorCode = errorCode;
|
|
||||||
|
|
||||||
return LoggedInModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual Task<TResultLoggedInModel> LoginAsync(string? email, string? password)
|
|
||||||
{
|
|
||||||
return TaskHelper.ToThreadPoolTask(() => Login(email, password));
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual bool Logout()
|
|
||||||
{
|
|
||||||
LoggedInModel?.Logout();
|
|
||||||
LoggedInModel = null;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual Task<bool> LogoutAsync()
|
|
||||||
{
|
|
||||||
return TaskHelper.ToThreadPoolTask(Logout);
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual AcErrorCode Registration(string email, string password, string? phoneNumber = null)
|
|
||||||
=> Registration(Guid.NewGuid(), email, password, phoneNumber);
|
|
||||||
|
|
||||||
public virtual AcErrorCode 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 errorCode;
|
|
||||||
|
|
||||||
var user = Activator.CreateInstance<TUser>();
|
|
||||||
user.Id = userId;
|
|
||||||
user.EmailAddress = email;
|
|
||||||
user.EmailConfirmed = true;
|
|
||||||
user.Password = PasswordHasher.HashPassword(password, PasswordHasher.GenerateDynamicSalt(userId));
|
|
||||||
|
|
||||||
var address = Activator.CreateInstance<TProfileAddress>();
|
|
||||||
address.Id = Guid.NewGuid();
|
|
||||||
|
|
||||||
var userName = email.Split('@')[0]; //TODO: generálni egy nevet... - J.
|
|
||||||
|
|
||||||
if (!userDal.AddUser(user, userName, address)) errorCode = AcErrorCode.DatabaseError;
|
|
||||||
|
|
||||||
return errorCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public virtual Task<AcErrorCode> RegistrationAsync(string email, string password, string? phoneNumber = null)
|
|
||||||
=> RegistrationAsync(Guid.NewGuid(), email, password, phoneNumber);
|
|
||||||
|
|
||||||
public virtual Task<AcErrorCode> RegistrationAsync(Guid userId, string email, string password, string? phoneNumber = null)
|
|
||||||
=> TaskHelper.ToThreadPoolTask(() => Registration(userId, email, password, phoneNumber));
|
|
||||||
|
|
||||||
public virtual bool SendConfirmationToken(string? email, string confirmationToken)
|
|
||||||
{
|
|
||||||
//var sendGrid = SendGrid.SendGridClient();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual Task<bool> SendConfirmationTokenAsync(string email, string confirmationToken)
|
|
||||||
=> TaskHelper.ToThreadPoolTask(() => SendConfirmationToken(email, confirmationToken));
|
|
||||||
|
|
||||||
public 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<Claim>
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
public 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string GenerateRefreshToken()
|
|
||||||
{
|
|
||||||
var randomNumber = new byte[32];
|
|
||||||
|
|
||||||
using var rng = RandomNumberGenerator.Create();
|
|
||||||
rng.GetBytes(randomNumber);
|
|
||||||
|
|
||||||
return Convert.ToBase64String(randomNumber);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -6,10 +6,6 @@
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.4" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\AyCode.Core\AyCode.Core.csproj" />
|
<ProjectReference Include="..\AyCode.Core\AyCode.Core.csproj" />
|
||||||
<ProjectReference Include="..\AyCode.Entities\AyCode.Entities.csproj" />
|
<ProjectReference Include="..\AyCode.Entities\AyCode.Entities.csproj" />
|
||||||
|
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
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<TUser, TProfile, TServiceProvider, TUserToServiceProvider, TProfileAddress> : IAcLoginServiceBase<TUser, TProfile, TServiceProvider, TUserToServiceProvider, TProfileAddress>
|
|
||||||
where TUser : class, IAcUser<TProfile, TServiceProvider, TUserToServiceProvider, TProfileAddress>
|
|
||||||
where TProfile : class, IAcProfile<TProfileAddress>
|
|
||||||
where TServiceProvider : class, IAcServiceProviderBase
|
|
||||||
where TUserToServiceProvider : class, IAcUserToServiceProviderBase
|
|
||||||
where TProfileAddress : class, IAcAddress
|
|
||||||
{
|
|
||||||
public virtual bool IsLoggedIn => LoggedInUser != null;
|
|
||||||
public virtual TUser? LoggedInUser { get; protected set; }
|
|
||||||
}
|
|
||||||
|
|
@ -1,59 +0,0 @@
|
||||||
using AyCode.Core.Consts;
|
|
||||||
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<TUser, TProfile, TServiceProvider, TUserToServiceProvider, TProfileAddress>
|
|
||||||
: AcLoginServiceBase<TUser, TProfile, TServiceProvider, TUserToServiceProvider, TProfileAddress>, IAcLoginServiceClient<TUser, TProfile, TServiceProvider, TUserToServiceProvider, TProfileAddress>
|
|
||||||
|
|
||||||
where TUser : class, IAcUser<TProfile, TServiceProvider, TUserToServiceProvider, TProfileAddress>
|
|
||||||
where TProfile : class, IAcProfile<TProfileAddress>
|
|
||||||
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<TUser?> LoginAsync(string email, string password)
|
|
||||||
{
|
|
||||||
return TaskHelper.ToThreadPoolTask(() => Login(email, password, out _));
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual bool Logout()
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual Task<bool> LogoutAsync()
|
|
||||||
{
|
|
||||||
return TaskHelper.ToThreadPoolTask(Logout);
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual AcErrorCode Registration(string email, string password, string? phoneNumber = null)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public AcErrorCode Registration(Guid userId, string email, string password, string? phoneNumber = null)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual Task<AcErrorCode> RegistrationAsync(string email, string password, string? phoneNumber = null)
|
|
||||||
{
|
|
||||||
return TaskHelper.ToThreadPoolTask(() => Registration(email, password, phoneNumber));
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<AcErrorCode> RegistrationAsync(Guid userId, string email, string password, string? phoneNumber = null)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -8,11 +8,7 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="JetBrains.Annotations" Version="2023.3.0" />
|
<PackageReference Include="JetBrains.Annotations" Version="2023.3.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="8.0.4" />
|
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="8.0.3" />
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Folder Include="Helpers\" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Text;
|
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
|
|
||||||
namespace AyCode.Core.Extensions
|
namespace AyCode.Utils.Extensions
|
||||||
{
|
{
|
||||||
public static class StringExtensions
|
public static class StringExtensions
|
||||||
{
|
{
|
||||||
|
|
@ -37,41 +36,5 @@ namespace AyCode.Core.Extensions
|
||||||
|
|
||||||
return char.ToUpper(str[0]) + str[1..];
|
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);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Example : chars1=ABC, chars2=DEF ==> ADBECF
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="firstChars"></param>
|
|
||||||
/// <param name="secondChars"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static string MixCharacters(this IEnumerable<char> firstChars, IEnumerable<char> 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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
using Microsoft.AspNetCore.Cryptography.KeyDerivation;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
|
namespace AyCode.Utils.Helpers
|
||||||
|
{
|
||||||
|
public class PasswordHasher
|
||||||
|
{
|
||||||
|
public string HashPassword(string password)
|
||||||
|
{
|
||||||
|
// Generate a random salt
|
||||||
|
byte[] 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));
|
||||||
|
|
||||||
|
// Combine the salt and hashed password
|
||||||
|
string combinedHash = $"$bcrypt$v=1$salt={Convert.ToBase64String(salt)}$hash={hashedPassword}";
|
||||||
|
|
||||||
|
return combinedHash;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool VerifyPassword(string password, string hashedPassword)
|
||||||
|
{
|
||||||
|
// Extract the salt and hashed password from the combined hash
|
||||||
|
string[] parts = hashedPassword.Split('$');
|
||||||
|
byte[] salt = Convert.FromBase64String(parts[3]);
|
||||||
|
string storedHash = parts[5];
|
||||||
|
|
||||||
|
// Hash the provided password with the extracted salt
|
||||||
|
string hashedProvidedPassword = Convert.ToBase64String(KeyDerivation.Pbkdf2(
|
||||||
|
password: password,
|
||||||
|
salt: salt,
|
||||||
|
prf: KeyDerivationPrf.HMACSHA512,
|
||||||
|
iterationCount: 10000,
|
||||||
|
numBytesRequested: 32));
|
||||||
|
|
||||||
|
// Compare the hashed passwords
|
||||||
|
return storedHash == hashedProvidedPassword;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Loading…
Reference in New Issue