Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions src/chrome/profile-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,25 @@ export class ProfileManager {
return false;
}

// Guard: if the persistent profile's Cookies file has been modified after
// the last sync, a headless session wrote cookies — do not overwrite them.
const persistentCookiesPath = path.join(
ProfileManager.PERSISTENT_PROFILE_DIR,
profileSubdir,
'Cookies'
);
try {
const persistentStat = fs.statSync(persistentCookiesPath);
if (persistentStat.mtimeMs > metadata.lastSyncTimestamp) {
console.error(
'[ProfileManager] Persistent profile cookies modified after last sync — skipping overwrite to preserve headless-acquired session'
);
return false;
}
} catch {
// Persistent Cookies file doesn't exist yet — sync is needed
}

if (currentHash !== metadata.sourceProfileHash) {
return true; // Source has changed
}
Expand Down
29 changes: 29 additions & 0 deletions tests/chrome/persistent-profile.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,35 @@ describe('ProfileManager', () => {
const manager = new ProfileManager();
expect(manager.needsSync(sourceDir)).toBe(false);
});

it('should return false when persistent profile Cookies were modified after last sync (headless guard)', () => {
// Set up source Cookies file and compute its hash
const cookiesPath = path.join(sourceDir, 'Default', 'Cookies');
fs.writeFileSync(cookiesPath, 'source-cookie-data');
const stat = fs.statSync(cookiesPath);
const hash = `${stat.mtimeMs}:${stat.size}`;

// Write metadata with an old timestamp (simulating last sync happened in the past)
const oldTimestamp = Date.now() - (40 * 60 * 1000); // 40 minutes ago
const metadata: SyncMetadata = {
lastSyncTimestamp: oldTimestamp,
sourceProfileHash: hash,
syncCount: 1,
sourceProfileDir: sourceDir,
};
fs.writeFileSync(ProfileManager.SYNC_METADATA_PATH, JSON.stringify(metadata));

// Create the persistent profile's Cookies file with a recent mtime
// (simulating a headless session that wrote cookies after the last sync)
const persistentCookiesDir = path.join(ProfileManager.PERSISTENT_PROFILE_DIR, 'Default');
fs.mkdirSync(persistentCookiesDir, { recursive: true });
fs.writeFileSync(path.join(persistentCookiesDir, 'Cookies'), 'headless-acquired-cookies');
// The persistent Cookies file was just written — its mtime is newer than oldTimestamp

const manager = new ProfileManager();
// Should NOT sync: persistent cookies were written after the last sync by a headless session
expect(manager.needsSync(sourceDir)).toBe(false);
});
});

// =========================================================================
Expand Down
Loading