Introduction

Name

plinth - a web front end for administering every aspect of a Freedom Box.

Synopsis

plinth.py

Description

The Freedom Box is a net appliance conceived by Eben Moglen. It contains free software and is designed to allow you to interface with the rest of the net under conditions of protected privacy and data security.

The Plinth front end is a web interface to administer the functions of the Freedom Box. For example, the Freedom Box is a wireless router, and the front end is where you can adjust its settings.

Overview

The front end is an extensible web platform for forms and menus. It allows authenticated users to fill out forms. The interface saves the form data and from them generates configuration files for the various services running on the box.

The interface is pluggable. Drop modules into place to add new capabilities to Plinth and your Freedom Box. Replace existing modules to get newer, better shinier functions. The modules will automatically integrate into the existing menu system so you can control all of the box's parts from one central location.

The interface will eventually have a 'basic' and an 'expert' mode. In basic mode, much of Plinth's configuration and capability are hidden. Sane defaults are chosen whenever possible. In expert mode, you can 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.

Getting Started

See the INSTALL file for additional details. Run:

$ make

Once make finishes, run Plinth on the local system with:

$ bash start.sh

Quick Start

Installing Plinth

Install the dependencies:

apt-get install pandoc psmisc python2.7 python-bcrypt python-cherrypy3 python-django python-passlib python-bootstrapform libjs-twitter-bootstrap sudo

Unzip and untar the source into a directory. Change to the directory containing the program. Run:

$ make

To start Plinth, run:

$ ./start.sh

and point your web browser at localhost:8000. The default username is "admin" and the default password is "secret".

Dependencies

The documentation has some dependencies too.

Building the Documentation

Documentation has been collected into a pdf that can be built using make doc. It also gets built into smaller files and other formats, including one suitable for install as a man page.

Themes and Templates

The visual look and feel of the front end is described in theme files while Django templates handle layout.

Themes

Themes are stored in /themes. Themes consist entirely of static files (e.g. css, images and javascript) and templates. The default or active theme is linked from /static/default and templates/default. If your theme needs to change anything other than these items, you'll need a module (perhaps you'll need both).

There is not currently any support for dynamically choosing a theme at runtime, but it is theoretically possible.

Templates

Plinth uses the Django templating system. Templates are stored in /templates. Template requirements are not specified.

TODO: formalize the template spec so template writers know what they need to implement and where they can deviate.

In this section, I'll attempt to document some of the assumptions the program has about templates. The goal is that if you write a tempate that implements the spec, it should work just fine.

The Template Stack

The template is a hierarchical stack, where some templates extend on others. At the base of this stack is base.tmpl. It should specify sections as blocks (rather than using the variables). This allows other templates to easily override the base template.

err.tmpl builds on top of page.tmpl by adding some decoration to the title field.

Layout

Plinth expects a main block. This is where the meat of the content goes. It is the center pain in the default layout. There is a title block that the program will fill with text describing the current page. sidebar_left contains the submenu navigation menu, and sidebar_right is where we put all short text that helps the admin fill out forms. They don't have to be sidebars, and they don't have to go on the left and right.

It is possible to override the footer, but I haven't yet found a reason to do so.

Hacking

This codebase could really use a testing framework.

If you are interested in helping out, writing tests is a great place to start-- you don't need to know much about the code or python to write useful tests.

In addition to a testing framework, the code is in need of some general cleanup. I've been inconsistent in capitalization conventions as well as in my use of underscores.

The plugin interface could use some attention as well. Right now, it's a a bit of a free-for-all until I see how the plugins actually code up. Channeling all that into a few plugin interface grooves would be a help.

If you're feeling more ambitious than that, the best way to improve Plinth is to add modules. More functionality, especially in the router section, could convert the Freedom Box from a good idea to a must-have appliance.

Beyond that, we need to train some expert eyes on the interaction between Freedom Boxes. Transparent, zero-config box-to-box backup is possible. We just need to build an auth and dns layer. There are lots of theories on how to do this well. The first theory reduced to practice wins!

There is a list of TODO items below. Some of them are discrete pieces that can be tackled without diving too deep into the code.

Repository

Plinth is available from github at git://github.com/jvasile/plinth.git. The project page on github is at https://github.com/jvasile/plinth.

Bugs

There are lots of bugs. We don't have a spec or tests, so a bug is really just any unexpected behavior. I am not easily surprised, but there are still lots of bugs.

There's an issue tracker. Please add things and consult it for things to tackle.

Coding Practices

I try to stick to PEP 8 recommendations. That's not to say I don't deviate, just that deviations are usually bugs that should be fixed.

Internationalization

Every module should from gettext import gettext as _ and wrap displayed strings with _(). We don't have the language stuff in place yet (we have no translation files), but we need to put the infrastructure in place for it from the start. Use it like this:

cfg.log.error(_("Couldn't import %s: %s") % (path, e))

Variables and Data Stores

Plinth needs to keep information for short and long term future use, and it can't just store all of that on the stack.

Global config information can be put in the cfg module namespace. Keep it thread and session safe, though, or you'll get undefined behavior as soon as multiple simultaneous users enter the picture.

Cherrpy has support for session variables. Use those for short term user-specific data.

For long term storage, the Plinth needs a back end storage solution. Databases are a bit opaque and can be hard for third party software or shell users to manipulate. For now, I've decided that persistent data should be placed in dicts and stored in json format. We'll need a file locking solution too.

The user_store.py module implements the UserStoreModule interface specified in plugin_mount.py. Any new system that respects that interface can be used. The existing user_store.py holds entire user files in memory and caches user files as it goes. This has two downsides: first, if you have lots of users and store big things in the user dict, you'll run out of memory. Second, it's not thread safe. Maybe a database is a good idea after all.

We do not yet have a means of storing module data for long terms. My current thinking is that modules can store data in their own directories. That makes removal easy.

Todo

Plinth has a number of open todo items. And there are items in the issue tracker that need tackling. Please help!

Modules

Almost all of the front end's functionality is contained in small, separate modules that reside in the directory tree beneath /modules/installed. Some are installed by default, some are required for operation, and some are entirely optional.

Installing and Loading Modules

Eventually, the goal is for module to be separate Debian package so installation is as simple as aptitude install freedombox-foo. As an intermediate step, we'll start scripting module installation. But until then, we can install them manually.

Modules are installed by copying them into the tree beneath the /modules/installed directory. They are activated by linking their .py files into the modules directory. (Freedom Box will not load modules unless they are symlinks.) If the module provides other resources, they can be linked from wherever in the working tree they need to be. So if a module provides a template, that template can be linked from /templates.

Modules can be organized into subdirectories beneath the installed directory. As an initial matter, I've made separate directories for each major tab. Modules that extend the functionality of the Freedom Box code base (as opposed to being user-visible interface modules under specific major tabs) go in modules/installed/lib. This convention can be adjusted or ignored as needed. In fact, modules can be installed anywhere in the file system as long as the symlinks are in /modules.

The names of the symlinks in the modules directory can be arbitrary, and if a name is already taken, (e.g. if router/info.py and apps/info.py both exist), append a counter to the end (e.g. link info.py to router/info.py and info1.py to apps/info.py).

If a module cannot be imported for any reason (e.g. it's a dead symlink), freedombox.py will log an error but will otherwise just keep going.

TODO: automatically prune dead links to clear out old module installs. This is something the install scripts should do.

Pluggable Module Structure

Plugin interfaces are contained in plugin_mount.py. Each interface is a metaclass. Classes that implement a given interface should inherit the metaclass and then provide the indicated properties. New metaclasses can be created to make new classes of plugins.

Any place that might be affected by arbitrary addition of modules should have its own metaclass.

Coding Practices for Modules

All the coding practices for hacking on the front end also apply to modules. In addition, I try to stick to the other practices listed in this section.

Scripts

The Plinth front end should not directly change any aspect of the underlying operating system. Instead, it should call upon scripts, either by shell command or (for python modules) via import.

Scripts live in /scripts. They should have the following characteristics:

The scripts should be of general utility. They should be usable to admin and configure the system even in the absence of Plinth. These scripts are the only supported method of making changes to a Freedom Plug, whtether by SSH or via Plinth.

Security

Password Storage

Here is an overview of how user passwords are currently being stored in Plinth.

Storing a password (add_user function in auth module):

  1. We check if the username or password is empty. If so, return an error message.

  2. Use bcrypt (from passlib) to hash the password with a random salt. bcrypt returns the hash in the format:

2a$<22-character salt><31-character checksum>

This hashed string will be used in step 5.

  1. If the password length is over 4096, bcrypt raises an exception. We catch this exception and return an error message.

  2. Check if the username exists in user store. If so, return an error message.

  3. If no error has occurred so far, create the new user. The username, hashed password, and salt are stored in the user store database. The salt is a substring of the hash output by bcrypt.

Checking password at login (check_credentials function in auth module):

  1. We check if the username or password is empty. If so, return an error message.

  2. Use bcrypt to hash the supplied password. This step is performed regardless of whether the user already exists. If the user exists, use the salt value stored for that user in the database, otherwise, a random salt is used.

  3. If the password length is over 4096, bcrypt raises an exception. We catch this exception and return an error message.

  4. Check if the user doesn't exist, or if the hashed password doesn't match the stored hash. Return an error message "Bad user-name or password" if either of these conditions are true.

  5. If no error has occurred so far, return None to indicate that the supplied credentials are valid.

Plinth and Freedom Plug FAQ

General Questions

What is the Freedom Plug?

The Freedom Plug is .... insert links...

The Freedom Plug is based on the GNU/Debian operating system. It is not a Linux distribution. It is a network appliance that depends on a series of Debian packages that configure a plug computer to behave as a Freedom Plug.

What is Plinth?

Plinth is the web-based GUI administration front end for the Freedom Plug.

On what hardware is the Freedom Plug based?

The current targets are the Guru Plug and the Dream Plug.

Accessing the Freedom Plug

Why does ssh listen on port 2222 instead of 22?

If ssh listens on port 2222, bots and scripts will forever attempt to guess your username and password. Maybe your password isn't so strong. Maybe the bots get lucky. Either way, if you allow ssh access on port 22, you're taking a chance that can be avoided quite easily by moving your ssh activity to a slightly more obscure port.

Because ssh activity on these boxes will be limited to programs configured to work specifically with Freedom Plugs as well relatively few people generally using ssh, the coordination necessary to use a non-standard port is easily achieved.

License to Copy Plinth

Plinth is Copyright 2011-2013 James Vasile (). It is distributed under the GNU Affero General Public License, Version 3 or later. A copy of AGPLv3 is available from the Free Software Foundation.

In addition, the documentation to this software is distributed under a Creative Commons Attribution-ShareAlike 3.0 Unported, Version 3 license. This CC-By-SA license is available in both full and summarized versions from Creative Commons.

The documentation to this software is also distributed under the GNU Free Documentation License, version 1.3 or later.

In default form, Plinth incorporates FileDict, a Python module released under a "MIT/BSD/Python" license, as per its blog page.

Colophon

This manual was typed in emacs, formatted using markdown and converted to pdf, html, troff and latex using pandoc and pdflatex.

The complete source code to this manual is available in the 'doc' directory of the Freedom Box front end source distribution.