Module: Browserctl
- Defined in:
- lib/browserctl/flows/stdlib/cloudflare_solve.rb,
lib/browserctl.rb,
lib/browserctl/flow.rb,
lib/browserctl/state.rb,
lib/browserctl/client.rb,
lib/browserctl/errors.rb,
lib/browserctl/logger.rb,
lib/browserctl/policy.rb,
lib/browserctl/runner.rb,
lib/browserctl/server.rb,
lib/browserctl/session.rb,
lib/browserctl/version.rb,
lib/browserctl/workflow.rb,
lib/browserctl/constants.rb,
lib/browserctl/detectors.rb,
lib/browserctl/recording.rb,
lib/browserctl/driver/cdp.rb,
lib/browserctl/driver/base.rb,
lib/browserctl/commands/ask.rb,
lib/browserctl/snapshot/ref.rb,
lib/browserctl/state/bundle.rb,
lib/browserctl/commands/fill.rb,
lib/browserctl/commands/flow.rb,
lib/browserctl/commands/init.rb,
lib/browserctl/commands/page.rb,
lib/browserctl/flow_registry.rb,
lib/browserctl/commands/click.rb,
lib/browserctl/commands/state.rb,
lib/browserctl/replay/context.rb,
lib/browserctl/commands/cookie.rb,
lib/browserctl/commands/daemon.rb,
lib/browserctl/commands/dialog.rb,
lib/browserctl/commands/record.rb,
lib/browserctl/commands/resume.rb,
lib/browserctl/driver/cdp_page.rb,
lib/browserctl/state/transport.rb,
lib/browserctl/commands/session.rb,
lib/browserctl/commands/storage.rb,
lib/browserctl/replay/telemetry.rb,
lib/browserctl/commands/snapshot.rb,
lib/browserctl/commands/workflow.rb,
lib/browserctl/workflow/promoter.rb,
lib/browserctl/snapshot/annotator.rb,
lib/browserctl/snapshot/extractor.rb,
lib/browserctl/commands/cli_output.rb,
lib/browserctl/commands/screenshot.rb,
lib/browserctl/server/idle_watcher.rb,
lib/browserctl/server/page_session.rb,
lib/browserctl/snapshot/serializer.rb,
lib/browserctl/state/transports/s3.rb,
lib/browserctl/replay/snapshot_diff.rb,
lib/browserctl/secret_resolvers/env.rb,
lib/browserctl/server/handlers/hitl.rb,
lib/browserctl/snapshot/fingerprint.rb,
lib/browserctl/flows/stdlib/totp_2fa.rb,
lib/browserctl/secret_resolvers/base.rb,
lib/browserctl/server/handlers/state.rb,
lib/browserctl/state/transports/file.rb,
lib/browserctl/workflow/flow_wrapper.rb,
lib/browserctl/detectors/auth_required.rb,
lib/browserctl/server/handlers/cookies.rb,
lib/browserctl/server/handlers/session.rb,
lib/browserctl/server/handlers/storage.rb,
lib/browserctl/server/snapshot_builder.rb,
lib/browserctl/secret_resolver_registry.rb,
lib/browserctl/server/handlers/devtools.rb,
lib/browserctl/server/command_dispatcher.rb,
lib/browserctl/workflow/promotion_ledger.rb,
lib/browserctl/replay/fingerprint_matcher.rb,
lib/browserctl/server/handlers/navigation.rb,
lib/browserctl/server/handlers/interaction.rb,
lib/browserctl/server/handlers/observation.rb,
lib/browserctl/secret_resolvers/one_password.rb,
lib/browserctl/state/transports/one_password.rb,
lib/browserctl/server/handlers/daemon_control.rb,
lib/browserctl/server/handlers/page_lifecycle.rb,
lib/browserctl/secret_resolvers/macos_keychain.rb
Overview
Pauses for a human to solve a Cloudflare challenge (Turnstile, “Just a moment…”, interactive checkbox), then verifies the challenge cleared before returning. Optionally saves the post-solve session under a name you can reload later with ‘state load` or `session_load`.
Reuses Browserctl::Detectors.cloudflare? — the server-side detector already shipped in v0.8 — by adapting the client-facing PageProxy to the duck-typed (current_url, body) interface the detector expects.
Defined Under Namespace
Modules: Commands, Detectors, Driver, Flows, Policy, Replay, SecretResolvers, Snapshot, State, Workflow
Classes: AuthRequiredError, BrowserNotFound, Client, CommandDispatcher, DaemonUnavailableError, DomainNotAllowed, Error, Flow, FlowConditionDef, FlowContext, FlowError, FlowParamDef, FlowParamError, FlowPostconditionError, FlowPreconditionError, FlowRegistry, FlowStepDef, FlowStepError, IdleWatcher, KeyNotFound, MultiLogger, PageNotFound, PageProxy, PageSession, ParamDef, PathNotAllowed, Recording, RefNotFound, Runner, SecretResolverError, SecretResolverRegistry, SelectorNotFound, Server, Session, SnapshotBuilder, StepDef, StepResult, TimeoutError, WorkflowContext, WorkflowDefinition, WorkflowError
Constant Summary
collapse
- LEVEL_MAP =
{
"debug" => ::Logger::DEBUG,
"info" => ::Logger::INFO,
"warn" => ::Logger::WARN,
"error" => ::Logger::ERROR
}.freeze
- VERSION =
"0.11.0"
- BROWSERCTL_DIR =
File.expand_path("~/.browserctl")
- IDLE_TTL =
30 * 60
- PROTOCOL_VERSION =
Increment when a breaking wire protocol change ships (new field names, removed commands, changed response shapes). Clients read this from ‘ping` to verify compatibility before sending commands.
"3"
- SOCKET_PATH =
Backward-compatible constants
socket_path
- PID_PATH =
pid_path
Class Method Summary
collapse
Class Method Details
.all_daemon_names ⇒ Object
36
37
38
39
|
# File 'lib/browserctl/constants.rb', line 36
def self.all_daemon_names
all_daemon_sockets.map { |f| File.basename(f, ".sock") }
.map { |n| n == "browserd" ? nil : n }
end
|
.all_daemon_sockets ⇒ Object
32
33
34
|
# File 'lib/browserctl/constants.rb', line 32
def self.all_daemon_sockets
Dir[File.join(BROWSERCTL_DIR, "*.sock")]
end
|
.build_logger(level_name, log_path: nil) ⇒ Object
41
42
43
44
45
46
47
48
49
50
51
52
53
|
# File 'lib/browserctl/logger.rb', line 41
def self.build_logger(level_name, log_path: nil)
level = LEVEL_MAP.fetch(level_name.to_s.downcase, ::Logger::INFO)
formatter = proc { |sev, t, prog, msg| "#{t.strftime('%Y-%m-%dT%H:%M:%S')} #{sev[0]} [#{prog}] #{msg}\n" }
stderr_log = make_logger($stderr, level, formatter)
return stderr_log unless log_path
FileUtils.mkdir_p(File.dirname(log_path), mode: 0o700)
FileUtils.touch(log_path)
File.chmod(0o600, log_path)
file_log = make_logger(log_path, level, formatter)
MultiLogger.new(stderr_log, file_log)
end
|
.flow(name, &block) ⇒ Object
192
193
194
195
196
197
198
|
# File 'lib/browserctl/flow.rb', line 192
def self.flow(name, &block)
raise ArgumentError, "Browserctl.flow requires a block" unless block
flow = Flow.new(name).tap { |f| f.instance_exec(&block) }
register_flow(flow)
flow
end
|
.flow_registry_reset! ⇒ Object
212
213
214
|
# File 'lib/browserctl/flow.rb', line 212
def self.flow_registry_reset!
@flow_registry_mutex.synchronize { @flow_registry.clear }
end
|
.flow_registry_snapshot ⇒ Object
208
209
210
|
# File 'lib/browserctl/flow.rb', line 208
def self.flow_registry_snapshot
@flow_registry_mutex.synchronize { @flow_registry.dup }
end
|
.log_path(name = nil) ⇒ Object
18
19
20
|
# File 'lib/browserctl/constants.rb', line 18
def self.log_path(name = nil)
File.join(BROWSERCTL_DIR, name ? "#{name}.log" : "browserd.log")
end
|
.logger ⇒ Object
33
34
35
|
# File 'lib/browserctl/logger.rb', line 33
def self.logger
@logger ||= build_logger("info")
end
|
.logger=(instance) ⇒ Object
37
38
39
|
# File 'lib/browserctl/logger.rb', line 37
def self.logger=(instance)
@logger = instance
end
|
.lookup_flow(name) ⇒ Object
204
205
206
|
# File 'lib/browserctl/flow.rb', line 204
def self.lookup_flow(name)
@flow_registry_mutex.synchronize { @flow_registry[name.to_s] }
end
|
.lookup_plugin_command(name) ⇒ Object
19
20
21
|
# File 'lib/browserctl.rb', line 19
def self.lookup_plugin_command(name)
@plugin_commands_mutex.synchronize { @plugin_commands[name.to_s] }
end
|
.lookup_workflow(name) ⇒ Object
497
498
499
|
# File 'lib/browserctl/workflow.rb', line 497
def self.lookup_workflow(name)
@registry_mutex.synchronize { @registry[name.to_s] }
end
|
.next_daemon_name ⇒ Object
Returns nil when the default (unnamed) slot is free; otherwise returns “d1”, “d2”, etc.
23
24
25
26
27
28
29
30
|
# File 'lib/browserctl/constants.rb', line 23
def self.next_daemon_name
return nil unless File.exist?(socket_path)
1.upto(99) do |i|
return "d#{i}" unless File.exist?(socket_path("d#{i}"))
end
raise "too many running daemons (limit: 99)"
end
|
.pid_path(name = nil) ⇒ Object
14
15
16
|
# File 'lib/browserctl/constants.rb', line 14
def self.pid_path(name = nil)
File.join(BROWSERCTL_DIR, name ? "#{name}.pid" : "browserd.pid")
end
|
.plugin_commands_snapshot ⇒ Object
23
24
25
|
# File 'lib/browserctl.rb', line 23
def self.plugin_commands_snapshot
@plugin_commands_mutex.synchronize { @plugin_commands.dup }
end
|
.register_command(name, &block) ⇒ Object
15
16
17
|
# File 'lib/browserctl.rb', line 15
def self.register_command(name, &block)
@plugin_commands_mutex.synchronize { @plugin_commands[name.to_s] = block }
end
|
.register_flow(flow) ⇒ Object
200
201
202
|
# File 'lib/browserctl/flow.rb', line 200
def self.register_flow(flow)
@flow_registry_mutex.synchronize { @flow_registry[flow.name] = flow }
end
|
.registry_snapshot ⇒ Object
501
502
503
|
# File 'lib/browserctl/workflow.rb', line 501
def self.registry_snapshot
@registry_mutex.synchronize { @registry.dup }
end
|
.socket_path(name = nil) ⇒ Object
10
11
12
|
# File 'lib/browserctl/constants.rb', line 10
def self.socket_path(name = nil)
File.join(BROWSERCTL_DIR, name ? "#{name}.sock" : "browserd.sock")
end
|
.workflow(name) ⇒ Object
491
492
493
494
495
|
# File 'lib/browserctl/workflow.rb', line 491
def self.workflow(name, &)
defn = WorkflowDefinition.new(name.to_s)
defn.instance_exec(&)
@registry_mutex.synchronize { @registry[name.to_s] = defn }
end
|