diff --git a/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js b/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js index 16f11db17f..04014165b3 100644 --- a/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js +++ b/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js @@ -4,6 +4,7 @@ 'require rpc'; 'require uci'; 'require ui'; +'require fs'; const callListAlgorithms = rpc.declare({ object: 'luci.swanctl', @@ -53,20 +54,90 @@ function sectionNameCheck(extra_class) { return el; }; +let migrationOverlay = null; + +function renderMigrationContent(errorMessage) { + const dialog = migrationOverlay.firstElementChild; + const migrateButton = E('button', { + 'class': 'btn cbi-button cbi-button-apply', + 'click': handleMigrate + }, [_('Migrate')]); + + const content = E([], [ + E('h4', _('Migrate IPsec configuration')), + E('p', _('A legacy IPsec configuration was found.') + ' ' + + _('It must be migrated to the new swanctl uci schema in ' + + '\'/etc/config/ipsec\' before it can be managed here.')), + E('p', _('Before migration, the file \'/etc/config/ipsec\' is moved to \'/etc/config/ipsec_bak\'.') + ' ' + + _('The migration may require manual intervention.') + ' ' + + _('Therefore, the VPN is not restarted.')), + E('p', _('Warning: The migration will drop all IPsec VPN connections.')) + ]); + + if (errorMessage) + content.appendChild(E('p', errorMessage)); + + content.appendChild(E('div', { 'class': 'right' }, [migrateButton])); + + dialog.replaceChildren(content); +} + +function showMigrationOverlay(viewNode) { + if (migrationOverlay) + return; + + const dialog = E('div', { 'class': 'modal', 'style': 'margin:0;' }); + migrationOverlay = E('div', { + 'class': 'migration-overlay', + 'style': 'position:absolute;top:0;right:0;bottom:0;left:0;z-index:900;display:flex;align-items:center;justify-content:center;padding:1em;pointer-events:all;' + }, [dialog]); + + viewNode.style.position = 'relative'; + viewNode.appendChild(migrationOverlay); + + const maincontent = document.getElementById('maincontent'); + if (maincontent) + maincontent.style.pointerEvents = 'none'; + + renderMigrationContent(null); +} + +function handleMigrate() { + const dialog = migrationOverlay.firstElementChild; + + dialog.replaceChildren(E([], [ + E('h4', _('Migrate IPsec configuration')), + E('p', _('Migrating IPsec configuration…')) + ])); + + fs.exec('/etc/init.d/swanctl', ['migrate', L.env.sessionid]).then(function (result) { + if (result.code != 0) + renderMigrationContent(_('Migration failed: %s').format(result.stderr || result.stdout || _('unknown error'))); + else + window.location.reload(); + }).catch(function (e) { + renderMigrationContent(_('Migration failed: %s').format(e.message)); + }); +} + return view.extend({ load: function () { return Promise.all([ callListAlgorithms(), L.resolveDefault(uci.load('network'), null), + L.resolveDefault(uci.load('ipsec'), null), ]).then(function (data) { + let hasNoGlobals = uci.sections('ipsec', 'globals').length === 0; return { algorithms: data[0], + legacyConfig: hasNoGlobals, }; }); }, render: function (result) { let m, s, o; + const legacyConfig = result.legacyConfig; const algorithms = result.algorithms.data ?? {}; const error = result.algorithms.error; @@ -576,6 +647,10 @@ return view.extend({ o.depends({'is_esp': '0', 'use_custom_proposal': '0'}); addAlgorithms(o, algorithms.prf); - return m.render(); + return m.render().then(function (node) { + if (legacyConfig) + showMigrationOverlay(node); + return node; + }); } }); diff --git a/applications/luci-app-strongswan-swanctl/root/usr/share/rpcd/acl.d/luci-app-strongswan-swanctl.json b/applications/luci-app-strongswan-swanctl/root/usr/share/rpcd/acl.d/luci-app-strongswan-swanctl.json index 7407183247..6bc70df644 100644 --- a/applications/luci-app-strongswan-swanctl/root/usr/share/rpcd/acl.d/luci-app-strongswan-swanctl.json +++ b/applications/luci-app-strongswan-swanctl/root/usr/share/rpcd/acl.d/luci-app-strongswan-swanctl.json @@ -3,6 +3,7 @@ "description": "Grant access to luci-app-strongswan-swanctl", "read": { "file": { + "/etc/config/ipsec": [ "list" ], "/usr/sbin/swanmon version": [ "exec" ], "/usr/sbin/swanmon stats": [ "exec" ] }, @@ -13,6 +14,7 @@ }, "write": { "file": { + "/etc/init.d/swanctl migrate *": [ "exec" ], "/usr/sbin/swanctl --initiate --ike *": [ "exec" ], "/usr/sbin/swanctl --initiate --child *": [ "exec" ], "/usr/sbin/swanctl --terminate --ike *": [ "exec" ],