119 lines
3.8 KiB
C#
119 lines
3.8 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using Paca.Core.Config;
|
|
using Paca.Core.Security;
|
|
using Xunit;
|
|
|
|
namespace Paca.Tests.Core;
|
|
|
|
public class SecurityAndConfigExtremeRedTests
|
|
{
|
|
private const string TestBase32Secret = "JBSWY3DPEHPK3PXP"; // "Hello!" in Base32
|
|
|
|
[Theory]
|
|
[InlineData(0)]
|
|
[InlineData(-10)]
|
|
[InlineData(-1)]
|
|
public void TotpEngine_ZeroOrNegativeTimeStep_DoesNotThrowDivideByZero(int timeStep)
|
|
{
|
|
var ex = Record.Exception(() =>
|
|
TotpEngine.GenerateCurrentCode(TestBase32Secret, timeStepSeconds: timeStep));
|
|
Assert.Null(ex);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(0)]
|
|
[InlineData(-30)]
|
|
public void TotpEngine_GetRemainingSeconds_ZeroOrNegativeTimeStep_DoesNotThrowDivideByZero(int timeStep)
|
|
{
|
|
var ex = Record.Exception(() =>
|
|
TotpEngine.GetRemainingSeconds(timeStepSeconds: timeStep));
|
|
Assert.Null(ex);
|
|
var remaining = TotpEngine.GetRemainingSeconds(timeStepSeconds: timeStep);
|
|
Assert.True(remaining > 0);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(0)]
|
|
[InlineData(-5)]
|
|
[InlineData(20)]
|
|
public void TotpEngine_InvalidDigits_ClampedToValidRange(int digits)
|
|
{
|
|
var code = TotpEngine.GenerateCurrentCode(TestBase32Secret, digits: digits);
|
|
Assert.True(code.Length >= 6 && code.Length <= 8);
|
|
}
|
|
|
|
[Fact]
|
|
public void CredentialSecurityAuditor_NullCredentials_ReturnsSafeReport()
|
|
{
|
|
var report = CredentialSecurityAuditor.PerformAudit(null!);
|
|
Assert.NotNull(report);
|
|
Assert.Equal(0, report.TotalAccounts);
|
|
Assert.Equal(100, report.OverallHealthScore);
|
|
}
|
|
|
|
[Fact]
|
|
public void CredentialSecurityAuditor_NegativeDays_ClampsToPositive()
|
|
{
|
|
var cred = new SiteCredentialRecord
|
|
{
|
|
Id = "1",
|
|
Domain = "example.com",
|
|
Username = "user",
|
|
DecryptedPassword = "SuperSecurePassword123!",
|
|
CreatedAt = DateTime.UtcNow,
|
|
LastModifiedAt = DateTime.UtcNow
|
|
};
|
|
|
|
var report = CredentialSecurityAuditor.PerformAudit(new[] { cred }, oldPasswordDays: -10);
|
|
Assert.Equal(0, report.OldPasswordCount);
|
|
}
|
|
|
|
[Fact]
|
|
public void CredentialSecurityAuditor_RecentlyModified_NotMarkedAsOldEvenIfCreatedLongAgo()
|
|
{
|
|
var cred = new SiteCredentialRecord
|
|
{
|
|
Id = "1",
|
|
Domain = "example.com",
|
|
Username = "user",
|
|
DecryptedPassword = "SuperSecurePassword123!",
|
|
CreatedAt = DateTime.UtcNow.AddDays(-200), // Created 200 days ago
|
|
LastModifiedAt = DateTime.UtcNow // But modified today!
|
|
};
|
|
|
|
var report = CredentialSecurityAuditor.PerformAudit(new[] { cred }, oldPasswordDays: 90);
|
|
Assert.Equal(0, report.OldPasswordCount);
|
|
Assert.DoesNotContain(report.Issues, i => i.IssueType == "OldPassword");
|
|
}
|
|
|
|
[Fact]
|
|
public void WorkspaceConfigSanitizer_ExcessiveWorkspaces_CappedTo20()
|
|
{
|
|
var many = Enumerable.Range(1, 100).Select(i => $"Workspace_{i}").ToList();
|
|
var sanitized = WorkspaceConfigSanitizer.Sanitize(many);
|
|
Assert.True(sanitized.Count <= 20);
|
|
}
|
|
|
|
[Fact]
|
|
public void WorkspaceConfigSanitizer_OverlyLongName_TruncatedSafely()
|
|
{
|
|
var longName = new string('A', 200);
|
|
var sanitized = WorkspaceConfigSanitizer.Sanitize(new[] { longName });
|
|
Assert.Single(sanitized);
|
|
Assert.True(sanitized[0].Length <= 30);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(null)]
|
|
[InlineData("")]
|
|
[InlineData(" ")]
|
|
public void PasswordSecurityEngine_EvaluateStrength_NullOrWhitespace_ReturnsZeroScore(string? emptyPass)
|
|
{
|
|
var result = PasswordSecurityEngine.EvaluateStrength(emptyPass!);
|
|
Assert.NotNull(result);
|
|
Assert.Equal(0, result.Score);
|
|
Assert.Equal(PasswordGrade.VeryWeak, result.Grade);
|
|
}
|
|
}
|