mirror of
https://github.com/freedombox/FreedomBox.git
synced 2026-09-19 04:59:01 +00:00
Merged with upstream.
This commit is contained in:
commit
a9c853e5bd
7
Makefile
7
Makefile
@ -4,7 +4,6 @@ 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,9 +28,9 @@ install: default
|
|||||||
mkdir -p $(DESTDIR)$(PYDIR) $(DESTDIR)$(DATADIR) $(DESTDIR)/usr/bin \
|
mkdir -p $(DESTDIR)$(PYDIR) $(DESTDIR)$(DATADIR) $(DESTDIR)/usr/bin \
|
||||||
$(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 actions $(DESTDIR)$(DATADIR)/
|
||||||
|
cp -a sudoers.d $(DESTDIR)/etc/sudoers.d
|
||||||
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
|
||||||
@ -81,7 +80,7 @@ clean:
|
|||||||
@find . -name "*.bak" -exec rm {} \;
|
@find . -name "*.bak" -exec rm {} \;
|
||||||
@$(MAKE) -s -C doc clean
|
@$(MAKE) -s -C doc clean
|
||||||
@$(MAKE) -s -C templates clean
|
@$(MAKE) -s -C templates clean
|
||||||
rm -rf $(BUILDDIR) $(DESTDIR)
|
rm -f plinth.config
|
||||||
rm -f predepend
|
rm -f predepend
|
||||||
|
|
||||||
hosting:
|
hosting:
|
||||||
|
|||||||
3
README
3
README
@ -43,9 +43,6 @@ get down into the details and configure things the average user never
|
|||||||
thinks about. For example, experts can turn off ntp or switch ntp
|
thinks about. For example, experts can turn off ntp or switch ntp
|
||||||
servers. Basic users should never even know those options exist.
|
servers. Basic users should never even know those options exist.
|
||||||
|
|
||||||
See comments in exmachina/exmachina.py for more details about the
|
|
||||||
configuration management process seperation scheme.
|
|
||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
|
|
||||||
See the INSTALL file for additional details. Run:
|
See the INSTALL file for additional details. Run:
|
||||||
|
|||||||
10
actions/hostname-change
Executable file
10
actions/hostname-change
Executable file
@ -0,0 +1,10 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
hostname="$1"
|
||||||
|
|
||||||
|
echo "$hostname" > /etc/hostname
|
||||||
|
if [ -x /etc/init.d/hostname.sh ] ; then
|
||||||
|
service hostname.sh start
|
||||||
|
else
|
||||||
|
service hostname start
|
||||||
|
fi
|
||||||
48
actions/owncloud-setup
Executable file
48
actions/owncloud-setup
Executable file
@ -0,0 +1,48 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
if [ -e /etc/apache2/conf-enabled/owncloud.conf ] ; then
|
||||||
|
owncloud_enable=true
|
||||||
|
else
|
||||||
|
owncloud_enable=false
|
||||||
|
fi
|
||||||
|
owncloud_enable_cur=$owncloud_enable
|
||||||
|
export owncloud_enable
|
||||||
|
|
||||||
|
|
||||||
|
while [ "$1" ] ; do
|
||||||
|
arg="$1"
|
||||||
|
shift
|
||||||
|
case "$arg" in
|
||||||
|
enable|noenable) # Not using disable for consistency with other options
|
||||||
|
if [ 'enable' = "$arg" ] ; then
|
||||||
|
owncloud_enable=true
|
||||||
|
else
|
||||||
|
owncloud_enable=false
|
||||||
|
fi
|
||||||
|
export owncloud_enable
|
||||||
|
;;
|
||||||
|
status)
|
||||||
|
printstatus() {
|
||||||
|
if $2 ; then
|
||||||
|
echo $1
|
||||||
|
else
|
||||||
|
echo no$1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
printstatus enable $owncloud_enable_cur
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "$owncloud_enable" != "$owncloud_enable_cur" ] ; then
|
||||||
|
if $owncloud_enable ; then
|
||||||
|
DEBIAN_FRONTEND=noninteractive apt-get install -y owncloud 2>&1 | logger -t owncloud-setup
|
||||||
|
a2enconf owncloud 2>&1 | logger -t owncloud-setup
|
||||||
|
else
|
||||||
|
a2disconf owncloud 2>&1 | logger -t owncloud-setup
|
||||||
|
fi
|
||||||
|
service apache2 restart 2>&1 | logger -t owncloud-setup
|
||||||
|
fi
|
||||||
14
actions/timezone-change
Executable file
14
actions/timezone-change
Executable file
@ -0,0 +1,14 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
zonename="$1"
|
||||||
|
|
||||||
|
tzpath="/usr/share/zoneinfo/$zonename"
|
||||||
|
|
||||||
|
if [ -e "$tzpath" ] ; then
|
||||||
|
cp "$tzpath" /etc/localtime
|
||||||
|
echo "$zonename" > /etc/timezone
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
echo "timezone not valid" 1>&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
@ -1,6 +1,9 @@
|
|||||||
import cherrypy
|
import cherrypy
|
||||||
|
from gettext import gettext as _
|
||||||
from modules.auth import require
|
from modules.auth import require
|
||||||
from plugin_mount import PagePlugin
|
from plugin_mount import PagePlugin
|
||||||
|
from forms import Form
|
||||||
|
from privilegedactions import privilegedaction_run
|
||||||
import cfg
|
import cfg
|
||||||
|
|
||||||
class Apps(PagePlugin):
|
class Apps(PagePlugin):
|
||||||
@ -9,6 +12,7 @@ class Apps(PagePlugin):
|
|||||||
self.register_page("apps")
|
self.register_page("apps")
|
||||||
self.menu = cfg.main_menu.add_item("Apps", "icon-download-alt", "/apps", 80)
|
self.menu = cfg.main_menu.add_item("Apps", "icon-download-alt", "/apps", 80)
|
||||||
self.menu.add_item("Photo Gallery", "icon-picture", "/apps/photos", 35)
|
self.menu.add_item("Photo Gallery", "icon-picture", "/apps/photos", 35)
|
||||||
|
self.menu.add_item("Owncloud", "icon-picture", "/apps/owncloud", 35)
|
||||||
|
|
||||||
@cherrypy.expose
|
@cherrypy.expose
|
||||||
def index(self):
|
def index(self):
|
||||||
@ -33,3 +37,47 @@ investment in the sentimental value of your family snaps? Keep those
|
|||||||
photos local, backed up, easily accessed and free from the whims of
|
photos local, backed up, easily accessed and free from the whims of
|
||||||
some other websites business model.</p>
|
some other websites business model.</p>
|
||||||
""")
|
""")
|
||||||
|
|
||||||
|
@cherrypy.expose
|
||||||
|
@require()
|
||||||
|
def owncloud(self, submitted=False, **kwargs):
|
||||||
|
checkedinfo = {
|
||||||
|
'enable' : False,
|
||||||
|
}
|
||||||
|
|
||||||
|
if submitted:
|
||||||
|
opts = []
|
||||||
|
for k in kwargs.keys():
|
||||||
|
if 'on' == kwargs[k]:
|
||||||
|
shortk = k.split("owncloud_").pop()
|
||||||
|
checkedinfo[shortk] = True
|
||||||
|
|
||||||
|
for key in checkedinfo.keys():
|
||||||
|
if checkedinfo[key]:
|
||||||
|
opts.append(key)
|
||||||
|
else:
|
||||||
|
opts.append('no'+key)
|
||||||
|
privilegedaction_run("owncloud-setup", opts)
|
||||||
|
|
||||||
|
output, error = privilegedaction_run("owncloud-setup", ['status'])
|
||||||
|
if error:
|
||||||
|
raise Exception("something is wrong: " + error)
|
||||||
|
for option in output.split():
|
||||||
|
checkedinfo[option] = True
|
||||||
|
|
||||||
|
main="""
|
||||||
|
"""
|
||||||
|
form = Form(title="Configuration",
|
||||||
|
action="/apps/owncloud",
|
||||||
|
name="configure_owncloud",
|
||||||
|
message='')
|
||||||
|
form.checkbox(_("Enable Owncloud"), name="owncloud_enable", id="owncloud_enable", checked=checkedinfo['enable'])
|
||||||
|
form.hidden(name="submitted", value="True")
|
||||||
|
form.html(_("<p>When enabled, the owncloud installation will be available from /owncloud/ on the web server.</p>"))
|
||||||
|
form.submit(_("Update setup"))
|
||||||
|
main += form.render()
|
||||||
|
sidebar_right="""
|
||||||
|
<strong>Owncloud</strong><p>gives you universal access to your files through a web interface or WebDAV. It also provides a platform to easily view & sync your contacts, calendars and bookmarks across all your devices and enables basic editing right on the web. Installation has minimal server requirements, doesn't need special permissions and is quick. ownCloud is extendable via a simple but powerful API for applications and plugins.
|
||||||
|
</p>
|
||||||
|
"""
|
||||||
|
return self.fill_template(title="Owncloud", main=main, sidebar_right=sidebar_right)
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import util as u
|
|||||||
from withsqlite.withsqlite import sqlite_db
|
from withsqlite.withsqlite import sqlite_db
|
||||||
import cfg
|
import cfg
|
||||||
import config
|
import config
|
||||||
|
from model import User
|
||||||
|
|
||||||
class FirstBoot(PagePlugin):
|
class FirstBoot(PagePlugin):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
@ -25,7 +26,7 @@ class FirstBoot(PagePlugin):
|
|||||||
return "fake key"
|
return "fake key"
|
||||||
|
|
||||||
@cherrypy.expose
|
@cherrypy.expose
|
||||||
def state0(self, message="", hostname="", box_key="", submitted=False):
|
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.
|
||||||
@ -62,9 +63,21 @@ class FirstBoot(PagePlugin):
|
|||||||
elif submitted and not box_key:
|
elif submitted and not box_key:
|
||||||
box_key = self.generate_box_key()
|
box_key = self.generate_box_key()
|
||||||
db['box_key'] = box_key
|
db['box_key'] = box_key
|
||||||
|
if username and md5_password:
|
||||||
|
di = {
|
||||||
|
'username':username,
|
||||||
|
'name':'First user - please change',
|
||||||
|
'expert':'on',
|
||||||
|
"groups": ["expert"],
|
||||||
|
'passphrase':md5_password,
|
||||||
|
}
|
||||||
|
new_user = User(di)
|
||||||
|
cfg.users.set(username,new_user)
|
||||||
|
validuser = True
|
||||||
|
else:
|
||||||
|
validuser = False
|
||||||
|
|
||||||
|
if hostname and box_key and '' == config.valid_hostname(hostname) and self.valid_box_key_p(box_key) and validuser:
|
||||||
if hostname and box_key and '' == config.valid_hostname(hostname) and self.valid_box_key_p(box_key):
|
|
||||||
## 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
|
||||||
@ -75,9 +88,14 @@ class FirstBoot(PagePlugin):
|
|||||||
action="firstboot",
|
action="firstboot",
|
||||||
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.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="hostname", value=hostname)
|
form.text_input('Name your FreedomBox', id="hostname", value=hostname)
|
||||||
form.html("<p>%(hostname)s uses cryptographic keys so it can prove its identity when talking to you. %(hostname)s can make a key for itself, but if one already exists (from a prior FreedomBox, for example), you can paste it below. This key should not be the same as your key because you are not your FreedomBox!</p>" % {'hostname':cfg.box_name})
|
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('Password:', id="password", type='password')
|
||||||
|
form.text_input(name="md5_password", type="hidden")
|
||||||
|
form.html("<p>%(box_name)s uses cryptographic keys so it can prove its identity when talking to you. %(box_name)s can make a key for itself, but if one already exists (from a prior FreedomBox, for example), you can paste it below. This key should not be the same as your key because you are not your FreedomBox!</p>" % {'box_name':cfg.box_name})
|
||||||
form.text_box("If you want, paste your box's key here.", id="box_key", value=box_key)
|
form.text_box("If you want, paste your box's key here.", id="box_key", value=box_key)
|
||||||
form.hidden(name="submitted", value="True")
|
form.hidden(name="submitted", value="True")
|
||||||
form.submit("Box it up!")
|
form.submit("Box it up!")
|
||||||
|
|||||||
@ -27,7 +27,10 @@ def check_credentials(username, passphrase):
|
|||||||
cfg.log(error)
|
cfg.log(error)
|
||||||
return error
|
return error
|
||||||
|
|
||||||
u = cfg.users[username]
|
if username in cfg.users:
|
||||||
|
u = cfg.users[username]
|
||||||
|
else:
|
||||||
|
u = None
|
||||||
# hash the password whether the user exists, to foil timing
|
# hash the password whether the user exists, to foil timing
|
||||||
# side-channel attacks
|
# side-channel attacks
|
||||||
pass_hash = hashlib.md5(passphrase).hexdigest()
|
pass_hash = hashlib.md5(passphrase).hexdigest()
|
||||||
|
|||||||
@ -142,6 +142,16 @@ class Form():
|
|||||||
<span>%s</span>
|
<span>%s</span>
|
||||||
<input type=checkbox name="%s" id="%s" %s/>
|
<input type=checkbox name="%s" id="%s" %s/>
|
||||||
</label></div>\n""" % (label, name, id, checked)
|
</label></div>\n""" % (label, name, id, checked)
|
||||||
|
def radiobutton(self, label='', name='', id='', value='', checked=''):
|
||||||
|
name, id = self.name_or_id(name, id)
|
||||||
|
if checked:
|
||||||
|
checked = 'checked="on"'
|
||||||
|
self.text += """
|
||||||
|
<div class="radio">
|
||||||
|
<label>
|
||||||
|
<span>%s</span>
|
||||||
|
<input type="radio" name="%s" id="%s" value="%s" %s/>
|
||||||
|
</label></div>\n""" % (label, name, id, value, checked)
|
||||||
def get_checkbox(self, name='', id=''):
|
def get_checkbox(self, name='', id=''):
|
||||||
return '<input type=checkbox name="%s" id="%s" />\n' % self.name_or_id(name, id)
|
return '<input type=checkbox name="%s" id="%s" />\n' % self.name_or_id(name, id)
|
||||||
def render(self):
|
def render(self):
|
||||||
|
|||||||
@ -9,6 +9,7 @@ from gettext import gettext as _
|
|||||||
from filedict import FileDict
|
from filedict import FileDict
|
||||||
from modules.auth import require
|
from modules.auth import require
|
||||||
from plugin_mount import PagePlugin, FormPlugin
|
from plugin_mount import PagePlugin, FormPlugin
|
||||||
|
from privilegedactions import privilegedaction_run
|
||||||
import cfg
|
import cfg
|
||||||
from forms import Form
|
from forms import Form
|
||||||
from model import User
|
from model import User
|
||||||
@ -48,20 +49,14 @@ def get_hostname():
|
|||||||
|
|
||||||
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("Changing hostname to '%s'" % hostname)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
cfg.exmachina.augeas.set("/files/etc/hostname/*", hostname)
|
privilegedaction_run("hostname-change", [hostname])
|
||||||
cfg.exmachina.augeas.save()
|
|
||||||
# don't persist/cache change unless it was saved successfuly
|
# don't persist/cache change unless it was saved successfuly
|
||||||
sys_store = filedict_con(cfg.store_file, 'sys')
|
sys_store = filedict_con(cfg.store_file, 'sys')
|
||||||
sys_store['hostname'] = hostname
|
sys_store['hostname'] = hostname
|
||||||
if platform.linux_distribution()[0]=="Ubuntu" :
|
|
||||||
cfg.exmachina.service.start("hostname")
|
|
||||||
else:
|
|
||||||
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, "Updating hostname failed: %s" % e)
|
||||||
|
|
||||||
class general(FormPlugin, PagePlugin):
|
class general(FormPlugin, PagePlugin):
|
||||||
url = ["/sys/config"]
|
url = ["/sys/config"]
|
||||||
@ -79,7 +74,7 @@ class general(FormPlugin, PagePlugin):
|
|||||||
return '<p>' + _('Only members of the expert group are allowed to see and modify the system setup.') + '</p>'
|
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 = get_hostname()
|
||||||
# this layer of persisting configuration in sys_store could/should be
|
# this layer of persisting configuration in sys_store could/should be
|
||||||
# removed -BLN
|
# removed -BLN
|
||||||
defaults = {'time_zone': "slurp('/etc/timezone').rstrip()",
|
defaults = {'time_zone': "slurp('/etc/timezone').rstrip()",
|
||||||
@ -139,10 +134,10 @@ class general(FormPlugin, PagePlugin):
|
|||||||
raise
|
raise
|
||||||
else:
|
else:
|
||||||
message += msg
|
message += msg
|
||||||
|
time_zone = time_zone.strip()
|
||||||
if time_zone != sys_store['time_zone']:
|
if time_zone != sys_store['time_zone']:
|
||||||
src = os.path.join("/usr/share/zoneinfo", time_zone)
|
|
||||||
cfg.log.info("Setting timezone to %s" % time_zone)
|
cfg.log.info("Setting timezone to %s" % time_zone)
|
||||||
cfg.exmachina.misc.set_timezone(time_zone)
|
privilegedaction_run("timezone-change", [time_zone])
|
||||||
sys_store['time_zone'] = time_zone
|
sys_store['time_zone'] = time_zone
|
||||||
return message or "Settings updated."
|
return message or "Settings updated."
|
||||||
|
|
||||||
|
|||||||
28
plinth.py
28
plinth.py
@ -18,7 +18,6 @@ from logger import Logger
|
|||||||
#from modules.auth import AuthController, require, member_of, name_is
|
#from modules.auth import AuthController, require, member_of, name_is
|
||||||
|
|
||||||
from withsqlite.withsqlite import sqlite_db
|
from withsqlite.withsqlite import sqlite_db
|
||||||
from exmachina.exmachina import ExMachinaClient
|
|
||||||
import socket
|
import socket
|
||||||
|
|
||||||
__version__ = "0.2.14"
|
__version__ = "0.2.14"
|
||||||
@ -86,8 +85,6 @@ def parse_arguments():
|
|||||||
parser = argparse.ArgumentParser(description='Plinth web interface for the FreedomBox.')
|
parser = argparse.ArgumentParser(description='Plinth web interface for the FreedomBox.')
|
||||||
parser.add_argument('--pidfile', default="",
|
parser.add_argument('--pidfile', default="",
|
||||||
help='specify a file in which the server may write its pid')
|
help='specify a file in which the server may write its pid')
|
||||||
parser.add_argument('--listen-exmachina-key', default=False, action='store_true',
|
|
||||||
help='listen for JSON-RPC shared secret key on stdin at startup')
|
|
||||||
parser.add_argument('--directory', default="/",
|
parser.add_argument('--directory', default="/",
|
||||||
help='specify a subdirectory to host the server.')
|
help='specify a subdirectory to host the server.')
|
||||||
|
|
||||||
@ -101,18 +98,6 @@ def parse_arguments():
|
|||||||
except AttributeError:
|
except AttributeError:
|
||||||
cfg.pidfile = "plinth.pid"
|
cfg.pidfile = "plinth.pid"
|
||||||
|
|
||||||
if args.listen_exmachina_key:
|
|
||||||
# this is where we optionally try to read in a shared secret key to
|
|
||||||
# authenticate connections to exmachina
|
|
||||||
cfg.exmachina_secret_key = sys.stdin.readline().strip()
|
|
||||||
else:
|
|
||||||
cfg.exmachina_secret_key = None
|
|
||||||
|
|
||||||
if not args.directory.startswith("/"):
|
|
||||||
args.directory = "/" + args.directory
|
|
||||||
|
|
||||||
return args
|
|
||||||
|
|
||||||
def setup():
|
def setup():
|
||||||
args = parse_arguments()
|
args = parse_arguments()
|
||||||
|
|
||||||
@ -123,19 +108,6 @@ def setup():
|
|||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
try:
|
|
||||||
from vendor.exmachina.exmachina import ExMachinaClient
|
|
||||||
except ImportError:
|
|
||||||
cfg.exmachina = None
|
|
||||||
print "unable to import exmachina client library, but continuing anyways..."
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
cfg.exmachina = ExMachinaClient(
|
|
||||||
secret_key=cfg.exmachina_secret_key or None)
|
|
||||||
except socket.error:
|
|
||||||
cfg.exmachina = None
|
|
||||||
print "couldn't connect to exmachina daemon, but continuing anyways..."
|
|
||||||
|
|
||||||
os.chdir(cfg.python_root)
|
os.chdir(cfg.python_root)
|
||||||
cherrypy.config.update({'error_page.404': error_page_404})
|
cherrypy.config.update({'error_page.404': error_page_404})
|
||||||
cherrypy.config.update({'error_page.500': error_page_500})
|
cherrypy.config.update({'error_page.500': error_page_500})
|
||||||
|
|||||||
@ -4,6 +4,7 @@ box_name = FreedomBox
|
|||||||
|
|
||||||
[Path]
|
[Path]
|
||||||
file_root = %(root)s
|
file_root = %(root)s
|
||||||
|
python_root = %(root)s
|
||||||
data_dir = %(file_root)s/data
|
data_dir = %(file_root)s/data
|
||||||
store_file = %(data_dir)s/store.sqlite3
|
store_file = %(data_dir)s/store.sqlite3
|
||||||
user_db = %(data_dir)s/users
|
user_db = %(data_dir)s/users
|
||||||
|
|||||||
15
privilegedactions.py
Normal file
15
privilegedactions.py
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import sys
|
||||||
|
import subprocess
|
||||||
|
import cfg
|
||||||
|
|
||||||
|
def privilegedaction_run(action, options):
|
||||||
|
cmd = ['sudo', '-n', "/usr/share/plinth/actions/%s" % action]
|
||||||
|
if options:
|
||||||
|
cmd.extend(options)
|
||||||
|
cfg.log.info('running: %s ' % ' '.join(cmd))
|
||||||
|
|
||||||
|
output, error = \
|
||||||
|
subprocess.Popen(cmd,
|
||||||
|
stdout = subprocess.PIPE,
|
||||||
|
stderr= subprocess.PIPE).communicate()
|
||||||
|
return output, error
|
||||||
@ -7,21 +7,17 @@
|
|||||||
# Default-Stop: 0 1 6
|
# Default-Stop: 0 1 6
|
||||||
# Short-Description: plinth web frontend
|
# Short-Description: plinth web frontend
|
||||||
# Description:
|
# Description:
|
||||||
# Control the exmachina privileged execution daemon and the plinth
|
# Control the plinth web frontend.
|
||||||
# web frontend.
|
|
||||||
### END INIT INFO
|
### END INIT INFO
|
||||||
|
|
||||||
# This file is /etc/init.d/plinth
|
# This file is /etc/init.d/plinth
|
||||||
DAEMON=/usr/local/bin/plinth.py
|
DAEMON=/usr/local/bin/plinth.py
|
||||||
EXMACHINA_DAEMON=/usr/local/bin/exmachina.py
|
|
||||||
PID_FILE=/var/run/plinth.pid
|
PID_FILE=/var/run/plinth.pid
|
||||||
EXMACHINA_PID_FILE=/var/run/exmachina.pid
|
|
||||||
|
|
||||||
PLINTH_USER=www-data
|
PLINTH_USER=www-data
|
||||||
PLINTH_GROUP=www-data
|
PLINTH_GROUP=www-data
|
||||||
|
|
||||||
test -x $DAEMON || exit 0
|
test -x $DAEMON || exit 0
|
||||||
test -x $EXMACHINA_DAEMON || exit 0
|
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
@ -31,17 +27,9 @@ start_plinth (){
|
|||||||
if [ -f $PID_FILE ]; then
|
if [ -f $PID_FILE ]; then
|
||||||
echo Already running with a pid of `cat $PID_FILE`.
|
echo Already running with a pid of `cat $PID_FILE`.
|
||||||
else
|
else
|
||||||
if [ -f $EXMACHINA_PID_FILE ]; then
|
|
||||||
echo exmachina was already running with a pid of `cat $EXMACHINA_PID_FILE`.
|
|
||||||
kill -15 `cat $EXMACHINA_PID_FILE`
|
|
||||||
rm -rf $EXMACHINA_PID_FILE
|
|
||||||
fi
|
|
||||||
SHAREDKEY=`$EXMACHINA_DAEMON --random-key`
|
|
||||||
touch $PID_FILE
|
touch $PID_FILE
|
||||||
chown $PLINTH_USER:$PLINTH_GROUP $PID_FILE
|
chown $PLINTH_USER:$PLINTH_GROUP $PID_FILE
|
||||||
echo $SHAREDKEY | $EXMACHINA_DAEMON --pidfile=$EXMACHINA_PID_FILE --group=$PLINTH_GROUP || rm $PID_FILE
|
sudo -u $PLINTH_USER -g $PLINTH_GROUP $DAEMON --pidfile=$PID_FILE
|
||||||
sleep 0.5
|
|
||||||
echo $SHAREDKEY | sudo -u $PLINTH_USER -g $PLINTH_GROUP $DAEMON --pidfile=$PID_FILE
|
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,13 +41,6 @@ stop_plinth () {
|
|||||||
else
|
else
|
||||||
echo "No pid file at $PID_FILE suggests plinth is not running."
|
echo "No pid file at $PID_FILE suggests plinth is not running."
|
||||||
fi
|
fi
|
||||||
if [ -f $EXMACHINA_PID_FILE ]; then
|
|
||||||
kill -15 `cat $EXMACHINA_PID_FILE` || true
|
|
||||||
rm -rf $EXMACHINA_PID_FILE
|
|
||||||
echo "killed exmachina"
|
|
||||||
else
|
|
||||||
echo "No pid file at $EXMACHINA_PID_FILE suggests exmachina is not running."
|
|
||||||
fi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
test -x $DAEMON || exit 0
|
test -x $DAEMON || exit 0
|
||||||
|
|||||||
5
start.sh
5
start.sh
@ -1,10 +1,7 @@
|
|||||||
#! /bin/sh
|
#! /bin/sh
|
||||||
|
|
||||||
#PYTHONPATH=vendor/exmachina:$PYTHONPATH
|
#PYTHONPATH=$PYTHONPATH
|
||||||
|
|
||||||
export PYTHONPATH
|
export PYTHONPATH
|
||||||
|
|
||||||
sudo killall exmachina.py
|
|
||||||
sudo vendor/exmachina/exmachina.py -v &
|
|
||||||
python plinth.py
|
python plinth.py
|
||||||
sudo killall exmachina.py
|
|
||||||
|
|||||||
1
sudoers.d/plinth
Normal file
1
sudoers.d/plinth
Normal file
@ -0,0 +1 @@
|
|||||||
|
plinth ALL=(ALL:ALL) NOPASSWD:/usr/share/plinth/actions/*
|
||||||
Loading…
x
Reference in New Issue
Block a user