From 9edab7afafd6f6db9338ada83a84b2ef14f397a9 Mon Sep 17 00:00:00 2001 From: Sasha Sorokin Date: Wed, 1 Jan 2020 04:15:05 +0700 Subject: Add translation project promotion link (#12736) This commit adds promotional notice on appearance settings about translation project if any other locale than English is used. It allows users to learn and contribute translations to Mastodon. Step ahead, in this commit one unusual string is added - link to a guide. By default it refers to Crowdin project itself, but if any of Mastodon localization teams established their own guide, they can refer it. Or, if Crowdin supports localized domain for language, it can also be put there (e.g. https://fr.crowdin.com/...). --- config/locales/en.yml | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'config') diff --git a/config/locales/en.yml b/config/locales/en.yml index c7179d304..42bd81e40 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -581,6 +581,10 @@ en: animations_and_accessibility: Animations and accessibility confirmation_dialogs: Confirmation dialogs discovery: Discovery + localization: + body: Mastodon is translated by volunteers. + guide_link: https://crowdin.com/project/mastodon + guide_link_text: Everyone can contribute. sensitive_content: Sensitive content toot_layout: Toot layout application_mailer: -- cgit From 09d54d1f626163fcc6e282544dfc9939fd3cdfd3 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 2 Jan 2020 17:14:58 +0100 Subject: Fix uncaught query param encoding errors (#12741) --- app/middleware/handle_bad_encoding_middleware.rb | 18 ++++++++++++++++++ config/application.rb | 2 ++ config/initializers/rack_attack.rb | 3 --- .../handle_bad_encoding_middleware_spec.rb | 21 +++++++++++++++++++++ 4 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 app/middleware/handle_bad_encoding_middleware.rb create mode 100644 spec/middleware/handle_bad_encoding_middleware_spec.rb (limited to 'config') diff --git a/app/middleware/handle_bad_encoding_middleware.rb b/app/middleware/handle_bad_encoding_middleware.rb new file mode 100644 index 000000000..6fce84b15 --- /dev/null +++ b/app/middleware/handle_bad_encoding_middleware.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true +# See: https://jamescrisp.org/2018/05/28/fixing-invalid-query-parameters-invalid-encoding-in-a-rails-app/ + +class HandleBadEncodingMiddleware + def initialize(app) + @app = app + end + + def call(env) + begin + Rack::Utils.parse_nested_query(env['QUERY_STRING'].to_s) + rescue Rack::Utils::InvalidParameterError + env['QUERY_STRING'] = '' + end + + @app.call(env) + end +end diff --git a/config/application.rb b/config/application.rb index e1f7ae707..58e59fd51 100644 --- a/config/application.rb +++ b/config/application.rb @@ -7,6 +7,7 @@ require 'rails/all' Bundler.require(*Rails.groups) require_relative '../app/lib/exceptions' +require_relative '../app/middleware/handle_bad_encoding_middleware' require_relative '../lib/paperclip/lazy_thumbnail' require_relative '../lib/paperclip/gif_transcoder' require_relative '../lib/paperclip/video_transcoder' @@ -118,6 +119,7 @@ module Mastodon config.active_job.queue_adapter = :sidekiq + config.middleware.insert_before Rack::Runtime, HandleBadEncodingMiddleware config.middleware.use Rack::Attack config.middleware.use Rack::Deflater diff --git a/config/initializers/rack_attack.rb b/config/initializers/rack_attack.rb index 273cac9ca..3cd7ea3a6 100644 --- a/config/initializers/rack_attack.rb +++ b/config/initializers/rack_attack.rb @@ -46,10 +46,7 @@ class Rack::Attack PROTECTED_PATHS_REGEX = Regexp.union(PROTECTED_PATHS.map { |path| /\A#{Regexp.escape(path)}/ }) - # Always allow requests from localhost - # (blocklist & throttles are skipped) Rack::Attack.safelist('allow from localhost') do |req| - # Requests are allowed if the return value is truthy req.remote_ip == '127.0.0.1' || req.remote_ip == '::1' end diff --git a/spec/middleware/handle_bad_encoding_middleware_spec.rb b/spec/middleware/handle_bad_encoding_middleware_spec.rb new file mode 100644 index 000000000..8c0d24f18 --- /dev/null +++ b/spec/middleware/handle_bad_encoding_middleware_spec.rb @@ -0,0 +1,21 @@ +require 'rails_helper' + +RSpec.describe HandleBadEncodingMiddleware do + let(:app) { double() } + let(:middleware) { HandleBadEncodingMiddleware.new(app) } + + it "request with query string is unchanged" do + expect(app).to receive(:call).with("PATH" => "/some/path", "QUERY_STRING" => "name=fred") + middleware.call("PATH" => "/some/path", "QUERY_STRING" => "name=fred") + end + + it "request with no query string is unchanged" do + expect(app).to receive(:call).with("PATH" => "/some/path") + middleware.call("PATH" => "/some/path") + end + + it "request with invalid encoding in query string drops query string" do + expect(app).to receive(:call).with("QUERY_STRING" => "", "PATH" => "/some/path") + middleware.call("QUERY_STRING" => "q=%2Fsearch%2Fall%Forder%3Ddescending%26page%3D5%26sort%3Dcreated_at", "PATH" => "/some/path") + end +end -- cgit From 59c697a30cae2d50e5be2dd273e5c3956b2a2d6e Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 3 Jan 2020 05:35:46 +0100 Subject: Fix resource_owner_from_credentials in Doorkeeper initializer (#12743) - Nil error when e-mail not found - LDAP authentication used in place of PAM authentication --- config/initializers/doorkeeper.rb | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) (limited to 'config') diff --git a/config/initializers/doorkeeper.rb b/config/initializers/doorkeeper.rb index 7784bec62..e03380cec 100644 --- a/config/initializers/doorkeeper.rb +++ b/config/initializers/doorkeeper.rb @@ -8,20 +8,15 @@ Doorkeeper.configure do end resource_owner_from_credentials do |_routes| - if Devise.ldap_authentication - user = User.authenticate_with_ldap({ :email => request.params[:username], :password => request.params[:password] }) - end - - if Devise.pam_authentication - user ||= User.authenticate_with_ldap({ :email => request.params[:username], :password => request.params[:password] }) - end + user = User.authenticate_with_ldap(email: request.params[:username], password: request.params[:password]) if Devise.ldap_authentication + user ||= User.authenticate_with_pam(email: request.params[:username], password: request.params[:password]) if Devise.pam_authentication if user.nil? user = User.find_by(email: request.params[:username]) - user = nil unless user.valid_password?(request.params[:password]) + user = nil unless user&.valid_password?(request.params[:password]) end - user if !user&.otp_required_for_login? + user unless user&.otp_required_for_login? end # If you want to restrict access to the web interface for adding oauth authorized applications, you need to declare the block below. -- cgit From 49b2f7c0a2aa41b1da77b652415078e19fcdcad8 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sat, 4 Jan 2020 01:54:07 +0100 Subject: Fix base64-encoded file uploads not being possible (#12748) Fix #3804, Fix #5776 --- app/controllers/admin/custom_emojis_controller.rb | 4 --- app/controllers/api/v1/media_controller.rb | 3 --- app/controllers/application_controller.rb | 1 + app/controllers/concerns/obfuscate_filename.rb | 16 ------------ app/controllers/settings/profiles_controller.rb | 5 ---- app/models/concerns/attachmentable.rb | 11 ++++++++ app/models/media_attachment.rb | 3 +++ config/initializers/paperclip.rb | 2 ++ spec/controllers/api/proofs_controller_spec.rb | 5 +--- .../concerns/obfuscate_filename_spec.rb | 30 ---------------------- spec/models/account_spec.rb | 1 + spec/models/media_attachment_spec.rb | 18 +++++++++++++ .../examples/models/concerns/account_avatar.rb | 20 +++++++++++++++ .../examples/models/concerns/account_header.rb | 23 +++++++++++++++++ 14 files changed, 80 insertions(+), 62 deletions(-) delete mode 100644 app/controllers/concerns/obfuscate_filename.rb delete mode 100644 spec/controllers/concerns/obfuscate_filename_spec.rb create mode 100644 spec/support/examples/models/concerns/account_header.rb (limited to 'config') diff --git a/app/controllers/admin/custom_emojis_controller.rb b/app/controllers/admin/custom_emojis_controller.rb index 2af90f051..a446465c9 100644 --- a/app/controllers/admin/custom_emojis_controller.rb +++ b/app/controllers/admin/custom_emojis_controller.rb @@ -2,10 +2,6 @@ module Admin class CustomEmojisController < BaseController - include ObfuscateFilename - - obfuscate_filename [:custom_emoji, :image] - def index authorize :custom_emoji, :index? diff --git a/app/controllers/api/v1/media_controller.rb b/app/controllers/api/v1/media_controller.rb index aaa93b615..81825db15 100644 --- a/app/controllers/api/v1/media_controller.rb +++ b/app/controllers/api/v1/media_controller.rb @@ -4,9 +4,6 @@ class Api::V1::MediaController < Api::BaseController before_action -> { doorkeeper_authorize! :write, :'write:media' } before_action :require_user! - include ObfuscateFilename - obfuscate_filename :file - respond_to :json def create diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 3f9205381..0cfa2b386 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -24,6 +24,7 @@ class ApplicationController < ActionController::Base rescue_from ActionController::InvalidAuthenticityToken, with: :unprocessable_entity rescue_from ActionController::UnknownFormat, with: :not_acceptable rescue_from ActionController::ParameterMissing, with: :bad_request + rescue_from Paperclip::AdapterRegistry::NoHandlerError, with: :bad_request rescue_from ActiveRecord::RecordNotFound, with: :not_found rescue_from Mastodon::NotPermittedError, with: :forbidden rescue_from HTTP::Error, OpenSSL::SSL::SSLError, with: :internal_server_error diff --git a/app/controllers/concerns/obfuscate_filename.rb b/app/controllers/concerns/obfuscate_filename.rb deleted file mode 100644 index 22736ec3a..000000000 --- a/app/controllers/concerns/obfuscate_filename.rb +++ /dev/null @@ -1,16 +0,0 @@ -# frozen_string_literal: true - -module ObfuscateFilename - extend ActiveSupport::Concern - - class_methods do - def obfuscate_filename(path) - before_action do - file = params.dig(*path) - next if file.nil? - - file.original_filename = SecureRandom.hex(8) + File.extname(file.original_filename) - end - end - end -end diff --git a/app/controllers/settings/profiles_controller.rb b/app/controllers/settings/profiles_controller.rb index 8b640cdca..19a7ce157 100644 --- a/app/controllers/settings/profiles_controller.rb +++ b/app/controllers/settings/profiles_controller.rb @@ -1,16 +1,11 @@ # frozen_string_literal: true class Settings::ProfilesController < Settings::BaseController - include ObfuscateFilename - layout 'admin' before_action :authenticate_user! before_action :set_account - obfuscate_filename [:account, :avatar] - obfuscate_filename [:account, :header] - def show @account.build_fields end diff --git a/app/models/concerns/attachmentable.rb b/app/models/concerns/attachmentable.rb index 3bbc6453c..1e8c4806f 100644 --- a/app/models/concerns/attachmentable.rb +++ b/app/models/concerns/attachmentable.rb @@ -9,6 +9,7 @@ module Attachmentable GIF_MATRIX_LIMIT = 921_600 # 1280x720px included do + before_post_process :obfuscate_file_name before_post_process :set_file_extensions before_post_process :check_image_dimensions before_post_process :set_file_content_type @@ -68,4 +69,14 @@ module Attachmentable rescue Terrapin::CommandLineError '' end + + def obfuscate_file_name + self.class.attachment_definitions.each_key do |attachment_name| + attachment = send(attachment_name) + + next if attachment.blank? + + attachment.instance_write :file_name, SecureRandom.hex(8) + File.extname(attachment.instance_read(:file_name)) + end + end end diff --git a/app/models/media_attachment.rb b/app/models/media_attachment.rb index 573ef5dfc..1fd0adfd0 100644 --- a/app/models/media_attachment.rb +++ b/app/models/media_attachment.rb @@ -202,9 +202,12 @@ class MediaAttachment < ApplicationRecord end after_commit :reset_parent_cache, on: :update + before_create :prepare_description, unless: :local? before_create :set_shortcode + before_post_process :set_type_and_extension + before_save :set_meta class << self diff --git a/config/initializers/paperclip.rb b/config/initializers/paperclip.rb index 5109baff7..8909678d6 100644 --- a/config/initializers/paperclip.rb +++ b/config/initializers/paperclip.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +Paperclip::DataUriAdapter.register + Paperclip.interpolates :filename do |attachment, style| if style == :original attachment.original_filename diff --git a/spec/controllers/api/proofs_controller_spec.rb b/spec/controllers/api/proofs_controller_spec.rb index dbde4927f..2fe615005 100644 --- a/spec/controllers/api/proofs_controller_spec.rb +++ b/spec/controllers/api/proofs_controller_spec.rb @@ -85,10 +85,7 @@ describe Api::ProofsController do end it 'has the correct avatar url' do - first_part = 'https://cb6e6126.ngrok.io/system/accounts/avatars/' - last_part = 'original/avatar.gif' - - expect(body_as_json[:avatar]).to match /#{Regexp.quote(first_part)}(?:\d{3,5}\/){3}#{Regexp.quote(last_part)}/ + expect(body_as_json[:avatar]).to match "https://cb6e6126.ngrok.io#{alice.avatar.url}" end end end diff --git a/spec/controllers/concerns/obfuscate_filename_spec.rb b/spec/controllers/concerns/obfuscate_filename_spec.rb deleted file mode 100644 index e06d53c03..000000000 --- a/spec/controllers/concerns/obfuscate_filename_spec.rb +++ /dev/null @@ -1,30 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe ApplicationController, type: :controller do - controller do - include ObfuscateFilename - - obfuscate_filename :file - - def file - render plain: params[:file]&.original_filename - end - end - - before do - routes.draw { get 'file' => 'anonymous#file' } - end - - it 'obfusticates filename if the given parameter is specified' do - file = fixture_file_upload('files/imports.txt', 'text/plain') - post 'file', params: { file: file } - expect(response.body).to end_with '.txt' - expect(response.body).not_to include 'imports' - end - - it 'does nothing if the given parameter is not specified' do - post 'file' - end -end diff --git a/spec/models/account_spec.rb b/spec/models/account_spec.rb index b2f6234cb..3cca9b343 100644 --- a/spec/models/account_spec.rb +++ b/spec/models/account_spec.rb @@ -823,4 +823,5 @@ RSpec.describe Account, type: :model do end include_examples 'AccountAvatar', :account + include_examples 'AccountHeader', :account end diff --git a/spec/models/media_attachment_spec.rb b/spec/models/media_attachment_spec.rb index 7ddfba7ed..a275621a1 100644 --- a/spec/models/media_attachment_spec.rb +++ b/spec/models/media_attachment_spec.rb @@ -133,6 +133,24 @@ RSpec.describe MediaAttachment, type: :model do expect(media.file.meta["small"]["height"]).to eq 327 expect(media.file.meta["small"]["aspect"]).to eq 490.0 / 327 end + + it 'gives the file a random name' do + expect(media.file_file_name).to_not eq 'attachment.jpg' + end + end + + describe 'base64-encoded jpeg' do + let(:base64_attachment) { "data:image/jpeg;base64,#{Base64.encode64(attachment_fixture('attachment.jpg').read)}" } + let(:media) { MediaAttachment.create(account: Fabricate(:account), file: base64_attachment) } + + it 'saves media attachment' do + expect(media.persisted?).to be true + expect(media.file).to_not be_nil + end + + it 'gives the file a file name' do + expect(media.file_file_name).to_not be_blank + end end describe 'descriptions for remote attachments' do diff --git a/spec/support/examples/models/concerns/account_avatar.rb b/spec/support/examples/models/concerns/account_avatar.rb index f2a8a2459..2180f5273 100644 --- a/spec/support/examples/models/concerns/account_avatar.rb +++ b/spec/support/examples/models/concerns/account_avatar.rb @@ -16,4 +16,24 @@ shared_examples 'AccountAvatar' do |fabricator| end end end + + describe 'base64-encoded files' do + let(:base64_attachment) { "data:image/jpeg;base64,#{Base64.encode64(attachment_fixture('attachment.jpg').read)}" } + let(:account) { Fabricate(fabricator, avatar: base64_attachment) } + + it 'saves avatar' do + expect(account.persisted?).to be true + expect(account.avatar).to_not be_nil + end + + it 'gives the avatar a file name' do + expect(account.avatar_file_name).to_not be_blank + end + + it 'saves a new avatar under a different file name' do + previous_file_name = account.avatar_file_name + account.update(avatar: base64_attachment) + expect(account.avatar_file_name).to_not eq previous_file_name + end + end end diff --git a/spec/support/examples/models/concerns/account_header.rb b/spec/support/examples/models/concerns/account_header.rb new file mode 100644 index 000000000..77ee0e629 --- /dev/null +++ b/spec/support/examples/models/concerns/account_header.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +shared_examples 'AccountHeader' do |fabricator| + describe 'base64-encoded files' do + let(:base64_attachment) { "data:image/jpeg;base64,#{Base64.encode64(attachment_fixture('attachment.jpg').read)}" } + let(:account) { Fabricate(fabricator, header: base64_attachment) } + + it 'saves header' do + expect(account.persisted?).to be true + expect(account.header).to_not be_nil + end + + it 'gives the header a file name' do + expect(account.header_file_name).to_not be_blank + end + + it 'saves a new header under a different file name' do + previous_file_name = account.header_file_name + account.update(header: base64_attachment) + expect(account.header_file_name).to_not eq previous_file_name + end + end +end -- cgit