forked from selfspy/selfspy
-
Notifications
You must be signed in to change notification settings - Fork 0
/
selfspy.py
executable file
·121 lines (91 loc) · 4.23 KB
/
selfspy.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#!/usr/bin/env python
import os
import sys
import time
import argparse
import ConfigParser
import daemon
import lockfile
import signal
import grp
import pwd
import hashlib
from Crypto.Cipher import Blowfish
from activity_store import ActivityStore
from password_dialog import get_password
import check_password
"""
Todo:
test keymap switch
---Later
code documentation, unittests, pychecker ;)
replay key and mouse for process and time interval (maybe store as macro)
word search
calculate personal keymap
"""
DATA_DIR = '~/.selfspy'
DBNAME = 'selfspy.sqlite'
LOCK_FILE = 'selfspy.pid'
def parse_config():
conf_parser = argparse.ArgumentParser(description=__doc__, add_help=False,
formatter_class=argparse.RawDescriptionHelpFormatter)
conf_parser.add_argument("-c", "--config",
help="Config file with defaults. Command line parameters will override those given in the config file. The config file must start with a \"[Defaults]\" section, followed by [argument]=[value] on each line.", metavar="FILE")
args, remaining_argv = conf_parser.parse_known_args()
defaults = {}
if args.config:
config = ConfigParser.SafeConfigParser()
config.read([args.config])
defaults = dict(config.items('Defaults'))
parser = argparse.ArgumentParser(description='Monitor your computer activities and store them in an encrypted database for later analysis or disaster recovery.', parents=[conf_parser])
parser.set_defaults(**defaults)
parser.add_argument('-p', '--password', help='Encryption password. If you want to keep your database unencrypted, specify -p "" here. If you don\'t specify a password in the command line arguments or in a config file, a dialog will pop up, asking for the password. The most secure is to not use either command line or config file but instead type it in on startup.')
parser.add_argument('-d', '--data-dir', help='Data directory for selfspy, where the database is stored. Remember that Selfspy must have read/write access. Default is %s' % DATA_DIR, default=DATA_DIR)
parser.add_argument('-n', '--no-text', action='store_true', help='Do not store what you type. This will make your database smaller and less sensitive to security breaches. Process name, window titles, window geometry, mouse clicks, number of keys pressed and key timings will still be stored, but not the actual letters. Key timings are stored to enable activity calculation in selfstats.py. If this switch is used, you will never be asked for password.')
return parser.parse_args()
def make_encrypter(password):
if password == "":
encrypter = None
else:
encrypter = Blowfish.new(hashlib.md5(password).digest())
return encrypter
if __name__ == '__main__':
args = vars(parse_config())
args['data_dir'] = os.path.expanduser(args['data_dir'])
def check_with_encrypter(password):
encrypter = make_encrypter(password)
return check_password.check(args['data_dir'], encrypter)
try:
os.makedirs(args['data_dir'])
except OSError:
pass
lockname = os.path.join(args['data_dir'], LOCK_FILE)
lock = lockfile.FileLock(lockname)
if lock.is_locked():
print '%s is locked! I am probably already running.' % lockname
print 'If you can find no selfspy process running, it is a stale lock and you can safely remove it.'
print 'Shutting down.'
sys.exit(1)
context = daemon.DaemonContext(
working_directory=args['data_dir'],
pidfile=lock,
stderr=sys.stderr
)
context.signal_map = {
signal.SIGTERM: 'terminate',
signal.SIGHUP: 'terminate'
}
if args['no_text']:
args['password'] = ""
if args['password'] is None:
args['password'] = get_password(verify=check_with_encrypter)
encrypter = make_encrypter(args['password'])
if not check_password.check(args['data_dir'], encrypter):
print 'Password failed'
sys.exit(1)
with context:
astore = ActivityStore(os.path.join(args['data_dir'], DBNAME), encrypter, store_text=(not args['no_text']))
try:
astore.run()
except SystemExit:
astore.close()