fix(epub): resolve PR #65 review comments for EPUB image rendering, path traversal validation, and security sanitization
This commit is contained in:
@@ -177,6 +177,96 @@ public class EpubReaderServiceTests : IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SanitizeParagraph_StripsUnsafeAttributesFromImgTags()
|
||||
{
|
||||
// Arrange
|
||||
var method = typeof(EpubReaderService).GetMethod("SanitizeParagraph", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
|
||||
method.Should().NotBeNull();
|
||||
|
||||
var input = "<img src=\"images/cover.jpg\" alt=\"Cover Image\" onerror=\"alert(1)\" onload=\"evil()\" style=\"color:red\" class=\"img-responsive\" />";
|
||||
|
||||
// Act
|
||||
var result = (string)method.Invoke(null, new object[] { input });
|
||||
|
||||
// Assert
|
||||
result.Should().NotContain("onerror");
|
||||
result.Should().NotContain("onload");
|
||||
result.Should().NotContain("style");
|
||||
result.Should().NotContain("class");
|
||||
result.Should().Contain("src=\"images/cover.jpg\"");
|
||||
result.Should().Contain("alt=\"Cover Image\"");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RewriteImageUrls_BlocksJavaScriptScheme()
|
||||
{
|
||||
// Arrange
|
||||
var method = typeof(EpubReaderService).GetMethod("RewriteImageUrls", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
|
||||
method.Should().NotBeNull();
|
||||
|
||||
var input = "<img src=\"javascript:alert(1)\" />";
|
||||
var ebookId = Guid.NewGuid();
|
||||
|
||||
// Act
|
||||
var result = (string)method.Invoke(null, new object[] { input, ebookId, "OEBPS/chapter1.xhtml" });
|
||||
|
||||
// Assert
|
||||
result.Should().NotContain("javascript:alert(1)");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetEpubResourceAsync_RejectsInvalidResourcePaths()
|
||||
{
|
||||
// Arrange
|
||||
var ebookId = Guid.NewGuid();
|
||||
var userId = "test-user-id";
|
||||
|
||||
using (var context = new AppDbContext(_contextOptions))
|
||||
{
|
||||
var user = new NexusUser
|
||||
{
|
||||
Id = userId,
|
||||
UserName = "testuser",
|
||||
Email = "test@nexus.com",
|
||||
TenantId = "tenant-123",
|
||||
SubscriptionPlanId = 1
|
||||
};
|
||||
context.Users.Add(user);
|
||||
|
||||
var author = new Author { Id = 10, Name = "Giorgio Vasari" };
|
||||
context.Authors.Add(author);
|
||||
|
||||
var ebook = new Ebook
|
||||
{
|
||||
Id = ebookId,
|
||||
UserId = userId,
|
||||
Title = "Test Book",
|
||||
AuthorId = author.Id,
|
||||
FilePath = "assets/book.epub",
|
||||
AddedDate = DateTime.UtcNow,
|
||||
LastReadDate = DateTime.UtcNow,
|
||||
Progress = 0,
|
||||
LastChapter = "Introduction"
|
||||
};
|
||||
context.Ebooks.Add(ebook);
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
var service = new EpubReaderService(_dbContextFactoryMock.Object, _loggerMock.Object);
|
||||
|
||||
// Act
|
||||
var traversalResult = await service.GetEpubResourceAsync(ebookId, "../../appsettings.json", userId);
|
||||
var colonResult = await service.GetEpubResourceAsync(ebookId, "C:\\windows\\win.ini", userId);
|
||||
|
||||
// Assert
|
||||
traversalResult.IsSuccess.Should().BeFalse();
|
||||
traversalResult.Errors.First().Message.Should().Contain("Invalid resource path");
|
||||
|
||||
colonResult.IsSuccess.Should().BeFalse();
|
||||
colonResult.Errors.First().Message.Should().Contain("Invalid resource path");
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_connection.Close();
|
||||
|
||||
Reference in New Issue
Block a user