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 +4 -4
- data/CHANGELOG +10 -0
- data/README.rdoc +1 -1
- data/doc/base.rdoc +3 -0
- data/doc/change_password.rdoc +2 -0
- data/doc/jwt.rdoc +1 -0
- data/doc/release_notes/1.13.0.txt +34 -0
- data/lib/rodauth/features/base.rb +5 -3
- data/lib/rodauth/features/change_password.rb +9 -2
- data/lib/rodauth/features/jwt.rb +10 -4
- data/lib/rodauth/version.rb +1 -1
- data/spec/change_password_spec.rb +26 -0
- data/spec/jwt_spec.rb +31 -0
- data/spec/login_spec.rb +24 -0
- data/spec/rodauth_spec.rb +34 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f6c97c6e01c1026bf027fb99348421103909a668
|
4
|
+
data.tar.gz: 910777f85e599d240356aeb2eba4339db0c481c3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
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.
|
data/doc/change_password.rdoc
CHANGED
@@ -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 =
|
239
|
+
opts = Hash[template_opts].merge!(opts)
|
240
|
+
opts[:locals] = {:value=>value, :opts=>opts}
|
239
241
|
opts[:path] = template_path('button')
|
240
|
-
opts[:cache] =
|
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] =
|
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
|
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,
|
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
|
data/lib/rodauth/features/jwt.rb
CHANGED
@@ -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
|
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(
|
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
|
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
|
229
|
+
if use_jwt? && !json_response_custom_error_status?
|
224
230
|
status = json_response_error_status
|
225
231
|
end
|
226
232
|
|
data/lib/rodauth/version.rb
CHANGED
@@ -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.
|
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-
|
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
|