freedombox Debian release 24.25

-----BEGIN PGP SIGNATURE-----
 
 iQJKBAABCgA0FiEEfWrbdQ+RCFWJSEvmd8DHXntlCAgFAmdg7jgWHGp2YWxsZXJv
 eUBtYWlsYm94Lm9yZwAKCRB3wMdee2UICKLqEACU/BYpXt9WrO4S7vKAlIU44t+H
 NZRD1RYzjWwGyPGELXwPFl5gFnP9RGyRwmpbM4Z96cWSEVN0rXsDWRUxgXXHXN0e
 0bMJGXvwBj6DeXmeKaUZDlHfRfvl8UDOdmmC6DZ5gb2Tb5cCB4od/VTUxyBbN8W/
 +bcpkKo3/7qnYTKZkjY5rs2zvUqTctNs8CK6yr3iFY0Dec8uzkdRmN7XG2pljIF/
 VwjO8oKSBu3thX+XisuVuibZNWYrYiwzvcrLqD4d1ihgcVUdXdUWQw7QK42LGkxS
 V4CdA4idB5eR+QN/DZoTMDiHZ058Qzjl47Bv4EISlcatikJhjB38B8+lnM0hvEmN
 CcIOb5CxeT5dFnZIPjflAPeC1vWInvVOIeH4Std40VOUsKD3hyX7tlEZrenFVEsr
 M/gvizpUPfwrolUxb7eYBeyeR2zNCRXpy/+PhhkfzrnRb69SnllIx79OAaZFVLFC
 SGCx91LI/DeOR/7La+RtWPcpdLdBgflXHRWMQx6Y/hDMWPkWzQJp4PrsLXodeSVg
 qzyUAXY7aEjs4C81+ycTziN1zVa4YJEWJ1ikIyVui2mKFmUXzOeG6Ks/HszpJsQ1
 TbDGhCoDms1k0Gr1OLHVEYA/tKee5WFK1ENx9yAMmh+txSxjvRH/m1c/9w+Ud0TN
 IqHwrdV1hB0hz2XF8w==
 =OYVr
 -----END PGP SIGNATURE-----
gpgsig -----BEGIN PGP SIGNATURE-----
 
 iQJKBAABCgA0FiEEfWrbdQ+RCFWJSEvmd8DHXntlCAgFAmdkEnIWHGp2YWxsZXJv
 eUBtYWlsYm94Lm9yZwAKCRB3wMdee2UICI6TD/9O2m1eQAicZNmqYfrVfW8mhNHD
 pPsZD1G8Sglf+75QcjxD4J9fC/PBfortyTRmESuzeoYkCs3iN3SoTkq3P9NSEYzs
 plzISzrBRy2FDnMXAGGfs4Mhtmj6ZfQe2BbU1tHX0z8ojnxn6Y3ohjUEr6VWz75M
 D1gB1ORtvMHv4JLCDu7ZGsPFAubM5Ah3wU9IZRX8X6NtG+XG+EzTEVeb0sJ1QstA
 JABiZVjCyf2JcQc8aXViVbn6ZPIqVnAXv9C0Vo0nKAY11bbEw6j5BZ9/TIUbg0UA
 HA+8HwIOJVf4yk18yOcRrOHxKDHxjZ4NJJKtBq/AoQPlrC45ogCZ0HSOLmanf5Ge
 lPQaLCr8VnNyDBxaEofVIclm3HNKXqtyAvoGWqQKhAnyuuCKxWwLaq46/XLta6FN
 Zin6O7kaZrwDPihRC3dMIxEJ6I3dZnWZd4BrSZwKPzh3Sksl0WRMTaFf6aqUhWrq
 +ven3zUBkUnSDHR8VquxcRZRmLEs3heJEILeeeHQAebIpPhcXlzi3aPOKT9XaLj2
 0Q5mWY6KIcmzxrR5G9fQyDtV2Gs9hlgVY0Dy0Kq0ptjM63vfy4zNPmPsidvKvITl
 nCZGGOyqq0Y/aGh6pOEKsHBGwXrWPgfwDZcLsFs20MsZO91Ff0WzJHQG8/ZmFZEf
 AXOn/YCM+kqa5gLA9Q==
 =0LIo
 -----END PGP SIGNATURE-----

Merge tag 'v24.25' into debian/bookworm-backports

freedombox Debian release 24.25

Signed-off-by: James Valleroy <jvalleroy@mailbox.org>
This commit is contained in:
James Valleroy 2024-12-19 07:32:47 -05:00
commit 561d43d61f
168 changed files with 16591 additions and 18054 deletions

View File

@ -19,7 +19,8 @@ RUN apt-get build-dep -y .
RUN apt-get install -y build-essential \
# Test dependencies
sshpass parted \
sudo python3-pip
sudo python3-pip \
python3-flake8
# Module dependencies
RUN apt-get install -y $(./run --list-dependencies)

View File

@ -83,7 +83,7 @@ RedirectMatch "^/$" "/plinth"
##
<LocationMatch "^/(plinth|freedombox)">
Header set Referrer-Policy 'same-origin'
Header set Content-Security-Policy "font-src 'self'; frame-src 'none'; img-src 'self'; manifest-src 'none'; media-src 'none'; object-src 'none'; script-src 'self'; style-src 'self'; worker-src 'self'; default-src 'self'; base-uri 'none'; sandbox allow-scripts allow-popups allow-popups-to-escape-sandbox allow-forms allow-same-origin allow-downloads; form-action 'self'; frame-ancestors 'none'; block-all-mixed-content;"
Header set Content-Security-Policy "font-src 'self'; frame-src 'none'; img-src 'self' data:; manifest-src 'none'; media-src 'none'; object-src 'none'; script-src 'self'; style-src 'self'; worker-src 'self'; default-src 'self'; base-uri 'none'; sandbox allow-scripts allow-popups allow-popups-to-escape-sandbox allow-forms allow-same-origin allow-downloads; form-action 'self'; frame-ancestors 'none'; block-all-mixed-content;"
Header set X-Content-Type-Options 'nosniff'
</LocationMatch>

112
debian/changelog vendored
View File

@ -1,3 +1,115 @@
freedombox (24.25) unstable; urgency=medium
[ Burak Yavuz ]
* Translated using Weblate (Turkish)
[ 109247019824 ]
* Translated using Weblate (Bulgarian)
* Translated using Weblate (Bulgarian)
[ Besnik Bleta ]
* Translated using Weblate (Albanian)
[ Ettore Atalan ]
* Translated using Weblate (German)
[ 大王叫我来巡山 ]
* Translated using Weblate (Chinese (Simplified Han script))
[ Jiří Podhorecký ]
* Translated using Weblate (Czech)
[ Paul Lettich ]
* Translated using Weblate (German)
[ John Doe ]
* Translated using Weblate (French)
[ Sunil Mohan Adapa ]
* tags: Fix issue with JS init on a page without tags
* notifications: Don't error when dismissing missing notifications
* help: Add a class to the help index page
* ui: Align app icons in the center for home, apps, and help pages
* ui: Allow users to provide a CSS file to customize styling
* Translated using Weblate (Russian)
* Translated using Weblate (Russian)
* ui: Switch to using bootstrap 5 (Closes: #1088412, #1088577)
* networks: Fix minor typo in template related to signal strength
* ui: Drop use of badge-* utility classes for newer replacements
* apache: Relax content security policy to allow data: URL
* networks: Use new accordion component from Bootstrap 5
* networks: Fix issue with loading create PPPoE form
* firewalld: Reduce severity for alert about service on internal zone
* help: Update the privacy notice on status log page
* diagnostics: Fix trimming an i18n string
* matrixsynapse: Fix trimming an i18n string
* ui: Use Bootstrap 5 styling for all alerts
* power: Refactor display of package manager busy alerts
* ui: Rename data- attributes to data-bs- for Bootstrap 5
* ui: app, system: Revert to earlier width for card lists
* ui: Show disabled form elements as grey for Bootstrap 5
* ui: Fix overflow of exception text in message
* ui: users: Fix close button for confirmation dialog for Bootstrap 5
* ui: app: Fix an incorrect HTML tag nesting
* ui: Reduce the gap at the top of the pages
* ui: diagnostics: Fix layout of repair buttons
* ui: diagnostics: Fix gap between headings
* ui: forms: Fix margins for form labels for Bootstrap 5
* ui: backups: Drop unused styling in verify host key page
* ui: Restore spacing between form elements in Bootstrap 5
* ui: snapshots: Fix horizontal form styling margins for Bootstrap 5
* ui: snapshots: Fix horizontal form layout on mobiles for Bootstrap 5
* ui: Fix toggle button styling for Bootstrap 5
* ui: Allow underlining for most links due to Bootstrap 5
* ui: Restyle tags, remove underlining of text
* ui: Accept default styling of Bootstrap 5 for warning button
* ui: Update custom button styles for Bootstrap 5
* ui: samba: Fix layout regressions with Bootstrap 5
* ui: Fix styling in dismiss button in form errors for Bootstrap 5
* ui: Update styling for navbar menu items
* ui: Workaround dropdowns not working with Bootstrap 5
* ui: Use collapse instead of dropdown for notification in Bootstrap 5
* ui: Fix issue with notifications icon showing twice in mobile view
* ui: Fix flash of notifications popdown during page load
* ui: Style the 'Log out' item properly
* ui: Don't use nav-link inside card
* ui: Cleanup use of colors with CSS variables
* ui: Fix placement of tags menu under tags input with Bootstrap 5
* diagnostics: tests: functional: Pick errors more specifically
* tests: functional: Disable smooth scrolling from Bootstrap 5
* ui: firewall: Fix styling with Bootstrap 5
* ui: backups: Use Bootstrap color variables instead of static values
* ui: help: Fix alignment issue with footer links in about page
* action_utils: Add utility to ensure that service is stopped
* deluge: Cleanup and simplify setup code
* letsencrypt: Declare explicit dependency on openssl
* openvpn: Declare explicit dependency on openssl
* sso: Switch using cryptography module instead of OpenSSL.crypto
(Closes: #1088760)
* ci: Add flake8 to gitlabci container
* d/control: Drop version specification on dependencies for Bookworm
* d/control: Drop unnecessary recommendations
* i2p: Drop app as it has not been available in Debian for a while
[ Veiko Aasa ]
* tags: tests: Fix deprecated webdriver attribute
* tests: functional: Don't try disable app after tests if app was not installed
* tests: functional: Fix app installation test skipped on slow machines
* deluge: Fix app installation on Debian testing
[ James Valleroy ]
* radicale: Update link to supported clients
* locale: Update translation strings
* doc: Fetch latest manual
[ Carles Pina i Estany ]
* Added po-debconf Catalan translation
[ gfbdrgng ]
* Translated using Weblate (Russian)
-- James Valleroy <jvalleroy@mailbox.org> Mon, 16 Dec 2024 21:32:08 -0500
freedombox (24.24~bpo12+1) bookworm-backports; urgency=medium
* Rebuild for bookworm-backports.

70
debian/control vendored
View File

@ -17,7 +17,7 @@ Build-Depends:
docbook-xsl,
e2fsprogs,
gir1.2-nm-1.0,
libjs-bootstrap4,
libjs-bootstrap5,
pybuild-plugin-pyproject,
python3-all:any,
python3-apt,
@ -26,18 +26,17 @@ Build-Depends:
python3-build,
python3-cherrypy3,
python3-configobj,
python3-cryptography,
python3-dbus,
python3-django (>= 1.11),
python3-django-axes (>= 5.0.0),
python3-django,
python3-django-axes,
python3-django-captcha,
# Explictly depend on ipware as it is optional dependecy for future versions
# of django-axes.
python3-django-ipware (>= 3),
python3-django-stronghold (>= 0.3.0),
# Explictly depend on ipware as it is optional dependecy of django-axes
python3-django-ipware,
python3-django-stronghold,
python3-gi,
python3-markupsafe,
python3-mypy,
python3-openssl,
python3-pampy,
python3-paramiko,
python3-pexpect,
@ -51,8 +50,8 @@ Build-Depends:
python3-ruamel.yaml,
python3-setuptools,
python3-setuptools-git,
# python3-tomli is not available in Bullseye
python3-tomli | python3-coverage (<< 6.0),
# python3-tomli is needed by python3-coverage when pyproject.toml is used
python3-tomli,
python3-typeshed,
python3-yaml,
sshpass,
@ -66,17 +65,11 @@ Rules-Requires-Root: no
Package: freedombox
Breaks:
freedombox-setup (<< 0.13~),
plinth (<< 0.46.0~),
# Ensure fuse gets replaced by fuse3 on upgrades from buster s.t. sshfs can be installed.
fuse (<< 3),
# If ufw is installed, remove it. See issue 2247.
ufw,
Replaces:
freedombox-setup (<< 0.13~),
plinth (<< 0.46.0~),
Architecture: all
Provides: plinth
Depends:
${python3:Depends},
${misc:Depends},
@ -98,7 +91,7 @@ Depends:
ldapscripts,
# For gdbus used to call hooks into service
libglib2.0-bin,
libjs-bootstrap4,
libjs-bootstrap5,
libjs-jquery,
lsof,
netcat-openbsd,
@ -112,12 +105,11 @@ Depends:
python3-cherrypy3,
python3-configobj,
python3-dbus,
python3-django (>= 1.11),
python3-django-axes (>= 5.0.0),
python3-django,
python3-django-axes,
python3-django-captcha,
# Explictly depend on ipware as it is optional dependecy for future versions
# of django-axes.
python3-django-ipware (>= 3),
# Explictly depend on ipware as it is optional dependecy of django-axes
python3-django-ipware,
python3-django-stronghold,
python3-gi,
python3-markupsafe,
@ -132,31 +124,13 @@ Depends:
sudo,
wget,
# Ensure fuse gets replaced by fuse3 on upgrades from buster s.t. sshfs can be installed.
fuse3 (>= 3),
fuse3,
Recommends:
# Priority: standard
bzip2,
# Provides brctl for controlling bridges
bridge-utils,
# Read, write to char devices
devio,
# Create, repair DOS filesystems
dosfstools,
# Priority: standard
file,
# Wifi firmware
firmware-ath9k-htc,
# FreedomBox documentation
freedombox-doc-en,
freedombox-doc-es,
# Monitor system resources
htop,
# Monitor network traffic statistics
iftop,
# Basic network utitlity ping
iputils-ping,
# Manage wireless devices
iw,
# Resolve .local address using mDNS
libnss-mdns,
# Resolve current hostname without /etc/hosts
@ -169,22 +143,10 @@ Recommends:
locales-all,
# Priority: standard
openssh-client,
# Priority: standard
pciutils,
# Used by unattended-upgrades to check if running on AC power
powermgmt-base,
# fuser, pstree and other utilities
# fuser, killall, pstree and other utilities
psmisc,
# Tool to kill WLAN, Bluetooth and moble broadband
rfkill,
# Monitor network traffic
tcpdump,
# Basic editor, VIM style
vim-tiny,
# Priority: standard
whois,
# Basic editor, Emacs style
zile,
Description: easy to manage, privacy oriented home server
FreedomBox is designed to be your own inexpensive server at home. It runs free
software and offers an increasing number of services ranging from a calendar or

36
debian/po/ca.po vendored Normal file
View File

@ -0,0 +1,36 @@
# Catalan translation of plinth's debconf messages
# Copyright © 2024 Free Software Foundation, Inc.
# This file is distributed under the same license as the plinth package.
# poc senderi <pocsenderi@protonmail.com>, 2024.
#
msgid ""
msgstr ""
"Project-Id-Version: plinth\n"
"Report-Msgid-Bugs-To: plinth@packages.debian.org\n"
"POT-Creation-Date: 2019-11-18 18:11-0500\n"
"PO-Revision-Date: 2024-11-05 22:18+0100\n"
"Language: ca\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Last-Translator: poc senderi <pocsenderi@protonmail.com>\n"
"Language-Team: Catalan <debian-l10n-catalan@lists.debian.org>\n"
"X-Generator: Poedit 2.4.2\n"
#. Type: note
#. Description
#: ../templates:1001
msgid "FreedomBox first wizard secret - ${secret}"
msgstr "Secret per a l'engegada inicial del «wizard» de FreedomBox - ${secret}"
#. Type: note
#. Description
#: ../templates:1001
msgid ""
"Please note down the above secret. You will be asked to enter this in the "
"first screen after you launch the FreedomBox web interface. In case you lose "
"it, you can retrieve it by running the following command:"
msgstr ""
"Anoteu el secret anterior. Us serà demanat a la primera pantalla després "
"d'engegar la interfície web del FreedomBox. En cas que el perdeu, el podeu "
"recuperar executant la següent ordre:"

View File

@ -8,5 +8,4 @@ very-long-line-length-in-source-file * [doc/manual/*.raw.wiki:*]
very-long-line-length-in-source-file * [plinth/modules/deluge/tests/data/sample.torrent:*]
very-long-line-length-in-source-file * [plinth/modules/transmission/tests/data/sample.torrent:*]
very-long-line-length-in-source-file * [doc/visual_design/FreedomBox-Logo.7z:*]
very-long-line-length-in-source-file * [plinth/modules/i2p/tests/data/router.config:*]
very-long-line-length-in-source-file * [COPYING.md:*]

View File

@ -14,5 +14,5 @@ Restrictions: needs-root, breaks-testbed
# Run unit and integration tests on installed files.
#
Test-Command: PYTHONPATH='/usr/lib/python3/dist-packages/' py.test-3 -p no:cacheprovider --cov=plinth --cov-report=html:debci/htmlcov --cov-report=term
Depends: git, python3-openssl, python3-pytest, python3-pytest-cov, python3-pytest-django, python3-tomli | python3-coverage (<< 6.0), @
Depends: git, python3-pytest, python3-pytest-cov, python3-pytest-django, python3-tomli, @
Restrictions: breaks-testbed

View File

@ -206,10 +206,10 @@ autodoc_mock_imports = [
'captcha',
'cherrypy',
'configobj',
'cryptography',
'dbus',
'gi',
'markupsafe',
'OpenSSL',
'pam',
'paramiko',
'psutil',

View File

@ -27,7 +27,7 @@ Installing !FreedomBox changes your Debian system in many important ways. This
Check the Troubleshooting section below, for any tips or workarounds that might help during the install.
1. [[InstallingDebianOn|Install Debian]] 12 (bookworm), or Unstable (sid) on your hardware.
1. [[InstallingDebianOn|Install Debian]] 12 (Bookworm) or newer on your hardware. During installation choosing "Btrfs" for root filesystem type is recommended as !FreedomBox uses it take regular snapshots of the system.
1. Update your package list.

View File

@ -1,36 +0,0 @@
#language en
##TAG:TRANSLATION-HEADER-START
~- [[de/FreedomBox/Manual/I2P|Deutsch]] - [[FreedomBox/Manual/I2P|English]] - [[es/FreedomBox/Manual/I2P|Español]] - [[DebianWiki/EditorGuide#translation|(+)]] -~
##TAG:TRANSLATION-HEADER-END
<<TableOfContents()>>
## BEGIN_INCLUDE
== I2P (Anonymity Network) ==
||<tablestyle="float: right;"> {{attachment:I2P-icon_en_V01.png|I2P icon}} ||
=== About I2P ===
The Invisible Internet Project is an anonymous network layer intended to protect communication from censorship and surveillance. I2P provides anonymity by sending encrypted traffic through a volunteer-run network distributed around the world.
=== Services Offered ===
The following services are offered via I2P in !FreedomBox by default. Additional services may be available when enabled from I2P router console that can be launched from !FreedomBox web interface.
* '''Anonymous Internet browsing''': I2P can be used to browse Internet anonymously. For this, configure your browser (preferable a Tor Browser) to connect to I2P proxy. This can be done by setting HTTP proxy and HTTPS proxy to ''freedombox.local'' (or your !FreedomBox's local IP address) and ports to ''4444'' and ''4445'' respectively. This service is available only when you are reaching !FreedomBox using local network (networks in internal zone) and not available when connecting to !FreedomBox from the Internet. One exception to this is when you connect to !FreedomBox's VPN service from Internet you can still use this service.
* '''Reaching eepsites''': I2P network can host websites that can remain anonymous. These are called eepsites and end with .i2p in their domain name. For example, http://i2p-projekt.i2p/ is the website for I2P project in the I2P network. eepsites are not reachable using a regular browser via regular Internet connection. To browse eepsites, your browser needs to be configured to use HTTP, HTTPS proxies as described above. This service is available only when you are reaching !FreedomBox using local network (networks in internal zone) and not available when connecting to !FreedomBox from the Internet. One exception to this is when you connect to !FreedomBox's VPN service from Internet you can still use this service.
* '''Anonymous torrent downloads''': I2PSnark, an application for anonymously downloading and sharing files over the !BitTorrent network is available in I2P and enabled by default in !FreedomBox. This application is controlled via a web interface that can be launched from 'Anonymous torrents' section of I2P app in !FreedomBox web interface or from the I2P router console interface. Only logged-in users belonging to 'Manage I2P application' group can use this service.
* '''IRC network''': I2P network contains an IRC network called Irc2P. This network hosts the I2P project's official IRC channel among other channels. This service is enabled by default in !FreedomBox. To use it, open your favourite IRC client. Then configure it to connect to host ''freedombox.local'' (or your !FreedomBox's local IP address) with port number ''6668''. This service is available only when you are reaching !FreedomBox using local network (networks in internal zone) and not available when connecting to !FreedomBox from the Internet. One exception to this is when you connect to !FreedomBox's VPN service from Internet you can still use this service.
* '''I2P router console''': This is the central management interface for I2P. It shows the current status of I2P, bandwidth statistics and allows modifying various configuration settings. You can tune your participation in the I2P network and use/edit a list of your favourite I2P sites (eepsites). Only logged-in users belonging to 'Manage I2P application' group can use this service.
=== External links ===
* Upstream website: https://geti2p.net/en/
* User documentation: https://i2pd.readthedocs.io/en/latest/
## END_INCLUDE
Back to [[FreedomBox/Features|Features introduction]] or [[FreedomBox/Manual|manual]] pages.
<<Include(FreedomBox/Portal)>>

View File

@ -0,0 +1,58 @@
#language en
##TAG:TRANSLATION-HEADER-START
~- [[FreedomBox/Manual/Nextcloud|English]] - [[DebianWiki/EditorGuide#translation|(+)]] -~
##TAG:TRANSLATION-HEADER-END
<<TableOfContents()>>
## BEGIN_INCLUDE
== Nextcloud (File Storage & Collaboration) ==
||<tablestyle="float: right;"> {{attachment:nextcloud.png|Nextcloud icon}} ||
'''Available since''': !FreedomBox 24.8
Nextcloud is considered experimental in !FreedomBox having to do with the integration of the Nextcloud container in the !FreedomBox system.
=== What is Nextcloud? ===
This page is new and needs a Nexcloud user to help with the content. This could be you!
Nextcloud is a self-hosted productivity platform which provides private and secure functions for file sharing, collaborative work, and more. Nextcloud includes the Nextcloud server, client applications for desktop computers, and mobile clients. The Nextcloud server provides a well integrated web interface.
All users of !FreedomBox can use Nextcloud. To perform administrative actions, use the "nextcloud-admin" user after setting a password here.
Please note that Nextcloud is installed and run inside a container provided by the Nextcloud community. Security, quality, privacy and legal reviews are done by the upstream project and not by Debian/FreedomBox. Updates are performed following an independent cycle.
{{{#!wiki comment
=== Screenshot ===
Please add a screenshot of your Nextcloud suitable for public display.
}}}
{{{#!wiki comment
=== Using Nextcloud ===
If you are a Nextcloud user share how this is done.
}}}
=== External Links ===
* Upstream Project: https://nextcloud.com/
* Upstream documentation: https://nextcloud.com/support/
* Upstream support forum: https://help.nextcloud.com/
* Debian Nextcloud wiki: https://wiki.debian.org/Nextcloud
{{{#!wiki comment
=== Client Apps ===
If this app has or needs client applications (apart from a web browser) list these here. As a Debian pure-blend the FreedomBox wiki should be suggesting client software that adheres to the Debian Free Software Guidelines. If this is not possible it should be noted.
}}}
## END_INCLUDE
Back to [[FreedomBox/Features|Features introduction]] or [[FreedomBox/Manual|manual]] pages.
<<Include(FreedomBox/Portal)>>
----
CategoryFreedomBox

View File

@ -127,7 +127,6 @@ The following services are known to '''work''':
* [[FreedomBox/Manual/Privoxy|Privoxy]],
* [[FreedomBox/Manual/Tor|Tor Socks]],
* [[FreedomBox/Manual/Shadowsocks|Shadowsocks]],
* [[FreedomBox/Manual/I2P|I2P Proxy]] and
* [[FreedomBox/Manual/Samba|Samba]].
Some services are known '''not''' to work at this time:

View File

@ -8,6 +8,82 @@ For more technical details, see the [[https://salsa.debian.org/freedombox-team/f
The following are the release notes for each !FreedomBox version.
== FreedomBox 24.25 (2024-12-16) ==
=== Highlights ===
* deluge: Fix app installation on Debian testing
* notifications: Don't error when dismissing missing notifications
* ui: Switch to using bootstrap 5
=== Other Changes ===
* action_utils: Add utility to ensure that service is stopped
* apache: Relax content security policy to allow data: URL
* ci: Add flake8 to gitlabci container
* d/control: Drop unnecessary recommendations
* d/control: Drop version specification on dependencies for Bookworm
* debian: Added po-debconf Catalan translation
* deluge: Cleanup and simplify setup code
* diagnostics: Fix trimming an i18n string
* diagnostics: tests: functional: Pick errors more specifically
* firewalld: Reduce severity for alert about service on internal zone
* help: Add a class to the help index page
* help: Update the privacy notice on status log page
* i2p: Drop app as it has not been available in Debian for a while
* letsencrypt: Declare explicit dependency on openssl
* locale: Update translations for Albanian, Bulgarian, Chinese (Simplified Han script), Czech, French, German, Russian, Turkish
* matrixsynapse: Fix trimming an i18n string
* networks: Fix issue with loading create PPPoE form
* networks: Fix minor typo in template related to signal strength
* networks: Use new accordion component from Bootstrap 5
* openvpn: Declare explicit dependency on openssl
* power: Refactor display of package manager busy alerts
* radicale: Update link to supported clients
* sso: Switch using cryptography module instead of OpenSSL.crypto
* tags: Fix issue with JS init on a page without tags
* tags: tests: Fix deprecated webdriver attribute
* tests: functional: Disable smooth scrolling from Bootstrap 5
* tests: functional: Don't try disable app after tests if app was not installed
* tests: functional: Fix app installation test skipped on slow machines
* ui: Accept default styling of Bootstrap 5 for warning button
* ui: Align app icons in the center for home, apps, and help pages
* ui: Allow underlining for most links due to Bootstrap 5
* ui: Allow users to provide a CSS file to customize styling
* ui: Cleanup use of colors with CSS variables
* ui: Don't use nav-link inside card
* ui: Drop use of badge-* utility classes for newer replacements
* ui: Fix flash of notifications popdown during page load
* ui: Fix issue with notifications icon showing twice in mobile view
* ui: Fix overflow of exception text in message
* ui: Fix placement of tags menu under tags input with Bootstrap 5
* ui: Fix styling in dismiss button in form errors for Bootstrap 5
* ui: Fix toggle button styling for Bootstrap 5
* ui: Reduce the gap at the top of the pages
* ui: Rename data- attributes to data-bs- for Bootstrap 5
* ui: Restore spacing between form elements in Bootstrap 5
* ui: Restyle tags, remove underlining of text
* ui: Show disabled form elements as grey for Bootstrap 5
* ui: Style the 'Log out' item properly
* ui: Update custom button styles for Bootstrap 5
* ui: Update styling for navbar menu items
* ui: Use Bootstrap 5 styling for all alerts
* ui: Use collapse instead of dropdown for notification in Bootstrap 5
* ui: Workaround dropdowns not working with Bootstrap 5
* ui: app, system: Revert to earlier width for card lists
* ui: app: Fix an incorrect HTML tag nesting
* ui: backups: Drop unused styling in verify host key page
* ui: backups: Use Bootstrap color variables instead of static values
* ui: diagnostics: Fix gap between headings
* ui: diagnostics: Fix layout of repair buttons
* ui: firewall: Fix styling with Bootstrap 5
* ui: forms: Fix margins for form labels for Bootstrap 5
* ui: help: Fix alignment issue with footer links in about page
* ui: samba: Fix layout regressions with Bootstrap 5
* ui: snapshots: Fix horizontal form layout on mobiles for Bootstrap 5
* ui: snapshots: Fix horizontal form styling margins for Bootstrap 5
* ui: users: Fix close button for confirmation dialog for Bootstrap 5
== FreedomBox 24.24 (2024-11-18) ==
=== Highlights ===

View File

@ -16,7 +16,6 @@ You can grant access to your !FreedomBox for other users. Provide the Username w
* feed-reader
* freedombox-share
* git-access
* i2p
* minidlna
* syncthing
* web-search

View File

@ -24,7 +24,6 @@
<<Include(FreedomBox/Manual/Email, , from="## BEGIN_INCLUDE", to="## END_INCLUDE")>>
<<Include(FreedomBox/Manual/FeatherWiki, , from="## BEGIN_INCLUDE", to="## END_INCLUDE")>>
<<Include(FreedomBox/Manual/GitWeb, , from="## BEGIN_INCLUDE", to="## END_INCLUDE")>>
<<Include(FreedomBox/Manual/I2P, , from="## BEGIN_INCLUDE", to="## END_INCLUDE")>>
<<Include(FreedomBox/Manual/Ikiwiki, , from="## BEGIN_INCLUDE", to="## END_INCLUDE")>>
<<Include(FreedomBox/Manual/Infinoted, , from="## BEGIN_INCLUDE", to="## END_INCLUDE")>>
<<Include(FreedomBox/Manual/Janus, , from="## BEGIN_INCLUDE", to="## END_INCLUDE")>>
@ -35,6 +34,7 @@
<<Include(FreedomBox/Manual/MiniDLNA, , from="## BEGIN_INCLUDE", to="## END_INCLUDE")>>
<<Include(FreedomBox/Manual/Miniflux, , from="## BEGIN_INCLUDE", to="## END_INCLUDE")>>
<<Include(FreedomBox/Manual/Mumble, , from="## BEGIN_INCLUDE", to="## END_INCLUDE")>>
<<Include(FreedomBox/Manual/Nextcloud, , from="## BEGIN_INCLUDE", to="## END_INCLUDE")>>
<<Include(FreedomBox/Manual/OpenVPN, , from="## BEGIN_INCLUDE", to="## END_INCLUDE")>>
<<Include(FreedomBox/Manual/Privoxy, , from="## BEGIN_INCLUDE", to="## END_INCLUDE")>>
<<Include(FreedomBox/Manual/Quassel, , from="## BEGIN_INCLUDE", to="## END_INCLUDE")>>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -27,7 +27,7 @@ Installing !FreedomBox changes your Debian system in many important ways. This
Check the Troubleshooting section below, for any tips or workarounds that might help during the install.
1. [[InstallingDebianOn|Install Debian]] 12 (bookworm), or Unstable (sid) on your hardware.
1. [[InstallingDebianOn|Install Debian]] 12 (Bookworm) or newer on your hardware. During installation choosing "Btrfs" for root filesystem type is recommended as !FreedomBox uses it take regular snapshots of the system.
1. Update your package list.

View File

@ -1,35 +0,0 @@
#language es
<<Include(FreedomBox/Manual/I2P, ,from="^##TAG:TRANSLATION-HEADER-START",to="^##TAG:TRANSLATION-HEADER-END")>>
<<TableOfContents()>>
## BEGIN_INCLUDE
== I2P (Red anónima) ==
||<tablestyle="float: right;"> {{attachment:FreedomBox/Manual/I2P/I2P-icon_en_V01.png|I2P icon}} ||
=== Acerca de I2P ===
El ''Proyecto Internet Invisible (I2P)'' es una capa anonimizadora de red concebida para protejer las comunicaciones de la censura y la vigilancia. I2P proporciona anonimato enviando tráfico cifrado a través de una red distribuída alrededor del mundo gestionada por voluntarios.
=== Servicios Ofrecidos ===
Los siguientes servicios se ofrecen en !FreedomBox a través de I2P de serie. Se pueden habilitar más servicios desde la consola de enrutado I2P que se puede abrir desde el interfaz web de !FreedomBox.
* '''Navegación web anónima''': I2P se puede usar para navegar por la web de forma anónima. Para ello configura tu navegador (preferíblemente un navegador Tor) para conectar al proxy I2P. Esto se puede hacer estableciendo los proxies HTTP y HTTPS a ''freedombox.local'' (o la IP local de tu !FreedomBox) con sus respectivos puertos a ''4444'' y ''4445''. Este servicio está disponible sólo cuando accedes a la !FreedomBox usando la red local (redes de la zona ''interna'' del cortaguegos) y no cuando llegas a la !FreedomBox desde Internet. Una excepción a esto es cuando te conectas al servicio VPN de la !FreedomBox desde Internet, en cuyo caso sí puedes usar el servicio de navegación web anónima a través de I2P.
* '''Acceso a eepsites''': La red I2P puede albergar sitios web anónimos llamados eepsites cuyo nombre de dominio acaba en `.i2p`. Por ejemplo, `http://i2p-projekt.i2p/` es el sitio web del proyecto I2P en la red I2P. Los eepsites son inaccesibles a un navegador normal a través de una conexión Internet normal. Para navegar a los eepsites tu navegador necesita configurarse para usar los proxies HTTP y HTTPS como se describió antes. Este servicio solo está disponible cuando accedes a la !FreedomBox usando la red local (redes de la zona ''interna'' del cortaguegos) y no cuando llegas a la !FreedomBox desde Internet. Una excepción a esto es cuando te conectas al servicio VPN de la !FreedomBox desde Internet, en cuyo caso sí puedes usar el servicio de acceso a eepsites a través de I2P.
* '''Descargas anónima de torrentes''': I2PSnark, una aplicación para descargar y compartir archivos anónimamente mediante la red !BitTorrent está disponible y habilitada por defecto en !FreedomBox. Esta aplicación se controla mediante un interfaz web que se puede abrir desde la sección ''Torrentes Anonimos'' de la app I2P en el interfaz web de !FreedomBox o de la consola de enrutado I2P. Solo los usuarios ingresados pertenecientes al grupo ''Manage I2P application'' pueden usar este servicio.
* '''Red IRC''': La red I2P contiene una red IRC llamada Irc2P. Esta red alberga el canal IRC oficial del proyecto I2P, entre otros. Este servicio viene habilitdo de serie en !FreedomBox. Para usarlo abre tu cliente IRC favorito y configuralo para conectar con ''freedombox.local'' (o la IP local de tu !FreedomBox) en el puerto ''6668''. Este servicio solo está disponible cuando accedes a la !FreedomBox usando la red local (redes de la zona ''interna'' del cortaguegos) y no cuando llegas a la !FreedomBox desde Internet. Una excepción a esto es cuando te conectas al servicio VPN de la !FreedomBox desde Internet, en cuyo caso sí puedes usar el servicio de IRC a través de I2P.
* '''Consola de enrutado I2P''': Este es el interfaz central de administración de I2P. Muestra el estado actual de I2P, estadísticas de ancho de banda y permite modificar varias preferencias de configuración. Puedes adecuar tu participación en la red I2P y usar/editar una lista con tus sitios I2P (eepsites) favoritos. Solo los usuarios ingresados pertenecientes al grupo ''Manage I2P application'' pueden usar este servicio.
=== Enlaces externos ===
* Sitio web: https://geti2p.net/es/
* Documentación de uso (en inglés): https://i2pd.readthedocs.io/en/latest/
## END_INCLUDE
Volver a la [[es/FreedomBox/Features|descripción de Funcionalidades]] o a las páginas del [[es/FreedomBox/Manual|manual]].
<<Include(es/FreedomBox/Portal)>>

View File

@ -24,7 +24,6 @@
<<Include(FreedomBox/Manual/Email, , from="## BEGIN_INCLUDE", to="## END_INCLUDE")>>
<<Include(FreedomBox/Manual/FeatherWiki, , from="## BEGIN_INCLUDE", to="## END_INCLUDE")>>
<<Include(FreedomBox/Manual/GitWeb, , from="## BEGIN_INCLUDE", to="## END_INCLUDE")>>
<<Include(FreedomBox/Manual/I2P, , from="## BEGIN_INCLUDE", to="## END_INCLUDE")>>
<<Include(FreedomBox/Manual/Ikiwiki, , from="## BEGIN_INCLUDE", to="## END_INCLUDE")>>
<<Include(FreedomBox/Manual/Infinoted, , from="## BEGIN_INCLUDE", to="## END_INCLUDE")>>
<<Include(FreedomBox/Manual/Janus, , from="## BEGIN_INCLUDE", to="## END_INCLUDE")>>
@ -35,6 +34,7 @@
<<Include(FreedomBox/Manual/MiniDLNA, , from="## BEGIN_INCLUDE", to="## END_INCLUDE")>>
<<Include(FreedomBox/Manual/Miniflux, , from="## BEGIN_INCLUDE", to="## END_INCLUDE")>>
<<Include(FreedomBox/Manual/Mumble, , from="## BEGIN_INCLUDE", to="## END_INCLUDE")>>
<<Include(FreedomBox/Manual/Nextcloud, , from="## BEGIN_INCLUDE", to="## END_INCLUDE")>>
<<Include(FreedomBox/Manual/OpenVPN, , from="## BEGIN_INCLUDE", to="## END_INCLUDE")>>
<<Include(FreedomBox/Manual/Privoxy, , from="## BEGIN_INCLUDE", to="## END_INCLUDE")>>
<<Include(FreedomBox/Manual/Quassel, , from="## BEGIN_INCLUDE", to="## END_INCLUDE")>>

View File

@ -125,7 +125,6 @@ Los siguientes servicios '''funcionan''' con OpenVPN:
* [[es/FreedomBox/Manual/Privoxy|Privoxy]],
* [[es/FreedomBox/Manual/Tor|Tor Socks]],
* [[es/FreedomBox/Manual/Shadowsocks|Shadowsocks]],
* [[es/FreedomBox/Manual/I2P|I2P Proxy]] and
* [[es/FreedomBox/Manual/Samba|Samba]].
Algunos servicios '''no''' funcionan aún con OpenVPN:

View File

@ -8,6 +8,82 @@ For more technical details, see the [[https://salsa.debian.org/freedombox-team/f
The following are the release notes for each !FreedomBox version.
== FreedomBox 24.25 (2024-12-16) ==
=== Highlights ===
* deluge: Fix app installation on Debian testing
* notifications: Don't error when dismissing missing notifications
* ui: Switch to using bootstrap 5
=== Other Changes ===
* action_utils: Add utility to ensure that service is stopped
* apache: Relax content security policy to allow data: URL
* ci: Add flake8 to gitlabci container
* d/control: Drop unnecessary recommendations
* d/control: Drop version specification on dependencies for Bookworm
* debian: Added po-debconf Catalan translation
* deluge: Cleanup and simplify setup code
* diagnostics: Fix trimming an i18n string
* diagnostics: tests: functional: Pick errors more specifically
* firewalld: Reduce severity for alert about service on internal zone
* help: Add a class to the help index page
* help: Update the privacy notice on status log page
* i2p: Drop app as it has not been available in Debian for a while
* letsencrypt: Declare explicit dependency on openssl
* locale: Update translations for Albanian, Bulgarian, Chinese (Simplified Han script), Czech, French, German, Russian, Turkish
* matrixsynapse: Fix trimming an i18n string
* networks: Fix issue with loading create PPPoE form
* networks: Fix minor typo in template related to signal strength
* networks: Use new accordion component from Bootstrap 5
* openvpn: Declare explicit dependency on openssl
* power: Refactor display of package manager busy alerts
* radicale: Update link to supported clients
* sso: Switch using cryptography module instead of OpenSSL.crypto
* tags: Fix issue with JS init on a page without tags
* tags: tests: Fix deprecated webdriver attribute
* tests: functional: Disable smooth scrolling from Bootstrap 5
* tests: functional: Don't try disable app after tests if app was not installed
* tests: functional: Fix app installation test skipped on slow machines
* ui: Accept default styling of Bootstrap 5 for warning button
* ui: Align app icons in the center for home, apps, and help pages
* ui: Allow underlining for most links due to Bootstrap 5
* ui: Allow users to provide a CSS file to customize styling
* ui: Cleanup use of colors with CSS variables
* ui: Don't use nav-link inside card
* ui: Drop use of badge-* utility classes for newer replacements
* ui: Fix flash of notifications popdown during page load
* ui: Fix issue with notifications icon showing twice in mobile view
* ui: Fix overflow of exception text in message
* ui: Fix placement of tags menu under tags input with Bootstrap 5
* ui: Fix styling in dismiss button in form errors for Bootstrap 5
* ui: Fix toggle button styling for Bootstrap 5
* ui: Reduce the gap at the top of the pages
* ui: Rename data- attributes to data-bs- for Bootstrap 5
* ui: Restore spacing between form elements in Bootstrap 5
* ui: Restyle tags, remove underlining of text
* ui: Show disabled form elements as grey for Bootstrap 5
* ui: Style the 'Log out' item properly
* ui: Update custom button styles for Bootstrap 5
* ui: Update styling for navbar menu items
* ui: Use Bootstrap 5 styling for all alerts
* ui: Use collapse instead of dropdown for notification in Bootstrap 5
* ui: Workaround dropdowns not working with Bootstrap 5
* ui: app, system: Revert to earlier width for card lists
* ui: app: Fix an incorrect HTML tag nesting
* ui: backups: Drop unused styling in verify host key page
* ui: backups: Use Bootstrap color variables instead of static values
* ui: diagnostics: Fix gap between headings
* ui: diagnostics: Fix layout of repair buttons
* ui: firewall: Fix styling with Bootstrap 5
* ui: forms: Fix margins for form labels for Bootstrap 5
* ui: help: Fix alignment issue with footer links in about page
* ui: samba: Fix layout regressions with Bootstrap 5
* ui: snapshots: Fix horizontal form layout on mobiles for Bootstrap 5
* ui: snapshots: Fix horizontal form styling margins for Bootstrap 5
* ui: users: Fix close button for confirmation dialog for Bootstrap 5
== FreedomBox 24.24 (2024-11-18) ==
=== Highlights ===

View File

@ -16,7 +16,6 @@ Puedes otorgar acceso a tu !FreedomBox a otros usuarios. Proporciona el nombre d
* feed-reader
* freedombox-share
* git-access
* i2p
* minidlna
* syncthing
* web-search

View File

@ -22,7 +22,6 @@
<<Include(es/FreedomBox/Manual/ejabberd, , from="## BEGIN_INCLUDE", to="## END_INCLUDE")>>
<<Include(es/FreedomBox/Manual/Email, , from="## BEGIN_INCLUDE", to="## END_INCLUDE")>>
<<Include(es/FreedomBox/Manual/GitWeb, , from="## BEGIN_INCLUDE", to="## END_INCLUDE")>>
<<Include(es/FreedomBox/Manual/I2P, , from="## BEGIN_INCLUDE", to="## END_INCLUDE")>>
<<Include(es/FreedomBox/Manual/Ikiwiki, , from="## BEGIN_INCLUDE", to="## END_INCLUDE")>>
<<Include(es/FreedomBox/Manual/Infinoted, , from="## BEGIN_INCLUDE", to="## END_INCLUDE")>>
<<Include(es/FreedomBox/Manual/Janus, , from="## BEGIN_INCLUDE", to="## END_INCLUDE")>>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

View File

@ -3,4 +3,4 @@
Package init file.
"""
__version__ = '24.24'
__version__ = '24.25'

View File

@ -64,6 +64,20 @@ def service_ensure_running(service_name):
service_disable(service_name)
@contextmanager
def service_ensure_stopped(service_name):
"""Ensure a service is stopped and return to previous state."""
starting_state = service_is_running(service_name)
if starting_state:
service_disable(service_name)
try:
yield starting_state
finally:
if starting_state:
service_enable(service_name)
def service_is_enabled(service_name, strict_check=False):
"""Check if service is enabled in systemd.

View File

@ -121,6 +121,15 @@ def splinter_wait_time():
return 0.01
@pytest.fixture(scope='session')
def splinter_driver_kwargs():
"""Disable smooth scrolling to fix 'Element x not clickable' errors."""
from selenium.webdriver.firefox.options import Options
driver_options = Options()
driver_options.set_preference('general.smoothScroll', False)
return {'options': driver_options}
@pytest.fixture(scope='session')
def splinter_browser_load_condition():
"""When a page it loaded, wait until <body> is available."""

View File

@ -8,7 +8,7 @@ import re
from django.utils.translation import gettext as _
from django.utils.translation import gettext_noop
from plinth import cfg
from plinth import cfg, web_server
from plinth.utils import is_user_admin
@ -35,6 +35,7 @@ def common(request):
'active_menu_urls': active_menu_urls,
'box_name': _(cfg.box_name),
'user_is_admin': is_user_admin(request, True),
'user_css': web_server.get_user_css(),
'notifications': notifications_context['notifications'],
'notifications_max_severity': notifications_context['max_severity']
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -9,15 +9,15 @@
}
.mount-error {
color: orange;
color: var(--bs-warning);
}
.mount-success {
color: black;
color: var(--bs-body-color);
}
.encrypted {
color: green;
color: var(--bs-success);
}
.inline-block {

View File

@ -15,13 +15,19 @@
{{ form|bootstrap }}
<div class="alert alert-warning" role="alert">
{% blocktrans trimmed %}
The credentials for this repository are stored on your {{ box_name }}.
<br />
To restore a backup on a new {{ box_name }} you need the SSH
credentials and, if chosen, the encryption passphrase.
{% endblocktrans %}
<div class="alert alert-warning d-flex align-items-center" role="alert">
<div class="me-2">
<span class="fa fa-exclamation-triangle" aria-hidden="true"></span>
<span class="visually-hidden">{% trans "Caution:" %}</span>
</div>
<div>
{% blocktrans trimmed %}
The credentials for this repository are stored on your {{ box_name }}.
<br />
To restore a backup on a new {{ box_name }} you need the SSH credentials
and, if chosen, the encryption passphrase.
{% endblocktrans %}
</div>
</div>
<input type="submit" class="btn btn-primary"

View File

@ -6,7 +6,7 @@
<div class="table-responsive">
<table class="table" id="archives-list">
<thead class="collapsible-button" data-toggle="collapse" data-target="#{{ uuid }}">
<thead class="collapsible-button" data-bs-toggle="collapse" data-bs-target="#{{ uuid }}">
<tr>
<th colspan="2">
<span class="fa fa-chevron-right fa-fw" aria-hidden="true"></span>

View File

@ -22,13 +22,17 @@
</p>
{% if max_filesize %}
<div class="alert alert-warning" role="alert">
<span class="fa fa-exclamation-triangle" aria-hidden="true"></span>
<span class="sr-only">{% trans "Caution:" %}</span>
{% blocktrans trimmed %}
You have {{ max_filesize }} available to restore a backup.
Exceeding this limit can leave your {{ box_name }} unusable.
{% endblocktrans %}
<div class="alert alert-warning d-flex align-items-center" role="alert">
<div class="me-2">
<span class="fa fa-exclamation-triangle" aria-hidden="true"></span>
<span class="visually-hidden">{% trans "Caution:" %}</span>
</div>
<div>
{% blocktrans trimmed %}
You have {{ max_filesize }} available to restore a backup.
Exceeding this limit can leave your {{ box_name }} unusable.
{% endblocktrans %}
</div>
</div>
{% endif %}

View File

@ -21,7 +21,13 @@
{% endblocktrans %}
</p>
{% if form.keyscan_error %}
<pre class="alert alert-danger">{{ form.keyscan_error }}</pre>
<div class="alert alert-danger d-flex align-items-center">
<div class="me-2">
<span class="fa fa-exclamation-triangle" aria-hidden="true"></span>
<span class="visually-hidden">{% trans "Caution:" %}</span>
</div>
<pre class="mb-0">{{ form.keyscan_error }}</pre>
</div>
{% endif %}
{% else %}
<p>
@ -35,12 +41,12 @@
<section>
<p>
<a class="btn btn-default collapsed collapsible-button"
data-toggle="collapse" href="#help" aria-expanded="false">
data-bs-toggle="collapse" href="#help" aria-expanded="false">
<span class="fa fa-chevron-right fa-fw" aria-hidden="true"></span>
{% trans "How to verify?" %}
</a>
</p>
<div class="collapse card-body" id="help">
<div class="collapse" id="help">
<p>
{% blocktrans trimmed %}
Run the following command on the SSH host machine. The output

View File

@ -11,6 +11,7 @@ from plinth.modules.apache.components import Webserver
from plinth.modules.backups.components import BackupRestore
from plinth.modules.firewall.components import (Firewall,
FirewallLocalProtection)
from plinth.modules.upgrades import get_current_release
from plinth.modules.users import add_user_to_share_group
from plinth.modules.users.components import UsersAndGroups
from plinth.package import Packages
@ -26,12 +27,26 @@ _description = [
SYSTEM_USER = 'debian-deluged'
class DelugePackages(Packages):
"""Mark deluge app as not available in Debian Bookworm.
deluge-web is broken in Debian Bookworm. Related bug report:
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1031593
"""
def has_unavailable_packages(self) -> bool | None:
if get_current_release()[1] == 'bookworm':
return True
return super().has_unavailable_packages()
class DelugeApp(app_module.App):
"""FreedomBox app for Deluge."""
app_id = 'deluge'
_version = 8
_version = 9
def __init__(self) -> None:
"""Create components for the app."""
@ -64,7 +79,7 @@ class DelugeApp(app_module.App):
allowed_groups=list(groups))
self.add(shortcut)
packages = Packages('packages-deluge', ['deluged', 'deluge-web'])
packages = DelugePackages('packages-deluge', ['deluged', 'deluge-web'])
self.add(packages)
dropin_configs = DropinConfigs(

View File

@ -0,0 +1,16 @@
[Service]
ExecStart=
ExecStart=/usr/bin/deluge-web --config /var/lib/deluged/config/ --base=deluge --do-not-daemonize
LockPersonality=yes
NoNewPrivileges=yes
PrivateDevices=yes
PrivateTmp=yes
ProtectControlGroups=yes
ProtectKernelLogs=yes
ProtectKernelModules=yes
ProtectKernelTunables=yes
ProtectSystem=yes
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
RestrictRealtime=yes
StateDirectory=deluged
SystemCallArchitectures=native

View File

@ -13,7 +13,7 @@ clients = [{
backup = {
'config': {
'directories': ['/var/lib/deluged/.config']
'directories': ['/var/lib/deluged/config']
},
'services': ['deluged', 'deluge-web']
}

View File

@ -3,69 +3,21 @@
import pathlib
import shutil
import subprocess
import time
import augeas
from plinth import action_utils
from plinth.actions import privileged
from plinth.modules.deluge.utils import Config
DELUGED_DEFAULT_FILE = '/etc/default/deluged'
DELUGE_CONF_DIR = pathlib.Path('/var/lib/deluged/.config/deluge/')
DELUGE_WEB_SYSTEMD_SERVICE_PATH = '/etc/systemd/system/deluge-web.service'
DELUGE_WEB_SYSTEMD_SERVICE = '''
#
# This file is managed and overwritten by Plinth. If you wish to edit
# it, disable Deluge in Plinth, remove this file and manage it manually.
#
[Unit]
Description=Deluge Web Interface
Documentation=man:deluge-web(1)
After=network.target
[Service]
ExecStart=bash -c "/usr/bin/deluge-web --base=deluge $(/usr/bin/deluge-web --version | grep deluge-web | cut -f2 -d' ' | grep -q '^1.' && echo '' || echo '--do-not-daemonize')"
Restart=on-failure
User=debian-deluged
Group=debian-deluged
LockPersonality=yes
NoNewPrivileges=yes
PrivateDevices=yes
PrivateTmp=yes
ProtectControlGroups=yes
ProtectKernelLogs=yes
ProtectKernelModules=yes
ProtectKernelTunables=yes
ProtectSystem=yes
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
RestrictRealtime=yes
StateDirectory=deluged
SystemCallArchitectures=native
[Install]
WantedBy=multi-user.target
''' # noqa: E501
DELUGE_CONF_DIR = pathlib.Path('/var/lib/deluged/config/')
def _set_configuration(filename, parameter, value):
"""Set the configuration parameter."""
deluged_is_running = action_utils.service_is_running('deluged')
if deluged_is_running:
action_utils.service_stop('deluged')
deluge_web_is_running = action_utils.service_is_running('deluge-web')
if deluge_web_is_running:
action_utils.service_stop('deluge-web')
with Config(DELUGE_CONF_DIR / filename) as config:
config.content[parameter] = value
if deluged_is_running:
action_utils.service_start('deluged')
if deluge_web_is_running:
action_utils.service_start('deluge-web')
with action_utils.service_ensure_stopped('deluge-web'):
with action_utils.service_ensure_stopped('deluged'):
with Config(DELUGE_CONF_DIR / filename) as config:
config.content[parameter] = value
def _get_host_id():
@ -78,20 +30,6 @@ def _get_host_id():
return config.content['hosts'][0][0]
def _set_deluged_daemon_options():
"""Set deluged daemon options."""
aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD +
augeas.Augeas.NO_MODL_AUTOLOAD)
aug.set('/augeas/load/Shellvars/lens', 'Shellvars.lns')
aug.set('/augeas/load/Shellvars/incl[last() + 1]', DELUGED_DEFAULT_FILE)
aug.load()
aug.set('/files' + DELUGED_DEFAULT_FILE + '/ENABLE_DELUGED', '1')
# overwrite daemon args, use default config directory (same as deluge-web)
aug.set('/files' + DELUGED_DEFAULT_FILE + '/DAEMON_ARGS',
'"-d -l /var/log/deluged/daemon.log -L info"')
aug.save()
@privileged
def get_configuration() -> dict[str, str]:
"""Return the current deluged configuration."""
@ -110,56 +48,44 @@ def set_configuration(download_location: str):
@privileged
def setup():
"""Perform initial setup for deluge."""
with open(DELUGE_WEB_SYSTEMD_SERVICE_PATH, 'w',
encoding='utf-8') as file_handle:
file_handle.write(DELUGE_WEB_SYSTEMD_SERVICE)
old_service_path = pathlib.Path('/etc/systemd/system/deluge-web.service')
if old_service_path.exists():
old_service_path.unlink(missing_ok=True)
_set_deluged_daemon_options()
subprocess.check_call(['systemctl', 'daemon-reload'])
# Restarting an old deluge-web service stops also possible deluged process
# that was started from the web interface.
action_utils.service_daemon_reload()
action_utils.service_try_restart('deluged')
action_utils.service_try_restart('deluge-web')
# Wait until core configuration is available so that status of the app can
# be shown properly.
_wait_for_configuration('deluged', 'core.conf')
_wait_for_configuration()
# Configure deluge-web to autoconnect to the default deluged daemon.
_wait_for_configuration('deluge-web', 'web.conf')
host_id = _get_host_id()
_set_configuration('web.conf', 'default_daemon', host_id)
def _wait_for_configuration(service, file_name):
def _wait_for_configuration():
"""Wait until configuration file has been created."""
conf_file = DELUGE_CONF_DIR / file_name
if conf_file.exists():
core_file = DELUGE_CONF_DIR / 'core.conf'
web_file = DELUGE_CONF_DIR / 'web.conf'
if core_file.exists() and web_file.exists():
return
# deluge-web creates files on first run. deluged on the other than differs
# in version. Older version in Debian Buster creates the files after a
# restart while newer versions create the files on first run. The following
# approach is slightly better for create-on-exit case.
is_running = action_utils.service_is_running(service)
for interval in range(7):
action_utils.service_restart(service)
if conf_file.exists():
break
# deluge-web and deluged create files on first run.
with action_utils.service_ensure_running('deluged'):
with action_utils.service_ensure_running('deluge-web'):
for _ in range(60):
if core_file.exists() and web_file.exists():
break
print('Waiting for {service} configuration')
time.sleep(2**interval) # Exponentially increase the time waited
else:
raise Exception(f'Unable to setup {service}.')
if not is_running:
action_utils.service_stop(service)
time.sleep(1)
else:
raise Exception('Unable to setup configuration')
@privileged
def uninstall():
"""Remove configuration and service files."""
# /etc/default/deluged is removed on purge
pathlib.Path(DELUGE_WEB_SYSTEMD_SERVICE_PATH).unlink(missing_ok=True)
shutil.rmtree(DELUGE_CONF_DIR, ignore_errors=True)

View File

@ -35,14 +35,12 @@ class TestDelugeApp(functional.BaseAppTests):
'nogroupuser')
assert not functional.is_available(session_browser, 'deluge')
functional.login(session_browser)
def test_upload_torrent(self, session_browser):
"""Test uploading a torrent."""
functional.app_enable(session_browser, 'deluge')
_remove_all_torrents(session_browser)
_upload_sample_torrent(session_browser)
assert _get_number_of_torrents(session_browser) == 1
assert len(_get_torrents(session_browser)) == 1
@pytest.mark.backups
def test_backup_restore(self, session_browser):
@ -55,7 +53,7 @@ class TestDelugeApp(functional.BaseAppTests):
_remove_all_torrents(session_browser)
functional.backup_restore(session_browser, 'deluge', 'test_deluge')
assert functional.service_is_running(session_browser, 'deluge')
assert _get_number_of_torrents(session_browser) == 1
assert len(_get_torrents(session_browser)) == 1
def _get_active_window_title(browser):
@ -81,49 +79,30 @@ def _ensure_logged_in(browser):
# After a backup restore, service may not be available immediately
functional.eventually(service_is_available)
time.sleep(1) # Wait for Ext.js application in initialize
functional.eventually(browser.is_element_present_by_id, ['add'])
if _get_active_window_title(browser) != 'Login':
return
def logged_in():
active_window_title = _get_active_window_title(browser)
browser.find_by_id('_password').first.fill('deluge')
_click_active_window_button(browser, 'Login')
# Change Default Password window appears once.
if active_window_title == 'Change Default Password':
_click_active_window_button(browser, 'No')
assert functional.eventually(
lambda: _get_active_window_title(browser) != 'Login')
functional.eventually(browser.is_element_not_present_by_css,
args=['#add.x-item-disabled'], timeout=0.3)
if active_window_title == 'Login':
browser.find_by_id('_password').first.fill('deluge')
_click_active_window_button(browser, 'Login')
return browser.is_element_not_present_by_css('#add .x-item-disabled')
def _open_connection_manager(browser):
"""Open the connection manager dialog if not already open."""
title = 'Connection Manager'
if _get_active_window_title(browser) == title:
return
browser.find_by_css('button.x-deluge-connection-manager').first.click()
functional.eventually(lambda: _get_active_window_title(browser) == title)
def _ensure_connected(browser):
"""Type the connection password if required and start Deluge daemon."""
_ensure_logged_in(browser)
# Change Default Password window appears once.
if _get_active_window_title(browser) == 'Change Default Password':
_click_active_window_button(browser, 'No')
assert functional.eventually(browser.is_element_not_present_by_css,
args=['#add.x-item-disabled'])
functional.eventually(logged_in)
def _remove_all_torrents(browser):
"""Remove all torrents from deluge."""
_ensure_connected(browser)
while browser.find_by_css('#torrentGrid .torrent-name'):
browser.find_by_css('#torrentGrid .torrent-name').first.click()
_ensure_logged_in(browser)
for torrent in _get_torrents(browser):
torrent.click()
# Click remove toolbar button
browser.find_by_id('remove').first.click()
@ -155,9 +134,9 @@ def _click_active_window_button(browser, button_text):
def _upload_sample_torrent(browser):
"""Upload a sample torrent into deluge."""
_ensure_connected(browser)
_ensure_logged_in(browser)
number_of_torrents = _get_number_of_torrents(browser)
number_of_torrents = len(_get_torrents(browser))
# Click add toolbar button
browser.find_by_id('add').first.click()
@ -168,35 +147,20 @@ def _upload_sample_torrent(browser):
file_path = os.path.join(os.path.dirname(__file__), 'data',
'sample.torrent')
if browser.find_by_id('fileUploadForm'): # deluge-web 2.x
browser.attach_file('file', file_path)
else: # deluge-web 1.x
browser.find_by_css('button.x-deluge-add-file').first.click()
# Add from file window appears
functional.eventually(
lambda: _get_active_window_title(browser) == 'Add from File')
# Attach file
browser.attach_file('file', file_path)
# Click Add
_click_active_window_button(browser, 'Add')
functional.eventually(
lambda: _get_active_window_title(browser) == 'Add Torrents')
browser.attach_file('file', file_path)
# Click Add
time.sleep(1)
_click_active_window_button(browser, 'Add')
functional.eventually(
lambda: _get_number_of_torrents(browser) > number_of_torrents)
lambda: len(_get_torrents(browser)) > number_of_torrents)
def _get_number_of_torrents(browser):
"""Return the number torrents currently in deluge."""
_ensure_connected(browser)
def _get_torrents(browser):
"""Return list of torrents currently in deluge."""
_ensure_logged_in(browser)
# wait until torrent list is loaded
functional.eventually(browser.is_element_present_by_css, ['.x-deluge-all'])
return len(browser.find_by_css('#torrentGrid .torrent-name'))
return browser.find_by_css('#torrentGrid .torrent-name')

View File

@ -9,27 +9,35 @@
<h2>{% trans "Diagnostic Results" %}</h2>
<div class="row align-items-center justify-content-between">
<h3>{% blocktrans %}App: {{ app_name }}{% endblocktrans %}</h3>
<section>
<div class="d-flex align-items-center justify-content-between">
<h3>{% blocktrans %}App: {{ app_name }}{% endblocktrans %}</h3>
{% if show_repair %}
<form class="form form-diagnostics-repair-button" method="post"
action="{% url 'diagnostics:repair' app_id=app_id %}">
{% csrf_token %}
<input type="submit" class="btn btn-default"
name="repair" value="{% trans "Try to repair" %}"/>
</form>
{% endif %}
</div>
{% if results %}
{% include "diagnostics_results.html" with results=results %}
{% elif exception %}
<div class="alert alert-danger" role="alert">
{{ exception }}
{% if show_repair %}
<form class="form form-diagnostics-repair-button" method="post"
action="{% url 'diagnostics:repair' app_id=app_id %}">
{% csrf_token %}
<input type="submit" class="btn btn-default"
name="repair" value="{% trans "Try to repair" %}"/>
</form>
{% endif %}
</div>
{% else %}
<p>{% trans "This app does not support diagnostics" %}</p>
{% endif %}
{% if results %}
{% include "diagnostics_results.html" with results=results %}
{% elif exception %}
<div class="alert alert-danger d-flex align-items-center" role="alert">
<div class="me-2">
<span class="fa fa-exclamation-triangle" aria-hidden="true"></span>
<span class="visually-hidden">{% trans "Caution:" %}</span>
</div>
<div>
{{ exception }}
</div>
</div>
{% else %}
<p>{% trans "This app does not support diagnostics" %}</p>
{% endif %}
</section>
{% endblock %}

View File

@ -33,32 +33,40 @@
{% if results %}
<h3>{% trans "Results" %}</h3>
{% for app_id, app_data in results.results.items %}
<div class="row align-items-center justify-content-between">
<h4>
{% blocktrans with app_name=app_data.name %}
App: {{app_name}}
{% endblocktrans %}
</h4>
<section>
<div class="d-flex align-items-center justify-content-between">
<h4>
{% blocktrans trimmed with app_name=app_data.name %}
App: {{app_name}}
{% endblocktrans %}
</h4>
{% if app_data.show_repair %}
<form class="form form-diagnostics-repair-button" method="post"
action="{% url 'diagnostics:repair' app_id=app_id %}">
{% csrf_token %}
<input type="submit" class="btn btn-default"
name="repair" value="{% trans "Try to repair" %}"/>
</form>
{% endif %}
</div>
{% if app_data.diagnosis %}
{% include "diagnostics_results.html" with results=app_data.diagnosis %}
{% elif app_data.exception %}
<div class="alert alert-danger" role="alert">
{{ app_data.exception }}
{% if app_data.show_repair %}
<form class="form form-diagnostics-repair-button" method="post"
action="{% url 'diagnostics:repair' app_id=app_id %}">
{% csrf_token %}
<input type="submit" class="btn btn-default"
name="repair" value="{% trans "Try to repair" %}"/>
</form>
{% endif %}
</div>
{% else %}
<p><span class="fa fa-hourglass-o"></span></p>
{% endif %}
{% if app_data.diagnosis %}
{% include "diagnostics_results.html" with results=app_data.diagnosis %}
{% elif app_data.exception %}
<div class="alert alert-danger d-flex align-items-center" role="alert">
<div class="me-2">
<span class="fa fa-exclamation-triangle" aria-hidden="true"></span>
<span class="visually-hidden">{% trans "Caution:" %}</span>
</div>
<div>
{{ app_data.exception }}
</div>
</div>
{% else %}
<p><span class="fa fa-hourglass-o"></span></p>
{% endif %}
</section>
{% endfor %}
{% endif %}

View File

@ -18,13 +18,13 @@
<td>{{ result.translated_description }}</td>
<td class="diagnostics-result">
{% if result.result == 'passed' %}
<span class="badge badge-success">{% trans result.result %}</span>
<span class="badge text-bg-success">{% trans result.result %}</span>
{% elif result.result == 'failed' %}
<span class="badge badge-danger">{% trans result.result %}</span>
<span class="badge text-bg-danger">{% trans result.result %}</span>
{% elif result.result == 'error' or result.result == 'warning' %}
<span class="badge badge-warning">{% trans result.result %}</span>
<span class="badge text-bg-warning">{% trans result.result %}</span>
{% elif result.result == 'skipped' %}
<span class="badge badge-secondary">{% trans result.result %}</span>
<span class="badge text-bg-secondary">{% trans result.result %}</span>
{% else %}
{{ result.result }}
{% endif %}

View File

@ -28,11 +28,11 @@
<td>{{ domain.timestamp|timesince }}</td>
<td>
{% if domain.result %}
<span class="badge badge-success">
<span class="badge text-bg-success">
{% trans "Success" %}
</span>
{% else %}
<span class="badge badge-warning">
<span class="badge text-bg-warning">
{% trans "Failed" %}
</span>
{% endif %}

View File

@ -2,12 +2,9 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
*/
a.dropdown-toggle {
color: black;
}
a.dropdown-toggle:hover {
.app-name > a.dropdown-toggle {
text-decoration: none;
color: var(--bs-table-color-state, var(--bs-table-color-type, var(--bs-table-color)));
}
td.service {
@ -22,7 +19,3 @@ td.service {
.service-status {
width: 11rem;
}
tr.collapse {
background-color: #f9f9f9;
}

View File

@ -28,18 +28,18 @@
<tr>
<td class="app-name">
<a class="dropdown-toggle" href="#"
data-toggle="collapse" role="button"
data-target=".{{component.component_id}}"
data-bs-toggle="collapse" role="button"
data-bs-target=".{{component.component_id}}"
aria-expanded="false"
aria-controls="{{component.component_id}}">
{{ component.name }}</a>
</td>
<td class="app-status">
{% if component.is_enabled %}
<span class='badge badge-success'>
<span class='badge text-bg-success'>
{% trans "Enabled" %}</span>
{% else %}
<span class='badge badge-warning'>
<span class='badge text-bg-warning'>
{% trans "Disabled" %}</span>
{% endif %}
</td>
@ -54,16 +54,16 @@
</td>
<td class="service-status">
{% if port.name in internal_enabled_ports and port.name in external_enabled_ports %}
<span class='badge badge-success'>
<span class='badge text-bg-success'>
{% trans "Permitted" %}</span>
{% elif port.name in internal_enabled_ports %}
<span class='badge badge-warning'>
<span class='badge text-bg-warning'>
{% trans "Permitted (internal only)" %}</span>
{% elif port.name in external_enabled_ports %}
<span class='badge badge-warning'>
<span class='badge text-bg-warning'>
{% trans "Permitted (external only)" %}</span>
{% else %}
<span class='badge badge-danger'>
<span class='badge text-bg-danger'>
{% trans "Blocked" %}</span>
{% endif %}
</td>

View File

@ -14,22 +14,34 @@
</p>
{% if version %}
<div class="alert {% if new_version %}alert-warning{% else %}alert-success{% endif %}">
{% blocktrans trimmed %}
You are running {{ os_release }} and {{ box_name }} version {{ version }}.
{% endblocktrans %}
<div class="alert {% if new_version %}alert-warning{% else %}alert-success{% endif %}
d-flex align-items-center">
<div class="me-2">
{% if new_version %}
<span class="fa fa-exclamation-triangle" aria-hidden="true"></span>
<span class="visually-hidden">{% trans "Caution:" %}</span>
{% else %}
<span class="fa fa-check-circle" aria-hidden="true"></span>
<span class="visually-hidden">{% trans "Success:" %}</span>
{% endif %}
</div>
<div>
{% blocktrans trimmed %}
You are running {{ os_release }} and {{ box_name }} version {{ version }}.
{% endblocktrans %}
{% if new_version %}
{% url 'upgrades:index' as upgrades_url %}
{% blocktrans trimmed %}
There is a new {{ box_name }} version
<a href="{{ upgrades_url }}">available</a>.
{% endblocktrans %}
{% else %}
{% blocktrans trimmed %}
{{ box_name }} is up to date.
{% endblocktrans %}
{% endif %}
{% if new_version %}
{% url 'upgrades:index' as upgrades_url %}
{% blocktrans trimmed %}
There is a new {{ box_name }} version
<a href="{{ upgrades_url }}">available</a>.
{% endblocktrans %}
{% else %}
{% blocktrans trimmed %}
{{ box_name }} is up to date.
{% endblocktrans %}
{% endif %}
</div>
</div>
{% endif %}

View File

@ -53,7 +53,7 @@
</p>
<p>
<a class="btn btn-default collapsed collapsible-button" role="button"
data-toggle="collapse" href="#collapse-issues" aria-expanded="false"
data-bs-toggle="collapse" href="#collapse-issues" aria-expanded="false"
aria-controls="collapse-issues">
<span class="fa fa-chevron-right fa-fw" aria-hidden="true"></span>
{% trans "Show issues" %}

View File

@ -7,6 +7,8 @@
{% load firstboot_extras %}
{% load static %}
{% block body_class %}help-page{% endblock %}
{% block content-container %}
<div class="container content-container">
<h2>{% trans "Help" %}</h2>

View File

@ -18,14 +18,18 @@
{% endblocktrans %}
</p>
<p class="alert alert-warning">
<span class="fa fa-exclamation-triangle" aria-hidden="true"></span>
<span class="sr-only">{% trans "Caution:" %}</span>
{% blocktrans trimmed %}
Please remove any passwords or other personal information from
the log before submitting the bug report.
{% endblocktrans %}
</p>
<div class="alert alert-warning d-flex align-items-center">
<div class="me-2">
<span class="fa fa-exclamation-triangle" aria-hidden="true"></span>
<span class="visually-hidden">{% trans "Caution:" %}</span>
</div>
<div>
{% blocktrans trimmed %}
Please remove any personal information from the log before submitting
the bug report.
{% endblocktrans %}
</div>
</div>
<p>
<pre class="status-log">{{ data }}</pre>

View File

@ -172,12 +172,12 @@ MANUAL_PAGES = ('Apache_userdir', 'APU', 'Backups', 'BananaPro', 'BeagleBone',
'DateTime', 'Debian', 'Deluge', 'Developer', 'Diagnostics',
'Download', 'DynamicDNS', 'ejabberd', 'Firewall',
'freedombox-manual', 'GettingHelp', 'GitWeb', 'Hardware',
'I2P', 'Ikiwiki', 'Infinoted', 'Introduction', 'JSXC',
'LetsEncrypt', 'Maker', 'MatrixSynapse', 'MediaWiki',
'Minetest', 'MiniDLNA', 'Mumble', 'NameServices', 'Networks',
'OpenVPN', 'OrangePiZero', 'PageKite', 'pcDuino3',
'Performance', 'PineA64+', 'PioneerEdition', 'Plinth', 'Power',
'Privoxy', 'Quassel', 'QuickStart', 'Radicale', 'RaspberryPi2',
'Ikiwiki', 'Infinoted', 'Introduction', 'JSXC', 'LetsEncrypt',
'Maker', 'MatrixSynapse', 'MediaWiki', 'Minetest', 'MiniDLNA',
'Mumble', 'NameServices', 'Networks', 'OpenVPN',
'OrangePiZero', 'PageKite', 'pcDuino3', 'Performance',
'PineA64+', 'PioneerEdition', 'Plinth', 'Power', 'Privoxy',
'Quassel', 'QuickStart', 'Radicale', 'RaspberryPi2',
'RaspberryPi3B+', 'RaspberryPi3B', 'RaspberryPi4B',
'ReleaseNotes', 'Rock64', 'RockPro64', 'Roundcube', 'Samba',
'Searx', 'SecureShell', 'Security', 'ServiceDiscovery',

View File

@ -1,122 +0,0 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
"""FreedomBox app to configure I2P."""
from django.utils.translation import gettext_lazy as _
from plinth import app as app_module
from plinth import frontpage, menu
from plinth.config import DropinConfigs
from plinth.daemon import Daemon
from plinth.modules.apache.components import Webserver
from plinth.modules.backups.components import BackupRestore
from plinth.modules.firewall.components import (Firewall,
FirewallLocalProtection)
from plinth.modules.i2p.resources import FAVORITES
from plinth.modules.users.components import UsersAndGroups
from plinth.package import Packages
from . import manifest, privileged
_description = [
_('The Invisible Internet Project is an anonymous network layer intended '
'to protect communication from censorship and surveillance. I2P '
'provides anonymity by sending encrypted traffic through a '
'volunteer-run network distributed around the world.'),
_('Find more information about I2P on their project '
'<a href="https://geti2p.net" target="_blank">homepage</a>.'),
_('The first visit to the provided web interface will initiate the '
'configuration process.')
]
tunnels_to_manage = {
'I2P HTTP Proxy': 'i2p-http-proxy-freedombox',
'I2P HTTPS Proxy': 'i2p-https-proxy-freedombox',
'Irc2P': 'i2p-irc-freedombox'
}
class I2PApp(app_module.App):
"""FreedomBox app for I2P."""
app_id = 'i2p'
_version = 3
def __init__(self) -> None:
"""Create components for the app."""
super().__init__()
groups = {'i2p': _('Manage I2P application')}
info = app_module.Info(app_id=self.app_id, version=self._version,
name=_('I2P'), icon_filename='i2p',
short_description=_('Anonymity Network'),
description=_description, manual_page='I2P',
clients=manifest.clients, tags=manifest.tags)
self.add(info)
menu_item = menu.Menu('menu-i2p', info.name, info.short_description,
info.icon_filename, 'i2p:index',
parent_url_name='apps')
self.add(menu_item)
shortcut = frontpage.Shortcut('shortcut-i2p', info.name,
short_description=info.short_description,
icon=info.icon_filename, url='/i2p/',
clients=info.clients,
login_required=True,
allowed_groups=list(groups))
self.add(shortcut)
packages = Packages('packages-i2p', ['i2p'])
self.add(packages)
dropin_configs = DropinConfigs('dropin-configs-i2p', [
'/etc/apache2/conf-available/i2p-freedombox.conf',
])
self.add(dropin_configs)
firewall = Firewall('firewall-i2p-web', info.name,
ports=['http', 'https'], is_external=True)
self.add(firewall)
firewall = Firewall('firewall-i2p-proxies', _('I2P Proxy'),
ports=tunnels_to_manage.values(),
is_external=False)
self.add(firewall)
firewall_local_protection = FirewallLocalProtection(
'firewall-local-protection-i2p', ['7657'])
self.add(firewall_local_protection)
webserver = Webserver('webserver-i2p', 'i2p-freedombox',
urls=['https://{host}/i2p/'])
self.add(webserver)
daemon = Daemon('daemon-i2p', 'i2p', listen_ports=[(7657, 'tcp6')])
self.add(daemon)
users_and_groups = UsersAndGroups('users-and-groups-i2p',
groups=groups)
self.add(users_and_groups)
backup_restore = BackupRestore('backup-restore-i2p', **manifest.backup)
self.add(backup_restore)
def setup(self, old_version):
"""Install and configure the app."""
super().setup(old_version)
if not old_version:
self.disable()
# Add favorites to the configuration
for fav in FAVORITES:
privileged.add_favorite(fav['name'], fav['url'],
fav.get('description'),
fav.get('icon'))
# Tunnels to all interfaces
for tunnel in tunnels_to_manage:
privileged.set_tunnel_property(tunnel, 'interface', '0.0.0.0')
self.enable()

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<service>
<short>I2P HTTP Proxy</short>
<description>The Invisible Internet Project is an anonymous network layer intended to protect communication from censorship and surveillance. I2P provides anonymity by sending encrypted traffic through a volunteer-run network distributed around the world. Enable this if a running an I2P server with HTTP proxy and wish to connect into the I2P network to browse eepsites.</description>
<port protocol="tcp" port="4444"/>
</service>

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<service>
<short>I2P HTTPS Proxy</short>
<description>The Invisible Internet Project is an anonymous network layer intended to protect communication from censorship and surveillance. I2P provides anonymity by sending encrypted traffic through a volunteer-run network distributed around the world. Enable this if a running an I2P server with HTTPS proxy and wish to connect into the I2P network to browse eepsites.</description>
<port protocol="tcp" port="4445"/>
</service>

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<service>
<short>I2P IRC Tunnel</short>
<description>The Invisible Internet Project is an anonymous network layer intended to protect communication from censorship and surveillance. I2P provides anonymity by sending encrypted traffic through a volunteer-run network distributed around the world. Enable this if a running an I2P server with IRC tunnel and wish to access the Irc2P network.</description>
<port protocol="tcp" port="6668"/>
</service>

View File

@ -1,30 +0,0 @@
##
## On all sites, provide I2P on a default path: /i2p
##
## Requires the following Apache modules to be enabled:
## mod_headers
## mod_proxy
## mod_proxy_http
## mod_proxy_html
##
<Location /i2p>
# Disable compression
# As soon as it has to be chunked, it doesn't work
RequestHeader unset Accept-Encoding
ProxyPass http://localhost:7657
ProxyPassReverse http://localhost:7657
# Rewrite absolute urls from i2p to pass through apache
ProxyHTMLEnable On
ProxyHTMLURLMap / /i2p/
Include includes/freedombox-single-sign-on.conf
<IfModule mod_auth_pubtkt.c>
TKTAuthToken "admin" "i2p"
</IfModule>
</Location>
# Catch some other root i2p addresses
# These are most likely generated by javascript
RedirectMatch "^/(i2p[^/]+.*)" "/i2p/$1"

View File

@ -1 +0,0 @@
plinth.modules.i2p

View File

@ -1,232 +0,0 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
"""
Various helpers for the I2P app.
"""
import os
import re
from collections import OrderedDict
import augeas
I2P_CONF_DIR = '/var/lib/i2p/i2p-config'
FILE_TUNNEL_CONF = os.path.join(I2P_CONF_DIR, 'i2ptunnel.config')
TUNNEL_IDX_REGEX = re.compile(r'tunnel.(\d+).name$')
I2P_ROUTER_CONF = os.path.join(I2P_CONF_DIR, 'router.config')
class TunnelEditor():
"""Helper to edit I2P tunnel configuration file using augeas.
:type aug: augeas.Augeas
"""
def __init__(self, conf_filename=None, idx=None):
self.conf_filename = conf_filename or FILE_TUNNEL_CONF
self.idx = idx
self.aug = None
@property
def lines(self):
"""Return lines from configuration file."""
if self.aug:
return self.aug.match('/files{}/*'.format(self.conf_filename))
return []
def read_conf(self):
"""Load an instance of Augeaus for processing APT configuration.
Chainable method.
"""
self.aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD +
augeas.Augeas.NO_MODL_AUTOLOAD)
self.aug.set('/augeas/load/Properties/lens', 'Properties.lns')
self.aug.set('/augeas/load/Properties/incl[last() + 1]',
self.conf_filename)
self.aug.load()
return self
def write_conf(self):
"""Write changes to the configuration file to disk.
Chainable method.
"""
self.aug.save()
return self
def set_tunnel_idx(self, name):
"""Finds the index of the tunnel with the given name.
Chainable method.
:type name: basestring
"""
for prop in self.aug.match('/files{}/*'.format(self.conf_filename)):
match = TUNNEL_IDX_REGEX.search(prop)
if match and self.aug.get(prop) == name:
self.idx = int(match.group(1))
return self
raise ValueError('No tunnel called {}'.format(name))
def calc_prop_path(self, tunnel_prop):
"""Calculates the property name as found in the properties files.
:type tunnel_prop: str
:rtype: basestring
"""
calced_prop_path = \
'/files{filepath}/tunnel.{idx}.{tunnel_prop}'.format(
idx=self.idx,
tunnel_prop=tunnel_prop,
filepath=self.conf_filename)
return calced_prop_path
def set_tunnel_prop(self, tunnel_prop, value):
"""Updates a tunnel's property.
The idx has to be set and the property has to exist in the config file
and belong to the tunnel's properties.
See calc_prop_path.
Chainable method.
:param tunnel_prop:
:type tunnel_prop: str
:param value:
:type value: basestring | int
:return:
:rtype:
"""
if self.idx is None:
raise ValueError(
'Please init the tunnel index before calling this method')
calc_prop_path = self.calc_prop_path(tunnel_prop)
self.aug.set(calc_prop_path, value)
return self
def __getitem__(self, tunnel_prop):
ret = self.aug.get(self.calc_prop_path(tunnel_prop))
if ret is None:
raise KeyError('Unknown property {}'.format(tunnel_prop))
return ret
def __setitem__(self, tunnel_prop, value):
self.aug.set(self.calc_prop_path(tunnel_prop), value)
class RouterEditor():
"""Helper to edit I2P router configuration file using augeas.
:type aug: augeas.Augeas
"""
FAVORITE_PROP = 'routerconsole.favorites'
FAVORITE_TUPLE_SIZE = 4
def __init__(self, filename=None):
self.conf_filename = filename or I2P_ROUTER_CONF
self.aug = None
def read_conf(self):
"""Load an instance of Augeaus for processing APT configuration.
Chainable method.
"""
self.aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD +
augeas.Augeas.NO_MODL_AUTOLOAD)
self.aug.set('/augeas/load/Properties/lens', 'Properties.lns')
self.aug.set('/augeas/load/Properties/incl[last() + 1]',
self.conf_filename)
self.aug.load()
return self
def write_conf(self):
"""Write changes to the configuration file to disk.
Chainable method.
"""
self.aug.save()
return self
@property
def favorite_property(self):
"""Return the favourites property from configuration file."""
return '/files{filename}/{prop}'.format(filename=self.conf_filename,
prop=self.FAVORITE_PROP)
def add_favorite(self, name, url, description=None, icon=None):
"""Add a favorite to the router configuration file.
Favorites are in a single string and separated by ','. none of the
incoming params can therefore use commas. I2P replaces the commas by
dots.
That's ok for the name and description, but not for the url and icon.
:type name: basestring
:type url: basestring
:type description: basestring
:type icon: basestring
"""
if not description:
description = ''
if not icon:
icon = '/themes/console/images/eepsite.png'
if ',' in url:
raise ValueError('URL cannot contain commas')
if ',' in icon:
raise ValueError('Icon cannot contain commas')
name = name.replace(',', '.')
description = description.replace(',', '.')
prop = self.favorite_property
favorites = self.aug.get(prop) or ''
new_favorite = '{name},{description},{url},{icon},'.format(
name=name, description=description, url=url, icon=icon)
self.aug.set(prop, favorites + new_favorite)
return self
def get_favorites(self):
"""Return list of favorites."""
favs_string = self.aug.get(self.favorite_property) or ''
favs_split = favs_string.split(',')
# There's a trailing comma --> 1 extra
favs_len = len(favs_split)
if favs_len > 0:
favs_split = favs_split[:-1]
favs_len = len(favs_split)
if favs_len % self.FAVORITE_TUPLE_SIZE:
raise SyntaxError("Invalid number of fields in favorite line")
favs = OrderedDict()
for index in range(0, favs_len, self.FAVORITE_TUPLE_SIZE):
next_index = index + self.FAVORITE_TUPLE_SIZE
name, description, url, icon = favs_split[index:next_index]
favs[url] = {
'name': name,
'description': description,
'icon': icon
}
return favs

View File

@ -1,43 +0,0 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
"""
Application manifest for I2P.
"""
from django.utils.translation import gettext_lazy as _
_package_id = 'net.geti2p.i2p'
_download_url = 'https://geti2p.net/download'
clients = [{
'name':
_('I2P'),
'platforms': [{
'type': 'web',
'url': '/i2p/'
}, {
'type': 'package',
'format': 'deb',
'name': 'i2p',
}, {
'type': 'download',
'os': 'gnu-linux',
'url': _download_url,
}, {
'type': 'download',
'os': 'macos',
'url': _download_url,
}, {
'type': 'download',
'os': 'windows',
'url': _download_url,
}]
}]
backup = {
'secrets': {
'directories': ['/var/lib/i2p/i2p-config']
},
'services': ['i2p']
}
tags = [_('Anonymity network'), _('Censorship resistance')]

View File

@ -1,24 +0,0 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
"""Configure I2P."""
from plinth.actions import privileged
from plinth.modules.i2p.helpers import RouterEditor, TunnelEditor
@privileged
def set_tunnel_property(name: str, property_: str, value: str):
"""Modify the configuration file for a certain tunnel."""
editor = TunnelEditor()
editor \
.read_conf() \
.set_tunnel_idx(name) \
.set_tunnel_prop(property_, value) \
.write_conf()
@privileged
def add_favorite(name: str, url: str, description: str | None,
icon: str | None):
"""Add a favorite to router.config."""
editor = RouterEditor()
editor.read_conf().add_favorite(name, url, description, icon).write_conf()

Some files were not shown because too many files have changed in this diff Show More