mirror of
https://github.com/freedombox/FreedomBox.git
synced 2026-06-10 11:00:22 +00:00
Remove modules 'expert_mode' and 'lib'.
The login/logout URLs are now in the 'users' module.
This commit is contained in:
parent
3abc5e9212
commit
90203986f2
1
LICENSES
1
LICENSES
@ -22,7 +22,6 @@ otherwise.
|
||||
- doc/Makefile :: -
|
||||
- doc/modules.mdwn :: -
|
||||
- doc/scripts.mdwn :: -
|
||||
- doc/security.mdwn :: -
|
||||
- doc/themes.mdwn :: -
|
||||
- static/themes/default/FreedomBox-Identity-Manual.pdf :: -
|
||||
- static/themes/default/FreedomBox-Logo.7z :: [[http://thread.gmane.org/gmane.linux.debian.freedombox.user/4124/focus=4439][GPL3+/CC-BY-SA]]
|
||||
|
||||
@ -30,13 +30,6 @@ to get newer, better shinier functions. The modules will
|
||||
automatically integrate into the existing menu system so you can
|
||||
control all of the box's parts from one central location.
|
||||
|
||||
The interface will eventually have a 'basic' and an 'expert' mode. In
|
||||
basic mode, much of Plinth's configuration and capability are hidden.
|
||||
Sane defaults are chosen whenever possible. In expert mode, you can
|
||||
get down into the details and configure things the average user never
|
||||
thinks about. For example, experts can turn off ntp or switch ntp
|
||||
servers. Basic users should never even know those options exist.
|
||||
|
||||
## Getting Started
|
||||
|
||||
See the INSTALL file for additional details and dependencies. To install run:
|
||||
|
||||
@ -1 +0,0 @@
|
||||
plinth.modules.expert_mode
|
||||
@ -1 +0,0 @@
|
||||
plinth.modules.lib
|
||||
@ -6,7 +6,7 @@ PDFLATEX=pdflatex
|
||||
|
||||
# List text files in the order in which you want them to appear in the
|
||||
# complete manual:
|
||||
SOURCES=README.mdwn INSTALL.mdwn themes.mdwn hacking.mdwn TODO.mdwn modules.mdwn scripts.mdwn security.mdwn faq.mdwn COPYING.mdwn colophon.mdwn
|
||||
SOURCES=README.mdwn INSTALL.mdwn themes.mdwn hacking.mdwn TODO.mdwn modules.mdwn scripts.mdwn faq.mdwn COPYING.mdwn colophon.mdwn
|
||||
OTHER=
|
||||
PYTHON_SOURCES:=$(shell find .. -name \*.py)
|
||||
TODO_SOURCES=$(patsubst TODO.mdwn,,$(SOURCES)) $(PYTHON_SOURCES)
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
Almost all of the front end's functionality is contained in small,
|
||||
separate modules that reside in the directory tree beneath
|
||||
`/modules/installed`. Some are installed by default, some are
|
||||
`plinth/modules`. Some are installed by default, some are
|
||||
required for operation, and some are entirely optional.
|
||||
|
||||
## Installing and Loading Modules
|
||||
@ -12,45 +12,15 @@ installation is as simple as `aptitude install freedombox-foo`. As an
|
||||
intermediate step, we'll start scripting module installation. But
|
||||
until then, we can install them manually.
|
||||
|
||||
Modules are installed by copying them into the tree beneath the
|
||||
`/modules/installed` directory. They are activated by linking their
|
||||
.py files into the modules directory. (Freedom Box will not load
|
||||
modules unless they are symlinks.) If the module provides other
|
||||
resources, they can be linked from wherever in the working tree they
|
||||
need to be. So if a module provides a template, that template can be
|
||||
linked from `/templates`.
|
||||
|
||||
Modules can be organized into subdirectories beneath the installed
|
||||
directory. As an initial matter, I've made separate directories for
|
||||
each major tab. Modules that extend the functionality of the Freedom
|
||||
Box code base (as opposed to being user-visible interface modules
|
||||
under specific major tabs) go in `modules/installed/lib`. This
|
||||
convention can be adjusted or ignored as needed. In fact, modules can
|
||||
be installed anywhere in the file system as long as the symlinks are
|
||||
in `/modules`.
|
||||
|
||||
The names of the symlinks in the `modules` directory can be arbitrary,
|
||||
and if a name is already taken, (e.g. if `router/info.py` and
|
||||
`apps/info.p`y both exist), append a counter to the end (e.g. link
|
||||
`info.py` to `router/info.py` and `info1.py` to `apps/info.py`).
|
||||
|
||||
If a module cannot be imported for any reason (e.g. it's a dead
|
||||
symlink), freedombox.py will log an error but will otherwise just keep
|
||||
going.
|
||||
A module can be represented inside of Plinth via a django app.
|
||||
To enable a module, put a file containing its python path into
|
||||
`data/etc/plinth/modules-enabled/`. Django is configured to use all
|
||||
modules of the `modules-enabled` folder as apps. With the python path
|
||||
you can also include modules/apps outside of plinth.
|
||||
|
||||
TODO: automatically prune dead links to clear out old module installs.
|
||||
This is something the install scripts should do.
|
||||
|
||||
## Pluggable Module Structure
|
||||
|
||||
Plugin interfaces are contained in `plugin_mount.py`. Each interface
|
||||
is a metaclass. Classes that implement a given interface should
|
||||
inherit the metaclass and then provide the indicated properties. New
|
||||
metaclasses can be created to make new classes of plugins.
|
||||
|
||||
Any place that might be affected by arbitrary addition of modules
|
||||
should have its own metaclass.
|
||||
|
||||
## Coding Practices for Modules
|
||||
|
||||
All the
|
||||
|
||||
@ -1,33 +0,0 @@
|
||||
# Security
|
||||
|
||||
## Password Storage
|
||||
|
||||
Here is an overview of how user passwords are currently being stored in Plinth.
|
||||
|
||||
### Storing a password (add_user function in auth module):
|
||||
|
||||
1. We check if the username or password is empty. If so, return an error message.
|
||||
|
||||
2. Use bcrypt (from passlib) to hash the password with a random salt. bcrypt returns the hash in the format:
|
||||
|
||||
$2a$<base 10 number of rounds>$<22-character salt><31-character checksum>
|
||||
|
||||
This hashed string will be used in step 5.
|
||||
|
||||
3. If the password length is over 4096, bcrypt raises an exception. We catch this exception and return an error message.
|
||||
|
||||
4. Check if the username exists in user store. If so, return an error message.
|
||||
|
||||
5. If no error has occurred so far, create the new user. The username, hashed password, and salt are stored in the user store database. The salt is a substring of the hash output by bcrypt.
|
||||
|
||||
### Checking password at login (check_credentials function in auth module):
|
||||
|
||||
1. We check if the username or password is empty. If so, return an error message.
|
||||
|
||||
2. Use bcrypt to hash the supplied password. This step is performed regardless of whether the user already exists. If the user exists, use the salt value stored for that user in the database, otherwise, a random salt is used.
|
||||
|
||||
3. If the password length is over 4096, bcrypt raises an exception. We catch this exception and return an error message.
|
||||
|
||||
4. Check if the user doesn't exist, or if the hashed password doesn't match the stored hash. Return an error message "Bad user-name or password" if either of these conditions are true.
|
||||
|
||||
5. If no error has occurred so far, return None to indicate that the supplied credentials are valid.
|
||||
@ -198,9 +198,9 @@ def configure_django():
|
||||
DEBUG=cfg.debug,
|
||||
INSTALLED_APPS=applications,
|
||||
LOGGING=logging_configuration,
|
||||
LOGIN_URL='lib:login',
|
||||
LOGIN_URL='users:login',
|
||||
LOGIN_REDIRECT_URL='apps:index',
|
||||
LOGOUT_URL='lib:logout',
|
||||
LOGOUT_URL='users:logout',
|
||||
MIDDLEWARE_CLASSES=(
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
|
||||
@ -105,8 +105,7 @@ def index(request):
|
||||
|
||||
form = None
|
||||
|
||||
is_expert = request.user.groups.filter(name='Expert').exists()
|
||||
if request.method == 'POST' and is_expert:
|
||||
if request.method == 'POST':
|
||||
form = ConfigurationForm(request.POST, prefix='configuration')
|
||||
# pylint: disable-msg=E1101
|
||||
if form.is_valid():
|
||||
@ -119,8 +118,7 @@ def index(request):
|
||||
|
||||
return TemplateResponse(request, 'config.html',
|
||||
{'title': _('General Configuration'),
|
||||
'form': form,
|
||||
'is_expert': is_expert})
|
||||
'form': form})
|
||||
|
||||
|
||||
def get_status():
|
||||
|
||||
@ -22,7 +22,6 @@
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% if is_expert %}
|
||||
|
||||
<form class="form" method="post">
|
||||
{% csrf_token %}
|
||||
@ -33,11 +32,5 @@
|
||||
|
||||
</form>
|
||||
|
||||
{% else %}
|
||||
|
||||
<p>Only members of the expert group are allowed to see and modify
|
||||
the system setup.</p>
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
@ -1,27 +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 expert mode configuration
|
||||
"""
|
||||
|
||||
from . import expert_mode
|
||||
from .expert_mode import init
|
||||
|
||||
__all__ = ['expert_mode', 'init']
|
||||
|
||||
depends = ['plinth.modules.system']
|
||||
@ -1,82 +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/>.
|
||||
#
|
||||
|
||||
from django import forms
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.template.response import TemplateResponse
|
||||
from gettext import gettext as _
|
||||
|
||||
from plinth import cfg
|
||||
from plinth.modules.lib.auth import get_or_create_group
|
||||
|
||||
|
||||
class ExpertsForm(forms.Form): # pylint: disable-msg=W0232
|
||||
"""Form to configure expert mode"""
|
||||
expert_mode = forms.BooleanField(
|
||||
label=_('Enable Expert Mode'), required=False)
|
||||
|
||||
|
||||
def init():
|
||||
"""Initialize the module"""
|
||||
menu = cfg.main_menu.get('system:index')
|
||||
menu.add_urlname(_('Expert Mode'), 'glyphicon-wrench',
|
||||
'expert_mode:index', 10)
|
||||
|
||||
|
||||
@login_required
|
||||
def index(request):
|
||||
"""Serve the configuration form"""
|
||||
status = get_status(request)
|
||||
|
||||
form = None
|
||||
|
||||
if request.method == 'POST':
|
||||
form = ExpertsForm(request.POST, prefix='experts')
|
||||
# pylint: disable-msg=E1101
|
||||
if form.is_valid():
|
||||
_apply_changes(request, form.cleaned_data)
|
||||
status = get_status(request)
|
||||
form = ExpertsForm(initial=status, prefix='experts')
|
||||
else:
|
||||
form = ExpertsForm(initial=status, prefix='experts')
|
||||
|
||||
return TemplateResponse(request, 'expert_mode.html',
|
||||
{'title': _('Expert Mode'),
|
||||
'form': form})
|
||||
|
||||
|
||||
def get_status(request):
|
||||
"""Return the current status"""
|
||||
return {'expert_mode': request.user.groups.filter(name='Expert').exists()}
|
||||
|
||||
|
||||
def _apply_changes(request, new_status):
|
||||
"""Apply expert mode configuration"""
|
||||
message = (messages.info, _('Settings unchanged'))
|
||||
|
||||
expert_group = get_or_create_group('Expert')
|
||||
if new_status['expert_mode']:
|
||||
if expert_group not in request.user.groups.all():
|
||||
request.user.groups.add(expert_group)
|
||||
message = (messages.success, _('Expert mode enabled'))
|
||||
else:
|
||||
if expert_group in request.user.groups.all():
|
||||
request.user.groups.remove(expert_group)
|
||||
message = (messages.success, _('Expert mode disabled'))
|
||||
|
||||
message[0](request, message[1])
|
||||
@ -1,51 +0,0 @@
|
||||
{% extends "base.html" %}
|
||||
{% comment %}
|
||||
#
|
||||
# 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/>.
|
||||
#
|
||||
{% endcomment %}
|
||||
|
||||
{% load bootstrap %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<h2>{{ title }}</h2>
|
||||
|
||||
<p>The {{ cfg.box_name }} can be administered in two modes, 'basic'
|
||||
and 'expert'. Basic mode hides a lot of features and configuration
|
||||
options that most users will never need to think about. Expert mode
|
||||
allows you to get into the details.</p>
|
||||
|
||||
<p>Most users can operate the {{ cfg.box_name }} by configuring the
|
||||
limited number of options visible in Basic mode. For the sake of
|
||||
simplicity and ease of use, we hid most of {{ cfg.product_name }}'s
|
||||
less frequently used options. But if you want more sophisticated
|
||||
features, you can enable Expert mode, and {{ cfg.product_name }}
|
||||
will present more advanced menu options.</p>
|
||||
|
||||
<p>You should be aware that it might be possible to render your
|
||||
{{ cfg.box_name }} inaccessible via Expert mode options.</p>
|
||||
|
||||
<form class="form" method="post">
|
||||
{% csrf_token %}
|
||||
|
||||
{{ form|bootstrap }}
|
||||
|
||||
<input type="submit" class="btn btn-primary" value="Submit"/>
|
||||
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
||||
@ -1,28 +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/>.
|
||||
#
|
||||
|
||||
"""
|
||||
URLs for the Expert Mode module
|
||||
"""
|
||||
|
||||
from django.conf.urls import patterns, url
|
||||
|
||||
|
||||
urlpatterns = patterns( # pylint: disable-msg=C0103
|
||||
'plinth.modules.expert_mode.expert_mode',
|
||||
url(r'^sys/expert/$', 'index', name='index'),
|
||||
)
|
||||
@ -56,7 +56,6 @@ than 63 characters in length.'),
|
||||
config.set_hostname(self.cleaned_data['hostname'])
|
||||
user = super(State0Form, self).save(commit=False)
|
||||
user.set_password(self.cleaned_data['password'])
|
||||
user.is_expert = True
|
||||
if commit:
|
||||
user.save()
|
||||
self.login_user()
|
||||
|
||||
@ -25,7 +25,7 @@
|
||||
{% if user.is_authenticated %}
|
||||
<p>Have fun with your {{ cfg.box_name }}!</p>
|
||||
{% else %}
|
||||
<p>Proceed to <a href="{% url 'lib:login' %}">login</a>.</p>
|
||||
<p>Proceed to <a href="{% url 'users:login' %}">login</a>.</p>
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
@ -1,24 +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 library modules
|
||||
"""
|
||||
|
||||
from . import auth
|
||||
|
||||
__all__ = ['auth']
|
||||
@ -1,46 +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/>.
|
||||
#
|
||||
|
||||
from django.contrib.auth.models import Group, User
|
||||
|
||||
|
||||
def add_user(username, passphrase, name='', email='', expert=False):
|
||||
"""Add a new user with specified username and passphrase"""
|
||||
if not username:
|
||||
return 'Must specify a username!'
|
||||
|
||||
if not passphrase:
|
||||
return 'Must specify a passphrase!'
|
||||
|
||||
user = User.objects.create_user(username, email=email,
|
||||
password=passphrase)
|
||||
user.first_name = name
|
||||
user.save()
|
||||
|
||||
if expert:
|
||||
user.groups.add(get_or_create_group('Expert'))
|
||||
|
||||
|
||||
def get_or_create_group(name):
|
||||
"""Return an existing or newly created group with given name"""
|
||||
try:
|
||||
group = Group.objects.get(name__exact=name)
|
||||
except Group.DoesNotExist:
|
||||
group = Group(name=name)
|
||||
group.save()
|
||||
|
||||
return group
|
||||
@ -1,32 +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/>.
|
||||
#
|
||||
|
||||
"""
|
||||
URLs for the Lib module
|
||||
"""
|
||||
|
||||
from django.conf.urls import patterns, url
|
||||
from django.core.urlresolvers import reverse_lazy
|
||||
|
||||
|
||||
urlpatterns = patterns( # pylint: disable-msg=C0103
|
||||
'',
|
||||
url(r'^accounts/login/$', 'django.contrib.auth.views.login',
|
||||
{'template_name': 'login.html'}, name='login'),
|
||||
url(r'^accounts/logout/$', 'django.contrib.auth.views.logout',
|
||||
{'next_page': reverse_lazy('index')}, name='logout')
|
||||
)
|
||||
@ -21,6 +21,7 @@ URLs for the Users module
|
||||
|
||||
from django.conf.urls import patterns, url
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.core.urlresolvers import reverse_lazy
|
||||
|
||||
from . import views
|
||||
|
||||
@ -38,4 +39,9 @@ urlpatterns = patterns(
|
||||
url(r'^sys/users/(?P<slug>[\w.@+-]+)/change_password/$',
|
||||
login_required(views.UserChangePassword.as_view()),
|
||||
name='change_password'),
|
||||
# add djangos login/logout urls
|
||||
url(r'^accounts/login/$', 'django.contrib.auth.views.login',
|
||||
{'template_name': 'login.html'}, name='login'),
|
||||
url(r'^accounts/logout/$', 'django.contrib.auth.views.logout',
|
||||
{'next_page': reverse_lazy('index')}, name='logout'),
|
||||
)
|
||||
|
||||
@ -110,14 +110,14 @@
|
||||
<p class="navbar-text pull-right">
|
||||
<i class="glyphicon glyphicon-user nav-icon"></i>
|
||||
Logged in as <a href="#">{{ user.username }}</a>.
|
||||
<a href="{% url 'lib:logout' %}" title="Log out">
|
||||
<a href="{% url 'users:logout' %}" title="Log out">
|
||||
Log out</a>.
|
||||
</p>
|
||||
{% else %}
|
||||
<p class="navbar-text pull-right">
|
||||
Not logged in.
|
||||
<i class="glyphicon glyphicon-user nav-icon"></i>
|
||||
<a href="{% url 'lib:login' %}" title="Log in">
|
||||
<a href="{% url 'users:login' %}" title="Log in">
|
||||
Log in</a>.
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user