sorcery 0.9.1 → 0.16.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (199) hide show
  1. checksums.yaml +5 -5
  2. data/.github/FUNDING.yml +1 -0
  3. data/.github/ISSUE_TEMPLATE.md +24 -0
  4. data/.github/PULL_REQUEST_TEMPLATE.md +7 -0
  5. data/.github/workflows/ruby.yml +70 -0
  6. data/.gitignore +3 -0
  7. data/.rubocop.yml +55 -0
  8. data/.rubocop_todo.yml +163 -0
  9. data/CHANGELOG.md +132 -34
  10. data/CODE_OF_CONDUCT.md +14 -0
  11. data/Gemfile +3 -17
  12. data/{LICENSE.txt → LICENSE.md} +1 -1
  13. data/MAINTAINING.md +64 -0
  14. data/README.md +146 -269
  15. data/Rakefile +4 -2
  16. data/SECURITY.md +19 -0
  17. data/gemfiles/rails_52.gemfile +7 -0
  18. data/gemfiles/rails_60.gemfile +7 -0
  19. data/gemfiles/rails_61.gemfile +7 -0
  20. data/gemfiles/rails_70.gemfile +7 -0
  21. data/lib/generators/sorcery/USAGE +1 -1
  22. data/lib/generators/sorcery/helpers.rb +8 -4
  23. data/lib/generators/sorcery/install_generator.rb +41 -35
  24. data/lib/generators/sorcery/templates/initializer.rb +216 -112
  25. data/lib/generators/sorcery/templates/migration/activity_logging.rb +7 -7
  26. data/lib/generators/sorcery/templates/migration/brute_force_protection.rb +5 -5
  27. data/lib/generators/sorcery/templates/migration/core.rb +5 -7
  28. data/lib/generators/sorcery/templates/migration/external.rb +4 -4
  29. data/lib/generators/sorcery/templates/migration/magic_login.rb +9 -0
  30. data/lib/generators/sorcery/templates/migration/remember_me.rb +5 -5
  31. data/lib/generators/sorcery/templates/migration/reset_password.rb +7 -6
  32. data/lib/generators/sorcery/templates/migration/user_activation.rb +6 -6
  33. data/lib/sorcery/adapters/active_record_adapter.rb +11 -21
  34. data/lib/sorcery/adapters/mongoid_adapter.rb +23 -11
  35. data/lib/sorcery/controller/config.rb +27 -23
  36. data/lib/sorcery/controller/submodules/activity_logging.rb +16 -18
  37. data/lib/sorcery/controller/submodules/brute_force_protection.rb +1 -2
  38. data/lib/sorcery/controller/submodules/external.rb +69 -44
  39. data/lib/sorcery/controller/submodules/http_basic_auth.rb +18 -19
  40. data/lib/sorcery/controller/submodules/remember_me.rb +16 -16
  41. data/lib/sorcery/controller/submodules/session_timeout.rb +33 -11
  42. data/lib/sorcery/controller.rb +50 -35
  43. data/lib/sorcery/crypto_providers/aes256.rb +17 -16
  44. data/lib/sorcery/crypto_providers/bcrypt.rb +26 -22
  45. data/lib/sorcery/crypto_providers/common.rb +1 -1
  46. data/lib/sorcery/crypto_providers/md5.rb +5 -5
  47. data/lib/sorcery/crypto_providers/sha1.rb +5 -5
  48. data/lib/sorcery/crypto_providers/sha256.rb +2 -2
  49. data/lib/sorcery/crypto_providers/sha512.rb +3 -3
  50. data/lib/sorcery/engine.rb +19 -11
  51. data/lib/sorcery/model/config.rb +73 -50
  52. data/lib/sorcery/model/submodules/activity_logging.rb +31 -12
  53. data/lib/sorcery/model/submodules/brute_force_protection.rb +38 -31
  54. data/lib/sorcery/model/submodules/external.rb +22 -10
  55. data/lib/sorcery/model/submodules/magic_login.rb +130 -0
  56. data/lib/sorcery/model/submodules/remember_me.rb +19 -7
  57. data/lib/sorcery/model/submodules/reset_password.rb +64 -42
  58. data/lib/sorcery/model/submodules/user_activation.rb +52 -54
  59. data/lib/sorcery/model/temporary_token.rb +30 -7
  60. data/lib/sorcery/model.rb +65 -40
  61. data/lib/sorcery/protocols/oauth.rb +4 -9
  62. data/lib/sorcery/protocols/oauth2.rb +0 -2
  63. data/lib/sorcery/providers/auth0.rb +46 -0
  64. data/lib/sorcery/providers/base.rb +4 -4
  65. data/lib/sorcery/providers/battlenet.rb +51 -0
  66. data/lib/sorcery/providers/discord.rb +52 -0
  67. data/lib/sorcery/providers/facebook.rb +8 -11
  68. data/lib/sorcery/providers/github.rb +5 -7
  69. data/lib/sorcery/providers/google.rb +3 -5
  70. data/lib/sorcery/providers/heroku.rb +7 -8
  71. data/lib/sorcery/providers/instagram.rb +73 -0
  72. data/lib/sorcery/providers/jira.rb +12 -17
  73. data/lib/sorcery/providers/line.rb +63 -0
  74. data/lib/sorcery/providers/linkedin.rb +44 -35
  75. data/lib/sorcery/providers/liveid.rb +4 -7
  76. data/lib/sorcery/providers/microsoft.rb +59 -0
  77. data/lib/sorcery/providers/paypal.rb +60 -0
  78. data/lib/sorcery/providers/salesforce.rb +3 -5
  79. data/lib/sorcery/providers/slack.rb +45 -0
  80. data/lib/sorcery/providers/twitter.rb +4 -6
  81. data/lib/sorcery/providers/vk.rb +8 -9
  82. data/lib/sorcery/providers/wechat.rb +81 -0
  83. data/lib/sorcery/providers/xing.rb +7 -10
  84. data/lib/sorcery/test_helpers/internal/rails.rb +25 -17
  85. data/lib/sorcery/test_helpers/internal.rb +15 -14
  86. data/lib/sorcery/test_helpers/rails/controller.rb +1 -1
  87. data/lib/sorcery/test_helpers/rails/integration.rb +5 -6
  88. data/lib/sorcery/test_helpers/rails/request.rb +20 -0
  89. data/lib/sorcery/version.rb +1 -1
  90. data/lib/sorcery.rb +4 -17
  91. data/sorcery.gemspec +43 -28
  92. data/spec/active_record/user_activation_spec.rb +4 -5
  93. data/spec/active_record/user_activity_logging_spec.rb +4 -6
  94. data/spec/active_record/user_brute_force_protection_spec.rb +5 -6
  95. data/spec/active_record/user_magic_login_spec.rb +15 -0
  96. data/spec/active_record/user_oauth_spec.rb +5 -6
  97. data/spec/active_record/user_remember_me_spec.rb +5 -6
  98. data/spec/active_record/user_reset_password_spec.rb +4 -5
  99. data/spec/active_record/user_spec.rb +7 -17
  100. data/spec/controllers/controller_activity_logging_spec.rb +13 -24
  101. data/spec/controllers/controller_brute_force_protection_spec.rb +8 -10
  102. data/spec/controllers/controller_http_basic_auth_spec.rb +20 -21
  103. data/spec/controllers/controller_oauth2_spec.rb +297 -158
  104. data/spec/controllers/controller_oauth_spec.rb +97 -71
  105. data/spec/controllers/controller_remember_me_spec.rb +49 -36
  106. data/spec/controllers/controller_session_timeout_spec.rb +106 -20
  107. data/spec/controllers/controller_spec.rb +87 -111
  108. data/spec/orm/active_record.rb +3 -3
  109. data/spec/providers/example_provider_spec.rb +17 -0
  110. data/spec/providers/example_spec.rb +17 -0
  111. data/spec/providers/examples_spec.rb +17 -0
  112. data/spec/providers/vk_spec.rb +42 -0
  113. data/spec/rails_app/app/active_record/authentication.rb +1 -1
  114. data/spec/rails_app/app/active_record/user.rb +2 -2
  115. data/spec/rails_app/app/assets/config/manifest.js +1 -0
  116. data/spec/rails_app/app/controllers/application_controller.rb +2 -0
  117. data/spec/rails_app/app/controllers/sorcery_controller.rb +250 -46
  118. data/spec/rails_app/app/mailers/sorcery_mailer.rb +23 -17
  119. data/spec/rails_app/app/views/sorcery_mailer/magic_login_email.html.erb +13 -0
  120. data/spec/rails_app/app/views/sorcery_mailer/magic_login_email.text.erb +6 -0
  121. data/spec/rails_app/config/application.rb +14 -9
  122. data/spec/rails_app/config/boot.rb +2 -2
  123. data/spec/rails_app/config/environment.rb +1 -1
  124. data/spec/rails_app/config/environments/test.rb +1 -1
  125. data/spec/rails_app/config/initializers/compatible_legacy_migration.rb +11 -0
  126. data/spec/rails_app/config/initializers/session_store.rb +3 -3
  127. data/spec/rails_app/config/routes.rb +31 -1
  128. data/spec/rails_app/config/secrets.yml +4 -0
  129. data/spec/rails_app/config.ru +1 -1
  130. data/spec/rails_app/db/migrate/activation/20101224223622_add_activation_to_users.rb +4 -4
  131. data/spec/rails_app/db/migrate/activity_logging/20101224223624_add_activity_logging_to_users.rb +10 -10
  132. data/spec/rails_app/db/migrate/brute_force_protection/20101224223626_add_brute_force_protection_to_users.rb +5 -5
  133. data/spec/rails_app/db/migrate/core/20101224223620_create_users.rb +5 -5
  134. data/spec/rails_app/db/migrate/external/20101224223628_create_authentications_and_user_providers.rb +3 -3
  135. data/spec/rails_app/db/migrate/invalidate_active_sessions/20180221093235_add_invalidate_active_sessions_before_to_users.rb +9 -0
  136. data/spec/rails_app/db/migrate/magic_login/20170924151831_add_magic_login_to_users.rb +17 -0
  137. data/spec/rails_app/db/migrate/remember_me/20101224223623_add_remember_me_token_to_users.rb +6 -6
  138. data/spec/rails_app/db/migrate/reset_password/20101224223622_add_reset_password_to_users.rb +7 -5
  139. data/spec/rails_app/db/schema.rb +7 -9
  140. data/spec/shared_examples/user_activation_shared_examples.rb +177 -58
  141. data/spec/shared_examples/user_activity_logging_shared_examples.rb +47 -41
  142. data/spec/shared_examples/user_brute_force_protection_shared_examples.rb +19 -24
  143. data/spec/shared_examples/user_magic_login_shared_examples.rb +150 -0
  144. data/spec/shared_examples/user_oauth_shared_examples.rb +7 -10
  145. data/spec/shared_examples/user_remember_me_shared_examples.rb +91 -22
  146. data/spec/shared_examples/user_reset_password_shared_examples.rb +153 -58
  147. data/spec/shared_examples/user_shared_examples.rb +328 -145
  148. data/spec/sorcery_crypto_providers_spec.rb +122 -75
  149. data/spec/sorcery_temporary_token_spec.rb +27 -0
  150. data/spec/spec.opts +1 -1
  151. data/spec/spec_helper.rb +19 -14
  152. data/spec/support/migration_helper.rb +29 -0
  153. data/spec/support/providers/example.rb +11 -0
  154. data/spec/support/providers/example_provider.rb +11 -0
  155. data/spec/support/providers/examples.rb +11 -0
  156. metadata +119 -89
  157. data/.travis.yml +0 -132
  158. data/gemfiles/active_record-rails40.gemfile +0 -7
  159. data/gemfiles/active_record-rails41.gemfile +0 -7
  160. data/gemfiles/mongo_mapper-rails40.gemfile +0 -9
  161. data/gemfiles/mongo_mapper-rails41.gemfile +0 -9
  162. data/gemfiles/mongoid-rails40.gemfile +0 -9
  163. data/gemfiles/mongoid-rails41.gemfile +0 -9
  164. data/gemfiles/mongoid3-rails32.gemfile +0 -9
  165. data/lib/sorcery/adapters/data_mapper_adapter.rb +0 -176
  166. data/lib/sorcery/adapters/mongo_mapper_adapter.rb +0 -110
  167. data/lib/sorcery/railties/tasks.rake +0 -6
  168. data/spec/data_mapper/user_activation_spec.rb +0 -10
  169. data/spec/data_mapper/user_activity_logging_spec.rb +0 -14
  170. data/spec/data_mapper/user_brute_force_protection_spec.rb +0 -9
  171. data/spec/data_mapper/user_oauth_spec.rb +0 -9
  172. data/spec/data_mapper/user_remember_me_spec.rb +0 -8
  173. data/spec/data_mapper/user_reset_password_spec.rb +0 -8
  174. data/spec/data_mapper/user_spec.rb +0 -27
  175. data/spec/mongo_mapper/user_activation_spec.rb +0 -9
  176. data/spec/mongo_mapper/user_activity_logging_spec.rb +0 -8
  177. data/spec/mongo_mapper/user_brute_force_protection_spec.rb +0 -8
  178. data/spec/mongo_mapper/user_oauth_spec.rb +0 -8
  179. data/spec/mongo_mapper/user_remember_me_spec.rb +0 -8
  180. data/spec/mongo_mapper/user_reset_password_spec.rb +0 -8
  181. data/spec/mongo_mapper/user_spec.rb +0 -37
  182. data/spec/mongoid/user_activation_spec.rb +0 -9
  183. data/spec/mongoid/user_activity_logging_spec.rb +0 -8
  184. data/spec/mongoid/user_brute_force_protection_spec.rb +0 -8
  185. data/spec/mongoid/user_oauth_spec.rb +0 -8
  186. data/spec/mongoid/user_remember_me_spec.rb +0 -8
  187. data/spec/mongoid/user_reset_password_spec.rb +0 -8
  188. data/spec/mongoid/user_spec.rb +0 -51
  189. data/spec/orm/data_mapper.rb +0 -48
  190. data/spec/orm/mongo_mapper.rb +0 -10
  191. data/spec/orm/mongoid.rb +0 -22
  192. data/spec/rails_app/app/data_mapper/authentication.rb +0 -8
  193. data/spec/rails_app/app/data_mapper/user.rb +0 -7
  194. data/spec/rails_app/app/mongo_mapper/authentication.rb +0 -6
  195. data/spec/rails_app/app/mongo_mapper/user.rb +0 -7
  196. data/spec/rails_app/app/mongoid/authentication.rb +0 -7
  197. data/spec/rails_app/app/mongoid/user.rb +0 -7
  198. data/spec/rails_app/config/initializers/secret_token.rb +0 -7
  199. data/spec/rails_app/log/development.log +0 -1791
@@ -1,10 +1,8 @@
1
- shared_examples_for "rails_3_core_model" do
2
-
1
+ shared_examples_for 'rails_3_core_model' do
3
2
  let(:user) { create_new_user }
4
3
  let(:crypted_password) { user.send User.sorcery_config.crypted_password_attribute_name }
5
4
 
6
- describe "loaded plugin configuration" do
7
-
5
+ describe 'loaded plugin configuration' do
8
6
  after(:each) { User.sorcery_config.reset! }
9
7
 
10
8
  it "enables configuration option 'username_attribute_names'" do
@@ -56,8 +54,15 @@ shared_examples_for "rails_3_core_model" do
56
54
  expect(User.sorcery_config.custom_encryption_provider).to eq Array
57
55
  end
58
56
 
57
+ it "enables configuration option 'pepper'" do
58
+ pepper = '*$%&%*++'
59
+ sorcery_model_property_set(:pepper, pepper)
60
+
61
+ expect(User.sorcery_config.pepper).to eq pepper
62
+ end
63
+
59
64
  it "enables configuration option 'salt_join_token'" do
60
- salt_join_token = "--%%*&-"
65
+ salt_join_token = '--%%*&-'
61
66
  sorcery_model_property_set(:salt_join_token, salt_join_token)
62
67
 
63
68
  expect(User.sorcery_config.salt_join_token).to eq salt_join_token
@@ -70,101 +75,151 @@ shared_examples_for "rails_3_core_model" do
70
75
  expect(User.sorcery_config.stretches).to eq stretches
71
76
  end
72
77
 
78
+ it "enables configuration option 'deliver_later_enabled" do
79
+ sorcery_model_property_set(:email_delivery_method, :deliver_later)
80
+ expect(User.sorcery_config.email_delivery_method).to eq :deliver_later
81
+ end
82
+
73
83
  it 'respond to username=' do
74
84
  expect(User.new).to respond_to(:username=)
75
85
  end
76
86
  end
77
87
 
78
- describe "when activated with sorcery" do
88
+ describe 'when activated with sorcery' do
79
89
  before(:all) { sorcery_reload! }
80
90
  before(:each) { User.sorcery_adapter.delete_all }
81
91
 
82
- it "does not add authenticate method to base class", active_record: true do
92
+ it 'does not add authenticate method to base class', active_record: true do
83
93
  expect(ActiveRecord::Base).not_to respond_to(:authenticate) if defined?(ActiveRecord)
84
94
  end
85
95
 
86
- it "responds to class method authenticate" do
96
+ it 'responds to class method authenticate' do
87
97
  expect(User).to respond_to :authenticate
88
98
  end
89
99
 
90
- describe "#authenticate" do
91
- it "returns user if credentials are good" do
92
- expect(User.authenticate user.email, 'secret').to eq user
100
+ describe '#authenticate' do
101
+ it 'returns user if credentials are good' do
102
+ expect(User.authenticate(user.email, 'secret')).to eq user
93
103
  end
94
104
 
95
- it "returns nil if credentials are bad" do
96
- expect(User.authenticate user.email, 'wrong!').to be nil
105
+ it 'returns nil if credentials are bad' do
106
+ expect(User.authenticate(user.email, 'wrong!')).to be nil
97
107
  end
98
108
 
99
- context "with empty credentials" do
100
- before do
101
- sorcery_model_property_set(:downcase_username_before_authenticating, true)
102
- end
103
-
109
+ context 'downcasing username' do
104
110
  after do
105
111
  sorcery_reload!
106
112
  end
107
113
 
108
- it "don't downcase empty credentials" do
109
- expect(User.authenticate(nil, 'wrong!')).to be_falsy
114
+ context 'when downcasing set to false' do
115
+ before do
116
+ sorcery_model_property_set(:downcase_username_before_authenticating, false)
117
+ end
118
+
119
+ it 'does not find user with wrongly capitalized username' do
120
+ expect(User.authenticate(user.email.capitalize, 'secret')).to be_nil
121
+ end
122
+
123
+ it 'finds user with correctly capitalized username' do
124
+ expect(User.authenticate(user.email, 'secret')).to eq user
125
+ end
110
126
  end
111
- end
112
127
 
113
- context "and model implements active_for_authentication?" do
128
+ context 'when downcasing set to true' do
129
+ before do
130
+ sorcery_model_property_set(:downcase_username_before_authenticating, true)
131
+ end
114
132
 
115
- it "authenticates returns user if active_for_authentication? returns true" do
133
+ it 'does not find user with wrongly capitalized username' do
134
+ expect(User.authenticate(user.email.capitalize, 'secret')).to eq user
135
+ end
136
+
137
+ it 'finds user with correctly capitalized username' do
138
+ expect(User.authenticate(user.email, 'secret')).to eq user
139
+ end
140
+ end
141
+ end
142
+
143
+ context 'and model implements active_for_authentication?' do
144
+ it 'authenticates returns user if active_for_authentication? returns true' do
116
145
  allow_any_instance_of(User).to receive(:active_for_authentication?) { true }
117
146
 
118
- expect(User.authenticate user.email, 'secret').to eq user
147
+ expect(User.authenticate(user.email, 'secret')).to eq user
119
148
  end
120
149
 
121
- it "authenticate returns nil if active_for_authentication? returns false" do
150
+ it 'authenticate returns nil if active_for_authentication? returns false' do
122
151
  allow_any_instance_of(User).to receive(:active_for_authentication?) { false }
123
152
 
124
- expect(User.authenticate user.email, 'secret').to be_nil
153
+ expect(User.authenticate(user.email, 'secret')).to be_nil
154
+ end
155
+ end
156
+
157
+ context 'in block mode' do
158
+ it 'yields the user if credentials are good' do
159
+ User.authenticate(user.email, 'secret') do |user2, failure|
160
+ expect(user2).to eq user
161
+ expect(failure).to be_nil
162
+ end
163
+ end
164
+
165
+ it 'yields the user and proper error if credentials are bad' do
166
+ User.authenticate(user.email, 'wrong!') do |user2, failure|
167
+ expect(user2).to eq user
168
+ expect(failure).to eq :invalid_password
169
+ end
170
+ end
171
+
172
+ it 'yields the proper error if no user exists' do
173
+ [nil, '', 'not@a.user'].each do |email|
174
+ User.authenticate(email, 'wrong!') do |user2, failure|
175
+ expect(user2).to be_nil
176
+ expect(failure).to eq :invalid_login
177
+ end
178
+ end
125
179
  end
126
180
  end
127
181
  end
128
182
 
129
183
  specify { expect(User).to respond_to(:encrypt) }
130
184
 
131
- it "subclass inherits config if defined so" do
132
- sorcery_reload!([],{:subclasses_inherit_config => true})
185
+ it 'subclass inherits config if defined so' do
186
+ sorcery_reload!([], subclasses_inherit_config: true)
133
187
  class Admin < User; end
134
188
 
135
189
  expect(Admin.sorcery_config).not_to be_nil
136
190
  expect(Admin.sorcery_config).to eq User.sorcery_config
137
191
  end
138
192
 
139
- it "subclass does not inherit config if not defined so" do
140
- sorcery_reload!([],{:subclasses_inherit_config => false})
193
+ it 'subclass does not inherit config if not defined so' do
194
+ sorcery_reload!([], subclasses_inherit_config: false)
141
195
  class Admin2 < User; end
142
196
 
143
197
  expect(Admin2.sorcery_config).to be_nil
144
198
  end
145
199
  end
146
200
 
147
-
148
- describe "registration" do
149
-
201
+ describe 'registration' do
150
202
  before(:all) { sorcery_reload! }
151
203
  before(:each) { User.sorcery_adapter.delete_all }
152
204
 
153
- it "by default, encryption_provider is not nil" do
205
+ it 'by default, encryption_provider is not nil' do
154
206
  expect(User.sorcery_config.encryption_provider).not_to be_nil
155
207
  end
156
208
 
157
- it "encrypts password when a new user is saved" do
158
- expect(User.sorcery_config.encryption_provider.matches? crypted_password, 'secret', user.salt).to be true
209
+ it 'encrypts password when a new user is saved' do
210
+ expect(
211
+ User.sorcery_config.encryption_provider.matches?(crypted_password, 'secret', user.salt)
212
+ ).to be true
159
213
  end
160
214
 
161
- it "clears the virtual password field if the encryption process worked" do
215
+ it 'clears the virtual password field if the encryption process worked' do
162
216
  expect(user.password).to be_nil
163
217
  end
164
218
 
165
- it "does not clear the virtual password field if save failed due to validity" do
219
+ it 'does not clear the virtual password field if save failed due to validity' do
166
220
  User.class_eval do
167
- validates_format_of :email, :with => /\A(.)+@(.)+\Z/, :if => Proc.new {|r| r.email}, :message => "is invalid"
221
+ validates_format_of :email, with: /\A(.)+@(.)+\Z/,
222
+ if: proc { |r| r.email }, message: 'is invalid'
168
223
  end
169
224
 
170
225
  user.password = 'blupush'
@@ -174,35 +229,42 @@ shared_examples_for "rails_3_core_model" do
174
229
  expect(user.password).not_to be_nil
175
230
  end
176
231
 
177
- it "does not clear the virtual password field if save failed due to exception" do
232
+ it 'does not clear the virtual password field if save failed due to exception' do
178
233
  user.password = '4blupush'
179
234
  user.username = nil
180
235
 
181
236
  expect(user).to receive(:save) { raise RuntimeError }
182
237
 
238
+ # rubocop:disable Lint/HandleExceptions
183
239
  begin
184
240
  user.save
185
- rescue
241
+ rescue RuntimeError
242
+ # Intentionally force exception during save
186
243
  end
244
+ # rubocop:enable Lint/HandleExceptions
187
245
 
188
246
  expect(user.password).not_to be_nil
189
247
  end
190
248
 
191
- it "does not encrypt the password twice when a user is updated" do
192
- user.email = "blup@bla.com"
249
+ it 'does not encrypt the password twice when a user is updated' do
250
+ user.email = 'blup@bla.com'
193
251
  user.save
194
252
 
195
- expect(User.sorcery_config.encryption_provider.matches? crypted_password, 'secret', user.salt).to be true
253
+ expect(
254
+ User.sorcery_config.encryption_provider.matches?(crypted_password, 'secret', user.salt)
255
+ ).to be true
196
256
  end
197
257
 
198
- it "replaces the crypted_password in case a new password is set" do
258
+ it 'replaces the crypted_password in case a new password is set' do
199
259
  user.password = 'new_secret'
200
260
  user.save
201
261
 
202
- expect(User.sorcery_config.encryption_provider.matches? crypted_password, 'secret', user.salt).to be false
262
+ expect(
263
+ User.sorcery_config.encryption_provider.matches?(crypted_password, 'secret', user.salt)
264
+ ).to be false
203
265
  end
204
266
 
205
- describe "when user has password_confirmation_defined" do
267
+ describe 'when user has password_confirmation_defined' do
206
268
  before(:all) do
207
269
  update_model { attr_accessor :password_confirmation }
208
270
  end
@@ -212,17 +274,25 @@ shared_examples_for "rails_3_core_model" do
212
274
  User.send(:remove_method, :password_confirmation=)
213
275
  end
214
276
 
215
- it "clears the virtual password field if the encryption process worked" do
216
- user = create_new_user(username: "u", password: "secret", password_confirmation: "secret", email: "email@example.com")
277
+ it 'clears the virtual password field if the encryption process worked' do
278
+ user = create_new_user(
279
+ username: 'u',
280
+ password: 'secret', password_confirmation: 'secret',
281
+ email: 'email@example.com'
282
+ )
217
283
 
218
284
  expect(user.password_confirmation).to be_nil
219
285
  end
220
286
 
221
- it "does not clear the virtual password field if save failed due to validity" do
287
+ it 'does not clear the virtual password field if save failed due to validity' do
222
288
  User.class_eval do
223
- validates_format_of :email, :with => /\A(.)+@(.)+\Z/
289
+ validates_format_of :email, with: /\A(.)+@(.)+\Z/
224
290
  end
225
- user = build_new_user(username: "u", password: "secret", password_confirmation: "secret", email: "asd")
291
+ user = build_new_user(
292
+ username: 'u',
293
+ password: 'secret', password_confirmation: 'secret',
294
+ email: 'asd'
295
+ )
226
296
  user.save
227
297
 
228
298
  expect(user.password_confirmation).not_to be_nil
@@ -230,25 +300,93 @@ shared_examples_for "rails_3_core_model" do
230
300
  end
231
301
  end
232
302
 
233
- describe "password validation" do
234
-
235
- let(:user_with_pass) { create_new_user({:username => 'foo_bar', :email => "foo@bar.com", :password => 'foobar'})}
303
+ describe 'password validation' do
304
+ let(:user_with_pass) do
305
+ create_new_user(username: 'foo_bar', email: 'foo@bar.com', password: 'foobar')
306
+ end
236
307
 
237
308
  specify { expect(user_with_pass).to respond_to :valid_password? }
238
-
239
- it "returns true if password is correct" do
240
- expect(user_with_pass.valid_password?("foobar")).to be true
309
+
310
+ it 'returns true if password is correct' do
311
+ expect(user_with_pass.valid_password?('foobar')).to be true
312
+ end
313
+
314
+ it 'returns false if password is incorrect' do
315
+ expect(user_with_pass.valid_password?('foobug')).to be false
316
+ end
317
+ end
318
+
319
+ describe 'generic send email' do
320
+ before(:all) do
321
+ MigrationHelper.migrate("#{Rails.root}/db/migrate/activation")
322
+ User.reset_column_information
241
323
  end
242
-
243
- it "returns false if password is incorrect" do
244
- expect(user_with_pass.valid_password?("foobug")).to be false
324
+
325
+ after(:all) do
326
+ MigrationHelper.rollback("#{Rails.root}/db/migrate/activation")
327
+ end
328
+
329
+ before do
330
+ @mail = double('mail')
331
+ allow(::SorceryMailer).to receive(:activation_success_email).and_return(@mail)
332
+ end
333
+
334
+ it 'use deliver_later' do
335
+ sorcery_reload!(
336
+ %i[
337
+ user_activation
338
+ user_activation_mailer
339
+ activation_needed_email_method_name
340
+ email_delivery_method
341
+ ],
342
+ user_activation_mailer: SorceryMailer,
343
+ activation_needed_email_method_name: nil,
344
+ email_delivery_method: :deliver_later
345
+ )
346
+
347
+ expect(@mail).to receive(:deliver_later).once
348
+ user.activate!
349
+ end
350
+
351
+ describe 'email_delivery_method is default' do
352
+ it 'use deliver_now if rails version 4.2+' do
353
+ allow(Rails).to receive(:version).and_return('4.2.0')
354
+ sorcery_reload!(
355
+ %i[
356
+ user_activation
357
+ user_activation_mailer
358
+ activation_needed_email_method_name
359
+ ],
360
+ user_activation_mailer: SorceryMailer,
361
+ activation_needed_email_method_name: nil
362
+ )
363
+
364
+ expect(@mail).to receive(:deliver_now).once
365
+ user.activate!
366
+ end
367
+
368
+ it 'use deliver if rails version < 4.2' do
369
+ allow(Rails).to receive(:version).and_return('4.1.0')
370
+ sorcery_reload!(
371
+ %i[
372
+ user_activation
373
+ user_activation_mailer
374
+ activation_needed_email_method_name
375
+ ],
376
+ user_activation_mailer: SorceryMailer,
377
+ activation_needed_email_method_name: nil
378
+ )
379
+
380
+ expect(@mail).to receive(:deliver).once
381
+ user.activate!
382
+ end
245
383
  end
246
384
  end
247
385
 
248
- describe "special encryption cases" do
386
+ describe 'special encryption cases' do
249
387
  before(:all) do
250
- sorcery_reload!()
251
- @text = "Some Text!"
388
+ sorcery_reload!
389
+ @text = 'Some Text!'
252
390
  end
253
391
 
254
392
  before(:each) do
@@ -259,20 +397,20 @@ shared_examples_for "rails_3_core_model" do
259
397
  User.sorcery_config.reset!
260
398
  end
261
399
 
262
- it "works with no password encryption" do
400
+ it 'works with no password encryption' do
263
401
  sorcery_model_property_set(:encryption_algorithm, :none)
264
402
  username = user.send(User.sorcery_config.username_attribute_names.first)
265
403
 
266
- expect(User.authenticate username, 'secret').to be_truthy
404
+ expect(User.authenticate(username, 'secret')).to be_truthy
267
405
  end
268
406
 
269
- it "works with custom password encryption" do
407
+ it 'works with custom password encryption' do
270
408
  class MyCrypto
271
409
  def self.encrypt(*tokens)
272
- tokens.flatten.join('').gsub(/e/,'A')
410
+ tokens.flatten.join('').tr('e', 'A')
273
411
  end
274
412
 
275
- def self.matches?(crypted,*tokens)
413
+ def self.matches?(crypted, *tokens)
276
414
  crypted == encrypt(*tokens)
277
415
  end
278
416
  end
@@ -281,87 +419,143 @@ shared_examples_for "rails_3_core_model" do
281
419
 
282
420
  username = user.send(User.sorcery_config.username_attribute_names.first)
283
421
 
284
- expect(User.authenticate username, 'secret').to be_truthy
422
+ expect(User.authenticate(username, 'secret')).to be_truthy
285
423
  end
286
424
 
287
- it "if encryption algo is aes256, it sets key to crypto provider" do
425
+ it 'if encryption algo is aes256, it sets key to crypto provider' do
288
426
  sorcery_model_property_set(:encryption_algorithm, :aes256)
289
427
  sorcery_model_property_set(:encryption_key, nil)
290
428
 
291
429
  expect { User.encrypt @text }.to raise_error(ArgumentError)
292
430
 
293
- sorcery_model_property_set(:encryption_key, "asd234dfs423fddsmndsflktsdf32343")
431
+ sorcery_model_property_set(:encryption_key, 'asd234dfs423fddsmndsflktsdf32343')
294
432
 
295
433
  expect { User.encrypt @text }.not_to raise_error
296
434
  end
297
435
 
298
- it "if encryption algo is aes256, it sets key to crypto provider, even if attributes are set in reverse" do
436
+ it 'if encryption algo is aes256, it sets key to crypto provider, even if attributes are set in reverse' do
299
437
  sorcery_model_property_set(:encryption_key, nil)
300
438
  sorcery_model_property_set(:encryption_algorithm, :none)
301
- sorcery_model_property_set(:encryption_key, "asd234dfs423fddsmndsflktsdf32343")
439
+ sorcery_model_property_set(:encryption_key, 'asd234dfs423fddsmndsflktsdf32343')
302
440
  sorcery_model_property_set(:encryption_algorithm, :aes256)
303
441
 
304
442
  expect { User.encrypt @text }.not_to raise_error
305
443
  end
306
444
 
307
- it "if encryption algo is md5 it works" do
445
+ it 'if encryption algo is md5 it works' do
308
446
  sorcery_model_property_set(:encryption_algorithm, :md5)
309
447
 
310
- expect(User.encrypt @text).to eq Sorcery::CryptoProviders::MD5.encrypt(@text)
448
+ expect(User.encrypt(@text)).to eq Sorcery::CryptoProviders::MD5.encrypt(@text)
311
449
  end
312
450
 
313
- it "if encryption algo is sha1 it works" do
451
+ it 'if encryption algo is sha1 it works' do
314
452
  sorcery_model_property_set(:encryption_algorithm, :sha1)
315
453
 
316
- expect(User.encrypt @text).to eq Sorcery::CryptoProviders::SHA1.encrypt(@text)
454
+ expect(User.encrypt(@text)).to eq Sorcery::CryptoProviders::SHA1.encrypt(@text)
317
455
  end
318
456
 
319
- it "if encryption algo is sha256 it works" do
457
+ it 'if encryption algo is sha256 it works' do
320
458
  sorcery_model_property_set(:encryption_algorithm, :sha256)
321
459
 
322
- expect(User.encrypt @text).to eq Sorcery::CryptoProviders::SHA256.encrypt(@text)
460
+ expect(User.encrypt(@text)).to eq Sorcery::CryptoProviders::SHA256.encrypt(@text)
323
461
  end
324
462
 
325
- it "if encryption algo is sha512 it works" do
463
+ it 'if encryption algo is sha512 it works' do
326
464
  sorcery_model_property_set(:encryption_algorithm, :sha512)
327
465
 
328
- expect(User.encrypt @text).to eq Sorcery::CryptoProviders::SHA512.encrypt(@text)
466
+ expect(User.encrypt(@text)).to eq Sorcery::CryptoProviders::SHA512.encrypt(@text)
329
467
  end
330
468
 
331
- it "salt is random for each user and saved in db" do
469
+ it 'if encryption algo is bcrypt it works' do
470
+ sorcery_model_property_set(:encryption_algorithm, :bcrypt)
471
+
472
+ # comparison is done using BCrypt::Password#==(raw_token), not by String#==
473
+ expect(User.encrypt(@text)).to be_an_instance_of BCrypt::Password
474
+ expect(User.encrypt(@text)).to eq @text
475
+ end
476
+
477
+ it 'salt is random for each user and saved in db' do
332
478
  sorcery_model_property_set(:salt_attribute_name, :salt)
333
479
 
334
480
  expect(user.salt).not_to be_nil
335
481
  end
336
482
 
337
- it "if salt is set uses it to encrypt" do
483
+ it 'if salt is set uses it to encrypt' do
338
484
  sorcery_model_property_set(:salt_attribute_name, :salt)
339
485
  sorcery_model_property_set(:encryption_algorithm, :sha512)
340
486
 
341
487
  expect(user.crypted_password).not_to eq Sorcery::CryptoProviders::SHA512.encrypt('secret')
342
- expect(user.crypted_password).to eq Sorcery::CryptoProviders::SHA512.encrypt('secret',user.salt)
488
+ expect(user.crypted_password).to eq Sorcery::CryptoProviders::SHA512.encrypt('secret', user.salt)
343
489
  end
344
490
 
345
- it "if salt_join_token is set uses it to encrypt" do
491
+ it 'if salt_join_token is set uses it to encrypt' do
346
492
  sorcery_model_property_set(:salt_attribute_name, :salt)
347
- sorcery_model_property_set(:salt_join_token, "-@=>")
493
+ sorcery_model_property_set(:salt_join_token, '-@=>')
348
494
  sorcery_model_property_set(:encryption_algorithm, :sha512)
349
495
 
350
496
  expect(user.crypted_password).not_to eq Sorcery::CryptoProviders::SHA512.encrypt('secret')
351
497
 
352
- Sorcery::CryptoProviders::SHA512.join_token = ""
498
+ Sorcery::CryptoProviders::SHA512.join_token = ''
353
499
 
354
- expect(user.crypted_password).not_to eq Sorcery::CryptoProviders::SHA512.encrypt('secret',user.salt)
500
+ expect(user.crypted_password).not_to eq Sorcery::CryptoProviders::SHA512.encrypt('secret', user.salt)
355
501
 
356
502
  Sorcery::CryptoProviders::SHA512.join_token = User.sorcery_config.salt_join_token
357
503
 
358
- expect(user.crypted_password).to eq Sorcery::CryptoProviders::SHA512.encrypt('secret',user.salt)
504
+ expect(user.crypted_password).to eq Sorcery::CryptoProviders::SHA512.encrypt('secret', user.salt)
505
+ end
506
+
507
+ it 'if pepper is set uses it to encrypt' do
508
+ sorcery_model_property_set(:salt_attribute_name, :salt)
509
+ sorcery_model_property_set(:pepper, '++@^$')
510
+ sorcery_model_property_set(:encryption_algorithm, :bcrypt)
511
+
512
+ # password comparison is done using BCrypt::Password#==(raw_token), not String#==
513
+ bcrypt_password = BCrypt::Password.new(user.crypted_password)
514
+ allow(::BCrypt::Password).to receive(:create) do |token, options = {}|
515
+ # need to use common BCrypt's salt when genarating BCrypt::Password objects
516
+ # so that any generated password hashes can be compared each other
517
+ ::BCrypt::Engine.hash_secret(token, bcrypt_password.salt)
518
+ end
519
+
520
+ expect(user.crypted_password).not_to eq Sorcery::CryptoProviders::BCrypt.encrypt('secret')
521
+
522
+ Sorcery::CryptoProviders::BCrypt.pepper = ''
523
+
524
+ expect(user.crypted_password).not_to eq Sorcery::CryptoProviders::BCrypt.encrypt('secret', user.salt)
525
+
526
+ Sorcery::CryptoProviders::BCrypt.pepper = User.sorcery_config.pepper
527
+
528
+ expect(user.crypted_password).to eq Sorcery::CryptoProviders::BCrypt.encrypt('secret', user.salt)
529
+ end
530
+
531
+ it 'if pepper is empty string (default) does not use pepper to encrypt' do
532
+ sorcery_model_property_set(:salt_attribute_name, :salt)
533
+ sorcery_model_property_set(:pepper, '')
534
+ sorcery_model_property_set(:encryption_algorithm, :bcrypt)
535
+
536
+ # password comparison is done using BCrypt::Password#==(raw_token), not String#==
537
+ bcrypt_password = BCrypt::Password.new(user.crypted_password)
538
+ allow(::BCrypt::Password).to receive(:create) do |token, options = {}|
539
+ # need to use common BCrypt's salt when genarating BCrypt::Password objects
540
+ # so that any generated password hashes can be compared each other
541
+ ::BCrypt::Engine.hash_secret(token, bcrypt_password.salt)
542
+ end
543
+
544
+ expect(user.crypted_password).not_to eq Sorcery::CryptoProviders::BCrypt.encrypt('secret')
545
+
546
+ Sorcery::CryptoProviders::BCrypt.pepper = 'some_pepper'
547
+
548
+ expect(user.crypted_password).not_to eq Sorcery::CryptoProviders::BCrypt.encrypt('secret', user.salt)
549
+
550
+ Sorcery::CryptoProviders::BCrypt.pepper = User.sorcery_config.pepper
551
+
552
+ expect(user.crypted_password).to eq Sorcery::CryptoProviders::BCrypt.encrypt('secret', user.salt)
359
553
  end
360
554
  end
361
555
 
362
- describe "ORM adapter" do
556
+ describe 'ORM adapter' do
363
557
  before(:all) do
364
- sorcery_reload!()
558
+ sorcery_reload!
365
559
  User.sorcery_adapter.delete_all
366
560
  end
367
561
 
@@ -372,29 +566,43 @@ shared_examples_for "rails_3_core_model" do
372
566
  User.sorcery_config.reset!
373
567
  end
374
568
 
375
-
376
- it "find_by_username works as expected" do
569
+ it 'find_by_username works as expected' do
377
570
  sorcery_model_property_set(:username_attribute_names, [:username])
378
571
 
379
- expect(User.sorcery_adapter.find_by_username "gizmo").to eq user
572
+ expect(User.sorcery_adapter.find_by_username('gizmo')).to eq user
380
573
  end
381
574
 
382
- it "find_by_username works as expected with multiple username attributes" do
383
- sorcery_model_property_set(:username_attribute_names, [:username, :email])
575
+ it 'find_by_username works as expected with multiple username attributes' do
576
+ sorcery_model_property_set(:username_attribute_names, %i[username email])
384
577
 
385
- expect(User.sorcery_adapter.find_by_username "gizmo").to eq user
578
+ expect(User.sorcery_adapter.find_by_username('gizmo')).to eq user
386
579
  end
387
580
 
388
- it "find_by_email works as expected" do
389
- expect(User.sorcery_adapter.find_by_email "bla@bla.com").to eq user
581
+ it 'find_by_email works as expected' do
582
+ expect(User.sorcery_adapter.find_by_email('bla@bla.com')).to eq user
390
583
  end
391
584
  end
392
585
  end
393
586
 
394
- shared_examples_for "external_user" do
587
+ shared_examples_for 'external_user' do
395
588
  let(:user) { create_new_user }
396
589
  let(:external_user) { create_new_external_user :twitter }
397
590
 
591
+ before(:all) do
592
+ if SORCERY_ORM == :active_record
593
+ MigrationHelper.migrate("#{Rails.root}/db/migrate/external")
594
+ MigrationHelper.migrate("#{Rails.root}/db/migrate/activation")
595
+ end
596
+ sorcery_reload!
597
+ end
598
+
599
+ after(:all) do
600
+ if SORCERY_ORM == :active_record
601
+ MigrationHelper.rollback("#{Rails.root}/db/migrate/external")
602
+ MigrationHelper.rollback("#{Rails.root}/db/migrate/activation")
603
+ end
604
+ end
605
+
398
606
  before(:each) do
399
607
  User.sorcery_adapter.delete_all
400
608
  end
@@ -403,85 +611,61 @@ shared_examples_for "external_user" do
403
611
  expect(user).to respond_to(:external?)
404
612
  end
405
613
 
406
- it "external? is false for regular users" do
614
+ it 'external? is false for regular users' do
407
615
  expect(user.external?).to be false
408
616
  end
409
617
 
410
- it "external? is true for external users" do
618
+ it 'external? is true for external users' do
411
619
  expect(external_user.external?).to be true
412
620
  end
413
621
 
414
- describe ".create_from_provider" do
415
-
416
- before(:all) do
417
- if SORCERY_ORM == :active_record
418
- ActiveRecord::Migrator.migrate("#{Rails.root}/db/migrate/external")
419
- User.reset_column_information
420
- end
421
-
622
+ describe '.create_from_provider' do
623
+ before(:each) do
422
624
  sorcery_reload!([:external])
423
- end
424
-
425
- after(:all) do
426
- if SORCERY_ORM == :active_record
427
- ActiveRecord::Migrator.rollback("#{Rails.root}/db/migrate/external")
428
- end
625
+ sorcery_model_property_set(:authentications_class, Authentication)
429
626
  end
430
627
 
431
628
  it 'supports nested attributes' do
432
- sorcery_model_property_set(:authentications_class, Authentication)
629
+ expect do
630
+ User.create_from_provider('facebook', '123', username: 'Noam Ben Ari')
631
+ end.to change { User.count }.by(1)
433
632
 
434
- expect { User.create_from_provider('facebook', '123', {username: 'Noam Ben Ari'}) }.to change { User.count }.by(1)
435
633
  expect(User.first.username).to eq 'Noam Ben Ari'
436
634
  end
437
635
 
438
636
  context 'with block' do
439
637
  it 'create user when block return true' do
440
- expect {
441
- User.create_from_provider('facebook', '123', {username: 'Noam Ben Ari'}) { true }
442
- }.to change { User.count }.by(1)
638
+ expect do
639
+ User.create_from_provider('facebook', '123', username: 'Noam Ben Ari') { true }
640
+ end.to change { User.count }.by(1)
443
641
  end
444
642
 
445
643
  it 'does not create user when block return false' do
446
- expect {
447
- User.create_from_provider('facebook', '123', {username: 'Noam Ben Ari'}) { false }
448
- }.not_to change { User.count }
644
+ expect do
645
+ User.create_from_provider('facebook', '123', username: 'Noam Ben Ari') { false }
646
+ end.not_to(change { User.count })
449
647
  end
450
648
  end
451
-
452
649
  end
453
650
 
454
651
  describe 'activation' do
455
- before(:all) do
456
- if SORCERY_ORM == :active_record
457
- ActiveRecord::Migrator.migrate("#{Rails.root}/db/migrate/external")
458
- ActiveRecord::Migrator.migrate("#{Rails.root}/db/migrate/activation")
459
- end
460
-
461
- sorcery_reload!([:user_activation,:external], :user_activation_mailer => ::SorceryMailer)
462
- end
463
-
464
- after(:all) do
465
- if SORCERY_ORM == :active_record
466
- ActiveRecord::Migrator.rollback("#{Rails.root}/db/migrate/activation")
467
- ActiveRecord::Migrator.rollback("#{Rails.root}/db/migrate/external")
468
- end
652
+ before(:each) do
653
+ sorcery_reload!(%i[user_activation external], user_activation_mailer: ::SorceryMailer)
469
654
  end
470
655
 
471
656
  after(:each) do
472
657
  User.sorcery_adapter.delete_all
473
658
  end
474
659
 
475
- [:facebook, :github, :google, :liveid].each do |provider|
476
-
477
- it "does not send activation email to external users" do
660
+ %i[facebook github google liveid slack].each do |provider|
661
+ it 'does not send activation email to external users' do
478
662
  old_size = ActionMailer::Base.deliveries.size
479
663
  create_new_external_user(provider)
480
664
 
481
665
  expect(ActionMailer::Base.deliveries.size).to eq old_size
482
666
  end
483
667
 
484
- it "does not send external users an activation success email" do
668
+ it 'does not send external users an activation success email' do
485
669
  sorcery_model_property_set(:activation_success_email_method_name, nil)
486
670
  create_new_external_user(provider)
487
671
  old_size = ActionMailer::Base.deliveries.size
@@ -490,6 +674,5 @@ shared_examples_for "external_user" do
490
674
  expect(ActionMailer::Base.deliveries.size).to eq old_size
491
675
  end
492
676
  end
493
-
494
677
  end
495
678
  end