weeeeeeeee

This commit is contained in:
tobi
2024-12-15 17:19:57 +01:00
parent 915034f6a6
commit 0ba6ab88a9
2780 changed files with 345 additions and 142681 deletions

View File

@@ -1,217 +0,0 @@
# frozen_string_literal: true
require_relative 'boot'
require 'rails'
require 'active_record/railtie'
# require 'active_storage/engine'
require 'action_controller/railtie'
require 'action_view/railtie'
require 'action_mailer/railtie'
require 'active_job/railtie'
# require 'action_cable/engine'
# require 'action_mailbox/engine'
# require 'action_text/engine'
# require 'rails/test_unit/railtie'
require 'sprockets/railtie'
# Used to be implicitly required in action_mailbox/engine
require 'mail'
# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)
require_relative '../lib/exceptions'
require_relative '../lib/sanitize_ext/sanitize_config'
require_relative '../lib/redis/namespace_extensions'
require_relative '../lib/paperclip/url_generator_extensions'
require_relative '../lib/paperclip/attachment_extensions'
require_relative '../lib/paperclip/lazy_thumbnail'
require_relative '../lib/paperclip/gif_transcoder'
require_relative '../lib/paperclip/media_type_spoof_detector_extensions'
require_relative '../lib/paperclip/transcoder'
require_relative '../lib/paperclip/type_corrector'
require_relative '../lib/paperclip/response_with_limit_adapter'
require_relative '../lib/terrapin/multi_pipe_extensions'
require_relative '../lib/mastodon/snowflake'
require_relative '../lib/mastodon/version'
require_relative '../lib/mastodon/rack_middleware'
require_relative '../lib/public_file_server_middleware'
require_relative '../lib/devise/two_factor_ldap_authenticatable'
require_relative '../lib/devise/two_factor_pam_authenticatable'
require_relative '../lib/chewy/settings_extensions'
require_relative '../lib/chewy/index_extensions'
require_relative '../lib/chewy/strategy/mastodon'
require_relative '../lib/chewy/strategy/bypass_with_warning'
require_relative '../lib/webpacker/manifest_extensions'
require_relative '../lib/webpacker/helper_extensions'
require_relative '../lib/rails/engine_extensions'
require_relative '../lib/active_record/database_tasks_extensions'
require_relative '../lib/active_record/batches'
require_relative '../lib/simple_navigation/item_extensions'
require_relative '../lib/http_extensions'
Dotenv::Railtie.load
Bundler.require(:pam_authentication) if ENV['PAM_ENABLED'] == 'true'
require_relative '../lib/mastodon/redis_config'
module Mastodon
class Application < Rails::Application
# Initialize configuration defaults for originally generated Rails version.
config.load_defaults 7.0
# TODO: Release a version which uses the 7.0 defaults as specified above,
# but preserves the 6.1 cache format as set below. In a subsequent change,
# remove this line setting to 6.1 cache format, and then release another version.
# https://guides.rubyonrails.org/upgrading_ruby_on_rails.html#new-activesupport-cache-serialization-format
# https://github.com/mastodon/mastodon/pull/24241#discussion_r1162890242
config.active_support.cache_format_version = 6.1
config.add_autoload_paths_to_load_path = false
# Settings in config/environments/* take precedence over those specified here.
# Application configuration should go into files in config/initializers
# -- all .rb files in that directory are automatically loaded.
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
# config.time_zone = 'Central Time (US & Canada)'
# All translations from config/locales/*.rb,yml are auto loaded.
# config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
config.i18n.available_locales = [
:af,
:an,
:ar,
:ast,
:be,
:bg,
:bn,
:br,
:bs,
:ca,
:ckb,
:co,
:cs,
:cy,
:da,
:de,
:el,
:en,
:'en-GB',
:eo,
:es,
:'es-AR',
:'es-MX',
:et,
:eu,
:fa,
:fi,
:fo,
:fr,
:'fr-QC',
:fy,
:ga,
:gd,
:gl,
:he,
:hi,
:hr,
:hu,
:hy,
:id,
:ig,
:io,
:is,
:it,
:ja,
:ka,
:kab,
:kk,
:kn,
:ko,
:ku,
:kw,
:la,
:lt,
:lv,
:mk,
:ml,
:mr,
:ms,
:my,
:nl,
:nn,
:no,
:oc,
:pa,
:pl,
:'pt-BR',
:'pt-PT',
:ro,
:ru,
:sa,
:sc,
:sco,
:si,
:sk,
:sl,
:sq,
:sr,
:'sr-Latn',
:sv,
:szl,
:ta,
:te,
:th,
:tr,
:tt,
:ug,
:uk,
:ur,
:vi,
:zgh,
:'zh-CN',
:'zh-HK',
:'zh-TW',
]
config.i18n.default_locale = begin
custom_default_locale = ENV['DEFAULT_LOCALE']&.to_sym
if config.i18n.available_locales.include?(custom_default_locale)
custom_default_locale
else
:en
end
end
# config.paths.add File.join('app', 'api'), glob: File.join('**', '*.rb')
# config.autoload_paths += Dir[Rails.root.join('app', 'api', '*')]
config.active_job.queue_adapter = :sidekiq
config.action_mailer.deliver_later_queue_name = 'mailers'
config.action_mailer.preview_path = Rails.root.join('spec', 'mailers', 'previews')
# We use our own middleware for this
config.public_file_server.enabled = false
config.middleware.use PublicFileServerMiddleware if Rails.env.development? || Rails.env.test? || ENV['RAILS_SERVE_STATIC_FILES'] == 'true'
config.middleware.use Rack::Attack
config.middleware.use Mastodon::RackMiddleware
config.to_prepare do
Doorkeeper::AuthorizationsController.layout 'modal'
Doorkeeper::AuthorizedApplicationsController.layout 'admin'
Doorkeeper::Application.include ApplicationExtension
Doorkeeper::AccessToken.include AccessTokenExtension
Devise::FailureApp.include AbstractController::Callbacks
Devise::FailureApp.include Localized
end
end
end

View File

@@ -1,11 +0,0 @@
# frozen_string_literal: true
unless ENV.key?('RAILS_ENV')
STDERR.puts 'ERROR: Missing RAILS_ENV environment variable, please set it to "production", "development", or "test".'
exit 1
end
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
require 'bundler/setup' # Set up gems listed in the Gemfile.
require 'bootsnap/setup' # Speed up boot time by caching expensive operations.

View File

@@ -1,35 +0,0 @@
# frozen_string_literal: true
lock '3.17.2'
set :repo_url, ENV.fetch('REPO', 'https://github.com/mastodon/mastodon.git')
set :branch, ENV.fetch('BRANCH', 'main')
set :application, 'mastodon'
set :rbenv_type, :user
set :rbenv_ruby, File.read('.ruby-version').strip
set :migration_role, :app
append :linked_files, '.env.production', 'public/robots.txt'
append :linked_dirs, 'vendor/bundle', 'node_modules', 'public/system'
SYSTEMD_SERVICES = %i[sidekiq streaming web].freeze
SERVICE_ACTIONS = %i[reload restart status].freeze
namespace :systemd do
SYSTEMD_SERVICES.each do |service|
SERVICE_ACTIONS.each do |action|
desc "Perform a #{action} on #{service} service"
task "#{service}:#{action}".to_sym do
on roles(:app) do
# runs e.g. "sudo restart mastodon-sidekiq.service"
sudo :systemctl, action, "#{fetch(:application)}-#{service}.service"
end
end
end
end
end
after 'deploy:publishing', 'systemd:web:reload'
after 'deploy:publishing', 'systemd:sidekiq:restart'
after 'deploy:publishing', 'systemd:streaming:restart'

View File

@@ -1,9 +0,0 @@
# frozen_string_literal: true
# Load the Rails application.
require_relative 'application'
# Initialize the Rails application.
Rails.application.initialize!
ActiveRecord::SchemaDumper.ignore_tables = ['deprecated_preview_cards']

View File

@@ -1,103 +0,0 @@
# frozen_string_literal: true
require 'active_support/core_ext/integer/time'
Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.
# In the development environment your application's code is reloaded any time
# it changes. This slows down response time but is perfect for development
# since you don't have to restart the web server when you make code changes.
config.cache_classes = false
# Do not eager load code on boot.
config.eager_load = false
# Show full error reports.
config.consider_all_requests_local = true
# Enable server timing
config.server_timing = true
# Enable/disable caching. By default caching is disabled.
# Run rails dev:cache to toggle caching.
if Rails.root.join('tmp', 'caching-dev.txt').exist?
config.action_controller.perform_caching = true
config.action_controller.enable_fragment_cache_logging = true
config.cache_store = :redis_cache_store, REDIS_CACHE_PARAMS
config.public_file_server.headers = {
'Cache-Control' => "public, max-age=#{2.days.to_i}",
}
else
config.action_controller.perform_caching = false
config.cache_store = :null_store
end
config.action_controller.forgery_protection_origin_check = ENV['DISABLE_FORGERY_REQUEST_PROTECTION'].nil?
ActiveSupport::Logger.new(STDOUT).tap do |logger|
logger.formatter = config.log_formatter
config.logger = ActiveSupport::TaggedLogging.new(logger)
end
# Generate random VAPID keys
Webpush.generate_key.tap do |vapid_key|
config.x.vapid_private_key = vapid_key.private_key
config.x.vapid_public_key = vapid_key.public_key
end
# Don't care if the mailer can't send.
config.action_mailer.raise_delivery_errors = false
config.action_mailer.perform_caching = false
# Print deprecation notices to the Rails logger.
config.active_support.deprecation = :log
# Raise exceptions for disallowed deprecations.
config.active_support.disallowed_deprecation = :raise
# Tell Active Support which deprecation messages to disallow.
config.active_support.disallowed_deprecation_warnings = []
# Raise an error on page load if there are pending migrations.
config.active_record.migration_error = :page_load
# Highlight code that triggered database queries in logs.
config.active_record.verbose_query_logs = true
# Debug mode disables concatenation and preprocessing of assets.
config.assets.debug = true
# Suppress logger output for asset requests.
config.assets.quiet = true
# Adds additional error checking when serving assets at runtime.
# Checks for improperly declared sprockets dependencies.
# Raises helpful error messages.
config.assets.raise_runtime_errors = true
# Raises error for missing translations.
# config.i18n.raise_on_missing_translations = true
# Annotate rendered view with file names.
# config.action_view.annotate_rendered_view_with_filenames = true
# Uncomment if you wish to allow Action Cable access from any origin.
# config.action_cable.disable_request_forgery_protection = true
config.action_mailer.default_options = { from: 'notifications@localhost' }
# If using a Heroku, Vagrant or generic remote development environment,
# use letter_opener_web, accessible at /letter_opener.
# Otherwise, use letter_opener, which launches a browser window to view sent mail.
config.action_mailer.delivery_method = (ENV['HEROKU'] || ENV['VAGRANT'] || ENV['REMOTE_DEV']) ? :letter_opener_web : :letter_opener
# We provide a default secret for the development environment here.
# This value should not be used in production environments!
config.x.otp_secret = ENV.fetch('OTP_SECRET', '1fc2b87989afa6351912abeebe31ffc5c476ead9bf8b3d74cbc4a302c7b69a45b40b1bbef3506ddad73e942e15ed5ca4b402bf9a66423626051104f4b5f05109')
end
Redis.raise_deprecations = true

View File

@@ -1,160 +0,0 @@
# frozen_string_literal: true
require "active_support/core_ext/integer/time"
Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.
# Code is not reloaded between requests.
config.cache_classes = true
# Eager load code on boot. This eager loads most of Rails and
# your application in memory, allowing both threaded web servers
# and those relying on copy on write to perform better.
# Rake tasks automatically ignore this option for performance.
config.eager_load = true
# Full error reports are disabled and caching is turned on.
config.consider_all_requests_local = false
config.action_controller.perform_caching = true
config.action_controller.asset_host = ENV['CDN_HOST'] if ENV['CDN_HOST'].present?
# Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"]
# or in config/master.key. This key is used to decrypt credentials (and other encrypted files).
# config.require_master_key = true
# Compress CSS using a preprocessor.
# config.assets.css_compressor = :sass
# Do not fallback to assets pipeline if a precompiled asset is missed.
config.assets.compile = false
# Enable serving of images, stylesheets, and JavaScripts from an asset server.
# config.asset_host = "http://assets.example.com"
# Specifies the header that your server uses for sending files.
config.action_dispatch.x_sendfile_header = ENV['SENDFILE_HEADER'] if ENV['SENDFILE_HEADER'].present?
# config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache
# config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX
# Allow to specify public IP of reverse proxy if it's needed
config.action_dispatch.trusted_proxies = ENV['TRUSTED_PROXY_IP'].split(/(?:\s*,\s*|\s+)/).map { |item| IPAddr.new(item) } if ENV['TRUSTED_PROXY_IP'].present?
# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
config.force_ssl = true
config.ssl_options = {
redirect: {
exclude: ->request { request.path.start_with?('/health') || request.headers["Host"].end_with?('.onion') || request.headers["Host"].end_with?('.i2p') }
}
}
# Include generic and useful information about system operation, but avoid logging too much
# information to avoid inadvertent exposure of personally identifiable information (PII).
# Use the lowest log level to ensure availability of diagnostic information
# when problems arise.
config.log_level = ENV.fetch('RAILS_LOG_LEVEL', 'info').to_sym
# Prepend all log lines with the following tags.
config.log_tags = [:request_id]
# Use a different cache store in production.
config.cache_store = :redis_cache_store, REDIS_CACHE_PARAMS
# Use a real queuing backend for Active Job (and separate queues per environment).
# config.active_job.queue_adapter = :resque
# config.active_job.queue_name_prefix = "mastodon_production"
config.action_mailer.perform_caching = false
# Ignore bad email addresses and do not raise email delivery errors.
# Set this to true and configure the email server for immediate delivery to raise delivery errors.
# config.action_mailer.raise_delivery_errors = false
# Enable locale fallbacks for I18n (makes lookups for any locale fall back to
# English when a translation cannot be found).
config.i18n.fallbacks = [:en]
# Send deprecation notices to registered listeners.
config.active_support.deprecation = :notify
# Use default logging formatter so that PID and timestamp are not suppressed.
config.log_formatter = ::Logger::Formatter.new
# Better log formatting
config.lograge.enabled = true
config.lograge.custom_payload do |controller|
if controller.respond_to?(:signed_request?) && controller.signed_request?
{ key: controller.signature_key_id }
end
end
# Use a different logger for distributed setups.
# require "syslog/logger"
# config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name")
ActiveSupport::Logger.new(STDOUT).tap do |logger|
logger.formatter = config.log_formatter
config.logger = ActiveSupport::TaggedLogging.new(logger)
end
# Do not dump schema after migrations.
config.active_record.dump_schema_after_migration = false
config.action_mailer.perform_caching = false
# E-mails
outgoing_email_address = ENV.fetch('SMTP_FROM_ADDRESS', 'notifications@localhost')
outgoing_email_domain = Mail::Address.new(outgoing_email_address).domain
config.action_mailer.default_options = {
from: outgoing_email_address,
message_id: -> { "<#{Mail.random_tag}@#{outgoing_email_domain}>" },
}
config.action_mailer.default_options[:reply_to] = ENV['SMTP_REPLY_TO'] if ENV['SMTP_REPLY_TO'].present?
config.action_mailer.default_options[:return_path] = ENV['SMTP_RETURN_PATH'] if ENV['SMTP_RETURN_PATH'].present?
enable_starttls = nil
enable_starttls_auto = nil
case ENV['SMTP_ENABLE_STARTTLS']
when 'always'
enable_starttls = true
when 'never'
enable_starttls = false
when 'auto'
enable_starttls_auto = true
else
enable_starttls_auto = ENV['SMTP_ENABLE_STARTTLS_AUTO'] != 'false'
end
config.action_mailer.smtp_settings = {
port: ENV['SMTP_PORT'],
address: ENV['SMTP_SERVER'],
user_name: ENV['SMTP_LOGIN'].presence,
password: ENV['SMTP_PASSWORD'].presence,
domain: ENV['SMTP_DOMAIN'] || ENV['LOCAL_DOMAIN'],
authentication: ENV['SMTP_AUTH_METHOD'] == 'none' ? nil : ENV['SMTP_AUTH_METHOD'] || :plain,
ca_file: ENV['SMTP_CA_FILE'].presence || '/etc/ssl/certs/ca-certificates.crt',
openssl_verify_mode: ENV['SMTP_OPENSSL_VERIFY_MODE'],
enable_starttls: enable_starttls,
enable_starttls_auto: enable_starttls_auto,
tls: ENV['SMTP_TLS'].presence && ENV['SMTP_TLS'] == 'true',
ssl: ENV['SMTP_SSL'].presence && ENV['SMTP_SSL'] == 'true',
read_timeout: 20,
}
config.action_mailer.delivery_method = ENV.fetch('SMTP_DELIVERY_METHOD', 'smtp').to_sym
config.action_dispatch.default_headers = {
'Server' => 'Mastodon',
'X-Frame-Options' => 'DENY',
'X-Content-Type-Options' => 'nosniff',
'X-XSS-Protection' => '0',
'X-Clacks-Overhead' => 'GNU Natalie Nguyen',
'Referrer-Policy' => 'same-origin',
}
config.x.otp_secret = ENV.fetch('OTP_SECRET')
end

View File

@@ -1,94 +0,0 @@
# frozen_string_literal: true
require 'active_support/core_ext/integer/time'
# The test environment is used exclusively to run your application's
# test suite. You never need to work with it otherwise. Remember that
# your test database is "scratch space" for the test suite and is wiped
# and recreated between test runs. Don't rely on the data there!
Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.
# Turn false under Spring and add config.action_view.cache_template_loading = true.
config.cache_classes = true
# Eager loading loads your whole application. When running a single test locally,
# this probably isn't necessary. It's a good idea to do in a continuous integration
# system, or in some way before deploying your code.
config.eager_load = ENV['CI'].present?
config.assets_digest = false
# Show full error reports and disable caching.
config.consider_all_requests_local = true
config.action_controller.perform_caching = false
config.cache_store = :memory_store
# Raise exceptions instead of rendering exception templates.
config.action_dispatch.show_exceptions = false
# Disable request forgery protection in test environment.
config.action_controller.allow_forgery_protection = false
config.action_mailer.perform_caching = false
config.action_mailer.default_options = { from: 'notifications@localhost' }
# Tell Action Mailer not to deliver emails to the real world.
# The :test delivery method accumulates sent emails in the
# ActionMailer::Base.deliveries array.
config.action_mailer.delivery_method = :test
# Print deprecation notices to the stderr.
config.active_support.deprecation = :stderr
config.x.otp_secret = '100c7faeef00caa29242f6b04156742bf76065771fd4117990c4282b8748ff3d99f8fdae97c982ab5bd2e6756a159121377cce4421f4a8ecd2d67bd7749a3fb4'
# Generate random VAPID keys
vapid_key = Webpush.generate_key
config.x.vapid_private_key = vapid_key.private_key
config.x.vapid_public_key = vapid_key.public_key
# Raise exceptions when a reorder occurs in in_batches
config.active_record.error_on_ignored_order = true
# Raise exceptions for disallowed deprecations.
config.active_support.disallowed_deprecation = :raise
config.i18n.default_locale = :en
config.i18n.fallbacks = true
config.to_prepare do
# Force Status to always be SHAPE_TOO_COMPLEX
# Ref: https://github.com/mastodon/mastodon/issues/23644
10.times { |i| Status.allocate.instance_variable_set(:"@ivar_#{i}", nil) }
end
# Tell Active Support which deprecation messages to disallow.
config.active_support.disallowed_deprecation_warnings = []
# Raises error for missing translations.
# config.i18n.raise_on_missing_translations = true
# Annotate rendered view with file names.
# config.action_view.annotate_rendered_view_with_filenames = true
end
Paperclip::Attachment.default_options[:path] = Rails.root.join('spec', 'test_files', ':class', ':id_partition', ':style.:extension')
# set fake_data for pam, don't do real calls, just use fake data
if ENV['PAM_ENABLED'] == 'true'
Rpam2.fake_data =
{
usernames: Set['pam_user1', 'pam_user2'],
servicenames: Set['pam_test', 'pam_test_controlled'],
password: '123456',
env: { email: 'pam@example.com' }
}
end
# Catch serialization warnings early
Sidekiq.strict_args!
Redis.raise_deprecations = true

View File

@@ -1,82 +0,0 @@
# i18n-tasks finds and manages missing and unused translations: https://github.com/glebm/i18n-tasks
# The "main" locale.
base_locale: en
data:
read:
- config/locales-glitch/%{locale}.yml
- config/locales-glitch/*.%{locale}.yml
write:
- [
'{devise, simple_form, doorkeeper}.*',
'config/locales-glitch/\1.%{locale}.yml',
]
- config/locales-glitch/%{locale}.yml
external:
- config/locales/%{locale}.yml
- config/locales/**/*.%{locale}.yml
yaml:
write:
line_width: -1
search:
paths:
- app/
- config/navigation.rb
relative_roots:
- app/controllers
- app/helpers
- app/mailers
- app/views
exclude:
- app/assets/images
- app/assets/fonts
- app/assets/videos
ignore_missing:
- 'activemodel.errors.*'
- 'activerecord.attributes.*'
- 'activerecord.errors.*'
- '{pagination,doorkeeper}.*'
- '{date,datetime,time,number}.*'
- 'errors.messages.*'
- 'activerecord.errors.models.doorkeeper/*'
- 'sessions.{browsers,platforms}.*'
- 'application_mailer.salutation'
- 'errors.500'
- 'auth.providers.*'
ignore_unused:
- 'activemodel.errors.*'
- 'activerecord.attributes.*'
- 'activerecord.errors.*'
- '{devise,pagination,doorkeeper}.*'
- '{date,datetime,time,number}.*'
- 'simple_form.{yes,no,recommended,not_recommended,overridden,glitch_only}'
- 'simple_form.{placeholders,hints,labels}.*'
- 'simple_form.{error_notification,required}.:'
- 'errors.messages.*'
- 'activerecord.errors.models.doorkeeper/*'
- 'errors.429'
- 'admin.accounts.roles.*'
- 'admin.action_logs.actions.*'
- 'admin.reports.summary.action_preambles.*'
- 'admin.reports.summary.actions.*'
- 'admin_mailer.new_appeal.actions.*'
- 'statuses.attached.*'
- 'themes.*'
- 'move_handler.carry_{mutes,blocks}_over_text'
- 'admin_mailer.*.subject'
- 'notification_mailer.*'
- 'imports.overwrite_preambles.{following,blocking,muting,domain_blocking,bookmarks,lists}_html'
- 'imports.preambles.{following,blocking,muting,domain_blocking,bookmarks,lists}_html'
- 'mail_subscriptions.unsubscribe.emails.*'
- 'preferences.other' # some locales are missing other keys, therefore leading i18n-tasks to detect `preferences` as plural and not finding use
ignore_inconsistent_interpolations:
- '*.one'

View File

@@ -1,27 +0,0 @@
<policymap>
<!-- Set some basic system resource limits -->
<policy domain="resource" name="time" value="60" />
<policy domain="module" rights="none" pattern="URL" />
<policy domain="filter" rights="none" pattern="*" />
<!--
Ideally, we would restrict ImageMagick to only accessing its own
disk-backed pixel cache as well as Mastodon-created Tempfiles.
However, those paths depend on the operating system and environment
variables, so they can only be known at runtime.
Furthermore, those paths are not necessarily shared across Mastodon
processes, so even creating a policy.xml at runtime is impractical.
For the time being, only disable indirect reads.
-->
<policy domain="path" rights="none" pattern="@*" />
<!-- Disallow any coder by default, and only enable ones required by Mastodon -->
<policy domain="coder" rights="none" pattern="*" />
<policy domain="coder" rights="read | write" pattern="{JPEG,PNG,GIF,WEBP,HEIC,AVIF}" />
<policy domain="coder" rights="write" pattern="{HISTOGRAM,RGB,INFO}" />
</policymap>

View File

@@ -1,56 +0,0 @@
# frozen_string_literal: true
# Some migrations have been present in glitch-soc for a long time and have then
# been merged in upstream Mastodon, under a different version number.
#
# This puts us in an uneasy situation in which if we remove upstream's
# migration file, people migrating from upstream will end up having a conflict
# with their already-ran migration.
#
# On the other hand, if we keep upstream's migration and remove our own,
# any current glitch-soc user will have a conflict during migration.
#
# For lack of a better solution, as those migrations are indeed identical,
# we decided monkey-patching Rails' Migrator to completely ignore the duplicate,
# keeping only the one that has run, or an arbitrary one.
ALLOWED_DUPLICATES = [2018_04_10_220657, 2018_08_31_171112].freeze
module ActiveRecord
class Migrator
def self.new(direction, migrations, schema_migration, target_version = nil)
migrated = Set.new(Base.connection.migration_context.get_all_versions)
migrations.group_by(&:name).each do |_name, duplicates|
next unless duplicates.length > 1 && duplicates.all? { |m| ALLOWED_DUPLICATES.include?(m.version) }
# We have a set of allowed duplicates. Keep the migrated one, if any.
non_migrated = duplicates.reject { |m| migrated.include?(m.version.to_i) }
migrations = begin
if duplicates.length == non_migrated.length || non_migrated.empty?
# There weren't any migrated one, so we have to pick one “canonical” migration
migrations - duplicates[1..]
else
# Just reject every duplicate which hasn't been migrated yet
migrations - non_migrated
end
end
end
super(direction, migrations, schema_migration, target_version)
end
end
class MigrationContext
def needs_migration?
# A set of duplicated migrations is considered migrated if at least one of
# them is migrated.
migrated = get_all_versions
migrations.group_by(&:name).each do |_name, duplicates|
return true unless duplicates.any? { |m| migrated.include?(m.version.to_i) }
end
false
end
end
end

View File

@@ -1,17 +0,0 @@
# frozen_string_literal: true
# Post deployment migrations are included by default. This file must be loaded
# before other initializers as Rails may otherwise memoize a list of migrations
# excluding the post deployment migrations.
unless ENV['SKIP_POST_DEPLOYMENT_MIGRATIONS']
Rails.application.config.paths['db'].each do |db_path|
path = Rails.root.join(db_path, 'post_migrate').to_s
Rails.application.config.paths['db/migrate'] << path
# Rails memoizes migrations at certain points where it won't read the above
# path just yet. As such we must also update the following list of paths.
ActiveRecord::Migrator.migrations_paths << path
end
end

View File

@@ -1,36 +0,0 @@
# frozen_string_literal: true
port = ENV.fetch('PORT') { 3000 }
host = ENV.fetch('LOCAL_DOMAIN') { "localhost:#{port}" }
web_host = ENV.fetch('WEB_DOMAIN') { host }
alternate_domains = ENV.fetch('ALTERNATE_DOMAINS') { '' }.split(/\s*,\s*/)
Rails.application.configure do
https = Rails.env.production? || ENV['LOCAL_HTTPS'] == 'true'
config.x.local_domain = host
config.x.web_domain = web_host
config.x.use_https = https
config.x.use_s3 = ENV['S3_ENABLED'] == 'true'
config.x.use_swift = ENV['SWIFT_ENABLED'] == 'true'
config.x.alternate_domains = alternate_domains
config.action_mailer.default_url_options = { host: web_host, protocol: https ? 'https://' : 'http://', trailing_slash: false }
config.x.streaming_api_base_url = ENV.fetch('STREAMING_API_BASE_URL') do
if Rails.env.production?
"ws#{https ? 's' : ''}://#{web_host}"
else
"ws://#{ENV['REMOTE_DEV'] == 'true' ? host.split(':').first : 'localhost'}:4000"
end
end
unless Rails.env.test?
config.hosts << host if host.present?
config.hosts << web_host if web_host.present?
config.hosts.concat(alternate_domains) if alternate_domains.present?
config.host_authorization = { exclude: ->(request) { request.path == '/health' } }
end
end

View File

@@ -1,7 +0,0 @@
# frozen_string_literal: true
Rails.application.configure do
config.x.limited_federation_mode = (ENV['LIMITED_FEDERATION_MODE'] || ENV['WHITELIST_MODE']) == 'true'
warn 'WARN: The environment variable WHITELIST_MODE has been replaced with LIMITED_FEDERATION_MODE, you should rename this environment variable in your configuration.' if ENV.key?('WHITELIST_MODE')
end

View File

@@ -1,110 +0,0 @@
# frozen_string_literal: true
# OmniAuth providers need to be initialized before the CSP initializer
# in `config/initializers/content_security_policy.rb`, which sets the
# `form-action` directive based on them.
Rails.application.config.middleware.use OmniAuth::Builder do
# Vanilla omniauth strategies
end
Devise.setup do |config|
# Devise omniauth strategies
options = {}
# CAS strategy
if ENV['CAS_ENABLED'] == 'true'
cas_options = {}
cas_options[:display_name] = ENV['CAS_DISPLAY_NAME']
cas_options[:url] = ENV['CAS_URL'] if ENV['CAS_URL']
cas_options[:host] = ENV['CAS_HOST'] if ENV['CAS_HOST']
cas_options[:port] = ENV['CAS_PORT'] if ENV['CAS_PORT']
cas_options[:ssl] = ENV['CAS_SSL'] == 'true' if ENV['CAS_SSL']
cas_options[:service_validate_url] = ENV['CAS_VALIDATE_URL'] if ENV['CAS_VALIDATE_URL']
cas_options[:callback_url] = ENV['CAS_CALLBACK_URL'] if ENV['CAS_CALLBACK_URL']
cas_options[:logout_url] = ENV['CAS_LOGOUT_URL'] if ENV['CAS_LOGOUT_URL']
cas_options[:login_url] = ENV['CAS_LOGIN_URL'] if ENV['CAS_LOGIN_URL']
cas_options[:uid_field] = ENV['CAS_UID_FIELD'] || 'user' if ENV['CAS_UID_FIELD']
cas_options[:ca_path] = ENV['CAS_CA_PATH'] if ENV['CAS_CA_PATH']
cas_options[:disable_ssl_verification] = ENV['CAS_DISABLE_SSL_VERIFICATION'] == 'true'
cas_options[:uid_key] = ENV['CAS_UID_KEY'] || 'user'
cas_options[:name_key] = ENV['CAS_NAME_KEY'] || 'name'
cas_options[:email_key] = ENV['CAS_EMAIL_KEY'] || 'email'
cas_options[:nickname_key] = ENV['CAS_NICKNAME_KEY'] || 'nickname'
cas_options[:first_name_key] = ENV['CAS_FIRST_NAME_KEY'] || 'firstname'
cas_options[:last_name_key] = ENV['CAS_LAST_NAME_KEY'] || 'lastname'
cas_options[:location_key] = ENV['CAS_LOCATION_KEY'] || 'location'
cas_options[:image_key] = ENV['CAS_IMAGE_KEY'] || 'image'
cas_options[:phone_key] = ENV['CAS_PHONE_KEY'] || 'phone'
cas_options[:security] = {}
cas_options[:security][:assume_email_is_verified] = ENV['CAS_SECURITY_ASSUME_EMAIL_IS_VERIFIED'] == 'true'
config.omniauth :cas, cas_options
end
# SAML strategy
if ENV['SAML_ENABLED'] == 'true'
saml_options = {}
saml_options[:display_name] = ENV['SAML_DISPLAY_NAME']
saml_options[:assertion_consumer_service_url] = ENV['SAML_ACS_URL'] if ENV['SAML_ACS_URL']
saml_options[:issuer] = ENV['SAML_ISSUER'] if ENV['SAML_ISSUER']
saml_options[:idp_sso_target_url] = ENV['SAML_IDP_SSO_TARGET_URL'] if ENV['SAML_IDP_SSO_TARGET_URL']
saml_options[:idp_sso_target_url_runtime_params] = ENV['SAML_IDP_SSO_TARGET_PARAMS'] if ENV['SAML_IDP_SSO_TARGET_PARAMS'] # FIXME: Should be parsable Hash
saml_options[:idp_cert] = ENV['SAML_IDP_CERT'] if ENV['SAML_IDP_CERT']
saml_options[:idp_cert_fingerprint] = ENV['SAML_IDP_CERT_FINGERPRINT'] if ENV['SAML_IDP_CERT_FINGERPRINT']
saml_options[:idp_cert_fingerprint_validator] = ENV['SAML_IDP_CERT_FINGERPRINT_VALIDATOR'] if ENV['SAML_IDP_CERT_FINGERPRINT_VALIDATOR'] # FIXME: Should be Lambda { |fingerprint| }
saml_options[:name_identifier_format] = ENV['SAML_NAME_IDENTIFIER_FORMAT'] if ENV['SAML_NAME_IDENTIFIER_FORMAT']
saml_options[:request_attributes] = {}
saml_options[:certificate] = ENV['SAML_CERT'] if ENV['SAML_CERT']
saml_options[:private_key] = ENV['SAML_PRIVATE_KEY'] if ENV['SAML_PRIVATE_KEY']
saml_options[:security] = {}
saml_options[:security][:want_assertions_signed] = ENV['SAML_SECURITY_WANT_ASSERTION_SIGNED'] == 'true'
saml_options[:security][:want_assertions_encrypted] = ENV['SAML_SECURITY_WANT_ASSERTION_ENCRYPTED'] == 'true'
saml_options[:security][:assume_email_is_verified] = ENV['SAML_SECURITY_ASSUME_EMAIL_IS_VERIFIED'] == 'true'
saml_options[:attribute_statements] = {}
saml_options[:attribute_statements][:uid] = [ENV['SAML_ATTRIBUTES_STATEMENTS_UID']] if ENV['SAML_ATTRIBUTES_STATEMENTS_UID']
saml_options[:attribute_statements][:email] = [ENV['SAML_ATTRIBUTES_STATEMENTS_EMAIL']] if ENV['SAML_ATTRIBUTES_STATEMENTS_EMAIL']
saml_options[:attribute_statements][:full_name] = [ENV['SAML_ATTRIBUTES_STATEMENTS_FULL_NAME']] if ENV['SAML_ATTRIBUTES_STATEMENTS_FULL_NAME']
saml_options[:attribute_statements][:first_name] = [ENV['SAML_ATTRIBUTES_STATEMENTS_FIRST_NAME']] if ENV['SAML_ATTRIBUTES_STATEMENTS_FIRST_NAME']
saml_options[:attribute_statements][:last_name] = [ENV['SAML_ATTRIBUTES_STATEMENTS_LAST_NAME']] if ENV['SAML_ATTRIBUTES_STATEMENTS_LAST_NAME']
saml_options[:attribute_statements][:verified] = [ENV['SAML_ATTRIBUTES_STATEMENTS_VERIFIED']] if ENV['SAML_ATTRIBUTES_STATEMENTS_VERIFIED']
saml_options[:attribute_statements][:verified_email] = [ENV['SAML_ATTRIBUTES_STATEMENTS_VERIFIED_EMAIL']] if ENV['SAML_ATTRIBUTES_STATEMENTS_VERIFIED_EMAIL']
saml_options[:uid_attribute] = ENV['SAML_UID_ATTRIBUTE'] if ENV['SAML_UID_ATTRIBUTE']
saml_options[:allowed_clock_drift] = ENV['SAML_ALLOWED_CLOCK_DRIFT'] if ENV['SAML_ALLOWED_CLOCK_DRIFT']
config.omniauth :saml, saml_options
end
# OpenID Connect Strategy
if ENV['OIDC_ENABLED'] == 'true'
oidc_options = {}
oidc_options[:display_name] = ENV['OIDC_DISPLAY_NAME'] # OPTIONAL
oidc_options[:issuer] = ENV['OIDC_ISSUER'] if ENV['OIDC_ISSUER'] # NEED
oidc_options[:discovery] = ENV['OIDC_DISCOVERY'] == 'true' if ENV['OIDC_DISCOVERY'] # OPTIONAL (default: false)
oidc_options[:client_auth_method] = ENV['OIDC_CLIENT_AUTH_METHOD'] if ENV['OIDC_CLIENT_AUTH_METHOD'] # OPTIONAL (default: basic)
scope_string = ENV['OIDC_SCOPE'] if ENV['OIDC_SCOPE'] # NEED
scopes = scope_string.split(',')
oidc_options[:scope] = scopes.map { |x| x.to_sym }
oidc_options[:response_type] = ENV['OIDC_RESPONSE_TYPE'] if ENV['OIDC_RESPONSE_TYPE'] # OPTIONAL (default: code)
oidc_options[:response_mode] = ENV['OIDC_RESPONSE_MODE'] if ENV['OIDC_RESPONSE_MODE'] # OPTIONAL (default: query)
oidc_options[:display] = ENV['OIDC_DISPLAY'] if ENV['OIDC_DISPLAY'] # OPTIONAL (default: page)
oidc_options[:prompt] = ENV['OIDC_PROMPT'] if ENV['OIDC_PROMPT'] # OPTIONAL
oidc_options[:send_nonce] = ENV['OIDC_SEND_NONCE'] == 'true' if ENV['OIDC_SEND_NONCE'] # OPTIONAL (default: true)
oidc_options[:send_scope_to_token_endpoint] = ENV['OIDC_SEND_SCOPE_TO_TOKEN_ENDPOINT'] == 'true' if ENV['OIDC_SEND_SCOPE_TO_TOKEN_ENDPOINT'] # OPTIONAL (default: true)
oidc_options[:post_logout_redirect_uri] = ENV['OIDC_IDP_LOGOUT_REDIRECT_URI'] if ENV['OIDC_IDP_LOGOUT_REDIRECT_URI'] # OPTIONAL
oidc_options[:uid_field] = ENV['OIDC_UID_FIELD'] if ENV['OIDC_UID_FIELD'] # NEED
oidc_options[:client_options] = {}
oidc_options[:client_options][:identifier] = ENV['OIDC_CLIENT_ID'] if ENV['OIDC_CLIENT_ID'] # NEED
oidc_options[:client_options][:secret] = ENV['OIDC_CLIENT_SECRET'] if ENV['OIDC_CLIENT_SECRET'] # NEED
oidc_options[:client_options][:redirect_uri] = ENV['OIDC_REDIRECT_URI'] if ENV['OIDC_REDIRECT_URI'] # NEED
oidc_options[:client_options][:scheme] = ENV['OIDC_HTTP_SCHEME'] if ENV['OIDC_HTTP_SCHEME'] # OPTIONAL (default: https)
oidc_options[:client_options][:host] = ENV['OIDC_HOST'] if ENV['OIDC_HOST'] # OPTIONAL
oidc_options[:client_options][:port] = ENV['OIDC_PORT'] if ENV['OIDC_PORT'] # OPTIONAL
oidc_options[:client_options][:authorization_endpoint] = ENV['OIDC_AUTH_ENDPOINT'] if ENV['OIDC_AUTH_ENDPOINT'] # NEED when discovery != true
oidc_options[:client_options][:token_endpoint] = ENV['OIDC_TOKEN_ENDPOINT'] if ENV['OIDC_TOKEN_ENDPOINT'] # NEED when discovery != true
oidc_options[:client_options][:userinfo_endpoint] = ENV['OIDC_USER_INFO_ENDPOINT'] if ENV['OIDC_USER_INFO_ENDPOINT'] # NEED when discovery != true
oidc_options[:client_options][:jwks_uri] = ENV['OIDC_JWKS_URI'] if ENV['OIDC_JWKS_URI'] # NEED when discovery != true
oidc_options[:client_options][:end_session_endpoint] = ENV['OIDC_END_SESSION_ENDPOINT'] if ENV['OIDC_END_SESSION_ENDPOINT'] # OPTIONAL
oidc_options[:security] = {}
oidc_options[:security][:assume_email_is_verified] = ENV['OIDC_SECURITY_ASSUME_EMAIL_IS_VERIFIED'] == 'true' # OPTIONAL
config.omniauth :openid_connect, oidc_options
end
end

View File

@@ -1,7 +0,0 @@
# frozen_string_literal: true
ActiveModelSerializers.config.tap do |config|
config.default_includes = '**'
end
ActiveSupport::Notifications.unsubscribe(ActiveModelSerializers::Logging::RENDER_EVENT)

View File

@@ -1,9 +0,0 @@
# frozen_string_literal: true
# Be sure to restart your server when you modify this file.
# ActiveSupport::Reloader.to_prepare do
# ApplicationController.renderer.defaults.merge!(
# http_host: 'example.org',
# https: false
# )
# end

View File

@@ -1,16 +0,0 @@
# frozen_string_literal: true
# Be sure to restart your server when you modify this file.
# Version of your assets, change this if you want to expire all your assets.
Rails.application.config.assets.version = '1.0'
# Add additional assets to the asset load path.
# Rails.application.config.assets.paths << Emoji.images_path
# Precompile additional assets.
# application.js, application.css, and all non-JS/CSS in the app/assets
# folder are already added.
# Rails.application.config.assets.precompile += %w( admin.js admin.css )
Rails.application.config.assets.initialize_on_precompile = true

View File

@@ -1,10 +0,0 @@
# frozen_string_literal: true
# Be sure to restart your server when you modify this file.
# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
# Rails.backtrace_cleaner.add_silencer { |line| /my_noisy_library/.match?(line) }
# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code
# by setting BACKTRACE=1 before calling your invocation, like "BACKTRACE=1 ./bin/rails runner 'MyClass.perform'".
Rails.backtrace_cleaner.remove_silencers! if ENV["BACKTRACE"]

View File

@@ -1,6 +0,0 @@
# frozen_string_literal: true
Rails.application.configure do
config.x.email_domains_blacklist = (ENV['EMAIL_DOMAIN_DENYLIST'] || ENV['EMAIL_DOMAIN_BLACKLIST']) || ''
config.x.email_domains_whitelist = (ENV['EMAIL_DOMAIN_ALLOWLIST'] || ENV['EMAIL_DOMAIN_WHITELIST']) || ''
end

View File

@@ -1,11 +0,0 @@
# frozen_string_literal: true
Rails.application.configure do
config.x.cache_buster_enabled = ENV['CACHE_BUSTER_ENABLED'] == 'true'
config.x.cache_buster = {
secret_header: ENV['CACHE_BUSTER_SECRET_HEADER'],
secret: ENV['CACHE_BUSTER_SECRET'],
http_method: ENV['CACHE_BUSTER_HTTP_METHOD'] || 'GET',
}
end

View File

@@ -1,5 +0,0 @@
# frozen_string_literal: true
# Log cache errors with Rail's logger
# This used to be the default in old Rails versions: https://github.com/rails/rails/commit/7fcf8590e788cef8b64cc266f75931c418902ca9#diff-f0748f0be8a653eea13369ebb1cadabcad71ede7cfaf20282447e64329817befL86
Rails.cache.logger = Rails.logger

View File

@@ -1,35 +0,0 @@
# frozen_string_literal: true
enabled = ENV['ES_ENABLED'] == 'true'
host = ENV.fetch('ES_HOST') { 'localhost' }
port = ENV.fetch('ES_PORT') { 9200 }
user = ENV.fetch('ES_USER') { nil }
password = ENV.fetch('ES_PASS') { nil }
fallback_prefix = ENV.fetch('REDIS_NAMESPACE') { nil }
prefix = ENV.fetch('ES_PREFIX') { fallback_prefix }
Chewy.settings = {
host: "#{host}:#{port}",
prefix: prefix,
enabled: enabled,
journal: false,
user: user,
password: password,
index: {
number_of_replicas: ['single_node_cluster', nil].include?(ENV['ES_PRESET'].presence) ? 0 : 1,
},
}
# We use our own async strategy even outside the request-response
# cycle, which takes care of checking if Elasticsearch is enabled
# or not. However, mind that for the Rails console, the :urgent
# strategy is set automatically with no way to override it.
Chewy.root_strategy = :bypass_with_warning if Rails.env.production?
Chewy.request_strategy = :mastodon
Chewy.use_after_commit_callbacks = false
# Elasticsearch uses Faraday internally. Faraday interprets the
# http_proxy env variable by default which leads to issues when
# Mastodon is run with hidden services enabled, because
# Elasticsearch is *not* supposed to be accessed through a proxy
Faraday.ignore_env_proxy = true

View File

@@ -1,107 +0,0 @@
# frozen_string_literal: true
# Define an application-wide content security policy
# For further information see the following documentation
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
def sso_host
return unless ENV['ONE_CLICK_SSO_LOGIN'] == 'true'
return unless ENV['OMNIAUTH_ONLY'] == 'true'
return unless Devise.omniauth_providers.length == 1
provider = Devise.omniauth_configs[Devise.omniauth_providers[0]]
@sso_host ||= begin
case provider.provider
when :cas
provider.cas_url
when :saml
provider.options[:idp_sso_target_url]
when :openid_connect
provider.options.dig(:client_options, :authorization_endpoint) || OpenIDConnect::Discovery::Provider::Config.discover!(provider.options[:issuer]).authorization_endpoint
end
end
end
unless Rails.env.development?
assets_host = Rails.configuration.action_controller.asset_host || "https://#{ENV['WEB_DOMAIN'] || ENV['LOCAL_DOMAIN']}"
data_hosts = [assets_host]
if ENV['S3_ENABLED'] == 'true' || ENV['AZURE_ENABLED'] == 'true'
attachments_host = "https://#{ENV['S3_ALIAS_HOST'] || ENV['S3_CLOUDFRONT_HOST'] || ENV['AZURE_ALIAS_HOST'] || ENV['S3_HOSTNAME'] || "s3-#{ENV['S3_REGION'] || 'us-east-1'}.amazonaws.com"}"
attachments_host = "https://#{Addressable::URI.parse(attachments_host).host}"
elsif ENV['SWIFT_ENABLED'] == 'true'
attachments_host = ENV['SWIFT_OBJECT_URL']
attachments_host = "https://#{Addressable::URI.parse(attachments_host).host}"
else
attachments_host = nil
end
data_hosts << attachments_host unless attachments_host.nil?
if ENV['PAPERCLIP_ROOT_URL']
url = Addressable::URI.parse(assets_host) + ENV['PAPERCLIP_ROOT_URL']
data_hosts << "https://#{url.host}"
end
data_hosts.concat(ENV['EXTRA_DATA_HOSTS'].split('|')) if ENV['EXTRA_DATA_HOSTS']
data_hosts.uniq!
Rails.application.config.content_security_policy do |p|
p.base_uri :none
p.default_src :none
p.frame_ancestors :none
p.script_src :self, assets_host, "'wasm-unsafe-eval'"
p.font_src :self, assets_host
p.img_src :self, :data, :blob, *data_hosts
p.style_src :self, assets_host
p.media_src :self, :data, *data_hosts
p.frame_src :self, :https
p.child_src :self, :blob, assets_host
p.worker_src :self, :blob, assets_host
p.connect_src :self, :blob, :data, Rails.configuration.x.streaming_api_base_url, *data_hosts
p.manifest_src :self, assets_host
if sso_host.present?
p.form_action :self, sso_host
else
p.form_action :self
end
end
end
# Report CSP violations to a specified URI
# For further information see the following documentation:
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only
# Rails.application.config.content_security_policy_report_only = true
Rails.application.config.content_security_policy_nonce_generator = ->request { SecureRandom.base64(16) }
Rails.application.config.content_security_policy_nonce_directives = %w(style-src)
Rails.application.reloader.to_prepare do
PgHero::HomeController.content_security_policy do |p|
p.script_src :self, :unsafe_inline, assets_host
p.style_src :self, :unsafe_inline, assets_host
end
PgHero::HomeController.after_action do
request.content_security_policy_nonce_generator = nil
end
if Rails.env.development?
LetterOpenerWeb::LettersController.content_security_policy do |p|
p.child_src :self
p.connect_src :none
p.frame_ancestors :self
p.frame_src :self
p.script_src :unsafe_inline
p.style_src :unsafe_inline
p.worker_src :none
end
LetterOpenerWeb::LettersController.after_action do |p|
request.content_security_policy_nonce_directives = %w(script-src)
end
end
end

View File

@@ -1,27 +0,0 @@
# frozen_string_literal: true
# TODO: Remove after 4.2.0
Rails.application.configure do
config.active_support.key_generator_hash_digest_class = OpenSSL::Digest::SHA1
end
Rails.application.config.after_initialize do
Rails.application.config.action_dispatch.cookies_rotations.tap do |cookies|
authenticated_encrypted_cookie_salt = Rails.application.config.action_dispatch.authenticated_encrypted_cookie_salt
signed_cookie_salt = Rails.application.config.action_dispatch.signed_cookie_salt
secret_key_base = Rails.application.secret_key_base
# TODO: Switch to SHA1 after 4.2.0
key_generator = ActiveSupport::KeyGenerator.new(
secret_key_base, iterations: 1000, hash_digest_class: OpenSSL::Digest::SHA256
)
key_len = ActiveSupport::MessageEncryptor.key_len
old_encrypted_secret = key_generator.generate_key(authenticated_encrypted_cookie_salt, key_len)
old_signed_secret = key_generator.generate_key(signed_cookie_salt)
cookies.rotate :encrypted, old_encrypted_secret
cookies.rotate :signed, old_signed_secret
end
end

View File

@@ -1,7 +0,0 @@
# frozen_string_literal: true
# Be sure to restart your server when you modify this file.
# Specify a serializer for the signed and encrypted cookie jars.
# Valid options are :json, :marshal, and :hybrid.
Rails.application.config.action_dispatch.cookies_serializer = :json

View File

@@ -1,26 +0,0 @@
# frozen_string_literal: true
# Be sure to restart your server when you modify this file.
# Avoid CORS issues when API is called from the frontend app.
# Handle Cross-Origin Resource Sharing (CORS) in order to accept cross-origin AJAX requests.
# Read more: https://github.com/cyu/rack-cors
Rails.application.config.middleware.insert_before 0, Rack::Cors do
allow do
origins '*'
with_options headers: :any, credentials: false do
with_options methods: [:get] do
resource '/.well-known/*'
resource '/@:username'
resource '/users/:username'
end
resource '/api/*',
expose: %w(Link X-RateLimit-Reset X-RateLimit-Limit X-RateLimit-Remaining X-Request-Id),
methods: %i(post put delete get patch options)
resource '/oauth/token', methods: [:post]
end
end
end

View File

@@ -1,417 +0,0 @@
# frozen_string_literal: true
require 'devise/strategies/authenticatable'
Warden::Manager.after_set_user except: :fetch do |user, warden|
session_id = warden.cookies.signed['_session_id'] || warden.raw_session['auth_id']
session_id = user.activate_session(warden.request) unless user.session_activations.active?(session_id)
warden.cookies.signed['_session_id'] = {
value: session_id,
expires: 1.year.from_now,
httponly: true,
same_site: :lax,
}
end
Warden::Manager.after_fetch do |user, warden|
session_id = warden.cookies.signed['_session_id'] || warden.raw_session['auth_id']
if session_id && (session = user.session_activations.find_by(session_id: session_id))
session.update(ip: warden.request.remote_ip) if session.ip != warden.request.remote_ip
warden.cookies.signed['_session_id'] = {
value: session_id,
expires: 1.year.from_now,
httponly: true,
same_site: :lax,
}
else
warden.logout
throw :warden, message: :unauthenticated
end
end
Warden::Manager.before_logout do |_, warden|
SessionActivation.deactivate warden.cookies.signed['_session_id']
warden.cookies.delete('_session_id')
end
module Devise
mattr_accessor :pam_authentication
@@pam_authentication = false
mattr_accessor :pam_controlled_service
@@pam_controlled_service = nil
mattr_accessor :check_at_sign
@@check_at_sign = false
mattr_accessor :ldap_authentication
@@ldap_authentication = false
mattr_accessor :ldap_host
@@ldap_host = nil
mattr_accessor :ldap_port
@@ldap_port = nil
mattr_accessor :ldap_method
@@ldap_method = nil
mattr_accessor :ldap_base
@@ldap_base = nil
mattr_accessor :ldap_uid
@@ldap_uid = nil
mattr_accessor :ldap_mail
@@ldap_mail = nil
mattr_accessor :ldap_bind_dn
@@ldap_bind_dn = nil
mattr_accessor :ldap_password
@@ldap_password = nil
mattr_accessor :ldap_tls_no_verify
@@ldap_tls_no_verify = false
mattr_accessor :ldap_search_filter
@@ldap_search_filter = nil
mattr_accessor :ldap_uid_conversion_enabled
@@ldap_uid_conversion_enabled = false
mattr_accessor :ldap_uid_conversion_search
@@ldap_uid_conversion_search = nil
mattr_accessor :ldap_uid_conversion_replace
@@ldap_uid_conversion_replace = nil
module Strategies
class PamAuthenticatable
def valid?
super && ::Devise.pam_authentication
end
end
class SessionActivationRememberable < Authenticatable
def valid?
@session_cookie = nil
session_cookie.present?
end
def authenticate!
resource = SessionActivation.find_by(session_id: session_cookie)&.user
unless resource
cookies.delete('_session_id')
return pass
end
if validate(resource)
success!(resource)
end
end
private
def session_cookie
@session_cookie ||= cookies.signed['_session_id']
end
end
end
end
Warden::Strategies.add(:session_activation_rememberable, Devise::Strategies::SessionActivationRememberable)
Devise.setup do |config|
config.warden do |manager|
manager.default_strategies(scope: :user).unshift :two_factor_ldap_authenticatable if Devise.ldap_authentication
manager.default_strategies(scope: :user).unshift :two_factor_pam_authenticatable if Devise.pam_authentication
manager.default_strategies(scope: :user).unshift :session_activation_rememberable
manager.default_strategies(scope: :user).unshift :two_factor_authenticatable
manager.default_strategies(scope: :user).unshift :two_factor_backupable
end
# The secret key used by Devise. Devise uses this key to generate
# random tokens. Changing this key will render invalid all existing
# confirmation, reset password and unlock tokens in the database.
# Devise will use the `secret_key_base` on Rails 4+ applications as its `secret_key`
# by default. You can change it below and use your own secret key.
# config.secret_key = '2f86974c4dd7735170fd70fbf399f7a477ffd635ef240d07a22cf4bd7cd13dbae17c4383a2996d0c1e79a991ec18a91a17424c53e4771adb75a8b21904bd1403'
# ==> Mailer Configuration
# Configure the e-mail address which will be shown in Devise::Mailer,
# note that it will be overwritten if you use your own mailer class
# with default "from" parameter.
# config.mailer_sender = ENV['SMTP_FROM_ADDRESS'] || 'notifications@localhost'
# Configure the class responsible to send e-mails.
config.mailer = 'UserMailer'
# ==> ORM configuration
# Load and configure the ORM. Supports :active_record (default) and
# :mongoid (bson_ext recommended) by default. Other ORMs may be
# available as additional gems.
require 'devise/orm/active_record'
# ==> Configuration for any authentication mechanism
# Configure which keys are used when authenticating a user. The default is
# just :email. You can configure it to use [:username, :subdomain], so for
# authenticating a user, both parameters are required. Remember that those
# parameters are used only when authenticating and not when retrieving from
# session. If you need permissions, you should implement that in a before filter.
# You can also supply a hash where the value is a boolean determining whether
# or not authentication should be aborted when the value is not present.
# config.authentication_keys = [:email]
# Configure parameters from the request object used for authentication. Each entry
# given should be a request method and it will automatically be passed to the
# find_for_authentication method and considered in your model lookup. For instance,
# if you set :request_keys to [:subdomain], :subdomain will be used on authentication.
# The same considerations mentioned for authentication_keys also apply to request_keys.
# config.request_keys = []
# Configure which authentication keys should be case-insensitive.
# These keys will be lowercased upon creating or modifying a user and when used
# to authenticate or find a user. Default is :email.
config.case_insensitive_keys = [:email]
# Configure which authentication keys should have whitespace stripped.
# These keys will have whitespace before and after removed upon creating or
# modifying a user and when used to authenticate or find a user. Default is :email.
config.strip_whitespace_keys = [:email]
# Tell if authentication through request.params is enabled. True by default.
# It can be set to an array that will enable params authentication only for the
# given strategies, for example, `config.params_authenticatable = [:database]` will
# enable it only for database (email + password) authentication.
# config.params_authenticatable = true
# Tell if authentication through HTTP Auth is enabled. False by default.
# It can be set to an array that will enable http authentication only for the
# given strategies, for example, `config.http_authenticatable = [:database]` will
# enable it only for database authentication. The supported strategies are:
# :database = Support basic authentication with authentication key + password
config.http_authenticatable = [:pam, :database]
# If 401 status code should be returned for AJAX requests. True by default.
# config.http_authenticatable_on_xhr = true
# The realm used in Http Basic Authentication. 'Application' by default.
# config.http_authentication_realm = 'Application'
# It will change confirmation, password recovery and other workflows
# to behave the same regardless if the e-mail provided was right or wrong.
# Does not affect registerable.
# See : https://github.com/plataformatec/devise/wiki/How-To:-Using-paranoid-mode,-avoid-user-enumeration-on-registerable
config.paranoid = true
# By default Devise will store the user in session. You can skip storage for
# particular strategies by setting this option.
# Notice that if you are skipping storage for all authentication paths, you
# may want to disable generating routes to Devise's sessions controller by
# passing skip: :sessions to `devise_for` in your config/routes.rb
config.skip_session_storage = [:http_auth]
# By default, Devise cleans up the CSRF token on authentication to
# avoid CSRF token fixation attacks. This means that, when using AJAX
# requests for sign in and sign up, you need to get a new CSRF token
# from the server. You can disable this option at your own risk.
# config.clean_up_csrf_token_on_authentication = true
# ==> Configuration for :database_authenticatable
# For bcrypt, this is the cost for hashing the password and defaults to 10. If
# using other encryptors, it sets how many times you want the password re-encrypted.
#
# Limiting the stretches to just one in testing will increase the performance of
# your test suite dramatically. However, it is STRONGLY RECOMMENDED to not use
# a value less than 10 in other environments. Note that, for bcrypt (the default
# encryptor), the cost increases exponentially with the number of stretches (e.g.
# a value of 20 is already extremely slow: approx. 60 seconds for 1 calculation).
config.stretches = Rails.env.test? ? 1 : 10
# Setup a pepper to generate the encrypted password.
# config.pepper = '104d16705f794923e77c5e5167b52452d00646dc952a2d30b541c24086e647012c7b9625f253c51912e455981e503446772973d5f1638631196c819d7137fad4'
# Send a notification to the original email when the user's email is changed.
config.send_email_changed_notification = true
# Send a notification email when the user's password is changed
config.send_password_change_notification = true
# ==> Configuration for :confirmable
# A period that the user is allowed to access the website even without
# confirming their account. For instance, if set to 2.days, the user will be
# able to access the website for two days without confirming their account,
# access will be blocked just in the third day. Default is 0.days, meaning
# the user cannot access the website without confirming their account.
# config.allow_unconfirmed_access_for = 2.days
# A period that the user is allowed to confirm their account before their
# token becomes invalid. For example, if set to 3.days, the user can confirm
# their account within 3 days after the mail was sent, but on the fourth day
# their account can't be confirmed with the token any more.
# Default is nil, meaning there is no restriction on how long a user can take
# before confirming their account.
config.confirm_within = 2.days
# If true, requires any email changes to be confirmed (exactly the same way as
# initial account confirmation) to be applied. Requires additional unconfirmed_email
# db field (see migrations). Until confirmed, new email is stored in
# unconfirmed_email column, and copied to email column on successful confirmation.
config.reconfirmable = true
# Defines which key will be used when confirming an account
# config.confirmation_keys = [:email]
# ==> Configuration for :rememberable
# The time the user will be remembered without asking for credentials again.
config.remember_for = 1.year
# Invalidates all the remember me tokens when the user signs out.
config.expire_all_remember_me_on_sign_out = true
# If true, extends the user's remember period when remembered via cookie.
# config.extend_remember_period = false
# Options to be passed to the created cookie. For instance, you can set
# secure: true in order to force SSL only cookies.
config.rememberable_options = {}
# ==> Configuration for :validatable
# Range for password length.
config.password_length = 8..72
# Email regex used to validate email formats. It simply asserts that
# one (and only one) @ exists in the given string. This is mainly
# to give user feedback and not to assert the e-mail validity.
# config.email_regexp = /\A[^@]+@[^@]+\z/
# ==> Configuration for :timeoutable
# The time you want to timeout the user session without activity. After this
# time the user will be asked for credentials again. Default is 30 minutes.
# config.timeout_in = 30.minutes
# ==> Configuration for :lockable
# Defines which strategy will be used to lock an account.
# :failed_attempts = Locks an account after a number of failed attempts to sign in.
# :none = No lock strategy. You should handle locking by yourself.
# config.lock_strategy = :failed_attempts
# Defines which key will be used when locking and unlocking an account
# config.unlock_keys = [:email]
# Defines which strategy will be used to unlock an account.
# :email = Sends an unlock link to the user email
# :time = Re-enables login after a certain amount of time (see :unlock_in below)
# :both = Enables both strategies
# :none = No unlock strategy. You should handle unlocking by yourself.
# config.unlock_strategy = :both
# Number of authentication tries before locking an account if lock_strategy
# is failed attempts.
# config.maximum_attempts = 20
# Time interval to unlock the account if :time is enabled as unlock_strategy.
# config.unlock_in = 1.hour
# Warn on the last attempt before the account is locked.
# config.last_attempt_warning = true
# ==> Configuration for :recoverable
#
# Defines which key will be used when recovering the password for an account
# config.reset_password_keys = [:email]
# Time interval you can reset your password with a reset password key.
# Don't put a too small interval or your users won't have the time to
# change their passwords.
config.reset_password_within = 6.hours
# When set to false, does not sign a user in automatically after their password is
# reset. Defaults to true, so a user is signed in automatically after a reset.
config.sign_in_after_reset_password = false
# ==> Configuration for :encryptable
# Allow you to use another encryption algorithm besides bcrypt (default). You can use
# :sha1, :sha512 or encryptors from others authentication tools as :clearance_sha1,
# :authlogic_sha512 (then you should set stretches above to 20 for default behavior)
# and :restful_authentication_sha1 (then you should set stretches to 10, and copy
# REST_AUTH_SITE_KEY to pepper).
#
# Require the `devise-encryptable` gem when using anything other than bcrypt
# config.encryptor = :sha512
# ==> Scopes configuration
# Turn scoped views on. Before rendering "sessions/new", it will first check for
# "users/sessions/new". It's turned off by default because it's slower if you
# are using only default views.
# config.scoped_views = false
# Configure the default scope given to Warden. By default it's the first
# devise role declared in your routes (usually :user).
# config.default_scope = :user
# Set this configuration to false if you want /users/sign_out to sign out
# only the current scope. By default, Devise signs out all scopes.
# config.sign_out_all_scopes = true
# ==> Navigation configuration
# Lists the formats that should be treated as navigational. Formats like
# :html, should redirect to the sign in page when the user does not have
# access, but formats like :xml or :json, should return 401.
#
# If you have any extra navigational formats, like :iphone or :mobile, you
# should add them to the navigational formats lists.
#
# The "*/*" below is required to match Internet Explorer requests.
# config.navigational_formats = ['*/*', :html]
# The default HTTP method used to sign out a resource. Default is :delete.
config.sign_out_via = :delete
# ==> OmniAuth
# Add a new OmniAuth provider. Check the wiki for more information on setting
# up on your models and hooks.
# config.omniauth :github, 'APP_ID', 'APP_SECRET', scope: 'user,public_repo'
# ==> Warden configuration
# If you want to use other strategies, that are not supported by Devise, or
# change the failure app, you can configure them inside the config.warden block.
#
# config.warden do |manager|
# manager.intercept_401 = false
# manager.default_strategies(scope: :user).unshift :some_external_strategy
# end
# ==> Mountable engine configurations
# When using Devise inside an engine, let's call it `MyEngine`, and this engine
# is mountable, there are some extra configurations to be taken into account.
# The following options are available, assuming the engine is mounted as:
#
# mount MyEngine, at: '/my_engine'
#
# The router that invoked `devise_for`, in the example above, would be:
# config.router_name = :my_engine
#
# When using OmniAuth, Devise cannot automatically set OmniAuth path,
# so you need to do it manually. For the users scope, it would be:
# config.omniauth_path_prefix = '/my_engine/users/auth'
if ENV['PAM_ENABLED'] == 'true'
config.pam_authentication = true
config.usernamefield = nil
config.emailfield = 'email'
config.check_at_sign = true
config.pam_default_suffix = ENV.fetch('PAM_EMAIL_DOMAIN') { ENV['LOCAL_DOMAIN'] }
config.pam_default_service = ENV.fetch('PAM_DEFAULT_SERVICE') { 'rpam' }
config.pam_controlled_service = ENV.fetch('PAM_CONTROLLED_SERVICE') { nil }
end
if ENV['LDAP_ENABLED'] == 'true'
config.ldap_authentication = true
config.check_at_sign = true
config.ldap_host = ENV.fetch('LDAP_HOST', 'localhost')
config.ldap_port = ENV.fetch('LDAP_PORT', 389).to_i
config.ldap_method = ENV.fetch('LDAP_METHOD', :simple_tls).to_sym
config.ldap_base = ENV.fetch('LDAP_BASE')
config.ldap_bind_dn = ENV.fetch('LDAP_BIND_DN')
config.ldap_password = ENV.fetch('LDAP_PASSWORD')
config.ldap_uid = ENV.fetch('LDAP_UID', 'cn')
config.ldap_mail = ENV.fetch('LDAP_MAIL', 'mail')
config.ldap_tls_no_verify = ENV['LDAP_TLS_NO_VERIFY'] == 'true'
config.ldap_search_filter = ENV.fetch('LDAP_SEARCH_FILTER', '(|(%{uid}=%{email})(%{mail}=%{email}))')
config.ldap_uid_conversion_enabled = ENV['LDAP_UID_CONVERSION_ENABLED'] == 'true'
config.ldap_uid_conversion_search = ENV.fetch('LDAP_UID_CONVERSION_SEARCH', '.,- ')
config.ldap_uid_conversion_replace = ENV.fetch('LDAP_UID_CONVERSION_REPLACE', '_')
end
end

View File

@@ -1,178 +0,0 @@
# frozen_string_literal: true
Doorkeeper.configure do
# Change the ORM that doorkeeper will use (needs plugins)
orm :active_record
# This block will be called to check whether the resource owner is authenticated or not.
resource_owner_authenticator do
current_user || redirect_to(new_user_session_url)
end
resource_owner_from_credentials do |_routes|
user = User.authenticate_with_ldap(email: request.params[:username], password: request.params[:password]) if Devise.ldap_authentication
user ||= User.authenticate_with_pam(email: request.params[:username], password: request.params[:password]) if Devise.pam_authentication
if user.nil?
user = User.find_by(email: request.params[:username])
user = nil unless user&.valid_password?(request.params[:password])
end
user unless user&.otp_required_for_login?
end
# If you want to restrict access to the web interface for adding oauth authorized applications, you need to declare the block below.
admin_authenticator do
current_user&.admin? || redirect_to(new_user_session_url)
end
# Authorization Code expiration time (default 10 minutes).
# authorization_code_expires_in 10.minutes
# Access token expiration time (default 2 hours).
# If you want to disable expiration, set this to nil.
access_token_expires_in nil
# Assign a custom TTL for implicit grants.
# custom_access_token_expires_in do |oauth_client|
# oauth_client.application.additional_settings.implicit_oauth_expiration
# end
# Use a custom class for generating the access token.
# https://github.com/doorkeeper-gem/doorkeeper#custom-access-token-generator
# access_token_generator "::Doorkeeper::JWT"
# The controller Doorkeeper::ApplicationController inherits from.
# Defaults to ActionController::Base.
# https://github.com/doorkeeper-gem/doorkeeper#custom-base-controller
base_controller 'ApplicationController'
# Reuse access token for the same resource owner within an application (disabled by default)
# Rationale: https://github.com/doorkeeper-gem/doorkeeper/issues/383
reuse_access_token
# Issue access tokens with refresh token (disabled by default)
# use_refresh_token
# Forbids creating/updating applications with arbitrary scopes that are
# not in configuration, i.e. `default_scopes` or `optional_scopes`.
# (Disabled by default)
enforce_configured_scopes
# Provide support for an owner to be assigned to each registered application (disabled by default)
# Optional parameter :confirmation => true (default false) if you want to enforce ownership of
# a registered application
# Note: you must also run the rails g doorkeeper:application_owner generator to provide the necessary support
enable_application_owner
# Define access token scopes for your provider
# For more information go to
# https://github.com/doorkeeper-gem/doorkeeper/wiki/Using-Scopes
default_scopes :read
optional_scopes :write,
:'write:accounts',
:'write:blocks',
:'write:bookmarks',
:'write:conversations',
:'write:favourites',
:'write:filters',
:'write:follows',
:'write:lists',
:'write:media',
:'write:mutes',
:'write:notifications',
:'write:reports',
:'write:statuses',
:read,
:'read:accounts',
:'read:blocks',
:'read:bookmarks',
:'read:favourites',
:'read:filters',
:'read:follows',
:'read:lists',
:'read:mutes',
:'read:notifications',
:'read:search',
:'read:statuses',
:follow,
:push,
:'admin:read',
:'admin:read:accounts',
:'admin:read:reports',
:'admin:read:domain_allows',
:'admin:read:domain_blocks',
:'admin:read:ip_blocks',
:'admin:read:email_domain_blocks',
:'admin:read:canonical_email_blocks',
:'admin:write',
:'admin:write:accounts',
:'admin:write:reports',
:'admin:write:domain_allows',
:'admin:write:domain_blocks',
:'admin:write:ip_blocks',
:'admin:write:email_domain_blocks',
:'admin:write:canonical_email_blocks',
:crypto
# Change the way client credentials are retrieved from the request object.
# By default it retrieves first from the `HTTP_AUTHORIZATION` header, then
# falls back to the `:client_id` and `:client_secret` params from the `params` object.
# Check out the wiki for more information on customization
# client_credentials :from_basic, :from_params
# Change the way access token is authenticated from the request object.
# By default it retrieves first from the `HTTP_AUTHORIZATION` header, then
# falls back to the `:access_token` or `:bearer_token` params from the `params` object.
# Check out the wiki for more information on customization
# access_token_methods :from_bearer_authorization, :from_access_token_param, :from_bearer_param
# Change the native redirect uri for client apps
# When clients register with the following redirect uri, they won't be redirected to any server and the authorization code will be displayed within the provider
# The value can be any string. Use nil to disable this feature. When disabled, clients must provide a valid URL
# (Similar behaviour: https://developers.google.com/accounts/docs/OAuth2InstalledApp#choosingredirecturi)
#
# native_redirect_uri 'urn:ietf:wg:oauth:2.0:oob'
# Forces the usage of the HTTPS protocol in non-native redirect uris (enabled
# by default in non-development environments). OAuth2 delegates security in
# communication to the HTTPS protocol so it is wise to keep this enabled.
#
force_ssl_in_redirect_uri false
# Specify what redirect URI's you want to block during Application creation.
# Any redirect URI is whitelisted by default.
#
# You can use this option in order to forbid URI's with 'javascript' scheme
# for example.
forbid_redirect_uri { |uri| %w[data vbscript javascript].include?(uri.scheme.to_s.downcase) }
# Specify what grant flows are enabled in array of Strings. The valid
# strings and the flows they enable are:
#
# "authorization_code" => Authorization Code Grant Flow
# "implicit" => Implicit Grant Flow
# "password" => Resource Owner Password Credentials Grant Flow
# "client_credentials" => Client Credentials Grant Flow
#
# If not specified, Doorkeeper enables authorization_code and
# client_credentials.
#
# implicit and password grant flows have risks that you should understand
# before enabling:
# http://tools.ietf.org/html/rfc6819#section-4.4.2
# http://tools.ietf.org/html/rfc6819#section-4.4.3
#
grant_flows %w(authorization_code password client_credentials)
# Under some circumstances you might want to have applications auto-approved,
# so that the user skips the authorization step.
# For example if dealing with a trusted application.
skip_authorization do |resource_owner, client|
client.application.superapp?
end
# WWW-Authenticate Realm (default "Doorkeeper").
# realm "Doorkeeper"
end

View File

@@ -1,7 +0,0 @@
# frozen_string_literal: true
if String.method_defined?(:blank_as?)
class String
alias blank? blank_as?
end
end

View File

@@ -1,5 +0,0 @@
# frozen_string_literal: true
if ENV['FFMPEG_BINARY'].present?
FFMPEG.ffmpeg_binary = ENV['FFMPEG_BINARY']
end

View File

@@ -1,10 +0,0 @@
# frozen_string_literal: true
# Be sure to restart your server when you modify this file.
# Configure parameters to be filtered from the log file. Use this to limit dissemination of
# sensitive information. See the ActiveSupport::ParameterFilter documentation for supported
# notations and behaviors.
Rails.application.config.filter_parameters += [
:passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn
]

View File

@@ -1,41 +0,0 @@
# frozen_string_literal: true
Rails.application.configure do
config.x.http_client_proxy = {}
if ENV['http_proxy'].present?
proxy = URI.parse(ENV['http_proxy'])
raise "Unsupported proxy type: #{proxy.scheme}" unless %w(http https).include? proxy.scheme
raise "No proxy host" unless proxy.host
host = proxy.host
host = host[1...-1] if host[0] == '[' # for IPv6 address
config.x.http_client_proxy[:proxy] = {
proxy_address: host,
proxy_port: proxy.port,
proxy_username: proxy.user,
proxy_password: proxy.password,
}.compact
end
if ENV['http_hidden_proxy'].present?
proxy = URI.parse(ENV['http_hidden_proxy'])
raise "Unsupported proxy type: #{proxy.scheme}" unless %w(http https).include? proxy.scheme
raise "No proxy host" unless proxy.host
host = proxy.host
host = host[1...-1] if host[0] == '[' # for IPv6 address
config.x.http_client_hidden_proxy[:proxy] = {
proxy_address: host,
proxy_port: proxy.port,
proxy_username: proxy.user,
proxy_password: proxy.password,
}.compact
end
config.x.access_to_hidden_service = ENV['ALLOW_ACCESS_TO_HIDDEN_SERVICE'] == 'true'
end

View File

@@ -1,7 +0,0 @@
# frozen_string_literal: true
HttpLog.configure do |config|
config.logger = Rails.logger
config.color = { color: :yellow }
config.compact_log = true
end

View File

@@ -1,34 +0,0 @@
# frozen_string_literal: true
# Be sure to restart your server when you modify this file.
# Add new inflection rules using the following format. Inflections
# are locale specific, and you may define rules for as many different
# locales as you wish. All of these examples are active by default:
# ActiveSupport::Inflector.inflections(:en) do |inflect|
# inflect.plural /^(ox)$/i, '\1en'
# inflect.singular /^(ox)en/i, '\1'
# inflect.irregular 'person', 'people'
# inflect.uncountable %w( fish sheep )
# end
ActiveSupport::Inflector.inflections(:en) do |inflect|
inflect.acronym 'StatsD'
inflect.acronym 'OEmbed'
inflect.acronym 'OStatus'
inflect.acronym 'ActivityPub'
inflect.acronym 'PubSubHubbub'
inflect.acronym 'ActivityStreams'
inflect.acronym 'JsonLd'
inflect.acronym 'NodeInfo'
inflect.acronym 'Ed25519'
inflect.acronym 'TOC'
inflect.acronym 'RSS'
inflect.acronym 'REST'
inflect.acronym 'URL'
inflect.acronym 'ASCII'
inflect.acronym 'DeepL'
inflect.acronym 'DSL'
inflect.singular 'data', 'data'
end

View File

@@ -1,4 +0,0 @@
# frozen_string_literal: true
require_relative '../../lib/json_ld/security'
require_relative '../../lib/json_ld/identity'

View File

@@ -1,7 +0,0 @@
# frozen_string_literal: true
Kaminari.configure do |config|
config.default_per_page = 40
config.window = 2
config.outer_window = 1
end

View File

@@ -1,9 +0,0 @@
# frozen_string_literal: true
Rails.application.configure do
config.i18n.load_path += Dir[Rails.root.join('app', 'javascript', 'flavours', '*', 'names.{rb,yml}').to_s]
config.i18n.load_path += Dir[Rails.root.join('app', 'javascript', 'flavours', '*', 'names', '*.{rb,yml}').to_s]
config.i18n.load_path += Dir[Rails.root.join('app', 'javascript', 'skins', '*', '*', 'names.{rb,yml}').to_s]
config.i18n.load_path += Dir[Rails.root.join('app', 'javascript', 'skins', '*', '*', 'names', '*.{rb,yml}').to_s]
config.i18n.load_path += Dir[Rails.root.join('config', 'locales-glitch', '*.{rb,yml}').to_s]
end

View File

@@ -1,5 +0,0 @@
# frozen_string_literal: true
ActionMailer::MailDeliveryJob.class_eval do
discard_on ActiveJob::DeserializationError
end

View File

@@ -1,7 +0,0 @@
# frozen_string_literal: true
Mime::Type.register 'application/json', :json, %w(text/x-json application/jsonrequest application/jrd+json application/activity+json application/ld+json)
Mime::Type.register 'text/xml', :xml, %w(application/xml application/atom+xml application/xrd+xml)
# WebP is not defined in Rack 2.2.
Rack::Mime::MIME_TYPES['.webp'] = 'image/webp'

View File

@@ -1,10 +0,0 @@
# frozen_string_literal: true
# TODO
# The Rails 7.0 framework default here is to set this true. However, we have a
# location in devise that redirects where we don't have an easy ability to
# override a method or set a config option, but where the redirect does not
# provide this option.
# https://github.com/heartcombo/devise/blob/v4.9.2/app/controllers/devise/confirmations_controller.rb#L28
# Once a solution is found, this line can be removed.
Rails.application.config.action_controller.raise_on_open_redirects = false

View File

@@ -1,3 +0,0 @@
# frozen_string_literal: true
Oj.default_options = { mode: :compat, time_format: :ruby, use_to_json: true }

View File

@@ -1,10 +0,0 @@
# frozen_string_literal: true
require 'open-uri'
module OpenURI
def self.redirectable?(uri1, uri2) # :nodoc:
uri1.scheme.casecmp(uri2.scheme).zero? ||
(/\A(?:http|https|ftp)\z/i.match?(uri1.scheme) && /\A(?:http|https|ftp)\z/i.match?(uri2.scheme))
end
end

View File

@@ -1,186 +0,0 @@
# frozen_string_literal: true
Paperclip::DataUriAdapter.register
Paperclip::ResponseWithLimitAdapter.register
Paperclip.interpolates :filename do |attachment, style|
if style == :original
attachment.original_filename
else
[basename(attachment, style), extension(attachment, style)].compact_blank!.join('.')
end
end
Paperclip.interpolates :prefix_path do |attachment, style|
if attachment.storage_schema_version >= 1 && attachment.instance.respond_to?(:local?) && !attachment.instance.local?
'cache' + File::SEPARATOR
else
''
end
end
Paperclip.interpolates :prefix_url do |attachment, style|
if attachment.storage_schema_version >= 1 && attachment.instance.respond_to?(:local?) && !attachment.instance.local?
'cache/'
else
''
end
end
Paperclip::Attachment.default_options.merge!(
use_timestamp: false,
path: ':prefix_url:class/:attachment/:id_partition/:style/:filename',
storage: :fog
)
if ENV['S3_ENABLED'] == 'true'
require 'aws-sdk-s3'
s3_region = ENV.fetch('S3_REGION') { 'us-east-1' }
s3_protocol = ENV.fetch('S3_PROTOCOL') { 'https' }
s3_hostname = ENV.fetch('S3_HOSTNAME') { "s3-#{s3_region}.amazonaws.com" }
Paperclip::Attachment.default_options.merge!(
storage: :s3,
s3_protocol: s3_protocol,
s3_host_name: s3_hostname,
s3_headers: {
'X-Amz-Multipart-Threshold' => ENV.fetch('S3_MULTIPART_THRESHOLD') { 15.megabytes }.to_i,
'Cache-Control' => 'public, max-age=315576000, immutable',
},
s3_permissions: ENV.fetch('S3_PERMISSION') { 'public-read' },
s3_region: s3_region,
s3_credentials: {
bucket: ENV['S3_BUCKET'],
access_key_id: ENV['AWS_ACCESS_KEY_ID'],
secret_access_key: ENV['AWS_SECRET_ACCESS_KEY'],
},
s3_options: {
signature_version: ENV.fetch('S3_SIGNATURE_VERSION') { 'v4' },
http_open_timeout: ENV.fetch('S3_OPEN_TIMEOUT') { '5' }.to_i,
http_read_timeout: ENV.fetch('S3_READ_TIMEOUT') { '5' }.to_i,
http_idle_timeout: 5,
retry_limit: 0,
}
)
Paperclip::Attachment.default_options[:s3_permissions] = ->(*) { nil } if ENV['S3_PERMISSION'] == ''
if ENV.has_key?('S3_ENDPOINT')
Paperclip::Attachment.default_options[:s3_options].merge!(
endpoint: ENV['S3_ENDPOINT'],
force_path_style: ENV['S3_OVERRIDE_PATH_STYLE'] != 'true',
)
Paperclip::Attachment.default_options[:url] = ':s3_path_url'
end
if ENV.has_key?('S3_ALIAS_HOST') || ENV.has_key?('S3_CLOUDFRONT_HOST')
Paperclip::Attachment.default_options.merge!(
url: ':s3_alias_url',
s3_host_alias: ENV['S3_ALIAS_HOST'] || ENV['S3_CLOUDFRONT_HOST']
)
end
Paperclip::Attachment.default_options[:s3_headers]['X-Amz-Storage-Class'] = ENV['S3_STORAGE_CLASS'] if ENV.has_key?('S3_STORAGE_CLASS')
# Some S3-compatible providers might not actually be compatible with some APIs
# used by kt-paperclip, see https://github.com/mastodon/mastodon/issues/16822
# and https://github.com/mastodon/mastodon/issues/26394
module Paperclip
module Storage
module S3Extensions
def copy_to_local_file(style, local_dest_path)
log("copying #{path(style)} to local file #{local_dest_path}")
options = {}
options[:mode] = 'single_request' if ENV['S3_FORCE_SINGLE_REQUEST'] == 'true'
options[:checksum_mode] = 'DISABLED' unless ENV['S3_ENABLE_CHECKSUM_MODE'] == 'true'
s3_object(style).download_file(local_dest_path, options)
rescue Aws::Errors::ServiceError => e
warn("#{e} - cannot copy #{path(style)} to local file #{local_dest_path}")
false
end
end
end
end
Paperclip::Storage::S3.prepend(Paperclip::Storage::S3Extensions)
elsif ENV['SWIFT_ENABLED'] == 'true'
require 'fog/openstack'
Paperclip::Attachment.default_options.merge!(
fog_credentials: {
provider: 'OpenStack',
openstack_username: ENV['SWIFT_USERNAME'],
openstack_project_id: ENV['SWIFT_PROJECT_ID'],
openstack_project_name: ENV['SWIFT_TENANT'],
openstack_tenant: ENV['SWIFT_TENANT'], # Some OpenStack-v2 ignores project_name but needs tenant
openstack_api_key: ENV['SWIFT_PASSWORD'],
openstack_auth_url: ENV['SWIFT_AUTH_URL'],
openstack_domain_name: ENV.fetch('SWIFT_DOMAIN_NAME') { 'default' },
openstack_region: ENV['SWIFT_REGION'],
openstack_cache_ttl: ENV.fetch('SWIFT_CACHE_TTL') { 60 },
openstack_temp_url_key: ENV['SWIFT_TEMP_URL_KEY'],
},
fog_file: { 'Cache-Control' => 'public, max-age=315576000, immutable' },
fog_directory: ENV['SWIFT_CONTAINER'],
fog_host: ENV['SWIFT_OBJECT_URL'],
fog_public: true
)
elsif ENV['AZURE_ENABLED'] == 'true'
require 'paperclip-azure'
Paperclip::Attachment.default_options.merge!(
storage: :azure,
azure_options: {
protocol: 'https',
},
azure_credentials: {
storage_account_name: ENV['AZURE_STORAGE_ACCOUNT'],
storage_access_key: ENV['AZURE_STORAGE_ACCESS_KEY'],
container: ENV['AZURE_CONTAINER_NAME'],
}
)
if ENV.has_key?('AZURE_ALIAS_HOST')
Paperclip::Attachment.default_options.merge!(
url: ':azure_alias_url',
azure_host_alias: ENV['AZURE_ALIAS_HOST']
)
end
else
Paperclip::Attachment.default_options.merge!(
storage: :filesystem,
path: File.join(ENV.fetch('PAPERCLIP_ROOT_PATH', File.join(':rails_root', 'public', 'system')), ':prefix_path:class', ':attachment', ':id_partition', ':style', ':filename'),
url: ENV.fetch('PAPERCLIP_ROOT_URL', '/system') + '/:prefix_url:class/:attachment/:id_partition/:style/:filename',
)
end
Rails.application.reloader.to_prepare do
Paperclip.options[:content_type_mappings] = { csv: Import::FILE_TYPES }
end
# In some places in the code, we rescue this exception, but we don't always
# load the S3 library, so it may be an undefined constant:
unless defined?(Seahorse)
module Seahorse
module Client
class NetworkingError < StandardError; end
end
end
end
# Set our ImageMagick security policy, but allow admins to override it
ENV['MAGICK_CONFIGURE_PATH'] = begin
imagemagick_config_paths = ENV.fetch('MAGICK_CONFIGURE_PATH', '').split(File::PATH_SEPARATOR)
imagemagick_config_paths << Rails.root.join('config', 'imagemagick').expand_path.to_s
imagemagick_config_paths.join(File::PATH_SEPARATOR)
end

View File

@@ -1,12 +0,0 @@
# frozen_string_literal: true
# Define an application-wide HTTP permissions policy. For further
# information see https://developers.google.com/web/updates/2018/06/feature-policy
#
# Rails.application.config.permissions_policy do |f|
# f.camera :none
# f.gyroscope :none
# f.microphone :none
# f.usb :none
# f.fullscreen :self
# f.payment :self, "https://secure.example.com"
# end

View File

@@ -1,3 +0,0 @@
# frozen_string_literal: true
PgHero.show_migrations = Rails.env.development?

View File

@@ -1,10 +0,0 @@
# frozen_string_literal: true
# Since Rails 6.1, ActionView adds preload links for javascript files
# in the Links header per default.
# In our case, that will bloat headers too much and potentially cause
# issues with reverse proxies. Furthermore, we don't need those links,
# as we already output them as HTML link tags.
Rails.application.config.action_view.preload_links_header = false

View File

@@ -1,8 +0,0 @@
# frozen_string_literal: true
require_relative '../../lib/mastodon/premailer_webpack_strategy'
Premailer::Rails.config.merge!(remove_ids: true,
adapter: :nokogiri,
generate_text_part: false,
strategies: [PremailerWebpackStrategy])

View File

@@ -1,153 +0,0 @@
# frozen_string_literal: true
require 'doorkeeper/grape/authorization_decorator'
class Rack::Attack
class Request
def authenticated_token
return @authenticated_token if defined?(@authenticated_token)
@authenticated_token = Doorkeeper::OAuth::Token.authenticate(
Doorkeeper::Grape::AuthorizationDecorator.new(self),
*Doorkeeper.configuration.access_token_methods
)
end
def remote_ip
@remote_ip ||= (@env["action_dispatch.remote_ip"] || ip).to_s
end
def throttleable_remote_ip
@throttleable_remote_ip ||= begin
ip = IPAddr.new(remote_ip)
if ip.ipv6?
ip.mask(64)
else
ip
end
end.to_s
end
def authenticated_user_id
authenticated_token&.resource_owner_id
end
def authenticated_token_id
authenticated_token&.id
end
def unauthenticated?
!authenticated_user_id
end
def api_request?
path.start_with?('/api')
end
def path_matches?(other_path)
/\A#{Regexp.escape(other_path)}(\..*)?\z/ =~ path
end
def web_request?
!api_request?
end
def paging_request?
params['page'].present? || params['min_id'].present? || params['max_id'].present? || params['since_id'].present?
end
end
Rack::Attack.safelist('allow from localhost') do |req|
req.remote_ip == '127.0.0.1' || req.remote_ip == '::1'
end
Rack::Attack.blocklist('deny from blocklist') do |req|
IpBlock.blocked?(req.remote_ip)
end
throttle('throttle_authenticated_api', limit: 1_500, period: 5.minutes) do |req|
req.authenticated_user_id if req.api_request?
end
throttle('throttle_per_token_api', limit: 300, period: 5.minutes) do |req|
req.authenticated_token_id if req.api_request?
end
throttle('throttle_unauthenticated_api', limit: 300, period: 5.minutes) do |req|
req.throttleable_remote_ip if req.api_request? && req.unauthenticated?
end
throttle('throttle_api_media', limit: 30, period: 30.minutes) do |req|
req.authenticated_user_id if req.post? && req.path.match?(%r{\A/api/v\d+/media\z}i)
end
throttle('throttle_media_proxy', limit: 30, period: 10.minutes) do |req|
req.throttleable_remote_ip if req.path.start_with?('/media_proxy')
end
throttle('throttle_api_sign_up', limit: 5, period: 30.minutes) do |req|
req.throttleable_remote_ip if req.post? && req.path == '/api/v1/accounts'
end
throttle('throttle_authenticated_paging', limit: 300, period: 15.minutes) do |req|
req.authenticated_user_id if req.paging_request?
end
throttle('throttle_unauthenticated_paging', limit: 300, period: 15.minutes) do |req|
req.throttleable_remote_ip if req.paging_request? && req.unauthenticated?
end
API_DELETE_REBLOG_REGEX = %r{\A/api/v1/statuses/\d+/unreblog\z}
API_DELETE_STATUS_REGEX = %r{\A/api/v1/statuses/\d+\z}
throttle('throttle_api_delete', limit: 30, period: 30.minutes) do |req|
req.authenticated_user_id if (req.post? && req.path.match?(API_DELETE_REBLOG_REGEX)) || (req.delete? && req.path.match?(API_DELETE_STATUS_REGEX))
end
throttle('throttle_sign_up_attempts/ip', limit: 25, period: 5.minutes) do |req|
req.throttleable_remote_ip if req.post? && req.path_matches?('/auth')
end
throttle('throttle_password_resets/ip', limit: 25, period: 5.minutes) do |req|
req.throttleable_remote_ip if req.post? && req.path_matches?('/auth/password')
end
throttle('throttle_password_resets/email', limit: 5, period: 30.minutes) do |req|
req.params.dig('user', 'email').presence if req.post? && req.path_matches?('/auth/password')
end
throttle('throttle_email_confirmations/ip', limit: 25, period: 5.minutes) do |req|
req.throttleable_remote_ip if req.post? && (req.path_matches?('/auth/confirmation') || req.path == '/api/v1/emails/confirmations')
end
throttle('throttle_email_confirmations/email', limit: 5, period: 30.minutes) do |req|
if req.post? && req.path_matches?('/auth/password')
req.params.dig('user', 'email').presence
elsif req.post? && req.path == '/api/v1/emails/confirmations'
req.authenticated_user_id
end
end
throttle('throttle_login_attempts/ip', limit: 25, period: 5.minutes) do |req|
req.throttleable_remote_ip if req.post? && req.path_matches?('/auth/sign_in')
end
throttle('throttle_login_attempts/email', limit: 25, period: 1.hour) do |req|
req.session[:attempt_user_id] || req.params.dig('user', 'email').presence if req.post? && req.path_matches?('/auth/sign_in')
end
self.throttled_responder = lambda do |request|
now = Time.now.utc
match_data = request.env['rack.attack.match_data']
headers = {
'Content-Type' => 'application/json',
'X-RateLimit-Limit' => match_data[:limit].to_s,
'X-RateLimit-Remaining' => '0',
'X-RateLimit-Reset' => (now + (match_data[:period] - (now.to_i % match_data[:period]))).iso8601(6),
}
[429, headers, [{ error: I18n.t('errors.429') }.to_json]]
end
end

View File

@@ -1,9 +0,0 @@
# frozen_string_literal: true
ActiveSupport::Notifications.subscribe(/rack_attack/) do |_name, _start, _finish, _request_id, payload|
req = payload[:request]
next unless [:throttle, :blacklist].include? req.env['rack.attack.match_type']
Rails.logger.info("Rate limit hit (#{req.env['rack.attack.match_type']}): #{req.ip} #{req.request_method} #{req.fullpath}")
end

View File

@@ -1,3 +0,0 @@
# frozen_string_literal: true
Redis.sadd_returns_boolean = false

View File

@@ -1,5 +0,0 @@
# frozen_string_literal: true
Rails.application.configure do
config.x.max_session_activations = ENV['MAX_SESSION_ACTIVATIONS'] || 10
end

View File

@@ -1,11 +0,0 @@
# frozen_string_literal: true
# Be sure to restart your server when you modify this file.
Rails
.application
.config
.session_store :cookie_store,
key: '_mastodon_session',
secure: false, # All cookies have their secure flag set by the force_ssl option in production
same_site: :lax

View File

@@ -1,39 +0,0 @@
# frozen_string_literal: true
require_relative '../../lib/mastodon/sidekiq_middleware'
Sidekiq.configure_server do |config|
config.redis = REDIS_SIDEKIQ_PARAMS
config.server_middleware do |chain|
chain.add Mastodon::SidekiqMiddleware
end
config.server_middleware do |chain|
chain.add SidekiqUniqueJobs::Middleware::Server
end
config.client_middleware do |chain|
chain.add SidekiqUniqueJobs::Middleware::Client
end
SidekiqUniqueJobs::Server.configure(config)
end
Sidekiq.configure_client do |config|
config.redis = REDIS_SIDEKIQ_PARAMS
config.client_middleware do |chain|
chain.add SidekiqUniqueJobs::Middleware::Client
end
end
Sidekiq.logger.level = ::Logger.const_get(ENV.fetch('RAILS_LOG_LEVEL', 'info').upcase.to_s)
SidekiqUniqueJobs.configure do |config|
config.reaper = :ruby
config.reaper_count = 1000
config.reaper_interval = 600
config.reaper_timeout = 150
config.lock_ttl = 50.days.to_i
end

View File

@@ -1,243 +0,0 @@
# frozen_string_literal: true
# Use this setup block to configure all options available in SimpleForm.
module AppendComponent
def append(_wrapper_options = nil)
@append ||= begin
options[:append].to_s.html_safe if options[:append].present?
end
end
end
module RecommendedComponent
def recommended(_wrapper_options = nil)
return unless options[:recommended]
key = options[:recommended].is_a?(Symbol) ? options[:recommended] : :recommended
options[:label_text] = ->(raw_label_text, _required_label_text, _label_present) { safe_join([raw_label_text, ' ', content_tag(:span, I18n.t(key, scope: 'simple_form'), class: key)]) }
nil
end
end
module WarningHintComponent
def warning_hint(_wrapper_options = nil)
@warning_hint ||= begin
options[:warning_hint].to_s.html_safe if options[:warning_hint].present?
end
end
end
module GlitchOnlyComponent
def glitch_only(_wrapper_options = nil)
return unless options[:glitch_only]
options[:label_text] = ->(raw_label_text, _required_label_text, _label_present) { safe_join([raw_label_text, ' ', content_tag(:span, I18n.t('simple_form.glitch_only'), class: 'glitch_only')]) }
nil
end
end
SimpleForm.include_component(AppendComponent)
SimpleForm.include_component(RecommendedComponent)
SimpleForm.include_component(WarningHintComponent)
SimpleForm.include_component(GlitchOnlyComponent)
SimpleForm.setup do |config|
# Wrappers are used by the form builder to generate a
# complete input. You can remove any component from the
# wrapper, change the order or even add your own to the
# stack. The options given below are used to wrap the
# whole input.
config.wrappers :default, class: :input, hint_class: :field_with_hint, error_class: :field_with_errors do |b|
## Extensions enabled by default
# Any of these extensions can be disabled for a
# given input by passing: `f.input EXTENSION_NAME => false`.
# You can make any of these extensions optional by
# renaming `b.use` to `b.optional`.
# Determines whether to use HTML5 (:email, :url, ...)
# and required attributes
b.use :html5
# Calculates placeholders automatically from I18n
# You can also pass a string as f.input placeholder: "Placeholder"
b.use :placeholder
## Optional extensions
# They are disabled unless you pass `f.input EXTENSION_NAME => true`
# to the input. If so, they will retrieve the values from the model
# if any exists. If you want to enable any of those
# extensions by default, you can change `b.optional` to `b.use`.
# Calculates maxlength from length validations for string inputs
b.optional :maxlength
# Calculates pattern from format validations for string inputs
b.optional :pattern
# Calculates min and max from length validations for numeric inputs
b.optional :min_max
# Calculates readonly automatically from readonly attributes
b.optional :readonly
## Inputs
b.use :input
b.use :hint, wrap_with: { tag: :span, class: :hint }
b.use :error, wrap_with: { tag: :span, class: :error }
## full_messages_for
# If you want to display the full error message for the attribute, you can
# use the component :full_error, like:
#
# b.use :full_error, wrap_with: { tag: :span, class: :error }
end
config.wrappers :with_label, class: [:input, :with_label], hint_class: :field_with_hint, error_class: :field_with_errors do |b|
b.use :html5
b.wrapper tag: :div, class: :label_input do |ba|
ba.optional :recommended
ba.optional :glitch_only
ba.use :label
ba.wrapper tag: :div, class: :label_input__wrapper do |bb|
bb.use :input
bb.optional :append, wrap_with: { tag: :div, class: 'label_input__append' }
end
end
b.use :warning_hint, wrap_with: { tag: :span, class: [:hint, 'warning-hint'] }
b.use :hint, wrap_with: { tag: :span, class: :hint }
b.use :error, wrap_with: { tag: :span, class: :error }
end
config.wrappers :with_floating_label, class: [:input, :with_floating_label], hint_class: :field_with_hint, error_class: :field_with_errors do |b|
b.use :html5
b.use :label_input, wrap_with: { tag: :div, class: :label_input }
b.use :hint, wrap_with: { tag: :span, class: :hint }
b.use :error, wrap_with: { tag: :span, class: :error }
end
config.wrappers :with_block_label, class: [:input, :with_block_label], hint_class: :field_with_hint, error_class: :field_with_errors do |b|
b.use :html5
b.use :label
b.use :warning_hint, wrap_with: { tag: :span, class: [:hint, 'warning-hint'] }
b.use :hint, wrap_with: { tag: :span, class: :hint }
b.use :input, wrap_with: { tag: :div, class: :label_input }
b.use :error, wrap_with: { tag: :span, class: :error }
end
# The default wrapper to be used by the FormBuilder.
config.default_wrapper = :default
# Define the way to render check boxes / radio buttons with labels.
# Defaults to :nested for bootstrap config.
# inline: input + label
# nested: label > input
config.boolean_style = :nested
# Default class for buttons
config.button_class = 'btn'
# Method used to tidy up errors. Specify any Rails Array method.
# :first lists the first message for each field.
# Use :to_sentence to list all errors for each field.
# config.error_method = :first
# Default tag used for error notification helper.
config.error_notification_tag = :div
# CSS class to add for error notification helper.
config.error_notification_class = 'error_notification'
# ID to add for error notification helper.
# config.error_notification_id = nil
# Series of attempts to detect a default label method for collection.
# config.collection_label_methods = [ :to_label, :name, :title, :to_s ]
# Series of attempts to detect a default value method for collection.
# config.collection_value_methods = [ :id, :to_s ]
# You can wrap a collection of radio/check boxes in a pre-defined tag, defaulting to none.
# config.collection_wrapper_tag = nil
# You can define the class to use on all collection wrappers. Defaulting to none.
# config.collection_wrapper_class = nil
# You can wrap each item in a collection of radio/check boxes with a tag,
# defaulting to :span.
# config.item_wrapper_tag = :span
# You can define a class to use in all item wrappers. Defaulting to none.
# config.item_wrapper_class = nil
# How the label text should be generated altogether with the required text.
config.label_text = lambda { |label, required, explicit_label| "#{label} #{required}" }
# You can define the class to use on all labels. Default is nil.
# config.label_class = nil
# You can define the default class to be used on forms. Can be overridden
# with `html: { :class }`. Defaulting to none.
# config.default_form_class = nil
# You can define which elements should obtain additional classes
# config.generate_additional_classes_for = [:wrapper, :label, :input]
# Whether attributes are required by default (or not). Default is true.
# config.required_by_default = true
# Tell browsers whether to use the native HTML5 validations (novalidate form option).
# These validations are enabled in SimpleForm's internal config but disabled by default
# in this configuration, which is recommended due to some quirks from different browsers.
# To stop SimpleForm from generating the novalidate option, enabling the HTML5 validations,
# change this configuration to true.
config.browser_validations = false
# Collection of methods to detect if a file type was given.
# config.file_methods = [ :mounted_as, :file?, :public_filename ]
# Custom mappings for input types. This should be a hash containing a regexp
# to match as key, and the input type that will be used when the field name
# matches the regexp as value.
# config.input_mappings = { /count/ => :integer }
# Custom wrappers for input types. This should be a hash containing an input
# type as key and the wrapper that will be used for all inputs with specified type.
# config.wrapper_mappings = { string: :prepend }
# Namespaces where SimpleForm should look for custom input classes that
# override default inputs.
# config.custom_inputs_namespaces << "CustomInputs"
# Default priority for time_zone inputs.
# config.time_zone_priority = nil
# Default priority for country inputs.
# config.country_priority = nil
# When false, do not use translations for labels.
# config.translate_labels = true
# Automatically discover new inputs in Rails' autoload path.
# config.inputs_discovery = true
# Cache SimpleForm inputs discovery
# config.cache_discovery = !Rails.env.development?
# Default class for inputs
# config.input_class = nil
# Define the default class of the input wrapper of the boolean input.
config.boolean_label_class = 'checkbox'
# Defines if the default input wrapper class should be included in radio
# collection wrappers.
# config.include_default_input_wrapper_class = true
# Defines which i18n scope will be used in Simple Form.
# config.i18n_scope = 'simple_form'
end

View File

@@ -1,5 +0,0 @@
# frozen_string_literal: true
Rails.application.configure do
config.x.single_user_mode = ENV['SINGLE_USER_MODE'] == 'true'
end

View File

@@ -1,15 +0,0 @@
# frozen_string_literal: true
if ENV['STATSD_ADDR'].present?
host, port = ENV['STATSD_ADDR'].split(':')
statsd = Statsd.new(host, port)
statsd.namespace = ENV.fetch('STATSD_NAMESPACE') { ['Mastodon', Rails.env].join('.') }
NSA.inform_statsd(statsd) do |informant|
informant.collect(:action_controller, :web)
informant.collect(:active_record, :db)
informant.collect(:active_support_cache, :cache)
informant.collect(:sidekiq, :sidekiq) if ENV['STATSD_SIDEKIQ'] == 'true'
end
end

View File

@@ -1,8 +0,0 @@
# frozen_string_literal: true
require 'stoplight'
Rails.application.reloader.to_prepare do
Stoplight::Light.default_data_store = Stoplight::DataStore::Redis.new(RedisConfiguration.new.connection)
Stoplight::Light.default_notifiers = [Stoplight::Notifier::Logger.new(Rails.logger)]
end

View File

@@ -1,4 +0,0 @@
# frozen_string_literal: true
StrongMigrations.start_after = 2017_09_24_022025
StrongMigrations.target_version = 10

View File

@@ -1,5 +0,0 @@
# frozen_string_literal: true
Rails.application.reloader.to_prepare do
ActionController::Base.log_warning_on_csrf_failure = false
end

View File

@@ -1,13 +0,0 @@
# frozen_string_literal: true
module Rack
class Request
def trusted_proxy?(ip)
if Rails.application.config.action_dispatch.trusted_proxies.nil?
super
else
Rails.application.config.action_dispatch.trusted_proxies.any? { |proxy| proxy === ip }
end
end
end
end

View File

@@ -1,82 +0,0 @@
# frozen_string_literal: true
module Twitter::TwitterText
class Configuration
def emoji_parsing_enabled
false
end
end
class Regex
REGEXEN[:valid_general_url_path_chars] = /[^\p{White_Space}<>()?]/iou
REGEXEN[:valid_url_path_ending_chars] = /[^\p{White_Space}()?!*"'「」<>;:=,.$%\[\]~&|@]|(?:#{REGEXEN[:valid_url_balanced_parens]})/iou
REGEXEN[:valid_url_balanced_parens] = /
\(
(?:
#{REGEXEN[:valid_general_url_path_chars]}+
|
# allow one nested level of balanced parentheses
(?:
#{REGEXEN[:valid_general_url_path_chars]}*
\(
#{REGEXEN[:valid_general_url_path_chars]}+
\)
#{REGEXEN[:valid_general_url_path_chars]}*
)
)
\)
/iox
# rubocop:disable Layout/LineLength
UCHARS = '\u{A0}-\u{D7FF}\u{F900}-\u{FDCF}\u{FDF0}-\u{FFEF}\u{10000}-\u{1FFFD}\u{20000}-\u{2FFFD}\u{30000}-\u{3FFFD}\u{40000}-\u{4FFFD}\u{50000}-\u{5FFFD}\u{60000}-\u{6FFFD}\u{70000}-\u{7FFFD}\u{80000}-\u{8FFFD}\u{90000}-\u{9FFFD}\u{A0000}-\u{AFFFD}\u{B0000}-\u{BFFFD}\u{C0000}-\u{CFFFD}\u{D0000}-\u{DFFFD}\u{E1000}-\u{EFFFD}\u{E000}-\u{F8FF}\u{F0000}-\u{FFFFD}\u{100000}-\u{10FFFD}'
# rubocop:enable Layout/LineLength
REGEXEN[:valid_url_query_chars] = %r{[a-z0-9!?*'();:&=+$/%#\[\]\-_.,~|@\^#{UCHARS}]}iou
REGEXEN[:valid_url_query_ending_chars] = %r{[a-z0-9_&=#/\-#{UCHARS}]}iou
REGEXEN[:valid_url_path] = %r{(?:
(?:
#{REGEXEN[:valid_general_url_path_chars]}*
(?:#{REGEXEN[:valid_url_balanced_parens]} #{REGEXEN[:valid_general_url_path_chars]}*)*
#{REGEXEN[:valid_url_path_ending_chars]}
)|(?:#{REGEXEN[:valid_general_url_path_chars]}+/)
)}iox
REGEXEN[:valid_url] = %r{
( # $1 total match
(#{REGEXEN[:valid_url_preceding_chars]}) # $2 Preceding character
( # $3 URL
((?:https?|dat|dweb|ipfs|ipns|ssb|gopher|gemini)://)? # $4 Protocol (optional)
(#{REGEXEN[:valid_domain]}) # $5 Domain(s)
(?::(#{REGEXEN[:valid_port_number]}))? # $6 Port number (optional)
(/#{REGEXEN[:valid_url_path]}*)? # $7 URL Path and anchor
(\?#{REGEXEN[:valid_url_query_chars]}*#{REGEXEN[:valid_url_query_ending_chars]})? # $8 Query String
)
)
}iox
REGEXEN[:validate_nodeid] = /(?:
#{REGEXEN[:validate_url_unreserved]}|
#{REGEXEN[:validate_url_pct_encoded]}|
[!$()*+,;=]
)/iox
REGEXEN[:validate_resid] = /(?:
#{REGEXEN[:validate_url_unreserved]}|
#{REGEXEN[:validate_url_pct_encoded]}|
#{REGEXEN[:validate_url_sub_delims]}
)/iox
REGEXEN[:valid_extended_uri] = %r{
( # $1 total match
(#{REGEXEN[:valid_url_preceding_chars]}) # $2 Preceding character
( # $3 URL
(
(xmpp:) # Protocol
(//#{REGEXEN[:validate_nodeid]}+@#{REGEXEN[:valid_domain]}/)? # Authority (optional)
(#{REGEXEN[:validate_nodeid]}+@)? # Username in path (optional)
(#{REGEXEN[:valid_domain]}) # Domain in path
(/#{REGEXEN[:validate_resid]}+)? # Resource in path (optional)
(\?#{REGEXEN[:valid_url_query_chars]}*#{REGEXEN[:valid_url_query_ending_chars]})? # Query String
) | (
(magnet:) # Protocol
(\?#{REGEXEN[:valid_url_query_chars]}*#{REGEXEN[:valid_url_query_ending_chars]}) # Query String
)
)
)
}iox
end
end

View File

@@ -1,16 +0,0 @@
# frozen_string_literal: true
Rails.application.configure do
# You can generate the keys using the following command (first is the private key, second is the public one)
# You should only generate this once per instance. If you later decide to change it, all push subscription will
# be invalidated, requiring the users to access the website again to resubscribe.
#
# Generate with `rake mastodon:webpush:generate_vapid_key` task (`docker-compose run --rm web rake mastodon:webpush:generate_vapid_key` if you use docker compose)
#
# For more information visit https://rossta.net/blog/using-the-web-push-api-with-vapid.html
if Rails.env.production?
config.x.vapid_private_key = ENV['VAPID_PRIVATE_KEY']
config.x.vapid_public_key = ENV['VAPID_PUBLIC_KEY']
end
end

View File

@@ -1,26 +0,0 @@
# frozen_string_literal: true
WebAuthn.configure do |config|
# This value needs to match `window.location.origin` evaluated by
# the User Agent during registration and authentication ceremonies.
config.origin = "#{Rails.configuration.x.use_https ? 'https' : 'http'}://#{Rails.configuration.x.web_domain}"
# Relying Party name for display purposes
config.rp_name = "Mastodon"
# Optionally configure a client timeout hint, in milliseconds.
# This hint specifies how long the browser should wait for an
# attestation or an assertion response.
# This hint may be overridden by the browser.
# https://www.w3.org/TR/webauthn/#dom-publickeycredentialcreationoptions-timeout
config.credential_options_timeout = 120_000
# You can optionally specify a different Relying Party ID
# (https://www.w3.org/TR/webauthn/#relying-party-identifier)
# if it differs from the default one.
#
# In this case the default would be "auth.example.com", but you can set it to
# the suffix "example.com"
#
# config.rp_id = "example.com"
end

View File

@@ -1,16 +0,0 @@
# frozen_string_literal: true
# Be sure to restart your server when you modify this file.
# This file contains settings for ActionController::ParamsWrapper which
# is enabled by default.
# Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
ActiveSupport.on_load(:action_controller) do
wrap_parameters format: [:json]
end
# To enable root element in JSON for ActiveRecord objects.
# ActiveSupport.on_load(:active_record) do
# self.include_root_in_json = true
# end

View File

@@ -1,73 +0,0 @@
# frozen_string_literal: true
SimpleNavigation::Configuration.run do |navigation|
navigation.items do |n|
n.item :web, safe_join([fa_icon('chevron-left fw'), t('settings.back')]), root_path
n.item :software_updates, safe_join([fa_icon('exclamation-circle fw'), t('admin.critical_update_pending')]), admin_software_updates_path, if: -> { ENV['UPDATE_CHECK_URL'] != '' && current_user.can?(:view_devops) && SoftwareUpdate.urgent_pending? }, html: { class: 'warning' }
n.item :profile, safe_join([fa_icon('user fw'), t('settings.profile')]), settings_profile_path, if: -> { current_user.functional? }, highlights_on: %r{/settings/profile|/settings/featured_tags|/settings/verification|/settings/privacy}
n.item :preferences, safe_join([fa_icon('cog fw'), t('settings.preferences')]), settings_preferences_path, if: -> { current_user.functional? } do |s|
s.item :appearance, safe_join([fa_icon('desktop fw'), t('settings.appearance')]), settings_preferences_appearance_path
s.item :notifications, safe_join([fa_icon('bell fw'), t('settings.notifications')]), settings_preferences_notifications_path
s.item :other, safe_join([fa_icon('cog fw'), t('preferences.other')]), settings_preferences_other_path
end
n.item :flavours, safe_join([fa_icon('paint-brush fw'), t('settings.flavours')]), settings_flavours_path do |flavours|
Themes.instance.flavours.each do |flavour|
flavours.item flavour.to_sym, safe_join([fa_icon('star fw'), t("flavours.#{flavour}.name", default: flavour)]), settings_flavour_path(flavour)
end
end
n.item :relationships, safe_join([fa_icon('users fw'), t('settings.relationships')]), relationships_path, if: -> { current_user.functional? }
n.item :filters, safe_join([fa_icon('filter fw'), t('filters.index.title')]), filters_path, highlights_on: %r{/filters}, if: -> { current_user.functional? }
n.item :statuses_cleanup, safe_join([fa_icon('history fw'), t('settings.statuses_cleanup')]), statuses_cleanup_path, if: -> { current_user.functional_or_moved? }
n.item :security, safe_join([fa_icon('lock fw'), t('settings.account')]), edit_user_registration_path do |s|
s.item :password, safe_join([fa_icon('lock fw'), t('settings.account_settings')]), edit_user_registration_path, highlights_on: %r{/auth/edit|/settings/delete|/settings/migration|/settings/aliases|/settings/login_activities|^/disputes}
s.item :two_factor_authentication, safe_join([fa_icon('mobile fw'), t('settings.two_factor_authentication')]), settings_two_factor_authentication_methods_path, highlights_on: %r{/settings/two_factor_authentication|/settings/otp_authentication|/settings/security_keys}
s.item :authorized_apps, safe_join([fa_icon('list fw'), t('settings.authorized_apps')]), oauth_authorized_applications_path
end
n.item :data, safe_join([fa_icon('cloud-download fw'), t('settings.import_and_export')]), settings_export_path do |s|
s.item :import, safe_join([fa_icon('cloud-upload fw'), t('settings.import')]), settings_imports_path, if: -> { current_user.functional? }
s.item :export, safe_join([fa_icon('cloud-download fw'), t('settings.export')]), settings_export_path
end
n.item :invites, safe_join([fa_icon('user-plus fw'), t('invites.title')]), invites_path, if: -> { current_user.can?(:invite_users) && current_user.functional? }
n.item :development, safe_join([fa_icon('code fw'), t('settings.development')]), settings_applications_path, if: -> { current_user.functional? }
n.item :trends, safe_join([fa_icon('fire fw'), t('admin.trends.title')]), admin_trends_statuses_path, if: -> { current_user.can?(:manage_taxonomies) } do |s|
s.item :statuses, safe_join([fa_icon('comments-o fw'), t('admin.trends.statuses.title')]), admin_trends_statuses_path, highlights_on: %r{/admin/trends/statuses}
s.item :tags, safe_join([fa_icon('hashtag fw'), t('admin.trends.tags.title')]), admin_trends_tags_path, highlights_on: %r{/admin/tags|/admin/trends/tags}
s.item :links, safe_join([fa_icon('newspaper-o fw'), t('admin.trends.links.title')]), admin_trends_links_path, highlights_on: %r{/admin/trends/links}
end
n.item :moderation, safe_join([fa_icon('gavel fw'), t('moderation.title')]), nil, if: -> { current_user.can?(:manage_reports, :view_audit_log, :manage_users, :manage_invites, :manage_taxonomies, :manage_federation, :manage_blocks) } do |s|
s.item :reports, safe_join([fa_icon('flag fw'), t('admin.reports.title')]), admin_reports_path, highlights_on: %r{/admin/reports}, if: -> { current_user.can?(:manage_reports) }
s.item :accounts, safe_join([fa_icon('users fw'), t('admin.accounts.title')]), admin_accounts_path(origin: 'local'), highlights_on: %r{/admin/accounts|/admin/pending_accounts|/admin/disputes|/admin/users}, if: -> { current_user.can?(:manage_users) }
s.item :invites, safe_join([fa_icon('user-plus fw'), t('admin.invites.title')]), admin_invites_path, if: -> { current_user.can?(:manage_invites) }
s.item :follow_recommendations, safe_join([fa_icon('user-plus fw'), t('admin.follow_recommendations.title')]), admin_follow_recommendations_path, highlights_on: %r{/admin/follow_recommendations}, if: -> { current_user.can?(:manage_taxonomies) }
s.item :instances, safe_join([fa_icon('cloud fw'), t('admin.instances.title')]), admin_instances_path(limited: limited_federation_mode? ? nil : '1'), highlights_on: %r{/admin/instances|/admin/domain_blocks|/admin/domain_allows}, if: -> { current_user.can?(:manage_federation) }
s.item :email_domain_blocks, safe_join([fa_icon('envelope fw'), t('admin.email_domain_blocks.title')]), admin_email_domain_blocks_path, highlights_on: %r{/admin/email_domain_blocks}, if: -> { current_user.can?(:manage_blocks) }
s.item :ip_blocks, safe_join([fa_icon('ban fw'), t('admin.ip_blocks.title')]), admin_ip_blocks_path, highlights_on: %r{/admin/ip_blocks}, if: -> { current_user.can?(:manage_blocks) }
s.item :action_logs, safe_join([fa_icon('bars fw'), t('admin.action_logs.title')]), admin_action_logs_path, if: -> { current_user.can?(:view_audit_log) }
end
n.item :admin, safe_join([fa_icon('cogs fw'), t('admin.title')]), nil, if: -> { current_user.can?(:view_dashboard, :manage_settings, :manage_rules, :manage_announcements, :manage_custom_emojis, :manage_webhooks, :manage_federation) } do |s|
s.item :dashboard, safe_join([fa_icon('tachometer fw'), t('admin.dashboard.title')]), admin_dashboard_path, if: -> { current_user.can?(:view_dashboard) }
s.item :settings, safe_join([fa_icon('cogs fw'), t('admin.settings.title')]), admin_settings_path, if: -> { current_user.can?(:manage_settings) }, highlights_on: %r{/admin/settings}
s.item :rules, safe_join([fa_icon('gavel fw'), t('admin.rules.title')]), admin_rules_path, highlights_on: %r{/admin/rules}, if: -> { current_user.can?(:manage_rules) }
s.item :roles, safe_join([fa_icon('vcard fw'), t('admin.roles.title')]), admin_roles_path, highlights_on: %r{/admin/roles}, if: -> { current_user.can?(:manage_roles) }
s.item :announcements, safe_join([fa_icon('bullhorn fw'), t('admin.announcements.title')]), admin_announcements_path, highlights_on: %r{/admin/announcements}, if: -> { current_user.can?(:manage_announcements) }
s.item :custom_emojis, safe_join([fa_icon('smile-o fw'), t('admin.custom_emojis.title')]), admin_custom_emojis_path, highlights_on: %r{/admin/custom_emojis}, if: -> { current_user.can?(:manage_custom_emojis) }
s.item :webhooks, safe_join([fa_icon('inbox fw'), t('admin.webhooks.title')]), admin_webhooks_path, highlights_on: %r{/admin/webhooks}, if: -> { current_user.can?(:manage_webhooks) }
s.item :relays, safe_join([fa_icon('exchange fw'), t('admin.relays.title')]), admin_relays_path, highlights_on: %r{/admin/relays}, if: -> { !limited_federation_mode? && current_user.can?(:manage_federation) }
end
n.item :sidekiq, safe_join([fa_icon('diamond fw'), 'Sidekiq']), sidekiq_path, link_html: { target: 'sidekiq' }, if: -> { current_user.can?(:view_devops) }
n.item :pghero, safe_join([fa_icon('database fw'), 'PgHero']), pghero_path, link_html: { target: 'pghero' }, if: -> { current_user.can?(:view_devops) }
n.item :logout, safe_join([fa_icon('sign-out fw'), t('auth.logout')]), destroy_user_session_path, link_html: { 'data-method' => 'delete' }
end
end

View File

@@ -1,41 +0,0 @@
databases:
primary:
# Database URL (defaults to app database)
# url: <%= ENV["DATABASE_URL"] %>
# Add more databases
# other:
# url: <%= ENV["OTHER_DATABASE_URL"] %>
# Minimum time for long running queries
# long_running_query_sec: 60
# Minimum average time for slow queries
# slow_query_ms: 20
# Minimum calls for slow queries
# slow_query_calls: 100
# Minimum connections for high connections warning
# total_connections_threshold: 500
# Statement timeout for explain
# explain_timeout_sec: 10
# Time zone (defaults to app time zone)
# time_zone: "Pacific Time (US & Canada)"
# Basic authentication
# username: admin
# password: secret
# Stats database URL (defaults to app database)
# stats_database_url: <%= ENV["PGHERO_STATS_DATABASE_URL"] %>
# AWS configuration (defaults to app AWS config)
# also need aws_db_instance_identifier with each database
# aws_access_key_id: ...
# aws_secret_access_key: ...
# aws_region: us-east-1
override_csp: false

View File

@@ -1,28 +0,0 @@
# frozen_string_literal: true
persistent_timeout ENV.fetch('PERSISTENT_TIMEOUT') { 20 }.to_i
max_threads_count = ENV.fetch('MAX_THREADS') { 5 }.to_i
min_threads_count = ENV.fetch('MIN_THREADS') { max_threads_count }.to_i
threads min_threads_count, max_threads_count
if ENV['SOCKET']
bind "unix://#{ENV['SOCKET']}"
else
bind "tcp://#{ENV.fetch('BIND', '127.0.0.1')}:#{ENV.fetch('PORT', 3000)}"
end
environment ENV.fetch('RAILS_ENV') { 'development' }
workers ENV.fetch('WEB_CONCURRENCY') { 2 }.to_i
preload_app!
on_worker_boot do
ActiveSupport.on_load(:active_record) do
ActiveRecord::Base.establish_connection
end
end
plugin :tmp_restart
set_remote_address(proxy_protocol: :v1) if ENV['PROXY_PROTO_V1'] == 'true'

View File

@@ -1,192 +0,0 @@
# frozen_string_literal: true
require 'sidekiq_unique_jobs/web'
require 'sidekiq-scheduler/web'
Rails.application.routes.draw do
# Paths of routes on the web app that to not require to be indexed or
# have alternative format representations requiring separate controllers
web_app_paths = %w(
/getting-started
/getting-started-misc
/keyboard-shortcuts
/home
/public
/public/local
/public/remote
/conversations
/lists/(*any)
/notifications
/favourites
/bookmarks
/pinned
/start
/directory
/explore/(*any)
/search
/publish
/follow_requests
/blocks
/domain_blocks
/mutes
/followed_tags
/statuses/(*any)
/deck/(*any)
).freeze
root 'home#index'
mount LetterOpenerWeb::Engine, at: 'letter_opener' if Rails.env.development?
get 'health', to: 'health#show'
authenticate :user, lambda { |u| u.role&.can?(:view_devops) } do
mount Sidekiq::Web, at: 'sidekiq', as: :sidekiq
mount PgHero::Engine, at: 'pghero', as: :pghero
end
use_doorkeeper do
controllers authorizations: 'oauth/authorizations',
authorized_applications: 'oauth/authorized_applications',
tokens: 'oauth/tokens'
end
get '.well-known/host-meta', to: 'well_known/host_meta#show', as: :host_meta, defaults: { format: 'xml' }
get '.well-known/nodeinfo', to: 'well_known/nodeinfo#index', as: :nodeinfo, defaults: { format: 'json' }
get '.well-known/webfinger', to: 'well_known/webfinger#show', as: :webfinger
get '.well-known/change-password', to: redirect('/auth/edit')
get '.well-known/proxy', to: redirect { |_, request| "/authorize_interaction?#{request.params.to_query}" }
get '/nodeinfo/2.0', to: 'well_known/nodeinfo#show', as: :nodeinfo_schema
get 'manifest', to: 'manifests#show', defaults: { format: 'json' }
get 'intent', to: 'intents#show'
get 'custom.css', to: 'custom_css#show', as: :custom_css
get 'remote_interaction_helper', to: 'remote_interaction_helper#index'
resource :instance_actor, path: 'actor', only: [:show] do
resource :inbox, only: [:create], module: :activitypub
resource :outbox, only: [:show], module: :activitypub
end
devise_scope :user do
get '/invite/:invite_code', to: 'auth/registrations#new', as: :public_invite
resource :unsubscribe, only: [:show, :create], controller: :mail_subscriptions
namespace :auth do
resource :setup, only: [:show, :update], controller: :setup
resource :challenge, only: [:create], controller: :challenges
get 'sessions/security_key_options', to: 'sessions#webauthn_options'
post 'captcha_confirmation', to: 'confirmations#confirm_captcha', as: :captcha_confirmation
end
end
devise_for :users, path: 'auth', format: false, controllers: {
omniauth_callbacks: 'auth/omniauth_callbacks',
sessions: 'auth/sessions',
registrations: 'auth/registrations',
passwords: 'auth/passwords',
confirmations: 'auth/confirmations',
}
get '/users/:username', to: redirect('/@%{username}'), constraints: lambda { |req| req.format.nil? || req.format.html? }
get '/users/:username/following', to: redirect('/@%{username}/following'), constraints: lambda { |req| req.format.nil? || req.format.html? }
get '/users/:username/followers', to: redirect('/@%{username}/followers'), constraints: lambda { |req| req.format.nil? || req.format.html? }
get '/users/:username/statuses/:id', to: redirect('/@%{username}/%{id}'), constraints: lambda { |req| req.format.nil? || req.format.html? }
get '/authorize_follow', to: redirect { |_, request| "/authorize_interaction?#{request.params.to_query}" }
resources :accounts, path: 'users', only: [:show], param: :username do
resources :statuses, only: [:show] do
member do
get :activity
get :embed
end
resources :replies, only: [:index], module: :activitypub
end
resources :followers, only: [:index], controller: :follower_accounts
resources :following, only: [:index], controller: :following_accounts
resource :outbox, only: [:show], module: :activitypub
resource :inbox, only: [:create], module: :activitypub
resource :claim, only: [:create], module: :activitypub
resources :collections, only: [:show], module: :activitypub
resource :followers_synchronization, only: [:show], module: :activitypub
end
resource :inbox, only: [:create], module: :activitypub
get '/:encoded_at(*path)', to: redirect("/@%{path}"), constraints: { encoded_at: /%40/ }
constraints(username: %r{[^@/.]+}) do
get '/@:username', to: 'accounts#show', as: :short_account
get '/@:username/with_replies', to: 'accounts#show', as: :short_account_with_replies
get '/@:username/media', to: 'accounts#show', as: :short_account_media
get '/@:username/tagged/:tag', to: 'accounts#show', as: :short_account_tag
end
constraints(account_username: %r{[^@/.]+}) do
get '/@:account_username/following', to: 'following_accounts#index'
get '/@:account_username/followers', to: 'follower_accounts#index'
get '/@:account_username/:id', to: 'statuses#show', as: :short_account_status
get '/@:account_username/:id/embed', to: 'statuses#embed', as: :embed_short_account_status
end
get '/@:username_with_domain/(*any)', to: 'home#index', constraints: { username_with_domain: %r{([^/])+?} }, format: false
get '/settings', to: redirect('/settings/profile')
draw(:settings)
namespace :disputes do
resources :strikes, only: [:show, :index] do
resource :appeal, only: [:create]
end
end
resources :media, only: [:show] do
get :player
end
resources :tags, only: [:show]
resources :emojis, only: [:show]
resources :invites, only: [:index, :create, :destroy]
resources :filters, except: [:show] do
resources :statuses, only: [:index], controller: 'filters/statuses' do
collection do
post :batch
end
end
end
resource :relationships, only: [:show, :update]
resource :statuses_cleanup, controller: :statuses_cleanup, only: [:show, :update]
get '/media_proxy/:id/(*any)', to: 'media_proxy#show', as: :media_proxy, format: false
get '/backups/:id/download', to: 'backups#download', as: :download_backup, format: false
resource :authorize_interaction, only: [:show]
resource :share, only: [:show]
draw(:admin)
get '/admin', to: redirect('/admin/dashboard', status: 302)
draw(:api)
web_app_paths.each do |path|
get path, to: 'home#index'
end
get '/web/(*any)', to: redirect('/%{any}', status: 302), as: :web, defaults: { any: '' }, format: false
get '/about', to: 'about#show'
get '/about/more', to: redirect('/about')
get '/privacy-policy', to: 'privacy#show', as: :privacy_policy
get '/terms', to: redirect('/privacy-policy')
match '/', via: [:post, :put, :patch, :delete], to: 'application#raise_not_found', format: false
match '*unmatched_route', via: :all, to: 'application#raise_not_found', format: false
end

View File

@@ -1,207 +0,0 @@
# frozen_string_literal: true
namespace :admin do
get '/dashboard', to: 'dashboard#index'
resources :domain_allows, only: [:new, :create, :destroy]
resources :domain_blocks, only: [:new, :create, :destroy, :update, :edit] do
collection do
post :batch
end
end
resources :export_domain_allows, only: [:new] do
collection do
get :export, constraints: { format: :csv }
post :import
end
end
resources :export_domain_blocks, only: [:new] do
collection do
get :export, constraints: { format: :csv }
post :import
end
end
resources :email_domain_blocks, only: [:index, :new, :create] do
collection do
post :batch
end
end
resources :action_logs, only: [:index]
resources :warning_presets, except: [:new, :show]
resources :announcements, except: [:show] do
member do
post :publish
post :unpublish
end
end
get '/settings', to: redirect('/admin/settings/branding')
get '/settings/edit', to: redirect('/admin/settings/branding')
namespace :settings do
resource :branding, only: [:show, :update], controller: 'branding'
resource :registrations, only: [:show, :update], controller: 'registrations'
resource :content_retention, only: [:show, :update], controller: 'content_retention'
resource :about, only: [:show, :update], controller: 'about'
resource :appearance, only: [:show, :update], controller: 'appearance'
resource :discovery, only: [:show, :update], controller: 'discovery'
resource :other, only: [:show, :update], controller: 'other'
end
resources :site_uploads, only: [:destroy]
resources :invites, only: [:index, :create, :destroy] do
collection do
post :deactivate_all
end
end
resources :relays, only: [:index, :new, :create, :destroy] do
member do
post :enable
post :disable
end
end
resources :instances, only: [:index, :show, :destroy], constraints: { id: %r{[^/]+} }, format: 'html' do
member do
post :clear_delivery_errors
post :restart_delivery
post :stop_delivery
end
end
resources :rules, only: [:index, :create, :edit, :update, :destroy]
resources :webhooks do
member do
post :enable
post :disable
end
resource :secret, only: [], controller: 'webhooks/secrets' do
post :rotate
end
end
resources :reports, only: [:index, :show] do
resources :actions, only: [:create], controller: 'reports/actions' do
collection do
post :preview
end
end
member do
post :assign_to_self
post :unassign
post :reopen
post :resolve
end
end
resources :report_notes, only: [:create, :destroy]
resources :accounts, only: [:index, :show, :destroy] do
member do
post :enable
post :unsensitive
post :unsilence
post :unsuspend
post :redownload
post :remove_avatar
post :remove_header
post :memorialize
post :approve
post :reject
post :unblock_email
end
collection do
post :batch
end
resource :change_email, only: [:show, :update]
resource :reset, only: [:create]
resource :action, only: [:new, :create], controller: 'account_actions'
resources :statuses, only: [:index, :show] do
collection do
post :batch
end
end
resources :relationships, only: [:index]
resource :confirmation, only: [:create] do
collection do
post :resend
end
end
end
resources :users, only: [] do
resource :two_factor_authentication, only: [:destroy], controller: 'users/two_factor_authentications'
resource :role, only: [:show, :update], controller: 'users/roles'
end
resources :custom_emojis, only: [:index, :new, :create] do
collection do
post :batch
end
end
resources :ip_blocks, only: [:index, :new, :create] do
collection do
post :batch
end
end
resources :roles, except: [:show]
resources :account_moderation_notes, only: [:create, :destroy]
resource :follow_recommendations, only: [:show, :update]
resources :tags, only: [:show, :update]
namespace :trends do
resources :links, only: [:index] do
collection do
post :batch
end
end
resources :tags, only: [:index] do
collection do
post :batch
end
end
resources :statuses, only: [:index] do
collection do
post :batch
end
end
namespace :links do
resources :preview_card_providers, only: [:index], path: :publishers do
collection do
post :batch
end
end
end
end
namespace :disputes do
resources :appeals, only: [:index] do
member do
post :approve
post :reject
end
end
end
resources :software_updates, only: [:index]
end

View File

@@ -1,320 +0,0 @@
# frozen_string_literal: true
namespace :api, format: false do
# OEmbed
get '/oembed', to: 'oembed#show', as: :oembed
# JSON / REST API
namespace :v1 do
resources :statuses, only: [:create, :show, :update, :destroy] do
scope module: :statuses do
resources :reblogged_by, controller: :reblogged_by_accounts, only: :index
resources :favourited_by, controller: :favourited_by_accounts, only: :index
resource :reblog, only: :create
post :unreblog, to: 'reblogs#destroy'
resource :favourite, only: :create
post :unfavourite, to: 'favourites#destroy'
resource :bookmark, only: :create
post :unbookmark, to: 'bookmarks#destroy'
resource :mute, only: :create
post :unmute, to: 'mutes#destroy'
resource :pin, only: :create
post :unpin, to: 'pins#destroy'
resource :history, only: :show
resource :source, only: :show
post :translate, to: 'translations#create'
end
member do
get :context
end
end
namespace :timelines do
resource :direct, only: :show, controller: :direct
resource :home, only: :show, controller: :home
resource :public, only: :show, controller: :public
resources :tag, only: :show
resources :list, only: :show
end
get '/streaming', to: 'streaming#index'
get '/streaming/(*any)', to: 'streaming#index'
resources :custom_emojis, only: [:index]
resources :suggestions, only: [:index, :destroy]
resources :scheduled_statuses, only: [:index, :show, :update, :destroy]
resources :preferences, only: [:index]
resources :announcements, only: [:index] do
scope module: :announcements do
resources :reactions, only: [:update, :destroy]
end
member do
post :dismiss
end
end
# namespace :crypto do
# resources :deliveries, only: :create
# namespace :keys do
# resource :upload, only: [:create]
# resource :query, only: [:create]
# resource :claim, only: [:create]
# resource :count, only: [:show]
# end
# resources :encrypted_messages, only: [:index] do
# collection do
# post :clear
# end
# end
# end
resources :conversations, only: [:index, :destroy] do
member do
post :read
post :unread
end
end
resources :media, only: [:create, :update, :show]
resources :blocks, only: [:index]
resources :mutes, only: [:index]
resources :favourites, only: [:index]
resources :bookmarks, only: [:index]
resources :reports, only: [:create]
resources :trends, only: [:index], controller: 'trends/tags'
resources :filters, only: [:index, :create, :show, :update, :destroy]
resources :endorsements, only: [:index]
resources :markers, only: [:index, :create]
namespace :profile do
resource :avatar, only: :destroy
resource :header, only: :destroy
end
namespace :apps do
get :verify_credentials, to: 'credentials#show'
end
resources :apps, only: [:create]
namespace :trends do
resources :tags, only: [:index]
resources :links, only: [:index]
resources :statuses, only: [:index]
end
namespace :emails do
resources :confirmations, only: [:create]
get :check_confirmation, to: 'confirmations#check'
end
resource :instance, only: [:show] do
resources :peers, only: [:index], controller: 'instances/peers'
resources :rules, only: [:index], controller: 'instances/rules'
resources :domain_blocks, only: [:index], controller: 'instances/domain_blocks'
resource :privacy_policy, only: [:show], controller: 'instances/privacy_policies'
resource :extended_description, only: [:show], controller: 'instances/extended_descriptions'
resource :translation_languages, only: [:show], controller: 'instances/translation_languages'
resource :languages, only: [:show], controller: 'instances/languages'
resource :activity, only: [:show], controller: 'instances/activity'
end
namespace :peers do
get :search, to: 'search#index'
end
resource :domain_blocks, only: [:show, :create, :destroy]
resource :directory, only: [:show]
resources :follow_requests, only: [:index] do
member do
post :authorize
post :reject
end
end
resources :notifications, only: [:index, :show, :destroy] do
collection do
post :clear
delete :destroy_multiple
end
member do
post :dismiss
end
end
namespace :accounts do
get :verify_credentials, to: 'credentials#show'
patch :update_credentials, to: 'credentials#update'
resource :search, only: :show, controller: :search
resource :lookup, only: :show, controller: :lookup
resources :relationships, only: :index
resources :familiar_followers, only: :index
end
resources :accounts, only: [:create, :show] do
resources :statuses, only: :index, controller: 'accounts/statuses'
resources :followers, only: :index, controller: 'accounts/follower_accounts'
resources :following, only: :index, controller: 'accounts/following_accounts'
resources :lists, only: :index, controller: 'accounts/lists'
resources :identity_proofs, only: :index, controller: 'accounts/identity_proofs'
resources :featured_tags, only: :index, controller: 'accounts/featured_tags'
member do
post :follow
post :unfollow
post :remove_from_followers
post :block
post :unblock
post :mute
post :unmute
end
resource :pin, only: :create, controller: 'accounts/pins'
post :unpin, to: 'accounts/pins#destroy'
resource :note, only: :create, controller: 'accounts/notes'
end
resources :tags, only: [:show] do
member do
post :follow
post :unfollow
end
end
resources :followed_tags, only: [:index]
resources :lists, only: [:index, :create, :show, :update, :destroy] do
resource :accounts, only: [:show, :create, :destroy], controller: 'lists/accounts'
end
namespace :featured_tags do
get :suggestions, to: 'suggestions#index'
end
resources :featured_tags, only: [:index, :create, :destroy]
resources :polls, only: [:create, :show] do
resources :votes, only: :create, controller: 'polls/votes'
end
namespace :push do
resource :subscription, only: [:create, :show, :update, :destroy]
end
namespace :admin do
resources :accounts, only: [:index, :show, :destroy] do
member do
post :enable
post :unsensitive
post :unsilence
post :unsuspend
post :approve
post :reject
end
resource :action, only: [:create], controller: 'account_actions'
end
resources :reports, only: [:index, :update, :show] do
member do
post :assign_to_self
post :unassign
post :reopen
post :resolve
end
end
resources :domain_allows, only: [:index, :show, :create, :destroy]
resources :domain_blocks, only: [:index, :show, :update, :create, :destroy]
resources :email_domain_blocks, only: [:index, :show, :create, :destroy]
resources :ip_blocks, only: [:index, :show, :update, :create, :destroy]
namespace :trends do
resources :tags, only: [:index] do
member do
post :approve
post :reject
end
end
resources :links, only: [:index] do
member do
post :approve
post :reject
end
end
resources :statuses, only: [:index] do
member do
post :approve
post :reject
end
end
namespace :links do
resources :preview_card_providers, only: [:index], path: :publishers do
member do
post :approve
post :reject
end
end
end
end
post :measures, to: 'measures#create'
post :dimensions, to: 'dimensions#create'
post :retention, to: 'retention#create'
resources :canonical_email_blocks, only: [:index, :create, :show, :destroy] do
collection do
post :test
end
end
resources :tags, only: [:index, :show, :update]
end
end
namespace :v2 do
get '/search', to: 'search#index', as: :search
resources :media, only: [:create]
resources :suggestions, only: [:index]
resource :instance, only: [:show]
resources :filters, only: [:index, :create, :show, :update, :destroy] do
resources :keywords, only: [:index, :create], controller: 'filters/keywords'
resources :statuses, only: [:index, :create], controller: 'filters/statuses'
end
namespace :filters do
resources :keywords, only: [:show, :update, :destroy]
resources :statuses, only: [:show, :destroy]
end
namespace :admin do
resources :accounts, only: [:index]
end
end
namespace :web do
resource :settings, only: [:update]
resources :embeds, only: [:show]
resources :push_subscriptions, only: [:create] do
member do
put :update
end
end
end
end

View File

@@ -1,76 +0,0 @@
# frozen_string_literal: true
namespace :settings do
resource :profile, only: [:show, :update] do
resources :pictures, only: :destroy
end
get :preferences, to: redirect('/settings/preferences/appearance')
namespace :preferences do
resource :appearance, only: [:show, :update], controller: :appearance
resource :notifications, only: [:show, :update]
resource :other, only: [:show, :update], controller: :other
end
resources :imports, only: [:index, :show, :destroy, :create] do
member do
post :confirm
get :failures
end
end
resource :export, only: [:show, :create]
namespace :exports, constraints: { format: :csv } do
resources :follows, only: :index, controller: :following_accounts
resources :blocks, only: :index, controller: :blocked_accounts
resources :mutes, only: :index, controller: :muted_accounts
resources :lists, only: :index, controller: :lists
resources :domain_blocks, only: :index, controller: :blocked_domains
resources :bookmarks, only: :index, controller: :bookmarks
end
resources :two_factor_authentication_methods, only: [:index] do
collection do
post :disable
end
end
resource :otp_authentication, only: [:show, :create], controller: 'two_factor_authentication/otp_authentication'
resources :webauthn_credentials, only: [:index, :new, :create, :destroy],
path: 'security_keys',
controller: 'two_factor_authentication/webauthn_credentials' do
collection do
get :options
end
end
namespace :two_factor_authentication do
resources :recovery_codes, only: [:create]
resource :confirmation, only: [:new, :create]
end
resources :applications, except: [:edit] do
member do
post :regenerate
end
end
resources :flavours, only: [:index, :show, :update], param: :flavour
resource :delete, only: [:show, :destroy]
resource :migration, only: [:show, :create]
resource :verification, only: :show
resource :privacy, only: [:show, :update], controller: 'privacy'
namespace :migration do
resource :redirect, only: [:new, :create, :destroy]
end
resources :aliases, only: [:index, :create, :destroy]
resources :sessions, only: [:destroy]
resources :featured_tags, only: [:index, :create, :destroy]
resources :login_activities, only: [:index]
end

View File

@@ -1,22 +0,0 @@
# Be sure to restart your server when you modify this file.
# Your secret key is used for verifying the integrity of signed cookies.
# If you change this key, all old signed cookies will become invalid!
# Make sure the secret is at least 30 characters and all random,
# no regular words or you'll be exposed to dictionary attacks.
# You can use `rails secret` to generate a secure secret key.
# Make sure the secrets in this file are kept private
# if you're sharing your code publicly.
development:
secret_key_base: d4398e4af52f1fc5be5c3c8764e9ecce7beac5462826cb8b649373b2aad5a0f133598ed817c4e9931e943041460d6b6eda40a854e825e1bbd510c4594b1538f2
test:
secret_key_base: 5be187ddbd651211a906f9aa399f4a148edf6e06b971c7c0b5429b9483df6e21d262cc846447d0f89b89c32d56a99e151039df5dd874ede7f712afbe041a9269
# Do not keep production secrets in the repository,
# instead read values from the environment.
production:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>

View File

@@ -1,64 +0,0 @@
---
:concurrency: <%= ENV.fetch('SIDEKIQ_CONCURRENCY', 5) %>
:queues:
- [default, 8]
- [push, 6]
- [ingress, 4]
- [mailers, 2]
- [pull]
- [scheduler]
:scheduler:
:listened_queues_only: true
:schedule:
scheduled_statuses_scheduler:
every: '5m'
class: Scheduler::ScheduledStatusesScheduler
queue: scheduler
trends_refresh_scheduler:
every: '5m'
class: Scheduler::Trends::RefreshScheduler
queue: scheduler
trends_review_notifications_scheduler:
every: '6h'
class: Scheduler::Trends::ReviewNotificationsScheduler
queue: scheduler
indexing_scheduler:
interval: 1 minute
class: Scheduler::IndexingScheduler
queue: scheduler
vacuum_scheduler:
cron: '<%= Random.rand(0..59) %> <%= Random.rand(3..5) %> * * *'
class: Scheduler::VacuumScheduler
queue: scheduler
follow_recommendations_scheduler:
cron: '<%= Random.rand(0..59) %> <%= Random.rand(6..9) %> * * *'
class: Scheduler::FollowRecommendationsScheduler
queue: scheduler
user_cleanup_scheduler:
cron: '<%= Random.rand(0..59) %> <%= Random.rand(4..6) %> * * *'
class: Scheduler::UserCleanupScheduler
queue: scheduler
ip_cleanup_scheduler:
cron: '<%= Random.rand(0..59) %> <%= Random.rand(3..5) %> * * *'
class: Scheduler::IpCleanupScheduler
queue: scheduler
pghero_scheduler:
cron: '0 0 * * *'
class: Scheduler::PgheroScheduler
queue: scheduler
instance_refresh_scheduler:
cron: '0 * * * *'
class: Scheduler::InstanceRefreshScheduler
queue: scheduler
accounts_statuses_cleanup_scheduler:
interval: 1 minute
class: Scheduler::AccountsStatusesCleanupScheduler
queue: scheduler
suspended_user_cleanup_scheduler:
interval: 1 minute
class: Scheduler::SuspendedUserCleanupScheduler
queue: scheduler
software_update_check_scheduler:
interval: 30 minutes
class: Scheduler::SoftwareUpdateCheckScheduler
queue: scheduler

View File