fix(tor-shield): Fix toggle using stale status, fetch fresh before action

The toggle handler was receiving status captured at render time which
could be stale due to polling. Now fetches fresh status before deciding
to enable or disable, and does a full page reload after action.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
CyberMind-FR 2026-01-28 14:57:17 +01:00
parent 98fafccf05
commit e44f801f36
2 changed files with 47 additions and 41 deletions

View File

@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-tor-shield PKG_NAME:=luci-app-tor-shield
PKG_VERSION:=1.0.0 PKG_VERSION:=1.0.0
PKG_RELEASE:=6 PKG_RELEASE:=7
PKG_ARCH:=all PKG_ARCH:=all
PKG_LICENSE:=MIT PKG_LICENSE:=MIT

View File

@ -15,46 +15,54 @@ return view.extend({
return api.getDashboardData(); return api.getDashboardData();
}, },
// Handle master toggle // Handle master toggle - fetches fresh status first
handleToggle: function(status) { handleToggle: function() {
var self = this; var self = this;
if (status.enabled && status.running) { // Show loading while fetching current status
// Disable Tor ui.showModal(_('Please wait...'), [
ui.showModal(_('Disable Tor Shield'), [ E('p', { 'class': 'spinning' }, _('Checking current status...'))
E('p', { 'class': 'spinning' }, _('Stopping Tor Shield...')) ]);
]);
api.disable().then(function(result) { // Get fresh status before deciding action
ui.hideModal(); api.getStatus().then(function(status) {
if (result.success) { ui.hideModal();
ui.addNotification(null, E('p', _('Tor Shield disabled. Your traffic is no longer anonymized.')), 'warning');
self.render();
} else {
ui.addNotification(null, E('p', result.error || _('Failed to disable')), 'error');
}
}).catch(function(err) {
ui.hideModal();
ui.addNotification(null, E('p', _('Error: %s').format(err.message || err)), 'error');
});
} else {
// Enable Tor with selected preset
ui.showModal(_('Enable Tor Shield'), [
E('p', { 'class': 'spinning' }, _('Starting Tor Shield with %s preset...').format(self.currentPreset))
]);
api.enable(self.currentPreset).then(function(result) { if (status.enabled && status.running) {
ui.hideModal(); // Disable Tor
if (result.success) { ui.showModal(_('Disable Tor Shield'), [
ui.addNotification(null, E('p', _('Tor Shield is starting. Please wait for bootstrap to complete.')), 'info'); E('p', { 'class': 'spinning' }, _('Stopping Tor Shield...'))
} else { ]);
ui.addNotification(null, E('p', result.error || _('Failed to enable')), 'error');
} return api.disable().then(function(result) {
}).catch(function(err) { ui.hideModal();
ui.hideModal(); if (result.success) {
ui.addNotification(null, E('p', _('Error: %s').format(err.message || err)), 'error'); ui.addNotification(null, E('p', _('Tor Shield disabled. Your traffic is no longer anonymized.')), 'warning');
}); window.location.reload();
} } else {
ui.addNotification(null, E('p', result.error || _('Failed to disable')), 'error');
}
});
} else {
// Enable Tor with selected preset
ui.showModal(_('Enable Tor Shield'), [
E('p', { 'class': 'spinning' }, _('Starting Tor Shield with %s preset...').format(self.currentPreset))
]);
return api.enable(self.currentPreset).then(function(result) {
ui.hideModal();
if (result.success) {
ui.addNotification(null, E('p', _('Tor Shield is starting. Please wait for bootstrap to complete.')), 'info');
window.location.reload();
} else {
ui.addNotification(null, E('p', result.error || _('Failed to enable')), 'error');
}
});
}
}).catch(function(err) {
ui.hideModal();
ui.addNotification(null, E('p', _('Error: %s').format(err.message || err)), 'error');
});
}, },
// Handle preset selection // Handle preset selection
@ -295,9 +303,7 @@ return view.extend({
'type': 'checkbox', 'type': 'checkbox',
'checked': isActive ? 'checked' : null, 'checked': isActive ? 'checked' : null,
'style': 'opacity: 0; width: 0; height: 0;', 'style': 'opacity: 0; width: 0; height: 0;',
'change': L.bind(function(ev) { 'change': L.bind(this.handleToggle, this)
this.handleToggle(status);
}, this)
}), }),
E('span', { E('span', {
'style': 'position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: ' + (isActive ? '#fff' : 'rgba(255,255,255,0.3)') + '; transition: 0.3s; border-radius: 34px;' 'style': 'position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: ' + (isActive ? '#fff' : 'rgba(255,255,255,0.3)') + '; transition: 0.3s; border-radius: 34px;'
@ -381,7 +387,7 @@ return view.extend({
E('div', { 'class': 'tor-toggle-section' }, [ E('div', { 'class': 'tor-toggle-section' }, [
E('button', { E('button', {
'class': 'tor-master-toggle' + (isActive ? ' active' : ''), 'class': 'tor-master-toggle' + (isActive ? ' active' : ''),
'click': L.bind(function() { this.handleToggle(status); }, this), 'click': L.bind(this.handleToggle, this),
'title': isActive ? _('Click to disable') : _('Click to enable') 'title': isActive ? _('Click to disable') : _('Click to enable')
}, '\uD83E\uDDC5'), }, '\uD83E\uDDC5'),
E('div', { 'class': 'tor-toggle-label' + (isActive ? ' active' : '') }, E('div', { 'class': 'tor-toggle-label' + (isActive ? ' active' : '') },