Skip to content
bitfocusPublic

About

Bitfocus Listener is a small remote-control server that lets you simulate keyboard and mouse input, open files, run shell commands, and stream basic system metrics.

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

30 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Bitfocus Listener

Bitfocus Listener is a small remote-control server. It exposes a WebSocket endpoint that lets an authenticated client simulate keyboard input, move and click the mouse, open files, run shell commands, and stream basic system metrics. It is written in Go with a Fyne GUI for configuration, and runs in the system tray / menu bar.

It was built by Bitfocus AS to remote control machines from Bitfocus Buttons modules and other automation, and is released under the MIT License.

Warning

Listener grants remote control of the machine it runs on. With shellRun, osxAppleScript or fileOpen enabled, an authenticated client can execute arbitrary code or launch programs. All three are off on new installs. Traffic is unencrypted and authentication is MD5 challenge-response. Read SECURITY.md before exposing it to any network you do not fully control.


Installing

Download a build from the releases page, or build from source (see below).

On macOS, grant the app Accessibility permission (and Automation for System Events) in System Settings → Privacy & Security. Keyboard and mouse control will silently do nothing without it. The About tab has a button that opens the right pane.


Configuration

Everything is configured from the GUI and stored in ~/.bitfocus_listener.config (JSON, mode 0600).

  • Connection — bind interface, port (default 12001), and the password. The password is generated on first run; Generate New rotates it and disconnects every connected client.
  • Security → Allowed Remote Actions — enable or disable each command type individually.
  • Security → Key Access Control — Full Access (any key) or Restricted, where you allow specific key categories and individual keys.
  • Activity Log — a live view of the audit log, also written to ~/.bitfocus_listener.log (rotated at 5 MB). Every connection, auth attempt, executed command, and settings change is recorded with source IP.

Closing the settings window hides it; the server keeps running. Use the tray / menu bar icon to reopen it or to quit.


Protocol

Connect to ws://<host>:<port>/ws. All messages are JSON objects with a type field.

Authentication

The server sends a challenge immediately on connect:

{ "type": "authChallenge", "salt": "1a2b3c4d5e6f7a8b" }

Reply with the hex MD5 of the salt concatenated with the configured password:

{ "type": "auth", "password": "<MD5(salt + password)>" }

The server answers with {"type":"authResponse","status":"authenticated"} or {"type":"authResponse","status":"failed"}. Every command other than auth is ignored until authentication succeeds. Failed attempts are rate-limited per source IP (5 attempts, then a 5 minute lockout).

Commands

Type Fields Notes
keyPress key Single key tap
keyCombinationPress key, modifiers[] e.g. key: "t", modifiers: ["cmd"]
keyDown / keyUp key Hold and release
keyString msg Type a literal string
mousePositionSet x, y Coordinates as strings
mousePositionGet — Replies mousePositionGetResponse
mouseClick button, double button: left, right, center; double: "true"
shellRun shell Arbitrary shell command, 60 s timeout
fileOpen path Opens with the system handler
fileWrite root, path, msg, newline Creates a file or adds msg to the end of one inside an allowed folder; see below
fileWriteRootsGet — Replies fileWriteRootsGetResponse with the folder names; see below
osxKeyPressProcess processName, key, modifiers[] macOS: activate an app, then send the key
osxAppleScript msg macOS: arbitrary AppleScript
subscribe / unsubscribe name mousePosition (1 s) or sysInfo (5 s)

Every command type can be enabled or disabled individually in the GUI under Security → Allowed Remote Actions. On a new install shellRun, osxAppleScript, fileOpen and fileWrite start off; upgrading keeps whatever an existing config already allows. A disabled command returns {"type":"error","message":"Command <type> is disabled on the server"}. A command this Listener doesn't have returns …is not supported by this version of Listener instead (or …is only supported on macOS for osx* commands on other platforms).

Legacy aliases (subscribeSysInfo, unsubscribeMousePosition, …) are still accepted and normalized.

Writing to files

fileWrite is off by default, and it only writes inside folders added under Security → Allowed write file paths. Each folder gets a short name, and clients pick a folder by that name, never by path:

{ "type": "fileWrite", "root": "logs", "path": "2026/show.csv", "msg": "cue 12,14:03:11", "newline": "lf" }
  • root is a folder name. It can be left out when only one folder is set up.
  • path is relative to the folder. Missing subfolders are created. .. and absolute paths are rejected, and so are symlinks that lead outside the folder.
  • <>:"|?* in path are replaced with - on every platform, so $(internal:time_hms) makes the same file name on macOS and Windows. Windows device names (CON, NUL, COM1, …) are rejected.
  • Only .csv .edl .json .jsonl .log .md .ndjson .srt .tsv .txt .vtt .xml .yaml .yml files can be written. Text is appended as UTF-8 and existing content is never overwritten.
  • newline is lf (the default), crlf or none. Use none with an empty msg to just create the file.
  • Each write may be up to 64 KB, and a file stops growing at 50 MB.
  • Text is written exactly as sent. Spreadsheet formulas in .csv content are not escaped.

To fill a folder picker, send {"type":"fileWriteRootsGet"}. The reply lists folder names and allowed file types, never the real paths:

{ "type": "fileWriteRootsGetResponse", "roots": ["cues", "logs"], "extensions": [".csv", ".txt", "…"] }

When the folders change, or fileWrite is turned on, every authenticated client receives the same message as fileWriteRootsChanged. Both are only available while fileWrite is enabled.

Failures come back as {"type":"error","message":"fileWrite: …"}. For example, the folder name may be unknown, or on Windows another program such as Excel may have the file open.

Key names

Use these exact lowercase strings in key, modifiers, and the key-access configuration:

Category Names
Letters / digits a–z, 0–9
Navigation up, down, left, right, home, end, pageup, pagedown, tab, backspace, delete, insert
Function f1–f24 (f21–f24 on Windows/Linux only)
System esc / escape, enter / return, space, capslock, menu (Windows/Linux only), print, scroll, break
Numpad num0–num9, num., num+, num-, num*, num/, num_enter, num_equal, num_lock (Clear on macOS)
Modifiers ctrl / control, alt / option, shift, cmd / command / win / meta
Media volumeup, volumedown, mute, play, pause, next, previous (stop on Windows/Linux only)

Examples:

{ "type": "keyPress", "key": "volumeup" }
{ "type": "keyCombinationPress", "key": "t", "modifiers": ["cmd"] }
{ "type": "keyString", "msg": "Hello world" }

Subscription payloads

{ "type": "mousePositionUpdate", "x": 100, "y": 200 }
{ "type": "sysInfoUpdate", "cpu": 12.5, "maxCPU": 48.0, "mem": 8589934592, "maxMem": 17179869184, "processes": 412 }

Building from source

Requires Go (version pinned in go.mod) and a CGO toolchain — CGO_ENABLED=1 is mandatory, since Fyne and the platform helpers are CGO-based.

go mod download
./tools/dev.sh                 # regenerates version.go, then runs the app

Or, once version.go exists:

go run .

Packaged builds:

./tools/build.sh mac ARM64        # platform: mac|windows, arch: X64|ARM64
./tools/build.sh windows X64
./tools/make-mac-app.sh arm64     # macOS .app bundle + dmg

Signing is opt-in and driven entirely by the environment: make-mac-app.sh signs only when CSC_LINK is set and notarizes only when APPLE_ID, APPLE_TEAM_ID and APPLE_APP_SPECIFIC_PASSWORD are also set. Without them you get a perfectly usable unsigned build, which is what CI produces for forks and pull requests.

version.go is generated by the tooling and is gitignored — do not edit it by hand. version.json holds the version number, and production tags must match it.


Platform notes

  • macOS — keyboard input goes through System Events via osascript, and media keys are posted in-process as NX aux-control events via CoreGraphics. robotgo's CGO keyboard path is deliberately avoided: it crashes with SIGTRAP when called from WebSocket goroutines. The app uses LSUIElement and sets the accessory activation policy so it stays out of the Dock.
  • Windows — shell commands run through cmd.exe with the console window hidden; files open via rundll32 url.dll,FileProtocolHandler. Both architectures bundle a Mesa3D opengl32.dll so the settings window can open without a hardware OpenGL driver. The arm64 DLL is Mesa's llvmpipe software renderer: Fyne asks Windows on ARM for OpenGL ES, which the system does not provide.
  • Linux — the code paths exist (sh, xdg-open, robotgo), but builds are not currently produced or tested.

Contributing

See CONTRIBUTING.md. Security reports go to domains@bitfocus.io — see SECURITY.md.

License

MIT — see LICENSE. Third-party components and their licenses are listed in THIRD-PARTY-NOTICES.md.

About

Bitfocus Listener is a small remote-control server that lets you simulate keyboard and mouse input, open files, run shell commands, and stream basic system metrics.

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages