Module: Browserctl::Commands::State

Extended by:
CliOutput
Defined in:
lib/browserctl/commands/state.rb

Overview

‘browserctl state` — top-level command for portable, encrypted, origin- scoped browser state. Wraps the daemon’s state_* RPCs.

Constant Summary collapse

USAGE =
"Usage: browserctl state <save|load|list|info|delete|rotate|export|import> [args]"
DAEMON_SUBCOMMANDS =
{
  "save" => :run_save, "load" => :run_load, "list" => :run_list,
  "info" => :run_info, "delete" => :run_delete, "rotate" => :run_rotate
}.freeze
LOCAL_SUBCOMMANDS =
{ "export" => :run_export, "import" => :run_import }.freeze

Constants included from CliOutput

CliOutput::AUTH_REQUIRED_EXIT_CODE

Class Method Summary collapse

Methods included from CliOutput

exit_code_for, print_result, structured_error_line

Class Method Details

.run(client, args) ⇒ Object



24
25
26
27
28
29
30
31
32
33
# File 'lib/browserctl/commands/state.rb', line 24

def self.run(client, args)
  sub = args.shift or abort USAGE
  if (m = DAEMON_SUBCOMMANDS[sub])
    sub == "list" ? send(m, client) : send(m, client, args)
  elsif (m = LOCAL_SUBCOMMANDS[sub])
    send(m, args)
  else
    abort "unknown state subcommand '#{sub}'\n#{USAGE}"
  end
end

.run_delete(client, args) ⇒ Object



61
62
63
64
# File 'lib/browserctl/commands/state.rb', line 61

def self.run_delete(client, args)
  name = args.shift or abort "usage: browserctl state delete <name>"
  print_result(client.state_delete(name))
end

.run_export(args) ⇒ Object



88
89
90
91
92
93
94
95
96
# File 'lib/browserctl/commands/state.rb', line 88

def self.run_export(args)
  name        = args.shift or abort "usage: browserctl state export <name> <destination>"
  destination = args.shift or abort "usage: browserctl state export <name> <destination>"
  require "browserctl/state"
  OutputFormat.current.emit(Browserctl::State.export(name, destination))
rescue Browserctl::State::Transport::TransportError, Browserctl::Error, ArgumentError => e
  warn "Error: #{e.message}"
  exit 1
end

.run_import(args) ⇒ Object



98
99
100
101
102
103
104
105
106
107
# File 'lib/browserctl/commands/state.rb', line 98

def self.run_import(args)
  name_override = extract_value!(args, "--name")
  source        = args.shift or abort "usage: browserctl state import <source> [--name NAME]"
  require "browserctl/state"
  OutputFormat.current.emit(Browserctl::State.import(source, name: name_override))
rescue Browserctl::State::Transport::TransportError, Browserctl::State::Bundle::BundleError,
       Browserctl::Error, ArgumentError => e
  warn "Error: #{e.message}"
  exit 1
end

.run_info(client, args) ⇒ Object



56
57
58
59
# File 'lib/browserctl/commands/state.rb', line 56

def self.run_info(client, args)
  name = args.shift or abort "usage: browserctl state info <name>"
  print_result(client.state_info(name))
end

.run_list(client) ⇒ Object



52
53
54
# File 'lib/browserctl/commands/state.rb', line 52

def self.run_list(client)
  print_result(client.state_list)
end

.run_load(client, args) ⇒ Object



46
47
48
49
50
# File 'lib/browserctl/commands/state.rb', line 46

def self.run_load(client, args)
  name = args.shift or abort "usage: browserctl state load <name>"
  passphrase = PassphrasePrompt.needed_for?(client, name) ? PassphrasePrompt.read : nil
  print_result(client.state_load(name, passphrase: passphrase))
end

.run_rotate(client, args) ⇒ Object

Re-runs the flow bound to <name> and re-saves it. Mutation logic lives in State::Mutator; this method is CLI plumbing.



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/browserctl/commands/state.rb', line 68

def self.run_rotate(client, args)
  require "browserctl/state/mutator"
  require "browserctl/runner"
  page_name   = extract_value!(args, "--page")
  params_path = extract_value!(args, "--params")
  name        = args.shift or abort "usage: browserctl state rotate <name> " \
                                    "[--page NAME] [--params FILE] [--key value ...]"

  file_params = params_path ? Browserctl::Runner.load_params_file(params_path) : {}
  cli_params  = args.each_slice(2).to_h { |flag, val| [flag.to_s.sub(/\A--/, "").to_sym, val] }
  page        = page_name ? Browserctl::PageProxy.new(page_name, client) : nil

  result = Browserctl::State::Mutator.new(client: client)
                                     .rotate(name: name, params: file_params.merge(cli_params), page: page)
  print_result(result.to_h)
rescue Browserctl::FlowError => e
  warn "Error: #{e.message}"
  exit 1
end

.run_save(client, args) ⇒ Object



35
36
37
38
39
40
41
42
43
44
# File 'lib/browserctl/commands/state.rb', line 35

def self.run_save(client, args)
  encrypt = args.delete("--encrypt")
  origins = extract_value!(args, "--origins")
  flow    = extract_value!(args, "--flow")
  name    = args.shift or abort "usage: browserctl state save <name> [--encrypt] " \
                                "[--origins a,b] [--flow NAME]"
  passphrase  = encrypt ? PassphrasePrompt.read(confirm: true) : nil
  origin_list = origins ? origins.split(",").map(&:strip).reject(&:empty?) : nil
  print_result(client.state_save(name, origins: origin_list, flow: flow, passphrase: passphrase))
end