@@ -124,6 +124,8 @@ async function enableTor(auto = false) {
124124 await chrome . privacy . network . webRTCIPHandlingPolicy . set ( { value : 'disable_non_proxied_udp' } ) ;
125125 } catch ( _ ) { /* privacy controlled elsewhere */ }
126126 await chrome . storage . local . set ( { torEnabled : true , torAuto : auto } ) ;
127+ // session storage is wiped on browser restart → marks Tor as on THIS session.
128+ try { await chrome . storage . session . set ( { torSession : { auto } } ) ; } catch ( _ ) { /* no-op */ }
127129 await setTorBadge ( true ) ;
128130}
129131
@@ -137,6 +139,7 @@ async function disableTor() {
137139 try { await chrome . proxy . settings . clear ( { scope : 'regular' } ) ; } catch ( _ ) { /* already clear */ }
138140 try { await chrome . privacy . network . webRTCIPHandlingPolicy . clear ( { } ) ; } catch ( _ ) { /* already clear */ }
139141 await chrome . storage . local . set ( { torEnabled : false , torAuto : false } ) ;
142+ try { await chrome . storage . session . remove ( 'torSession' ) ; } catch ( _ ) { /* no-op */ }
140143 await setTorBadge ( false ) ;
141144}
142145
@@ -216,48 +219,62 @@ chrome.runtime.onMessage.addListener((msg, _sender, sendResponse) => {
216219 }
217220} ) ;
218221
219- // Tor defaults OFF on every fresh browser start. Nobody should be routed through
220- // Tor unless they ask — and the daemon isn't running yet at launch, so a
221- // left-over proxy would just break browsing. (Within a session the proxy is a
222- // persisted setting, so Tor stays on across service-worker restarts on its own.)
223- chrome . runtime . onStartup . addListener ( ( ) => {
224- disableTor ( ) . catch ( ( ) => { } ) ;
225- } ) ;
222+ // Tor defaults OFF on every fresh browser start — nobody is routed through Tor
223+ // unless they ask (or load a .onion). chrome.storage.session is wiped on browser
224+ // restart, so it tells a fresh launch from a service-worker restart mid-session.
225+ ( async ( ) => {
226+ try {
227+ const { torSession } = await chrome . storage . session . get ( 'torSession' ) ;
228+ if ( torSession ) {
229+ // Same session, SW just restarted → keep Tor on (re-apply the proxy).
230+ await enableTor ( ! ! torSession . auto ) ;
231+ } else {
232+ // Fresh browser start. If local still says Tor was on (carried over from
233+ // the last run), clear it + any persisted proxy. Otherwise leave the
234+ // proxy untouched.
235+ const { torEnabled } = await chrome . storage . local . get ( 'torEnabled' ) ;
236+ if ( torEnabled ) await disableTor ( ) ;
237+ }
238+ } catch ( _ ) { /* best effort */ }
239+ } ) ( ) ;
226240
227- // Auto-enable Tor when navigating to a .onion site (they only resolve through
228- // Tor). Redirect to a "Connecting to Tor…" page so there's no raw DNS error,
229- // bring Tor up, then send the tab to the onion once it routes.
230- chrome . webNavigation . onBeforeNavigate . addListener ( async ( details ) => {
231- if ( details . frameId !== 0 ) return ; // top-level navigations only
232- let host ;
233- try { host = new URL ( details . url ) . hostname ; } catch ( _ ) { return ; }
234- if ( ! host . endsWith ( '.onion' ) ) return ;
241+ // Auto-enable Tor for .onion sites (they only resolve through Tor). A .onion
242+ // with Tor off fails DNS → onErrorOccurred fires; that's our trigger. We show a
243+ // "Connecting to Tor…" page, bring Tor up, then send the tab to the onion.
244+ const onionInProgress = new Set ( ) ;
235245
246+ async function handleOnionNavigation ( onion , tabId ) {
247+ if ( tabId == null || tabId < 0 || onionInProgress . has ( tabId ) ) return ;
236248 const { torEnabled } = await chrome . storage . local . get ( 'torEnabled' ) ;
237- const onion = details . url ;
238- const tabId = details . tabId ;
239-
240- // If Tor is already on, the navigation will resolve through it — leave it.
241- if ( torEnabled ) return ;
249+ if ( torEnabled ) return ; // already routing through Tor
242250
243- // Swap the failing onion navigation for the connecting page.
244- const interstitial = chrome . runtime . getURL ( 'onion-connecting.html' ) + '?u=' + encodeURIComponent ( onion ) ;
245- try { await chrome . tabs . update ( tabId , { url : interstitial } ) ; } catch ( _ ) { return ; }
251+ onionInProgress . add ( tabId ) ;
252+ console . log ( '[tron-tor] .onion detected, connecting Tor:' , onion ) ;
253+ try {
254+ const interstitial = chrome . runtime . getURL ( 'onion-connecting.html' ) + '?u=' + encodeURIComponent ( onion ) ;
255+ try { await chrome . tabs . update ( tabId , { url : interstitial } ) ; } catch ( _ ) { /* tab gone */ }
246256
247- const started = await startTorViaHelper ( ) ;
248- if ( started . error === 'unreachable' || started . error === 'tor-not-installed' ) {
249- chrome . runtime . sendMessage ( { type : 'onion-error' , reason : started . error } ) . catch ( ( ) => { } ) ;
250- return ;
251- }
252- const result = await waitForTor ( ( pct ) => {
253- chrome . runtime . sendMessage ( { type : 'tor-progress' , pct } ) . catch ( ( ) => { } ) ;
254- } ) ;
255- if ( result . ready ) {
256- await enableTor ( true ) ; // auto: released when the .onion tabs close
257- try { await chrome . tabs . update ( tabId , { url : onion } ) ; } catch ( _ ) { /* tab gone */ }
258- } else {
259- chrome . runtime . sendMessage ( { type : 'onion-error' , reason : result . error || 'tor-exited' } ) . catch ( ( ) => { } ) ;
257+ const started = await startTorViaHelper ( ) ;
258+ if ( started . error === 'unreachable' || started . error === 'tor-not-installed' ) {
259+ chrome . runtime . sendMessage ( { type : 'onion-error' , reason : started . error } ) . catch ( ( ) => { } ) ;
260+ return ;
261+ }
262+ const result = await waitForTor ( ( pct ) => {
263+ chrome . runtime . sendMessage ( { type : 'tor-progress' , pct } ) . catch ( ( ) => { } ) ;
264+ } ) ;
265+ if ( result . ready ) {
266+ await enableTor ( true ) ; // auto: released when the .onion tabs close
267+ try { await chrome . tabs . update ( tabId , { url : onion } ) ; } catch ( _ ) { /* tab gone */ }
268+ } else {
269+ chrome . runtime . sendMessage ( { type : 'onion-error' , reason : result . error || 'tor-exited' } ) . catch ( ( ) => { } ) ;
270+ }
271+ } finally {
272+ onionInProgress . delete ( tabId ) ;
260273 }
274+ }
275+
276+ chrome . webNavigation . onErrorOccurred . addListener ( ( d ) => {
277+ if ( d . frameId === 0 && isOnionUrl ( d . url ) ) handleOnionNavigation ( d . url , d . tabId ) ;
261278} ) ;
262279
263280// Auto-disable Tor once the last .onion tab is gone (only if we auto-enabled it).
0 commit comments