rack_warden 0.0.9 → 0.0.10

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.
Files changed (39) hide show
  1. checksums.yaml +8 -8
  2. data/.gitignore +2 -0
  3. data/Gemfile +13 -10
  4. data/README.md +115 -53
  5. data/config.ru +1 -0
  6. data/lib/rack_warden.rb +33 -5
  7. data/lib/rack_warden/app.rb +73 -58
  8. data/lib/rack_warden/core_patches.rb +20 -0
  9. data/lib/rack_warden/env.rb +27 -0
  10. data/lib/rack_warden/frameworks.rb +34 -36
  11. data/lib/rack_warden/frameworks/rack.rb +36 -0
  12. data/lib/rack_warden/frameworks/rails.rb +29 -9
  13. data/lib/rack_warden/frameworks/sinatra.rb +15 -11
  14. data/lib/rack_warden/helpers.rb +197 -29
  15. data/lib/rack_warden/mail.rb +26 -0
  16. data/lib/rack_warden/models.rb +79 -40
  17. data/lib/rack_warden/models/user.rb +180 -22
  18. data/lib/rack_warden/routes.rb +159 -83
  19. data/lib/rack_warden/sinatra/decompile.rb +127 -0
  20. data/lib/rack_warden/sinatra/json.rb +131 -0
  21. data/lib/rack_warden/sinatra/namespace.rb +285 -0
  22. data/lib/rack_warden/sinatra/respond_with.rb +277 -0
  23. data/lib/rack_warden/version.rb +1 -1
  24. data/lib/rack_warden/views/rw_account_widget.html.erb +8 -0
  25. data/lib/rack_warden/views/rw_activation.email.erb +3 -0
  26. data/lib/rack_warden/views/rw_admin.html.erb +7 -5
  27. data/lib/rack_warden/views/rw_dbinfo.html.erb +5 -4
  28. data/lib/rack_warden/views/rw_error.html.erb +1 -0
  29. data/lib/rack_warden/views/rw_flash_widget.html.erb +12 -0
  30. data/lib/rack_warden/views/rw_index.html.erb +1 -1
  31. data/lib/rack_warden/views/rw_layout.html.erb +13 -19
  32. data/lib/rack_warden/views/rw_layout_admin.html.erb +6 -6
  33. data/lib/rack_warden/views/rw_login.html.erb +18 -5
  34. data/lib/rack_warden/views/rw_new_user.html.erb +22 -6
  35. data/lib/rack_warden/views/rw_protected.xml.erb +10 -0
  36. data/lib/rack_warden/views/rw_session.html.erb +34 -0
  37. data/lib/rack_warden/warden.rb +161 -30
  38. data/rack_warden.gemspec +16 -13
  39. metadata +84 -29
@@ -0,0 +1,277 @@
1
+ require 'rack_warden/sinatra/json'
2
+ require 'sinatra/base'
3
+ require 'erb'
4
+
5
+ module RackWarden
6
+ App.logger.debug "RW loading RespondWith"
7
+
8
+ #
9
+ # = Sinatra::RespondWith
10
+ #
11
+ # These extensions let Sinatra automatically choose what template to render or
12
+ # action to perform depending on the request's Accept header.
13
+ #
14
+ # Example:
15
+ #
16
+ # # Without Sinatra::RespondWith
17
+ # get '/' do
18
+ # data = { :name => 'example' }
19
+ # request.accept.each do |type|
20
+ # case type.to_s
21
+ # when 'text/html'
22
+ # halt haml(:index, :locals => data)
23
+ # when 'text/json'
24
+ # halt data.to_json
25
+ # when 'application/atom+xml'
26
+ # halt nokogiri(:'index.atom', :locals => data)
27
+ # when 'application/xml', 'text/xml'
28
+ # halt nokogiri(:'index.xml', :locals => data)
29
+ # when 'text/plain'
30
+ # halt 'just an example'
31
+ # end
32
+ # end
33
+ # error 406
34
+ # end
35
+ #
36
+ # # With Sinatra::RespondWith
37
+ # get '/' do
38
+ # respond_with :index, :name => 'example' do |f|
39
+ # f.txt { 'just an example' }
40
+ # end
41
+ # end
42
+ #
43
+ # Both helper methods +respond_to+ and +respond_with+ let you define custom
44
+ # handlers like the one above for +text/plain+. +respond_with+ additionally
45
+ # takes a template name and/or an object to offer the following default
46
+ # behavior:
47
+ #
48
+ # * If a template name is given, search for a template called
49
+ # +name.format.engine+ (+index.xml.nokogiri+ in the above example).
50
+ # * If a template name is given, search for a templated called +name.engine+
51
+ # for engines known to result in the requested format (+index.haml+).
52
+ # * If a file extension associated with the mime type is known to Sinatra, and
53
+ # the object responds to +to_extension+, call that method and use the result
54
+ # (+data.to_json+).
55
+ #
56
+ # == Security
57
+ #
58
+ # Since methods are triggered based on client input, this can lead to security
59
+ # issues (but not as severe as those might appear in the first place: keep in
60
+ # mind that only known file extensions are used). You should limit
61
+ # the possible formats you serve.
62
+ #
63
+ # This is possible with the +provides+ condition:
64
+ #
65
+ # get '/', :provides => [:html, :json, :xml, :atom] do
66
+ # respond_with :index, :name => 'example'
67
+ # end
68
+ #
69
+ # However, since you have to set +provides+ for every route, this extension
70
+ # adds an app global (class method) `respond_to`, that lets you define content
71
+ # types for all routes:
72
+ #
73
+ # respond_to :html, :json, :xml, :atom
74
+ # get('/a') { respond_with :index, :name => 'a' }
75
+ # get('/b') { respond_with :index, :name => 'b' }
76
+ #
77
+ # == Custom Types
78
+ #
79
+ # Use the +on+ method for defining actions for custom types:
80
+ #
81
+ # get '/' do
82
+ # respond_to do |f|
83
+ # f.xml { nokogiri :index }
84
+ # f.on('application/custom') { custom_action }
85
+ # f.on('text/*') { data.to_s }
86
+ # f.on('*/*') { "matches everything" }
87
+ # end
88
+ # end
89
+ #
90
+ # Definition order does not matter.
91
+ module RespondWith
92
+ class Format
93
+ def initialize(app)
94
+ @app, @map, @generic, @default = app, {}, {}, nil
95
+ end
96
+
97
+ def on(type, &block)
98
+ # WBR
99
+ @app.logger.debug "RW respond_with.on type: #{type}"
100
+ @app.logger.debug "RW respond_with.on block: #{block}"
101
+ @app.logger.debug "RW respond_with.on @app.params: #{@app.params}"
102
+ @app.logger.debug "RW respond_with.on @app.settings.mime_types(type): #{@app.settings.mime_types(type)}"
103
+
104
+ @app.settings.mime_types(type).each do |mime|
105
+ case mime
106
+ when '*/*' then @default = block
107
+ when /^([^\/]+)\/\*$/ then @generic[$1] = block
108
+ else @map[mime] = block
109
+ end
110
+ end
111
+ end
112
+
113
+ def finish
114
+ yield self if block_given?
115
+ # WBR - adds format/extension of uri to front of mime-types.
116
+ # You must capture the format string in the params with your route declaration.
117
+ format_type = @app.settings.mime_types(@app.params['format'])[0]
118
+ @app.logger.debug "RW respond_with.finish format_type (WBR): #{format_type}, #{format_type.class}"
119
+ mime_type = format_type ||
120
+ @app.content_type ||
121
+ @app.request.preferred_type(@map.keys) ||
122
+ @app.request.preferred_type ||
123
+ 'text/html'
124
+ type = mime_type.split(/\s*;\s*/, 2).first
125
+ @app.logger.debug "RW respond_with.finish type: #{type}"
126
+ @app.logger.debug "RW respond_with.finish @map: #{@map}"
127
+ @app.logger.debug "RW respond_with.finish @default: #{@default}"
128
+ @app.logger.debug "RW respond_with.finish @generic: #{@generic}"
129
+ handlers = [@map[type], @generic[type[/^[^\/]+/]], @default].compact
130
+ handlers.each do |block|
131
+ if result = block.call(type)
132
+ @app.content_type mime_type
133
+ @app.halt result
134
+ end
135
+ end
136
+ @app.halt 406
137
+ end
138
+
139
+ def method_missing(method, *args, &block)
140
+ return super if args.any? or block.nil? or not @app.mime_type(method)
141
+ on(method, &block)
142
+ end
143
+ end
144
+
145
+ module Helpers
146
+ include Sinatra::JSON
147
+
148
+ def respond_with(template, object = nil, &block)
149
+ object, template = template, nil unless Symbol === template
150
+ format = Format.new(self)
151
+ format.on "*/*" do |type|
152
+ exts = settings.ext_map[type]
153
+ exts << :xml if type.end_with? '+xml'
154
+ # WBR - not necessary, since the hack of #finish method above.
155
+ #exts.unshift params[:format].to_sym if params[:format]
156
+ logger.debug "RW respond_with format: #{params[:format]}"
157
+
158
+ logger.debug "RW respond_with exts: #{exts.inspect}"
159
+ if template
160
+ args = template_cache.fetch(type, template) { template_for(template, exts) }
161
+ if args.any?
162
+ locals = { :object => object }
163
+ locals.merge! object.to_hash if object.respond_to? :to_hash
164
+
165
+ renderer = args.first
166
+ options = args[1..-1] + [{:locals => locals}]
167
+
168
+ halt send(renderer, *options)
169
+ end
170
+ end
171
+ if object
172
+ exts.each do |ext|
173
+ halt json(object) if ext == :json
174
+ next unless object.respond_to? method = "to_#{ext}"
175
+ halt(*object.send(method))
176
+ end
177
+ end
178
+ false
179
+ end
180
+ format.finish(&block)
181
+ end
182
+
183
+ def respond_to(&block)
184
+ Format.new(self).finish(&block)
185
+ end
186
+
187
+ private
188
+
189
+ def template_for(name, exts)
190
+ logger.debug "RW respond_with#template_for name, exts: #{name}, #{exts}"
191
+ # in production this is cached, so don't worry too much about runtime
192
+ possible = []
193
+ settings.template_engines[:all].each do |engine|
194
+ exts.each { |ext| possible << [engine, "#{name}.#{ext}"] }
195
+ end
196
+ exts.each do |ext|
197
+ settings.template_engines[ext].each { |e| possible << [e, name] }
198
+ end
199
+ logger.debug "RW respond_with#template_for possible: #{possible.inspect}"
200
+ possible.each do |engine, template|
201
+ # not exactly like Tilt[engine], but does not trigger a require
202
+ klass = Tilt.mappings[Tilt.normalize(engine)].first
203
+ logger.debug "RW respond_with#template_for klass : #{klass}"
204
+ find_template(settings.views, template, klass) do |file|
205
+ #logger.debug "RW respond_with#template_for find_template file: #{file}"
206
+ #logger.debug "RW respond_with#template_for find_template engine: #{engine.inspect}"
207
+ #logger.debug "RW respond_with#template_for find_template template: #{template.inspect}"
208
+ next unless File.exist? file
209
+ return settings.rendering_method(engine) << template.to_sym
210
+ end
211
+ end
212
+
213
+ [] # nil or false would not be cached
214
+ end
215
+ end
216
+
217
+ def remap_extensions
218
+ ext_map.clear
219
+ Rack::Mime::MIME_TYPES.each { |e,t| ext_map[t] << e[1..-1].to_sym }
220
+ ext_map['text/javascript'] << 'js'
221
+ ext_map['text/xml'] << 'xml'
222
+ end
223
+
224
+ def mime_type(*)
225
+ result = super
226
+ remap_extensions
227
+ result
228
+ end
229
+
230
+ def respond_to(*formats)
231
+ if formats.any?
232
+ @respond_to ||= []
233
+ @respond_to.concat formats
234
+ elsif @respond_to.nil? and superclass.respond_to? :respond_to
235
+ superclass.respond_to
236
+ else
237
+ @respond_to
238
+ end
239
+ end
240
+
241
+ def rendering_method(engine)
242
+ return [engine] if Sinatra::Templates.method_defined? engine
243
+ return [:mab] if engine.to_sym == :markaby
244
+ [:render, :engine]
245
+ end
246
+
247
+ private
248
+
249
+ def compile!(verb, path, block, options = {})
250
+ options[:provides] ||= respond_to if respond_to
251
+ super
252
+ end
253
+
254
+ ENGINES = {
255
+ :css => [:less, :sass, :scss],
256
+ :xml => [:builder, :nokogiri],
257
+ :js => [:coffee],
258
+ :json => [:yajl],
259
+ :html => [:erb, :erubis, :haml, :slim, :liquid, :radius, :mab, :markdown,
260
+ :textile, :rdoc],
261
+ :all => Sinatra::Templates.instance_methods.map(&:to_sym) + [:mab] -
262
+ [:find_template, :markaby]
263
+ }
264
+
265
+ ENGINES.default = []
266
+
267
+ def self.registered(base)
268
+ base.set :ext_map, Hash.new { |h,k| h[k] = [] }
269
+ base.set :template_engines, ENGINES.dup
270
+ base.remap_extensions
271
+ base.helpers Helpers
272
+ end
273
+ end
274
+
275
+ #register RespondWith
276
+ #Delegator.delegate :respond_to
277
+ end
@@ -1,3 +1,3 @@
1
1
  module RackWarden
2
- VERSION = "0.0.9"
2
+ VERSION = "0.0.10"
3
3
  end
@@ -0,0 +1,8 @@
1
+ <span class="rw-account-widget">
2
+ <% if logged_in? %>
3
+ Logged in as <b><a href="<%=url_for('/')%>"><%=current_user.username%></a></b> |
4
+ <a href="<%=url_for('/logout')%>">Logout</a>
5
+ <% else %>
6
+ <a href="<%=url_for('/login')%>">Login</a>
7
+ <% end %>
8
+ </span>
@@ -0,0 +1,3 @@
1
+ Activate your new account with this link
2
+
3
+ http://localhost:4567/auth/activate/<%=RackWarden::App.uri_encode(user.activation_code)%>
@@ -5,18 +5,20 @@
5
5
  <table>
6
6
  <thead>
7
7
  <tr>
8
- <th>Email</th>
9
- <th>User</th>
10
8
  <th>Id</th>
9
+ <th>User</th>
10
+ <th>Email</th>
11
+ <th>Activated</th>
11
12
  </tr>
12
13
  <tbody>
13
14
  <% RackWarden::User.all(:limit=>100).each do |user| %>
14
15
  <tr>
15
- <td><%=user.email%></td>
16
- <td><%=user.username%></td>
17
16
  <td><%=user.id%></td>
17
+ <td><%=user.username%></td>
18
+ <td><%=user.email%></td>
19
+ <td><%=user.activated_at%></td>
18
20
  </tr>
19
21
  <% end %>
20
22
  </tbody>
21
23
  </table>
22
- </p>
24
+ </p>
@@ -3,7 +3,8 @@
3
3
  </p>
4
4
 
5
5
  <p>
6
- <%= DataMapper.repository.adapter.select('select * from SQLITE_MASTER').to_yaml.gsub(/\n|\r/, '<br>').gsub(/ /, '&nbsp;&nbsp;') %>
7
- <br><br>
8
- <%= DataMapper.repository.adapter.to_yaml.gsub(/\n|\r/, '<br>') %>
9
- </p>
6
+ <%#= DataMapper.repository.adapter.select('select * from SQLITE_MASTER').to_yaml.to_html %>
7
+ <%#= DataMapper.repository.adapter.to_yaml.gsub(/\n|\r/, '<br>') %>
8
+ <%= DataMapper.repository(settings.repository_name).adapter.options.dup.tap{|o| o.delete(:password); o.delete('password')}.to_yaml.to_html %>
9
+ </p>
10
+ <br>
@@ -0,0 +1 @@
1
+ <h2>Oops! We encountered an error</h2>
@@ -0,0 +1,12 @@
1
+ <% if defined? :flash %>
2
+ <% if flash.rw_success %>
3
+ <div style="color:green;">
4
+ <%= flash.rw_success %>
5
+ </div>
6
+ <% end %>
7
+ <% if flash.rw_error %>
8
+ <div style="color:red;">
9
+ <%= flash.rw_error %>
10
+ </div>
11
+ <% end %>
12
+ <% end %>
@@ -1,3 +1,3 @@
1
1
  <p>
2
- <h3>Warden authentication for rack based apps<h3>
2
+ <h4>Warden authentication for rack based apps<h3>
3
3
  </p>
@@ -4,38 +4,32 @@
4
4
  <title>Rack Warden</title>
5
5
 
6
6
  <style>
7
- body {
8
- margin: 10px auto;
9
- width: 800px;
10
- }
7
+ body {
8
+ margin: 10px auto;
9
+ width: 800px;
10
+ }
11
11
  </style>
12
12
 
13
13
  <script src='https://www.google.com/recaptcha/api.js'></script>
14
14
  </head>
15
15
  <body>
16
+ <br>
16
17
  <h1>Rack Warden</h1>
17
18
 
18
19
  <p>
19
- <a href="<%=url('/auth/login', false)%>">Log In</a> |
20
- <a href="<%=url('/', false)%>">Home</a> |
21
- <a href="<%=url('/auth/protected', false)%>">Test Protected Page</a> |
22
- <a href="<%=url('/auth/logout', false)%>">Log Out</a>
20
+ <a href="<%=url('/', false)%>">Main Site</a> |
21
+ <a href="<%=url_for('/protected')%>">Test Protected Page</a> |
22
+ <%= erb :'rw_account_widget.html', :layout=>false %>
23
23
  </p>
24
24
 
25
- <% if flash(:rwarden)[:success] %>
26
- <div style="color:green;">
27
- <%= flash(:rwarden)[:success] %>
28
- </div>
29
- <% end %>
30
-
31
- <% if flash(:rwarden)[:error] %>
32
- <div style="color:red;">
33
- <%= flash(:rwarden)[:error] %>
34
- </div>
35
- <% end %>
25
+ <%= erb :'rw_flash_widget.html', :layout=>false %>
36
26
 
37
27
  <div id="content">
28
+ <br>
29
+ <br>
38
30
  <%= yield if block_given? %>
31
+ <br>
32
+ <br>
39
33
  </div>
40
34
  </body>
41
35
  </html>
@@ -1,12 +1,12 @@
1
1
  <!-- A partial layout for admin. -->
2
2
  <%# @section_title = "RackWarden Admin" %>
3
- <h2>RackWarden Admin</h2>
3
+ <h2>Account Management</h2>
4
4
  <p>
5
- <a href="<%=url('/auth/login', false)%>">Log In</a> |
6
- <a href="<%=url('/auth', false)%>">Home</a> |
7
- <a href="<%=url('/auth/admin', false)%>">User Accounts</a> |
8
- <a href="<%=url('/auth/dbinfo', false)%>">Database Info</a> |
9
- <a href="<%=url('/auth/logout', false)%>">Log Out</a>
5
+ <a href="<%=url_for('/')%>">RackWarden Home</a> |
6
+ <a href="<%=url_for('/admin')%>">User Accounts</a> |
7
+ <a href="<%=url_for('/dbinfo')%>">Database Info</a> |
8
+ <a href="<%=url_for('/sessinfo')%>">Session Info</a> |
9
+ <%=account_widget%>
10
10
  </p>
11
11
 
12
12
  <br>
@@ -1,9 +1,22 @@
1
- <% @section_title = "Login" %>
2
- <form action="<%=url('/auth/login', false)%>" method="post">
3
- <p>Username or Email <input type="text" name="user[username]" /></p>
4
- <p>Password <input type="password" name="user[password]" /></p>
1
+ <h3>Login</h3>
2
+ <form action="<%=url_for('/login')%>" method="post" class="rw">
3
+ <style scoped="scoped">
4
+ .rw label {font-size: .95em; color: grey; display: block;}
5
+ .rw input {font-size: 1.15em; margin-bottom: 20px; padding:7px;}
6
+ </style>
7
+
8
+ <label for="user_username">Username or Email</label>
9
+ <input type="text" name="user[username]" id="user_username"/>
10
+
11
+ <label for="user_password">Password</label>
12
+ <input type="password" name="user[password]" id="user_password" />
13
+
14
+ <label for="user_remember_me">Remember me
15
+ <input name="user[remember_me]" type="checkbox" value="1" id="user_remember_me" />
16
+ </label>
17
+
5
18
  <input type="submit" value="Log In" />
6
19
  <% if settings.allow_public_signup %>
7
- or <a href="<%=url('/auth/new', false)%>">Create a new account</a>
20
+ or <a href="<%=url_for('/new')%>">Create a new account</a>
8
21
  <% end %>
9
22
  </form>