1
0
mirror of https://github.com/XFox111/SimpleOTP.git synced 2026-04-22 08:00:45 +03:00

Major 2.0 (#20)

* New 2.0 version + DependencyInjection library

* Updated docs and repo settings (devcontainers, vscode, github, etc.)

* Added tests

* Fixed bugs

* Minor test project refactoring

* Updated projects
- Added symbol packages
- Updated package versions to pre-release

* Updated SECURITY.md

* Added GitHub Actions workflows
This commit is contained in:
2024-09-26 03:20:30 +03:00
committed by GitHub
parent 42f968171b
commit 1b989e7b35
87 changed files with 4076 additions and 2532 deletions
+66
View File
@@ -0,0 +1,66 @@
using NUnit.Framework;
namespace SimpleOTP.Tests;
[TestFixture]
public class ConfigTests
{
private static readonly byte[] secretBytes = [0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x21, 0xde, 0xad, 0xbe, 0xef];
private const string username = "eugene@xfox111.net";
private const string appName = "Example App";
private const string issuer = "example.com";
[TestCase("otpauth://totp/eugene%40xfox111.net?secret=JBSWY3DPEHPK3PXP&issuer=example.com&algorithm=SHA1&digits=6&period=30",
"SHA1", OtpType.Totp, 6, 30, null)]
[TestCase("otpauth://totp/Example%20App:eugene%40xfox111.net?secret=JBSWY3DPEHPK3PXP&issuer=example.com&algorithm=SHA1&digits=6&period=30",
"SHA1", OtpType.Totp, 6, 30, appName)]
[TestCase("apple-otpauth://totp/Example%20App:eugene%40xfox111.net?secret=JBSWY3DPEHPK3PXP&issuer=example.com&algorithm=SHA1&digits=6&period=30",
"SHA1", OtpType.Totp, 6, 30, appName)]
[TestCase("otpauth://totp/Example%20App:eugene%40xfox111.net?secret=JBSWY3DPEHPK3PXP&issuer=example.com&algorithm=SHA256&digits=8&period=60",
"SHA256", OtpType.Totp, 8, 60, appName)]
[TestCase("otpauth://totp/eugene%40xfox111.net?secret=JBSWY3DPEHPK3PXP&issuer=example.com&algorithm=SHA512&digits=6&period=30",
"SHA512", OtpType.Totp, 6, 30, null)]
[TestCase("otpauth://hotp/eugene%40xfox111.net?secret=JBSWY3DPEHPK3PXP&issuer=example.com&algorithm=SHA512&digits=6&counter=0",
"SHA512", OtpType.Hotp, 6, 30, null)]
[TestCase("otpauth://hotp/eugene%40xfox111.net?secret=JBSWY3DPEHPK3PXP&issuer=example.com&algorithm=HmacSHA512&digits=6&counter=0",
"SHA512", OtpType.Hotp, 6, 30, null)]
public void ParseTest(string uri, string algorithm, OtpType type, int digits, int period, string? appName)
{
OtpConfig config = OtpConfig.ParseUri(uri);
Assert.That(config.Label, Is.EqualTo(username));
Assert.That(config.Secret, Is.EqualTo(secretBytes));
Assert.That(config.Issuer, Is.EqualTo(issuer));
Assert.That(config.IssuerLabel, Is.EqualTo(appName));
Assert.That(config.Algorithm, Is.EqualTo(algorithm));
Assert.That(config.Digits, Is.EqualTo(digits));
Assert.That(config.Period, Is.EqualTo(period));
Assert.That(config.Type, Is.EqualTo(type));
}
[TestCase(OtpUriFormat.Google | OtpUriFormat.Minimal, false,
"otpauth://totp/eugene%40xfox111.net?secret=JBSWY3DPEHPK3PXP&issuer=example.com")]
[TestCase(OtpUriFormat.Google | OtpUriFormat.Full, false,
"otpauth://totp/eugene%40xfox111.net?secret=JBSWY3DPEHPK3PXP&issuer=example.com&algorithm=SHA1&digits=6&period=30")]
[TestCase(OtpUriFormat.Apple | OtpUriFormat.Minimal, true,
"apple-otpauth://totp/Example%20App:eugene%40xfox111.net?secret=JBSWY3DPEHPK3PXP&issuer=example.com")]
[TestCase(OtpUriFormat.Apple | OtpUriFormat.Full, true,
"apple-otpauth://totp/Example%20App:eugene%40xfox111.net?secret=JBSWY3DPEHPK3PXP&issuer=example.com&algorithm=SHA1&digits=6&period=30")]
[TestCase(OtpUriFormat.IBM | OtpUriFormat.Full, false,
"otpauth://totp/eugene%40xfox111.net?secret=JBSWY3DPEHPK3PXP&issuer=example.com&algorithm=HmacSHA1&digits=6&period=30")]
public void ToUriTest(OtpUriFormat format, bool appendIssuerLabel, string expectedUri)
{
OtpConfig config = new(username)
{
Issuer = issuer,
Secret = OtpSecret.FromBytes(secretBytes)
};
if (appendIssuerLabel)
config.IssuerLabel = appName;
Uri uri = config.ToUri(format);
Assert.That(uri.AbsoluteUri, Is.EqualTo(expectedUri));
}
}
+23
View File
@@ -0,0 +1,23 @@
<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="Microsoft.NET.Test.Sdk" Version="17.6.0" />
<PackageReference Include="NUnit" Version="4.2.2" />
<PackageReference Include="NUnit3TestAdapter" Version="4.6.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\libraries\SimpleOTP\SimpleOTP.csproj" />
<ProjectReference Include="..\libraries\SimpleOTP.DependencyInjection\SimpleOTP.DependencyInjection.csproj" />
</ItemGroup>
</Project>
+63
View File
@@ -0,0 +1,63 @@
using NUnit.Framework;
namespace SimpleOTP.Tests;
[TestFixture]
public class TotpTests
{
private const string secret1 = "GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ";
private const string secret2 = "GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQGEZA";
private const string secret3 = "GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQGEZDGNA";
[TestCase(secret1, "SHA1", 59, "94287082", 60)]
[TestCase(secret2, "SHA256", 59, "46119246", 60)]
[TestCase(secret3, "SHA512", 59, "90693936", 60)]
[TestCase(secret1, "SHA1", 1111111109, "07081804", 1111111110)]
[TestCase(secret2, "SHA256", 1111111109, "68084774", 1111111110)]
[TestCase(secret3, "SHA512", 1111111109, "25091201", 1111111110)]
[TestCase(secret1, "SHA1", 1111111111, "14050471", 1111111140)]
[TestCase(secret2, "SHA256", 1111111111, "67062674", 1111111140)]
[TestCase(secret3, "SHA512", 1111111111, "99943326", 1111111140)]
[TestCase(secret1, "SHA1", 1234567890, "89005924", 1234567920)]
[TestCase(secret2, "SHA256", 1234567890, "91819424", 1234567920)]
[TestCase(secret3, "SHA512", 1234567890, "93441116", 1234567920)]
[TestCase(secret1, "SHA1", 2000000000, "69279037", 2000000010)]
[TestCase(secret2, "SHA256", 2000000000, "90698825", 2000000010)]
[TestCase(secret3, "SHA512", 2000000000, "38618901", 2000000010)]
[TestCase(secret1, "SHA1", 20000000000, "65353130", 20000000010)]
[TestCase(secret2, "SHA256", 20000000000, "77737706", 20000000010)]
[TestCase(secret3, "SHA512", 20000000000, "47863826", 20000000010)]
[TestCase(secret1, "SHA1", 20000000000, "353130", 20000000010)]
[TestCase(secret2, "SHA256", 20000000000, "737706", 20000000010)]
[TestCase(secret3, "SHA512", 20000000000, "863826", 20000000010)]
public void ComputeTest(string secret, string algorithm, long timestamp, string expectedOtp, long expectedExpiration)
{
using OtpSecret otpSecret = OtpSecret.Parse(secret);
Totp totp = new(otpSecret, 30, (OtpAlgorithm)algorithm, expectedOtp.Length);
DateTimeOffset time = DateTimeOffset.FromUnixTimeSeconds(timestamp);
OtpCode code = totp.Generate(time);
Assert.That(code.ToString(), Is.EqualTo(expectedOtp));
Assert.That(code.ExpirationTime, Is.EqualTo(DateTimeOffset.FromUnixTimeSeconds(expectedExpiration)));
}
[TestCase(59, "287082", 1, true, 0)]
[TestCase(0, "287082", 1, true, 1)]
[TestCase(10, "287082", 0, false, 0)]
[TestCase(20000000000, "353130", 1, true, 0)]
[TestCase(20000000030, "353130", 0, false, 0)]
[TestCase(20000000030, "353130", 1, true, -1)]
[TestCase(20000000060, "353130", 1, false, 0)]
[TestCase(20000000060, "353130", 2, true, -2)]
public void ValidateOffsetTest(long timestamp, string code, int toleranceWindow, bool expectedResult, int expectedResync)
{
using OtpSecret secret = OtpSecret.Parse(secret1);
Totp totp = new(secret, 30, code.Length);
DateTimeOffset time = DateTimeOffset.FromUnixTimeSeconds(timestamp);
bool result = totp.Validate((OtpCode)code, toleranceWindow, time, out int resyncValue);
Assert.That(result, Is.EqualTo(expectedResult));
Assert.That(resyncValue, Is.EqualTo(expectedResync));
}
}