mirror of
https://github.com/freedombox/FreedomBox.git
synced 2026-01-28 08:03:36 +00:00
Closes: #729. Tests: - Install Shadowsocks Server. Install Shadowsocks Client, and set the server to localhost, and set the same password as the server. Use curl to connect to local SOCKS proxy on port 1080 and fetch a website. Signed-off-by: James Valleroy <jvalleroy@mailbox.org> [sunil: Update some docstring comments for shadowsocks clients] [sunil: Use the term Censorship instead of network filters] [sunil: Prevent enabling both apps when setup is re-run] [sunil: Update typehint for a privileged method to be minimal] [sunil: Accept connections from external IPs too] Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org> Reviewed-by: Sunil Mohan Adapa <sunil@medhas.org>
97 lines
3.6 KiB
Python
97 lines
3.6 KiB
Python
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
"""FreedomBox app to configure Shadowsocks Client."""
|
|
|
|
from django.urls import reverse_lazy
|
|
from django.utils.translation import gettext_lazy as _
|
|
|
|
from plinth import app as app_module
|
|
from plinth import cfg, frontpage, menu
|
|
from plinth.daemon import Daemon
|
|
from plinth.modules.backups.components import BackupRestore
|
|
from plinth.modules.firewall.components import Firewall
|
|
from plinth.package import Packages
|
|
from plinth.utils import format_lazy
|
|
|
|
from . import manifest, privileged
|
|
|
|
_description = [
|
|
_('Shadowsocks is a tool for securely forwarding network requests to a'
|
|
' remote server. It consists of two parts: (1) a Shadowsocks server,'
|
|
' and (2) a Shadowsocks client with a SOCKS5 proxy.'),
|
|
_('Shadowsocks can be used to bypass Internet filtering and '
|
|
'censorship. This requires that the Shadowsocks server is in a '
|
|
'location where it can freely access the Internet, without '
|
|
'filtering.'),
|
|
format_lazy(
|
|
_('Your {box_name} can run a Shadowsocks client, that can connect to '
|
|
'a Shadowsocks server. It will also run a SOCKS5 proxy. Local '
|
|
'devices can connect to this proxy, and their data will be '
|
|
'encrypted and proxied through the Shadowsocks server.'),
|
|
box_name=_(cfg.box_name)),
|
|
_('To use Shadowsocks after setup, set the SOCKS5 proxy URL in your '
|
|
'device, browser or application to http://freedombox_address:1080/')
|
|
]
|
|
|
|
|
|
class ShadowsocksApp(app_module.App):
|
|
"""FreedomBox app for Shadowsocks Client."""
|
|
|
|
app_id = 'shadowsocks'
|
|
|
|
_version = 3
|
|
|
|
DAEMON = 'shadowsocks-libev-local@freedombox'
|
|
|
|
def __init__(self):
|
|
"""Create components for the app."""
|
|
super().__init__()
|
|
|
|
info = app_module.Info(app_id=self.app_id, version=self._version,
|
|
name=_('Shadowsocks Client'),
|
|
icon_filename='shadowsocks',
|
|
short_description=_('Bypass Censorship'),
|
|
description=_description,
|
|
manual_page='Shadowsocks')
|
|
self.add(info)
|
|
|
|
menu_item = menu.Menu('menu-shadowsocks', info.name,
|
|
info.short_description, info.icon_filename,
|
|
'shadowsocks:index', parent_url_name='apps')
|
|
self.add(menu_item)
|
|
|
|
shortcut = frontpage.Shortcut(
|
|
'shortcut-shadowsocks', info.name,
|
|
short_description=info.short_description, icon=info.icon_filename,
|
|
description=info.description, manual_page=info.manual_page,
|
|
configure_url=reverse_lazy('shadowsocks:index'),
|
|
login_required=True)
|
|
self.add(shortcut)
|
|
|
|
packages = Packages('packages-shadowsocks', ['shadowsocks-libev'])
|
|
self.add(packages)
|
|
|
|
firewall = Firewall('firewall-shadowsocks', info.name,
|
|
ports=['shadowsocks-local-plinth'],
|
|
is_external=False)
|
|
self.add(firewall)
|
|
|
|
daemon = Daemon('daemon-shadowsocks', self.DAEMON,
|
|
listen_ports=[(1080, 'tcp4'), (1080, 'tcp6')])
|
|
self.add(daemon)
|
|
|
|
backup_restore = BackupRestore('backup-restore-shadowsocks',
|
|
**manifest.backup)
|
|
self.add(backup_restore)
|
|
|
|
def setup(self, old_version):
|
|
"""Install and configure the app."""
|
|
super().setup(old_version)
|
|
privileged.setup()
|
|
if not old_version:
|
|
self.enable()
|
|
|
|
def uninstall(self):
|
|
"""De-configure and uninstall the app."""
|
|
super().uninstall()
|
|
privileged.uninstall()
|