Skip to content
Open
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
23 changes: 23 additions & 0 deletions shell/settings.html
Original file line number Diff line number Diff line change
Expand Up @@ -819,6 +819,14 @@ <h2>🛡️ Stealth</h2>
</div>
<input type="text" id="cfg-customAcceptLanguage" placeholder="nl-BE,nl;q=0.9,en-US;q=0.8" />
</div>

<div class="field" style="flex-direction:column;align-items:flex-start;">
<div class="field-info" style="margin-bottom:8px;">
<div class="field-label">Stealth skip hosts</div>
<div class="field-desc">Sites that actively detect stealth patches and break when injected.<br/>These sites get no stealth injection — they run as a normal browser.</div>
</div>
<textarea id="cfg-skipHosts" style="width:100%;min-height:60px;background:var(--input-bg);color:var(--text);border:1px solid var(--border);border-radius:6px;padding:8px;font-size:12px;resize:vertical;" placeholder="x.com&#10;twitter.com&#10;abs.twimg.com"></textarea>
</div>
</div>

<!-- ═══ Sync ═══ -->
Expand Down Expand Up @@ -1132,6 +1140,11 @@ <h3 id="modal-title">Are you sure?</h3>
toggleField('field-customUserAgent', st.userAgent === 'custom');
toggleField('field-customAcceptLanguage', st.acceptLanguage === 'custom');

const skipHotsEl = document.getElementById('cfg-skipHosts');
if (skipHotsEl && st.skipHosts) {
skipHotsEl.value = st.skipHosts.join('\n');
}

// Sync
const sy = config.sync || {};
setChecked('cfg-chromeBookmarks', !!sy.chromeBookmarks);
Expand Down Expand Up @@ -1368,6 +1381,16 @@ <h3 id="modal-title">Are you sure?</h3>
wire('cfg-chromeBookmarks', 'sync.chromeBookmarks');
wire('cfg-chromeProfile', 'sync.chromeProfile');
wire('cfg-trackingEnabled', 'behavior.trackingEnabled');

// Stealth skip hosts
const skipHotsEl = document.getElementById('cfg-skipHosts');
if (skipHotsEl) {
skipHotsEl.addEventListener('change', () => {
const hosts = skipHotsEl.value.split('\n').map(s => s.trim()).filter(Boolean);
saveConfig({stealth: { skipHosts: hosts }});
});
}

// Folder picker for screenshot storage path
document.getElementById('btn-chooseFolder').addEventListener('click', async () => {
try {
Expand Down
2 changes: 2 additions & 0 deletions src/config/manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export interface TandemConfig {
stealthLevel: 'low' | 'medium' | 'high';
acceptLanguage: 'auto' | 'custom';
customAcceptLanguage: string;
skipHosts: string[];
};

// Sync (Chrome bookmarks import)
Expand Down Expand Up @@ -152,6 +153,7 @@ const DEFAULT_CONFIG: TandemConfig = {
stealthLevel: 'medium',
acceptLanguage: 'auto',
customAcceptLanguage: '',
skipHosts: ['x.com', 'twitter.com', 'abs.twimg.com'],
},
sync: {
chromeBookmarks: false,
Expand Down
1 change: 1 addition & 0 deletions src/config/tests/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ describe('ConfigManager', () => {
expect(config.stealth.stealthLevel).toBe('medium');
expect(config.stealth.acceptLanguage).toBe('auto');
expect(config.stealth.customAcceptLanguage).toBe('');
expect(config.stealth.skipHosts).toEqual(['x.com', 'twitter.com', 'abs.twimg.com']);
});

it('loads with correct autonomy defaults', () => {
Expand Down
2 changes: 1 addition & 1 deletion src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ async function createWindow(): Promise<BrowserWindow> {
contents.on('dom-ready', () => {
// Skip stealth injection on sites that detect and block stealth patches
const url = contents.getURL();
if (isGoogleAuthUrl(url) || shouldSkipStealth(url)) {
if (isGoogleAuthUrl(url) || shouldSkipStealth(url, runtime?.configManager.getConfig().stealth.skipHosts)) {
log.info('🔑 Skipping stealth for:', url.substring(0, 60));
return;
}
Expand Down
16 changes: 2 additions & 14 deletions src/utils/security.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,23 +76,11 @@ export function isGoogleAuthUrl(rawValue: string): boolean {
);
}

/**
* Sites that actively detect stealth patches and break when injected.
* These sites get no stealth injection — they run as a normal browser.
*/
const STEALTH_SKIP_HOSTS = new Set([
'x.com',
'twitter.com',
'abs.twimg.com',
'zhipin.com',
'login.zhipin.com',
]);

export function shouldSkipStealth(rawValue: string): boolean {
export function shouldSkipStealth(rawValue: string, skipHosts: Array<string> = []): boolean {
const parsed = tryParseUrl(rawValue);
if (!parsed || !urlHasProtocol(parsed, 'http:', 'https:')) return false;
const host = parsed.hostname.replace(/^www\./, '');
return STEALTH_SKIP_HOSTS.has(host);
return new Set(skipHosts).has(host);
}

export function isSearchEngineResultsUrl(rawValue: string): boolean {
Expand Down