def main(dryrun=True): # TODO: Use wordlist instead of argument sensitive_words = ["sensitive"] aw = ActivityWatchClient(testing=True) re_word = r'\b{}\b' buckets = aw.get_buckets() for bid in buckets.keys(): if "window" not in bid: continue print("Checking bucket: {}".format(bid)) events = aw.get_events(bid, limit=-1) old_matches = set() for event in events: for key, val in event.data.items(): if isinstance(val, str): matches = [re.findall(re_word.format(word), val.lower()) for word in sensitive_words] matches = set(sum(matches, [])) if matches: event.data[key] = "REDACTED" if val not in old_matches: print(f"{'(DRYRUN) ' if dryrun else ''} Matches: {matches}, redacting: {val}") old_matches.add(val) if not dryrun: aw.insert_event(bid, event)
def shutdown(bucket_name,start_time,end_time,activity): client = ActivityWatchClient("aw-watcher-cli", testing=False) bucket_id = "{}_{}".format(bucket_name, client.hostname) event_type = "cli_activity" client.create_bucket(bucket_id, event_type=event_type) shutdown_data = {"label": activity} shutdown_event = Event(timestamp=start_time, data=shutdown_data, duration=(end_time -start_time)) inserted_event = client.insert_event(bucket_id, shutdown_event) rd = relativedelta.relativedelta (end_time, start_time) print("Spent {:02}:{:02}:{:02} doing {}:".format(rd.hours, rd.minutes, rd.seconds,activity))
class CLIWatcher: def __init__(self, bucket, etype, testing=False): self.client = ActivityWatchClient("aw-watcher-cli", testing=testing) self.bucketname = bucket self.etype = etype self.client.create_bucket(self.bucketname, event_type=self.etype) def run(self): logger.info( "aw-watcher-cli started for bucket '%s' containing events of type '%s'" % (self.bucketname, self.etype)) def updateLastEvent(self): logger.info("Updating previous event duration.") try: last = self.client.get_events(bucket_id=self.bucketname, limit=1)[0] except IndexError: logger.info("No previous event found.") return duration = abs((datetime.now(timezone.utc) - last.timestamp).seconds) logger.info( "Previous event '%s' occurred at %s. Duration since: %ss" % (last.data, last.timestamp.strftime("%Y-%m-%d %T%z"), duration)) last.duration = duration self.client.insert_event(self.bucketname, last) def addStringEvent(self, eventString, duration): logger.info("Adding event %s (duration: %s) to bucket %s" % (eventString, duration, self.bucketname)) data = {"label": eventString} event = Event(timestamp=datetime.now(timezone.utc), data=data, duration=duration) inserted_event = self.client.insert_event(self.bucketname, event) assert inserted_event.id is not None
def end_current_event(start_ts, category, item, end_dt=None): start_dt = datetime.utcfromtimestamp(start_ts) if end_dt is None: end_dt = datetime.utcnow() app.logger.debug('Instantiating client (127.0.0.1:5600)') client = ActivityWatchClient( "aw-watcher-manual-flaskweb", host='127.0.0.1:5600' ) bucket_id = "{}_{}".format("aw-watcher-manual-flaskweb", client.hostname) app.logger.debug('Creating bucket: %s', bucket_id) client.create_bucket(bucket_id, event_type="currentwindow") t = 'manual: %s/%s' % (category, item) evt = Event( timestamp=start_dt, duration=(end_dt - start_dt).total_seconds(), data={'app': t, 'title': t, 'category': category, 'item': item} ) inserted_event = client.insert_event(bucket_id, evt) app.logger.info('Inserted event: %s', inserted_event)
# Sleep a second until next heartbeat sleep(sleeptime) # Update timestamp for next heartbeat heartbeat_event.timestamp = datetime.now(timezone.utc) # Give the dispatcher thread some time to complete sending the last events. # If we don't do this the events might possibly queue up and be sent the # next time the client starts instead. sleep(1) # Synchronous example, insert an event event_data = {"label": "non-heartbeat event"} now = datetime.now(timezone.utc) event = Event(timestamp=now, data=event_data) inserted_event = client.insert_event(bucket_id, event) # The event returned from insert_event has been assigned an id by aw-server assert inserted_event.id is not None # Fetch last 10 events from bucket # Should be two events in order of newest to oldest # - "shutdown" event with a duration of 0 # - "heartbeat" event with a duration of 5*sleeptime events = client.get_events(bucket_id=bucket_id, limit=10) print(events) # Now lets clean up after us. # You probably don't want this in your watchers though! client.delete_bucket(bucket_id)
#!/usr/bin/env python3 from datetime import datetime, timezone from aw_core.models import Event from aw_client import ActivityWatchClient # We'll run with testing=True so we don't mess up any production instance. # Make sure you've started aw-server with the `--testing` flag as well. client = ActivityWatchClient("test-client", testing=True) bucket_id = "{}_{}".format("test-client-bucket", client.client_hostname) client.create_bucket(bucket_id, event_type="dummydata") shutdown_data = {"label": "some interesting data"} now = datetime.now(timezone.utc) shutdown_event = Event(timestamp=now, data=shutdown_data) inserted_event = client.insert_event(bucket_id, shutdown_event) events = client.get_events(bucket_id=bucket_id, limit=1) print(events) # Should print a single event in a list client.delete_bucket(bucket_id)
#!/usr/bin/env python3 from datetime import datetime, timezone from aw_core.models import Event from aw_client import ActivityWatchClient # We'll run with testing=True so we don't mess up any production instance. # Make sure you've started aw-server with the `--testing` flag as well. client = ActivityWatchClient("test-client", testing=True) bucket_id = "{}_{}".format("test-client-bucket", client.hostname) client.create_bucket(bucket_id, event_type="dummydata") shutdown_data = {"label": "some interesting data"} now = datetime.now(timezone.utc) shutdown_event = Event(timestamp=now, data=shutdown_data) inserted_event = client.insert_event(bucket_id, shutdown_event) events = client.get_events(bucket_id=bucket_id, limit=1) print(events) # Should print a single event in a list client.delete_bucket(bucket_id)
class MessageHandler: def __init__(self, testing=False, send_commands=True, send_heartbeats=True): # Create client self._client = ActivityWatchClient(client_id, testing=testing) self._client.connect() self._init_buckets() # Settings self.pulsetime = 10 self.send_commands = send_commands self.send_heartbeats = send_heartbeats # Initialize the EventQueue self._event_queue = EventQueue(callback=self._handle_event, time_buffer=(self.pulsetime / 2)) self._event_handlers = { 'preopen': self._preopen, 'preexec': self._preexec, 'precmd': self._precmd, 'preclose': self._preclose } self._terminal_sessions = {} def __enter__(self): return self def __exit__(self, exc_type, exc_val, exc_tb): self._client.disconnect() def _init_buckets(self): """Set self._buckets and create these buckets if not existing""" self._buckets = { 'commands': { 'id': "{}-commands_{}".format(client_id, self._client.hostname), 'event_type': 'app.terminal.command' }, 'activity': { 'id': "{}-activity_{}".format(client_id, self._client.hostname), 'event_type': 'app.terminal.activity' } } # Create buckets if not existing for key, bucket in self._buckets.items(): logger.debug("Creating bucket: {}".format(bucket['id'])) self._client.create_bucket(bucket['id'], bucket['event_type'], queued=True) def update_event_queue(self): self._event_queue.update() def handle_fifo_message(self, message): for line in message.split('\n'): if not len(line): continue cli_args = shlex.split(line) args, unknown_args = parser_base.parse_known_args(cli_args) # Make sure that events are called in the right order # (based on args.timestamp) by passing it to the event queue # The event queue will trigger the callback when the time_buffer # is exceeded logger.debug("adding event to event_queue: {}".format(cli_args)) self._event_queue.add_event(cli_args, args.timestamp) def _handle_event(self, cli_args): logger.debug("handling event: {}".format(cli_args)) args, unknown_args = parser_base.parse_known_args(cli_args) # Store terminal session if not already existing pid = args.pid if pid not in self._terminal_sessions: self._terminal_sessions[pid] = TerminalSessionData(pid) if self.send_commands: if args.event not in self._event_handlers: logger.error("Unknown event: {}".format(args.event)) else: self._event_handlers[args.event](cli_args) if self.send_heartbeats: self._heartbeat(cli_args) def _preopen(self, cli_args: list) -> None: """Handle terminal creation""" pass def _preexec(self, cli_args: list) -> None: """Send event containing command execution data""" args, unknown_args = parser_preexec.parse_known_args(cli_args) process = self._terminal_sessions[args.pid] event_data = { 'command': args.command, 'path': args.path, 'shell': args.shell, 'exit_code': 'unknown', 'session_id': process.unique_id } process.event = self._insert_event(data=event_data, timestamp=args.timestamp) def _precmd(self, cli_args: list) -> None: """Update the stored event with duration and exit_code""" args, unknown_args = parser_precmd.parse_known_args(cli_args) process = self._terminal_sessions[args.pid] if process.event is None: return event_data = process.event.data # Calculate time delta between preexec and precmd timestamp = process.event.timestamp cur_time = args.timestamp time_delta = cur_time - timestamp event_data['exit_code'] = args.exit_code self._insert_event(data=event_data, id=process.event.id, timestamp=timestamp, duration=time_delta) process.event = None def _preclose(self, args: argparse.Namespace, args_raw: list) -> None: """Remove pid and related data from terminal_processes_data""" args, unknown_args = parser_preclose.parse_known_args(cli_args) self._terminal_sessions.pop(args.pid) def _heartbeat(self, cli_args: list) -> None: """Send heartbeat to activity bucket""" args, unknown_args = parser_heartbeat.parse_known_args(cli_args) process = self._terminal_sessions[args.pid] event_data = { 'session_id': process.unique_id, 'shell': args.shell, 'path': args.path } event = Event(data=event_data, timestamp=args.timestamp) inserted_heartbeat = self._client.heartbeat( self._buckets['activity']['id'], event, pulsetime=self.pulsetime, queued=True) if inserted_heartbeat and inserted_heartbeat.id: logger.debug('Successfully sent heartbeat') def _insert_event(self, *args, **kwargs) -> Event: """Send event to the aw-server""" event = Event(*args, **kwargs) inserted_event = self._client.insert_event( self._buckets['commands']['id'], event) # aw-server assigned the event an id assert inserted_event.id is not None logger.debug("Successfully sent event") return inserted_event
client = ActivityWatchClient("aw-test-client", testing=True) client.connect() bucket_name = "test-bucket" bucket_etype = "test" # Delete bucket before creating it, and handle error if it doesn't already exist try: client.delete_bucket(bucket_name) except HTTPError as e: pass client.create_bucket(bucket_name, bucket_etype) e1 = create_unique_event() client.insert_event(bucket_name, e1) print("Getting events") events = client.get_events(bucket_name) print("Asserting events") assert events[0]['data']['label'] == e1['data']['label'] print("Getting eventcount") eventcount = client.get_eventcount(bucket_name) assert eventcount == 1 print("Getting bucket") buckets = client.get_buckets() print("Asserting bucket") assert bucket_name in buckets