From 085f37de160c0efc2b0d0449db194a0b4b77a94a Mon Sep 17 00:00:00 2001 From: Developer 02 Date: Tue, 10 Dec 2024 22:05:52 +0100 Subject: [PATCH] =?UTF-8?q?feat(CodeGenerator):=20Die=20Methoden=20Generat?= =?UTF-8?q?eTotpSecretKey,=20GenerateTotpQrCode=20und=20GenerateTotpQrCode?= =?UTF-8?q?=20wurden=20als=20Schnittstellenimplementierung=20hinzugef?= =?UTF-8?q?=C3=BCgt.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Configurations/CodeGeneratorConfig.cs | 7 ---- .../Configurations/CodeGeneratorParams.cs | 18 +++++++++ .../Contracts/ICodeGenerator.cs | 6 +++ .../Extensions/DIExtensions.cs | 6 ++- .../Extensions/MappingExtensions.cs | 3 ++ .../Services/CodeGenerator.cs | 39 ++++++++++++++++--- 6 files changed, 65 insertions(+), 14 deletions(-) delete mode 100644 EnvelopeGenerator.Application/Configurations/CodeGeneratorConfig.cs create mode 100644 EnvelopeGenerator.Application/Configurations/CodeGeneratorParams.cs diff --git a/EnvelopeGenerator.Application/Configurations/CodeGeneratorConfig.cs b/EnvelopeGenerator.Application/Configurations/CodeGeneratorConfig.cs deleted file mode 100644 index b44c989a..00000000 --- a/EnvelopeGenerator.Application/Configurations/CodeGeneratorConfig.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace EnvelopeGenerator.Application.Configurations -{ - public class CodeGeneratorConfig - { - public string CharPool { get; init; } = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890123456789012345678901234567890123456789"; - } -} \ No newline at end of file diff --git a/EnvelopeGenerator.Application/Configurations/CodeGeneratorParams.cs b/EnvelopeGenerator.Application/Configurations/CodeGeneratorParams.cs new file mode 100644 index 00000000..f4c8e1b1 --- /dev/null +++ b/EnvelopeGenerator.Application/Configurations/CodeGeneratorParams.cs @@ -0,0 +1,18 @@ +namespace EnvelopeGenerator.Application.Configurations +{ + public class CodeGeneratorParams + { + public string CharPool { get; init; } = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890123456789012345678901234567890123456789"; + + public int DefaultTotpSecretKeyLength { get; init; } = 32; + + public string TotpIssuer { get; init; } = "signFlow"; + + /// + /// 0 is user email, 1 is secret key and 2 is issuer. + /// + public string TotpUrlFormat { get; init; } = "otpauth://totp/{0}?secret={1}&issuer={2}"; + + public int TotpQRPixelsPerModule { get; init; } = 20; + } +} \ No newline at end of file diff --git a/EnvelopeGenerator.Application/Contracts/ICodeGenerator.cs b/EnvelopeGenerator.Application/Contracts/ICodeGenerator.cs index 4a282c66..38a27b85 100644 --- a/EnvelopeGenerator.Application/Contracts/ICodeGenerator.cs +++ b/EnvelopeGenerator.Application/Contracts/ICodeGenerator.cs @@ -3,5 +3,11 @@ public interface ICodeGenerator { string GenerateCode(int length); + + public string GenerateTotpSecretKey(int? length = null); + + public byte[] GenerateTotpQrCode(string userEmail, string secretKey, string? issuer = null, string? totpUrlFormat = null, int? pixelsPerModule = null); + + public byte[] GenerateTotpQrCode(string userEmail, int? length = null, string? issuer = null, string? totpUrlFormat = null, int? pixelsPerModule = null); } } \ No newline at end of file diff --git a/EnvelopeGenerator.Application/Extensions/DIExtensions.cs b/EnvelopeGenerator.Application/Extensions/DIExtensions.cs index 3c1c62d5..ae8fedf9 100644 --- a/EnvelopeGenerator.Application/Extensions/DIExtensions.cs +++ b/EnvelopeGenerator.Application/Extensions/DIExtensions.cs @@ -10,6 +10,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using DigitalData.Core.Client; using EnvelopeGenerator.Application.Configurations.GtxMessaging; +using QRCoder; namespace EnvelopeGenerator.Application.Extensions { @@ -55,13 +56,14 @@ namespace EnvelopeGenerator.Application.Extensions services.Configure(dispatcherConfigSection); services.Configure(mailConfigSection); - services.Configure(codeGeneratorConfigSection); + services.Configure(codeGeneratorConfigSection); services.Configure(envelopeReceiverCacheParamsSection); services.AddHttpClientService(smsConfigSection); services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(); + services.TryAddSingleton(); return services; } @@ -70,7 +72,7 @@ namespace EnvelopeGenerator.Application.Extensions dispatcherConfigSection: config.GetSection("DispatcherConfig"), mailConfigSection: config.GetSection("MailConfig"), smsConfigSection: config.GetSection("SmsConfig"), - codeGeneratorConfigSection: config.GetSection("CodeGeneratorConfig"), + codeGeneratorConfigSection: config.GetSection("CodeGeneratorParams"), envelopeReceiverCacheParamsSection: config.GetSection("EnvelopeReceiverCacheParams")); } } \ No newline at end of file diff --git a/EnvelopeGenerator.Application/Extensions/MappingExtensions.cs b/EnvelopeGenerator.Application/Extensions/MappingExtensions.cs index 0d7f19c8..bd996b58 100644 --- a/EnvelopeGenerator.Application/Extensions/MappingExtensions.cs +++ b/EnvelopeGenerator.Application/Extensions/MappingExtensions.cs @@ -7,5 +7,8 @@ namespace EnvelopeGenerator.Application.Extensions public static bool Ok(this GtxMessagingResponse gtxMessagingResponse) => gtxMessagingResponse.TryGetValue("message-status", out var status) && status?.ToString()?.ToLower() == "ok"; + + public static string ToBase64String(this byte[] bytes) + => Convert.ToBase64String(bytes); } } \ No newline at end of file diff --git a/EnvelopeGenerator.Application/Services/CodeGenerator.cs b/EnvelopeGenerator.Application/Services/CodeGenerator.cs index 7b3f4b3c..89d22522 100644 --- a/EnvelopeGenerator.Application/Services/CodeGenerator.cs +++ b/EnvelopeGenerator.Application/Services/CodeGenerator.cs @@ -1,21 +1,26 @@ using EnvelopeGenerator.Application.Configurations; using EnvelopeGenerator.Application.Contracts; using Microsoft.Extensions.Options; +using OtpNet; +using QRCoder; using System.Text; namespace EnvelopeGenerator.Application.Services { public class CodeGenerator : ICodeGenerator { - public static Lazy LazyStatic => new(() => new CodeGenerator(Options.Create(new()))); + public static Lazy LazyStatic => new(() => new CodeGenerator(Options.Create(new()), new QRCodeGenerator())); public static CodeGenerator Static => LazyStatic.Value; - private readonly string _charPool; + private readonly CodeGeneratorParams _params; - public CodeGenerator(IOptions options) + private readonly QRCodeGenerator _qrCodeGenerator; + + public CodeGenerator(IOptions options, QRCodeGenerator qrCodeGenerator) { - _charPool = options.Value.CharPool; + _params = options.Value; + _qrCodeGenerator = qrCodeGenerator; } public string GenerateCode(int length) @@ -29,9 +34,33 @@ namespace EnvelopeGenerator.Application.Services var passwordBuilder = new StringBuilder(length); for (int i = 0; i < length; i++) - passwordBuilder.Append(_charPool[random.Next(_charPool.Length)]); + passwordBuilder.Append(_params.CharPool[random.Next(_params.CharPool.Length)]); return passwordBuilder.ToString(); } + + public string GenerateTotpSecretKey(int? length = null) + => Base32Encoding.ToString(KeyGeneration.GenerateRandomKey(length ?? _params.DefaultTotpSecretKeyLength)); + + public byte[] GenerateTotpQrCode(string userEmail, string secretKey, string? issuer = null, string? totpUrlFormat = null, int? pixelsPerModule = null) + { + var url = string.Format(totpUrlFormat ?? _params.TotpUrlFormat, + Uri.EscapeDataString(userEmail), + Uri.EscapeDataString(secretKey), + Uri.EscapeDataString(issuer ?? _params.TotpIssuer)); + using var qrCodeData = _qrCodeGenerator.CreateQrCode(url, QRCodeGenerator.ECCLevel.Q); + using var qrCode = new BitmapByteQRCode(qrCodeData); + return qrCode.GetGraphic(pixelsPerModule ?? _params.TotpQRPixelsPerModule); + } + + public byte[] GenerateTotpQrCode(string userEmail, int? length = null, string? issuer = null, string? totpUrlFormat = null, int? pixelsPerModule = null) + { + return GenerateTotpQrCode( + userEmail: userEmail, + secretKey: GenerateTotpSecretKey(length: length), + issuer: issuer, + totpUrlFormat: totpUrlFormat, + pixelsPerModule: pixelsPerModule); + } } } \ No newline at end of file