add my script to find processes using secure input
- ID
045f4ea- date
2022-12-02 22:55:47+00:00- author
Alex Chan <alex@alexwlchan.net>- parent
8f6c097- message
add my script to find processes using secure input- changed files
1 file, 95 additions
Changed files
find_processes_using_secure_input (0) → find_processes_using_secure_input (3069)
diff --git a/find_processes_using_secure_input b/find_processes_using_secure_input
new file mode 100755
index 0000000..f738fa6
--- /dev/null
+++ b/find_processes_using_secure_input
@@ -0,0 +1,95 @@
+#!/usr/bin/env python3
+"""
+If macOS detects that you're typing sensitive data (e.g. a password), it prevents
+other apps from reading keystrokes. This is normally a good thing, but it's mildly
+annoying if you use an app like TextExpander, and macOS doesn't notice that it's
+no longer using Secure Input. Then your keyboard shortcuts stop working!
+
+This script will print a list of processes that have Secure Input enabled, e.g.:
+
+ The following processes are using Secure Input:
+ 113 loginwindow
+ 302 Safari
+ 519 Firefox
+
+It relies on two interesting commands:
+
+ ioreg -a -l -w 0
+ prints the I/O Kit Registry in XML format, which includes information about
+ a process using Secure Input in the kCGSSessionSecureInputPID key
+
+ ps -c -o command= -p <pid>
+ prints the executable name associated with a process ID (pid), which is
+ used for the output
+
+See https://alexwlchan.net/2021/04/secure-input/
+
+"""
+
+import plistlib
+import subprocess
+
+
+def find_dicts_in_tree(d):
+ """
+ Traverses the values of d, returning everything that looks dict-like.
+
+ Ideally I'd have a better idea of the structure of the output of ioreg,
+ but I don't care to spend that much time on this problem.
+ """
+ if isinstance(d, dict):
+ yield d
+ for dict_value in d.values():
+ for dv in find_dicts_in_tree(dict_value):
+ yield dv
+ elif isinstance(d, list):
+ for list_item in d:
+ for lv in find_dicts_in_tree(list_item):
+ yield lv
+ else:
+ pass
+
+
+def executable_name(pid):
+ """
+ Returns the executable name associated with a given pid.
+ """
+ return subprocess.check_output([
+ "ps",
+ "-c", # Only show the executable name, not the full command line
+ "-o", "command=", # Only show the command column, no header
+ "-p", str(pid) # Only show the given process ID
+ ]).strip().encode("utf8")
+
+
+if __name__ == "__main__":
+ ioreg_output = subprocess.check_output([
+ "ioreg",
+ "-a", # Archive the output in XML
+ "-l", # Show properties for all displayed objects
+ "-w", "0" # Unlimited line width
+ ])
+
+ try:
+ plist = plistlib.loads(ioreg_output, fmt=plistlib.FMT_XML)
+ except AttributeError: # Python 2
+ plist = plistlib.readPlistFromString(ioreg_output)
+
+ process_ids = set()
+ for d in find_dicts_in_tree(plist):
+ if "kCGSSessionSecureInputPID" in d:
+ process_ids.add(d["kCGSSessionSecureInputPID"])
+
+ sorted_pids = [
+ str(pid)
+ for pid in sorted(int(p) for p in process_ids)
+ ]
+
+ print("The following processes are using Secure Input:")
+ if sorted_pids:
+ subprocess.check_call([
+ "ps",
+ "-c", # Only show the executable name, not the full command line
+ "-o", "pid=,command=", # Only show the PID/command column, no header
+ "-p", ",".join(sorted_pids) # Only get the selected processes
+ ])