bacchus 0.0.9 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/bacchus.rb CHANGED
@@ -1,2 +1,4 @@
1
1
  require "bacchus/version"
2
+ require "bacchus/access_pass"
3
+ require "bacchus/backend"
2
4
  require "bacchus/rack/beta_site"
@@ -0,0 +1,24 @@
1
+ module Bacchus
2
+ class AccessPass # TODO: AccessCode elsewhere (backend, see other places).
3
+ PARAM_KEY = "access_pass"
4
+ COOKIE_KEY = "access_pass"
5
+
6
+ def self.get(request)
7
+ AccessPass.new(request)
8
+ end
9
+
10
+ def initialize(request)
11
+ param = request.params[PARAM_KEY]
12
+ @pass = param || request.cookies[COOKIE_KEY] || ""
13
+ @updated = !param.nil? && !param.empty?
14
+ end
15
+
16
+ def maybe_save(response)
17
+ response.set_cookie(COOKIE_KEY, @pass) if @updated
18
+ end
19
+
20
+ def to_s
21
+ @pass
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,21 @@
1
+ require 'rest_client'
2
+
3
+ module Bacchus
4
+ class Backend
5
+ def initialize(base_url)
6
+ @base_url = base_url
7
+ end
8
+
9
+ def locked?(access_pass)
10
+ RestClient.get(path_to("/api/1/access/#{access_pass.to_s}")) do |response, _|
11
+ return response.code != 200
12
+ end
13
+ end
14
+
15
+ def path_to(resource)
16
+ File.join(@base_url, resource)
17
+ end
18
+ end
19
+ end
20
+
21
+
@@ -21,31 +21,48 @@ module Rack
21
21
  @excluded_routes = options[:except] || []
22
22
  @access_form_routes = options[:access_through] || []
23
23
  @access_template_route = options[:access_template] or raise "Specify the route to the template for the access form."
24
- @server = options[:server] or raise "Specify the address of the server."
24
+ base_url = options[:backend] or raise "Specify the address of the backend server."
25
+ @backend = Bacchus::Backend.new(base_url)
25
26
  end
26
27
 
27
28
  def call(env)
28
29
  request = Request.new(env)
29
- if access_form_route?(request)
30
- request.path = @access_template_route
31
- env["PATH_INFO"] = request.path
32
- env["REQUEST_URI"] = request.fullpath
33
- render_with_bacchus(env)
34
- elsif access_denied?(request)
35
- render_locked
36
- else
37
- @app.call(env)
38
- end
30
+ access_pass = Bacchus::AccessPass.get(request)
31
+ status, headers, body = respond_to(request, access_pass)
32
+ response = Response.new(body, status, headers)
33
+ access_pass.maybe_save(response)
34
+ response.finish
39
35
  end
40
36
 
41
37
  private
38
+
39
+ def respond_to(request, access_pass)
40
+ if @backend.locked?(access_pass)
41
+ if access_form_route?(request)
42
+ return render_with_bacchus(redirect(request, @access_template_route))
43
+ elsif access_denied?(request)
44
+ return render_locked
45
+ end
46
+ end
47
+
48
+ @app.call(request.env)
49
+ end
50
+
51
+ def redirect(original_request, path)
52
+ request = original_request.dup
53
+ request.path = @access_template_route
54
+ env = request.env
55
+ env["PATH_INFO"] = request.path
56
+ env["REQUEST_URI"] = request.fullpath
57
+ Request.new(env)
58
+ end
42
59
 
43
60
  def access_form_route?(request) # TODO: Duplication -- access_denied? & excluded_route?
44
61
  @access_form_routes.index {|route| matching_path?(request, route)}
45
62
  end
46
63
 
47
- def render_with_bacchus(env)
48
- status, headers, body = @app.call(env)
64
+ def render_with_bacchus(request)
65
+ status, headers, body = @app.call(request.env)
49
66
  script = <<-EOS
50
67
  <script src="#{path_to('bacchus.js')}" type="text/javascript"></script>
51
68
  EOS
@@ -57,7 +74,7 @@ module Rack
57
74
  ########################################################
58
75
 
59
76
  def path_to(file)
60
- ::File.join(@server, file)
77
+ @backend.path_to(file)
61
78
  end
62
79
 
63
80
  ########################################################
@@ -1,3 +1,3 @@
1
1
  module Bacchus
2
- VERSION = "0.0.9"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -0,0 +1,54 @@
1
+ require_relative '../../lib/bacchus/access_pass'
2
+
3
+ module Bacchus
4
+ describe AccessPass do
5
+ let(:request) { mock("request") }
6
+ let(:access_pass) { "399tehu" }
7
+
8
+ before(:each) do
9
+ request.stub!(:params).and_return({})
10
+ request.stub!(:cookies).and_return({})
11
+ end
12
+
13
+ context "retrieving" do
14
+ it "should try to get it from request params" do
15
+ request.should_receive(:params).and_return({})
16
+ AccessPass.get(request)
17
+ end
18
+
19
+ it "should get it from params if present" do
20
+ request.stub!(:params).and_return("access_pass" => access_pass)
21
+ AccessPass.get(request).to_s.should == access_pass
22
+ end
23
+
24
+ it "should get it from cookies if not in params" do
25
+ request.stub!(:params).and_return({})
26
+ request.should_receive(:cookies).and_return("access_pass" => access_pass)
27
+ AccessPass.get(request).to_s.should == access_pass
28
+ end
29
+
30
+ it "should be empty if neither in params nor in cookies" do
31
+ request.stub!(:params).and_return({})
32
+ request.stub!(:cookies).and_return({})
33
+ AccessPass.get(request).to_s.should == ""
34
+ end
35
+ end
36
+
37
+ context "saving" do
38
+ let(:response) { mock("response") }
39
+
40
+ it "should save if updated from params" do
41
+ request.stub!(:params).and_return("access_pass" => access_pass)
42
+ response.should_receive(:set_cookie).with("access_pass", access_pass)
43
+ AccessPass.get(request).maybe_save(response)
44
+ end
45
+
46
+ it "should not save if not updated" do
47
+ request.stub!(:params).and_return({})
48
+ request.stub!(:cookies).and_return("access_pass" => access_pass)
49
+ response.should_not_receive(:set_cookie)
50
+ AccessPass.get(request).maybe_save(response)
51
+ end
52
+ end
53
+ end
54
+ end
@@ -1,47 +1,95 @@
1
1
  require 'rack/mock'
2
2
  require_relative '../../../lib/bacchus/rack/beta_site'
3
+ require_relative '../../../lib/bacchus/backend'
4
+ require_relative '../../../lib/bacchus/access_pass'
3
5
 
4
6
  describe Rack::BetaSite do
5
7
  let(:app) { lambda { |env| app_response } }
6
8
  let(:app_response) { [200, { 'Content-Type' => 'text/plain' }, ['<body>hello</body>']] }
7
9
  let(:access_template_route) { "/access_template" }
8
- let(:middleware) { Rack::BetaSite.new(app, except: ["/", %r{^/open/?$}], access_through: ["/form"], server: "localhost", access_template: access_template_route) }
10
+ let(:backend) { mock("backend").as_null_object }
11
+ let(:access_pass) { mock("access_pass").as_null_object }
12
+ let(:middleware) { Rack::BetaSite.new(app, except: ["/", %r{^/open/?$}], access_through: ["/form"], backend: "localhost", access_template: access_template_route) }
13
+
14
+ before(:each) do
15
+ Bacchus::Backend.stub!(:new).and_return(backend)
16
+ Bacchus::AccessPass.stub!(:get).and_return(access_pass)
17
+ end
9
18
 
10
19
  def response_for(sample_app, path)
11
20
  sample_app.call(Rack::MockRequest.env_for(path))
12
21
  end
13
22
 
23
+ it "should query the backend if the site is locked" do
24
+ request = mock("request").as_null_object
25
+ Rack::Request.stub!(:new).and_return(request)
26
+ Bacchus::AccessPass.should_receive(:get).with(request).and_return(access_pass)
27
+ backend.should_receive(:locked?).with(access_pass)
28
+ response_for(middleware, "/")
29
+ end
30
+
14
31
  context "given a locked site" do
32
+
33
+ before(:each) do
34
+ backend.stub!(:locked?).and_return(true)
35
+ end
36
+
15
37
  it "should block access to all pages" do
16
- sample_app = middleware
17
38
  status, * = response_for(middleware, "/page1")
18
39
  status.should == 500
19
40
  end
20
41
 
21
42
  it "should support string exceptions" do
22
- sample_app = middleware
23
43
  status, * = response_for(middleware, "/")
24
44
  status.should == 200
25
45
  end
26
46
 
27
47
  it "should support regex exceptions" do
28
- sample_app = middleware
29
48
  status, * = response_for(middleware, "/open")
30
49
  status.should == 200
31
50
  end
32
51
 
33
52
  it "should render access form script after the body closing tag" do
34
- sample_app = middleware
35
- status, _, body = response_for(middleware, "/form")
53
+ status, _, res = response_for(middleware, "/form")
36
54
  status.should == 200
37
- body.first.should include("hello")
38
- body.first.should include("</body>\n<script")
55
+ res.body.first.should include("hello")
56
+ res.body.first.should include("</body>\n<script")
39
57
  end
40
58
 
41
59
  it "should redirect to access template" do
42
- sample_app = middleware
43
60
  app.should_receive(:call).with(hash_including("PATH_INFO" => "/access_template")).and_return(app_response)
44
61
  response_for(middleware, "/form")
45
62
  end
46
63
  end
64
+
65
+ context "given an unlocked site" do
66
+ before(:each) do
67
+ backend.stub!(:locked?).and_return(false)
68
+ end
69
+
70
+ it "should allow access to all pages" do
71
+ status, * = response_for(middleware, "/page1")
72
+ status.should == 200
73
+ end
74
+
75
+ it "should not render access form script" do
76
+ status, _, res = response_for(middleware, "/form")
77
+ status.should == 200
78
+ res.body.first.should_not include("</body>\n<script")
79
+ end
80
+ end
81
+
82
+ context "should save access code" do
83
+ let(:response) { mock("response").as_null_object }
84
+ let(:access_pass) { mock("access_pass") }
85
+
86
+ before(:each) do
87
+ Rack::Response.stub!(:new).and_return(response)
88
+ end
89
+
90
+ it "should not set if not present" do
91
+ access_pass.should_receive(:maybe_save).with(response)
92
+ response_for(middleware, "/")
93
+ end
94
+ end
47
95
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bacchus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.9
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,8 +9,24 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-11-03 00:00:00.000000000 Z
13
- dependencies: []
12
+ date: 2012-11-06 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rest-client
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
14
30
  description: Adds support for private beta invites for Rack-based apps.
15
31
  email:
16
32
  - gyamtso@gmail.com
@@ -20,9 +36,12 @@ extra_rdoc_files: []
20
36
  files:
21
37
  - README.md
22
38
  - LICENSE.txt
39
+ - lib/bacchus/access_pass.rb
40
+ - lib/bacchus/backend.rb
23
41
  - lib/bacchus/rack/beta_site.rb
24
42
  - lib/bacchus/version.rb
25
43
  - lib/bacchus.rb
44
+ - spec/bacchus/access_pass_spec.rb
26
45
  - spec/bacchus/rack/beta_site_spec.rb
27
46
  homepage: ''
28
47
  licenses: []
@@ -49,4 +68,5 @@ signing_key:
49
68
  specification_version: 3
50
69
  summary: Beta invites for Rack-based apps.
51
70
  test_files:
71
+ - spec/bacchus/access_pass_spec.rb
52
72
  - spec/bacchus/rack/beta_site_spec.rb