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

Tomb close automatically with a timer #293

Open
vonpupp opened this issue Dec 30, 2017 · 8 comments
Open

Tomb close automatically with a timer #293

vonpupp opened this issue Dec 30, 2017 · 8 comments
Labels
discussion wish feature we wish someone would refine and implement

Comments

@vonpupp
Copy link

vonpupp commented Dec 30, 2017

Hi,

Thank you for Tomb, it is just amazing!

I wonder if there is a feature already available to automatically close a tomb after X minutes. I have seen that feature in the pass-tomb plugin, but apparently it is not something within Tomb, but the plugin itself.

In pass-tomb is something like this:

pass tomb <gpg-id> --timer=10min

And after 10min the tomb automagically closes, which is very convenient IMHO for security.

Is there any way to achieve this with pure Tomb?

Thank you very much.

@Narrat
Copy link
Collaborator

Narrat commented Dec 31, 2017

Currently not.
And looking at the timer solution in pass-tomb, I doubt it would be implemented like that as it uses a systemd timer. Maybe as an extra tool.
An alternative would be a classic cron-job (and working with the issue, that this specific crontab entry needs to be dropped).
Additionally, if only tombs should be closed if x min/h/whatever have gone without user interaction (plus using Xorg) then something could be done with xautolock (only working if tomb script can be used without entering a sudo password)

@roddhjav
Copy link
Contributor

roddhjav commented Dec 31, 2017

Tomb currently does not support timer. I don't know if @jaromil likes this idea, but it could be easy to add it in tomb using a cron-job.

@Narrat For the record, I plan to rewrite the timer part in pass-tomb because indeed it is crappy.

@Narrat
Copy link
Collaborator

Narrat commented Dec 31, 2017

@roddhjav: Whatever gets the job done. :) I don't have a problem with systemd based solutions. The issue is more like, it requires distributions which use systemd. The rest is left behind.
On the other hand relying on cron is of a similar problem. Distributions with systemd don't necessarily offer a cron implementation installed per default (although this case is easier to solve: installing one). And personally I uninstalled cronie after timer became available.

So whatever is chosen it should be optional (100% sure it would happen like that anyway), and if it is implemented, should it be in the script itself or put into extras/.

@jaromil
Copy link
Member

jaromil commented Jan 2, 2018

Hello. This would be a nice usability feature indeed.

I see problems with both systemd and cron solutions, mostly related to minimalist design and to what cron is really meant for. FTR in UNIX systems the standard tool to schedule a single event in the future is ATD(8) which may come handy.

In my standard practice when in need to schedule a future event I do not use ATD myself, but use this little python script that runs alarms and other things while showing me a countdown (but can also be launched in background). In my own setup this script is called ding and accepts a human-friendly syntax like ding in 4m to count 4 minutes and then start an alarm.

#!/usr/bin/env python
"""Simple CLI beep tool"""

from __future__ import unicode_literals
from __future__ import print_function

import os
import sys
import time
import datetime


EXIT_MSG = """Invalid arguments: {}\n---------
$ ding at hh[:mm[:ss]]
$ ding in \d+[smh]( +\d+[smh])*

Examples:
    $ ding at 15:30
    $ ding in 5m 30s
"""

VERSION = '1.2.0'
N_BEEPS = 4
WAIT_BEEPS = 0.15


class InvalidArguments(Exception):
    pass


def check_input(args):
    """Validate user input"""
    if len(args) < 2 or args[0] not in ['in', 'at']:
        raise InvalidArguments('insufficient number of arguments')

    if args[0] == 'in':
        if not all(arg.endswith(('s', 'm', 'h')) for arg in args[1:]):
            raise InvalidArguments('please use s/m/h suffixes')
        if not all(arg[:-1].isdigit() for arg in args[1:]):
            raise InvalidArguments('please use numbers for specifying the duration of time units')

    if args[0] == 'at':
        if len(args) > 2:
            raise InvalidArguments('too many arguments')
        if not all([arg.isdigit() for arg in args[1].split(':')]):
            raise InvalidArguments('there should only be numbers optionally separated by ":"')
        # Valid time
        try:
            datetime.time(*map(int, args[1].split(':')))
        except ValueError as e:
            raise InvalidArguments(e)

    return args

class TimeParser():
    """Class helping with parsing user provided time into seconds"""
    time_map = {
        's': 1,
        'm': 60,
        'h': 60 * 60,
    }

    def __init__(self, time, relative):
        self.time = time
        self.relative = relative

    def get_seconds(self):
        return self._get_seconds_relative() if self.relative else self._get_seconds_absolute()

    def _get_seconds_relative(self):
        return sum([self.time_map[t[-1]] * int(t[:-1]) for t in self.time])

    def _get_seconds_absolute(self):
        now = datetime.datetime.now()
        user_time = (datetime.datetime.combine(datetime.date.today(),
                                               datetime.time(*map(int, self.time[0].split(':')))))
        return ((user_time - now).seconds if user_time > now
                else (user_time + datetime.timedelta(days=1) - now).seconds)


def print_time(seconds):
    """Print countdown for `seconds`"""
    while seconds > 0:
        start = time.time()
        os.system('cls' if os.name == 'nt' else 'clear') # accommodate Windows
        print(datetime.timedelta(seconds=seconds))
        seconds -= 1
        time.sleep(1 - time.time() + start)


def beep(seconds):
    """Make the beep noise"""
    for _ in range(N_BEEPS):
        # sys.stdout.write('\a')
	os.system('beep')
        sys.stdout.flush()
        time.sleep(WAIT_BEEPS)


def parse_time(args):
    """Figure out the number of seconds to wait"""
    relative = True if args[0] == 'in' else False
    user_time = args[1:]
    parser = TimeParser(user_time, relative)
    return parser.get_seconds()


def main(args=sys.argv[1:]):
    if args and args[0] == '--version':
        print(VERSION)
        sys.exit()
    try:
        seconds = parse_time(check_input(args))
    except InvalidArguments as e:
        sys.exit(EXIT_MSG.format(e))
    print_time(seconds)
    beep(seconds)

if __name__ == '__main__':
    main()

@jaromil
Copy link
Member

jaromil commented Jan 2, 2018

Also see in cryptsetup 2.0:

* Deferral removal

  Cryptsetup now can mark device for deferred removal by using a new option
  --deferred. This means that close command will not fail if the device is still
  in use, but will instruct the kernel to remove the device automatically after
  use count drops to zero (for example, once the filesystem is unmounted).

from: https://www.kernel.org/pub/linux/utils/cryptsetup/v2.0/v2.0.0-rc0-ReleaseNotes

@roddhjav
Copy link
Contributor

roddhjav commented Jan 2, 2018

Well, it seems cryptsetup might be the best solution to add a timer to tomb. We don't need to support systemd or cron, but can we require cryptsetup 2.0 for the timer to work in tomb? What about the distribution that will not have cryptsetup before long?

@jaromil
Copy link
Member

jaromil commented Jan 2, 2018

I suspect this won't solve the issue. Cryptsetup close command is different from losetup -d which will fail anyway until the actual close is done, plus this is not a callback but a kernel-level flag inside dm-crypt. It can be part of the solution of this and another issue I still have with running processes preventing the local loopback device to detach.

@jaromil jaromil added discussion wish feature we wish someone would refine and implement labels Jan 3, 2018
@vonpupp
Copy link
Author

vonpupp commented Jan 17, 2018

I was travelling due to a family medical issue and got off for some days.

Thanks for your comments and the healthy discussion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
discussion wish feature we wish someone would refine and implement
Projects
None yet
Development

No branches or pull requests

4 participants