Template tests / tests (pull_request) Failing after 33s
Phase 3 of the improvement plan (PR 10 of the sequence): honest Wayland behavior and a least-privilege alternative to the broad `input` group the audit flagged as a keylogging surface. Least-privilege input access: - packaging/linux/common/60-stepforge-input.rules grants the ACTIVE session read access to MOUSE devices only (ID_INPUT_MOUSE, excluding ID_INPUT_KEYBOARD) via a systemd uaccess ACL — session-scoped, device- scoped, and never keyboards. This replaces `usermod -aG input`, which grants every input device (keyboards included) to the user permanently. - scripts/linux/enable-click-capture.sh installs it opt-in: it prints the exact rule, requires confirmation, and documents the security tradeoff. It never runs the broad-group command. Honest trigger reporting: - New chooseCaptureTrigger() (app/platform/linux/diagnostics.js, re-exported from app/platform/index.js) maps a capability profile to the real trigger: per-click with a marker on X11+xinput; per-click WITHOUT coordinates or a marker on Wayland evdev (the platform exposes no pointer position); and an honest hotkey/interval fallback otherwise. It never promises per-click capture with coordinates on Wayland. - platform:capabilities now includes the active trigger for the machine and the user's fallback setting, for the diagnostics UI. Docs: - GETTING_STARTED_WITH_LINUX.md no longer instructs every Wayland user to join the `input` group; it presents that as a warning, documents the least- privilege script, corrects the capability table (per-click is opt-in, mice only; hotkey/interval is the default Wayland trigger), and points at Settings → Diagnostics. Tests: trigger decisions for X11/xinput, Wayland evdev (no coordinates/marker), Wayland fallback (interval/hotkey with an honest note), the platform facade wiring, Windows; the udev rule (mouse-only, excludes keyboards, uaccess); the opt-in enable script (confirms, installs the rule, never runs usermod -aG input as a command); and docs guards. 289 unit tests pass; startup smoke and click self-test unchanged (stream, markers 3/3, burst 8/8). Co-Authored-By: Claude Fable 5 <[email protected]>
82 lines
3.0 KiB
JavaScript
82 lines
3.0 KiB
JavaScript
'use strict';
|
|
|
|
/**
|
|
* The single factory that selects a platform implementation. The rest of the
|
|
* app depends on the interfaces in ./interfaces.js and asks this module for a
|
|
* concrete adapter — it never branches on `process.platform` itself.
|
|
*
|
|
* As Linux runtime capture is implemented, its ClickSource / ScreenFrameSource
|
|
* adapters are added here; today this provides the WindowContextProvider for
|
|
* every platform and the Linux capability diagnostics.
|
|
*/
|
|
|
|
const { assertWindowContextProvider } = require('./interfaces');
|
|
|
|
function detectPlatform(platform = process.platform) {
|
|
if (platform === 'win32') return 'windows';
|
|
if (platform === 'darwin') return 'darwin';
|
|
if (platform === 'linux') return 'linux';
|
|
return 'unsupported';
|
|
}
|
|
|
|
/**
|
|
* Build the WindowContextProvider for the current OS. `platform` is injectable
|
|
* so the selection logic is unit-testable off the target OS.
|
|
*/
|
|
function createWindowContextProvider({ platform = process.platform } = {}) {
|
|
const os = detectPlatform(platform);
|
|
let provider;
|
|
switch (os) {
|
|
case 'windows':
|
|
provider = require('./windows/window-context').createWindowsWindowContextProvider();
|
|
break;
|
|
case 'darwin':
|
|
provider = require('./darwin/window-context').createDarwinWindowContextProvider();
|
|
break;
|
|
case 'linux':
|
|
provider = require('./linux/window-context').createLinuxWindowContextProvider();
|
|
break;
|
|
default:
|
|
// Unsupported OS: a null-object provider so callers still work.
|
|
provider = { async collect() { return { appName: '', windowTitle: '' }; } };
|
|
}
|
|
return assertWindowContextProvider(provider);
|
|
}
|
|
|
|
/**
|
|
* Capability profile for the current OS (used by diagnostics UI). Only Linux
|
|
* has a rich profile today; other platforms report their OS and a capable
|
|
* baseline.
|
|
*/
|
|
function detectCapabilities({ platform = process.platform, env = process.env } = {}) {
|
|
const os = detectPlatform(platform);
|
|
if (os === 'linux') {
|
|
return require('./linux/diagnostics').detectLinuxCapabilities({ env });
|
|
}
|
|
return {
|
|
os,
|
|
sessionType: os,
|
|
isWayland: false,
|
|
clickCapture: os === 'windows' ? 'windows-hook' : os,
|
|
screenCapture: os,
|
|
messages: [],
|
|
};
|
|
}
|
|
|
|
/**
|
|
* The honest capture-trigger decision for the current capabilities. On Linux
|
|
* this defers to the diagnostics helper (which never promises per-click
|
|
* capture with coordinates on Wayland); other platforms have a fixed answer.
|
|
*/
|
|
function chooseCaptureTrigger(capabilities, userTriggerPreference = 'interval') {
|
|
if (capabilities && capabilities.os === 'linux') {
|
|
return require('./linux/diagnostics').chooseCaptureTrigger(capabilities, userTriggerPreference);
|
|
}
|
|
if (capabilities && capabilities.os === 'windows') {
|
|
return { trigger: 'click', clickSource: 'windows-hook', coordinates: true, marker: true, note: '' };
|
|
}
|
|
return { trigger: 'click', clickSource: capabilities ? capabilities.os : 'unavailable', coordinates: true, marker: true, note: '' };
|
|
}
|
|
|
|
module.exports = { detectPlatform, createWindowContextProvider, detectCapabilities, chooseCaptureTrigger };
|