kbsecret 1.2.0 → 1.3.0.pre.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +5 -5
  3. data/bin/kbsecret +6 -14
  4. data/lib/kbsecret/cli/command/abstract.rb +51 -0
  5. data/lib/kbsecret/cli/command/conf.rb +42 -0
  6. data/lib/kbsecret/cli/command/cp.rb +54 -0
  7. data/lib/kbsecret/cli/command/dump_fields.rb +53 -0
  8. data/lib/kbsecret/cli/command/env.rb +66 -0
  9. data/lib/kbsecret/cli/command/generator.rb +62 -0
  10. data/lib/kbsecret/cli/command/generators.rb +37 -0
  11. data/lib/kbsecret/cli/command/list.rb +48 -0
  12. data/lib/kbsecret/cli/command/login.rb +66 -0
  13. data/lib/kbsecret/cli/command/new.rb +82 -0
  14. data/lib/kbsecret/cli/command/pass.rb +51 -0
  15. data/lib/kbsecret/cli/command/raw_edit.rb +46 -0
  16. data/lib/kbsecret/cli/command/rm.rb +58 -0
  17. data/lib/kbsecret/cli/command/session.rb +128 -0
  18. data/lib/kbsecret/cli/command/sessions.rb +47 -0
  19. data/lib/kbsecret/cli/command/stash_file.rb +62 -0
  20. data/lib/kbsecret/cli/command/todo.rb +78 -0
  21. data/lib/kbsecret/cli/command.rb +45 -0
  22. data/lib/kbsecret/cli.rb +6 -4
  23. data/lib/kbsecret/config.rb +4 -3
  24. data/lib/kbsecret/record/abstract.rb +2 -2
  25. data/lib/kbsecret/record.rb +9 -7
  26. data/lib/kbsecret/version.rb +1 -1
  27. metadata +22 -20
  28. data/lib/kbsecret/cli/kbsecret-conf +0 -31
  29. data/lib/kbsecret/cli/kbsecret-cp +0 -44
  30. data/lib/kbsecret/cli/kbsecret-dump-fields +0 -39
  31. data/lib/kbsecret/cli/kbsecret-env +0 -53
  32. data/lib/kbsecret/cli/kbsecret-generator +0 -42
  33. data/lib/kbsecret/cli/kbsecret-generators +0 -28
  34. data/lib/kbsecret/cli/kbsecret-list +0 -36
  35. data/lib/kbsecret/cli/kbsecret-login +0 -53
  36. data/lib/kbsecret/cli/kbsecret-new +0 -68
  37. data/lib/kbsecret/cli/kbsecret-pass +0 -37
  38. data/lib/kbsecret/cli/kbsecret-raw-edit +0 -31
  39. data/lib/kbsecret/cli/kbsecret-rm +0 -44
  40. data/lib/kbsecret/cli/kbsecret-session +0 -105
  41. data/lib/kbsecret/cli/kbsecret-sessions +0 -38
  42. data/lib/kbsecret/cli/kbsecret-stash-file +0 -48
  43. data/lib/kbsecret/cli/kbsecret-todo +0 -47
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3b7e55fb17c53bed43e18cbd8c7a8c57aaacce276af208638d5110284f38f763
4
- data.tar.gz: 3c5ea62a9a2d7d418d26369a1a55d6af2119d9328d6a86455d46be29e419e377
3
+ metadata.gz: 5a564bac0dc6d8ba790b99238519dd12c2e1efea7fccfbf832a69e9861cb98f7
4
+ data.tar.gz: 502c1bb72096256a854631bf375a30f917f04fd636b28e186ce5b5294f8830e5
5
5
  SHA512:
6
- metadata.gz: bb715c6c6602411bfe70f150c1c600cd51b7513a4b4433147b75df2f2b70df9d35345a9d85698acb8db37c450e43b8cb2823e9346c8b0d2a93d7397e6353e06c
7
- data.tar.gz: 6799876c9f29cd4b5ce9f39d5ec05329e6d1c3ea25e7cf49d0dd49e2d915ede5725d05222d5b68fc4d4bf9ca274195f671755f2658bc19f5bcc30974473b8156
6
+ metadata.gz: 8a508c3a12446379ba2947d78950f506214ee3c0f8240279cbc09592f44b119af150611a6d1addb18d5173cdb877da95ea9d1553ce0a0b2eef448b963abc47b2
7
+ data.tar.gz: 87c3e9ba9f42a2c5372b40a16bc7b8ce33042d34955e9ac65dff6fede1169be9214644c2d91f8b15d7e6d3eed19b1274a79c75cf2c6ac8e8f8d20d12b424f722
data/README.md CHANGED
@@ -9,11 +9,11 @@ KBSecret is a command line utility and library for managing *secrets*.
9
9
 
10
10
  Quick links:
11
11
 
12
- * [Installation instructions](https://kbsecret.github.io/installation)
13
- * [Quick start guide](https://kbsecret.github.io/quickstart)
14
- * [CLI documentation](https://kbsecret.github.io/man/)
12
+ * [Installation instructions](https://kbsecret.github.io/#/install/)
13
+ * [Quick start guide](https://kbsecret.github.io/#/quickstart/)
14
+ * [CLI documentation](https://kbsecret.github.io/man/kbsecret.1.html)
15
15
  * [API documentation](http://www.rubydoc.info/gems/kbsecret/)
16
- * [Customizing your installation](https://kbsecret.github.io/customization)
16
+ * [Customizing your installation](https://kbsecret.github.io/#/customize/)
17
17
 
18
18
  ## Hacking on KBSecret
19
19
 
@@ -22,7 +22,7 @@ Want to hack on KBSecret? Here's how you can get started:
22
22
  ```bash
23
23
  $ git clone git@github.com:kbsecret/kbsecret.git && cd kbsecret
24
24
  $ bundle install --path vendor/bundle
25
- $ RUBYLIB=./lib PATH=./bin:${PATH} bundle exec ./bin/kbsecret help
25
+ $ bundle exec ./bin/kbsecret help
26
26
  ```
27
27
 
28
28
  ### Manual Pages
data/bin/kbsecret CHANGED
@@ -6,12 +6,6 @@ require "fileutils"
6
6
 
7
7
  BUILTIN_CMDS = %w[help version commands types].freeze
8
8
 
9
- INTERNAL_CMD_PATH = File.join(File.dirname(__dir__), "lib/kbsecret/cli")
10
-
11
- INTERNAL_PATHS = Dir[File.join(INTERNAL_CMD_PATH, "*")].freeze
12
-
13
- INTERNAL_CMDS = INTERNAL_PATHS.map { |p| File.basename(p).sub!("kbsecret-", "") }
14
-
15
9
  EXT_PATHS = ENV["PATH"].split(File::PATH_SEPARATOR).map do |path|
16
10
  Dir[File.join(path, "kbsecret-*")]
17
11
  end.flatten.uniq.freeze
@@ -27,7 +21,7 @@ ALIASES = Hash.new { |_, k| k }.update(
27
21
  "-v" => "version"
28
22
  ).freeze
29
23
 
30
- ALL_CMDS = (ALIASES.keys + BUILTIN_CMDS + INTERNAL_CMDS + EXT_CMDS).freeze
24
+ ALL_CMDS = (ALIASES.keys + BUILTIN_CMDS + KBSecret::CLI::Command.command_names + EXT_CMDS).freeze
31
25
 
32
26
  KBSECRET_HELP = <<~KBSECRET_HELP
33
27
  Usage:
@@ -50,7 +44,7 @@ def migrate_configs
50
44
  end
51
45
 
52
46
  def internal?(cmd)
53
- INTERNAL_CMDS.include?(cmd)
47
+ KBSecret::CLI::Command.command_names.include?(cmd)
54
48
  end
55
49
 
56
50
  def external?(cmd)
@@ -72,11 +66,7 @@ end
72
66
  def expand(cmd)
73
67
  return cmd if alias?(cmd) || builtin?(cmd)
74
68
 
75
- if internal? cmd
76
- File.join(INTERNAL_CMD_PATH, "kbsecret-#{cmd}")
77
- else
78
- "kbsecret-#{cmd}"
79
- end
69
+ "kbsecret-#{cmd}"
80
70
  end
81
71
 
82
72
  def help(*args)
@@ -148,7 +138,9 @@ args = KBSecret::Config.command_args(command) + ARGV
148
138
 
149
139
  if builtin?(command)
150
140
  send command, *args
151
- elsif external?(command) || internal?(command)
141
+ elsif internal?(command)
142
+ KBSecret::CLI::Command.run! command, *args
143
+ elsif external?(command)
152
144
  exec expand(command), *args
153
145
  else
154
146
  KBSecret::CLI.die "Unknown command: '#{command}'."
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KBSecret
4
+ class CLI
5
+ module Command
6
+ # Represents an abstract {KBSecret} command that can be subclassed to produce a more
7
+ # useful command. {KBSecret::CLI::Command::List} is an example of this.
8
+ # @abstract
9
+ class Abstract
10
+ # @return [CLI] the CLI state corresponding to the command
11
+ attr_reader :cli
12
+
13
+ # @return [String] the command's CLI-friendly name
14
+ # @example
15
+ # KBSecret::CLI::Command::StashFile # => "stash-file"
16
+ def self.command_name
17
+ name.split("::")
18
+ .last
19
+ .gsub(/([^A-Z])([A-Z]+)/, '\1-\2')
20
+ .downcase
21
+ end
22
+
23
+ # @param argv [String] the arguments to call the command with
24
+ def initialize(argv)
25
+ @cli = CLI.create(argv) { |_o| nil }
26
+ @cli.guard do
27
+ yield @cli if block_given?
28
+ end
29
+ end
30
+
31
+ # Sets up any state used by the command. Implemented by children.
32
+ # @abstract
33
+ def setup!
34
+ nil
35
+ end
36
+
37
+ # Runs any validation checks required by the command. Implemented by children.
38
+ # @abstract
39
+ def validate!
40
+ nil
41
+ end
42
+
43
+ # Runs the command. Implemented by children.
44
+ # @abstract
45
+ def run!
46
+ nil
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KBSecret
4
+ class CLI
5
+ module Command
6
+ # The implementation of `kbsecret conf`.
7
+ class Conf < Abstract
8
+ def initialize(argv)
9
+ super(argv) do |cli|
10
+ cli.slop do |o|
11
+ o.banner = <<~HELP
12
+ Usage: kbsecret conf [options]
13
+ HELP
14
+
15
+ o.bool "-c", "--commands", "open the commands config (commands.ini)"
16
+ o.bool "-d", "--directory", "print the path to the config directory"
17
+ o.bool "-r", "--record-directory", "print the path to the custom record directory"
18
+ end
19
+ end
20
+ end
21
+
22
+ # @see Command::Abstract#validate!
23
+ def validate!
24
+ cli.die "Missing $EDITOR." unless ENV["EDITOR"]
25
+ end
26
+
27
+ # @see Command::Abstract#run!
28
+ def run!
29
+ if cli.opts.commands?
30
+ exec "#{ENV["EDITOR"]} #{Config::COMMAND_CONFIG_FILE}"
31
+ elsif cli.opts.directory?
32
+ puts Config::CONFIG_DIR
33
+ elsif cli.opts.record_directory?
34
+ puts Config::CUSTOM_TYPES_DIR
35
+ else
36
+ exec "#{ENV["EDITOR"]} #{Config::CONFIG_FILE}"
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KBSecret
4
+ class CLI
5
+ module Command
6
+ # The implementation of `kbsecret cp`.
7
+ class Cp < Abstract
8
+ def initialize(argv)
9
+ super(argv) do |cli|
10
+ cli.slop do |o|
11
+ o.banner = <<~HELP
12
+ Usage:
13
+ kbsecret cp [options] <source> <destination> <record [record ...]>
14
+ HELP
15
+
16
+ o.bool "-f", "--force", "force copying (ignore overwrites)"
17
+ o.bool "-m", "--move", "delete the record after copying"
18
+ end
19
+
20
+ cli.dreck do
21
+ string :src_sess
22
+ string :dst_sess
23
+ list :string, :labels
24
+ end
25
+ end
26
+ end
27
+
28
+ # @see Command::Abstract#run!
29
+ def run!
30
+ cli.guard do
31
+ src_sess = Session[cli.args[:src_sess]]
32
+ dst_sess = Session[cli.args[:dst_sess]]
33
+
34
+ selected_records = src_sess.records.select { |r| cli.args[:labels].include?(r.label) }
35
+ cli.die "No such record(s)." if selected_records.empty?
36
+
37
+ overlaps = dst_sess.record_labels & selected_records.map(&:label)
38
+
39
+ # the code below actually handles the overwriting if necessary, but we fail early here
40
+ # for friendliness and to avoid half-copying the selected records
41
+ unless overlaps.empty? || cli.opts.force?
42
+ cli.die "Refusing to overwrite existing record(s) without --force."
43
+ end
44
+
45
+ selected_records.each do |record|
46
+ dst_sess.import_record(record, overwrite: cli.opts.force?)
47
+ src_sess.delete_record(label) if cli.opts.move?
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KBSecret
4
+ class CLI
5
+ module Command
6
+ # The implementation of `kbsecret dump-fields`.
7
+ class DumpFields < Abstract
8
+ def initialize(argv)
9
+ super(argv) do |cli|
10
+ cli.slop do |o|
11
+ o.banner = <<~HELP
12
+ Usage:
13
+ kbsecret dump-fields [options] <record>
14
+ HELP
15
+
16
+ o.string "-s", "--session", "the session to search in", default: :default
17
+ o.bool "-x", "--terse", "output in field<sep>value format"
18
+ o.string "-i", "--ifs", "separate terse pairs with this string", default: CLI.ifs
19
+ end
20
+
21
+ cli.dreck do
22
+ string :label
23
+ end
24
+
25
+ cli.ensure_session!
26
+ end
27
+ end
28
+
29
+ # @see Command::Abstract#setup!
30
+ def setup!
31
+ @record = cli.session[cli.args[:label]]
32
+ end
33
+
34
+ # @see Command::Abstract#validate!
35
+ def validate!
36
+ cli.die "No such record." unless @record
37
+ end
38
+
39
+ # @see Command::Abstract#run!
40
+ def run!
41
+ field_values = @record.data_fields.map { |f| @record.send f }
42
+ field_pairs = @record.data_fields.zip(field_values)
43
+
44
+ if cli.opts.terse?
45
+ puts field_pairs.map { |f, v| "#{f}#{cli.opts[:ifs]}#{v}" }.join "\n"
46
+ else
47
+ puts field_pairs.map { |f, v| "#{f}: #{v}" }.join "\n"
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KBSecret
4
+ class CLI
5
+ module Command
6
+ # The implementation of `kbsecret env`.
7
+ class Env < Abstract
8
+ def initialize(argv)
9
+ super(argv) do |cli|
10
+ cli.slop do |o|
11
+ o.banner = <<~HELP
12
+ Usage:
13
+ kbsecret env [options] <record [record ...]>
14
+ HELP
15
+
16
+ o.string "-s", "--session", "the session to search in", default: :default
17
+ o.bool "-a", "--all", "retrieve all environment records, not just listed ones"
18
+ o.bool "-v", "--value-only", "print only the environment value, not the key"
19
+ o.bool "-n", "--no-export", "print only VAR=val keypairs without `export`"
20
+ o.bool "-u", "--unescape-plus", "escape any pluses in the variable and/or value"
21
+ end
22
+
23
+ unless cli.opts.all?
24
+ cli.dreck do
25
+ list :string, :labels
26
+ end
27
+ end
28
+
29
+ cli.ensure_session!
30
+ end
31
+ end
32
+
33
+ # @see Command::Abstract#setup!
34
+ def setup!
35
+ @records = if cli.opts.all?
36
+ cli.session.records :environment
37
+ else
38
+ cli.session.records(:environment).select do |record|
39
+ cli.args[:labels].include? record.label
40
+ end
41
+ end
42
+ end
43
+
44
+ # @see Command::Abstract#validate!
45
+ def validate!
46
+ cli.die "No such record(s)." if @records.empty?
47
+ end
48
+
49
+ # @see Command::Abstract#run!
50
+ def run!
51
+ env_output = if cli.opts.no_export?
52
+ @records.map(&:to_assignment).join(" ")
53
+ elsif cli.opts.value_only?
54
+ @records.map(&:value).join("\n")
55
+ else
56
+ @records.map(&:to_export).join("\n")
57
+ end
58
+
59
+ env_output.gsub!("\\+", "+") if cli.opts.unescape_plus?
60
+
61
+ puts env_output
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KBSecret
4
+ class CLI
5
+ module Command
6
+ # The implementation of `kbsecret generator`.
7
+ class Generator < Abstract
8
+ # The list of subcommands supported by `kbsecret generator`.
9
+ SUBCOMMANDS = %w[new rm].freeze
10
+
11
+ def initialize(argv)
12
+ super(argv) do |cli|
13
+ cli.slop cmds: SUBCOMMANDS do |o|
14
+ o.banner = <<~HELP
15
+ Usage:
16
+ kbsecret generator [options] <new|rm> <generator>
17
+ HELP
18
+
19
+ o.string "-F", "--format", "the format of the secrets generated", default: "hex"
20
+ o.integer "-l", "--length", "the length, in bytes, of the secrets generated",
21
+ default: 16
22
+ o.bool "-f", "--force", "force generator creation (ignore overwrite)"
23
+ end
24
+
25
+ cli.dreck do
26
+ string :command
27
+ string :generator
28
+ end
29
+
30
+ cli.ensure_generator! :argument if cli.args[:command] == "rm"
31
+ end
32
+ end
33
+
34
+ # @see Command::Abstract#setup!
35
+ def setup!
36
+ @subcmd = cli.args[:command]
37
+ end
38
+
39
+ # @see Command::Abstract#validate!
40
+ def validate!
41
+ cli.die "Unknown subcommand: #{@subcmd}." unless SUBCOMMANDS.include?(@subcmd)
42
+ end
43
+
44
+ # @see Command::Abstract#run!
45
+ def run!
46
+ case @subcmd
47
+ when "new"
48
+ if Config.generator?(cli.args[:generator]) && !cli.opts.force?
49
+ cli.die "Refusing to overwrite an existing generator without --force."
50
+ end
51
+
52
+ Config.configure_generator(cli.args[:generator],
53
+ format: cli.opts[:format],
54
+ length: cli.opts[:length])
55
+ when "rm"
56
+ Config.deconfigure_generator(cli.args[:generator])
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KBSecret
4
+ class CLI
5
+ module Command
6
+ # The implementation of `kbsecret generators`.
7
+ class Generators < Abstract
8
+ def initialize(argv)
9
+ super(argv) do |cli|
10
+ cli.slop do |o|
11
+ o.banner = <<~HELP
12
+ Usage:
13
+ kbsecret generators [options]
14
+ HELP
15
+
16
+ o.bool "-a", "--show-all", "show each generator in depth (i.e. metadata)"
17
+ end
18
+ end
19
+ end
20
+
21
+ # @see Command::Abstract#run!
22
+ def run!
23
+ Config[:generators].each do |label, config|
24
+ puts label
25
+
26
+ next unless cli.opts.show_all?
27
+
28
+ puts <<~DETAIL
29
+ \tFormat: #{config[:format]}
30
+ \tLength: #{config[:length]}
31
+ DETAIL
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KBSecret
4
+ class CLI
5
+ module Command
6
+ # The implementation of `kbsecret list`.
7
+ class List < Abstract
8
+ def initialize(argv)
9
+ super(argv) do |cli|
10
+ cli.slop do |o|
11
+ o.banner = <<~HELP
12
+ Usage:
13
+ kbsecret list [options]
14
+ HELP
15
+
16
+ o.string "-s", "--session", "the session to list from", default: :default
17
+ o.string "-t", "--type", "the type of secrets to list", default: nil
18
+ o.bool "-a", "--show-all", "show everything in each secret (i.e. metadata)"
19
+ end
20
+
21
+ cli.ensure_type! if cli.opts[:type]
22
+ cli.ensure_session!
23
+ end
24
+ end
25
+
26
+ # @see Command::Abstract#setup!
27
+ def setup!
28
+ @records = cli.session.records cli.opts[:type]
29
+ end
30
+
31
+ # @see Command::Abstract#setup!
32
+ def run!
33
+ @records.each do |record|
34
+ puts record.label
35
+
36
+ next unless cli.opts.show_all?
37
+
38
+ puts <<~DETAIL
39
+ \tType: #{record.type}
40
+ \tLast changed: #{Time.at(record.timestamp)}
41
+ \tRaw data: #{record.data}
42
+ DETAIL
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KBSecret
4
+ class CLI
5
+ module Command
6
+ # The implementation of `kbsecret login`.
7
+ class Login < Abstract
8
+ def initialize(argv)
9
+ super(argv) do |cli|
10
+ cli.slop do |o|
11
+ o.banner = <<~HELP
12
+ Usage:
13
+ kbsecret login [options] <record [record ...]>
14
+ HELP
15
+
16
+ o.string "-s", "--session", "the session to search in", default: :default
17
+ o.bool "-a", "--all", "retrieve all login records, not just listed ones"
18
+ o.bool "-x", "--terse", "output in label<sep>username<sep>password format"
19
+ o.string "-i", "--ifs", "separate terse fields with this string", default: CLI.ifs
20
+ end
21
+
22
+ unless cli.opts.all?
23
+ cli.dreck do
24
+ list :string, :labels
25
+ end
26
+ end
27
+
28
+ cli.ensure_session!
29
+ end
30
+ end
31
+
32
+ # @see Command::Abstract#setup!
33
+ def setup!
34
+ @records = if cli.opts.all?
35
+ cli.session.records :login
36
+ else
37
+ cli.session.records(:login).select do |record|
38
+ cli.args[:labels].include? record.label
39
+ end
40
+ end
41
+ end
42
+
43
+ # @see Command::Abstract#validate!
44
+ def validate!
45
+ cli.die "No such record(s)." if @records.empty?
46
+ end
47
+
48
+ # @see Command::Abstract#run!
49
+ def run!
50
+ @records.each do |record|
51
+ if cli.opts.terse?
52
+ fields = %i[label username password].map { |m| record.send(m) }
53
+ puts fields.join(cli.opts[:ifs])
54
+ else
55
+ puts <<~DETAIL
56
+ Label: #{record.label}
57
+ \tUsername: #{record.username}
58
+ \tPassword: #{record.password}
59
+ DETAIL
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,82 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "abbrev"
5
+ require "tty-prompt"
6
+
7
+ module KBSecret
8
+ class CLI
9
+ module Command
10
+ # The implementation of `kbsecret new`.
11
+ class New < Abstract
12
+ def initialize(argv)
13
+ super(argv) do |cli|
14
+ cli.slop do |o|
15
+ o.banner = <<~HELP
16
+ Usage:
17
+ kbsecret new [options] <type> <label>
18
+ HELP
19
+
20
+ o.string "-s", "--session", "the session to contain the record", default: :default
21
+ o.bool "-f", "--force", "force creation (ignore overwrites, etc.)"
22
+ o.bool "-e", "--echo", "echo input to tty (only affects interactive input)"
23
+ o.bool "-G", "--generate", "generate secret fields (interactive only)"
24
+ o.string "-g", "--generator", "the generator to use for secret fields",
25
+ default: :default
26
+ o.bool "-x", "--terse", "read fields from input in a terse format"
27
+ o.string "-i", "--ifs", "separate terse fields with this string", default: CLI.ifs
28
+ end
29
+
30
+ cli.dreck do
31
+ string :type
32
+ string :label
33
+ end
34
+
35
+ cli.ensure_generator!
36
+ cli.ensure_type! :argument
37
+ cli.ensure_session!
38
+ end
39
+ end
40
+
41
+ # @see Command::Abstract#setup!
42
+ def setup!
43
+ @label = cli.args[:label]
44
+ @type = CLI::TYPE_ALIASES[cli.args[:type]]
45
+ end
46
+
47
+ # @see Command::Abstract#validate!
48
+ def validate!
49
+ # the code below actually handles the overwriting if necessary, but we fail early here
50
+ # for friendliness and to avoid prompting the user for input unnecessarily
51
+ if cli.session.record?(@label) && !cli.opts.force?
52
+ cli.die "Refusing to overwrite a record without --force."
53
+ end
54
+ end
55
+
56
+ # @see Command::Abstract#run!
57
+ def run!
58
+ generator = KBSecret::Generator.new(cli.opts[:generator]) if cli.opts.generate?
59
+
60
+ fields = if cli.opts.terse?
61
+ STDIN.read.chomp.split cli.opts[:ifs]
62
+ else
63
+ prompt = TTY::Prompt.new
64
+ klass = Record.class_for(@type)
65
+ klass.external_fields.map do |field|
66
+ if cli.opts.generate? && klass.sensitive?(field)
67
+ generator.secret
68
+ else
69
+ prompt.ask "#{field.capitalize}?",
70
+ echo: !klass.sensitive?(field) || cli.opts.echo?
71
+ end
72
+ end
73
+ end
74
+
75
+ cli.guard do
76
+ cli.session.add_record @type, @label, *fields, overwrite: cli.opts.force?
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end