From 339ce1c4e90605b736745b1f04493a247b2627ec Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sun, 8 Mar 2020 15:17:39 +0100 Subject: Add specific rate limits for posting and following (#13172) --- app/lib/exceptions.rb | 1 + app/lib/rate_limiter.rb | 64 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 app/lib/rate_limiter.rb (limited to 'app/lib') diff --git a/app/lib/exceptions.rb b/app/lib/exceptions.rb index 01346bfe5..3362576b0 100644 --- a/app/lib/exceptions.rb +++ b/app/lib/exceptions.rb @@ -8,6 +8,7 @@ module Mastodon class LengthValidationError < ValidationError; end class DimensionsValidationError < ValidationError; end class RaceConditionError < Error; end + class RateLimitExceededError < Error; end class UnexpectedResponseError < Error def initialize(response = nil) diff --git a/app/lib/rate_limiter.rb b/app/lib/rate_limiter.rb new file mode 100644 index 000000000..68dae9add --- /dev/null +++ b/app/lib/rate_limiter.rb @@ -0,0 +1,64 @@ +# frozen_string_literal: true + +class RateLimiter + include Redisable + + FAMILIES = { + follows: { + limit: 400, + period: 24.hours.freeze, + }.freeze, + + statuses: { + limit: 300, + period: 3.hours.freeze, + }.freeze, + + media: { + limit: 30, + period: 30.minutes.freeze, + }.freeze, + }.freeze + + def initialize(by, options = {}) + @by = by + @family = options[:family] + @limit = FAMILIES[@family][:limit] + @period = FAMILIES[@family][:period].to_i + end + + def record! + count = redis.get(key) + + if count.nil? + redis.set(key, 0) + redis.expire(key, (@period - (last_epoch_time % @period) + 1).to_i) + end + + raise Mastodon::RateLimitExceededError if count.present? && count.to_i >= @limit + + redis.incr(key) + end + + def rollback! + redis.decr(key) + end + + def to_headers(now = Time.now.utc) + { + 'X-RateLimit-Limit' => @limit.to_s, + 'X-RateLimit-Remaining' => (@limit - (redis.get(key) || 0).to_i).to_s, + 'X-RateLimit-Reset' => (now + (@period - now.to_i % @period)).iso8601(6), + } + end + + private + + def key + @key ||= "rate_limit:#{@by.id}:#{@family}:#{(last_epoch_time / @period).to_i}" + end + + def last_epoch_time + @last_epoch_time ||= Time.now.to_i + end +end -- cgit From 7088633ae11bfb79bed0d853f70547396c4380f2 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 9 Mar 2020 00:12:52 +0100 Subject: Bump cld3 from 3.2.6 to 3.3.0 (#13107) * Bump cld3 from 3.2.6 to 3.3.0 Bumps [cld3](https://github.com/akihikodaki/cld3-ruby) from 3.2.6 to 3.3.0. - [Release notes](https://github.com/akihikodaki/cld3-ruby/releases) - [Commits](https://github.com/akihikodaki/cld3-ruby/compare/v3.2.6...v3.3.0) Signed-off-by: dependabot-preview[bot] * Fix compatibility with cld3 3.3.0 Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> Co-authored-by: Eugen Rochko --- Gemfile | 2 +- Gemfile.lock | 4 ++-- app/lib/language_detector.rb | 4 +++- 3 files changed, 6 insertions(+), 4 deletions(-) (limited to 'app/lib') diff --git a/Gemfile b/Gemfile index f6c705765..d3056c929 100644 --- a/Gemfile +++ b/Gemfile @@ -35,7 +35,7 @@ gem 'browser' gem 'charlock_holmes', '~> 0.7.7' gem 'iso-639' gem 'chewy', '~> 5.1' -gem 'cld3', '~> 3.2.6' +gem 'cld3', '~> 3.3.0' gem 'devise', '~> 4.7' gem 'devise-two-factor', '~> 3.1' diff --git a/Gemfile.lock b/Gemfile.lock index cd255bc3e..82e6360ff 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -160,7 +160,7 @@ GEM elasticsearch (>= 2.0.0) elasticsearch-dsl chunky_png (1.3.11) - cld3 (3.2.6) + cld3 (3.3.0) ffi (>= 1.1.0, < 1.12.0) climate_control (0.2.0) cocaine (0.5.8) @@ -681,7 +681,7 @@ DEPENDENCIES capybara (~> 3.31) charlock_holmes (~> 0.7.7) chewy (~> 5.1) - cld3 (~> 3.2.6) + cld3 (~> 3.3.0) climate_control (~> 0.2) concurrent-ruby connection_pool diff --git a/app/lib/language_detector.rb b/app/lib/language_detector.rb index 302072bcc..05a06726d 100644 --- a/app/lib/language_detector.rb +++ b/app/lib/language_detector.rb @@ -52,8 +52,10 @@ class LanguageDetector def detect_language_code(text) return if unreliable_input?(text) + result = @identifier.find_language(text) - iso6391(result.language.to_s).to_sym if result.reliable? + + iso6391(result.language.to_s).to_sym if result&.reliable? end def iso6391(bcp47) -- cgit From 2c510ee00a9fb4141a428d9a21dbd561171b3409 Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Sun, 22 Mar 2020 16:59:29 +0100 Subject: Fix glitch-soc marking every link in toots as a tag Fixes #1281 --- app/lib/formatter.rb | 2 +- app/lib/sanitize_config.rb | 11 ++++++++++- spec/lib/sanitize_config_spec.rb | 6 +++++- 3 files changed, 16 insertions(+), 3 deletions(-) (limited to 'app/lib') diff --git a/app/lib/formatter.rb b/app/lib/formatter.rb index fcc99d009..b7a0286d2 100644 --- a/app/lib/formatter.rb +++ b/app/lib/formatter.rb @@ -131,7 +131,7 @@ class Formatter end def link_url(url) - "#{link_html(url)}" + "#{link_html(url)}" end private diff --git a/app/lib/sanitize_config.rb b/app/lib/sanitize_config.rb index e3fc94ba6..8bbcca4ce 100644 --- a/app/lib/sanitize_config.rb +++ b/app/lib/sanitize_config.rb @@ -54,6 +54,15 @@ class Sanitize end end + LINK_REL_TRANSFORMER = lambda do |env| + return unless env[:node_name] == 'a' + + node = env[:node] + + rel = (node['rel'] || '').split(' ') & ['tag'] + node['rel'] = (['nofollow', 'noopener', 'noreferrer'] + rel).join(' ') + end + UNSUPPORTED_HREF_TRANSFORMER = lambda do |env| return unless env[:node_name] == 'a' @@ -82,7 +91,6 @@ class Sanitize add_attributes: { 'a' => { - 'rel' => 'nofollow noopener tag noreferrer', 'target' => '_blank', }, }, @@ -95,6 +103,7 @@ class Sanitize transformers: [ CLASS_WHITELIST_TRANSFORMER, IMG_TAG_TRANSFORMER, + LINK_REL_TRANSFORMER, UNSUPPORTED_HREF_TRANSFORMER, ] ) diff --git a/spec/lib/sanitize_config_spec.rb b/spec/lib/sanitize_config_spec.rb index 50558a0d8..2d82c00ea 100644 --- a/spec/lib/sanitize_config_spec.rb +++ b/spec/lib/sanitize_config_spec.rb @@ -28,7 +28,11 @@ describe Sanitize::Config do end it 'keeps a with href' do - expect(Sanitize.fragment('Test', subject)).to eq 'Test' + expect(Sanitize.fragment('Test', subject)).to eq 'Test' + end + + it 'keeps a with href and rel tag' do + expect(Sanitize.fragment('', subject)).to eq 'Test' end end end -- cgit From 02f1c04fabab221130de8dfb5611be81825b193b Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Sun, 22 Mar 2020 17:56:49 +0100 Subject: Make sanitizer *not* add no-referrer etc. in local markdown toots if the link is “safe” MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/lib/formatter.rb | 6 +++--- app/lib/sanitize_config.rb | 7 +++++-- spec/lib/sanitize_config_spec.rb | 13 ++++++++++++- 3 files changed, 20 insertions(+), 6 deletions(-) (limited to 'app/lib') diff --git a/app/lib/formatter.rb b/app/lib/formatter.rb index b7a0286d2..051f27408 100644 --- a/app/lib/formatter.rb +++ b/app/lib/formatter.rb @@ -59,7 +59,7 @@ class Formatter html = "RT @#{prepend_reblog} #{html}" if prepend_reblog html = format_markdown(html) if status.content_type == 'text/markdown' html = encode_and_link_urls(html, linkable_accounts, keep_html: %w(text/markdown text/html).include?(status.content_type)) - html = reformat(html) if %w(text/markdown text/html).include?(status.content_type) + html = reformat(html, true) if %w(text/markdown text/html).include?(status.content_type) html = encode_custom_emojis(html, status.emojis, options[:autoplay]) if options[:custom_emojify] unless %w(text/markdown text/html).include?(status.content_type) @@ -75,8 +75,8 @@ class Formatter html.delete("\r").delete("\n") end - def reformat(html) - sanitize(html, Sanitize::Config::MASTODON_STRICT) + def reformat(html, outgoing = false) + sanitize(html, Sanitize::Config::MASTODON_STRICT.merge(outgoing: outgoing)) rescue ArgumentError '' end diff --git a/app/lib/sanitize_config.rb b/app/lib/sanitize_config.rb index 8bbcca4ce..34793ed93 100644 --- a/app/lib/sanitize_config.rb +++ b/app/lib/sanitize_config.rb @@ -60,7 +60,10 @@ class Sanitize node = env[:node] rel = (node['rel'] || '').split(' ') & ['tag'] - node['rel'] = (['nofollow', 'noopener', 'noreferrer'] + rel).join(' ') + unless env[:config][:outgoing] && TagManager.instance.local_url?(node['href']) + rel += ['nofollow', 'noopener', 'noreferrer'] + end + node['rel'] = rel.join(' ') end UNSUPPORTED_HREF_TRANSFORMER = lambda do |env| @@ -103,8 +106,8 @@ class Sanitize transformers: [ CLASS_WHITELIST_TRANSFORMER, IMG_TAG_TRANSFORMER, - LINK_REL_TRANSFORMER, UNSUPPORTED_HREF_TRANSFORMER, + LINK_REL_TRANSFORMER, ] ) diff --git a/spec/lib/sanitize_config_spec.rb b/spec/lib/sanitize_config_spec.rb index 2d82c00ea..7370c536b 100644 --- a/spec/lib/sanitize_config_spec.rb +++ b/spec/lib/sanitize_config_spec.rb @@ -7,6 +7,12 @@ describe Sanitize::Config do describe '::MASTODON_STRICT' do subject { Sanitize::Config::MASTODON_STRICT } + around do |example| + original_web_domain = Rails.configuration.x.web_domain + example.run + Rails.configuration.x.web_domain = original_web_domain + end + it 'keeps h1' do expect(Sanitize.fragment('

Foo

', subject)).to eq '

Foo

' end @@ -32,7 +38,12 @@ describe Sanitize::Config do end it 'keeps a with href and rel tag' do - expect(Sanitize.fragment('', subject)).to eq 'Test' + expect(Sanitize.fragment('', subject)).to eq 'Test' + end + + it 'keeps a with href and rel tag, not adding to rel if url is local' do + Rails.configuration.x.web_domain = 'domain.test' + expect(Sanitize.fragment('', subject.merge(outgoing: true))).to eq '' end end end -- cgit From 0c8945e5ff9e75dd322ee2b2c4ea9cc1dc728911 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 26 Mar 2020 01:56:41 +0100 Subject: Change `tootctl media remove-orphans` to work for all classes (#13316) Change `tootctl media lookup` to not use an interactive prompt --- app/lib/activitypub/tag_manager.rb | 2 + app/models/media_attachment.rb | 13 ---- lib/mastodon/media_cli.rb | 111 ++++++++++++++++++++++++--------- lib/paperclip/attachment_extensions.rb | 13 ++++ 4 files changed, 98 insertions(+), 41 deletions(-) (limited to 'app/lib') diff --git a/app/lib/activitypub/tag_manager.rb b/app/lib/activitypub/tag_manager.rb index ed680d762..1523f86d4 100644 --- a/app/lib/activitypub/tag_manager.rb +++ b/app/lib/activitypub/tag_manager.rb @@ -15,6 +15,8 @@ class ActivityPub::TagManager def url_for(target) return target.url if target.respond_to?(:local?) && !target.local? + return unless target.respond_to?(:object_type) + case target.object_type when :person target.instance_actor? ? about_more_url(instance_actor: true) : short_account_url(target) diff --git a/app/models/media_attachment.rb b/app/models/media_attachment.rb index 31aa918b7..f45e2c9f7 100644 --- a/app/models/media_attachment.rb +++ b/app/models/media_attachment.rb @@ -184,19 +184,6 @@ class MediaAttachment < ApplicationRecord audio? || video? end - def variant?(other_file_name) - return true if file_file_name == other_file_name - return false if file_file_name.nil? - - formats = file.styles.values.map(&:format).compact - - return false if formats.empty? - - extension = File.extname(other_file_name) - - formats.include?(extension.delete('.')) && File.basename(other_file_name, extension) == File.basename(file_file_name, File.extname(file_file_name)) - end - def to_param shortcode end diff --git a/lib/mastodon/media_cli.rb b/lib/mastodon/media_cli.rb index d842b986f..b4ad78fe5 100644 --- a/lib/mastodon/media_cli.rb +++ b/lib/mastodon/media_cli.rb @@ -45,6 +45,7 @@ module Mastodon end option :start_after + option :prefix option :dry_run, type: :boolean, default: false desc 'remove-orphans', 'Scan storage and check for files that do not belong to existing media attachments' long_desc <<~LONG_DESC @@ -58,6 +59,7 @@ module Mastodon reclaimed_bytes = 0 removed = 0 dry_run = options[:dry_run] ? ' (DRY RUN)' : '' + prefix = options[:prefix] case Paperclip::Attachment.default_options[:storage] when :s3 @@ -69,7 +71,7 @@ module Mastodon loop do objects = begin begin - bucket.objects(start_after: last_key, prefix: 'media_attachments/files/').limit(1000).map { |x| x } + bucket.objects(start_after: last_key, prefix: prefix).limit(1000).map { |x| x } rescue => e progress.log(pastel.red("Error fetching list of files: #{e}")) progress.log("If you want to continue from this point, add --start-after=#{last_key} to your command") if last_key @@ -79,16 +81,21 @@ module Mastodon break if objects.empty? - last_key = objects.last.key - attachments_map = MediaAttachment.where(id: objects.map { |object| object.key.split('/')[2..-2].join.to_i }).each_with_object({}) { |attachment, map| map[attachment.id] = attachment } + last_key = objects.last.key + record_map = preload_records_from_mixed_objects(objects) objects.each do |object| - attachment_id = object.key.split('/')[2..-2].join.to_i - filename = object.key.split('/').last + path_segments = object.key.split('/') + model_name = path_segments.first.classify + attachment_name = path_segments[1].singularize + record_id = path_segments[2..-2].join.to_i + file_name = path_segments.last + record = record_map.dig(model_name, record_id) + attachment = record&.public_send(attachment_name) progress.increment - next unless attachments_map[attachment_id].nil? || !attachments_map[attachment_id].variant?(filename) + next unless attachment.blank? || !attachment.variant?(file_name) begin object.delete unless options[:dry_run] @@ -110,17 +117,24 @@ module Mastodon root_path = ENV.fetch('RAILS_ROOT_PATH', File.join(':rails_root', 'public', 'system')).gsub(':rails_root', Rails.root.to_s) - Find.find(File.join(root_path, 'media_attachments', 'files')) do |path| + Find.find(File.join(*[root_path, prefix].compact)) do |path| next if File.directory?(path) - key = path.gsub("#{root_path}#{File::SEPARATOR}", '') - attachment_id = key.split(File::SEPARATOR)[2..-2].join.to_i - filename = key.split(File::SEPARATOR).last - attachment = MediaAttachment.find_by(id: attachment_id) + key = path.gsub("#{root_path}#{File::SEPARATOR}", '') + path_segments = key.split(File::SEPARATOR) + model_name = path_segments.first.classify + record_id = path_segments[2..-2].join.to_i + attachment_name = path_segments[1].singularize + file_name = path_segments.last + + next unless PRELOAD_MODEL_WHITELIST.include?(model_name) + + record = model_name.constantize.find_by(id: record_id) + attachment = record&.public_send(attachment_name) progress.increment - next unless attachment.nil? || !attachment.variant?(filename) + next unless attachment.blank? || !attachment.variant?(file_name) begin size = File.size(path) @@ -213,25 +227,66 @@ module Mastodon say("Settings:\t#{number_to_human_size(SiteUpload.sum(:file_file_size))}") end - desc 'lookup', 'Lookup where media is displayed by passing a media URL' - def lookup - prompt = TTY::Prompt.new + desc 'lookup URL', 'Lookup where media is displayed by passing a media URL' + def lookup(url) + path = Addressable::URI.parse(url).path + path_segments = path.split('/')[2..-1] + model_name = path_segments.first.classify + record_id = path_segments[2..-2].join.to_i - url = prompt.ask('Please enter a URL to the media to lookup:', required: true) + unless PRELOAD_MODEL_WHITELIST.include?(model_name) + say("Cannot find corresponding model: #{model_name}", :red) + exit(1) + end - attachment_id = url - .split('/')[0..-2] - .grep(/\A\d+\z/) - .join('') + record = model_name.constantize.find_by(id: record_id) + record = record.status if record.respond_to?(:status) - if url.split('/')[0..-2].include? 'media_attachments' - model = MediaAttachment.find(attachment_id).status - prompt.say(ActivityPub::TagManager.instance.url_for(model)) - elsif url.split('/')[0..-2].include? 'accounts' - model = Account.find(attachment_id) - prompt.say(ActivityPub::TagManager.instance.url_for(model)) - else - prompt.say('Not found') + unless record + say('Cannot find corresponding record', :red) + exit(1) + end + + display_url = ActivityPub::TagManager.instance.url_for(record) + + if display_url.blank? + say('No public URL for this type of record', :red) + exit(1) + end + + say(display_url, :blue) + rescue Addressable::URI::InvalidURIError + say('Invalid URL', :red) + exit(1) + end + + private + + PRELOAD_MODEL_WHITELIST = %w( + Account + Backup + CustomEmoji + Import + MediaAttachment + PreviewCard + SiteUpload + ).freeze + + def preload_records_from_mixed_objects(objects) + preload_map = Hash.new { |hash, key| hash[key] = [] } + + objects.map do |object| + segments = object.key.split('/').first + model_name = segments.first.classify + record_id = segments[2..-2].join.to_i + + next unless PRELOAD_MODEL_WHITELIST.include?(model_name) + + preload_map[model_name] << record_id + end + + preload_map.each_with_object({}) do |(model_name, record_ids), model_map| + model_map[model_name] = model_name.constantize.where(id: record_ids).each_with_object({}) { |record, record_map| record_map[record.id] = record } end end end diff --git a/lib/paperclip/attachment_extensions.rb b/lib/paperclip/attachment_extensions.rb index 3b308af5f..d9ec0159a 100644 --- a/lib/paperclip/attachment_extensions.rb +++ b/lib/paperclip/attachment_extensions.rb @@ -24,6 +24,19 @@ module Paperclip flush_deletes end end + + def variant?(other_filename) + return true if original_filename == other_filename + return false if original_filename.nil? + + formats = styles.values.map(&:format).compact + + return false if formats.empty? + + other_extension = File.extname(other_filename) + + formats.include?(other_extension.delete('.')) && File.basename(other_filename, other_extension) == File.basename(original_filename, File.extname(original_filename)) + end end end -- cgit From 89e28c76744dc888e7c5f85aef305452681fd6be Mon Sep 17 00:00:00 2001 From: ThibG Date: Sun, 5 Apr 2020 12:51:22 +0200 Subject: Fix PostgreSQL load when linking in announcements (#13250) * Fix PostgreSQL load when linking in announcements Fixes #13245 by caching status lookups Since statuses are supposed to be known already and we only need their URLs and a few other things, caching them should be fine. Since it's only used by announcements so far, there won't be much statuses to cache. * Perform status lookup when saving announcements, not when rendering them * Change EntityCache#status to fetch URLs instead of looking into the database * Move announcement link lookup to publishing worker * Address issues pointed out during review --- app/lib/entity_cache.rb | 4 ++++ app/models/announcement.rb | 9 ++++++++- app/models/status.rb | 2 +- app/workers/publish_scheduled_announcement_worker.rb | 15 ++++++++++++--- .../20200312162302_add_status_ids_to_announcements.rb | 6 ++++++ db/schema.rb | 1 + 6 files changed, 32 insertions(+), 5 deletions(-) create mode 100644 db/migrate/20200312162302_add_status_ids_to_announcements.rb (limited to 'app/lib') diff --git a/app/lib/entity_cache.rb b/app/lib/entity_cache.rb index 35a3773d2..afdbd70f2 100644 --- a/app/lib/entity_cache.rb +++ b/app/lib/entity_cache.rb @@ -7,6 +7,10 @@ class EntityCache MAX_EXPIRATION = 7.days.freeze + def status(url) + Rails.cache.fetch(to_key(:status, url), expires_in: MAX_EXPIRATION) { FetchRemoteStatusService.new.call(url) } + end + def mention(username, domain) Rails.cache.fetch(to_key(:mention, username, domain), expires_in: MAX_EXPIRATION) { Account.select(:id, :username, :domain, :url).find_remote(username, domain) } end diff --git a/app/models/announcement.rb b/app/models/announcement.rb index f8ac4e09d..a4e427b49 100644 --- a/app/models/announcement.rb +++ b/app/models/announcement.rb @@ -14,6 +14,7 @@ # created_at :datetime not null # updated_at :datetime not null # published_at :datetime +# status_ids :bigint is an Array # class Announcement < ApplicationRecord @@ -49,7 +50,13 @@ class Announcement < ApplicationRecord end def statuses - @statuses ||= Status.from_text(text) + @statuses ||= begin + if status_ids.nil? + [] + else + Status.where(id: status_ids, visibility: [:public, :unlisted]) + end + end end def tags diff --git a/app/models/status.rb b/app/models/status.rb index ff653100a..fef4e2596 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -379,7 +379,7 @@ class Status < ApplicationRecord if TagManager.instance.local_url?(url) ActivityPub::TagManager.instance.uri_to_resource(url, Status) else - Status.find_by(uri: url) || Status.find_by(url: url) + EntityCache.instance.status(url) end end status&.distributable? ? status : nil diff --git a/app/workers/publish_scheduled_announcement_worker.rb b/app/workers/publish_scheduled_announcement_worker.rb index efca39d3d..1392efed0 100644 --- a/app/workers/publish_scheduled_announcement_worker.rb +++ b/app/workers/publish_scheduled_announcement_worker.rb @@ -5,15 +5,24 @@ class PublishScheduledAnnouncementWorker include Redisable def perform(announcement_id) - announcement = Announcement.find(announcement_id) + @announcement = Announcement.find(announcement_id) - announcement.publish! unless announcement.published? + refresh_status_ids! - payload = InlineRenderer.render(announcement, nil, :announcement) + @announcement.publish! unless @announcement.published? + + payload = InlineRenderer.render(@announcement, nil, :announcement) payload = Oj.dump(event: :announcement, payload: payload) FeedManager.instance.with_active_accounts do |account| redis.publish("timeline:#{account.id}", payload) if redis.exists("subscribed:timeline:#{account.id}") end end + + private + + def refresh_status_ids! + @announcement.status_ids = Status.from_text(@announcement.text).map(&:id) + @announcement.save + end end diff --git a/db/migrate/20200312162302_add_status_ids_to_announcements.rb b/db/migrate/20200312162302_add_status_ids_to_announcements.rb new file mode 100644 index 000000000..42aa6513d --- /dev/null +++ b/db/migrate/20200312162302_add_status_ids_to_announcements.rb @@ -0,0 +1,6 @@ +class AddStatusIdsToAnnouncements < ActiveRecord::Migration[5.2] + def change + add_column :announcements, :status_ids, :bigint, array: true + end +end + diff --git a/db/schema.rb b/db/schema.rb index 7f28f2ec4..021ddac89 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -231,6 +231,7 @@ ActiveRecord::Schema.define(version: 2020_03_12_185443) do t.datetime "created_at", null: false t.datetime "updated_at", null: false t.datetime "published_at" + t.bigint "status_ids", array: true end create_table "backups", force: :cascade do |t| -- cgit From c9efb400b429696d1ee5464931f7f62e38edf1d6 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sun, 5 Apr 2020 14:40:08 +0200 Subject: Add rate limit for reporting (#13390) --- app/controllers/api/v1/reports_controller.rb | 2 ++ app/lib/rate_limiter.rb | 6 +++--- app/models/report.rb | 3 +++ 3 files changed, 8 insertions(+), 3 deletions(-) (limited to 'app/lib') diff --git a/app/controllers/api/v1/reports_controller.rb b/app/controllers/api/v1/reports_controller.rb index 66c40f6f4..e10083d45 100644 --- a/app/controllers/api/v1/reports_controller.rb +++ b/app/controllers/api/v1/reports_controller.rb @@ -4,6 +4,8 @@ class Api::V1::ReportsController < Api::BaseController before_action -> { doorkeeper_authorize! :write, :'write:reports' }, only: [:create] before_action :require_user! + override_rate_limit_headers :create, family: :reports + def create @report = ReportService.new.call( current_account, diff --git a/app/lib/rate_limiter.rb b/app/lib/rate_limiter.rb index 68dae9add..0e2c9a894 100644 --- a/app/lib/rate_limiter.rb +++ b/app/lib/rate_limiter.rb @@ -14,9 +14,9 @@ class RateLimiter period: 3.hours.freeze, }.freeze, - media: { - limit: 30, - period: 30.minutes.freeze, + reports: { + limit: 400, + period: 24.hours.freeze, }.freeze, }.freeze diff --git a/app/models/report.rb b/app/models/report.rb index 356c23d68..f31bcfd2e 100644 --- a/app/models/report.rb +++ b/app/models/report.rb @@ -18,6 +18,9 @@ class Report < ApplicationRecord include Paginable + include RateLimitable + + rate_limit by: :account, family: :reports belongs_to :account belongs_to :target_account, class_name: 'Account' -- cgit