mirror of
https://github.com/freedombox/FreedomBox.git
synced 2026-01-21 07:55:00 +00:00
minor layout cleanup
This commit is contained in:
parent
3cc0cb74a6
commit
ef08f40447
@ -18,7 +18,7 @@
|
||||
#
|
||||
|
||||
"""
|
||||
Configuration helper for Plint PageKite interface
|
||||
Configuration helper for Plinth PageKite interface
|
||||
|
||||
Unfortunately there is no python3 package for augeas yet
|
||||
"""
|
||||
|
||||
@ -19,11 +19,14 @@
|
||||
|
||||
"""
|
||||
Utilities for configuring PageKite.
|
||||
|
||||
The variables/functions defined here are used by both the action script
|
||||
and the plinth pagekite module.
|
||||
"""
|
||||
# ATTENTION: This file has to be both python2 and python3 compatible
|
||||
# TODO:
|
||||
# Once python-augeas is available for python3 import the following things
|
||||
# from plinth.modules.pagekite.util (instead of having a copy in here):
|
||||
#
|
||||
# SERVICE_PARAMS, convert_service_to_string, convert_to_service
|
||||
#
|
||||
# until then, this file is python2 and python3 compatible for the unittests
|
||||
|
||||
import os
|
||||
import shlex
|
||||
|
||||
@ -222,9 +222,6 @@ def configure_django():
|
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||
'plinth.modules.first_boot.middleware.FirstBootMiddleware',
|
||||
),
|
||||
MESSAGE_TAGS = {
|
||||
messages_constants.ERROR: 'danger'
|
||||
},
|
||||
ROOT_URLCONF='plinth.urls',
|
||||
SECURE_PROXY_SSL_HEADER=secure_proxy_ssl_header,
|
||||
SESSION_ENGINE='django.contrib.sessions.backends.file',
|
||||
|
||||
@ -21,9 +21,8 @@ Plinth module to configure PageKite
|
||||
|
||||
from gettext import gettext as _
|
||||
from plinth import cfg
|
||||
from . import pagekite
|
||||
|
||||
__all__ = ['pagekite', 'init']
|
||||
__all__ = ['init']
|
||||
|
||||
depends = ['plinth.modules.apps']
|
||||
|
||||
|
||||
@ -23,10 +23,9 @@ from django import forms
|
||||
from django.contrib import messages
|
||||
from django.core import validators
|
||||
|
||||
from actions.pagekite_util import convert_service_to_string
|
||||
from plinth.errors import ActionError
|
||||
from .util import PREDEFINED_SERVICES, _run, get_kite_details, KITE_NAME, \
|
||||
KITE_SECRET, BACKEND_HOST
|
||||
from .util import _run, convert_service_to_string, get_kite_details, \
|
||||
BACKEND_HOST, KITE_NAME, KITE_SECRET, PREDEFINED_SERVICES
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@ -1,183 +0,0 @@
|
||||
#
|
||||
# This file is part of Plinth.
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
"""
|
||||
Plinth module for configuring PageKite service
|
||||
"""
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
return super(TrimmedCharField, self).clean(value)
|
||||
|
||||
|
||||
class ConfigureForm(forms.Form): # pylint: disable-msg=W0232
|
||||
"""Form to configure PageKite"""
|
||||
enabled = forms.BooleanField(label=_('Enable PageKite'),
|
||||
required=False)
|
||||
|
||||
server = forms.CharField(
|
||||
label=_('Server'), required=False,
|
||||
help_text=_('Select your pagekite.net server. Set "pagekite.net" to '
|
||||
'use the default pagekite.net server'),
|
||||
widget=forms.TextInput())
|
||||
|
||||
kite_name = TrimmedCharField(
|
||||
label=_('Kite name'),
|
||||
help_text=_('Example: mybox1-myacc.pagekite.me'),
|
||||
validators=[
|
||||
validators.RegexValidator(r'^[\w-]{1,63}(\.[\w-]{1,63})*$',
|
||||
_('Invalid kite name'))])
|
||||
|
||||
kite_secret = TrimmedCharField(
|
||||
label=_('Kite secret'),
|
||||
help_text=_('A secret associated with the kite or the default secret \
|
||||
for your account if no secret is set on the kite'))
|
||||
|
||||
http_enabled = forms.BooleanField(
|
||||
label=_('Web Server (HTTP)'), required=False,
|
||||
help_text=_('Site will be available at \
|
||||
<a href="http://mybox1-myacc.pagekite.me">http://mybox1-myacc.pagekite.me \
|
||||
</a>'))
|
||||
|
||||
ssh_enabled = forms.BooleanField(
|
||||
label=_('Secure Shell (SSH)'), required=False,
|
||||
help_text=_('See SSH client setup <a href="\
|
||||
https://pagekite.net/wiki/Howto/SshOverPageKite/">instructions</a>'))
|
||||
|
||||
|
||||
@login_required
|
||||
@package.required(['pagekite'])
|
||||
def configure(request):
|
||||
"""Serve the configuration form"""
|
||||
status = get_status()
|
||||
|
||||
form = None
|
||||
|
||||
if request.method == 'POST':
|
||||
form = ConfigureForm(request.POST, prefix='pagekite')
|
||||
# pylint: disable-msg=E1101
|
||||
if form.is_valid():
|
||||
_apply_changes(request, status, form.cleaned_data)
|
||||
status = get_status()
|
||||
form = ConfigureForm(initial=status, prefix='pagekite')
|
||||
else:
|
||||
form = ConfigureForm(initial=status, prefix='pagekite')
|
||||
|
||||
return TemplateResponse(request, 'pagekite_configure.html',
|
||||
{'title': _('Configure PageKite'),
|
||||
'status': status,
|
||||
'form': form,
|
||||
'subsubmenu': subsubmenu})
|
||||
|
||||
|
||||
def get_status():
|
||||
"""
|
||||
Return the current status of PageKite configuration by
|
||||
executing various actions.
|
||||
"""
|
||||
status = {}
|
||||
|
||||
# PageKite service enabled/disabled
|
||||
output = _run(['get-status'])
|
||||
status['enabled'] = (output.split()[0] == 'enabled')
|
||||
|
||||
# PageKite kite details
|
||||
output = _run(['get-kite'])
|
||||
kite_details = output.split()
|
||||
status['kite_name'] = kite_details[0]
|
||||
status['kite_secret'] = kite_details[1]
|
||||
|
||||
# PageKite server: 'pagekite.net' if flag 'defaults' is set,
|
||||
# the value of 'frontend' otherwise
|
||||
use_pagekitenet_server = _run(['get-pagekitenet-frontend-status'])
|
||||
if "enabled" in use_pagekitenet_server:
|
||||
value = 'pagekite.net'
|
||||
elif "disabled" in use_pagekitenet_server:
|
||||
value = _run(['get-frontend'])
|
||||
status['server'] = value.replace('\n', '')
|
||||
|
||||
# Service status
|
||||
status['service'] = {}
|
||||
for service in ('http', 'ssh'):
|
||||
output = _run(['get-service-status', service])
|
||||
status[service + '_enabled'] = (output.split()[0] == 'enabled')
|
||||
|
||||
return status
|
||||
|
||||
|
||||
def _apply_changes(request, old_status, new_status):
|
||||
"""Apply the changes to PageKite configuration"""
|
||||
LOGGER.info('New status is - %s', new_status)
|
||||
|
||||
if old_status != new_status:
|
||||
_run(['stop'])
|
||||
|
||||
if old_status['enabled'] != new_status['enabled']:
|
||||
if new_status['enabled']:
|
||||
_run(['set-status', 'enable'])
|
||||
messages.success(request, _('PageKite enabled'))
|
||||
else:
|
||||
_run(['set-status', 'disable'])
|
||||
messages.success(request, _('PageKite disabled'))
|
||||
|
||||
if old_status['kite_name'] != new_status['kite_name'] or \
|
||||
old_status['kite_secret'] != new_status['kite_secret']:
|
||||
_run(['set-kite', '--kite-name', new_status['kite_name'],
|
||||
'--kite-secret', new_status['kite_secret']])
|
||||
messages.success(request, _('Kite details set'))
|
||||
|
||||
if old_status['server'] != new_status['server']:
|
||||
server = new_status['server']
|
||||
if server in ('defaults', 'default', 'pagekite.net'):
|
||||
_run(['enable-pagekitenet-frontend'])
|
||||
else:
|
||||
_run(['set-frontend', server])
|
||||
messages.success(request, _('Pagekite server set'))
|
||||
|
||||
for service in ['http', 'ssh']:
|
||||
if old_status[service + '_enabled'] != \
|
||||
new_status[service + '_enabled']:
|
||||
if new_status[service + '_enabled']:
|
||||
_run(['set-service-status', service, 'enable'])
|
||||
messages.success(request, _('Service enabled: {service}')
|
||||
.format(service=service))
|
||||
else:
|
||||
_run(['set-service-status', service, 'disable'])
|
||||
messages.success(request, _('Service disabled: {service}')
|
||||
.format(service=service))
|
||||
|
||||
if old_status != new_status:
|
||||
_run(['start'])
|
||||
|
||||
|
||||
def _run(arguments, superuser=True):
|
||||
"""Run a given command and raise exception if there was an error"""
|
||||
command = 'pagekite-configure'
|
||||
|
||||
if superuser:
|
||||
return actions.superuser_run(command, arguments)
|
||||
else:
|
||||
return actions.run(command, arguments)
|
||||
@ -27,7 +27,7 @@
|
||||
|
||||
{% include 'bootstrapform/field.html' with field=form.enabled %}
|
||||
|
||||
<div class='pagekite-post-enabled-form'
|
||||
<div id='pagekite-post-enabled-form'
|
||||
style='display: {{ form.enabled.value|yesno:'block,none' }};'>
|
||||
<h3>PageKite Account</h3>
|
||||
{{ form.server|bootstrap_horizontal }}
|
||||
@ -47,9 +47,9 @@
|
||||
|
||||
$('#id_pagekite-enabled').change(function() {
|
||||
if ($('#id_pagekite-enabled').prop('checked')) {
|
||||
$('.pagekite-post-enabled-form').show('slow');
|
||||
$('#pagekite-post-enabled-form').show('slow');
|
||||
} else {
|
||||
$('.pagekite-post-enabled-form').hide('slow');
|
||||
$('#pagekite-post-enabled-form').hide('slow');
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@ -26,10 +26,6 @@
|
||||
display: inline-block;
|
||||
margin: 0px 10px;
|
||||
}
|
||||
div.custom-services span.service {
|
||||
display: inline-block;
|
||||
padding-top: 6px;
|
||||
}
|
||||
input.btn {
|
||||
margin: 10px 15px;
|
||||
}
|
||||
|
||||
@ -22,7 +22,7 @@
|
||||
|
||||
<p>PageKite is a system for exposing {{ cfg.box_name }} services when
|
||||
you don't have a direct connection to the Internet. You only need this
|
||||
service if your {{ cfg.box_name }} services are unreachable from the
|
||||
if your {{ cfg.box_name }} services are unreachable from the
|
||||
rest of the Internet. This includes the following situations: </p>
|
||||
|
||||
<ul>
|
||||
@ -41,11 +41,10 @@ rest of the Internet. This includes the following situations: </p>
|
||||
</ul>
|
||||
|
||||
<p>PageKite works around NAT, firewalls and IP-address limitations by
|
||||
using a combination of tunnels and reverse proxies. Currently,
|
||||
exposing web server and SSH server are supported. You can use any
|
||||
server that offers a pagekite service, for example
|
||||
using a combination of tunnels and reverse proxies. You can use any
|
||||
pagekite service provider, for example
|
||||
<a href="https://pagekite.net">pagekite.net</a>.
|
||||
In future, it might be possible to use your buddy's
|
||||
In future it might be possible to use your buddy's
|
||||
{{ cfg.box_name }} for this.</p>
|
||||
|
||||
<p>
|
||||
|
||||
@ -17,17 +17,20 @@
|
||||
|
||||
from gettext import gettext as _
|
||||
import logging
|
||||
import shlex
|
||||
|
||||
from actions.pagekite_util import convert_to_service
|
||||
from plinth import actions
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
||||
# defaults for the credentials; @kitename acts as a placeholder and is
|
||||
# understood (and replaced with the actual kitename) by pagekite.
|
||||
BACKEND_HOST = 'localhost'
|
||||
KITE_NAME = '@kitename'
|
||||
KITE_SECRET = '@kitesecret'
|
||||
BACKEND_HOST = 'localhost'
|
||||
|
||||
SERVICE_PARAMS = ['protocol', 'kitename', 'backend_host', 'backend_port',
|
||||
'secret']
|
||||
|
||||
# Predefined services are used to build the PredefinedServiceForm
|
||||
#
|
||||
@ -68,6 +71,57 @@ PREDEFINED_SERVICES = {
|
||||
}
|
||||
|
||||
|
||||
def convert_to_service(service_string):
|
||||
""" Convert a service string into a service parameter dictionary
|
||||
>>> convert_to_service('https/443:@kitename:localhost:443:@kitesecret')
|
||||
{'kitename': '@kitename', 'backend_host': 'localhost', \
|
||||
'secret': '@kitesecret', 'protocol': 'https/443', 'backend_port': '443'}
|
||||
"""
|
||||
# The actions.py uses shlex.quote() to escape/quote malicious user input.
|
||||
# That affects '*.@kitename', so the params string gets quoted.
|
||||
# If the string is escaped and contains '*.@kitename', look whether shlex
|
||||
# would still quote/escape the string when we remove '*.@kitename'.
|
||||
|
||||
if service_string.startswith("'") and service_string.endswith("'"):
|
||||
unquoted_string = service_string[1:-1]
|
||||
error_msg = "The parameters contain suspicious characters: %s "
|
||||
if '*.@kitename' in service_string:
|
||||
unquoted_test_string = unquoted_string.replace('*.@kitename', '')
|
||||
if unquoted_test_string == shlex.quote(unquoted_test_string):
|
||||
# no other malicious characters found, use the unquoted string
|
||||
service_string = unquoted_string
|
||||
else:
|
||||
raise RuntimeError(error_msg % service_string)
|
||||
else:
|
||||
raise RuntimeError(error_msg % service_string)
|
||||
|
||||
try:
|
||||
params = dict(zip(SERVICE_PARAMS, service_string.split(':')))
|
||||
except Exception:
|
||||
msg = """params are expected to be a ':'-separated string containing
|
||||
values for: %s , for example:\n"--params
|
||||
http/8000:@kitename:localhost:8000:@kitesecret"
|
||||
"""
|
||||
raise ValueError(msg % ", ".join(SERVICE_PARAMS))
|
||||
return params
|
||||
|
||||
|
||||
def convert_service_to_string(service):
|
||||
""" Convert service dict into a ":"-separated parameter string
|
||||
|
||||
>>> convert_service_to_string({'kitename': '@kitename', \
|
||||
'backend_host': 'localhost', 'secret': '@kitesecret', \
|
||||
'protocol': 'https/443', 'backend_port': '443'})
|
||||
'https/443:@kitename:localhost:443:@kitesecret'
|
||||
"""
|
||||
try:
|
||||
service_string = ":".join([str(service[param]) for param in
|
||||
SERVICE_PARAMS])
|
||||
except KeyError:
|
||||
raise ValueError("Could not parse params: %s " % service)
|
||||
return service_string
|
||||
|
||||
|
||||
def get_kite_details():
|
||||
output = _run(['get-kite'])
|
||||
kite_details = output.split()
|
||||
|
||||
@ -30,6 +30,7 @@ from .forms import ConfigurationForm, DefaultServiceForm, \
|
||||
AddCustomServiceForm, DeleteCustomServiceForm
|
||||
|
||||
|
||||
required_packages = ('pagekite', 'augeas-tools', 'python-augeas')
|
||||
subsubmenu = [{'url': reverse_lazy('pagekite:index'),
|
||||
'text': _('About PageKite')},
|
||||
{'url': reverse_lazy('pagekite:configure'),
|
||||
@ -50,7 +51,7 @@ def index(request):
|
||||
class ContextMixin(object):
|
||||
"""Mixin to add 'subsubmenu' and 'title' to the context.
|
||||
|
||||
Also requires 'pagekite' to be installed.
|
||||
Also adds the requirement of all necessary packages to be installed
|
||||
"""
|
||||
def get_context_data(self, **kwargs):
|
||||
"""Use self.title and the module-level subsubmenu"""
|
||||
@ -59,8 +60,7 @@ class ContextMixin(object):
|
||||
context['subsubmenu'] = subsubmenu
|
||||
return context
|
||||
|
||||
@method_decorator(package.required('pagekite', 'augeas-tools',
|
||||
'python-augeas'))
|
||||
@method_decorator(package.required(required_packages))
|
||||
def dispatch(self, *args, **kwargs):
|
||||
return super(ContextMixin, self).dispatch(*args, **kwargs)
|
||||
|
||||
|
||||
@ -18,12 +18,13 @@
|
||||
import os
|
||||
import unittest
|
||||
|
||||
from actions.pagekite_util import get_augeas_servicefile_path, CONF_PATH, \
|
||||
convert_to_service, convert_service_to_string
|
||||
from actions.pagekite_util import get_augeas_servicefile_path, CONF_PATH
|
||||
from plinth.modules.pagekite.util import convert_to_service, \
|
||||
convert_service_to_string
|
||||
|
||||
|
||||
class TestPagekiteActions(unittest.TestCase):
|
||||
# test-cases to convert parameter-strings into param dicts and back
|
||||
"""Test-cases for the pagekite action utils"""
|
||||
_tests = [
|
||||
{
|
||||
'line': 'https/8080:*.@kitename:localhost:8080:@kitesecret',
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user