Merge branch 'master' into first-boot-create-user

Resolve conflicts in modules/installed/first_boot.py.
This commit is contained in:
Petter Reinholdtsen 2013-09-16 05:27:57 +02:00
commit f24d1fb94d
15 changed files with 83 additions and 37 deletions

View File

@ -4,6 +4,7 @@ CSS=$(wildcard *.css)
CSS=$(subst .tiny,,$(shell find themes -type f -name '*.css')) CSS=$(subst .tiny,,$(shell find themes -type f -name '*.css'))
COMPRESSED_CSS := $(patsubst %.css,%.tiny.css,$(CSS)) COMPRESSED_CSS := $(patsubst %.css,%.tiny.css,$(CSS))
PWD=`pwd` PWD=`pwd`
BUILDDIR=vendor
# hosting variables # hosting variables
SLEEP_TIME=300 SLEEP_TIME=300
@ -29,6 +30,8 @@ install: default
$(DESTDIR)/usr/share/doc/plinth $(DESTDIR)/usr/share/man/man1 $(DESTDIR)/usr/share/doc/plinth $(DESTDIR)/usr/share/man/man1
cp -a static themes $(DESTDIR)$(DATADIR)/ cp -a static themes $(DESTDIR)$(DATADIR)/
cp -a *.py modules templates $(DESTDIR)$(PYDIR)/ cp -a *.py modules templates $(DESTDIR)$(PYDIR)/
mkdir -p $(DESTDIR)$(PYDIR)/exmachina
cp -a vendor/exmachina/exmachina.py $(DESTDIR)$(PYDIR)/exmachina/.
cp share/init.d/plinth $(DESTDIR)/etc/init.d cp share/init.d/plinth $(DESTDIR)/etc/init.d
install plinth $(DESTDIR)/usr/bin/ install plinth $(DESTDIR)/usr/bin/
mkdir -p $(DESTDIR)/var/lib/plinth/cherrypy_sessions $(DESTDIR)/var/log/plinth $(DESTDIR)/var/run mkdir -p $(DESTDIR)/var/lib/plinth/cherrypy_sessions $(DESTDIR)/var/log/plinth $(DESTDIR)/var/run

0
exmachina/__init__.py Normal file
View File

5
fabfile.py vendored
View File

@ -7,7 +7,10 @@
# plinth box # plinth box
import os,sys, subprocess import os,sys, subprocess
import simplejson as json try:
import simplejson as json
except ImportError:
import json
import fabric.api import fabric.api
from fabric.api import local, env, cd, put, get, task from fabric.api import local, env, cd, put, get, task

View File

@ -5,7 +5,10 @@ Author: Erez Shinan
Date : 31-May-2009 Date : 31-May-2009
""" """
import simplejson as json ## jlv replaced pickle with json try:
import simplejson as json ## jlv replaced pickle with json
except ImportError:
import json
import UserDict import UserDict
##import cPickle as pickle ##import cPickle as pickle

View File

@ -1,5 +1,8 @@
import simplejson as json
from urlparse import urlparse from urlparse import urlparse
try:
import simplejson as json
except ImportError:
import json
import cherrypy import cherrypy
import cfg import cfg

View File

@ -7,6 +7,7 @@ from forms import Form
import util as u import util as u
from withsqlite.withsqlite import sqlite_db from withsqlite.withsqlite import sqlite_db
import cfg import cfg
import config
from model import User from model import User
class FirstBoot(PagePlugin): class FirstBoot(PagePlugin):
@ -19,18 +20,13 @@ class FirstBoot(PagePlugin):
return self.state0(*args, **kwargs) return self.state0(*args, **kwargs)
## TODO: flesh out these tests values ## TODO: flesh out these tests values
def valid_box_name_p(self, name):
name = name.strip()
if re.search("\W", name):
return False
return True
def valid_box_key_p(self, key): def valid_box_key_p(self, key):
return True return True
def generate_box_key(self): def generate_box_key(self):
return "fake key" return "fake key"
@cherrypy.expose @cherrypy.expose
def state0(self, message="", box_name="", box_key="", username="", md5_password="", submitted=False, **kwargs): def state0(self, message="", hostname="", box_key="", submitted=False, username="", md5_password="", **kwargs):
""" """
In this state, we do time config over HTTP, name the box and In this state, we do time config over HTTP, name the box and
server key selection. server key selection.
@ -50,15 +46,13 @@ class FirstBoot(PagePlugin):
## Must resist the sick temptation to write an LDAP interface to the sqlite file ## Must resist the sick temptation to write an LDAP interface to the sqlite file
with sqlite_db(cfg.store_file, table="thisbox", autocommit=True) as db: with sqlite_db(cfg.store_file, table="thisbox", autocommit=True) as db:
db['about'] = "This table is for information about this FreedomBox" db['about'] = "This table is for information about this FreedomBox"
if box_name: if hostname:
if self.valid_box_name_p(box_name): if '' == config.valid_hostname(hostname):
db['box_name'] = box_name config.set_hostname(hostname)
else: else:
message += _("Invalid box name.") message += _("Invalid box name: %s") % config.valid_hostname(hostname)
elif 'box_name' in db and db['box_name']: else:
box_name = db['box_name'] hostname = config.get_hostname()
#TODO: set /etc/hostname to box name via ex machina
if box_key: if box_key:
if self.valid_box_key_p(box_key): if self.valid_box_key_p(box_key):
db['box_key'] = box_key db['box_key'] = box_key
@ -83,8 +77,7 @@ class FirstBoot(PagePlugin):
else: else:
validuser = False validuser = False
if hostname and box_key and '' == config.valid_hostname(hostname) and self.valid_box_key_p(box_key) and validuser:
if box_name and box_key and self.valid_box_name_p(box_name) and self.valid_box_key_p(box_key) and validuser:
## Update state to 1 and head there ## Update state to 1 and head there
with sqlite_db(cfg.store_file, table="firstboot", autocommit=True) as db: with sqlite_db(cfg.store_file, table="firstboot", autocommit=True) as db:
db['state']=1 db['state']=1
@ -97,10 +90,8 @@ class FirstBoot(PagePlugin):
name="whats_my_name", name="whats_my_name",
message=message) message=message)
form.text = '<script type="text/javascript" src="/static/js/md5.js"></script>\n'+form.text form.text = '<script type="text/javascript" src="/static/js/md5.js"></script>\n'+form.text
if not box_name:
box_name = cfg.box_name
form.html("<p>For convenience, your FreedomBox needs a name. It should be something short that doesn't contain spaces or punctuation. 'Willard' would be a good name. 'Freestyle McFreedomBox!!!' would not.</p>") form.html("<p>For convenience, your FreedomBox needs a name. It should be something short that doesn't contain spaces or punctuation. 'Willard' would be a good name. 'Freestyle McFreedomBox!!!' would not.</p>")
form.text_input('Name your FreedomBox', id="box_name", value=box_name) form.text_input('Name your FreedomBox', id="hostname", value=hostname)
form.html("<p><strong>Initial user and password.</strong> Access to this web interface is protected by knowing a username and password. Provide one here to register the initial privileged user. The password can be changed and other users added later.</p>") form.html("<p><strong>Initial user and password.</strong> Access to this web interface is protected by knowing a username and password. Provide one here to register the initial privileged user. The password can be changed and other users added later.</p>")
form.text_input('Username:', id="username", value=username) form.text_input('Username:', id="username", value=username)
form.text_input('Password:', id="password", type='password') form.text_input('Password:', id="password", type='password')
@ -129,6 +120,15 @@ TODO: explain all this cert stuff to the user.</p>
<p>TODO: add instrux for installing certificate.</p> <p>TODO: add instrux for installing certificate.</p>
<p>After you have installed <p>After you have installed
""" """
# TODO complete first_boot handling
# Make sure the user is not stuck on a dead end for now.
with sqlite_db(cfg.store_file, table="firstboot", autocommit=True) as db:
db['state']=5
main = main + """
<p>Welcome screen not completely implemented yet. Press <a href="/router">continue</a> to
see the rest of the web interface.</p>"
"""
if False: if False:
## Update state to 2 and head there ## Update state to 2 and head there
with sqlite_db(cfg.store_file, table="firstboot", autocommit=True) as db: with sqlite_db(cfg.store_file, table="firstboot", autocommit=True) as db:

View File

@ -1,5 +1,8 @@
import os import os
import simplejson as json try:
import simplejson as json
except ImportError:
import json
import cherrypy import cherrypy
import cfg import cfg
from model import User from model import User
@ -10,13 +13,27 @@ class UserStore(UserStoreModule, sqlite_db):
def __init__(self): def __init__(self):
self.data_dir = cfg.users_dir self.data_dir = cfg.users_dir
self.db_file = cfg.user_db self.db_file = cfg.user_db
sqlite_db.__init__(self, self.db_file, autocommit=True) sqlite_db.__init__(self, self.db_file, autocommit=True, check_same_thread=False)
self.__enter__() self.__enter__()
def close(self): def close(self):
self.__exit__(None,None,None) self.__exit__(None,None,None)
def current(self, name=False):
"""Return current user, if there is one, else None.
If name = True, return the username instead of the user."""
try:
username = cherrypy.session.get(cfg.session_key)
if name:
return username
else:
return self.get(username)
except AttributeError:
return None
def expert(self, username=None): def expert(self, username=None):
if not username:
username = self.current(name=True)
groups = self.attr(username,"groups") groups = self.attr(username,"groups")
if not groups: if not groups:
return False return False

View File

@ -7,7 +7,10 @@ haven't figured that one all the way through yet.
import os, sys import os, sys
import cherrypy import cherrypy
import simplejson as json try:
import simplejson as json
except ImportError:
import json
from gettext import gettext as _ from gettext import gettext as _
from plugin_mount import PagePlugin from plugin_mount import PagePlugin
from modules.auth import require from modules.auth import require

View File

@ -1,7 +1,10 @@
import os, subprocess import os, subprocess
from socket import gethostname from socket import gethostname
import cherrypy import cherrypy
import simplejson as json try:
import simplejson as json
except ImportError:
import json
from gettext import gettext as _ from gettext import gettext as _
from filedict import FileDict from filedict import FileDict
from modules.auth import require from modules.auth import require
@ -40,6 +43,9 @@ def valid_hostname(name):
return message return message
def get_hostname():
return gethostname()
def set_hostname(hostname): def set_hostname(hostname):
"Sets machine hostname to hostname" "Sets machine hostname to hostname"
cfg.log.info("Writing '%s' to /etc/hostname with exmachina" % hostname) cfg.log.info("Writing '%s' to /etc/hostname with exmachina" % hostname)
@ -53,7 +59,7 @@ def set_hostname(hostname):
if platform.linux_distribution()[0]=="Ubuntu" : if platform.linux_distribution()[0]=="Ubuntu" :
cfg.exmachina.service.start("hostname") cfg.exmachina.service.start("hostname")
else: else:
cfg.exmachina.initd.restart("hostname.sh") # is hostname.sh debian-only? cfg.exmachina.initd.start("hostname.sh") # is hostname.sh debian-only?
except OSError, e: except OSError, e:
raise cherrypy.HTTPError(500, "Hostname restart failed: %s" % e) raise cherrypy.HTTPError(500, "Hostname restart failed: %s" % e)
@ -62,10 +68,6 @@ class general(FormPlugin, PagePlugin):
order = 30 order = 30
def help(self, *args, **kwargs): def help(self, *args, **kwargs):
## only expert users are going to get deep enough to see any timestamps
if not cfg.users.expert():
return ''
return _(#"""<strong>Time Zone</strong> return _(#"""<strong>Time Zone</strong>
"""<p>Set your timezone to get accurate """<p>Set your timezone to get accurate
timestamps. %(product)s will use this information to set your timestamps. %(product)s will use this information to set your
@ -73,6 +75,9 @@ class general(FormPlugin, PagePlugin):
""" % {'product':cfg.product_name, 'box':cfg.box_name}) """ % {'product':cfg.product_name, 'box':cfg.box_name})
def main(self, message='', **kwargs): def main(self, message='', **kwargs):
if not cfg.users.expert():
return '<p>' + _('Only members of the expert group are allowed to see and modify the system setup.') + '</p>'
sys_store = filedict_con(cfg.store_file, 'sys') sys_store = filedict_con(cfg.store_file, 'sys')
hostname = cfg.exmachina.augeas.get("/files/etc/hostname/*") hostname = cfg.exmachina.augeas.get("/files/etc/hostname/*")
# this layer of persisting configuration in sys_store could/should be # this layer of persisting configuration in sys_store could/should be

View File

@ -1,6 +1,9 @@
import os import os
import cherrypy import cherrypy
import simplejson as json try:
import simplejson as json
except ImportError:
import json
from gettext import gettext as _ from gettext import gettext as _
from filedict import FileDict from filedict import FileDict
from modules.auth import require from modules.auth import require

View File

@ -1,6 +1,9 @@
import os import os
import cherrypy import cherrypy
import simplejson as json try:
import simplejson as json
except ImportError:
import json
from gettext import gettext as _ from gettext import gettext as _
from filedict import FileDict from filedict import FileDict
from auth import require from auth import require

View File

@ -1,6 +1,9 @@
import os import os
import cherrypy import cherrypy
import simplejson as json try:
import simplejson as json
except ImportError:
import json
from gettext import gettext as _ from gettext import gettext as _
from filedict import FileDict from filedict import FileDict
from modules.auth import require from modules.auth import require

View File

@ -114,9 +114,10 @@ def setup():
pass pass
try: try:
from exmachina import ExMachinaClient from vendor.exmachina.exmachina import ExMachinaClient
except ImportError: except ImportError:
cfg.exmachina = None cfg.exmachina = None
print "unable to import exmachina client library, but continuing anyways..."
else: else:
try: try:
cfg.exmachina = ExMachinaClient( cfg.exmachina = ExMachinaClient(

View File

@ -5,6 +5,6 @@
export PYTHONPATH export PYTHONPATH
sudo killall exmachina.py sudo killall exmachina.py
sudo /usr/share/pyshared/exmachina/exmachina.py -v & sudo vendor/exmachina/exmachina.py -v &
python plinth.py python plinth.py
sudo killall exmachina.py sudo killall exmachina.py

View File

@ -1,6 +1,5 @@
#! /bin/sh #! /bin/sh
PYTHONPATH=build/exmachina:$PYTHONPATH
PYTHONPATH=modules/installed/lib:$PYTHONPATH PYTHONPATH=modules/installed/lib:$PYTHONPATH
PYTHONPATH=vendor:$PYTHONPATH PYTHONPATH=vendor:$PYTHONPATH