trunk 0.1.0 → 0.1.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/.gitignore +2 -0
- data/README.md +3 -11
- data/lib/trunk.rb +9 -1
- data/lib/trunk/cli.rb +37 -58
- data/lib/trunk/serializers/base_64.rb +13 -0
- data/lib/trunk/serializers/composite.rb +27 -0
- data/lib/trunk/serializers/crypto.rb +17 -0
- data/lib/trunk/storage.rb +2 -62
- data/lib/trunk/version.rb +1 -1
- data/lib/trunk/yaml_storage.rb +39 -0
- data/trunk.gemspec +3 -2
- metadata +22 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 237505d740522814bab6d0401ae982a01d12b56792dc3913cf1594dcf50d2ad5
|
4
|
+
data.tar.gz: c9e2b68bdd588fee6e82095662f62bdd025def1c7f948f3085939f83f4d48b51
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7b6900e6f99a1bd58ebd0fa4185535be1c6ec03d9b7649d805263bb19a41715c7a5175d80bc32a13b922e431934c0cd0929ea28a446d7100e22dbd5cd8b9bb8f
|
7
|
+
data.tar.gz: bf4a7c862bdfb9ef31621f70cf6bcd3da6f2ab08221eb2c4ce0f4de2b8f2524fe986e9867e12317c5f5428b112ccc6b55f7ec52a86ca6f2b5003a1b67ac7fd62
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -22,17 +22,9 @@ Or install it yourself as:
|
|
22
22
|
|
23
23
|
## Usage
|
24
24
|
|
25
|
-
TODO: Write usage instructions here
|
26
|
-
|
27
25
|
```bash
|
28
|
-
$ trunk add
|
29
|
-
$ trunk add
|
30
|
-
$ trunk add
|
31
|
-
$ title:>
|
32
|
-
$ username:>
|
33
|
-
$ password:>
|
34
|
-
|
35
|
-
|
26
|
+
$ trunk add key password
|
27
|
+
$ trunk add key - # read password from stdin
|
36
28
|
$ trunk show title
|
37
29
|
```
|
38
30
|
|
@@ -51,7 +43,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
51
43
|
|
52
44
|
## Contributing
|
53
45
|
|
54
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
46
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/mokhan/trunk.
|
55
47
|
|
56
48
|
## License
|
57
49
|
|
data/lib/trunk.rb
CHANGED
@@ -1,7 +1,15 @@
|
|
1
|
-
require '
|
1
|
+
require 'base64'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'openssl'
|
4
|
+
require 'thor'
|
5
|
+
require 'yaml'
|
2
6
|
|
3
7
|
require "trunk/cli"
|
8
|
+
require "trunk/serializers/base_64"
|
9
|
+
require "trunk/serializers/composite"
|
10
|
+
require "trunk/serializers/crypto"
|
4
11
|
require "trunk/storage"
|
12
|
+
require "trunk/yaml_storage"
|
5
13
|
require "trunk/version"
|
6
14
|
|
7
15
|
module Trunk
|
data/lib/trunk/cli.rb
CHANGED
@@ -1,77 +1,56 @@
|
|
1
1
|
module Trunk
|
2
|
-
class
|
3
|
-
|
4
|
-
|
2
|
+
class CLI < Thor
|
3
|
+
desc "add NAME PASSWORD", "add a key and password"
|
4
|
+
def add(name, password = $stdin.gets.strip)
|
5
|
+
storage.store(name, password)
|
5
6
|
end
|
6
7
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
end.parse!(arguments)
|
8
|
+
desc "show NAME", "print the password associated with a key"
|
9
|
+
def show(name)
|
10
|
+
print storage.fetch(name)
|
11
|
+
rescue OpenSSL::PKey::RSAError => error
|
12
|
+
say error.message, :red
|
13
|
+
end
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
print "password:> "
|
20
|
-
password = STDIN.gets
|
15
|
+
desc "version", "print the version"
|
16
|
+
def version
|
17
|
+
say Trunk::VERSION
|
18
|
+
end
|
21
19
|
|
22
|
-
|
20
|
+
desc "setup", "create the database and private key file."
|
21
|
+
method_option :algorithm, type: :string, default: 'AES-256-CBC'
|
22
|
+
def setup
|
23
|
+
FileUtils.mkdir_p(dir)
|
24
|
+
exit(0) unless file_collision(private_key_path) if File.exist?(private_key_path)
|
25
|
+
IO.write(private_key_path, OpenSSL::PKey::RSA.new(4096).export(options[:algorithm], passphrase))
|
26
|
+
FileUtils.touch(database_path)
|
27
|
+
[database_path, private_key_path].each { |x| FileUtils.chmod(0600, x) }
|
23
28
|
end
|
24
|
-
end
|
25
29
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
parser.on("-v", "--[no-]verbose", "run verbosely") do |v|
|
31
|
-
end
|
32
|
-
parser.on("--version", "show version") do |v|
|
33
|
-
puts Trunk::VERSION
|
34
|
-
end
|
35
|
-
parser.on_tail("-h", "--help", "print help") do
|
36
|
-
puts parser
|
37
|
-
end
|
38
|
-
parser.parse!(arguments)
|
30
|
+
private
|
31
|
+
|
32
|
+
def storage
|
33
|
+
@storage ||= Trunk::YAMLStorage.new(database_path, private_key)
|
39
34
|
end
|
40
|
-
end
|
41
35
|
|
42
|
-
|
43
|
-
|
36
|
+
def database_path
|
37
|
+
File.join(dir, '.trunk.enc')
|
38
|
+
end
|
44
39
|
|
45
|
-
def
|
46
|
-
|
47
|
-
@commands.push(AddCommand.new)
|
40
|
+
def private_key_path
|
41
|
+
File.join(dir, '.trunk.key.enc')
|
48
42
|
end
|
49
43
|
|
50
|
-
def
|
51
|
-
|
52
|
-
DefaultCommand.new
|
53
|
-
else
|
54
|
-
commands.find { |x| x.matches?(arguments[0]) }
|
55
|
-
end
|
44
|
+
def dir
|
45
|
+
ENV['TRUNK_HOME'] || File.join(Dir.home, '.trunk')
|
56
46
|
end
|
57
47
|
|
58
|
-
def
|
59
|
-
|
60
|
-
parser.on("-v", "--[no-]verbose", "run verbosely") do |v|
|
61
|
-
options[:verbose] = v
|
62
|
-
end
|
63
|
-
parser.on("--version", "show version") do |v|
|
64
|
-
puts Trunk::VERSION
|
65
|
-
end
|
66
|
-
parser.on_tail("-h", "--help", "print help") do
|
67
|
-
puts parser
|
68
|
-
end
|
69
|
-
parser.parse!(arguments)
|
48
|
+
def private_key
|
49
|
+
OpenSSL::PKey::RSA.new(IO.read(private_key_path), passphrase)
|
70
50
|
end
|
71
51
|
|
72
|
-
def
|
73
|
-
|
74
|
-
cli.command_for(arguments).run(arguments)
|
52
|
+
def passphrase
|
53
|
+
ENV['TRUNK_PASSPHRASE'] || ask("passphrase:", echo: false)
|
75
54
|
end
|
76
55
|
end
|
77
56
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Trunk
|
2
|
+
module Serializers
|
3
|
+
class Composite
|
4
|
+
def initialize(serializers = [])
|
5
|
+
@serializers = serializers
|
6
|
+
end
|
7
|
+
|
8
|
+
def add(serializer)
|
9
|
+
@serializers.push(serializer)
|
10
|
+
end
|
11
|
+
|
12
|
+
def serialize(value)
|
13
|
+
@serializers.each do |x|
|
14
|
+
value = x.serialize(value)
|
15
|
+
end
|
16
|
+
value
|
17
|
+
end
|
18
|
+
|
19
|
+
def deserialize(value)
|
20
|
+
@serializers.reverse.each do |x|
|
21
|
+
value = x.deserialize(value)
|
22
|
+
end
|
23
|
+
value
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Trunk
|
2
|
+
module Serializers
|
3
|
+
class Crypto
|
4
|
+
def initialize(private_key)
|
5
|
+
@private_key = private_key
|
6
|
+
end
|
7
|
+
|
8
|
+
def serialize(plain_text)
|
9
|
+
@private_key.public_encrypt(plain_text)
|
10
|
+
end
|
11
|
+
|
12
|
+
def deserialize(cipher_text)
|
13
|
+
@private_key.private_decrypt(cipher_text)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/trunk/storage.rb
CHANGED
@@ -1,67 +1,7 @@
|
|
1
1
|
module Trunk
|
2
|
-
class CompositeSerializer
|
3
|
-
def initialize(serializers = [])
|
4
|
-
@serializers = serializers
|
5
|
-
end
|
6
|
-
|
7
|
-
def add(serializer)
|
8
|
-
@serializers.push(serializer)
|
9
|
-
end
|
10
|
-
|
11
|
-
def serialize(value)
|
12
|
-
@serializers.each do |x|
|
13
|
-
value = x.serialize(value)
|
14
|
-
end
|
15
|
-
value
|
16
|
-
end
|
17
|
-
|
18
|
-
def deserialize(value)
|
19
|
-
puts "deserialize"
|
20
|
-
@serializers.reverse.each do |x|
|
21
|
-
puts x.class
|
22
|
-
value = x.deserialize(value)
|
23
|
-
end
|
24
|
-
value
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
class Base64Serializer
|
29
|
-
def serialize(value)
|
30
|
-
Base64.strict_encode64(value)
|
31
|
-
end
|
32
|
-
|
33
|
-
def deserialize(value)
|
34
|
-
Base64.decode64(value)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
class SymmetricCrypto
|
39
|
-
attr_reader :private_key, :algorithm
|
40
|
-
|
41
|
-
def initialize(private_key, algorithm: 'AES-256-CBC')
|
42
|
-
@private_key = private_key
|
43
|
-
@algorithm = algorithm
|
44
|
-
end
|
45
|
-
|
46
|
-
def serialize(plain_text)
|
47
|
-
cipher = OpenSSL::Cipher.new(algorithm)
|
48
|
-
cipher.encrypt
|
49
|
-
cipher.key = private_key
|
50
|
-
cipher.random_iv + cipher.update(plain_text) + cipher.final
|
51
|
-
end
|
52
|
-
|
53
|
-
def deserialize(cipher_text)
|
54
|
-
cipher = OpenSSL::Cipher.new(algorithm)
|
55
|
-
cipher.decrypt
|
56
|
-
iv = cipher_text[0..cipher.iv_len - 1]
|
57
|
-
data = cipher_text[cipher.iv_len..-1]
|
58
|
-
cipher.key = private_key
|
59
|
-
cipher.iv = iv
|
60
|
-
cipher.update(data) + cipher.final
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
2
|
class Storage
|
3
|
+
attr_reader :hash
|
4
|
+
|
65
5
|
def initialize(hash, serializer)
|
66
6
|
@hash = hash
|
67
7
|
@serializer = serializer
|
data/lib/trunk/version.rb
CHANGED
@@ -0,0 +1,39 @@
|
|
1
|
+
module Trunk
|
2
|
+
class YAMLStorage
|
3
|
+
attr_reader :private_key, :absolute_path
|
4
|
+
|
5
|
+
def initialize(absolute_path, private_key)
|
6
|
+
@absolute_path = absolute_path
|
7
|
+
@private_key = private_key
|
8
|
+
end
|
9
|
+
|
10
|
+
def fetch(*args)
|
11
|
+
transaction do |storage|
|
12
|
+
storage.fetch(*args)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def store(*args)
|
17
|
+
transaction do |storage|
|
18
|
+
storage.store(*args)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def transaction
|
25
|
+
hash = YAML.load(IO.read(absolute_path)) || {}
|
26
|
+
storage = Storage.new(hash, serializer)
|
27
|
+
yield storage
|
28
|
+
ensure
|
29
|
+
IO.write(absolute_path, YAML.dump(hash))
|
30
|
+
end
|
31
|
+
|
32
|
+
def serializer
|
33
|
+
serializer = Trunk::Serializers::Composite.new
|
34
|
+
serializer.add(Trunk::Serializers::Crypto.new(private_key))
|
35
|
+
serializer.add(Trunk::Serializers::Base64.new)
|
36
|
+
serializer
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/trunk.gemspec
CHANGED
@@ -6,8 +6,8 @@ require "trunk/version"
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = "trunk"
|
8
8
|
spec.version = Trunk::VERSION
|
9
|
-
spec.authors = ["
|
10
|
-
spec.email = ["
|
9
|
+
spec.authors = ["mo"]
|
10
|
+
spec.email = ["mo@mokhan.ca"]
|
11
11
|
|
12
12
|
spec.summary = %q{A safe place to put things.}
|
13
13
|
spec.description = %q{A safe place to put things.}
|
@@ -21,6 +21,7 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
22
22
|
spec.require_paths = ["lib"]
|
23
23
|
|
24
|
+
spec.add_dependency "thor", "~> 0.20"
|
24
25
|
spec.add_development_dependency "bundler", "~> 1.16"
|
25
26
|
spec.add_development_dependency "rake", "~> 10.0"
|
26
27
|
spec.add_development_dependency "rspec", "~> 3.0"
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: trunk
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
-
-
|
7
|
+
- mo
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-06-
|
11
|
+
date: 2018-06-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: thor
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.20'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.20'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: bundler
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -54,7 +68,7 @@ dependencies:
|
|
54
68
|
version: '3.0'
|
55
69
|
description: A safe place to put things.
|
56
70
|
email:
|
57
|
-
-
|
71
|
+
- mo@mokhan.ca
|
58
72
|
executables:
|
59
73
|
- trunk
|
60
74
|
extensions: []
|
@@ -72,8 +86,12 @@ files:
|
|
72
86
|
- exe/trunk
|
73
87
|
- lib/trunk.rb
|
74
88
|
- lib/trunk/cli.rb
|
89
|
+
- lib/trunk/serializers/base_64.rb
|
90
|
+
- lib/trunk/serializers/composite.rb
|
91
|
+
- lib/trunk/serializers/crypto.rb
|
75
92
|
- lib/trunk/storage.rb
|
76
93
|
- lib/trunk/version.rb
|
94
|
+
- lib/trunk/yaml_storage.rb
|
77
95
|
- trunk.gemspec
|
78
96
|
homepage: https://www.mokhan.ca
|
79
97
|
licenses:
|