Merge commit '36631e40cc' into kb_migration

This commit is contained in:
KMY 2023-04-26 11:39:42 +09:00
commit 9461db713b
40 changed files with 165 additions and 36 deletions

View file

@ -37,6 +37,7 @@ jobs:
latest=auto latest=auto
tags: | tags: |
type=raw,value=nightly type=raw,value=nightly
type=schedule,pattern=nightly-{{date 'YYYY-MM-DD' tz='Etc/UTC'}}
labels: | labels: |
org.opencontainers.image.description=Nightly build image used for testing purposes org.opencontainers.image.description=Nightly build image used for testing purposes

View file

@ -6,13 +6,15 @@ class Api::BaseController < ApplicationController
include RateLimitHeaders include RateLimitHeaders
include AccessTokenTrackingConcern include AccessTokenTrackingConcern
include ApiCachingConcern
skip_before_action :store_current_location
skip_before_action :require_functional!, unless: :whitelist_mode? skip_before_action :require_functional!, unless: :whitelist_mode?
before_action :require_authenticated_user!, if: :disallow_unauthenticated_api_access? before_action :require_authenticated_user!, if: :disallow_unauthenticated_api_access?
before_action :require_not_suspended! before_action :require_not_suspended!
vary_by 'Authorization'
protect_from_forgery with: :null_session protect_from_forgery with: :null_session
content_security_policy do |p| content_security_policy do |p|

View file

@ -6,6 +6,7 @@ class Api::V1::Accounts::FollowerAccountsController < Api::BaseController
after_action :insert_pagination_headers after_action :insert_pagination_headers
def index def index
cache_if_unauthenticated!
@accounts = load_accounts @accounts = load_accounts
render json: @accounts, each_serializer: REST::AccountSerializer render json: @accounts, each_serializer: REST::AccountSerializer
end end

View file

@ -6,6 +6,7 @@ class Api::V1::Accounts::FollowingAccountsController < Api::BaseController
after_action :insert_pagination_headers after_action :insert_pagination_headers
def index def index
cache_if_unauthenticated!
@accounts = load_accounts @accounts = load_accounts
render json: @accounts, each_serializer: REST::AccountSerializer render json: @accounts, each_serializer: REST::AccountSerializer
end end

View file

@ -5,6 +5,7 @@ class Api::V1::Accounts::LookupController < Api::BaseController
before_action :set_account before_action :set_account
def show def show
cache_if_unauthenticated!
render json: @account, serializer: REST::AccountSerializer render json: @account, serializer: REST::AccountSerializer
end end

View file

@ -7,6 +7,7 @@ class Api::V1::Accounts::StatusesController < Api::BaseController
after_action :insert_pagination_headers, unless: -> { truthy_param?(:pinned) } after_action :insert_pagination_headers, unless: -> { truthy_param?(:pinned) }
def index def index
cache_if_unauthenticated!
@statuses = load_statuses @statuses = load_statuses
render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id) render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id)
end end

View file

@ -18,6 +18,7 @@ class Api::V1::AccountsController < Api::BaseController
override_rate_limit_headers :follow, family: :follows override_rate_limit_headers :follow, family: :follows
def show def show
cache_if_unauthenticated!
render json: @account, serializer: REST::AccountSerializer render json: @account, serializer: REST::AccountSerializer
end end

View file

@ -1,8 +1,10 @@
# frozen_string_literal: true # frozen_string_literal: true
class Api::V1::CustomEmojisController < Api::BaseController class Api::V1::CustomEmojisController < Api::BaseController
vary_by ''
def index def index
expires_in 3.minutes, public: true cache_even_if_authenticated!
render_with_cache(each_serializer: REST::CustomEmojiSerializer) { CustomEmoji.listed.includes(:category) } render_with_cache(each_serializer: REST::CustomEmojiSerializer) { CustomEmoji.listed.includes(:category) }
end end
end end

View file

@ -5,6 +5,7 @@ class Api::V1::DirectoriesController < Api::BaseController
before_action :set_accounts before_action :set_accounts
def show def show
cache_if_unauthenticated!
render json: @accounts, each_serializer: REST::AccountSerializer render json: @accounts, each_serializer: REST::AccountSerializer
end end

View file

@ -5,8 +5,10 @@ class Api::V1::Instances::ActivityController < Api::BaseController
skip_before_action :require_authenticated_user!, unless: :whitelist_mode? skip_before_action :require_authenticated_user!, unless: :whitelist_mode?
vary_by ''
def show def show
expires_in 1.day, public: true cache_even_if_authenticated!
render_with_cache json: :activity, expires_in: 1.day render_with_cache json: :activity, expires_in: 1.day
end end

View file

@ -6,8 +6,10 @@ class Api::V1::Instances::DomainBlocksController < Api::BaseController
before_action :require_enabled_api! before_action :require_enabled_api!
before_action :set_domain_blocks before_action :set_domain_blocks
vary_by ''
def index def index
expires_in 3.minutes, public: true cache_even_if_authenticated!
render json: @domain_blocks, each_serializer: REST::DomainBlockSerializer, with_comment: (Setting.show_domain_blocks_rationale == 'all' || (Setting.show_domain_blocks_rationale == 'users' && user_signed_in?)) render json: @domain_blocks, each_serializer: REST::DomainBlockSerializer, with_comment: (Setting.show_domain_blocks_rationale == 'all' || (Setting.show_domain_blocks_rationale == 'users' && user_signed_in?))
end end

View file

@ -2,11 +2,19 @@
class Api::V1::Instances::ExtendedDescriptionsController < Api::BaseController class Api::V1::Instances::ExtendedDescriptionsController < Api::BaseController
skip_before_action :require_authenticated_user!, unless: :whitelist_mode? skip_before_action :require_authenticated_user!, unless: :whitelist_mode?
skip_around_action :set_locale
before_action :set_extended_description before_action :set_extended_description
vary_by ''
# Override `current_user` to avoid reading session cookies unless in whitelist mode
def current_user
super if whitelist_mode?
end
def show def show
expires_in 3.minutes, public: true cache_even_if_authenticated!
render json: @extended_description, serializer: REST::ExtendedDescriptionSerializer render json: @extended_description, serializer: REST::ExtendedDescriptionSerializer
end end

View file

@ -4,9 +4,17 @@ class Api::V1::Instances::PeersController < Api::BaseController
before_action :require_enabled_api! before_action :require_enabled_api!
skip_before_action :require_authenticated_user!, unless: :whitelist_mode? skip_before_action :require_authenticated_user!, unless: :whitelist_mode?
skip_around_action :set_locale
vary_by ''
# Override `current_user` to avoid reading session cookies unless in whitelist mode
def current_user
super if whitelist_mode?
end
def index def index
expires_in 1.day, public: true cache_even_if_authenticated!
render_with_cache(expires_in: 1.day) { Instance.where.not(domain: DomainBlock.select(:domain)).pluck(:domain) } render_with_cache(expires_in: 1.day) { Instance.where.not(domain: DomainBlock.select(:domain)).pluck(:domain) }
end end

View file

@ -5,8 +5,10 @@ class Api::V1::Instances::PrivacyPoliciesController < Api::BaseController
before_action :set_privacy_policy before_action :set_privacy_policy
vary_by ''
def show def show
expires_in 1.day, public: true cache_even_if_authenticated!
render json: @privacy_policy, serializer: REST::PrivacyPolicySerializer render json: @privacy_policy, serializer: REST::PrivacyPolicySerializer
end end

View file

@ -2,10 +2,19 @@
class Api::V1::Instances::RulesController < Api::BaseController class Api::V1::Instances::RulesController < Api::BaseController
skip_before_action :require_authenticated_user!, unless: :whitelist_mode? skip_before_action :require_authenticated_user!, unless: :whitelist_mode?
skip_around_action :set_locale
before_action :set_rules before_action :set_rules
vary_by ''
# Override `current_user` to avoid reading session cookies unless in whitelist mode
def current_user
super if whitelist_mode?
end
def index def index
cache_even_if_authenticated!
render json: @rules, each_serializer: REST::RuleSerializer render json: @rules, each_serializer: REST::RuleSerializer
end end

View file

@ -5,8 +5,10 @@ class Api::V1::Instances::TranslationLanguagesController < Api::BaseController
before_action :set_languages before_action :set_languages
vary_by ''
def show def show
expires_in 1.day, public: true cache_even_if_authenticated!
render json: @languages render json: @languages
end end

View file

@ -2,9 +2,17 @@
class Api::V1::InstancesController < Api::BaseController class Api::V1::InstancesController < Api::BaseController
skip_before_action :require_authenticated_user!, unless: :whitelist_mode? skip_before_action :require_authenticated_user!, unless: :whitelist_mode?
skip_around_action :set_locale
vary_by ''
# Override `current_user` to avoid reading session cookies unless in whitelist mode
def current_user
super if whitelist_mode?
end
def show def show
expires_in 3.minutes, public: true cache_even_if_authenticated!
render_with_cache json: InstancePresenter.new, serializer: REST::V1::InstanceSerializer, root: 'instance' render_with_cache json: InstancePresenter.new, serializer: REST::V1::InstanceSerializer, root: 'instance'
end end
end end

View file

@ -8,6 +8,7 @@ class Api::V1::PollsController < Api::BaseController
before_action :refresh_poll before_action :refresh_poll
def show def show
cache_if_unauthenticated!
render json: @poll, serializer: REST::PollSerializer, include_results: true render json: @poll, serializer: REST::PollSerializer, include_results: true
end end

View file

@ -8,6 +8,7 @@ class Api::V1::Statuses::FavouritedByAccountsController < Api::BaseController
after_action :insert_pagination_headers after_action :insert_pagination_headers
def index def index
cache_if_unauthenticated!
@accounts = load_accounts @accounts = load_accounts
render json: @accounts, each_serializer: REST::AccountSerializer render json: @accounts, each_serializer: REST::AccountSerializer
end end

View file

@ -7,6 +7,7 @@ class Api::V1::Statuses::HistoriesController < Api::BaseController
before_action :set_status before_action :set_status
def show def show
cache_if_unauthenticated!
render json: @status.edits.includes(:account, status: [:account]), each_serializer: REST::StatusEditSerializer render json: @status.edits.includes(:account, status: [:account]), each_serializer: REST::StatusEditSerializer
end end

View file

@ -8,6 +8,7 @@ class Api::V1::Statuses::RebloggedByAccountsController < Api::BaseController
after_action :insert_pagination_headers after_action :insert_pagination_headers
def index def index
cache_if_unauthenticated!
@accounts = load_accounts @accounts = load_accounts
render json: @accounts, each_serializer: REST::AccountSerializer render json: @accounts, each_serializer: REST::AccountSerializer
end end

View file

@ -24,11 +24,14 @@ class Api::V1::StatusesController < Api::BaseController
DESCENDANTS_DEPTH_LIMIT = 20 DESCENDANTS_DEPTH_LIMIT = 20
def show def show
cache_if_unauthenticated!
@status = cache_collection([@status], Status).first @status = cache_collection([@status], Status).first
render json: @status, serializer: REST::StatusSerializer render json: @status, serializer: REST::StatusSerializer
end end
def context def context
cache_if_unauthenticated!
ancestors_limit = CONTEXT_LIMIT ancestors_limit = CONTEXT_LIMIT
descendants_limit = CONTEXT_LIMIT descendants_limit = CONTEXT_LIMIT
descendants_depth_limit = nil descendants_depth_limit = nil

View file

@ -8,6 +8,7 @@ class Api::V1::TagsController < Api::BaseController
override_rate_limit_headers :follow, family: :follows override_rate_limit_headers :follow, family: :follows
def show def show
cache_if_unauthenticated!
render json: @tag, serializer: REST::TagSerializer render json: @tag, serializer: REST::TagSerializer
end end

View file

@ -5,6 +5,7 @@ class Api::V1::Timelines::PublicController < Api::BaseController
after_action :insert_pagination_headers, unless: -> { @statuses.empty? } after_action :insert_pagination_headers, unless: -> { @statuses.empty? }
def show def show
cache_if_unauthenticated!
@statuses = load_statuses @statuses = load_statuses
render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id) render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id)
end end

View file

@ -5,6 +5,7 @@ class Api::V1::Timelines::TagController < Api::BaseController
after_action :insert_pagination_headers, unless: -> { @statuses.empty? } after_action :insert_pagination_headers, unless: -> { @statuses.empty? }
def show def show
cache_if_unauthenticated!
@statuses = load_statuses @statuses = load_statuses
render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id) render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id)
end end

View file

@ -1,6 +1,8 @@
# frozen_string_literal: true # frozen_string_literal: true
class Api::V1::Trends::LinksController < Api::BaseController class Api::V1::Trends::LinksController < Api::BaseController
vary_by 'Authorization, Accept-Language'
before_action :set_links before_action :set_links
after_action :insert_pagination_headers after_action :insert_pagination_headers
@ -8,6 +10,7 @@ class Api::V1::Trends::LinksController < Api::BaseController
DEFAULT_LINKS_LIMIT = 10 DEFAULT_LINKS_LIMIT = 10
def index def index
cache_if_unauthenticated!
render json: @links, each_serializer: REST::Trends::LinkSerializer render json: @links, each_serializer: REST::Trends::LinkSerializer
end end

View file

@ -1,11 +1,14 @@
# frozen_string_literal: true # frozen_string_literal: true
class Api::V1::Trends::StatusesController < Api::BaseController class Api::V1::Trends::StatusesController < Api::BaseController
vary_by 'Authorization, Accept-Language'
before_action :set_statuses before_action :set_statuses
after_action :insert_pagination_headers after_action :insert_pagination_headers
def index def index
cache_if_unauthenticated!
render json: @statuses, each_serializer: REST::StatusSerializer render json: @statuses, each_serializer: REST::StatusSerializer
end end

View file

@ -8,6 +8,7 @@ class Api::V1::Trends::TagsController < Api::BaseController
DEFAULT_TAGS_LIMIT = 10 DEFAULT_TAGS_LIMIT = 10
def index def index
cache_if_unauthenticated!
render json: @tags, each_serializer: REST::TagSerializer, relationships: TagRelationshipsPresenter.new(@tags, current_user&.account_id) render json: @tags, each_serializer: REST::TagSerializer, relationships: TagRelationshipsPresenter.new(@tags, current_user&.account_id)
end end

View file

@ -2,7 +2,7 @@
class Api::V2::InstancesController < Api::V1::InstancesController class Api::V2::InstancesController < Api::V1::InstancesController
def show def show
expires_in 3.minutes, public: true cache_even_if_authenticated!
render_with_cache json: InstancePresenter.new, serializer: REST::InstanceSerializer, root: 'instance' render_with_cache json: InstancePresenter.new, serializer: REST::InstanceSerializer, root: 'instance'
end end
end end

View file

@ -20,6 +20,7 @@ class ApplicationController < ActionController::Base
helper_method :sso_account_settings helper_method :sso_account_settings
helper_method :whitelist_mode? helper_method :whitelist_mode?
helper_method :body_class_string helper_method :body_class_string
helper_method :skip_csrf_meta_tags?
rescue_from ActionController::ParameterMissing, Paperclip::AdapterRegistry::NoHandlerError, with: :bad_request rescue_from ActionController::ParameterMissing, Paperclip::AdapterRegistry::NoHandlerError, with: :bad_request
rescue_from Mastodon::NotPermittedError, with: :forbidden rescue_from Mastodon::NotPermittedError, with: :forbidden
@ -36,7 +37,7 @@ class ApplicationController < ActionController::Base
service_unavailable service_unavailable
end end
before_action :store_current_location, except: :raise_not_found, unless: :devise_controller? before_action :store_referrer, except: :raise_not_found, if: :devise_controller?
before_action :require_functional!, if: :user_signed_in? before_action :require_functional!, if: :user_signed_in?
before_action :set_cache_control_defaults before_action :set_cache_control_defaults
@ -57,14 +58,25 @@ class ApplicationController < ActionController::Base
!authorized_fetch_mode? !authorized_fetch_mode?
end end
def store_current_location def store_referrer
store_location_for(:user, request.url) unless [:json, :rss].include?(request.format&.to_sym) return if request.referer.blank?
redirect_uri = URI(request.referer)
return if redirect_uri.path.start_with?('/auth')
stored_url = redirect_uri.to_s if redirect_uri.host == request.host && redirect_uri.port == request.port
store_location_for(:user, stored_url)
end end
def require_functional! def require_functional!
redirect_to edit_user_registration_path unless current_user.functional? redirect_to edit_user_registration_path unless current_user.functional?
end end
def skip_csrf_meta_tags?
false
end
def after_sign_out_path_for(_resource_or_scope) def after_sign_out_path_for(_resource_or_scope)
if ENV['OMNIAUTH_ONLY'] == 'true' && ENV['OIDC_ENABLED'] == 'true' if ENV['OMNIAUTH_ONLY'] == 'true' && ENV['OIDC_ENABLED'] == 'true'
'/auth/auth/openid_connect/logout' '/auth/auth/openid_connect/logout'

View file

@ -0,0 +1,13 @@
# frozen_string_literal: true
module ApiCachingConcern
extend ActiveSupport::Concern
def cache_if_unauthenticated!
expires_in(15.seconds, public: true, stale_while_revalidate: 30.seconds, stale_if_error: 1.day) unless user_signed_in?
end
def cache_even_if_authenticated!
expires_in(5.minutes, public: true, stale_while_revalidate: 30.seconds, stale_if_error: 1.day) unless whitelist_mode?
end
end

View file

@ -10,6 +10,10 @@ module WebAppControllerConcern
vary_by 'Accept, Accept-Language, Cookie' vary_by 'Accept, Accept-Language, Cookie'
end end
def skip_csrf_meta_tags?
current_user.nil?
end
def set_app_body_class def set_app_body_class
@body_classes = 'app-body' @body_classes = 'app-body'
end end

View file

@ -1,6 +1,10 @@
# frozen_string_literal: true # frozen_string_literal: true
class ManifestsController < ActionController::Base # rubocop:disable Rails/ApplicationController class ManifestsController < ActionController::Base # rubocop:disable Rails/ApplicationController
# Prevent `active_model_serializer`'s `ActionController::Serialization` from calling `current_user`
# and thus re-issuing session cookies
serialization_scope nil
def show def show
expires_in 3.minutes, public: true expires_in 3.minutes, public: true
render json: InstancePresenter.new, serializer: ManifestSerializer, root: 'instance' render json: InstancePresenter.new, serializer: ManifestSerializer, root: 'instance'

View file

@ -3,7 +3,6 @@
class MediaController < ApplicationController class MediaController < ApplicationController
include Authorization include Authorization
skip_before_action :store_current_location
skip_before_action :require_functional!, unless: :whitelist_mode? skip_before_action :require_functional!, unless: :whitelist_mode?
before_action :authenticate_user!, if: :whitelist_mode? before_action :authenticate_user!, if: :whitelist_mode?

View file

@ -6,7 +6,6 @@ class MediaProxyController < ApplicationController
include Redisable include Redisable
include Lockable include Lockable
skip_before_action :store_current_location
skip_before_action :require_functional! skip_before_action :require_functional!
before_action :authenticate_user!, if: :whitelist_mode? before_action :authenticate_user!, if: :whitelist_mode?

View file

@ -4,6 +4,10 @@ module WellKnown
class NodeInfoController < ActionController::Base # rubocop:disable Rails/ApplicationController class NodeInfoController < ActionController::Base # rubocop:disable Rails/ApplicationController
include CacheConcern include CacheConcern
# Prevent `active_model_serializer`'s `ActionController::Serialization` from calling `current_user`
# and thus re-issuing session cookies
serialization_scope nil
def index def index
expires_in 3.days, public: true expires_in 3.days, public: true
render_with_cache json: {}, serializer: NodeInfo::DiscoverySerializer, adapter: NodeInfo::Adapter, expires_in: 3.days, root: 'nodeinfo' render_with_cache json: {}, serializer: NodeInfo::DiscoverySerializer, adapter: NodeInfo::Adapter, expires_in: 3.days, root: 'nodeinfo'

View file

@ -1180,7 +1180,7 @@ body > [data-popper-placement] {
width: 0; width: 0;
position: absolute; position: absolute;
top: 0; top: 0;
inset-inline-start: 16px + ((46px - 2px) / 2); inset-inline-start: 16px + ((46px - 2px) * 0.5);
&--full { &--full {
top: 0; top: 0;

View file

@ -30,7 +30,7 @@
= stylesheet_pack_tag current_theme, media: 'all', crossorigin: 'anonymous' = stylesheet_pack_tag current_theme, media: 'all', crossorigin: 'anonymous'
= javascript_pack_tag 'common', crossorigin: 'anonymous' = javascript_pack_tag 'common', crossorigin: 'anonymous'
= javascript_pack_tag "locale_#{I18n.locale}", crossorigin: 'anonymous' = javascript_pack_tag "locale_#{I18n.locale}", crossorigin: 'anonymous'
= csrf_meta_tags = csrf_meta_tags unless skip_csrf_meta_tags?
%meta{ name: 'style-nonce', content: request.content_security_policy_nonce } %meta{ name: 'style-nonce', content: request.content_security_policy_nonce }
= stylesheet_link_tag '/inert.css', skip_pipeline: true, media: 'all', id: 'inert-style' = stylesheet_link_tag '/inert.css', skip_pipeline: true, media: 'all', id: 'inert-style'

View file

@ -132,25 +132,6 @@ describe ApplicationController, type: :controller do
include_examples 'respond_with_error', 422 include_examples 'respond_with_error', 422
end end
describe 'before_action :store_current_location' do
it 'stores location for user if it is not devise controller' do
routes.draw { get 'success' => 'anonymous#success' }
get 'success'
expect(controller.stored_location_for(:user)).to eq '/success'
end
context do
controller Devise::SessionsController do
end
it 'does not store location for user if it is devise controller' do
@request.env['devise.mapping'] = Devise.mappings[:user]
get 'create'
expect(controller.stored_location_for(:user)).to be_nil
end
end
end
describe 'before_action :check_suspension' do describe 'before_action :check_suspension' do
before do before do
routes.draw { get 'success' => 'anonymous#success' } routes.draw { get 'success' => 'anonymous#success' }

View file

@ -0,0 +1,44 @@
# frozen_string_literal: true
require 'rails_helper'
context 'when visited anonymously' do
around do |example|
old = ActionController::Base.allow_forgery_protection
ActionController::Base.allow_forgery_protection = true
example.run
ActionController::Base.allow_forgery_protection = old
end
describe 'account pages' do
it 'do not set cookies' do
alice = Fabricate(:account, username: 'alice', display_name: 'Alice')
_status = Fabricate(:status, account: alice, text: 'Hello World')
get '/@alice'
expect(response.cookies).to be_empty
end
end
describe 'status pages' do
it 'do not set cookies' do
alice = Fabricate(:account, username: 'alice', display_name: 'Alice')
status = Fabricate(:status, account: alice, text: 'Hello World')
get short_account_status_url(alice, status)
expect(response.cookies).to be_empty
end
end
describe 'the /about page' do
it 'does not set cookies' do
get '/about'
expect(response.cookies).to be_empty
end
end
end