diff --git a/luci-app-tailscale-community/Makefile b/luci-app-tailscale-community/Makefile deleted file mode 100644 index d0ba87cb1..000000000 --- a/luci-app-tailscale-community/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -include $(TOPDIR)/rules.mk - -LUCI_TITLE:=LuCI support for Tailscale -LUCI_URL:=https://github.com/tokisaki-galaxy/luci-app-tailscale-community -PKG_DESCRIPTION:=Provides a LuCI Web management interface for Tailscale, allowing viewing status, configuring nodes and daemons. -PKG_MAINTAINER:=Tokisaki-Galaxy -LUCI_DEPENDS:=+tailscale +ip +luci-base -LUCI_PKGARCH:=all - -include $(TOPDIR)/feeds/luci/luci.mk - -# call BuildPackage - OpenWrt buildroot signature diff --git a/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js b/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js deleted file mode 100644 index b7f2d7bdc..000000000 --- a/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js +++ /dev/null @@ -1,590 +0,0 @@ -'use strict'; -'require view'; -'require form'; -'require rpc'; -'require ui'; -'require uci'; -'require tools.widgets as widgets'; - -const callGetStatus = rpc.declare({ object: 'tailscale', method: 'get_status' }); -const callGetSettings = rpc.declare({ object: 'tailscale', method: 'get_settings' }); -const callSetSettings = rpc.declare({ object: 'tailscale', method: 'set_settings', params: ['form_data'] }); -const callDoLogin = rpc.declare({ object: 'tailscale', method: 'do_login', params: ['form_data'] }); -const callDoLogout = rpc.declare({ object: 'tailscale', method: 'do_logout' }); -const callGetSubroutes = rpc.declare({ object: 'tailscale', method: 'get_subroutes' }); -const callSetupFirewall = rpc.declare({ object: 'tailscale', method: 'setup_firewall' }); -let map; - -const tailscaleSettingsConf = [ - [form.ListValue, 'fw_mode', _('Firewall Mode'), _('Select the firewall backend for Tailscale to use. Requires service restart to take effect.'), {values: ['nftables','iptables'],rmempty: false}], - [form.Flag, 'accept_routes', _('Accept Routes'), _('Allow accepting routes announced by other nodes.'), { rmempty: false }], - [form.Flag, 'advertise_exit_node', _('Advertise Exit Node'), _('Declare this device as an Exit Node.'), { rmempty: false }], - [form.Flag, 'exit_node_allow_lan_access', _('Allow LAN Access'), _('When using the exit node, access to the local LAN is allowed.'), { rmempty: false }], - [form.Flag, 'runwebclient', _('Enable Web Interface'), _('Expose a web interface on port 5252 for managing this node over Tailscale.'), { rmempty: false }], - [form.Flag, 'nosnat', _('Disable SNAT'), _('Disable Source NAT (SNAT) for traffic to advertised routes. Most users should leave this unchecked.'), { rmempty: false }], - [form.Flag, 'shields_up', _('Shields Up'), _('When enabled, blocks all inbound connections from the Tailscale network.'), { rmempty: false }], - [form.Flag, 'ssh', _('Enable Tailscale SSH'), _('Allow connecting to this device through the SSH function of Tailscale.'), { rmempty: false }], - [form.Flag, 'disable_magic_dns', _('Disable MagicDNS'), _('Use system DNS instead of MagicDNS.'), { rmempty: false }] -]; - -const accountConf = []; // dynamic created in render function - -const daemonConf = [ - //[form.Value, 'daemon_mtu', _('Daemon MTU'), _('Set a custom MTU for the Tailscale daemon. Leave blank to use the default value.'), { datatype: 'uinteger', placeholder: '1280' }, { rmempty: false }], - [form.Flag, 'daemon_reduce_memory', _('(Experimental) Reduce Memory Usage'), _('Enabling this option can reduce memory usage, but it may sacrifice some performance (set GOGC=10).'), { rmempty: false }] -]; - -const derpMapUrl = 'https://controlplane.tailscale.com/derpmap/default'; -let regionCodeMap = {}; - -// this function copy from luci-app-frpc. thx -function setParams(o, params) { - if (!params) return; - - for (const [key, val] of Object.entries(params)) { - if (key === 'values') { - [].concat(val).forEach(v => - o.value.apply(o, Array.isArray(v) ? v : [v]) - ); - } else if (key === 'depends') { - const arr = Array.isArray(val) ? val : [val]; - o.deps = arr.map(dep => Object.assign({}, ...o.deps, dep)); - } else { - o[key] = val; - } - } - - if (params.datatype === 'bool') - Object.assign(o, { enabled: 'true', disabled: 'false' }); -} - -// this function copy from luci-app-frpc. thx -function defTabOpts(s, t, opts, params) { - for (let i = 0; i < opts.length; i++) { - const opt = opts[i]; - const o = s.taboption(t, opt[0], opt[1], opt[2], opt[3]); - setParams(o, opt[4]); - setParams(o, params); - } -} - -function getRunningStatus() { - return L.resolveDefault(callGetStatus(), { running: false }).then(function (res) { - return res; - }); -} - -function formatBytes(bytes) { - const bytes_num = parseInt(bytes, 10); - if (isNaN(bytes_num) || bytes_num === 0) return '-'; - const k = 1000; - const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB']; - const i = Math.floor(Math.log(bytes_num) / Math.log(k)); - return parseFloat((bytes_num / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; -} - -function formatLastSeen(d) { - if (!d) return _('N/A'); - if (d === '0001-01-01T00:00:00Z') return _('Now'); - const t = new Date(d); - if (isNaN(t)) return _('Invalid Date'); - const diff = (Date.now() - t) / 1000; - if (diff < 0) return t.toLocaleString(); - if (diff < 60) return _('Just now'); - - const mins = diff / 60, hrs = mins / 60, days = hrs / 24; - const fmt = (n, s, p) => `${Math.floor(n)} ${Math.floor(n) === 1 ? _(s) : _(p)} ${_('ago')}`; - - if (mins < 60) return fmt(mins, 'minute', 'minutes'); - if (hrs < 24) return fmt(hrs, 'hour', 'hours'); - if (days < 30) return fmt(days, 'day', 'days'); - - return t.toISOString().slice(0, 10); -} - -async function initializeRegionMap() { - const cacheKey = 'tailscale_derp_map_cache'; - const ttl = 7 * 24 * 60 * 60 * 1000; // 7 days in milliseconds - - try { - const cachedItem = localStorage.getItem(cacheKey); - if (cachedItem) { - const cached = JSON.parse(cachedItem); - // Check if the cached data is still valid (not expired) - if (Date.now() - cached.timestamp < ttl) { - regionCodeMap = cached.data; - return; - } - } - } catch (e) { - ui.addTimeLimitedNotification(null, [ E('p', _('Error reading cached DERP region map: %s').format(e.message || _('Unknown error'))) ], 7000, 'error'); - } - - // If no valid cache, fetch from the network - try { - const response = await fetch(derpMapUrl); - if (!response.ok) { - return; - } - const data = await response.json(); - const newRegionMap = {}; - for (const regionId in data.Regions) { - const region = data.Regions[regionId]; - const code = (region.RegionCode || '').toLowerCase(); - const name = region.RegionName || region.RegionCode || `Region ${regionId}`; - newRegionMap[code] = name; - } - regionCodeMap = newRegionMap; - - // Save the newly fetched data to the cache - try { - const itemToCache = { - timestamp: Date.now(), - data: regionCodeMap - }; - localStorage.setItem(cacheKey, JSON.stringify(itemToCache)); - } catch (e) { - ui.addTimeLimitedNotification(null, [ E('p', _('Error caching DERP region map: %s').format(e.message || _('Unknown error'))) ], 7000, 'error'); - } - } catch (error) { - ui.addTimeLimitedNotification(null, [ E('p', _('Error fetching DERP region map: %s').format(error.message || _('Unknown error'))) ], 7000, 'error'); - } -} - -function formatConnectionInfo(info) { - if (!info) { return '-'; } - if (typeof info === 'string' && info.length === 3) { - const lowerCaseInfo = info.toLowerCase(); - return regionCodeMap[lowerCaseInfo] || info; - } - return info; -} - -function renderStatus(status) { - // If status object is not yet available, show a loading message. - if (!status || !status.hasOwnProperty('status')) { - return E('em', {}, _('Collecting data ...')); - } - - const notificationId = 'tailscale_health_notification'; - let notificationElement = document.getElementById(notificationId); - if (status.health != '') { - const message = _('Tailscale Health Check: %s').format(status.health); - if (notificationElement) { - notificationElement.textContent = message; - } - else { - let newNotificationContent = E('p', { 'id': notificationId }, message); - ui.addNotification(null, newNotificationContent, 'info'); - } - }else{ - try{ - notificationElement.parentNode.parentNode.remove(); - }catch(e){} - } - - if (Object.keys(regionCodeMap).length === 0) { - initializeRegionMap(); - } - - // --- Part 1: Handle non-running states --- - - // State: Tailscale binary not found. - if (status.status == 'not_installed') { - return E('dl', { 'class': 'cbi-value' }, [ - E('dt', {}, _('Service Status')), - E('dd', {}, E('span', { 'style': 'color:red;' }, E('strong', {}, _('TAILSCALE NOT FOUND')))) - ]); - } - - // State: Logged out, requires user action. - if (status.status == 'logout') { - return E('dl', { 'class': 'cbi-value' }, [ - E('dt', {}, _('Service Status')), - E('dd', {}, [ - E('span', { 'style': 'color:orange;' }, E('strong', {}, _('LOGGED OUT'))), - E('br'), - E('span', {}, _('Please use the login button in the settings below to authenticate.')) - ]) - ]); - } - - // State: Service is installed but not running. - if (status.status != 'running') { - return E('dl', { 'class': 'cbi-value' }, [ - E('dt', {}, _('Service Status')), - E('dd', {}, E('span', { 'style': 'color:red;' }, E('strong', {}, _('NOT RUNNING')))) - ]); - } - - // --- Part 2: Render the full status display for a running service --- - - // A helper array to define the data for the main status table. - const statusData = [ - { label: _('Service Status'), value: E('span', { 'style': 'color:green;' }, E('strong', {}, _('RUNNING'))) }, - { label: _('Version'), value: status.version || 'N/A' }, - { label: _('TUN Mode'), value: status.TUNMode ? _('Enabled') : _('Disabled') }, - { label: _('Tailscale IPv4'), value: status.ipv4 || 'N/A' }, - { label: _('Tailscale IPv6'), value: status.ipv6 || 'N/A' }, - { label: _('Tailnet Name'), value: status.domain_name || 'N/A' } - ]; - - // Build the horizontal status table using the data array. - const statusTable = E('table', { 'style': 'width: 100%; border-spacing: 0 5px;' }, [ - E('tr', {}, statusData.map(item => E('td', { 'style': 'padding-right: 20px;' }, E('strong', {}, item.label)))), - E('tr', {}, statusData.map(item => E('td', { 'style': 'padding-right: 20px;' }, item.value))) - ]); - - // --- Part 3: Render the Peers/Network Devices table --- - - const peers = status.peers; - let peersContent; - - if (!peers || Object.keys(peers).length === 0) { - // Display a message if no peers are found. - peersContent = E('p', {}, _('No peer devices found.')); - } else { - // Define headers for the peers table. - const peerTableHeaders = [ - { text: _('Status'), style: 'width: 80px;' }, - { text: _('Hostname') }, - { text: _('Tailscale IP') }, - { text: _('OS') }, - { text: _('Connection Info') }, - { text: _('RX') }, - { text: _('TX') }, - { text: _('Last Seen') } - ]; - - // Build the peers table. - peersContent = E('table', { 'class': 'cbi-table' }, [ - // Table Header Row - E('tr', { 'class': 'cbi-table-header' }, peerTableHeaders.map(header => { - let th_style = 'padding-right: 20px; text-align: left;'; - if (header.style) { - th_style += header.style; - } - return E('th', { 'class': 'cbi-table-cell', 'style': th_style }, header.text); - })), - - // Table Body Rows (one for each peer) - ...Object.entries(peers).map(([peerid, peer]) => { - const td_style = 'padding-right: 20px;'; - - return E('tr', { 'class': 'cbi-rowstyle-1' }, [ - E('td', { 'class': 'cbi-value-field', 'style': td_style }, - E('span', { - 'style': `color:${peer.exit_node ? 'blue' : (peer.online ? 'green' : 'gray')};`, - 'title': (peer.exit_node ? _('Exit Node') + ' ' : '') + (peer.online ? _('Online') : _('Offline')) - }, peer.online ? '●' : '○') - ), - E('td', { 'class': 'cbi-value-field', 'style': td_style }, E('strong', {}, peer.hostname + (peer.exit_node_option ? ' (ExNode)' : ''))), - E('td', { 'class': 'cbi-value-field', 'style': td_style }, peer.ip || 'N/A'), - E('td', { 'class': 'cbi-value-field', 'style': td_style }, peer.ostype || 'N/A'), - E('td', { 'class': 'cbi-value-field', 'style': td_style }, formatConnectionInfo(peer.linkadress || '-')), - E('td', { 'class': 'cbi-value-field', 'style': td_style }, formatBytes(peer.rx)), - E('td', { 'class': 'cbi-value-field', 'style': td_style }, formatBytes(peer.tx)), - E('td', { 'class': 'cbi-value-field', 'style': td_style }, formatLastSeen(peer.lastseen)) - ]); - }) - ]); - } - - // Combine all parts into a single DocumentFragment. - // Using E() without a tag name creates a fragment, which is perfect for grouping elements. - return E([ - statusTable, - E('div', { 'style': 'margin-top: 25px;' }, [ - E('h4', {}, _('Network Devices')), - peersContent - ]) - ]); -} - -return view.extend({ - load() { - return Promise.all([ - L.resolveDefault(callGetStatus(), { running: '', peers: [] }), - L.resolveDefault(callGetSettings(), { accept_routes: false }), - L.resolveDefault(callGetSubroutes(), { routes: [] }) - ]) - .then(function([status, settings_from_rpc, subroutes]) { - return uci.load('tailscale').then(function() { - if (uci.get('tailscale', 'settings') === null) { - // No existing settings found; initialize UCI with RPC settings - uci.add('tailscale', 'settings', 'settings'); - uci.set('tailscale', 'settings', 'fw_mode', 'nftables'); - uci.set('tailscale', 'settings', 'accept_routes', (settings_from_rpc.accept_routes ? '1' : '0')); - uci.set('tailscale', 'settings', 'advertise_exit_node', ((settings_from_rpc.advertise_exit_node || false) ? '1' : '0')); - uci.set('tailscale', 'settings', 'advertise_routes', (settings_from_rpc.advertise_routes || []).join(', ')); - uci.set('tailscale', 'settings', 'exit_node', settings_from_rpc.exit_node || ''); - uci.set('tailscale', 'settings', 'exit_node_allow_lan_access', ((settings_from_rpc.exit_node_allow_lan_access || false) ? '1' : '0')); - uci.set('tailscale', 'settings', 'ssh', ((settings_from_rpc.ssh || false) ? '1' : '0')); - uci.set('tailscale', 'settings', 'shields_up', ((settings_from_rpc.shields_up || false) ? '1' : '0')); - uci.set('tailscale', 'settings', 'runwebclient', ((settings_from_rpc.runwebclient || false) ? '1' : '0')); - uci.set('tailscale', 'settings', 'nosnat', ((settings_from_rpc.nosnat || false) ? '1' : '0')); - uci.set('tailscale', 'settings', 'disable_magic_dns', ((settings_from_rpc.disable_magic_dns || false) ? '1' : '0')); - - uci.set('tailscale', 'settings', 'daemon_reduce_memory', '0'); - uci.set('tailscale', 'settings', 'daemon_mtu', ''); - return uci.save(); - } - }).then(function() { - return [status, settings_from_rpc, subroutes]; - }); - }); - }, - - render ([status = {}, settings = {}, subroutes_obj]) { - const subroutes = (subroutes_obj && subroutes_obj.routes) ? subroutes_obj.routes : []; - - let s; - map = new form.Map('tailscale', _('Tailscale'), _('Tailscale is a mesh VPN solution that makes it easy to connect your devices securely. This configuration page allows you to manage Tailscale settings on your OpenWrt device.')); - - s = map.section(form.NamedSection, '_status'); - s.anonymous = true; - s.render = function (section_id) { - L.Poll.add( - function () { - return getRunningStatus().then(function (res) { - const view = document.getElementById("service_status_display"); - if (view) { - const content = renderStatus(res); - view.replaceChildren(content); - } - - // login button only available when logged out - const login_btn=document.getElementsByClassName('cbi-button cbi-button-apply')[0]; - if(login_btn) { login_btn.disabled=(res.status != 'logout'); } - }); - }, 10); - - return E('div', { 'id': 'service_status_display', 'class': 'cbi-value' }, - _('Collecting data ...') - ); - } - - // Bind settings to the 'settings' section of uci - s = map.section(form.NamedSection, 'settings', 'settings', _('Settings')); - s.dynamic = true; - - // Create the "General Settings" tab and apply tailscaleSettingsConf - s.tab('general', _('General Settings')); - - defTabOpts(s, 'general', tailscaleSettingsConf, { optional: false }); - - const en = s.taboption('general', form.ListValue, 'exit_node', _('Exit Node'), _('Select an exit node from the list. If enabled, Allow LAN Access is enabled implicitly.')); - en.value('', _('None')); - if (status.peers) { - Object.values(status.peers).forEach(function(peer) { - if (peer.exit_node_option) { - const primaryIp = peer.ip.split('
')[0]; - const label = peer.hostname ? `${peer.hostname} (${primaryIp})` : primaryIp; - en.value(primaryIp, label); - } - }); - } - en.rmempty = true; - en.cfgvalue = function(section_id) { - if (status && status.status === 'running' && status.peers) { - for (const id in status.peers) { - if (status.peers[id].exit_node) { - return status.peers[id].ip.split('
')[0]; - } - } - return ''; - } - return uci.get('tailscale', 'settings', 'exit_node') || ''; - }; - - const o = s.taboption('general', form.DynamicList, 'advertise_routes', _('Advertise Routes'),_('Advertise subnet routes behind this device. Select from the detected subnets below or enter custom routes (comma-separated).')); - if (subroutes.length > 0) { - subroutes.forEach(function(subnet) { - o.value(subnet, subnet); - }); - } - o.rmempty = true; - - const fwBtn = s.taboption('general', form.Button, '_setup_firewall', _('Auto Configure Firewall')); - fwBtn.description = _('Essential configuration for Subnet Routing (Site-to-Site) and Exit Node features.') - +'
'+_('It automatically creates the tailscale interface, sets up firewall zones for LAN <-> Tailscale forwarding,') - +'
'+_('and enables Masquerading and MSS Clamping (MTU fix) to ensure stable connections.'); - fwBtn.inputstyle = 'action'; - fwBtn.onclick = function() { - const btn = this; - btn.disabled = true; - return callSetupFirewall().then(function(res) { - const msg = res?.message || _('Firewall configuration applied.'); - ui.addNotification(null, E('p', {}, msg), 'info'); - }).catch(function(err) { - ui.addNotification(null, E('p', {}, _('Failed to configure firewall: %s').format(err?.message || err || 'Unknown error')), 'error'); - }).finally(function() { - btn.disabled = false; - }); - }; - - const helpTitle = s.taboption('general', form.DummyValue, '_help_title'); - helpTitle.title = _('How to enable Site-to-Site?'); - helpTitle.render = function() { - return E('div', { 'class': 'cbi-value', 'style': 'margin-top: 1em; border-top: 1px font-weight: bold;' }, [ - E('label', { 'class': 'cbi-value-title' }, this.title), - E('div', { 'class': 'cbi-value-field', 'style': 'line-height: 1.6em; font-size: 95%; color: #555;' }, [ - _('1. Select "Accept Routes" (to access remote devices).'), E('br'), - _('2. In "Advertise Routes", select your local subnet (to allow remote devices to access this LAN).'), E('br'), - _('3. Click "Auto Configure Firewall" (to allow traffic forwarding).'), E('br'), - E('strong', { 'style': 'color: #d9534f;' }, _('[Important] Log in to the Tailscale admin console and manually enable "Subnet Routes" for this device.')) - ]) - ]); - }; - - // Create the account settings - s.tab('account', _('Account Settings')); - defTabOpts(s, 'account', accountConf, { optional: false }); - - const loginBtn = s.taboption('account', form.Button, '_login', _('Login'), - _('Click to get a login URL for this device.') - +'
'+_('If the timeout is displayed, you can refresh the page and click Login again.')); - loginBtn.inputstyle = 'apply'; - - const customLoginUrl = s.taboption('account', form.Value, 'custom_login_url', - _('Custom Login Server'), - _('Optional: Specify a custom control server URL (e.g., a Headscale instance, %s).'.format('https://example.com')) - +'
'+_('Leave blank for default Tailscale control plane.') - ); - customLoginUrl.placeholder = ''; - customLoginUrl.rmempty = true; - - const customLoginAuthKey = s.taboption('account', form.Value, 'custom_login_AuthKey', - _('Custom Login Server Auth Key'), - _('Optional: Specify an authentication key for the custom control server. Leave blank if not required.') - +'
'+_('If you are using custom login server but not providing an Auth Key, will redirect to the login page without pre-filling the key.') - ); - customLoginAuthKey.placeholder = ''; - customLoginAuthKey.rmempty = true; - - const logoutBtn = s.taboption('account', form.Button, '_logout', _('Logout'), - _('Click to Log out account on this device.') - +'
'+_('Disconnect from Tailscale and expire current node key.')); - logoutBtn.inputstyle = 'apply'; - logoutBtn.id = 'tailscale_logout_btn'; - - loginBtn.onclick = function() { - const customServerInput = document.getElementById('widget.cbid.tailscale.settings.custom_login_url'); - const customServer = customServerInput ? customServerInput.value : ''; - const customserverAuthInput = document.getElementById('widget.cbid.tailscale.settings.custom_login_AuthKey'); - const customServerAuth = customserverAuthInput ? customserverAuthInput.value : ''; - const loginWindow = window.open('', '_blank'); - if (!loginWindow) { - ui.addTimeLimitedNotification(null, [ E('p', _('Could not open a new tab. Please check if your browser or an extension blocked the pop-up.')) ], 10000, 'error'); - return; - } - // Display a prompt message in the new window - const doc = loginWindow.document; - doc.body.innerHTML = - '

' + _('Tailscale Login') + '

' + - '

' + _('Requesting Tailscale login URL... Please wait.') + '

' + - '

' + _('This can take up to 30 seconds.') + '

'; - - ui.showModal(_('Requesting Login URL...'), E('em', {}, _('Please wait.'))); - const payload = { - loginserver: customServer || '', - loginserver_authkey: customServerAuth || '' - }; - // Show a "loading" modal and execute the asynchronous RPC call - ui.showModal(_('Requesting Login URL...'), E('em', {}, _('Please wait.'))); - return callDoLogin(payload).then(function(res) { - ui.hideModal(); - if (res && res.url) { - // After successfully obtaining the URL, redirect the previously opened tab - loginWindow.location.href = res.url; - } else { - // If it fails, inform the user and they can close the new tab - doc.body.innerHTML = - '

' + _('Error') + '

' + - '

' + _('Failed to get login URL. You may close this tab.') + '

'; - ui.addTimeLimitedNotification(null, [ E('p', _('Failed to get login URL: Invalid response from server.')) ], 7000, 'error'); - } - }).catch(function(err) { - ui.hideModal(); - ui.addTimeLimitedNotification(null, [ E('p', _('Failed to get login URL: %s').format(err.message || _('Unknown error'))) ], 7000, 'error'); - }); - }; - - logoutBtn.onclick = function() { - const confirmationContent = E([ - E('p', {}, _('Are you sure you want to log out?') - +'
'+_('This will disconnect this device from your Tailnet and require you to re-authenticate.')), - - E('div', { 'style': 'text-align: right; margin-top: 1em;' }, [ - E('button', { - 'class': 'cbi-button', - 'click': ui.hideModal - }, _('Cancel')), - ' ', - E('button', { - 'class': 'cbi-button cbi-button-negative', - 'click': function() { - ui.hideModal(); - ui.showModal(_('Logging out...'), E('em', {}, _('Please wait.'))); - - return callDoLogout().then(function(res) { - ui.hideModal(); - ui.addTimeLimitedNotification(null, [ E('p', _('Successfully logged out.')) ], 5000, 'info'); - }).catch(function(err) { - ui.hideModal(); - ui.addTimeLimitedNotification(null, [ E('p', _('Logout failed: %s').format(err.message || _('Unknown error'))) ], 7000, 'error'); - }); - } - }, _('Logout')) - ]) - ]); - ui.showModal(_('Confirm Logout'), confirmationContent); - }; - - // Create the "Daemon Settings" tab and apply daemonConf - //s.tab('daemon', _('Daemon Settings')); - //defTabOpts(s, 'daemon', daemonConf, { optional: false }); - - return map.render(); - }, - - // The handleSaveApply function is executed after clicking "Save & Apply" - handleSaveApply(ev) { - return map.save().then(function () { - const data = map.data.get('tailscale', 'settings'); - - // fix empty value issue - if(!data.advertise_exit_node) data.advertise_exit_node = ''; - if(!data.advertise_routes) data.advertise_routes = ''; - if(!data.exit_node) data.exit_node = ''; - if(!data.custom_login_url) data.custom_login_url = ''; - if(!data.custom_login_AuthKey) data.custom_login_AuthKey = ''; - - ui.showModal(_('Applying changes...'), E('em', {}, _('Please wait.'))); - - return callSetSettings(data).then(function (response) { - if (response.success) { - ui.hideModal(); - setTimeout(function() { - ui.addTimeLimitedNotification(null, [ E('p', _('Tailscale settings applied successfully.')) ], 5000, 'info'); - }, 1000); - try { - L.ui.changes.revert(); - } catch (error) { - ui.addTimeLimitedNotification(null, [ E('p', _('Error saving settings: %s').format(error || _('Unknown error'))) ], 7000, 'error'); - } - } else { - ui.hideModal(); - ui.addTimeLimitedNotification(null, [ E('p', _('Error applying settings: %s').format(response.error || _('Unknown error'))) ], 7000, 'error'); - } - }); - }).catch(function(err) { - ui.hideModal(); - //console.error('Save failed:', err); - ui.addTimeLimitedNotification(null, [ E('p', _('Failed to save settings: %s').format(err.message)) ], 7000, 'error'); - }); - }, - - handleSave: null, - handleReset: null -}); diff --git a/luci-app-tailscale-community/po/templates/community.pot b/luci-app-tailscale-community/po/templates/community.pot deleted file mode 100644 index 12882f266..000000000 --- a/luci-app-tailscale-community/po/templates/community.pot +++ /dev/null @@ -1,503 +0,0 @@ -msgid "" -msgstr "Content-Type: text/plain; charset=UTF-8" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:34 -msgid "(Experimental) Reduce Memory Usage" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:432 -msgid "1. Select \"Accept Routes\" (to access remote devices)." -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:433 -msgid "" -"2. In \"Advertise Routes\", select your local subnet (to allow remote " -"devices to access this LAN)." -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:434 -msgid "3. Click \"Auto Configure Firewall\" (to allow traffic forwarding)." -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:20 -msgid "Accept Routes" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:441 -msgid "Account Settings" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:21 -msgid "Advertise Exit Node" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:400 -msgid "Advertise Routes" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:400 -msgid "" -"Advertise subnet routes behind this device. Select from the detected subnets " -"below or enter custom routes (comma-separated)." -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:22 -msgid "Allow LAN Access" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:20 -msgid "Allow accepting routes announced by other nodes." -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:26 -msgid "Allow connecting to this device through the SSH function of Tailscale." -msgstr "" - -#: applications/luci-app-tailscale-community/root/usr/share/rpcd/acl.d/luci-app-tailscale-community.json:3 -msgid "Allow user access to tailscale" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:563 -msgid "Applying changes..." -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:515 -msgid "Are you sure you want to log out?" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:408 -msgid "Auto Configure Firewall" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:522 -msgid "Cancel" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:466 -msgid "Click to Log out account on this device." -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:445 -msgid "Click to get a login URL for this device." -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:166 -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:363 -msgid "Collecting data ..." -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:541 -msgid "Confirm Logout" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:253 -msgid "Connection Info" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:478 -msgid "" -"Could not open a new tab. Please check if your browser or an extension " -"blocked the pop-up." -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:450 -msgid "Custom Login Server" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:458 -msgid "Custom Login Server Auth Key" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:21 -msgid "Declare this device as an Exit Node." -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:27 -msgid "Disable MagicDNS" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:24 -msgid "Disable SNAT" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:24 -msgid "" -"Disable Source NAT (SNAT) for traffic to advertised routes. Most users " -"should leave this unchecked." -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:226 -msgid "Disabled" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:467 -msgid "Disconnect from Tailscale and expire current node key." -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:26 -msgid "Enable Tailscale SSH" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:23 -msgid "Enable Web Interface" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:226 -msgid "Enabled" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:34 -msgid "" -"Enabling this option can reduce memory usage, but it may sacrifice some " -"performance (set GOGC=10)." -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:503 -msgid "Error" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:578 -msgid "Error applying settings: %s" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:147 -msgid "Error caching DERP region map: %s" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:150 -msgid "Error fetching DERP region map: %s" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:120 -msgid "Error reading cached DERP region map: %s" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:574 -msgid "Error saving settings: %s" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:409 -msgid "" -"Essential configuration for Subnet Routing (Site-to-Site) and Exit Node " -"features." -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:278 -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:376 -msgid "Exit Node" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:23 -msgid "" -"Expose a web interface on port 5252 for managing this node over Tailscale." -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:420 -msgid "Failed to configure firewall: %s" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:504 -msgid "Failed to get login URL. You may close this tab." -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:509 -msgid "Failed to get login URL: %s" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:505 -msgid "Failed to get login URL: Invalid response from server." -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:584 -msgid "Failed to save settings: %s" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:19 -msgid "Firewall Mode" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:417 -msgid "Firewall configuration applied." -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:372 -msgid "General Settings" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:250 -msgid "Hostname" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:427 -msgid "How to enable Site-to-Site?" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:446 -msgid "" -"If the timeout is displayed, you can refresh the page and click Login again." -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:460 -msgid "" -"If you are using custom login server but not providing an Auth Key, will " -"redirect to the login page without pre-filling the key." -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:90 -msgid "Invalid Date" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:410 -msgid "" -"It automatically creates the tailscale interface, sets up firewall zones for " -"LAN <-> Tailscale forwarding," -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:93 -msgid "Just now" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:205 -msgid "LOGGED OUT" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:256 -msgid "Last Seen" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:452 -msgid "Leave blank for default Tailscale control plane." -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:528 -msgid "Logging out..." -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:444 -msgid "Login" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:465 -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:538 -msgid "Logout" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:535 -msgid "Logout failed: %s" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:87 -msgid "N/A" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:216 -msgid "NOT RUNNING" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:298 -msgid "Network Devices" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:245 -msgid "No peer devices found." -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:377 -msgid "None" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:88 -msgid "Now" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:252 -msgid "OS" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:278 -msgid "Offline" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:278 -msgid "Online" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:451 -msgid "" -"Optional: Specify a custom control server URL (e.g., a Headscale instance, " -"%s)." -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:459 -msgid "" -"Optional: Specify an authentication key for the custom control server. Leave " -"blank if not required." -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:207 -msgid "Please use the login button in the settings below to authenticate." -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:488 -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:494 -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:528 -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:563 -msgid "Please wait." -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:224 -msgid "RUNNING" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:254 -msgid "RX" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:488 -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:494 -msgid "Requesting Login URL..." -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:485 -msgid "Requesting Tailscale login URL... Please wait." -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:376 -msgid "" -"Select an exit node from the list. If enabled, Allow LAN Access is enabled " -"implicitly." -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:19 -msgid "" -"Select the firewall backend for Tailscale to use. Requires service restart " -"to take effect." -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:195 -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:203 -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:215 -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:224 -msgid "Service Status" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:368 -msgid "Settings" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:25 -msgid "Shields Up" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:249 -msgid "Status" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:532 -msgid "Successfully logged out." -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:196 -msgid "TAILSCALE NOT FOUND" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:226 -msgid "TUN Mode" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:255 -msgid "TX" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:229 -msgid "Tailnet Name" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:342 -#: applications/luci-app-tailscale-community/root/usr/share/luci/menu.d/luci-app-tailscale-community.json:3 -msgid "Tailscale" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:172 -msgid "Tailscale Health Check: %s" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:251 -msgid "Tailscale IP" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:227 -msgid "Tailscale IPv4" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:228 -msgid "Tailscale IPv6" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:484 -msgid "Tailscale Login" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:342 -msgid "" -"Tailscale is a mesh VPN solution that makes it easy to connect your devices " -"securely. This configuration page allows you to manage Tailscale settings on " -"your OpenWrt device." -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:569 -msgid "Tailscale settings applied successfully." -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:486 -msgid "This can take up to 30 seconds." -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:516 -msgid "" -"This will disconnect this device from your Tailnet and require you to re-" -"authenticate." -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:120 -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:147 -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:150 -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:509 -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:535 -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:574 -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:578 -msgid "Unknown error" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:27 -msgid "Use system DNS instead of MagicDNS." -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:225 -msgid "Version" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:25 -msgid "" -"When enabled, blocks all inbound connections from the Tailscale network." -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:22 -msgid "When using the exit node, access to the local LAN is allowed." -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:435 -msgid "" -"[Important] Log in to the Tailscale admin console and manually enable " -"\"Subnet Routes\" for this device." -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:96 -msgid "ago" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:411 -msgid "" -"and enables Masquerading and MSS Clamping (MTU fix) to ensure stable " -"connections." -msgstr "" diff --git a/luci-app-tailscale-community/po/zh-cn b/luci-app-tailscale-community/po/zh-cn deleted file mode 120000 index 8d69574dd..000000000 --- a/luci-app-tailscale-community/po/zh-cn +++ /dev/null @@ -1 +0,0 @@ -zh_Hans \ No newline at end of file diff --git a/luci-app-tailscale-community/po/zh_Hans/community.po b/luci-app-tailscale-community/po/zh_Hans/community.po deleted file mode 100644 index 6e108e6d4..000000000 --- a/luci-app-tailscale-community/po/zh_Hans/community.po +++ /dev/null @@ -1,510 +0,0 @@ -msgid "" -msgstr "Content-Type: text/plain; charset=UTF-8\n" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:34 -msgid "(Experimental) Reduce Memory Usage" -msgstr "(实验性) 减少内存使用" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:432 -msgid "1. Select \"Accept Routes\" (to access remote devices)." -msgstr "1. 勾选 接受路由 (接受远程设备访问)。" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:433 -msgid "" -"2. In \"Advertise Routes\", select your local subnet (to allow remote " -"devices to access this LAN)." -msgstr "2. 在 通告路由 选择本设备的局域网段 (让远程设备能访问你)。" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:434 -msgid "3. Click \"Auto Configure Firewall\" (to allow traffic forwarding)." -msgstr "3. 点击 自动配置防火墙 (打通防火墙转发)。" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:20 -msgid "Accept Routes" -msgstr "接受路由" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:441 -msgid "Account Settings" -msgstr "账户设置" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:21 -msgid "Advertise Exit Node" -msgstr "通告出口节点" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:400 -msgid "Advertise Routes" -msgstr "通告路由" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:400 -msgid "" -"Advertise subnet routes behind this device. Select from the detected subnets " -"below or enter custom routes (comma-separated)." -msgstr "" -"通告此设备后的子网路由。从下面的子网中选择,或输入自定义路由 (逗号分隔)。" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:22 -msgid "Allow LAN Access" -msgstr "允许局域网访问" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:20 -msgid "Allow accepting routes announced by other nodes." -msgstr "允许接受由其他节点通告的路由。" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:26 -msgid "Allow connecting to this device through the SSH function of Tailscale." -msgstr "允许通过 Tailscale 的 SSH 功能连接到此设备。" - -#: applications/luci-app-tailscale-community/root/usr/share/rpcd/acl.d/luci-app-tailscale-community.json:3 -msgid "Allow user access to tailscale" -msgstr "允许用户访问 Tailscale" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:563 -msgid "Applying changes..." -msgstr "正在应用更改..." - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:515 -msgid "Are you sure you want to log out?" -msgstr "您确定要登出吗?" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:408 -msgid "Auto Configure Firewall" -msgstr "自动配置防火墙" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:522 -msgid "Cancel" -msgstr "取消" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:466 -msgid "Click to Log out account on this device." -msgstr "点击以登出此设备上的账户。" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:445 -msgid "Click to get a login URL for this device." -msgstr "点击获取此设备的登录 URL。" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:166 -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:363 -msgid "Collecting data ..." -msgstr "正在收集数据..." - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:541 -msgid "Confirm Logout" -msgstr "确认登出" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:253 -msgid "Connection Info" -msgstr "连接信息" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:478 -msgid "" -"Could not open a new tab. Please check if your browser or an extension " -"blocked the pop-up." -msgstr "无法打开新标签页。请检查您的浏览器或扩展程序是否阻止了弹出窗口。" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:450 -msgid "Custom Login Server" -msgstr "自定义登录服务器" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:458 -msgid "Custom Login Server Auth Key" -msgstr "自定义登录服务器认证密钥" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:21 -msgid "Declare this device as an Exit Node." -msgstr "将此设备声明为出口节点。" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:27 -msgid "Disable MagicDNS" -msgstr "禁用 MagicDNS" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:24 -msgid "Disable SNAT" -msgstr "禁用 SNAT" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:24 -msgid "" -"Disable Source NAT (SNAT) for traffic to advertised routes. Most users " -"should leave this unchecked." -msgstr "为通告路由的流量禁用源地址转换 (SNAT)。大多数用户应保持此项不勾选。" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:226 -msgid "Disabled" -msgstr "已禁用" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:467 -msgid "Disconnect from Tailscale and expire current node key." -msgstr "从 Tailscale 断开连接并使当前节点密钥过期。" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:26 -msgid "Enable Tailscale SSH" -msgstr "启用 Tailscale SSH" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:23 -msgid "Enable Web Interface" -msgstr "启用 Web 界面" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:226 -msgid "Enabled" -msgstr "已启用" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:34 -msgid "" -"Enabling this option can reduce memory usage, but it may sacrifice some " -"performance (set GOGC=10)." -msgstr "启用此选项可以减少内存使用,但可能会牺牲一些性能 (设置 GOGC=10)。" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:503 -msgid "Error" -msgstr "错误" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:578 -msgid "Error applying settings: %s" -msgstr "应用设置时出错: %s" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:147 -msgid "Error caching DERP region map: %s" -msgstr "缓存 DERP 区域地图时出错: %s" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:150 -msgid "Error fetching DERP region map: %s" -msgstr "获取 DERP 区域地图时出错: %s" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:120 -msgid "Error reading cached DERP region map: %s" -msgstr "读取缓存的 DERP 区域地图时出错: %s" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:574 -msgid "Error saving settings: %s" -msgstr "保存设置时出错: %s" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:409 -msgid "" -"Essential configuration for Subnet Routing (Site-to-Site) and Exit Node " -"features." -msgstr "子网路由和出口节点的基本配置。" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:278 -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:376 -msgid "Exit Node" -msgstr "出口节点" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:23 -msgid "" -"Expose a web interface on port 5252 for managing this node over Tailscale." -msgstr "在端口 5252 上暴露一个 Web 界面,用于通过 Tailscale 管理此节点。" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:420 -msgid "Failed to configure firewall: %s" -msgstr "获取防火墙设置失败: %s" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:504 -msgid "Failed to get login URL. You may close this tab." -msgstr "获取登录 URL 失败。您可以关闭此标签页。" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:509 -msgid "Failed to get login URL: %s" -msgstr "获取登录 URL 失败: %s" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:505 -msgid "Failed to get login URL: Invalid response from server." -msgstr "获取登录 URL 失败: 服务器响应无效。" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:584 -msgid "Failed to save settings: %s" -msgstr "保存设置失败: %s" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:19 -msgid "Firewall Mode" -msgstr "防火墙模式" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:417 -msgid "Firewall configuration applied." -msgstr "已应用防火墙配置" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:372 -msgid "General Settings" -msgstr "常规设置" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:250 -msgid "Hostname" -msgstr "主机名" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:427 -msgid "How to enable Site-to-Site?" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:446 -msgid "" -"If the timeout is displayed, you can refresh the page and click Login again." -msgstr "如果显示超时,您可以刷新页面并再次点击登录。" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:460 -msgid "" -"If you are using custom login server but not providing an Auth Key, will " -"redirect to the login page without pre-filling the key." -msgstr "" -"如果您使用自定义登录服务器但未提供认证密钥,将重定向到登录页面而不会预先填充" -"密钥。" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:90 -msgid "Invalid Date" -msgstr "无效日期" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:410 -msgid "" -"It automatically creates the tailscale interface, sets up firewall zones for " -"LAN <-> Tailscale forwarding," -msgstr "" -"子网路由和出口节点的基本配置。会自动tailscale接口,设置防火墙区域LAN <-> " -"Tailscale转发" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:93 -msgid "Just now" -msgstr "刚才" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:205 -msgid "LOGGED OUT" -msgstr "已登出" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:256 -msgid "Last Seen" -msgstr "上次在线" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:452 -msgid "Leave blank for default Tailscale control plane." -msgstr "留空以使用默认的 Tailscale 控制平面。" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:528 -msgid "Logging out..." -msgstr "正在登出..." - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:444 -msgid "Login" -msgstr "登录" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:465 -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:538 -msgid "Logout" -msgstr "登出" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:535 -msgid "Logout failed: %s" -msgstr "登出失败: %s" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:87 -msgid "N/A" -msgstr "N/A" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:216 -msgid "NOT RUNNING" -msgstr "未运行" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:298 -msgid "Network Devices" -msgstr "网络设备" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:245 -msgid "No peer devices found." -msgstr "未找到对等设备。" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:377 -msgid "None" -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:88 -msgid "Now" -msgstr "现在" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:252 -msgid "OS" -msgstr "操作系统" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:278 -msgid "Offline" -msgstr "离线" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:278 -msgid "Online" -msgstr "在线" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:451 -msgid "" -"Optional: Specify a custom control server URL (e.g., a Headscale instance, " -"%s)." -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:459 -msgid "" -"Optional: Specify an authentication key for the custom control server. Leave " -"blank if not required." -msgstr "可选:为自定义控制服务器指定一个认证密钥。如果不需要,请留空。" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:207 -msgid "Please use the login button in the settings below to authenticate." -msgstr "请使用下方设置中的登录按钮进行认证。" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:488 -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:494 -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:528 -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:563 -msgid "Please wait." -msgstr "请稍候。" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:224 -msgid "RUNNING" -msgstr "正在运行" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:254 -msgid "RX" -msgstr "接收" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:488 -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:494 -msgid "Requesting Login URL..." -msgstr "正在请求登录 URL..." - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:485 -msgid "Requesting Tailscale login URL... Please wait." -msgstr "正在请求 Tailscale 登录 URL... 请稍候。" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:376 -msgid "" -"Select an exit node from the list. If enabled, Allow LAN Access is enabled " -"implicitly." -msgstr "" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:19 -msgid "" -"Select the firewall backend for Tailscale to use. Requires service restart " -"to take effect." -msgstr "选择 Tailscale 使用的防火墙后端。需要重启服务才能生效。" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:195 -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:203 -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:215 -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:224 -msgid "Service Status" -msgstr "服务状态" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:368 -msgid "Settings" -msgstr "设置" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:25 -msgid "Shields Up" -msgstr "开启防护 (Shields Up)" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:249 -msgid "Status" -msgstr "状态" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:532 -msgid "Successfully logged out." -msgstr "登出成功。" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:196 -msgid "TAILSCALE NOT FOUND" -msgstr "未找到 TAILSCALE" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:226 -msgid "TUN Mode" -msgstr "TUN 模式" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:255 -msgid "TX" -msgstr "发送" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:229 -msgid "Tailnet Name" -msgstr "Tailnet 名称" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:342 -#: applications/luci-app-tailscale-community/root/usr/share/luci/menu.d/luci-app-tailscale-community.json:3 -msgid "Tailscale" -msgstr "Tailscale" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:172 -msgid "Tailscale Health Check: %s" -msgstr "Tailscale 健康检查: %s" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:251 -msgid "Tailscale IP" -msgstr "Tailscale IP" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:227 -msgid "Tailscale IPv4" -msgstr "Tailscale IPv4" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:228 -msgid "Tailscale IPv6" -msgstr "Tailscale IPv6" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:484 -msgid "Tailscale Login" -msgstr "Tailscale 登录" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:342 -msgid "" -"Tailscale is a mesh VPN solution that makes it easy to connect your devices " -"securely. This configuration page allows you to manage Tailscale settings on " -"your OpenWrt device." -msgstr "" -"Tailscale 是一个网状 VPN 解决方案,可以轻松地安全连接您的设备。此配置页面允许" -"您在 OpenWrt 设备上管理 Tailscale 设置。" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:569 -msgid "Tailscale settings applied successfully." -msgstr "Tailscale 设置已成功应用。" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:486 -msgid "This can take up to 30 seconds." -msgstr "此过程最多可能需要 30 秒。" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:516 -msgid "" -"This will disconnect this device from your Tailnet and require you to re-" -"authenticate." -msgstr "这将使此设备从您的 Tailnet 断开连接,并需要您重新进行身份验证。" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:120 -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:147 -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:150 -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:509 -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:535 -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:574 -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:578 -msgid "Unknown error" -msgstr "未知错误" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:27 -msgid "Use system DNS instead of MagicDNS." -msgstr "使用系统 DNS 而不是 MagicDNS。" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:225 -msgid "Version" -msgstr "版本" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:25 -msgid "" -"When enabled, blocks all inbound connections from the Tailscale network." -msgstr "启用后,将阻止来自 Tailscale 网络的所有入站连接。" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:22 -msgid "When using the exit node, access to the local LAN is allowed." -msgstr "使用出口节点时,允许访问本地局域网。" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:435 -msgid "" -"[Important] Log in to the Tailscale admin console and manually enable " -"\"Subnet Routes\" for this device." -msgstr "【重要】 登录 Tailscale 控制平面,在设备设置中手动授权子网路由。" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:96 -msgid "ago" -msgstr "前" - -#: applications/luci-app-tailscale-community/htdocs/luci-static/resources/view/tailscale.js:411 -msgid "" -"and enables Masquerading and MSS Clamping (MTU fix) to ensure stable " -"connections." -msgstr "并启用地址伪装和 MSS钳制确保连接稳定。" diff --git a/luci-app-tailscale-community/root/usr/share/luci/menu.d/luci-app-tailscale-community.json b/luci-app-tailscale-community/root/usr/share/luci/menu.d/luci-app-tailscale-community.json deleted file mode 100644 index 70c90695c..000000000 --- a/luci-app-tailscale-community/root/usr/share/luci/menu.d/luci-app-tailscale-community.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "admin/services/tailscale": { - "title": "Tailscale", - "order": 90, - "action": { - "type": "view", - "path": "tailscale" - } - } -} diff --git a/luci-app-tailscale-community/root/usr/share/rpcd/acl.d/luci-app-tailscale-community.json b/luci-app-tailscale-community/root/usr/share/rpcd/acl.d/luci-app-tailscale-community.json deleted file mode 100644 index f80185ff1..000000000 --- a/luci-app-tailscale-community/root/usr/share/rpcd/acl.d/luci-app-tailscale-community.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "luci-app-tailscale-community": { - "description": "Allow user access to tailscale", - "read": { - "ubus": { - "tailscale": [ - "get_status", - "get_settings", - "get_subroutes" - ] - }, - "uci": [ "tailscale" ] - }, - "write": { - "ubus": { - "tailscale": [ - "do_login", - "do_logout", - "setup_firewall", - "set_settings" - ] - }, - "uci": [ "tailscale" ] - } - } -} diff --git a/luci-app-tailscale-community/root/usr/share/rpcd/ucode/tailscale.uc b/luci-app-tailscale-community/root/usr/share/rpcd/ucode/tailscale.uc deleted file mode 100644 index fe734a47c..000000000 --- a/luci-app-tailscale-community/root/usr/share/rpcd/ucode/tailscale.uc +++ /dev/null @@ -1,393 +0,0 @@ -#!/usr/bin/env ucode - -'use strict'; - -import { access, popen, readfile, writefile, unlink } from 'fs'; -import { cursor } from 'uci'; - -const uci = cursor(); - -function exec(command) { - let stdout_content = ''; - let p = popen(command, 'r'); - sleep(100); - if (p == null) { - return { code: -1, stdout: '', stderr: `Failed to execute: ${command}` }; - } - for (let line = p.read('line'); length(line); line = p.read('line')) { - stdout_content = stdout_content+line; - } - stdout_content = rtrim(stdout_content); - stdout_content = split(stdout_content, '\n'); - - let exit_code = p.close(); - let stderr_content = ''; - if (exit_code != 0) { - stderr_content = stdout_content; - } - return { code: exit_code, stdout: stdout_content, stderr: stderr_content }; -} - -function shell_quote(s) { - if (s == null || s == '') return "''"; - return "'" + replace(s, "'", "'\\''") + "'"; -} - -const methods = {}; - -methods.get_status = { - call: function() { - let data = { - status: '', - version: '', - TUNMode: '', - health: '', - ipv4: "Not running", - ipv6: null, - domain_name: '', - peers: [] - }; - if (access('/usr/sbin/tailscale')==true || access('/usr/bin/tailscale')==true){ }else{ - data.status = 'not_installed'; - return data; - } - - let status_json_output = exec('tailscale status --json'); - let peer_map = {}; - if (status_json_output.code == 0 && length(status_json_output.stdout) > 0) { - try { - let status_data = json(join('',status_json_output.stdout)); - data.version = status_data?.Version || 'Unknown'; - data.health = status_data?.Health || ''; - data.TUNMode = status_data?.TUN || 'true'; - if (status_data?.BackendState == 'Running') { data.status = 'running'; } - if (status_data?.BackendState == 'NeedsLogin') { data.status = 'logout'; } - - data.ipv4 = status_data?.Self?.TailscaleIPs?.[0] || 'No IP assigned'; - data.ipv6 = status_data?.Self?.TailscaleIPs?.[1] || null; - data.domain_name = status_data?.CurrentTailnet?.Name || ''; - - // peers list - for (let p in status_data?.Peer) { - p = status_data.Peer[p]; - peer_map[p.ID] = { - ip: join('
', p?.TailscaleIPs) || '', - hostname: split(p?.DNSName || '','.')[0] || '', - ostype: p?.OS, - online: p?.Online, - linkadress: (!p?.CurAddr) ? p?.Relay : p?.CurAddr, - lastseen: p?.LastSeen, - exit_node: !!p?.ExitNode, - exit_node_option: !!p?.ExitNodeOption, - tx: p?.TxBytes || '', - rx: p?.RxBytes || '' - }; - } - } catch (e) { /* ignore */ } - } - - data.peers = peer_map; - return data; - } -}; - -methods.get_settings = { - call: function() { - let settings = {}; - uci.load('tailscale'); - let state_file_path = uci.get('tailscale', 'settings', 'state_file') || "/etc/tailscale/tailscaled.state"; - if (access(state_file_path)) { - try { - let state_content = readfile(state_file_path); - if (state_content != null) { - let state_data = json(state_content); - let profiles_b64 = state_data?._profiles; - if (!profiles_b64) return settings; - - let profiles_data = json(b64dec(profiles_b64)); - let profiles_key = null; - for (let key in profiles_data) { - profiles_key = key; - break; - } - profiles_key = 'profile-'+profiles_key; - - let status_data = json(b64dec(state_data?.[profiles_key])); - if (status_data != null) { - settings.accept_routes = status_data?.RouteAll || false; - settings.advertise_exit_node = status_data?.AdvertiseExitNode || false; - settings.advertise_routes = status_data?.AdvertiseRoutes || []; - settings.exit_node = status_data?.ExitNodeID || ""; - settings.exit_node_allow_lan_access = status_data?.ExitNodeAllowLANAccess || false; - settings.shields_up = status_data?.ShieldsUp || false; - settings.ssh = status_data?.RunSSH || false; - settings.runwebclient = status_data?.RunWebClient || false; - settings.nosnat = status_data?.NoSNAT || false; - settings.disable_magic_dns = !status_data?.CorpDNS || false; - settings.fw_mode = split(uci.get('tailscale', 'settings', 'fw_mode'),' ')[0] || 'nftables'; - } - } - } catch (e) { /* ignore */ } - } - return settings; - } -}; - -methods.set_settings = { - args: { form_data: {} }, - call: function(request) { - const form_data = request.args.form_data; - if (form_data == null || length(form_data) == 0) { - return { error: 'Missing or invalid form_data parameter. Please provide settings data.' }; - } - let args = ['set']; - - push(args,'--accept-routes=' + (form_data.accept_routes == '1')); - push(args,'--advertise-exit-node=' + ((form_data.advertise_exit_node == '1')&&(form_data.exit_node == ""))); - if (form_data.exit_node == "") push(args,'--exit-node-allow-lan-access=' + (form_data.exit_node_allow_lan_access == '1')); - push(args,'--ssh=' + (form_data.ssh == '1')); - push(args,'--accept-dns=' + (form_data.disable_magic_dns != '1')); - push(args,'--shields-up=' + (form_data.shields_up == '1')); - push(args,'--webclient=' + (form_data.runwebclient == '1')); - push(args,'--snat-subnet-routes=' + (form_data.nosnat != '1')); - push(args,'--advertise-routes ' + (shell_quote(join(',',form_data.advertise_routes)) || '\"\"')); - push(args,'--exit-node=' + (shell_quote(form_data.exit_node) || '\"\"')); - if (form_data.exit_node != "") push(args,' --exit-node-allow-lan-access=true'); - push(args,'--hostname ' + (shell_quote(form_data.hostname) || '\"\"')); - - let cmd_array = 'tailscale '+join(' ', args); - let set_result = exec(cmd_array); - if (set_result.code != 0) { - return { error: 'Failed to apply node settings: ' + set_result.stderr }; - } - - uci.load('tailscale'); - for (let key in form_data) { - uci.set('tailscale', 'settings', key, form_data[key]); - } - uci.save('tailscale'); - uci.commit('tailscale'); - - // process reduce memory https://github.com/GuNanOvO/openwrt-tailscale - // some new versions of Tailscale may not work well with this method - //if (form_data.daemon_mtu != "" || form_data.daemon_reduce_memory != "") { - // popen('/bin/sh -c ". ' + env_script_path + ' && /etc/init.d/tailscale restart" &'); - //} - return { success: true }; - } -}; - -methods.do_login = { - args: { form_data: {} }, - call: function(request) { - const form_data = request.args.form_data; - let loginargs = []; - if (form_data == null || length(form_data) == 0) { - return { error: 'Missing or invalid form_data parameter. Please provide login data.' }; - } - - let status=methods.get_status.call(); - if (status.status != 'logout') { - return { error: 'Tailscale is already logged in and running.' }; - } - - // --- 1. Prepare and Run Login Command (Once) --- - const loginserver = trim(form_data.loginserver) || ''; - const loginserver_authkey = trim(form_data.loginserver_authkey) || ''; - - if (loginserver!='') { - push(loginargs,'--login-server '+shell_quote(loginserver)); - if (loginserver_authkey!='') { - push(loginargs,'--auth-key '+shell_quote(loginserver_authkey)); - } - } - - // Run the command in the background using /bin/sh -c to handle the '&' correctly - let login_cmd = 'tailscale login '+join(' ', loginargs); - popen('/bin/sh -c "' + login_cmd + ' &"', 'r'); - - // --- 2. Loop to Check Status for URL --- - let max_attempts = 15; - let interval = 2000; - - for (let i = 0; i < max_attempts; i++) { - let tresult = exec('tailscale status'); - for (let line in tresult.stdout) { - let trline = trim(line); - if (index(trline, 'http') != -1) { - let parts = split(trline, ' '); - for (let part in parts) { - if (index(part, 'http') != -1) { - return { url: part }; - } - } - } - } - sleep(interval); - } - return { error: 'Could not retrieve login URL from tailscale command after 30 seconds.' }; - } -}; - -methods.do_logout = { - call: function() { - let status=methods.get_status.call(); - if (status.status != 'running') { - return { error: 'Tailscale is not running. Cannot perform logout.' }; - } - - let logout_result = exec('tailscale logout'); - if (logout_result.code != 0) { - return { error: 'Failed to logout: ' + logout_result.stderr }; - } - return { success: true }; - } -}; - -methods.get_subroutes = { - call: function() { - try { - let cmd = 'ip -j route'; - let result = exec(cmd); - let subnets = []; - - if (result.code == 0 && length(result.stdout) > 0) { - let routes_json = json(join('',result.stdout)); - - for (let route in routes_json) { - // We need to filter out local subnets - // 1. 'dst' (target address) is not' default' (default gateway) - // 2. 'scope' is' link' (indicating directly connected network) - // 3. It is an IPv4 address (simple judgment: including'.') - if (route?.dst && route.dst != 'default' && route?.scope == 'link' && index(route.dst,'.') != -1) { - push(subnets,route.dst); - } - } - } - return { routes: subnets }; - } - catch(e) { - return { routes: [] }; - } - } -}; - -methods.setup_firewall = { - call: function() { - try { - uci.load('network'); - uci.load('firewall'); - - let changed_network = false; - let changed_firewall = false; - - // 1. config Network Interface - let net_ts = uci.get('network', 'tailscale'); - if (net_ts == null) { - uci.set('network', 'tailscale', 'interface'); - uci.set('network', 'tailscale', 'proto', 'none'); - uci.set('network', 'tailscale', 'device', 'tailscale0'); - changed_network = true; - } else { - let current_dev = uci.get('network', 'tailscale', 'device'); - if (current_dev != 'tailscale0') { - uci.set('network', 'tailscale', 'device', 'tailscale0'); - changed_network = true; - } - } - - // 2. config Firewall Zone - let fw_all = uci.get_all('firewall'); - let ts_zone_section = null; - let fwd_lan_to_ts = false; - let fwd_ts_to_lan = false; - - for (let sec_key in fw_all) { - let s = fw_all[sec_key]; - if (s['.type'] == 'zone' && s['name'] == 'tailscale') { - ts_zone_section = sec_key; - } - if (s['.type'] == 'forwarding') { - if (s.src == 'lan' && s.dest == 'tailscale') fwd_lan_to_ts = true; - if (s.src == 'tailscale' && s.dest == 'lan') fwd_ts_to_lan = true; - } - } - - if (ts_zone_section == null) { - let zid = uci.add('firewall', 'zone'); - uci.set('firewall', zid, 'name', 'tailscale'); - uci.set('firewall', zid, 'input', 'ACCEPT'); - uci.set('firewall', zid, 'output', 'ACCEPT'); - uci.set('firewall', zid, 'forward', 'ACCEPT'); - uci.set('firewall', zid, 'masq', '1'); - uci.set('firewall', zid, 'mtu_fix', '1'); - uci.set('firewall', zid, 'network', ['tailscale']); - changed_firewall = true; - } else { - let nets = uci.get('firewall', ts_zone_section, 'network'); - let net_list = []; - let has_ts_net = false; - - if (type(nets) == 'array') { - net_list = nets; - } else if (type(nets) == 'string') { - net_list = [nets]; - } - - // check if 'tailscale' is already in the list - for (let n in net_list) { - if (net_list[n] == 'tailscale') { - has_ts_net = true; - break; - } - } - - if (!has_ts_net) { - push(net_list, 'tailscale'); - uci.set('firewall', ts_zone_section, 'network', net_list); - changed_firewall = true; - } - } - - // 3. config Forwarding - if (!fwd_lan_to_ts) { - let fid = uci.add('firewall', 'forwarding'); - uci.set('firewall', fid, 'src', 'lan'); - uci.set('firewall', fid, 'dest', 'tailscale'); - changed_firewall = true; - } - - if (!fwd_ts_to_lan) { - let fid = uci.add('firewall', 'forwarding'); - uci.set('firewall', fid, 'src', 'tailscale'); - uci.set('firewall', fid, 'dest', 'lan'); - changed_firewall = true; - } - - // 4. save - if (changed_network) { - uci.save('network'); - uci.commit('network'); - exec('/etc/init.d/network reload'); - } - - if (changed_firewall) { - uci.save('firewall'); - uci.commit('firewall'); - exec('/etc/init.d/firewall reload'); - } - - return { - success: true, - changed_network: changed_network, - changed_firewall: changed_firewall, - message: (changed_network || changed_firewall) ? 'Tailscale firewall/interface configuration applied.' : 'Tailscale firewall/interface already configured.' - }; - - } catch (e) { - return { error: 'Exception in setup_firewall: ' + e + '\nStack: ' + (e.stacktrace || '') }; - } - } -}; - -return { 'tailscale': methods }; diff --git a/luci-app-tailscale/Makefile b/luci-app-tailscale/Makefile deleted file mode 100644 index 4feaeb43d..000000000 --- a/luci-app-tailscale/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -# SPDX-License-Identifier: GPL-3.0-only -# -# Copyright (C) 2024 asvow - -include $(TOPDIR)/rules.mk - -LUCI_TITLE:=LuCI for Tailscale -LUCI_DEPENDS:=+tailscale -LUCI_PKGARCH:=all - -PKG_VERSION:=1.2.6 -PKG_RELEASE:=1 - -include $(TOPDIR)/feeds/luci/luci.mk - -# call BuildPackage - OpenWrt buildroot signature \ No newline at end of file diff --git a/luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/interface.js b/luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/interface.js deleted file mode 100644 index 68098c241..000000000 --- a/luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/interface.js +++ /dev/null @@ -1,115 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-only - * - * Copyright (C) 2022 ImmortalWrt.org - * Copyright (C) 2024 asvow - */ - -'use strict'; -'require dom'; -'require fs'; -'require poll'; -'require ui'; -'require view'; - -return view.extend({ - async load() { - const res = await fs.exec('/sbin/ip', ['-s', '-j', 'ad']); - if (res.code !== 0 || !res.stdout || res.stdout.trim() === '') { - ui.addNotification(null, E('p', {}, _('Unable to get interface info: %s.').format(res.message))); - return []; - } - - try { - const interfaces = JSON.parse(res.stdout); - const tailscaleInterfaces = interfaces.filter(iface => iface.ifname.match(/tailscale[0-9]+/)); - - return tailscaleInterfaces.map(iface => { - const parsedInfo = { - name: iface.ifname - }; - - const addr_info = iface.addr_info || []; - addr_info.forEach(addr => { - if (addr.family === 'inet' && !parsedInfo.ipv4) { - parsedInfo.ipv4 = addr.local; - } else if (addr.family === 'inet6' && !parsedInfo.ipv6) { - parsedInfo.ipv6 = addr.local; - } - }); - - parsedInfo.mtu = iface.mtu; - parsedInfo.rxBytes = '%1024mB'.format(iface.stats64.rx.bytes); - parsedInfo.txBytes = '%1024mB'.format(iface.stats64.tx.bytes); - - return parsedInfo; - }); - } catch (e) { - ui.addNotification(null, E('p', {}, _('Error parsing interface info: %s.').format(e.message))); - return []; - } - }, - - pollData(container) { - poll.add(async () => { - const data = await this.load(); - dom.content(container, this.renderContent(data)); - }); - }, - - renderContent(data) { - if (!Array.isArray(data) || data.length === 0) { - return E('div', {}, _('No interface online.')); - } - const rows = [ - E('th', { class: 'th', colspan: '2' }, _('Network Interface Information')) - ]; - data.forEach(interfaceData => { - rows.push( - E('tr', { class: 'tr' }, [ - E('td', { class: 'td left', width: '25%' }, _('Interface Name')), - E('td', { class: 'td left', width: '25%' }, interfaceData.name) - ]), - E('tr', { class: 'tr' }, [ - E('td', { class: 'td left', width: '25%' }, _('IPv4 Address')), - E('td', { class: 'td left', width: '25%' }, interfaceData.ipv4) - ]), - E('tr', { class: 'tr' }, [ - E('td', { class: 'td left', width: '25%' }, _('IPv6 Address')), - E('td', { class: 'td left', width: '25%' }, interfaceData.ipv6) - ]), - E('tr', { class: 'tr' }, [ - E('td', { class: 'td left', width: '25%' }, _('MTU')), - E('td', { class: 'td left', width: '25%' }, interfaceData.mtu) - ]), - E('tr', { class: 'tr' }, [ - E('td', { class: 'td left', width: '25%' }, _('Total Download')), - E('td', { class: 'td left', width: '25%' }, interfaceData.rxBytes) - ]), - E('tr', { class: 'tr' }, [ - E('td', { class: 'td left', width: '25%' }, _('Total Upload')), - E('td', { class: 'td left', width: '25%' }, interfaceData.txBytes) - ]) - ); - }); - - return E('table', { 'class': 'table' }, rows); - }, - - render(data) { - const content = E([], [ - E('h2', { class: 'content' }, _('Tailscale')), - E('div', { class: 'cbi-map-descr' }, _('Tailscale is a cross-platform and easy to use virtual LAN.')), - E('div') - ]); - const container = content.lastElementChild; - - dom.content(container, this.renderContent(data)); - this.pollData(container); - - return content; - }, - - handleSaveApply: null, - handleSave: null, - handleReset: null -}); diff --git a/luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/log.js b/luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/log.js deleted file mode 100644 index bdb995c33..000000000 --- a/luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/log.js +++ /dev/null @@ -1,92 +0,0 @@ -'use strict'; -'require fs'; -'require poll'; -'require ui'; -'require view'; - -return view.extend({ - async retrieveLog() { - const stat = await Promise.all([ - L.resolveDefault(fs.stat('/sbin/logread'), null), - L.resolveDefault(fs.stat('/usr/sbin/logread'), null) - ]); - const logger = stat[0] ? stat[0].path : stat[1] ? stat[1].path : null; - - const logdata = await fs.exec_direct(logger, ['-e', 'tailscale']); - const statusMappings = { - 'daemon.err': { status: 'StdErr', startIndex: 9 }, - 'daemon.notice': { status: 'Info', startIndex: 10 } - }; - const loglines = logdata.trim().split(/\n/).map(function(log) { - const logParts = log.split(' ').filter(Boolean); - if (logParts.length >= 6) { - const formattedTime = `${logParts[1]} ${logParts[2]} - ${logParts[3]}`; - const status = logParts[5]; - const mapping = statusMappings[status] || { status: status, startIndex: 9 }; - const newStatus = mapping.status; - const startIndex = mapping.startIndex; - const message = logParts.slice(startIndex).join(' '); - return `${formattedTime} [ ${newStatus} ] - ${message}`; - } else { - return 'Log is empty.'; - } - }).filter(Boolean); - return { value: loglines.join('\n'), rows: loglines.length + 1 }; - }, - - async pollLog() { - const element = document.getElementById('syslog'); - if (element) { - try { - const log = await this.retrieveLog(); - element.value = log.value; - element.rows = log.rows; - } catch (err) { - ui.addNotification(null, E('p', {}, _('Unable to load log data: ' + err.message))); - } - } - }, - - load() { - poll.add(this.pollLog.bind(this)); - return this.retrieveLog(); - }, - - render(loglines) { - const scrollDownButton = E('button', { - id: 'scrollDownButton', - class: 'cbi-button cbi-button-neutral' - }, _('Scroll to tail', 'scroll to bottom (the tail) of the log file') - ); - scrollDownButton.addEventListener('click', function() { - scrollUpButton.scrollIntoView(); - }); - - const scrollUpButton = E('button', { - id : 'scrollUpButton', - class: 'cbi-button cbi-button-neutral' - }, _('Scroll to head', 'scroll to top (the head) of the log file') - ); - scrollUpButton.addEventListener('click', function() { - scrollDownButton.scrollIntoView(); - }); - - return E([], [ - E('div', { id: 'content_syslog' }, [ - E('div', { style: 'padding-bottom: 20px' }, [scrollDownButton]), - E('textarea', { - id: 'syslog', - style: 'font-size:12px', - readonly: 'readonly', - wrap: 'off', - rows: loglines.rows, - }, [ loglines.value ]), - E('div', { style: 'padding-bottom: 20px' }, [scrollUpButton]) - ]) - ]); - }, - - handleSaveApply: null, - handleSave: null, - handleReset: null -}); diff --git a/luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js b/luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js deleted file mode 100644 index 08f53f0dd..000000000 --- a/luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js +++ /dev/null @@ -1,268 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-only - * - * Copyright (C) 2024 asvow - */ - -'use strict'; -'require form'; -'require fs'; -'require network'; -'require poll'; -'require rpc'; -'require uci'; -'require view'; - -const callServiceList = rpc.declare({ - object: 'service', - method: 'list', - params: ['name'], - expect: { '': {} } -}); - -async function getInterfaceSubnets(interfaces = ['lan', 'wan']) { - const networks = await network.getNetworks(); - return [...new Set( - networks - .filter(ifc => interfaces.includes(ifc.getName())) - .flatMap(ifc => ifc.getIPAddrs()) - .filter(addr => addr.includes('/')) - .map(addr => { - const [ip, cidr] = addr.split('/'); - const ipParts = ip.split('.').map(Number); - const mask = ~((1 << (32 - parseInt(cidr))) - 1); - const subnetParts = ipParts.map((part, i) => (part & (mask >> (24 - i * 8))) & 255); - return `${subnetParts.join('.')}/${cidr}`; - }) - )]; -} - -async function getStatus() { - const status = { - isRunning: false, - backendState: undefined, - authURL: undefined, - displayName: undefined, - onlineExitNodes: [], - subnetRoutes: [] - }; - const res = await callServiceList('tailscale'); - try { - status.isRunning = res['tailscale']['instances']['instance1']['running']; - } catch (e) { - return status; - } - const tailscaleRes = await fs.exec("/usr/sbin/tailscale", ["status", "--json"]); - const tailscaleStatus = JSON.parse(tailscaleRes.stdout.replace(/("\w+"):\s*(\d+)/g, '$1:"$2"')); - if (!tailscaleStatus.AuthURL && tailscaleStatus.BackendState === "NeedsLogin") { - fs.exec("/usr/sbin/tailscale", ["login"]); - } - status.backendState = tailscaleStatus.BackendState; - status.authURL = tailscaleStatus.AuthURL; - status.displayName = (status.backendState === "Running") ? tailscaleStatus.User[tailscaleStatus.Self.UserID].DisplayName : undefined; - if (tailscaleStatus.Peer) { - status.onlineExitNodes = Object.values(tailscaleStatus.Peer) - .flatMap(peer => (peer.ExitNodeOption && peer.Online) ? [peer.HostName] : []); - status.subnetRoutes = Object.values(tailscaleStatus.Peer) - .flatMap(peer => peer.PrimaryRoutes || []); - } - return status; -} - -function renderStatus(isRunning) { - const spanTemp = '%s %s'; - let renderHTML; - if (isRunning) { - renderHTML = String.format(spanTemp, 'green', _('Tailscale'), _('RUNNING')); - } else { - renderHTML = String.format(spanTemp, 'red', _('Tailscale'), _('NOT RUNNING')); - } - - return renderHTML; -} - -function renderLogin(loginStatus, authURL, displayName) { - const spanTemp = '%s'; - let renderHTML; - if (loginStatus === "NeedsLogin") { - renderHTML = String.format('%s', authURL, _('Need to log in')); - } else if (loginStatus === "Running") { - renderHTML = String.format('%s', 'https://login.tailscale.com/admin/machines', displayName); - renderHTML += String.format('
%s', _('Log out and Unbind')); - } else { - renderHTML = String.format(spanTemp, 'orange', _('NOT RUNNING')); - } - - return renderHTML; -} - -return view.extend({ - load() { - return Promise.all([ - uci.load('tailscale'), - getStatus(), - getInterfaceSubnets() - ]); - }, - - render(data) { - let m, s, o; - const statusData = data[1]; - const interfaceSubnets = data[2]; - const onlineExitNodes = statusData.onlineExitNodes; - const subnetRoutes = statusData.subnetRoutes; - - m = new form.Map('tailscale', _('Tailscale'), _('Tailscale is a cross-platform and easy to use virtual LAN.')); - - s = m.section(form.TypedSection); - s.anonymous = true; - s.render = function () { - poll.add(async function() { - const res = await getStatus(); - const service_view = document.getElementById("service_status"); - const login_view = document.getElementById("login_status_div"); - service_view.innerHTML = renderStatus(res.isRunning); - login_view.innerHTML = renderLogin(res.backendState, res.authURL, res.displayName); - const logoutButton = document.getElementById('logout_button'); - if (logoutButton) { - logoutButton.onclick = function() { - if (confirm(_('Are you sure you want to log out and unbind the current device?'))) { - fs.exec("/usr/sbin/tailscale", ["logout"]); - } - } - } - }); - - return E('div', { class: 'cbi-section', id: 'status_bar' }, [ - E('p', { id: 'service_status' }, _('Collecting data ...')) - ]); - } - - s = m.section(form.NamedSection, 'settings', 'config'); - s.tab('basic', _('Basic Settings')); - - o = s.taboption('basic', form.Flag, 'enabled', _('Enable')); - o.default = o.disabled; - o.rmempty = false; - - o = s.taboption('basic', form.DummyValue, 'login_status', _('Login Status')); - o.depends('enabled', '1'); - o.renderWidget = function(section_id, option_id) { - return E('div', { 'id': 'login_status_div' }, _('Collecting data ...')); - }; - - o = s.taboption('basic', form.Value, 'port', _('Port'), _('Set the Tailscale port number.')); - o.datatype = 'port'; - o.default = '41641'; - o.rmempty = false; - - o = s.taboption('basic', form.Value, 'config_path', _('Workdir'), _('The working directory contains config files, audit logs, and runtime info.')); - o.default = '/etc/tailscale'; - o.rmempty = false; - - o = s.taboption('basic', form.ListValue, 'fw_mode', _('Firewall Mode')); - o.value('iptables', 'iptables'); - o.value('nftables', 'nftables'); - o.default = 'iptables'; - o.rmempty = false; - - o = s.taboption('basic', form.Flag, 'log_stdout', _('StdOut Log'), _('Logging program activities.')); - o.default = o.enabled; - o.rmempty = false; - - o = s.taboption('basic', form.Flag, 'log_stderr', _('StdErr Log'), _('Logging program errors and exceptions.')); - o.default = o.enabled; - o.rmempty = false; - - s.tab('advance', _('Advanced Settings')); - - o = s.taboption('advance', form.Flag, 'accept_routes', _('Accept Routes'), _('Accept subnet routes that other nodes advertise.')); - o.default = o.disabled; - o.rmempty = false; - - o = s.taboption('advance', form.Value, 'hostname', _('Device Name'), _("Leave blank to use the device's hostname.")); - o.default = ''; - o.rmempty = true; - - o = s.taboption('advance', form.Flag, 'accept_dns', _('Accept DNS'), _('Accept DNS configuration from the Tailscale admin console.')); - o.default = o.enabled; - o.rmempty = false; - - o = s.taboption('advance', form.Flag, 'advertise_exit_node', _('Exit Node'), _('Offer to be an exit node for outbound internet traffic from the Tailscale network.')); - o.default = o.disabled; - o.rmempty = false; - - o = s.taboption('advance', form.ListValue, 'exit_node', _('Online Exit Nodes'), _('Select an online machine name to use as an exit node.')); - if (onlineExitNodes.length > 0) { - o.optional = true; - onlineExitNodes.forEach(function(node) { - o.value(node, node); - }); - } else { - o.value('', _('No Available Exit Nodes')); - o.readonly = true; - } - o.default = ''; - o.depends('advertise_exit_node', '0'); - o.rmempty = true; - - o = s.taboption('advance', form.DynamicList, 'advertise_routes', _('Expose Subnets'), _('Expose physical network routes into Tailscale, e.g. 10.0.0.0/24.')); - if (interfaceSubnets.length > 0) { - interfaceSubnets.forEach(function(subnet) { - o.value(subnet, subnet); - }); - } - o.default = ''; - o.rmempty = true; - - o = s.taboption('advance', form.Flag, 'disable_snat_subnet_routes', _('Site To Site'), _('Use site-to-site layer 3 networking to connect subnets on the Tailscale network.')); - o.default = o.disabled; - o.depends('accept_routes', '1'); - o.rmempty = false; - - o = s.taboption('advance', form.DynamicList, 'subnet_routes', _('Subnet Routes'), _('Select subnet routes advertised by other nodes in Tailscale network.')); - if (subnetRoutes.length > 0) { - subnetRoutes.forEach(function(route) { - o.value(route, route); - }); - } else { - o.value('', _('No Available Subnet Routes')); - o.readonly = true; - } - o.default = ''; - o.depends('disable_snat_subnet_routes', '1'); - o.rmempty = true; - - o = s.taboption('advance', form.MultiValue, 'access', _('Access Control')); - o.value('ts_ac_lan', _('Tailscale access LAN')); - o.value('ts_ac_wan', _('Tailscale access WAN')); - o.value('lan_ac_ts', _('LAN access Tailscale')); - o.value('wan_ac_ts', _('WAN access Tailscale')); - o.default = "ts_ac_lan ts_ac_wan lan_ac_ts"; - o.rmempty = true; - - s.tab('extra', _('Extra Settings')); - - o = s.taboption('extra', form.DynamicList, 'flags', _('Additional Flags'), - String.format( - _('List of extra flags. Format: --flags=value, e.g. --exit-node=10.0.0.1.
%s for enabling settings upon the initiation of Tailscale.'), - '' + _('Available flags') + '' - ) - ); - o.default = ''; - o.rmempty = true; - - s = m.section(form.NamedSection, 'settings', 'config'); - s.title = _('Custom Server Settings'); - s.description = String.format(_('Use %s to deploy a private server.'), 'headscale'); - - o = s.option(form.Value, 'login_server', _('Server Address')); - o.default = ''; - o.rmempty = true; - - o = s.option(form.Value, 'authKey', _('Auth Key')); - o.default = ''; - o.rmempty = true; - - return m.render(); - } -}); diff --git a/luci-app-tailscale/po/templates/tailscale.pot b/luci-app-tailscale/po/templates/tailscale.pot deleted file mode 100644 index b546effb7..000000000 --- a/luci-app-tailscale/po/templates/tailscale.pot +++ /dev/null @@ -1,295 +0,0 @@ -msgid "" -msgstr "Content-Type: text/plain; charset=UTF-8" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:186 -msgid "Accept DNS" -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:186 -msgid "Accept DNS configuration from the Tailscale admin console." -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:178 -msgid "Accept Routes" -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:178 -msgid "Accept subnet routes that other nodes advertise." -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:235 -msgid "Access Control" -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:245 -msgid "Additional Flags" -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:176 -msgid "Advanced Settings" -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:128 -msgid "Are you sure you want to log out and unbind the current device?" -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:262 -msgid "Auth Key" -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:248 -msgid "Available flags" -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:141 -msgid "Basic Settings" -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:136 -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:150 -msgid "Collecting data ..." -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:255 -msgid "Custom Server Settings" -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:182 -msgid "Device Name" -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:143 -msgid "Enable" -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/interface.js:47 -msgid "Error parsing interface info: %s." -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:190 -msgid "Exit Node" -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:208 -msgid "Expose Subnets" -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:208 -msgid "" -"Expose physical network routes into Tailscale, e.g. 10.0.0.0/24." -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:243 -msgid "Extra Settings" -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:162 -msgid "Firewall Mode" -msgstr "" - -#: luci-app-tailscale/root/usr/share/luci/menu.d/luci-app-tailscale.json:14 -msgid "Global Settings" -msgstr "" - -#: luci-app-tailscale/root/usr/share/rpcd/acl.d/luci-app-tailscale.json:3 -msgid "Grant access to Tailscale configuration" -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/interface.js:73 -msgid "IPv4 Address" -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/interface.js:77 -msgid "IPv6 Address" -msgstr "" - -#: luci-app-tailscale/root/usr/share/luci/menu.d/luci-app-tailscale.json:22 -msgid "Interface Info" -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/interface.js:69 -msgid "Interface Name" -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:238 -msgid "LAN access Tailscale" -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:182 -msgid "Leave blank to use the device's hostname." -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:247 -msgid "" -"List of extra flags. Format: --flags=value, e.g. --exit-node=10.0.0.1.
%s for enabling settings upon the initiation of Tailscale." -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:90 -msgid "Log out and Unbind" -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:168 -msgid "Logging program activities." -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:172 -msgid "Logging program errors and exceptions." -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:147 -msgid "Login Status" -msgstr "" - -#: luci-app-tailscale/root/usr/share/luci/menu.d/luci-app-tailscale.json:30 -msgid "Logs" -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/interface.js:81 -msgid "MTU" -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:77 -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:92 -msgid "NOT RUNNING" -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:87 -msgid "Need to log in" -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/interface.js:64 -msgid "Network Interface Information" -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:201 -msgid "No Available Exit Nodes" -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:228 -msgid "No Available Subnet Routes" -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/interface.js:61 -msgid "No interface online." -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:190 -msgid "" -"Offer to be an exit node for outbound internet traffic from the Tailscale " -"network." -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:194 -msgid "Online Exit Nodes" -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:153 -msgid "Port" -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:75 -msgid "RUNNING" -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/log.js:68 -msgctxt "scroll to top (the head) of the log file" -msgid "Scroll to head" -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/log.js:59 -msgctxt "scroll to bottom (the tail) of the log file" -msgid "Scroll to tail" -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:194 -msgid "Select an online machine name to use as an exit node." -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:222 -msgid "Select subnet routes advertised by other nodes in Tailscale network." -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:258 -msgid "Server Address" -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:153 -msgid "Set the Tailscale port number." -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:217 -msgid "Site To Site" -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:172 -msgid "StdErr Log" -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:168 -msgid "StdOut Log" -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:222 -msgid "Subnet Routes" -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/interface.js:100 -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:75 -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:77 -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:114 -#: luci-app-tailscale/root/usr/share/luci/menu.d/luci-app-tailscale.json:3 -msgid "Tailscale" -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:236 -msgid "Tailscale access LAN" -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:237 -msgid "Tailscale access WAN" -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/interface.js:101 -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:114 -msgid "Tailscale is a cross-platform and easy to use virtual LAN." -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:158 -msgid "" -"The working directory contains config files, audit logs, and runtime info." -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/interface.js:85 -msgid "Total Download" -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/interface.js:89 -msgid "Total Upload" -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/interface.js:18 -msgid "Unable to get interface info: %s." -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/log.js:45 -msgid "Unable to load log data:" -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:256 -msgid "Use %s to deploy a private server." -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:217 -msgid "" -"Use site-to-site layer 3 networking to connect subnets on the Tailscale " -"network." -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:239 -msgid "WAN access Tailscale" -msgstr "" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:158 -msgid "Workdir" -msgstr "" diff --git a/luci-app-tailscale/po/zh-cn b/luci-app-tailscale/po/zh-cn deleted file mode 120000 index 8d69574dd..000000000 --- a/luci-app-tailscale/po/zh-cn +++ /dev/null @@ -1 +0,0 @@ -zh_Hans \ No newline at end of file diff --git a/luci-app-tailscale/po/zh_Hans/tailscale.po b/luci-app-tailscale/po/zh_Hans/tailscale.po deleted file mode 100644 index 6ec185139..000000000 --- a/luci-app-tailscale/po/zh_Hans/tailscale.po +++ /dev/null @@ -1,301 +0,0 @@ -msgid "" -msgstr "" -"Content-Type: text/plain; charset=UTF-8\n" -"Last-Translator: Automatically generated\n" -"Language-Team: none\n" -"Language: zh_Hans\n" -"MIME-Version: 1.0\n" -"Content-Transfer-Encoding: 8bit\n" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:186 -msgid "Accept DNS" -msgstr "允许DNS" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:186 -msgid "Accept DNS configuration from the Tailscale admin console." -msgstr "使用 Tailscale 管理控制台的 DNS 配置。" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:178 -msgid "Accept Routes" -msgstr "启用路由" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:178 -msgid "Accept subnet routes that other nodes advertise." -msgstr "接受其他节点广播的子网路由。" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:235 -msgid "Access Control" -msgstr "访问控制" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:245 -msgid "Additional Flags" -msgstr "参数列表" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:176 -msgid "Advanced Settings" -msgstr "高级设置" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:128 -msgid "Are you sure you want to log out and unbind the current device?" -msgstr "是否注销当前登录并且解绑当前设备?" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:262 -msgid "Auth Key" -msgstr "认证密钥" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:248 -msgid "Available flags" -msgstr "可用参数" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:141 -msgid "Basic Settings" -msgstr "基础设置" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:136 -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:150 -msgid "Collecting data ..." -msgstr "正在收集数据..." - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:255 -msgid "Custom Server Settings" -msgstr "自定义服务器" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:182 -msgid "Device Name" -msgstr "设备名称" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:143 -msgid "Enable" -msgstr "启用" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/interface.js:47 -msgid "Error parsing interface info: %s." -msgstr "接口信息解析错误:%s。" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:190 -msgid "Exit Node" -msgstr "出口节点" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:208 -msgid "Expose Subnets" -msgstr "公开网段" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:208 -msgid "" -"Expose physical network routes into Tailscale, e.g. 10.0.0.0/24." -msgstr "广播子网路由至 Tailscale,例如:10.0.0.0/24。" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:243 -msgid "Extra Settings" -msgstr "附加设置" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:162 -msgid "Firewall Mode" -msgstr "防火墙模式" - -#: luci-app-tailscale/root/usr/share/luci/menu.d/luci-app-tailscale.json:14 -msgid "Global Settings" -msgstr "全局设置" - -#: luci-app-tailscale/root/usr/share/rpcd/acl.d/luci-app-tailscale.json:3 -msgid "Grant access to Tailscale configuration" -msgstr "授予访问 Tailscale 配置的权限" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/interface.js:73 -msgid "IPv4 Address" -msgstr "IPv4地址" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/interface.js:77 -msgid "IPv6 Address" -msgstr "IPv6地址" - -#: luci-app-tailscale/root/usr/share/luci/menu.d/luci-app-tailscale.json:22 -msgid "Interface Info" -msgstr "接口信息" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/interface.js:69 -msgid "Interface Name" -msgstr "接口名称" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:238 -msgid "LAN access Tailscale" -msgstr "本地局域网访问虚拟局域网" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:182 -msgid "Leave blank to use the device's hostname." -msgstr "留空以使用设备的主机名。" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:247 -msgid "" -"List of extra flags. Format: --flags=value, e.g. --exit-node=10.0.0.1.
%s for enabling settings upon the initiation of Tailscale." -msgstr "额外参数的列表。格式:--flags=value,例如 --exit-node=10.0.0.1。
在 Tailscale 启动时的%s。" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:90 -msgid "Log out and Unbind" -msgstr "注销登录并解除绑定" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:168 -msgid "Logging program activities." -msgstr "记录程序运行信息。" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:172 -msgid "Logging program errors and exceptions." -msgstr "记录程序错误和警告信息。" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:147 -msgid "Login Status" -msgstr "已绑定用户" - -#: luci-app-tailscale/root/usr/share/luci/menu.d/luci-app-tailscale.json:30 -msgid "Logs" -msgstr "日志" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/interface.js:81 -msgid "MTU" -msgstr "MTU" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:77 -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:92 -msgid "NOT RUNNING" -msgstr "未运行" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:87 -msgid "Need to log in" -msgstr "未登录" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/interface.js:64 -msgid "Network Interface Information" -msgstr "网络接口信息" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:201 -msgid "No Available Exit Nodes" -msgstr "没有可用的出口节点" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:228 -msgid "No Available Subnet Routes" -msgstr "没有可用的子网路由" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/interface.js:61 -msgid "No interface online." -msgstr "无在线接口。" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:190 -msgid "" -"Offer to be an exit node for outbound internet traffic from the Tailscale " -"network." -msgstr "作为 Tailscale 广域网出口节点。" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:194 -msgid "Online Exit Nodes" -msgstr "可用出口节点" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:153 -msgid "Port" -msgstr "端口" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:75 -msgid "RUNNING" -msgstr "运行中" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/log.js:68 -msgctxt "scroll to top (the head) of the log file" -msgid "Scroll to head" -msgstr "滚动到顶部" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/log.js:59 -msgctxt "scroll to bottom (the tail) of the log file" -msgid "Scroll to tail" -msgstr "滚动到底部" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:194 -msgid "Select an online machine name to use as an exit node." -msgstr "选择一个可用的节点名称作为出口节点使用。" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:222 -msgid "Select subnet routes advertised by other nodes in Tailscale network." -msgstr "选择非本设备广播的子网路由。" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:258 -msgid "Server Address" -msgstr "服务器地址" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:153 -msgid "Set the Tailscale port number." -msgstr "设置 Tailscale 端口号。" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:217 -msgid "Site To Site" -msgstr "子网互通" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:172 -msgid "StdErr Log" -msgstr "错误日志" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:168 -msgid "StdOut Log" -msgstr "运行日志" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:222 -msgid "Subnet Routes" -msgstr "子网路由" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/interface.js:100 -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:75 -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:77 -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:114 -#: luci-app-tailscale/root/usr/share/luci/menu.d/luci-app-tailscale.json:3 -msgid "Tailscale" -msgstr "Tailscale" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:236 -msgid "Tailscale access LAN" -msgstr "虚拟局域网访问本地局域网" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:237 -msgid "Tailscale access WAN" -msgstr "虚拟局域网访问本地广域网" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/interface.js:101 -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:114 -msgid "Tailscale is a cross-platform and easy to use virtual LAN." -msgstr "Tailscale 是一个跨平台且易于使用的虚拟局域网 VPN。" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:158 -msgid "" -"The working directory contains config files, audit logs, and runtime info." -msgstr "工作目录包含配置文件、审计日志和运行时信息。" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/interface.js:85 -msgid "Total Download" -msgstr "总下载量" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/interface.js:89 -msgid "Total Upload" -msgstr "总上传量" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/interface.js:18 -msgid "Unable to get interface info: %s." -msgstr "无法获取接口信息:%s。" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/log.js:45 -msgid "Unable to load log data:" -msgstr "无法读取日志数据:" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:256 -msgid "Use %s to deploy a private server." -msgstr "使用 %s 部署私有服务器" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:217 -msgid "" -"Use site-to-site layer 3 networking to connect subnets on the Tailscale " -"network." -msgstr "使用站点到站点的三层网络连接 Tailscale 中的子网。" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:239 -msgid "WAN access Tailscale" -msgstr "本地广域网访问虚拟局域网" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:158 -msgid "Workdir" -msgstr "工作目录" diff --git a/luci-app-tailscale/po/zh_Hant/tailscale.po b/luci-app-tailscale/po/zh_Hant/tailscale.po deleted file mode 100644 index fa5a70e7b..000000000 --- a/luci-app-tailscale/po/zh_Hant/tailscale.po +++ /dev/null @@ -1,301 +0,0 @@ -msgid "" -msgstr "" -"Content-Type: text/plain; charset=UTF-8\n" -"Last-Translator: Automatically generated\n" -"Language-Team: none\n" -"Language: zh_Hant\n" -"MIME-Version: 1.0\n" -"Content-Transfer-Encoding: 8bit\n" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:186 -msgid "Accept DNS" -msgstr "允許DNS" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:186 -msgid "Accept DNS configuration from the Tailscale admin console." -msgstr "使用 Tailscale 管理控制台的 DNS 設定。" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:178 -msgid "Accept Routes" -msgstr "啟用路由" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:178 -msgid "Accept subnet routes that other nodes advertise." -msgstr "接受其他節點廣播的子網路由。" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:235 -msgid "Access Control" -msgstr "訪問控制" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:245 -msgid "Additional Flags" -msgstr "參數列表" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:176 -msgid "Advanced Settings" -msgstr "高級設置" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:128 -msgid "Are you sure you want to log out and unbind the current device?" -msgstr "是否註銷當前登錄並且解綁當前設備?" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:262 -msgid "Auth Key" -msgstr "認證密鑰" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:248 -msgid "Available flags" -msgstr "可用參數" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:141 -msgid "Basic Settings" -msgstr "基礎設置" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:136 -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:150 -msgid "Collecting data ..." -msgstr "正在收集數據..." - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:255 -msgid "Custom Server Settings" -msgstr "自定義伺服器" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:182 -msgid "Device Name" -msgstr "設備名稱" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:143 -msgid "Enable" -msgstr "啟用" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/interface.js:47 -msgid "Error parsing interface info: %s." -msgstr "接口信息解析錯誤:%s。" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:190 -msgid "Exit Node" -msgstr "出口節點" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:208 -msgid "Expose Subnets" -msgstr "公開網段" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:208 -msgid "" -"Expose physical network routes into Tailscale, e.g. 10.0.0.0/24." -msgstr "廣播子網路由至 Tailscale,例如:10.0.0.0/24。" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:243 -msgid "Extra Settings" -msgstr "附加設置" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:162 -msgid "Firewall Mode" -msgstr "防火牆模式" - -#: luci-app-tailscale/root/usr/share/luci/menu.d/luci-app-tailscale.json:14 -msgid "Global Settings" -msgstr "全局設置" - -#: luci-app-tailscale/root/usr/share/rpcd/acl.d/luci-app-tailscale.json:3 -msgid "Grant access to Tailscale configuration" -msgstr "授予訪問 Tailscale 配置的權限" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/interface.js:73 -msgid "IPv4 Address" -msgstr "IPv4地址" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/interface.js:77 -msgid "IPv6 Address" -msgstr "IPv6地址" - -#: luci-app-tailscale/root/usr/share/luci/menu.d/luci-app-tailscale.json:22 -msgid "Interface Info" -msgstr "接口信息" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/interface.js:69 -msgid "Interface Name" -msgstr "接口名稱" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:238 -msgid "LAN access Tailscale" -msgstr "本地局域網訪問虛擬局域網" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:182 -msgid "Leave blank to use the device's hostname." -msgstr "留空以使用設備的主機名。" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:247 -msgid "" -"List of extra flags. Format: --flags=value, e.g. --exit-node=10.0.0.1.
%s for enabling settings upon the initiation of Tailscale." -msgstr "額外參數的列表。格式:--flags=value,例如 --exit-node=10.0.0.1。
在 Tailscale 啟動時的%s。" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:90 -msgid "Log out and Unbind" -msgstr "註銷登錄並解除綁定" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:168 -msgid "Logging program activities." -msgstr "記錄程式運行信息。" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:172 -msgid "Logging program errors and exceptions." -msgstr "記錄程式錯誤和警告信息。" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:147 -msgid "Login Status" -msgstr "已綁定用戶" - -#: luci-app-tailscale/root/usr/share/luci/menu.d/luci-app-tailscale.json:30 -msgid "Logs" -msgstr "日誌" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/interface.js:81 -msgid "MTU" -msgstr "MTU" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:77 -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:92 -msgid "NOT RUNNING" -msgstr "未運行" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:87 -msgid "Need to log in" -msgstr "未登錄" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/interface.js:64 -msgid "Network Interface Information" -msgstr "網絡接口信息" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:201 -msgid "No Available Exit Nodes" -msgstr "没有可用的出口節點" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:228 -msgid "No Available Subnet Routes" -msgstr "沒有可用的子網路由" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/interface.js:61 -msgid "No interface online." -msgstr "無在線接口。" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:190 -msgid "" -"Offer to be an exit node for outbound internet traffic from the Tailscale " -"network." -msgstr "作為 Tailscale 廣域網出口節點。" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:194 -msgid "Online Exit Nodes" -msgstr "可用出口節點" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:153 -msgid "Port" -msgstr "端口" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:75 -msgid "RUNNING" -msgstr "運行中" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/log.js:68 -msgctxt "scroll to top (the head) of the log file" -msgid "Scroll to head" -msgstr "捲動到頂部" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/log.js:59 -msgctxt "scroll to bottom (the tail) of the log file" -msgid "Scroll to tail" -msgstr "捲動到尾部" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:194 -msgid "Select an online machine name to use as an exit node." -msgstr "選擇一個可用的節點名稱作為出口節點使用。" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:222 -msgid "Select subnet routes advertised by other nodes in Tailscale network." -msgstr "選擇非本設備廣播的子網路由。" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:258 -msgid "Server Address" -msgstr "伺服器地址" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:153 -msgid "Set the Tailscale port number." -msgstr "設置 Tailscale 端口號。" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:217 -msgid "Site To Site" -msgstr "子網互通" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:172 -msgid "StdErr Log" -msgstr "錯誤日誌" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:168 -msgid "StdOut Log" -msgstr "運行日誌" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:222 -msgid "Subnet Routes" -msgstr "子網路由" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/interface.js:100 -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:75 -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:77 -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:114 -#: luci-app-tailscale/root/usr/share/luci/menu.d/luci-app-tailscale.json:3 -msgid "Tailscale" -msgstr "Tailscale" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:236 -msgid "Tailscale access LAN" -msgstr "虛擬局域網訪問本地局域網" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:237 -msgid "Tailscale access WAN" -msgstr "虛擬局域網訪問本地廣域網" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/interface.js:101 -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:114 -msgid "Tailscale is a cross-platform and easy to use virtual LAN." -msgstr "Tailscale 是一個跨平台且易於使用的虛擬局域網 VPN。" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:158 -msgid "" -"The working directory contains config files, audit logs, and runtime info." -msgstr "工作目錄包含配置文件、審計日誌和運行時信息。" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/interface.js:85 -msgid "Total Download" -msgstr "總下載量" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/interface.js:89 -msgid "Total Upload" -msgstr "總上傳量" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/interface.js:18 -msgid "Unable to get interface info: %s." -msgstr "無法獲取接口信息:%s。" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/log.js:45 -msgid "Unable to load log data:" -msgstr "無法載入日誌檔:" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:256 -msgid "Use %s to deploy a private server." -msgstr "使用 %s 部署私有伺服器" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:217 -msgid "" -"Use site-to-site layer 3 networking to connect subnets on the Tailscale " -"network." -msgstr "使用站點到站點的三層網路連線 Tailscale 中的子網。" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:239 -msgid "WAN access Tailscale" -msgstr "本地廣域網訪問虛擬局域網" - -#: luci-app-tailscale/htdocs/luci-static/resources/view/tailscale/setting.js:158 -msgid "Workdir" -msgstr "工作目錄" diff --git a/luci-app-tailscale/root/etc/config/tailscale b/luci-app-tailscale/root/etc/config/tailscale deleted file mode 100644 index bbb154408..000000000 --- a/luci-app-tailscale/root/etc/config/tailscale +++ /dev/null @@ -1,43 +0,0 @@ -config tailscale 'settings' - # Set whether Tailcale is enabled or not - option enabled '0' - # Set the port to listen on for incoming Tailscale packets (default 41641) - option port '41641' - # Path to config file - option config_path '/etc/tailscale' - # Default to using nftables - change below to 'iptables' if still using iptables - option fw_mode 'iptables' - # Enable stdout log - option log_stdout '1' - # Enable stderr log - option log_stderr '1' - # Accept subnet routes that other nodes advertise - #option accept_routes '1' - # Provide a hostname to use for the device instead of the one provided by the OS - #option hostname '' - # Accept DNS configuration from the admin console. (default accept) - option accept_dns '1' - # Offer to be an exit node for outbound internet traffic from the Tailscale network - #option advertise_exit_node '1' - # Provide a Tailscale IP or machine name to use as an exit node - #option exit_node '' - # Expose physical subnet routes to your entire Tailscale network (e.g. 10.0.0.0/24) - #list advertise_routes '' - # Set to '1' to disable subnet route masquerading - #option disable_snat_subnet_routes '1' - # To connect subnets within your tailnet (e.g. 192.168.1.0/24) - # Documentation https://tailscale.com/kb/1214/site-to-site - #list subnet_routes '' - # Set firewall zone (ts_ac_lan: Tailscale access LAN, ts_ac_wan: Tailscale access WAN:, lan_ac_ts: LAN access Tailscale, wan_ac_ts: WAN access Tailscale) - # Documentation https://openwrt.org/docs/guide-user/services/vpn/tailscale/start - #list access 'ts_ac_lan' - #list access 'ts_ac_wan' - #list access 'lan_ac_ts' - #list access 'wan_ac_ts' - # Set extra flags for enabling settings upon the initiation of Tailscale - # Documentation https://tailscale.com/kb/1241/tailscale-up - #list flags '' - # Provide the base URL of a custom server instead of https://controlplane.tailscale.com - #option login_server '' - # Set auth Key of custom server - #option authkey '' diff --git a/luci-app-tailscale/root/etc/hotplug.d/iface/40-tailscale b/luci-app-tailscale/root/etc/hotplug.d/iface/40-tailscale deleted file mode 100755 index 971ed550d..000000000 --- a/luci-app-tailscale/root/etc/hotplug.d/iface/40-tailscale +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -tailscale_enable="$(uci get tailscale.settings.enabled)" - -[ "$ACTION" = ifup -o "$ACTION" = ifupdate ] || exit 0 -[ "$ACTION" = ifupdate -a -z "$IFUPDATE_ADDRESSES" -a -z "$IFUPDATE_DATA" ] && exit 0 -[ "$tailscale_enable" -eq "1" ] || exit 0 -/etc/init.d/tailscale start > /tmp/tailscale.log 2>&1 & diff --git a/luci-app-tailscale/root/etc/init.d/tailscale b/luci-app-tailscale/root/etc/init.d/tailscale deleted file mode 100755 index cc63258ca..000000000 --- a/luci-app-tailscale/root/etc/init.d/tailscale +++ /dev/null @@ -1,155 +0,0 @@ -#!/bin/sh /etc/rc.common - -START=90 - -USE_PROCD=1 - -PROG=/usr/sbin/tailscale_helper -PROGD=/usr/sbin/tailscaled -CONFIG_PATH=/var/lib/tailscale - -service_triggers() { - procd_add_reload_trigger "tailscale" - procd_add_interface_trigger "interface.*.up" wan /etc/init.d/tailscale reload -} - -section_enabled() { - config_get_bool enabled "$1" 'enabled' 0 - [ $enabled -gt 0 ] -} - -tailscale_helper() { - local cfg="$1" - local accept_routes hostname accept_dns advertise_exit_node exit_node advertise_routes disable_snat_subnet_routes subnet_routes access flags login_server authkey std_out std_err - - config_get_bool accept_routes $cfg 'accept_routes' - config_get hostname $cfg 'hostname' - config_get_bool accept_dns $cfg 'accept_dns' - config_get_bool advertise_exit_node $cfg 'advertise_exit_node' - config_get exit_node $cfg 'exit_node' - config_get advertise_routes $cfg 'advertise_routes' - config_get_bool disable_snat_subnet_routes $cfg 'disable_snat_subnet_routes' - config_get subnet_routes $cfg 'subnet_routes' - config_get access $cfg 'access' - config_get flags $cfg 'flags' - config_get login_server $cfg 'login_server' - config_get authkey $cfg 'authkey' - config_get_bool std_out $cfg 'log_stdout' - config_get_bool std_err $cfg 'log_stderr' - - procd_open_instance - procd_set_param command $PROG - - [ "$accept_routes" = "1" ] && procd_append_param command --accept-routes=true - [ -n "$hostname" ] && procd_append_param command --hostname="$hostname" - [ "$accept_dns" = "0" ] && procd_append_param command --accept-dns=false - [ "$advertise_exit_node" = "1" ] && procd_append_param command --advertise-exit-node - [ -n "$exit_node" ] && { - procd_append_param command --exit-node="$exit_node" - procd_append_param command --exit-node-allow-lan-access=true - } - [ -n "$advertise_routes" ] && procd_append_param command --advertise-routes="$(echo $advertise_routes | tr ' ' ',')" - [ "$disable_snat_subnet_routes" = "1" ] && procd_append_param command --snat-subnet-routes=false - [ -n "$flags" ] && procd_append_param command $flags - [ -n "$login_server" ] && procd_append_param command --login-server="$login_server" - [ -n "$authkey" ] && procd_append_param command --authkey="$authkey" - - procd_set_param env \ - ACCEPT_DNS="$accept_dns" \ - EXIT_NODE="$exit_node" \ - SUBNET_ROUTES="$subnet_routes" \ - ACCESS="$access" - - procd_set_param respawn - procd_set_param stdout "$std_out" - procd_set_param stderr "$std_err" - procd_close_instance -} - -start_instance() { - local cfg="$1" - local port config_path fw_mode std_out std_err state_file - - if ! section_enabled "$cfg"; then - echo "disabled in /etc/config/tailscale" - return 1 - fi - - config_get port $cfg 'port' - config_get config_path $cfg 'config_path' - config_get fw_mode $cfg 'fw_mode' - config_get_bool std_out $cfg 'log_stdout' - config_get_bool std_err $cfg 'log_stderr' - - [ -d $config_path ] || mkdir -p $config_path - [ -d $CONFIG_PATH ] || mkdir -p $CONFIG_PATH - state_file="$config_path/tailscaled.state" - - /usr/sbin/tailscaled --cleanup - - procd_open_instance - procd_set_param command $PROGD - - [ -n "$port" ] && procd_append_param command --port "$port" - [ -n "$state_file" ] && procd_append_param command --state "$state_file" - - procd_set_param env TS_DEBUG_FIREWALL_MODE="$fw_mode" - - procd_set_param respawn - procd_set_param stdout "$std_out" - procd_set_param stderr "$std_err" - procd_close_instance - - tailscale_helper "$cfg" -} - -start_service() { - config_load 'tailscale' - config_foreach start_instance 'tailscale' -} - -stop_instance() { - local cfg="$1" - - # Remove dnsmasq settings - MagicDNSSuffix=$(tailscale status --json | awk -F'"' '/"MagicDNSSuffix"/ {last=$(NF-1)} END {print last}') - for suffix in $(uci show dhcp | grep -E "address=.*/${MagicDNSSuffix}/" | sed "s/'//g"); do - uci -q del_list $suffix - done - - # Remove network settings - uci -q delete network.tailscale - uci -q delete network.ts_lan - for route in $(uci show network | grep 'network.ts_subnet[0-9]\+=route' | grep -o 'network.ts_subnet[0-9]\+'); do - uci -q delete $route - done - - # Remove firewall settings - index=$(uci show firewall | grep "firewall.@forwarding\[[0-9]\+\]\.src='lan'" -B 1 -A 1 | grep "firewall.@forwarding\[[0-9]\+\]\.dest='wan'" | grep -o '[0-9]\+') - uci -q delete firewall.@forwarding[$index].enabled - uci -q delete firewall.tszone - uci -q delete firewall.ts_ac_lan - uci -q delete firewall.ts_ac_wan - uci -q delete firewall.lan_ac_ts - uci -q delete firewall.wan_ac_ts - - # Commit configuration changes and reload service - [ -n "$(uci changes dhcp)" ] && uci commit dhcp && /etc/init.d/dnsmasq reload - [ -n "$(uci changes network)" ] && uci commit network && /etc/init.d/network reload - [ -n "$(uci changes firewall)" ] && uci commit firewall && /etc/init.d/firewall reload - - /usr/sbin/tailscaled --cleanup - - # Remove existing link or folder - rm -rf "$CONFIG_PATH" -} - -stop_service() { - config_load 'tailscale' - config_foreach stop_instance 'tailscale' -} - -reload_service() { - stop - start -} diff --git a/luci-app-tailscale/root/etc/uci-defaults/40_luci-tailscale b/luci-app-tailscale/root/etc/uci-defaults/40_luci-tailscale deleted file mode 100755 index 90cd2d6b3..000000000 --- a/luci-app-tailscale/root/etc/uci-defaults/40_luci-tailscale +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh - -uci -q batch <<-EOF >/dev/null - delete ucitrack.@tailscale[-1] - commit ucitrack -EOF - -rm -f /tmp/luci-indexcache -exit 0 diff --git a/luci-app-tailscale/root/usr/sbin/tailscale_helper b/luci-app-tailscale/root/usr/sbin/tailscale_helper deleted file mode 100755 index 85b986c65..000000000 --- a/luci-app-tailscale/root/usr/sbin/tailscale_helper +++ /dev/null @@ -1,147 +0,0 @@ -#!/bin/sh - -# Copyright (C) 2025 asvow -# SPDX-License-Identifier: GPL-3.0-only - -# Error handling function -revert_exit() { - logger -p daemon.err -t tailscale_helper "$(date '+%Y/%m/%d %H:%M:%S') $1" - uci revert dhcp && uci revert network && uci revert firewall - /etc/init.d/tailscale stop - exit 1 -} - -# Execute tailscale up command -/usr/sbin/tailscale up --reset "$@" || revert_exit "tailscale up failed." - -# Use flock to acquire an exclusive lock -LOCK_FILE="/var/lock/tailscale.lock" -exec 9> "$LOCK_FILE" -flock -xn 9 || { revert_exit "Failed to acquire lock on $LOCK_FILE"; } -trap 'rm -f "$LOCK_FILE"; exit' INT TERM EXIT - -# Wait for Tailscale IPv4 address -count=0 -while [ -z "$(ifconfig | grep 'tailscale' | awk '{print $1}')" ] || [ -z "$(tailscale ip -4)" ]; do - sleep 2 - count=$((count + 1)) - [ "${count}" -ge 5 ] && revert_exit "Failed to get Tailscale IPv4 address after 5 attempts." -done - -# Configure Tailscale MagicDNS -if [ "$ACCEPT_DNS" = "1" ]; then - MagicDNSSuffix=$(tailscale status --json | awk -F'"' '/"MagicDNSSuffix"/ {last=$(NF-1)} END {print last}') - target_address="/$MagicDNSSuffix/100.100.100.100" - index=$(uci show dhcp | grep 'dhcp.@dnsmasq\[[0-9]\+\]=dnsmasq' | grep -o '[0-9]\+') - for i in $index; do - if ! uci get dhcp.@dnsmasq[$i].address 2>/dev/null | grep -qxF "$target_address"; then - uci add_list "dhcp.@dnsmasq[$i].address=$target_address" || revert_exit "Failed to add DNS address." - fi - done -fi - -# Configure network interface for Tailscale -ts0=$(ifconfig | grep 'tailscale' | awk '{print $1}') -if [ -z "$(uci -q get network.tailscale)" ]; then - uci set network.tailscale='interface' - if [ "$ts0" = *$'\n'* ]; then - [ -n "$(uci batch <<-EOF 2>&1 - set network.ts_lan='device' - set network.ts_lan.type='bridge' - set network.ts_lan.name='ts-lan' - set network.tailscale.proto='none' - set network.tailscale.device='ts-lan' - EOF - )" ] && revert_exit "Failed to configure network interface for Tailscale." - for port in "${ts0}"; do - uci add_list network.ts_lan.ports=$port || revert_exit "Failed to add port $port." - done - else - [ -n "$(uci batch <<-EOF 2>&1 - set network.tailscale.proto='static' - set network.tailscale.ipaddr=$(tailscale ip -4) - add_list network.tailscale.ip6addr=$(tailscale ip -6) - set network.tailscale.netmask='255.0.0.0' - set network.tailscale.device=$ts0 - EOF - )" ] && revert_exit "Failed to configure network interface for Tailscale." - fi -fi - -# Configure exit node firewall rules -if [ -n "$EXIT_NODE" ]; then - uci set firewall.@defaults[0].forward='REJECT' || revert_exit "Failed to set default forward policy to REJECT." - # Find the LAN to WAN forwarding rule index - index=$(uci show firewall | grep "firewall.@forwarding\[[0-9]\+\]\.src='lan'" -B 1 -A 1 | grep "firewall.@forwarding\[[0-9]\+\]\.dest='wan'" | grep -o '[0-9]\+') - [ -n "$index" ] && uci set firewall.@forwarding[$index].enabled='0' || revert_exit "Failed to disable forwarding rule." -fi - -# Configure subnet routes for site to site -if [ -n "$SUBNET_ROUTES" ]; then - i=1 - ts_ip=$(tailscale ip -4) - for route in $SUBNET_ROUTES; do - [ -n "$(uci batch <<-EOF 2>&1 - set network.ts_subnet$i='route' - set network.ts_subnet$i.interface='tailscale' - set network.ts_subnet$i.target=$route - set network.ts_subnet$i.gateway=$ts_ip - EOF - )" ] && revert_exit "Failed to configure subnet routes for site to site." - let i++ - done -fi - -# Configure firewall zone and rules -if [ -n "$ACCESS" ]; then - [ -n "$(uci batch <<-EOF 2>&1 - set firewall.tszone='zone' - set firewall.tszone.input='ACCEPT' - set firewall.tszone.output='ACCEPT' - set firewall.tszone.forward='ACCEPT' - set firewall.tszone.masq='1' - set firewall.tszone.mtu_fix='1' - set firewall.tszone.name='tailscale' - set firewall.tszone.network='tailscale' - EOF - )" ] && revert_exit "Failed to create firewall zone and forwarding rules for Tailscale." -fi - -# Configure specific firewall forwarding rules between Tailscale, LAN, and WAN -if [ "${ACCESS//ts_ac_lan/}" != "$ACCESS" ]; then - [ -n "$(uci batch <<-EOF 2>&1 - set firewall.ts_ac_lan=forwarding - set firewall.ts_ac_lan.dest='lan' - set firewall.ts_ac_lan.src='tailscale' - EOF - )" ] && revert_exit "Failed to configure ts_ac_lan firewall forwarding rules." -fi -if [ "${ACCESS//ts_ac_wan/}" != "$ACCESS" ]; then - [ -n "$(uci batch <<-EOF 2>&1 - set firewall.ts_ac_wan=forwarding - set firewall.ts_ac_wan.dest='wan' - set firewall.ts_ac_wan.src='tailscale' - EOF - )" ] && revert_exit "Failed to configure ts_ac_wan firewall forwarding rules." -fi -if [ "${ACCESS//lan_ac_ts/}" != "$ACCESS" ]; then - [ -n "$(uci batch <<-EOF 2>&1 - set firewall.lan_ac_ts=forwarding - set firewall.lan_ac_ts.dest='tailscale' - set firewall.lan_ac_ts.src='lan' - EOF - )" ] && revert_exit "Failed to configure lan_ac_ts firewall forwarding rules." -fi -if [ "${ACCESS//wan_ac_ts/}" != "$ACCESS" ]; then - [ -n "$(uci batch <<-EOF 2>&1 - set firewall.wan_ac_ts=forwarding - set firewall.wan_ac_ts.dest='tailscale' - set firewall.wan_ac_ts.src='wan' - EOF - )" ] && revert_exit "Failed to configure wan_ac_ts firewall forwarding rules." -fi - -# Commit configuration changes and reload service -[ -n "$(uci changes dhcp)" ] && uci commit dhcp && /etc/init.d/dnsmasq reload -[ -n "$(uci changes network)" ] && uci commit network && /etc/init.d/network reload -[ -n "$(uci changes firewall)" ] && uci commit firewall && /etc/init.d/firewall reload diff --git a/luci-app-tailscale/root/usr/share/luci/menu.d/luci-app-tailscale.json b/luci-app-tailscale/root/usr/share/luci/menu.d/luci-app-tailscale.json deleted file mode 100644 index 946749d71..000000000 --- a/luci-app-tailscale/root/usr/share/luci/menu.d/luci-app-tailscale.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "admin/vpn/tailscale": { - "title": "Tailscale", - "order": 90, - "action": { - "type": "firstchild" - }, - "depends": { - "acl": [ "luci-app-tailscale" ], - "uci": { "tailscale": true } - } - }, - "admin/vpn/tailscale/setting": { - "title": "Global Settings", - "order": 10, - "action": { - "type": "view", - "path": "tailscale/setting" - } - }, - "admin/vpn/tailscale/interface": { - "title": "Interface Info", - "order": 20, - "action": { - "type": "view", - "path": "tailscale/interface" - } - }, - "admin/vpn/tailscale/log": { - "title": "Logs", - "order": 30, - "action": { - "type": "view", - "path": "tailscale/log" - } - } -} diff --git a/luci-app-tailscale/root/usr/share/rpcd/acl.d/luci-app-tailscale.json b/luci-app-tailscale/root/usr/share/rpcd/acl.d/luci-app-tailscale.json deleted file mode 100644 index 37841759c..000000000 --- a/luci-app-tailscale/root/usr/share/rpcd/acl.d/luci-app-tailscale.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "luci-app-tailscale": { - "description": "Grant access to Tailscale configuration", - "read": { - "file": { - "/sbin/ip -s -j ad": [ "exec" ], - "/sbin/logread -e tailscale": [ "exec" ], - "/usr/sbin/tailscale status --json": [ "exec" ], - "/usr/sbin/tailscale login": [ "exec" ], - "/usr/sbin/tailscale logout": [ "exec" ] - }, - "ubus": { - "service": [ "list" ] - }, - "uci": [ "tailscale" ] - }, - "write": { - "uci": [ "tailscale" ] - } - } -}