relishable 0.6 → 0.7

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile.lock CHANGED
@@ -1,14 +1,17 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- relishable (0.5)
5
- fog
4
+ relishable (0.7)
5
+ fernet (~> 1.4)
6
+ fog (~> 1.6)
6
7
 
7
8
  GEM
8
9
  remote: http://rubygems.org/
9
10
  specs:
10
11
  builder (3.1.3)
11
12
  excon (0.16.4)
13
+ fernet (1.4)
14
+ yajl-ruby
12
15
  fog (1.6.0)
13
16
  builder
14
17
  excon (~> 0.14)
@@ -29,6 +32,7 @@ GEM
29
32
  jruby-pageant (>= 1.1.1)
30
33
  nokogiri (1.5.5)
31
34
  ruby-hmac (0.4.0)
35
+ yajl-ruby (1.1.0)
32
36
 
33
37
  PLATFORMS
34
38
  ruby
@@ -0,0 +1,63 @@
1
+ require "fog"
2
+
3
+ class Relish
4
+ class DynamoHelper
5
+
6
+ def initialize(aws_access_key, aws_secret_key, table_name)
7
+ @aws_access_key = aws_access_key
8
+ @aws_secret_key = aws_secret_key
9
+ @table_name = table_name
10
+ end
11
+
12
+ def db
13
+ @db ||= Fog::AWS::DynamoDB.new(:aws_access_key_id => @aws_access_key, :aws_secret_access_key => @aws_secret_key)
14
+ end
15
+
16
+ def query_current_version(id)
17
+ response = db.query(@table_name, {:S => id}, :ConsistentRead => true, :Limit => 1, :ScanIndexForward => false)
18
+ if response.status != 200
19
+ raise('status: #{response.status}')
20
+ end
21
+ if response.body['Count'] == 1
22
+ response.body['Items'].first
23
+ end
24
+ end
25
+
26
+ def put_current_version(item)
27
+ response = db.put_item(@table_name, item, {:Expected => {:id => {:Exists => false}, :version => {:Exists => false}}})
28
+ if response.status != 200
29
+ raise('status: #{response.status}')
30
+ end
31
+ end
32
+
33
+ def get_version(id, version)
34
+ response = db.get_item(@table_name, {:HashKeyElement => {:S => id}, :RangeKeyElement => {:N => version}})
35
+ if response.status != 200
36
+ raise('status: #{response.status}')
37
+ end
38
+ response.body['Item']
39
+ end
40
+
41
+ def put_version(id, version, item)
42
+ response = db.put_item(@table_name, item, {:Expected => {:id => {:Value => {:S => id}}, :version => {:Value => {:N => version}}}})
43
+ if response.status != 200
44
+ raise('status: #{response.status}')
45
+ end
46
+ end
47
+
48
+ def put(item)
49
+ response = db.put_item(@table_name, item)
50
+ if response.status != 200
51
+ raise('status: #{response.status}')
52
+ end
53
+ end
54
+
55
+ def query(id, consistent, limit)
56
+ response = db.query(@table_name, {:S => id}, :ConsistentRead => consistent, :Limit => limit, :ScanIndexForward => false)
57
+ if response.status != 200
58
+ raise('status: #{response.status}')
59
+ end
60
+ response.body['Items']
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,57 @@
1
+ require "fernet"
2
+ require "openssl"
3
+
4
+ class RelishDecryptionFailed < RuntimeError; end
5
+
6
+ class Relish
7
+ class EncryptionHelper
8
+
9
+ def initialize(static_secret, secrets)
10
+ @static_secret = static_secret
11
+ @secrets = secrets
12
+ end
13
+
14
+ def hmac_secrets
15
+ @hmac_secrets ||= @secrets.map do |secret|
16
+ OpenSSL::HMAC.hexdigest('sha256', @static_secret, secret)
17
+ end
18
+ end
19
+
20
+ def encrypt_env(env)
21
+ encrypt_key_with_secret("env", env, hmac_secrets.first)
22
+ end
23
+
24
+ def decrypt_env(encrypted_token)
25
+ hmac_secrets.each_with_index do |secret, i|
26
+ success, env = try_decrypt(secret, encrypted_token, "env")
27
+ if success
28
+ return env
29
+ end
30
+ end
31
+ raise RelishDecryptionFailed
32
+ end
33
+
34
+ def try_decrypt(secret, encrypted_token, hash_key)
35
+ decrypt_key(secret, encrypted_token, hash_key)
36
+ rescue OpenSSL::Cipher::CipherError => e
37
+ return false, {}
38
+ end
39
+
40
+ protected
41
+
42
+ def decrypt_key(secret, encrypted_token, hash_key)
43
+ verifier = Fernet.verifier(secret, encrypted_token)
44
+ verifier.enforce_ttl = false
45
+ unless verifier.valid?
46
+ return false, {}
47
+ end
48
+ [true, verifier.data[hash_key]]
49
+ end
50
+
51
+ def encrypt_key_with_secret(hash_key, value, secret)
52
+ Fernet.generate(secret) do |gen|
53
+ gen.data = {hash_key => value}
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,25 @@
1
+ class Relish
2
+ class Release
3
+
4
+ attr_accessor :item
5
+
6
+ def self.schema(attrs)
7
+ attrs.each do |attr, type|
8
+ class_eval "def #{attr}; @item['#{attr}']['#{type}'] if @item.key? '#{attr}' end", __FILE__, __LINE__
9
+ class_eval "def #{attr}= value; @item['#{attr}'] = {'#{type}' => value} end", __FILE__, __LINE__
10
+ end
11
+ end
12
+
13
+ schema :id => :S,
14
+ :version => :N,
15
+ :descr => :S,
16
+ :user_id => :N,
17
+ :slug_id => :S,
18
+ :slug_version => :N,
19
+ :stack => :S,
20
+ :language_pack => :S,
21
+ :env => :S,
22
+ :pstable => :S,
23
+ :addons => :S
24
+ end
25
+ end
data/lib/relish.rb CHANGED
@@ -1,103 +1,28 @@
1
- require "fog"
1
+ require "relish/dynamo_helper"
2
+ require "relish/release"
3
+ require "relish/encryption_helper"
2
4
 
3
5
  class Relish
4
6
 
5
- attr_accessor :item
6
-
7
- def self.conf(*attrs)
8
- attrs.each do |attr|
9
- instance_eval "def #{attr}; @#{attr} end", __FILE__, __LINE__
10
- instance_eval "def #{attr}= value; @#{attr} = value end", __FILE__, __LINE__
11
- end
12
- end
13
-
14
- conf :aws_access_key, :aws_secret_key, :table_name
15
-
16
- def self.schema(attrs)
17
- attrs.each do |attr, type|
18
- class_eval "def #{attr}; @item['#{attr}']['#{type}'] if @item.key? '#{attr}' end", __FILE__, __LINE__
19
- class_eval "def #{attr}= value; @item['#{attr}'] = {'#{type}' => value} end", __FILE__, __LINE__
20
- end
21
- end
22
-
23
- schema :id => :S,
24
- :version => :N,
25
- :descr => :S,
26
- :user_id => :N,
27
- :slug_id => :S,
28
- :slug_version => :N,
29
- :stack => :S,
30
- :language_pack => :S,
31
- :env_json => :S,
32
- :pstable_json => :S,
33
- :addons_json => :S
34
-
35
- def self.db
36
- @db ||= Fog::AWS::DynamoDB.new(:aws_access_key_id => aws_access_key, :aws_secret_access_key => aws_secret_key)
37
- end
38
-
39
- def self.db_query_current_version(id)
40
- response = db.query(table_name, {:S => id}, :ConsistentRead => true, :Limit => 1, :ScanIndexForward => false)
41
- if response.status != 200
42
- raise('status: #{response.status}')
43
- end
44
- if response.body['Count'] == 1
45
- response.body['Items'].first
46
- end
47
- end
48
-
49
- def self.db_put_current_version(item)
50
- response = db.put_item(table_name, item, {:Expected => {:id => {:Exists => false}, :version => {:Exists => false}}})
51
- if response.status != 200
52
- raise('status: #{response.status}')
53
- end
54
- end
55
-
56
- def self.db_get_version(id, version)
57
- response = db.get_item(table_name, {:HashKeyElement => {:S => id}, :RangeKeyElement => {:N => version}})
58
- if response.status != 200
59
- raise('status: #{response.status}')
60
- end
61
- response.body['Item']
62
- end
63
-
64
- def self.db_put_version(id, version, item)
65
- response = db.put_item(table_name, item, {:Expected => {:id => {:Value => {:S => id}}, :version => {:Value => {:N => version}}}})
66
- if response.status != 200
67
- raise('status: #{response.status}')
68
- end
69
- end
70
-
71
- def self.db_put(item)
72
- response = db.put_item(table_name, item)
73
- if response.status != 200
74
- raise('status: #{response.status}')
75
- end
76
- end
77
-
78
- def self.db_query(id, limit)
79
- response = db.query(table_name, {:S => id}, :ConsistentRead => true, :Limit => limit, :ScanIndexForward => false)
80
- if response.status != 200
81
- raise('status: #{response.status}')
82
- end
83
- response.body['Items']
7
+ def initialize(*args)
8
+ @db = DynamoHelper.new(*args)
84
9
  end
85
10
 
86
- def self.copy(id, version, data)
87
- release = new
11
+ def copy(id, version, data)
12
+ release = Release.new
88
13
  release.item = {}
89
14
  release.id = id
90
15
  release.version = version
91
16
  data.each do |k, v|
92
17
  release.send("#{k}=", v.to_s) unless v.nil?
93
18
  end
94
- db_put(release.item)
19
+ @db.put(release.item)
95
20
  release
96
21
  end
97
22
 
98
- def self.create(id, data)
99
- item = db_query_current_version(id)
100
- release = new
23
+ def create(id, data)
24
+ item = @db.query_current_version(id)
25
+ release = Release.new
101
26
  if item.nil?
102
27
  release.item = {}
103
28
  release.id = id
@@ -109,46 +34,46 @@ class Relish
109
34
  data.each do |k, v|
110
35
  release.send("#{k}=", v.to_s) unless v.nil?
111
36
  end
112
- db_put_current_version(release.item)
37
+ @db.put_current_version(release.item)
113
38
  release
114
39
  end
115
40
 
116
- def self.current(id)
117
- item = db_query_current_version(id)
41
+ def current(id)
42
+ item = @db.query_current_version(id)
118
43
  unless item.nil?
119
- release = new
44
+ release = Release.new
120
45
  release.item = item
121
46
  release
122
47
  end
123
48
  end
124
49
 
125
- def self.read(id, version)
126
- item = db_get_version(id, version)
50
+ def read(id, version)
51
+ item = @db.get_version(id, version)
127
52
  unless item.nil?
128
- release = new
53
+ release = Release.new
129
54
  release.item = item
130
55
  release
131
56
  end
132
57
  end
133
58
 
134
- def self.dump(id, limit=nil)
135
- items = db_query(id, limit)
59
+ def dump(id, consistent=nil, limit=nil)
60
+ items = @db.query(id, limit)
136
61
  items.map do |item|
137
- release = new
62
+ release = Release.new
138
63
  release.item = item
139
64
  release
140
65
  end
141
66
  end
142
67
 
143
- def self.update(id, version, data)
144
- item = db_get_version(id, version)
68
+ def update(id, version, data)
69
+ item = @db.get_version(id, version)
145
70
  unless item.nil?
146
- release = new
71
+ release = Release.new
147
72
  release.item = item
148
73
  data.each do |k, v|
149
74
  release.send("#{k}=", v.to_s) unless v.nil?
150
75
  end
151
- db_put_version(id, version, release.item)
76
+ @db.put_version(id, version, release.item)
152
77
  release
153
78
  end
154
79
  end
metadata CHANGED
@@ -1,11 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: relishable
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.6'
4
+ version: '0.7'
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
8
8
  - Mark Fine
9
+ - Blake Gentry
9
10
  autorequire:
10
11
  bindir: bin
11
12
  cert_chain: []
@@ -16,23 +17,42 @@ dependencies:
16
17
  requirement: !ruby/object:Gem::Requirement
17
18
  none: false
18
19
  requirements:
19
- - - ! '>='
20
+ - - ~>
20
21
  - !ruby/object:Gem::Version
21
- version: '0'
22
+ version: '1.6'
22
23
  type: :runtime
23
24
  prerelease: false
24
25
  version_requirements: !ruby/object:Gem::Requirement
25
26
  none: false
26
27
  requirements:
27
- - - ! '>='
28
+ - - ~>
28
29
  - !ruby/object:Gem::Version
29
- version: '0'
30
+ version: '1.6'
31
+ - !ruby/object:Gem::Dependency
32
+ name: fernet
33
+ requirement: !ruby/object:Gem::Requirement
34
+ none: false
35
+ requirements:
36
+ - - ~>
37
+ - !ruby/object:Gem::Version
38
+ version: '1.4'
39
+ type: :runtime
40
+ prerelease: false
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ~>
45
+ - !ruby/object:Gem::Version
46
+ version: '1.4'
30
47
  description: Release manager.
31
48
  email: mark.fine@gmail.com
32
49
  executables: []
33
50
  extensions: []
34
51
  extra_rdoc_files: []
35
52
  files:
53
+ - lib/relish/dynamo_helper.rb
54
+ - lib/relish/encryption_helper.rb
55
+ - lib/relish/release.rb
36
56
  - lib/relish.rb
37
57
  - Gemfile
38
58
  - Gemfile.lock