cabal-api 0.0.1 → 0.0.3

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: 4f688c08e5f4980a83b4aafcc40a8d17bc380207
4
- data.tar.gz: ac046c92c6b2abff293cae3e6acd664b055ec003
3
+ metadata.gz: 633175e3c38cc1c65baddaedcd27f2759e89a1af
4
+ data.tar.gz: b547ecf19c5443809c21be14cc22fe1466055962
5
5
  SHA512:
6
- metadata.gz: b8cc784a699804d19c30a8b6dc5d9adab2c5e805ed6d6ca6054979a6396ee8495e6616b7110f2f1c3dca553ecdb0e615da70b4fb9920fc0d17b5a2c6faf03cf5
7
- data.tar.gz: ae0cbe3a2d79b6882498f5a5dccb3aa9bf3a1f28702dbf288b077e33be547374eefbe2719e68f676bf456c3ffc9d865d3350e29271766c29a35926e2577c0b6b
6
+ metadata.gz: d5d78bb2f96f4d25a08d85edbb72cb376ddfb008d838364d61c4ed2be0a0c9859876072ddfc06f58888df3b9cacb355af26a2cd9bd7e53788123ecbc79d6ec4c
7
+ data.tar.gz: a3c43b4d082fb850033607e999467e214cdc557641145ac41b356606bbae08843c5e5cec6939dca697ab9c02b4af63b9d2a502d538482cbe1aeaefe2268b60f0
data/cabal-api.gemspec CHANGED
@@ -24,8 +24,13 @@ Gem::Specification.new do |spec|
24
24
  spec.add_development_dependency "rack-test", '~> 0.6'
25
25
  spec.add_development_dependency "rspec", '~> 3.3'
26
26
  spec.add_development_dependency "factis", '~> 1.0'
27
- spec.add_development_dependency "fakeredis", '~> 0.5'
28
27
  spec.add_development_dependency "simplecov", '~> 0.10'
28
+ spec.add_development_dependency "redis"
29
+ spec.add_development_dependency "database_cleaner"
29
30
  spec.add_runtime_dependency "cabal", '~> 0.2'
30
31
  spec.add_runtime_dependency "grape", '~> 0.13'
32
+ spec.add_runtime_dependency "ohm"
33
+ spec.add_runtime_dependency "ohm-contrib"
34
+ spec.add_runtime_dependency "bcrypt"
35
+ spec.add_runtime_dependency "sshkey"
31
36
  end
@@ -1,10 +1,12 @@
1
1
  require 'grape'
2
2
  require 'cabal/api/v1/base'
3
+ require 'cabal/api/v2/base'
3
4
 
4
5
  module Cabal
5
6
  module API
6
7
  class Base < Grape::API
7
8
  mount Cabal::API::V1::Base
9
+ mount Cabal::API::V2::Base
8
10
  end
9
11
  end
10
12
  end
@@ -0,0 +1,39 @@
1
+ require 'ohm'
2
+ require 'ohm/contrib'
3
+ require 'sshkey'
4
+ require 'cabal/util'
5
+
6
+ module Cabal
7
+ module API
8
+ class Cluster < Ohm::Model
9
+ include Ohm::Callbacks
10
+
11
+ # The secret key should not be saved plain, but we want to access it
12
+ # immediately after creation
13
+ attr_accessor :secret_key
14
+
15
+ attribute :name
16
+ attribute :private_key
17
+ attribute :public_key
18
+
19
+ # Enable lookups via cluster name
20
+ index :name
21
+
22
+ # Ensure that cluster name is unique
23
+ unique :name
24
+
25
+ def before_create
26
+ self.name = Cabal::Util.normalize(name)
27
+
28
+ sshkey = SSHKey.generate(type: 'RSA', bits: 2048, comment: "#{name}-cabal")
29
+ self.private_key = sshkey.private_key
30
+ self.public_key = sshkey.ssh_public_key
31
+ end
32
+
33
+ def self.by_cluster_name(name)
34
+ name = Cabal::Util.normalize(name)
35
+ find(name: name).first || create(name: name)
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,30 @@
1
+ require 'cabal/api/user'
2
+
3
+ module Cabal
4
+ module API
5
+ module Common
6
+ module Authenticated
7
+ def self.included(base)
8
+ base.class_eval do
9
+ helpers do
10
+ def current_user
11
+ authorization = headers['Authorization'].to_s
12
+ access_key, signature = authorization.split(':')
13
+ user = Cabal::API::User.find(access_key: access_key).first
14
+ if user && user.authenticated_with?(signature)
15
+ user
16
+ else
17
+ nil
18
+ end
19
+ end
20
+
21
+ def authenticate!
22
+ error!({message: 'Unauthorized.'}, 401) unless current_user
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,21 @@
1
+ module Cabal
2
+ module API
3
+ module Common
4
+ module Mistakes
5
+ def self.included(base)
6
+ base.class_eval do
7
+ error_formatter :txt, ->(message, backtrace, options, env) {
8
+ message[:message]
9
+ }
10
+
11
+ helpers do
12
+ def messagify(message)
13
+ {message: message}
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,26 @@
1
+ require 'cabal/util'
2
+ require 'cabal/api/cluster'
3
+
4
+ module Cabal
5
+ module API
6
+ module Common
7
+ module PublicKey
8
+ def self.included(base)
9
+ base.class_eval do
10
+ formatter :txt, ->(object, env) {
11
+ object[:public_ssh_key]
12
+ }
13
+
14
+ get '/key/:name' do
15
+ cluster = Cabal::API::Cluster.by_cluster_name(params[:name])
16
+ {
17
+ name: cluster.name,
18
+ public_ssh_key: cluster.public_key
19
+ }
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1 @@
1
+ require 'cabal/api/common/public_key'
@@ -0,0 +1,49 @@
1
+ require 'ohm'
2
+ require 'ohm/contrib'
3
+ require 'bcrypt'
4
+ require 'securerandom'
5
+
6
+ module Cabal
7
+ module API
8
+ class User < Ohm::Model
9
+ include Ohm::Callbacks
10
+
11
+ # The secret key should not be saved plain, but we want to access it
12
+ # immediately after creation
13
+ attr_accessor :secret_key
14
+
15
+ attribute :email
16
+ attribute :access_key
17
+ attribute :crypted_secret_key
18
+
19
+ # Enable lookups via either the user's email or their access key.
20
+ index :email
21
+ index :access_key
22
+
23
+ # Ensure that email and access keys are unique
24
+ unique :email
25
+ unique :access_key
26
+
27
+ def before_create
28
+ set_access_key
29
+ set_secret_key
30
+ end
31
+
32
+ def authenticated_with?(secret_key)
33
+ return false unless crypted_secret_key
34
+
35
+ BCrypt::Password.new(crypted_secret_key) == secret_key
36
+ end
37
+
38
+ private
39
+ def set_access_key
40
+ self.access_key = SecureRandom.hex(16)
41
+ end
42
+
43
+ def set_secret_key
44
+ self.secret_key = SecureRandom.hex(32)
45
+ self.crypted_secret_key = BCrypt::Password.create(secret_key)
46
+ end
47
+ end
48
+ end
49
+ end
@@ -1,6 +1,5 @@
1
1
  require 'grape'
2
2
  require 'cabal/api/v1/public_key'
3
- #require 'cabal/api/v1/keys'
4
3
 
5
4
  module Cabal
6
5
  module API
@@ -1,22 +1,12 @@
1
1
  require 'grape'
2
- require 'cabal/cluster'
3
2
  require 'cabal/util'
3
+ require 'cabal/api/common'
4
4
 
5
5
  module Cabal
6
6
  module API
7
7
  module V1
8
8
  class PublicKey < Grape::API
9
- formatter :txt, ->(object, env) {
10
- object[:public_ssh_key]
11
- }
12
-
13
- get '/key/:name' do
14
- name = Cabal::Util.normalize(params[:name])
15
- {
16
- name: name,
17
- public_ssh_key: Cabal::Cluster.new(name).public_ssh_key
18
- }
19
- end
9
+ include Cabal::API::Common::PublicKey
20
10
  end
21
11
  end
22
12
  end
@@ -0,0 +1,16 @@
1
+ require 'grape'
2
+ require 'cabal/api/v2/public_key'
3
+ require 'cabal/api/v2/private_key'
4
+
5
+ module Cabal
6
+ module API
7
+ module V2
8
+ class Base < Grape::API
9
+ version 'v2', using: :path
10
+
11
+ mount Cabal::API::V2::PublicKey
12
+ mount Cabal::API::V2::PrivateKey
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,46 @@
1
+ require 'grape'
2
+ require 'cabal/util'
3
+ require 'cabal/api/cluster'
4
+ require 'cabal/api/user'
5
+ require 'cabal/api/common/authenticated'
6
+ require 'cabal/api/common/mistakes'
7
+
8
+ module Cabal
9
+ module API
10
+ module V2
11
+ class PrivateKey < Grape::API
12
+ include Cabal::API::Common::Authenticated
13
+ include Cabal::API::Common::Mistakes
14
+
15
+ formatter :txt, ->(object, env) {
16
+ object[:private_ssh_key]
17
+ }
18
+
19
+ helpers do
20
+ def error_if_not_found!(cluster, name)
21
+ unless cluster
22
+ error!(
23
+ messagify("The cluster '#{name}' could not be found."),
24
+ 404
25
+ )
26
+ end
27
+ end
28
+ end
29
+
30
+ get '/private-key/:name' do
31
+ authenticate!
32
+
33
+ cluster_name = Cabal::Util.normalize(params[:name])
34
+ cluster = Cabal::API::Cluster.find(name: cluster_name).first
35
+
36
+ error_if_not_found!(cluster, cluster_name)
37
+
38
+ {
39
+ name: cluster.name,
40
+ private_ssh_key: cluster.private_key
41
+ }
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,13 @@
1
+ require 'grape'
2
+ require 'cabal/util'
3
+ require 'cabal/api/common'
4
+
5
+ module Cabal
6
+ module API
7
+ module V2
8
+ class PublicKey < Grape::API
9
+ include Cabal::API::Common::PublicKey
10
+ end
11
+ end
12
+ end
13
+ end
@@ -1,5 +1,5 @@
1
1
  module Cabal
2
2
  module Api
3
- VERSION = "0.0.1"
3
+ VERSION = "0.0.3"
4
4
  end
5
5
  end
data/lib/cabal/api.rb CHANGED
@@ -1,7 +1,11 @@
1
- require "cabal/api/version"
2
- require "cabal/api/base"
1
+ require 'ohm'
2
+ require 'cabal/api/version'
3
+ require 'cabal/api/base'
4
+ require 'cabal/api/cluster'
5
+ require 'cabal/api/user'
3
6
 
4
7
  module Cabal
5
8
  module Api
9
+ Ohm.redis = Redic.new(ENV['REDIS_URL'] || 'redis://localhost:6379')
6
10
  end
7
11
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cabal-api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dennis Walters
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2015-10-12 00:00:00.000000000 Z
11
+ date: 2015-10-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -95,33 +95,47 @@ dependencies:
95
95
  - !ruby/object:Gem::Version
96
96
  version: '1.0'
97
97
  - !ruby/object:Gem::Dependency
98
- name: fakeredis
98
+ name: simplecov
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: '0.5'
103
+ version: '0.10'
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: '0.5'
110
+ version: '0.10'
111
111
  - !ruby/object:Gem::Dependency
112
- name: simplecov
112
+ name: redis
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
- - - "~>"
115
+ - - ">="
116
116
  - !ruby/object:Gem::Version
117
- version: '0.10'
117
+ version: '0'
118
118
  type: :development
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
- - - "~>"
122
+ - - ">="
123
123
  - !ruby/object:Gem::Version
124
- version: '0.10'
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: database_cleaner
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
125
139
  - !ruby/object:Gem::Dependency
126
140
  name: cabal
127
141
  requirement: !ruby/object:Gem::Requirement
@@ -150,6 +164,62 @@ dependencies:
150
164
  - - "~>"
151
165
  - !ruby/object:Gem::Version
152
166
  version: '0.13'
167
+ - !ruby/object:Gem::Dependency
168
+ name: ohm
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ type: :runtime
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
181
+ - !ruby/object:Gem::Dependency
182
+ name: ohm-contrib
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - ">="
186
+ - !ruby/object:Gem::Version
187
+ version: '0'
188
+ type: :runtime
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - ">="
193
+ - !ruby/object:Gem::Version
194
+ version: '0'
195
+ - !ruby/object:Gem::Dependency
196
+ name: bcrypt
197
+ requirement: !ruby/object:Gem::Requirement
198
+ requirements:
199
+ - - ">="
200
+ - !ruby/object:Gem::Version
201
+ version: '0'
202
+ type: :runtime
203
+ prerelease: false
204
+ version_requirements: !ruby/object:Gem::Requirement
205
+ requirements:
206
+ - - ">="
207
+ - !ruby/object:Gem::Version
208
+ version: '0'
209
+ - !ruby/object:Gem::Dependency
210
+ name: sshkey
211
+ requirement: !ruby/object:Gem::Requirement
212
+ requirements:
213
+ - - ">="
214
+ - !ruby/object:Gem::Version
215
+ version: '0'
216
+ type: :runtime
217
+ prerelease: false
218
+ version_requirements: !ruby/object:Gem::Requirement
219
+ requirements:
220
+ - - ">="
221
+ - !ruby/object:Gem::Version
222
+ version: '0'
153
223
  description:
154
224
  email:
155
225
  - dwalters@engineyard.com
@@ -172,8 +242,17 @@ files:
172
242
  - config/cucumber.yml
173
243
  - lib/cabal/api.rb
174
244
  - lib/cabal/api/base.rb
245
+ - lib/cabal/api/cluster.rb
246
+ - lib/cabal/api/common.rb
247
+ - lib/cabal/api/common/authenticated.rb
248
+ - lib/cabal/api/common/mistakes.rb
249
+ - lib/cabal/api/common/public_key.rb
250
+ - lib/cabal/api/user.rb
175
251
  - lib/cabal/api/v1/base.rb
176
252
  - lib/cabal/api/v1/public_key.rb
253
+ - lib/cabal/api/v2/base.rb
254
+ - lib/cabal/api/v2/private_key.rb
255
+ - lib/cabal/api/v2/public_key.rb
177
256
  - lib/cabal/api/version.rb
178
257
  homepage: http://github.com/ess/cabal-api
179
258
  licenses: