Files
ersatztv/ErsatzTV.Tests/Controllers/IptvControllerCacheHeaderTests.cs
T
timothyandtimothy 0c063c23fb
Build ErsatzTV Image / API docs in sync (OpenAPI + endpoint index) (push) Has been skipped
Build ErsatzTV Image / Formatting (changed .cs conform to .editorconfig) (push) Has been skipped
Build ErsatzTV Image / Build & test (.NET) (push) Successful in 7m45s
Build ErsatzTV Image / Functional E2E (curl contracts) (push) Successful in 14m19s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (push) Successful in 18m27s
Build ErsatzTV Image / Build & push image (amd64) (push) Successful in 4m10s
harden(421,559): percent-encode access_token in IPTV URLs, redact from logs, no-store on tokened manifests (#574)
Co-authored-by: Timothy <timothy.look@gmail.com>
Co-committed-by: Timothy <timothy.look@gmail.com>
2026-07-23 16:30:59 +00:00

43 lines
1.5 KiB
C#

using ErsatzTV.Application.Channels;
using ErsatzTV.Controllers;
using ErsatzTV.Core.Interfaces.FFmpeg;
using ErsatzTV.Core.Interfaces.Streaming;
using ErsatzTV.Core.Iptv;
using MediatR;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using NSubstitute;
using NUnit.Framework;
using Shouldly;
namespace ErsatzTV.Tests.Controllers;
// #559: dynamic /iptv manifests embed the caller's access_token in their body/URLs, so the response must
// be marked no-store to keep a browser or intermediary from caching (and later replaying) the token.
[TestFixture]
public class IptvControllerCacheHeaderTests
{
[Test]
public async Task GetChannelPlaylist_sets_no_store()
{
var mediator = Substitute.For<IMediator>();
mediator.Send(Arg.Any<GetChannelPlaylist>(), Arg.Any<CancellationToken>())
.Returns(new ChannelPlaylist("https", "tv.example.com", string.Empty, [], "VLC/3.0", accessToken: null));
var controller = new IptvController(
mediator,
Substitute.For<IGraphicsEngine>(),
Substitute.For<ILogger<IptvController>>(),
Substitute.For<IFFmpegSegmenterService>(),
Substitute.For<IDirectStreamSessionTracker>())
{
ControllerContext = new ControllerContext { HttpContext = new DefaultHttpContext() }
};
await controller.GetChannelPlaylist();
controller.Response.Headers.CacheControl.ToString().ShouldBe("private, no-store");
}
}