From 0e5bab19d618c856de6700e0df736eda1cd76180 Mon Sep 17 00:00:00 2001 From: Petter Reinholdtsen Date: Wed, 11 Sep 2013 09:58:42 +0200 Subject: [PATCH 01/10] Create admin user on first boot. Extend the first_boot module to ask for username and password of user to create on first boot, and create it as a privileged user. This should remove the need for the admin user with well known password. --- modules/installed/first_boot.py | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/modules/installed/first_boot.py b/modules/installed/first_boot.py index ff3a27e63..b55425981 100644 --- a/modules/installed/first_boot.py +++ b/modules/installed/first_boot.py @@ -7,6 +7,7 @@ from forms import Form import util as u from withsqlite.withsqlite import sqlite_db import cfg +from model import User class FirstBoot(PagePlugin): def __init__(self, *args, **kwargs): @@ -29,7 +30,7 @@ class FirstBoot(PagePlugin): return "fake key" @cherrypy.expose - def state0(self, message="", box_name="", box_key="", submitted=False): + def state0(self, message="", box_name="", box_key="", username="", md5_password="", submitted=False, **kwargs): """ In this state, we do time config over HTTP, name the box and server key selection. @@ -68,9 +69,22 @@ class FirstBoot(PagePlugin): elif submitted and not box_key: box_key = self.generate_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 box_name and box_key and self.valid_box_name_p(box_name) and self.valid_box_key_p(box_key): + 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 with sqlite_db(cfg.store_file, table="firstboot", autocommit=True) as db: db['state']=1 @@ -79,12 +93,18 @@ class FirstBoot(PagePlugin): main = "

Welcome. It looks like this FreedomBox isn't set up yet. We'll need to ask you a just few questions to get started.

" form = Form(title="Welcome to Your FreedomBox!", action="/firstboot", + onsubmit="return md5ify('whats_my_name', 'password')", name="whats_my_name", message=message) + form.text = '\n'+form.text if not box_name: box_name = cfg.box_name form.html("

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.

") form.text_input('Name your FreedomBox', id="box_name", value=box_name) + form.html("

Initial user and password. 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.

") + 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("

%(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!

" % {'box_name':cfg.box_name}) form.text_box("If you want, paste your box's key here.", id="box_key", value=box_key) form.hidden(name="submitted", value="True") From 3c78b92d04c83085b5e595c090f09ff4bf64c380 Mon Sep 17 00:00:00 2001 From: Petter Reinholdtsen Date: Thu, 19 Sep 2013 12:35:16 +0200 Subject: [PATCH 02/10] Add support for radio buttons. --- modules/installed/lib/forms.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/modules/installed/lib/forms.py b/modules/installed/lib/forms.py index 2be810f18..827e11048 100644 --- a/modules/installed/lib/forms.py +++ b/modules/installed/lib/forms.py @@ -142,6 +142,16 @@ class Form(): %s \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 += """ +
+
\n""" % (label, name, id, value, checked) def get_checkbox(self, name='', id=''): return '\n' % self.name_or_id(name, id) def render(self): From 444365ec785031f3dbb17bf20991648249aa52fe Mon Sep 17 00:00:00 2001 From: Petter Reinholdtsen Date: Mon, 23 Sep 2013 09:37:04 +0200 Subject: [PATCH 03/10] Rewrite plinth to use sudo and action scripts instead of exmachina for privileged accesss. --- Makefile | 4 ++-- README | 3 --- actions/hostname-change | 10 ++++++++++ actions/timezone-change | 14 ++++++++++++++ modules/installed/system/config.py | 19 +++++++------------ plinth.py | 23 ----------------------- privilegedactions.py | 15 +++++++++++++++ share/init.d/plinth | 23 ++--------------------- start.sh | 5 +---- sudoers.d/plinth | 1 + 10 files changed, 52 insertions(+), 65 deletions(-) create mode 100755 actions/hostname-change create mode 100755 actions/timezone-change create mode 100644 privilegedactions.py create mode 100644 sudoers.d/plinth diff --git a/Makefile b/Makefile index c9a6b4cdc..99c053509 100644 --- a/Makefile +++ b/Makefile @@ -29,9 +29,9 @@ install: default mkdir -p $(DESTDIR)$(PYDIR) $(DESTDIR)$(DATADIR) $(DESTDIR)/usr/bin \ $(DESTDIR)/usr/share/doc/plinth $(DESTDIR)/usr/share/man/man1 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)/ - mkdir -p $(DESTDIR)$(PYDIR)/exmachina - cp -a vendor/exmachina/exmachina.py $(DESTDIR)$(PYDIR)/exmachina/. cp share/init.d/plinth $(DESTDIR)/etc/init.d install plinth $(DESTDIR)/usr/bin/ mkdir -p $(DESTDIR)/var/lib/plinth/cherrypy_sessions $(DESTDIR)/var/log/plinth $(DESTDIR)/var/run diff --git a/README b/README index a5e4bf906..6c8382b54 100644 --- a/README +++ b/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 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 See the INSTALL file for additional details. Run: diff --git a/actions/hostname-change b/actions/hostname-change new file mode 100755 index 000000000..ad71edc80 --- /dev/null +++ b/actions/hostname-change @@ -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 diff --git a/actions/timezone-change b/actions/timezone-change new file mode 100755 index 000000000..6a5ed13c2 --- /dev/null +++ b/actions/timezone-change @@ -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 diff --git a/modules/installed/system/config.py b/modules/installed/system/config.py index 89d878a35..6863b22bd 100644 --- a/modules/installed/system/config.py +++ b/modules/installed/system/config.py @@ -9,6 +9,7 @@ from gettext import gettext as _ from filedict import FileDict from modules.auth import require from plugin_mount import PagePlugin, FormPlugin +from privilegedactions import privilegedaction_run import cfg from forms import Form from model import User @@ -48,20 +49,14 @@ def get_hostname(): def set_hostname(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: - cfg.exmachina.augeas.set("/files/etc/hostname/*", hostname) - cfg.exmachina.augeas.save() + privilegedaction_run("hostname-change", [hostname]) # don't persist/cache change unless it was saved successfuly sys_store = filedict_con(cfg.store_file, 'sys') 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: - raise cherrypy.HTTPError(500, "Hostname restart failed: %s" % e) + raise cherrypy.HTTPError(500, "Updating hostname failed: %s" % e) class general(FormPlugin, PagePlugin): url = ["/sys/config"] @@ -79,7 +74,7 @@ class general(FormPlugin, PagePlugin): return '

' + _('Only members of the expert group are allowed to see and modify the system setup.') + '

' 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 # removed -BLN defaults = {'time_zone': "slurp('/etc/timezone').rstrip()", @@ -139,10 +134,10 @@ class general(FormPlugin, PagePlugin): raise else: message += msg + time_zone = time_zone.strip() 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.exmachina.misc.set_timezone(time_zone) + privilegedaction_run("timezone-change", [time_zone]) sys_store['time_zone'] = time_zone return message or "Settings updated." diff --git a/plinth.py b/plinth.py index e2bd80818..5ebac5e29 100755 --- a/plinth.py +++ b/plinth.py @@ -18,7 +18,6 @@ from logger import Logger #from modules.auth import AuthController, require, member_of, name_is from withsqlite.withsqlite import sqlite_db -from exmachina.exmachina import ExMachinaClient import socket __version__ = "0.2.14" @@ -84,8 +83,6 @@ def parse_arguments(): parser = argparse.ArgumentParser(description='Plinth web interface for the FreedomBox.') parser.add_argument('--pidfile', default="", 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') args=parser.parse_args() if args.pidfile: cfg.pidfile = args.pidfile @@ -96,13 +93,6 @@ def parse_arguments(): except AttributeError: 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 - def setup(): parse_arguments() @@ -113,19 +103,6 @@ def setup(): except AttributeError: 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) cherrypy.config.update({'error_page.404': error_page_404}) cherrypy.config.update({'error_page.500': error_page_500}) diff --git a/privilegedactions.py b/privilegedactions.py new file mode 100644 index 000000000..37ac23891 --- /dev/null +++ b/privilegedactions.py @@ -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 diff --git a/share/init.d/plinth b/share/init.d/plinth index 8bc056eea..cea43f54c 100755 --- a/share/init.d/plinth +++ b/share/init.d/plinth @@ -7,21 +7,17 @@ # Default-Stop: 0 1 6 # Short-Description: plinth web frontend # Description: -# Control the exmachina privileged execution daemon and the plinth -# web frontend. +# Control the plinth web frontend. ### END INIT INFO # This file is /etc/init.d/plinth DAEMON=/usr/local/bin/plinth.py -EXMACHINA_DAEMON=/usr/local/bin/exmachina.py PID_FILE=/var/run/plinth.pid -EXMACHINA_PID_FILE=/var/run/exmachina.pid PLINTH_USER=www-data PLINTH_GROUP=www-data test -x $DAEMON || exit 0 -test -x $EXMACHINA_DAEMON || exit 0 set -e @@ -31,17 +27,9 @@ start_plinth (){ if [ -f $PID_FILE ]; then echo Already running with a pid of `cat $PID_FILE`. 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 chown $PLINTH_USER:$PLINTH_GROUP $PID_FILE - echo $SHAREDKEY | $EXMACHINA_DAEMON --pidfile=$EXMACHINA_PID_FILE --group=$PLINTH_GROUP || rm $PID_FILE - sleep 0.5 - echo $SHAREDKEY | sudo -u $PLINTH_USER -g $PLINTH_GROUP $DAEMON --pidfile=$PID_FILE + sudo -u $PLINTH_USER -g $PLINTH_GROUP $DAEMON --pidfile=$PID_FILE fi } @@ -53,13 +41,6 @@ stop_plinth () { else echo "No pid file at $PID_FILE suggests plinth is not running." 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 diff --git a/start.sh b/start.sh index 8b97c0bcd..0ee1c534d 100755 --- a/start.sh +++ b/start.sh @@ -1,10 +1,7 @@ #! /bin/sh -#PYTHONPATH=vendor/exmachina:$PYTHONPATH +#PYTHONPATH=$PYTHONPATH export PYTHONPATH -sudo killall exmachina.py -sudo vendor/exmachina/exmachina.py -v & python plinth.py -sudo killall exmachina.py diff --git a/sudoers.d/plinth b/sudoers.d/plinth new file mode 100644 index 000000000..aaefc5e62 --- /dev/null +++ b/sudoers.d/plinth @@ -0,0 +1 @@ +plinth ALL=(ALL:ALL) NOPASSWD:/usr/share/plinth/actions/* From fe33c348b4d15052d44df83989cbbee1d9c79cb3 Mon Sep 17 00:00:00 2001 From: Petter Reinholdtsen Date: Mon, 23 Sep 2013 15:14:32 +0200 Subject: [PATCH 04/10] First draft to add owncloud support. --- actions/owncloud-setup | 48 +++++++++++++++++++++++++++++++++ modules/installed/apps/apps.py | 49 ++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+) create mode 100755 actions/owncloud-setup diff --git a/actions/owncloud-setup b/actions/owncloud-setup new file mode 100755 index 000000000..0394c2e23 --- /dev/null +++ b/actions/owncloud-setup @@ -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 + apt-get install -y owncloud + a2enconf owncloud + else + a2disconf owncloud + fi + service apache2 restart +fi diff --git a/modules/installed/apps/apps.py b/modules/installed/apps/apps.py index 83b977e28..ef82a01de 100644 --- a/modules/installed/apps/apps.py +++ b/modules/installed/apps/apps.py @@ -1,6 +1,9 @@ import cherrypy +from gettext import gettext as _ from modules.auth import require from plugin_mount import PagePlugin +from forms import Form +from privilegedactions import privilegedaction_run import cfg class Apps(PagePlugin): @@ -9,6 +12,7 @@ class Apps(PagePlugin): self.register_page("apps") 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("Owncloud", "icon-picture", "/apps/owncloud", 35) @cherrypy.expose def index(self): @@ -33,3 +37,48 @@ investment in the sentimental value of your family snaps? Keep those photos local, backed up, easily accessed and free from the whims of some other websites business model.

""") + + @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() + cfg.log.info('found: %s, short %s ' % (k, shortk)) + 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(_("

When enabled, the owncloud installation will be available from /owncloud/ on the web server.

")) + form.submit(_("Update setup")) + main += form.render() + sidebar_right=""" +Owncloud

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. +

+""" + return self.fill_template(title="Owncloud", main=main, sidebar_right=sidebar_right) From 55bf19865abe1b2574802f72d6d38722c789937a Mon Sep 17 00:00:00 2001 From: Petter Reinholdtsen Date: Wed, 25 Sep 2013 11:23:51 +0200 Subject: [PATCH 05/10] Avoid removing vendor and $(DESTDIR). The vendor/ directory contain source used during build, and $(DESTDIR) might point to /usr/. Neither should be removed in the clean target. --- Makefile | 2 -- 1 file changed, 2 deletions(-) diff --git a/Makefile b/Makefile index c9a6b4cdc..d3e6496fc 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,6 @@ CSS=$(wildcard *.css) CSS=$(subst .tiny,,$(shell find themes -type f -name '*.css')) COMPRESSED_CSS := $(patsubst %.css,%.tiny.css,$(CSS)) PWD=`pwd` -BUILDDIR=vendor # hosting variables SLEEP_TIME=300 @@ -81,7 +80,6 @@ clean: @find . -name "*.bak" -exec rm {} \; @$(MAKE) -s -C doc clean @$(MAKE) -s -C templates clean - rm -rf $(BUILDDIR) $(DESTDIR) rm -f predepend hosting: From 829e40198da7a37f40690e8583046cfef2be8cc4 Mon Sep 17 00:00:00 2001 From: Petter Reinholdtsen Date: Thu, 26 Sep 2013 11:34:04 +0200 Subject: [PATCH 06/10] Get owncloud enabling limping along. --- actions/owncloud-setup | 8 ++++---- modules/installed/apps/apps.py | 1 - 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/actions/owncloud-setup b/actions/owncloud-setup index 0394c2e23..f040582a8 100755 --- a/actions/owncloud-setup +++ b/actions/owncloud-setup @@ -39,10 +39,10 @@ done if [ "$owncloud_enable" != "$owncloud_enable_cur" ] ; then if $owncloud_enable ; then - apt-get install -y owncloud - a2enconf owncloud + apt-get install -y owncloud 2>&1 | logger -t owncloud-setup + a2enconf owncloud 2>&1 | logger -t owncloud-setup else - a2disconf owncloud + a2disconf owncloud 2>&1 | logger -t owncloud-setup fi - service apache2 restart + service apache2 restart 2>&1 | logger -t owncloud-setup fi diff --git a/modules/installed/apps/apps.py b/modules/installed/apps/apps.py index ef82a01de..ef2e1b7d3 100644 --- a/modules/installed/apps/apps.py +++ b/modules/installed/apps/apps.py @@ -50,7 +50,6 @@ some other websites business model.

for k in kwargs.keys(): if 'on' == kwargs[k]: shortk = k.split("owncloud_").pop() - cfg.log.info('found: %s, short %s ' % (k, shortk)) checkedinfo[shortk] = True for key in checkedinfo.keys(): From 7b9f6e09d38d6693644711ae4bffdc4bcfef76d3 Mon Sep 17 00:00:00 2001 From: Petter Reinholdtsen Date: Thu, 26 Sep 2013 13:26:21 +0200 Subject: [PATCH 07/10] Make sure apt do not ask questions when installing owncloud. --- actions/owncloud-setup | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actions/owncloud-setup b/actions/owncloud-setup index f040582a8..e5c8eb44f 100755 --- a/actions/owncloud-setup +++ b/actions/owncloud-setup @@ -39,7 +39,7 @@ done if [ "$owncloud_enable" != "$owncloud_enable_cur" ] ; then if $owncloud_enable ; then - apt-get install -y owncloud 2>&1 | logger -t owncloud-setup + 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 From 6630a8f3d50b3beada3817c313dfe455ba8f6205 Mon Sep 17 00:00:00 2001 From: Petter Reinholdtsen Date: Thu, 26 Sep 2013 20:04:27 +0200 Subject: [PATCH 08/10] Make sure login do not throw exception for unknown users. --- modules/installed/lib/auth.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/modules/installed/lib/auth.py b/modules/installed/lib/auth.py index 74f387595..fb2ad2ac9 100644 --- a/modules/installed/lib/auth.py +++ b/modules/installed/lib/auth.py @@ -27,7 +27,10 @@ def check_credentials(username, passphrase): cfg.log(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 # side-channel attacks pass_hash = hashlib.md5(passphrase).hexdigest() From 4048e7773842a97a782a2905fa7d7be8ca44b4c6 Mon Sep 17 00:00:00 2001 From: James Valleroy Date: Sat, 28 Sep 2013 18:04:53 -0400 Subject: [PATCH 09/10] Fixes for plinth.config when run from source folder. --- Makefile | 1 + plinth.sample.config | 1 + 2 files changed, 2 insertions(+) diff --git a/Makefile b/Makefile index d02c4a34f..b4c313b02 100644 --- a/Makefile +++ b/Makefile @@ -80,6 +80,7 @@ clean: @find . -name "*.bak" -exec rm {} \; @$(MAKE) -s -C doc clean @$(MAKE) -s -C templates clean + rm -f plinth.config rm -f predepend hosting: diff --git a/plinth.sample.config b/plinth.sample.config index ece4d06d7..1134b2e81 100644 --- a/plinth.sample.config +++ b/plinth.sample.config @@ -4,6 +4,7 @@ box_name = FreedomBox [Path] file_root = %(root)s +python_root = %(root)s data_dir = %(file_root)s/data store_file = %(data_dir)s/store.sqlite3 user_db = %(data_dir)s/users From cda21f395fb1ef510bb81c7c9839a7a40c04d879 Mon Sep 17 00:00:00 2001 From: James Valleroy Date: Sat, 28 Sep 2013 18:06:03 -0400 Subject: [PATCH 10/10] Fix to avoid python error about non-ASCII character. --- modules/installed/apps/apps.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/installed/apps/apps.py b/modules/installed/apps/apps.py index ef2e1b7d3..d6ba9d662 100644 --- a/modules/installed/apps/apps.py +++ b/modules/installed/apps/apps.py @@ -77,7 +77,7 @@ some other websites business model.

form.submit(_("Update setup")) main += form.render() sidebar_right=""" -Owncloud

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. +Owncloud

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.

""" return self.fill_template(title="Owncloud", main=main, sidebar_right=sidebar_right)