rcredstash 0.1.1 → 0.2.0

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
  SHA1:
3
- metadata.gz: 8a93b119dd169d80cf8ffaee1b098f153b0c7f5b
4
- data.tar.gz: 37722f3b8674110281a0c292120a4a58a0629252
3
+ metadata.gz: 54924cbb3ef0b7e9e664afc6fe17bf2ed7f8b083
4
+ data.tar.gz: d97592afae4bb20e1bc0550275ae35866ab35c46
5
5
  SHA512:
6
- metadata.gz: 9e2940ee12917db050ce6b5cdaa9c951c8a4d92d54d5c1be8a868dd6695681ba006f1f4bfa711b0837deab1e9ac3eaccc8c512af3531420d925f82ce922bd853
7
- data.tar.gz: d319431cc1f5f7f357602485b972bb1d66deff5639d4a327efb6f2b1790023d9e915dd97692f7a647eb23ed7e9e4e686c0a9eb235aeb4a9fca5be0a4730bc850
6
+ metadata.gz: b07368c741370d224b0027fecf4dddd63d9dcf87785f0ff3c2eb5e2d9c819da7cfdc6b8c4f6178252379816f751e0d6a0022c091d1d005d1b4d911ada29c4bcd
7
+ data.tar.gz: 259753ebbadb4e6e6c0c49819e68b5f78b250e1074b77dd459cf39788f6882a83e513cf95ace9ff9b764f338a848c43fa2a3b94e7b18663aa0a58068b803d45c
@@ -1,3 +1,3 @@
1
1
  module CredStash
2
- VERSION = "0.1.1"
2
+ VERSION = "0.2.0"
3
3
  end
data/lib/cred_stash.rb CHANGED
@@ -1,36 +1,127 @@
1
1
  require 'aws-sdk'
2
+
2
3
  module CredStash
3
- def self.get(name)
4
- dynamodb = Aws::DynamoDB::Client.new
5
- res = dynamodb.query(
6
- table_name: 'credential-store',
7
- limit: 1,
8
- consistent_read: true,
9
- scan_index_forward: false,
10
- key_condition_expression: "#name = :name",
11
- expression_attribute_names: { "#name" => "name"},
12
- expression_attribute_values: { ":name" => name }
13
- )
14
- material = res.items.first
15
- data = Base64.decode64(material["key"])
16
- contents = Base64.decode64(material["contents"])
17
-
18
- kms = Aws::KMS::Client.new
19
- kms_res = kms.decrypt(ciphertext_blob: data)
20
-
21
- key = kms_res.plaintext[0..32]
22
- hmackey = kms_res.plaintext[32..-1]
23
-
24
- unless OpenSSL::HMAC.hexdigest("sha256", hmackey, contents) == material["hmac"]
25
- raise "invalid"
4
+ class << self
5
+ def get(name)
6
+ dynamodb = Aws::DynamoDB::Client.new
7
+ res = dynamodb.query(
8
+ table_name: 'credential-store',
9
+ limit: 1,
10
+ consistent_read: true,
11
+ scan_index_forward: false,
12
+ key_condition_expression: "#name = :name",
13
+ expression_attribute_names: { "#name" => "name"},
14
+ expression_attribute_values: { ":name" => name }
15
+ )
16
+ material = res.items.first
17
+ data = Base64.decode64(material["key"])
18
+ contents = Base64.decode64(material["contents"])
19
+
20
+ kms = Aws::KMS::Client.new
21
+ kms_res = kms.decrypt(ciphertext_blob: data)
22
+
23
+ key = kms_res.plaintext[0..32]
24
+ hmackey = kms_res.plaintext[32..-1]
25
+
26
+ unless OpenSSL::HMAC.hexdigest("sha256", hmackey, contents) == material["hmac"]
27
+ raise "invalid"
28
+ end
29
+
30
+ cipher = OpenSSL::Cipher::AES.new(256, "CTR")
31
+ cipher.decrypt
32
+ cipher.key = key
33
+ # FIXME It is better to generate and store initial counter
34
+ cipher.iv = %w(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1).map(&:hex).pack('C' * 16)
35
+ value = cipher.update(contents) + cipher.final
36
+ value.force_encoding("UTF-8")
37
+ end
38
+
39
+ def put(name, value)
40
+ kms = Aws::KMS::Client.new
41
+ kms_res = kms.generate_data_key(key_id: 'alias/credstash', number_of_bytes: 64)
42
+ data_key = kms_res.plaintext[0..32]
43
+ hmac_key = kms_res.plaintext[32..-1]
44
+ wrapped_key = kms_res.ciphertext_blob
45
+
46
+ cipher = OpenSSL::Cipher::AES.new(256, "CTR")
47
+ cipher.encrypt
48
+ cipher.key = data_key
49
+ # FIXME It is better to generate and store initial counter
50
+ cipher.iv = %w(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1).map(&:hex).pack('C' * 16)
51
+ contents = cipher.update(value) + cipher.final
52
+
53
+ hmac = OpenSSL::HMAC.hexdigest("sha256", hmac_key, contents)
54
+
55
+ version = get_highest_version(name) + 1
56
+
57
+ dynamodb = Aws::DynamoDB::Client.new
58
+ dynamodb.put_item(
59
+ table_name: 'credential-store',
60
+ item: {
61
+ name: name,
62
+ version: "%019d" % version,
63
+ key: Base64.encode64(wrapped_key),
64
+ contents: Base64.encode64(contents),
65
+ hmac: hmac
66
+ },
67
+ condition_expression: "attribute_not_exists(#name)",
68
+ expression_attribute_names: { "#name" => "name" },
69
+ )
70
+ end
71
+
72
+ def list
73
+ dynamodb = Aws::DynamoDB::Client.new
74
+ res = dynamodb.scan(
75
+ table_name: 'credential-store',
76
+ projection_expression: '#name, version',
77
+ expression_attribute_names: { "#name" => "name" },
78
+ )
79
+ res.items.inject({}) {|h, i| h[i['name']] = i['version']; h }
80
+ end
81
+
82
+ def delete(name)
83
+ dynamodb = Aws::DynamoDB::Client.new
84
+ res = dynamodb.query(
85
+ table_name: 'credential-store',
86
+ consistent_read: true,
87
+ key_condition_expression: "#name = :name",
88
+ expression_attribute_names: { "#name" => "name"},
89
+ expression_attribute_values: { ":name" => name }
90
+ )
91
+ # TODO needs delete target version option
92
+
93
+ item = res.items.first
94
+ dynamodb.delete_item(
95
+ table_name: 'credential-store',
96
+ key: {
97
+ name: item['name'],
98
+ version: item['version'],
99
+ }
100
+ )
26
101
  end
27
102
 
28
- cipher = OpenSSL::Cipher::AES.new(256, "CTR")
29
- cipher.decrypt
30
- cipher.key = key
31
- # FIXME It is better to generate and store initial counter
32
- cipher.iv = %w(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1).map(&:hex).pack('C' * 16)
33
- value = cipher.update(contents) + cipher.final
34
- value.force_encoding("UTF-8")
103
+ private
104
+
105
+ def get_highest_version(name)
106
+ dynamodb = Aws::DynamoDB::Client.new
107
+ res = dynamodb.query(
108
+ table_name: 'credential-store',
109
+ limit: 1,
110
+ consistent_read: true,
111
+ scan_index_forward: false,
112
+ key_condition_expression: "#name = :name",
113
+ expression_attribute_names: { "#name" => "name"},
114
+ expression_attribute_values: { ":name" => name },
115
+ projection_expression: 'version',
116
+ )
117
+
118
+ item = res.items.first
119
+
120
+ if item
121
+ item['version'].to_i
122
+ else
123
+ 0
124
+ end
125
+ end
35
126
  end
36
127
  end
data/rcredstash.gemspec CHANGED
@@ -8,6 +8,7 @@ Gem::Specification.new do |spec|
8
8
  spec.version = CredStash::VERSION
9
9
  spec.authors = ["adorechic"]
10
10
  spec.email = ["adorechic@gmail.com"]
11
+ spec.homepage = 'https://github.com/adorechic/rcredstash'
11
12
 
12
13
  spec.summary = %q{A Ruby port of CredStash}
13
14
  spec.description = %q{A Ruby port of CredStash}
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rcredstash
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - adorechic
@@ -88,7 +88,7 @@ files:
88
88
  - lib/rcredstash.rb
89
89
  - lib/rcredstash/version.rb
90
90
  - rcredstash.gemspec
91
- homepage:
91
+ homepage: https://github.com/adorechic/rcredstash
92
92
  licenses:
93
93
  - MIT
94
94
  metadata: {}