vanilla 1.9.11.1 → 1.9.12

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -25,7 +25,7 @@ if Object.const_defined?(:Gem)
25
25
 
26
26
  # Change these as appropriate
27
27
  s.name = "vanilla"
28
- s.version = "1.9.11.1"
28
+ s.version = "1.9.12"
29
29
  s.summary = "A bliki-type web content thing."
30
30
  s.author = "James Adam"
31
31
  s.email = "james@lazyatom.com.com"
@@ -47,6 +47,7 @@ if Object.const_defined?(:Gem)
47
47
  s.add_dependency("RedCloth", ">= 4.1.1")
48
48
  s.add_dependency("BlueCloth", ">= 1.0.0")
49
49
  s.add_dependency("treetop", ">= 1.4.1")
50
+ s.add_dependency("warden", ">= 0.5.2")
50
51
 
51
52
  s.add_development_dependency("rspec") # add any other gems for testing/development
52
53
 
data/config.ru CHANGED
@@ -2,9 +2,19 @@ $:.unshift File.join(File.dirname(__FILE__), *%w[lib])
2
2
  require 'vanilla'
3
3
 
4
4
  app = Vanilla::App.new(ENV['VANILLA_CONFIG'])
5
+
5
6
  use Rack::Session::Cookie, :key => 'vanilla.session',
6
7
  :path => '/',
7
8
  :expire_after => 2592000,
8
9
  :secret => app.config[:secret]
10
+
11
+ require 'vanilla/authentication/warden'
12
+ app.authenticator = Vanilla::Authentication::Warden.new(app)
13
+ use Warden::Manager do |manager|
14
+ manager.default_strategies :vanilla
15
+ manager.failure_app = lambda{|e| [401, {"Content-Type" => "text/plain"}, ["Fail App"]]}
16
+ end
17
+
9
18
  use Rack::Static, :urls => ["/public"], :root => File.join(File.dirname(__FILE__))
10
- run app
19
+
20
+ run app
data/lib/vanilla/app.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'vanilla/request'
2
+ require 'vanilla/authentication'
2
3
  require 'vanilla/routes'
3
4
  require 'vanilla/soup_with_timestamps'
4
5
 
@@ -11,16 +12,19 @@ require 'vanilla/renderers/erb'
11
12
  module Vanilla
12
13
  class App
13
14
  include Routes
14
-
15
+
15
16
  attr_reader :request, :response, :config, :soup
16
-
17
+ attr_accessor :authenticator
18
+
17
19
  def initialize(config_file=nil)
18
20
  prepare_configuration(config_file)
19
21
  @soup = SoupWithTimestamps.new(config[:soup])
22
+ @authenticator = Vanilla::Authentication::Base.new(self)
20
23
  end
21
-
24
+
22
25
  # Returns a Rack-appropriate 3-element array (via Rack::Response#finish)
23
26
  def call(env)
27
+ env['vanilla.app'] = self
24
28
  @request = Vanilla::Request.new(env, self)
25
29
  @response = Rack::Response.new
26
30
 
@@ -30,7 +34,7 @@ module Vanilla
30
34
  @response.status = 500
31
35
  output = e.to_s
32
36
  end
33
- response_format = request.format
37
+ response_format = request.format
34
38
  response_format = 'plain' if response_format == 'raw'
35
39
  @response['Content-Type'] = "text/#{response_format}"
36
40
  @response.write(output)
@@ -59,34 +63,34 @@ module Vanilla
59
63
  end
60
64
  end
61
65
 
62
- # Given the snip and parameters, yield an instance of the appropriate
66
+ # Given the snip and parameters, yield an instance of the appropriate
63
67
  # Vanilla::Render::Base subclass
64
68
  def rendering(snip)
65
69
  renderer_instance = renderer_for(snip).new(self)
66
70
  yield renderer_instance
67
71
  rescue Exception => e
68
- "<pre>[Error rendering '#{snip.name}' - \"" +
69
- e.message.gsub("<", "&lt;").gsub(">", "&gt;") + "\"]\n" +
72
+ "<pre>[Error rendering '#{snip.name}' - \"" +
73
+ e.message.gsub("<", "&lt;").gsub(">", "&gt;") + "\"]\n" +
70
74
  e.backtrace.join("\n").gsub("<", "&lt;").gsub(">", "&gt;") + "</pre>"
71
75
  end
72
-
76
+
73
77
  # Returns the renderer class for a given snip
74
78
  def renderer_for(snip)
75
79
  return Renderers::Base unless snip.render_as && !snip.render_as.empty?
76
80
  Vanilla::Renderers.const_get(snip.render_as)
77
81
  end
78
-
82
+
79
83
  # Other things can call this when a snip cannot be loaded.
80
84
  def render_missing_snip(snip_name)
81
85
  "[snip '#{snip_name}' cannot be found]"
82
86
  end
83
-
87
+
84
88
  def snip(attributes)
85
89
  @soup.new_snip(attributes)
86
90
  end
87
-
91
+
88
92
  private
89
-
93
+
90
94
  def prepare_configuration(config_file)
91
95
  config_file ||= "config.yml"
92
96
  @config = YAML.load(File.open(config_file)) rescue {}
@@ -0,0 +1,42 @@
1
+ require 'warden'
2
+
3
+ module Vanilla
4
+ module Authentication
5
+ class Warden < Base
6
+ def initialize(app)
7
+ super
8
+ ::Warden::Strategies.add(:vanilla, Vanilla::Authentication::Warden::Strategy)
9
+ end
10
+
11
+ def authenticated?
12
+ @app.request.env['warden'].authenticated?
13
+ end
14
+
15
+ def user
16
+ @app.request.env['warden'].user
17
+ end
18
+
19
+ def authenticate!
20
+ @app.request.env['warden'].authenticate!
21
+ end
22
+
23
+ def logout
24
+ @app.request.env['warden'].logout
25
+ end
26
+
27
+ class Strategy < ::Warden::Strategies::Base
28
+ def valid?
29
+ params["name"] || params["password"]
30
+ end
31
+
32
+ def authenticate!
33
+ if env['vanilla.app'].config[:credentials][params["name"]] == MD5.md5(params["password"]).to_s
34
+ success!(params["name"])
35
+ else
36
+ redirect!("/login")
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,24 @@
1
+ module Vanilla
2
+ module Authentication
3
+ # A pass-through authenticator, which never
4
+ # requires a login
5
+ class Base
6
+ def initialize(app)
7
+ @app = app
8
+ end
9
+
10
+ def authenticated?
11
+ true
12
+ end
13
+
14
+ def user
15
+ end
16
+
17
+ def authenticate!
18
+ end
19
+
20
+ def logout
21
+ end
22
+ end
23
+ end
24
+ end
@@ -4,18 +4,18 @@ require 'vanilla/dynasnips/login'
4
4
  # The edit dyna will load the snip given in the 'snip_to_edit' part of the
5
5
  # params
6
6
  class EditSnip < Dynasnip
7
- include Login::Helper
8
-
9
7
  snip_name "edit"
10
-
8
+
11
9
  def get(snip_name=nil)
12
- return login_required unless logged_in?
10
+ app.request.authenticate!
11
+
13
12
  snip = app.soup[snip_name || app.request.params[:name]]
14
13
  edit(snip)
15
14
  end
16
-
15
+
17
16
  def post(*args)
18
- return login_required unless logged_in?
17
+ app.request.authenticate!
18
+
19
19
  snip_attributes = cleaned_params
20
20
  snip_attributes.delete(:save_button)
21
21
  return 'no params' if snip_attributes.empty?
@@ -29,20 +29,20 @@ class EditSnip < Dynasnip
29
29
  app.soup << snip_attributes
30
30
  %{Created snip #{link_to snip_attributes[:name]} ok}
31
31
  end
32
-
32
+
33
33
  def edit(snip)
34
34
  renderer = Vanilla::Renderers::Erb.new(app)
35
35
  renderer.instance_eval { @snip_to_edit = snip } # hacky!
36
36
  snip_in_edit_template = renderer.render_without_including_snips(app.soup['edit'], :template)
37
37
  prevent_snip_inclusion(snip_in_edit_template)
38
38
  end
39
-
39
+
40
40
  private
41
-
41
+
42
42
  def prevent_snip_inclusion(content)
43
43
  content.gsub("{", "&#123;").gsub("}" ,"&#125;")
44
44
  end
45
-
45
+
46
46
  attribute :template, %{
47
47
  <form action="<%= url_to 'edit' %>" method="post">
48
48
  <dl class="attributes">
@@ -57,4 +57,4 @@ class EditSnip < Dynasnip
57
57
  <button name='save_button'>Save</button>
58
58
  </form>
59
59
  }
60
- end
60
+ end
@@ -3,43 +3,27 @@ require 'yaml'
3
3
  require 'md5'
4
4
 
5
5
  class Login < Dynasnip
6
- module Helper
7
- def logged_in?
8
- !current_user.nil?
9
- end
10
-
11
- def current_user
12
- app.request.session['logged_in_as']
13
- end
14
-
15
- def login_required
16
- "You need to <a href='/login'>login</a> to do that."
17
- end
18
- end
19
- include Helper
20
-
21
6
  def get(*args)
22
- if logged_in?
7
+ if app.request.authenticated?
23
8
  login_controls
24
9
  else
25
10
  render(self, 'template')
26
11
  end
27
12
  end
28
-
13
+
29
14
  def post(*args)
30
- if app.config[:credentials][cleaned_params[:name]] == MD5.md5(cleaned_params[:password]).to_s
31
- app.request.session['logged_in_as'] = cleaned_params[:name]
15
+ if app.request.authenticate!
32
16
  login_controls
33
17
  else
34
18
  "login fail!"
35
19
  end
36
20
  end
37
-
21
+
38
22
  def delete(*args)
39
- app.request.session['logged_in_as'] = nil
23
+ app.request.logout
40
24
  "Logged out"
41
25
  end
42
-
26
+
43
27
  attribute :template, <<-EHTML
44
28
  <form action='/login' method='post'>
45
29
  <label>Name: <input type="text" name="name"></input></label>
@@ -47,10 +31,10 @@ class Login < Dynasnip
47
31
  <button>login</button>
48
32
  </form>
49
33
  EHTML
50
-
34
+
51
35
  private
52
-
36
+
53
37
  def login_controls
54
- "logged in as {link_to #{app.request.session['logged_in_as']}}; <a href='/login?_method=delete'>logout</a>"
38
+ "logged in as #{link_to app.request.user}; <a href='/login?_method=delete'>logout</a>"
55
39
  end
56
40
  end
@@ -2,13 +2,14 @@ require 'vanilla/dynasnip'
2
2
  require 'vanilla/dynasnips/login'
3
3
 
4
4
  class NewSnip < Dynasnip
5
- include Login::Helper
6
-
5
+ # include Login::Helper
6
+
7
7
  snip_name :new
8
-
8
+
9
9
  def handle(*arg)
10
- return login_required unless logged_in?
10
+ app.request.authenticate!
11
+
11
12
  base_params = {:render_as => '', :content => '', :author => current_user}.update(app.request.params)
12
13
  editor = EditSnip.new(app).edit(Snip.new(base_params))
13
14
  end
14
- end
15
+ end
@@ -4,9 +4,10 @@ module Vanilla
4
4
  # Create a request with symbolised access to the params, and some special
5
5
  # accessors to the snip, part and format based on our routing.
6
6
  class Request
7
- attr_reader :snip_name, :part, :format, :method
8
-
7
+ attr_reader :snip_name, :part, :format, :method, :env
8
+
9
9
  def initialize(env, app)
10
+ @env = env
10
11
  @rack_request = Rack::Request.new(env)
11
12
  @app = app
12
13
  determine_request_uri_parts
@@ -16,41 +17,57 @@ module Vanilla
16
17
  # Don't you just love how terse functional programming tends to look like maths?
17
18
  @symbolised_params ||= @rack_request.params.inject({}) { |p, (k,v)| p[k.to_sym] = v; p }
18
19
  end
19
-
20
+
20
21
  # Returns the snip referenced by the request's URL. Performs no exception
21
22
  # handling, so if the snip does not exist, an exception will be thrown.
22
23
  def snip
23
24
  @app.soup[snip_name]
24
25
  end
25
-
26
+
26
27
  def cookies
27
28
  @rack_request.cookies
28
29
  end
29
-
30
+
30
31
  def ip
31
32
  @rack_request.env["REMOTE_ADDR"]
32
33
  end
33
-
34
+
34
35
  def session
35
36
  @rack_request.env["rack.session"]
36
37
  end
37
-
38
+
39
+ def authenticated?
40
+ @app.authenticator.authenticated?
41
+ end
42
+
43
+ def user
44
+ @app.authenticator.user
45
+ end
46
+
47
+ def authenticate!
48
+ @app.authenticator.authenticate!
49
+ end
50
+
51
+ def logout
52
+ @app.authenticator.logout
53
+ end
54
+
38
55
  private
39
-
56
+
40
57
  def determine_request_uri_parts
41
58
  @snip_name, @part, @format = request_uri_parts(@rack_request)
42
59
  @format ||= 'html'
43
60
  @method = (params.delete(:_method) || @rack_request.request_method).downcase
44
61
  end
45
-
62
+
46
63
  def uri_path(request)
47
64
  request.path_info
48
65
  end
49
-
66
+
50
67
  URL_ROOT = /\A\/\Z/ # i.e. /
51
68
  URL_SNIP = /\A\/([\w\-\s]+)(\/|\.(\w+))?\Z/ # i.e. /start, /start.html
52
69
  URL_SNIP_AND_PART = /\A\/([\w\-\s]+)\/([\w\-\s]+)(\/|\.(\w+))?\Z/ # i.e. /blah/part, /blah/part.raw
53
-
70
+
54
71
  # Returns an array of the requested snip, part and format
55
72
  def request_uri_parts(request)
56
73
  case CGI.unescape(uri_path(request))
@@ -64,6 +81,6 @@ module Vanilla
64
81
  []
65
82
  end
66
83
  end
67
-
84
+
68
85
  end
69
- end
86
+ end
@@ -9,6 +9,7 @@ system.main_template = <<-HTML
9
9
  <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
10
10
  <title>{current_snip name}</title>
11
11
  <script language="javascript" src="/public/javascripts/jquery.js"></script>
12
+ <script language="javascript" src="/public/javascripts/jquery.autogrow-textarea.js"></script>
12
13
  <script language="javascript" src="/public/javascripts/vanilla.js"></script>
13
14
  <link rel="stylesheet" type="text/css" media="screen" href="<%= url_to("system", "css.css") %>" />
14
15
  </head>
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vanilla
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.9.11.1
4
+ version: 1.9.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - James Adam
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-10-16 00:00:00 +01:00
12
+ date: 2009-11-10 00:00:00 +00:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -72,6 +72,16 @@ dependencies:
72
72
  - !ruby/object:Gem::Version
73
73
  version: 1.4.1
74
74
  version:
75
+ - !ruby/object:Gem::Dependency
76
+ name: warden
77
+ type: :runtime
78
+ version_requirement:
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: 0.5.2
84
+ version:
75
85
  - !ruby/object:Gem::Dependency
76
86
  name: rspec
77
87
  type: :development
@@ -113,6 +123,8 @@ files:
113
123
  - lib/defensio.rb
114
124
  - lib/tasks/vanilla.rake
115
125
  - lib/vanilla/app.rb
126
+ - lib/vanilla/authentication/warden.rb
127
+ - lib/vanilla/authentication.rb
116
128
  - lib/vanilla/console.rb
117
129
  - lib/vanilla/dynasnip.rb
118
130
  - lib/vanilla/dynasnips/comments.rb