minor layout cleanup

This commit is contained in:
fonfon 2015-01-23 10:35:56 +00:00
parent 3cc0cb74a6
commit ef08f40447
13 changed files with 81 additions and 216 deletions

View File

View File

@ -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
"""

View File

@ -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

View File

@ -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',

View 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']

View File

@ -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__)

View File

@ -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)

View File

@ -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');
}
});

View File

@ -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;
}

View File

@ -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>

View File

@ -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()

View File

@ -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)

View File

@ -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',