kbsecret 0.0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 9587292e2be80b4a53d26f4bdda06e2a94d1b7be
4
+ data.tar.gz: 5dd01f1c1819f0f17537487ff73e621e27193938
5
+ SHA512:
6
+ metadata.gz: 4227a95d277ed064a5cd1b4dd3add4dedcabb97d041c66c5dffec753a87ab0de73684582a4d18e34bd33c192912d54dc173527516daa10a172dbd19d55e73574
7
+ data.tar.gz: b14e1d1524a71d70e85185c7c61c43a3791923c5698273b68398b6dcf1d072a682a3f7bfb695666d1cd25819812d740e5cf150c71142571d741dd5e426091845
data/.yardopts ADDED
@@ -0,0 +1 @@
1
+ --no-private --markup-provider=redcarpet --markup=markdown - *.md LICENSE
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 William Woodruff <william @ tuffbizz.com>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,66 @@
1
+ kbsecret
2
+ ========
3
+
4
+ kbsecret is a combined library/utility that provides a secret management
5
+ interface for [KBFS](https://keybase.io/docs/kbfs) and
6
+ [Keybase](https://keybase.io/).
7
+
8
+ ### Benefits over current offerings
9
+
10
+ * Easy password and environment sharing across multiple users.
11
+ - `kbsecret -s dev-team login github` prints the dev team's GitHub login.
12
+ * No PGP/SSH key setup necessary - you only need a Keybase account.
13
+ - No more worrying about losing your key.
14
+ * Transparent access - KBFS provides a VFS layer over all reads/writes.
15
+ - All records are stored encrypted on KBFS.
16
+
17
+ ### Installation
18
+
19
+ kbsecret is available via RubyGems:
20
+
21
+ ```bash
22
+ $ gem install kbsecret
23
+ ```
24
+
25
+ For hacking:
26
+
27
+ ```bash
28
+ $ git clone git@github.com:woodruffw/kbsecret.git && cd kbsecret
29
+ $ RUBYLIB=./lib PATH=${PATH}:./bin ./bin/kbsecret help
30
+ ```
31
+
32
+ ### Usage
33
+
34
+ ```bash
35
+ # create a new login record under the default session
36
+ $ kbsecret new login gmail "foo@example.com" "barbazquux"
37
+
38
+ # list all records under the default session
39
+ $ kbsecret list
40
+ gmail
41
+
42
+ # show the requested login record
43
+ $ kbsecret login gmail
44
+ Label: gmail
45
+ Username: foo@example.com
46
+ Password: barbazquux
47
+
48
+ # create a new session between 3 keybase users (foo, bar, and baz)
49
+ $ kbsecret new-session -l dev-team -u foo,bar,baz
50
+
51
+ # list available sessions
52
+ $ kbsecret sessions
53
+ default
54
+ dev-team
55
+
56
+ # add an environment record to the dev-team session
57
+ $ kbsecret new environment API_KEY 0xBADBEEF -s dev-team
58
+
59
+ # list all records under the dev-team session
60
+ $ kbsecret list -s dev-team
61
+ API_KEY
62
+
63
+ # get all environment records in dev-team in an easy-to-source format
64
+ $ kbsecret env -s dev-team --all
65
+ export API_KEY='0xBADBEEF'
66
+ ```
data/bin/kbsecret ADDED
@@ -0,0 +1,108 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "kbsecret"
4
+
5
+ BUILTIN_CMDS = [
6
+ "help",
7
+ "version",
8
+ ].freeze
9
+
10
+ EXT_PATHS = ENV["PATH"].split(File::PATH_SEPARATOR).map do |path|
11
+ Dir[File.join(path, "kbsecret-*")]
12
+ end.flatten.freeze
13
+
14
+ EXT_CMDS = EXT_PATHS.map do |c|
15
+ File.basename(c, File.extname(c)).sub!("kbsecret-", "")
16
+ end.freeze
17
+
18
+ ALIASES = Hash.new { |_, k| k }.update({
19
+ "--help" => "help",
20
+ "-h" => "help",
21
+ "l" => "login",
22
+ "pw" => "login",
23
+ "del" => "rm",
24
+ "create" => "new",
25
+ }).freeze
26
+
27
+ ALL_CMDS = (ALIASES.keys + BUILTIN_CMDS + EXT_CMDS).freeze
28
+
29
+ def external?(cmd)
30
+ EXT_CMDS.include?(cmd)
31
+ end
32
+
33
+ def builtin?(cmd)
34
+ BUILTIN_CMDS.include?(cmd)
35
+ end
36
+
37
+ def alias?(cmd)
38
+ ALIASES.keys.include?(cmd)
39
+ end
40
+
41
+ def normalize(cmd)
42
+ ALIASES[cmd]
43
+ end
44
+
45
+ def expand(cmd)
46
+ return cmd if alias?(cmd) || builtin?(cmd)
47
+ "kbsecret-#{cmd}"
48
+ end
49
+
50
+ def help(*args)
51
+ command = normalize args.shift
52
+ if command.nil?
53
+ puts <<~EOS
54
+ Usage:
55
+ kbsecret <command> <args ...>
56
+
57
+ Available commands:
58
+ #{ALL_CMDS.join(", ")}
59
+
60
+ More more information about a particular command, try:
61
+ kbsecret help <command>
62
+ EOS
63
+ else
64
+ if builtin? command
65
+ send "#{command}_help"
66
+ else
67
+ system expand(command), "--help"
68
+ end
69
+ end
70
+ end
71
+
72
+ # lol
73
+ def help_help
74
+ puts <<~EOS
75
+ Prints brief help for the given command.
76
+
77
+ Usage:
78
+ kbsecret help <command>
79
+
80
+ For a list of all commands, see:
81
+ kbsecret help
82
+ EOS
83
+ end
84
+
85
+ def version(*args)
86
+ puts <<~EOS
87
+ kbsecret version #{KBSecret::VERSION}.
88
+ EOS
89
+ end
90
+
91
+ def version_help
92
+ puts <<~EOS
93
+ Prints kbsecret's version.
94
+
95
+ Usage:
96
+ kbsecret version
97
+ EOS
98
+ end
99
+
100
+ command = normalize(ARGV.shift || "help")
101
+
102
+ if builtin? command
103
+ send command, *ARGV
104
+ elsif external? command
105
+ system expand(command), *ARGV
106
+ else
107
+ STDERR.puts "Fatal: Unknown command: '#{command}'."
108
+ end
data/bin/kbsecret-env ADDED
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "kbsecret"
4
+ require "slop"
5
+
6
+ opts = Slop.parse suppress_errors: true do |o|
7
+ o.banner = <<~EOS
8
+ Retrieve environment records in a source-able format.
9
+
10
+ Usage:
11
+ kbsecret env [--session <name>] [--all] <label1 label2 ...>
12
+
13
+ Examples:
14
+ kbsecret env --all
15
+ kbsecret env staging beta
16
+ EOS
17
+
18
+ o.string "-s", "--session", "the session name", default: :default
19
+ o.bool "-a", "--all", "retrieve all environment records, not just listed ones"
20
+
21
+ o.on "-h", "--help" do
22
+ puts o
23
+ exit
24
+ end
25
+ end
26
+
27
+ sess_name = opts[:session]
28
+
29
+ unless KBSecret::Config.session? sess_name
30
+ abort "Fatal: Unknown session: '#{sess_name}'."
31
+ end
32
+
33
+ session = KBSecret::Session.new label: sess_name
34
+
35
+ env_records = session.records.select { |r| r.type == "environment" }
36
+
37
+ if opts.all?
38
+ selected_records = env_records
39
+ else
40
+ selected_labels = opts.args.uniq
41
+
42
+ # instead of complaining about nonexistent records, just ignore them
43
+ selected_records = selected_labels.map do |l|
44
+ env_records.find { |r| r.label == l }
45
+ end.compact
46
+ end
47
+
48
+ env_records.each do |record|
49
+ puts record.to_export
50
+ end
data/bin/kbsecret-list ADDED
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "kbsecret"
4
+ require "slop"
5
+
6
+ opts = Slop.parse suppress_errors: true do |o|
7
+ o.banner = <<~EOS
8
+ List all secrets known to the specified session (or the default session).
9
+
10
+ Usage:
11
+ kbsecret list [--session <name>] [--show-all]
12
+ EOS
13
+
14
+ o.string "-s", "--session", "the session name", default: :default
15
+ o.bool "-a", "--show-all", "show everything in each secret (i.e. metadata)"
16
+
17
+ o.on "-h", "--help" do
18
+ puts o
19
+ exit
20
+ end
21
+ end
22
+
23
+ sess_name = opts[:session]
24
+
25
+ unless KBSecret::Config.session? sess_name
26
+ abort "Fatal: Unknown session: '#{sess_name}'."
27
+ end
28
+
29
+ session = KBSecret::Session.new label: sess_name
30
+
31
+ session.records.each do |record|
32
+ line = "#{record.label}\n"
33
+ line << <<~EOS if opts.show_all?
34
+ \tType: #{record.type}
35
+ \tLast changed: #{Time.at(record.timestamp)}
36
+ \tRaw data: #{record.data}
37
+ EOS
38
+
39
+ puts line
40
+ end
41
+
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "kbsecret"
4
+ require "slop"
5
+
6
+ opts = Slop.parse suppress_errors: true do |o|
7
+ o.banner = <<~EOS
8
+ Retrieve login records.
9
+
10
+ Usage:
11
+ kbsecret env [--session <name>] <label1 label2 ...>
12
+
13
+ Examples:
14
+ kbsecret login gmail
15
+ kbsecret login gmail netflix
16
+ EOS
17
+
18
+ o.bool "-a", "--all", "retrieve all login records, not just listed ones"
19
+ o.string "-s", "--session", "the session name", default: :default
20
+
21
+ o.on "-h", "--help" do
22
+ puts o
23
+ exit
24
+ end
25
+ end
26
+
27
+ sess_name = opts[:session]
28
+
29
+ unless KBSecret::Config.session? sess_name
30
+ abort "Fatal: Unknown session: '#{sess_name}'."
31
+ end
32
+
33
+ session = KBSecret::Session.new label: sess_name
34
+
35
+ login_records = session.records.select { |r| r.type == "login" }
36
+
37
+ if opts.all?
38
+ selected_records = login_records
39
+ else
40
+ selected_labels = opts.args.uniq
41
+
42
+ # instead of complaining about nonexistent records, just ignore them
43
+ selected_records = selected_labels.map do |l|
44
+ login_records.find { |r| r.label == l }
45
+ end.compact
46
+ end
47
+
48
+ selected_records.each do |record|
49
+ puts <<~EOS
50
+ Label: #{record.label}
51
+ \tUsername: #{record.username}
52
+ \tPassword: #{record.password}
53
+ EOS
54
+ end
data/bin/kbsecret-new ADDED
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "kbsecret"
4
+ require "slop"
5
+
6
+ opts = Slop.parse suppress_errors: true do |o|
7
+ o.banner = <<~EOS
8
+ Create a new secret record.
9
+
10
+ Usage:
11
+ kbsecret new [--session <name>] [--force] <type> <label> <args ...>
12
+
13
+ Examples:
14
+ kbsecret new login gmail "foo@bar.com" "mytopsecretpassword"
15
+ kbsecret new environment API_KEY "abcdef-0123456789"
16
+ EOS
17
+
18
+ o.string "-s", "--session", "the session name", default: :default
19
+ o.bool "-f", "--force", "force creation (ignore overwrites, etc.)"
20
+
21
+ o.on "-h", "--help" do
22
+ puts o
23
+ exit
24
+ end
25
+ end
26
+
27
+ sess_name = opts[:session]
28
+
29
+ unless KBSecret::Config.session? sess_name
30
+ abort "Fatal: Unknown session: '#{sess_name}'."
31
+ end
32
+
33
+ abort "Fatal: Not enough arguments." if opts.args.size < 2
34
+
35
+ session = KBSecret::Session.new label: sess_name
36
+ type, label = opts.args.shift 2
37
+
38
+ if session.record?(label) && !opts.force?
39
+ abort "Fatal: Refusing to overwrite an existing record without --force."
40
+ end
41
+
42
+ unless KBSecret::Record.type?(type)
43
+ abort <<~EOS
44
+ Fatal: Unknown record type: '#{type}'.
45
+ Known types are: #{KBSecret::Record.record_types.join(", ")}.
46
+ EOS
47
+ end
48
+
49
+ begin
50
+ session.add_record(type, label, *opts.args)
51
+ rescue => e
52
+ abort "Fatal: #{e.to_s}."
53
+ end
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "keybase"
4
+ require "kbsecret"
5
+ require "slop"
6
+
7
+ opts = Slop.parse suppress_errors: true do |o|
8
+ o.banner = <<~EOS
9
+ Create a new session.
10
+
11
+ Usage:
12
+ kbsecret new-session --label <label> --users <user1,...> --root <dir>
13
+
14
+ Example:
15
+ kbsecret new-session -l dev -u me,otherperson -r devsecrets
16
+ EOS
17
+
18
+ o.string "-l", "--label", "the session label", default: :default
19
+ o.array "-u", "--users", "the keybase users", default: [Keybase.current_user]
20
+ o.string "-r", "--root", "the secret root directory", default: "kbsecret"
21
+ o.bool "-f", "--force", "force creation (ignore overwrites, etc.)"
22
+
23
+ o.on "-h", "--help" do
24
+ puts o
25
+ exit
26
+ end
27
+ end
28
+
29
+ session_label = opts[:label]
30
+
31
+ if KBSecret::Config.session?(session_label) && !opts.force?
32
+ abort "Fatal: Refusing to overwrite an existing session without --force."
33
+ end
34
+
35
+ session_hash = {
36
+ users: opts[:users],
37
+ root: opts[:root],
38
+ }
39
+
40
+ KBSecret::Config.add_session(session_label, session_hash)
data/bin/kbsecret-rm ADDED
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "kbsecret"
4
+ require "slop"
5
+ require "tty-prompt"
6
+
7
+ $VERBOSE = nil # tty-prompt blasts us with irrelevant warnings on 2.4
8
+
9
+ opts = Slop.parse suppress_errors: true do |o|
10
+ o.banner = <<~EOS
11
+ Delete a record.
12
+
13
+ Usage:
14
+ kbsecret rm [--session <name>] <label>
15
+ EOS
16
+
17
+ o.string "-s", "--session", "the session name", default: :default
18
+ o.bool "-i", "--interactive", "ask for confirmation before deleting"
19
+
20
+ o.on "-h", "--help" do
21
+ puts o
22
+ exit
23
+ end
24
+ end
25
+
26
+ sess_name = opts[:session]
27
+
28
+ unless KBSecret::Config.session? sess_name
29
+ abort "Fatal: Unknown session: '#{sess_name}'."
30
+ end
31
+
32
+ session = KBSecret::Session.new label: sess_name
33
+
34
+ label = opts.args.shift
35
+
36
+ abort "Fatal: I need the label of a record to delete." unless label
37
+
38
+ tty = TTY::Prompt.new
39
+ confirm = true
40
+
41
+ if opts.interactive?
42
+ confirm = tty.yes?("Delete '#{label}' from the #{session.label} session?")
43
+ end
44
+
45
+ session.delete_record(label) if confirm
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "kbsecret"
4
+ require "slop"
5
+
6
+ opts = Slop.parse suppress_errors: true do |o|
7
+ o.banner = <<~EOS
8
+ List all available sessions.
9
+ The sessions listed can be passed to other commands via the -s flag.
10
+
11
+ Usage:
12
+ kbsecret sessions [--show-all]
13
+ EOS
14
+
15
+ o.bool "-a", "--show-all", "show each session in depth (i.e. metadata)"
16
+
17
+ o.on "-h", "--help" do
18
+ puts o
19
+ exit
20
+ end
21
+ end
22
+
23
+ KBSecret::Config.session_names.each do |sess_name|
24
+ session_hash = KBSecret::Config.session(sess_name)
25
+ session = KBSecret::Session.new label: sess_name
26
+ line = "#{sess_name}\n"
27
+ line << <<~EOS if opts.show_all?
28
+ \tUsers: #{session_hash[:users].join(", ")}
29
+ \tSecrets root: #{session_hash[:root]} (#{session.directory})
30
+ EOS
31
+
32
+ puts line
33
+ end
data/lib/kbsecret.rb ADDED
@@ -0,0 +1,13 @@
1
+ require "keybase"
2
+
3
+ require_relative "kbsecret/config"
4
+ require_relative "kbsecret/exceptions"
5
+ require_relative "kbsecret/record"
6
+ require_relative "kbsecret/session"
7
+
8
+ module KBSecret
9
+ VERSION = "0.0.1".freeze
10
+
11
+ raise Keybase::KeybaseNotRunningError unless Keybase.running?
12
+ raise Keybase::KBFSNotRunningError unless Dir.exist?(Config[:mount])
13
+ end
@@ -0,0 +1,52 @@
1
+ require "yaml"
2
+ require "fileutils"
3
+
4
+ module KBSecret
5
+ class Config
6
+ CONFIG_DIR = File.expand_path("~/.config/kbsecret").freeze
7
+
8
+ CONFIG_FILE = File.join(CONFIG_DIR, "config.yml").freeze
9
+
10
+ DEFAULT_CONFIG = {
11
+ mount: "/keybase",
12
+
13
+ sessions: {
14
+ default: {
15
+ users: [Keybase.current_user],
16
+ root: "kbsecret",
17
+ }
18
+ }
19
+ }.freeze
20
+
21
+ def self.[](key)
22
+ @@config[key]
23
+ end
24
+
25
+ def self.session(sess)
26
+ @@config[:sessions][sess]
27
+ end
28
+
29
+ def self.session_names
30
+ @@config[:sessions].keys
31
+ end
32
+
33
+ def self.session?(sess)
34
+ session_names.include?(sess.to_sym)
35
+ end
36
+
37
+ def self.add_session(label, hsh)
38
+ @@config[:sessions][label.to_sym] = hsh
39
+ File.open(CONFIG_FILE, "w") { |io| io.write @@config.to_yaml }
40
+ end
41
+
42
+ if File.exist?(CONFIG_FILE)
43
+ user_config = YAML.load_file(CONFIG_FILE)
44
+ else
45
+ user_config = DEFAULT_CONFIG
46
+ FileUtils.mkdir_p CONFIG_DIR
47
+ File.open(CONFIG_FILE, "w") { |io| io.write DEFAULT_CONFIG.to_yaml }
48
+ end
49
+
50
+ @@config = DEFAULT_CONFIG.merge(user_config)
51
+ end
52
+ end
@@ -0,0 +1,10 @@
1
+ module KBSecret
2
+ class KBSecretError < RuntimeError
3
+ end
4
+
5
+ class RecordCreationArityError < RuntimeError
6
+ def initialize(exp, act)
7
+ super "Needed #{exp} arguments for this record, got #{act}"
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,30 @@
1
+ require "json"
2
+
3
+ require_relative "record/abstract"
4
+ require_relative "record/login"
5
+ require_relative "record/environment"
6
+ require_relative "record/unstructured"
7
+
8
+ module KBSecret
9
+ module Record
10
+ def self.record_classes
11
+ klasses = constants.map(&Record.method(:const_get)).grep(Class)
12
+ klasses.delete(Record::Abstract)
13
+ klasses
14
+ end
15
+
16
+ def self.record_types
17
+ record_classes.map(&:type)
18
+ end
19
+
20
+ def self.type?(type)
21
+ record_types.include?(type)
22
+ end
23
+
24
+ def self.load_record!(session, path)
25
+ hsh = JSON.parse(File.read(path), symbolize_names: true)
26
+ klass = record_classes.find { |c| c.type == hsh[:type] }
27
+ klass.load!(session, hsh)
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,61 @@
1
+ require "json"
2
+
3
+ module KBSecret
4
+ module Record
5
+ # @abstract
6
+ class Abstract
7
+ attr_accessor :session
8
+ attr_reader :timestamp
9
+ attr_reader :label
10
+ attr_reader :type
11
+ attr_reader :data
12
+
13
+ def self.type
14
+ name.split("::").last.downcase
15
+ end
16
+
17
+ def self.load!(session, hsh)
18
+ instance = allocate
19
+ instance.session = session
20
+ instance.initialize_from_hash(hsh)
21
+
22
+ instance
23
+ end
24
+
25
+ def initialize(session, label)
26
+ @session = session
27
+ @timestamp = Time.now.to_i
28
+ @label = label
29
+ @type = self.class.type
30
+ @data = {}
31
+ end
32
+
33
+ def initialize_from_hash(hsh)
34
+ @timestamp = hsh[:timestamp]
35
+ @label = hsh[:label]
36
+ @type = hsh[:type]
37
+ @data = hsh[:data]
38
+ end
39
+
40
+ def path
41
+ File.join(session.directory, "#{label}.json")
42
+ end
43
+
44
+ def to_h
45
+ {
46
+ timestamp: timestamp,
47
+ label: label,
48
+ type: type,
49
+ data: data,
50
+ }
51
+ end
52
+
53
+ def sync!
54
+ # bump the timestamp every time we sync
55
+ @timestamp = Time.now.to_i
56
+
57
+ File.write(path, JSON.pretty_generate(to_h))
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,42 @@
1
+ module KBSecret
2
+ module Record
3
+ class Environment < Abstract
4
+ def initialize(session, label, variable, value)
5
+ super(session, label)
6
+
7
+ @data = {
8
+ environment: {
9
+ variable: variable,
10
+ value: value,
11
+ },
12
+ }
13
+ end
14
+
15
+ def variable
16
+ @data[:environment][:variable]
17
+ end
18
+
19
+ def variable=(var)
20
+ @data[:environment][:variable] = var
21
+ sync!
22
+ end
23
+
24
+ def value
25
+ @data[:environment][:value]
26
+ end
27
+
28
+ def value=(val)
29
+ @data[:environment][:value] = val
30
+ sync!
31
+ end
32
+
33
+ def to_assignment
34
+ "#{variable}='#{value}'"
35
+ end
36
+
37
+ def to_export
38
+ "export #{to_assignment}"
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,34 @@
1
+ module KBSecret
2
+ module Record
3
+ class Login < Abstract
4
+ def initialize(session, label, user, pass)
5
+ super(session, label)
6
+
7
+ @data = {
8
+ login: {
9
+ username: user,
10
+ password: pass,
11
+ },
12
+ }
13
+ end
14
+
15
+ def username
16
+ @data[:login][:username]
17
+ end
18
+
19
+ def username=(user)
20
+ @data[:login][:username] = user
21
+ sync!
22
+ end
23
+
24
+ def password
25
+ @data[:login][:password]
26
+ end
27
+
28
+ def password=(pass)
29
+ @data[:login][:password] = pass
30
+ sync!
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,22 @@
1
+ module KBSecret
2
+ module Record
3
+ class Unstructured < Abstract
4
+ def initialize(session, label, text)
5
+ super(session, label)
6
+
7
+ @data = {
8
+ text: text
9
+ }
10
+ end
11
+
12
+ def text
13
+ @data[:text]
14
+ end
15
+
16
+ def text=(new_text)
17
+ @data[:text] = new_text
18
+ sync!
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,69 @@
1
+ module KBSecret
2
+ class Session
3
+ attr_reader :label
4
+ attr_reader :config
5
+ attr_reader :directory
6
+ attr_reader :records
7
+
8
+ def initialize(label: :default)
9
+ @label = label
10
+ @config = Config.session(label.to_sym)
11
+
12
+ @directory = rel_path config[:root], mkdir: true
13
+ @records = load_records!
14
+ end
15
+
16
+ def record_labels
17
+ records.map(&:label)
18
+ end
19
+
20
+ def add_record(type, label, *args)
21
+ klass = Record.record_classes.find { |k| k.type == type }
22
+ arity = klass.instance_method(:initialize).arity - 2
23
+
24
+ unless arity == args.size
25
+ raise RecordCreationArityError.new(arity, args.size)
26
+ end
27
+
28
+ record = klass.new(self, label, *args)
29
+ records << record
30
+ record.sync!
31
+ end
32
+
33
+ def delete_record(rec_label)
34
+ record = records.find { |r| r.label == rec_label }
35
+ return unless record
36
+
37
+ File.delete(record.path)
38
+ records.delete(record)
39
+ end
40
+
41
+ def record?(label)
42
+ record_labels.include?(label)
43
+ end
44
+
45
+ private
46
+
47
+ def record_paths
48
+ Dir[File.join(directory, "*.json")]
49
+ end
50
+
51
+ def load_records!
52
+ record_paths.map do |path|
53
+ Record.load_record! self, path
54
+ end
55
+ end
56
+
57
+ def stringified_users
58
+ config[:users].join(",")
59
+ end
60
+
61
+ def rel_path(rel, mkdir: false)
62
+ path = File.join(Config[:mount], "private", stringified_users, rel)
63
+
64
+ FileUtils.mkdir_p path if mkdir
65
+
66
+ path
67
+ end
68
+ end
69
+ end
metadata ADDED
@@ -0,0 +1,113 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: kbsecret
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - William Woodruff
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-02-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: keybase-unofficial
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: slop
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '4.4'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '4.4'
41
+ - !ruby/object:Gem::Dependency
42
+ name: tty-prompt
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 0.10.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 0.10.0
55
+ description: Manages your passwords, environment, and more via KBFS.
56
+ email: william@tuffbizz.com
57
+ executables:
58
+ - kbsecret
59
+ - kbsecret-rm
60
+ - kbsecret-login
61
+ - kbsecret-new
62
+ - kbsecret-env
63
+ - kbsecret-new-session
64
+ - kbsecret-list
65
+ - kbsecret-sessions
66
+ extensions: []
67
+ extra_rdoc_files: []
68
+ files:
69
+ - ".yardopts"
70
+ - LICENSE
71
+ - README.md
72
+ - bin/kbsecret
73
+ - bin/kbsecret-env
74
+ - bin/kbsecret-list
75
+ - bin/kbsecret-login
76
+ - bin/kbsecret-new
77
+ - bin/kbsecret-new-session
78
+ - bin/kbsecret-rm
79
+ - bin/kbsecret-sessions
80
+ - lib/kbsecret.rb
81
+ - lib/kbsecret/config.rb
82
+ - lib/kbsecret/exceptions.rb
83
+ - lib/kbsecret/record.rb
84
+ - lib/kbsecret/record/abstract.rb
85
+ - lib/kbsecret/record/environment.rb
86
+ - lib/kbsecret/record/login.rb
87
+ - lib/kbsecret/record/unstructured.rb
88
+ - lib/kbsecret/session.rb
89
+ homepage: https://github.com/woodruffw/kbsecret
90
+ licenses:
91
+ - MIT
92
+ metadata: {}
93
+ post_install_message:
94
+ rdoc_options: []
95
+ require_paths:
96
+ - lib
97
+ required_ruby_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ version: 2.3.0
102
+ required_rubygems_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ requirements: []
108
+ rubyforge_project:
109
+ rubygems_version: 2.6.8
110
+ signing_key:
111
+ specification_version: 4
112
+ summary: kbsecret - A KBFS (Keybase) backed secret manager.
113
+ test_files: []