diff --git a/README.md b/README.md index f534cf6..84c8c64 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,12 @@ -# focusfriend +# FocusFriend + +FocusFriend is an app that empowers users to utilize their computers mindfully. + + +## Unkillable Process + +Our monitoring process has to be unkillable. + +I have found [this](https://skallwar.fr/posts/unkillable_process/) solution that +uses Kernel hooks, but I think the approach via sudo is cleaner. -FocusFriend is an app that empowers users to utilize their computers mindfully. \ No newline at end of file diff --git a/blocker.py b/blocker.py new file mode 100644 index 0000000..9d84edb --- /dev/null +++ b/blocker.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python3 + +import os +import psutil +import re +import subprocess +import sys +import time + + +XDOTOOL_CMD = ["xdotool", "getactivewindow", "getwindowname", "getwindowpid"] + + +BLOCKED_BROWSER_WORDS = [] + +def is_window_blocked(window_name, blocked): + for b in blocked: + if type(b) is str and b == window_name: + return True + elif type(b) is re.Pattern and b.findall(window_name): + return True + return False + + +def main(): + blocked = [re.compile(f"{word}.*(Firefox|Chromium)", flags=re.IGNORECASE) + for word in BLOCKED_BROWSER_WORDS] + while True: + time.sleep(1) + p = subprocess.run(XDOTOOL_CMD, capture_output=True) + if p.returncode != 0: + continue + window_name, window_pid, _ = p.stdout.decode().split("\n") + if is_window_blocked(window_name, blocked): + p = psutil.Process(int(window_pid)) + p.kill() + print(f"Kill {window_name}") + + +if __name__ == "__main__": + if os.geteuid() == 0: + newpid = os.fork() + if newpid == 0: + main() + else: + cmd = ["sudo"] + sys.argv + subprocess.Popen(cmd, start_new_session=True) + diff --git a/focus.py b/focus.py new file mode 100644 index 0000000..0bcd3df --- /dev/null +++ b/focus.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python3 + +import os +import psutil +import re +import subprocess +import sys +import time + + +XDOTOOL_CMD = ["xdotool", "getactivewindow", "getwindowname", "getwindowpid"] + + +SESSIONS = { + "sicp": [ + "~", + "~/dev/sicp", + "mit-scheme", + "Mozilla Firefox", + "[No Name] - VIM", + re.compile("sicp-ex-"), + re.compile("\.scm"), + re.compile("Structure and Interpretation of Computer Programs"), + re.compile("SICP-Solutions"), + ] +} + + +def is_window_allowed(window_name, allowed): + for a in allowed: + if type(a) is str and a == window_name: + return True + elif type(a) is re.Pattern and a.findall(window_name): + return True + return False + + +def main(session_name): + allowed_window_names = SESSIONS[session_name] + start_time = time.time() + + while time.time() - start_time < 60 * 60: + time.sleep(5) + p = subprocess.run(XDOTOOL_CMD, capture_output=True) + if p.returncode != 0: + continue + window_name, window_pid, _ = p.stdout.decode().split("\n") + if not is_window_allowed(window_name, allowed_window_names): + p = psutil.Process(int(window_pid)) + p.kill() + + +if __name__ == "__main__": + try: + session_name = sys.argv[1] + except IndexError: + print("Provide a session name as the first argument.") + sys.exit(1) + if not session_name in SESSIONS: + print(f"Session with name {session_name} does not exist.") + sys.exit(1) + + if os.geteuid() == 0: + newpid = os.fork() + if newpid == 0: + main(session_name) + else: + cmd = ["sudo"] + sys.argv + subprocess.Popen(cmd, start_new_session=True) + diff --git a/hash.py b/hash.py new file mode 100755 index 0000000..7978b1b --- /dev/null +++ b/hash.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python3 + +import hashlib +import sys +import time +import getpass + + +def get_input(): + total_count = 0 + while not total_count: + try: + total_count = int(float(input("Enter count: "))) + except ValueError: + print("Enter a positive integer.") + + seed, seed_check = "a", "b" + while seed != seed_check: + seed = getpass.getpass() + seed_check = getpass.getpass(prompt="Confirm password: ") + if seed != seed_check: + print("Passwords must match.") + return total_count, seed + + +def print_progress(total_count, passed_time, current_count): + projected_time = total_count * passed_time / current_count + progress_time = "[{:.2f} / {:.2f}s".format(passed_time, projected_time) + progress_percent = current_count / total_count * 100 + progress_percent = "- {:.2f}%]".format(progress_percent) + print(progress_time, progress_percent, " ", end='\r') + + +if __name__ == "__main__": + total_count, seed = get_input() + + start_time = time.time() + current_time = start_time + m = hashlib.sha256() + m.update(seed.encode()) + + for current_count in range(total_count): + if time.time() - current_time > 1: + current_time = time.time() + passed_time = current_time - start_time + print_progress(total_count, passed_time, current_count) + m.update(m.digest()) + + print("{} hashes done. Final result:".format(total_count)) + print(m.hexdigest()) +