mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-11 02:46:16 -08:00
fix(backup): invalidate restored stalker state
This commit is contained in:
1 parent
f5090d623e
commit
8f7c4761ea
4 files changed
+138
-1
No files matched your search
@@ -212,6 +212,14 @@ test.describe('Electron playlist backup security acceptance', () => {
|
||||
},
|
||||
},
|
||||
skippedXtream,
|
||||
{
|
||||
...redactedStalker,
|
||||
connection: { ...redactedStalker.connection },
|
||||
userState: {
|
||||
favorites: [],
|
||||
recentlyViewed: [],
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
writeFileSync(
|
||||
@@ -278,7 +286,7 @@ test.describe('Electron playlist backup security acceptance', () => {
|
||||
|
||||
await expect(
|
||||
app.mainWindow.getByText(
|
||||
'Backup import finished: 0 imported, 1 merged, 1 skipped, 0 failed.'
|
||||
'Backup import finished: 0 imported, 2 merged, 1 skipped, 0 failed.'
|
||||
)
|
||||
).toBeVisible({ timeout: 15000 });
|
||||
|
||||
@@ -304,6 +312,32 @@ test.describe('Electron playlist backup security acceptance', () => {
|
||||
await readPlaylist(app.mainWindow, SKIPPED_XTREAM_PLAYLIST_ID)
|
||||
).toBeNull();
|
||||
|
||||
const restoredStalker = await readPlaylist(
|
||||
app.mainWindow,
|
||||
STALKER_PLAYLIST_ID
|
||||
);
|
||||
expect(restoredStalker).toMatchObject({
|
||||
_id: STALKER_PLAYLIST_ID,
|
||||
password: STALKER_PASSWORD,
|
||||
stalkerIdentityOverrides: {
|
||||
deviceId1: 'STRUCTURED-BACKUP-DEVICE-1',
|
||||
serialNumber: STALKER_STRUCTURED_SERIAL,
|
||||
},
|
||||
username: STALKER_USERNAME,
|
||||
});
|
||||
expect(restoredStalker).not.toHaveProperty('stalkerAccountInfo');
|
||||
expect(restoredStalker).not.toHaveProperty('stalkerLandingUrl');
|
||||
expect(restoredStalker).not.toHaveProperty(
|
||||
'stalkerLastVerifiedAt'
|
||||
);
|
||||
expect(restoredStalker).not.toHaveProperty(
|
||||
'stalkerRecipeClassifierVersion'
|
||||
);
|
||||
expect(restoredStalker).not.toHaveProperty(
|
||||
'stalkerRequestRecipe'
|
||||
);
|
||||
expect(restoredStalker).not.toHaveProperty('stalkerToken');
|
||||
|
||||
const allPlaylists = await readAllPlaylists(app.mainWindow);
|
||||
expect(allPlaylists).toHaveLength(2);
|
||||
expect(
|
||||
|
||||
@@ -72,6 +72,10 @@ export async function seedProviderPlaylists(page: Page): Promise<void> {
|
||||
id: 'mag250-public-5_1-minimal-v1',
|
||||
version: 1,
|
||||
},
|
||||
stalkerLandingUrl: 'https://stalker-backup.test/c/',
|
||||
stalkerLastVerifiedAt: '2026-07-27T10:00:00.000Z',
|
||||
stalkerRecipeClassifierVersion: 1,
|
||||
stalkerRequestRecipe: 'stateless-mac',
|
||||
stalkerSerialNumber: STALKER_LEGACY_SERIAL,
|
||||
stalkerSignature1: STALKER_LEGACY_SIGNATURE_1,
|
||||
stalkerSignature2: STALKER_LEGACY_SIGNATURE_2,
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
import { of } from 'rxjs';
|
||||
import {
|
||||
Playlist,
|
||||
PlaylistBackupManifestV1,
|
||||
PLAYLIST_BACKUP_KIND,
|
||||
PLAYLIST_BACKUP_VERSION,
|
||||
StalkerPlaylistBackupEntry,
|
||||
} from '@iptvnator/shared/interfaces';
|
||||
import { createPlaylistBackupService } from './playlist-backup.service.test-helpers';
|
||||
|
||||
describe('PlaylistBackupService Stalker learned-state restore', () => {
|
||||
it.each([false, true])(
|
||||
'clears excluded learned connection state when merging a %s-secret backup',
|
||||
async (includeSecrets) => {
|
||||
const local: Playlist = {
|
||||
_id: 'stalker-backup',
|
||||
title: 'Local Stalker',
|
||||
count: 1,
|
||||
importDate: '2026-07-01T00:00:00.000Z',
|
||||
lastUsage: '2026-07-01T00:00:00.000Z',
|
||||
autoRefresh: false,
|
||||
portalUrl: 'https://portal.test/server/load.php',
|
||||
stalkerSourceUrl: 'https://portal.test/c/',
|
||||
macAddress: '00:1A:79:AA:BB:CC',
|
||||
stalkerProfilePreset: {
|
||||
id: 'mag250-public-5_1-minimal-v1',
|
||||
version: 1,
|
||||
},
|
||||
username: 'local-user',
|
||||
password: 'local-password',
|
||||
stalkerIdentityOverrides: {
|
||||
serialNumber: 'LOCAL-SERIAL',
|
||||
},
|
||||
stalkerLandingUrl: 'https://portal.test/c/',
|
||||
stalkerLastVerifiedAt: '2026-07-27T10:00:00.000Z',
|
||||
stalkerRecipeClassifierVersion: 1,
|
||||
stalkerRequestRecipe: 'stateless-mac',
|
||||
} as Playlist;
|
||||
const backupEntry: StalkerPlaylistBackupEntry = {
|
||||
portalType: 'stalker',
|
||||
exportedId: local._id,
|
||||
title: 'Restored Stalker',
|
||||
autoRefresh: false,
|
||||
connection: {
|
||||
portalUrl: local.portalUrl as string,
|
||||
sourceUrl: local.stalkerSourceUrl,
|
||||
macAddress: local.macAddress as string,
|
||||
profilePreset: local.stalkerProfilePreset,
|
||||
...(includeSecrets
|
||||
? {
|
||||
identityOverrides:
|
||||
local.stalkerIdentityOverrides,
|
||||
username: local.username,
|
||||
password: 'replacement-password',
|
||||
}
|
||||
: {}),
|
||||
},
|
||||
userState: {
|
||||
favorites: [],
|
||||
recentlyViewed: [],
|
||||
},
|
||||
};
|
||||
const manifest: PlaylistBackupManifestV1 = {
|
||||
kind: PLAYLIST_BACKUP_KIND,
|
||||
version: PLAYLIST_BACKUP_VERSION,
|
||||
exportedAt: '2026-07-27T00:00:00.000Z',
|
||||
includeSecrets,
|
||||
playlists: [backupEntry],
|
||||
};
|
||||
const playlistsService = {
|
||||
addPlaylist: jest.fn((playlist: Playlist) => of(playlist)),
|
||||
getAllData: jest.fn(() => of([local])),
|
||||
getRawPlaylistById: jest.fn(() => of('#EXTM3U')),
|
||||
handlePlaylistParsing: jest.fn(),
|
||||
};
|
||||
const service = createPlaylistBackupService({
|
||||
playlistsService,
|
||||
});
|
||||
|
||||
await expect(
|
||||
service.importBackup(JSON.stringify(manifest))
|
||||
).resolves.toMatchObject({ imported: 0, merged: 1, failed: 0 });
|
||||
|
||||
expect(playlistsService.addPlaylist).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
_id: local._id,
|
||||
stalkerLandingUrl: undefined,
|
||||
stalkerLastVerifiedAt: undefined,
|
||||
stalkerRecipeClassifierVersion: undefined,
|
||||
stalkerRequestRecipe: undefined,
|
||||
})
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
@@ -1215,6 +1215,10 @@ export class PlaylistBackupService {
|
||||
...(hasOwn(entry.connection, 'stalkerSignature2')
|
||||
? { stalkerSignature2: entry.connection.stalkerSignature2 }
|
||||
: {}),
|
||||
stalkerLandingUrl: undefined,
|
||||
stalkerLastVerifiedAt: undefined,
|
||||
stalkerRecipeClassifierVersion: undefined,
|
||||
stalkerRequestRecipe: undefined,
|
||||
stalkerToken: undefined,
|
||||
stalkerAccountInfo: undefined,
|
||||
};
|
||||
|
||||
Reference in new issue
Block a user