kbsecret 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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: []