mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-14 13:16:16 -08:00
fix(settings): fail closed for direct worker title lookups and capture the Stalker lock dialog context before the PIN
Catalog title matching and multi-source discovery query the SQLite worker directly; they now return nothing while the parental lock withholds everything (unreadable store or a bridge without the worker filter). The Stalker lock dialog captures its playlist, provider and section before the PIN prompt and re-checks them after it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
b5ba77b67b
commit
4ddacab663
7 files changed
+143
-18
No files matched your search
+29
@@ -966,6 +966,35 @@ describe('WorkspaceContextPanelComponent', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('opens nothing when the route changed while the PIN was asked', async () => {
|
||||
enableLock();
|
||||
fixture.componentRef.setInput('context', {
|
||||
provider: 'stalker',
|
||||
playlistId: 'stalker-1',
|
||||
});
|
||||
fixture.componentRef.setInput('section', 'itv');
|
||||
fixture.detectChanges();
|
||||
const parentalLock = TestBed.inject(ParentalLockService);
|
||||
jest.spyOn(parentalLock, 'requestUnlock').mockImplementation(
|
||||
async () => {
|
||||
fixture.componentRef.setInput('context', {
|
||||
provider: 'xtreams',
|
||||
playlistId: 'xtream-2',
|
||||
});
|
||||
return true;
|
||||
}
|
||||
);
|
||||
const component = fixture.componentInstance;
|
||||
component.loadStalkerLockDialog = jest.fn(
|
||||
async () => class DialogStub {}
|
||||
);
|
||||
|
||||
await component.openManageStalkerCategories();
|
||||
|
||||
expect(component.loadStalkerLockDialog).not.toHaveBeenCalled();
|
||||
expect(dialog.open).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('opens nothing when the route changed during the lazy import', async () => {
|
||||
enableLock();
|
||||
fixture.componentRef.setInput('context', {
|
||||
|
||||
+15
-11
@@ -533,26 +533,30 @@ export class WorkspaceContextPanelComponent {
|
||||
if (!this.canManageStalkerCategories()) {
|
||||
return;
|
||||
}
|
||||
if (!(await this.parentalLock.requestUnlock())) {
|
||||
return;
|
||||
}
|
||||
// Captured before any await (the PIN prompt loads lazily on first
|
||||
// use) and re-checked after each: the store follows the CURRENT
|
||||
// route, and another portal's categories must not reach a dialog
|
||||
// that saves them under this playlist.
|
||||
const context = this.context();
|
||||
const section = this.section();
|
||||
const contentType = toParentalLockStalkerCategoryType(section);
|
||||
if (!contentType) {
|
||||
const unchanged = (): boolean =>
|
||||
this.context().playlistId === context.playlistId &&
|
||||
this.context().provider === context.provider &&
|
||||
this.section() === section &&
|
||||
this.canManageStalkerCategories();
|
||||
if (!contentType || !(await this.parentalLock.requestUnlock())) {
|
||||
return;
|
||||
}
|
||||
// Snapshot before the lazy import: the store follows the CURRENT
|
||||
// route, so reading it afterwards could hand another portal's
|
||||
// categories to a dialog that saves them under this playlist.
|
||||
if (!unchanged()) {
|
||||
return;
|
||||
}
|
||||
// Snapshot before the lazy import, for the same reason.
|
||||
const categories = this.stalkerStore
|
||||
.getAllCategoriesForSelectedType()
|
||||
.filter((category) => String(category.category_id) !== '*');
|
||||
const dialogComponent = await this.loadStalkerLockDialog();
|
||||
if (
|
||||
this.context().playlistId !== context.playlistId ||
|
||||
this.section() !== section
|
||||
) {
|
||||
if (!unchanged()) {
|
||||
return;
|
||||
}
|
||||
this.dialog.open(dialogComponent, {
|
||||
|
||||
Reference in new issue
Block a user