kbsecret 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +4 -2
- data/lib/kbsecret/config.rb +21 -0
- data/lib/kbsecret/exceptions.rb +2 -0
- data/lib/kbsecret/record/abstract.rb +27 -0
- data/lib/kbsecret/record/environment.rb +21 -1
- data/lib/kbsecret/record/login.rb +13 -0
- data/lib/kbsecret/record/unstructured.rb +8 -0
- data/lib/kbsecret/record.rb +9 -0
- data/lib/kbsecret/session.rb +26 -0
- data/lib/kbsecret.rb +4 -1
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f468bb679d062bf75ce1d379e4cd76c4544c090f
|
4
|
+
data.tar.gz: d862b1c03920b88de8942fac32ad6f7b4fb89bd2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a9de681a6224e5f577deb31e8a72cafe288fa9d48c7de5e7438616c8887408a3705e813bd588fdfc328b84683e0f5b51540f58911163c81494cde918851306a4
|
7
|
+
data.tar.gz: 0fbe3224bc94a6a39eea6e1e0c578ab01fcd4755e92e827cd08441151086bd1cc2c65d00c2de8cfbefca0a32847001d53d7fc5496058de45bdf937cc7e3e64b7
|
data/README.md
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
kbsecret
|
2
2
|
========
|
3
3
|
|
4
|
+
*Note*: This is still a work in process. Use it with caution.
|
5
|
+
|
4
6
|
kbsecret is a combined library/utility that provides a secret management
|
5
7
|
interface for [KBFS](https://keybase.io/docs/kbfs) and
|
6
8
|
[Keybase](https://keybase.io/).
|
@@ -16,7 +18,7 @@ interface for [KBFS](https://keybase.io/docs/kbfs) and
|
|
16
18
|
|
17
19
|
### Installation
|
18
20
|
|
19
|
-
kbsecret is available via RubyGems:
|
21
|
+
kbsecret is available via [RubyGems](https://rubygems.org/gems/kbsecret):
|
20
22
|
|
21
23
|
```bash
|
22
24
|
$ gem install kbsecret
|
@@ -26,7 +28,7 @@ For hacking:
|
|
26
28
|
|
27
29
|
```bash
|
28
30
|
$ git clone git@github.com:woodruffw/kbsecret.git && cd kbsecret
|
29
|
-
$ RUBYLIB=./lib PATH
|
31
|
+
$ RUBYLIB=./lib PATH=./bin:${PATH} ./bin/kbsecret help
|
30
32
|
```
|
31
33
|
|
32
34
|
### Usage
|
data/lib/kbsecret/config.rb
CHANGED
@@ -2,11 +2,18 @@ require "yaml"
|
|
2
2
|
require "fileutils"
|
3
3
|
|
4
4
|
module KBSecret
|
5
|
+
# Global and per-session configuration for kbsecret.
|
5
6
|
class Config
|
7
|
+
# the configuration directory
|
8
|
+
# @api private
|
6
9
|
CONFIG_DIR = File.expand_path("~/.config/kbsecret").freeze
|
7
10
|
|
11
|
+
# the configuration file
|
12
|
+
# @api private
|
8
13
|
CONFIG_FILE = File.join(CONFIG_DIR, "config.yml").freeze
|
9
14
|
|
15
|
+
# configuration defaults
|
16
|
+
# @api private
|
10
17
|
DEFAULT_CONFIG = {
|
11
18
|
mount: "/keybase",
|
12
19
|
|
@@ -18,22 +25,36 @@ module KBSecret
|
|
18
25
|
}
|
19
26
|
}.freeze
|
20
27
|
|
28
|
+
# Retrieve a configured value.
|
29
|
+
# @param key [String]
|
30
|
+
# @return [Object] the corresponding configuration
|
21
31
|
def self.[](key)
|
22
32
|
@@config[key]
|
23
33
|
end
|
24
34
|
|
35
|
+
# Retrieve a session's configuration.
|
36
|
+
# @param sess [Symbol] the session's label
|
37
|
+
# @return [Hash] the session configuration
|
25
38
|
def self.session(sess)
|
26
39
|
@@config[:sessions][sess]
|
27
40
|
end
|
28
41
|
|
42
|
+
# @return [Array<Symbol>] all configured session labels
|
43
|
+
# @todo This should be session_labels.
|
29
44
|
def self.session_names
|
30
45
|
@@config[:sessions].keys
|
31
46
|
end
|
32
47
|
|
48
|
+
# @param sess [Symbol] the session label
|
49
|
+
# @return [Boolean] whether or not the given session is configured
|
33
50
|
def self.session?(sess)
|
34
51
|
session_names.include?(sess.to_sym)
|
35
52
|
end
|
36
53
|
|
54
|
+
# Configure a session.
|
55
|
+
# @param label [Symbol] the session label
|
56
|
+
# @param hsh [Hash] the session configuration
|
57
|
+
# @todo This should be configure_session.
|
37
58
|
def self.add_session(label, hsh)
|
38
59
|
@@config[:sessions][label.to_sym] = hsh
|
39
60
|
File.open(CONFIG_FILE, "w") { |io| io.write @@config.to_yaml }
|
data/lib/kbsecret/exceptions.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
module KBSecret
|
2
|
+
# A generic error in kbsecret.
|
2
3
|
class KBSecretError < RuntimeError
|
3
4
|
end
|
4
5
|
|
6
|
+
# Raised during record creation if too many/few arguments are given.
|
5
7
|
class RecordCreationArityError < RuntimeError
|
6
8
|
def initialize(exp, act)
|
7
9
|
super "Needed #{exp} arguments for this record, got #{act}"
|
@@ -2,6 +2,8 @@ require "json"
|
|
2
2
|
|
3
3
|
module KBSecret
|
4
4
|
module Record
|
5
|
+
# Represents an abstract kbsecret record that can be subclassed to produce
|
6
|
+
# more useful records.
|
5
7
|
# @abstract
|
6
8
|
class Abstract
|
7
9
|
attr_accessor :session
|
@@ -10,10 +12,18 @@ module KBSecret
|
|
10
12
|
attr_reader :type
|
11
13
|
attr_reader :data
|
12
14
|
|
15
|
+
# @return [String] the record's type
|
16
|
+
# @example
|
17
|
+
# KBSecret::Record::Abstract.type # => "abstract"
|
13
18
|
def self.type
|
14
19
|
name.split("::").last.downcase
|
15
20
|
end
|
16
21
|
|
22
|
+
# Load the given hash-representation into a record.
|
23
|
+
# @param session [Session] the session to associate with
|
24
|
+
# @param hsh [Hash] the record's hash-representation
|
25
|
+
# @return [Record::AbstractRecord] the created record
|
26
|
+
# @api private
|
17
27
|
def self.load!(session, hsh)
|
18
28
|
instance = allocate
|
19
29
|
instance.session = session
|
@@ -22,6 +32,10 @@ module KBSecret
|
|
22
32
|
instance
|
23
33
|
end
|
24
34
|
|
35
|
+
# Create a brand new record, associated with a session.
|
36
|
+
# @param session [Session] the session to associate with
|
37
|
+
# @param label [Symbol] the new record's label
|
38
|
+
# @note Creation does *not* sync the new record; see {#sync!} for that.
|
25
39
|
def initialize(session, label)
|
26
40
|
@session = session
|
27
41
|
@timestamp = Time.now.to_i
|
@@ -30,6 +44,10 @@ module KBSecret
|
|
30
44
|
@data = {}
|
31
45
|
end
|
32
46
|
|
47
|
+
# Fill in instance fields from a record's hash-representation.
|
48
|
+
# @param hsh [Hash] the record's hash-representation.
|
49
|
+
# @return [void]
|
50
|
+
# @api private
|
33
51
|
def initialize_from_hash(hsh)
|
34
52
|
@timestamp = hsh[:timestamp]
|
35
53
|
@label = hsh[:label]
|
@@ -37,10 +55,16 @@ module KBSecret
|
|
37
55
|
@data = hsh[:data]
|
38
56
|
end
|
39
57
|
|
58
|
+
# The fully qualified path to the record's file.
|
59
|
+
# @return [String] the path
|
60
|
+
# @note If the record hasn't been synced to disk, this path may not
|
61
|
+
# exist yet.
|
40
62
|
def path
|
41
63
|
File.join(session.directory, "#{label}.json")
|
42
64
|
end
|
43
65
|
|
66
|
+
# Create a hash-representation of the current record.
|
67
|
+
# @return [Hash] the hash-representation
|
44
68
|
def to_h
|
45
69
|
{
|
46
70
|
timestamp: timestamp,
|
@@ -50,6 +74,9 @@ module KBSecret
|
|
50
74
|
}
|
51
75
|
end
|
52
76
|
|
77
|
+
# Write the record's in-memory state to disk.
|
78
|
+
# @note Every sync updates the record's timestamp.
|
79
|
+
# @return [void]
|
53
80
|
def sync!
|
54
81
|
# bump the timestamp every time we sync
|
55
82
|
@timestamp = Time.now.to_i
|
@@ -1,9 +1,19 @@
|
|
1
|
+
require "shellwords"
|
2
|
+
|
1
3
|
module KBSecret
|
2
4
|
module Record
|
5
|
+
# Represents a record containing an environment variable and value.
|
3
6
|
class Environment < Abstract
|
7
|
+
# @param session [Session] the session to associate with
|
8
|
+
# @param label [Symbol] the new record's label
|
9
|
+
# @param variable [String] the new record's variable
|
10
|
+
# @param value [String] the new record's value
|
4
11
|
def initialize(session, label, variable, value)
|
5
12
|
super(session, label)
|
6
13
|
|
14
|
+
value = value.shellescape
|
15
|
+
variable = variable.shellescape
|
16
|
+
|
7
17
|
@data = {
|
8
18
|
environment: {
|
9
19
|
variable: variable,
|
@@ -12,28 +22,38 @@ module KBSecret
|
|
12
22
|
}
|
13
23
|
end
|
14
24
|
|
25
|
+
# @return [String] the record's variable
|
15
26
|
def variable
|
16
27
|
@data[:environment][:variable]
|
17
28
|
end
|
18
29
|
|
30
|
+
# @param var [String] the new variable to insert into the record
|
31
|
+
# @return [void]
|
32
|
+
# @note Triggers a record sync; see {Abstract#sync!}.
|
19
33
|
def variable=(var)
|
20
34
|
@data[:environment][:variable] = var
|
21
35
|
sync!
|
22
36
|
end
|
23
37
|
|
38
|
+
# @return [String] the record's value
|
24
39
|
def value
|
25
40
|
@data[:environment][:value]
|
26
41
|
end
|
27
42
|
|
43
|
+
# @param val [String] the new value to insert into the record
|
44
|
+
# @return [void]
|
45
|
+
# @note Triggers a record sync; see {Abstract#sync!}.
|
28
46
|
def value=(val)
|
29
47
|
@data[:environment][:value] = val
|
30
48
|
sync!
|
31
49
|
end
|
32
50
|
|
51
|
+
# @return [String] a sh-style environment assignment
|
33
52
|
def to_assignment
|
34
|
-
"#{variable}
|
53
|
+
"#{variable}=#{value}"
|
35
54
|
end
|
36
55
|
|
56
|
+
# @return [String] a sh-style environment export line
|
37
57
|
def to_export
|
38
58
|
"export #{to_assignment}"
|
39
59
|
end
|
@@ -1,6 +1,11 @@
|
|
1
1
|
module KBSecret
|
2
2
|
module Record
|
3
|
+
# Represents a record containing a login (username, password) pair.
|
3
4
|
class Login < Abstract
|
5
|
+
# @param session [Session] the session to associate with
|
6
|
+
# @param label [Symbol] the new record's label
|
7
|
+
# @param user [String] the new record's username
|
8
|
+
# @param pass [String] the new record's password
|
4
9
|
def initialize(session, label, user, pass)
|
5
10
|
super(session, label)
|
6
11
|
|
@@ -12,19 +17,27 @@ module KBSecret
|
|
12
17
|
}
|
13
18
|
end
|
14
19
|
|
20
|
+
# @return [String] the record's username
|
15
21
|
def username
|
16
22
|
@data[:login][:username]
|
17
23
|
end
|
18
24
|
|
25
|
+
# @param user [String] the new username to insert into the record
|
26
|
+
# @return [void]
|
27
|
+
# @note Triggers a record sync; see {Abstract#sync!}.
|
19
28
|
def username=(user)
|
20
29
|
@data[:login][:username] = user
|
21
30
|
sync!
|
22
31
|
end
|
23
32
|
|
33
|
+
# @return [String] the record's password
|
24
34
|
def password
|
25
35
|
@data[:login][:password]
|
26
36
|
end
|
27
37
|
|
38
|
+
# @param pass [String] the new password to insert into the record
|
39
|
+
# @return [void]
|
40
|
+
# @note Triggers a record sync; see {Abstract#sync!}.
|
28
41
|
def password=(pass)
|
29
42
|
@data[:login][:password] = pass
|
30
43
|
sync!
|
@@ -1,6 +1,10 @@
|
|
1
1
|
module KBSecret
|
2
2
|
module Record
|
3
|
+
# Represents a record containing unstructured text.
|
3
4
|
class Unstructured < Abstract
|
5
|
+
# @param session [Session] the session to associate with
|
6
|
+
# @param label [Symbol] the new record's label
|
7
|
+
# @param text [String] the new record's unstructured text
|
4
8
|
def initialize(session, label, text)
|
5
9
|
super(session, label)
|
6
10
|
|
@@ -9,10 +13,14 @@ module KBSecret
|
|
9
13
|
}
|
10
14
|
end
|
11
15
|
|
16
|
+
# @return [String] the record's unstructured text
|
12
17
|
def text
|
13
18
|
@data[:text]
|
14
19
|
end
|
15
20
|
|
21
|
+
# @param new_text [String] the new text to insert into the record
|
22
|
+
# @return [void]
|
23
|
+
# @note Triggers a record sync; see {Abstract#sync!}.
|
16
24
|
def text=(new_text)
|
17
25
|
@data[:text] = new_text
|
18
26
|
sync!
|
data/lib/kbsecret/record.rb
CHANGED
@@ -6,21 +6,30 @@ require_relative "record/environment"
|
|
6
6
|
require_relative "record/unstructured"
|
7
7
|
|
8
8
|
module KBSecret
|
9
|
+
# The namespace for kbsecret records types.
|
9
10
|
module Record
|
11
|
+
# @return [Array<Class>] the class objects of all non-abstract record types
|
10
12
|
def self.record_classes
|
11
13
|
klasses = constants.map(&Record.method(:const_get)).grep(Class)
|
12
14
|
klasses.delete(Record::Abstract)
|
13
15
|
klasses
|
14
16
|
end
|
15
17
|
|
18
|
+
# @return [Array<String>] the types of all records
|
16
19
|
def self.record_types
|
17
20
|
record_classes.map(&:type)
|
18
21
|
end
|
19
22
|
|
23
|
+
# @return [Boolean] whether a record class exists of the given type
|
20
24
|
def self.type?(type)
|
21
25
|
record_types.include?(type)
|
22
26
|
end
|
23
27
|
|
28
|
+
# Load a record by path into the given session.
|
29
|
+
# @param session [Session] the session to load into
|
30
|
+
# @param path [String] the fully-qualified record path
|
31
|
+
# @return [Record::AbstractRecord] the loaded record
|
32
|
+
# @api private
|
24
33
|
def self.load_record!(session, path)
|
25
34
|
hsh = JSON.parse(File.read(path), symbolize_names: true)
|
26
35
|
klass = record_classes.find { |c| c.type == hsh[:type] }
|
data/lib/kbsecret/session.rb
CHANGED
@@ -1,10 +1,20 @@
|
|
1
1
|
module KBSecret
|
2
|
+
# Represents a session of N keybase users with collective read/write
|
3
|
+
# access to a collection of records.
|
2
4
|
class Session
|
5
|
+
# @return [Symbol] the session's label
|
3
6
|
attr_reader :label
|
7
|
+
|
8
|
+
# @return [Hash] the session-specific configuration, from
|
9
|
+
# {Config::CONFIG_FILE}
|
4
10
|
attr_reader :config
|
5
11
|
attr_reader :directory
|
6
12
|
attr_reader :records
|
7
13
|
|
14
|
+
# @param label [Symbol] the label of the session to initialize
|
15
|
+
# @note This does not *create* a new session, but loads one already
|
16
|
+
# specified in {Config::CONFIG_FILE}. To *create* a new session,
|
17
|
+
# see {Config.add_session}.
|
8
18
|
def initialize(label: :default)
|
9
19
|
@label = label
|
10
20
|
@config = Config.session(label.to_sym)
|
@@ -13,10 +23,20 @@ module KBSecret
|
|
13
23
|
@records = load_records!
|
14
24
|
end
|
15
25
|
|
26
|
+
# @return [Array<Symbol>] the labels of all records known to the session
|
27
|
+
# @example
|
28
|
+
# session.record_labels # => [:website1, :apikey1, :website2]
|
16
29
|
def record_labels
|
17
30
|
records.map(&:label)
|
18
31
|
end
|
19
32
|
|
33
|
+
# Add a record to the session.
|
34
|
+
# @param type [String] the type of record (see {Record.record_types})
|
35
|
+
# @param label [Symbol] the new record's label
|
36
|
+
# @param args [Array<String>] the record-type specific arguments
|
37
|
+
# @return [void]
|
38
|
+
# @raise RecordCreationArityError if the number of specified record
|
39
|
+
# arguments does not match the record type's constructor
|
20
40
|
def add_record(type, label, *args)
|
21
41
|
klass = Record.record_classes.find { |k| k.type == type }
|
22
42
|
arity = klass.instance_method(:initialize).arity - 2
|
@@ -30,6 +50,10 @@ module KBSecret
|
|
30
50
|
record.sync!
|
31
51
|
end
|
32
52
|
|
53
|
+
# Delete a record from the session, if it exists. Does nothing if
|
54
|
+
# no such record can be found.
|
55
|
+
# @param rec_label [Symbol] the label of the record to delete
|
56
|
+
# @return [void]
|
33
57
|
def delete_record(rec_label)
|
34
58
|
record = records.find { |r| r.label == rec_label }
|
35
59
|
return unless record
|
@@ -38,6 +62,8 @@ module KBSecret
|
|
38
62
|
records.delete(record)
|
39
63
|
end
|
40
64
|
|
65
|
+
# @return [Boolean] whether or not the session contains a record with the
|
66
|
+
# given label
|
41
67
|
def record?(label)
|
42
68
|
record_labels.include?(label)
|
43
69
|
end
|
data/lib/kbsecret.rb
CHANGED
@@ -5,9 +5,12 @@ require_relative "kbsecret/exceptions"
|
|
5
5
|
require_relative "kbsecret/record"
|
6
6
|
require_relative "kbsecret/session"
|
7
7
|
|
8
|
+
# The primary namespace for kbsecret.
|
8
9
|
module KBSecret
|
9
|
-
|
10
|
+
# kbsecret's current version
|
11
|
+
VERSION = "0.0.2".freeze
|
10
12
|
|
13
|
+
# fail very early if the user doesn't have keybase and KBFS running
|
11
14
|
raise Keybase::KeybaseNotRunningError unless Keybase.running?
|
12
15
|
raise Keybase::KBFSNotRunningError unless Dir.exist?(Config[:mount])
|
13
16
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kbsecret
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- William Woodruff
|
@@ -55,14 +55,14 @@ dependencies:
|
|
55
55
|
description: Manages your passwords, environment, and more via KBFS.
|
56
56
|
email: william@tuffbizz.com
|
57
57
|
executables:
|
58
|
-
- kbsecret
|
58
|
+
- kbsecret-sessions
|
59
|
+
- kbsecret-new-session
|
60
|
+
- kbsecret-new
|
59
61
|
- kbsecret-rm
|
62
|
+
- kbsecret-list
|
60
63
|
- kbsecret-login
|
61
|
-
- kbsecret-new
|
62
64
|
- kbsecret-env
|
63
|
-
- kbsecret
|
64
|
-
- kbsecret-list
|
65
|
-
- kbsecret-sessions
|
65
|
+
- kbsecret
|
66
66
|
extensions: []
|
67
67
|
extra_rdoc_files: []
|
68
68
|
files:
|