From 6aff183b54d0af4c6cf2a97a8a16047100f16e1c Mon Sep 17 00:00:00 2001 From: James Vasile Date: Thu, 1 Dec 2011 09:18:44 -0500 Subject: [PATCH 01/31] move to sqlite3 + json dict storage for users --- Makefile | 7 ++++++- cfg.py | 1 + data/users.sqlite3.distrib | Bin 0 -> 3072 bytes modules/installed/lib/user_store.py | 13 ++++++++++++- plinth.py | 9 +++++++-- 5 files changed, 26 insertions(+), 4 deletions(-) create mode 100644 data/users.sqlite3.distrib diff --git a/Makefile b/Makefile index 70bc7ad3d..35086eb87 100644 --- a/Makefile +++ b/Makefile @@ -8,9 +8,14 @@ COMPRESSED_CSS := $(patsubst %.css,%.tiny.css,$(CSS)) PWD=`pwd` ## Catch-all tagets -default: cherrypy.config dirs template css docs +default: cherrypy.config dirs template css docs dbs all: default +dbs: data/users.sqlite3 + +data/users.sqlite3: data/users.sqlite3.distrib + cp data/users.sqlite3.distrib data/users.sqlite3 + dirs: @mkdir -p data/cherrypy_sessions diff --git a/cfg.py b/cfg.py index db237fc40..0f98be007 100644 --- a/cfg.py +++ b/cfg.py @@ -4,6 +4,7 @@ import os file_root = os.path.dirname(os.path.realpath(__file__)) data_dir = os.path.join(file_root, "data") store_file = os.path.join(data_dir, "store.sqlite3") +user_db = os.path.join(data_dir, "users") status_log_file = os.path.join(data_dir, "status.log") access_log_file = os.path.join(data_dir, "access.log") users_dir = os.path.join(data_dir, "users") diff --git a/data/users.sqlite3.distrib b/data/users.sqlite3.distrib new file mode 100644 index 0000000000000000000000000000000000000000..2d805a1537d2501e6dddf3302a83dd69935d620c GIT binary patch literal 3072 zcmeHH!Ab)$5KT6vV4>%|#`R*M!dkUjL9l9Xy{Ns3l(ajwi@TdP$!bMBh{t}Nzu-rB z@?etfLMiwKX2>L&H}fXsL2`TDj}_1f7b#Qp096pi=$ul7kf)t!FAeLB@zU1!CAPVG zXzy#gPJWO_mWV9L=VpP6odQk)tH2em`o522#YPE8#YHiBmp8rcphpMYi++zjT!21AK{Er Date: Thu, 1 Dec 2011 09:20:26 -0500 Subject: [PATCH 02/31] add TODO: at exit, commit db --- modules/installed/lib/user_store.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/installed/lib/user_store.py b/modules/installed/lib/user_store.py index c3fb0e17e..01a3e7724 100644 --- a/modules/installed/lib/user_store.py +++ b/modules/installed/lib/user_store.py @@ -15,6 +15,8 @@ class UserStore(UserStoreModule, sqlite_db): def close(self): self.__exit__() + #TODO: at exit, commit db + class UserStoreOld(): #class UserStore(UserStoreModule): """The user storage is on disk. Rather than slurp the entire From df140feb52a5736c42bd66e54df9bdc9a6ea52f0 Mon Sep 17 00:00:00 2001 From: James Vasile Date: Thu, 1 Dec 2011 09:31:10 -0500 Subject: [PATCH 03/31] autocommit --- modules/installed/lib/user_store.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/modules/installed/lib/user_store.py b/modules/installed/lib/user_store.py index 01a3e7724..3466555fa 100644 --- a/modules/installed/lib/user_store.py +++ b/modules/installed/lib/user_store.py @@ -10,13 +10,11 @@ class UserStore(UserStoreModule, sqlite_db): def __init__(self): self.data_dir = cfg.users_dir self.db_file = cfg.user_db - sqlite_db.__init__(self, self.db_file) + sqlite_db.__init__(self, self.db_file, autocommit=True) self.__enter__() def close(self): self.__exit__() - #TODO: at exit, commit db - class UserStoreOld(): #class UserStore(UserStoreModule): """The user storage is on disk. Rather than slurp the entire From 69856fdbbdb8e30e96971a7a58239881263a6c82 Mon Sep 17 00:00:00 2001 From: James Vasile Date: Thu, 1 Dec 2011 10:04:46 -0500 Subject: [PATCH 04/31] complete the transition to sqlite --- modules/installed/lib/auth.py | 2 +- modules/installed/lib/user_store.py | 2 ++ modules/installed/router/router.py | 2 +- modules/installed/system/users.py | 14 +++++++------- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/modules/installed/lib/auth.py b/modules/installed/lib/auth.py index 4b0f22973..988f8dd9d 100644 --- a/modules/installed/lib/auth.py +++ b/modules/installed/lib/auth.py @@ -18,7 +18,7 @@ def check_credentials(username, passphrase): """Verifies credentials for username and passphrase. Returns None on success or a string describing the error on failure""" - u = cfg.users.get(username) + u = cfg.users[username] if u is None: cfg.log("Unknown user: %s" % username) return u"Username %s is unknown to me." % username diff --git a/modules/installed/lib/user_store.py b/modules/installed/lib/user_store.py index 3466555fa..a4042c102 100644 --- a/modules/installed/lib/user_store.py +++ b/modules/installed/lib/user_store.py @@ -14,6 +14,8 @@ class UserStore(UserStoreModule, sqlite_db): self.__enter__() def close(self): self.__exit__() + def expert(self): + return False class UserStoreOld(): #class UserStore(UserStoreModule): diff --git a/modules/installed/router/router.py b/modules/installed/router/router.py index 764d43c4d..0d12c875e 100644 --- a/modules/installed/router/router.py +++ b/modules/installed/router/router.py @@ -60,7 +60,7 @@ router does. With the addition of some extra modules, its abilities can rival those of high-end routers costing hundreds of dollars.

""" % cfg.box_name + parts['sidebar_right'] if not cfg.users.expert(): - main += """

In basic mode, you don't need to do any + parts['main'] += """

In basic mode, you don't need to do any router setup before you can go online. Just plug your %(product)s in to your cable or DSL modem and the router will try to get you on the internet using DHCP.

diff --git a/modules/installed/system/users.py b/modules/installed/system/users.py index ce99f6417..669183c69 100644 --- a/modules/installed/system/users.py +++ b/modules/installed/system/users.py @@ -51,11 +51,11 @@ class add(FormPlugin, PagePlugin): if not username: msg = add_message(msg, _("Must specify a username!")) if not md5_password: msg = add_message(msg, _("Must specify a password!")) - if cfg.users.get(username): + if username in cfg.users: msg = add_message(msg, _("User already exists!")) else: try: - cfg.users.set(User(dict={'username':username, 'name':name, 'email':email, 'password':md5_password})) + cfg.users[username]= User(dict={'username':username, 'name':name, 'email':email, 'password':md5_password}) except: msg = add_message(msg, _("Error storing user!")) @@ -77,7 +77,7 @@ class edit(FormPlugin, PagePlugin): system.

Deleting users is permanent!

""" % (cfg.product_name, cfg.box_name)) def main(self, msg=''): - users = cfg.users.get_all() + users = cfg.users.keys() add_form = Form(title=_("Edit or Delete User"), action="/sys/users/edit", message=msg) add_form.html('Delete
') for uname in sorted(users.keys()): @@ -95,12 +95,12 @@ class edit(FormPlugin, PagePlugin): cfg.log.info("%s asked to delete %s" % (cherrypy.session.get(cfg.session_key), usernames)) if usernames: for username in usernames: - if cfg.users.exists(username): + if username in cfg.users: try: - cfg.users.remove(username) + del cfg.users[username] msg.add(_("Deleted user %s." % username)) except IOError, e: - if cfg.users.get('username', reload=True): + if 'username' in cfg.users: m = _("Error on deletion, user %s not fully deleted: %s" % (username, e)) cfg.log.error(m) msg.add(m) @@ -117,7 +117,7 @@ class edit(FormPlugin, PagePlugin): return self.fill_template(title="", main=main, sidebar_left=self.sidebar_left, sidebar_right=self.sidebar_right) sidebar_right = '' - u = cfg.users.get(kwargs['username']) + u = cfg.users[kwargs['username']] if not u: main = _("

Could not find a user with username of %s!

" % kwargs['username']) return self.fill_template(template="err", title=_("Unnown User"), main=main, From 2ec8608585f4fcfaa1f297bac43c40e041ecca6f Mon Sep 17 00:00:00 2001 From: James Vasile Date: Thu, 1 Dec 2011 10:05:42 -0500 Subject: [PATCH 05/31] move away from importing all of util --- plugin_mount.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/plugin_mount.py b/plugin_mount.py index d8b7022d3..5ad414a8b 100644 --- a/plugin_mount.py +++ b/plugin_mount.py @@ -2,6 +2,7 @@ import cherrypy from modules.auth import require import cfg from util import * +import util as u class PluginMount(type): """See http://martyalchin.com/2008/jan/10/simple-plugin-framework/ for documentation""" @@ -72,7 +73,7 @@ class PagePlugin: cfg.log.info("Registering page: %s" % url) exec "cfg.html_root.%s = self" % (url) def fill_template(self, *args, **kwargs): - return page_template(*args, **kwargs) + return u.page_template(*args, **kwargs) def forms(self, url, *args, **kwargs): for form in cfg.forms: @@ -152,7 +153,7 @@ class FormPlugin(): except AttributeError: pass cfg.log("%%%%%%%%%%% %s" % kwargs) - return page_template(*args, **kwargs) + return u.page_template(*args, **kwargs) class UserStoreModule: """ From d728cb1cd58ce7ecadb453d7777020a8b89ac4bb Mon Sep 17 00:00:00 2001 From: James Vasile Date: Thu, 1 Dec 2011 10:06:49 -0500 Subject: [PATCH 06/31] add withsqlite --- vendor/withsqlite/__init__.py | 0 vendor/withsqlite/withsqlite.py | 197 ++++++++++++++++++++++++++++++++ 2 files changed, 197 insertions(+) create mode 100644 vendor/withsqlite/__init__.py create mode 100644 vendor/withsqlite/withsqlite.py diff --git a/vendor/withsqlite/__init__.py b/vendor/withsqlite/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/vendor/withsqlite/withsqlite.py b/vendor/withsqlite/withsqlite.py new file mode 100644 index 000000000..40aaa8812 --- /dev/null +++ b/vendor/withsqlite/withsqlite.py @@ -0,0 +1,197 @@ +#!/usr/bin/env python + +""" +withsqlite - uses an sqlite db as a back end for a dict-like object, +kind of like shelve but with json and sqlite3. + +Copyright 2011 James Vasile +Released under the GNU General Public License, version 3 or later. +See https://www.gnu.org/licenses/gpl-3.0.html for terms. + +Repo is at . Patches welcome! + +This file was developed as part of planeteria + +""" +import os, sys, sqlite3, time +import simplejson as json + +def to_json(python_object): + if isinstance(python_object, time.struct_time): + return {'__class__': 'time.asctime', + '__value__': time.asctime(python_object)} + + return {'__class__': 'basestring', + '__value__': str(python_object)} + +class sqlite_db(): + """ +Backends a dict on an sqlite db. This class aims to present like a +dict wherever it can. + +USE: +import sqlite_db from withsqlite +with sqlite_db("filename") as db: + db['aaa'] = {'test':'ok'} + print db.items() + +BUGS: + +vals are json serialized before being written, so if you can't +serialize it, you can't put it in the dict. + +Unimplemented mapping API: +a.copy() a (shallow) copy of a +a.update([b]) updates a with key/value pairs from b, overwriting existing keys, returns None +a.fromkeys(seq[, value]) Creates a new dictionary with keys from seq and values set to value +a.setdefault(k[, x]) a[k] if k in a, else x (also setting it) +a.pop(k[, x]) a[k] if k in a, else x (and remove k) +a.popitem() remove and return an arbitrary (key, value) pair +a.iteritems() return an iterator over (key, value) pairs +a.iterkeys() return an iterator over the mapping's keys +a.itervalues() return an iterator over the mapping's values + +>>> with sqlite_db("test") as db: +... db.clear() +... db.items() +... +[] +>>> with sqlite_db("test") as db: +... db['a']="test" +... db.items() +... +[(u'a', u'test')] +>>> with sqlite_db("test") as db: +... db['as']="test" +... db.items() +... +[(u'a', u'test'), (u'as', u'test')] +>>> with sqlite_db("test") as db: +... db['b']=[1,2,3,4,5] +... del db['b'] +... +>>> with sqlite_db("test") as db: +... db.items() +... len(db) +... +[(u'a', u'test'), (u'as', u'test')] +2 +>>> with sqlite_db("test") as db: +... db.keys() +... +[u'a', u'as'] +>>> with sqlite_db("test") as db: +... db.values() +... +[u'test', u'test'] +>>> with sqlite_db("test") as db: +... db.get('b',5) +... +5 +>>> with sqlite_db("test") as db: +... db.get('b') +... +>>> with sqlite_db("test") as db: +... db.get('c',5) +... +5 +>>> with sqlite_db("test") as db: +... 'as' in db +... +True +>>> with sqlite_db("test") as db: +... 'asdf' not in db +... +True +>>> with sqlite_db("test") as db: +... db.has_key('as') +... +True +>>> +""" + + def __init__(self, fname, autocommit=False, check_same_thread=False): + self.fname = fname + ".sqlite3" + self.autocomit = autocommit + self.check_same_thread = check_same_thread + def __enter__(self): + if not os.path.exists(self.fname): + self.make_db() + self.conn = sqlite3.connect(self.fname, check_same_thread = self.check_same_thread) + self.crsr = self.conn.cursor() + return self + def __exit__(self, type, value, traceback): + self.conn.commit() + self.crsr.close() + def make_db(self): + conn = sqlite3.connect(self.fname) + c = conn.cursor() + c.execute('''create table store (key text unique, val text)''') + conn.commit() + c.close() + def __delitem__(self, key): + """del a[k] remove a[k] from a""" + self.crsr.execute("delete from store where key=?", [key]) + def jsonize(self,val): + "If it's just a string, serialize it ourselves" + if isinstance(val, basestring): + return '"%s"' % val + return json.dumps(val, default=to_json, sort_keys=True, indent=3) + def __setitem__(self, key, val): + """a[k] = v set a[k] to v """ + + try: + if val == self.__getitem__(key): + return + self.crsr.execute("update or fail store set val=? where key==?", [self.jsonize(val), key]) + except KeyError: + self.crsr.execute("insert into store values (?, ?)", [key, self.jsonize(val)]) + + if self.autocommit: self.commit() + def __getitem__(self, key): + """a[k] the item of a with key k (1), (10)""" + self.crsr.execute('select val from store where key=?', [key]) + try: + f = self.crsr.fetchone()[0] + except TypeError: + raise KeyError, key + return json.loads(f) + def __contains__(self, key): + """k in a True if a has a key k, else False + k not in a Equivalent to not k in a""" + self.crsr.execute("select COUNT(*) from store where key=?", [key]) + return self.crsr.fetchone()[0] != 0 + def has_key(self, key): + return self.__contains__(key) + def __len__(self): + """len(a) the number of items in a""" + self.crsr.execute("select COUNT(*) from store") + return self.crsr.fetchone()[0] + def keys(self): + """a.keys() a copy of a's list of keys""" + self.crsr.execute("select key from store") + return [f[0] for f in self.crsr.fetchall()] + def values(self): + """a.values() a copy of a's list of values""" + self.crsr.execute("select val from store") + return [json.loads(f[0]) for f in self.crsr.fetchall()] + def items(self): + """a.items() a copy of a's list of (key, value) pairs""" + self.crsr.execute("select * from store") + return [(f[0], json.loads(f[1])) for f in self.crsr.fetchall()] + def get(self, k, x=None): + """a.get(k[, x]) a[k] if k in a, else x """ + try: + return self.__getitem__(k) + except KeyError: + return x + def commit(self): + self.conn.commit() + def clear(self): + """a.clear() remove all items from a""" + self.crsr.execute("delete from store") + if self.autocommit: self.commit() + +if __name__=="__main__": + import doctest + doctest.testmod() From de840a566a6865c8a95167f541114735c2e193bb Mon Sep 17 00:00:00 2001 From: James Vasile Date: Thu, 15 Dec 2011 15:40:06 -0500 Subject: [PATCH 07/31] cfg.py shouldn't overwrite local config on update --- cfg.py => cfg.sample.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename cfg.py => cfg.sample.py (100%) diff --git a/cfg.py b/cfg.sample.py similarity index 100% rename from cfg.py rename to cfg.sample.py From d641d884bf85028cfa28d723690cdfb36534b42d Mon Sep 17 00:00:00 2001 From: James Vasile Date: Thu, 15 Dec 2011 15:52:39 -0500 Subject: [PATCH 08/31] cfg.py shouldn't overwrite local config on update --- Makefile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 35086eb87..3afdbcfb0 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,4 @@ +#SHELL := /bin/bash MAKE=make #TODO: add install target @@ -8,7 +9,7 @@ COMPRESSED_CSS := $(patsubst %.css,%.tiny.css,$(CSS)) PWD=`pwd` ## Catch-all tagets -default: cherrypy.config dirs template css docs dbs +default: cfg cherrypy.config dirs template css docs dbs all: default dbs: data/users.sqlite3 @@ -19,6 +20,9 @@ data/users.sqlite3: data/users.sqlite3.distrib dirs: @mkdir -p data/cherrypy_sessions +cfg: Makefile + test -f cfg.py || cp cfg.sample.py cfg.py + cherrypy.config: Makefile @echo [global]\\n\ server.socket_host = \'0.0.0.0\'\\n\ From cbc452d86cfb41d0273b07943e266fc86c50cae3 Mon Sep 17 00:00:00 2001 From: James Vasile Date: Thu, 15 Dec 2011 17:52:15 -0500 Subject: [PATCH 09/31] start to make proxy --- share/apache2/plinth.conf | 1 + 1 file changed, 1 insertion(+) create mode 100644 share/apache2/plinth.conf diff --git a/share/apache2/plinth.conf b/share/apache2/plinth.conf new file mode 100644 index 000000000..c25e39840 --- /dev/null +++ b/share/apache2/plinth.conf @@ -0,0 +1 @@ +ProxyPass /plinth/ http://localhost:8000/ From 62efdd96b5f91a2e13948c31625fb950cbf13603 Mon Sep 17 00:00:00 2001 From: James Vasile Date: Fri, 16 Dec 2011 20:54:01 -0500 Subject: [PATCH 10/31] daemonize --- plinth.py | 24 ++++++++++++++++++++++-- share/init.d/plinth | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 2 deletions(-) create mode 100755 share/init.d/plinth diff --git a/plinth.py b/plinth.py index 6f350097c..7a60adcda 100755 --- a/plinth.py +++ b/plinth.py @@ -1,7 +1,6 @@ #!/usr/bin/env python -# Start listener, just for testing -import os, sys +import os, sys, argparse #import logging from gettext import gettext as _ import cfg @@ -9,6 +8,10 @@ if not os.path.join(cfg.file_root, "vendor") in sys.path: sys.path.append(os.path.join(cfg.file_root, "vendor")) import cherrypy +from cherrypy import _cpserver +from cherrypy.process.plugins import Daemonizer +Daemonizer(cherrypy.engine).subscribe() + import plugin_mount from util import * from logger import Logger @@ -96,7 +99,24 @@ tools.staticfile.on = True tools.staticfile.filename = "{fileroot}/static/theme/favicon.ico" """.format(fileroot=cfg.file_root)) +def parse_arguments(): + parser = argparse.ArgumentParser(description='Plinht web interface for the FreedomBox.') + parser.add_argument('--pidfile', default="", + help='specify a file in which the server may write its pid') + args=parser.parse_args() + if args.pidfile: + cfg.pidfile = args.pidfile + def setup(): + parse_arguments() + + try: + if cfg.pidfile: + from cherrypy.process.plugins import PIDFile + PIDFile(cherrypy.engine, cfg.pidfile).subscribe() + except AttributeError: + pass + os.chdir(cfg.file_root) cherrypy.config.update({'error_page.404': error_page_404}) cherrypy.config.update({'error_page.500': error_page_500}) diff --git a/share/init.d/plinth b/share/init.d/plinth new file mode 100755 index 000000000..f5df9b712 --- /dev/null +++ b/share/init.d/plinth @@ -0,0 +1,38 @@ +#!/bin/bash +# This file is /etc/init.d/plinth +DAEMON=/usr/bin/plinth.py +PID_FILE=/var/run/plinth.pid + +start_plinth (){ + if [ -f $PID_FILE ]; then + echo Already running with a pid of `cat $PID_FILE`. + else + $DAEMON --pidfile=$PID_FILE + fi +} + +stop_plinth () { + if [ -f $PID_FILE ]; then + kill -15 `cat $PID_FILE` + rm -rf $PID_FILE + else + echo "No pid file at $PID_FILE suggests plinth is not running." + fi +} + +test -x $DAEMON || exit 0 +case "$1" in + start) + echo "Starting Plinth." + start_plinth + ;; + stop) + echo "Stoping Plinth." + stop_plinth + ;; + restart) + $0 stop + $0 start + ;; + +esac From d8c1a051c2db12b5e6e798cdbd1ff17886dae108 Mon Sep 17 00:00:00 2001 From: James Vasile Date: Fri, 16 Dec 2011 23:42:18 -0500 Subject: [PATCH 11/31] move port to cfg --- cfg.sample.py | 3 +++ plinth.py | 10 +++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/cfg.sample.py b/cfg.sample.py index 0f98be007..34ca0231d 100644 --- a/cfg.sample.py +++ b/cfg.sample.py @@ -12,6 +12,9 @@ users_dir = os.path.join(data_dir, "users") product_name = "Plinth" box_name = "Freedom Plug" +port = 8000 + +## Do not edit below this line ## html_root = None main_menu = Menu() diff --git a/plinth.py b/plinth.py index 7a60adcda..f630ccd28 100755 --- a/plinth.py +++ b/plinth.py @@ -81,14 +81,14 @@ def write_cherrypy_config(): [global] server.socket_host = '0.0.0.0' -server.socket_port = 8000 +server.socket_port = %(port)s server.thread_pool = 10 -tools.staticdir.root = "{fileroot}" +tools.staticdir.root = "%(fileroot)s" tools.sessions.on = True tools.auth.on = True tools.sessions.storage_type = "file" tools.sessions.timeout = 90 -tools.sessions.storage_path = "{fileroot}/data/cherrypy_sessions" +tools.sessions.storage_path = "%(fileroot)s/data/cherrypy_sessions" [/static] tools.staticdir.on = True @@ -96,8 +96,8 @@ tools.staticdir.dir = "static" [/favicon.ico] tools.staticfile.on = True -tools.staticfile.filename = "{fileroot}/static/theme/favicon.ico" -""".format(fileroot=cfg.file_root)) +tools.staticfile.filename = "%(fileroot)s/static/theme/favicon.ico" +""" % {'port':cfg.port, 'fileroot':cfg.file_root}) def parse_arguments(): parser = argparse.ArgumentParser(description='Plinht web interface for the FreedomBox.') From 1a00c3adb743b313fb44f9833139f25027136c7b Mon Sep 17 00:00:00 2001 From: James Vasile Date: Fri, 16 Dec 2011 23:42:29 -0500 Subject: [PATCH 12/31] mkdir --- util.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/util.py b/util.py index 11bb647e0..e43af8371 100644 --- a/util.py +++ b/util.py @@ -1,9 +1,27 @@ -import sys +import os, sys import cherrypy import cfg import sqlite3 from filedict import FileDict +def mkdir(newdir): + """works the way a good mkdir should :) + - already exists, silently complete + - regular file in the way, raise an exception + - parent directory(ies) does not exist, make them as well + """ + if os.path.isdir(newdir): + pass + elif os.path.isfile(newdir): + raise OSError("a file with the same name as the desired " \ + "dir, '%s', already exists." % newdir) + else: + head, tail = os.path.split(newdir) + if head and not os.path.isdir(head): + mkdir(head) + #print "mkdir %s" % repr(newdir) + if tail: + os.mkdir(newdir) def is_string(obj): isinstance(obj, basestring) def is_ascii(s): From 69f3375a4f02986e11c4e86b8c0b153a1a5683ce Mon Sep 17 00:00:00 2001 From: James Vasile Date: Fri, 16 Dec 2011 23:43:30 -0500 Subject: [PATCH 13/31] start adding base_href --- cfg.sample.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cfg.sample.py b/cfg.sample.py index 34ca0231d..186f48729 100644 --- a/cfg.sample.py +++ b/cfg.sample.py @@ -3,6 +3,7 @@ import os file_root = os.path.dirname(os.path.realpath(__file__)) data_dir = os.path.join(file_root, "data") +base_href="" store_file = os.path.join(data_dir, "store.sqlite3") user_db = os.path.join(data_dir, "users") status_log_file = os.path.join(data_dir, "status.log") From 9eada7d59640a4c418de127432efc20847896085 Mon Sep 17 00:00:00 2001 From: James Vasile Date: Fri, 16 Dec 2011 23:44:13 -0500 Subject: [PATCH 14/31] update withsqlite.py --- vendor/withsqlite/withsqlite.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/withsqlite/withsqlite.py b/vendor/withsqlite/withsqlite.py index 40aaa8812..45d66c17b 100644 --- a/vendor/withsqlite/withsqlite.py +++ b/vendor/withsqlite/withsqlite.py @@ -112,7 +112,7 @@ True def __init__(self, fname, autocommit=False, check_same_thread=False): self.fname = fname + ".sqlite3" - self.autocomit = autocommit + self.autocommit = autocommit self.check_same_thread = check_same_thread def __enter__(self): if not os.path.exists(self.fname): From fa89070e011fc205529073ed18d962f98ea3efd4 Mon Sep 17 00:00:00 2001 From: James Vasile Date: Fri, 16 Dec 2011 23:44:54 -0500 Subject: [PATCH 15/31] add order to privacy page plugin --- modules/installed/privacy/privacy.py | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/installed/privacy/privacy.py b/modules/installed/privacy/privacy.py index b62ba5d2e..8eee56524 100644 --- a/modules/installed/privacy/privacy.py +++ b/modules/installed/privacy/privacy.py @@ -5,6 +5,7 @@ from modules.auth import require import cfg class Privacy(PagePlugin): + order = 20 # order of running init in PagePlugins def __init__(self, *args, **kwargs): PagePlugin.__init__(self, *args, **kwargs) self.register_page("privacy") From c5d647018356cf0bc24cacc43e3c04abb4a7c381 Mon Sep 17 00:00:00 2001 From: James Vasile Date: Fri, 16 Dec 2011 23:45:23 -0500 Subject: [PATCH 16/31] start second server --- plinth.py | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/plinth.py b/plinth.py index f630ccd28..7edbf1062 100755 --- a/plinth.py +++ b/plinth.py @@ -129,11 +129,43 @@ def setup(): cfg.log("Loaded %d page plugins" % len(cfg.page_plugins)) cfg.forms = plugin_mount.FormPlugin.get_plugins() + # Add an extra server + server = _cpserver.Server() + server.socket_host = '127.0.0.1' + server.socket_port = 52854 + server.subscribe() + + # Configure default server + cherrypy.config.update({'server.socket_host': '0.0.0.0', + 'server.socket_port': cfg.port, + 'server.thread_pool':10, + 'tools.staticdir.root': cfg.file_root, + 'tools.sessions.on':True, + 'tools.auth.on':True, + 'tools.sessions.storage_type':"file", + 'tools.sessions.timeout':90, + 'tools.sessions.storage_path':"%s/data/cherrypy_sessions" % cfg.file_root, + + }) + + config = {'/': {'tools.staticdir.root': '%s/static' % cfg.file_root}, + '/static': {'tools.staticdir.on': True, + 'tools.staticdir.dir':"."}, + '/favicon.ico':{'tools.staticfile.on':True, + 'tools.staticfile.filename': "%s/static/theme/favicon.ico" % cfg.file_root} + } + cherrypy.tree.mount(cfg.html_root, '/', config=config) + + + cherrypy.engine.signal_handler.subscribe() + + def main(): setup() - cherrypy.quickstart(cfg.html_root, script_name='/', config="cherrypy.config") - + print "localhost %d" % cfg.port + cherrypy.engine.start() + cherrypy.engine.block() if __name__ == '__main__': main() From 515b133c4c51cbd80bcf98f090d770711f97b16e Mon Sep 17 00:00:00 2001 From: James Vasile Date: Sat, 17 Dec 2011 14:02:37 -0500 Subject: [PATCH 17/31] rm old code --- plinth.py | 33 --------------------------------- 1 file changed, 33 deletions(-) diff --git a/plinth.py b/plinth.py index 7edbf1062..954cb2cc0 100755 --- a/plinth.py +++ b/plinth.py @@ -67,38 +67,6 @@ def load_modules(): else: cfg.log("skipping %s" % name) -def write_cherrypy_config(): - """Write the cherrpy.config file. - - We could just make a dict instead of writing a data file and then - reading it back, but I like the output for debugging purposes. - Future versions might do the more efficient thing. - """ - - with open(os.path.join(cfg.file_root, "cherrypy.config"), 'w') as OUTF: - OUTF.write( -"""### Generated file, do not edit! ### - -[global] -server.socket_host = '0.0.0.0' -server.socket_port = %(port)s -server.thread_pool = 10 -tools.staticdir.root = "%(fileroot)s" -tools.sessions.on = True -tools.auth.on = True -tools.sessions.storage_type = "file" -tools.sessions.timeout = 90 -tools.sessions.storage_path = "%(fileroot)s/data/cherrypy_sessions" - -[/static] -tools.staticdir.on = True -tools.staticdir.dir = "static" - -[/favicon.ico] -tools.staticfile.on = True -tools.staticfile.filename = "%(fileroot)s/static/theme/favicon.ico" -""" % {'port':cfg.port, 'fileroot':cfg.file_root}) - def parse_arguments(): parser = argparse.ArgumentParser(description='Plinht web interface for the FreedomBox.') parser.add_argument('--pidfile', default="", @@ -120,7 +88,6 @@ def setup(): os.chdir(cfg.file_root) cherrypy.config.update({'error_page.404': error_page_404}) cherrypy.config.update({'error_page.500': error_page_500}) - write_cherrypy_config() cfg.log = Logger() load_modules() cfg.html_root = Root() From ca9f8e31243427dadd064e1a6934397e804b664e Mon Sep 17 00:00:00 2001 From: James Vasile Date: Mon, 19 Dec 2011 09:04:29 -0500 Subject: [PATCH 18/31] redirect / and /plinth to /plinth/ --- share/apache2/plinth.conf | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/share/apache2/plinth.conf b/share/apache2/plinth.conf index c25e39840..7046b10d9 100644 --- a/share/apache2/plinth.conf +++ b/share/apache2/plinth.conf @@ -1 +1,11 @@ ProxyPass /plinth/ http://localhost:8000/ + + +Options Indexes FollowSymLinks + +RewriteEngine on +RewriteRule [^/]*/plinth$ plinth/ [R] +RewriteRule [^/]*/$ plinth/ [R] +#RewriteRule ^$ plinth/ [R] + + From c9863bc0f8270ec16f05c6edb614ca285feaa890 Mon Sep 17 00:00:00 2001 From: James Vasile Date: Tue, 20 Dec 2011 20:50:58 -0500 Subject: [PATCH 19/31] subdomain for plinth --- share/apache2/plinth.conf | 40 +++++++++++++++++++++++++++++++-------- static/static | 1 + 2 files changed, 33 insertions(+), 8 deletions(-) create mode 120000 static/static diff --git a/share/apache2/plinth.conf b/share/apache2/plinth.conf index 7046b10d9..6f0612f6a 100644 --- a/share/apache2/plinth.conf +++ b/share/apache2/plinth.conf @@ -1,11 +1,35 @@ -ProxyPass /plinth/ http://localhost:8000/ - -Options Indexes FollowSymLinks + + DocumentRoot /dev/null + ServerName plinth -RewriteEngine on -RewriteRule [^/]*/plinth$ plinth/ [R] -RewriteRule [^/]*/$ plinth/ [R] -#RewriteRule ^$ plinth/ [R] + ## Force ssl + RewriteEngine on + ReWriteCond %{SERVER_PORT} !^443$ + RewriteRule ^/(.*) https://%{HTTP_HOST}/$1 [NC,R,L] + + + + + DocumentRoot /home/james/src/plinth/static + ServerName plinth + + SSLEngine on + SSLCertificateFile /etc/apache2/ssl/apache.pem + + ## Use a rule like this to hang plinth off a subdir + #RewriteEngine on + #RewriteRule ^/plinth/(.*)$ http://localhost:8000/$1 [P,L] + #Use the following to debug rewrite rules + #RewriteLog "/var/log/apache2/rewrite.log" + #RewriteLogLevel 9 + + ## Use proxy directives to hand plinth off a domain or subdomain + ProxyPass /static ! + ProxyPass / http://localhost:8000/ + ProxyPassReverse / http://localhost:8000/ + + allow from all + + - diff --git a/static/static b/static/static new file mode 120000 index 000000000..945c9b46d --- /dev/null +++ b/static/static @@ -0,0 +1 @@ +. \ No newline at end of file From 51a74abc82d005a49c52e86ef499acf03b3d8a74 Mon Sep 17 00:00:00 2001 From: James Vasile Date: Tue, 20 Dec 2011 21:22:36 -0500 Subject: [PATCH 20/31] listen locally only, proxy to the outside world --- plinth.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/plinth.py b/plinth.py index 954cb2cc0..b8afa7582 100755 --- a/plinth.py +++ b/plinth.py @@ -103,8 +103,8 @@ def setup(): server.subscribe() # Configure default server - cherrypy.config.update({'server.socket_host': '0.0.0.0', - 'server.socket_port': cfg.port, + cherrypy.config.update({'server.socket_host': '127.0.0.1', + 'server.socket_port': cfg.port, 'server.thread_pool':10, 'tools.staticdir.root': cfg.file_root, 'tools.sessions.on':True, @@ -115,15 +115,14 @@ def setup(): }) - config = {'/': {'tools.staticdir.root': '%s/static' % cfg.file_root}, + config = {'/': {'tools.staticdir.root': '%s/static' % cfg.file_root, + 'tools.proxy.on':True,}, '/static': {'tools.staticdir.on': True, 'tools.staticdir.dir':"."}, '/favicon.ico':{'tools.staticfile.on':True, 'tools.staticfile.filename': "%s/static/theme/favicon.ico" % cfg.file_root} } cherrypy.tree.mount(cfg.html_root, '/', config=config) - - cherrypy.engine.signal_handler.subscribe() From 873709794cd36267d76fabed45e0cb7768e73406 Mon Sep 17 00:00:00 2001 From: James Vasile Date: Tue, 20 Dec 2011 21:25:20 -0500 Subject: [PATCH 21/31] move basehref --- cfg.sample.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cfg.sample.py b/cfg.sample.py index 186f48729..2c8a8adf1 100644 --- a/cfg.sample.py +++ b/cfg.sample.py @@ -3,7 +3,6 @@ import os file_root = os.path.dirname(os.path.realpath(__file__)) data_dir = os.path.join(file_root, "data") -base_href="" store_file = os.path.join(data_dir, "store.sqlite3") user_db = os.path.join(data_dir, "users") status_log_file = os.path.join(data_dir, "status.log") @@ -18,4 +17,5 @@ port = 8000 ## Do not edit below this line ## html_root = None main_menu = Menu() +base_href = "" From 3605889eeb9253f7a3f550b3cae62adfdf901f1f Mon Sep 17 00:00:00 2001 From: James Vasile Date: Tue, 20 Dec 2011 21:26:03 -0500 Subject: [PATCH 22/31] ignore backups --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index f5dbc143c..2088e658a 100644 --- a/.gitignore +++ b/.gitignore @@ -18,4 +18,5 @@ doc/oneline.txt doc/plinth.1 templates/*.py TODO -\#* \ No newline at end of file +\#* +.#* From 157d522bf69cfdacadb382d8a4227b691478743a Mon Sep 17 00:00:00 2001 From: James Vasile Date: Tue, 20 Dec 2011 21:26:51 -0500 Subject: [PATCH 23/31] plinth is in local --- share/init.d/plinth | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/init.d/plinth b/share/init.d/plinth index f5df9b712..46bc36933 100755 --- a/share/init.d/plinth +++ b/share/init.d/plinth @@ -1,6 +1,6 @@ #!/bin/bash # This file is /etc/init.d/plinth -DAEMON=/usr/bin/plinth.py +DAEMON=/usr/local/bin/plinth.py PID_FILE=/var/run/plinth.pid start_plinth (){ From 7007a013ad6fd7bd1e76b30f96fc6d98e1bc7d0b Mon Sep 17 00:00:00 2001 From: James Vasile Date: Tue, 20 Dec 2011 21:28:00 -0500 Subject: [PATCH 24/31] add base_href to templates --- templates/base.tmpl | 18 +++++++++--------- templates/two_col.tmpl | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/templates/base.tmpl b/templates/base.tmpl index f191589c9..10f0d4adf 100644 --- a/templates/base.tmpl +++ b/templates/base.tmpl @@ -13,11 +13,11 @@ - - + + $css - - + + $js $main_menu_js $sub_menu_js @@ -30,12 +30,12 @@ diff --git a/templates/two_col.tmpl b/templates/two_col.tmpl index 0b559ade8..3acef6965 100644 --- a/templates/two_col.tmpl +++ b/templates/two_col.tmpl @@ -1,5 +1,5 @@ #extends templates.base #def css - + #end def From 1bdf38f4704035d8cc14f0ea7aa0f73da9bbccb8 Mon Sep 17 00:00:00 2001 From: James Vasile Date: Tue, 20 Dec 2011 21:28:26 -0500 Subject: [PATCH 25/31] base href defaults to blank --- util.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/util.py b/util.py index e43af8371..98fb18a3d 100644 --- a/util.py +++ b/util.py @@ -58,10 +58,12 @@ class Message(): self.text += "
%s" % text def page_template(template='base', **kwargs): - for k in ['sidebar_left', 'sidebar_right', 'main', 'js', 'onload', 'nav', 'css', 'title']: + for k in ['sidebar_left', 'sidebar_right', 'main', 'js', 'onload', 'nav', 'css', 'title', 'basehref']: if not k in kwargs: kwargs[k] = '' + if kwargs['basehref'] == '': + kwargs['basehref'] = cfg.base_href if template=='base' and kwargs['sidebar_right']=='': template='two_col' if isinstance(template, basestring): From 130ca2e436075d550aa58d24e703e548d4b83438 Mon Sep 17 00:00:00 2001 From: James Vasile Date: Tue, 20 Dec 2011 21:29:58 -0500 Subject: [PATCH 26/31] set documentroot to /dev/null --- share/apache2/plinth.conf | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/share/apache2/plinth.conf b/share/apache2/plinth.conf index 6f0612f6a..aab477fa1 100644 --- a/share/apache2/plinth.conf +++ b/share/apache2/plinth.conf @@ -1,5 +1,6 @@ + # The DocumentRoot is set by fabric DocumentRoot /dev/null ServerName plinth @@ -11,7 +12,8 @@ - DocumentRoot /home/james/src/plinth/static + # The DocumentRoot is set by fabric + DocumentRoot /dev/null ServerName plinth SSLEngine on From d7d768308d849df7066f48700fcbc22df7163956 Mon Sep 17 00:00:00 2001 From: James Vasile Date: Tue, 20 Dec 2011 21:30:21 -0500 Subject: [PATCH 27/31] menu can add base href automatically --- menu.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/menu.py b/menu.py index e0e376a5c..3e682e4b5 100644 --- a/menu.py +++ b/menu.py @@ -27,9 +27,15 @@ class Menu(): def sort_items(self): """Sort the items in self.items by order.""" self.items = sorted(self.items, key=lambda x: x.order, reverse=False) - def add_item(self, label, url, order=50): + def add_item(self, label, url, order=50, basehref=True): """This method creates a menu item with the parameters, adds - that menu item to this menu, and returns the item.""" + that menu item to this menu, and returns the item. + + If BASEHREF is true and url start with a slash, prepend the cfg.base_href to it""" + + if basehref and url.startswith("/"): + url = cfg.base_href + url + item = Menu(label=label, url=url, order=order) self.items.append(item) self.sort_items() From fbcb4f7753bd4d40c574561e71f3f70fb859c60b Mon Sep 17 00:00:00 2001 From: James Vasile Date: Tue, 20 Dec 2011 22:42:21 -0500 Subject: [PATCH 28/31] starting santiago --- modules/installed/santiago/santiago.py | 123 +++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 modules/installed/santiago/santiago.py diff --git a/modules/installed/santiago/santiago.py b/modules/installed/santiago/santiago.py new file mode 100644 index 000000000..169e9d7e2 --- /dev/null +++ b/modules/installed/santiago/santiago.py @@ -0,0 +1,123 @@ +""" +santiago is the interface that listens over a tor hidden service. It +accepts json requests and responds with json data structures filled +with information. There is authentication involved, although I +haven't figured that one all the way through yet. +""" + +import os +import cherrypy +import simplejson as json +from gettext import gettext as _ +from plugin_mount import PagePlugin +from modules.auth import require +import cfg +import util as u + +santiago_port = 52854 + +import gnupg + +def check_sig(query, sig): + "Verify that the sig and the query match" + gpg = gnupg.GPG(gnupghome='/home/james/') + return True + +class Santiago(PagePlugin): + order = 90 # order of running init in PagePlugins + def __init__(self, *args, **kwargs): + + self.register_page("santiago") + self.santiago_address = self.get_santiago_address() #TODO: multiple santiago ports + #set a listener on the santiago address + + def get_santiago_address(self): + if 'santiago' in cfg.users['admin'] and 'address' in cfg.users['admin']['santiago']: + return cfg.users['admin']['santiago']['address'] + else: + admin = cfg.users['admin'] + admin['santiago'] = {} + + with open ("/etc/tor/torrc", 'r') as INF: + rc = INF.read() + + self.santiago_dir = os.path.join(cfg.file_root, "data", "santiago", "tor") + self.tor_dir = os.path.join(self.santiago_dir, "general") + u.mkdir(self.santiago_dir) + os.system( 'chmod a+w %s' % self.santiago_dir) + hidden_service_config = "HiddenServiceDir %s\nHiddenServicePort 80 127.0.0.1:%d" % (self.tor_dir, santiago_port) + if hidden_service_config in rc: + ## get info from dir (but how? we need perms) + ## just fake it for now + admin['santiago']['address'] = "b5wycujkfh2jxfdo.onion" + cfg.users['admin'] = admin + return cfg.users['admin']['santiago']['address'] + print "Need to add these two lines to /etc/torrc:\n%s" % hidden_service_config + return "" + + def check_for_hidden_service(self): + pass + + @cherrypy.expose + def index(self, *args, **kw): + + """ + A request is a dict with some required keys: + req - this is the request. It is a dict that has keys of use to serving the request. + version - the version number of this description (currently 1) + entropy - a random string of at least 256 bytes. + signature - an optional signature + """ + if (cherrypy.request.local.port != santiago_port + #or not check_sig(kw['q'], kw['sig']) + + #or cherrypy.request.method.upper() != "POST" + ): + raise cherrypy.HTTPError(404) + + return kw['q'] + from pprint import pformat + + #return str(cherrypy.request.params) + + return ''' +CP Info +
%s
+''' % pformat({ + 'args': args, + 'kw': kw, + 'request': dict([(k, getattr(cherrypy.request, k)) + for k in dir(cherrypy.request) + if not k.startswith('_')]), + }) + + + + + #try: + # query = json.loads(q) + #except: + # raise cherrypy.HTTPError(404) + + ## client requests proxy methods + ## we send back a list of proxy methods (complete with routes/IP addresses to connect to) + + + return str(cherrypy.request.local.port) + a = "
".join(dir(cherrypy.request)) + a += cherrypy.request.query_string + "!!!!!!!!!!!!" + a += str(cherrypy.request.local.port) + return a + return "test " + cherrypy.request.method.upper() + " "+t + +## Plinth page to config santiago +class santiago(PagePlugin): + def __init__(self, *args, **kwargs): + PagePlugin.__init__(self, *args, **kwargs) + self.menu = cfg.html_root.privacy.menu.add_item("Santiago", "/privacy/santiago", 10) + self.register_page("privacy.santiago") + + @cherrypy.expose + @require() + def index(self): + return "Santiago's config goes here." From caeb6bc7aa752b8f0f53ad769323644c07cebc68 Mon Sep 17 00:00:00 2001 From: James Vasile Date: Wed, 21 Dec 2011 11:59:27 -0500 Subject: [PATCH 29/31] enable santiago --- modules/santiago.py | 1 + 1 file changed, 1 insertion(+) create mode 120000 modules/santiago.py diff --git a/modules/santiago.py b/modules/santiago.py new file mode 120000 index 000000000..ae4ef986e --- /dev/null +++ b/modules/santiago.py @@ -0,0 +1 @@ +installed/santiago/santiago.py \ No newline at end of file From 1dc3d28a999e131c9bf6ed1382c2acad48574946 Mon Sep 17 00:00:00 2001 From: James Vasile Date: Thu, 22 Dec 2011 17:07:27 -0500 Subject: [PATCH 30/31] tag init.d script --- share/init.d/plinth | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/share/init.d/plinth b/share/init.d/plinth index 46bc36933..e364fc123 100755 --- a/share/init.d/plinth +++ b/share/init.d/plinth @@ -1,4 +1,15 @@ #!/bin/bash +### BEGIN INIT INFO +# Provides: plinth +# Required-Start: $syslog +# Required-Stop: $syslog +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: plinth web frontend +# Description: +# +### END INIT INFO + # This file is /etc/init.d/plinth DAEMON=/usr/local/bin/plinth.py PID_FILE=/var/run/plinth.pid From e648c05039dd4c5a0e636c0b91ff17eaad70712b Mon Sep 17 00:00:00 2001 From: James Vasile Date: Sun, 19 Feb 2012 14:41:40 -0500 Subject: [PATCH 31/31] flesh out santiago and apache config a bit --- modules/installed/santiago/santiago.py | 40 +++++++++++++------------- share/apache2/plinth.conf | 2 ++ 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/modules/installed/santiago/santiago.py b/modules/installed/santiago/santiago.py index 169e9d7e2..38e651206 100644 --- a/modules/installed/santiago/santiago.py +++ b/modules/installed/santiago/santiago.py @@ -5,7 +5,7 @@ with information. There is authentication involved, although I haven't figured that one all the way through yet. """ -import os +import os, sys import cherrypy import simplejson as json from gettext import gettext as _ @@ -16,22 +16,22 @@ import util as u santiago_port = 52854 -import gnupg +#import gnupg -def check_sig(query, sig): - "Verify that the sig and the query match" - gpg = gnupg.GPG(gnupghome='/home/james/') - return True +#def check_sig(query, sig): +# "Verify that the sig and the query match" +# gpg = gnupg.GPG(gnupghome='/home/james/') +# return True class Santiago(PagePlugin): - order = 90 # order of running init in PagePlugins - def __init__(self, *args, **kwargs): + order = 90 # order of running init in PagePlugins + def __init__(self, *args, **kwargs): self.register_page("santiago") self.santiago_address = self.get_santiago_address() #TODO: multiple santiago ports #set a listener on the santiago address - def get_santiago_address(self): + def get_santiago_address(self): if 'santiago' in cfg.users['admin'] and 'address' in cfg.users['admin']['santiago']: return cfg.users['admin']['santiago']['address'] else: @@ -55,11 +55,11 @@ class Santiago(PagePlugin): print "Need to add these two lines to /etc/torrc:\n%s" % hidden_service_config return "" - def check_for_hidden_service(self): + def check_for_hidden_service(self): pass - @cherrypy.expose - def index(self, *args, **kw): + @cherrypy.expose + def index(self, *args, **kw): """ A request is a dict with some required keys: @@ -112,12 +112,12 @@ class Santiago(PagePlugin): ## Plinth page to config santiago class santiago(PagePlugin): - def __init__(self, *args, **kwargs): - PagePlugin.__init__(self, *args, **kwargs) - self.menu = cfg.html_root.privacy.menu.add_item("Santiago", "/privacy/santiago", 10) - self.register_page("privacy.santiago") + def __init__(self, *args, **kwargs): + PagePlugin.__init__(self, *args, **kwargs) + self.menu = cfg.html_root.privacy.menu.add_item("Santiago", "/privacy/santiago", 10) + self.register_page("privacy.santiago") - @cherrypy.expose - @require() - def index(self): - return "Santiago's config goes here." + @cherrypy.expose + @require() + def index(self): + return "Santiago's config goes here." diff --git a/share/apache2/plinth.conf b/share/apache2/plinth.conf index aab477fa1..8c45eb1d9 100644 --- a/share/apache2/plinth.conf +++ b/share/apache2/plinth.conf @@ -3,6 +3,7 @@ # The DocumentRoot is set by fabric DocumentRoot /dev/null ServerName plinth + ServerAlias plinth.* ## Force ssl RewriteEngine on @@ -15,6 +16,7 @@ # The DocumentRoot is set by fabric DocumentRoot /dev/null ServerName plinth + ServerAlias plinth.* SSLEngine on SSLCertificateFile /etc/apache2/ssl/apache.pem