From f866fb2c800ce4f919a2367e9a1f589e965cb8e9 Mon Sep 17 00:00:00 2001 From: Eugene Fox Date: Sun, 30 May 2021 18:12:45 +0300 Subject: [PATCH] Updated validation methods signatures (#13) Improved code coverage results --- README.md | 2 +- .../Models/OTPConfigurationUnitTest.cs | 3 ++- SimpleOTP.Test/OTPFactoryUnitTest.cs | 3 ++- SimpleOTP.Test/OTPServiceUnitTest.cs | 26 +++++++++++-------- SimpleOTP/OTPService.cs | 18 +++++++++++-- SimpleOTP/SimpleOTP.csproj | 14 ++-------- 6 files changed, 38 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 0136632..d663734 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ OTPCode code = OTPService.GenerateCode(ref config); ### Validate code ```csharp int codeToValidate = 350386; -bool isValid = OTPService.ValidateCode(codeToValidate, config, TimeSpan.FromSeconds(30)); // True +bool isValid = OTPService.ValidateTotp(codeToValidate, config, TimeSpan.FromSeconds(30)); // True ``` ### Generate setup config diff --git a/SimpleOTP.Test/Models/OTPConfigurationUnitTest.cs b/SimpleOTP.Test/Models/OTPConfigurationUnitTest.cs index 6dcf87d..ad34ac6 100644 --- a/SimpleOTP.Test/Models/OTPConfigurationUnitTest.cs +++ b/SimpleOTP.Test/Models/OTPConfigurationUnitTest.cs @@ -26,7 +26,8 @@ namespace SimpleOTP.Test.Models public void TestShortLinkGenerator() { OTPConfiguration config = OTPConfiguration.GenerateConfiguration("FoxDev Studio", "eugene@xfox111.net"); - System.Diagnostics.Debug.WriteLine(config.Id); + var testId = config.Id; + System.Diagnostics.Debug.WriteLine(testId); Uri uri = config.GetUri(); Assert.AreEqual($"otpauth://totp/FoxDev+Studio:eugene@xfox111.net?secret={config.Secret}&issuer=FoxDev+Studio", uri.AbsoluteUri); } diff --git a/SimpleOTP.Test/OTPFactoryUnitTest.cs b/SimpleOTP.Test/OTPFactoryUnitTest.cs index 27bdf23..0582817 100644 --- a/SimpleOTP.Test/OTPFactoryUnitTest.cs +++ b/SimpleOTP.Test/OTPFactoryUnitTest.cs @@ -29,7 +29,8 @@ namespace SimpleOTP.Test OTPConfiguration config = OTPConfiguration.GetConfiguration("ESQVTYRM2CWZC3NX24GRRWIAUUWVHWQH", "FoxDev Studio", "eugene@xfox111.net"); config.Period = TimeSpan.FromSeconds(3); using OTPFactory factory = new (config, 1500); - System.Diagnostics.Debug.WriteLine(factory.Configuration); + var testGetConfig = factory.Configuration; + System.Diagnostics.Debug.WriteLine(testGetConfig); var code = factory.CurrentCode; factory.Configuration = config; diff --git a/SimpleOTP.Test/OTPServiceUnitTest.cs b/SimpleOTP.Test/OTPServiceUnitTest.cs index e279842..a5238bd 100644 --- a/SimpleOTP.Test/OTPServiceUnitTest.cs +++ b/SimpleOTP.Test/OTPServiceUnitTest.cs @@ -66,13 +66,15 @@ namespace SimpleOTP.Test OTPService.GenerateCode(ref totpConfig, DateTime.UtcNow.AddSeconds(15)).Code, OTPService.GenerateCode(ref totpConfig, DateTime.UtcNow.AddSeconds(45)).Code, }; - Assert.IsFalse(OTPService.ValidateCode(codes[0], totpConfig)); - Assert.IsTrue(OTPService.ValidateCode(codes[1], totpConfig)); - Assert.IsTrue(OTPService.ValidateCode(codes[2], totpConfig)); - Assert.IsTrue(OTPService.ValidateCode(codes[3], totpConfig)); - Assert.IsFalse(OTPService.ValidateCode(codes[4], totpConfig)); + Assert.IsFalse(OTPService.ValidateTotp(codes[0], totpConfig)); + Assert.IsTrue(OTPService.ValidateTotp(codes[1], totpConfig)); + Assert.IsTrue(OTPService.ValidateTotp(codes[2], totpConfig)); + Assert.IsTrue(OTPService.ValidateTotp(codes[3], totpConfig)); + Assert.IsFalse(OTPService.ValidateTotp(codes[4], totpConfig)); - Assert.IsTrue(OTPService.ValidateCode(codes[0], totpConfig, TimeSpan.FromSeconds(60))); + Assert.IsTrue(OTPService.ValidateTotp(codes[0], totpConfig, TimeSpan.FromSeconds(60))); + + Assert.ThrowsException(() => OTPService.ValidateTotp(0, hotpConfig)); } /// @@ -92,19 +94,21 @@ namespace SimpleOTP.Test }; hotpConfig.Counter = 10002; - Assert.IsFalse(OTPService.ValidateCode(codes[0], ref hotpConfig, 1, true)); + Assert.IsFalse(OTPService.ValidateHotp(codes[0], ref hotpConfig, 1, true)); Assert.AreEqual(10002, hotpConfig.Counter); - Assert.IsTrue(OTPService.ValidateCode(codes[1], ref hotpConfig, 1, true)); + Assert.IsTrue(OTPService.ValidateHotp(codes[1], ref hotpConfig, 1, true)); Assert.AreEqual(10001, hotpConfig.Counter); hotpConfig.Counter = 10002; - Assert.IsTrue(OTPService.ValidateCode(codes[2], ref hotpConfig, 1, true)); + Assert.IsTrue(OTPService.ValidateHotp(codes[2], ref hotpConfig, 1, true)); Assert.AreEqual(10002, hotpConfig.Counter); hotpConfig.Counter = 10002; - Assert.IsTrue(OTPService.ValidateCode(codes[3], ref hotpConfig, 1, true)); + Assert.IsTrue(OTPService.ValidateHotp(codes[3], ref hotpConfig, 1, true)); Assert.AreEqual(10003, hotpConfig.Counter); hotpConfig.Counter = 10002; - Assert.IsFalse(OTPService.ValidateCode(codes[4], ref hotpConfig, 1, true)); + Assert.IsFalse(OTPService.ValidateHotp(codes[4], ref hotpConfig, 1, true)); Assert.AreEqual(10002, hotpConfig.Counter); + + Assert.ThrowsException(() => OTPService.ValidateHotp(0, ref totpConfig, 1, true)); } } } \ No newline at end of file diff --git a/SimpleOTP/OTPService.cs b/SimpleOTP/OTPService.cs index d815e90..789909e 100644 --- a/SimpleOTP/OTPService.cs +++ b/SimpleOTP/OTPService.cs @@ -96,8 +96,10 @@ namespace SimpleOTP /// Counter span from which OTP codes remain valid. /// Defines whether method should resync of the or not after successful validation. /// True if code is valid, False if it isn't. - public static bool ValidateCode(int otp, ref OTPConfiguration target, int toleranceSpan, bool resyncCounter) + public static bool ValidateHotp(int otp, ref OTPConfiguration target, int toleranceSpan, bool resyncCounter) { + if (target?.Type != OTPType.HOTP) + throw new ArgumentException("Invalid configuration. This method only validates HOTP codes. For TOTP codes use OTPService.ValidateTotp()"); long currentCounter = target.Counter; List<(int Code, long Counter)> codes = new (); for (long i = currentCounter - toleranceSpan; i <= currentCounter + toleranceSpan; i++) @@ -123,8 +125,10 @@ namespace SimpleOTP /// Time span from which OTP codes remain valid.
/// Default: 15 seconds. /// True if code is valid, False if it isn't. - public static bool ValidateCode(int otp, OTPConfiguration target, TimeSpan? toleranceTime = null) + public static bool ValidateTotp(int otp, OTPConfiguration target, TimeSpan? toleranceTime = null) { + if (target?.Type != OTPType.TOTP) + throw new ArgumentException("Invalid configuration. This method only validates TOTP codes. For HOTP codes use OTPService.ValidateHotp()"); toleranceTime ??= TimeSpan.FromSeconds(15); DateTime now = DateTime.UtcNow; List codes = new (); @@ -134,6 +138,16 @@ namespace SimpleOTP return codes.Any(i => i == otp); } + /// + [Obsolete("Use ValidateHotp() instead.")] + public static bool ValidateCode(int otp, ref OTPConfiguration target, int toleranceSpan, bool resyncCounter) => + ValidateHotp(otp, ref target, toleranceSpan, resyncCounter); + + /// + [Obsolete("Use ValidateTotp() instead.")] + public static bool ValidateCode(int otp, OTPConfiguration target, TimeSpan? toleranceTime = null) => + ValidateTotp(otp, target, toleranceTime); + private static long GetCurrentCounter(DateTime date, int period) => (long)(date - DateTime.UnixEpoch).TotalSeconds / period; } diff --git a/SimpleOTP/SimpleOTP.csproj b/SimpleOTP/SimpleOTP.csproj index 852f9f7..af2e7a1 100644 --- a/SimpleOTP/SimpleOTP.csproj +++ b/SimpleOTP/SimpleOTP.csproj @@ -11,7 +11,7 @@ SimpleOTP SimpleOTP - 1.0.0 + 1.1.0 .NET library for TOTP/HOTP implementation on server (ASP.NET) or client (Xamarin) side Eugene Fox FoxDev Studio @@ -21,17 +21,7 @@ https://github.com/XFox111/SimpleOTP en-US otp;totp;dotnet;hotp;authenticator;2fa;mfa;security;oath - .NET library for TOTP/HOTP implementation on server (ASP.NET) or client (Xamarin) side - -Features -- Generate and validate OTP codes -- Support of TOTP (RFC 6238) and HOTP (RFC 4226) algorithms -- Support of HMAC-SHA1, HMAC-SHA256 and HMAC-SHA512 hashing algorithms -- Setup URI parser -- Database-ready configuration models -- Configuration generator for server-side implementation -- QR code generator -- No dependencies + - Updated OTP validation methods signatures: `ValidateCode()` is now deprecated and will be removed in future releases