Merge commit '5e1ec8b18a48b36b0fc66f04292df9c519b21883' into glitch-soc/stable-4.6
This commit is contained in:
commit
3a5da4cb92
52 files changed
+439
-166
No files matched your search
@@ -2,6 +2,22 @@
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## [4.6.7] - 2026-09-01
|
||||
|
||||
## Security
|
||||
|
||||
- Update dependencies
|
||||
- Fix password authentication bypass in 2FA auth for LDAP/PAM/SSO accounts ([GHSA-vx32-x96w-qq65](https://github.com/mastodon/mastodon/security/advisories/GHSA-vx32-x96w-qq65))
|
||||
- Fix Denial of Service when processing pathological JSON-LD activities ([GHSA-vgm8-frgh-rh2v](https://github.com/mastodon/mastodon/security/advisories/GHSA-vgm8-frgh-rh2v))
|
||||
- Fix disabled staff accounts still having access to admin API ([GHSA-62j4-hvj7-px3f](https://github.com/mastodon/mastodon/security/advisories/GHSA-62j4-hvj7-px3f))
|
||||
|
||||
### Fixes
|
||||
|
||||
- Fix `config/` directory missing from Bootsnap precompilation options in Dockerfile (#40255 by @ClearlyClaire)
|
||||
- Fix autosuggestions overstaying their welcome in languages that don't use spaces (#40217 by @Gargron)
|
||||
- Fix error when processing remote actors with `null` public keys (#40194 by @ClearlyClaire)
|
||||
- Fix various off-by-one errors in statistics time ranges (#40193 by @ClearlyClaire)
|
||||
|
||||
## [4.6.6] - 2026-08-13
|
||||
|
||||
### Changed
|
||||
|
||||
+54
-54
@@ -12,29 +12,29 @@ GEM
|
||||
specs:
|
||||
action_text-trix (2.1.19)
|
||||
railties
|
||||
actioncable (8.1.3)
|
||||
actionpack (= 8.1.3)
|
||||
activesupport (= 8.1.3)
|
||||
actioncable (8.1.3.1)
|
||||
actionpack (= 8.1.3.1)
|
||||
activesupport (= 8.1.3.1)
|
||||
nio4r (~> 2.0)
|
||||
websocket-driver (>= 0.6.1)
|
||||
zeitwerk (~> 2.6)
|
||||
actionmailbox (8.1.3)
|
||||
actionpack (= 8.1.3)
|
||||
activejob (= 8.1.3)
|
||||
activerecord (= 8.1.3)
|
||||
activestorage (= 8.1.3)
|
||||
activesupport (= 8.1.3)
|
||||
actionmailbox (8.1.3.1)
|
||||
actionpack (= 8.1.3.1)
|
||||
activejob (= 8.1.3.1)
|
||||
activerecord (= 8.1.3.1)
|
||||
activestorage (= 8.1.3.1)
|
||||
activesupport (= 8.1.3.1)
|
||||
mail (>= 2.8.0)
|
||||
actionmailer (8.1.3)
|
||||
actionpack (= 8.1.3)
|
||||
actionview (= 8.1.3)
|
||||
activejob (= 8.1.3)
|
||||
activesupport (= 8.1.3)
|
||||
actionmailer (8.1.3.1)
|
||||
actionpack (= 8.1.3.1)
|
||||
actionview (= 8.1.3.1)
|
||||
activejob (= 8.1.3.1)
|
||||
activesupport (= 8.1.3.1)
|
||||
mail (>= 2.8.0)
|
||||
rails-dom-testing (~> 2.2)
|
||||
actionpack (8.1.3)
|
||||
actionview (= 8.1.3)
|
||||
activesupport (= 8.1.3)
|
||||
actionpack (8.1.3.1)
|
||||
actionview (= 8.1.3.1)
|
||||
activesupport (= 8.1.3.1)
|
||||
nokogiri (>= 1.8.5)
|
||||
rack (>= 2.2.4)
|
||||
rack-session (>= 1.0.1)
|
||||
@@ -42,16 +42,16 @@ GEM
|
||||
rails-dom-testing (~> 2.2)
|
||||
rails-html-sanitizer (~> 1.6)
|
||||
useragent (~> 0.16)
|
||||
actiontext (8.1.3)
|
||||
actiontext (8.1.3.1)
|
||||
action_text-trix (~> 2.1.15)
|
||||
actionpack (= 8.1.3)
|
||||
activerecord (= 8.1.3)
|
||||
activestorage (= 8.1.3)
|
||||
activesupport (= 8.1.3)
|
||||
actionpack (= 8.1.3.1)
|
||||
activerecord (= 8.1.3.1)
|
||||
activestorage (= 8.1.3.1)
|
||||
activesupport (= 8.1.3.1)
|
||||
globalid (>= 0.6.0)
|
||||
nokogiri (>= 1.8.5)
|
||||
actionview (8.1.3)
|
||||
activesupport (= 8.1.3)
|
||||
actionview (8.1.3.1)
|
||||
activesupport (= 8.1.3.1)
|
||||
builder (~> 3.1)
|
||||
erubi (~> 1.11)
|
||||
rails-dom-testing (~> 2.2)
|
||||
@@ -61,22 +61,22 @@ GEM
|
||||
activemodel (>= 4.1)
|
||||
case_transform (>= 0.2)
|
||||
jsonapi-renderer (>= 0.1.1.beta1, < 0.3)
|
||||
activejob (8.1.3)
|
||||
activesupport (= 8.1.3)
|
||||
activejob (8.1.3.1)
|
||||
activesupport (= 8.1.3.1)
|
||||
globalid (>= 0.3.6)
|
||||
activemodel (8.1.3)
|
||||
activesupport (= 8.1.3)
|
||||
activerecord (8.1.3)
|
||||
activemodel (= 8.1.3)
|
||||
activesupport (= 8.1.3)
|
||||
activemodel (8.1.3.1)
|
||||
activesupport (= 8.1.3.1)
|
||||
activerecord (8.1.3.1)
|
||||
activemodel (= 8.1.3.1)
|
||||
activesupport (= 8.1.3.1)
|
||||
timeout (>= 0.4.0)
|
||||
activestorage (8.1.3)
|
||||
actionpack (= 8.1.3)
|
||||
activejob (= 8.1.3)
|
||||
activerecord (= 8.1.3)
|
||||
activesupport (= 8.1.3)
|
||||
activestorage (8.1.3.1)
|
||||
actionpack (= 8.1.3.1)
|
||||
activejob (= 8.1.3.1)
|
||||
activerecord (= 8.1.3.1)
|
||||
activesupport (= 8.1.3.1)
|
||||
marcel (~> 1.0)
|
||||
activesupport (8.1.3)
|
||||
activesupport (8.1.3.1)
|
||||
base64
|
||||
bigdecimal
|
||||
concurrent-ruby (~> 1.0, >= 1.3.1)
|
||||
@@ -431,7 +431,7 @@ GEM
|
||||
loofah (2.25.2)
|
||||
crass (~> 1.0.2)
|
||||
nokogiri (>= 1.12.0)
|
||||
mail (2.9.0)
|
||||
mail (2.9.1)
|
||||
logger
|
||||
mini_mime (>= 0.1.1)
|
||||
net-imap
|
||||
@@ -654,20 +654,20 @@ GEM
|
||||
rack (>= 1.3)
|
||||
rackup (2.3.1)
|
||||
rack (>= 3)
|
||||
rails (8.1.3)
|
||||
actioncable (= 8.1.3)
|
||||
actionmailbox (= 8.1.3)
|
||||
actionmailer (= 8.1.3)
|
||||
actionpack (= 8.1.3)
|
||||
actiontext (= 8.1.3)
|
||||
actionview (= 8.1.3)
|
||||
activejob (= 8.1.3)
|
||||
activemodel (= 8.1.3)
|
||||
activerecord (= 8.1.3)
|
||||
activestorage (= 8.1.3)
|
||||
activesupport (= 8.1.3)
|
||||
rails (8.1.3.1)
|
||||
actioncable (= 8.1.3.1)
|
||||
actionmailbox (= 8.1.3.1)
|
||||
actionmailer (= 8.1.3.1)
|
||||
actionpack (= 8.1.3.1)
|
||||
actiontext (= 8.1.3.1)
|
||||
actionview (= 8.1.3.1)
|
||||
activejob (= 8.1.3.1)
|
||||
activemodel (= 8.1.3.1)
|
||||
activerecord (= 8.1.3.1)
|
||||
activestorage (= 8.1.3.1)
|
||||
activesupport (= 8.1.3.1)
|
||||
bundler (>= 1.15.0)
|
||||
railties (= 8.1.3)
|
||||
railties (= 8.1.3.1)
|
||||
rails-dom-testing (2.3.0)
|
||||
activesupport (>= 5.0.0)
|
||||
minitest
|
||||
@@ -678,9 +678,9 @@ GEM
|
||||
rails-i18n (8.1.0)
|
||||
i18n (>= 0.7, < 2)
|
||||
railties (>= 8.0.0, < 9)
|
||||
railties (8.1.3)
|
||||
actionpack (= 8.1.3)
|
||||
activesupport (= 8.1.3)
|
||||
railties (8.1.3.1)
|
||||
actionpack (= 8.1.3.1)
|
||||
activesupport (= 8.1.3.1)
|
||||
irb (~> 1.13)
|
||||
rackup (>= 1.0.0)
|
||||
rake (>= 12.2)
|
||||
|
||||
@@ -4,9 +4,11 @@ module Admin
|
||||
class BaseController < ApplicationController
|
||||
include Authorization
|
||||
include AccountableConcern
|
||||
include Admin::PermissionsConcern
|
||||
|
||||
layout 'admin'
|
||||
|
||||
before_action :require_moderator_or_admin_permissions
|
||||
before_action :set_referrer_policy_header
|
||||
|
||||
after_action :verify_authorized
|
||||
@@ -20,5 +22,10 @@ module Admin
|
||||
def set_user
|
||||
@user = Account.find(params[:account_id]).user || raise(ActiveRecord::RecordNotFound)
|
||||
end
|
||||
|
||||
def require_moderator_or_admin_permissions
|
||||
# not using #authorize here, so #verify_authorized still makes sure more fine-grained rules are enforced down the line
|
||||
forbidden unless Admin::BasePolicy.new(current_account, :base).access?
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
class Api::V1::Admin::AccountActionsController < Api::BaseController
|
||||
include Authorization
|
||||
include Admin::PermissionsConcern
|
||||
|
||||
before_action -> { authorize_if_got_token! :'admin:write', :'admin:write:accounts' }
|
||||
before_action :set_account
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
class Api::V1::Admin::AccountsController < Api::BaseController
|
||||
include Authorization
|
||||
include AccountableConcern
|
||||
include Admin::PermissionsConcern
|
||||
|
||||
LIMIT = 100
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
class Api::V1::Admin::CanonicalEmailBlocksController < Api::BaseController
|
||||
include Authorization
|
||||
include AccountableConcern
|
||||
include Admin::PermissionsConcern
|
||||
|
||||
LIMIT = 100
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
class Api::V1::Admin::DimensionsController < Api::BaseController
|
||||
include Authorization
|
||||
include Admin::PermissionsConcern
|
||||
|
||||
before_action -> { authorize_if_got_token! :'admin:read' }
|
||||
before_action :set_dimensions
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
class Api::V1::Admin::DomainAllowsController < Api::BaseController
|
||||
include Authorization
|
||||
include AccountableConcern
|
||||
include Admin::PermissionsConcern
|
||||
|
||||
LIMIT = 100
|
||||
MAX_LIMIT = 500
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
class Api::V1::Admin::DomainBlocksController < Api::BaseController
|
||||
include Authorization
|
||||
include AccountableConcern
|
||||
include Admin::PermissionsConcern
|
||||
|
||||
LIMIT = 100
|
||||
MAX_LIMIT = 500
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
class Api::V1::Admin::EmailDomainBlocksController < Api::BaseController
|
||||
include Authorization
|
||||
include AccountableConcern
|
||||
include Admin::PermissionsConcern
|
||||
|
||||
LIMIT = 100
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
class Api::V1::Admin::IpBlocksController < Api::BaseController
|
||||
include Authorization
|
||||
include AccountableConcern
|
||||
include Admin::PermissionsConcern
|
||||
|
||||
LIMIT = 100
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
class Api::V1::Admin::MeasuresController < Api::BaseController
|
||||
include Authorization
|
||||
include Admin::PermissionsConcern
|
||||
|
||||
before_action -> { authorize_if_got_token! :'admin:read' }
|
||||
before_action :set_measures
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
class Api::V1::Admin::ReportsController < Api::BaseController
|
||||
include Authorization
|
||||
include AccountableConcern
|
||||
include Admin::PermissionsConcern
|
||||
|
||||
LIMIT = 100
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
class Api::V1::Admin::RetentionController < Api::BaseController
|
||||
include Authorization
|
||||
include Admin::PermissionsConcern
|
||||
|
||||
before_action -> { authorize_if_got_token! :'admin:read' }
|
||||
before_action :set_retention
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
class Api::V1::Admin::TagsController < Api::BaseController
|
||||
include Authorization
|
||||
include Admin::PermissionsConcern
|
||||
|
||||
before_action -> { authorize_if_got_token! :'admin:read' }, only: [:index, :show]
|
||||
before_action -> { authorize_if_got_token! :'admin:write' }, only: :update
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
class Api::V1::Admin::Trends::Links::PreviewCardProvidersController < Api::BaseController
|
||||
include Authorization
|
||||
include Admin::PermissionsConcern
|
||||
|
||||
LIMIT = 100
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
class Api::V1::Admin::Trends::LinksController < Api::V1::Trends::LinksController
|
||||
include Authorization
|
||||
include Admin::PermissionsConcern
|
||||
|
||||
before_action -> { authorize_if_got_token! :'admin:read' }, only: :index
|
||||
before_action -> { authorize_if_got_token! :'admin:write' }, except: :index
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
class Api::V1::Admin::Trends::StatusesController < Api::V1::Trends::StatusesController
|
||||
include Authorization
|
||||
include Admin::PermissionsConcern
|
||||
|
||||
before_action -> { authorize_if_got_token! :'admin:read' }, only: :index
|
||||
before_action -> { authorize_if_got_token! :'admin:write' }, except: :index
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
class Api::V1::Admin::Trends::TagsController < Api::V1::Trends::TagsController
|
||||
include Authorization
|
||||
include Admin::PermissionsConcern
|
||||
|
||||
before_action -> { authorize_if_got_token! :'admin:read' }, only: :index
|
||||
before_action -> { authorize_if_got_token! :'admin:write' }, except: :index
|
||||
|
||||
@@ -51,8 +51,14 @@ class Auth::SessionsController < Devise::SessionsController
|
||||
def find_user_from_params
|
||||
user = User.authenticate_with_ldap(user_params) if Devise.ldap_authentication
|
||||
user ||= User.authenticate_with_pam(user_params) if Devise.pam_authentication
|
||||
user ||= User.find_for_authentication(email: user_params[:email])
|
||||
user
|
||||
|
||||
if user.present?
|
||||
@password_verified_externally = true
|
||||
return user
|
||||
end
|
||||
|
||||
user = User.find_for_authentication(email: user_params[:email])
|
||||
user if user&.encrypted_password.present?
|
||||
end
|
||||
|
||||
def user_params
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Admin::PermissionsConcern
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
before_action :require_moderator_or_admin_permissions
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def require_moderator_or_admin_permissions
|
||||
# not using #authorize here, so #verify_authorized still makes sure more fine-grained rules are enforced down the line
|
||||
forbidden unless Admin::BasePolicy.new(current_account, :base).access?
|
||||
end
|
||||
end
|
||||
@@ -38,7 +38,7 @@ module Auth::TwoFactorAuthenticationConcern
|
||||
def authenticate_with_two_factor
|
||||
if user_params[:email].present?
|
||||
user = self.resource = find_user_from_params
|
||||
prompt_for_two_factor(user) if user&.external_or_valid_password?(user_params[:password])
|
||||
prompt_for_two_factor(user) if user && (@password_verified_externally || user.valid_password?(user_params[:password]))
|
||||
elsif session[:attempt_user_id]
|
||||
user = self.resource = User.find_by(id: session[:attempt_user_id])
|
||||
return if user.nil?
|
||||
|
||||
@@ -112,6 +112,30 @@ module JsonLdHelper
|
||||
compacted
|
||||
end
|
||||
|
||||
# Checks for unsupported JSON-LD features or too many nodes
|
||||
def check_jsonld_limits!(json, budget = 1_000)
|
||||
budget -= 1
|
||||
|
||||
if json.is_a?(Hash)
|
||||
json.each do |key, value|
|
||||
raise Mastodon::InvalidJsonLdError, 'contains unsupported JSON-LD features' if UNSUPPORTED_JSONLD_KEYWORDS.include?(key)
|
||||
raise Mastodon::InvalidJsonLdError, 'has too many nodes' if budget < 1
|
||||
|
||||
budget = check_jsonld_limits!(value, budget)
|
||||
end
|
||||
elsif json.is_a?(Array)
|
||||
json.each do |value|
|
||||
raise Mastodon::InvalidJsonLdError, 'has too many nodes' if budget < 1
|
||||
|
||||
budget = check_jsonld_limits!(value, budget)
|
||||
end
|
||||
end
|
||||
|
||||
raise Mastodon::InvalidJsonLdError, 'has too many nodes' if budget < 0 # rubocop:disable Style/NumericPredicate
|
||||
|
||||
budget
|
||||
end
|
||||
|
||||
def unsupported_jsonld_features?(json)
|
||||
if json.is_a?(Hash)
|
||||
json.any? { |key, value| UNSUPPORTED_JSONLD_KEYWORDS.include?(key) || unsupported_jsonld_features?(value) }
|
||||
|
||||
+1
-8
@@ -317,13 +317,6 @@ class User < ApplicationRecord
|
||||
super
|
||||
end
|
||||
|
||||
def external_or_valid_password?(compare_password)
|
||||
# If encrypted_password is blank, we got the user from LDAP or PAM,
|
||||
# so credentials are already valid
|
||||
|
||||
encrypted_password.blank? || valid_password?(compare_password)
|
||||
end
|
||||
|
||||
def send_reset_password_instructions
|
||||
return false if encrypted_password.blank?
|
||||
|
||||
@@ -525,7 +518,7 @@ class User < ApplicationRecord
|
||||
end
|
||||
|
||||
def invite_text_required?
|
||||
Setting.require_invite_text && !open_registrations? && !invited? && !external? && !bypass_registration_checks?
|
||||
Setting.require_invite_text && !open_registrations? && !invite&.bypass_approval? && !external? && !bypass_registration_checks?
|
||||
end
|
||||
|
||||
def trigger_webhooks
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class Admin::BasePolicy < ApplicationPolicy
|
||||
def access?
|
||||
role.administrator? || role.can?(*UserRole::Flags::CATEGORIES.fetch_values(:moderation, :administration, :devops).flatten)
|
||||
end
|
||||
end
|
||||
@@ -19,6 +19,8 @@ class ApplicationPolicy
|
||||
end
|
||||
|
||||
def role
|
||||
return UserRole.nobody if current_user&.disabled?
|
||||
|
||||
current_user&.role || UserRole.nobody
|
||||
end
|
||||
end
|
||||
@@ -13,10 +13,10 @@ class ActivityPub::ProcessCollectionService < BaseService
|
||||
|
||||
begin
|
||||
@json = compact(@json) if @json['signature'].is_a?(Hash)
|
||||
if unsupported_jsonld_features?(@json)
|
||||
Rails.logger.debug { "JSON-LD document for #{value_or_id(@json['actor'])} contains unsupported JSON-LD features" }
|
||||
@json = original_json.without('signature')
|
||||
end
|
||||
check_jsonld_limits!(@json)
|
||||
rescue Mastodon::InvalidJsonLdError => e
|
||||
Rails.logger.debug { "JSON-LD handling for document from #{value_or_id(@json['actor'])} skipped: #{e.message}" }
|
||||
@json = original_json.without('signature')
|
||||
rescue JSON::LD::JsonLdError => e
|
||||
Rails.logger.debug { "Error when compacting JSON-LD document for #{value_or_id(@json['actor'])}: #{e.message}" }
|
||||
@json = original_json.without('signature')
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
required: true,
|
||||
wrapper: :with_block_label
|
||||
|
||||
- if approved_registrations? && @invite.blank?
|
||||
- if approved_registrations? && !@invite&.bypass_approval?
|
||||
.fields-group
|
||||
= f.simple_fields_for :invite_request, resource.invite_request || resource.build_invite_request do |invite_request_fields|
|
||||
= invite_request_fields.input :text,
|
||||
@@ -81,4 +81,4 @@
|
||||
wrapper: :with_label
|
||||
|
||||
.actions
|
||||
= f.button :button, @invite.present? ? t('auth.register') : sign_up_message, type: :submit
|
||||
= f.button :button, @invite&.bypass_approval? ? t('auth.register') : sign_up_message, type: :submit
|
||||
+3
-3
@@ -60,7 +60,7 @@ services:
|
||||
web:
|
||||
# You can uncomment the following line if you want to not use the prebuilt image, for example if you have local code changes
|
||||
# build: .
|
||||
image: ghcr.io/glitch-soc/mastodon:v4.6.6
|
||||
image: ghcr.io/glitch-soc/mastodon:v4.6.7
|
||||
restart: always
|
||||
env_file: .env.production
|
||||
command: bundle exec puma -C config/puma.rb
|
||||
@@ -84,7 +84,7 @@ services:
|
||||
# build:
|
||||
# dockerfile: ./streaming/Dockerfile
|
||||
# context: .
|
||||
image: ghcr.io/glitch-soc/mastodon-streaming:v4.6.6
|
||||
image: ghcr.io/glitch-soc/mastodon-streaming:v4.6.7
|
||||
restart: always
|
||||
env_file: .env.production
|
||||
command: node ./streaming/index.js
|
||||
@@ -103,7 +103,7 @@ services:
|
||||
sidekiq:
|
||||
# You can uncomment the following line if you want to not use the prebuilt image, for example if you have local code changes
|
||||
# build: .
|
||||
image: ghcr.io/glitch-soc/mastodon:v4.6.6
|
||||
image: ghcr.io/glitch-soc/mastodon:v4.6.7
|
||||
restart: always
|
||||
env_file: .env.production
|
||||
command: bundle exec sidekiq
|
||||
|
||||
@@ -15,6 +15,7 @@ module Mastodon
|
||||
class SignatureVerificationError < Error; end
|
||||
class MalformedHeaderError < Error; end
|
||||
class RecursionLimitExceededError < Error; end
|
||||
class InvalidJsonLdError < Error; end
|
||||
|
||||
class UnexpectedResponseError < Error
|
||||
attr_reader :response
|
||||
|
||||
@@ -13,7 +13,7 @@ module Mastodon
|
||||
end
|
||||
|
||||
def patch
|
||||
6
|
||||
7
|
||||
end
|
||||
|
||||
def default_prerelease
|
||||
|
||||
@@ -252,94 +252,6 @@ RSpec.describe Auth::RegistrationsController do
|
||||
end
|
||||
end
|
||||
|
||||
context 'with Approval-based registrations without invite' do
|
||||
subject do
|
||||
Setting.registrations_mode = 'approved'
|
||||
request.headers['Accept-Language'] = accept_language
|
||||
post :create, params: { user: { account_attributes: { username: 'test' }, email: 'test@example.com', password: '12345678', password_confirmation: '12345678', agreement: 'true' } }
|
||||
end
|
||||
|
||||
it 'redirects to setup and creates user' do
|
||||
subject
|
||||
|
||||
expect(response)
|
||||
.to redirect_to auth_setup_path
|
||||
|
||||
expect(User.find_by(email: 'test@example.com'))
|
||||
.to be_present
|
||||
.and have_attributes(
|
||||
locale: eq(accept_language),
|
||||
approved: be(false)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with Approval-based registrations with expired invite' do
|
||||
subject do
|
||||
Setting.registrations_mode = 'approved'
|
||||
request.headers['Accept-Language'] = accept_language
|
||||
invite = Fabricate(:invite, max_uses: nil, expires_at: 1.hour.ago)
|
||||
post :create, params: { user: { account_attributes: { username: 'test' }, email: 'test@example.com', password: '12345678', password_confirmation: '12345678', invite_code: invite.code, agreement: 'true' } }
|
||||
end
|
||||
|
||||
it 'redirects to setup and creates user' do
|
||||
subject
|
||||
|
||||
expect(response).to redirect_to auth_setup_path
|
||||
|
||||
expect(User.find_by(email: 'test@example.com'))
|
||||
.to be_present
|
||||
.and have_attributes(
|
||||
locale: eq(accept_language),
|
||||
approved: be(false)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with Approval-based registrations with valid invite and required invite text' do
|
||||
subject do
|
||||
Setting.registrations_mode = 'approved'
|
||||
Setting.require_invite_text = true
|
||||
request.headers['Accept-Language'] = accept_language
|
||||
invite = Fabricate(:invite, user: inviter, max_uses: nil, expires_at: 1.hour.from_now)
|
||||
post :create, params: { user: { account_attributes: { username: 'test' }, email: 'test@example.com', password: '12345678', password_confirmation: '12345678', invite_code: invite.code, agreement: 'true' } }
|
||||
end
|
||||
|
||||
let!(:inviter) { Fabricate(:user, confirmed_at: 2.days.ago) }
|
||||
|
||||
it 'redirects to setup and creates user in a non-approved state' do
|
||||
subject
|
||||
|
||||
expect(response).to redirect_to auth_setup_path
|
||||
|
||||
expect(User.find_by(email: 'test@example.com'))
|
||||
.to be_present
|
||||
.and have_attributes(
|
||||
locale: eq(accept_language),
|
||||
approved: be(false)
|
||||
)
|
||||
end
|
||||
|
||||
context 'when the inviting user has the permission to bypass approval' do
|
||||
before do
|
||||
inviter.role.update!(permissions: inviter.role.permissions | UserRole::FLAGS[:invite_bypass_approval])
|
||||
end
|
||||
|
||||
it 'redirects to setup and creates user in an approved state' do
|
||||
subject
|
||||
|
||||
expect(response).to redirect_to auth_setup_path
|
||||
|
||||
expect(User.find_by(email: 'test@example.com'))
|
||||
.to be_present
|
||||
.and have_attributes(
|
||||
locale: eq(accept_language),
|
||||
approved: be(true)
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with an already taken username' do
|
||||
subject do
|
||||
Setting.registrations_mode = 'open'
|
||||
|
||||
@@ -374,7 +374,7 @@ RSpec.describe Mastodon::CLI::Accounts do
|
||||
.to output_results(new_password)
|
||||
|
||||
expect(user).to have_received(:change_password!).with(new_password)
|
||||
expect(user.reload).to_not be_external_or_valid_password(original_password)
|
||||
expect(user.reload).to_not be_valid_password(original_password)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -462,7 +462,7 @@ RSpec.describe User do
|
||||
.and remove_user_web_subscriptions
|
||||
|
||||
expect(user)
|
||||
.to_not be_external_or_valid_password(original_password)
|
||||
.to_not be_valid_password(original_password)
|
||||
expect { session_activation.reload }
|
||||
.to raise_error(ActiveRecord::RecordNotFound)
|
||||
expect { web_push_subscription.reload }
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Admin::BasePolicy do
|
||||
let(:policy) { described_class }
|
||||
let(:custom_devops_role) do
|
||||
Fabricate(:user_role, permissions_as_keys: [:view_devops])
|
||||
end
|
||||
let(:custom_role_with_one_admin_permission) do
|
||||
Fabricate(:user_role, permissions_as_keys: [:manage_announcements])
|
||||
end
|
||||
let(:custom_role_with_one_moderator_permission) do
|
||||
Fabricate(:user_role, permissions_as_keys: [:manage_invites])
|
||||
end
|
||||
let(:admin) { Fabricate(:admin_user).account }
|
||||
let(:moderator) { Fabricate(:moderator_user).account }
|
||||
let(:devops_user) { Fabricate(:user, role: custom_devops_role).account }
|
||||
let(:custom_admin) { Fabricate(:user, role: custom_role_with_one_admin_permission).account }
|
||||
let(:custom_moderator) { Fabricate(:user, role: custom_role_with_one_moderator_permission).account }
|
||||
let(:regular_user) { Fabricate(:account) }
|
||||
|
||||
permissions :access? do
|
||||
context 'with an admin' do
|
||||
it 'permits' do
|
||||
expect(policy).to permit(admin, :base)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a moderator' do
|
||||
it 'permits' do
|
||||
expect(policy).to permit(moderator, :base)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a user with devops permissions' do
|
||||
it 'permits' do
|
||||
expect(policy).to permit(devops_user, :base)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a user with a custom role that grants a single admin permission' do
|
||||
it 'permits' do
|
||||
expect(policy).to permit(custom_admin, :base)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a user with a custom role that grants a single moderator permission' do
|
||||
it 'permits' do
|
||||
expect(policy).to permit(custom_moderator, :base)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a non-admin' do
|
||||
it 'denies' do
|
||||
expect(policy).to_not permit(regular_user, :base)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,37 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe ApplicationPolicy do
|
||||
subject do
|
||||
Class.new(described_class) do
|
||||
def spec?
|
||||
role.can?(:manage_users)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
let(:admin) { Fabricate(:admin_user).account }
|
||||
let(:john) { Fabricate(:account) }
|
||||
let(:alice) { Fabricate(:admin_user, disabled: true).account }
|
||||
|
||||
permissions :spec? do
|
||||
context 'when staff' do
|
||||
it 'permits' do
|
||||
expect(subject).to permit(admin)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when not staff' do
|
||||
it 'denies' do
|
||||
expect(subject).to_not permit(john)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when staff but disabled' do
|
||||
it 'denies' do
|
||||
expect(subject).to_not permit(alice)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -51,6 +51,7 @@ RSpec.describe 'Account actions' do
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'admin:read admin:read:accounts'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for disabled user'
|
||||
it_behaves_like 'a successful notification delivery'
|
||||
it_behaves_like 'a successful logged action', :disable, :user
|
||||
|
||||
@@ -67,6 +68,7 @@ RSpec.describe 'Account actions' do
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'admin:read admin:read:accounts'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for disabled user'
|
||||
it_behaves_like 'a successful notification delivery'
|
||||
it_behaves_like 'a successful logged action', :sensitive, :account
|
||||
|
||||
@@ -83,6 +85,7 @@ RSpec.describe 'Account actions' do
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'admin:read admin:read:accounts'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for disabled user'
|
||||
it_behaves_like 'a successful notification delivery'
|
||||
it_behaves_like 'a successful logged action', :silence, :account
|
||||
|
||||
@@ -99,6 +102,7 @@ RSpec.describe 'Account actions' do
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'admin:read admin:read:accounts'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for disabled user'
|
||||
it_behaves_like 'a successful notification delivery'
|
||||
it_behaves_like 'a successful logged action', :suspend, :account
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ RSpec.describe 'Accounts' do
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'read read:accounts admin:write admin:write:accounts'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for disabled user'
|
||||
|
||||
context 'when requesting active local staff accounts' do
|
||||
let(:expected_results) { [admin_account] }
|
||||
@@ -107,6 +108,7 @@ RSpec.describe 'Accounts' do
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'read read:accounts admin:write admin:write:accounts'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for disabled user'
|
||||
|
||||
it 'returns the requested account successfully', :aggregate_failures do
|
||||
subject
|
||||
@@ -144,6 +146,7 @@ RSpec.describe 'Accounts' do
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write write:accounts read admin:read'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for disabled user'
|
||||
|
||||
it 'approves the user successfully', :aggregate_failures do
|
||||
subject
|
||||
@@ -202,6 +205,7 @@ RSpec.describe 'Accounts' do
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write write:accounts read admin:read'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for disabled user'
|
||||
|
||||
it 'removes the user successfully and logs action', :aggregate_failures do
|
||||
subject
|
||||
@@ -255,6 +259,7 @@ RSpec.describe 'Accounts' do
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write write:accounts read admin:read'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for disabled user'
|
||||
|
||||
it 'enables the user successfully', :aggregate_failures do
|
||||
subject
|
||||
@@ -290,6 +295,7 @@ RSpec.describe 'Accounts' do
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write write:accounts read admin:read'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for disabled user'
|
||||
|
||||
it 'unsuspends the account successfully', :aggregate_failures do
|
||||
subject
|
||||
@@ -335,6 +341,7 @@ RSpec.describe 'Accounts' do
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write write:accounts read admin:read'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for disabled user'
|
||||
|
||||
it 'unsensitizes the account successfully', :aggregate_failures do
|
||||
subject
|
||||
@@ -369,6 +376,7 @@ RSpec.describe 'Accounts' do
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write write:accounts read admin:read'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for disabled user'
|
||||
|
||||
it 'unsilences the account successfully', :aggregate_failures do
|
||||
subject
|
||||
@@ -404,6 +412,7 @@ RSpec.describe 'Accounts' do
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write write:accounts read admin:read'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for disabled user'
|
||||
|
||||
it 'deletes the account successfully', :aggregate_failures do
|
||||
allow(Admin::AccountDeletionWorker).to receive(:perform_async)
|
||||
|
||||
@@ -15,6 +15,7 @@ RSpec.describe 'Canonical Email Blocks' do
|
||||
it_behaves_like 'forbidden for wrong scope', 'read:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for wrong role', 'Moderator'
|
||||
it_behaves_like 'forbidden for disabled user'
|
||||
|
||||
context 'when there is no canonical email block' do
|
||||
it 'returns an empty list' do
|
||||
@@ -90,6 +91,7 @@ RSpec.describe 'Canonical Email Blocks' do
|
||||
it_behaves_like 'forbidden for wrong scope', 'read:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for wrong role', 'Moderator'
|
||||
it_behaves_like 'forbidden for disabled user'
|
||||
|
||||
context 'when the requested canonical email block exists' do
|
||||
it 'returns the requested canonical email block data correctly', :aggregate_failures do
|
||||
@@ -127,6 +129,7 @@ RSpec.describe 'Canonical Email Blocks' do
|
||||
it_behaves_like 'forbidden for wrong scope', 'read:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for wrong role', 'Moderator'
|
||||
it_behaves_like 'forbidden for disabled user'
|
||||
|
||||
context 'when the required email param is not provided' do
|
||||
let(:params) { {} }
|
||||
@@ -178,6 +181,7 @@ RSpec.describe 'Canonical Email Blocks' do
|
||||
it_behaves_like 'forbidden for wrong scope', 'read:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for wrong role', 'Moderator'
|
||||
it_behaves_like 'forbidden for disabled user'
|
||||
|
||||
it 'returns the canonical_email_hash correctly', :aggregate_failures do
|
||||
subject
|
||||
@@ -252,6 +256,7 @@ RSpec.describe 'Canonical Email Blocks' do
|
||||
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for wrong role', 'Moderator'
|
||||
it_behaves_like 'forbidden for disabled user'
|
||||
|
||||
it 'deletes the canonical email block', :aggregate_failures do
|
||||
subject
|
||||
|
||||
@@ -15,6 +15,7 @@ RSpec.describe 'Domain Allows' do
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for wrong role', 'Moderator'
|
||||
it_behaves_like 'forbidden for disabled user'
|
||||
|
||||
context 'when there is no allowed domains' do
|
||||
it 'returns an empty body' do
|
||||
@@ -73,6 +74,7 @@ RSpec.describe 'Domain Allows' do
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for wrong role', 'Moderator'
|
||||
it_behaves_like 'forbidden for disabled user'
|
||||
|
||||
it 'returns the expected allowed domain name', :aggregate_failures do
|
||||
subject
|
||||
@@ -104,6 +106,7 @@ RSpec.describe 'Domain Allows' do
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for wrong role', 'Moderator'
|
||||
it_behaves_like 'forbidden for disabled user'
|
||||
|
||||
context 'with a valid domain name' do
|
||||
it 'returns the expected domain name', :aggregate_failures do
|
||||
@@ -164,6 +167,7 @@ RSpec.describe 'Domain Allows' do
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for wrong role', 'Moderator'
|
||||
it_behaves_like 'forbidden for disabled user'
|
||||
|
||||
it 'deletes the allowed domain', :aggregate_failures do
|
||||
subject
|
||||
|
||||
@@ -15,6 +15,7 @@ RSpec.describe 'Domain Blocks' do
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for wrong role', 'Moderator'
|
||||
it_behaves_like 'forbidden for disabled user'
|
||||
|
||||
context 'when there are no domain blocks' do
|
||||
it 'returns an empty list' do
|
||||
@@ -89,6 +90,7 @@ RSpec.describe 'Domain Blocks' do
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for wrong role', 'Moderator'
|
||||
it_behaves_like 'forbidden for disabled user'
|
||||
|
||||
it 'returns the expected domain block content', :aggregate_failures do
|
||||
subject
|
||||
@@ -131,6 +133,7 @@ RSpec.describe 'Domain Blocks' do
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for wrong role', 'Moderator'
|
||||
it_behaves_like 'forbidden for disabled user'
|
||||
|
||||
it 'creates a domain block with the expected domain name and severity', :aggregate_failures do
|
||||
subject
|
||||
@@ -239,6 +242,7 @@ RSpec.describe 'Domain Blocks' do
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for wrong role', 'Moderator'
|
||||
it_behaves_like 'forbidden for disabled user'
|
||||
|
||||
it 'returns the updated domain block', :aggregate_failures do
|
||||
subject
|
||||
@@ -281,6 +285,7 @@ RSpec.describe 'Domain Blocks' do
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for wrong role', 'Moderator'
|
||||
it_behaves_like 'forbidden for disabled user'
|
||||
|
||||
it 'deletes the domain block', :aggregate_failures do
|
||||
subject
|
||||
|
||||
@@ -15,6 +15,7 @@ RSpec.describe 'Email Domain Blocks' do
|
||||
it_behaves_like 'forbidden for wrong scope', 'read:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for wrong role', 'Moderator'
|
||||
it_behaves_like 'forbidden for disabled user'
|
||||
|
||||
context 'when there is no email domain block' do
|
||||
it 'returns an empty list' do
|
||||
@@ -90,6 +91,7 @@ RSpec.describe 'Email Domain Blocks' do
|
||||
it_behaves_like 'forbidden for wrong scope', 'read:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for wrong role', 'Moderator'
|
||||
it_behaves_like 'forbidden for disabled user'
|
||||
|
||||
context 'when email domain block exists' do
|
||||
it 'returns the correct blocked domain', :aggregate_failures do
|
||||
@@ -123,6 +125,7 @@ RSpec.describe 'Email Domain Blocks' do
|
||||
it_behaves_like 'forbidden for wrong scope', 'read:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for wrong role', 'Moderator'
|
||||
it_behaves_like 'forbidden for disabled user'
|
||||
|
||||
it 'returns the correct blocked email domain', :aggregate_failures do
|
||||
subject
|
||||
@@ -182,6 +185,7 @@ RSpec.describe 'Email Domain Blocks' do
|
||||
it_behaves_like 'forbidden for wrong scope', 'read:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for wrong role', 'Moderator'
|
||||
it_behaves_like 'forbidden for disabled user'
|
||||
|
||||
it 'deletes email domain block', :aggregate_failures do
|
||||
subject
|
||||
|
||||
@@ -15,6 +15,7 @@ RSpec.describe 'IP Blocks' do
|
||||
it_behaves_like 'forbidden for wrong scope', 'admin:write:ip_blocks'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for wrong role', 'Moderator'
|
||||
it_behaves_like 'forbidden for disabled user'
|
||||
|
||||
context 'when there is no ip block' do
|
||||
it 'returns an empty body' do
|
||||
@@ -83,6 +84,7 @@ RSpec.describe 'IP Blocks' do
|
||||
it_behaves_like 'forbidden for wrong scope', 'admin:write:ip_blocks'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for wrong role', 'Moderator'
|
||||
it_behaves_like 'forbidden for disabled user'
|
||||
|
||||
it 'returns the correct ip block', :aggregate_failures do
|
||||
subject
|
||||
@@ -119,6 +121,7 @@ RSpec.describe 'IP Blocks' do
|
||||
it_behaves_like 'forbidden for wrong scope', 'admin:read:ip_blocks'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for wrong role', 'Moderator'
|
||||
it_behaves_like 'forbidden for disabled user'
|
||||
|
||||
it 'returns the correct ip block', :aggregate_failures do
|
||||
subject
|
||||
|
||||
@@ -14,6 +14,7 @@ RSpec.describe 'Reports' do
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for disabled user'
|
||||
|
||||
context 'when there are no reports' do
|
||||
it 'returns an empty list' do
|
||||
@@ -132,6 +133,7 @@ RSpec.describe 'Reports' do
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for disabled user'
|
||||
|
||||
it 'returns the requested report content', :aggregate_failures do
|
||||
subject
|
||||
@@ -199,6 +201,7 @@ RSpec.describe 'Reports' do
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for disabled user'
|
||||
|
||||
it 'marks report as resolved', :aggregate_failures do
|
||||
expect { subject }
|
||||
@@ -219,6 +222,7 @@ RSpec.describe 'Reports' do
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for disabled user'
|
||||
|
||||
it 'marks report as unresolved', :aggregate_failures do
|
||||
expect { subject }
|
||||
@@ -239,6 +243,7 @@ RSpec.describe 'Reports' do
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for disabled user'
|
||||
|
||||
it 'assigns report to the requesting user', :aggregate_failures do
|
||||
expect { subject }
|
||||
@@ -259,6 +264,7 @@ RSpec.describe 'Reports' do
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for disabled user'
|
||||
|
||||
it 'unassigns report from assignee', :aggregate_failures do
|
||||
expect { subject }
|
||||
|
||||
@@ -17,6 +17,7 @@ RSpec.describe 'Tags' do
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for disabled user'
|
||||
|
||||
context 'when there are no tags' do
|
||||
it 'returns an empty list' do
|
||||
@@ -74,6 +75,7 @@ RSpec.describe 'Tags' do
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for disabled user'
|
||||
|
||||
it 'returns http success and expected tag content' do
|
||||
subject
|
||||
@@ -111,6 +113,7 @@ RSpec.describe 'Tags' do
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong scope', 'admin:read'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for disabled user'
|
||||
|
||||
it 'returns http success and updates tag' do
|
||||
subject
|
||||
|
||||
@@ -28,6 +28,7 @@ RSpec.describe 'Links' do
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'read write'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for disabled user'
|
||||
|
||||
it 'returns http success' do
|
||||
expect { subject }
|
||||
@@ -87,6 +88,7 @@ RSpec.describe 'Links' do
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'read write'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for disabled user'
|
||||
|
||||
it 'returns http success' do
|
||||
expect { subject }
|
||||
|
||||
@@ -25,6 +25,7 @@ RSpec.describe 'API V1 Admin Trends Links Preview Card Providers' do
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for disabled user'
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
@@ -40,6 +41,7 @@ RSpec.describe 'API V1 Admin Trends Links Preview Card Providers' do
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for disabled user'
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
|
||||
@@ -25,6 +25,7 @@ RSpec.describe 'API V1 Admin Trends Statuses' do
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for disabled user'
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
@@ -40,6 +41,7 @@ RSpec.describe 'API V1 Admin Trends Statuses' do
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for disabled user'
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
|
||||
@@ -25,6 +25,7 @@ RSpec.describe 'API V1 Admin Trends Tags' do
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for disabled user'
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
@@ -40,6 +41,7 @@ RSpec.describe 'API V1 Admin Trends Tags' do
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for disabled user'
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
|
||||
@@ -27,7 +27,7 @@ RSpec.describe 'Auth Passwords' do
|
||||
|
||||
expect(User.find(user.id))
|
||||
.to be_present
|
||||
.and be_external_or_valid_password(user.password)
|
||||
.and be_valid_password(user.password)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -22,3 +22,14 @@ RSpec.shared_examples 'forbidden for wrong role' do |wrong_role|
|
||||
expect(response).to have_http_status(403)
|
||||
end
|
||||
end
|
||||
|
||||
RSpec.shared_examples 'forbidden for disabled user' do
|
||||
let(:user) { Fabricate(:admin_user, disabled: true) }
|
||||
|
||||
it 'returns http forbidden' do
|
||||
# Some examples have a subject which needs to be called to make a request
|
||||
subject if request.nil?
|
||||
|
||||
expect(response).to have_http_status(403)
|
||||
end
|
||||
end
|
||||
@@ -36,6 +36,120 @@ RSpec.describe 'Auth Registration' do
|
||||
end
|
||||
end
|
||||
|
||||
context 'with approval-based registrations' do
|
||||
subject { visit new_user_registration_path }
|
||||
|
||||
shared_examples 'approval is required' do
|
||||
context 'when reason to join is not required' do
|
||||
before { Setting.require_invite_text = false }
|
||||
|
||||
it 'asks for an optional reason to join, creates the user as unapproved' do
|
||||
subject
|
||||
|
||||
expect(page)
|
||||
.to have_title(I18n.t('auth.register'))
|
||||
|
||||
expect(page)
|
||||
.to have_text(I18n.t('simple_form.labels.invite_request.text'))
|
||||
|
||||
expect { fill_in_and_submit_form(apply: true) }
|
||||
.to change(User, :count).by(1)
|
||||
|
||||
expect(User.find_by(email: 'test@example.com'))
|
||||
.to have_attributes(approved: false)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when reason to join is required' do
|
||||
before { Setting.require_invite_text = true }
|
||||
|
||||
it 'asks for a required reason to join, creates the user unapproved' do
|
||||
subject
|
||||
|
||||
expect(page)
|
||||
.to have_title(I18n.t('auth.register'))
|
||||
|
||||
expect(page)
|
||||
.to have_text(I18n.t('simple_form.labels.invite_request.text'))
|
||||
|
||||
# Not providing the invite text results in an error
|
||||
expect { fill_in_and_submit_form(apply: true) }
|
||||
.to_not change(User, :count)
|
||||
expect(page)
|
||||
.to have_text(/error below/)
|
||||
|
||||
# Providing the invite text succeeds
|
||||
expect { fill_in_and_submit_form(apply: true, invite_text: 'Hello world') }
|
||||
.to change(User, :count).by(1)
|
||||
|
||||
expect(User.find_by(email: 'test@example.com'))
|
||||
.to have_attributes(approved: false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
before do
|
||||
Setting.registrations_mode = 'approved'
|
||||
end
|
||||
|
||||
it_behaves_like 'approval is required'
|
||||
|
||||
context 'with an invitation' do
|
||||
subject { visit new_user_registration_path(invite_code: invite.code) }
|
||||
|
||||
let!(:inviter) { Fabricate(:user, confirmed_at: 2.days.ago, bypass_registration_checks: true) }
|
||||
let(:invite) { Fabricate(:invite, user: inviter) }
|
||||
|
||||
before do
|
||||
inviter.approve!
|
||||
end
|
||||
|
||||
it_behaves_like 'approval is required'
|
||||
|
||||
context 'when the invite allows bypassing approval' do
|
||||
before do
|
||||
inviter.role.update!(permissions: inviter.role.permissions | UserRole::FLAGS[:invite_bypass_approval])
|
||||
end
|
||||
|
||||
it 'does not ask for a required reason to join, creates the user approved' do
|
||||
subject
|
||||
|
||||
expect(page)
|
||||
.to have_title(I18n.t('auth.register'))
|
||||
|
||||
expect(page)
|
||||
.to have_no_text(I18n.t('simple_form.labels.invite_request.text'))
|
||||
|
||||
expect { fill_in_and_submit_form(apply: false) }
|
||||
.to change(User, :count).by(1)
|
||||
|
||||
expect(User.find_by(email: 'test@example.com'))
|
||||
.to have_attributes(approved: true)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when invite has expired' do
|
||||
let(:invite) { Fabricate(:invite, user: inviter, expires_at: 1.hour.ago) }
|
||||
|
||||
it_behaves_like 'approval is required'
|
||||
end
|
||||
end
|
||||
|
||||
def fill_in_and_submit_form(apply: false, invite_text: nil)
|
||||
# Avoid the registration spam check
|
||||
travel_to 10.seconds.from_now
|
||||
|
||||
fill_in 'user_account_attributes_username', with: 'test'
|
||||
fill_in 'user_email', with: 'test@example.com'
|
||||
fill_in 'user_password', with: 'Test.123.Pass'
|
||||
fill_in 'user_password_confirmation', with: 'Test.123.Pass'
|
||||
fill_in 'user_invite_request_attributes_text', with: invite_text if invite_text.present?
|
||||
check 'user_agreement'
|
||||
|
||||
click_on(apply ? I18n.t('auth.apply_for_account') : I18n.t('auth.register'))
|
||||
end
|
||||
end
|
||||
|
||||
context 'when age verification is enabled' do
|
||||
before { Setting.min_age = 16 }
|
||||
|
||||
|
||||
Reference in new issue
Block a user