Merge tag 'v4.3.0-rc.1'

This commit is contained in:
Mike Barnes 2024-10-02 10:34:27 +10:00
commit 26c9b9ba39
3459 changed files with 130932 additions and 69993 deletions

View file

@ -5,16 +5,15 @@ require_relative 'boot'
require 'rails'
require 'active_record/railtie'
#require 'active_storage/engine'
# 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'
# require 'action_cable/engine'
# require 'action_mailbox/engine'
# require 'action_text/engine'
# require 'rails/test_unit/railtie'
# Used to be implicitly required in action_mailbox/engine
require 'mail'
@ -28,7 +27,7 @@ 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'
@ -39,8 +38,9 @@ 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/devise/strategies/two_factor_ldap_authenticatable'
require_relative '../lib/devise/strategies/two_factor_pam_authenticatable'
require_relative '../lib/elasticsearch/client_extensions'
require_relative '../lib/chewy/settings_extensions'
require_relative '../lib/chewy/index_extensions'
require_relative '../lib/chewy/strategy/mastodon'
@ -49,147 +49,37 @@ require_relative '../lib/webpacker/manifest_extensions'
require_relative '../lib/webpacker/helper_extensions'
require_relative '../lib/rails/engine_extensions'
require_relative '../lib/action_dispatch/remote_ip_extensions'
require_relative '../lib/stoplight/redis_data_store_extensions'
require_relative '../lib/active_record/database_tasks_extensions'
require_relative '../lib/active_record/batches'
require_relative '../lib/active_record/with_recursive'
require_relative '../lib/arel/union_parenthesizing'
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
config.load_defaults 7.1
# 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
# Explicitly set the cache format version to align with Rails version
config.active_support.cache_format_version = 7.1
config.add_autoload_paths_to_load_path = false
# Please, add to the `ignore` list any other `lib` subdirectories that do
# not contain `.rb` files, or that should not be reloaded or eager loaded.
# Common ones are `templates`, `generators`, or `middleware`, for example.
# config.autoload_lib(ignore: %w(assets tasks templates generators))
# TODO: We should enable this eventually, but for now there are many things
# in the wrong path from the perspective of zeitwerk.
# 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
# Configuration for the application, engines, and railties goes here.
#
# These settings can be overridden in specific environments using the files
# in config/environments, which are processed later.
#
# config.time_zone = "Central Time (US & Canada)"
# config.eager_load_paths << Rails.root.join("extras")
config.public_file_server.headers = {
'X-Content-Type-Options' => 'nosniff',
@ -201,20 +91,39 @@ module Mastodon
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')
config.action_mailer.preview_paths << 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 PublicFileServerMiddleware if Rails.env.local? || ENV['RAILS_SERVE_STATIC_FILES'] == 'true'
config.middleware.use Rack::Attack
config.middleware.use Mastodon::RackMiddleware
initializer :deprecator do |app|
app.deprecators[:mastodon] = ActiveSupport::Deprecation.new('4.3', 'mastodon/mastodon')
end
config.before_configuration do
require 'mastodon/redis_configuration'
::REDIS_CONFIGURATION = Mastodon::RedisConfiguration.new
config.x.use_vips = ENV['MASTODON_USE_LIBVIPS'] == 'true'
if config.x.use_vips
require_relative '../lib/paperclip/vips_lazy_thumbnail'
else
require_relative '../lib/paperclip/lazy_thumbnail'
end
end
config.to_prepare do
Doorkeeper::AuthorizationsController.layout 'modal'
Doorkeeper::AuthorizedApplicationsController.layout 'admin'
Doorkeeper::Application.include ApplicationExtension
Doorkeeper::AccessGrant.include AccessGrantExtension
Doorkeeper::AccessToken.include AccessTokenExtension
Doorkeeper::OAuth::PreAuthorization.include OauthPreAuthorizationExtension
Devise::FailureApp.include AbstractController::Callbacks
Devise::FailureApp.include Localized
end

View file

@ -1,8 +1,15 @@
# 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
abort <<~ERROR
The RAILS_ENV environment variable is not set.
Please set it correctly depending on context:
- Use "production" for a live deployment of the application
- Use "development" for local feature work
- Use "test" when running the automated spec suite
ERROR
end
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)

View file

@ -1,96 +0,0 @@
{
"ignored_warnings": [
{
"warning_type": "Cross-Site Scripting",
"warning_code": 2,
"fingerprint": "71cf98c8235b5cfa9946b5db8fdc1a2f3a862566abb34e4542be6f3acae78233",
"check_name": "CrossSiteScripting",
"message": "Unescaped model attribute",
"file": "app/views/admin/disputes/appeals/_appeal.html.haml",
"line": 7,
"link": "https://brakemanscanner.org/docs/warning_types/cross_site_scripting",
"code": "t((Unresolved Model).new.strike.action, :scope => \"admin.strikes.actions\", :name => content_tag(:span, (Unresolved Model).new.strike.account.username, :class => \"username\"), :target => content_tag(:span, (Unresolved Model).new.account.username, :class => \"target\"))",
"render_path": [
{
"type": "template",
"name": "admin/disputes/appeals/index",
"line": 20,
"file": "app/views/admin/disputes/appeals/index.html.haml",
"rendered": {
"name": "admin/disputes/appeals/_appeal",
"file": "app/views/admin/disputes/appeals/_appeal.html.haml"
}
}
],
"location": {
"type": "template",
"template": "admin/disputes/appeals/_appeal"
},
"user_input": "(Unresolved Model).new.strike",
"confidence": "Weak",
"cwe_id": [
79
],
"note": ""
},
{
"warning_type": "Denial of Service",
"warning_code": 76,
"fingerprint": "7b6abba5699755348e7ee82a4694bfbf574b41c7cce2d0db0f7c11ae3f983c72",
"check_name": "RegexDoS",
"message": "Model attribute used in regular expression",
"file": "lib/mastodon/cli/domains.rb",
"line": 128,
"link": "https://brakemanscanner.org/docs/warning_types/denial_of_service/",
"code": "/\\.?(#{DomainBlock.where(:severity => 1).pluck(:domain).map do\n Regexp.escape(domain)\n end.join(\"|\")})$/",
"render_path": null,
"location": {
"type": "method",
"class": "Mastodon::CLI::Domains",
"method": "crawl"
},
"user_input": "DomainBlock.where(:severity => 1).pluck(:domain)",
"confidence": "Weak",
"cwe_id": [
20,
185
],
"note": ""
},
{
"warning_type": "Cross-Site Scripting",
"warning_code": 4,
"fingerprint": "cd5cfd7f40037fbfa753e494d7129df16e358bfc43ef0da3febafbf4ee1ed3ac",
"check_name": "LinkToHref",
"message": "Potentially unsafe model attribute in `link_to` href",
"file": "app/views/admin/trends/links/_preview_card.html.haml",
"line": 7,
"link": "https://brakemanscanner.org/docs/warning_types/link_to_href",
"code": "link_to((Unresolved Model).new.title, (Unresolved Model).new.url)",
"render_path": [
{
"type": "template",
"name": "admin/trends/links/index",
"line": 49,
"file": "app/views/admin/trends/links/index.html.haml",
"rendered": {
"name": "admin/trends/links/_preview_card",
"file": "app/views/admin/trends/links/_preview_card.html.haml"
}
}
],
"location": {
"type": "template",
"template": "admin/trends/links/_preview_card"
},
"user_input": "(Unresolved Model).new.url",
"confidence": "Weak",
"cwe_id": [
79
],
"note": ""
}
],
"updated": "2023-07-12 11:20:51 -0400",
"brakeman_version": "6.0.0"
}

View file

@ -1,3 +1,5 @@
---
:skip_checks:
- CheckPermitAttributes
:url_safe_methods:
- url_for_preview_card

View file

@ -1,6 +1,6 @@
default: &default
adapter: postgresql
pool: <%= ENV["DB_POOL"] || ENV['MAX_THREADS'] || 5 %>
pool: <%= ENV["DB_POOL"] || (if Sidekiq.server? then Sidekiq[:concurrency] else ENV['MAX_THREADS'] end) || 5 %>
timeout: 5000
connect_timeout: 15
encoding: unicode

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

@ -8,7 +8,7 @@ Rails.application.configure do
# 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
config.enable_reloading = true
# Do not eager load code on boot.
config.eager_load = false
@ -25,7 +25,7 @@ Rails.application.configure do
config.action_controller.perform_caching = true
config.action_controller.enable_fragment_cache_logging = true
config.cache_store = :redis_cache_store, REDIS_CACHE_PARAMS
config.cache_store = :redis_cache_store, REDIS_CONFIGURATION.cache
config.public_file_server.headers = {
'Cache-Control' => "public, max-age=#{2.days.to_i}",
}
@ -37,7 +37,7 @@ Rails.application.configure do
config.action_controller.forgery_protection_origin_check = ENV['DISABLE_FORGERY_REQUEST_PROTECTION'].nil?
ActiveSupport::Logger.new(STDOUT).tap do |logger|
ActiveSupport::Logger.new($stdout).tap do |logger|
logger.formatter = config.log_formatter
config.logger = ActiveSupport::TaggedLogging.new(logger)
end
@ -68,16 +68,8 @@ Rails.application.configure do
# 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
# Highlight code that enqueued background job in logs.
config.active_job.verbose_enqueue_logs = true
# Raises error for missing translations.
# config.i18n.raise_on_missing_translations = true
@ -93,11 +85,13 @@ Rails.application.configure do
# 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
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!
# TODO: Remove once devise-two-factor data migration complete
config.x.otp_secret = ENV.fetch('OTP_SECRET', '1fc2b87989afa6351912abeebe31ffc5c476ead9bf8b3d74cbc4a302c7b69a45b40b1bbef3506ddad73e942e15ed5ca4b402bf9a66423626051104f4b5f05109')
# Raise error when a before_action's only/except options reference missing actions
config.action_controller.raise_on_missing_callback_actions = true
end
Redis.raise_deprecations = true

View file

@ -1,12 +1,12 @@
# frozen_string_literal: true
require "active_support/core_ext/integer/time"
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
config.enable_reloading = false
# Eager load code on boot. This eager loads most of Rails and
# your application in memory, allowing both threaded web servers
@ -19,8 +19,8 @@ Rails.application.configure do
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).
# Ensures that a master key has been made available in ENV["RAILS_MASTER_KEY"], config/master.key, or an environment
# key such as config/credentials/production.key. This key is used to decrypt credentials (and other encrypted files).
# config.require_master_key = true
# Compress CSS using a preprocessor.
@ -44,21 +44,20 @@ Rails.application.configure do
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') }
}
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.
# Info include generic and useful information about system operation, but avoids logging too much
# information to avoid inadvertent exposure of personally identifiable information (PII). If you
# want to log everything, set the level to "debug".
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
config.cache_store = :redis_cache_store, REDIS_CONFIGURATION.cache
# Use a real queuing backend for Active Job (and separate queues per environment).
# config.active_job.queue_adapter = :resque
@ -72,10 +71,13 @@ Rails.application.configure do
# Enable locale fallbacks for I18n (makes lookups for any locale fall back to
# English when a translation cannot be found).
config.i18n.fallbacks = true
# This setting would typically be `true` to use the `I18n.default_locale`.
# Some locales are missing translation entries and would have errors:
# https://github.com/mastodon/mastodon/pull/24727
config.i18n.fallbacks = [:en]
# Send deprecation notices to registered listeners.
config.active_support.deprecation = :notify
# Don't log any deprecations.
config.active_support.report_deprecations = false
# Use default logging formatter so that PID and timestamp are not suppressed.
config.log_formatter = ::Logger::Formatter.new
@ -84,19 +86,17 @@ Rails.application.configure do
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
{ key: controller.signature_key_id } if controller.respond_to?(:signed_request?) && controller.signed_request?
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
# Log to STDOUT by default
config.logger = ActiveSupport::Logger.new($stdout)
.tap { |logger| logger.formatter = ::Logger::Formatter.new }
.then { |logger| ActiveSupport::TaggedLogging.new(logger) }
# Do not dump schema after migrations.
config.active_record.dump_schema_after_migration = false
@ -148,12 +148,25 @@ Rails.application.configure do
config.action_mailer.delivery_method = ENV.fetch('SMTP_DELIVERY_METHOD', 'smtp').to_sym
config.action_dispatch.default_headers = {
'Server' => 'Mastodon',
'X-Frame-Options' => 'DENY',
'Server' => 'Mastodon',
'X-Frame-Options' => 'DENY',
'X-Content-Type-Options' => 'nosniff',
'X-XSS-Protection' => '0',
'Referrer-Policy' => 'same-origin',
'X-XSS-Protection' => '0',
'Referrer-Policy' => 'same-origin',
}
config.x.otp_secret = ENV.fetch('OTP_SECRET')
# TODO: Remove once devise-two-factor data migration complete
config.x.otp_secret = if ENV['SECRET_KEY_BASE_DUMMY']
SecureRandom.hex(64)
else
ENV.fetch('OTP_SECRET')
end
# Enable DNS rebinding protection and other `Host` header attacks.
# config.hosts = [
# "example.com", # Allow requests from example.com
# /.*\.example\.com/ # Allow requests from subdomains like `www.example.com`
# ]
# Skip DNS rebinding protection for the default health check endpoint.
# config.host_authorization = { exclude: ->(request) { request.path == "/up" } }
end

View file

@ -10,12 +10,13 @@ require 'active_support/core_ext/integer/time'
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
# While tests run files are not watched, reloading is not necessary.
config.enable_reloading = false
# 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.
# Eager loading loads your entire application. When running a single test locally,
# this is usually not necessary, and can slow down your test suite. However, it's
# recommended that you enable it in continuous integration systems to ensure eager
# loading is working properly before deploying your code.
config.eager_load = ENV['CI'].present?
config.assets_digest = false
@ -26,7 +27,7 @@ Rails.application.configure do
config.cache_store = :memory_store
# Raise exceptions instead of rendering exception templates.
config.action_dispatch.show_exceptions = false
config.action_dispatch.show_exceptions = :rescuable
# Disable request forgery protection in test environment.
config.action_controller.allow_forgery_protection = false
@ -43,6 +44,7 @@ Rails.application.configure do
# Print deprecation notices to the stderr.
config.active_support.deprecation = :stderr
# TODO: Remove once devise-two-factor data migration complete
config.x.otp_secret = '100c7faeef00caa29242f6b04156742bf76065771fd4117990c4282b8748ff3d99f8fdae97c982ab5bd2e6756a159121377cce4421f4a8ecd2d67bd7749a3fb4'
# Generate random VAPID keys
@ -59,12 +61,6 @@ Rails.application.configure do
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 = []
@ -73,18 +69,21 @@ Rails.application.configure do
# Annotate rendered view with file names.
# config.action_view.annotate_rendered_view_with_filenames = true
# Raise error when a before_action's only/except options reference missing actions
config.action_controller.raise_on_missing_callback_actions = 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
# Enable fake_data for PAM
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' }
env: { email: 'pam@example.com' },
}
end

View file

@ -64,11 +64,13 @@ ignore_unused:
- 'statuses.attached.*'
- 'move_handler.carry_{mutes,blocks}_over_text'
- 'admin_mailer.*.subject'
- 'user_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
- 'edit_profile.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

@ -23,7 +23,7 @@ Rails.application.configure do
if Rails.env.production?
"ws#{https ? 's' : ''}://#{web_host}"
else
"ws://#{ENV['REMOTE_DEV'] == 'true' ? host.split(':').first : 'localhost'}:4000"
"ws://#{host.split(':').first}:4000"
end
end

View file

@ -9,9 +9,6 @@ Rails.application.config.middleware.use OmniAuth::Builder do
end
Devise.setup do |config|
# Devise omniauth strategies
options = {}
# CAS strategy
if ENV['CAS_ENABLED'] == 'true'
cas_options = {}
@ -76,35 +73,36 @@ Devise.setup do |config|
# 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
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[:scope] = scopes.map(&: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[:pkce] = ENV['OIDC_USE_PKCE'] == 'true' if ENV['OIDC_USE_PKCE'] # OPTIONAL (default: false)
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[: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
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

@ -0,0 +1,41 @@
# frozen_string_literal: true
%w(
ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY
ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT
ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY
).each do |key|
if ENV['SECRET_KEY_BASE_DUMMY']
# Use placeholder value during production env asset compilation
ENV[key] = SecureRandom.hex(64)
end
value = ENV.fetch(key) do
abort <<~MESSAGE
Mastodon now requires that these variables are set:
- ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY
- ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT
- ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY
Run `bin/rails db:encryption:init` to generate new secrets and then assign the environment variables.
MESSAGE
end
next unless Rails.env.production? && value.end_with?('DO_NOT_USE_IN_PRODUCTION')
abort <<~MESSAGE
It looks like you are trying to run Mastodon in production with a #{key} value from the test environment.
Please generate fresh secrets using `bin/rails db:encryption:init` and use them instead.
MESSAGE
end
Rails.application.configure do
config.active_record.encryption.deterministic_key = ENV.fetch('ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY')
config.active_record.encryption.key_derivation_salt = ENV.fetch('ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT')
config.active_record.encryption.primary_key = ENV.fetch('ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY')
config.active_record.encryption.support_sha1_for_non_deterministic_encryption = true
end

View file

@ -1,4 +1,5 @@
# frozen_string_literal: true
# Be sure to restart your server when you modify this file.
# ActiveSupport::Reloader.to_prepare do

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

@ -7,4 +7,4 @@
# 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"]
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

@ -3,10 +3,13 @@
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 }
user = ENV.fetch('ES_USER', nil).presence
password = ENV.fetch('ES_PASS', nil).presence
fallback_prefix = ENV.fetch('REDIS_NAMESPACE', nil).presence
prefix = ENV.fetch('ES_PREFIX') { fallback_prefix }
ca_file = ENV.fetch('ES_CA_FILE', nil).presence
transport_options = { ssl: { ca_file: ca_file } } if ca_file.present?
Chewy.settings = {
host: "#{host}:#{port}",
@ -18,6 +21,7 @@ Chewy.settings = {
index: {
number_of_replicas: ['single_node_cluster', nil].include?(ENV['ES_PRESET'].presence) ? 0 : 1,
},
transport_options: transport_options,
}
# We use our own async strategy even outside the request-response

View file

@ -1,75 +1,47 @@
# 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
# Be sure to restart your server when you modify this file.
def host_to_url(str)
return if str.blank?
# Define an application-wide content security policy.
# See the Securing Rails Applications Guide for more information:
# https://guides.rubyonrails.org/security.html#content-security-policy-header
uri = Addressable::URI.parse("http#{Rails.configuration.x.use_https ? 's' : ''}://#{str}")
uri.path += '/' unless uri.path.blank? || uri.path.end_with?('/')
uri.to_s
end
require_relative '../../app/lib/content_security_policy'
base_host = Rails.configuration.x.web_domain
assets_host = Rails.configuration.action_controller.asset_host
assets_host ||= host_to_url(base_host)
media_host = host_to_url(ENV['S3_ALIAS_HOST'])
media_host ||= host_to_url(ENV['S3_CLOUDFRONT_HOST'])
media_host ||= host_to_url(ENV['AZURE_ALIAS_HOST'])
media_host ||= host_to_url(ENV['S3_HOSTNAME']) if ENV['S3_ENABLED'] == 'true'
media_host ||= assets_host
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
policy = ContentSecurityPolicy.new
assets_host = policy.assets_host
media_hosts = policy.media_hosts
Rails.application.config.content_security_policy do |p|
p.base_uri :none
p.default_src :none
p.frame_ancestors :none
p.font_src :self, assets_host
p.img_src :self, :https, :data, :blob, assets_host
p.img_src :self, :data, :blob, *media_hosts
p.style_src :self, assets_host
p.media_src :self, :https, :data, assets_host
p.frame_src :self, :https
p.media_src :self, :data, *media_hosts
p.manifest_src :self, assets_host
if sso_host.present?
p.form_action :self, sso_host
if policy.sso_host.present?
p.form_action :self, policy.sso_host
else
p.form_action :self
p.form_action :self
end
p.child_src :self, :blob, assets_host
p.worker_src :self, :blob, assets_host
p.child_src :self, :blob, assets_host
p.worker_src :self, :blob, assets_host
if Rails.env.development?
webpacker_public_host = ENV.fetch('WEBPACKER_DEV_SERVER_PUBLIC', Webpacker.config.dev_server[:public])
webpacker_urls = %w(ws http).map { |protocol| "#{protocol}#{Webpacker.dev_server.https? ? 's' : ''}://#{webpacker_public_host}" }
front_end_build_urls = %w(ws http).map { |protocol| "#{protocol}#{Webpacker.dev_server.https? ? 's' : ''}://#{webpacker_public_host}" }
p.connect_src :self, :data, :blob, assets_host, media_host, Rails.configuration.x.streaming_api_base_url, *webpacker_urls
p.connect_src :self, :data, :blob, *media_hosts, Rails.configuration.x.streaming_api_base_url, *front_end_build_urls
p.script_src :self, :unsafe_inline, :unsafe_eval, assets_host
p.frame_src :self, :https, :http
else
p.connect_src :self, :data, :blob, assets_host, media_host, Rails.configuration.x.streaming_api_base_url
p.connect_src :self, :data, :blob, *media_hosts, Rails.configuration.x.streaming_api_base_url
p.script_src :self, assets_host, "'wasm-unsafe-eval'"
p.frame_src :self, :https
end
end
@ -78,7 +50,7 @@ end
# 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_generator = ->(_request) { SecureRandom.base64(16) }
Rails.application.config.content_security_policy_nonce_directives = %w(style-src)
@ -103,7 +75,7 @@ Rails.application.reloader.to_prepare do
p.worker_src :none
end
LetterOpenerWeb::LettersController.after_action do |p|
LetterOpenerWeb::LettersController.after_action do
request.content_security_policy_nonce_directives = %w(script-src)
end
end

View file

@ -1,9 +1,6 @@
# 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
# TODO: remove this file some time after 4.3.0
Rails.application.config.after_initialize do
Rails.application.config.action_dispatch.cookies_rotations.tap do |cookies|
@ -12,9 +9,8 @@ Rails.application.config.after_initialize do
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
secret_key_base, iterations: 1000, hash_digest_class: OpenSSL::Digest::SHA1
)
key_len = ActiveSupport::MessageEncryptor.key_len

View file

@ -3,7 +3,7 @@
# 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.
# Handle Cross-Origin Resource Sharing (CORS) in order to accept cross-origin Ajax requests.
# Read more: https://github.com/cyu/rack-cors
@ -11,26 +11,18 @@ Rails.application.config.middleware.insert_before 0, Rack::Cors do
allow do
origins '*'
resource '/.well-known/*',
headers: :any,
methods: [:get],
credentials: false
resource '/@:username',
headers: :any,
methods: [:get],
credentials: false
resource '/users/:username',
headers: :any,
methods: [:get],
credentials: false
resource '/api/*',
headers: :any,
methods: [:post, :put, :delete, :get, :patch, :options],
credentials: false,
expose: ['Link', 'X-RateLimit-Reset', 'X-RateLimit-Limit', 'X-RateLimit-Remaining', 'X-Request-Id']
resource '/oauth/token',
headers: :any,
methods: [:post],
credentials: false
with_options headers: :any, credentials: false do
with_options methods: [:get] do
resource '/.well-known/*'
resource '/nodeinfo/*'
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]
resource '/oauth/revoke', methods: [:post]
end
end
end

View file

@ -38,42 +38,25 @@ Warden::Manager.before_logout do |_, warden|
end
module Devise
mattr_accessor :pam_authentication
@@pam_authentication = false
mattr_accessor :pam_controlled_service
@@pam_controlled_service = nil
mattr_accessor :pam_authentication, default: false
mattr_accessor :pam_controlled_service, default: nil
mattr_accessor :check_at_sign
@@check_at_sign = false
mattr_accessor :check_at_sign, default: 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
mattr_accessor :ldap_authentication, default: false
mattr_accessor :ldap_host, default: nil
mattr_accessor :ldap_port, default: nil
mattr_accessor :ldap_method, default: nil
mattr_accessor :ldap_base, default: nil
mattr_accessor :ldap_uid, default: nil
mattr_accessor :ldap_mail, default: nil
mattr_accessor :ldap_bind_dn, default: nil
mattr_accessor :ldap_password, default: nil
mattr_accessor :ldap_tls_no_verify, default: false
mattr_accessor :ldap_search_filter, default: nil
mattr_accessor :ldap_uid_conversion_enabled, default: false
mattr_accessor :ldap_uid_conversion_search, default: nil
mattr_accessor :ldap_uid_conversion_replace, default: nil
module Strategies
class PamAuthenticatable
@ -96,9 +79,7 @@ module Devise
return pass
end
if validate(resource)
success!(resource)
end
success!(resource) if validate(resource)
end
private
@ -124,9 +105,11 @@ Devise.setup do |config|
# 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'
#
# Set explicitly to Rails default to avoid deprecation warnings.
# https://github.com/heartcombo/devise/pull/5645#issuecomment-1871849856
# Remove when Devise changes `SecretKeyFinder` to not emit deprecations.
config.secret_key = Rails.application.secret_key_base
# ==> Mailer Configuration
# Configure the e-mail address which will be shown in Devise::Mailer,
@ -394,7 +377,7 @@ Devise.setup do |config|
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 }
config.pam_controlled_service = ENV.fetch('PAM_CONTROLLED_SERVICE', nil).presence
end
if ENV['LDAP_ENABLED'] == 'true'

View file

@ -74,7 +74,8 @@ Doorkeeper.configure do
# For more information go to
# https://github.com/doorkeeper-gem/doorkeeper/wiki/Using-Scopes
default_scopes :read
optional_scopes :write,
optional_scopes :profile,
:write,
:'write:accounts',
:'write:blocks',
:'write:bookmarks',
@ -117,8 +118,7 @@ Doorkeeper.configure do
:'admin:write:domain_blocks',
:'admin:write:ip_blocks',
:'admin:write:email_domain_blocks',
:'admin:write:canonical_email_blocks',
:crypto
:'admin:write:canonical_email_blocks'
# Change the way client credentials are retrieved from the request object.
# By default it retrieves first from the `HTTP_AUTHORIZATION` header, then
@ -146,11 +146,11 @@ Doorkeeper.configure do
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.
# Any redirect URI is allowed 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) }
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:
@ -174,7 +174,7 @@ Doorkeeper.configure do
# 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|
skip_authorization do |_resource_owner, client|
client.application.superapp?
end

View file

@ -0,0 +1,6 @@
# frozen_string_literal: true
Rails.application.configure do
config.x.email_domains_denylist = ENV.fetch('EMAIL_DOMAIN_DENYLIST', nil) || ENV.fetch('EMAIL_DOMAIN_BLACKLIST', '')
config.x.email_domains_allowlist = ENV.fetch('EMAIL_DOMAIN_ALLOWLIST', nil) || ENV.fetch('EMAIL_DOMAIN_WHITELIST', '')
end

View file

@ -0,0 +1,13 @@
# frozen_string_literal: true
# Automatically enable YJIT as of Ruby 3.3, as it brings very
# sizeable performance improvements.
# If you are deploying to a memory constrained environment
# you may want to delete this file, but otherwise it's free
# performance.
if defined?(RubyVM::YJIT.enable)
Rails.application.config.after_initialize do
RubyVM::YJIT.enable
end
end

View file

@ -2,9 +2,9 @@
# 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.
# Configure parameters to be partially matched (e.g. passw matches password) and 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
:passw, :email, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn
]

View file

@ -7,7 +7,7 @@ Rails.application.configure do
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
raise 'No proxy host' unless proxy.host
host = proxy.host
host = host[1...-1] if host[0] == '[' # for IPv6 address
@ -24,7 +24,7 @@ Rails.application.configure do
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
raise 'No proxy host' unless proxy.host
host = proxy.host
host = host[1...-1] if host[0] == '[' # for IPv6 address

112
config/initializers/i18n.rb Normal file
View file

@ -0,0 +1,112 @@
# frozen_string_literal: true
Rails.application.configure do
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-CA',
:fy,
:ga,
:gd,
:gl,
:he,
:hi,
:hr,
:hu,
:hy,
:ia,
:id,
:ie,
: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 Rails.configuration.i18n.available_locales.include?(custom_default_locale)
custom_default_locale
else
:en
end
end
end

View file

@ -6,29 +6,33 @@
# 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.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 'CLI'
inflect.acronym 'DeepL'
inflect.acronym 'DSL'
inflect.acronym 'JsonLd'
inflect.acronym 'OEmbed'
inflect.acronym 'OStatus'
inflect.acronym 'PubSubHubbub'
inflect.acronym 'REST'
inflect.acronym 'RSS'
inflect.acronym 'StatsD'
inflect.acronym 'TOC'
inflect.acronym 'URL'
inflect.singular 'data', 'data'
end
# These inflection rules are supported but not enabled by default:
# ActiveSupport::Inflector.inflections(:en) do |inflect|
# inflect.acronym "RESTful"
# 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

@ -0,0 +1,86 @@
# frozen_string_literal: true
# This file generated automatically from http://w3id.org/identity/v1
require 'json/ld'
class JSON::LD::Context
add_preloaded("http://w3id.org/identity/v1") do
new(term_definitions: {
"Credential" => TermDefinition.new("Credential", id: "https://w3id.org/credentials#Credential", simple: true),
"CryptographicKey" => TermDefinition.new("CryptographicKey", id: "https://w3id.org/security#Key", simple: true),
"CryptographicKeyCredential" => TermDefinition.new("CryptographicKeyCredential", id: "https://w3id.org/credentials#CryptographicKeyCredential", simple: true),
"EncryptedMessage" => TermDefinition.new("EncryptedMessage", id: "https://w3id.org/security#EncryptedMessage", simple: true),
"GraphSignature2012" => TermDefinition.new("GraphSignature2012", id: "https://w3id.org/security#GraphSignature2012", simple: true),
"Group" => TermDefinition.new("Group", id: "https://www.w3.org/ns/activitystreams#Group", simple: true),
"Identity" => TermDefinition.new("Identity", id: "https://w3id.org/identity#Identity", simple: true),
"LinkedDataSignature2015" => TermDefinition.new("LinkedDataSignature2015", id: "https://w3id.org/security#LinkedDataSignature2015", simple: true),
"Organization" => TermDefinition.new("Organization", id: "http://schema.org/Organization", simple: true),
"Person" => TermDefinition.new("Person", id: "http://schema.org/Person", simple: true),
"PostalAddress" => TermDefinition.new("PostalAddress", id: "http://schema.org/PostalAddress", simple: true),
"about" => TermDefinition.new("about", id: "http://schema.org/about", type_mapping: "@id"),
"accessControl" => TermDefinition.new("accessControl", id: "https://w3id.org/permissions#accessControl", type_mapping: "@id"),
"address" => TermDefinition.new("address", id: "http://schema.org/address", type_mapping: "@id"),
"addressCountry" => TermDefinition.new("addressCountry", id: "http://schema.org/addressCountry", simple: true),
"addressLocality" => TermDefinition.new("addressLocality", id: "http://schema.org/addressLocality", simple: true),
"addressRegion" => TermDefinition.new("addressRegion", id: "http://schema.org/addressRegion", simple: true),
"cipherAlgorithm" => TermDefinition.new("cipherAlgorithm", id: "https://w3id.org/security#cipherAlgorithm", simple: true),
"cipherData" => TermDefinition.new("cipherData", id: "https://w3id.org/security#cipherData", simple: true),
"cipherKey" => TermDefinition.new("cipherKey", id: "https://w3id.org/security#cipherKey", simple: true),
"claim" => TermDefinition.new("claim", id: "https://w3id.org/credentials#claim", type_mapping: "@id"),
"comment" => TermDefinition.new("comment", id: "http://www.w3.org/2000/01/rdf-schema#comment", simple: true),
"created" => TermDefinition.new("created", id: "http://purl.org/dc/terms/created", type_mapping: "http://www.w3.org/2001/XMLSchema#dateTime"),
"creator" => TermDefinition.new("creator", id: "http://purl.org/dc/terms/creator", type_mapping: "@id"),
"cred" => TermDefinition.new("cred", id: "https://w3id.org/credentials#", simple: true, prefix: true),
"credential" => TermDefinition.new("credential", id: "https://w3id.org/credentials#credential", type_mapping: "@id"),
"dc" => TermDefinition.new("dc", id: "http://purl.org/dc/terms/", simple: true, prefix: true),
"description" => TermDefinition.new("description", id: "http://schema.org/description", simple: true),
"digestAlgorithm" => TermDefinition.new("digestAlgorithm", id: "https://w3id.org/security#digestAlgorithm", simple: true),
"digestValue" => TermDefinition.new("digestValue", id: "https://w3id.org/security#digestValue", simple: true),
"domain" => TermDefinition.new("domain", id: "https://w3id.org/security#domain", simple: true),
"email" => TermDefinition.new("email", id: "http://schema.org/email", simple: true),
"expires" => TermDefinition.new("expires", id: "https://w3id.org/security#expiration", type_mapping: "http://www.w3.org/2001/XMLSchema#dateTime"),
"familyName" => TermDefinition.new("familyName", id: "http://schema.org/familyName", simple: true),
"givenName" => TermDefinition.new("givenName", id: "http://schema.org/givenName", simple: true),
"id" => TermDefinition.new("id", id: "@id", simple: true),
"identity" => TermDefinition.new("identity", id: "https://w3id.org/identity#", simple: true, prefix: true),
"identityService" => TermDefinition.new("identityService", id: "https://w3id.org/identity#identityService", type_mapping: "@id"),
"idp" => TermDefinition.new("idp", id: "https://w3id.org/identity#idp", type_mapping: "@id"),
"image" => TermDefinition.new("image", id: "http://schema.org/image", type_mapping: "@id"),
"initializationVector" => TermDefinition.new("initializationVector", id: "https://w3id.org/security#initializationVector", simple: true),
"issued" => TermDefinition.new("issued", id: "https://w3id.org/credentials#issued", type_mapping: "http://www.w3.org/2001/XMLSchema#dateTime"),
"issuer" => TermDefinition.new("issuer", id: "https://w3id.org/credentials#issuer", type_mapping: "@id"),
"label" => TermDefinition.new("label", id: "http://www.w3.org/2000/01/rdf-schema#label", simple: true),
"member" => TermDefinition.new("member", id: "http://schema.org/member", type_mapping: "@id"),
"memberOf" => TermDefinition.new("memberOf", id: "http://schema.org/memberOf", type_mapping: "@id"),
"name" => TermDefinition.new("name", id: "http://schema.org/name", simple: true),
"nonce" => TermDefinition.new("nonce", id: "https://w3id.org/security#nonce", simple: true),
"normalizationAlgorithm" => TermDefinition.new("normalizationAlgorithm", id: "https://w3id.org/security#normalizationAlgorithm", simple: true),
"owner" => TermDefinition.new("owner", id: "https://w3id.org/security#owner", type_mapping: "@id"),
"password" => TermDefinition.new("password", id: "https://w3id.org/security#password", simple: true),
"paymentProcessor" => TermDefinition.new("paymentProcessor", id: "https://w3id.org/payswarm#processor", simple: true),
"perm" => TermDefinition.new("perm", id: "https://w3id.org/permissions#", simple: true, prefix: true),
"postalCode" => TermDefinition.new("postalCode", id: "http://schema.org/postalCode", simple: true),
"preferences" => TermDefinition.new("preferences", id: "https://w3id.org/payswarm#preferences", type_mapping: "@vocab"),
"privateKey" => TermDefinition.new("privateKey", id: "https://w3id.org/security#privateKey", type_mapping: "@id"),
"privateKeyPem" => TermDefinition.new("privateKeyPem", id: "https://w3id.org/security#privateKeyPem", simple: true),
"ps" => TermDefinition.new("ps", id: "https://w3id.org/payswarm#", simple: true, prefix: true),
"publicKey" => TermDefinition.new("publicKey", id: "https://w3id.org/security#publicKey", type_mapping: "@id"),
"publicKeyPem" => TermDefinition.new("publicKeyPem", id: "https://w3id.org/security#publicKeyPem", simple: true),
"publicKeyService" => TermDefinition.new("publicKeyService", id: "https://w3id.org/security#publicKeyService", type_mapping: "@id"),
"rdf" => TermDefinition.new("rdf", id: "http://www.w3.org/1999/02/22-rdf-syntax-ns#", simple: true, prefix: true),
"rdfs" => TermDefinition.new("rdfs", id: "http://www.w3.org/2000/01/rdf-schema#", simple: true, prefix: true),
"recipient" => TermDefinition.new("recipient", id: "https://w3id.org/credentials#recipient", type_mapping: "@id"),
"revoked" => TermDefinition.new("revoked", id: "https://w3id.org/security#revoked", type_mapping: "http://www.w3.org/2001/XMLSchema#dateTime"),
"schema" => TermDefinition.new("schema", id: "http://schema.org/", simple: true, prefix: true),
"sec" => TermDefinition.new("sec", id: "https://w3id.org/security#", simple: true, prefix: true),
"signature" => TermDefinition.new("signature", id: "https://w3id.org/security#signature", simple: true),
"signatureAlgorithm" => TermDefinition.new("signatureAlgorithm", id: "https://w3id.org/security#signatureAlgorithm", simple: true),
"signatureValue" => TermDefinition.new("signatureValue", id: "https://w3id.org/security#signatureValue", simple: true),
"streetAddress" => TermDefinition.new("streetAddress", id: "http://schema.org/streetAddress", simple: true),
"title" => TermDefinition.new("title", id: "http://purl.org/dc/terms/title", simple: true),
"type" => TermDefinition.new("type", id: "@type", simple: true),
"url" => TermDefinition.new("url", id: "http://schema.org/url", type_mapping: "@id"),
"writePermission" => TermDefinition.new("writePermission", id: "https://w3id.org/permissions#writePermission", type_mapping: "@id"),
"xsd" => TermDefinition.new("xsd", id: "http://www.w3.org/2001/XMLSchema#", simple: true, prefix: true)
})
end
alias_preloaded("https://w3id.org/identity/v1", "http://w3id.org/identity/v1")
end

View file

@ -0,0 +1,50 @@
# frozen_string_literal: true
# This file generated automatically from http://w3id.org/security/v1
require 'json/ld'
class JSON::LD::Context
add_preloaded("http://w3id.org/security/v1") do
new(processingMode: "json-ld-1.0", term_definitions: {
"CryptographicKey" => TermDefinition.new("CryptographicKey", id: "https://w3id.org/security#Key", simple: true),
"EcdsaKoblitzSignature2016" => TermDefinition.new("EcdsaKoblitzSignature2016", id: "https://w3id.org/security#EcdsaKoblitzSignature2016", simple: true),
"EncryptedMessage" => TermDefinition.new("EncryptedMessage", id: "https://w3id.org/security#EncryptedMessage", simple: true),
"GraphSignature2012" => TermDefinition.new("GraphSignature2012", id: "https://w3id.org/security#GraphSignature2012", simple: true),
"LinkedDataSignature2015" => TermDefinition.new("LinkedDataSignature2015", id: "https://w3id.org/security#LinkedDataSignature2015", simple: true),
"LinkedDataSignature2016" => TermDefinition.new("LinkedDataSignature2016", id: "https://w3id.org/security#LinkedDataSignature2016", simple: true),
"authenticationTag" => TermDefinition.new("authenticationTag", id: "https://w3id.org/security#authenticationTag", simple: true),
"canonicalizationAlgorithm" => TermDefinition.new("canonicalizationAlgorithm", id: "https://w3id.org/security#canonicalizationAlgorithm", simple: true),
"cipherAlgorithm" => TermDefinition.new("cipherAlgorithm", id: "https://w3id.org/security#cipherAlgorithm", simple: true),
"cipherData" => TermDefinition.new("cipherData", id: "https://w3id.org/security#cipherData", simple: true),
"cipherKey" => TermDefinition.new("cipherKey", id: "https://w3id.org/security#cipherKey", simple: true),
"created" => TermDefinition.new("created", id: "http://purl.org/dc/terms/created", type_mapping: "http://www.w3.org/2001/XMLSchema#dateTime"),
"creator" => TermDefinition.new("creator", id: "http://purl.org/dc/terms/creator", type_mapping: "@id"),
"dc" => TermDefinition.new("dc", id: "http://purl.org/dc/terms/", simple: true, prefix: true),
"digestAlgorithm" => TermDefinition.new("digestAlgorithm", id: "https://w3id.org/security#digestAlgorithm", simple: true),
"digestValue" => TermDefinition.new("digestValue", id: "https://w3id.org/security#digestValue", simple: true),
"domain" => TermDefinition.new("domain", id: "https://w3id.org/security#domain", simple: true),
"encryptionKey" => TermDefinition.new("encryptionKey", id: "https://w3id.org/security#encryptionKey", simple: true),
"expiration" => TermDefinition.new("expiration", id: "https://w3id.org/security#expiration", type_mapping: "http://www.w3.org/2001/XMLSchema#dateTime"),
"expires" => TermDefinition.new("expires", id: "https://w3id.org/security#expiration", type_mapping: "http://www.w3.org/2001/XMLSchema#dateTime"),
"id" => TermDefinition.new("id", id: "@id", simple: true),
"initializationVector" => TermDefinition.new("initializationVector", id: "https://w3id.org/security#initializationVector", simple: true),
"iterationCount" => TermDefinition.new("iterationCount", id: "https://w3id.org/security#iterationCount", simple: true),
"nonce" => TermDefinition.new("nonce", id: "https://w3id.org/security#nonce", simple: true),
"normalizationAlgorithm" => TermDefinition.new("normalizationAlgorithm", id: "https://w3id.org/security#normalizationAlgorithm", simple: true),
"owner" => TermDefinition.new("owner", id: "https://w3id.org/security#owner", type_mapping: "@id"),
"password" => TermDefinition.new("password", id: "https://w3id.org/security#password", simple: true),
"privateKey" => TermDefinition.new("privateKey", id: "https://w3id.org/security#privateKey", type_mapping: "@id"),
"privateKeyPem" => TermDefinition.new("privateKeyPem", id: "https://w3id.org/security#privateKeyPem", simple: true),
"publicKey" => TermDefinition.new("publicKey", id: "https://w3id.org/security#publicKey", type_mapping: "@id"),
"publicKeyPem" => TermDefinition.new("publicKeyPem", id: "https://w3id.org/security#publicKeyPem", simple: true),
"publicKeyService" => TermDefinition.new("publicKeyService", id: "https://w3id.org/security#publicKeyService", type_mapping: "@id"),
"revoked" => TermDefinition.new("revoked", id: "https://w3id.org/security#revoked", type_mapping: "http://www.w3.org/2001/XMLSchema#dateTime"),
"salt" => TermDefinition.new("salt", id: "https://w3id.org/security#salt", simple: true),
"sec" => TermDefinition.new("sec", id: "https://w3id.org/security#", simple: true, prefix: true),
"signature" => TermDefinition.new("signature", id: "https://w3id.org/security#signature", simple: true),
"signatureAlgorithm" => TermDefinition.new("signatureAlgorithm", id: "https://w3id.org/security#signingAlgorithm", simple: true),
"signatureValue" => TermDefinition.new("signatureValue", id: "https://w3id.org/security#signatureValue", simple: true),
"type" => TermDefinition.new("type", id: "@type", simple: true),
"xsd" => TermDefinition.new("xsd", id: "http://www.w3.org/2001/XMLSchema#", simple: true, prefix: true)
})
end
alias_preloaded("https://w3id.org/security/v1", "http://w3id.org/security/v1")
end

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

@ -0,0 +1,7 @@
# frozen_string_literal: true
# TODO: Starting with Rails 7.0, the framework default is true for this setting.
# This location in devise redirects and we can't hook in or override:
# https://github.com/heartcombo/devise/blob/v4.9.3/app/controllers/devise/confirmations_controller.rb#L28
# When solution is found, this setting can go back to default.
Rails.application.config.action_controller.raise_on_open_redirects = false

View file

@ -0,0 +1,71 @@
# frozen_string_literal: true
# Set OTEL_* environment variables according to OTel docs:
# https://opentelemetry.io/docs/concepts/sdk-configuration/
if ENV.keys.any? { |name| name.match?(/OTEL_.*_ENDPOINT/) }
require 'opentelemetry/sdk'
require 'opentelemetry/exporter/otlp'
require 'opentelemetry/instrumentation/active_job'
require 'opentelemetry/instrumentation/active_model_serializers'
require 'opentelemetry/instrumentation/concurrent_ruby'
require 'opentelemetry/instrumentation/excon'
require 'opentelemetry/instrumentation/faraday'
require 'opentelemetry/instrumentation/http'
require 'opentelemetry/instrumentation/http_client'
require 'opentelemetry/instrumentation/net/http'
require 'opentelemetry/instrumentation/pg'
require 'opentelemetry/instrumentation/rack'
require 'opentelemetry/instrumentation/rails'
require 'opentelemetry/instrumentation/redis'
require 'opentelemetry/instrumentation/sidekiq'
OpenTelemetry::SDK.configure do |c|
# use_all() attempts to load ALL the auto-instrumentations
# currently loaded by Ruby requires.
#
# Load attempts will emit an INFO or WARN to the console
# about the success/failure to wire up an auto-instrumentation.
# "WARN -- : Instrumentation: <X> failed to install" is most
# likely caused by <X> not being a Ruby library loaded by
# the application or the instrumentation has been explicitly
# disabled.
#
# To disable an instrumentation, set an environment variable
# along this pattern:
#
# OTEL_RUBY_INSTRUMENTATION_<X>_ENABLED=false
#
# For example, PostgreSQL and Redis produce a lot of child spans
# in the course of this application doing its business. To turn
# them off, set the env vars below, but recognize that you will
# be missing details about what particular calls to the
# datastores are slow.
#
# OTEL_RUBY_INSTRUMENTATION_PG_ENABLED=false
# OTEL_RUBY_INSTRUMENTATION_REDIS_ENABLED=false
c.use_all({
'OpenTelemetry::Instrumentation::Rack' => {
use_rack_events: false, # instead of events, use middleware; allows for untraced_endpoints to ignore child spans
untraced_endpoints: ['/health'],
},
'OpenTelemetry::Instrumentation::Sidekiq' => {
span_naming: :job_class, # Use the job class as the span name, otherwise this is the queue name and not very helpful
},
})
prefix = ENV.fetch('OTEL_SERVICE_NAME_PREFIX', 'mastodon')
separator = ENV.fetch('OTEL_SERVICE_NAME_SEPARATOR', '/')
c.service_name = case $PROGRAM_NAME
when /puma/ then "#{prefix}#{separator}web"
else
"#{prefix}#{separator}#{$PROGRAM_NAME.split('/').last}"
end
c.service_version = Mastodon::Version.to_s
end
end
MastodonOTELTracer = OpenTelemetry.tracer_provider.tracer('mastodon')

View file

@ -3,6 +3,8 @@
Paperclip::DataUriAdapter.register
Paperclip::ResponseWithLimitAdapter.register
PATH = ':prefix_url:class/:attachment/:id_partition/:style/:filename'
Paperclip.interpolates :filename do |attachment, style|
if style == :original
attachment.original_filename
@ -11,15 +13,15 @@ Paperclip.interpolates :filename do |attachment, style|
end
end
Paperclip.interpolates :prefix_path do |attachment, style|
Paperclip.interpolates :prefix_path do |attachment, _style|
if attachment.storage_schema_version >= 1 && attachment.instance.respond_to?(:local?) && !attachment.instance.local?
'cache' + File::SEPARATOR
"cache#{File::SEPARATOR}"
else
''
end
end
Paperclip.interpolates :prefix_url do |attachment, style|
Paperclip.interpolates :prefix_url do |attachment, _style|
if attachment.storage_schema_version >= 1 && attachment.instance.respond_to?(:local?) && !attachment.instance.local?
'cache/'
else
@ -29,7 +31,7 @@ end
Paperclip::Attachment.default_options.merge!(
use_timestamp: false,
path: ':prefix_url:class/:attachment/:id_partition/:style/:filename',
path: PATH,
storage: :fog
)
@ -40,6 +42,8 @@ if ENV['S3_ENABLED'] == 'true'
s3_protocol = ENV.fetch('S3_PROTOCOL') { 'https' }
s3_hostname = ENV.fetch('S3_HOSTNAME') { "s3-#{s3_region}.amazonaws.com" }
Paperclip::Attachment.default_options[:path] = ENV.fetch('S3_KEY_PREFIX') + "/#{PATH}" if ENV.has_key?('S3_KEY_PREFIX')
Paperclip::Attachment.default_options.merge!(
storage: :s3,
s3_protocol: s3_protocol,
@ -64,16 +68,16 @@ if ENV['S3_ENABLED'] == 'true'
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,
retry_limit: ENV.fetch('S3_RETRY_LIMIT') { '0' }.to_i,
}
)
Paperclip::Attachment.default_options[:s3_permissions] = ->(*) { nil } if ENV['S3_PERMISSION'] == ''
Paperclip::Attachment.default_options[:s3_permissions] = ->(*) {} 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',
force_path_style: ENV['S3_OVERRIDE_PATH_STYLE'] != 'true'
)
Paperclip::Attachment.default_options[:url] = ':s3_path_url'
@ -156,10 +160,11 @@ elsif ENV['AZURE_ENABLED'] == 'true'
)
end
else
Rails.configuration.x.file_storage_root_path = ENV.fetch('PAPERCLIP_ROOT_PATH', File.join(':rails_root', 'public', 'system'))
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',
path: File.join(Rails.configuration.x.file_storage_root_path, ':prefix_path:class', ':attachment', ':id_partition', ':style', ':filename'),
url: ENV.fetch('PAPERCLIP_ROOT_URL', '/system') + "/#{PATH}"
)
end

View file

@ -1,12 +1,15 @@
# frozen_string_literal: true
# Be sure to restart your server when you modify this file.
# 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"
# information see: https://developers.google.com/web/updates/2018/06/feature-policy
# Rails.application.config.permissions_policy do |policy|
# policy.camera :none
# policy.gyroscope :none
# policy.microphone :none
# policy.usb :none
# policy.fullscreen :self
# policy.payment :self, "https://secure.example.com"
# end

View file

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

View file

@ -0,0 +1,7 @@
# frozen_string_literal: true
# SVG icons
Rails.application.config.assets.paths << Rails.root.join('app', 'javascript', 'images')
# Material Design icons
Rails.application.config.assets.paths << Rails.root.join('app', 'javascript', 'material-icons')

View file

@ -14,7 +14,7 @@ class Rack::Attack
end
def remote_ip
@remote_ip ||= (@env["action_dispatch.remote_ip"] || ip).to_s
@remote_ip ||= (@env['action_dispatch.remote_ip'] || ip).to_s
end
def throttleable_remote_ip
@ -150,10 +150,10 @@ class Rack::Attack
match_data = request.env['rack.attack.match_data']
headers = {
'Content-Type' => 'application/json',
'X-RateLimit-Limit' => match_data[:limit].to_s,
'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),
'X-RateLimit-Reset' => (now + (match_data[:period] - (now.to_i % match_data[:period]))).iso8601(6),
}
[429, headers, [{ error: I18n.t('errors.429') }.to_json]]

View file

@ -3,7 +3,7 @@
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']
next unless [:throttle, :blocklist].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

@ -2,7 +2,10 @@
# 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
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

@ -3,12 +3,24 @@
require_relative '../../lib/mastodon/sidekiq_middleware'
Sidekiq.configure_server do |config|
if Rails.configuration.database_configuration.dig('production', 'adapter') == 'postgresql_makara'
STDERR.puts 'ERROR: Database replication is not currently supported in Sidekiq workers. Check your configuration.'
exit 1
end
config.redis = REDIS_CONFIGURATION.sidekiq
config.redis = REDIS_SIDEKIQ_PARAMS
# This is used in Kubernetes setups, to signal that the Sidekiq process has started and will begin processing jobs
# This comes from https://github.com/sidekiq/sidekiq/wiki/Kubernetes#sidekiq
ready_filename = ENV.fetch('MASTODON_SIDEKIQ_READY_FILENAME', nil)
if ready_filename
raise 'MASTODON_SIDEKIQ_READY_FILENAME is not a valid filename' if File.basename(ready_filename) != ready_filename
ready_path = Rails.root.join('tmp', ready_filename)
config.on(:startup) do
FileUtils.touch(ready_path)
end
config.on(:shutdown) do
FileUtils.rm_f(ready_path)
end
end
config.server_middleware do |chain|
chain.add Mastodon::SidekiqMiddleware
@ -22,11 +34,24 @@ Sidekiq.configure_server do |config|
chain.add SidekiqUniqueJobs::Middleware::Client
end
config.on(:startup) do
if SelfDestructHelper.self_destruct?
Sidekiq.schedule = {
'self_destruct_scheduler' => {
'interval' => ['1m'],
'class' => 'Scheduler::SelfDestructScheduler',
'queue' => 'scheduler',
},
}
SidekiqScheduler::Scheduler.instance.reload_schedule!
end
end
SidekiqUniqueJobs::Server.configure(config)
end
Sidekiq.configure_client do |config|
config.redis = REDIS_SIDEKIQ_PARAMS
config.redis = REDIS_CONFIGURATION.sidekiq
config.client_middleware do |chain|
chain.add SidekiqUniqueJobs::Middleware::Client
@ -36,6 +61,7 @@ end
Sidekiq.logger.level = ::Logger.const_get(ENV.fetch('RAILS_LOG_LEVEL', 'info').upcase.to_s)
SidekiqUniqueJobs.configure do |config|
config.enabled = !Rails.env.test?
config.reaper = :ruby
config.reaper_count = 1000
config.reaper_interval = 600

View file

@ -0,0 +1,19 @@
# frozen_string_literal: true
# TODO: https://github.com/simplecov-ruby/simplecov/pull/1084
# Patches this missing condition, monitor for upstream fix
module SimpleCov
module SourceFileExtensions
def build_branches
coverage_branch_data = coverage_data.fetch('branches', {}) || {} # Add the final empty hash in case where 'branches' is present, but returns nil
branches = coverage_branch_data.flat_map do |condition, coverage_branches|
build_branches_from(condition, coverage_branches)
end
process_skipped_branches(branches)
end
end
end
SimpleCov::SourceFile.prepend(SimpleCov::SourceFileExtensions) if defined?(SimpleCov::SourceFile)

View file

@ -164,7 +164,7 @@ SimpleForm.setup do |config|
# 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}" }
config.label_text = ->(label, required, _explicit_label) { "#{label} #{required}" }
# You can define the class to use on all labels. Default is nil.
# config.label_class = nil

View file

@ -1,19 +0,0 @@
# frozen_string_literal: true
if ENV['STATSD_ADDR'].present?
host, port = ENV['STATSD_ADDR'].split(':')
begin
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
rescue
Rails.logger.warn("statsd address #{ENV['STATSD_ADDR']} not reachable, proceeding without statsd")
end
end

View file

@ -3,6 +3,6 @@
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)]
Stoplight.default_data_store = Stoplight::DataStore::Redis.new(RedisConnection.new.connection)
Stoplight.default_notifiers = [Stoplight::Notifier::Logger.new(Rails.logger)]
end

View file

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

View file

@ -1,13 +1,8 @@
# 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
unless Rails.application.config.action_dispatch.trusted_proxies.nil?
# Rack is configured with a default collection of trusted proxies
# If Rails has been configured to use a specific list, configure
# Rack to use this Proc, which enforces the Rails-configured list.
Rack::Request.ip_filter = ->(ip) { Rails.application.config.action_dispatch.trusted_proxies.include?(ip) }
end

View file

@ -9,7 +9,7 @@ module Twitter::TwitterText
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_path_ending_chars] = /[^\p{White_Space}()?!*"'「」<>;:=,.$%\[\]~&|]|(?:#{REGEXEN[:valid_url_balanced_parens]})/iou
REGEXEN[:valid_url_balanced_parens] = /
\(
(?:

View file

@ -5,7 +5,7 @@ Rails.application.configure do
# 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)
# Generate with `bundle exec rails mastodon:webpush:generate_vapid_key` task (`docker-compose run --rm web bundle exec rails 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

View file

@ -0,0 +1,39 @@
# frozen_string_literal: true
if Rails.configuration.x.use_vips
ENV['VIPS_BLOCK_UNTRUSTED'] = 'true'
require 'vips'
unless Vips.at_least_libvips?(8, 13)
abort <<~ERROR.squish
Incompatible libvips version (#{Vips.version_string}), please install libvips >= 8.13
ERROR
end
Vips.block('VipsForeign', true)
%w(
VipsForeignLoadNsgif
VipsForeignLoadJpeg
VipsForeignLoadPng
VipsForeignLoadWebp
VipsForeignLoadHeif
VipsForeignSavePng
VipsForeignSaveSpng
VipsForeignSaveJpeg
VipsForeignSaveWebp
).each do |operation|
Vips.block(operation, false)
end
Vips.block_untrusted(true)
end
# In some places of the code, we rescue this exception, but we don't always
# load libvips, so it may be an undefined constant:
unless defined?(Vips)
module Vips
class Error < StandardError; end
end
end

View file

@ -6,7 +6,7 @@ WebAuthn.configure do |config|
config.origin = "#{Rails.configuration.x.use_https ? 'https' : 'http'}://#{Rails.configuration.x.web_domain}"
# Relying Party name for display purposes
config.rp_name = "Mastodon"
config.rp_name = 'Mastodon'
# Optionally configure a client timeout hint, in milliseconds.
# This hint specifies how long the browser should wait for an

View file

@ -53,3 +53,7 @@ af:
position:
elevated: kan nie hoër as jou huidige rol wees nie
own_role: kan nie verander word met jou huidige rol nie
webhook:
attributes:
events:
invalid_permissions: geleenthede waartoe jy nie toegang het nie mag nie ingesluit word nie

View file

@ -18,7 +18,7 @@ ast:
account:
attributes:
username:
invalid: ha contener namás lletres, númberos ya guiones baxos
invalid: ha contener namás lletres, númberos y guiones baxos
reserved: ta acutáu
admin/webhook:
attributes:

View file

@ -15,6 +15,8 @@ be:
user/invite_request:
text: Прычына
errors:
messages:
too_many_lines: перавышана абмежаванне ў %{limit} радкоў
models:
account:
attributes:

View file

@ -15,6 +15,12 @@ bg:
user/invite_request:
text: Причина
errors:
attributes:
domain:
invalid: не е действително име на домейн
messages:
invalid_domain_on_line: "%{value} не е действително име на домейн"
too_many_lines: е над ограничение от %{limit} реда
models:
account:
attributes:

View file

@ -15,6 +15,12 @@ ca:
user/invite_request:
text: Motiu
errors:
attributes:
domain:
invalid: no és un nom de domini vàlid
messages:
invalid_domain_on_line: "%{value} no és un nom de domini vàlid"
too_many_lines: sobrepassa el límit de %{limit} línies
models:
account:
attributes:

View file

@ -15,6 +15,12 @@ cy:
user/invite_request:
text: Rheswm
errors:
attributes:
domain:
invalid: "- nid yw'n enw parth dilys"
messages:
invalid_domain_on_line: Nid yw %{value} yn enw parth dilys
too_many_lines: "- dros y terfyn o %{limit} llinell"
models:
account:
attributes:

View file

@ -15,6 +15,12 @@ da:
user/invite_request:
text: Årsag
errors:
attributes:
domain:
invalid: er ikke et gyldigt domænenavn
messages:
invalid_domain_on_line: "%{value} er ikke et gyldigt domænenavn"
too_many_lines: overstiger grænsen på %{limit} linjer
models:
account:
attributes:

View file

@ -15,6 +15,12 @@ de:
user/invite_request:
text: Begründung
errors:
attributes:
domain:
invalid: ist kein gültiger Domain-Name
messages:
invalid_domain_on_line: "%{value} ist kein gültiger Domain-Name"
too_many_lines: übersteigt das Limit von %{limit} Zeilen
models:
account:
attributes:

View file

@ -15,6 +15,12 @@ el:
user/invite_request:
text: Αιτιολογία
errors:
attributes:
domain:
invalid: δεν είναι έγκυρο όνομα τομέα
messages:
invalid_domain_on_line: το %{value} δεν είναι έγκυρο όνομα τομέα
too_many_lines: υπερβαίνει το όριο των %{limit} γραμμών
models:
account:
attributes:
@ -36,14 +42,14 @@ el:
status:
attributes:
reblog:
taken: της κατάστασης ήδη υπάρχει
taken: της ανάρτησης υπάρχει ήδη
user:
attributes:
email:
blocked: χρησιμοποιεί μη επιτρεπόμενο πάροχο e-mail
unreachable: δεν φαίνεται να υπάρχει
role_id:
elevated: δεν μπορεί να είναι μεγαλύτερο από τον τρέχοντα ρόλο σας
elevated: δεν μπορεί να είναι υψηλότερο από τον τρέχοντα ρόλο σου
user_role:
attributes:
permissions_as_keys:
@ -53,3 +59,7 @@ el:
position:
elevated: δεν μπορεί να είναι μεγαλύτερο από τον τρέχοντα ρόλο σας
own_role: δεν μπορεί να αλλάξει με τον τρέχοντα ρόλο σας
webhook:
attributes:
events:
invalid_permissions: δεν μπορείτε να συμπεριλάβετε συμβάντα για τα οποία δεν έχετε τα δικαιώματα

View file

@ -15,6 +15,12 @@ en-GB:
user/invite_request:
text: Reason
errors:
attributes:
domain:
invalid: is not a valid domain name
messages:
invalid_domain_on_line: "%{value} is not a valid domain name"
too_many_lines: is over the limit of %{limit} lines
models:
account:
attributes:

View file

@ -15,6 +15,12 @@ en:
user/invite_request:
text: Reason
errors:
attributes:
domain:
invalid: is not a valid domain name
messages:
invalid_domain_on_line: "%{value} is not a valid domain name"
too_many_lines: is over the limit of %{limit} lines
models:
account:
attributes:

View file

@ -15,6 +15,12 @@ eo:
user/invite_request:
text: Kialo
errors:
attributes:
domain:
invalid: ne estas valida domajna nomo
messages:
invalid_domain_on_line: "%{value} ne estas valida domajna nomo"
too_many_lines: superas la limon de %{limit} linioj
models:
account:
attributes:

View file

@ -15,6 +15,12 @@ es-AR:
user/invite_request:
text: Motivo
errors:
attributes:
domain:
invalid: no es un nombre de dominio válido
messages:
invalid_domain_on_line: "%{value} no es un nombre de dominio válido"
too_many_lines: está por encima del límite de %{limit} líneas
models:
account:
attributes:

View file

@ -15,6 +15,12 @@ es-MX:
user/invite_request:
text: Motivo
errors:
attributes:
domain:
invalid: no es un nombre de dominio válido
messages:
invalid_domain_on_line: "%{value} no es un nombre de dominio válido"
too_many_lines: excede el límite de %{limit} líneas
models:
account:
attributes:

View file

@ -15,6 +15,12 @@ es:
user/invite_request:
text: Razón
errors:
attributes:
domain:
invalid: no es un nombre de dominio válido
messages:
invalid_domain_on_line: "%{value} no es un nombre de dominio válido"
too_many_lines: excede el límite de %{limit} líneas
models:
account:
attributes:
@ -56,4 +62,4 @@ es:
webhook:
attributes:
events:
invalid_permissions: no se pueden incluir eventos para los que no tienes derechos
invalid_permissions: no puede incluir eventos para los que no tienes permisos

View file

@ -15,6 +15,12 @@ et:
user/invite_request:
text: Põhjus
errors:
attributes:
domain:
invalid: pole kehtiv domeeninimi
messages:
invalid_domain_on_line: "%{value} ei ole kehtiv domeeninimi"
too_many_lines: on üle limiidi %{limit} rida
models:
account:
attributes:

View file

@ -19,7 +19,7 @@ eu:
account:
attributes:
username:
invalid: letrak, zenbakiak eta gidoi baxuak besterik ez
invalid: letrak, zenbakiak eta azpimarrak soilik izan behar ditu
reserved: erreserbatuta dago
admin/webhook:
attributes:

View file

@ -4,17 +4,23 @@ fi:
attributes:
poll:
expires_at: Määräaika
options: Valinnat
options: Vaihtoehdot
user:
agreement: Palvelusopimus
email: Sähköpostiosoite
locale: Alue
password: Salasana
user/account:
username: Käyttäjätunnus
username: Käyttäjänimi
user/invite_request:
text: Syy
errors:
attributes:
domain:
invalid: ei ole kelvollinen verkkotunnus
messages:
invalid_domain_on_line: "%{value} ei ole kelvollinen verkkotunnus"
too_many_lines: ylittää %{limit} rivin rajan
models:
account:
attributes:
@ -28,7 +34,7 @@ fi:
doorkeeper/application:
attributes:
website:
invalid: ei ole kelvollinen verkko-osoite
invalid: ei ole kelvollinen URL-osoite
import:
attributes:
data:
@ -36,19 +42,19 @@ fi:
status:
attributes:
reblog:
taken: tila on jo olemassa
taken: tästä julkaisusta on jo tehty
user:
attributes:
email:
blocked: käyttää kiellettyä sähköpostipalvelun tarjoajaa
blocked: käyttää kiellettyä sähköpostipalveluntarjoajaa
unreachable: ei näytä olevan olemassa
role_id:
elevated: ei voi olla korkeampi kuin nykyinen roolisi
user_role:
attributes:
permissions_as_keys:
dangerous: sisältää oikeudet, jotka eivät ole turvallisia perusroolille
elevated: ei voi sisältää oikeuksia, joita nykyisellä roolillasi ei ole
dangerous: sisällytä käyttöoikeuksia, jotka eivät ole turvallisia perusroolille
elevated: ei voi sisältää käyttöoikeuksia, joita nykyisellä roolillasi ei ole
own_role: ei voi muuttaa nykyisellä roolillasi
position:
elevated: ei voi olla korkeampi kuin nykyinen roolisi

View file

@ -0,0 +1 @@
fil:

View file

@ -15,6 +15,12 @@ fo:
user/invite_request:
text: Orsøk
errors:
attributes:
domain:
invalid: er ikki eitt virkið økisnavn
messages:
invalid_domain_on_line: "%{value} er ikki eitt virkið økisnavn"
too_many_lines: er longri enn markið á %{limit} reglur
models:
account:
attributes:

View file

@ -1,5 +1,5 @@
---
fr-QC:
fr-CA:
activerecord:
attributes:
poll:
@ -15,6 +15,12 @@ fr-QC:
user/invite_request:
text: Raison
errors:
attributes:
domain:
invalid: n'est pas un nom de domaine valide
messages:
invalid_domain_on_line: "%{value} n'est pas un nom de domaine valide"
too_many_lines: dépasse la limite de %{limit} lignes
models:
account:
attributes:

View file

@ -15,6 +15,12 @@ fr:
user/invite_request:
text: Motif
errors:
attributes:
domain:
invalid: n'est pas un nom de domaine valide
messages:
invalid_domain_on_line: "%{value} n'est pas un nom de domaine valide"
too_many_lines: dépasse la limite de %{limit} lignes
models:
account:
attributes:

View file

@ -15,12 +15,51 @@ ga:
user/invite_request:
text: Fáth
errors:
attributes:
domain:
invalid: nach ainm fearainn bailí é
messages:
invalid_domain_on_line: Ní ainm fearainn bailí é %{value}
too_many_lines: thar an teorainn de %{limit} línte
models:
account:
attributes:
username:
invalid: ní mór go mbeadh litreacha, uimhreacha agus pointí béime amháin
reserved: in áirithe
admin/webhook:
attributes:
url:
invalid: nach URL bailí é
doorkeeper/application:
attributes:
website:
invalid: nach URL bailí é
import:
attributes:
data:
malformed: míchumtha
status:
attributes:
reblog:
taken: den phost cheana féin
user:
attributes:
email:
blocked: úsáideann soláthraí ríomhphoist dícheadaithe
unreachable: ní cosúil go bhfuil sé ann
role_id:
elevated: ní féidir leat a bheith níos airde ná do ról reatha
user_role:
attributes:
permissions_as_keys:
dangerous: cuir san áireamh ceadanna nach bhfuil sábháilte don ról bunúsach
elevated: ní féidir ceadanna nach bhfuil ag do ról reatha a áireamh
own_role: ní féidir é a athrú le do ról reatha
position:
elevated: ní féidir leat a bheith níos airde ná do ról reatha
own_role: ní féidir é a athrú le do ról reatha
webhook:
attributes:
events:
invalid_permissions: ní féidir imeachtaí nach bhfuil na cearta agat ina leith a chur san áireamh

View file

@ -15,6 +15,12 @@ gd:
user/invite_request:
text: Adhbhar
errors:
attributes:
domain:
invalid: " chan eil seo na ainm àrainne dligheach"
messages:
invalid_domain_on_line: Chan eil %{value} na ainm àrainne dligheach
too_many_lines: " tha seo thar crìoch de %{limit} nan loidhnichean"
models:
account:
attributes:

View file

@ -15,6 +15,12 @@ gl:
user/invite_request:
text: Razón
errors:
attributes:
domain:
invalid: non é un nome de dominio válido
messages:
invalid_domain_on_line: "%{value} non é un nome de dominio válido"
too_many_lines: superou o límite de %{limit} liñas
models:
account:
attributes:

View file

@ -9,12 +9,18 @@ he:
agreement: הסכם שירות
email: כתובת דוא"ל
locale: הגדרות אזוריות
password: סיסמא
password: סיסמה
user/account:
username: שם משתמש/ת
user/invite_request:
text: סיבה
errors:
attributes:
domain:
invalid: אינו שם מתחם קביל
messages:
invalid_domain_on_line: "%{value} אינו שם מתחם קביל"
too_many_lines: מעבר למגבלה של %{limit} שורות
models:
account:
attributes:

View file

@ -6,7 +6,9 @@ hr:
expires_at: Krajnji rok
options: Opcije
user:
agreement: Ugovor o uslugama
email: E-mail adresa
locale: Lokalitet
password: Lozinka
user/account:
username: Korisničko ime
@ -18,3 +20,16 @@ hr:
attributes:
username:
invalid: mora sadržavati samo slova, brojeve i _
reserved: je rezervisano
admin/webhook:
attributes:
url:
invalid: nije validan URL
doorkeeper/application:
attributes:
website:
invalid: nije validan URL
import:
attributes:
data:
malformed: je neispravan

View file

@ -15,12 +15,18 @@ hu:
user/invite_request:
text: Indoklás
errors:
attributes:
domain:
invalid: nem egy érvényes domain név
messages:
invalid_domain_on_line: "%{value} nem egy érvényes domain név"
too_many_lines: túllépi a(z) %{limit} soros korlátot
models:
account:
attributes:
username:
invalid: csak betűket, számokat vagy alávonást tartalmazhat
reserved: fenntartott
reserved: foglalt
admin/webhook:
attributes:
url:

View file

@ -0,0 +1,64 @@
---
ia:
activerecord:
attributes:
poll:
expires_at: Data limite
options: Optiones
user:
agreement: Accordo de servicio
email: Adresse de e-mail
locale: Region
password: Contrasigno
user/account:
username: Nomine de usator
user/invite_request:
text: Motivo
errors:
attributes:
domain:
invalid: non es un nomine de dominio valide
messages:
invalid_domain_on_line: "%{value} non es un nomine de dominio valide"
models:
account:
attributes:
username:
invalid: debe continer solmente litteras, numeros e lineettas basse
reserved: es reservate
admin/webhook:
attributes:
url:
invalid: non es un URL valide
doorkeeper/application:
attributes:
website:
invalid: non es un URL valide
import:
attributes:
data:
malformed: es mal formate
status:
attributes:
reblog:
taken: del message jam existe
user:
attributes:
email:
blocked: usa un fornitor de e-mail prohibite
unreachable: non pare exister
role_id:
elevated: non pote esser superior a tu rolo actual
user_role:
attributes:
permissions_as_keys:
dangerous: includer permissiones non secur pro le rolo de base
elevated: non pote includer permissiones que tu rolo actual non possede
own_role: non pote esser cambiate con tu rolo actual
position:
elevated: non pote esser superior a tu rolo actual
own_role: non pote esser cambiate con tu rolo actual
webhook:
attributes:
events:
invalid_permissions: non pote includer eventos pro le quales tu non ha le derectos

View file

@ -0,0 +1,59 @@
---
ie:
activerecord:
attributes:
poll:
expires_at: Cludent date
options: Optiones
user:
agreement: Acorde de servicie
email: E-posta
locale: Local
password: Passa-parol
user/account:
username: Nómine del usator
user/invite_request:
text: Rason
errors:
models:
account:
attributes:
username:
invalid: deve contener solmen lítteres, númeres e sublineas
reserved: es reservat
admin/webhook:
attributes:
url:
invalid: ne es un valid URL
doorkeeper/application:
attributes:
website:
invalid: ne es un valid URL
import:
attributes:
data:
malformed: es malformat
status:
attributes:
reblog:
taken: de posta ja existe
user:
attributes:
email:
blocked: usa un ne-permisset provisor de e-posta
unreachable: sembla ne exister
role_id:
elevated: ne posse esser plu alt quam tui actual rol
user_role:
attributes:
permissions_as_keys:
dangerous: include permissones ne secur por li rol de base
elevated: ne posse includer permissiones ne possedet de tui rol actual
own_role: ne posse esser changeat con tui actual rol
position:
elevated: ne posse esser plu alt quam tui actual rol
own_role: ne posse esser changeat con tui actual rol
webhook:
attributes:
events:
invalid_permissions: ne posse includer evenimentes por queles tu ne have li yures

View file

@ -15,6 +15,12 @@ io:
user/invite_request:
text: Rezono
errors:
attributes:
domain:
invalid: ne esas valida domennomo
messages:
invalid_domain_on_line: "%{value} ne esas valida domennomo"
too_many_lines: esas plu kam la limito qua esas %{limit} linei
models:
account:
attributes:

View file

@ -15,6 +15,12 @@ is:
user/invite_request:
text: Ástæða
errors:
attributes:
domain:
invalid: er ekki leyfilegt nafn á léni
messages:
invalid_domain_on_line: "%{value} er ekki leyfilegt nafn á léni"
too_many_lines: er yfir takmörkum á %{limit} línum
models:
account:
attributes:

View file

@ -15,6 +15,12 @@ it:
user/invite_request:
text: Motivo
errors:
attributes:
domain:
invalid: non è un nome di dominio valido
messages:
invalid_domain_on_line: "%{value} non è un nome di dominio valido"
too_many_lines: è oltre il limite di %{limit} righe
models:
account:
attributes:

View file

@ -19,8 +19,20 @@ kab:
account:
attributes:
username:
invalid: isekkilen, uṭṭunen d yijerriden n wadda kan
invalid: ilaq ad ilin isekkilen, uṭṭunen d yijerriden n wadda kan
reserved: yettwaṭṭef
admin/webhook:
attributes:
url:
invalid: mačči d URL ameɣtu
doorkeeper/application:
attributes:
website:
invalid: mačči d URL ameɣtu
import:
attributes:
data:
malformed: yir amsal
status:
attributes:
reblog:
@ -28,4 +40,20 @@ kab:
user:
attributes:
email:
blocked: isseqdac asaǧǧaw n yimayl ur yettusirgen ara
unreachable: ur d-ttban ara d akken yella
role_id:
elevated: ur yezmir ara ad iεeddi tamlilt-ik tamirant
user_role:
attributes:
permissions_as_keys:
dangerous: deg-s tisirag tiriɣelsanin i temlilt tazadurt
elevated: ur yezmir ara ad yesεu tirirag ur nelli ara deg temlilit-ik tamirant
own_role: ur yezmir ara ad yettwabeddel s temlilt-ik tamirant
position:
elevated: ur yezmir ara ad iεeddi tamlilt-ik tamirant
own_role: ur yezmir ara ad yettwabeddel s temlilt-ik tamirant
webhook:
attributes:
events:
invalid_permissions: ur yezmir ara ad yesεu tidyanin iwumi ur tesεiḍ ara tisirag

View file

@ -15,6 +15,12 @@ ko:
user/invite_request:
text: 이유
errors:
attributes:
domain:
invalid: 올바른 도메인 네임이 아닙니다
messages:
invalid_domain_on_line: "%{value}는 올바른 도메인 네임이 아닙니다"
too_many_lines: "%{limit}줄 제한을 초과합니다"
models:
account:
attributes:

View file

@ -0,0 +1,59 @@
---
lad:
activerecord:
attributes:
poll:
expires_at: Limito temporal
options: Opsyones
user:
agreement: Akodro de servisyo
email: Adreso de posta elektronika
locale: Lingua
password: Kod
user/account:
username: Nombre de utilizador
user/invite_request:
text: Razon
errors:
models:
account:
attributes:
username:
invalid: solo puede kontener letras, shifras i sulinyados
reserved: esta rezervado
admin/webhook:
attributes:
url:
invalid: no es adreso URL valido
doorkeeper/application:
attributes:
website:
invalid: no es adreso URL valido
import:
attributes:
data:
malformed: tiene formato yerrado
status:
attributes:
reblog:
taken: de publikasyon ya existe
user:
attributes:
email:
blocked: uza un prokurador de posta no autorizado
unreachable: no parese existir
role_id:
elevated: no puede ser mas alto ke tu rolo aktual
user_role:
attributes:
permissions_as_keys:
dangerous: inkluir permisos ke no son siguros para el rolo de baza
elevated: no se puede inkluir permisos kualos no tiene tu rolo aktual
own_role: no se puede trokar kon tu rolo aktual
position:
elevated: no puede ser mas alto ke tu rolo aktual
own_role: no se puede trokar kon tu rolo aktual
webhook:
attributes:
events:
invalid_permissions: no puedes inkluir evenimientos a los kualos no estas autorizado

View file

@ -1 +1,65 @@
---
lt:
activerecord:
attributes:
poll:
expires_at: Galutinė data
options: Pasirinkimai
user:
agreement: Paslaugos sutartis
email: El. laiško adresas
locale: Lokali
password: Slaptažodis
user/account:
username: Naudotojo vardas
user/invite_request:
text: Priežastis
errors:
attributes:
domain:
invalid: nėra tinkamas domeno vardas.
messages:
invalid_domain_on_line: "%{value} nėra tinkamas domeno vardas."
too_many_lines: yra daugiau nei %{limit} eilučių ribojimą.
models:
account:
attributes:
username:
invalid: turi būti tik raidės, skaičiai ir pabraukimai.
reserved: užimtas.
admin/webhook:
attributes:
url:
invalid: nėra tinkamas URL adresas.
doorkeeper/application:
attributes:
website:
invalid: nėra tinkamas URL adresas.
import:
attributes:
data:
malformed: yra netaisyklinga.
status:
attributes:
reblog:
taken: įrašas jau egzistuoja.
user:
attributes:
email:
blocked: naudoja neleidžiamą el. laiško paslaugų teikėją.
unreachable: neatrodo, kad egzistuoja.
role_id:
elevated: negali būti didesnis nei tavo dabartinis vaidmuo.
user_role:
attributes:
permissions_as_keys:
dangerous: apima leidimus, kurie nėra saugūs pagrindiniam vaidmeniui.
elevated: negali apimti leidimų, kurių neturi tavo dabartinis vaidmuo.
own_role: negali būti pakeistas tavo dabartinis vaidmuo.
position:
elevated: negali būti didesnis nei tavo dabartinis vaidmuo.
own_role: negali būti pakeistas tavo dabartinis vaidmuo.
webhook:
attributes:
events:
invalid_permissions: negali įtraukti įvykių, į kuriuos neturi teisių.

View file

@ -15,6 +15,12 @@ lv:
user/invite_request:
text: Iemesls
errors:
attributes:
domain:
invalid: nav derīgs domēna nosaukums
messages:
invalid_domain_on_line: "%{value} nav derīgs domēna nosaukums"
too_many_lines: pārsniedz %{limit} līniju ierobežojumu
models:
account:
attributes:

View file

@ -0,0 +1 @@
ne:

View file

@ -15,6 +15,12 @@ nl:
user/invite_request:
text: Reden
errors:
attributes:
domain:
invalid: is een ongeldige domeinnaam
messages:
invalid_domain_on_line: "%{value} is een ongeldige domeinnaam"
too_many_lines: overschrijdt de limiet van %{limit} regels
models:
account:
attributes:

View file

@ -15,6 +15,12 @@ nn:
user/invite_request:
text: Grunn
errors:
attributes:
domain:
invalid: er ikkje eit gyldig domenenamn
messages:
invalid_domain_on_line: "%{value} er ikkje gyldig i eit domenenamn"
too_many_lines: er over grensa på %{limit} liner
models:
account:
attributes:

View file

@ -1 +1,23 @@
---
pa:
activerecord:
attributes:
poll:
expires_at: ਆਖਰੀ ਤਾਰੀਖ
options: ਚੋਣਾਂ
user:
agreement: ਸੇਵਾ ਸਮਝੌਤਾ
email: ਈਮੇਲ ਪਤਾ
locale: ਲੋਕੇਲ
password: ਪਾਸਵਰਡ
user/account:
username: ਵਰਤੋਂਕਾਰ-ਨਾਂ
user/invite_request:
text: ਕਾਰਨ
errors:
models:
account:
attributes:
username:
invalid: ਸਿਰਫ਼ ਅੱਖਰ, ਅੰਕ ਅਤੇ ਹੇਠਾਂ-ਰੇਖਾ ਹੀ ਹੋੋਣੀ ਚਾਹੀਦੀ ਹੈ
reserved: ਰਾਖਵਾਂ ਹੈ

View file

@ -15,6 +15,12 @@ pl:
user/invite_request:
text: Powód
errors:
attributes:
domain:
invalid: nie jest prawidłową nazwą domeny
messages:
invalid_domain_on_line: "%{value} nie jest prawidłową nazwą domeny"
too_many_lines: przekracza limit %{limit} linii
models:
account:
attributes:

View file

@ -15,6 +15,12 @@ pt-BR:
user/invite_request:
text: Razão
errors:
attributes:
domain:
invalid: não é um nome de domínio válido
messages:
invalid_domain_on_line: "%{value} não é um nome de domínio válido"
too_many_lines: está acima do limite de %{limit} linhas
models:
account:
attributes:
@ -32,7 +38,7 @@ pt-BR:
import:
attributes:
data:
malformed: está incorreto
malformed: está malformado
status:
attributes:
reblog:
@ -43,16 +49,16 @@ pt-BR:
blocked: usa provedor de e-mail não permitido
unreachable: parece não existir
role_id:
elevated: não pode ser maior que seu cargo atual
elevated: não pode maior que sua função atual
user_role:
attributes:
permissions_as_keys:
dangerous: incluir permissões que não são seguras para o cargo base
elevated: não pode incluir permissões que o seu cargo atual não possui
own_role: não pode ser alterado com seu cargo atual
dangerous: incluir permissões que não são seguras para a função base
elevated: não pode incluir permissões que a sua função atual não possui
own_role: não pode ser alterado com sua função atual
position:
elevated: não pode ser maior do que seu cargo atual
own_role: não pode ser alterado com seu cargo atual
elevated: não pode ser maior do que sua função atual
own_role: não pode ser alterado com sua função atual
webhook:
attributes:
events:

View file

@ -6,7 +6,7 @@ pt-PT:
expires_at: Prazo
options: Escolhas
user:
agreement: Acordo de serviço
agreement: Contrato de prestação de serviço
email: Endereço de correio electrónico
locale: Região
password: Palavra-passe
@ -19,7 +19,7 @@ pt-PT:
account:
attributes:
username:
invalid: apenas letras, números e underscores
invalid: deve conter apenas letras, números e traços inferiores
reserved: está reservado
admin/webhook:
attributes:
@ -43,15 +43,15 @@ pt-PT:
blocked: usa um fornecedor de e-mail que não é permitido
unreachable: não parece existir
role_id:
elevated: não pode ser maior que o da sua função atual
elevated: não pode ser superior à sua função atual
user_role:
attributes:
permissions_as_keys:
dangerous: incluir permissões que não são seguras para a função base
elevated: não pode incluir permissões que a sua função atual não possui
elevated: não pode incluir permissões que a sua função atual não possua
own_role: não pode ser alterado com a sua função atual
position:
elevated: não pode ser maior que o da sua função atual
elevated: não pode ser superior à sua função atual
own_role: não pode ser alterado com a sua função atual
webhook:
attributes:

View file

@ -11,15 +11,21 @@ ro:
locale: Localizare
password: Parolă
user/account:
username: Nume utilizator
username: Nume de utilizator
user/invite_request:
text: Motiv
errors:
attributes:
domain:
invalid: nu este un nume de domeniu valid
messages:
invalid_domain_on_line: "%{value} nu este un nume de domeniu valid"
too_many_lines: este peste limita de %{limit} linii
models:
account:
attributes:
username:
invalid: doar litere, numere și sublinieri
invalid: trebuie să conțină numai litere, cifre și bară jos (_)
reserved: este rezervat
admin/webhook:
attributes:
@ -56,4 +62,4 @@ ro:
webhook:
attributes:
events:
invalid_permissions: nu poate include evenimente la care nu aveți drepturi
invalid_permissions: nu poate include evenimente la care nu aveți dreptul

View file

@ -15,6 +15,12 @@ ru:
user/invite_request:
text: Причина
errors:
attributes:
domain:
invalid: не является действующим доменным именем
messages:
invalid_domain_on_line: "%{value} Не является действительным доменным именем"
too_many_lines: Превышает предел %{limit} строк
models:
account:
attributes:
@ -36,7 +42,7 @@ ru:
status:
attributes:
reblog:
taken: поста уже существует
taken: пост уже существует
user:
attributes:
email:

Some files were not shown because too many files have changed in this diff Show more