SkoolOS/bgservice/bgservice.py
2020-06-16 23:47:28 -04:00

290 lines
7.7 KiB
Python

"""
A simple background service to log events in a directory,
check for git commands in bash/zsh history,
and check for non-whitelisted files in the watched directory.
"""
import time
import sys
import os
import pyinotify
from pathlib import Path
from glob import glob
NOTIFIER = None
STDOUT = sys.stdout
DIR = None
START_TIME = None
def watch_dir(watched_dir=str(Path.home()), log_dir="SkoolOS/logs"):
"""
Watches the specified directory for changes and outputs it in
human readable format to a log file in the specified log directory.
param watched_dir: directory to watch for changes
param log_dir: directory to store log files
return: none
"""
global DIR
global START_TIME
global NOTIFIER
DIR = watched_dir
if not os.path.exists(log_dir):
os.makedirs(log_dir)
logfile_ = log_dir + "/skooloslog"
if os.path.isfile(logfile_):
os.remove(logfile_)
logfile = open(logfile_, 'w')
START_TIME = time.time()
wm = pyinotify.WatchManager()
mask = pyinotify.IN_CREATE | pyinotify.IN_CLOSE_WRITE | pyinotify.IN_DELETE | \
pyinotify.IN_MOVED_TO | pyinotify.IN_MOVED_FROM | pyinotify.IN_OPEN
NOTIFIER = pyinotify.ThreadedNotifier(wm, EventHandler())
NOTIFIER.start()
sys.stdout = open("/dev/null", 'w')
wm.add_watch(watched_dir, mask, rec=True)
time.sleep(1)
sys.stdout = logfile
print("Start time: " +
time.strftime("%A, %B %d, %Y %H:%M:%S", time.localtime()) + "\n")
def stop_watching():
"""
Stops the watch started by watch_dir()
return: none
"""
NOTIFIER.stop()
now = time.time()
print("End time: " +
time.strftime("%A, %B %d, %Y %H:%M:%S", time.localtime()))
print("\nTotal work time: " +
time.strftime("%H:%M:%S", time.gmtime(now - START_TIME)))
print("\n" + shell_check())
suspicious_files = file_check(DIR)
if suspicious_files != []:
print(
"\n\n--------------------------------------------------\n\n\n" +
"WARNING: One or more file did not have file extensions that are acceptable.\n"
+ "The paths to these files are listed below:\n")
print(*suspicious_files, sep='\n')
sys.stdout = STDOUT
file_whitelist = [
# text and document files
".doc",
".docx",
".odt",
".pdf",
".rtf",
".tex",
".txt",
".wpd",
# video files
".3g2",
".3gp",
".avi",
".flv",
".h264",
".m4v",
".mkv",
".mov",
".mp4",
".mpg",
".mpeg",
".rm",
".swf",
".vob",
".wmv",
# spreadsheet files
".ods",
".xls",
".xlsm",
".xlsx",
".csv",
# programming files
".c",
".class",
".cpp",
".cs",
".go",
".h",
".java",
".pl",
".sh",
".swift",
".vb",
# presentation files
".key",
".odp",
".pps",
".ppt",
".pptx",
# image files
".ai",
".bmp",
".gif",
".ico",
".jpeg",
".jpg",
".png",
".ps",
".psd",
".svg",
".tif",
".tiff",
]
def shell_check():
"""
Check .bash_history and .histfile for git commands that could interfere with SkoolOS
return: results of the check
"""
bash_history = [
line.strip()
for line in open(os.path.expanduser("~/.bash_history"), 'r')
]
zsh_history = [
line.strip() for line in open(os.path.expanduser("~/.histfile"), 'r')
]
suspicious_commands = []
for i in bash_history + zsh_history:
if "git" in i:
suspicious_commands.append(i)
if suspicious_commands:
return str(
len(suspicious_commands)
) + " suspicious commands found:\n" + "\n".join(suspicious_commands)
return "Nothing suspicious found in bash or zsh history."
def verify_file(file_):
"""
Check if the file name has an extension in the list of whitelisted file exentsions
param file_: path to file
return: whether or not the file's extension is whitelisted
"""
for ext in file_whitelist:
if len(file_) > len(ext):
if file_[len(file_) - len(ext):] == ext:
return True
return False
def file_check(dir_):
"""
Checks specified dir_ for non-whitelisted files using verify_file()
param dir_: directory to check
return: list of suspicious files
"""
files = glob(dir_ + "/**/*", recursive=True)
suspicious_files = []
for file_ in files:
if not verify_file(file_):
suspicious_files.append(file_)
return suspicious_files
class EventHandler(pyinotify.ProcessEvent):
"""
Custom event handler for watching a SkoolOS work directory
"""
_methods = [
"IN_CREATE",
"IN_CLOSE_WRITE",
"IN_DELETE",
"IN_MOVED_TO",
"IN_MOVED_FROM",
"IN_OPEN",
]
def process_IN_CREATE(self, event):
"""
Generates an output to record for IN_CREATE events
param event: event automatically passed to function
return: none
"""
description = \
"Event: Created file\n" \
"Event Path: {}\n" \
"Timestamp: {}\n".format(
event.pathname,
time.strftime("%A, %B %d, %Y %H:%M:%S", time.localtime())
)
print(description)
def process_IN_CLOSE_WRITE(self, event):
"""
Generates an output to record for IN_CLOSE_WRITE events
param event: event automatically passed to function
return: none
"""
description = \
"Event: Wrote to a file\n" \
"Event Path: {}\n" \
"Timestamp: {}\n".format(
event.pathname,
time.strftime("%A, %B %d, %Y %H:%M:%S", time.localtime())
)
print(description)
def process_IN_DELETE(self, event):
"""
Generates an output to record for IN_DELETE events
param event: event automatically passed to function
return: none
"""
description = \
"Event: Deleted file\n" \
"Event Path: {}\n" \
"Timestamp: {}\n".format(
event.pathname,
time.strftime("%A, %B %d, %Y %H:%M:%S", time.localtime())
)
print(description)
def process_IN_MOVED_TO(self, event):
"""
Generates an output to record for IN_MOVED_TO events
param event: event automatically passed to function
return: none
"""
description = \
"Event: Moved a file in\n" \
"Event Path: {}\n" \
"Timestamp: {}\n".format(
event.pathname,
time.strftime("%A, %B %d, %Y %H:%M:%S", time.localtime())
)
print(description)
def process_IN_MOVED_FROM(self, event):
"""
Generates an output to record for IN_MOVED_FROM events
param event: event automatically passed to function
return: none
"""
description = \
"Event: Moved a file out\n" \
"Event Path: {}\n" \
"Timestamp: {}\n".format(
event.pathname,
time.strftime("%A, %B %d, %Y %H:%M:%S", time.localtime())
)
print(description)
def process_IN_OPEN(self, event):
"""
Generates an output to record for IN_OPEN events
param event: event automatically passed to function
return: none
"""
description = \
"Event: Opened file\n" \
"Event Path: {}\n" \
"Timestamp: {}\n".format(
event.pathname,
time.strftime("%A, %B %d, %Y %H:%M:%S", time.localtime())
)
print(description)