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.
- checksums.yaml +4 -4
- data/README.md +5 -5
- data/bin/kbsecret +6 -14
- data/lib/kbsecret/cli/command/abstract.rb +51 -0
- data/lib/kbsecret/cli/command/conf.rb +42 -0
- data/lib/kbsecret/cli/command/cp.rb +54 -0
- data/lib/kbsecret/cli/command/dump_fields.rb +53 -0
- data/lib/kbsecret/cli/command/env.rb +66 -0
- data/lib/kbsecret/cli/command/generator.rb +62 -0
- data/lib/kbsecret/cli/command/generators.rb +37 -0
- data/lib/kbsecret/cli/command/list.rb +48 -0
- data/lib/kbsecret/cli/command/login.rb +66 -0
- data/lib/kbsecret/cli/command/new.rb +82 -0
- data/lib/kbsecret/cli/command/pass.rb +51 -0
- data/lib/kbsecret/cli/command/raw_edit.rb +46 -0
- data/lib/kbsecret/cli/command/rm.rb +58 -0
- data/lib/kbsecret/cli/command/session.rb +128 -0
- data/lib/kbsecret/cli/command/sessions.rb +47 -0
- data/lib/kbsecret/cli/command/stash_file.rb +62 -0
- data/lib/kbsecret/cli/command/todo.rb +78 -0
- data/lib/kbsecret/cli/command.rb +45 -0
- data/lib/kbsecret/cli.rb +6 -4
- data/lib/kbsecret/config.rb +4 -3
- data/lib/kbsecret/record/abstract.rb +2 -2
- data/lib/kbsecret/record.rb +9 -7
- data/lib/kbsecret/version.rb +1 -1
- metadata +22 -20
- data/lib/kbsecret/cli/kbsecret-conf +0 -31
- data/lib/kbsecret/cli/kbsecret-cp +0 -44
- data/lib/kbsecret/cli/kbsecret-dump-fields +0 -39
- data/lib/kbsecret/cli/kbsecret-env +0 -53
- data/lib/kbsecret/cli/kbsecret-generator +0 -42
- data/lib/kbsecret/cli/kbsecret-generators +0 -28
- data/lib/kbsecret/cli/kbsecret-list +0 -36
- data/lib/kbsecret/cli/kbsecret-login +0 -53
- data/lib/kbsecret/cli/kbsecret-new +0 -68
- data/lib/kbsecret/cli/kbsecret-pass +0 -37
- data/lib/kbsecret/cli/kbsecret-raw-edit +0 -31
- data/lib/kbsecret/cli/kbsecret-rm +0 -44
- data/lib/kbsecret/cli/kbsecret-session +0 -105
- data/lib/kbsecret/cli/kbsecret-sessions +0 -38
- data/lib/kbsecret/cli/kbsecret-stash-file +0 -48
- data/lib/kbsecret/cli/kbsecret-todo +0 -47
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5a564bac0dc6d8ba790b99238519dd12c2e1efea7fccfbf832a69e9861cb98f7
|
4
|
+
data.tar.gz: 502c1bb72096256a854631bf375a30f917f04fd636b28e186ce5b5294f8830e5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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/
|
13
|
-
* [Quick start guide](https://kbsecret.github.io/
|
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/
|
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
|
-
$
|
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 +
|
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
|
-
|
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
|
-
|
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
|
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
|