user_spec.rb 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554
  1. # frozen_string_literal: true
  2. require 'rails_helper'
  3. require 'devise_two_factor/spec_helpers'
  4. RSpec.describe User do
  5. let(:password) { 'abcd1234' }
  6. let(:account) { Fabricate(:account, username: 'alice') }
  7. it_behaves_like 'two_factor_backupable'
  8. describe 'otp_secret' do
  9. it 'is encrypted with OTP_SECRET environment variable' do
  10. user = Fabricate(:user,
  11. encrypted_otp_secret: "Fttsy7QAa0edaDfdfSz094rRLAxc8cJweDQ4BsWH/zozcdVA8o9GLqcKhn2b\nGi/V\n",
  12. encrypted_otp_secret_iv: 'rys3THICkr60BoWC',
  13. encrypted_otp_secret_salt: '_LMkAGvdg7a+sDIKjI3mR2Q==')
  14. expect(user.otp_secret).to eq 'anotpsecretthatshouldbeencrypted'
  15. end
  16. end
  17. describe 'validations' do
  18. it 'is invalid without an account' do
  19. user = Fabricate.build(:user, account: nil)
  20. user.valid?
  21. expect(user).to model_have_error_on_field(:account)
  22. end
  23. it 'is invalid without a valid locale' do
  24. user = Fabricate.build(:user, locale: 'toto')
  25. user.valid?
  26. expect(user).to model_have_error_on_field(:locale)
  27. end
  28. it 'is invalid without a valid email' do
  29. user = Fabricate.build(:user, email: 'john@')
  30. user.valid?
  31. expect(user).to model_have_error_on_field(:email)
  32. end
  33. it 'is valid with an invalid e-mail that has already been saved' do
  34. user = Fabricate.build(:user, email: 'invalid-email')
  35. user.save(validate: false)
  36. expect(user.valid?).to be true
  37. end
  38. it 'cleans out empty string from languages' do
  39. user = Fabricate.build(:user, chosen_languages: [''])
  40. user.valid?
  41. expect(user.chosen_languages).to be_nil
  42. end
  43. end
  44. describe 'scopes' do
  45. describe 'recent' do
  46. it 'returns an array of recent users ordered by id' do
  47. user_1 = Fabricate(:user)
  48. user_2 = Fabricate(:user)
  49. expect(described_class.recent).to eq [user_2, user_1]
  50. end
  51. end
  52. describe 'confirmed' do
  53. it 'returns an array of users who are confirmed' do
  54. user_1 = Fabricate(:user, confirmed_at: nil)
  55. user_2 = Fabricate(:user, confirmed_at: Time.zone.now)
  56. expect(described_class.confirmed).to contain_exactly(user_2)
  57. end
  58. end
  59. describe 'inactive' do
  60. it 'returns a relation of inactive users' do
  61. specified = Fabricate(:user, current_sign_in_at: 15.days.ago)
  62. Fabricate(:user, current_sign_in_at: 6.days.ago)
  63. expect(described_class.inactive).to contain_exactly(specified)
  64. end
  65. end
  66. describe 'matches_email' do
  67. it 'returns a relation of users whose email starts with the given string' do
  68. specified = Fabricate(:user, email: 'specified@spec')
  69. Fabricate(:user, email: 'unspecified@spec')
  70. expect(described_class.matches_email('specified')).to contain_exactly(specified)
  71. end
  72. end
  73. describe 'matches_ip' do
  74. it 'returns a relation of users whose ip address is matching with the given CIDR' do
  75. user1 = Fabricate(:user)
  76. user2 = Fabricate(:user)
  77. Fabricate(:session_activation, user: user1, ip: '2160:2160::22', session_id: '1')
  78. Fabricate(:session_activation, user: user1, ip: '2160:2160::23', session_id: '2')
  79. Fabricate(:session_activation, user: user2, ip: '2160:8888::24', session_id: '3')
  80. Fabricate(:session_activation, user: user2, ip: '2160:8888::25', session_id: '4')
  81. expect(described_class.matches_ip('2160:2160::/32')).to contain_exactly(user1)
  82. end
  83. end
  84. end
  85. describe 'blacklist' do
  86. around(:each) do |example|
  87. old_blacklist = Rails.configuration.x.email_blacklist
  88. Rails.configuration.x.email_domains_blacklist = 'mvrht.com'
  89. example.run
  90. Rails.configuration.x.email_domains_blacklist = old_blacklist
  91. end
  92. it 'allows a non-blacklisted user to be created' do
  93. user = described_class.new(email: 'foo@example.com', account: account, password: password, agreement: true)
  94. expect(user).to be_valid
  95. end
  96. it 'does not allow a blacklisted user to be created' do
  97. user = described_class.new(email: 'foo@mvrht.com', account: account, password: password, agreement: true)
  98. expect(user).to_not be_valid
  99. end
  100. it 'does not allow a subdomain blacklisted user to be created' do
  101. user = described_class.new(email: 'foo@mvrht.com.topdomain.tld', account: account, password: password, agreement: true)
  102. expect(user).to_not be_valid
  103. end
  104. end
  105. describe '#confirmed?' do
  106. it 'returns true when a confirmed_at is set' do
  107. user = Fabricate.build(:user, confirmed_at: Time.now.utc)
  108. expect(user.confirmed?).to be true
  109. end
  110. it 'returns false if a confirmed_at is nil' do
  111. user = Fabricate.build(:user, confirmed_at: nil)
  112. expect(user.confirmed?).to be false
  113. end
  114. end
  115. describe '#confirm' do
  116. subject { user.confirm }
  117. let(:new_email) { 'new-email@example.com' }
  118. before do
  119. allow(TriggerWebhookWorker).to receive(:perform_async)
  120. end
  121. context 'when the user is already confirmed' do
  122. let!(:user) { Fabricate(:user, confirmed_at: Time.now.utc, approved: true, unconfirmed_email: new_email) }
  123. it 'sets email to unconfirmed_email' do
  124. expect { subject }.to change { user.reload.email }.to(new_email)
  125. end
  126. it 'does not trigger the account.approved Web Hook' do
  127. subject
  128. expect(TriggerWebhookWorker).to_not have_received(:perform_async).with('account.approved', 'Account', user.account_id)
  129. end
  130. end
  131. context 'when the user is a new user' do
  132. let(:user) { Fabricate(:user, confirmed_at: nil, unconfirmed_email: new_email) }
  133. context 'when the user is already approved' do
  134. around(:example) do |example|
  135. registrations_mode = Setting.registrations_mode
  136. Setting.registrations_mode = 'approved'
  137. example.run
  138. Setting.registrations_mode = registrations_mode
  139. end
  140. before do
  141. user.approve!
  142. end
  143. it 'sets email to unconfirmed_email' do
  144. expect { subject }.to change { user.reload.email }.to(new_email)
  145. end
  146. it 'triggers the account.approved Web Hook' do
  147. user.confirm
  148. expect(TriggerWebhookWorker).to have_received(:perform_async).with('account.approved', 'Account', user.account_id).once
  149. end
  150. end
  151. context 'when the user does not require explicit approval' do
  152. around(:example) do |example|
  153. registrations_mode = Setting.registrations_mode
  154. Setting.registrations_mode = 'open'
  155. example.run
  156. Setting.registrations_mode = registrations_mode
  157. end
  158. it 'sets email to unconfirmed_email' do
  159. expect { subject }.to change { user.reload.email }.to(new_email)
  160. end
  161. it 'triggers the account.approved Web Hook' do
  162. user.confirm
  163. expect(TriggerWebhookWorker).to have_received(:perform_async).with('account.approved', 'Account', user.account_id).once
  164. end
  165. end
  166. context 'when the user requires explicit approval but is not approved' do
  167. around(:example) do |example|
  168. registrations_mode = Setting.registrations_mode
  169. Setting.registrations_mode = 'approved'
  170. example.run
  171. Setting.registrations_mode = registrations_mode
  172. end
  173. it 'sets email to unconfirmed_email' do
  174. expect { subject }.to change { user.reload.email }.to(new_email)
  175. end
  176. it 'does not trigger the account.approved Web Hook' do
  177. subject
  178. expect(TriggerWebhookWorker).to_not have_received(:perform_async).with('account.approved', 'Account', user.account_id)
  179. end
  180. end
  181. end
  182. end
  183. describe '#approve!' do
  184. subject { user.approve! }
  185. around(:example) do |example|
  186. registrations_mode = Setting.registrations_mode
  187. Setting.registrations_mode = 'approved'
  188. example.run
  189. Setting.registrations_mode = registrations_mode
  190. end
  191. before do
  192. allow(TriggerWebhookWorker).to receive(:perform_async)
  193. end
  194. context 'when the user is already confirmed' do
  195. let(:user) { Fabricate(:user, confirmed_at: Time.now.utc, approved: false) }
  196. it 'sets the approved flag' do
  197. expect { subject }.to change { user.reload.approved? }.to(true)
  198. end
  199. it 'triggers the account.approved Web Hook' do
  200. subject
  201. expect(TriggerWebhookWorker).to have_received(:perform_async).with('account.approved', 'Account', user.account_id).once
  202. end
  203. end
  204. context 'when the user is not confirmed' do
  205. let(:user) { Fabricate(:user, confirmed_at: nil, approved: false) }
  206. it 'sets the approved flag' do
  207. expect { subject }.to change { user.reload.approved? }.to(true)
  208. end
  209. it 'does not trigger the account.approved Web Hook' do
  210. subject
  211. expect(TriggerWebhookWorker).to_not have_received(:perform_async).with('account.approved', 'Account', user.account_id)
  212. end
  213. end
  214. end
  215. describe '#disable_two_factor!' do
  216. it 'saves false for otp_required_for_login' do
  217. user = Fabricate.build(:user, otp_required_for_login: true)
  218. user.disable_two_factor!
  219. expect(user.reload.otp_required_for_login).to be false
  220. end
  221. it 'saves nil for otp_secret' do
  222. user = Fabricate.build(:user, otp_secret: 'oldotpcode')
  223. user.disable_two_factor!
  224. expect(user.reload.otp_secret).to be_nil
  225. end
  226. it 'saves cleared otp_backup_codes' do
  227. user = Fabricate.build(:user, otp_backup_codes: %w(dummy dummy))
  228. user.disable_two_factor!
  229. expect(user.reload.otp_backup_codes.empty?).to be true
  230. end
  231. end
  232. describe '#send_confirmation_instructions' do
  233. around do |example|
  234. queue_adapter = ActiveJob::Base.queue_adapter
  235. example.run
  236. ActiveJob::Base.queue_adapter = queue_adapter
  237. end
  238. it 'delivers confirmation instructions later' do
  239. user = Fabricate(:user)
  240. ActiveJob::Base.queue_adapter = :test
  241. expect { user.send_confirmation_instructions }.to have_enqueued_job(ActionMailer::MailDeliveryJob)
  242. end
  243. end
  244. describe 'settings' do
  245. it 'is instance of UserSettings' do
  246. user = Fabricate(:user)
  247. expect(user.settings).to be_a UserSettings
  248. end
  249. end
  250. describe '#setting_default_privacy' do
  251. it 'returns default privacy setting if user has configured' do
  252. user = Fabricate(:user)
  253. user.settings[:default_privacy] = 'unlisted'
  254. expect(user.setting_default_privacy).to eq 'unlisted'
  255. end
  256. it "returns 'private' if user has not configured default privacy setting and account is locked" do
  257. user = Fabricate(:account, locked: true).user
  258. expect(user.setting_default_privacy).to eq 'private'
  259. end
  260. it "returns 'public' if user has not configured default privacy setting and account is not locked" do
  261. user = Fabricate(:account, locked: false).user
  262. expect(user.setting_default_privacy).to eq 'public'
  263. end
  264. end
  265. describe 'whitelist' do
  266. around(:each) do |example|
  267. old_whitelist = Rails.configuration.x.email_domains_whitelist
  268. Rails.configuration.x.email_domains_whitelist = 'mastodon.space'
  269. example.run
  270. Rails.configuration.x.email_domains_whitelist = old_whitelist
  271. end
  272. it 'does not allow a user to be created unless they are whitelisted' do
  273. user = described_class.new(email: 'foo@example.com', account: account, password: password, agreement: true)
  274. expect(user).to_not be_valid
  275. end
  276. it 'allows a user to be created if they are whitelisted' do
  277. user = described_class.new(email: 'foo@mastodon.space', account: account, password: password, agreement: true)
  278. expect(user).to be_valid
  279. end
  280. it 'does not allow a user with a whitelisted top domain as subdomain in their email address to be created' do
  281. user = described_class.new(email: 'foo@mastodon.space.userdomain.com', account: account, password: password, agreement: true)
  282. expect(user).to_not be_valid
  283. end
  284. context 'with a blacklisted subdomain' do
  285. around do |example|
  286. old_blacklist = Rails.configuration.x.email_blacklist
  287. example.run
  288. Rails.configuration.x.email_domains_blacklist = old_blacklist
  289. end
  290. it 'does not allow a user to be created with a specific blacklisted subdomain even if the top domain is whitelisted' do
  291. Rails.configuration.x.email_domains_blacklist = 'blacklisted.mastodon.space'
  292. user = described_class.new(email: 'foo@blacklisted.mastodon.space', account: account, password: password)
  293. expect(user).to_not be_valid
  294. end
  295. end
  296. end
  297. describe 'token_for_app' do
  298. let(:user) { Fabricate(:user) }
  299. let(:app) { Fabricate(:application, owner: user) }
  300. it 'returns a token' do
  301. expect(user.token_for_app(app)).to be_a(Doorkeeper::AccessToken)
  302. end
  303. it 'persists a token' do
  304. t = user.token_for_app(app)
  305. expect(user.token_for_app(app)).to eql(t)
  306. end
  307. it 'is nil if user does not own app' do
  308. app.update!(owner: nil)
  309. expect(user.token_for_app(app)).to be_nil
  310. end
  311. end
  312. describe '#disable!' do
  313. subject(:user) { Fabricate(:user, disabled: false, current_sign_in_at: current_sign_in_at, last_sign_in_at: nil) }
  314. let(:current_sign_in_at) { Time.zone.now }
  315. before do
  316. user.disable!
  317. end
  318. it 'disables user' do
  319. expect(user).to have_attributes(disabled: true)
  320. end
  321. end
  322. describe '#enable!' do
  323. subject(:user) { Fabricate(:user, disabled: true) }
  324. before do
  325. user.enable!
  326. end
  327. it 'enables user' do
  328. expect(user).to have_attributes(disabled: false)
  329. end
  330. end
  331. describe '#reset_password!' do
  332. subject(:user) { Fabricate(:user, password: 'foobar12345') }
  333. let!(:session_activation) { Fabricate(:session_activation, user: user) }
  334. let!(:access_token) { Fabricate(:access_token, resource_owner_id: user.id) }
  335. let!(:web_push_subscription) { Fabricate(:web_push_subscription, access_token: access_token) }
  336. before do
  337. user.reset_password!
  338. end
  339. it 'changes the password immediately' do
  340. expect(user.external_or_valid_password?('foobar12345')).to be false
  341. end
  342. it 'deactivates all sessions' do
  343. expect(user.session_activations.count).to eq 0
  344. end
  345. it 'revokes all access tokens' do
  346. expect(Doorkeeper::AccessToken.active_for(user).count).to eq 0
  347. end
  348. it 'removes push subscriptions' do
  349. expect(Web::PushSubscription.where(user: user).or(Web::PushSubscription.where(access_token: access_token)).count).to eq 0
  350. end
  351. end
  352. describe '#confirm!' do
  353. subject(:user) { Fabricate(:user, confirmed_at: confirmed_at) }
  354. before do
  355. ActionMailer::Base.deliveries.clear
  356. user.confirm!
  357. end
  358. after { ActionMailer::Base.deliveries.clear }
  359. context 'when user is new' do
  360. let(:confirmed_at) { nil }
  361. it 'confirms user' do
  362. expect(user.confirmed_at).to be_present
  363. end
  364. it 'delivers mails' do
  365. expect(ActionMailer::Base.deliveries.count).to eq 2
  366. end
  367. end
  368. context 'when user is not new' do
  369. let(:confirmed_at) { Time.zone.now }
  370. it 'confirms user' do
  371. expect(user.confirmed_at).to be_present
  372. end
  373. it 'does not deliver mail' do
  374. expect(ActionMailer::Base.deliveries.count).to eq 0
  375. end
  376. end
  377. end
  378. describe '#active_for_authentication?' do
  379. subject { user.active_for_authentication? }
  380. let(:user) { Fabricate(:user, disabled: disabled, confirmed_at: confirmed_at) }
  381. context 'when user is disabled' do
  382. let(:disabled) { true }
  383. context 'when user is confirmed' do
  384. let(:confirmed_at) { Time.zone.now }
  385. it { is_expected.to be true }
  386. end
  387. context 'when user is not confirmed' do
  388. let(:confirmed_at) { nil }
  389. it { is_expected.to be true }
  390. end
  391. end
  392. context 'when user is not disabled' do
  393. let(:disabled) { false }
  394. context 'when user is confirmed' do
  395. let(:confirmed_at) { Time.zone.now }
  396. it { is_expected.to be true }
  397. end
  398. context 'when user is not confirmed' do
  399. let(:confirmed_at) { nil }
  400. it { is_expected.to be true }
  401. end
  402. end
  403. end
  404. describe '.those_who_can' do
  405. before { Fabricate(:user, role: UserRole.find_by(name: 'Moderator')) }
  406. context 'when there are not any user roles' do
  407. before { UserRole.destroy_all }
  408. it 'returns an empty list' do
  409. expect(described_class.those_who_can(:manage_blocks)).to eq([])
  410. end
  411. end
  412. context 'when there are not users with the needed role' do
  413. it 'returns an empty list' do
  414. expect(described_class.those_who_can(:manage_blocks)).to eq([])
  415. end
  416. end
  417. context 'when there are users with roles' do
  418. let!(:admin_user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
  419. it 'returns the users with the role' do
  420. expect(described_class.those_who_can(:manage_blocks)).to eq([admin_user])
  421. end
  422. end
  423. end
  424. end