Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use systemd to unmount gocryptfs folders on logout #12

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 13 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ gnome-gocryptfs
![](https://github.com/cjermain/gnome-gocryptfs/workflows/Run%20Tests/badge.svg)

*gnome-gocryptfs* integrates [gocryptfs][cfs] folders into the GNOME desktop by storing
their passwords in the [keyring][gkr] and optionally mounting them at login
using GNOME's autostart mechanism. This package is a fork of the [gnome-encfs][gef]
project.
their passwords in the [keyring][gkr] and optionally mounting them at login (and
unmouting them at logout
[on most distribution](#automatically-unmount-gocryptfs-folders-on-logout)). This package
is a fork of the [gnome-encfs][gef] project.

*gnome-gocryptfs* allows you to use strong passwords for gocryptfs folders while still
mounting them painlessly (i.e. no password prompt). This is an advantage over
Expand Down Expand Up @@ -97,9 +98,15 @@ Usage should be straight forward - otherwise [submit an issue][itr].

### Automatically unmount gocryptfs folders on logout

Unfortunately there's no equivalent to GNOME's autostart scripts which could be
used to automatically unmount your gocryptfs folders on logout (without shutting
down). However, there's a manual solution using a [GDM hook script][gdm]:
If your distribution uses systemd to handle user sessions, your gocryptfs folders
will be automatically mounted/unmounted at login/logout.

Otherwise, gocryptfs folders can still be automatically mount at login using GNOME's
autostart mechanism. Unfortunately there's no equivalent to GNOME's autostart scripts
which could be used to automatically unmount your gocryptfs folders on logout
(without shutting down).

However, there's a manual solution using a [GDM hook script][gdm]:
`/etc/gdm/PostSession/Default`. Open this file in an editor (requires *root*
privileges) and add these lines:

Expand Down Expand Up @@ -128,4 +135,3 @@ License
[gkr]: http://live.gnome.org/GnomeKeyring
[gpl]: http://www.gnu.org/licenses/gpl.html
[itr]: https://github.com/cjermain/gnome-gocryptfs/issues

96 changes: 93 additions & 3 deletions gnome-gocryptfs
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,10 @@ from gi.repository import Secret

__version__ = "0.3"

TEST = "GNOME_GOCRYPTFS_TEST" in os.environ

TEST_ENV_VARNAME = "GNOME_GOCRYPTFS_TEST"
TEST_SYSTEMD_TOKEN = "SYSTEMD"
TEST = TEST_ENV_VARNAME in os.environ
TEST_TYPE = os.environ[TEST_ENV_VARNAME] if TEST else ""

class LockedKeyring(Exception):
pass
Expand Down Expand Up @@ -181,6 +183,13 @@ MSG_NO_MATCH = ("No matching gocryptfs items in keyring.\n"
MSG_NO_GOCRYPTFS_PATH = ("No gocryptfs at given path (or the gocryptfs config file "
"location is invalid)")

MSG_NO_SYSTEMD_SESSION = (
"*WARNING* Systemd doesn't handle user sessions. Fallback to "
"GNOME's autostart mechanism.\n"
"Your gocryptfs folders will not be unmounted on logout. See gnome-gocryptfs "
"README for a workaround."
)

DESCRIPTION = """Painlessly mount and manage gocryptfs folders using GNOME's
keyring."""

Expand Down Expand Up @@ -258,7 +267,62 @@ def _is_gocryptfs(path, config):
p.communicate()
return p.returncode == 0

def _autostart(enable):
def _enable_systemd_unit(enable):
command = [
"systemctl",
"--user",
"enable" if enable else "disable",
"gnome-gocryptfs.service",
]
p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
p.communicate()
if p.returncode != 0:
print(
f"Failed to {'enable' if enable else 'disable'} gnome-gocryptfs service in systemd"
)

def _create_systemd_unit(enable):
"""Set up a systemd user unit to automount folders when user logins"""

if TEST:
fname = os.path.join(os.path.curdir, "autostart.service")
else:
fname = os.path.join(xdg_config_home, "systemd/user", "gnome-gocryptfs.service")

if not enable:
_enable_systemd_unit(enable)
if os.path.exists(fname):
os.remove(fname)
return

# Systemd user config directory may not exist...
os.makedirs(os.path.dirname(fname), exist_ok=True)

# '~/.local/bin' is not in the default PATH (in systemd user unit)
# So use the absolute path to this script.
# TODO: Remove this test patch
our_path = os.path.realpath(__file__) if not TEST else "gnome-gocryptfs"
content = (
"[Unit]\n"
"Description=Gnome gocryptfs automounter service\n"
"PartOf=graphical-session.target\n"
"\n"
"[Service]\n"
"Type=oneshot\n"
"RemainAfterExit=yes\n"
f"ExecStart={our_path} mount --auto\n"
f"ExecStop={our_path} unmount\n"
"\n"
"[Install]\n"
"WantedBy=graphical-session.target\n"
)

with open(fname, "w", encoding="utf-8") as f:
f.write(content)

_enable_systemd_unit(enable)

def _create_desktop_file(enable):
"""Set up XDG autostart file."""

if TEST:
Expand Down Expand Up @@ -286,6 +350,32 @@ def _autostart(enable):
entry.validate()
entry.write()

def _autostart(enable):
"""Ensure folders are automatically mount and properly unmounted."""

# Test if user sessions are handled by systemd
command = [
"systemctl",
"--user",
"is-enabled",
"--quiet",
"graphical-session.target",
]
p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
p.communicate()

# TODO: Remove this test patch
is_systemd_available = (p.returncode == 0) if not TEST else (TEST_TYPE == TEST_SYSTEMD_TOKEN)

if is_systemd_available:
_create_desktop_file(False)
_create_systemd_unit(enable)
else: # Fallback to GNOME's autostart mechanism
print(MSG_NO_SYSTEMD_SESSION)
_create_systemd_unit(False)
_create_desktop_file(enable)


# =============================================================================
# actions
# =============================================================================
Expand Down
31 changes: 28 additions & 3 deletions tests/test.exp
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,29 @@ autostart on
# EXPECT: autostart on
autostart on
# EXPECT: autostart content
[Unit]
Description=Gnome gocryptfs automounter service
PartOf=graphical-session.target

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=gnome-gocryptfs mount --auto
ExecStop=gnome-gocryptfs unmount

[Install]
WantedBy=graphical-session.target
# EXPECT: 1 succeeding edits
# EXPECT: autostart off
autostart off
# EXPECT: autostart using desktop method
*WARNING* Systemd doesn't handle user sessions. Fallback to GNOME's autostart mechanism.
Your gocryptfs folders will not be unmounted on logout. See gnome-gocryptfs README for a workaround.
# EXPECT: autostart systemd off
autostart systemd off
# EXPECT: autostart desktop on
autostart desktop on
# EXPECT: autostart desktop content

Comment=Mount gocryptfs folders configured in GNOME's keyring
[Desktop Entry]
Expand All @@ -219,9 +242,11 @@ Name=Mount gocryptfs
Type=Application
Version=1.0
X-GNOME-Autostart-enabled=true
# EXPECT: 1 succeeding edits
# EXPECT: autostart off
autostart off
# EXPECT: autostart using systemd method
# EXPECT: autostart systemd on
autostart systemd on
# EXPECT: autostart desktop off
autostart desktop off
# EXPECT: succeeding add (1) with custom config file location
# EXPECT: 1 listed item (1)
STASH : ./tenv/e1
Expand Down
32 changes: 26 additions & 6 deletions tests/test.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
export GNOME_GOCRYPTFS_TEST=""
TEST_SYSTEMD="SYSTEMD"
TEST_NO_SYSTEMD="NO_SYSTEMD"
export GNOME_GOCRYPTFS_TEST=$TEST_SYSTEMD

expect() {
echo "# EXPECT: $1"
Expand Down Expand Up @@ -119,18 +121,36 @@ $GGOCRYPTFS edit $TENV/m3b --config "-" --password p3 --path $TENV/e3 --mount $T
expect "3 items (1,2,3b)"
$GGOCRYPTFS list
expect "autostart on"
test -e autostart.desktop && echo "autostart on" || echo "autostart off"
test -e autostart.service && echo "autostart on" || echo "autostart off"
expect "2 succeeding edits"
$GGOCRYPTFS edit $TENV/m1 --config "-" --password p1 --path $TENV/e1 --mount $TENV/m1 --proceed n --auto-mount n
$GGOCRYPTFS edit $TENV/m2 --config "-" --password p2 --path $TENV/e2 --mount $TENV/m2 --proceed n --auto-mount n
expect "autostart on"
test -e autostart.desktop && echo "autostart on" || echo "autostart off"
test -e autostart.service && echo "autostart on" || echo "autostart off"
expect "autostart content"
cat autostart.desktop | sort -d # Ensure that the order does not matter
cat autostart.service
expect "1 succeeding edits"
$GGOCRYPTFS edit $TENV/m3b --config "-" --password p3 --path $TENV/e3 --mount $TENV/m3b --proceed n --auto-mount n
expect "autostart off"
test -e autostart.desktop && echo "autostart on" || echo "autostart off"
test -e autostart.service && echo "autostart on" || echo "autostart off"

# Test alternative autostart method
expect "autostart using desktop method"
export GNOME_GOCRYPTFS_TEST=$TEST_NO_SYSTEMD
$GGOCRYPTFS edit $TENV/m3b --config "-" --password p3 --path $TENV/e3 --mount $TENV/m3b --proceed n --auto-mount y
expect "autostart systemd off"
test -e autostart.service && echo "autostart systemd on" || echo "autostart systemd off"
expect "autostart desktop on"
test -e autostart.desktop && echo "autostart desktop on" || echo "autostart desktop off"
expect "autostart desktop content"
cat autostart.desktop | sort -d # Ensure that the order does not matter
expect "autostart using systemd method"
export GNOME_GOCRYPTFS_TEST=$TEST_SYSTEMD
$GGOCRYPTFS edit $TENV/m3b --config "-" --password p3 --path $TENV/e3 --mount $TENV/m3b --proceed n --auto-mount y
expect "autostart systemd on"
test -e autostart.service && echo "autostart systemd on" || echo "autostart systemd off"
expect "autostart desktop off"
test -e autostart.desktop && echo "autostart desktop on" || echo "autostart desktop off"

# clean up keyring

Expand Down Expand Up @@ -180,5 +200,5 @@ $GGOCRYPTFS list | grep "^MOUNT " | grep "/tenv/m[0-9]" | awk {'print $3'} | \
expect "no listed items"
$GGOCRYPTFS list
expect "autostart off"
test -e autostart.desktop && echo "autostart on" || echo "autostart off"
test -e autostart.service && echo "autostart on" || echo "autostart off"

Loading