Merge branch 'master' into glitch-soc/merge-upstream
Conflicts: - app/controllers/directories_controller.rb - package.json - yarn.lock
This commit is contained in:
		
						commit
						4973ba2d1f
					
				
					 59 changed files with 779 additions and 221 deletions
				
			
		
							
								
								
									
										8
									
								
								Gemfile
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								Gemfile
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -15,7 +15,7 @@ gem 'makara', '~> 0.4'
 | 
			
		|||
gem 'pghero', '~> 2.2'
 | 
			
		||||
gem 'dotenv-rails', '~> 2.7'
 | 
			
		||||
 | 
			
		||||
gem 'aws-sdk-s3', '~> 1.45', require: false
 | 
			
		||||
gem 'aws-sdk-s3', '~> 1.46', require: false
 | 
			
		||||
gem 'fog-core', '<= 2.1.0'
 | 
			
		||||
gem 'fog-openstack', '~> 0.3', require: false
 | 
			
		||||
gem 'paperclip', '~> 6.0'
 | 
			
		||||
| 
						 | 
				
			
			@ -53,7 +53,7 @@ gem 'html2text'
 | 
			
		|||
gem 'htmlentities', '~> 4.3'
 | 
			
		||||
gem 'http', '~> 3.3'
 | 
			
		||||
gem 'http_accept_language', '~> 2.1'
 | 
			
		||||
gem 'http_parser.rb', '~> 0.6', git: 'https://github.com/tmm1/http_parser.rb', ref: '54b17ba8c7d8d20a16dfc65d1775241833219cf2'
 | 
			
		||||
gem 'http_parser.rb', '~> 0.6', git: 'https://github.com/tmm1/http_parser.rb', ref: '54b17ba8c7d8d20a16dfc65d1775241833219cf2', submodules: true
 | 
			
		||||
gem 'httplog', '~> 1.3'
 | 
			
		||||
gem 'idn-ruby', require: 'idn'
 | 
			
		||||
gem 'kaminari', '~> 1.1'
 | 
			
		||||
| 
						 | 
				
			
			@ -113,7 +113,7 @@ group :production, :test do
 | 
			
		|||
end
 | 
			
		||||
 | 
			
		||||
group :test do
 | 
			
		||||
  gem 'capybara', '~> 3.26'
 | 
			
		||||
  gem 'capybara', '~> 3.27'
 | 
			
		||||
  gem 'climate_control', '~> 0.2'
 | 
			
		||||
  gem 'faker', '~> 1.9'
 | 
			
		||||
  gem 'microformats', '~> 4.1'
 | 
			
		||||
| 
						 | 
				
			
			@ -135,7 +135,7 @@ group :development do
 | 
			
		|||
  gem 'memory_profiler'
 | 
			
		||||
  gem 'rubocop', '~> 0.73', require: false
 | 
			
		||||
  gem 'rubocop-rails', '~> 2.2', require: false
 | 
			
		||||
  gem 'brakeman', '~> 4.5', require: false
 | 
			
		||||
  gem 'brakeman', '~> 4.6', require: false
 | 
			
		||||
  gem 'bundler-audit', '~> 0.6', require: false
 | 
			
		||||
 | 
			
		||||
  gem 'capistrano', '~> 3.11'
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										27
									
								
								Gemfile.lock
									
									
									
									
									
								
							
							
						
						
									
										27
									
								
								Gemfile.lock
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -22,6 +22,7 @@ GIT
 | 
			
		|||
  remote: https://github.com/tmm1/http_parser.rb
 | 
			
		||||
  revision: 54b17ba8c7d8d20a16dfc65d1775241833219cf2
 | 
			
		||||
  ref: 54b17ba8c7d8d20a16dfc65d1775241833219cf2
 | 
			
		||||
  submodules: true
 | 
			
		||||
  specs:
 | 
			
		||||
    http_parser.rb (0.6.1)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -96,17 +97,17 @@ GEM
 | 
			
		|||
    av (0.9.0)
 | 
			
		||||
      cocaine (~> 0.5.3)
 | 
			
		||||
    aws-eventstream (1.0.3)
 | 
			
		||||
    aws-partitions (1.184.0)
 | 
			
		||||
    aws-sdk-core (3.59.0)
 | 
			
		||||
    aws-partitions (1.193.0)
 | 
			
		||||
    aws-sdk-core (3.61.1)
 | 
			
		||||
      aws-eventstream (~> 1.0, >= 1.0.2)
 | 
			
		||||
      aws-partitions (~> 1.0)
 | 
			
		||||
      aws-sigv4 (~> 1.1)
 | 
			
		||||
      jmespath (~> 1.0)
 | 
			
		||||
    aws-sdk-kms (1.23.0)
 | 
			
		||||
      aws-sdk-core (~> 3, >= 3.58.0)
 | 
			
		||||
    aws-sdk-kms (1.24.0)
 | 
			
		||||
      aws-sdk-core (~> 3, >= 3.61.1)
 | 
			
		||||
      aws-sigv4 (~> 1.1)
 | 
			
		||||
    aws-sdk-s3 (1.45.0)
 | 
			
		||||
      aws-sdk-core (~> 3, >= 3.58.0)
 | 
			
		||||
    aws-sdk-s3 (1.46.0)
 | 
			
		||||
      aws-sdk-core (~> 3, >= 3.61.1)
 | 
			
		||||
      aws-sdk-kms (~> 1)
 | 
			
		||||
      aws-sigv4 (~> 1.1)
 | 
			
		||||
    aws-sigv4 (1.1.0)
 | 
			
		||||
| 
						 | 
				
			
			@ -123,7 +124,7 @@ GEM
 | 
			
		|||
      ffi (~> 1.10.0)
 | 
			
		||||
    bootsnap (1.4.4)
 | 
			
		||||
      msgpack (~> 1.0)
 | 
			
		||||
    brakeman (4.5.1)
 | 
			
		||||
    brakeman (4.6.1)
 | 
			
		||||
    browser (2.6.1)
 | 
			
		||||
    builder (3.2.3)
 | 
			
		||||
    bullet (6.0.1)
 | 
			
		||||
| 
						 | 
				
			
			@ -149,7 +150,7 @@ GEM
 | 
			
		|||
      sshkit (~> 1.3)
 | 
			
		||||
    capistrano-yarn (2.0.2)
 | 
			
		||||
      capistrano (~> 3.0)
 | 
			
		||||
    capybara (3.26.0)
 | 
			
		||||
    capybara (3.27.0)
 | 
			
		||||
      addressable
 | 
			
		||||
      mini_mime (>= 0.1.3)
 | 
			
		||||
      nokogiri (~> 1.8)
 | 
			
		||||
| 
						 | 
				
			
			@ -291,7 +292,7 @@ GEM
 | 
			
		|||
      domain_name (~> 0.5)
 | 
			
		||||
    http-form_data (2.1.1)
 | 
			
		||||
    http_accept_language (2.1.1)
 | 
			
		||||
    httplog (1.3.1)
 | 
			
		||||
    httplog (1.3.2)
 | 
			
		||||
      rack (>= 1.0)
 | 
			
		||||
      rainbow (>= 2.0.0)
 | 
			
		||||
    i18n (1.6.0)
 | 
			
		||||
| 
						 | 
				
			
			@ -386,7 +387,7 @@ GEM
 | 
			
		|||
      concurrent-ruby (~> 1.0, >= 1.0.2)
 | 
			
		||||
      sidekiq (>= 3.5)
 | 
			
		||||
      statsd-ruby (~> 1.4, >= 1.4.0)
 | 
			
		||||
    oj (3.8.0)
 | 
			
		||||
    oj (3.8.1)
 | 
			
		||||
    omniauth (1.9.0)
 | 
			
		||||
      hashie (>= 3.4.6, < 3.7.0)
 | 
			
		||||
      rack (>= 1.6.2, < 3)
 | 
			
		||||
| 
						 | 
				
			
			@ -670,12 +671,12 @@ DEPENDENCIES
 | 
			
		|||
  active_record_query_trace (~> 1.6)
 | 
			
		||||
  addressable (~> 2.6)
 | 
			
		||||
  annotate (~> 2.7)
 | 
			
		||||
  aws-sdk-s3 (~> 1.45)
 | 
			
		||||
  aws-sdk-s3 (~> 1.46)
 | 
			
		||||
  better_errors (~> 2.5)
 | 
			
		||||
  binding_of_caller (~> 0.7)
 | 
			
		||||
  blurhash (~> 0.1)
 | 
			
		||||
  bootsnap (~> 1.4)
 | 
			
		||||
  brakeman (~> 4.5)
 | 
			
		||||
  brakeman (~> 4.6)
 | 
			
		||||
  browser
 | 
			
		||||
  bullet (~> 6.0)
 | 
			
		||||
  bundler-audit (~> 0.6)
 | 
			
		||||
| 
						 | 
				
			
			@ -683,7 +684,7 @@ DEPENDENCIES
 | 
			
		|||
  capistrano-rails (~> 1.4)
 | 
			
		||||
  capistrano-rbenv (~> 2.1)
 | 
			
		||||
  capistrano-yarn (~> 2.0)
 | 
			
		||||
  capybara (~> 3.26)
 | 
			
		||||
  capybara (~> 3.27)
 | 
			
		||||
  charlock_holmes (~> 0.7.6)
 | 
			
		||||
  chewy (~> 5.0)
 | 
			
		||||
  cld3 (~> 3.2.4)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,6 +4,7 @@ class AboutController < ApplicationController
 | 
			
		|||
  before_action :set_pack
 | 
			
		||||
  layout 'public'
 | 
			
		||||
 | 
			
		||||
  before_action :require_open_federation!, only: [:show, :more]
 | 
			
		||||
  before_action :set_body_classes, only: :show
 | 
			
		||||
  before_action :set_instance_presenter
 | 
			
		||||
  before_action :set_expires_in
 | 
			
		||||
| 
						 | 
				
			
			@ -20,6 +21,10 @@ class AboutController < ApplicationController
 | 
			
		|||
 | 
			
		||||
  private
 | 
			
		||||
 | 
			
		||||
  def require_open_federation!
 | 
			
		||||
    not_found if whitelist_mode?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def new_user
 | 
			
		||||
    User.new.tap do |user|
 | 
			
		||||
      user.build_account
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,8 @@
 | 
			
		|||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class ActivityPub::BaseController < Api::BaseController
 | 
			
		||||
  skip_before_action :require_authenticated_user!
 | 
			
		||||
 | 
			
		||||
  private
 | 
			
		||||
 | 
			
		||||
  def set_cache_headers
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class ActivityPub::InboxesController < Api::BaseController
 | 
			
		||||
class ActivityPub::InboxesController < ActivityPub::BaseController
 | 
			
		||||
  include SignatureVerification
 | 
			
		||||
  include JsonLdHelper
 | 
			
		||||
  include AccountOwnedConcern
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										40
									
								
								app/controllers/admin/domain_allows_controller.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								app/controllers/admin/domain_allows_controller.rb
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,40 @@
 | 
			
		|||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class Admin::DomainAllowsController < Admin::BaseController
 | 
			
		||||
  before_action :set_domain_allow, only: [:destroy]
 | 
			
		||||
 | 
			
		||||
  def new
 | 
			
		||||
    authorize :domain_allow, :create?
 | 
			
		||||
 | 
			
		||||
    @domain_allow = DomainAllow.new(domain: params[:_domain])
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def create
 | 
			
		||||
    authorize :domain_allow, :create?
 | 
			
		||||
 | 
			
		||||
    @domain_allow = DomainAllow.new(resource_params)
 | 
			
		||||
 | 
			
		||||
    if @domain_allow.save
 | 
			
		||||
      log_action :create, @domain_allow
 | 
			
		||||
      redirect_to admin_instances_path, notice: I18n.t('admin.domain_allows.created_msg')
 | 
			
		||||
    else
 | 
			
		||||
      render :new
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def destroy
 | 
			
		||||
    authorize @domain_allow, :destroy?
 | 
			
		||||
    UnallowDomainService.new.call(@domain_allow)
 | 
			
		||||
    redirect_to admin_instances_path, notice: I18n.t('admin.domain_allows.destroyed_msg')
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  private
 | 
			
		||||
 | 
			
		||||
  def set_domain_allow
 | 
			
		||||
    @domain_allow = DomainAllow.find(params[:id])
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def resource_params
 | 
			
		||||
    params.require(:domain_allow).permit(:domain)
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -2,6 +2,10 @@
 | 
			
		|||
 | 
			
		||||
module Admin
 | 
			
		||||
  class InstancesController < BaseController
 | 
			
		||||
    before_action :set_domain_block, only: :show
 | 
			
		||||
    before_action :set_domain_allow, only: :show
 | 
			
		||||
    before_action :set_instance, only: :show
 | 
			
		||||
 | 
			
		||||
    def index
 | 
			
		||||
      authorize :instance, :index?
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -11,20 +15,38 @@ module Admin
 | 
			
		|||
    def show
 | 
			
		||||
      authorize :instance, :show?
 | 
			
		||||
 | 
			
		||||
      @instance        = Instance.new(Account.by_domain_accounts.find_by(domain: params[:id]) || DomainBlock.find_by!(domain: params[:id]))
 | 
			
		||||
      @following_count = Follow.where(account: Account.where(domain: params[:id])).count
 | 
			
		||||
      @followers_count = Follow.where(target_account: Account.where(domain: params[:id])).count
 | 
			
		||||
      @reports_count   = Report.where(target_account: Account.where(domain: params[:id])).count
 | 
			
		||||
      @blocks_count    = Block.where(target_account: Account.where(domain: params[:id])).count
 | 
			
		||||
      @available       = DeliveryFailureTracker.available?(Account.select(:shared_inbox_url).where(domain: params[:id]).first&.shared_inbox_url)
 | 
			
		||||
      @media_storage   = MediaAttachment.where(account: Account.where(domain: params[:id])).sum(:file_file_size)
 | 
			
		||||
      @domain_block    = DomainBlock.rule_for(params[:id])
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    private
 | 
			
		||||
 | 
			
		||||
    def set_domain_block
 | 
			
		||||
      @domain_block = DomainBlock.rule_for(params[:id])
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def set_domain_allow
 | 
			
		||||
      @domain_allow = DomainAllow.rule_for(params[:id])
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def set_instance
 | 
			
		||||
      resource   = Account.by_domain_accounts.find_by(domain: params[:id])
 | 
			
		||||
      resource ||= @domain_block
 | 
			
		||||
      resource ||= @domain_allow
 | 
			
		||||
 | 
			
		||||
      if resource
 | 
			
		||||
        @instance = Instance.new(resource)
 | 
			
		||||
      else
 | 
			
		||||
        not_found
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def filtered_instances
 | 
			
		||||
      InstanceFilter.new(filter_params).results
 | 
			
		||||
      InstanceFilter.new(whitelist_mode? ? { allowed: true } : filter_params).results
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def paginated_instances
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,6 +9,7 @@ class Api::BaseController < ApplicationController
 | 
			
		|||
  skip_before_action :store_current_location
 | 
			
		||||
  skip_before_action :require_functional!
 | 
			
		||||
 | 
			
		||||
  before_action :require_authenticated_user!, if: :disallow_unauthenticated_api_access?
 | 
			
		||||
  before_action :set_cache_headers
 | 
			
		||||
 | 
			
		||||
  protect_from_forgery with: :null_session
 | 
			
		||||
| 
						 | 
				
			
			@ -69,6 +70,10 @@ class Api::BaseController < ApplicationController
 | 
			
		|||
    nil
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def require_authenticated_user!
 | 
			
		||||
    render json: { error: 'This API requires an authenticated user' }, status: 401 unless current_user
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def require_user!
 | 
			
		||||
    if !current_user
 | 
			
		||||
      render json: { error: 'This method requires an authenticated user' }, status: 422
 | 
			
		||||
| 
						 | 
				
			
			@ -94,4 +99,8 @@ class Api::BaseController < ApplicationController
 | 
			
		|||
  def set_cache_headers
 | 
			
		||||
    response.headers['Cache-Control'] = 'no-cache, no-store, max-age=0, must-revalidate'
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def disallow_unauthenticated_api_access?
 | 
			
		||||
    authorized_fetch_mode?
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,6 +12,8 @@ class Api::V1::AccountsController < Api::BaseController
 | 
			
		|||
  before_action :check_account_suspension, only: [:show]
 | 
			
		||||
  before_action :check_enabled_registrations, only: [:create]
 | 
			
		||||
 | 
			
		||||
  skip_before_action :require_authenticated_user!, only: :create
 | 
			
		||||
 | 
			
		||||
  respond_to :json
 | 
			
		||||
 | 
			
		||||
  def show
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,8 @@
 | 
			
		|||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class Api::V1::AppsController < Api::BaseController
 | 
			
		||||
  skip_before_action :require_authenticated_user!
 | 
			
		||||
 | 
			
		||||
  def create
 | 
			
		||||
    @app = Doorkeeper::Application.create!(application_options)
 | 
			
		||||
    render json: @app, serializer: REST::ApplicationSerializer
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,6 +2,7 @@
 | 
			
		|||
 | 
			
		||||
class Api::V1::Instances::ActivityController < Api::BaseController
 | 
			
		||||
  before_action :require_enabled_api!
 | 
			
		||||
 | 
			
		||||
  skip_before_action :set_cache_headers
 | 
			
		||||
 | 
			
		||||
  respond_to :json
 | 
			
		||||
| 
						 | 
				
			
			@ -33,6 +34,6 @@ class Api::V1::Instances::ActivityController < Api::BaseController
 | 
			
		|||
  end
 | 
			
		||||
 | 
			
		||||
  def require_enabled_api!
 | 
			
		||||
    head 404 unless Setting.activity_api_enabled
 | 
			
		||||
    head 404 unless Setting.activity_api_enabled && !whitelist_mode?
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,6 +2,7 @@
 | 
			
		|||
 | 
			
		||||
class Api::V1::Instances::PeersController < Api::BaseController
 | 
			
		||||
  before_action :require_enabled_api!
 | 
			
		||||
 | 
			
		||||
  skip_before_action :set_cache_headers
 | 
			
		||||
 | 
			
		||||
  respond_to :json
 | 
			
		||||
| 
						 | 
				
			
			@ -14,6 +15,6 @@ class Api::V1::Instances::PeersController < Api::BaseController
 | 
			
		|||
  private
 | 
			
		||||
 | 
			
		||||
  def require_enabled_api!
 | 
			
		||||
    head 404 unless Setting.peers_api_enabled
 | 
			
		||||
    head 404 unless Setting.peers_api_enabled && !whitelist_mode?
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,6 +2,7 @@
 | 
			
		|||
 | 
			
		||||
class Api::V1::InstancesController < Api::BaseController
 | 
			
		||||
  respond_to :json
 | 
			
		||||
 | 
			
		||||
  skip_before_action :set_cache_headers
 | 
			
		||||
 | 
			
		||||
  def show
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,6 +11,7 @@ class ApplicationController < ActionController::Base
 | 
			
		|||
  include UserTrackingConcern
 | 
			
		||||
  include SessionTrackingConcern
 | 
			
		||||
  include CacheConcern
 | 
			
		||||
  include DomainControlHelper
 | 
			
		||||
 | 
			
		||||
  helper_method :current_account
 | 
			
		||||
  helper_method :current_session
 | 
			
		||||
| 
						 | 
				
			
			@ -18,6 +19,7 @@ class ApplicationController < ActionController::Base
 | 
			
		|||
  helper_method :current_skin
 | 
			
		||||
  helper_method :single_user_mode?
 | 
			
		||||
  helper_method :use_seamless_external_login?
 | 
			
		||||
  helper_method :whitelist_mode?
 | 
			
		||||
 | 
			
		||||
  rescue_from ActionController::RoutingError, with: :not_found
 | 
			
		||||
  rescue_from ActiveRecord::RecordNotFound, with: :not_found
 | 
			
		||||
| 
						 | 
				
			
			@ -39,7 +41,7 @@ class ApplicationController < ActionController::Base
 | 
			
		|||
  end
 | 
			
		||||
 | 
			
		||||
  def authorized_fetch_mode?
 | 
			
		||||
    ENV['AUTHORIZED_FETCH'] == 'true'
 | 
			
		||||
    ENV['AUTHORIZED_FETCH'] == 'true' || Rails.configuration.x.whitelist_mode
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def public_fetch_mode?
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,6 +4,7 @@ module AccountOwnedConcern
 | 
			
		|||
  extend ActiveSupport::Concern
 | 
			
		||||
 | 
			
		||||
  included do
 | 
			
		||||
    before_action :authenticate_user!, if: -> { whitelist_mode? && request.format != :json }
 | 
			
		||||
    before_action :set_account, if: :account_required?
 | 
			
		||||
    before_action :check_account_approval, if: :account_required?
 | 
			
		||||
    before_action :check_account_suspension, if: :account_required?
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,8 @@
 | 
			
		|||
class DirectoriesController < ApplicationController
 | 
			
		||||
  layout 'public'
 | 
			
		||||
 | 
			
		||||
  before_action :check_enabled
 | 
			
		||||
  before_action :authenticate_user!, if: :whitelist_mode?
 | 
			
		||||
  before_action :require_enabled!
 | 
			
		||||
  before_action :set_instance_presenter
 | 
			
		||||
  before_action :set_tag, only: :show
 | 
			
		||||
  before_action :set_tags
 | 
			
		||||
| 
						 | 
				
			
			@ -24,7 +25,7 @@ class DirectoriesController < ApplicationController
 | 
			
		|||
    use_pack 'share'
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def check_enabled
 | 
			
		||||
  def require_enabled!
 | 
			
		||||
    return not_found unless Setting.profile_directory
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -61,7 +61,7 @@ class HomeController < ApplicationController
 | 
			
		|||
  end
 | 
			
		||||
 | 
			
		||||
  def default_redirect_path
 | 
			
		||||
    if request.path.start_with?('/web')
 | 
			
		||||
    if request.path.start_with?('/web') || whitelist_mode?
 | 
			
		||||
      new_user_session_path
 | 
			
		||||
    elsif single_user_mode?
 | 
			
		||||
      short_account_path(Account.local.without_suspended.where('id > 0').first)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,6 +5,7 @@ class MediaController < ApplicationController
 | 
			
		|||
 | 
			
		||||
  skip_before_action :store_current_location
 | 
			
		||||
 | 
			
		||||
  before_action :authenticate_user!, if: :whitelist_mode?
 | 
			
		||||
  before_action :set_media_attachment
 | 
			
		||||
  before_action :verify_permitted_status!
 | 
			
		||||
  before_action :check_playable, only: :player
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,6 +5,8 @@ class MediaProxyController < ApplicationController
 | 
			
		|||
 | 
			
		||||
  skip_before_action :store_current_location
 | 
			
		||||
 | 
			
		||||
  before_action :authenticate_user!, if: :whitelist_mode?
 | 
			
		||||
 | 
			
		||||
  def show
 | 
			
		||||
    RedisLock.acquire(lock_options) do |lock|
 | 
			
		||||
      if lock.acquired?
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,7 +4,8 @@ class PublicTimelinesController < ApplicationController
 | 
			
		|||
  before_action :set_pack
 | 
			
		||||
  layout 'public'
 | 
			
		||||
 | 
			
		||||
  before_action :check_enabled
 | 
			
		||||
  before_action :authenticate_user!, if: :whitelist_mode?
 | 
			
		||||
  before_action :require_enabled!
 | 
			
		||||
  before_action :set_body_classes
 | 
			
		||||
  before_action :set_instance_presenter
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -17,7 +18,7 @@ class PublicTimelinesController < ApplicationController
 | 
			
		|||
 | 
			
		||||
  private
 | 
			
		||||
 | 
			
		||||
  def check_enabled
 | 
			
		||||
  def require_enabled!
 | 
			
		||||
    not_found unless Setting.timeline_preview
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,6 +5,7 @@ class RemoteInteractionController < ApplicationController
 | 
			
		|||
 | 
			
		||||
  layout 'modal'
 | 
			
		||||
 | 
			
		||||
  before_action :authenticate_user!, if: :whitelist_mode?
 | 
			
		||||
  before_action :set_interaction_type
 | 
			
		||||
  before_action :set_status
 | 
			
		||||
  before_action :set_body_classes
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,6 +8,7 @@ class TagsController < ApplicationController
 | 
			
		|||
  layout 'public'
 | 
			
		||||
 | 
			
		||||
  before_action :require_signature!, if: -> { request.format == :json && authorized_fetch_mode? }
 | 
			
		||||
  before_action :authenticate_user!, if: :whitelist_mode?
 | 
			
		||||
  before_action :set_tag
 | 
			
		||||
  before_action :set_body_classes
 | 
			
		||||
  before_action :set_instance_presenter
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,6 +12,14 @@ module DomainControlHelper
 | 
			
		|||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    DomainBlock.blocked?(domain)
 | 
			
		||||
    if whitelist_mode?
 | 
			
		||||
      !DomainAllow.allowed?(domain)
 | 
			
		||||
    else
 | 
			
		||||
      DomainBlock.blocked?(domain)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def whitelist_mode?
 | 
			
		||||
    Rails.configuration.x.whitelist_mode
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -418,16 +418,16 @@ export function selectComposeSuggestion(position, token, suggestion, path) {
 | 
			
		|||
  return (dispatch, getState) => {
 | 
			
		||||
    let completion, startPosition;
 | 
			
		||||
 | 
			
		||||
    if (typeof suggestion === 'object' && suggestion.id) {
 | 
			
		||||
    if (suggestion.type === 'emoji') {
 | 
			
		||||
      completion    = suggestion.native || suggestion.colons;
 | 
			
		||||
      startPosition = position - 1;
 | 
			
		||||
 | 
			
		||||
      dispatch(useEmoji(suggestion));
 | 
			
		||||
    } else if (typeof suggestion === 'object' && suggestion.name) {
 | 
			
		||||
    } else if (suggestion.type === 'hashtag') {
 | 
			
		||||
      completion    = `#${suggestion.name}`;
 | 
			
		||||
      startPosition = position - 1;
 | 
			
		||||
    } else {
 | 
			
		||||
      completion    = getState().getIn(['accounts', suggestion, 'acct']);
 | 
			
		||||
    } else if (suggestion.type === 'account') {
 | 
			
		||||
      completion    = getState().getIn(['accounts', suggestion.id, 'acct']);
 | 
			
		||||
      startPosition = position;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -168,15 +168,15 @@ export default class AutosuggestInput extends ImmutablePureComponent {
 | 
			
		|||
    const { selectedSuggestion } = this.state;
 | 
			
		||||
    let inner, key;
 | 
			
		||||
 | 
			
		||||
    if (typeof suggestion === 'object' && suggestion.shortcode) {
 | 
			
		||||
    if (suggestion.type === 'emoji') {
 | 
			
		||||
      inner = <AutosuggestEmoji emoji={suggestion} />;
 | 
			
		||||
      key   = suggestion.id;
 | 
			
		||||
    } else if (typeof suggestion === 'object' && suggestion.name) {
 | 
			
		||||
    } else if (suggestion.type ==='hashtag') {
 | 
			
		||||
      inner = <AutosuggestHashtag tag={suggestion} />;
 | 
			
		||||
      key   = suggestion.name;
 | 
			
		||||
    } else {
 | 
			
		||||
      inner = <AutosuggestAccountContainer id={suggestion} />;
 | 
			
		||||
      key   = suggestion;
 | 
			
		||||
    } else if (suggestion.type === 'account') {
 | 
			
		||||
      inner = <AutosuggestAccountContainer id={suggestion.id} />;
 | 
			
		||||
      key   = suggestion.id;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -174,15 +174,15 @@ export default class AutosuggestTextarea extends ImmutablePureComponent {
 | 
			
		|||
    const { selectedSuggestion } = this.state;
 | 
			
		||||
    let inner, key;
 | 
			
		||||
 | 
			
		||||
    if (typeof suggestion === 'object' && suggestion.shortcode) {
 | 
			
		||||
    if (suggestion.type === 'emoji') {
 | 
			
		||||
      inner = <AutosuggestEmoji emoji={suggestion} />;
 | 
			
		||||
      key   = suggestion.id;
 | 
			
		||||
    } else if (typeof suggestion === 'object' && suggestion.name) {
 | 
			
		||||
    } else if (suggestion.type === 'hashtag') {
 | 
			
		||||
      inner = <AutosuggestHashtag tag={suggestion} />;
 | 
			
		||||
      key   = suggestion.name;
 | 
			
		||||
    } else {
 | 
			
		||||
      inner = <AutosuggestAccountContainer id={suggestion} />;
 | 
			
		||||
      key   = suggestion;
 | 
			
		||||
    } else if (suggestion.type === 'account') {
 | 
			
		||||
      inner = <AutosuggestAccountContainer id={suggestion.id} />;
 | 
			
		||||
      key   = suggestion.id;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,9 +8,71 @@ import classnames from 'classnames';
 | 
			
		|||
import PollContainer from 'mastodon/containers/poll_container';
 | 
			
		||||
import Icon from 'mastodon/components/icon';
 | 
			
		||||
import { autoPlayGif } from 'mastodon/initial_state';
 | 
			
		||||
import { decode as decodeIDNA } from 'mastodon/utils/idna';
 | 
			
		||||
 | 
			
		||||
const MAX_HEIGHT = 642; // 20px * 32 (+ 2px padding at the top)
 | 
			
		||||
 | 
			
		||||
// Regex matching what "looks like a link", that is, something that starts with
 | 
			
		||||
// an optional "http://" or "https://" scheme and then what could look like a
 | 
			
		||||
// domain main, that is, at least two sequences of characters not including spaces
 | 
			
		||||
// and separated by "." or an homoglyph. The idea is not to match valid URLs or
 | 
			
		||||
// domain names, but what could be confused for a valid URL or domain name,
 | 
			
		||||
// especially to the untrained eye.
 | 
			
		||||
 | 
			
		||||
const h_confusables = 'h\u13c2\u1d58d\u1d4f1\u1d691\u0068\uff48\u1d525\u210e\u1d489\u1d629\u0570\u1d4bd\u1d65d\u1d421\u1d5c1\u1d5f5\u04bb\u1d559';
 | 
			
		||||
const t_confusables = 't\u1d42d\u1d5cd\u1d531\u1d565\u1d4c9\u1d669\u1d4fd\u1d69d\u0074\u1d461\u1d601\u1d495\u1d635\u1d599';
 | 
			
		||||
const p_confusables = 'p\u0440\u03c1\u1d52d\u1d631\u1d665\u1d429\uff50\u1d6e0\u1d45d\u1d561\u1d595\u1d71a\u1d699\u1d78e\u2ca3\u1d754\u1d6d2\u1d491\u1d7c8\u1d746\u1d4c5\u1d70c\u1d5c9\u0070\u1d780\u03f1\u1d5fd\u2374\u1d7ba\u1d4f9';
 | 
			
		||||
const s_confusables = 's\u1d530\u118c1\u1d494\u1d634\u1d4c8\u1d668\uabaa\u1d42c\u1d5cc\u1d460\u1d600\ua731\u0073\uff53\u1d564\u0455\u1d598\u1d4fc\u1d69c\u10448\u01bd';
 | 
			
		||||
const column_confusables = ':\u0903\u0a83\u0703\u1803\u05c3\u0704\u0589\u1809\ua789\u16ec\ufe30\u02d0\u2236\u02f8\u003a\uff1a\u205a\ua4fd';
 | 
			
		||||
const slash_confusables = '/\u2041\u2f03\u2044\u2cc6\u27cb\u30ce\u002f\u2571\u31d3\u3033\u1735\u2215\u29f8\u1d23a\u4e3f';
 | 
			
		||||
const dot_confusables = '.\u002e\u0660\u06f0\u0701\u0702\u2024\ua4f8\ua60e\u10a50\u1d16d';
 | 
			
		||||
 | 
			
		||||
const linkRegex = new RegExp(`^\\s*(([${h_confusables}][${t_confusables}][${t_confusables}][${p_confusables}][${s_confusables}]?[${column_confusables}][${slash_confusables}][${slash_confusables}]))?[^:/\\n ]+([${dot_confusables}][^:/\\n ]+)+`);
 | 
			
		||||
 | 
			
		||||
const isLinkMisleading = (link) => {
 | 
			
		||||
  let linkTextParts = [];
 | 
			
		||||
 | 
			
		||||
  // Reconstruct visible text, as we do not have much control over how links
 | 
			
		||||
  // from remote software look, and we can't rely on `innerText` because the
 | 
			
		||||
  // `invisible` class does not set `display` to `none`.
 | 
			
		||||
 | 
			
		||||
  const walk = (node) => {
 | 
			
		||||
    switch (node.nodeType) {
 | 
			
		||||
    case Node.TEXT_NODE:
 | 
			
		||||
      linkTextParts.push(node.textContent);
 | 
			
		||||
      break;
 | 
			
		||||
    case Node.ELEMENT_NODE:
 | 
			
		||||
      if (node.classList.contains('invisible')) return;
 | 
			
		||||
      const children = node.childNodes;
 | 
			
		||||
      for (let i = 0; i < children.length; i++) {
 | 
			
		||||
        walk(children[i]);
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  walk(link);
 | 
			
		||||
 | 
			
		||||
  const linkText = linkTextParts.join('');
 | 
			
		||||
  const targetURL = new URL(link.href);
 | 
			
		||||
 | 
			
		||||
  // The following may not work with international domain names
 | 
			
		||||
  if (linkText === targetURL.origin || linkText === targetURL.host || 'www.' + linkText === targetURL.host || linkText.startsWith(targetURL.origin + '/') || linkText.startsWith(targetURL.host + '/')) {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // The link hasn't been recognized, maybe it features an international domain name
 | 
			
		||||
  const hostname = decodeIDNA(targetURL.hostname);
 | 
			
		||||
  const host = targetURL.host.replace(targetURL.hostname, hostname);
 | 
			
		||||
  const origin = targetURL.origin.replace(targetURL.host, host);
 | 
			
		||||
  if (linkText === origin || linkText === host || linkText.startsWith(origin + '/') || linkText.startsWith(host + '/')) {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // If the link text looks like an URL or auto-generated link, it is misleading
 | 
			
		||||
  return linkRegex.test(linkText);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default class StatusContent extends React.PureComponent {
 | 
			
		||||
 | 
			
		||||
  static contextTypes = {
 | 
			
		||||
| 
						 | 
				
			
			@ -56,6 +118,34 @@ export default class StatusContent extends React.PureComponent {
 | 
			
		|||
      } else {
 | 
			
		||||
        link.setAttribute('title', link.href);
 | 
			
		||||
        link.classList.add('unhandled-link');
 | 
			
		||||
 | 
			
		||||
        if (isLinkMisleading(link)) {
 | 
			
		||||
          while (link.firstChild) {
 | 
			
		||||
            link.removeChild(link.firstChild);
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          const prefix = (link.href.match(/https?:\/\/(www\.)?/) || [''])[0];
 | 
			
		||||
          const text   = link.href.substr(prefix.length, 30);
 | 
			
		||||
          const suffix = link.href.substr(prefix.length + 30);
 | 
			
		||||
          const cutoff = !!suffix;
 | 
			
		||||
 | 
			
		||||
          const prefixTag = document.createElement('span');
 | 
			
		||||
          prefixTag.classList.add('invisible');
 | 
			
		||||
          prefixTag.textContent = prefix;
 | 
			
		||||
          link.appendChild(prefixTag);
 | 
			
		||||
 | 
			
		||||
          const textTag = document.createElement('span');
 | 
			
		||||
          if (cutoff) {
 | 
			
		||||
            textTag.classList.add('ellipsis');
 | 
			
		||||
          }
 | 
			
		||||
          textTag.textContent = text;
 | 
			
		||||
          link.appendChild(textTag);
 | 
			
		||||
 | 
			
		||||
          const suffixTag = document.createElement('span');
 | 
			
		||||
          suffixTag.classList.add('invisible');
 | 
			
		||||
          suffixTag.textContent = suffix;
 | 
			
		||||
          link.appendChild(suffixTag);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      link.setAttribute('target', '_blank');
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,18 +2,9 @@ import React from 'react';
 | 
			
		|||
import PropTypes from 'prop-types';
 | 
			
		||||
import Immutable from 'immutable';
 | 
			
		||||
import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
			
		||||
import punycode from 'punycode';
 | 
			
		||||
import classnames from 'classnames';
 | 
			
		||||
import Icon from 'mastodon/components/icon';
 | 
			
		||||
 | 
			
		||||
const IDNA_PREFIX = 'xn--';
 | 
			
		||||
 | 
			
		||||
const decodeIDNA = domain => {
 | 
			
		||||
  return domain
 | 
			
		||||
    .split('.')
 | 
			
		||||
    .map(part => part.indexOf(IDNA_PREFIX) === 0 ? punycode.decode(part.slice(IDNA_PREFIX.length)) : part)
 | 
			
		||||
    .join('.');
 | 
			
		||||
};
 | 
			
		||||
import { decode as decodeIDNA } from 'mastodon/utils/idna';
 | 
			
		||||
 | 
			
		||||
const getHostname = url => {
 | 
			
		||||
  const parser = document.createElement('a');
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -207,11 +207,11 @@ const expiresInFromExpiresAt = expires_at => {
 | 
			
		|||
 | 
			
		||||
const normalizeSuggestions = (state, { accounts, emojis, tags }) => {
 | 
			
		||||
  if (accounts) {
 | 
			
		||||
    return accounts.map(item => item.id);
 | 
			
		||||
    return accounts.map(item => ({ id: item.id, type: 'account' }));
 | 
			
		||||
  } else if (emojis) {
 | 
			
		||||
    return emojis;
 | 
			
		||||
    return emojis.map(item => ({ ...item, type: 'emoji' }));
 | 
			
		||||
  } else {
 | 
			
		||||
    return sortHashtagsByUse(state, tags);
 | 
			
		||||
    return sortHashtagsByUse(state, tags.map(item => ({ ...item, type: 'hashtag' })));
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -44,7 +44,8 @@ export default function search(state = initialState, action) {
 | 
			
		|||
      hashtags: fromJS(action.results.hashtags),
 | 
			
		||||
    })).set('submitted', true).set('searchTerm', action.searchTerm);
 | 
			
		||||
  case SEARCH_EXPAND_SUCCESS:
 | 
			
		||||
    return state.updateIn(['results', action.searchType], list => list.concat(action.results[action.searchType].map(item => item.id)));
 | 
			
		||||
    const results = action.searchType === 'hashtags' ? fromJS(action.results.hashtags) : action.results[action.searchType].map(item => item.id);
 | 
			
		||||
    return state.updateIn(['results', action.searchType], list => list.concat(results));
 | 
			
		||||
  default:
 | 
			
		||||
    return state;
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										10
									
								
								app/javascript/mastodon/utils/idna.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								app/javascript/mastodon/utils/idna.js
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,10 @@
 | 
			
		|||
import punycode from 'punycode';
 | 
			
		||||
 | 
			
		||||
const IDNA_PREFIX = 'xn--';
 | 
			
		||||
 | 
			
		||||
export const decode = domain => {
 | 
			
		||||
  return domain
 | 
			
		||||
    .split('.')
 | 
			
		||||
    .map(part => part.indexOf(IDNA_PREFIX) === 0 ? punycode.decode(part.slice(IDNA_PREFIX.length)) : part)
 | 
			
		||||
    .join('.');
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										33
									
								
								app/models/domain_allow.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								app/models/domain_allow.rb
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,33 @@
 | 
			
		|||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
# == Schema Information
 | 
			
		||||
#
 | 
			
		||||
# Table name: domain_allows
 | 
			
		||||
#
 | 
			
		||||
#  id         :bigint(8)        not null, primary key
 | 
			
		||||
#  domain     :string           default(""), not null
 | 
			
		||||
#  created_at :datetime         not null
 | 
			
		||||
#  updated_at :datetime         not null
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
class DomainAllow < ApplicationRecord
 | 
			
		||||
  include DomainNormalizable
 | 
			
		||||
 | 
			
		||||
  validates :domain, presence: true, uniqueness: true
 | 
			
		||||
 | 
			
		||||
  scope :matches_domain, ->(value) { where(arel_table[:domain].matches("%#{value}%")) }
 | 
			
		||||
 | 
			
		||||
  class << self
 | 
			
		||||
    def allowed?(domain)
 | 
			
		||||
      !rule_for(domain).nil?
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def rule_for(domain)
 | 
			
		||||
      return if domain.blank?
 | 
			
		||||
 | 
			
		||||
      uri = Addressable::URI.new.tap { |u| u.host = domain.gsub(/[\/]/, '') }
 | 
			
		||||
 | 
			
		||||
      find_by(domain: uri.normalized_host)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -7,8 +7,9 @@ class Instance
 | 
			
		|||
 | 
			
		||||
  def initialize(resource)
 | 
			
		||||
    @domain         = resource.domain
 | 
			
		||||
    @accounts_count = resource.is_a?(DomainBlock) ? nil : resource.accounts_count
 | 
			
		||||
    @accounts_count = resource.respond_to?(:accounts_count) ? resource.accounts_count : nil
 | 
			
		||||
    @domain_block   = resource.is_a?(DomainBlock) ? resource : DomainBlock.rule_for(domain)
 | 
			
		||||
    @domain_allow   = resource.is_a?(DomainAllow) ? resource : DomainAllow.rule_for(domain)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def countable?
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,6 +12,10 @@ class InstanceFilter
 | 
			
		|||
      scope = DomainBlock
 | 
			
		||||
      scope = scope.matches_domain(params[:by_domain]) if params[:by_domain].present?
 | 
			
		||||
      scope.order(id: :desc)
 | 
			
		||||
    elsif params[:allowed].present?
 | 
			
		||||
      scope = DomainAllow
 | 
			
		||||
      scope = scope.matches_domain(params[:by_domain]) if params[:by_domain].present?
 | 
			
		||||
      scope.order(id: :desc)
 | 
			
		||||
    else
 | 
			
		||||
      scope = Account.remote
 | 
			
		||||
      scope = scope.matches_domain(params[:by_domain]) if params[:by_domain].present?
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -65,7 +65,7 @@ class Tag < ApplicationRecord
 | 
			
		|||
 | 
			
		||||
  class << self
 | 
			
		||||
    def find_or_create_by_names(name_or_names)
 | 
			
		||||
      Array(name_or_names).map(&method(:normalize)).uniq.map do |normalized_name|
 | 
			
		||||
      Array(name_or_names).map(&method(:normalize)).uniq { |str| str.mb_chars.downcase.to_s }.map do |normalized_name|
 | 
			
		||||
        tag = matching_name(normalized_name).first || create(name: normalized_name)
 | 
			
		||||
 | 
			
		||||
        yield tag if block_given?
 | 
			
		||||
| 
						 | 
				
			
			@ -77,7 +77,7 @@ class Tag < ApplicationRecord
 | 
			
		|||
    def search_for(term, limit = 5, offset = 0)
 | 
			
		||||
      pattern = sanitize_sql_like(normalize(term.strip)) + '%'
 | 
			
		||||
 | 
			
		||||
      Tag.where(arel_table[:name].lower.matches(pattern.downcase))
 | 
			
		||||
      Tag.where(arel_table[:name].lower.matches(pattern.mb_chars.downcase.to_s))
 | 
			
		||||
         .order(:name)
 | 
			
		||||
         .limit(limit)
 | 
			
		||||
         .offset(offset)
 | 
			
		||||
| 
						 | 
				
			
			@ -92,7 +92,7 @@ class Tag < ApplicationRecord
 | 
			
		|||
    end
 | 
			
		||||
 | 
			
		||||
    def matching_name(name_or_names)
 | 
			
		||||
      names = Array(name_or_names).map { |name| normalize(name).downcase }
 | 
			
		||||
      names = Array(name_or_names).map { |name| normalize(name).mb_chars.downcase.to_s }
 | 
			
		||||
 | 
			
		||||
      if names.size == 1
 | 
			
		||||
        where(arel_table[:name].lower.eq(names.first))
 | 
			
		||||
| 
						 | 
				
			
			@ -104,7 +104,7 @@ class Tag < ApplicationRecord
 | 
			
		|||
    private
 | 
			
		||||
 | 
			
		||||
    def normalize(str)
 | 
			
		||||
      str.gsub(/\A#/, '').mb_chars.to_s
 | 
			
		||||
      str.gsub(/\A#/, '')
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										11
									
								
								app/policies/domain_allow_policy.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								app/policies/domain_allow_policy.rb
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class DomainAllowPolicy < ApplicationPolicy
 | 
			
		||||
  def create?
 | 
			
		||||
    admin?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def destroy?
 | 
			
		||||
    admin?
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -14,6 +14,6 @@ module Payloadable
 | 
			
		|||
  end
 | 
			
		||||
 | 
			
		||||
  def signing_enabled?
 | 
			
		||||
    ENV['AUTHORIZED_FETCH'] != 'true'
 | 
			
		||||
    ENV['AUTHORIZED_FETCH'] != 'true' && !Rails.configuration.x.whitelist_mode
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										11
									
								
								app/services/unallow_domain_service.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								app/services/unallow_domain_service.rb
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class UnallowDomainService < BaseService
 | 
			
		||||
  def call(domain_allow)
 | 
			
		||||
    Account.where(domain: domain_allow.domain).find_each do |account|
 | 
			
		||||
      SuspendAccountService.new.call(account, destroy: true)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    domain_allow.destroy
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										14
									
								
								app/views/admin/domain_allows/new.html.haml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								app/views/admin/domain_allows/new.html.haml
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,14 @@
 | 
			
		|||
- content_for :header_tags do
 | 
			
		||||
  = javascript_pack_tag 'admin', integrity: true, async: true, crossorigin: 'anonymous'
 | 
			
		||||
 | 
			
		||||
- content_for :page_title do
 | 
			
		||||
  = t('admin.domain_allows.add_new')
 | 
			
		||||
 | 
			
		||||
= simple_form_for @domain_allow, url: admin_domain_allows_path do |f|
 | 
			
		||||
  = render 'shared/error_messages', object: @domain_allow
 | 
			
		||||
 | 
			
		||||
  .fields-group
 | 
			
		||||
    = f.input :domain, wrapper: :with_label, label: t('admin.domain_blocks.domain'), required: true
 | 
			
		||||
 | 
			
		||||
  .actions
 | 
			
		||||
    = f.button :button, t('admin.domain_allows.add_new'), type: :submit
 | 
			
		||||
| 
						 | 
				
			
			@ -6,24 +6,30 @@
 | 
			
		|||
    %strong= t('admin.instances.moderation.title')
 | 
			
		||||
    %ul
 | 
			
		||||
      %li= filter_link_to t('admin.instances.moderation.all'), limited: nil
 | 
			
		||||
      %li= filter_link_to t('admin.instances.moderation.limited'), limited: '1'
 | 
			
		||||
 | 
			
		||||
      - unless whitelist_mode?
 | 
			
		||||
        %li= filter_link_to t('admin.instances.moderation.limited'), limited: '1'
 | 
			
		||||
 | 
			
		||||
  %div{ style: 'flex: 1 1 auto; text-align: right' }
 | 
			
		||||
    = link_to t('admin.domain_blocks.add_new'), new_admin_domain_block_path, class: 'button'
 | 
			
		||||
    - if whitelist_mode?
 | 
			
		||||
      = link_to t('admin.domain_allows.add_new'), new_admin_domain_allow_path, class: 'button'
 | 
			
		||||
    - else
 | 
			
		||||
      = link_to t('admin.domain_blocks.add_new'), new_admin_domain_block_path, class: 'button'
 | 
			
		||||
 | 
			
		||||
= form_tag admin_instances_url, method: 'GET', class: 'simple_form' do
 | 
			
		||||
  .fields-group
 | 
			
		||||
    - Admin::FilterHelper::INSTANCES_FILTERS.each do |key|
 | 
			
		||||
      - if params[key].present?
 | 
			
		||||
        = hidden_field_tag key, params[key]
 | 
			
		||||
- unless whitelist_mode?
 | 
			
		||||
  = form_tag admin_instances_url, method: 'GET', class: 'simple_form' do
 | 
			
		||||
    .fields-group
 | 
			
		||||
      - Admin::FilterHelper::INSTANCES_FILTERS.each do |key|
 | 
			
		||||
        - if params[key].present?
 | 
			
		||||
          = hidden_field_tag key, params[key]
 | 
			
		||||
 | 
			
		||||
    - %i(by_domain).each do |key|
 | 
			
		||||
      .input.string.optional
 | 
			
		||||
        = text_field_tag key, params[key], class: 'string optional', placeholder: I18n.t("admin.instances.#{key}")
 | 
			
		||||
      - %i(by_domain).each do |key|
 | 
			
		||||
        .input.string.optional
 | 
			
		||||
          = text_field_tag key, params[key], class: 'string optional', placeholder: I18n.t("admin.instances.#{key}")
 | 
			
		||||
 | 
			
		||||
    .actions
 | 
			
		||||
      %button= t('admin.accounts.search')
 | 
			
		||||
      = link_to t('admin.accounts.reset'), admin_instances_path, class: 'button negative'
 | 
			
		||||
      .actions
 | 
			
		||||
        %button= t('admin.accounts.search')
 | 
			
		||||
        = link_to t('admin.accounts.reset'), admin_instances_path, class: 'button negative'
 | 
			
		||||
 | 
			
		||||
%hr.spacer/
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -47,8 +53,11 @@
 | 
			
		|||
              - unless first_item
 | 
			
		||||
                •
 | 
			
		||||
              = t('admin.domain_blocks.rejecting_reports')
 | 
			
		||||
          - elsif whitelist_mode?
 | 
			
		||||
            = t('admin.accounts.whitelisted')
 | 
			
		||||
          - else
 | 
			
		||||
            = t('admin.accounts.no_limits_imposed')
 | 
			
		||||
      - if instance.countable?
 | 
			
		||||
        .trends__item__current{ title: t('admin.instances.known_accounts', count: instance.accounts_count) }= number_to_human instance.accounts_count, strip_insignificant_zeros: true
 | 
			
		||||
 | 
			
		||||
= paginate paginated_instances
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -38,7 +38,9 @@
 | 
			
		|||
    = link_to t('admin.accounts.title'), admin_accounts_path(remote: '1', by_domain: @instance.domain), class: 'button'
 | 
			
		||||
 | 
			
		||||
  %div{ style: 'float: right' }
 | 
			
		||||
    - if @domain_block
 | 
			
		||||
    - if @domain_allow
 | 
			
		||||
      = link_to t('admin.domain_allows.undo'), admin_domain_allow_path(@domain_allow), class: 'button button--destructive', data: { confirm: t('admin.accounts.are_you_sure'), method: :delete }
 | 
			
		||||
    - elsif @domain_block
 | 
			
		||||
      = link_to t('admin.domain_blocks.undo'), admin_domain_block_path(@domain_block), class: 'button'
 | 
			
		||||
    - else
 | 
			
		||||
      = link_to t('admin.domain_blocks.add_new'), new_admin_domain_block_path(_domain: @instance.domain), class: 'button'
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -42,11 +42,12 @@
 | 
			
		|||
 | 
			
		||||
  %hr.spacer/
 | 
			
		||||
 | 
			
		||||
  .fields-group
 | 
			
		||||
    = f.input :timeline_preview, as: :boolean, wrapper: :with_label, label: t('admin.settings.timeline_preview.title'), hint: t('admin.settings.timeline_preview.desc_html')
 | 
			
		||||
  - unless whitelist_mode?
 | 
			
		||||
    .fields-group
 | 
			
		||||
      = f.input :timeline_preview, as: :boolean, wrapper: :with_label, label: t('admin.settings.timeline_preview.title'), hint: t('admin.settings.timeline_preview.desc_html')
 | 
			
		||||
 | 
			
		||||
  .fields-group
 | 
			
		||||
    = f.input :show_known_fediverse_at_about_page, as: :boolean, wrapper: :with_label, label: t('admin.settings.show_known_fediverse_at_about_page.title'), hint: t('admin.settings.show_known_fediverse_at_about_page.desc_html')
 | 
			
		||||
    .fields-group
 | 
			
		||||
      = f.input :show_known_fediverse_at_about_page, as: :boolean, wrapper: :with_label, label: t('admin.settings.show_known_fediverse_at_about_page.title'), hint: t('admin.settings.show_known_fediverse_at_about_page.desc_html')
 | 
			
		||||
 | 
			
		||||
  .fields-group
 | 
			
		||||
    = f.input :show_staff_badge, as: :boolean, wrapper: :with_label, label: t('admin.settings.show_staff_badge.title'), hint: t('admin.settings.show_staff_badge.desc_html')
 | 
			
		||||
| 
						 | 
				
			
			@ -54,17 +55,18 @@
 | 
			
		|||
  .fields-group
 | 
			
		||||
    = f.input :open_deletion, as: :boolean, wrapper: :with_label, label: t('admin.settings.registrations.deletion.title'), hint: t('admin.settings.registrations.deletion.desc_html')
 | 
			
		||||
 | 
			
		||||
  .fields-group
 | 
			
		||||
    = f.input :activity_api_enabled, as: :boolean, wrapper: :with_label, label: t('admin.settings.activity_api_enabled.title'), hint: t('admin.settings.activity_api_enabled.desc_html')
 | 
			
		||||
  - unless whitelist_mode?
 | 
			
		||||
    .fields-group
 | 
			
		||||
      = f.input :activity_api_enabled, as: :boolean, wrapper: :with_label, label: t('admin.settings.activity_api_enabled.title'), hint: t('admin.settings.activity_api_enabled.desc_html')
 | 
			
		||||
 | 
			
		||||
  .fields-group
 | 
			
		||||
    = f.input :peers_api_enabled, as: :boolean, wrapper: :with_label, label: t('admin.settings.peers_api_enabled.title'), hint: t('admin.settings.peers_api_enabled.desc_html')
 | 
			
		||||
    .fields-group
 | 
			
		||||
      = f.input :peers_api_enabled, as: :boolean, wrapper: :with_label, label: t('admin.settings.peers_api_enabled.title'), hint: t('admin.settings.peers_api_enabled.desc_html')
 | 
			
		||||
 | 
			
		||||
  .fields-group
 | 
			
		||||
    = f.input :preview_sensitive_media, as: :boolean, wrapper: :with_label, label: t('admin.settings.preview_sensitive_media.title'), hint: t('admin.settings.preview_sensitive_media.desc_html')
 | 
			
		||||
    .fields-group
 | 
			
		||||
      = f.input :preview_sensitive_media, as: :boolean, wrapper: :with_label, label: t('admin.settings.preview_sensitive_media.title'), hint: t('admin.settings.preview_sensitive_media.desc_html')
 | 
			
		||||
 | 
			
		||||
  .fields-group
 | 
			
		||||
    = f.input :profile_directory, as: :boolean, wrapper: :with_label, label: t('admin.settings.profile_directory.title'), hint: t('admin.settings.profile_directory.desc_html')
 | 
			
		||||
    .fields-group
 | 
			
		||||
      = f.input :profile_directory, as: :boolean, wrapper: :with_label, label: t('admin.settings.profile_directory.title'), hint: t('admin.settings.profile_directory.desc_html')
 | 
			
		||||
 | 
			
		||||
  .fields-group
 | 
			
		||||
    = f.input :hide_followers_count, as: :boolean, wrapper: :with_label, label: t('admin.settings.hide_followers_count.title'), hint: t('admin.settings.hide_followers_count.desc_html')
 | 
			
		||||
| 
						 | 
				
			
			@ -88,7 +90,7 @@
 | 
			
		|||
 | 
			
		||||
  .fields-group
 | 
			
		||||
    = f.input :closed_registrations_message, as: :text, wrapper: :with_block_label, label: t('admin.settings.registrations.closed_message.title'), hint: t('admin.settings.registrations.closed_message.desc_html'), input_html: { rows: 8 }
 | 
			
		||||
    = f.input :site_extended_description, wrapper: :with_block_label, as: :text, label: t('admin.settings.site_description_extended.title'), hint: t('admin.settings.site_description_extended.desc_html'), input_html: { rows: 8 }
 | 
			
		||||
    = f.input :site_extended_description, wrapper: :with_block_label, as: :text, label: t('admin.settings.site_description_extended.title'), hint: t('admin.settings.site_description_extended.desc_html'), input_html: { rows: 8 } unless whitelist_mode?
 | 
			
		||||
    = f.input :site_terms, wrapper: :with_block_label, as: :text, label: t('admin.settings.site_terms.title'), hint: t('admin.settings.site_terms.desc_html'), input_html: { rows: 8 }
 | 
			
		||||
    = f.input :custom_css, wrapper: :with_block_label, as: :text, input_html: { rows: 8 }, label: t('admin.settings.custom_css.title'), hint: t('admin.settings.custom_css.desc_html')
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -33,7 +33,7 @@
 | 
			
		|||
  = f.input :invite_code, as: :hidden
 | 
			
		||||
 | 
			
		||||
  .fields-group
 | 
			
		||||
    = f.input :agreement, as: :boolean, wrapper: :with_label, label: t('auth.checkbox_agreement_html', rules_path: about_more_path, terms_path: terms_path)
 | 
			
		||||
    = f.input :agreement, as: :boolean, wrapper: :with_label, label: whitelist_mode? ? t('auth.checkbox_agreement_without_rules_html', terms_path: terms_path) : t('auth.checkbox_agreement_html', rules_path: about_more_path, terms_path: terms_path)
 | 
			
		||||
 | 
			
		||||
  .actions
 | 
			
		||||
    = f.button :button, @invite.present? ? t('auth.register') : sign_up_message, type: :submit
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,10 +7,13 @@
 | 
			
		|||
            = link_to root_url, class: 'brand' do
 | 
			
		||||
              = svg_logo_full
 | 
			
		||||
 | 
			
		||||
            = link_to t('directories.directory'), explore_path, class: 'nav-link optional' if Setting.profile_directory
 | 
			
		||||
            = link_to t('about.about_this'), about_more_path, class: 'nav-link optional'
 | 
			
		||||
            = link_to t('about.apps'), 'https://joinmastodon.org/apps', class: 'nav-link optional'
 | 
			
		||||
            - unless whitelist_mode?
 | 
			
		||||
              = link_to t('directories.directory'), explore_path, class: 'nav-link optional' if Setting.profile_directory
 | 
			
		||||
              = link_to t('about.about_this'), about_more_path, class: 'nav-link optional'
 | 
			
		||||
              = link_to t('about.apps'), 'https://joinmastodon.org/apps', class: 'nav-link optional'
 | 
			
		||||
 | 
			
		||||
          .nav-center
 | 
			
		||||
 | 
			
		||||
          .nav-right
 | 
			
		||||
            - if user_signed_in?
 | 
			
		||||
              = link_to t('settings.back'), root_url, class: 'nav-link nav-button webapp-btn'
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										5
									
								
								config/initializers/2_whitelist_mode.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								config/initializers/2_whitelist_mode.rb
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,5 @@
 | 
			
		|||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
Rails.application.configure do
 | 
			
		||||
  config.x.whitelist_mode = ENV['WHITELIST_MODE'] == 'true'
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -186,6 +186,7 @@ en:
 | 
			
		|||
      username: Username
 | 
			
		||||
      warn: Warn
 | 
			
		||||
      web: Web
 | 
			
		||||
      whitelisted: Whitelisted
 | 
			
		||||
    action_logs:
 | 
			
		||||
      actions:
 | 
			
		||||
        assigned_to_self_report: "%{name} assigned report %{target} to themselves"
 | 
			
		||||
| 
						 | 
				
			
			@ -270,6 +271,11 @@ en:
 | 
			
		|||
      week_interactions: interactions this week
 | 
			
		||||
      week_users_active: active this week
 | 
			
		||||
      week_users_new: users this week
 | 
			
		||||
    domain_allows:
 | 
			
		||||
      add_new: Whitelist domain
 | 
			
		||||
      created_msg: Domain has been successfully whitelisted
 | 
			
		||||
      destroyed_msg: Domain has been removed from the whitelist
 | 
			
		||||
      undo: Remove from whitelist
 | 
			
		||||
    domain_blocks:
 | 
			
		||||
      add_new: Add new domain block
 | 
			
		||||
      created_msg: Domain block is now being processed
 | 
			
		||||
| 
						 | 
				
			
			@ -537,6 +543,7 @@ en:
 | 
			
		|||
    apply_for_account: Request an invite
 | 
			
		||||
    change_password: Password
 | 
			
		||||
    checkbox_agreement_html: I agree to the <a href="%{rules_path}" target="_blank">server rules</a> and <a href="%{terms_path}" target="_blank">terms of service</a>
 | 
			
		||||
    checkbox_agreement_without_rules_html: I agree to the <a href="%{terms_path}" target="_blank">terms of service</a>
 | 
			
		||||
    delete_account: Delete account
 | 
			
		||||
    delete_account_html: If you wish to delete your account, you can <a href="%{path}">proceed here</a>. You will be asked for confirmation.
 | 
			
		||||
    didnt_get_confirmation: Didn't receive confirmation instructions?
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -43,6 +43,8 @@ en:
 | 
			
		|||
        setting_use_pending_items: Hide timeline updates behind a click instead of automatically scrolling the feed
 | 
			
		||||
        username: Your username will be unique on %{domain}
 | 
			
		||||
        whole_word: When the keyword or phrase is alphanumeric only, it will only be applied if it matches the whole word
 | 
			
		||||
      domain_allow:
 | 
			
		||||
        domain: This domain will be able to fetch data from this server and incoming data from it will be processed and stored
 | 
			
		||||
      featured_tag:
 | 
			
		||||
        name: 'You might want to use one of these:'
 | 
			
		||||
      imports:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -45,7 +45,7 @@ SimpleNavigation::Configuration.run do |navigation|
 | 
			
		|||
      s.item :accounts, safe_join([fa_icon('users fw'), t('admin.accounts.title')]), admin_accounts_url, highlights_on: %r{/admin/accounts|/admin/pending_accounts}
 | 
			
		||||
      s.item :invites, safe_join([fa_icon('user-plus fw'), t('admin.invites.title')]), admin_invites_path
 | 
			
		||||
      s.item :tags, safe_join([fa_icon('tag fw'), t('admin.tags.title')]), admin_tags_path
 | 
			
		||||
      s.item :instances, safe_join([fa_icon('cloud fw'), t('admin.instances.title')]), admin_instances_url(limited: '1'), highlights_on: %r{/admin/instances|/admin/domain_blocks}, if: -> { current_user.admin? }
 | 
			
		||||
      s.item :instances, safe_join([fa_icon('cloud fw'), t('admin.instances.title')]), admin_instances_url(limited: whitelist_mode? ? nil : '1'), highlights_on: %r{/admin/instances|/admin/domain_blocks|/admin/domain_allows}, if: -> { current_user.admin? }
 | 
			
		||||
      s.item :email_domain_blocks, safe_join([fa_icon('envelope fw'), t('admin.email_domain_blocks.title')]), admin_email_domain_blocks_url, highlights_on: %r{/admin/email_domain_blocks}, if: -> { current_user.admin? }
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -156,6 +156,7 @@ Rails.application.routes.draw do
 | 
			
		|||
  namespace :admin do
 | 
			
		||||
    get '/dashboard', to: 'dashboard#index'
 | 
			
		||||
 | 
			
		||||
    resources :domain_allows, only: [:new, :create, :show, :destroy]
 | 
			
		||||
    resources :domain_blocks, only: [:new, :create, :show, :destroy]
 | 
			
		||||
    resources :email_domain_blocks, only: [:index, :new, :create, :destroy]
 | 
			
		||||
    resources :action_logs, only: [:index]
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										9
									
								
								db/migrate/20190705002136_create_domain_allows.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								db/migrate/20190705002136_create_domain_allows.rb
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,9 @@
 | 
			
		|||
class CreateDomainAllows < ActiveRecord::Migration[5.2]
 | 
			
		||||
  def change
 | 
			
		||||
    create_table :domain_allows do |t|
 | 
			
		||||
      t.string :domain, default: '', null: false, index: { unique: true }
 | 
			
		||||
 | 
			
		||||
      t.timestamps
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -2,6 +2,19 @@ class AddCaseInsensitiveIndexToTags < ActiveRecord::Migration[5.2]
 | 
			
		|||
  disable_ddl_transaction!
 | 
			
		||||
 | 
			
		||||
  def up
 | 
			
		||||
    Tag.connection.select_all('SELECT string_agg(id::text, \',\') AS ids FROM tags GROUP BY lower(name) HAVING count(*) > 1').to_hash.each do |row|
 | 
			
		||||
      canonical_tag_id  = row['ids'].split(',').first
 | 
			
		||||
      redundant_tag_ids = row['ids'].split(',')[1..-1]
 | 
			
		||||
 | 
			
		||||
      safety_assured do
 | 
			
		||||
        execute "UPDATE accounts_tags AS t0 SET tag_id = #{canonical_tag_id} WHERE tag_id IN (#{redundant_tag_ids.join(', ')}) AND NOT EXISTS (SELECT t1.tag_id FROM accounts_tags AS t1 WHERE t1.tag_id = #{canonical_tag_id} AND t1.account_id = t0.account_id)"
 | 
			
		||||
        execute "UPDATE statuses_tags AS t0 SET tag_id = #{canonical_tag_id} WHERE tag_id IN (#{redundant_tag_ids.join(', ')}) AND NOT EXISTS (SELECT t1.tag_id FROM statuses_tags AS t1 WHERE t1.tag_id = #{canonical_tag_id} AND t1.status_id = t0.status_id)"
 | 
			
		||||
        execute "UPDATE featured_tags AS t0 SET tag_id = #{canonical_tag_id} WHERE tag_id IN (#{redundant_tag_ids.join(', ')})  AND NOT EXISTS (SELECT t1.tag_id FROM featured_tags AS t1 WHERE t1.tag_id = #{canonical_tag_id} AND t1.account_id = t0.account_id)"
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      Tag.where(id: redundant_tag_ids).in_batches.delete_all
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    safety_assured { execute 'CREATE UNIQUE INDEX CONCURRENTLY index_tags_on_name_lower ON tags (lower(name))' }
 | 
			
		||||
    remove_index :tags, name: 'index_tags_on_name'
 | 
			
		||||
    remove_index :tags, name: 'hashtag_search_index'
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,7 +10,7 @@
 | 
			
		|||
#
 | 
			
		||||
# It's strongly recommended that you check this file into your version control system.
 | 
			
		||||
 | 
			
		||||
ActiveRecord::Schema.define(version: 2019_07_26_175042) do
 | 
			
		||||
ActiveRecord::Schema.define(version: 2019_07_28_084117) do
 | 
			
		||||
 | 
			
		||||
  # These are extensions that must be enabled in order to support this database
 | 
			
		||||
  enable_extension "plpgsql"
 | 
			
		||||
| 
						 | 
				
			
			@ -255,6 +255,13 @@ ActiveRecord::Schema.define(version: 2019_07_26_175042) do
 | 
			
		|||
    t.index ["account_id"], name: "index_custom_filters_on_account_id"
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  create_table "domain_allows", force: :cascade do |t|
 | 
			
		||||
    t.string "domain", default: "", null: false
 | 
			
		||||
    t.datetime "created_at", null: false
 | 
			
		||||
    t.datetime "updated_at", null: false
 | 
			
		||||
    t.index ["domain"], name: "index_domain_allows_on_domain", unique: true
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  create_table "domain_blocks", force: :cascade do |t|
 | 
			
		||||
    t.string "domain", default: "", null: false
 | 
			
		||||
    t.datetime "created_at", null: false
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,17 +12,33 @@ module Mastodon
 | 
			
		|||
    end
 | 
			
		||||
 | 
			
		||||
    option :dry_run, type: :boolean
 | 
			
		||||
    desc 'purge DOMAIN', 'Remove accounts from a DOMAIN without a trace'
 | 
			
		||||
    option :whitelist_mode, type: :boolean
 | 
			
		||||
    desc 'purge [DOMAIN]', 'Remove accounts from a DOMAIN without a trace'
 | 
			
		||||
    long_desc <<-LONG_DESC
 | 
			
		||||
      Remove all accounts from a given DOMAIN without leaving behind any
 | 
			
		||||
      records. Unlike a suspension, if the DOMAIN still exists in the wild,
 | 
			
		||||
      it means the accounts could return if they are resolved again.
 | 
			
		||||
 | 
			
		||||
      When the --whitelist-mode option is given, instead of purging accounts
 | 
			
		||||
      from a single domain, all accounts from domains that are not whitelisted
 | 
			
		||||
      are removed from the database.
 | 
			
		||||
    LONG_DESC
 | 
			
		||||
    def purge(domain)
 | 
			
		||||
    def purge(domain = nil)
 | 
			
		||||
      removed = 0
 | 
			
		||||
      dry_run = options[:dry_run] ? ' (DRY RUN)' : ''
 | 
			
		||||
 | 
			
		||||
      Account.where(domain: domain).find_each do |account|
 | 
			
		||||
      scope = begin
 | 
			
		||||
        if options[:whitelist_mode]
 | 
			
		||||
          Account.remote.where.not(domain: DomainAllow.pluck(:domain))
 | 
			
		||||
        elsif domain.present?
 | 
			
		||||
          Account.remote.where(domain: domain)
 | 
			
		||||
        else
 | 
			
		||||
          say('No domain given', :red)
 | 
			
		||||
          exit(1)
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      scope.find_each do |account|
 | 
			
		||||
        SuspendAccountService.new.call(account, destroy: true) unless options[:dry_run]
 | 
			
		||||
        removed += 1
 | 
			
		||||
        say('.', :green, false)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										10
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								package.json
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -69,13 +69,13 @@
 | 
			
		|||
    "@babel/plugin-transform-react-jsx-self": "^7.2.0",
 | 
			
		||||
    "@babel/plugin-transform-react-jsx-source": "^7.2.0",
 | 
			
		||||
    "@babel/plugin-transform-runtime": "^7.4.4",
 | 
			
		||||
    "@babel/preset-env": "^7.4.5",
 | 
			
		||||
    "@babel/preset-env": "^7.5.5",
 | 
			
		||||
    "@babel/preset-react": "^7.0.0",
 | 
			
		||||
    "@babel/runtime": "^7.5.4",
 | 
			
		||||
    "@clusterws/cws": "^0.15.0",
 | 
			
		||||
    "array-includes": "^3.0.3",
 | 
			
		||||
    "atrament": "^0.2.3",
 | 
			
		||||
    "autoprefixer": "^9.6.0",
 | 
			
		||||
    "autoprefixer": "^9.6.1",
 | 
			
		||||
    "axios": "^0.19.0",
 | 
			
		||||
    "babel-loader": "^8.0.6",
 | 
			
		||||
    "babel-plugin-lodash": "^3.3.4",
 | 
			
		||||
| 
						 | 
				
			
			@ -97,7 +97,7 @@
 | 
			
		|||
    "exif-js": "^2.3.0",
 | 
			
		||||
    "express": "^4.17.1",
 | 
			
		||||
    "favico.js": "^0.3.10",
 | 
			
		||||
    "file-loader": "^4.0.0",
 | 
			
		||||
    "file-loader": "^4.1.0",
 | 
			
		||||
    "font-awesome": "^4.7.0",
 | 
			
		||||
    "glob": "^7.1.1",
 | 
			
		||||
    "http-link-header": "^1.0.2",
 | 
			
		||||
| 
						 | 
				
			
			@ -153,7 +153,7 @@
 | 
			
		|||
    "requestidlecallback": "^0.3.0",
 | 
			
		||||
    "reselect": "^4.0.0",
 | 
			
		||||
    "rimraf": "^2.6.3",
 | 
			
		||||
    "sass": "^1.20.3",
 | 
			
		||||
    "sass": "^1.22.7",
 | 
			
		||||
    "sass-loader": "^7.0.3",
 | 
			
		||||
    "stringz": "^2.0.0",
 | 
			
		||||
    "substring-trie": "^1.0.2",
 | 
			
		||||
| 
						 | 
				
			
			@ -184,6 +184,6 @@
 | 
			
		|||
    "react-test-renderer": "^16.8.6",
 | 
			
		||||
    "sass-lint": "^1.13.1",
 | 
			
		||||
    "webpack-dev-server": "^3.7.2",
 | 
			
		||||
    "yargs": "^12.0.5"
 | 
			
		||||
    "yargs": "^13.3.0"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										3
									
								
								spec/fabricators/domain_allow_fabricator.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								spec/fabricators/domain_allow_fabricator.rb
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,3 @@
 | 
			
		|||
Fabricator(:domain_allow) do
 | 
			
		||||
  domain "MyString"
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										5
									
								
								spec/models/domain_allow_spec.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								spec/models/domain_allow_spec.rb
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,5 @@
 | 
			
		|||
require 'rails_helper'
 | 
			
		||||
 | 
			
		||||
RSpec.describe DomainAllow, type: :model do
 | 
			
		||||
  pending "add some examples to (or delete) #{__FILE__}"
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -82,6 +82,40 @@ RSpec.describe Tag, type: :model do
 | 
			
		|||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe '.find_normalized' do
 | 
			
		||||
    it 'returns tag for a multibyte case-insensitive name' do
 | 
			
		||||
      upcase_string   = 'abcABCabcABCやゆよ'
 | 
			
		||||
      downcase_string = 'abcabcabcabcやゆよ';
 | 
			
		||||
 | 
			
		||||
      tag = Fabricate(:tag, name: downcase_string)
 | 
			
		||||
      expect(Tag.find_normalized(upcase_string)).to eq tag
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe '.matching_name' do
 | 
			
		||||
    it 'returns tags for multibyte case-insensitive names' do
 | 
			
		||||
      upcase_string   = 'abcABCabcABCやゆよ'
 | 
			
		||||
      downcase_string = 'abcabcabcabcやゆよ';
 | 
			
		||||
 | 
			
		||||
      tag = Fabricate(:tag, name: downcase_string)
 | 
			
		||||
      expect(Tag.matching_name(upcase_string)).to eq [tag]
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe '.find_or_create_by_names' do
 | 
			
		||||
    it 'runs a passed block once per tag regardless of duplicates' do
 | 
			
		||||
      upcase_string   = 'abcABCabcABCやゆよ'
 | 
			
		||||
      downcase_string = 'abcabcabcabcやゆよ';
 | 
			
		||||
      count           = 0
 | 
			
		||||
 | 
			
		||||
      Tag.find_or_create_by_names([upcase_string, downcase_string]) do |tag|
 | 
			
		||||
        count += 1
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      expect(count).to eq 1
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe '.search_for' do
 | 
			
		||||
    it 'finds tag records with matching names' do
 | 
			
		||||
      tag = Fabricate(:tag, name: "match")
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,6 +12,7 @@ const uuid = require('uuid');
 | 
			
		|||
const fs = require('fs');
 | 
			
		||||
 | 
			
		||||
const env = process.env.NODE_ENV || 'development';
 | 
			
		||||
const alwaysRequireAuth = process.env.WHITELIST_MODE === 'true' || process.env.AUTHORIZED_FETCH === 'true';
 | 
			
		||||
 | 
			
		||||
dotenv.config({
 | 
			
		||||
  path: env === 'production' ? '.env.production' : '.env',
 | 
			
		||||
| 
						 | 
				
			
			@ -271,7 +272,7 @@ const startWorker = (workerId) => {
 | 
			
		|||
 | 
			
		||||
  const wsVerifyClient = (info, cb) => {
 | 
			
		||||
    const location = url.parse(info.req.url, true);
 | 
			
		||||
    const authRequired = !PUBLIC_STREAMS.some(stream => stream === location.query.stream);
 | 
			
		||||
    const authRequired = alwaysRequireAuth || !PUBLIC_STREAMS.some(stream => stream === location.query.stream);
 | 
			
		||||
    const allowedScopes = [];
 | 
			
		||||
 | 
			
		||||
    if (authRequired) {
 | 
			
		||||
| 
						 | 
				
			
			@ -306,7 +307,7 @@ const startWorker = (workerId) => {
 | 
			
		|||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const authRequired = !PUBLIC_ENDPOINTS.some(endpoint => endpoint === req.path);
 | 
			
		||||
    const authRequired = alwaysRequireAuth || !PUBLIC_ENDPOINTS.some(endpoint => endpoint === req.path);
 | 
			
		||||
    const allowedScopes = [];
 | 
			
		||||
 | 
			
		||||
    if (authRequired) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										397
									
								
								yarn.lock
									
									
									
									
									
								
							
							
						
						
									
										397
									
								
								yarn.lock
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -9,6 +9,13 @@
 | 
			
		|||
  dependencies:
 | 
			
		||||
    "@babel/highlight" "^7.0.0"
 | 
			
		||||
 | 
			
		||||
"@babel/code-frame@^7.5.5":
 | 
			
		||||
  version "7.5.5"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.5.5.tgz#bc0782f6d69f7b7d49531219699b988f669a8f9d"
 | 
			
		||||
  integrity sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@babel/highlight" "^7.0.0"
 | 
			
		||||
 | 
			
		||||
"@babel/core@^7.1.0":
 | 
			
		||||
  version "7.3.4"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.3.4.tgz#921a5a13746c21e32445bf0798680e9d11a6530b"
 | 
			
		||||
| 
						 | 
				
			
			@ -71,6 +78,17 @@
 | 
			
		|||
    source-map "^0.5.0"
 | 
			
		||||
    trim-right "^1.0.1"
 | 
			
		||||
 | 
			
		||||
"@babel/generator@^7.5.5":
 | 
			
		||||
  version "7.5.5"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.5.5.tgz#873a7f936a3c89491b43536d12245b626664e3cf"
 | 
			
		||||
  integrity sha512-ETI/4vyTSxTzGnU2c49XHv2zhExkv9JHLTwDAFz85kmcwuShvYG2H08FwgIguQf4JC75CBnXAUM5PqeF4fj0nQ==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@babel/types" "^7.5.5"
 | 
			
		||||
    jsesc "^2.5.1"
 | 
			
		||||
    lodash "^4.17.13"
 | 
			
		||||
    source-map "^0.5.0"
 | 
			
		||||
    trim-right "^1.0.1"
 | 
			
		||||
 | 
			
		||||
"@babel/helper-annotate-as-pure@^7.0.0":
 | 
			
		||||
  version "7.0.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz#323d39dd0b50e10c7c06ca7d7638e6864d8c5c32"
 | 
			
		||||
| 
						 | 
				
			
			@ -115,14 +133,14 @@
 | 
			
		|||
    "@babel/helper-replace-supers" "^7.4.4"
 | 
			
		||||
    "@babel/helper-split-export-declaration" "^7.4.4"
 | 
			
		||||
 | 
			
		||||
"@babel/helper-define-map@^7.4.4":
 | 
			
		||||
  version "7.4.4"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.4.4.tgz#6969d1f570b46bdc900d1eba8e5d59c48ba2c12a"
 | 
			
		||||
  integrity sha512-IX3Ln8gLhZpSuqHJSnTNBWGDE9kdkTEWl21A/K7PQ00tseBwbqCHTvNLHSBd9M0R5rER4h5Rsvj9vw0R5SieBg==
 | 
			
		||||
"@babel/helper-define-map@^7.5.5":
 | 
			
		||||
  version "7.5.5"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.5.5.tgz#3dec32c2046f37e09b28c93eb0b103fd2a25d369"
 | 
			
		||||
  integrity sha512-fTfxx7i0B5NJqvUOBBGREnrqbTxRh7zinBANpZXAVDlsZxYdclDp467G1sQ8VZYMnAURY3RpBUAgOYT9GfzHBg==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@babel/helper-function-name" "^7.1.0"
 | 
			
		||||
    "@babel/types" "^7.4.4"
 | 
			
		||||
    lodash "^4.17.11"
 | 
			
		||||
    "@babel/types" "^7.5.5"
 | 
			
		||||
    lodash "^4.17.13"
 | 
			
		||||
 | 
			
		||||
"@babel/helper-explode-assignable-expression@^7.1.0":
 | 
			
		||||
  version "7.1.0"
 | 
			
		||||
| 
						 | 
				
			
			@ -162,6 +180,13 @@
 | 
			
		|||
  dependencies:
 | 
			
		||||
    "@babel/types" "^7.0.0"
 | 
			
		||||
 | 
			
		||||
"@babel/helper-member-expression-to-functions@^7.5.5":
 | 
			
		||||
  version "7.5.5"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.5.5.tgz#1fb5b8ec4453a93c439ee9fe3aeea4a84b76b590"
 | 
			
		||||
  integrity sha512-5qZ3D1uMclSNqYcXqiHoA0meVdv+xUEex9em2fqMnrk/scphGlGgg66zjMrPJESPwrFJ6sbfFQYUSa0Mz7FabA==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@babel/types" "^7.5.5"
 | 
			
		||||
 | 
			
		||||
"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.0.0-beta.49":
 | 
			
		||||
  version "7.0.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz#96081b7111e486da4d2cd971ad1a4fe216cc2e3d"
 | 
			
		||||
| 
						 | 
				
			
			@ -211,7 +236,7 @@
 | 
			
		|||
    "@babel/traverse" "^7.1.0"
 | 
			
		||||
    "@babel/types" "^7.0.0"
 | 
			
		||||
 | 
			
		||||
"@babel/helper-replace-supers@^7.1.0", "@babel/helper-replace-supers@^7.4.4":
 | 
			
		||||
"@babel/helper-replace-supers@^7.4.4":
 | 
			
		||||
  version "7.4.4"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.4.4.tgz#aee41783ebe4f2d3ab3ae775e1cc6f1a90cefa27"
 | 
			
		||||
  integrity sha512-04xGEnd+s01nY1l15EuMS1rfKktNF+1CkKmHoErDppjAAZL+IUBZpzT748x262HF7fibaQPhbvWUl5HeSt1EXg==
 | 
			
		||||
| 
						 | 
				
			
			@ -221,6 +246,16 @@
 | 
			
		|||
    "@babel/traverse" "^7.4.4"
 | 
			
		||||
    "@babel/types" "^7.4.4"
 | 
			
		||||
 | 
			
		||||
"@babel/helper-replace-supers@^7.5.5":
 | 
			
		||||
  version "7.5.5"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.5.5.tgz#f84ce43df031222d2bad068d2626cb5799c34bc2"
 | 
			
		||||
  integrity sha512-XvRFWrNnlsow2u7jXDuH4jDDctkxbS7gXssrP4q2nUD606ukXHRvydj346wmNg+zAgpFx4MWf4+usfC93bElJg==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@babel/helper-member-expression-to-functions" "^7.5.5"
 | 
			
		||||
    "@babel/helper-optimise-call-expression" "^7.0.0"
 | 
			
		||||
    "@babel/traverse" "^7.5.5"
 | 
			
		||||
    "@babel/types" "^7.5.5"
 | 
			
		||||
 | 
			
		||||
"@babel/helper-simple-access@^7.1.0":
 | 
			
		||||
  version "7.1.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.1.0.tgz#65eeb954c8c245beaa4e859da6188f39d71e585c"
 | 
			
		||||
| 
						 | 
				
			
			@ -278,6 +313,11 @@
 | 
			
		|||
  resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.4.5.tgz#04af8d5d5a2b044a2a1bffacc1e5e6673544e872"
 | 
			
		||||
  integrity sha512-9mUqkL1FF5T7f0WDFfAoDdiMVPWsdD1gZYzSnaXsxUCUqzuch/8of9G3VUSNiZmMBoRxT3neyVsqeiL/ZPcjew==
 | 
			
		||||
 | 
			
		||||
"@babel/parser@^7.5.5":
 | 
			
		||||
  version "7.5.5"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.5.5.tgz#02f077ac8817d3df4a832ef59de67565e71cca4b"
 | 
			
		||||
  integrity sha512-E5BN68cqR7dhKan1SfqgPGhQ178bkVKpXTPEXnFJBrEt8/DKRZlybmy+IgYLTeN7tp1R5Ccmbm2rBk17sHYU3g==
 | 
			
		||||
 | 
			
		||||
"@babel/plugin-proposal-async-generator-functions@^7.2.0":
 | 
			
		||||
  version "7.2.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.2.0.tgz#b289b306669dce4ad20b0252889a15768c9d417e"
 | 
			
		||||
| 
						 | 
				
			
			@ -304,6 +344,14 @@
 | 
			
		|||
    "@babel/helper-plugin-utils" "^7.0.0"
 | 
			
		||||
    "@babel/plugin-syntax-decorators" "^7.2.0"
 | 
			
		||||
 | 
			
		||||
"@babel/plugin-proposal-dynamic-import@^7.5.0":
 | 
			
		||||
  version "7.5.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.5.0.tgz#e532202db4838723691b10a67b8ce509e397c506"
 | 
			
		||||
  integrity sha512-x/iMjggsKTFHYC6g11PL7Qy58IK8H5zqfm9e6hu4z1iH2IRyAp9u9dL80zA6R76yFovETFLKz2VJIC2iIPBuFw==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@babel/helper-plugin-utils" "^7.0.0"
 | 
			
		||||
    "@babel/plugin-syntax-dynamic-import" "^7.2.0"
 | 
			
		||||
 | 
			
		||||
"@babel/plugin-proposal-json-strings@^7.2.0":
 | 
			
		||||
  version "7.2.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.2.0.tgz#568ecc446c6148ae6b267f02551130891e29f317"
 | 
			
		||||
| 
						 | 
				
			
			@ -312,10 +360,10 @@
 | 
			
		|||
    "@babel/helper-plugin-utils" "^7.0.0"
 | 
			
		||||
    "@babel/plugin-syntax-json-strings" "^7.2.0"
 | 
			
		||||
 | 
			
		||||
"@babel/plugin-proposal-object-rest-spread@^7.4.4":
 | 
			
		||||
  version "7.4.4"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.4.4.tgz#1ef173fcf24b3e2df92a678f027673b55e7e3005"
 | 
			
		||||
  integrity sha512-dMBG6cSPBbHeEBdFXeQ2QLc5gUpg4Vkaz8octD4aoW/ISO+jBOcsuxYL7bsb5WSu8RLP6boxrBIALEHgoHtO9g==
 | 
			
		||||
"@babel/plugin-proposal-object-rest-spread@^7.4.4", "@babel/plugin-proposal-object-rest-spread@^7.5.5":
 | 
			
		||||
  version "7.5.5"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.5.5.tgz#61939744f71ba76a3ae46b5eea18a54c16d22e58"
 | 
			
		||||
  integrity sha512-F2DxJJSQ7f64FyTVl5cw/9MWn6naXGdk3Q3UhDbFEEHv+EilCPoeRD3Zh/Utx1CJz4uyKlQ4uH+bJPbEhMV7Zw==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@babel/helper-plugin-utils" "^7.0.0"
 | 
			
		||||
    "@babel/plugin-syntax-object-rest-spread" "^7.2.0"
 | 
			
		||||
| 
						 | 
				
			
			@ -393,10 +441,10 @@
 | 
			
		|||
  dependencies:
 | 
			
		||||
    "@babel/helper-plugin-utils" "^7.0.0"
 | 
			
		||||
 | 
			
		||||
"@babel/plugin-transform-async-to-generator@^7.4.4":
 | 
			
		||||
  version "7.4.4"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.4.4.tgz#a3f1d01f2f21cadab20b33a82133116f14fb5894"
 | 
			
		||||
  integrity sha512-YiqW2Li8TXmzgbXw+STsSqPBPFnGviiaSp6CYOq55X8GQ2SGVLrXB6pNid8HkqkZAzOH6knbai3snhP7v0fNwA==
 | 
			
		||||
"@babel/plugin-transform-async-to-generator@^7.5.0":
 | 
			
		||||
  version "7.5.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.5.0.tgz#89a3848a0166623b5bc481164b5936ab947e887e"
 | 
			
		||||
  integrity sha512-mqvkzwIGkq0bEF1zLRRiTdjfomZJDV33AH3oQzHVGkI2VzEmXLpKKOBvEVaFZBJdN0XTyH38s9j/Kiqr68dggg==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@babel/helper-module-imports" "^7.0.0"
 | 
			
		||||
    "@babel/helper-plugin-utils" "^7.0.0"
 | 
			
		||||
| 
						 | 
				
			
			@ -409,25 +457,25 @@
 | 
			
		|||
  dependencies:
 | 
			
		||||
    "@babel/helper-plugin-utils" "^7.0.0"
 | 
			
		||||
 | 
			
		||||
"@babel/plugin-transform-block-scoping@^7.4.4":
 | 
			
		||||
  version "7.4.4"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.4.4.tgz#c13279fabf6b916661531841a23c4b7dae29646d"
 | 
			
		||||
  integrity sha512-jkTUyWZcTrwxu5DD4rWz6rDB5Cjdmgz6z7M7RLXOJyCUkFBawssDGcGh8M/0FTSB87avyJI1HsTwUXp9nKA1PA==
 | 
			
		||||
"@babel/plugin-transform-block-scoping@^7.5.5":
 | 
			
		||||
  version "7.5.5"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.5.5.tgz#a35f395e5402822f10d2119f6f8e045e3639a2ce"
 | 
			
		||||
  integrity sha512-82A3CLRRdYubkG85lKwhZB0WZoHxLGsJdux/cOVaJCJpvYFl1LVzAIFyRsa7CvXqW8rBM4Zf3Bfn8PHt5DP0Sg==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@babel/helper-plugin-utils" "^7.0.0"
 | 
			
		||||
    lodash "^4.17.11"
 | 
			
		||||
    lodash "^4.17.13"
 | 
			
		||||
 | 
			
		||||
"@babel/plugin-transform-classes@^7.4.4":
 | 
			
		||||
  version "7.4.4"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.4.4.tgz#0ce4094cdafd709721076d3b9c38ad31ca715eb6"
 | 
			
		||||
  integrity sha512-/e44eFLImEGIpL9qPxSRat13I5QNRgBLu2hOQJCF7VLy/otSM/sypV1+XaIw5+502RX/+6YaSAPmldk+nhHDPw==
 | 
			
		||||
"@babel/plugin-transform-classes@^7.5.5":
 | 
			
		||||
  version "7.5.5"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.5.5.tgz#d094299d9bd680a14a2a0edae38305ad60fb4de9"
 | 
			
		||||
  integrity sha512-U2htCNK/6e9K7jGyJ++1p5XRU+LJjrwtoiVn9SzRlDT2KubcZ11OOwy3s24TjHxPgxNwonCYP7U2K51uVYCMDg==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@babel/helper-annotate-as-pure" "^7.0.0"
 | 
			
		||||
    "@babel/helper-define-map" "^7.4.4"
 | 
			
		||||
    "@babel/helper-define-map" "^7.5.5"
 | 
			
		||||
    "@babel/helper-function-name" "^7.1.0"
 | 
			
		||||
    "@babel/helper-optimise-call-expression" "^7.0.0"
 | 
			
		||||
    "@babel/helper-plugin-utils" "^7.0.0"
 | 
			
		||||
    "@babel/helper-replace-supers" "^7.4.4"
 | 
			
		||||
    "@babel/helper-replace-supers" "^7.5.5"
 | 
			
		||||
    "@babel/helper-split-export-declaration" "^7.4.4"
 | 
			
		||||
    globals "^11.1.0"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -438,10 +486,10 @@
 | 
			
		|||
  dependencies:
 | 
			
		||||
    "@babel/helper-plugin-utils" "^7.0.0"
 | 
			
		||||
 | 
			
		||||
"@babel/plugin-transform-destructuring@^7.4.4":
 | 
			
		||||
  version "7.4.4"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.4.4.tgz#9d964717829cc9e4b601fc82a26a71a4d8faf20f"
 | 
			
		||||
  integrity sha512-/aOx+nW0w8eHiEHm+BTERB2oJn5D127iye/SUQl7NjHy0lf+j7h4MKMMSOwdazGq9OxgiNADncE+SRJkCxjZpQ==
 | 
			
		||||
"@babel/plugin-transform-destructuring@^7.5.0":
 | 
			
		||||
  version "7.5.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.5.0.tgz#f6c09fdfe3f94516ff074fe877db7bc9ef05855a"
 | 
			
		||||
  integrity sha512-YbYgbd3TryYYLGyC7ZR+Tq8H/+bCmwoaxHfJHupom5ECstzbRLTch6gOQbhEY9Z4hiCNHEURgq06ykFv9JZ/QQ==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@babel/helper-plugin-utils" "^7.0.0"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -454,10 +502,10 @@
 | 
			
		|||
    "@babel/helper-regex" "^7.4.4"
 | 
			
		||||
    regexpu-core "^4.5.4"
 | 
			
		||||
 | 
			
		||||
"@babel/plugin-transform-duplicate-keys@^7.2.0":
 | 
			
		||||
  version "7.2.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.2.0.tgz#d952c4930f312a4dbfff18f0b2914e60c35530b3"
 | 
			
		||||
  integrity sha512-q+yuxW4DsTjNceUiTzK0L+AfQ0zD9rWaTLiUqHA8p0gxx7lu1EylenfzjeIWNkPy6e/0VG/Wjw9uf9LueQwLOw==
 | 
			
		||||
"@babel/plugin-transform-duplicate-keys@^7.5.0":
 | 
			
		||||
  version "7.5.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.5.0.tgz#c5dbf5106bf84cdf691222c0974c12b1df931853"
 | 
			
		||||
  integrity sha512-igcziksHizyQPlX9gfSjHkE2wmoCH3evvD2qR5w29/Dk0SMKE/eOI7f1HhBdNhR/zxJDqrgpoDTq5YSLH/XMsQ==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@babel/helper-plugin-utils" "^7.0.0"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -498,30 +546,33 @@
 | 
			
		|||
  dependencies:
 | 
			
		||||
    "@babel/helper-plugin-utils" "^7.0.0"
 | 
			
		||||
 | 
			
		||||
"@babel/plugin-transform-modules-amd@^7.2.0":
 | 
			
		||||
  version "7.2.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.2.0.tgz#82a9bce45b95441f617a24011dc89d12da7f4ee6"
 | 
			
		||||
  integrity sha512-mK2A8ucqz1qhrdqjS9VMIDfIvvT2thrEsIQzbaTdc5QFzhDjQv2CkJJ5f6BXIkgbmaoax3zBr2RyvV/8zeoUZw==
 | 
			
		||||
"@babel/plugin-transform-modules-amd@^7.5.0":
 | 
			
		||||
  version "7.5.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.5.0.tgz#ef00435d46da0a5961aa728a1d2ecff063e4fb91"
 | 
			
		||||
  integrity sha512-n20UsQMKnWrltocZZm24cRURxQnWIvsABPJlw/fvoy9c6AgHZzoelAIzajDHAQrDpuKFFPPcFGd7ChsYuIUMpg==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@babel/helper-module-transforms" "^7.1.0"
 | 
			
		||||
    "@babel/helper-plugin-utils" "^7.0.0"
 | 
			
		||||
    babel-plugin-dynamic-import-node "^2.3.0"
 | 
			
		||||
 | 
			
		||||
"@babel/plugin-transform-modules-commonjs@^7.4.4":
 | 
			
		||||
  version "7.4.4"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.4.4.tgz#0bef4713d30f1d78c2e59b3d6db40e60192cac1e"
 | 
			
		||||
  integrity sha512-4sfBOJt58sEo9a2BQXnZq+Q3ZTSAUXyK3E30o36BOGnJ+tvJ6YSxF0PG6kERvbeISgProodWuI9UVG3/FMY6iw==
 | 
			
		||||
"@babel/plugin-transform-modules-commonjs@^7.5.0":
 | 
			
		||||
  version "7.5.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.5.0.tgz#425127e6045231360858eeaa47a71d75eded7a74"
 | 
			
		||||
  integrity sha512-xmHq0B+ytyrWJvQTc5OWAC4ii6Dhr0s22STOoydokG51JjWhyYo5mRPXoi+ZmtHQhZZwuXNN+GG5jy5UZZJxIQ==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@babel/helper-module-transforms" "^7.4.4"
 | 
			
		||||
    "@babel/helper-plugin-utils" "^7.0.0"
 | 
			
		||||
    "@babel/helper-simple-access" "^7.1.0"
 | 
			
		||||
    babel-plugin-dynamic-import-node "^2.3.0"
 | 
			
		||||
 | 
			
		||||
"@babel/plugin-transform-modules-systemjs@^7.4.4":
 | 
			
		||||
  version "7.4.4"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.4.4.tgz#dc83c5665b07d6c2a7b224c00ac63659ea36a405"
 | 
			
		||||
  integrity sha512-MSiModfILQc3/oqnG7NrP1jHaSPryO6tA2kOMmAQApz5dayPxWiHqmq4sWH2xF5LcQK56LlbKByCd8Aah/OIkQ==
 | 
			
		||||
"@babel/plugin-transform-modules-systemjs@^7.5.0":
 | 
			
		||||
  version "7.5.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.5.0.tgz#e75266a13ef94202db2a0620977756f51d52d249"
 | 
			
		||||
  integrity sha512-Q2m56tyoQWmuNGxEtUyeEkm6qJYFqs4c+XyXH5RAuYxObRNz9Zgj/1g2GMnjYp2EUyEy7YTrxliGCXzecl/vJg==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@babel/helper-hoist-variables" "^7.4.4"
 | 
			
		||||
    "@babel/helper-plugin-utils" "^7.0.0"
 | 
			
		||||
    babel-plugin-dynamic-import-node "^2.3.0"
 | 
			
		||||
 | 
			
		||||
"@babel/plugin-transform-modules-umd@^7.2.0":
 | 
			
		||||
  version "7.2.0"
 | 
			
		||||
| 
						 | 
				
			
			@ -545,13 +596,13 @@
 | 
			
		|||
  dependencies:
 | 
			
		||||
    "@babel/helper-plugin-utils" "^7.0.0"
 | 
			
		||||
 | 
			
		||||
"@babel/plugin-transform-object-super@^7.2.0":
 | 
			
		||||
  version "7.2.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.2.0.tgz#b35d4c10f56bab5d650047dad0f1d8e8814b6598"
 | 
			
		||||
  integrity sha512-VMyhPYZISFZAqAPVkiYb7dUe2AsVi2/wCT5+wZdsNO31FojQJa9ns40hzZ6U9f50Jlq4w6qwzdBB2uwqZ00ebg==
 | 
			
		||||
"@babel/plugin-transform-object-super@^7.5.5":
 | 
			
		||||
  version "7.5.5"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.5.5.tgz#c70021df834073c65eb613b8679cc4a381d1a9f9"
 | 
			
		||||
  integrity sha512-un1zJQAhSosGFBduPgN/YFNvWVpRuHKU7IHBglLoLZsGmruJPOo6pbInneflUdmq7YvSVqhpPs5zdBvLnteltQ==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@babel/helper-plugin-utils" "^7.0.0"
 | 
			
		||||
    "@babel/helper-replace-supers" "^7.1.0"
 | 
			
		||||
    "@babel/helper-replace-supers" "^7.5.5"
 | 
			
		||||
 | 
			
		||||
"@babel/plugin-transform-parameters@^7.4.4":
 | 
			
		||||
  version "7.4.4"
 | 
			
		||||
| 
						 | 
				
			
			@ -679,43 +730,45 @@
 | 
			
		|||
    "@babel/helper-regex" "^7.4.4"
 | 
			
		||||
    regexpu-core "^4.5.4"
 | 
			
		||||
 | 
			
		||||
"@babel/preset-env@^7.4.5":
 | 
			
		||||
  version "7.4.5"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.4.5.tgz#2fad7f62983d5af563b5f3139242755884998a58"
 | 
			
		||||
  integrity sha512-f2yNVXM+FsR5V8UwcFeIHzHWgnhXg3NpRmy0ADvALpnhB0SLbCvrCRr4BLOUYbQNLS+Z0Yer46x9dJXpXewI7w==
 | 
			
		||||
"@babel/preset-env@^7.5.5":
 | 
			
		||||
  version "7.5.5"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.5.5.tgz#bc470b53acaa48df4b8db24a570d6da1fef53c9a"
 | 
			
		||||
  integrity sha512-GMZQka/+INwsMz1A5UEql8tG015h5j/qjptpKY2gJ7giy8ohzU710YciJB5rcKsWGWHiW3RUnHib0E5/m3Tp3A==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@babel/helper-module-imports" "^7.0.0"
 | 
			
		||||
    "@babel/helper-plugin-utils" "^7.0.0"
 | 
			
		||||
    "@babel/plugin-proposal-async-generator-functions" "^7.2.0"
 | 
			
		||||
    "@babel/plugin-proposal-dynamic-import" "^7.5.0"
 | 
			
		||||
    "@babel/plugin-proposal-json-strings" "^7.2.0"
 | 
			
		||||
    "@babel/plugin-proposal-object-rest-spread" "^7.4.4"
 | 
			
		||||
    "@babel/plugin-proposal-object-rest-spread" "^7.5.5"
 | 
			
		||||
    "@babel/plugin-proposal-optional-catch-binding" "^7.2.0"
 | 
			
		||||
    "@babel/plugin-proposal-unicode-property-regex" "^7.4.4"
 | 
			
		||||
    "@babel/plugin-syntax-async-generators" "^7.2.0"
 | 
			
		||||
    "@babel/plugin-syntax-dynamic-import" "^7.2.0"
 | 
			
		||||
    "@babel/plugin-syntax-json-strings" "^7.2.0"
 | 
			
		||||
    "@babel/plugin-syntax-object-rest-spread" "^7.2.0"
 | 
			
		||||
    "@babel/plugin-syntax-optional-catch-binding" "^7.2.0"
 | 
			
		||||
    "@babel/plugin-transform-arrow-functions" "^7.2.0"
 | 
			
		||||
    "@babel/plugin-transform-async-to-generator" "^7.4.4"
 | 
			
		||||
    "@babel/plugin-transform-async-to-generator" "^7.5.0"
 | 
			
		||||
    "@babel/plugin-transform-block-scoped-functions" "^7.2.0"
 | 
			
		||||
    "@babel/plugin-transform-block-scoping" "^7.4.4"
 | 
			
		||||
    "@babel/plugin-transform-classes" "^7.4.4"
 | 
			
		||||
    "@babel/plugin-transform-block-scoping" "^7.5.5"
 | 
			
		||||
    "@babel/plugin-transform-classes" "^7.5.5"
 | 
			
		||||
    "@babel/plugin-transform-computed-properties" "^7.2.0"
 | 
			
		||||
    "@babel/plugin-transform-destructuring" "^7.4.4"
 | 
			
		||||
    "@babel/plugin-transform-destructuring" "^7.5.0"
 | 
			
		||||
    "@babel/plugin-transform-dotall-regex" "^7.4.4"
 | 
			
		||||
    "@babel/plugin-transform-duplicate-keys" "^7.2.0"
 | 
			
		||||
    "@babel/plugin-transform-duplicate-keys" "^7.5.0"
 | 
			
		||||
    "@babel/plugin-transform-exponentiation-operator" "^7.2.0"
 | 
			
		||||
    "@babel/plugin-transform-for-of" "^7.4.4"
 | 
			
		||||
    "@babel/plugin-transform-function-name" "^7.4.4"
 | 
			
		||||
    "@babel/plugin-transform-literals" "^7.2.0"
 | 
			
		||||
    "@babel/plugin-transform-member-expression-literals" "^7.2.0"
 | 
			
		||||
    "@babel/plugin-transform-modules-amd" "^7.2.0"
 | 
			
		||||
    "@babel/plugin-transform-modules-commonjs" "^7.4.4"
 | 
			
		||||
    "@babel/plugin-transform-modules-systemjs" "^7.4.4"
 | 
			
		||||
    "@babel/plugin-transform-modules-amd" "^7.5.0"
 | 
			
		||||
    "@babel/plugin-transform-modules-commonjs" "^7.5.0"
 | 
			
		||||
    "@babel/plugin-transform-modules-systemjs" "^7.5.0"
 | 
			
		||||
    "@babel/plugin-transform-modules-umd" "^7.2.0"
 | 
			
		||||
    "@babel/plugin-transform-named-capturing-groups-regex" "^7.4.5"
 | 
			
		||||
    "@babel/plugin-transform-new-target" "^7.4.4"
 | 
			
		||||
    "@babel/plugin-transform-object-super" "^7.2.0"
 | 
			
		||||
    "@babel/plugin-transform-object-super" "^7.5.5"
 | 
			
		||||
    "@babel/plugin-transform-parameters" "^7.4.4"
 | 
			
		||||
    "@babel/plugin-transform-property-literals" "^7.2.0"
 | 
			
		||||
    "@babel/plugin-transform-regenerator" "^7.4.5"
 | 
			
		||||
| 
						 | 
				
			
			@ -726,7 +779,7 @@
 | 
			
		|||
    "@babel/plugin-transform-template-literals" "^7.4.4"
 | 
			
		||||
    "@babel/plugin-transform-typeof-symbol" "^7.2.0"
 | 
			
		||||
    "@babel/plugin-transform-unicode-regex" "^7.4.4"
 | 
			
		||||
    "@babel/types" "^7.4.4"
 | 
			
		||||
    "@babel/types" "^7.5.5"
 | 
			
		||||
    browserslist "^4.6.0"
 | 
			
		||||
    core-js-compat "^3.1.1"
 | 
			
		||||
    invariant "^2.2.2"
 | 
			
		||||
| 
						 | 
				
			
			@ -798,13 +851,28 @@
 | 
			
		|||
    globals "^11.1.0"
 | 
			
		||||
    lodash "^4.17.11"
 | 
			
		||||
 | 
			
		||||
"@babel/types@^7.0.0", "@babel/types@^7.0.0-beta.49", "@babel/types@^7.2.0", "@babel/types@^7.2.2", "@babel/types@^7.3.0", "@babel/types@^7.3.4", "@babel/types@^7.4.4":
 | 
			
		||||
  version "7.4.4"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.4.4.tgz#8db9e9a629bb7c29370009b4b779ed93fe57d5f0"
 | 
			
		||||
  integrity sha512-dOllgYdnEFOebhkKCjzSVFqw/PmmB8pH6RGOWkY4GsboQNd47b1fBThBSwlHAq9alF9vc1M3+6oqR47R50L0tQ==
 | 
			
		||||
"@babel/traverse@^7.5.5":
 | 
			
		||||
  version "7.5.5"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.5.5.tgz#f664f8f368ed32988cd648da9f72d5ca70f165bb"
 | 
			
		||||
  integrity sha512-MqB0782whsfffYfSjH4TM+LMjrJnhCNEDMDIjeTpl+ASaUvxcjoiVCo/sM1GhS1pHOXYfWVCYneLjMckuUxDaQ==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@babel/code-frame" "^7.5.5"
 | 
			
		||||
    "@babel/generator" "^7.5.5"
 | 
			
		||||
    "@babel/helper-function-name" "^7.1.0"
 | 
			
		||||
    "@babel/helper-split-export-declaration" "^7.4.4"
 | 
			
		||||
    "@babel/parser" "^7.5.5"
 | 
			
		||||
    "@babel/types" "^7.5.5"
 | 
			
		||||
    debug "^4.1.0"
 | 
			
		||||
    globals "^11.1.0"
 | 
			
		||||
    lodash "^4.17.13"
 | 
			
		||||
 | 
			
		||||
"@babel/types@^7.0.0", "@babel/types@^7.0.0-beta.49", "@babel/types@^7.2.0", "@babel/types@^7.2.2", "@babel/types@^7.3.0", "@babel/types@^7.3.4", "@babel/types@^7.4.4", "@babel/types@^7.5.5":
 | 
			
		||||
  version "7.5.5"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.5.5.tgz#97b9f728e182785909aa4ab56264f090a028d18a"
 | 
			
		||||
  integrity sha512-s63F9nJioLqOlW3UkyMd+BYhXt44YuaFm/VV0VwuteqjYwRrObkU7ra9pY4wAJR3oXi8hJrMcrcJdO/HH33vtw==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    esutils "^2.0.2"
 | 
			
		||||
    lodash "^4.17.11"
 | 
			
		||||
    lodash "^4.17.13"
 | 
			
		||||
    to-fast-properties "^2.0.0"
 | 
			
		||||
 | 
			
		||||
"@clusterws/cws@^0.15.0":
 | 
			
		||||
| 
						 | 
				
			
			@ -1445,6 +1513,14 @@ anymatch@^2.0.0:
 | 
			
		|||
    micromatch "^3.1.4"
 | 
			
		||||
    normalize-path "^2.1.1"
 | 
			
		||||
 | 
			
		||||
anymatch@^3.0.1:
 | 
			
		||||
  version "3.0.3"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.0.3.tgz#2fb624fe0e84bccab00afee3d0006ed310f22f09"
 | 
			
		||||
  integrity sha512-c6IvoeBECQlMVuYUjSwimnhmztImpErfxJzWZhIQinIvQWoGOnB0dLIgifbPHQt5heS6mNlaZG16f06H3C8t1g==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    normalize-path "^3.0.0"
 | 
			
		||||
    picomatch "^2.0.4"
 | 
			
		||||
 | 
			
		||||
aproba@^1.0.3, aproba@^1.1.1:
 | 
			
		||||
  version "1.2.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a"
 | 
			
		||||
| 
						 | 
				
			
			@ -1632,18 +1708,18 @@ atrament@^0.2.3:
 | 
			
		|||
  version "0.2.3"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/atrament/-/atrament-0.2.3.tgz#6ccbc0daa6d3f25e5aeaeb31befeb78e86980348"
 | 
			
		||||
 | 
			
		||||
autoprefixer@^9.6.0:
 | 
			
		||||
  version "9.6.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.6.0.tgz#0111c6bde2ad20c6f17995a33fad7cf6854b4c87"
 | 
			
		||||
  integrity sha512-kuip9YilBqhirhHEGHaBTZKXL//xxGnzvsD0FtBQa6z+A69qZD6s/BAX9VzDF1i9VKDquTJDQaPLSEhOnL6FvQ==
 | 
			
		||||
autoprefixer@^9.6.1:
 | 
			
		||||
  version "9.6.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.6.1.tgz#51967a02d2d2300bb01866c1611ec8348d355a47"
 | 
			
		||||
  integrity sha512-aVo5WxR3VyvyJxcJC3h4FKfwCQvQWb1tSI5VHNibddCVWrcD1NvlxEweg3TSgiPztMnWfjpy2FURKA2kvDE+Tw==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    browserslist "^4.6.1"
 | 
			
		||||
    caniuse-lite "^1.0.30000971"
 | 
			
		||||
    browserslist "^4.6.3"
 | 
			
		||||
    caniuse-lite "^1.0.30000980"
 | 
			
		||||
    chalk "^2.4.2"
 | 
			
		||||
    normalize-range "^0.1.2"
 | 
			
		||||
    num2fraction "^1.2.2"
 | 
			
		||||
    postcss "^7.0.16"
 | 
			
		||||
    postcss-value-parser "^3.3.1"
 | 
			
		||||
    postcss "^7.0.17"
 | 
			
		||||
    postcss-value-parser "^4.0.0"
 | 
			
		||||
 | 
			
		||||
aws-sign2@~0.7.0:
 | 
			
		||||
  version "0.7.0"
 | 
			
		||||
| 
						 | 
				
			
			@ -1705,6 +1781,13 @@ babel-loader@^8.0.6:
 | 
			
		|||
    mkdirp "^0.5.1"
 | 
			
		||||
    pify "^4.0.1"
 | 
			
		||||
 | 
			
		||||
babel-plugin-dynamic-import-node@^2.3.0:
 | 
			
		||||
  version "2.3.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz#f00f507bdaa3c3e3ff6e7e5e98d90a7acab96f7f"
 | 
			
		||||
  integrity sha512-o6qFkpeQEBxcqt0XYlWzAVxNCSCZdUgcR8IRlhD/8DylxjjO4foPcvTW0GGKa/cVt3rvxZ7o5ippJ+/0nvLhlQ==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    object.assign "^4.1.0"
 | 
			
		||||
 | 
			
		||||
babel-plugin-emotion@^9.2.11:
 | 
			
		||||
  version "9.2.11"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/babel-plugin-emotion/-/babel-plugin-emotion-9.2.11.tgz#319c005a9ee1d15bb447f59fe504c35fd5807728"
 | 
			
		||||
| 
						 | 
				
			
			@ -1876,6 +1959,11 @@ binary-extensions@^1.0.0:
 | 
			
		|||
  resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.12.0.tgz#c2d780f53d45bba8317a8902d4ceeaf3a6385b14"
 | 
			
		||||
  integrity sha512-DYWGk01lDcxeS/K9IHPGWfT8PsJmbXRtRd2Sx72Tnb8pcYZQFF1oSDb8hJtS1vhp212q1Rzi5dUf9+nq0o9UIg==
 | 
			
		||||
 | 
			
		||||
binary-extensions@^2.0.0:
 | 
			
		||||
  version "2.0.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.0.0.tgz#23c0df14f6a88077f5f986c0d167ec03c3d5537c"
 | 
			
		||||
  integrity sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==
 | 
			
		||||
 | 
			
		||||
bluebird@^3.5.1, bluebird@^3.5.3:
 | 
			
		||||
  version "3.5.3"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.3.tgz#7d01c6f9616c9a51ab0f8c549a79dfe6ec33efa7"
 | 
			
		||||
| 
						 | 
				
			
			@ -1948,6 +2036,13 @@ braces@^2.3.1, braces@^2.3.2:
 | 
			
		|||
    split-string "^3.0.2"
 | 
			
		||||
    to-regex "^3.0.1"
 | 
			
		||||
 | 
			
		||||
braces@^3.0.2:
 | 
			
		||||
  version "3.0.2"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
 | 
			
		||||
  integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    fill-range "^7.0.1"
 | 
			
		||||
 | 
			
		||||
bricks.js@^1.7.0:
 | 
			
		||||
  version "1.8.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/bricks.js/-/bricks.js-1.8.0.tgz#8fdeb3c0226af251f4d5727a7df7f9ac0092b4b2"
 | 
			
		||||
| 
						 | 
				
			
			@ -2031,14 +2126,14 @@ browserify-zlib@^0.2.0:
 | 
			
		|||
  dependencies:
 | 
			
		||||
    pako "~1.0.5"
 | 
			
		||||
 | 
			
		||||
browserslist@^4.0.0, browserslist@^4.6.0, browserslist@^4.6.1:
 | 
			
		||||
  version "4.6.2"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.6.2.tgz#574c665950915c2ac73a4594b8537a9eba26203f"
 | 
			
		||||
  integrity sha512-2neU/V0giQy9h3XMPwLhEY3+Ao0uHSwHvU8Q1Ea6AgLVL1sXbX3dzPrJ8NWe5Hi4PoTkCYXOtVR9rfRLI0J/8Q==
 | 
			
		||||
browserslist@^4.0.0, browserslist@^4.6.0, browserslist@^4.6.3:
 | 
			
		||||
  version "4.6.6"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.6.6.tgz#6e4bf467cde520bc9dbdf3747dafa03531cec453"
 | 
			
		||||
  integrity sha512-D2Nk3W9JL9Fp/gIcWei8LrERCS+eXu9AM5cfXA8WEZ84lFks+ARnZ0q/R69m2SV3Wjma83QDDPxsNKXUwdIsyA==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    caniuse-lite "^1.0.30000974"
 | 
			
		||||
    electron-to-chromium "^1.3.150"
 | 
			
		||||
    node-releases "^1.1.23"
 | 
			
		||||
    caniuse-lite "^1.0.30000984"
 | 
			
		||||
    electron-to-chromium "^1.3.191"
 | 
			
		||||
    node-releases "^1.1.25"
 | 
			
		||||
 | 
			
		||||
bser@^2.0.0:
 | 
			
		||||
  version "2.0.0"
 | 
			
		||||
| 
						 | 
				
			
			@ -2182,10 +2277,10 @@ caniuse-api@^3.0.0:
 | 
			
		|||
    lodash.memoize "^4.1.2"
 | 
			
		||||
    lodash.uniq "^4.5.0"
 | 
			
		||||
 | 
			
		||||
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000971, caniuse-lite@^1.0.30000974:
 | 
			
		||||
  version "1.0.30000974"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000974.tgz#b7afe14ee004e97ce6dc73e3f878290a12928ad8"
 | 
			
		||||
  integrity sha512-xc3rkNS/Zc3CmpMKuczWEdY2sZgx09BkAxfvkxlAEBTqcMHeL8QnPqhKse+5sRTi3nrw2pJwToD2WvKn1Uhvww==
 | 
			
		||||
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000980, caniuse-lite@^1.0.30000984:
 | 
			
		||||
  version "1.0.30000986"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000986.tgz#f34350e367cc900509511574817ac092112bf7ab"
 | 
			
		||||
  integrity sha512-pM+LnkoAX0+QnIH3tpW5EnkmfpEoqOD8FAcoBvsl3Xh6DXkgctiCxeCbXphP/k3XJtJzm+zOAJbi6U6IVkpWZQ==
 | 
			
		||||
 | 
			
		||||
capture-exit@^1.2.0:
 | 
			
		||||
  version "1.2.0"
 | 
			
		||||
| 
						 | 
				
			
			@ -2241,7 +2336,22 @@ cheerio@^1.0.0-rc.2:
 | 
			
		|||
    lodash "^4.15.0"
 | 
			
		||||
    parse5 "^3.0.1"
 | 
			
		||||
 | 
			
		||||
chokidar@^2.0.0, chokidar@^2.0.2, chokidar@^2.1.6:
 | 
			
		||||
"chokidar@>=2.0.0 <4.0.0":
 | 
			
		||||
  version "3.0.2"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.0.2.tgz#0d1cd6d04eb2df0327446188cd13736a3367d681"
 | 
			
		||||
  integrity sha512-c4PR2egjNjI1um6bamCQ6bUNPDiyofNQruHvKgHQ4gDUP/ITSVSzNsiI5OWtHOsX323i5ha/kk4YmOZ1Ktg7KA==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    anymatch "^3.0.1"
 | 
			
		||||
    braces "^3.0.2"
 | 
			
		||||
    glob-parent "^5.0.0"
 | 
			
		||||
    is-binary-path "^2.1.0"
 | 
			
		||||
    is-glob "^4.0.1"
 | 
			
		||||
    normalize-path "^3.0.0"
 | 
			
		||||
    readdirp "^3.1.1"
 | 
			
		||||
  optionalDependencies:
 | 
			
		||||
    fsevents "^2.0.6"
 | 
			
		||||
 | 
			
		||||
chokidar@^2.0.2, chokidar@^2.1.6:
 | 
			
		||||
  version "2.1.6"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.6.tgz#b6cad653a929e244ce8a834244164d241fa954c5"
 | 
			
		||||
  integrity sha512-V2jUo67OKkc6ySiRpJrjlpJKl9kDuG+Xb8VgsGzb+aEouhgS1D0weyPU4lEzdAcsCAvrih2J2BqyXqHWvVLw5g==
 | 
			
		||||
| 
						 | 
				
			
			@ -3299,10 +3409,10 @@ ejs@^2.3.4, ejs@^2.6.1:
 | 
			
		|||
  resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.6.1.tgz#498ec0d495655abc6f23cd61868d926464071aa0"
 | 
			
		||||
  integrity sha512-0xy4A/twfrRCnkhfk8ErDi5DqdAsAqeGxht4xkCUrsvhhbQNs7E+4jV0CN7+NKIY0aHE72+XvqtBIXzD31ZbXQ==
 | 
			
		||||
 | 
			
		||||
electron-to-chromium@^1.3.150:
 | 
			
		||||
  version "1.3.163"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.163.tgz#7fc3d637f5d8fa4ca4a052cad0de7675bd98b911"
 | 
			
		||||
  integrity sha512-uCEoqQeKrjlhUSUudY0XvyNVDhWR5XmnCIV0WXr2Qo9PVzEVXI75LHGtzwro9Qh8NNetRjSitrm8AfQvPGaSqA==
 | 
			
		||||
electron-to-chromium@^1.3.191:
 | 
			
		||||
  version "1.3.203"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.203.tgz#76de1b76eaaf7208e587a26b8e45407535a00abd"
 | 
			
		||||
  integrity sha512-Z1FjJKEBhYrCNmnususVk8khiBabVI/bSJB/295V4ghVt4MFmtbP+mXgRZLQZinEBI469U6FtiGgpXnlLs6qiQ==
 | 
			
		||||
 | 
			
		||||
elliptic@^6.0.0:
 | 
			
		||||
  version "6.4.1"
 | 
			
		||||
| 
						 | 
				
			
			@ -4086,13 +4196,13 @@ file-entry-cache@^5.0.1:
 | 
			
		|||
  dependencies:
 | 
			
		||||
    flat-cache "^2.0.1"
 | 
			
		||||
 | 
			
		||||
file-loader@^4.0.0:
 | 
			
		||||
  version "4.0.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-4.0.0.tgz#c3570783fefb6e1bc0978a856f4bf5825b966c2a"
 | 
			
		||||
  integrity sha512-roAbL6IdSGczwfXxhMi6Zq+jD4IfUpL0jWHD7fvmjdOVb7xBfdRUHe4LpBgO23VtVK5AW1OlWZo0p34Jvx3iWg==
 | 
			
		||||
file-loader@^4.1.0:
 | 
			
		||||
  version "4.1.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-4.1.0.tgz#3a763391bc9502da7c59612fe348e38fc1980336"
 | 
			
		||||
  integrity sha512-ajDk1nlByoalZAGR4b0H6oD+EGlWnyW1qbSxzaUc7RFiqmn+RbXQQRbTc72jsiUIlVusJ4Et58ltds8ZwTfnAw==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    loader-utils "^1.2.2"
 | 
			
		||||
    schema-utils "^1.0.0"
 | 
			
		||||
    loader-utils "^1.2.3"
 | 
			
		||||
    schema-utils "^2.0.0"
 | 
			
		||||
 | 
			
		||||
filesize@^3.6.1:
 | 
			
		||||
  version "3.6.1"
 | 
			
		||||
| 
						 | 
				
			
			@ -4109,6 +4219,13 @@ fill-range@^4.0.0:
 | 
			
		|||
    repeat-string "^1.6.1"
 | 
			
		||||
    to-regex-range "^2.1.0"
 | 
			
		||||
 | 
			
		||||
fill-range@^7.0.1:
 | 
			
		||||
  version "7.0.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
 | 
			
		||||
  integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    to-regex-range "^5.0.1"
 | 
			
		||||
 | 
			
		||||
finalhandler@~1.1.2:
 | 
			
		||||
  version "1.1.2"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d"
 | 
			
		||||
| 
						 | 
				
			
			@ -4339,6 +4456,11 @@ fsevents@^1.2.7:
 | 
			
		|||
    nan "^2.12.1"
 | 
			
		||||
    node-pre-gyp "^0.12.0"
 | 
			
		||||
 | 
			
		||||
fsevents@^2.0.6:
 | 
			
		||||
  version "2.0.7"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.0.7.tgz#382c9b443c6cbac4c57187cdda23aa3bf1ccfc2a"
 | 
			
		||||
  integrity sha512-a7YT0SV3RB+DjYcppwVDLtn13UQnmg0SWZS7ezZD0UjnLwXmy8Zm21GMVGLaFGimIqcvyMQaOJBrop8MyOp1kQ==
 | 
			
		||||
 | 
			
		||||
function-bind@^1.0.2, function-bind@^1.1.1:
 | 
			
		||||
  version "1.1.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
 | 
			
		||||
| 
						 | 
				
			
			@ -5115,6 +5237,13 @@ is-binary-path@^1.0.0:
 | 
			
		|||
  dependencies:
 | 
			
		||||
    binary-extensions "^1.0.0"
 | 
			
		||||
 | 
			
		||||
is-binary-path@^2.1.0:
 | 
			
		||||
  version "2.1.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
 | 
			
		||||
  integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    binary-extensions "^2.0.0"
 | 
			
		||||
 | 
			
		||||
is-boolean-object@^1.0.0:
 | 
			
		||||
  version "1.0.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.0.0.tgz#98f8b28030684219a95f375cfbd88ce3405dff93"
 | 
			
		||||
| 
						 | 
				
			
			@ -5286,6 +5415,11 @@ is-number@^3.0.0:
 | 
			
		|||
  dependencies:
 | 
			
		||||
    kind-of "^3.0.2"
 | 
			
		||||
 | 
			
		||||
is-number@^7.0.0:
 | 
			
		||||
  version "7.0.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
 | 
			
		||||
  integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
 | 
			
		||||
 | 
			
		||||
is-obj@^1.0.0:
 | 
			
		||||
  version "1.0.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f"
 | 
			
		||||
| 
						 | 
				
			
			@ -6107,7 +6241,7 @@ loader-utils@0.2.x:
 | 
			
		|||
    json5 "^0.5.0"
 | 
			
		||||
    object-assign "^4.0.1"
 | 
			
		||||
 | 
			
		||||
loader-utils@1.2.3, loader-utils@^1.0.1, loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.2.2, loader-utils@^1.2.3:
 | 
			
		||||
loader-utils@1.2.3, loader-utils@^1.0.1, loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.2.3:
 | 
			
		||||
  version "1.2.3"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.2.3.tgz#1ff5dc6911c9f0a062531a4c04b609406108c2c7"
 | 
			
		||||
  integrity sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==
 | 
			
		||||
| 
						 | 
				
			
			@ -6209,7 +6343,7 @@ lodash.uniq@^4.5.0:
 | 
			
		|||
  resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
 | 
			
		||||
  integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
 | 
			
		||||
 | 
			
		||||
lodash@^4.0.0, lodash@^4.13.1, lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.14, lodash@^4.17.5, lodash@^4.3.0, lodash@~4.17.10:
 | 
			
		||||
lodash@^4.0.0, lodash@^4.13.1, lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.5, lodash@^4.3.0, lodash@~4.17.10:
 | 
			
		||||
  version "4.17.15"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
 | 
			
		||||
  integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
 | 
			
		||||
| 
						 | 
				
			
			@ -6718,10 +6852,10 @@ node-pre-gyp@^0.12.0:
 | 
			
		|||
    semver "^5.3.0"
 | 
			
		||||
    tar "^4"
 | 
			
		||||
 | 
			
		||||
node-releases@^1.1.23:
 | 
			
		||||
  version "1.1.23"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.23.tgz#de7409f72de044a2fa59c097f436ba89c39997f0"
 | 
			
		||||
  integrity sha512-uq1iL79YjfYC0WXoHbC/z28q/9pOl8kSHaXdWmAAc8No+bDwqkZbzIJz55g/MUsPgSGm9LZ7QSUbzTcH5tz47w==
 | 
			
		||||
node-releases@^1.1.25:
 | 
			
		||||
  version "1.1.26"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.26.tgz#f30563edc5c7dc20cf524cc8652ffa7be0762937"
 | 
			
		||||
  integrity sha512-fZPsuhhUHMTlfkhDLGtfY80DSJTjOcx+qD1j5pqPkuhUHVS7xHZIg9EE4DHK8O3f0zTxXHX5VIkDG8pu98/wfQ==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    semver "^5.3.0"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -7385,6 +7519,11 @@ pgpass@1.*:
 | 
			
		|||
  dependencies:
 | 
			
		||||
    split "^1.0.0"
 | 
			
		||||
 | 
			
		||||
picomatch@^2.0.4:
 | 
			
		||||
  version "2.0.7"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.0.7.tgz#514169d8c7cd0bdbeecc8a2609e34a7163de69f6"
 | 
			
		||||
  integrity sha512-oLHIdio3tZ0qH76NybpeneBhYVj0QFTfXEFTc/B3zKQspYfYYkWYgFsmzo+4kvId/bQRcNkVeguI3y+CD22BtA==
 | 
			
		||||
 | 
			
		||||
pify@^2.0.0:
 | 
			
		||||
  version "2.3.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
 | 
			
		||||
| 
						 | 
				
			
			@ -8463,6 +8602,13 @@ readdirp@^2.2.1:
 | 
			
		|||
    micromatch "^3.1.10"
 | 
			
		||||
    readable-stream "^2.0.2"
 | 
			
		||||
 | 
			
		||||
readdirp@^3.1.1:
 | 
			
		||||
  version "3.1.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.1.1.tgz#b158123ac343c8b0f31d65680269cc0fc1025db1"
 | 
			
		||||
  integrity sha512-XXdSXZrQuvqoETj50+JAitxz1UPdt5dupjT6T5nVB+WvjMv2XKYj+s7hPeAVCXvmJrL36O4YYyWlIC3an2ePiQ==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    picomatch "^2.0.4"
 | 
			
		||||
 | 
			
		||||
readline2@^1.0.1:
 | 
			
		||||
  version "1.0.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35"
 | 
			
		||||
| 
						 | 
				
			
			@ -8920,12 +9066,12 @@ sass-loader@^7.0.3:
 | 
			
		|||
    pify "^3.0.0"
 | 
			
		||||
    semver "^5.5.0"
 | 
			
		||||
 | 
			
		||||
sass@^1.20.3:
 | 
			
		||||
  version "1.20.3"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/sass/-/sass-1.20.3.tgz#18284a7bac6eab9cbb80453288473194f29efb84"
 | 
			
		||||
  integrity sha512-kvf+w5XT7FrmFrCKz1gPHqegufG+gxifC8oQesX/s8gkShdeiTqiuvP0c8TvfBwMAuI1YGOgobZQ2KIJGn//jA==
 | 
			
		||||
sass@^1.22.7:
 | 
			
		||||
  version "1.22.7"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/sass/-/sass-1.22.7.tgz#5a1a77dc11aa659db4e782d238bf9f3d44a60546"
 | 
			
		||||
  integrity sha512-ahREi0AdG7RTovSv14+yd1prQSfIvFcrDpOsth5EQf1+RM7SvOxsSttzNQaFmK1aa/k/3vyYwlYF5l0Xl+6c+g==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    chokidar "^2.0.0"
 | 
			
		||||
    chokidar ">=2.0.0 <4.0.0"
 | 
			
		||||
 | 
			
		||||
sax@^1.2.4, sax@~1.2.4:
 | 
			
		||||
  version "1.2.4"
 | 
			
		||||
| 
						 | 
				
			
			@ -9782,6 +9928,13 @@ to-regex-range@^2.1.0:
 | 
			
		|||
    is-number "^3.0.0"
 | 
			
		||||
    repeat-string "^1.6.1"
 | 
			
		||||
 | 
			
		||||
to-regex-range@^5.0.1:
 | 
			
		||||
  version "5.0.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
 | 
			
		||||
  integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    is-number "^7.0.0"
 | 
			
		||||
 | 
			
		||||
to-regex@^3.0.1, to-regex@^3.0.2:
 | 
			
		||||
  version "3.0.2"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce"
 | 
			
		||||
| 
						 | 
				
			
			@ -10478,7 +10631,7 @@ yargs-parser@^11.1.1:
 | 
			
		|||
    camelcase "^5.0.0"
 | 
			
		||||
    decamelize "^1.2.0"
 | 
			
		||||
 | 
			
		||||
yargs-parser@^13.1.0:
 | 
			
		||||
yargs-parser@^13.1.0, yargs-parser@^13.1.1:
 | 
			
		||||
  version "13.1.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.1.tgz#d26058532aa06d365fe091f6a1fc06b2f7e5eca0"
 | 
			
		||||
  integrity sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==
 | 
			
		||||
| 
						 | 
				
			
			@ -10486,7 +10639,7 @@ yargs-parser@^13.1.0:
 | 
			
		|||
    camelcase "^5.0.0"
 | 
			
		||||
    decamelize "^1.2.0"
 | 
			
		||||
 | 
			
		||||
yargs@12.0.5, yargs@^12.0.2, yargs@^12.0.5:
 | 
			
		||||
yargs@12.0.5, yargs@^12.0.2:
 | 
			
		||||
  version "12.0.5"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.5.tgz#05f5997b609647b64f66b81e3b4b10a368e7ad13"
 | 
			
		||||
  integrity sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==
 | 
			
		||||
| 
						 | 
				
			
			@ -10520,3 +10673,19 @@ yargs@13.2.4:
 | 
			
		|||
    which-module "^2.0.0"
 | 
			
		||||
    y18n "^4.0.0"
 | 
			
		||||
    yargs-parser "^13.1.0"
 | 
			
		||||
 | 
			
		||||
yargs@^13.3.0:
 | 
			
		||||
  version "13.3.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.0.tgz#4c657a55e07e5f2cf947f8a366567c04a0dedc83"
 | 
			
		||||
  integrity sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    cliui "^5.0.0"
 | 
			
		||||
    find-up "^3.0.0"
 | 
			
		||||
    get-caller-file "^2.0.1"
 | 
			
		||||
    require-directory "^2.1.1"
 | 
			
		||||
    require-main-filename "^2.0.0"
 | 
			
		||||
    set-blocking "^2.0.0"
 | 
			
		||||
    string-width "^3.0.0"
 | 
			
		||||
    which-module "^2.0.0"
 | 
			
		||||
    y18n "^4.0.0"
 | 
			
		||||
    yargs-parser "^13.1.1"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue