Skip to content

fix(tracker): AV-safe keyboard/mouse activity detection#254

Merged
parth0025 merged 4 commits into
stagingfrom
fix/tracker-activity-powermonitor
Jun 18, 2026
Merged

fix(tracker): AV-safe keyboard/mouse activity detection#254
parth0025 merged 4 commits into
stagingfrom
fix/tracker-activity-powermonitor

Conversation

@parth0025

Copy link
Copy Markdown
Collaborator

Tracker: AV-safe keyboard/mouse activity detection

Problem

The desktop time tracker used node-global-key-listener, which ships a native global-hook binary (WinKeyServer.exe). Antivirus (Bitdefender) flags that signature as a keylogger and quarantines it, silently stopping all keyboard/mouse activity — every timesheet showed "Active 0 of N min". This hits any customer running AV, since AlianHub is self-hosted/distributed.

Fix

Replace the global hook with two hook-free, built-in OS signals, sampled once per second while tracking:

  • powerMonitor.getSystemIdleTime() — seconds since last input (keyboard or mouse)
  • screen.getCursorScreenPoint() — current cursor position

Classification: cursor moved this second → mouse activity; input with no cursor movement (typing) → keyboard activity. No native binary, no accessibility permission, AV-proof, cross-platform.

Web frontend unchanged

Strokes stay in the existing { keyboard, mouse } shape, so helper.js and the timesheet display are untouched — production renders the new data correctly with no web deploy. Net diff is desktop-only.

Scope

  • time-tracker-app/main/background.js — cursor-movement + idle sampler
  • time-tracker-app/renderer/store/timelog.jssetActivityTick buckets { keyboard, mouse } per minute
  • time-tracker-app/renderer/pages/trackerRunning.jsx, controller/tracker/tracker.js — wire activity ticks + strokes
  • time-tracker-app/package.json + lockfile — drop node-global-key-listener; bump to 5.0.1
  • No web-frontend changes (net)

Verified

End-to-end local run against production data: both Keyboard and Mouse columns populate with realistic per-minute values; "Active X of Y min" and the activity bar work; AV does not quarantine the build.

Caveats

  • Mouse activity is movement-based — a click that doesn't move the cursor counts as keyboard (exact click counts would require the AV-flagged global hook).
  • The distributable .exe is unsigned (SmartScreen "unknown publisher"); code-signing is a separate follow-up.

🤖 Generated with Claude Code

parth0025 and others added 4 commits June 17, 2026 19:49
…ivity

node-global-key-listener ships a native hook binary (WinKeyServer.exe) that antivirus (Bitdefender) flags as a keylogger and quarantines, silently zeroing all keyboard/mouse activity counts. Replace it with Electron's built-in powerMonitor.getSystemIdleTime(): while tracking, sample once per second and emit an activity tick per active second. No native binary, no accessibility permission, AV-proof, cross-platform.

Desktop: background.js runs a 1 Hz idle sampler emitting 'activity:tick'; timelog.js setActivityTick buckets ticks per minute as { active: N }; trackerRunning.jsx and tracker.js consume it and strokes carry { active }; package.json drops the dependency. Frontend helper.js surfaces the active value in the existing Keyboard column (Mouse stays 0); old timesheets keep their original keyboard/mouse counts. Backend and DB schema unchanged - strokes are stored opaquely in trackShots.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Refines the powerMonitor approach so the timesheet shows real Keyboard AND Mouse activity instead of one combined value. Each second while tracking, the sampler reads two hook-free signals - powerMonitor.getSystemIdleTime() and screen.getCursorScreenPoint(): cursor moved => mouse activity; input with no cursor movement (typing) => keyboard activity. Still no global input hook, so antivirus does not flag it. A click that does not move the cursor counts as keyboard (acceptable trade-off vs the AV-flagged hook).

Strokes return to the { keyboard, mouse } shape, so the web frontend needs no change: helper.js reverts to its original (reads keyboard/mouse) and the production website displays the data correctly with no deploy.

background.js: cursor-movement + idle sampler emits activity:tick with a type; timelog.js setActivityTick buckets per minute as { keyboard, mouse }; trackerRunning.jsx and tracker.js pass the type and build keyboard/mouse strokes; helper.js reverted to original.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 13e58a19-0f32-4c09-99b9-037889ad587b

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/tracker-activity-powermonitor

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@parth0025 parth0025 merged commit 5b11989 into staging Jun 18, 2026
3 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant