authenticate 0.3.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/README.md +1 -1
- data/app/controllers/authenticate/passwords_controller.rb +1 -1
- data/app/controllers/authenticate/users_controller.rb +12 -10
- data/lib/authenticate/configuration.rb +78 -37
- data/lib/authenticate/lifecycle.rb +7 -7
- data/lib/authenticate/user.rb +4 -1
- data/lib/authenticate/version.rb +1 -1
- data/lib/generators/authenticate/controllers/controllers_generator.rb +1 -1
- data/spec/features/password_reset_spec.rb +54 -0
- data/spec/model/configuration_spec.rb +1 -1
- metadata +2 -8
- data/app/assets/config/authenticate_manifest.js +0 -0
- data/app/assets/images/authenticate/.keep +0 -0
- data/app/assets/javascripts/authenticate/.keep +0 -0
- data/app/assets/stylesheets/authenticate/.keep +0 -0
- data/app/helpers/.keep +0 -0
- data/app/models/.keep +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0f9f51572691eba2fb35eb46618d2235898149f5
|
4
|
+
data.tar.gz: 69fb6dcf45f900f7433f43e11feb8b69ec966bba
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 195b410e9982a6a410bd53abf79ff90aba67d7ab9eca23f7fa00ab278aa28de5a592577783820d15e2bd3a2f752338c8bf2b4c695be515dd09efa2753548eac3
|
7
|
+
data.tar.gz: 0a06b879d4f468e62bf22037d94338a384987e5e1bc4ee72752c038700f87dfb5214d50436e5bd2a69a713fc419e3b5377ea14b7a726ec988f107a32b5d27df9
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,17 @@
|
|
1
1
|
# Authenticate Changelog
|
2
2
|
|
3
|
+
## [0.3.1] - March 10, 2016
|
4
|
+
|
5
|
+
User controller now allows arbitrary parameters without having to explicitly declare
|
6
|
+
them. Still requires email and password.
|
7
|
+
Mailer now checks for mail.respond_to?(:deliver_later) rather than rails version,
|
8
|
+
to decide deliver vs deliver_later.
|
9
|
+
Removed unused user_id_parameter config method.
|
10
|
+
|
11
|
+
[0.3.1]: https://github.com/tomichj/authenticate/compare/v0.3.0...v0.3.1
|
12
|
+
|
13
|
+
|
14
|
+
|
3
15
|
## [0.3.0] - February 24, 2016
|
4
16
|
|
5
17
|
Moved normalize_email and find_normalized_email methods to base User module.
|
data/README.md
CHANGED
@@ -28,7 +28,7 @@ Authenticate:
|
|
28
28
|
* loads modules into your user model to provide authentication functionality
|
29
29
|
* loads `callbacks` that are triggered during authentication and access events. All authentication
|
30
30
|
decisions are performed in callbacks, e.g. do you have a valid session, has your session timed out, etc.
|
31
|
-
* loads a module into your controllers (typically
|
31
|
+
* loads a module into your controllers (typically `ApplicationController`) to secure controller actions
|
32
32
|
|
33
33
|
The callback architecture is based on the system used by devise and warden, but significantly simplified.
|
34
34
|
|
@@ -56,7 +56,7 @@ class Authenticate::PasswordsController < Authenticate::AuthenticateController
|
|
56
56
|
def deliver_email(user)
|
57
57
|
mail = ::AuthenticateMailer.change_password(user)
|
58
58
|
|
59
|
-
if
|
59
|
+
if mail.respond_to?(:deliver_later)
|
60
60
|
mail.deliver_later
|
61
61
|
else
|
62
62
|
mail.deliver
|
@@ -30,18 +30,20 @@ class Authenticate::UsersController < Authenticate::AuthenticateController
|
|
30
30
|
Authenticate.configuration.redirect_url
|
31
31
|
end
|
32
32
|
|
33
|
+
|
33
34
|
def user_from_params
|
34
|
-
|
35
|
-
|
36
|
-
|
35
|
+
email = user_params.delete(:email)
|
36
|
+
password = user_params.delete(:password)
|
37
|
+
|
38
|
+
Authenticate.configuration.user_model_class.new(user_params).tap do |user|
|
39
|
+
user.email = email
|
40
|
+
user.password = password
|
41
|
+
end
|
37
42
|
end
|
38
43
|
|
39
|
-
|
40
|
-
|
41
|
-
#
|
42
|
-
# * param_key - String used for parameter names, ActiveModel::Naming.param_key
|
43
|
-
#
|
44
|
-
def user_params(param_key)
|
45
|
-
params.require(param_key).permit(:username, :email, :password)
|
44
|
+
def user_params
|
45
|
+
params[Authenticate.configuration.user_model_param_key] || Hash.new
|
46
46
|
end
|
47
|
+
|
48
|
+
|
47
49
|
end
|
@@ -1,8 +1,10 @@
|
|
1
1
|
module Authenticate
|
2
2
|
class Configuration
|
3
3
|
|
4
|
-
# ActiveRecord model class name that represents your user.
|
5
|
-
#
|
4
|
+
# ActiveRecord model class name that represents your user. Specify as a String.
|
5
|
+
#
|
6
|
+
# Defaults to '::User'.
|
7
|
+
#
|
6
8
|
# To set to a different class:
|
7
9
|
#
|
8
10
|
# Authenticate.configure do |config|
|
@@ -13,12 +15,20 @@ module Authenticate
|
|
13
15
|
attr_accessor :user_model
|
14
16
|
|
15
17
|
# Name of the session cookie Authenticate will send to client browser.
|
18
|
+
#
|
16
19
|
# Defaults to 'authenticate_session_token'.
|
20
|
+
#
|
17
21
|
# @return [String]
|
18
22
|
attr_accessor :cookie_name
|
19
23
|
|
20
|
-
# A lambda called to set the remember token cookie expires attribute.
|
21
|
-
#
|
24
|
+
# A lambda called to set the remember token cookie expires attribute.
|
25
|
+
#
|
26
|
+
# Defaults to 1 year expiration.
|
27
|
+
#
|
28
|
+
# Note this is NOT the authenticate session's max lifetime, but only the cookie's lifetime.
|
29
|
+
#
|
30
|
+
# See #max_session_lifetime for more on the session lifetime.
|
31
|
+
#
|
22
32
|
# To set cookie expiration yourself:
|
23
33
|
#
|
24
34
|
# Authenticate.configure do |config|
|
@@ -29,44 +39,59 @@ module Authenticate
|
|
29
39
|
attr_accessor :cookie_expiration
|
30
40
|
|
31
41
|
# The domain to set for the Authenticate session cookie.
|
32
|
-
#
|
33
|
-
# to the domain of the request.
|
42
|
+
#
|
43
|
+
# Defaults to nil, which will cause the cookie domain to set to the domain of the request.
|
44
|
+
#
|
34
45
|
# @return [String]
|
35
46
|
attr_accessor :cookie_domain
|
36
47
|
|
37
48
|
# Controls which paths the session token cookie is valid for.
|
49
|
+
#
|
38
50
|
# Defaults to `"/"` for the entire domain.
|
51
|
+
#
|
39
52
|
# For more, see [RFC6265](http://tools.ietf.org/html/rfc6265#section-5.1.4).
|
40
53
|
# @return [String]
|
41
54
|
attr_accessor :cookie_path
|
42
55
|
|
43
|
-
# Controls the secure setting on the session cookie.
|
44
|
-
#
|
56
|
+
# Controls the secure setting on the session cookie.
|
57
|
+
#
|
58
|
+
# Defaults to `false`.
|
59
|
+
#
|
60
|
+
# When set to 'true', the browser will only send the cookie to the server over HTTPS.
|
45
61
|
# If set to true over an insecure http (not https) connection, the cookie will not
|
46
62
|
# be usable and the user will not be successfully authenticated.
|
47
63
|
#
|
48
64
|
# You should set this value to true in live environments to prevent session hijacking.
|
49
65
|
#
|
66
|
+
# Set to false in development environments.
|
67
|
+
#
|
50
68
|
# For more, see [RFC6265](http://tools.ietf.org/html/rfc6265#section-5.2.5).
|
51
69
|
# @return [Boolean]
|
52
70
|
attr_accessor :secure_cookie
|
53
71
|
|
54
72
|
# Controls whether the HttpOnly flag should be set on the session cookie.
|
55
|
-
#
|
73
|
+
# If `true`, the cookie will not be made available to JavaScript.
|
74
|
+
#
|
75
|
+
# Defaults to `true`.
|
76
|
+
#
|
56
77
|
# For more see [RFC6265](http://tools.ietf.org/html/rfc6265#section-5.2.6).
|
57
78
|
# @return [Boolean]
|
58
79
|
attr_accessor :cookie_http_only
|
59
80
|
|
60
|
-
# Controls the 'from' address for Authenticate emails.
|
81
|
+
# Controls the 'from' address for Authenticate emails. Set this to a value appropriate to your application.
|
82
|
+
#
|
61
83
|
# Defaults to reply@example.com.
|
84
|
+
#
|
62
85
|
# @return [String]
|
63
86
|
attr_accessor :mailer_sender
|
64
87
|
|
65
88
|
# Determines what crypto is used when authenticating and setting passwords.
|
66
|
-
# Defaults to {Authenticate::Model::BCrypt}. At the moment Bcrypt is the only
|
67
|
-
# option offered.
|
68
89
|
#
|
69
|
-
#
|
90
|
+
# Defaults to {Authenticate::Model::BCrypt}.
|
91
|
+
#
|
92
|
+
# At the moment Bcrypt is the only option offered.
|
93
|
+
#
|
94
|
+
# Crypto implementations must implement:
|
70
95
|
# * match?(secret, encrypted)
|
71
96
|
# * encrypt(secret)
|
72
97
|
#
|
@@ -76,6 +101,7 @@ module Authenticate
|
|
76
101
|
# Invalidate the session after the specified period of idle time.
|
77
102
|
# If the interval between the current access time and the last access time is greater than timeout_in,
|
78
103
|
# the session is invalidated. The user will be prompted for authentication again.
|
104
|
+
#
|
79
105
|
# Defaults to nil, which is no idle timeout.
|
80
106
|
#
|
81
107
|
# Authenticate.configure do |config|
|
@@ -86,9 +112,11 @@ module Authenticate
|
|
86
112
|
attr_accessor :timeout_in
|
87
113
|
|
88
114
|
# Allow a session to 'live' for no more than the given elapsed time, e.g. 8.hours.
|
89
|
-
#
|
90
|
-
#
|
91
|
-
#
|
115
|
+
#
|
116
|
+
# Defaults to nil, or no max session time.
|
117
|
+
#
|
118
|
+
# If set, a user session will expire once it has been active for max_session_lifetime.
|
119
|
+
# The user session is invalidated and the next access will will prompt the user for authentication.
|
92
120
|
#
|
93
121
|
# Authenticate.configure do |config|
|
94
122
|
# config.max_session_lifetime = 8.hours
|
@@ -97,8 +125,8 @@ module Authenticate
|
|
97
125
|
# @return [ActiveSupport::CoreExtensions::Numeric::Time]
|
98
126
|
attr_accessor :max_session_lifetime
|
99
127
|
|
100
|
-
# Number of consecutive bad login attempts allowed.
|
101
|
-
# The user's consecutive bad logins will be tracked, and if they exceed the allowed
|
128
|
+
# Number of consecutive bad login attempts allowed. Commonly called "brute force protection".
|
129
|
+
# The user's consecutive bad logins will be tracked, and if they exceed the allowed maximum,
|
102
130
|
# the user's account will be locked. The length of the lockout is determined by [#bad_login_lockout_period].
|
103
131
|
#
|
104
132
|
# Default is nil, which disables this feature.
|
@@ -112,20 +140,24 @@ module Authenticate
|
|
112
140
|
attr_accessor :max_consecutive_bad_logins_allowed
|
113
141
|
|
114
142
|
# Time period to lock an account for if the user exceeds max_consecutive_bad_logins_allowed.
|
143
|
+
#
|
115
144
|
# If set to nil, account is locked out indefinitely.
|
116
145
|
#
|
117
146
|
# @return [ActiveSupport::CoreExtensions::Numeric::Time]
|
118
147
|
attr_accessor :bad_login_lockout_period
|
119
148
|
|
120
|
-
# Range requirement for password length.
|
149
|
+
# Range requirement for password length.
|
150
|
+
#
|
151
|
+
# Defaults to `8..128`.
|
152
|
+
#
|
121
153
|
# @return [Range]
|
122
154
|
attr_accessor :password_length
|
123
155
|
|
124
156
|
# Strategy for authentication.
|
125
157
|
#
|
126
158
|
# Available strategies:
|
127
|
-
#
|
128
|
-
#
|
159
|
+
# * :email - requires user have attribute :email
|
160
|
+
# * :username - requires user have attribute :username
|
129
161
|
#
|
130
162
|
# Defaults to :email. To set to :username:
|
131
163
|
#
|
@@ -143,34 +175,47 @@ module Authenticate
|
|
143
175
|
attr_accessor :authentication_strategy
|
144
176
|
|
145
177
|
# The default path Authenticate will redirect signed in users to.
|
146
|
-
#
|
147
|
-
#
|
178
|
+
#
|
179
|
+
# Defaults to `"/"`.
|
180
|
+
#
|
181
|
+
# This can also be overridden for specific scenarios by overriding controller methods that rely on it.
|
148
182
|
# @return [String]
|
149
183
|
attr_accessor :redirect_url
|
150
184
|
|
151
185
|
# Controls whether the "sign up" route, allowing creation of users, is enabled.
|
152
|
-
#
|
153
|
-
#
|
186
|
+
#
|
187
|
+
# Defaults to `true`.
|
188
|
+
#
|
189
|
+
# Set to `false` to disable user creation routes. The setting is ignored if routes are disabled.
|
190
|
+
#
|
154
191
|
# @param [Boolean] value
|
155
192
|
# @return [Boolean]
|
156
193
|
attr_accessor :allow_sign_up
|
157
194
|
|
158
|
-
# Enable or disable Authenticate's built-in routes.
|
159
|
-
#
|
195
|
+
# Enable or disable Authenticate's built-in routes.
|
196
|
+
#
|
197
|
+
# Defaults to 'true'.
|
198
|
+
#
|
160
199
|
# If you disable the routes, your application is responsible for all routes.
|
200
|
+
#
|
161
201
|
# You can deploy a copy of Authenticate's routes with `rails generate authenticate:routes`,
|
162
202
|
# which will also set `config.routes = false`.
|
203
|
+
#
|
163
204
|
# @return [Boolean]
|
164
205
|
attr_accessor :routes
|
165
206
|
|
166
207
|
# The time period within which the password must be reset or the token expires.
|
167
208
|
# If set to nil, the password reset token does not expire.
|
209
|
+
#
|
168
210
|
# Defaults to `2.days`.
|
211
|
+
#
|
169
212
|
# @return [ActiveSupport::CoreExtensions::Numeric::Time]
|
170
213
|
attr_accessor :reset_password_within
|
171
214
|
|
172
215
|
# An array of additional modules to load into the User module.
|
216
|
+
#
|
173
217
|
# Defaults to an empty array.
|
218
|
+
#
|
174
219
|
# @return [Array]
|
175
220
|
attr_accessor :modules
|
176
221
|
|
@@ -188,7 +233,7 @@ module Authenticate
|
|
188
233
|
@cookie_domain = nil
|
189
234
|
@cookie_path = '/'
|
190
235
|
@secure_cookie = false
|
191
|
-
@cookie_http_only =
|
236
|
+
@cookie_http_only = true
|
192
237
|
@mailer_sender = 'reply@example.com'
|
193
238
|
@redirect_url = '/'
|
194
239
|
@allow_sign_up = true
|
@@ -204,22 +249,18 @@ module Authenticate
|
|
204
249
|
@user_model_class ||= user_model.constantize
|
205
250
|
end
|
206
251
|
|
252
|
+
# The routing key for user routes. See `routes.rb`.
|
253
|
+
# @return [Symbol]
|
207
254
|
def user_model_route_key
|
208
255
|
return :users if @user_model == '::User' # avoid nil in generator
|
209
256
|
user_model_class.model_name.route_key
|
210
257
|
end
|
211
258
|
|
259
|
+
# The key for accessing user parameters.
|
260
|
+
# @return [Symbol]
|
212
261
|
def user_model_param_key
|
213
262
|
return :user if @user_model == '::User' # avoid nil in generator
|
214
|
-
user_model_class.model_name.param_key
|
215
|
-
end
|
216
|
-
|
217
|
-
# The name of foreign key parameter for the configured user model.
|
218
|
-
# This is derived from the `model_name` of the `user_model` setting.
|
219
|
-
# In the default configuration, this is `user_id`.
|
220
|
-
# @return [Symbol]
|
221
|
-
def user_id_parameter
|
222
|
-
"#{user_model_class.model_name.singular}_id".to_sym
|
263
|
+
user_model_class.model_name.param_key.to_sym
|
223
264
|
end
|
224
265
|
|
225
266
|
# Is the user sign up route enabled?
|
@@ -5,8 +5,8 @@ module Authenticate
|
|
5
5
|
# Heavily borrowed from warden (https://github.com/hassox/warden).
|
6
6
|
#
|
7
7
|
# = Events:
|
8
|
-
#
|
9
|
-
#
|
8
|
+
# * :set_user - called after the user object is loaded, either through id/password or via session token.
|
9
|
+
# * :authentication - called after the user authenticates with id & password
|
10
10
|
#
|
11
11
|
# Callbacks are added via after_set_user or after_authentication.
|
12
12
|
#
|
@@ -16,17 +16,17 @@ module Authenticate
|
|
16
16
|
# = Options
|
17
17
|
#
|
18
18
|
# The callback options may optionally specify when to run the callback:
|
19
|
-
#
|
20
|
-
#
|
19
|
+
# * only - executes the callback only if it matches the event(s) given
|
20
|
+
# * except - executes the callback except if it matches the event(s) given
|
21
21
|
#
|
22
22
|
# The callback may also specify a 'name' key in options. This is for debugging purposes only.
|
23
23
|
#
|
24
24
|
# = Callback block parameters
|
25
25
|
#
|
26
26
|
# Callbacks are invoked with the following block parameters: |user, session, opts|
|
27
|
-
#
|
28
|
-
#
|
29
|
-
#
|
27
|
+
# * user - the user object just loaded
|
28
|
+
# * session - the Authenticate::Session
|
29
|
+
# * opts - any options you want passed into the callback
|
30
30
|
#
|
31
31
|
# = Example
|
32
32
|
#
|
data/lib/authenticate/user.rb
CHANGED
@@ -4,7 +4,7 @@ require 'authenticate/callbacks/authenticatable'
|
|
4
4
|
|
5
5
|
module Authenticate
|
6
6
|
|
7
|
-
# Required to be included in your
|
7
|
+
# Required to be included in your configured user class, which is `User` by
|
8
8
|
# default, but can be changed with {Configuration#user_model=}.
|
9
9
|
#
|
10
10
|
# class User
|
@@ -27,6 +27,9 @@ module Authenticate
|
|
27
27
|
# - generate_session_token - generates and sets the Authenticate session token
|
28
28
|
# - reset_session_token! - calls generate_session_token and save! immediately
|
29
29
|
#
|
30
|
+
# Every user will have these two class methods to normalize email addresses:
|
31
|
+
# - normalize_email(email) - normalize the given email address by downcasing, removing spaces.
|
32
|
+
# - find_by_normalized_email(email) - find a user by his/her normalized email address
|
30
33
|
module User
|
31
34
|
extend ActiveSupport::Concern
|
32
35
|
|
data/lib/authenticate/version.rb
CHANGED
@@ -67,3 +67,57 @@ end
|
|
67
67
|
def expect_mailer_to_have_no_deliveries
|
68
68
|
expect(ActionMailer::Base.deliveries).to be_empty
|
69
69
|
end
|
70
|
+
|
71
|
+
|
72
|
+
|
73
|
+
|
74
|
+
|
75
|
+
feature 'visitor sets new password' do
|
76
|
+
scenario 'requests password change' do
|
77
|
+
user = given_user_with_password_reset_token
|
78
|
+
visit_password_update_page_for user
|
79
|
+
request_password_change_for user
|
80
|
+
expect_password_is_changed_for user
|
81
|
+
expect_redirect_to_root
|
82
|
+
end
|
83
|
+
|
84
|
+
scenario 'attempts password change with fake password reset token' do
|
85
|
+
user = given_user_with_fake_password_reset_token
|
86
|
+
visit_password_update_page_for user
|
87
|
+
expect_failure_flash
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
def given_user_with_fake_password_reset_token
|
93
|
+
user = create :user
|
94
|
+
user.password_reset_token = 'big_fake_token'
|
95
|
+
user
|
96
|
+
end
|
97
|
+
|
98
|
+
def given_user_with_password_reset_token
|
99
|
+
create :user, :with_password_reset_token_and_timestamp
|
100
|
+
end
|
101
|
+
|
102
|
+
def visit_password_update_page_for user
|
103
|
+
visit edit_users_password_path(user.id, token: user.password_reset_token)
|
104
|
+
end
|
105
|
+
|
106
|
+
def request_password_change_for user
|
107
|
+
fill_in 'password_reset_password', with: 'new_dumb_password'
|
108
|
+
click_button 'Save this password'
|
109
|
+
end
|
110
|
+
|
111
|
+
def expect_password_is_changed_for user
|
112
|
+
old_encrypted_password = user.encrypted_password
|
113
|
+
expect(user.reload.encrypted_password).to_not eq old_encrypted_password
|
114
|
+
end
|
115
|
+
|
116
|
+
def expect_redirect_to_root
|
117
|
+
expect(current_path).to eq Authenticate.configuration.redirect_url
|
118
|
+
end
|
119
|
+
|
120
|
+
def expect_failure_flash
|
121
|
+
expect(page).to have_content 'Please double check the URL or try submitting the form again.'
|
122
|
+
end
|
123
|
+
|
@@ -24,7 +24,7 @@ describe Authenticate::Configuration do
|
|
24
24
|
end
|
25
25
|
|
26
26
|
it 'get a param key for a user model' do
|
27
|
-
expect(@conf.user_model_param_key).to eq(
|
27
|
+
expect(@conf.user_model_param_key).to eq(:gug_profile)
|
28
28
|
end
|
29
29
|
|
30
30
|
describe '#authentication_strategy' do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: authenticate
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justin Tomich
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-03-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bcrypt
|
@@ -190,17 +190,11 @@ files:
|
|
190
190
|
- LICENSE
|
191
191
|
- README.md
|
192
192
|
- Rakefile
|
193
|
-
- app/assets/config/authenticate_manifest.js
|
194
|
-
- app/assets/images/authenticate/.keep
|
195
|
-
- app/assets/javascripts/authenticate/.keep
|
196
|
-
- app/assets/stylesheets/authenticate/.keep
|
197
193
|
- app/controllers/authenticate/authenticate_controller.rb
|
198
194
|
- app/controllers/authenticate/passwords_controller.rb
|
199
195
|
- app/controllers/authenticate/sessions_controller.rb
|
200
196
|
- app/controllers/authenticate/users_controller.rb
|
201
|
-
- app/helpers/.keep
|
202
197
|
- app/mailers/authenticate_mailer.rb
|
203
|
-
- app/models/.keep
|
204
198
|
- app/views/authenticate_mailer/change_password.html.erb
|
205
199
|
- app/views/authenticate_mailer/change_password.text.erb
|
206
200
|
- app/views/layouts/application.html.erb
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
data/app/helpers/.keep
DELETED
File without changes
|
data/app/models/.keep
DELETED
File without changes
|