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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d63e9f1885845c0dcfbddc0e2e2b8e9a685e732d19fdb0b6e0b319064b7093c6
4
- data.tar.gz: ea15f59e0f1864d0d8ad77ea6ad2be038938314481e9d299c00d5aa0a548a413
3
+ metadata.gz: 237505d740522814bab6d0401ae982a01d12b56792dc3913cf1594dcf50d2ad5
4
+ data.tar.gz: c9e2b68bdd588fee6e82095662f62bdd025def1c7f948f3085939f83f4d48b51
5
5
  SHA512:
6
- metadata.gz: 4878ac13c5a8508eb4b426bbf3f76d8907c8d2abbd6790fa508e2612f8da6f817309db678e301c67123899b7502f6981ce7c95b89e4abcc038fef05bea351d8e
7
- data.tar.gz: 42f5ddbc1b13dd8c82846b0363fcfb1edab7cbef80ef7714f73196e705025660ecb374a0db5f19d713601304b06aa3c9f45d0437fe81d2efb126530bfc974e69
6
+ metadata.gz: 7b6900e6f99a1bd58ebd0fa4185535be1c6ec03d9b7649d805263bb19a41715c7a5175d80bc32a13b922e431934c0cd0929ea28a446d7100e22dbd5cd8b9bb8f
7
+ data.tar.gz: bf4a7c862bdfb9ef31621f70cf6bcd3da6f2ab08221eb2c4ce0f4de2b8f2524fe986e9867e12317c5f5428b112ccc6b55f7ec52a86ca6f2b5003a1b67ac7fd62
data/.gitignore CHANGED
@@ -10,3 +10,5 @@
10
10
  # rspec failure tracking
11
11
  .rspec_status
12
12
  Gemfile.lock
13
+ .trunk.enc
14
+ .trunk.key.enc
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 --title=title --username=username --password=password
29
- $ trunk add <title> <username> - # read password from stdin
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/[USERNAME]/trunk.
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 'optparse'
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 AddCommand
3
- def matches?(command)
4
- "add" == command
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
- def run(arguments)
8
- OptionParser.new do |parser|
9
- parser.banner = "Usage: trunk add [options]"
10
- parser.on_tail("-h", "--help", "print help") do
11
- puts parser
12
- end
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
- print "title:> "
16
- title = STDIN.gets
17
- print "username:> "
18
- username = STDIN.gets
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
- puts [title, username, password].inspect
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
- class DefaultCommand
27
- def run(arguments)
28
- parser = OptionParser.new
29
- parser.banner = "Usage: trunk [options]"
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
- class CLI
43
- attr_reader :parser, :commands
36
+ def database_path
37
+ File.join(dir, '.trunk.enc')
38
+ end
44
39
 
45
- def initialize
46
- @commands = []
47
- @commands.push(AddCommand.new)
40
+ def private_key_path
41
+ File.join(dir, '.trunk.key.enc')
48
42
  end
49
43
 
50
- def command_for(arguments)
51
- if arguments.empty? || arguments[0]&.start_with?("-")
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 run(arguments)
59
- parser.banner = "Usage: trunk [options]"
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 self.start(arguments)
73
- cli = new
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,13 @@
1
+ module Trunk
2
+ module Serializers
3
+ class Base64
4
+ def serialize(value)
5
+ ::Base64.strict_encode64(value)
6
+ end
7
+
8
+ def deserialize(value)
9
+ ::Base64.decode64(value)
10
+ end
11
+ end
12
+ end
13
+ 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
@@ -1,3 +1,3 @@
1
1
  module Trunk
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
@@ -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 = ["mokha"]
10
- spec.email = ["mokha@cisco.com"]
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.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
- - mokha
7
+ - mo
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-06-09 00:00:00.000000000 Z
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
- - mokha@cisco.com
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: