From ab8a84520286714b40c12264204cac4b1ffa1696 Mon Sep 17 00:00:00 2001 From: Ulzii Otgonbaatar Date: Wed, 11 Feb 2026 14:56:19 -0700 Subject: [PATCH] feat: add ambient mouse API endpoint for anti-bot event diversity Add POST /computer/ambient_mouse to toggle a background loop of diverse input events (mouse drift, scroll, micro-drag, click, key tap). The loop acquires inputMu per action so it cooperates with explicit computer-use API calls instead of contending with them. - Configurable intervals (min/max_interval_ms) and per-action weights - Display geometry cached for 30s to minimize lock hold time - Mouseup uses background context to prevent stuck mouse button on cancel - Clean shutdown via Shutdown() cancels the ambient context Co-authored-by: Cursor --- server/cmd/api/api/ambient_mouse.go | 262 +++++++++++++ server/cmd/api/api/api.go | 17 + server/lib/oapi/oapi.go | 579 +++++++++++++++++++++------- server/openapi.yaml | 90 +++++ 4 files changed, 807 insertions(+), 141 deletions(-) create mode 100644 server/cmd/api/api/ambient_mouse.go diff --git a/server/cmd/api/api/ambient_mouse.go b/server/cmd/api/api/ambient_mouse.go new file mode 100644 index 00000000..d5e8618a --- /dev/null +++ b/server/cmd/api/api/ambient_mouse.go @@ -0,0 +1,262 @@ +package api + +import ( + "context" + "fmt" + "math/rand" + "strconv" + "strings" + "time" + + "github.com/onkernel/kernel-images/server/lib/logger" + oapi "github.com/onkernel/kernel-images/server/lib/oapi" +) + +// ambientAction identifies the type of ambient event to emit. +type ambientAction int + +const ( + ambientMouseDrift ambientAction = iota + ambientScroll + ambientMicroDrag + ambientClick + ambientKeyTap +) + +// ambientConfig holds the resolved configuration for the ambient mouse loop. +type ambientConfig struct { + minIntervalMs int + maxIntervalMs int + weights []struct { + action ambientAction + weight int + } + totalWeight int +} + +func (s *ApiService) SetAmbientMouse(ctx context.Context, request oapi.SetAmbientMouseRequestObject) (oapi.SetAmbientMouseResponseObject, error) { + log := logger.FromContext(ctx) + + if request.Body == nil { + return oapi.SetAmbientMouse400JSONResponse{BadRequestErrorJSONResponse: oapi.BadRequestErrorJSONResponse{ + Message: "request body is required"}, + }, nil + } + body := *request.Body + + s.inputMu.Lock() + + // Stop any running ambient loop first. + if s.ambientCancel != nil { + s.ambientCancel() + s.ambientCancel = nil + } + + if !body.Enabled { + s.inputMu.Unlock() + log.Info("ambient mouse disabled") + return oapi.SetAmbientMouse200JSONResponse(oapi.AmbientMouseResponse{Enabled: false}), nil + } + + // Resolve configuration with defaults. + cfg, err := resolveAmbientConfig(body) + if err != nil { + s.inputMu.Unlock() + return oapi.SetAmbientMouse400JSONResponse{BadRequestErrorJSONResponse: oapi.BadRequestErrorJSONResponse{ + Message: err.Error()}, + }, nil + } + + ambientCtx, cancel := context.WithCancel(context.Background()) + s.ambientCancel = cancel + s.inputMu.Unlock() + + go s.runAmbientLoop(ambientCtx, cfg) + + log.Info("ambient mouse enabled", + "min_interval_ms", cfg.minIntervalMs, + "max_interval_ms", cfg.maxIntervalMs, + ) + return oapi.SetAmbientMouse200JSONResponse(oapi.AmbientMouseResponse{Enabled: true}), nil +} + +// resolveAmbientConfig builds an ambientConfig from the request body, applying defaults. +func resolveAmbientConfig(body oapi.AmbientMouseRequest) (ambientConfig, error) { + cfg := ambientConfig{ + minIntervalMs: 200, + maxIntervalMs: 600, + } + if body.MinIntervalMs != nil { + cfg.minIntervalMs = *body.MinIntervalMs + } + if body.MaxIntervalMs != nil { + cfg.maxIntervalMs = *body.MaxIntervalMs + } + if cfg.minIntervalMs > cfg.maxIntervalMs { + return cfg, fmt.Errorf("min_interval_ms must be <= max_interval_ms") + } + + driftW := 55 + scrollW := 20 + microDragW := 12 + clickW := 10 + keyTapW := 3 + if body.MouseDriftWeight != nil { + driftW = *body.MouseDriftWeight + } + if body.ScrollWeight != nil { + scrollW = *body.ScrollWeight + } + if body.MicroDragWeight != nil { + microDragW = *body.MicroDragWeight + } + if body.ClickWeight != nil { + clickW = *body.ClickWeight + } + if body.KeyTapWeight != nil { + keyTapW = *body.KeyTapWeight + } + + cfg.weights = []struct { + action ambientAction + weight int + }{ + {ambientMouseDrift, driftW}, + {ambientScroll, scrollW}, + {ambientMicroDrag, microDragW}, + {ambientClick, clickW}, + {ambientKeyTap, keyTapW}, + } + for _, w := range cfg.weights { + cfg.totalWeight += w.weight + } + if cfg.totalWeight == 0 { + return cfg, fmt.Errorf("at least one action weight must be > 0") + } + return cfg, nil +} + +// runAmbientLoop is the background goroutine that emits diverse input events. +// It acquires inputMu for each action, so it cooperates with explicit API calls. +func (s *ApiService) runAmbientLoop(ctx context.Context, cfg ambientConfig) { + r := rand.New(rand.NewSource(time.Now().UnixNano())) + + for { + select { + case <-ctx.Done(): + return + default: + } + + action := pickAmbientAction(r, cfg) + s.inputMu.Lock() + s.execAmbientAction(ctx, r, action) + s.inputMu.Unlock() + + // Random delay between events. + delayMs := cfg.minIntervalMs + r.Intn(cfg.maxIntervalMs-cfg.minIntervalMs+1) + select { + case <-ctx.Done(): + return + case <-time.After(time.Duration(delayMs) * time.Millisecond): + } + } +} + +func pickAmbientAction(r *rand.Rand, cfg ambientConfig) ambientAction { + n := r.Intn(cfg.totalWeight) + for _, w := range cfg.weights { + if n < w.weight { + return w.action + } + n -= w.weight + } + return ambientMouseDrift +} + +// execAmbientAction performs a single ambient event via xdotool. Must be called +// with inputMu held. +func (s *ApiService) execAmbientAction(ctx context.Context, r *rand.Rand, action ambientAction) { + switch action { + case ambientMouseDrift: + dx := r.Intn(8) - 4 + dy := r.Intn(8) - 4 + if dx == 0 && dy == 0 { + dx = 1 + } + defaultXdoTool.Run(ctx, "mousemove_relative", "--", fmt.Sprintf("%d", dx), fmt.Sprintf("%d", dy)) + + case ambientScroll: + w, h := s.getDisplayGeometry(ctx) + if w > 0 && h > 0 { + x := w/2 + r.Intn(80) - 40 + y := h/2 + r.Intn(80) - 40 + defaultXdoTool.Run(ctx, "mousemove", strconv.Itoa(x), strconv.Itoa(y)) + btn := "4" + if r.Intn(2) == 0 { + btn = "5" + } + defaultXdoTool.Run(ctx, "click", btn) + } + + case ambientMicroDrag: + dx := 3 + r.Intn(6) + dy := 3 + r.Intn(6) + if r.Intn(2) == 0 { + dx = -dx + } + if r.Intn(2) == 0 { + dy = -dy + } + defaultXdoTool.Run(ctx, "mousedown", "1") + defaultXdoTool.Run(ctx, "mousemove_relative", "--", fmt.Sprintf("%d", dx), fmt.Sprintf("%d", dy)) + // Use background context so mouseup always fires even if ctx is cancelled, + // preventing a stuck mouse button. + defaultXdoTool.Run(context.Background(), "mouseup", "1") + + case ambientClick: + w, h := s.getDisplayGeometry(ctx) + if w > 200 && h > 200 { + pad := 100 + if w < 400 { + pad = w / 4 + } + x := pad + r.Intn(max(1, w-2*pad)) + y := pad + r.Intn(max(1, h-2*pad)) + defaultXdoTool.Run(ctx, "mousemove", strconv.Itoa(x), strconv.Itoa(y)) + defaultXdoTool.Run(ctx, "click", "1") + } + + case ambientKeyTap: + // Modifier tap; least likely to trigger page behavior. + defaultXdoTool.Run(ctx, "key", "shift") + } +} + +// getDisplayGeometry returns the current display dimensions via xdotool. +// The result is cached for 30 seconds to avoid shelling out on every ambient event. +func (s *ApiService) getDisplayGeometry(ctx context.Context) (int, int) { + s.displayGeomMu.Lock() + defer s.displayGeomMu.Unlock() + + if time.Since(s.displayGeomAt) < 30*time.Second && s.displayGeomW > 0 { + return s.displayGeomW, s.displayGeomH + } + + out, err := defaultXdoTool.Run(ctx, "getdisplaygeometry") + if err != nil { + return s.displayGeomW, s.displayGeomH + } + parts := strings.Fields(strings.TrimSpace(string(out))) + if len(parts) >= 2 { + w, _ := strconv.Atoi(parts[0]) + h, _ := strconv.Atoi(parts[1]) + if w > 0 && h > 0 { + s.displayGeomW = w + s.displayGeomH = h + s.displayGeomAt = time.Now() + return w, h + } + } + return s.displayGeomW, s.displayGeomH +} diff --git a/server/cmd/api/api/api.go b/server/cmd/api/api/api.go index 910410b9..6782888c 100644 --- a/server/cmd/api/api/api.go +++ b/server/cmd/api/api/api.go @@ -53,6 +53,15 @@ type ApiService struct { // policy management policy *policy.Policy + + // ambientCancel stops the ambient mouse loop (protected by inputMu) + ambientCancel context.CancelFunc + + // displayGeom caches xdotool getdisplaygeometry to avoid shelling out per ambient event + displayGeomMu sync.Mutex + displayGeomW int + displayGeomH int + displayGeomAt time.Time } var _ oapi.StrictServerInterface = (*ApiService)(nil) @@ -298,5 +307,13 @@ func (s *ApiService) ListRecorders(ctx context.Context, _ oapi.ListRecordersRequ } func (s *ApiService) Shutdown(ctx context.Context) error { + // Stop ambient mouse loop if running. + s.inputMu.Lock() + if s.ambientCancel != nil { + s.ambientCancel() + s.ambientCancel = nil + } + s.inputMu.Unlock() + return s.recordManager.StopAll(ctx) } diff --git a/server/lib/oapi/oapi.go b/server/lib/oapi/oapi.go index 686fbc48..39e50603 100644 --- a/server/lib/oapi/oapi.go +++ b/server/lib/oapi/oapi.go @@ -115,6 +115,41 @@ const ( Supervisor LogsStreamParamsSource = "supervisor" ) +// AmbientMouseRequest Enable or disable ambient mouse activity. When enabled, the server runs a background +// loop emitting diverse input events (drift, scroll, micro-drag, click, key tap) to +// make the session appear human-like to anti-bot sensors. +type AmbientMouseRequest struct { + // ClickWeight Relative weight for click events. + ClickWeight *int `json:"click_weight,omitempty"` + + // Enabled Whether ambient mouse activity should be active. + Enabled bool `json:"enabled"` + + // KeyTapWeight Relative weight for key tap events. + KeyTapWeight *int `json:"key_tap_weight,omitempty"` + + // MaxIntervalMs Maximum delay in milliseconds between ambient events. + MaxIntervalMs *int `json:"max_interval_ms,omitempty"` + + // MicroDragWeight Relative weight for micro-drag events. + MicroDragWeight *int `json:"micro_drag_weight,omitempty"` + + // MinIntervalMs Minimum delay in milliseconds between ambient events. + MinIntervalMs *int `json:"min_interval_ms,omitempty"` + + // MouseDriftWeight Relative weight for mouse drift events. + MouseDriftWeight *int `json:"mouse_drift_weight,omitempty"` + + // ScrollWeight Relative weight for scroll events. + ScrollWeight *int `json:"scroll_weight,omitempty"` +} + +// AmbientMouseResponse Current state of ambient mouse activity. +type AmbientMouseResponse struct { + // Enabled Whether ambient mouse activity is currently active. + Enabled bool `json:"enabled"` +} + // BatchComputerActionRequest A batch of computer actions to execute sequentially. type BatchComputerActionRequest struct { // Actions Ordered list of actions to execute. Execution stops on the first error. @@ -793,6 +828,9 @@ type PatchChromiumFlagsJSONRequestBody PatchChromiumFlagsJSONBody // UploadExtensionsAndRestartMultipartRequestBody defines body for UploadExtensionsAndRestart for multipart/form-data ContentType. type UploadExtensionsAndRestartMultipartRequestBody UploadExtensionsAndRestartMultipartBody +// SetAmbientMouseJSONRequestBody defines body for SetAmbientMouse for application/json ContentType. +type SetAmbientMouseJSONRequestBody = AmbientMouseRequest + // BatchComputerActionJSONRequestBody defines body for BatchComputerAction for application/json ContentType. type BatchComputerActionJSONRequestBody = BatchComputerActionRequest @@ -958,6 +996,11 @@ type ClientInterface interface { // UploadExtensionsAndRestartWithBody request with any body UploadExtensionsAndRestartWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) + // SetAmbientMouseWithBody request with any body + SetAmbientMouseWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) + + SetAmbientMouse(ctx context.Context, body SetAmbientMouseJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + // BatchComputerActionWithBody request with any body BatchComputerActionWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -1171,6 +1214,30 @@ func (c *Client) UploadExtensionsAndRestartWithBody(ctx context.Context, content return c.Client.Do(req) } +func (c *Client) SetAmbientMouseWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewSetAmbientMouseRequestWithBody(c.Server, contentType, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) SetAmbientMouse(ctx context.Context, body SetAmbientMouseJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewSetAmbientMouseRequest(c.Server, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + func (c *Client) BatchComputerActionWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { req, err := NewBatchComputerActionRequestWithBody(c.Server, contentType, body) if err != nil { @@ -2044,6 +2111,46 @@ func NewUploadExtensionsAndRestartRequestWithBody(server string, contentType str return req, nil } +// NewSetAmbientMouseRequest calls the generic SetAmbientMouse builder with application/json body +func NewSetAmbientMouseRequest(server string, body SetAmbientMouseJSONRequestBody) (*http.Request, error) { + var bodyReader io.Reader + buf, err := json.Marshal(body) + if err != nil { + return nil, err + } + bodyReader = bytes.NewReader(buf) + return NewSetAmbientMouseRequestWithBody(server, "application/json", bodyReader) +} + +// NewSetAmbientMouseRequestWithBody generates requests for SetAmbientMouse with any type of body +func NewSetAmbientMouseRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) { + var err error + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/computer/ambient_mouse") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("POST", queryURL.String(), body) + if err != nil { + return nil, err + } + + req.Header.Add("Content-Type", contentType) + + return req, nil +} + // NewBatchComputerActionRequest calls the generic BatchComputerAction builder with application/json body func NewBatchComputerActionRequest(server string, body BatchComputerActionJSONRequestBody) (*http.Request, error) { var bodyReader io.Reader @@ -3839,6 +3946,11 @@ type ClientWithResponsesInterface interface { // UploadExtensionsAndRestartWithBodyWithResponse request with any body UploadExtensionsAndRestartWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*UploadExtensionsAndRestartResponse, error) + // SetAmbientMouseWithBodyWithResponse request with any body + SetAmbientMouseWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*SetAmbientMouseResponse, error) + + SetAmbientMouseWithResponse(ctx context.Context, body SetAmbientMouseJSONRequestBody, reqEditors ...RequestEditorFn) (*SetAmbientMouseResponse, error) + // BatchComputerActionWithBodyWithResponse request with any body BatchComputerActionWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*BatchComputerActionResponse, error) @@ -4062,6 +4174,30 @@ func (r UploadExtensionsAndRestartResponse) StatusCode() int { return 0 } +type SetAmbientMouseResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *AmbientMouseResponse + JSON400 *BadRequestError + JSON500 *InternalError +} + +// Status returns HTTPResponse.Status +func (r SetAmbientMouseResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r SetAmbientMouseResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + type BatchComputerActionResponse struct { Body []byte HTTPResponse *http.Response @@ -5093,6 +5229,23 @@ func (c *ClientWithResponses) UploadExtensionsAndRestartWithBodyWithResponse(ctx return ParseUploadExtensionsAndRestartResponse(rsp) } +// SetAmbientMouseWithBodyWithResponse request with arbitrary body returning *SetAmbientMouseResponse +func (c *ClientWithResponses) SetAmbientMouseWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*SetAmbientMouseResponse, error) { + rsp, err := c.SetAmbientMouseWithBody(ctx, contentType, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseSetAmbientMouseResponse(rsp) +} + +func (c *ClientWithResponses) SetAmbientMouseWithResponse(ctx context.Context, body SetAmbientMouseJSONRequestBody, reqEditors ...RequestEditorFn) (*SetAmbientMouseResponse, error) { + rsp, err := c.SetAmbientMouse(ctx, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseSetAmbientMouseResponse(rsp) +} + // BatchComputerActionWithBodyWithResponse request with arbitrary body returning *BatchComputerActionResponse func (c *ClientWithResponses) BatchComputerActionWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*BatchComputerActionResponse, error) { rsp, err := c.BatchComputerActionWithBody(ctx, contentType, body, reqEditors...) @@ -5737,6 +5890,46 @@ func ParseUploadExtensionsAndRestartResponse(rsp *http.Response) (*UploadExtensi return response, nil } +// ParseSetAmbientMouseResponse parses an HTTP response from a SetAmbientMouseWithResponse call +func ParseSetAmbientMouseResponse(rsp *http.Response) (*SetAmbientMouseResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &SetAmbientMouseResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest AmbientMouseResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400: + var dest BadRequestError + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON400 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 500: + var dest InternalError + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON500 = &dest + + } + + return response, nil +} + // ParseBatchComputerActionResponse parses an HTTP response from a BatchComputerActionWithResponse call func ParseBatchComputerActionResponse(rsp *http.Response) (*BatchComputerActionResponse, error) { bodyBytes, err := io.ReadAll(rsp.Body) @@ -7383,6 +7576,9 @@ type ServerInterface interface { // Upload one or more unpacked extensions (as zips) and restart Chromium // (POST /chromium/upload-extensions-and-restart) UploadExtensionsAndRestart(w http.ResponseWriter, r *http.Request) + // Enable or disable ambient mouse activity + // (POST /computer/ambient_mouse) + SetAmbientMouse(w http.ResponseWriter, r *http.Request) // Execute a batch of computer actions sequentially // (POST /computer/batch) BatchComputerAction(w http.ResponseWriter, r *http.Request) @@ -7527,6 +7723,12 @@ func (_ Unimplemented) UploadExtensionsAndRestart(w http.ResponseWriter, r *http w.WriteHeader(http.StatusNotImplemented) } +// Enable or disable ambient mouse activity +// (POST /computer/ambient_mouse) +func (_ Unimplemented) SetAmbientMouse(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusNotImplemented) +} + // Execute a batch of computer actions sequentially // (POST /computer/batch) func (_ Unimplemented) BatchComputerAction(w http.ResponseWriter, r *http.Request) { @@ -7816,6 +8018,20 @@ func (siw *ServerInterfaceWrapper) UploadExtensionsAndRestart(w http.ResponseWri handler.ServeHTTP(w, r) } +// SetAmbientMouse operation middleware +func (siw *ServerInterfaceWrapper) SetAmbientMouse(w http.ResponseWriter, r *http.Request) { + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.SetAmbientMouse(w, r) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + // BatchComputerAction operation middleware func (siw *ServerInterfaceWrapper) BatchComputerAction(w http.ResponseWriter, r *http.Request) { @@ -8793,6 +9009,9 @@ func HandlerWithOptions(si ServerInterface, options ChiServerOptions) http.Handl r.Group(func(r chi.Router) { r.Post(options.BaseURL+"/chromium/upload-extensions-and-restart", wrapper.UploadExtensionsAndRestart) }) + r.Group(func(r chi.Router) { + r.Post(options.BaseURL+"/computer/ambient_mouse", wrapper.SetAmbientMouse) + }) r.Group(func(r chi.Router) { r.Post(options.BaseURL+"/computer/batch", wrapper.BatchComputerAction) }) @@ -8999,6 +9218,41 @@ func (response UploadExtensionsAndRestart500JSONResponse) VisitUploadExtensionsA return json.NewEncoder(w).Encode(response) } +type SetAmbientMouseRequestObject struct { + Body *SetAmbientMouseJSONRequestBody +} + +type SetAmbientMouseResponseObject interface { + VisitSetAmbientMouseResponse(w http.ResponseWriter) error +} + +type SetAmbientMouse200JSONResponse AmbientMouseResponse + +func (response SetAmbientMouse200JSONResponse) VisitSetAmbientMouseResponse(w http.ResponseWriter) error { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + + return json.NewEncoder(w).Encode(response) +} + +type SetAmbientMouse400JSONResponse struct{ BadRequestErrorJSONResponse } + +func (response SetAmbientMouse400JSONResponse) VisitSetAmbientMouseResponse(w http.ResponseWriter) error { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(400) + + return json.NewEncoder(w).Encode(response) +} + +type SetAmbientMouse500JSONResponse struct{ InternalErrorJSONResponse } + +func (response SetAmbientMouse500JSONResponse) VisitSetAmbientMouseResponse(w http.ResponseWriter) error { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(500) + + return json.NewEncoder(w).Encode(response) +} + type BatchComputerActionRequestObject struct { Body *BatchComputerActionJSONRequestBody } @@ -10846,6 +11100,9 @@ type StrictServerInterface interface { // Upload one or more unpacked extensions (as zips) and restart Chromium // (POST /chromium/upload-extensions-and-restart) UploadExtensionsAndRestart(ctx context.Context, request UploadExtensionsAndRestartRequestObject) (UploadExtensionsAndRestartResponseObject, error) + // Enable or disable ambient mouse activity + // (POST /computer/ambient_mouse) + SetAmbientMouse(ctx context.Context, request SetAmbientMouseRequestObject) (SetAmbientMouseResponseObject, error) // Execute a batch of computer actions sequentially // (POST /computer/batch) BatchComputerAction(ctx context.Context, request BatchComputerActionRequestObject) (BatchComputerActionResponseObject, error) @@ -11065,6 +11322,37 @@ func (sh *strictHandler) UploadExtensionsAndRestart(w http.ResponseWriter, r *ht } } +// SetAmbientMouse operation middleware +func (sh *strictHandler) SetAmbientMouse(w http.ResponseWriter, r *http.Request) { + var request SetAmbientMouseRequestObject + + var body SetAmbientMouseJSONRequestBody + if err := json.NewDecoder(r.Body).Decode(&body); err != nil { + sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err)) + return + } + request.Body = &body + + handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { + return sh.ssi.SetAmbientMouse(ctx, request.(SetAmbientMouseRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "SetAmbientMouse") + } + + response, err := handler(r.Context(), w, r, request) + + if err != nil { + sh.options.ResponseErrorHandlerFunc(w, r, err) + } else if validResponse, ok := response.(SetAmbientMouseResponseObject); ok { + if err := validResponse.VisitSetAmbientMouseResponse(w); err != nil { + sh.options.ResponseErrorHandlerFunc(w, r, err) + } + } else if response != nil { + sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response)) + } +} + // BatchComputerAction operation middleware func (sh *strictHandler) BatchComputerAction(w http.ResponseWriter, r *http.Request) { var request BatchComputerActionRequestObject @@ -12304,147 +12592,156 @@ func (sh *strictHandler) StopRecording(w http.ResponseWriter, r *http.Request) { // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "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", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/server/openapi.yaml b/server/openapi.yaml index 3d09aca3..d9d2d6db 100644 --- a/server/openapi.yaml +++ b/server/openapi.yaml @@ -502,6 +502,38 @@ paths: $ref: "#/components/responses/BadRequestError" "500": $ref: "#/components/responses/InternalError" + /computer/ambient_mouse: + post: + summary: Enable or disable ambient mouse activity + description: | + Toggle a background loop that emits diverse input events (mouse drift, scroll, + micro-drag, click, key tap) to make the browser session appear more human-like to + anti-bot sensors. + + When enabled, the loop acquires the same input lock used by all other computer-use + APIs, so ambient events never interleave with explicit actions. The loop automatically + yields the lock between events, allowing explicit API calls to take priority. + + Call with enabled=false to stop the loop. Calling with enabled=true while already + running replaces the configuration (restarts the loop). + operationId: setAmbientMouse + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/AmbientMouseRequest" + responses: + "200": + description: Ambient mouse state updated + content: + application/json: + schema: + $ref: "#/components/schemas/AmbientMouseResponse" + "400": + $ref: "#/components/responses/BadRequestError" + "500": + $ref: "#/components/responses/InternalError" /logs/stream: get: summary: Stream logs over SSE @@ -1831,6 +1863,64 @@ components: items: $ref: "#/components/schemas/ComputerAction" additionalProperties: false + AmbientMouseRequest: + type: object + description: | + Enable or disable ambient mouse activity. When enabled, the server runs a background + loop emitting diverse input events (drift, scroll, micro-drag, click, key tap) to + make the session appear human-like to anti-bot sensors. + required: [enabled] + properties: + enabled: + type: boolean + description: Whether ambient mouse activity should be active. + min_interval_ms: + type: integer + description: Minimum delay in milliseconds between ambient events. + minimum: 50 + maximum: 10000 + default: 200 + max_interval_ms: + type: integer + description: Maximum delay in milliseconds between ambient events. + minimum: 50 + maximum: 30000 + default: 600 + mouse_drift_weight: + type: integer + description: Relative weight for mouse drift events. + minimum: 0 + default: 55 + scroll_weight: + type: integer + description: Relative weight for scroll events. + minimum: 0 + default: 20 + micro_drag_weight: + type: integer + description: Relative weight for micro-drag events. + minimum: 0 + default: 12 + click_weight: + type: integer + description: Relative weight for click events. + minimum: 0 + default: 10 + key_tap_weight: + type: integer + description: Relative weight for key tap events. + minimum: 0 + default: 3 + additionalProperties: false + AmbientMouseResponse: + type: object + description: Current state of ambient mouse activity. + required: [enabled] + properties: + enabled: + type: boolean + description: Whether ambient mouse activity is currently active. + additionalProperties: false responses: BadRequestError: description: Bad Request