mirror of
https://github.com/freedombox/FreedomBox.git
synced 2026-02-04 08:13:38 +00:00
Release v19.24 to unstable
-----BEGIN PGP SIGNATURE----- iQJKBAABCgA0FiEEfWrbdQ+RCFWJSEvmd8DHXntlCAgFAl4KsAYWHGp2YWxsZXJv eUBtYWlsYm94Lm9yZwAKCRB3wMdee2UICCKJD/9/dh/L75e42MfAFFr07PrjLWQt zQQPvHLYZysuBoVEJ2Jbgz5vY74Q/YQ4cWGyP0TJ4if5WRDcv6sdonqRnPbpRsyY Y61JaZwQs5brWz9t6jSlomqo/AQwtjCQaFGYqcpnCxbk3MXdeSwDjpC9NP36lhZo vYnmYTMcPruqQDwnBYQETQMYQ5Eb2Q1SzE/RWemcwSmQg21ZYTv2h3/S1q8zhPHq 5Ysl81RLsdNow7nJG6BXexjFtR8E50tRGAJPgg+v9IutIs1KvnjpnMdC3Juzbsi1 T0ZYh0XnQRiMp6U7buPHmKUTzeAoUd2qmX3ZJd0kV2jfINuoGD3Xbwdl2w0OQJLY eXTvG+tjAOfa/UjKlufvZGcTvDFVkrTKl9saIUg0EkaeZWtgJt+4XfvKLsx7lF7e SosAmFgZYPYVN5caJKx/R///okbkihL04cB1y1Pe1bHBt5mLJM4a2V94Dpy9cPEk 1pclp9lPe5fiNQAUuOsqYE/DzrjMO2+5wA7XQypD4nV6TwzDKNHN1e6eMJVI1jaf Qq5isdqMlshp9IWlhxg6FYs5XAFZejIjU9EP2QsTtcRT7Y0DcRt91TdiBwRwYUIy 1v0BhsfbUbkKWCOvq1mL6YrIS2/A5GHsYI+1cEit8mf5vdZSVDjOMs6pwXtmSrD7 KezjorZHWyPI8gQMBQ== =uGVf -----END PGP SIGNATURE----- gpgsig -----BEGIN PGP SIGNATURE----- iQJKBAABCgA0FiEEfWrbdQ+RCFWJSEvmd8DHXntlCAgFAl4OmGkWHGp2YWxsZXJv eUBtYWlsYm94Lm9yZwAKCRB3wMdee2UICJkNEACcr8CPofqc+2FQywqBN6EeYX8s W3Z867JtL0VNHnIYYvlZmaxEyhQP9cSZ6chrezayHTABLzKTIhNfd+vJUJlXcjyo ZZ7qKjMN14ZK9DE8WpWjwh09cyD068yBZI53YhdVExQu3Gt+fBMFW1a1OXJdSfEd FH+DMqpc2zJnKR9MJ0CH4+3A8BphV/MxDzzUYnpE0qK1zSQtYnARRGwLx9Fbcpx8 yIAojkARz+PZ1vhQi9vaYbzyZX5my0b+0cCexb8bgSZul89kLSomQNPGTcyd9wPP +BE18uFXOA1DeJuD5Mfkm9pEh3tWwWuR+t8Fq/QP9OILVISryo0Ys8h29QjRPsnb jdCNiQka6KRrmqZL/+XUHs9A1aGsDZUXneqd5Ith4TgdHsaxaZRmD0wWuuljJE1n JIVULCvXgxbzIC3gu+mSDZq0dGHRG2u2b/B31+vMjKfQFPxoPyL86O2e37kCuiL0 4sNmd0R2OOM1w+sLlh2/E9JSviWwmcn7budKEpNSQFphrkwoz7NEbDhaeZ1CWRVh 0TbyPPw6iCVA6peHt1pJh6qO9kh3hV6QZCKqcvMpsoNCucpjEK9ZniPyKQpcLOhm qdhFZz6NIWZY20EenPZmBv667MSkrdrX7p7JD02w/M52oLCji6aPSm+Q5kNNqOhm BR29egi7Yz3h+bJYnw== =QTqM -----END PGP SIGNATURE----- Merge tag 'v19.24' into debian/buster-backports Release v19.24 to unstable Signed-off-by: James Valleroy <jvalleroy@mailbox.org>
This commit is contained in:
commit
75755b5df3
@ -22,7 +22,7 @@ run-unit-tests:
|
||||
- cp -r . /home/tester/plinth
|
||||
- chown -R tester:tester /home/tester/plinth
|
||||
- su -c "cd ~/plinth; python3 -m flake8 --exclude actions/domainname-change,actions/dynamicdns,actions/hostname-change,actions/networks plinth actions/*" tester
|
||||
- su -c "cd ~/plinth; py.test-3 --cov=plinth --cov-report=html:/home/tester/plinth/htmlcov --cov-report=term" tester
|
||||
- su -c "cd ~/plinth;PYTHONPATH='.' py.test-3 --cov=plinth --cov-report=html:/home/tester/plinth/htmlcov --cov-report=term" tester
|
||||
- cp -r /home/tester/plinth/htmlcov test-coverage-report
|
||||
|
||||
coverage: '/^TOTAL\s+.*\s+(\d+\.\d+%)$/'
|
||||
|
||||
@ -38,6 +38,20 @@ ExecStart=bash -c "/usr/bin/deluge-web --base=deluge $(/usr/bin/deluge-web --ver
|
||||
Restart=on-failure
|
||||
User=debian-deluged
|
||||
Group=debian-deluged
|
||||
LockPersonality=yes
|
||||
NoNewPrivileges=yes
|
||||
PrivateDevices=yes
|
||||
PrivateTmp=yes
|
||||
PrivateUsers=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
|
||||
|
||||
@ -94,6 +94,24 @@ After=network.target
|
||||
User=infinoted
|
||||
Group=infinoted
|
||||
ExecStart=/usr/bin/infinoted
|
||||
ConfigurationDirectory=infinoted
|
||||
ConfigurationDirectoryMode=0750
|
||||
LockPersonality=yes
|
||||
NoNewPrivileges=yes
|
||||
PrivateDevices=yes
|
||||
PrivateMounts=yes
|
||||
PrivateTmp=yes
|
||||
PrivateUsers=yes
|
||||
ProtectControlGroups=yes
|
||||
ProtectHome=yes
|
||||
ProtectKernelLogs=yes
|
||||
ProtectKernelModules=yes
|
||||
ProtectKernelTunables=yes
|
||||
ProtectSystem=full
|
||||
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
|
||||
RestrictRealtime=yes
|
||||
StateDirectory=infinoted
|
||||
SystemCallArchitectures=native
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@ -130,11 +148,10 @@ def subcommand_setup(_):
|
||||
with open(CONF_PATH, 'w') as file_handle:
|
||||
file_handle.write(CONF)
|
||||
|
||||
if not os.path.isfile(SYSTEMD_SERVICE_PATH):
|
||||
with open(SYSTEMD_SERVICE_PATH, 'w') as file_handle:
|
||||
file_handle.write(SYSTEMD_SERVICE)
|
||||
with open(SYSTEMD_SERVICE_PATH, 'w') as file_handle:
|
||||
file_handle.write(SYSTEMD_SERVICE)
|
||||
|
||||
subprocess.check_call(['systemctl', 'daemon-reload'])
|
||||
subprocess.check_call(['systemctl', 'daemon-reload'])
|
||||
|
||||
# Create infinoted group if needed.
|
||||
try:
|
||||
|
||||
@ -25,7 +25,7 @@ import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
from plinth.utils import generate_password, grep
|
||||
from plinth.utils import generate_password
|
||||
|
||||
MAINTENANCE_SCRIPTS_DIR = "/usr/share/mediawiki/maintenance"
|
||||
CONF_FILE = '/etc/mediawiki/FreedomBoxSettings.php'
|
||||
@ -87,12 +87,30 @@ def subcommand_setup(_):
|
||||
|
||||
|
||||
def include_custom_config():
|
||||
"""Include FreedomBox specific configuration in LocalSettings.php
|
||||
"""
|
||||
if not grep(r'FreedomBoxSettings', LOCAL_SETTINGS_CONF):
|
||||
with open(LOCAL_SETTINGS_CONF, 'a') as conf_file:
|
||||
conf_file.write(
|
||||
'include dirname(__FILE__)."/FreedomBoxSettings.php";\n')
|
||||
"""Include FreedomBox specific configuration in LocalSettings.php."""
|
||||
with open(LOCAL_SETTINGS_CONF, 'r') as conf_file:
|
||||
lines = conf_file.readlines()
|
||||
|
||||
static_settings_index = None
|
||||
settings_index = None
|
||||
for line_number, line in enumerate(lines):
|
||||
if 'FreedomBoxSettings.php' in line:
|
||||
settings_index = line_number
|
||||
|
||||
if 'FreedomBoxStaticSettings.php' in line:
|
||||
static_settings_index = line_number
|
||||
|
||||
if settings_index is None:
|
||||
settings_index = len(lines)
|
||||
lines.append('include dirname(__FILE__)."/FreedomBoxSettings.php";\n')
|
||||
|
||||
if static_settings_index is None:
|
||||
lines.insert(
|
||||
settings_index,
|
||||
'include dirname(__FILE__)."/FreedomBoxStaticSettings.php";\n')
|
||||
|
||||
with open(LOCAL_SETTINGS_CONF, 'w') as conf_file:
|
||||
conf_file.writelines(lines)
|
||||
|
||||
|
||||
def subcommand_change_password(arguments):
|
||||
@ -110,7 +128,7 @@ def subcommand_change_password(arguments):
|
||||
def subcommand_update(_):
|
||||
"""Run update.php maintenance script when version upgrades happen."""
|
||||
update_script = os.path.join(MAINTENANCE_SCRIPTS_DIR, 'update.php')
|
||||
subprocess.check_call(['php', update_script])
|
||||
subprocess.check_call(['php', update_script, '--quick'])
|
||||
|
||||
|
||||
def subcommand_public_registrations(arguments):
|
||||
|
||||
140
actions/samba
140
actions/samba
@ -51,11 +51,11 @@ CONF = r'''
|
||||
logging = file
|
||||
panic action = /usr/share/samba/panic-action %d
|
||||
server role = standalone server
|
||||
obey pam restrictions = yes
|
||||
unix password sync = yes
|
||||
passwd program = /usr/bin/passwd %u
|
||||
passwd chat = *Enter\snew\s*\spassword:* %n\n *Retype\snew\s*\spassword:* %n\n *password\supdated\ssuccessfully* .
|
||||
pam password change = yes
|
||||
#obey pam restrictions = yes
|
||||
#unix password sync = yes
|
||||
#passwd program = /usr/bin/passwd %u
|
||||
#passwd chat = *Enter\snew\s*\spassword:* %n\n *Retype\snew\s*\spassword:* %n\n *password\supdated\ssuccessfully* .
|
||||
#pam password change = yes
|
||||
map to guest = bad user
|
||||
# connection inactivity timeout in minutes
|
||||
deadtime = 5
|
||||
@ -73,9 +73,13 @@ def parse_arguments():
|
||||
|
||||
subparsers.add_parser('get-shares', help='Get configured samba shares')
|
||||
|
||||
subparsers.add_parser('get-users', help='Get users from Samba database')
|
||||
|
||||
subparser = subparsers.add_parser('add-share', help='Add new samba share')
|
||||
subparser.add_argument('--mount-point', help='Path of the mount point',
|
||||
required=True)
|
||||
subparser.add_argument('--share-type', help='Type of the share',
|
||||
required=True, choices=['open', 'group', 'home'])
|
||||
subparser.add_argument('--windows-filesystem', required=False,
|
||||
default=False, action='store_true',
|
||||
help='Path is Windows filesystem')
|
||||
@ -84,6 +88,8 @@ def parse_arguments():
|
||||
'delete-share', help='Delete a samba share configuration')
|
||||
subparser.add_argument('--mount-point', help='Path of the mount point',
|
||||
required=True)
|
||||
subparser.add_argument('--share-type', help='Type of the share',
|
||||
required=True, choices=['open', 'group', 'home'])
|
||||
|
||||
subparsers.add_parser('dump-shares',
|
||||
help='Dump share configuration to file')
|
||||
@ -104,20 +110,38 @@ def _conf_command(parameters, **kwargs):
|
||||
subprocess.check_call(['net', 'conf'] + parameters, **kwargs)
|
||||
|
||||
|
||||
def _create_share(mount_point, windows_filesystem=False):
|
||||
"""Create a samba share."""
|
||||
def _create_share(mount_point, share_type, windows_filesystem=False):
|
||||
"""Create samba public, group and private shares."""
|
||||
if share_type == 'open':
|
||||
subdir = 'open_share'
|
||||
elif share_type == 'group':
|
||||
subdir = 'group_share'
|
||||
elif share_type == 'home':
|
||||
subdir = 'homes'
|
||||
|
||||
shares_path = _get_shares_path(mount_point)
|
||||
open_share_path = os.path.join(mount_point, shares_path, 'open_share')
|
||||
os.makedirs(open_share_path, exist_ok=True)
|
||||
share_path = os.path.join(mount_point, shares_path, subdir)
|
||||
os.makedirs(share_path, exist_ok=True)
|
||||
|
||||
_make_mounts_readable_by_others(mount_point)
|
||||
|
||||
# FAT and NTFS partitions don't support setting permissions
|
||||
if not windows_filesystem:
|
||||
_set_open_share_permissions(open_share_path)
|
||||
if share_type in ['open', 'group']:
|
||||
_set_share_permissions(share_path)
|
||||
else:
|
||||
shutil.chown(share_path, group='users')
|
||||
os.chmod(share_path, 0o0775)
|
||||
|
||||
share_name = _create_share_name(mount_point)
|
||||
_define_open_share(share_name, open_share_path, windows_filesystem)
|
||||
|
||||
if share_type == 'open':
|
||||
_define_open_share(share_name, share_path, windows_filesystem)
|
||||
elif share_type == 'group':
|
||||
_define_group_share(share_name + '_group', share_path,
|
||||
windows_filesystem)
|
||||
elif share_type == 'home':
|
||||
_define_homes_share(share_name + '_home', share_path)
|
||||
|
||||
|
||||
def _create_share_name(mount_point):
|
||||
@ -141,17 +165,40 @@ def _define_open_share(name, path, windows_filesystem=False):
|
||||
_conf_command(['setparm', name, 'inherit permissions', 'yes'])
|
||||
|
||||
|
||||
def _define_group_share(name, path, windows_filesystem=False):
|
||||
"""Define a group samba share."""
|
||||
try:
|
||||
_conf_command(['delshare', name], stderr=subprocess.DEVNULL)
|
||||
except subprocess.CalledProcessError:
|
||||
pass
|
||||
_conf_command(['addshare', name, path, 'writeable=y', 'guest_ok=n'])
|
||||
_conf_command(['setparm', name, 'valid users', '@freedombox-share @admin'])
|
||||
if not windows_filesystem:
|
||||
_conf_command(['setparm', name, 'force group', 'freedombox-share'])
|
||||
_conf_command(['setparm', name, 'inherit permissions', 'yes'])
|
||||
|
||||
|
||||
def _define_homes_share(name, path):
|
||||
"""Define a samba share for private homes."""
|
||||
try:
|
||||
_conf_command(['delshare', name], stderr=subprocess.DEVNULL)
|
||||
except subprocess.CalledProcessError:
|
||||
pass
|
||||
userpath = os.path.join(path, '%u')
|
||||
_conf_command(['addshare', name, userpath, 'writeable=y', 'guest_ok=n'])
|
||||
_conf_command(['setparm', name, 'valid users', '@freedombox-share @admin'])
|
||||
_conf_command(
|
||||
['setparm', name, 'preexec', 'mkdir -p -m 755 {}'.format(userpath)])
|
||||
|
||||
|
||||
def _get_mount_point(path):
|
||||
"""Get the mount point where the share is."""
|
||||
subpath = 'FreedomBox/shares/'
|
||||
if '/var/lib/freedombox/shares/' in path:
|
||||
try:
|
||||
# test whether var directory is a mount point
|
||||
_validate_mount_point(path.split('lib/freedombox/shares/')[0])
|
||||
except RuntimeError:
|
||||
subpath = 'var/lib/freedombox/shares/'
|
||||
else:
|
||||
if os.path.ismount(path.split('lib/freedombox/shares/')[0]):
|
||||
subpath = 'lib/freedombox/shares/'
|
||||
else:
|
||||
subpath = 'var/lib/freedombox/shares/'
|
||||
|
||||
return path.split(subpath)[0]
|
||||
|
||||
@ -160,13 +207,20 @@ def _get_shares():
|
||||
"""Get shares."""
|
||||
shares = []
|
||||
output = subprocess.check_output(['net', 'conf', 'list'])
|
||||
config = configparser.ConfigParser()
|
||||
config = configparser.RawConfigParser()
|
||||
config.read_string(output.decode())
|
||||
for name in config.sections():
|
||||
path = config[name]['path']
|
||||
mount_point = _get_mount_point(path)
|
||||
share_type = 'open'
|
||||
if name.endswith('_group'):
|
||||
share_type = 'group'
|
||||
elif name.endswith('_home'):
|
||||
share_type = 'home'
|
||||
share_path = config[name]['path']
|
||||
mount_point = _get_mount_point(share_path)
|
||||
mount_point = os.path.normpath(mount_point)
|
||||
shares.append(dict(name=name, mount_point=mount_point, path=path))
|
||||
shares.append(
|
||||
dict(name=name, mount_point=mount_point, path=share_path,
|
||||
share_type=share_type))
|
||||
|
||||
return shares
|
||||
|
||||
@ -221,19 +275,31 @@ def _use_config_file(conf_file):
|
||||
aug.save()
|
||||
|
||||
|
||||
def _validate_mount_point(path):
|
||||
"""Validate that given path string is a mount point."""
|
||||
if path != '/':
|
||||
parent_path = os.path.dirname(path)
|
||||
if os.stat(path).st_dev == os.stat(parent_path).st_dev:
|
||||
raise RuntimeError('Path "{0}" is not a mount point.'.format(path))
|
||||
def _set_share_permissions(directory):
|
||||
"""Set file and directory permissions for a share."""
|
||||
shutil.chown(directory, group='freedombox-share')
|
||||
os.chmod(directory, 0o2775)
|
||||
for root, dirs, files in os.walk(directory):
|
||||
for subdir in dirs:
|
||||
subdir_path = os.path.join(root, subdir)
|
||||
shutil.chown(subdir_path, group='freedombox-share')
|
||||
os.chmod(subdir_path, 0o2775)
|
||||
for file in files:
|
||||
file_path = os.path.join(root, file)
|
||||
shutil.chown(file_path, group='freedombox-share')
|
||||
os.chmod(file_path, 0o0664)
|
||||
subprocess.check_call(['setfacl', '-Rm', 'g::rwX', directory])
|
||||
subprocess.check_call(['setfacl', '-Rdm', 'g::rwX', directory])
|
||||
|
||||
|
||||
def subcommand_add_share(arguments):
|
||||
"""Create a samba share."""
|
||||
mount_point = os.path.normpath(arguments.mount_point)
|
||||
_validate_mount_point(mount_point)
|
||||
_create_share(mount_point, arguments.windows_filesystem)
|
||||
if not os.path.ismount(mount_point):
|
||||
raise RuntimeError(
|
||||
'Path "{0}" is not a mount point.'.format(mount_point))
|
||||
_create_share(mount_point, arguments.share_type,
|
||||
arguments.windows_filesystem)
|
||||
|
||||
|
||||
def subcommand_delete_share(arguments):
|
||||
@ -241,13 +307,10 @@ def subcommand_delete_share(arguments):
|
||||
mount_point = os.path.normpath(arguments.mount_point)
|
||||
shares = _get_shares()
|
||||
for share in shares:
|
||||
if share['mount_point'] == mount_point:
|
||||
if share['mount_point'] == mount_point and share[
|
||||
'share_type'] == arguments.share_type:
|
||||
_close_share(share['name'])
|
||||
_conf_command(['delshare', share['name']])
|
||||
break
|
||||
else:
|
||||
raise RuntimeError(
|
||||
'Mount point "{0}" is not shared.'.format(mount_point))
|
||||
|
||||
|
||||
def subcommand_get_shares(_):
|
||||
@ -255,11 +318,20 @@ def subcommand_get_shares(_):
|
||||
print(json.dumps(_get_shares()))
|
||||
|
||||
|
||||
def subcommand_get_users(_):
|
||||
"""Get users from Samba database."""
|
||||
output = subprocess.check_output(['pdbedit', '-L']).decode()
|
||||
samba_users = [line.split(':')[0] for line in output.split()]
|
||||
print(json.dumps({'users': samba_users}))
|
||||
|
||||
|
||||
def subcommand_setup(_):
|
||||
"""Configure samba, use custom samba config file."""
|
||||
with open(CONF_PATH, 'w') as file_handle:
|
||||
file_handle.write(CONF)
|
||||
_use_config_file(CONF_PATH)
|
||||
os.makedirs('/var/lib/freedombox', exist_ok=True)
|
||||
os.chmod('/var/lib/freedombox', 0o0755)
|
||||
if action_utils.service_is_running('smbd'):
|
||||
action_utils.service_restart('smbd')
|
||||
|
||||
|
||||
@ -26,7 +26,7 @@ import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
from plinth import action_utils
|
||||
from plinth.modules.apache.components import check_url
|
||||
|
||||
AUTO_CONF_FILE = '/etc/apt/apt.conf.d/20auto-upgrades'
|
||||
LOG_FILE = '/var/log/unattended-upgrades/unattended-upgrades.log'
|
||||
@ -129,8 +129,7 @@ def _is_release_file_available(protocol):
|
||||
if protocol == 'tor+http':
|
||||
wrapper = 'torsocks'
|
||||
|
||||
result = action_utils.check_url(BUSTER_BACKPORTS_RELEASE_FILE_URL,
|
||||
wrapper=wrapper)
|
||||
result = check_url(BUSTER_BACKPORTS_RELEASE_FILE_URL, wrapper=wrapper)
|
||||
return result == 'passed'
|
||||
|
||||
|
||||
|
||||
@ -27,7 +27,6 @@ import subprocess
|
||||
import sys
|
||||
|
||||
import augeas
|
||||
|
||||
from plinth import action_utils
|
||||
|
||||
ACCESS_CONF = '/etc/security/access.conf'
|
||||
@ -80,6 +79,12 @@ def parse_arguments():
|
||||
subparser.add_argument('username', help='LDAP user to add to group')
|
||||
subparser.add_argument('groupname', help='LDAP group to add the user to')
|
||||
|
||||
subparser = subparsers.add_parser('set-user-status',
|
||||
help='Set user as active or inactive')
|
||||
subparser.add_argument('username', help='User to change status')
|
||||
subparser.add_argument('status', choices=['active', 'inactive'],
|
||||
help='New status of the user')
|
||||
|
||||
subparser = subparsers.add_parser(
|
||||
'remove-user-from-group',
|
||||
help='Remove an LDAP user from an LDAP group')
|
||||
@ -210,8 +215,8 @@ def configure_ldapscripts():
|
||||
# modify a copy of the config file
|
||||
shutil.copy('/etc/ldapscripts/ldapscripts.conf', LDAPSCRIPTS_CONF)
|
||||
|
||||
aug = augeas.Augeas(flags=augeas.Augeas.NO_LOAD +
|
||||
augeas.Augeas.NO_MODL_AUTOLOAD)
|
||||
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]', LDAPSCRIPTS_CONF)
|
||||
aug.load()
|
||||
@ -227,6 +232,30 @@ def configure_ldapscripts():
|
||||
aug.save()
|
||||
|
||||
|
||||
def get_samba_users():
|
||||
"""Get users from the Samba user database."""
|
||||
# 'pdbedit -L' is better for listing users but is installed only with samba
|
||||
stdout = subprocess.check_output(
|
||||
['tdbdump', '/var/lib/samba/private/passdb.tdb']).decode()
|
||||
return re.findall(r'USER_(.*)\\0', stdout)
|
||||
|
||||
|
||||
def delete_samba_user(username):
|
||||
"""Delete a Samba user."""
|
||||
if username in get_samba_users():
|
||||
subprocess.check_call(['smbpasswd', '-x', username])
|
||||
disconnect_samba_user(username)
|
||||
|
||||
|
||||
def disconnect_samba_user(username):
|
||||
"""Disconnect a Samba user."""
|
||||
try:
|
||||
subprocess.check_call(['pkill', '-U', username, 'smbd'])
|
||||
except subprocess.CalledProcessError as error:
|
||||
if error.returncode != 1:
|
||||
raise
|
||||
|
||||
|
||||
def read_password():
|
||||
"""Read the password from stdin."""
|
||||
return ''.join(sys.stdin)
|
||||
@ -235,8 +264,10 @@ def read_password():
|
||||
def subcommand_create_user(arguments):
|
||||
"""Create an LDAP user, set password and flush cache."""
|
||||
_run(['ldapadduser', arguments.username, 'users'])
|
||||
set_user_password(arguments.username, read_password())
|
||||
password = read_password()
|
||||
set_user_password(arguments.username, password)
|
||||
flush_cache()
|
||||
set_samba_user(arguments.username, password)
|
||||
|
||||
|
||||
def subcommand_remove_user(arguments):
|
||||
@ -244,10 +275,13 @@ def subcommand_remove_user(arguments):
|
||||
username = arguments.username
|
||||
groups = get_user_groups(username)
|
||||
|
||||
delete_samba_user(username)
|
||||
|
||||
for group in groups:
|
||||
remove_user_from_group(username, group)
|
||||
|
||||
_run(['ldapdeleteuser', username])
|
||||
|
||||
flush_cache()
|
||||
|
||||
|
||||
@ -257,6 +291,8 @@ def subcommand_rename_user(arguments):
|
||||
new_username = arguments.newusername
|
||||
groups = get_user_groups(old_username)
|
||||
|
||||
delete_samba_user(old_username)
|
||||
|
||||
for group in groups:
|
||||
remove_user_from_group(old_username, group)
|
||||
|
||||
@ -275,9 +311,25 @@ def set_user_password(username, password):
|
||||
_run(['ldapsetpasswd', username, password])
|
||||
|
||||
|
||||
def set_samba_user(username, password):
|
||||
"""Insert a user to the Samba database.
|
||||
|
||||
If a user already exists, update password.
|
||||
"""
|
||||
proc = subprocess.Popen(['smbpasswd', '-a', '-s', username],
|
||||
stdin=subprocess.PIPE, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
_, stderr = proc.communicate(input='{0}\n{0}\n'.format(password).encode(),
|
||||
timeout=10)
|
||||
if proc.returncode != 0:
|
||||
raise RuntimeError('Unable to add Samba user: ', stderr)
|
||||
|
||||
|
||||
def subcommand_set_user_password(arguments):
|
||||
"""Set a user's password."""
|
||||
set_user_password(arguments.username, read_password())
|
||||
password = read_password()
|
||||
set_user_password(arguments.username, password)
|
||||
set_samba_user(arguments.username, password)
|
||||
|
||||
|
||||
def get_user_groups(username):
|
||||
@ -352,6 +404,8 @@ def subcommand_remove_user_from_group(arguments):
|
||||
"""Remove an LDAP user from an LDAP group."""
|
||||
remove_user_from_group(arguments.username, arguments.groupname)
|
||||
flush_cache()
|
||||
if arguments.groupname == 'freedombox-share':
|
||||
disconnect_samba_user(arguments.username)
|
||||
|
||||
|
||||
def subcommand_get_group_users(arguments):
|
||||
@ -369,6 +423,22 @@ def subcommand_get_group_users(arguments):
|
||||
print(user)
|
||||
|
||||
|
||||
def subcommand_set_user_status(arguments):
|
||||
"""Set the status of the user."""
|
||||
username = arguments.username
|
||||
status = arguments.status
|
||||
|
||||
if status == 'active':
|
||||
flag = '-e'
|
||||
else:
|
||||
flag = '-d'
|
||||
|
||||
if username in get_samba_users():
|
||||
subprocess.check_call(['smbpasswd', flag, username])
|
||||
if status == 'inactive':
|
||||
disconnect_samba_user(username)
|
||||
|
||||
|
||||
def flush_cache():
|
||||
"""Flush nscd and apache2 cache."""
|
||||
_run(['nscd', '--invalidate=passwd'])
|
||||
|
||||
@ -71,6 +71,13 @@ def fixture_needs_root():
|
||||
pytest.skip('Needs to be root')
|
||||
|
||||
|
||||
@pytest.fixture(name='needs_not_root', scope='session')
|
||||
def fixture_needs_not_root():
|
||||
"""Skip test if running in root mode."""
|
||||
if os.geteuid() == 0:
|
||||
pytest.skip('Needs not to be root')
|
||||
|
||||
|
||||
@pytest.fixture(name='needs_sudo')
|
||||
def fixture_needs_sudo():
|
||||
"""Skip test if sudo command is not available."""
|
||||
|
||||
70
debian/changelog
vendored
70
debian/changelog
vendored
@ -1,3 +1,73 @@
|
||||
plinth (19.24) unstable; urgency=medium
|
||||
|
||||
[ Thomas Vincent ]
|
||||
* Translated using Weblate (French)
|
||||
* Translated using Weblate (French)
|
||||
|
||||
[ Veiko Aasa ]
|
||||
* app: Fix javascript doesn't run on first visit
|
||||
* samba: private shares
|
||||
* storage: Tests for the directory validation action
|
||||
* users: Add tests for the Samba user database
|
||||
|
||||
[ James Valleroy ]
|
||||
* samba: Fix spelling in description
|
||||
* debian: Update French debconf translation (Closes: #947386)
|
||||
- Thanks to Jean-Pierre Giraud for the patch.
|
||||
* firewall: Support upgrading firewalld to 0.8
|
||||
* mldonkey: Add ProtectKernelLogs
|
||||
* deluge: Use systemd sandboxing features
|
||||
* infinoted: Use systemd sandboxing features
|
||||
* storage: Add systemd sandboxing features to udiskie service
|
||||
* upgrades: Add systemd sandboxing features to repository setup service
|
||||
* security: List whether each app is sandboxed
|
||||
* locale: Update translation strings
|
||||
* debian: Update Dutch debconf translation (Closes: #947136)
|
||||
- Thanks to Frans Spiesschaert for the patch.
|
||||
* doc: Fetch latest manual
|
||||
|
||||
[ Michael Breidenbach ]
|
||||
* Translated using Weblate (German)
|
||||
* Translated using Weblate (Swedish)
|
||||
|
||||
[ Nektarios Katakis ]
|
||||
* Translated using Weblate (Greek)
|
||||
|
||||
[ Doma Gergő ]
|
||||
* Translated using Weblate (Hungarian)
|
||||
|
||||
[ Allan Nordhøy ]
|
||||
* Translated using Weblate (Norwegian Bokmål)
|
||||
|
||||
[ Kunal Mehta ]
|
||||
* mediawiki: Pass --quick when running update.php
|
||||
|
||||
[ Sunil Mohan Adapa ]
|
||||
* help: Refactor to move app into __init__.py for consistency
|
||||
* app: Introduce API to return a list of all apps
|
||||
* app: Introduce API to run diagnostics on an app
|
||||
* apache: Implement diagnostic test for web server component
|
||||
* daemon: Implement diagnostic test for daemon component
|
||||
* daemon: Implement diagnostic test to check if a daemon is running
|
||||
* firewall: Implement new diagnostic tests to check port status
|
||||
* diagnostics: Use new component based API for all diagnostic tests
|
||||
* cosmetic: Yapf and isort fixes
|
||||
* daemon: Move diagnosing port listening into daemon module
|
||||
* daemon: Move diagnosing using netcat to daemon module
|
||||
* apache: Move diagnostics for checking URLs into apache module
|
||||
* app: Implement API to check if app/component has diagnostics
|
||||
* views: Don't require sending diagnostics module name separately
|
||||
* minidlna: Fix showing clients information
|
||||
* mediawiki: Fix problem with session cache failing logins
|
||||
|
||||
[ Ralf Barkow ]
|
||||
* Translated using Weblate (German)
|
||||
|
||||
[ erlendnagel ]
|
||||
* Translated using Weblate (Dutch)
|
||||
|
||||
-- James Valleroy <jvalleroy@mailbox.org> Mon, 30 Dec 2019 21:17:58 -0500
|
||||
|
||||
plinth (19.23~bpo10+1) buster-backports; urgency=medium
|
||||
|
||||
* Rebuild for buster-backports.
|
||||
|
||||
12
debian/po/fr.po
vendored
12
debian/po/fr.po
vendored
@ -1,14 +1,14 @@
|
||||
# Translation of plinth debconf templates to French
|
||||
# Copyright (C) 2018 FreedomBox packaging team <freedombox-pkg-team@lists.alioth.debian.org>
|
||||
# This file is distributed under the same license as the plinth package.
|
||||
# Jean-Pierre Giraud <jean-pierregiraud@neuf.fr>, 2018.
|
||||
#
|
||||
# Jean-Pierre Giraud <jean-pierregiraud@neuf.fr>, 2018, 2019.
|
||||
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: 2018-07-30 23:19+0100\n"
|
||||
"PO-Revision-Date: 2019-12-16 10:23+0100\n"
|
||||
"Last-Translator: Jean-Pierre Giraud <jean-pierregiraud@neuf.fr>\n"
|
||||
"Language-Team: French <debian-l10n-french@lists.debian.org>\n"
|
||||
"Language: fr_FR\n"
|
||||
@ -27,7 +27,6 @@ msgstr "Phrase secrète du premier assistant de FreedomBox - ${secret}"
|
||||
#. Type: note
|
||||
#. Description
|
||||
#: ../templates:1001
|
||||
#, fuzzy
|
||||
#| msgid ""
|
||||
#| "Please save this string. You will be asked to enter this in the first "
|
||||
#| "screen after you launch the FreedomBox interface. In case you lose it, "
|
||||
@ -37,6 +36,7 @@ msgid ""
|
||||
"first screen after you launch the FreedomBox web interface. In case you lose "
|
||||
"it, you can retrieve it by running the following command:"
|
||||
msgstr ""
|
||||
"Veuillez retenir cette chaîne. Le premier écran après le chargement de "
|
||||
"l'interface de FreedomBox vous la demandera. Si vous l'avez oubliée, vous "
|
||||
"pourrez la retrouver dans le fichier /var/lib/plinth/firstboot-wizard-secret."
|
||||
"Veuillez noter cette phrase secrète. Le premier écran après le chargement de "
|
||||
"l'interface web de FreedomBox vous la demandera. Si vous l'avez oubliée, vous "
|
||||
"pourrez la récupérer en exécutant la commande suivante :"
|
||||
|
||||
|
||||
19
debian/po/nl.po
vendored
19
debian/po/nl.po
vendored
@ -6,10 +6,10 @@
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: plinth_0.34.0\n"
|
||||
"Project-Id-Version: plinth_19.21\n"
|
||||
"Report-Msgid-Bugs-To: plinth@packages.debian.org\n"
|
||||
"POT-Creation-Date: 2019-11-18 18:11-0500\n"
|
||||
"PO-Revision-Date: 2018-07-31 16:32+0200\n"
|
||||
"PO-Revision-Date: 2019-12-02 21:04+0100\n"
|
||||
"Last-Translator: Frans Spiesschaert <Frans.Spiesschaert@yucom.be>\n"
|
||||
"Language-Team: Debian Dutch l10n Team <debian-l10n-dutch@lists.debian.org>\n"
|
||||
"Language: nl\n"
|
||||
@ -17,7 +17,7 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Generator: Gtranslator 2.91.7\n"
|
||||
"X-Generator: Poedit 2.2.1\n"
|
||||
|
||||
#. Type: note
|
||||
#. Description
|
||||
@ -28,17 +28,12 @@ msgstr "Geheime code voor de initiële wizard van FreedomBox - ${secret}"
|
||||
#. Type: note
|
||||
#. Description
|
||||
#: ../templates:1001
|
||||
#, fuzzy
|
||||
#| msgid ""
|
||||
#| "Please save this string. You will be asked to enter this in the first "
|
||||
#| "screen after you launch the FreedomBox interface. In case you lose it, "
|
||||
#| "you can find it in the file /var/lib/plinth/firstboot-wizard-secret."
|
||||
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 ""
|
||||
"Bewaar deze tekenreeks. Er zal u gevraagd worden om ze in te voeren in het "
|
||||
"openingsscherm bij de eerste opstart van de FreedomBox-interface. In geval u "
|
||||
"ze kwijtraakt kunt u ze terugvinden in het bestand /var/lib/plinth/firstboot-"
|
||||
"wizard-secret."
|
||||
"Noteer bovenstaande geheime code. Er zal u gevraagd worden om ze in het "
|
||||
"openingsscherm in te voeren wanneer u de FreedomBox-interface opstart. In "
|
||||
"geval u ze kwijtraakt, kunt u ze terughalen door het volgende commando uit "
|
||||
"te voeren:"
|
||||
|
||||
@ -14,21 +14,6 @@ are loaded. The ``init()`` call order guarantees that other applications that
|
||||
this application depends on will be initialized before this application is
|
||||
initialized.
|
||||
|
||||
<app-module>.diagnose()
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Optional. Called when the user invokes system-wide diagnostics by visiting
|
||||
**System -> Diagnositcs**. This method must return an array of diagnostic
|
||||
results. Each diagnostic result must be a two-tuple with first element as a
|
||||
string that is shown to the user as name of the test and second element is the
|
||||
result of the test. It must be one of ``passed``, ``failed``, ``error``. Example
|
||||
return value:
|
||||
|
||||
.. code-block:: python3
|
||||
|
||||
[('Check http://localhost/app is reachable', 'passed'),
|
||||
('Check configuration is sane', 'passed')]
|
||||
|
||||
<app-module>.depends
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
||||
@ -26,14 +26,17 @@ our app's class.
|
||||
def __init__(self):
|
||||
...
|
||||
|
||||
daemon = Daemon('daemon-transmission', managed_services[0])
|
||||
daemon = Daemon('daemon-transmission', managed_services[0],
|
||||
listen_ports=[(9091, 'tcp4')])
|
||||
self.add(daemon)
|
||||
|
||||
|
||||
The first argument to instantiate the :class:`~plinth.daemon.Daemon` class is a
|
||||
unique ID. The second is the name of the `systemd
|
||||
<https://www.freedesktop.org/wiki/Software/systemd/>`_ unit file which manages
|
||||
the daemon.
|
||||
the daemon. The final argument is the list of ports that this daemon listens on.
|
||||
This information is used to check if the daemon is listening on the expected
|
||||
ports when the user requests diagnostic tests on the app.
|
||||
|
||||
Managing web server configuration
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -57,14 +60,18 @@ app. Let us do that in our app's class.
|
||||
def __init__(self):
|
||||
...
|
||||
|
||||
webserver = Webserver('webserver-transmission', 'transmission-plinth')
|
||||
webserver = Webserver('webserver-transmission', 'transmission-plinth'
|
||||
urls=['https://{host}/transmission'])
|
||||
self.add(webserver)
|
||||
|
||||
The first argument to instantiate the
|
||||
:class:`~plinth.modules.apache.components.Webserver` class is a unique ID. The
|
||||
second is the name of the Apache2 web server configuration snippet that contains
|
||||
the directives to proxy Transmission web interface via Apache2. We then need to
|
||||
create the configuration file itself in ``tranmission-freedombox.conf``.
|
||||
create the configuration file itself in ``tranmission-freedombox.conf``. The
|
||||
final argument is the list of URLs that the app exposes to the users of the app.
|
||||
This information is used to check if the URLs are accessible as expected when
|
||||
the user requests diagnostic tests on the app.
|
||||
|
||||
.. code-block:: apache
|
||||
|
||||
|
||||
@ -102,57 +102,38 @@ daemons should be stopped during the backup process. In ``__init__.py``, add:
|
||||
Creating diagnostics
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
When the app does not work as expected, the user should known what is happening
|
||||
with the app. The FreedomBox framework provides an API for running and showing
|
||||
diagnostics results. The app has to implement a method for actually running the
|
||||
diagnostics and return the results as a list. FreedomBox then takes care of
|
||||
When the app does not work as expected, the user should know what is happening
|
||||
with the app. FreedomBox framework provides an API for running and showing
|
||||
diagnostics results. Most of the common diagnostic tests are implemented by the
|
||||
framework as part of the components used by an app. FreedomBox takes care of
|
||||
calling the diagnostics method and displaying the list in a formatted manner.
|
||||
|
||||
To implement the diagnostics, a method called ``diagnose()`` has to be available
|
||||
as ``<app-module>.diagnose()``. It must return a list in which each item is the
|
||||
result of a test performed. The item itself is a two-tuple containing the
|
||||
display name of the test followed by the result as ``passed``, ``failed`` or
|
||||
``error``.
|
||||
To implement additional diagnostic tests on top of those provided by the
|
||||
framework, the method :meth:`plinth.app.App.diagnose` has to be overridden or in
|
||||
a component that belongs to the app, the method
|
||||
:meth:`plinth.app.Component.diagnose` has to be overridden. The methods must
|
||||
return a list in which each item is the result of a test performed. The item
|
||||
itself is a two-tuple containing the display name of the test followed by the
|
||||
result as ``passed``, ``failed`` or ``error``.
|
||||
|
||||
.. code-block:: python3
|
||||
|
||||
def diagnose():
|
||||
"""Run diagnostics and return the results."""
|
||||
results = []
|
||||
|
||||
results.extend(action_utils.diagnose_url_on_all(
|
||||
'https://{host}/transmission', extra_options=['--no-check-certificate']))
|
||||
|
||||
return results
|
||||
|
||||
Now that we have implemented diagnostics, we also need to show a diagnostics
|
||||
button in the App's page. Adding an attribute to the
|
||||
:class:`~plinth.views.AppView` will take care of this.
|
||||
|
||||
.. code-block:: python3
|
||||
|
||||
class TransmissionView(views.AppView):
|
||||
class TransmissionAppView(views.AppView):
|
||||
...
|
||||
diagnostics_module_name = 'transmission'
|
||||
def diagnose():
|
||||
"""Run diagnostics and return the results."""
|
||||
results = super().diagnose()
|
||||
|
||||
There are several helpers available to implement some of the common diagnostic
|
||||
tests. For our application we wish to implement a test to check whether the
|
||||
``/transmission`` URL is accessible. Since this is a commonly performed test,
|
||||
there is a helper method available and we have used it in the above code. The
|
||||
``{host}`` tag replaced with various IP addresses, hostnames and domain names by
|
||||
the helper to produce different kinds of URLs and they are all tested. Results
|
||||
for all tests are returned which we then pass on to the framework.
|
||||
results.append(['Example test', 'passed'])
|
||||
|
||||
return results
|
||||
|
||||
The user can trigger the diagnostics test by going to **System -> Diagnostics**
|
||||
page. This runs diagnostics for all the applications. Users can also run
|
||||
diagnostics specifically for this app from the app's page. A diagnostics button
|
||||
is shown by the `app.html` template automatically when
|
||||
``diagnostics_module_name`` attribute is set in the app's ``AppView`` derived
|
||||
from :obj:`plinth.views.AppView`.
|
||||
|
||||
.. code-block:: django
|
||||
|
||||
{% include "diagnostics_button.html" with module="ttrss" enabled=True %}
|
||||
diagnostics specifically for this app from the app's page. A diagnostics menu
|
||||
item is shown by the :class:`plinth.views.AppView` and `app.html` template
|
||||
automatically when ``diagnose()`` method is overridden in the app or a
|
||||
component.
|
||||
|
||||
Logging
|
||||
^^^^^^^
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
5
doc/manual/en/MiniDLNA.raw.xml
Normal file
5
doc/manual/en/MiniDLNA.raw.xml
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -4,6 +4,18 @@
|
||||
<articleinfo>
|
||||
<title>FreedomBox/Manual</title>
|
||||
<revhistory>
|
||||
<revision>
|
||||
<revnumber>80</revnumber>
|
||||
<date>2019-12-25 18:43:42</date>
|
||||
<authorinitials>Drahtseil</authorinitials>
|
||||
<revremark>added MiniDLNA</revremark>
|
||||
</revision>
|
||||
<revision>
|
||||
<revnumber>79</revnumber>
|
||||
<date>2019-12-20 19:58:30</date>
|
||||
<authorinitials>Drahtseil</authorinitials>
|
||||
<revremark>Placed Simple Gitweb in the correct place</revremark>
|
||||
</revision>
|
||||
<revision>
|
||||
<revnumber>78</revnumber>
|
||||
<date>2019-12-15 19:26:31</date>
|
||||
@ -1811,6 +1823,15 @@ echo 'select name from users' | sqlite3 /var/lib/matrix-synapse/homeserver.db ]
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>If you wish to create a community in Matrix Synapse, a Matrix user with server admin privileges is needed. Run the following commands: </para>
|
||||
<itemizedlist>
|
||||
<listitem override="none">
|
||||
<screen><![CDATA[sudo apt install sqlite3
|
||||
echo "UPDATE users SET admin=1 WHERE name='@username:domainname'" | sudo sqlite3 /var/lib/matrix-synapse/homeserver.db ]]></screen>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
</section>
|
||||
</section>
|
||||
@ -2351,6 +2372,31 @@ echo 'select name from users' | sqlite3 /var/lib/matrix-synapse/homeserver.db ]
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
<section>
|
||||
<title>MiniDLNA</title>
|
||||
<para>MiniDLNA is a media server with the aim to be compliant with DLNA/UPnP clients. </para>
|
||||
<section>
|
||||
<title>What is UPnP/DLNA?</title>
|
||||
<para>Universal plug & play is a set of networking protocols that allow devices within a network such as PCs, TVs, printers etc. to seamlessly discover each other and establish communication for data sharing. It is zero configuration protocol and requires only a media server and a media player that are compliant with the protocol. </para>
|
||||
<para>DLNA is derived from UPnP as a form of standardizing media interoperability. It forms a standard/certification which many consumer electronics conform to. </para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Setting up MiniDLNA on your FreedomBox.</title>
|
||||
<para>To install/enable the media server you need to navigate at MiniDLNA page and enable it. The application is intended to be available in the internal (home) network and therefore it requires a network interface configured for internal traffic. </para>
|
||||
<para>After installation a web page becomes available on <ulink url="https://<your-freedombox>/_minidlna"/>. It includes information for how many files the server is detecting, how many connections exist etc. This is very useful if plugging external disks with media to check if the new media files are detected properly. If that is not happening, disabling and enabling the server will fix it. </para>
|
||||
</section>
|
||||
<section>
|
||||
<title>File systems for external drives.</title>
|
||||
<para>If using an external drive that is used also from a Windows system the preferred filesystem should be NTFS. NTFS will keep Linux file permissions and UTF8 encoding for file names. This is useful if file names are in your language. </para>
|
||||
</section>
|
||||
<section>
|
||||
<title>External links</title>
|
||||
<para>
|
||||
<ulink url="http://minidlna.sourceforge.net/"/>
|
||||
<ulink url="https://en.wikipedia.org/wiki/Digital_Living_Network_Alliance"/>
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
<section>
|
||||
<title>News Feed Reader (Tiny Tiny RSS)</title>
|
||||
<para>Tiny Tiny RSS is a news feed (RSS/Atom) reader and aggregator, designed to allow reading news from any location, while feeling as close to a real desktop application as possible. </para>
|
||||
@ -2506,6 +2552,34 @@ echo 'select name from users' | sqlite3 /var/lib/matrix-synapse/homeserver.db ]
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
<section>
|
||||
<title>Simple Git Hosting (GitWeb)</title>
|
||||
<para>Git is a distributed version-control system for tracking changes in source code during software development. GitWeb provides a web interface to Git repositories. You can browse history and content of source code, use search to find relevant commits and code. You can also clone repositories and upload code changes with a command-line Git client or with multiple available graphical clients. And you can share your code with people around the world. </para>
|
||||
<para>To learn more on how to use Git visit <ulink url="https://git-scm.com/docs/gittutorial">Git tutorial</ulink>. </para>
|
||||
<para><emphasis role="strong">Available since version:</emphasis> 19.19 </para>
|
||||
<section>
|
||||
<title>Managing the repositories</title>
|
||||
<para>After installation of GitWeb, a new repository can be created. It can be marked as <emphasis>private</emphasis> to limit access. </para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Access</title>
|
||||
<para>GitWeb can be accessed after installation e.g. by the web client through <ulink url="https://<my"/> freedombox name>/gitweb </para>
|
||||
</section>
|
||||
<section>
|
||||
<title>HTTP basic auth</title>
|
||||
<para>GitWeb on FreedomBox currently supports HTTP remotes only. To avoid having to enter the password each time you pull/push to the repository, you can edit your remote to include the credentials. </para>
|
||||
<para>
|
||||
<emphasis>Example:</emphasis>
|
||||
<ulink url="https://username@password:my.freedombox.rocks/gitweb/myrepo"/>
|
||||
</para>
|
||||
<para>Your username and password will be encrypted. Someone monitoring the network traffic will notice the domain name only.</para>
|
||||
<para><emphasis role="strong">Note:</emphasis> If using this method, your password will be stored in plain text in the local repository's .git/config file. </para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Mirroring</title>
|
||||
<para>Though your repositories are primarily hosted on your own FreedomBox, you can configure a repository on another Git hosting system like <ulink url="https://wiki.debian.org/FreedomBox/Manual/GitLab#">GitLab</ulink> as a mirror. </para>
|
||||
</section>
|
||||
</section>
|
||||
<section>
|
||||
<title>SIP Server (repro)</title>
|
||||
<caution>
|
||||
@ -3119,34 +3193,6 @@ echo "newpassword" | su mumble-server -s /bin/sh -c "/usr/sbin/murmurd -ini /etc
|
||||
</itemizedlist>
|
||||
</section>
|
||||
</section>
|
||||
<section>
|
||||
<title>Simple Git Hosting (GitWeb)</title>
|
||||
<para>Git is a distributed version-control system for tracking changes in source code during software development. GitWeb provides a web interface to Git repositories. You can browse history and content of source code, use search to find relevant commits and code. You can also clone repositories and upload code changes with a command-line Git client or with multiple available graphical clients. And you can share your code with people around the world. </para>
|
||||
<para>To learn more on how to use Git visit <ulink url="https://git-scm.com/docs/gittutorial">Git tutorial</ulink>. </para>
|
||||
<para><emphasis role="strong">Available since version:</emphasis> 19.19 </para>
|
||||
<section>
|
||||
<title>Managing the repositories</title>
|
||||
<para>After installation of GitWeb, a new repository can be created. It can be marked as <emphasis>private</emphasis> to limit access. </para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Access</title>
|
||||
<para>GitWeb can be accessed after installation e.g. by the web client through <ulink url="https://<my"/> freedombox name>/gitweb </para>
|
||||
</section>
|
||||
<section>
|
||||
<title>HTTP basic auth</title>
|
||||
<para>GitWeb on FreedomBox currently supports HTTP remotes only. To avoid having to enter the password each time you pull/push to the repository, you can edit your remote to include the credentials. </para>
|
||||
<para>
|
||||
<emphasis>Example:</emphasis>
|
||||
<ulink url="https://username@password:my.freedombox.rocks/gitweb/myrepo"/>
|
||||
</para>
|
||||
<para>Your username and password will be encrypted. Someone monitoring the network traffic will notice the domain name only.</para>
|
||||
<para><emphasis role="strong">Note:</emphasis> If using this method, your password will be stored in plain text in the local repository's .git/config file. </para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Mirroring</title>
|
||||
<para>Though your repositories are primarily hosted on your own FreedomBox, you can configure a repository on another Git hosting system like <ulink url="https://wiki.debian.org/FreedomBox/Manual/GitLab#">GitLab</ulink> as a mirror. </para>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
<section>
|
||||
<title>System</title>
|
||||
@ -9990,6 +10036,50 @@ wget https://www.thinkpenguin.com/files/ath9k_firmware_free-version/htc_7010.fw]
|
||||
<section>
|
||||
<title>Release Notes</title>
|
||||
<para>The following are the release notes for each FreedomBox version. </para>
|
||||
<section>
|
||||
<title>FreedomBox 19.24 (2019-12-30)</title>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>app: Fix JavaScript doesn't run on first visit </para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>samba: Add private shares </para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>firewall: Support upgrading firewalld to 0.8 </para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>deluge: Add systemd sandboxing features </para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>infinoted: Add systemd sandboxing features </para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>storage: Add systemd sandboxing features to udiskie service </para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>upgrades: Add systemd sandboxing features to repository setup service </para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>security: List whether each app is sandboxed </para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>mediawiki: Avoid delay in update script </para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>diagnostics: Use new component based API for all diagnostic tests </para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>minidlna: Fix showing clients information </para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>mediawiki: Fix problem with session cache failing logins </para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>locale: Update translations for French, German, Swedish, Greek, Hungarian, Norwegian Bokmål, and Dutch </para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
<section>
|
||||
<title>FreedomBox 19.23 (2019-12-16)</title>
|
||||
<itemizedlist>
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
5
doc/manual/es/GitWeb.raw.xml
Normal file
5
doc/manual/es/GitWeb.raw.xml
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
5
doc/manual/es/MiniDLNA.raw.xml
Normal file
5
doc/manual/es/MiniDLNA.raw.xml
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user