summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rwxr-xr-xtools/gnome-encfs423
-rwxr-xr-xtools/install-defaults24
2 files changed, 447 insertions, 0 deletions
diff --git a/tools/gnome-encfs b/tools/gnome-encfs
new file mode 100755
index 0000000..f760797
--- /dev/null
+++ b/tools/gnome-encfs
@@ -0,0 +1,423 @@
+#!/usr/bin/python
+
+# =============================================================================
+#
+# gnome-encfs - GNOME keyring and auto-mount integration of EncFS folders.
+# Copyright (C) 2010 Oben Sonne <obensonne@googlemail.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# =============================================================================
+
+import getpass
+import os
+import os.path
+import optparse
+import subprocess
+import sys
+
+from xdg.DesktopEntry import DesktopEntry as xdg_de
+from xdg.BaseDirectory import xdg_config_home as xdg_ch
+
+import gtk # automatically set application name
+import gnomekeyring as gk
+
+# =============================================================================
+# test mode related
+# =============================================================================
+
+TEST = "GNOME_ENCFS_TEST" in os.environ
+
+class preset:
+ """Preset user input. Used for non-interactive testing mode."""
+
+ proceed = None
+ password = None
+ epath = None
+ mpoint = None
+ amount = None
+
+# =============================================================================
+# constants
+# =============================================================================
+
+# attributes to detect gnome-encfs items in keyring
+GENCFS_ATTR = {"gnome-encfs": TEST and "test" or "" }
+
+KEYRING = gk.get_default_keyring_sync()
+
+ITYPE = gk.ITEM_GENERIC_SECRET
+
+MSG_NO_MATCH = ("No matching EncFS items in keyring.\n"
+ "Use option --list to show available items or "
+ "option --add to add items.")
+
+USAGE = """Usage: %prog --list
+ %prog --mount [ENCFS-PATH-or-MOUNT-POINT]
+ %prog --add ENCFS-PATH MOUNT-POINT
+ %prog --edit MOUNT-POINT
+ %prog --remove MOUNT-POINT"""
+
+DESCRIPTION = """Painlessly mount and manage EncFS folders using GNOME's
+keyring."""
+
+EPILOG = """This tool stores EncFS paths,
+corresponding mount points as well as passwords in the GNOME keyring and
+optionally mounts EncFS paths automatically on login to a GNOME session (works
+only if gnome-encfs is installed in the system path, at /usr/bin or
+/usr/local/bin).
+"""
+
+VERSION="0.1"
+
+# =============================================================================
+# helper
+# =============================================================================
+
+def _options():
+ """Parse command line options."""
+
+ op = optparse.OptionParser(usage=USAGE, version=VERSION,
+ description=DESCRIPTION, epilog=EPILOG)
+
+ op.add_option("-l", "--list", action="store_true", default=False,
+ help="list all EncFS items stored in keyring")
+ op.add_option("-m", "--mount", action="store_true", default=False,
+ help="mount all or selected EncFS paths stored in keyring")
+ op.add_option("-a", "--add", action="store_true", default=False,
+ help="add a new EncFS item to keyring")
+ op.add_option("-e", "--edit", action="store_true", default=False,
+ help="edit an EncFS item in keyring")
+ op.add_option("-r", "--remove", action="store_true", default=False,
+ help="remove an EncFS item from keyring")
+
+ og = optparse.OptionGroup(op, "Non-interactive")
+ og.add_option("", "--proceed", default=None,
+ help="Input for proceed question")
+ og.add_option("", "--password", default=None, metavar="PW",
+ help="Input for password prompt")
+ og.add_option("", "--epath", default=None,
+ help="Input for EncFS path edit")
+ og.add_option("", "--mpoint", default=None,
+ help="Input for mount point edit")
+ og.add_option("", "--amount", default=None,
+ help="Input for auto mount question")
+ op.add_option_group(og)
+
+ opts, args = op.parse_args()
+
+ try:
+ args.remove("autostart")
+ opts.autostart = True
+ opts.mount = True
+ except ValueError:
+ opts.autostart = False
+
+ if opts.list + opts.mount + opts.add + opts.edit + opts.remove != 1:
+ op.print_help()
+ op.exit(1)
+
+ # normalize paths
+ args = [_pathify(a) for a in args]
+
+ opts.p1 = args and args.pop(0) or None
+ opts.p2 = args and args.pop(0) or None
+
+ if opts.add and not (opts.p1 and opts.p2):
+ op.error("add needs an EncFS path and a moint point")
+ op.print_help()
+ op.exit(1)
+
+ if opts.remove and not opts.p1:
+ op.error("remove needs a moint point")
+ op.print_help()
+ op.exit(1)
+
+ preset.proceed = opts.proceed
+ preset.password = opts.password
+ preset.epath = opts.epath
+ preset.mpoint = opts.mpoint
+ preset.amount = opts.amount
+
+ return opts
+
+def _exit(ec):
+ """Exit with additional check if autostart file is still needed."""
+
+ _autostart(_get_items(amount="y"))
+ sys.exit(ec)
+
+def _proceed(msg):
+ print("Warning: %s" % msg)
+ proceed = preset.proceed or raw_input("Proceed [y/N]: ")
+ if proceed.strip()[0].lower() != "y":
+ _exit(2)
+
+def _pathify(path):
+
+ path = os.path.expanduser(path)
+ path = os.path.expandvars(path)
+ path = os.path.abspath(path)
+ path = os.path.realpath(path)
+ return path
+
+def _is_mounted(mpoint):
+ """Check of something is mounted at given mount point."""
+
+ p = subprocess.Popen(["mount"], stdout=subprocess.PIPE)
+ mount = p.communicate()[0]
+ lines = mount.strip('\n').split('\n')
+ points = map(lambda line: line.split()[2], lines)
+ points = [os.path.abspath(p) for p in points]
+ return os.path.abspath(mpoint) in points
+
+def _is_encfs(epath):
+ """Check if 'epath' points to an EncFS directory."""
+
+ p = subprocess.Popen(["encfsctl", "info", epath], stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ p.communicate()
+ return p.returncode == 0
+
+_items_cached = None
+
+def _get_items(mpoint=None, epath=None, anypath=None, amount=None):
+ """Get all EncFS items or those matching given attributes."""
+
+ global _items_cached
+
+ if _items_cached is None:
+ try:
+ _items_cached = gk.find_items_sync(ITYPE, GENCFS_ATTR)
+ except gk.NoMatchError:
+ _items_cached = []
+
+ match = []
+ for item in _items_cached:
+ if mpoint and item.attributes["mount-point"] != mpoint:
+ continue
+ if epath and item.attributes["encfs-path"] != epath:
+ continue
+ if anypath and (item.attributes["mount-point"] != anypath and
+ item.attributes["encfs-path"] != anypath):
+ continue
+ if amount and item.attributes["auto-mount"] != amount:
+ continue
+ match.append(item)
+
+ return match
+
+def _autostart(enable):
+ """Set up XDG autostart file."""
+
+ if TEST:
+ fname = os.path.join(os.path.curdir, "autostart.desktop")
+ else:
+ fname = os.path.join(xdg_ch, "autostart", "gnome-encfs.desktop")
+
+ if not enable:
+ if os.path.exists(fname):
+ os.remove(fname)
+ return
+
+ content = {
+ "Exec": "gnome-encfs autostart",
+ "Name": "EncFS",
+ "Comment": "Mount EncFS folders configured in GNOME's keyring",
+ "Icon": "folder",
+ "Version": "1.0",
+ "X-GNOME-Autostart-enabled": "true"
+ }
+
+ de = xdg_de(filename=fname)
+ for key, value in content.items():
+ de.set(key, value)
+ de.validate()
+ de.write()
+
+# =============================================================================
+# actions
+# =============================================================================
+
+def list_items(path=None):
+ """List EncFS items in keyring."""
+
+ items = _get_items(anypath=path)
+
+ if not items and path:
+ print(MSG_NO_MATCH)
+ return False
+
+ for item in items:
+ epath = item.attributes["encfs-path"]
+ mpoint = item.attributes["mount-point"]
+ amount = item.attributes["auto-mount"]
+ print("* encfs path : %s" % epath)
+ print(" mount point : %s" % mpoint)
+ print(" mount at login : %s" % (amount == "y" and "yes" or "no"))
+
+ return True
+
+def add_item(epath, mpoint):
+ """Add new EncFS item to keyring."""
+
+ if not _is_encfs(epath):
+ _proceed("no EncFS at given path")
+ if not os.path.isdir(mpoint):
+ _proceed("mount point is not a directory")
+ if _get_items(mpoint=mpoint):
+ _proceed("mount point already in keyring")
+
+ secret = preset.password or getpass.getpass("EncFS password: ")
+ amount = preset.amount or raw_input("Mount at login [Y/n]: ") or "y"
+ amount = amount.strip()[0].lower() == "y" and "y" or "n"
+ attr = {"encfs-path": epath, "mount-point": mpoint, "auto-mount": amount}
+ attr.update(GENCFS_ATTR)
+ name = "EncFS mount at %s" % mpoint
+ gk.item_create_sync(KEYRING, ITYPE, name, attr, secret, False)
+
+ global _items_cached
+ _items_cached = None
+
+ return True
+
+def edit_item(mpoint):
+ """Edit EncFS item in keyring."""
+
+ items = _get_items()
+ edits = _get_items(mpoint=mpoint)
+
+ if not edits:
+ print(MSG_NO_MATCH)
+ return False
+
+ for item in edits:
+
+ # get item data
+ epath = item.attributes["encfs-path"]
+ mpoint = item.attributes["mount-point"]
+ amount = item.attributes["auto-mount"]
+ epath = preset.epath or raw_input("EncFS path [%s]: " % epath) or epath
+ mpoint = preset.mpoint or raw_input("Mount point [%s]: " % mpoint) or mpoint
+ secret = preset.password or getpass.getpass("Password [**current**]: ") or item.secret
+ hint = amount == "y" and "Y/n" or "y/N"
+ amount = preset.amount or raw_input("Mount at login [%s]: " % hint) or amount
+ amount = amount.strip()[0].lower() == "y" and "y" or "n"
+ mpoint = _pathify(mpoint)
+ epath = _pathify(epath)
+
+ # check item data
+ for other in [i for i in items if i.item_id != item.item_id]:
+ if other.attributes["mount-point"] == mpoint:
+ _proceed("mount point already in use")
+ if not _is_encfs(epath):
+ _proceed("no EncFS at given path")
+ if not os.path.isdir(mpoint):
+ _proceed("mount point is not a directory")
+
+ # update item data
+ attributes = GENCFS_ATTR.copy()
+ attributes["encfs-path"] = epath
+ attributes["mount-point"] = mpoint
+ attributes["auto-mount"] = amount
+ gk.item_set_attributes_sync(KEYRING, item.item_id, attributes)
+ info = gk.item_get_info_sync(KEYRING, item.item_id)
+ info.set_secret(secret)
+ gk.item_set_info_sync(KEYRING, item.item_id, info)
+
+ global _items_cached
+ _items_cached = None
+
+ return True
+
+def remove_item(mpoint):
+ """Remove EncFS item from keyring."""
+
+ items = _get_items(mpoint=mpoint)
+
+ if not items:
+ print(MSG_NO_MATCH)
+ return False
+
+ for item in items:
+ gk.item_delete_sync(KEYRING, item.item_id)
+
+ global _items_cached
+ _items_cached = None
+
+ return True
+
+def mount_items(path, autostart):
+ """Mount selected items.
+
+ If `path` is set, mount only those items where the EncFS path or mount
+ point equals `path`. If `autostart` is True, mount only those items where
+ auto-mount is set to 'y'.
+
+ """
+ items = _get_items(anypath=path, amount=(autostart and "y" or None))
+
+ if not items and path:
+ print(MSG_NO_MATCH)
+ return False
+
+ rc = True
+
+ for item in items:
+ epath = item.attributes["encfs-path"]
+ mpoint = item.attributes["mount-point"]
+ msg = "Mounting %s at %s: " % (epath, mpoint)
+ if _is_mounted(mpoint):
+ msg += "mount point already in use"
+ elif not os.path.isdir(mpoint):
+ msg += "mount point does not exist or is not a directory"
+ rc = False
+ else:
+ cmd = ["encfs", "-o", "nonempty", "-S", epath, mpoint]
+ p = subprocess.Popen(cmd, stdin=subprocess.PIPE)
+ p.communicate(input="%s\n" % item.secret)
+ msg += p.returncode and "FAILED" or "OK"
+ rc &= not p.returncode
+
+ print(msg)
+
+ return rc
+
+# =============================================================================
+# main
+# =============================================================================
+
+def main():
+
+ opts = _options()
+
+ if opts.add:
+ ok = add_item(opts.p1, opts.p2)
+ elif opts.list:
+ ok = list_items(opts.p1)
+ elif opts.mount:
+ ok = mount_items(opts.p1, opts.autostart)
+ elif opts.edit:
+ ok = edit_item(opts.p1)
+ elif opts.remove:
+ ok = remove_item(opts.p1)
+ else:
+ assert False
+
+ return ok
+
+if __name__ == '__main__':
+
+ ret = main()
+ _exit(int(not ret))
diff --git a/tools/install-defaults b/tools/install-defaults
new file mode 100755
index 0000000..f7b75d0
--- /dev/null
+++ b/tools/install-defaults
@@ -0,0 +1,24 @@
+#!/bin/zsh
+
+for DF in ~/.resources/default-dotfiles/*[^~]; do
+ SDF=$(echo $(basename $DF) | sed -e's@__@/@g')
+ DOTNAME=~/.${SDF}
+ DIROF=$(dirname $DOTNAME)
+ mkdir -p $DIROF
+ if [ ! -e $DOTNAME ]; then
+ echo Installing $DOTNAME
+ cp $DF $DOTNAME
+ else
+ cmp -s $DF $DOTNAME
+ if [ "$?" != "0" ]; then
+ echo "$DOTNAME has changed:"
+ diff -u $DOTNAME $DF
+ echo "Apply changes [Y/n]?"
+ read FOO
+ if [ "x$FOO" = "xy" -o "x$FOO" = "x" ]; then
+ cp $DF $DOTNAME
+ fi
+ fi
+ fi
+done
+