rodauth 1.12.0 → 1.13.0

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: 888e341c90edf3af686821f3d64998da9fcdd5cb
4
- data.tar.gz: 5f50386e3657dce0c24b81465a2e54ad8c81221a
3
+ metadata.gz: f6c97c6e01c1026bf027fb99348421103909a668
4
+ data.tar.gz: 910777f85e599d240356aeb2eba4339db0c481c3
5
5
  SHA512:
6
- metadata.gz: 2315ff44b30666ac9291217ba2c9fa2ecb928b0b6ac0919d4a6debc70ec093c1b42f1866191024ee00f0d086c9103b996b173e36a092b84eb56ea9017a7baea0
7
- data.tar.gz: c432df2a344582f4aef84b7512fa4f5a5a72058dc9a8528ee315e95e21044bff3d46ac29052cc1a9968e5dd298370e447df31f31a19519880b5da200df680eb9
6
+ metadata.gz: c2a571d6eac5c96a458da39020a074edb561c2f71ef32a93382177fcdfe67d73d0ad5dd548255d7c8a09e9f9d67166becd616ec1d8c650d30d766a42b24990ae
7
+ data.tar.gz: '070838b8388668fa6c7ac73145c82dd0e825d61c83ea43e603789f1efd0383d3c57b147345f55b47d709f6a3786f475fc78fa2e1f5fd30213d6e691fcb6ba5ba'
data/CHANGELOG CHANGED
@@ -1,3 +1,13 @@
1
+ === 1.13.0 (2017-11-21)
2
+
3
+ * Add json_response_body(hash) configuration method to jwt feature (jeremyevans)
4
+
5
+ * Support invalid_previous_password_message configuration method in change_password feature (jeremyevans)
6
+
7
+ * Use custom error statuses if only_json? and json_response_custom_error_status? are true even if request isn't in json format (jeremyevans)
8
+
9
+ * Add cache_templates configuration method for disabling caching of templates (adam12, jeremyevans) (#46)
10
+
1
11
  === 1.12.0 (2017-10-03)
2
12
 
3
13
  * [SECURITY] Clear expired password reset key for account before retrieving password reset key (chanks, jeremyevans) (#43)
data/README.rdoc CHANGED
@@ -940,7 +940,7 @@ inside the middleware, you can easily provide a way for your
940
940
  application to call Rodauth methods.
941
941
 
942
942
  Here are some examples of integrating Rodauth into applications that
943
- doesn't use Roda:
943
+ don't use Roda:
944
944
 
945
945
  * {Ginatra, a Sinatra-based git repository viewer}[https://github.com/jeremyevans/ginatra/commit/28108ebec96e8d42596ee55b01c3f7b50c155dd1]
946
946
  * {Rodauth's demo site as a Rails application}[https://github.com/jeremyevans/rodauth-demo-rails] (
data/doc/base.rdoc CHANGED
@@ -37,6 +37,9 @@ account_select :: An array of columns to select from +accounts_table+. By
37
37
  default, selects all columns in the table.
38
38
  account_status_column :: The status id column in the account model.
39
39
  account_unverified_status_value :: The representating unverified accounts.
40
+ cache_templates :: Whether to cache templates. True by default. It may be worth
41
+ switching this to false in development if you are using your
42
+ own templates instead of the templates provided by Rodauth.
40
43
  default_redirect :: Where to redirect after most successful actions.
41
44
  invalid_field_error_status :: The response status to use for invalid field
42
45
  value errors, 422 by default.
@@ -25,3 +25,5 @@ after_change_password :: Run arbitrary code after successful password change.
25
25
  before_change_password :: Run arbitrary code before changing the password for an account.
26
26
  before_change_password_route :: Run arbitrary code before handling a change password route.
27
27
  change_password_view :: The HTML to use for the change password form.
28
+ invalid_previous_password_message :: The message to use when the previous password was
29
+ incorrect. Defaults to invalid_password_message.
data/doc/jwt.rdoc CHANGED
@@ -66,6 +66,7 @@ use_jwt? :: Whether to use the JWT in the Authorization header for authenticatio
66
66
  == Auth Methods
67
67
 
68
68
  json_request? :: Whether the current request is a JSON request, looks at the Content-Type request header by default.
69
+ json_response_body(hash) :: The body to use for JSON response. By default just converts hash to JSON. Can be used to reformat JSON output in arbitrary ways.
69
70
  jwt_session_hash :: The session hash used to create the session_jwt. Can be used to set JWT claims.
70
71
  jwt_token :: Retrieve the JWT token from the request, by default taking it from the Authorization header.
71
72
  session_jwt :: An encoded JWT for the current session.
@@ -0,0 +1,34 @@
1
+ = New Features
2
+
3
+ * A cache_templates configuration method has been added, which can be
4
+ set to false to disable the default caching of templates. The main
5
+ time you would want to use this is if you were overriding Rodauth's
6
+ templates with your own templates and modifying such templates in
7
+ development mode. If that is the case, you may want to use
8
+ something like:
9
+
10
+ cache_templates(ENV['RACK_ENV'] != 'development')
11
+
12
+ * An invalid_previous_password_message configuration method has been
13
+ added to the change_password feature, which overrides the default
14
+ invalid_password_message configuration method if the incorrect
15
+ previous password is used when changing the password. This is
16
+ designed for use when invalid_password_message has been overridden
17
+ and the message doesn't make sense in the change password case.
18
+
19
+ * A json_response_body(hash) configuration method has been added to
20
+ the jwt feature, allowing for custom formatting of the JSON
21
+ response body. This is called with the hash to use in the
22
+ response, and should return a JSON-formatted string. Example:
23
+
24
+ json_response_body do |hash|
25
+ super('status'=>response.status, 'detail'=>hash)
26
+ end
27
+
28
+ = Other Improvements
29
+
30
+ * In the jwt feature, if json_response_custom_error_status? is set to
31
+ true, custom error statuses will be used if only_json? is set to
32
+ true, even if the request is not in JSON format. Previously,
33
+ custom error statuses were only used if the request was in JSON
34
+ format.
@@ -17,6 +17,7 @@ module Rodauth
17
17
  auth_value_method :account_status_column, :status_id
18
18
  auth_value_method :account_unverified_status_value, 1
19
19
  auth_value_method :accounts_table, :accounts
20
+ auth_value_method :cache_templates, true
20
21
  auth_value_method :default_redirect, '/'
21
22
  auth_value_method :invalid_field_error_status, 422
22
23
  auth_value_method :invalid_key_error_status, 401
@@ -235,9 +236,10 @@ module Rodauth
235
236
  end
236
237
 
237
238
  def button_opts(value, opts)
238
- opts = {:locals=>{:value=>value, :opts=>opts}}
239
+ opts = Hash[template_opts].merge!(opts)
240
+ opts[:locals] = {:value=>value, :opts=>opts}
239
241
  opts[:path] = template_path('button')
240
- opts[:cache] = true
242
+ opts[:cache] = cache_templates
241
243
  opts[:cache_key] = :rodauth_button
242
244
  opts
243
245
  end
@@ -516,7 +518,7 @@ module Rodauth
516
518
  opts = template_opts.dup
517
519
  opts[:locals] = opts[:locals] ? opts[:locals].dup : {}
518
520
  opts[:locals][:rodauth] = self
519
- opts[:cache] = true
521
+ opts[:cache] = cache_templates
520
522
  opts[:cache_key] = :"rodauth_#{page}"
521
523
 
522
524
  scope.instance_exec do
@@ -17,7 +17,10 @@ module Rodauth
17
17
  auth_value_method :new_password_label, 'New Password'
18
18
  auth_value_method :new_password_param, 'new-password'
19
19
 
20
- auth_value_methods :change_password_requires_password?
20
+ auth_value_methods(
21
+ :change_password_requires_password?,
22
+ :invalid_previous_password_message
23
+ )
21
24
 
22
25
  route do |r|
23
26
  require_account
@@ -30,7 +33,7 @@ module Rodauth
30
33
  r.post do
31
34
  catch_error do
32
35
  if change_password_requires_password? && !password_match?(param(password_param))
33
- throw_error_status(invalid_password_error_status, password_param, invalid_password_message)
36
+ throw_error_status(invalid_password_error_status, password_param, invalid_previous_password_message)
34
37
  end
35
38
 
36
39
  password = param(new_password_param)
@@ -63,5 +66,9 @@ module Rodauth
63
66
  def change_password_requires_password?
64
67
  modifications_require_password?
65
68
  end
69
+
70
+ def invalid_previous_password_message
71
+ invalid_password_message
72
+ end
66
73
  end
67
74
  end
@@ -38,6 +38,8 @@ module Rodauth
38
38
  :set_jwt_token
39
39
  )
40
40
 
41
+ auth_private_methods :json_response_body
42
+
41
43
  def session
42
44
  return @session if defined?(@session)
43
45
  return super unless use_jwt?
@@ -163,7 +165,7 @@ module Rodauth
163
165
 
164
166
  def before_view_recovery_codes
165
167
  super if defined?(super)
166
- if json_request?
168
+ if use_jwt?
167
169
  json_response[:codes] = recovery_codes
168
170
  json_response[json_response_success_key] ||= "" if include_success_messages?
169
171
  end
@@ -201,11 +203,15 @@ module Rodauth
201
203
  return_json_response
202
204
  end
203
205
 
206
+ def _json_response_body(hash)
207
+ request.send(:convert_to_json, hash)
208
+ end
209
+
204
210
  def return_json_response
205
211
  response.status ||= json_response_error_status if json_response[json_response_error_key]
206
212
  set_jwt
207
213
  response['Content-Type'] ||= json_response_content_type
208
- response.write(request.send(:convert_to_json, json_response))
214
+ response.write(_json_response_body(json_response))
209
215
  request.halt
210
216
  end
211
217
 
@@ -214,13 +220,13 @@ module Rodauth
214
220
  end
215
221
 
216
222
  def set_redirect_error_status(status)
217
- if json_request? && json_response_custom_error_status?
223
+ if use_jwt? && json_response_custom_error_status?
218
224
  response.status = status
219
225
  end
220
226
  end
221
227
 
222
228
  def set_response_error_status(status)
223
- if json_request? && !json_response_custom_error_status?
229
+ if use_jwt? && !json_response_custom_error_status?
224
230
  status = json_response_error_status
225
231
  end
226
232
 
@@ -1,7 +1,7 @@
1
1
  # frozen-string-literal: true
2
2
 
3
3
  module Rodauth
4
- VERSION = '1.12.0'.freeze
4
+ VERSION = '1.13.0'.freeze
5
5
 
6
6
  def self.version
7
7
  VERSION
@@ -91,6 +91,32 @@ describe 'Rodauth change_password feature' do
91
91
  page.find('#notice_flash').text.must_equal "Your password has been changed"
92
92
  end
93
93
 
94
+ it "should support invalid_previous_password_message" do
95
+ require_password = true
96
+ rodauth do
97
+ enable :login, :logout, :change_password
98
+ invalid_previous_password_message "Previous password not correct"
99
+ end
100
+ roda do |r|
101
+ r.rodauth
102
+ r.root{view :content=>""}
103
+ end
104
+
105
+ login
106
+ page.current_path.must_equal '/'
107
+
108
+ visit '/change-password'
109
+ page.title.must_equal 'Change Password'
110
+
111
+ fill_in 'Password', :with=>'0123456'
112
+ fill_in 'New Password', :with=>'0123456'
113
+ fill_in 'Confirm Password', :with=>'0123456'
114
+ click_button 'Change Password'
115
+ page.find('#error_flash').text.must_equal "There was an error changing your password"
116
+ page.body.must_include 'Previous password not correct'
117
+ page.current_path.must_equal '/change-password'
118
+ end
119
+
94
120
  it "should support setting requirements for passwords" do
95
121
  rodauth do
96
122
  enable :login, :create_account, :change_password
data/spec/jwt_spec.rb CHANGED
@@ -33,6 +33,22 @@ describe 'Rodauth login feature' do
33
33
  res.must_equal [400, {'error'=>'invalid JWT format or claim in Authorization header'}]
34
34
  end
35
35
 
36
+ it "should use custom JSON error statuses even if the request isn't in JSON format if a JWT is in use" do
37
+ rodauth do
38
+ only_json? true
39
+ end
40
+ roda(:jwt) do |r|
41
+ r.rodauth
42
+ rodauth.require_authentication
43
+ '1'
44
+ end
45
+
46
+ status, headers, body = json_request("/", :headers=>{'CONTENT_TYPE'=>'text/html'}, :include_headers=>true)
47
+ status.must_equal 401
48
+ headers['Content-Type'].must_equal 'application/json'
49
+ JSON.parse(body.join).must_equal("error"=>"Please login to continue")
50
+ end
51
+
36
52
  it "should require json request content type in only json mode for rodauth endpoints only" do
37
53
  oj = false
38
54
  rodauth do
@@ -103,6 +119,21 @@ describe 'Rodauth login feature' do
103
119
  res.must_equal [405, {'error'=>'non-POST method used in JSON API'}]
104
120
  end
105
121
 
122
+ it "should allow customizing JSON response bodies" do
123
+ rodauth do
124
+ enable :login, :logout, :jwt
125
+ json_response_body do |hash|
126
+ super('status'=>response.status, 'detail'=>hash)
127
+ end
128
+ end
129
+ roda(:jwt) do |r|
130
+ r.rodauth
131
+ end
132
+
133
+ res = json_request("/login", :method=>'GET')
134
+ res.must_equal [405, {'status'=>405, 'detail'=>{'error'=>'non-POST method used in JSON API'}}]
135
+ end
136
+
106
137
  it "should support valid_jwt? method for checking for valid JWT tokens" do
107
138
  rodauth do
108
139
  enable :login, :logout, :jwt
data/spec/login_spec.rb CHANGED
@@ -154,6 +154,30 @@ describe 'Rodauth login feature' do
154
154
  page.current_path.must_equal '/auth/lin'
155
155
  end
156
156
 
157
+ it "should use correct redirect paths when using prefix" do
158
+ rodauth do
159
+ enable :login, :logout
160
+ prefix '/auth'
161
+ end
162
+ roda do |r|
163
+ r.on 'auth' do
164
+ r.rodauth
165
+ rodauth.require_login
166
+ end
167
+ rodauth.send("#{r.remaining_path[1..-1]}_redirect")
168
+ end
169
+
170
+ visit '/login'
171
+ page.html.must_equal '/'
172
+ visit '/logout'
173
+ page.html.must_equal '/auth/login'
174
+ visit '/require_login'
175
+ page.html.must_equal '/auth/login'
176
+
177
+ visit '/auth'
178
+ page.current_path.must_equal '/auth/login'
179
+ end
180
+
157
181
  it "should login and logout via jwt" do
158
182
  rodauth do
159
183
  enable :login, :logout
data/spec/rodauth_spec.rb CHANGED
@@ -38,6 +38,40 @@ describe 'Rodauth' do
38
38
  page.title.must_equal 'Login'
39
39
  end
40
40
 
41
+ it "should pick up template changes if not caching templates" do
42
+ begin
43
+ @no_freeze = true
44
+ cache = true
45
+ rodauth do
46
+ enable :login
47
+ cache_templates{cache}
48
+ end
49
+ roda do |r|
50
+ r.rodauth
51
+ end
52
+ dir = 'spec/views2'
53
+ file = "#{dir}/login.str"
54
+ app.plugin :render, :views=>dir, :engine=>'str'
55
+ Dir.mkdir(dir) unless File.directory?(dir)
56
+
57
+ text = File.read('spec/views/login.str')
58
+ File.open(file, 'wb'){|f| f.write text}
59
+ visit '/login'
60
+ page.all('label').first.text.must_equal 'Login'
61
+
62
+ File.open(file, 'wb'){|f| f.write text.gsub('Login', 'Banana')}
63
+ visit '/login'
64
+ page.all('label').first.text.must_equal 'Login'
65
+
66
+ cache = false
67
+ visit '/login'
68
+ page.all('label').first.text.must_equal 'Banana'
69
+ ensure
70
+ File.delete(file) if File.file?(file)
71
+ Dir.rmdir(dir) if File.directory?(dir)
72
+ end
73
+ end
74
+
41
75
  it "should require login to perform certain actions" do
42
76
  rodauth do
43
77
  enable :login, :change_password, :change_login, :close_account
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rodauth
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.12.0
4
+ version: 1.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Evans
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-10-03 00:00:00.000000000 Z
11
+ date: 2017-11-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sequel
@@ -241,6 +241,7 @@ extra_rdoc_files:
241
241
  - doc/release_notes/1.10.0.txt
242
242
  - doc/release_notes/1.11.0.txt
243
243
  - doc/release_notes/1.12.0.txt
244
+ - doc/release_notes/1.13.0.txt
244
245
  files:
245
246
  - CHANGELOG
246
247
  - MIT-LICENSE
@@ -272,6 +273,7 @@ files:
272
273
  - doc/release_notes/1.10.0.txt
273
274
  - doc/release_notes/1.11.0.txt
274
275
  - doc/release_notes/1.12.0.txt
276
+ - doc/release_notes/1.13.0.txt
275
277
  - doc/release_notes/1.2.0.txt
276
278
  - doc/release_notes/1.3.0.txt
277
279
  - doc/release_notes/1.4.0.txt