[Init] Initial commit - NetMesh terminal manager
Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled
Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled
This commit is contained in:
183
electron/bridges/appLockSystemAuthBridge.cjs
Normal file
183
electron/bridges/appLockSystemAuthBridge.cjs
Normal file
@@ -0,0 +1,183 @@
|
||||
const path = require("node:path");
|
||||
const { execFile: defaultExecFile } = require("node:child_process");
|
||||
|
||||
const SYSTEM_AUTH_STATUS_TIMEOUT_MS = 15000;
|
||||
const SYSTEM_AUTH_VERIFY_TIMEOUT_MS = 120000;
|
||||
const UNAVAILABLE_ERRORS = new Set([
|
||||
"DeviceNotPresent",
|
||||
"NotConfiguredForUser",
|
||||
"DisabledByPolicy",
|
||||
"DeviceBusy",
|
||||
"unavailable",
|
||||
]);
|
||||
const CANCELLED_ERRORS = new Set([
|
||||
"Canceled",
|
||||
"cancelled",
|
||||
"RetriesExhausted",
|
||||
]);
|
||||
|
||||
function unsupportedStatus() {
|
||||
return {
|
||||
supported: false,
|
||||
available: false,
|
||||
platform: "unsupported",
|
||||
label: null,
|
||||
reason: null,
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeSystemAuthStatus(input, platform = "unsupported") {
|
||||
if (!input || typeof input !== "object") return unsupportedStatus();
|
||||
const normalizedPlatform = platform === "darwin" || platform === "win32" ? platform : "unsupported";
|
||||
if (normalizedPlatform === "unsupported") return unsupportedStatus();
|
||||
return {
|
||||
supported: input.supported === true,
|
||||
available: input.available === true,
|
||||
platform: normalizedPlatform,
|
||||
label: normalizedPlatform === "darwin" ? "Touch ID" : "Windows Hello",
|
||||
reason: typeof input.reason === "string" && input.reason ? input.reason : null,
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeSystemAuthUnlockResult(input) {
|
||||
if (input && typeof input === "object" && input.ok === true) {
|
||||
return { ok: true };
|
||||
}
|
||||
const error = input && typeof input === "object" ? input.error : null;
|
||||
if (typeof error === "string") {
|
||||
if (CANCELLED_ERRORS.has(error)) return { ok: false, error: "cancelled" };
|
||||
if (UNAVAILABLE_ERRORS.has(error)) return { ok: false, error: "unavailable" };
|
||||
if (error === "unsupported") return { ok: false, error: "unsupported" };
|
||||
if (error === "failed") return { ok: false, error: "failed" };
|
||||
}
|
||||
return { ok: false, error: "failed" };
|
||||
}
|
||||
|
||||
function parseHelperJson(stdout) {
|
||||
try {
|
||||
return JSON.parse(String(stdout || "").trim());
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function nativeWindowHandleToDecimal(handle) {
|
||||
if (!Buffer.isBuffer(handle) || handle.length === 0) return null;
|
||||
let value = 0n;
|
||||
const byteCount = Math.min(handle.length, 8);
|
||||
for (let index = byteCount - 1; index >= 0; index -= 1) {
|
||||
value = (value << 8n) + BigInt(handle[index]);
|
||||
}
|
||||
return value > 0n ? value.toString(10) : null;
|
||||
}
|
||||
|
||||
function runHelper(execFile, helperPath, args, timeout) {
|
||||
return new Promise((resolve) => {
|
||||
if (!helperPath) {
|
||||
resolve({ ok: false, error: "unavailable" });
|
||||
return;
|
||||
}
|
||||
execFile(helperPath, args, {
|
||||
encoding: "utf8",
|
||||
timeout,
|
||||
windowsHide: true,
|
||||
maxBuffer: 1024 * 1024,
|
||||
}, (error, stdout) => {
|
||||
if (error) {
|
||||
resolve({ ok: false, error: "failed" });
|
||||
return;
|
||||
}
|
||||
resolve(parseHelperJson(stdout));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function resolveDefaultHelperPath({
|
||||
platform = process.platform,
|
||||
arch = process.arch,
|
||||
isPackaged = false,
|
||||
resourcesPath = process.resourcesPath,
|
||||
} = {}) {
|
||||
if (platform !== "win32") return null;
|
||||
if (isPackaged) {
|
||||
return path.win32.join(resourcesPath, "windowsHello", "NetcattyWindowsHello.exe");
|
||||
}
|
||||
return path.join(__dirname, "windowsHelloHelper", "build", arch, "NetcattyWindowsHello.exe");
|
||||
}
|
||||
|
||||
function createAppLockSystemAuthBridge({
|
||||
platform = process.platform,
|
||||
systemPreferences = null,
|
||||
execFile = defaultExecFile,
|
||||
helperPath = resolveDefaultHelperPath(),
|
||||
getNativeWindowHandle = () => null,
|
||||
} = {}) {
|
||||
async function getMacStatus() {
|
||||
const canPrompt = typeof systemPreferences?.canPromptTouchID === "function"
|
||||
? systemPreferences.canPromptTouchID()
|
||||
: false;
|
||||
return normalizeSystemAuthStatus({
|
||||
supported: true,
|
||||
available: canPrompt === true,
|
||||
reason: canPrompt === true ? null : "unavailable",
|
||||
}, "darwin");
|
||||
}
|
||||
|
||||
async function requestMacUnlock() {
|
||||
if (typeof systemPreferences?.promptTouchID !== "function") {
|
||||
return { ok: false, error: "unavailable" };
|
||||
}
|
||||
try {
|
||||
await systemPreferences.promptTouchID("Unlock Netcatty");
|
||||
return { ok: true };
|
||||
} catch (err) {
|
||||
// Electron exposes only a localized rejection message here. Since the
|
||||
// status check already established availability, a rejected prompt is a
|
||||
// user-visible cancellation regardless of system language.
|
||||
void err;
|
||||
return { ok: false, error: "cancelled" };
|
||||
}
|
||||
}
|
||||
|
||||
async function getWindowsStatus() {
|
||||
const result = await runHelper(execFile, helperPath, ["status"], SYSTEM_AUTH_STATUS_TIMEOUT_MS);
|
||||
return normalizeSystemAuthStatus({
|
||||
supported: true,
|
||||
available: result?.available === true,
|
||||
reason: typeof result?.reason === "string" ? result.reason : null,
|
||||
}, "win32");
|
||||
}
|
||||
|
||||
async function requestWindowsUnlock() {
|
||||
const hwnd = nativeWindowHandleToDecimal(getNativeWindowHandle());
|
||||
if (!hwnd) return { ok: false, error: "unavailable" };
|
||||
const result = await runHelper(
|
||||
execFile,
|
||||
helperPath,
|
||||
["verify", "--hwnd", hwnd, "--message", "Unlock Netcatty"],
|
||||
SYSTEM_AUTH_VERIFY_TIMEOUT_MS,
|
||||
);
|
||||
return normalizeSystemAuthUnlockResult(result);
|
||||
}
|
||||
|
||||
return {
|
||||
async getStatus() {
|
||||
if (platform === "darwin") return getMacStatus();
|
||||
if (platform === "win32") return getWindowsStatus();
|
||||
return unsupportedStatus();
|
||||
},
|
||||
async requestUnlock() {
|
||||
if (platform === "darwin") return requestMacUnlock();
|
||||
if (platform === "win32") return requestWindowsUnlock();
|
||||
return { ok: false, error: "unsupported" };
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
createAppLockSystemAuthBridge,
|
||||
nativeWindowHandleToDecimal,
|
||||
normalizeSystemAuthStatus,
|
||||
normalizeSystemAuthUnlockResult,
|
||||
resolveDefaultHelperPath,
|
||||
};
|
||||
Reference in New Issue
Block a user