mirror of
https://github.com/freedombox/FreedomBox.git
synced 2026-09-19 04:59:01 +00:00
commit
9b1f2c6f0d
2
.gitignore
vendored
2
.gitignore
vendored
@ -24,7 +24,7 @@ TODO
|
|||||||
\#*
|
\#*
|
||||||
.#*
|
.#*
|
||||||
*~
|
*~
|
||||||
data/users.sqlite3
|
data/plinth.sqlite3
|
||||||
predepend
|
predepend
|
||||||
build/
|
build/
|
||||||
*.pid
|
*.pid
|
||||||
|
|||||||
6
COPYING
6
COPYING
@ -1,4 +1,4 @@
|
|||||||
# License to Copy Plinth
|
# License to Copy Plinth
|
||||||
|
|
||||||
Plinth is Copyright 2011-2013 James Vasile (<james@hackervisions.org>). It
|
Plinth is Copyright 2011-2013 James Vasile (<james@hackervisions.org>). It
|
||||||
is distributed under the GNU Affero General Public License, Version 3
|
is distributed under the GNU Affero General Public License, Version 3
|
||||||
@ -16,10 +16,6 @@ The documentation to this software is also distributed under the [GNU
|
|||||||
Free Documentation License](http://www.gnu.org/licenses/fdl.html),
|
Free Documentation License](http://www.gnu.org/licenses/fdl.html),
|
||||||
version 1.3 or later.
|
version 1.3 or later.
|
||||||
|
|
||||||
In default form, Plinth incorporates FileDict, a Python module
|
|
||||||
released under a "MIT/BSD/Python" license, as per [its blog
|
|
||||||
page](https://erezsh.wordpress.com/2009/05/31/filedict-bug-fixes-and-updates/).
|
|
||||||
|
|
||||||
## GNU Affero General Public License, Version 3
|
## GNU Affero General Public License, Version 3
|
||||||
|
|
||||||
GNU AFFERO GENERAL PUBLIC LICENSE
|
GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
|||||||
5
LICENSES
5
LICENSES
@ -9,18 +9,15 @@ specified and linked otherwise.
|
|||||||
- COPYING :: N/A
|
- COPYING :: N/A
|
||||||
- COPYRIGHTS :: N/A
|
- COPYRIGHTS :: N/A
|
||||||
- fabfile.py :: -
|
- fabfile.py :: -
|
||||||
- filedict.py :: [[http://erez.wikidot.com/filedict-0-1-code][CC-BY-SA 3.0]]
|
|
||||||
- INSTALL :: -
|
- INSTALL :: -
|
||||||
- logger.py :: -
|
- logger.py :: -
|
||||||
- Makefile :: -
|
- Makefile :: -
|
||||||
- menu.py :: -
|
- menu.py :: -
|
||||||
- model.py :: -
|
|
||||||
- NOTES :: -
|
- NOTES :: -
|
||||||
- plinth :: -
|
- plinth :: -
|
||||||
- plinth.config :: -
|
- plinth.config :: -
|
||||||
- plinth.py :: [[file:plinth.py::__license__%20%3D%20"GPLv3%20or%20later"]["GPLv3 or later"]]
|
- plinth.py :: [[file:plinth.py::__license__%20%3D%20"GPLv3%20or%20later"]["GPLv3 or later"]]
|
||||||
- plinth.sample.config :: -
|
- plinth.sample.config :: -
|
||||||
- plugin_mount.py :: [[http://martyalchin.com/2008/jan/10/simple-plugin-framework/][CC-BY-SA 3.0]]
|
|
||||||
- README :: -
|
- README :: -
|
||||||
- start.sh :: -
|
- start.sh :: -
|
||||||
- test.sh :: -
|
- test.sh :: -
|
||||||
@ -51,9 +48,7 @@ specified and linked otherwise.
|
|||||||
- modules/expert_mode/expert_mode.py :: -
|
- modules/expert_mode/expert_mode.py :: -
|
||||||
- modules/first_boot/first_boot.py :: -
|
- modules/first_boot/first_boot.py :: -
|
||||||
- modules/help/help.py :: -
|
- modules/help/help.py :: -
|
||||||
- modules/lib/auth_page.py :: -
|
|
||||||
- modules/lib/auth.py :: -
|
- modules/lib/auth.py :: -
|
||||||
- modules/lib/user_store.py :: -
|
|
||||||
- modules/owncloud/owncloud.py :: -
|
- modules/owncloud/owncloud.py :: -
|
||||||
- modules/packages/packages.py :: -
|
- modules/packages/packages.py :: -
|
||||||
- modules/santiago/santiago.py :: -
|
- modules/santiago/santiago.py :: -
|
||||||
|
|||||||
2
cfg.py
2
cfg.py
@ -19,7 +19,7 @@ host = None
|
|||||||
port = None
|
port = None
|
||||||
debug = False
|
debug = False
|
||||||
no_daemon = False
|
no_daemon = False
|
||||||
session_key = '_username'
|
server_dir = ''
|
||||||
|
|
||||||
main_menu = Menu()
|
main_menu = Menu()
|
||||||
|
|
||||||
|
|||||||
152
filedict.py
152
filedict.py
@ -1,152 +0,0 @@
|
|||||||
"""filedict.py
|
|
||||||
a Persistent Dictionary in Python
|
|
||||||
|
|
||||||
Author: Erez Shinan
|
|
||||||
Date : 31-May-2009
|
|
||||||
"""
|
|
||||||
|
|
||||||
import json
|
|
||||||
|
|
||||||
import UserDict
|
|
||||||
|
|
||||||
import sqlite3
|
|
||||||
|
|
||||||
|
|
||||||
class DefaultArg(object):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class Solutions(object):
|
|
||||||
Sqlite3 = 0
|
|
||||||
|
|
||||||
|
|
||||||
class FileDict(UserDict.DictMixin):
|
|
||||||
"A dictionary that stores its data persistantly in a file"
|
|
||||||
|
|
||||||
def __init__(self, solution=Solutions.Sqlite3, **options):
|
|
||||||
assert solution == Solutions.Sqlite3
|
|
||||||
try:
|
|
||||||
self.__conn = options.pop('connection')
|
|
||||||
except KeyError:
|
|
||||||
filename = options.pop('filename')
|
|
||||||
self.__conn = sqlite3.connect(filename)
|
|
||||||
|
|
||||||
self.__tablename = options.pop('table', 'dict')
|
|
||||||
|
|
||||||
self._nocommit = False
|
|
||||||
|
|
||||||
assert not options, "Unrecognized options: %s" % options
|
|
||||||
|
|
||||||
self.__conn.execute('create table if not exists %s (id integer primary key, hash integer, key blob, value blob);'%self.__tablename)
|
|
||||||
self.__conn.execute('create index if not exists %s_index ON %s(hash);' % (self.__tablename, self.__tablename))
|
|
||||||
self.__conn.commit()
|
|
||||||
|
|
||||||
def _commit(self):
|
|
||||||
if self._nocommit:
|
|
||||||
return
|
|
||||||
|
|
||||||
self.__conn.commit()
|
|
||||||
|
|
||||||
def __pack(self, value):
|
|
||||||
return sqlite3.Binary(json.dumps(value))
|
|
||||||
##return sqlite3.Binary(pickle.dumps(value, -1))
|
|
||||||
def __unpack(self, value):
|
|
||||||
return json.loads(str(value))
|
|
||||||
##return pickle.loads(str(value))
|
|
||||||
|
|
||||||
def __get_id(self, key):
|
|
||||||
cursor = self.__conn.execute('select key,id from %s where hash=?;'%self.__tablename, (hash(key),))
|
|
||||||
for k,id in cursor:
|
|
||||||
if self.__unpack(k) == key:
|
|
||||||
return id
|
|
||||||
|
|
||||||
raise KeyError(key)
|
|
||||||
|
|
||||||
def __getitem__(self, key):
|
|
||||||
cursor = self.__conn.execute('select key,value from %s where hash=?;'%self.__tablename, (hash(key),))
|
|
||||||
for k,v in cursor:
|
|
||||||
if self.__unpack(k) == key:
|
|
||||||
return self.__unpack(v)
|
|
||||||
|
|
||||||
raise KeyError(key)
|
|
||||||
|
|
||||||
def __setitem(self, key, value):
|
|
||||||
value_pickle = self.__pack(value)
|
|
||||||
|
|
||||||
try:
|
|
||||||
id = self.__get_id(key)
|
|
||||||
cursor = self.__conn.execute('update %s set value=? where id=?;'%self.__tablename, (value_pickle, id) )
|
|
||||||
except KeyError:
|
|
||||||
key_pickle = self.__pack(key)
|
|
||||||
cursor = self.__conn.execute('insert into %s (hash, key, value) values (?, ?, ?);'
|
|
||||||
%self.__tablename, (hash(key), key_pickle, value_pickle) )
|
|
||||||
|
|
||||||
assert cursor.rowcount == 1
|
|
||||||
|
|
||||||
def __setitem__(self, key, value):
|
|
||||||
self.__setitem(key, value)
|
|
||||||
self._commit()
|
|
||||||
|
|
||||||
def __delitem__(self, key):
|
|
||||||
id = self.__get_id(key)
|
|
||||||
cursor = self.__conn.execute('delete from %s where id=?;'%self.__tablename, (id,))
|
|
||||||
if cursor.rowcount <= 0:
|
|
||||||
raise KeyError(key)
|
|
||||||
|
|
||||||
self._commit()
|
|
||||||
|
|
||||||
def update(self, d):
|
|
||||||
for k,v in d.iteritems():
|
|
||||||
self.__setitem(k, v)
|
|
||||||
self._commit()
|
|
||||||
|
|
||||||
def __iter__(self):
|
|
||||||
return (self.__unpack(x[0]) for x in self.__conn.execute('select key from %s;'%self.__tablename) )
|
|
||||||
def keys(self):
|
|
||||||
return iter(self)
|
|
||||||
def values(self):
|
|
||||||
return (self.__unpack(x[0]) for x in self.__conn.execute('select value from %s;'%self.__tablename) )
|
|
||||||
def items(self):
|
|
||||||
return (map(self.__unpack, x) for x in self.__conn.execute('select key,value from %s;'%self.__tablename) )
|
|
||||||
def iterkeys(self):
|
|
||||||
return self.keys()
|
|
||||||
def itervalues(self):
|
|
||||||
return self.values()
|
|
||||||
def iteritems(self):
|
|
||||||
return self.items()
|
|
||||||
|
|
||||||
def __contains__(self, key):
|
|
||||||
try:
|
|
||||||
self.__get_id(key)
|
|
||||||
return True
|
|
||||||
except KeyError:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def __len__(self):
|
|
||||||
return self.__conn.execute('select count(*) from %s;' % self.__tablename).fetchone()[0]
|
|
||||||
|
|
||||||
def __del__(self):
|
|
||||||
try:
|
|
||||||
self.__conn
|
|
||||||
except AttributeError:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
self.__conn.commit()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def batch(self):
|
|
||||||
return self._Batch(self)
|
|
||||||
|
|
||||||
class _Batch(object):
|
|
||||||
def __init__(self, d):
|
|
||||||
self.__d = d
|
|
||||||
|
|
||||||
def __enter__(self):
|
|
||||||
self.__old_nocommit = self.__d._nocommit
|
|
||||||
self.__d._nocommit = True
|
|
||||||
return self.__d
|
|
||||||
|
|
||||||
def __exit__(self, type, value, traceback):
|
|
||||||
self.__d._nocommit = self.__old_nocommit
|
|
||||||
self.__d._commit()
|
|
||||||
return True
|
|
||||||
@ -14,11 +14,7 @@ def init():
|
|||||||
class Logger(object):
|
class Logger(object):
|
||||||
"""By convention, log levels are DEBUG, INFO, WARNING, ERROR and CRITICAL."""
|
"""By convention, log levels are DEBUG, INFO, WARNING, ERROR and CRITICAL."""
|
||||||
def log(self, msg, level="DEBUG"):
|
def log(self, msg, level="DEBUG"):
|
||||||
try:
|
cherrypy.log.error("%s %s" % (level, msg), inspect.stack()[2][3], 20)
|
||||||
username = cherrypy.session.get(cfg.session_key)
|
|
||||||
except AttributeError:
|
|
||||||
username = ''
|
|
||||||
cherrypy.log.error("%s %s %s" % (username, level, msg), inspect.stack()[2][3], 20)
|
|
||||||
def __call__(self, *args):
|
def __call__(self, *args):
|
||||||
self.log(*args)
|
self.log(*args)
|
||||||
|
|
||||||
|
|||||||
17
model.py
17
model.py
@ -1,17 +0,0 @@
|
|||||||
class User(dict):
|
|
||||||
""" Every user must have keys for a username, name, passphrase (this
|
|
||||||
is a bcrypt hash of the password), salt, groups, and an email address.
|
|
||||||
They can be blank or None, but the keys must exist. """
|
|
||||||
def __init__(self, dict=None):
|
|
||||||
super(User, self).__init__()
|
|
||||||
|
|
||||||
for key in ['username', 'name', 'passphrase', 'salt', 'email']:
|
|
||||||
self[key] = ''
|
|
||||||
for key in ['groups']:
|
|
||||||
self[key] = []
|
|
||||||
if dict:
|
|
||||||
for key in dict:
|
|
||||||
self[key] = dict[key]
|
|
||||||
|
|
||||||
def __getattr__(self, attr):
|
|
||||||
return None
|
|
||||||
@ -21,6 +21,7 @@ Plinth module for configuring timezone, hostname etc.
|
|||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.core import validators
|
from django.core import validators
|
||||||
from django.template.response import TemplateResponse
|
from django.template.response import TemplateResponse
|
||||||
from gettext import gettext as _
|
from gettext import gettext as _
|
||||||
@ -29,7 +30,6 @@ import socket
|
|||||||
|
|
||||||
import actions
|
import actions
|
||||||
import cfg
|
import cfg
|
||||||
from ..lib.auth import login_required
|
|
||||||
import util
|
import util
|
||||||
|
|
||||||
|
|
||||||
@ -102,7 +102,7 @@ def index(request):
|
|||||||
|
|
||||||
form = None
|
form = None
|
||||||
|
|
||||||
is_expert = cfg.users.expert(request=request)
|
is_expert = request.user.groups.filter(name='Expert').exists()
|
||||||
if request.method == 'POST' and is_expert:
|
if request.method == 'POST' and is_expert:
|
||||||
form = ConfigurationForm(request.POST, prefix='configuration')
|
form = ConfigurationForm(request.POST, prefix='configuration')
|
||||||
# pylint: disable-msg=E1101
|
# pylint: disable-msg=E1101
|
||||||
@ -160,9 +160,6 @@ def set_hostname(hostname):
|
|||||||
actions.superuser_run("xmpp-pre-hostname-change")
|
actions.superuser_run("xmpp-pre-hostname-change")
|
||||||
actions.superuser_run("hostname-change", hostname)
|
actions.superuser_run("hostname-change", hostname)
|
||||||
actions.superuser_run("xmpp-hostname-change", hostname, async=True)
|
actions.superuser_run("xmpp-hostname-change", hostname, async=True)
|
||||||
# don't persist/cache change unless it was saved successfuly
|
|
||||||
sys_store = util.filedict_con(cfg.store_file, 'sys')
|
|
||||||
sys_store['hostname'] = hostname
|
|
||||||
except OSError:
|
except OSError:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|||||||
@ -19,12 +19,12 @@
|
|||||||
Plinth module for running diagnostics
|
Plinth module for running diagnostics
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from gettext import gettext as _
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.template.response import TemplateResponse
|
from django.template.response import TemplateResponse
|
||||||
|
from gettext import gettext as _
|
||||||
|
|
||||||
import actions
|
import actions
|
||||||
import cfg
|
import cfg
|
||||||
from ..lib.auth import login_required
|
|
||||||
|
|
||||||
|
|
||||||
def init():
|
def init():
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
from django import forms
|
from django import forms
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.template.response import TemplateResponse
|
from django.template.response import TemplateResponse
|
||||||
from gettext import gettext as _
|
from gettext import gettext as _
|
||||||
|
|
||||||
import cfg
|
import cfg
|
||||||
from ..lib.auth import login_required
|
from ..lib.auth import get_group
|
||||||
|
|
||||||
|
|
||||||
class ExpertsForm(forms.Form): # pylint: disable-msg=W0232
|
class ExpertsForm(forms.Form): # pylint: disable-msg=W0232
|
||||||
@ -43,23 +44,21 @@ def index(request):
|
|||||||
|
|
||||||
def get_status(request):
|
def get_status(request):
|
||||||
"""Return the current status"""
|
"""Return the current status"""
|
||||||
return {'expert_mode': cfg.users.expert(request=request)}
|
return {'expert_mode': request.user.groups.filter(name='Expert').exists()}
|
||||||
|
|
||||||
|
|
||||||
def _apply_changes(request, new_status):
|
def _apply_changes(request, new_status):
|
||||||
"""Apply expert mode configuration"""
|
"""Apply expert mode configuration"""
|
||||||
message = (messages.info, _('Settings unchanged'))
|
message = (messages.info, _('Settings unchanged'))
|
||||||
|
|
||||||
user = cfg.users.current(request=request)
|
expert_group = get_group('Expert')
|
||||||
|
|
||||||
if new_status['expert_mode']:
|
if new_status['expert_mode']:
|
||||||
if not 'expert' in user['groups']:
|
if not expert_group in request.user.groups.all():
|
||||||
user['groups'].append('expert')
|
request.user.groups.add(expert_group)
|
||||||
message = (messages.success, _('Expert mode enabled'))
|
message = (messages.success, _('Expert mode enabled'))
|
||||||
else:
|
else:
|
||||||
if 'expert' in user['groups']:
|
if expert_group in request.user.groups.all():
|
||||||
user['groups'].remove('expert')
|
request.user.groups.remove(expert_group)
|
||||||
message = (messages.success, _('Expert mode disabled'))
|
message = (messages.success, _('Expert mode disabled'))
|
||||||
|
|
||||||
cfg.users.set(user['username'], user)
|
|
||||||
message[0](request, message[1])
|
message[0](request, message[1])
|
||||||
|
|||||||
@ -19,12 +19,12 @@
|
|||||||
Plinth module to configure a firewall
|
Plinth module to configure a firewall
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.template.response import TemplateResponse
|
from django.template.response import TemplateResponse
|
||||||
from gettext import gettext as _
|
from gettext import gettext as _
|
||||||
|
|
||||||
import actions
|
import actions
|
||||||
import cfg
|
import cfg
|
||||||
from ..lib.auth import login_required
|
|
||||||
import service as service_module
|
import service as service_module
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -20,9 +20,5 @@ Plinth library modules
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
from . import auth
|
from . import auth
|
||||||
from . import auth_page
|
|
||||||
from . import user_store
|
|
||||||
|
|
||||||
__all__ = ['auth',
|
__all__ = ['auth']
|
||||||
'auth_page',
|
|
||||||
'user_store']
|
|
||||||
|
|||||||
@ -1,98 +1,29 @@
|
|||||||
from django.http.response import HttpResponseRedirect
|
from django.contrib.auth.models import Group, User
|
||||||
import functools
|
|
||||||
from passlib.hash import bcrypt
|
|
||||||
from passlib.exc import PasswordSizeError
|
|
||||||
|
|
||||||
import cfg
|
|
||||||
from model import User
|
|
||||||
|
|
||||||
|
|
||||||
def add_user(username, passphrase, name='', email='', expert=False):
|
def add_user(username, passphrase, name='', email='', expert=False):
|
||||||
"""Add a new user with specified username and passphrase.
|
"""Add a new user with specified username and passphrase"""
|
||||||
"""
|
if not username:
|
||||||
error = None
|
return 'Must specify a username!'
|
||||||
if not username: error = "Must specify a username!"
|
|
||||||
if not passphrase: error = "Must specify a passphrase!"
|
|
||||||
|
|
||||||
if error is None:
|
if not passphrase:
|
||||||
if username in map(lambda x: x[0], cfg.users.get_all()):
|
return 'Must specify a passphrase!'
|
||||||
error = "User already exists!"
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
pass_hash = bcrypt.encrypt(passphrase)
|
|
||||||
except PasswordSizeError:
|
|
||||||
error = "Password is too long."
|
|
||||||
|
|
||||||
if error is None:
|
user = User.objects.create_user(username, email=email,
|
||||||
di = {
|
password=passphrase)
|
||||||
'username':username,
|
user.first_name = name
|
||||||
'name':name,
|
user.save()
|
||||||
'email':email,
|
|
||||||
'expert':'on' if expert else 'off',
|
|
||||||
'groups':['expert'] if expert else [],
|
|
||||||
'passphrase':pass_hash,
|
|
||||||
'salt':pass_hash[7:29], # for bcrypt
|
|
||||||
}
|
|
||||||
new_user = User(di)
|
|
||||||
cfg.users.set(username,new_user)
|
|
||||||
|
|
||||||
if error:
|
if expert:
|
||||||
cfg.log(error)
|
user.groups.add(get_group('Expert'))
|
||||||
return error
|
|
||||||
|
|
||||||
|
|
||||||
def check_credentials(username, passphrase):
|
def get_group(name):
|
||||||
"""Verifies credentials for username and passphrase.
|
"""Return an existing or newly created group with given name"""
|
||||||
|
|
||||||
Returns None on success or a string describing the error on failure.
|
|
||||||
|
|
||||||
Handles passwords up to 4096 bytes:
|
|
||||||
|
|
||||||
>>> len("A" * 4096)
|
|
||||||
4096
|
|
||||||
>>> len(u"u|2603" * 682)
|
|
||||||
4092
|
|
||||||
|
|
||||||
"""
|
|
||||||
if not username or not passphrase:
|
|
||||||
error = "No username or password."
|
|
||||||
cfg.log(error)
|
|
||||||
return error
|
|
||||||
|
|
||||||
bad_authentication = "Bad username or password."
|
|
||||||
hashed_password = None
|
|
||||||
|
|
||||||
if username not in cfg.users or 'passphrase' not in cfg.users[username]:
|
|
||||||
cfg.log(bad_authentication)
|
|
||||||
return bad_authentication
|
|
||||||
|
|
||||||
hashed_password = cfg.users[username]['passphrase']
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# time-dependent comparison when non-ASCII characters are used.
|
group = Group.objects.get(name__exact=name)
|
||||||
if not bcrypt.verify(passphrase, hashed_password):
|
except Group.DoesNotExist:
|
||||||
error = bad_authentication
|
group = Group(name=name)
|
||||||
else:
|
group.save()
|
||||||
error = None
|
|
||||||
except PasswordSizeError:
|
|
||||||
error = bad_authentication
|
|
||||||
|
|
||||||
if error:
|
return group
|
||||||
cfg.log(error)
|
|
||||||
|
|
||||||
return error
|
|
||||||
|
|
||||||
|
|
||||||
# XXX: Only required until we start using Django authentication system properly
|
|
||||||
def login_required(func):
|
|
||||||
"""A decorator to ensure that user is logged in before accessing a view"""
|
|
||||||
@functools.wraps(func)
|
|
||||||
def wrapper(request, *args, **kwargs):
|
|
||||||
"""Check that user is logged in"""
|
|
||||||
if not request.session.get(cfg.session_key, None):
|
|
||||||
return HttpResponseRedirect(
|
|
||||||
cfg.server_dir + "/auth/login?from_page=%s" % request.path)
|
|
||||||
|
|
||||||
return func(request, *args, **kwargs)
|
|
||||||
|
|
||||||
return wrapper
|
|
||||||
|
|||||||
@ -1,67 +0,0 @@
|
|||||||
"""
|
|
||||||
Controller to provide login and logout actions
|
|
||||||
"""
|
|
||||||
|
|
||||||
import cfg
|
|
||||||
from django import forms
|
|
||||||
from django.http.response import HttpResponseRedirect
|
|
||||||
from django.template.response import TemplateResponse
|
|
||||||
from gettext import gettext as _
|
|
||||||
|
|
||||||
from . import auth
|
|
||||||
|
|
||||||
|
|
||||||
class LoginForm(forms.Form): # pylint: disable-msg=W0232
|
|
||||||
"""Login form"""
|
|
||||||
username = forms.CharField(label=_('Username'))
|
|
||||||
password = forms.CharField(label=_('Passphrase'),
|
|
||||||
widget=forms.PasswordInput())
|
|
||||||
|
|
||||||
def clean(self):
|
|
||||||
"""Check for valid credentials"""
|
|
||||||
# pylint: disable-msg=E1101
|
|
||||||
if 'username' in self._errors or 'password' in self._errors:
|
|
||||||
return self.cleaned_data
|
|
||||||
|
|
||||||
error_msg = auth.check_credentials(self.cleaned_data['username'],
|
|
||||||
self.cleaned_data['password'])
|
|
||||||
if error_msg:
|
|
||||||
raise forms.ValidationError(error_msg, code='invalid_credentials')
|
|
||||||
|
|
||||||
return self.cleaned_data
|
|
||||||
|
|
||||||
|
|
||||||
def login(request):
|
|
||||||
"""Serve the login page"""
|
|
||||||
form = None
|
|
||||||
|
|
||||||
if request.method == 'POST':
|
|
||||||
form = LoginForm(request.POST, prefix='auth')
|
|
||||||
# pylint: disable-msg=E1101
|
|
||||||
if form.is_valid():
|
|
||||||
username = form.cleaned_data['username']
|
|
||||||
request.session[cfg.session_key] = username
|
|
||||||
return HttpResponseRedirect(_get_from_page(request))
|
|
||||||
else:
|
|
||||||
form = LoginForm(prefix='auth')
|
|
||||||
|
|
||||||
return TemplateResponse(request, 'form.html',
|
|
||||||
{'title': _('Login'),
|
|
||||||
'form': form,
|
|
||||||
'submit_text': _('Login')})
|
|
||||||
|
|
||||||
|
|
||||||
def logout(request):
|
|
||||||
"""Logout and redirect to origin page"""
|
|
||||||
try:
|
|
||||||
del request.session[cfg.session_key]
|
|
||||||
request.session.flush()
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
return HttpResponseRedirect(_get_from_page(request))
|
|
||||||
|
|
||||||
|
|
||||||
def _get_from_page(request):
|
|
||||||
"""Return the 'from page' of a request"""
|
|
||||||
return request.GET.get('from_page', cfg.server_dir + '/')
|
|
||||||
@ -21,9 +21,13 @@ URLs for the Lib module
|
|||||||
|
|
||||||
from django.conf.urls import patterns, url
|
from django.conf.urls import patterns, url
|
||||||
|
|
||||||
|
import cfg
|
||||||
|
|
||||||
|
|
||||||
urlpatterns = patterns( # pylint: disable-msg=C0103
|
urlpatterns = patterns( # pylint: disable-msg=C0103
|
||||||
'modules.lib.auth_page',
|
'',
|
||||||
url(r'^auth/login/$', 'login'),
|
url(r'^accounts/login/$', 'django.contrib.auth.views.login',
|
||||||
url(r'^auth/logout/$', 'logout')
|
{'template_name': 'login.html'}),
|
||||||
|
url(r'^accounts/logout/$', 'django.contrib.auth.views.logout',
|
||||||
|
{'next_page': cfg.server_dir})
|
||||||
)
|
)
|
||||||
|
|||||||
@ -1,73 +0,0 @@
|
|||||||
import cfg
|
|
||||||
from model import User
|
|
||||||
from plugin_mount import UserStoreModule
|
|
||||||
from withsqlite.withsqlite import sqlite_db
|
|
||||||
|
|
||||||
|
|
||||||
class UserStore(UserStoreModule, sqlite_db):
|
|
||||||
def __init__(self):
|
|
||||||
super(UserStore, self).__init__()
|
|
||||||
|
|
||||||
self.db_file = cfg.user_db
|
|
||||||
sqlite_db.__init__(self, self.db_file, autocommit=True, check_same_thread=False)
|
|
||||||
self.__enter__()
|
|
||||||
|
|
||||||
def close(self):
|
|
||||||
self.__exit__(None,None,None)
|
|
||||||
|
|
||||||
def current(self, request=None, name=False):
|
|
||||||
"""Return current user, if there is one, else None.
|
|
||||||
If name = True, return the username instead of the user."""
|
|
||||||
if not request:
|
|
||||||
return None
|
|
||||||
|
|
||||||
try:
|
|
||||||
username = request.session[cfg.session_key]
|
|
||||||
except KeyError:
|
|
||||||
return None
|
|
||||||
|
|
||||||
if name:
|
|
||||||
return username
|
|
||||||
|
|
||||||
return self.get(username)
|
|
||||||
|
|
||||||
def expert(self, username=None, request=None):
|
|
||||||
"""Return whether the current or provided user is an expert"""
|
|
||||||
if not username:
|
|
||||||
if not request:
|
|
||||||
return False
|
|
||||||
|
|
||||||
username = self.current(request=request, name=True)
|
|
||||||
|
|
||||||
groups = self.attr(username, 'groups')
|
|
||||||
|
|
||||||
if not groups:
|
|
||||||
return False
|
|
||||||
|
|
||||||
return 'expert' in groups
|
|
||||||
|
|
||||||
def attr(self, username=None, field=None):
|
|
||||||
return self.get(username)[field]
|
|
||||||
|
|
||||||
def get(self,username=None):
|
|
||||||
return User(sqlite_db.get(self,username))
|
|
||||||
|
|
||||||
def exists(self, username=None):
|
|
||||||
try:
|
|
||||||
user = self.get(username)
|
|
||||||
if not user:
|
|
||||||
return False
|
|
||||||
elif user["username"]=='':
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
except TypeError:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def remove(self,username=None):
|
|
||||||
self.__delitem__(username)
|
|
||||||
|
|
||||||
def get_all(self):
|
|
||||||
return self.items()
|
|
||||||
|
|
||||||
def set(self,username=None,user=None):
|
|
||||||
sqlite_db.__setitem__(self,username, user)
|
|
||||||
@ -1,11 +1,11 @@
|
|||||||
from django import forms
|
from django import forms
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.template.response import TemplateResponse
|
from django.template.response import TemplateResponse
|
||||||
from gettext import gettext as _
|
from gettext import gettext as _
|
||||||
|
|
||||||
import actions
|
import actions
|
||||||
import cfg
|
import cfg
|
||||||
from ..lib.auth import login_required
|
|
||||||
import service
|
import service
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
from django import forms
|
from django import forms
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.template.response import TemplateResponse
|
from django.template.response import TemplateResponse
|
||||||
from gettext import gettext as _
|
from gettext import gettext as _
|
||||||
|
|
||||||
import actions
|
import actions
|
||||||
import cfg
|
import cfg
|
||||||
from ..lib.auth import login_required
|
|
||||||
|
|
||||||
|
|
||||||
def get_modules_available():
|
def get_modules_available():
|
||||||
|
|||||||
@ -21,6 +21,7 @@ Plinth module for configuring PageKite service
|
|||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.core import validators
|
from django.core import validators
|
||||||
from django.template import RequestContext
|
from django.template import RequestContext
|
||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
@ -29,7 +30,6 @@ from gettext import gettext as _
|
|||||||
|
|
||||||
import actions
|
import actions
|
||||||
import cfg
|
import cfg
|
||||||
from ..lib.auth import login_required
|
|
||||||
|
|
||||||
|
|
||||||
def init():
|
def init():
|
||||||
|
|||||||
@ -19,12 +19,12 @@
|
|||||||
Plinth module for configuring Tor
|
Plinth module for configuring Tor
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.template.response import TemplateResponse
|
from django.template.response import TemplateResponse
|
||||||
from gettext import gettext as _
|
from gettext import gettext as _
|
||||||
|
|
||||||
import actions
|
import actions
|
||||||
import cfg
|
import cfg
|
||||||
from ..lib.auth import login_required
|
|
||||||
|
|
||||||
|
|
||||||
def init():
|
def init():
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
from django import forms
|
from django import forms
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
|
from django.contrib.auth.decorators import login_required
|
||||||
|
from django.contrib.auth.models import User
|
||||||
from django.core import validators
|
from django.core import validators
|
||||||
from django.template import RequestContext
|
from django.template import RequestContext
|
||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
@ -7,8 +9,7 @@ from django.template.response import TemplateResponse
|
|||||||
from gettext import gettext as _
|
from gettext import gettext as _
|
||||||
|
|
||||||
import cfg
|
import cfg
|
||||||
from ..lib.auth import add_user, login_required
|
from ..lib.auth import add_user
|
||||||
from model import User
|
|
||||||
|
|
||||||
|
|
||||||
def init():
|
def init():
|
||||||
@ -72,7 +73,7 @@ def add(request):
|
|||||||
|
|
||||||
def _add_user(request, data):
|
def _add_user(request, data):
|
||||||
"""Add a user"""
|
"""Add a user"""
|
||||||
if cfg.users.exists(data['username']):
|
if User.objects.filter(username=data['username']).exists():
|
||||||
messages.error(request, _('User "{username}" already exists').format(
|
messages.error(request, _('User "{username}" already exists').format(
|
||||||
username=data['username']))
|
username=data['username']))
|
||||||
return
|
return
|
||||||
@ -89,14 +90,11 @@ class UserEditForm(forms.Form): # pylint: disable-msg=W0232
|
|||||||
# pylint: disable-msg=E1002
|
# pylint: disable-msg=E1002
|
||||||
super(forms.Form, self).__init__(*args, **kwargs)
|
super(forms.Form, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
users = cfg.users.get_all()
|
for user in User.objects.all():
|
||||||
for uname in users:
|
label = '%s (%s)' % (user.first_name, user.username)
|
||||||
user = User(uname[1])
|
|
||||||
|
|
||||||
label = '%s (%s)' % (user['name'], user['username'])
|
|
||||||
field = forms.BooleanField(label=label, required=False)
|
field = forms.BooleanField(label=label, required=False)
|
||||||
# pylint: disable-msg=E1101
|
# pylint: disable-msg=E1101
|
||||||
self.fields['delete_user_' + user['username']] = field
|
self.fields['delete_user_' + user.username] = field
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@ -129,21 +127,21 @@ def _apply_edit_changes(request, data):
|
|||||||
|
|
||||||
username = field.split('delete_user_')[1]
|
username = field.split('delete_user_')[1]
|
||||||
|
|
||||||
requesting_user = request.session.get(cfg.session_key, None)
|
requesting_user = request.user.username
|
||||||
cfg.log.info('%s asked to delete %s' %
|
cfg.log.info('%s asked to delete %s' %
|
||||||
(requesting_user, username))
|
(requesting_user, username))
|
||||||
|
|
||||||
if username == cfg.users.current(request=request, name=True):
|
if username == requesting_user:
|
||||||
messages.error(
|
messages.error(
|
||||||
request, _('Can not delete current account - "%s"') % username)
|
request, _('Can not delete current account - "%s"') % username)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if not cfg.users.exists(username):
|
if not User.objects.filter(username=username).exists():
|
||||||
messages.error(request, _('User "%s" does not exist') % username)
|
messages.error(request, _('User "%s" does not exist') % username)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
try:
|
try:
|
||||||
cfg.users.remove(username)
|
User.objects.filter(username=username).delete()
|
||||||
messages.success(request, _('User "%s" deleted') % username)
|
messages.success(request, _('User "%s" deleted') % username)
|
||||||
except IOError as exception:
|
except IOError as exception:
|
||||||
messages.error(request, _('Error deleting "%s" - %s') %
|
messages.error(request, _('Error deleting "%s" - %s') %
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
from django import forms
|
from django import forms
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.template import RequestContext
|
from django.template import RequestContext
|
||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
from django.template.response import TemplateResponse
|
from django.template.response import TemplateResponse
|
||||||
@ -7,7 +8,6 @@ from gettext import gettext as _
|
|||||||
|
|
||||||
import actions
|
import actions
|
||||||
import cfg
|
import cfg
|
||||||
from ..lib.auth import login_required
|
|
||||||
import service
|
import service
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
33
plinth.py
33
plinth.py
@ -1,10 +1,12 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import django.conf
|
import django.conf
|
||||||
|
import django.core.management
|
||||||
import django.core.wsgi
|
import django.core.wsgi
|
||||||
|
import os
|
||||||
|
import stat
|
||||||
|
import sys
|
||||||
|
|
||||||
import cherrypy
|
import cherrypy
|
||||||
from cherrypy import _cpserver
|
from cherrypy import _cpserver
|
||||||
@ -12,7 +14,6 @@ from cherrypy.process.plugins import Daemonizer
|
|||||||
|
|
||||||
import cfg
|
import cfg
|
||||||
import module_loader
|
import module_loader
|
||||||
import plugin_mount
|
|
||||||
import service
|
import service
|
||||||
|
|
||||||
import logger
|
import logger
|
||||||
@ -112,7 +113,6 @@ def context_processor(request):
|
|||||||
'submenu': cfg.main_menu.active_item(request),
|
'submenu': cfg.main_menu.active_item(request),
|
||||||
'request_path': request.path,
|
'request_path': request.path,
|
||||||
'basehref': cfg.server_dir,
|
'basehref': cfg.server_dir,
|
||||||
'username': request.session.get(cfg.session_key, None),
|
|
||||||
'active_menu_urls': active_menu_urls
|
'active_menu_urls': active_menu_urls
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,19 +129,36 @@ def configure_django():
|
|||||||
'django.contrib.messages.context_processors.messages',
|
'django.contrib.messages.context_processors.messages',
|
||||||
'plinth.context_processor']
|
'plinth.context_processor']
|
||||||
|
|
||||||
|
data_file = os.path.join(cfg.data_dir, 'plinth.sqlite3')
|
||||||
|
|
||||||
template_directories = module_loader.get_template_directories()
|
template_directories = module_loader.get_template_directories()
|
||||||
sessions_directory = os.path.join(cfg.data_dir, 'sessions')
|
sessions_directory = os.path.join(cfg.data_dir, 'sessions')
|
||||||
django.conf.settings.configure(
|
django.conf.settings.configure(
|
||||||
DEBUG=cfg.debug,
|
|
||||||
ALLOWED_HOSTS=['127.0.0.1', 'localhost'],
|
ALLOWED_HOSTS=['127.0.0.1', 'localhost'],
|
||||||
TEMPLATE_DIRS=template_directories,
|
CACHES={'default':
|
||||||
|
{'BACKEND': 'django.core.cache.backends.dummy.DummyCache'}},
|
||||||
|
DATABASES={'default':
|
||||||
|
{'ENGINE': 'django.db.backends.sqlite3',
|
||||||
|
'NAME': data_file}},
|
||||||
|
DEBUG=cfg.debug,
|
||||||
INSTALLED_APPS=['bootstrapform',
|
INSTALLED_APPS=['bootstrapform',
|
||||||
|
'django.contrib.auth',
|
||||||
|
'django.contrib.contenttypes',
|
||||||
'django.contrib.messages'],
|
'django.contrib.messages'],
|
||||||
|
LOGIN_URL=cfg.server_dir + '/accounts/login/',
|
||||||
|
LOGIN_REDIRECT_URL=cfg.server_dir + '/',
|
||||||
|
LOGOUT_URL=cfg.server_dir + '/accounts/logout/',
|
||||||
ROOT_URLCONF='urls',
|
ROOT_URLCONF='urls',
|
||||||
SESSION_ENGINE='django.contrib.sessions.backends.file',
|
SESSION_ENGINE='django.contrib.sessions.backends.file',
|
||||||
SESSION_FILE_PATH=sessions_directory,
|
SESSION_FILE_PATH=sessions_directory,
|
||||||
STATIC_URL=cfg.server_dir + '/static/',
|
STATIC_URL=cfg.server_dir + '/static/',
|
||||||
TEMPLATE_CONTEXT_PROCESSORS=context_processors)
|
TEMPLATE_CONTEXT_PROCESSORS=context_processors,
|
||||||
|
TEMPLATE_DIRS=template_directories)
|
||||||
|
|
||||||
|
if not os.path.isfile(data_file):
|
||||||
|
cfg.log.info('Creating and initializing data file')
|
||||||
|
django.core.management.call_command('syncdb', interactive=False)
|
||||||
|
os.chmod(data_file, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
@ -160,8 +177,6 @@ def main():
|
|||||||
|
|
||||||
module_loader.load_modules()
|
module_loader.load_modules()
|
||||||
|
|
||||||
cfg.users = plugin_mount.UserStoreModule.get_plugins()[0]
|
|
||||||
|
|
||||||
setup_server()
|
setup_server()
|
||||||
|
|
||||||
cherrypy.engine.start()
|
cherrypy.engine.start()
|
||||||
|
|||||||
@ -1,54 +0,0 @@
|
|||||||
import cfg
|
|
||||||
|
|
||||||
|
|
||||||
class PluginMount(type):
|
|
||||||
"""See http://martyalchin.com/2008/jan/10/simple-plugin-framework/ for documentation"""
|
|
||||||
def __init__(cls, name, bases, attrs):
|
|
||||||
if not hasattr(cls, 'plugins'):
|
|
||||||
cls.plugins = []
|
|
||||||
else:
|
|
||||||
cls.plugins.append(cls)
|
|
||||||
|
|
||||||
def init_plugins(cls, *args, **kwargs):
|
|
||||||
try:
|
|
||||||
cls.plugins = sorted(cls.plugins, key=lambda x: x.order, reverse=False)
|
|
||||||
except AttributeError:
|
|
||||||
pass
|
|
||||||
return [p(*args, **kwargs) for p in cls.plugins]
|
|
||||||
def get_plugins(cls, *args, **kwargs):
|
|
||||||
return cls.init_plugins(*args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class MultiplePluginViolation(Exception):
|
|
||||||
"""Multiple plugins found for a type where only one is expected"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class PluginMountSingular(PluginMount):
|
|
||||||
"""Plugin mounter that allows only one plugin of this meta type"""
|
|
||||||
def __init__(cls, name, bases, attrs):
|
|
||||||
if not hasattr(cls, 'plugins'):
|
|
||||||
cls.plugins = []
|
|
||||||
else:
|
|
||||||
if len(cls.plugins) > 0:
|
|
||||||
raise MultiplePluginViolation
|
|
||||||
cls.plugins.append(cls)
|
|
||||||
|
|
||||||
|
|
||||||
class UserStoreModule(object):
|
|
||||||
"""
|
|
||||||
Mount Point for plugins that will manage the user backend storage,
|
|
||||||
where we keep a hash for each user.
|
|
||||||
|
|
||||||
Plugins implementing this reference should provide the following
|
|
||||||
methods, as described in the doc strings of the default
|
|
||||||
user_store.py: get, get_all, set, exists, remove, attr, expert.
|
|
||||||
See source code for doc strings.
|
|
||||||
|
|
||||||
This is designed as a plugin so mutiple types of user store can be
|
|
||||||
supported. But the project is moving towards LDAP for
|
|
||||||
compatibility with third party software. A future version of
|
|
||||||
Plinth is likely to require LDAP.
|
|
||||||
"""
|
|
||||||
# Singular because we can only use one user store at a time
|
|
||||||
__metaclass__ = PluginMountSingular
|
|
||||||
@ -82,18 +82,18 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
{% if username %}
|
{% if user.is_authenticated %}
|
||||||
<p class="navbar-text pull-right">
|
<p class="navbar-text pull-right">
|
||||||
<i class="icon-user icon-white nav-icon"></i>
|
<i class="icon-user icon-white nav-icon"></i>
|
||||||
Logged in as <a href="{{ username }}">{{ username }}</a>.
|
Logged in as <a href="{{ user.username }}">{{ user.username }}</a>.
|
||||||
<a href="{{ basehref }}/auth/logout" title="Log out">
|
<a href="{{ basehref }}/accounts/logout" title="Log out">
|
||||||
Log out</a>.
|
Log out</a>.
|
||||||
</p>
|
</p>
|
||||||
{% else %}
|
{% else %}
|
||||||
<p class="navbar-text pull-right">
|
<p class="navbar-text pull-right">
|
||||||
Not logged in.
|
Not logged in.
|
||||||
<i class="icon-user icon-white nav-icon"></i>
|
<i class="icon-user icon-white nav-icon"></i>
|
||||||
<a href="{{ basehref }}/auth/login" title="Log in">
|
<a href="{{ basehref }}/accounts/login" title="Log in">
|
||||||
Log in</a>.
|
Log in</a>.
|
||||||
</p>
|
</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@ -22,8 +22,6 @@
|
|||||||
|
|
||||||
{% block main_block %}
|
{% block main_block %}
|
||||||
|
|
||||||
{% include 'messages.html' %}
|
|
||||||
|
|
||||||
<form class="form" method="post">
|
<form class="form" method="post">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
|
|
||||||
|
|||||||
34
templates/login.html
Normal file
34
templates/login.html
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
{% 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 main_block %}
|
||||||
|
|
||||||
|
<form class="form" method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
|
||||||
|
{{ form|bootstrap }}
|
||||||
|
|
||||||
|
<input type="submit" class="btn-primary" value="Login" />
|
||||||
|
<input type="hidden" name="next" value="{{ next }}" />
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
14
util.py
14
util.py
@ -1,9 +1,4 @@
|
|||||||
import os
|
import os
|
||||||
import sys
|
|
||||||
import cfg
|
|
||||||
import sqlite3
|
|
||||||
|
|
||||||
from filedict import FileDict
|
|
||||||
|
|
||||||
|
|
||||||
def mkdir(newdir):
|
def mkdir(newdir):
|
||||||
@ -34,12 +29,3 @@ def slurp(filespec):
|
|||||||
def unslurp(filespec, msg):
|
def unslurp(filespec, msg):
|
||||||
with open(filespec, 'w') as x:
|
with open(filespec, 'w') as x:
|
||||||
x.write(msg)
|
x.write(msg)
|
||||||
|
|
||||||
|
|
||||||
def filedict_con(filespec=None, table='dict'):
|
|
||||||
"""TODO: better error handling in filedict_con"""
|
|
||||||
try:
|
|
||||||
return FileDict(connection=sqlite3.connect(filespec), table=table)
|
|
||||||
except IOError as (errno, strerror):
|
|
||||||
cfg.log.critical("I/O error({0}): {1}".format(errno, strerror))
|
|
||||||
sys.exit(-1)
|
|
||||||
|
|||||||
8
views.py
8
views.py
@ -20,8 +20,6 @@ Main Plinth views
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
from django.http.response import HttpResponseRedirect
|
from django.http.response import HttpResponseRedirect
|
||||||
import os
|
|
||||||
import stat
|
|
||||||
|
|
||||||
import cfg
|
import cfg
|
||||||
from withsqlite.withsqlite import sqlite_db
|
from withsqlite.withsqlite import sqlite_db
|
||||||
@ -32,10 +30,6 @@ def index(request):
|
|||||||
# TODO: Move firstboot handling to firstboot module somehow
|
# TODO: Move firstboot handling to firstboot module somehow
|
||||||
with sqlite_db(cfg.store_file, table='firstboot') as database:
|
with sqlite_db(cfg.store_file, table='firstboot') as database:
|
||||||
if not 'state' in database:
|
if not 'state' in database:
|
||||||
# If we created a new user db, make sure it can't be read by
|
|
||||||
# everyone
|
|
||||||
userdb_fname = '{}.sqlite3'.format(cfg.user_db)
|
|
||||||
os.chmod(userdb_fname, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP)
|
|
||||||
# Permanent redirect causes the browser to cache the redirect,
|
# Permanent redirect causes the browser to cache the redirect,
|
||||||
# preventing the user from navigating to /plinth until the
|
# preventing the user from navigating to /plinth until the
|
||||||
# browser is restarted.
|
# browser is restarted.
|
||||||
@ -46,7 +40,7 @@ def index(request):
|
|||||||
return HttpResponseRedirect(
|
return HttpResponseRedirect(
|
||||||
cfg.server_dir + '/firstboot/state%d' % database['state'])
|
cfg.server_dir + '/firstboot/state%d' % database['state'])
|
||||||
|
|
||||||
if request.session.get(cfg.session_key, None):
|
if request.user.is_authenticated():
|
||||||
return HttpResponseRedirect(cfg.server_dir + '/apps')
|
return HttpResponseRedirect(cfg.server_dir + '/apps')
|
||||||
|
|
||||||
return HttpResponseRedirect(cfg.server_dir + '/help/about')
|
return HttpResponseRedirect(cfg.server_dir + '/help/about')
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user