mirror of
https://github.com/freedombox/FreedomBox.git
synced 2026-06-17 11:10:23 +00:00
bepasty: Add public access config form
Signed-off-by: James Valleroy <jvalleroy@mailbox.org> Reviewed-by: Sunil Mohan Adapa <sunil@medhas.org>
This commit is contained in:
parent
7edc2f4e13
commit
65f4b6750b
@ -9,6 +9,7 @@ import json
|
||||
import grp
|
||||
import os
|
||||
import pwd
|
||||
import re
|
||||
import secrets
|
||||
import shutil
|
||||
import string
|
||||
@ -30,6 +31,7 @@ PERMISSIONS = {{
|
||||
'{}': 'list,create,read,delete', # editor
|
||||
'{}': 'list,read', # viewer
|
||||
}}
|
||||
DEFAULT_PERMISSIONS = ''
|
||||
"""
|
||||
|
||||
PASSWORD_LENGTH = 20
|
||||
@ -64,6 +66,15 @@ def parse_arguments():
|
||||
remove_password.add_argument('--password', required=True,
|
||||
help='The password to be removed')
|
||||
|
||||
subparsers.add_parser('get-default', help='Get default permissions')
|
||||
|
||||
set_default = subparsers.add_parser('set-default',
|
||||
help='Set default permissions')
|
||||
set_default.add_argument(
|
||||
'--permissions', nargs='*',
|
||||
help='Any number of permissions from the set: {}'.format(', '.join(
|
||||
bepasty.PERMISSIONS.keys())))
|
||||
|
||||
subparsers.required = True
|
||||
return parser.parse_args()
|
||||
|
||||
@ -121,34 +132,25 @@ def subcommand_list_passwords(_):
|
||||
if line.startswith('}'):
|
||||
in_permissions = False
|
||||
else:
|
||||
parts = line.split('#')
|
||||
try:
|
||||
comment = parts[1].strip()
|
||||
except IndexError:
|
||||
comment = ''
|
||||
match = re.match(r"\s*'(.*)': '(.*)',\s*(#\s*.*)?", line)
|
||||
if match:
|
||||
password = match.group(1)
|
||||
permissions = match.group(2).split(',')
|
||||
comment = match.group(3) or ''
|
||||
comment = comment.lstrip('#').strip()
|
||||
|
||||
parts = parts[0].split(':')
|
||||
password = parts[0].replace("'", '').strip()
|
||||
permissions = parts[1].replace(
|
||||
"'", '').strip().rstrip(',').split(',')
|
||||
passwords.append({
|
||||
'password': password,
|
||||
'permissions': ', '.join(permissions),
|
||||
'comment': comment
|
||||
})
|
||||
passwords.append({
|
||||
'password': password,
|
||||
'permissions': ', '.join(permissions),
|
||||
'comment': comment
|
||||
})
|
||||
|
||||
print(json.dumps(passwords))
|
||||
|
||||
|
||||
def subcommand_add_password(arguments):
|
||||
"""Generate a password with given permissions"""
|
||||
if arguments.permissions:
|
||||
permissions = set(bepasty.PERMISSIONS.keys()).intersection(
|
||||
arguments.permissions)
|
||||
permissions = ','.join(permissions)
|
||||
else:
|
||||
permissions = ''
|
||||
|
||||
permissions = _format_permissions(arguments.permissions)
|
||||
password = _generate_password()
|
||||
with open(CONF_FILE, 'r') as conf_file:
|
||||
lines = conf_file.readlines()
|
||||
@ -194,6 +196,41 @@ def subcommand_remove_password(arguments):
|
||||
action_utils.service_try_restart('uwsgi')
|
||||
|
||||
|
||||
def subcommand_get_default(_):
|
||||
"""Get default permissions"""
|
||||
with open(CONF_FILE, 'r') as conf_file:
|
||||
lines = conf_file.readlines()
|
||||
|
||||
for line in lines:
|
||||
match = re.match(r"DEFAULT_PERMISSIONS = '(.*)'", line)
|
||||
if match:
|
||||
print(match.group(1).replace(',', ' '))
|
||||
return
|
||||
|
||||
|
||||
def subcommand_set_default(arguments):
|
||||
"""Set default permissions"""
|
||||
permissions = _format_permissions(arguments.permissions)
|
||||
with open(CONF_FILE, 'r') as conf_file:
|
||||
lines = conf_file.readlines()
|
||||
|
||||
with open(CONF_FILE, 'w') as conf_file:
|
||||
for line in lines:
|
||||
if line.startswith('DEFAULT_PERMISSIONS'):
|
||||
conf_file.write(
|
||||
"DEFAULT_PERMISSIONS = '{}'\n".format(permissions))
|
||||
else:
|
||||
conf_file.write(line)
|
||||
|
||||
action_utils.service_try_restart('uwsgi')
|
||||
|
||||
|
||||
def _format_permissions(permissions=None):
|
||||
"""Format permissions as comma-separated"""
|
||||
return ','.join(set(bepasty.PERMISSIONS.keys()).intersection(
|
||||
permissions)) if permissions else ''
|
||||
|
||||
|
||||
def _generate_password():
|
||||
"""Generate a random password"""
|
||||
alphabet = string.ascii_letters + string.digits
|
||||
|
||||
@ -44,6 +44,12 @@ PERMISSIONS = {
|
||||
'admin': _('Admin (lock/unlock files)'),
|
||||
}
|
||||
|
||||
DEFAULT_PERMISSIONS = {
|
||||
'': _('None (password always required)'),
|
||||
'read': _('Read files (using their web address)'),
|
||||
'read list': _('List and read all files'),
|
||||
}
|
||||
|
||||
|
||||
class BepastyApp(app_module.App):
|
||||
"""FreedomBox app for bepasty."""
|
||||
@ -113,3 +119,16 @@ def remove_password(password):
|
||||
"""Remove a password and its permissions"""
|
||||
actions.superuser_run('bepasty',
|
||||
['remove-password', '--password', password])
|
||||
|
||||
|
||||
def get_default_permissions():
|
||||
"""Get default permissions"""
|
||||
output = actions.superuser_run('bepasty', ['get-default']).strip()
|
||||
output = 'read list' if output == 'list read' else output
|
||||
return output.strip()
|
||||
|
||||
|
||||
def set_default_permissions(permissions):
|
||||
"""Set default permissions"""
|
||||
perm = permissions.split()
|
||||
actions.superuser_run('bepasty', ['set-default', '--permissions'] + perm)
|
||||
|
||||
@ -9,6 +9,16 @@ from django.utils.translation import ugettext_lazy as _
|
||||
from plinth.modules import bepasty
|
||||
|
||||
|
||||
class SetDefaultPermissionsForm(forms.Form):
|
||||
"""Form to set default permissions"""
|
||||
default_permissions = forms.ChoiceField(
|
||||
choices=bepasty.DEFAULT_PERMISSIONS.items(), required=False,
|
||||
widget=forms.RadioSelect(),
|
||||
label=_('Public Access (default permissions)'),
|
||||
help_text=_('Permissions for anonymous users, who have not provided a '
|
||||
'password.'))
|
||||
|
||||
|
||||
class AddPasswordForm(forms.Form):
|
||||
"""Form to add a new password."""
|
||||
|
||||
|
||||
@ -13,6 +13,18 @@ Scenario: Enable bepasty application
|
||||
When I enable the bepasty application
|
||||
Then the bepasty site should be available
|
||||
|
||||
Scenario: Set default permissions to List and read all files
|
||||
Given the bepasty application is enabled
|
||||
And I am not logged in to bepasty
|
||||
When I set the default permissions to List and read all files
|
||||
Then I should be able to List all Items in bepasty
|
||||
|
||||
Scenario: Set default permissions to Read files
|
||||
Given the bepasty application is enabled
|
||||
And I am not logged in to bepasty
|
||||
When I set the default permissions to Read files
|
||||
Then I should not be able to List all Items in bepasty
|
||||
|
||||
Scenario: Add password
|
||||
Given the bepasty application is enabled
|
||||
When I add a password
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
Functional, browser based tests for bepasty app.
|
||||
"""
|
||||
|
||||
from pytest_bdd import scenarios, then, when
|
||||
from pytest_bdd import given, scenarios, then, when
|
||||
|
||||
from plinth.tests import functional
|
||||
|
||||
@ -12,6 +12,21 @@ scenarios('bepasty.feature')
|
||||
last_password_added = None
|
||||
|
||||
|
||||
@given('I am not logged in to bepasty')
|
||||
def not_logged_in(session_browser):
|
||||
_logout(session_browser)
|
||||
|
||||
|
||||
@when('I set the default permissions to Read files')
|
||||
def set_default_permissions_read(session_browser):
|
||||
_set_default_permissions(session_browser, 'read')
|
||||
|
||||
|
||||
@when('I set the default permissions to List and read all files')
|
||||
def set_default_permissions_list_read(session_browser):
|
||||
_set_default_permissions(session_browser, 'read list')
|
||||
|
||||
|
||||
@when('I add a password')
|
||||
def add_password(session_browser):
|
||||
global last_password_added
|
||||
@ -35,6 +50,22 @@ def should_not_login(session_browser):
|
||||
assert not _can_login(session_browser, last_password_added)
|
||||
|
||||
|
||||
@then('I should be able to List all Items in bepasty')
|
||||
def should_list_all(session_browser):
|
||||
assert _can_list_all(session_browser)
|
||||
|
||||
|
||||
@then('I should not be able to List all Items in bepasty')
|
||||
def should_not_list_all(session_browser):
|
||||
assert _cannot_list_all(session_browser)
|
||||
|
||||
|
||||
def _set_default_permissions(browser, permissions=''):
|
||||
functional.nav_to_module(browser, 'bepasty')
|
||||
browser.choose('default_permissions', permissions)
|
||||
functional.submit(browser, form_class='form-configuration')
|
||||
|
||||
|
||||
def _add_password(browser):
|
||||
functional.visit(browser, '/plinth/apps/bepasty/add')
|
||||
for permission in ['read', 'create', 'list', 'delete', 'admin']:
|
||||
@ -45,7 +76,7 @@ def _add_password(browser):
|
||||
|
||||
|
||||
def _remove_all_passwords(browser):
|
||||
functional.visit(browser, '/plinth/apps/bepasty')
|
||||
functional.nav_to_module(browser, 'bepasty')
|
||||
while True:
|
||||
remove_button = browser.find_by_css('.password-remove')
|
||||
if remove_button:
|
||||
@ -55,18 +86,32 @@ def _remove_all_passwords(browser):
|
||||
|
||||
|
||||
def _get_password(browser):
|
||||
functional.visit(browser, '/plinth/apps/bepasty')
|
||||
functional.nav_to_module(browser, 'bepasty')
|
||||
return browser.find_by_css('.password-password').first.text
|
||||
|
||||
|
||||
def _can_login(browser, password):
|
||||
functional.visit(browser, '/bepasty')
|
||||
logout = browser.find_by_value('Logout')
|
||||
if logout:
|
||||
logout.click()
|
||||
|
||||
_logout(browser)
|
||||
browser.fill('token', password)
|
||||
login = browser.find_by_xpath('//form//button')
|
||||
functional.submit(browser, login, '/bepasty')
|
||||
|
||||
return bool(browser.find_by_value('Logout'))
|
||||
|
||||
|
||||
def _logout(browser):
|
||||
functional.visit(browser, '/bepasty')
|
||||
logout = browser.find_by_value('Logout')
|
||||
if logout:
|
||||
logout.click()
|
||||
|
||||
|
||||
def _can_list_all(browser):
|
||||
functional.visit(browser, '/bepasty')
|
||||
return functional.eventually(browser.links.find_by_href,
|
||||
['/bepasty/+list'], 5)
|
||||
|
||||
|
||||
def _cannot_list_all(browser):
|
||||
functional.visit(browser, '/bepasty/+list')
|
||||
return functional.eventually(browser.is_text_present, ['Forbidden'], 5)
|
||||
|
||||
@ -11,16 +11,17 @@ from django.utils.translation import ugettext_lazy as _
|
||||
from django.views.decorators.http import require_POST
|
||||
from django.views.generic import FormView
|
||||
|
||||
from plinth.errors import ActionError
|
||||
from plinth.modules import bepasty
|
||||
from plinth.views import AppView
|
||||
|
||||
from .forms import AddPasswordForm
|
||||
from .forms import AddPasswordForm, SetDefaultPermissionsForm
|
||||
|
||||
|
||||
class BepastyView(AppView):
|
||||
"""Serve configuration page."""
|
||||
app_id = 'bepasty'
|
||||
diagnostics_module_name = 'bepasty'
|
||||
form_class = SetDefaultPermissionsForm
|
||||
template_name = 'bepasty.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
@ -29,6 +30,28 @@ class BepastyView(AppView):
|
||||
context['passwords'] = bepasty.list_passwords()
|
||||
return context
|
||||
|
||||
def get_initial(self):
|
||||
"""Return the status of the service to fill in the form."""
|
||||
initial = super().get_initial()
|
||||
initial['default_permissions'] = bepasty.get_default_permissions()
|
||||
return initial
|
||||
|
||||
def form_valid(self, form):
|
||||
"""Apply the changes submitted in the form."""
|
||||
old_data = form.initial
|
||||
form_data = form.cleaned_data
|
||||
|
||||
if old_data['default_permissions'] != form_data['default_permissions']:
|
||||
try:
|
||||
bepasty.set_default_permissions(
|
||||
form_data['default_permissions'])
|
||||
messages.success(self.request, _('Configuration updated.'))
|
||||
except ActionError:
|
||||
messages.error(self.request,
|
||||
_('An error occurred during configuration.'))
|
||||
|
||||
return super().form_valid(form)
|
||||
|
||||
|
||||
class AddPasswordView(SuccessMessageMixin, FormView):
|
||||
"""View to add a new password."""
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user