mirror of
https://github.com/mastodon/mastodon.git
synced 2024-12-12 06:06:22 +01:00
Merge branch 'main' into glitch-soc/merge-upstream
This commit is contained in:
commit
4e2a8c9b38
8
Gemfile
8
Gemfile
@ -17,7 +17,7 @@ gem 'makara', '~> 0.5'
|
||||
gem 'pghero', '~> 2.8'
|
||||
gem 'dotenv-rails', '~> 2.7'
|
||||
|
||||
gem 'aws-sdk-s3', '~> 1.98', require: false
|
||||
gem 'aws-sdk-s3', '~> 1.99', require: false
|
||||
gem 'fog-core', '<= 2.1.0'
|
||||
gem 'fog-openstack', '~> 0.3', require: false
|
||||
gem 'paperclip', '~> 6.0'
|
||||
@ -62,7 +62,7 @@ gem 'link_header', '~> 0.0'
|
||||
gem 'mime-types', '~> 3.3.1', require: 'mime/types/columnar'
|
||||
gem 'nokogiri', '~> 1.12'
|
||||
gem 'nsa', '~> 0.2'
|
||||
gem 'oj', '~> 3.12'
|
||||
gem 'oj', '~> 3.13'
|
||||
gem 'ox', '~> 2.14'
|
||||
gem 'parslet'
|
||||
gem 'parallel', '~> 1.20'
|
||||
@ -122,7 +122,7 @@ group :test do
|
||||
gem 'rails-controller-testing', '~> 1.0'
|
||||
gem 'rspec-sidekiq', '~> 3.1'
|
||||
gem 'simplecov', '~> 0.21', require: false
|
||||
gem 'webmock', '~> 3.13'
|
||||
gem 'webmock', '~> 3.14'
|
||||
gem 'parallel_tests', '~> 3.7'
|
||||
gem 'rspec_junit_formatter', '~> 0.4'
|
||||
end
|
||||
@ -136,7 +136,7 @@ group :development do
|
||||
gem 'letter_opener', '~> 1.7'
|
||||
gem 'letter_opener_web', '~> 1.4'
|
||||
gem 'memory_profiler'
|
||||
gem 'rubocop', '~> 1.18', require: false
|
||||
gem 'rubocop', '~> 1.19', require: false
|
||||
gem 'rubocop-rails', '~> 2.11', require: false
|
||||
gem 'brakeman', '~> 5.1', require: false
|
||||
gem 'bundler-audit', '~> 0.8', require: false
|
||||
|
46
Gemfile.lock
46
Gemfile.lock
@ -79,7 +79,7 @@ GEM
|
||||
encryptor (~> 3.0.0)
|
||||
awrence (1.1.1)
|
||||
aws-eventstream (1.1.1)
|
||||
aws-partitions (1.482.0)
|
||||
aws-partitions (1.488.0)
|
||||
aws-sdk-core (3.119.0)
|
||||
aws-eventstream (~> 1, >= 1.0.2)
|
||||
aws-partitions (~> 1, >= 1.239.0)
|
||||
@ -88,7 +88,7 @@ GEM
|
||||
aws-sdk-kms (1.46.0)
|
||||
aws-sdk-core (~> 3, >= 3.119.0)
|
||||
aws-sigv4 (~> 1.1)
|
||||
aws-sdk-s3 (1.98.0)
|
||||
aws-sdk-s3 (1.99.0)
|
||||
aws-sdk-core (~> 3, >= 3.119.0)
|
||||
aws-sdk-kms (~> 1)
|
||||
aws-sigv4 (~> 1.1)
|
||||
@ -112,7 +112,7 @@ GEM
|
||||
concurrent-ruby (~> 1.0, >= 1.0.5)
|
||||
redis (>= 1.0, <= 5.0)
|
||||
builder (3.2.4)
|
||||
bullet (6.1.4)
|
||||
bullet (6.1.5)
|
||||
activesupport (>= 3.0.0)
|
||||
uniform_notifier (~> 1.11)
|
||||
bundler-audit (0.8.0)
|
||||
@ -218,8 +218,8 @@ GEM
|
||||
multipart-post (>= 1.2, < 3)
|
||||
ruby2_keywords
|
||||
faraday-net_http (1.0.1)
|
||||
fast_blank (1.0.0)
|
||||
fastimage (2.2.4)
|
||||
fast_blank (1.0.1)
|
||||
fastimage (2.2.5)
|
||||
ffi (1.15.0)
|
||||
ffi-compiler (1.0.1)
|
||||
ffi (>= 1.0.0)
|
||||
@ -332,7 +332,7 @@ GEM
|
||||
activesupport (>= 4)
|
||||
railties (>= 4)
|
||||
request_store (~> 1.0)
|
||||
loofah (2.10.0)
|
||||
loofah (2.12.0)
|
||||
crass (~> 1.0.2)
|
||||
nokogiri (>= 1.5.9)
|
||||
mail (2.7.1)
|
||||
@ -364,7 +364,7 @@ GEM
|
||||
net-ssh (>= 2.6.5, < 7.0.0)
|
||||
net-ssh (6.1.0)
|
||||
nio4r (2.5.7)
|
||||
nokogiri (1.12.2)
|
||||
nokogiri (1.12.3)
|
||||
mini_portile2 (~> 2.6.1)
|
||||
racc (~> 1.4)
|
||||
nsa (0.2.8)
|
||||
@ -372,7 +372,7 @@ GEM
|
||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||
sidekiq (>= 3.5)
|
||||
statsd-ruby (~> 1.4, >= 1.4.0)
|
||||
oj (3.12.2)
|
||||
oj (3.13.2)
|
||||
omniauth (1.9.1)
|
||||
hashie (>= 3.4.6)
|
||||
rack (>= 1.6.2, < 3)
|
||||
@ -397,7 +397,7 @@ GEM
|
||||
mimemagic (~> 0.3.0)
|
||||
terrapin (~> 0.6.0)
|
||||
parallel (1.20.1)
|
||||
parallel_tests (3.7.0)
|
||||
parallel_tests (3.7.1)
|
||||
parallel
|
||||
parser (3.0.2.0)
|
||||
ast (~> 2.4.1)
|
||||
@ -428,7 +428,7 @@ GEM
|
||||
public_suffix (4.0.6)
|
||||
puma (5.4.0)
|
||||
nio4r (~> 2.0)
|
||||
pundit (2.1.0)
|
||||
pundit (2.1.1)
|
||||
activesupport (>= 3.0.0)
|
||||
raabro (1.4.0)
|
||||
racc (1.5.2)
|
||||
@ -477,7 +477,7 @@ GEM
|
||||
rake (>= 0.13)
|
||||
thor (~> 1.0)
|
||||
rainbow (3.0.0)
|
||||
rake (13.0.3)
|
||||
rake (13.0.6)
|
||||
rdf (3.1.15)
|
||||
hamster (~> 3.0)
|
||||
link_header (~> 0.0, >= 0.0.8)
|
||||
@ -508,7 +508,7 @@ GEM
|
||||
rspec-mocks (3.10.2)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.10.0)
|
||||
rspec-rails (5.0.1)
|
||||
rspec-rails (5.0.2)
|
||||
actionpack (>= 5.2)
|
||||
activesupport (>= 5.2)
|
||||
railties (>= 5.2)
|
||||
@ -522,16 +522,16 @@ GEM
|
||||
rspec-support (3.10.2)
|
||||
rspec_junit_formatter (0.4.1)
|
||||
rspec-core (>= 2, < 4, != 2.12.0)
|
||||
rubocop (1.18.4)
|
||||
rubocop (1.19.0)
|
||||
parallel (~> 1.10)
|
||||
parser (>= 3.0.0.0)
|
||||
rainbow (>= 2.2.2, < 4.0)
|
||||
regexp_parser (>= 1.8, < 3.0)
|
||||
rexml
|
||||
rubocop-ast (>= 1.8.0, < 2.0)
|
||||
rubocop-ast (>= 1.9.1, < 2.0)
|
||||
ruby-progressbar (~> 1.7)
|
||||
unicode-display_width (>= 1.4.0, < 3.0)
|
||||
rubocop-ast (1.8.0)
|
||||
rubocop-ast (1.10.0)
|
||||
parser (>= 3.0.1.1)
|
||||
rubocop-rails (2.11.3)
|
||||
activesupport (>= 4.2.0)
|
||||
@ -595,7 +595,7 @@ GEM
|
||||
stackprof (0.2.17)
|
||||
statsd-ruby (1.5.0)
|
||||
stoplight (2.2.1)
|
||||
strong_migrations (0.7.7)
|
||||
strong_migrations (0.7.8)
|
||||
activerecord (>= 5)
|
||||
temple (0.8.2)
|
||||
terminal-table (3.0.0)
|
||||
@ -630,7 +630,7 @@ GEM
|
||||
unf_ext
|
||||
unf_ext (0.0.7.7)
|
||||
unicode-display_width (1.7.0)
|
||||
uniform_notifier (1.14.1)
|
||||
uniform_notifier (1.14.2)
|
||||
warden (1.2.9)
|
||||
rack (>= 2.0.9)
|
||||
webauthn (3.0.0.alpha1)
|
||||
@ -643,8 +643,8 @@ GEM
|
||||
safety_net_attestation (~> 0.4.0)
|
||||
securecompare (~> 1.0)
|
||||
tpm-key_attestation (~> 0.9.0)
|
||||
webmock (3.13.0)
|
||||
addressable (>= 2.3.6)
|
||||
webmock (3.14.0)
|
||||
addressable (>= 2.8.0)
|
||||
crack (>= 0.3.2)
|
||||
hashdiff (>= 0.4.0, < 2.0.0)
|
||||
webpacker (5.4.0)
|
||||
@ -672,7 +672,7 @@ DEPENDENCIES
|
||||
active_record_query_trace (~> 1.8)
|
||||
addressable (~> 2.8)
|
||||
annotate (~> 3.1)
|
||||
aws-sdk-s3 (~> 1.98)
|
||||
aws-sdk-s3 (~> 1.99)
|
||||
better_errors (~> 2.9)
|
||||
binding_of_caller (~> 1.0)
|
||||
blurhash (~> 0.1)
|
||||
@ -731,7 +731,7 @@ DEPENDENCIES
|
||||
net-ldap (~> 0.17)
|
||||
nokogiri (~> 1.12)
|
||||
nsa (~> 0.2)
|
||||
oj (~> 3.12)
|
||||
oj (~> 3.13)
|
||||
omniauth (~> 1.9)
|
||||
omniauth-cas (~> 2.0)
|
||||
omniauth-rails_csrf_protection (~> 0.1)
|
||||
@ -766,7 +766,7 @@ DEPENDENCIES
|
||||
rspec-rails (~> 5.0)
|
||||
rspec-sidekiq (~> 3.1)
|
||||
rspec_junit_formatter (~> 0.4)
|
||||
rubocop (~> 1.18)
|
||||
rubocop (~> 1.19)
|
||||
rubocop-rails (~> 2.11)
|
||||
ruby-progressbar (~> 1.11)
|
||||
sanitize (~> 6.0)
|
||||
@ -788,7 +788,7 @@ DEPENDENCIES
|
||||
twitter-text (~> 3.1.0)
|
||||
tzinfo-data (~> 1.2021)
|
||||
webauthn (~> 3.0.0.alpha1)
|
||||
webmock (~> 3.13)
|
||||
webmock (~> 3.14)
|
||||
webpacker (~> 5.4)
|
||||
webpush (~> 0.3)
|
||||
xorcist (~> 1.1)
|
||||
|
@ -2,6 +2,8 @@ import React from 'react';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import PropTypes from 'prop-types';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import classNames from 'classnames';
|
||||
import Icon from 'mastodon/components/icon';
|
||||
|
||||
const filename = url => url.split('/').pop().split('#')[0].split('?')[0];
|
||||
@ -16,29 +18,13 @@ export default class AttachmentList extends ImmutablePureComponent {
|
||||
render () {
|
||||
const { media, compact } = this.props;
|
||||
|
||||
if (compact) {
|
||||
return (
|
||||
<div className='attachment-list compact'>
|
||||
<ul className='attachment-list__list'>
|
||||
{media.map(attachment => {
|
||||
const displayUrl = attachment.get('remote_url') || attachment.get('url');
|
||||
|
||||
return (
|
||||
<li key={attachment.get('id')}>
|
||||
<a href={displayUrl} target='_blank' rel='noopener noreferrer'><Icon id='link' /> {filename(displayUrl)}</a>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='attachment-list'>
|
||||
<div className='attachment-list__icon'>
|
||||
<Icon id='link' />
|
||||
</div>
|
||||
<div className={classNames('attachment-list', { compact })}>
|
||||
{!compact && (
|
||||
<div className='attachment-list__icon'>
|
||||
<Icon id='link' />
|
||||
</div>
|
||||
)}
|
||||
|
||||
<ul className='attachment-list__list'>
|
||||
{media.map(attachment => {
|
||||
@ -46,7 +32,11 @@ export default class AttachmentList extends ImmutablePureComponent {
|
||||
|
||||
return (
|
||||
<li key={attachment.get('id')}>
|
||||
<a href={displayUrl} target='_blank' rel='noopener noreferrer'>{filename(displayUrl)}</a>
|
||||
<a href={displayUrl} target='_blank' rel='noopener noreferrer'>
|
||||
{compact && <Icon id='link' />}
|
||||
{compact && ' ' }
|
||||
{displayUrl ? filename(displayUrl) : <FormattedMessage id='attachments_list.unprocessed' defaultMessage='(unprocessed)' />}
|
||||
</a>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
|
@ -5542,7 +5542,8 @@ a.status-card.compact:hover {
|
||||
opacity: 0.2;
|
||||
}
|
||||
|
||||
.video-player__buttons button {
|
||||
.video-player__buttons button,
|
||||
.video-player__buttons a {
|
||||
color: currentColor;
|
||||
opacity: 0.75;
|
||||
|
||||
|
@ -58,8 +58,9 @@ class Account < ApplicationRecord
|
||||
hub_url
|
||||
)
|
||||
|
||||
USERNAME_RE = /[a-z0-9_]+([a-z0-9_\.-]+[a-z0-9_]+)?/i
|
||||
MENTION_RE = /(?<=^|[^\/[:word:]])@((#{USERNAME_RE})(?:@[[:word:]\.\-]+[a-z0-9]+)?)/i
|
||||
USERNAME_RE = /[a-z0-9_]+([a-z0-9_\.-]+[a-z0-9_]+)?/i
|
||||
MENTION_RE = /(?<=^|[^\/[:word:]])@((#{USERNAME_RE})(?:@[[:word:]\.\-]+[a-z0-9]+)?)/i
|
||||
URL_PREFIX_RE = /\Ahttp(s?):\/\/[^\/]+/
|
||||
|
||||
include AccountAssociations
|
||||
include AccountAvatar
|
||||
@ -381,7 +382,7 @@ class Account < ApplicationRecord
|
||||
def synchronization_uri_prefix
|
||||
return 'local' if local?
|
||||
|
||||
@synchronization_uri_prefix ||= uri[/http(s?):\/\/[^\/]+\//]
|
||||
@synchronization_uri_prefix ||= "#{uri[URL_PREFIX_RE]}/"
|
||||
end
|
||||
|
||||
class Field < ActiveModelSerializers::Model
|
||||
|
@ -254,10 +254,13 @@ module AccountInteractions
|
||||
.where('users.current_sign_in_at > ?', User::ACTIVE_DURATION.ago)
|
||||
end
|
||||
|
||||
def remote_followers_hash(url_prefix)
|
||||
Rails.cache.fetch("followers_hash:#{id}:#{url_prefix}") do
|
||||
def remote_followers_hash(url)
|
||||
url_prefix = url[Account::URL_PREFIX_RE]
|
||||
return if url_prefix.blank?
|
||||
|
||||
Rails.cache.fetch("followers_hash:#{id}:#{url_prefix}/") do
|
||||
digest = "\x00" * 32
|
||||
followers.where(Account.arel_table[:uri].matches(url_prefix + '%', false, true)).pluck_each(:uri) do |uri|
|
||||
followers.where(Account.arel_table[:uri].matches("#{Account.sanitize_sql_like(url_prefix)}/%", false, true)).or(followers.where(uri: url_prefix)).pluck_each(:uri) do |uri|
|
||||
Xorcist.xor!(digest, Digest::SHA256.digest(uri))
|
||||
end
|
||||
digest.unpack('H*')[0]
|
||||
|
@ -142,6 +142,7 @@ class ResolveAccountService < BaseService
|
||||
end
|
||||
|
||||
def queue_deletion!
|
||||
@account.suspend!(origin: :remote)
|
||||
AccountDeletionWorker.perform_async(@account.id, reserve_username: false, skip_activitypub: true)
|
||||
end
|
||||
|
||||
|
@ -1,13 +1,14 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class UnsuspendAccountService < BaseService
|
||||
include Payloadable
|
||||
def call(account)
|
||||
@account = account
|
||||
|
||||
unsuspend!
|
||||
refresh_remote_account!
|
||||
|
||||
return if @account.nil?
|
||||
return if @account.nil? || @account.suspended?
|
||||
|
||||
merge_into_home_timelines!
|
||||
merge_into_list_timelines!
|
||||
|
@ -44,11 +44,7 @@ class ActivityPub::DeliveryWorker
|
||||
end
|
||||
|
||||
def synchronization_header
|
||||
"collectionId=\"#{account_followers_url(@source_account)}\", digest=\"#{@source_account.remote_followers_hash(inbox_url_prefix)}\", url=\"#{account_followers_synchronization_url(@source_account)}\""
|
||||
end
|
||||
|
||||
def inbox_url_prefix
|
||||
@inbox_url[/http(s?):\/\/[^\/]+\//]
|
||||
"collectionId=\"#{account_followers_url(@source_account)}\", digest=\"#{@source_account.remote_followers_hash(@inbox_url)}\", url=\"#{account_followers_synchronization_url(@source_account)}\""
|
||||
end
|
||||
|
||||
def perform_request
|
||||
|
9
dist/nginx.conf
vendored
9
dist/nginx.conf
vendored
@ -31,6 +31,7 @@ server {
|
||||
ssl_ciphers HIGH:!MEDIUM:!LOW:!aNULL:!NULL:!SHA;
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_session_cache shared:SSL:10m;
|
||||
ssl_session_tickets off;
|
||||
|
||||
# Uncomment these lines once you acquire a certificate:
|
||||
# ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
|
||||
@ -51,7 +52,7 @@ server {
|
||||
gzip_http_version 1.1;
|
||||
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
|
||||
|
||||
add_header Strict-Transport-Security "max-age=31536000";
|
||||
add_header Strict-Transport-Security "max-age=31536000" always;
|
||||
|
||||
location / {
|
||||
try_files $uri @proxy;
|
||||
@ -59,13 +60,13 @@ server {
|
||||
|
||||
location ~ ^/(emoji|packs|system/accounts/avatars|system/media_attachments/files) {
|
||||
add_header Cache-Control "public, max-age=31536000, immutable";
|
||||
add_header Strict-Transport-Security "max-age=31536000";
|
||||
add_header Strict-Transport-Security "max-age=31536000" always;
|
||||
try_files $uri @proxy;
|
||||
}
|
||||
|
||||
location /sw.js {
|
||||
add_header Cache-Control "public, max-age=0";
|
||||
add_header Strict-Transport-Security "max-age=31536000";
|
||||
add_header Strict-Transport-Security "max-age=31536000" always;
|
||||
try_files $uri @proxy;
|
||||
}
|
||||
|
||||
@ -89,7 +90,7 @@ server {
|
||||
proxy_cache_valid 410 24h;
|
||||
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
|
||||
add_header X-Cached $upstream_cache_status;
|
||||
add_header Strict-Transport-Security "max-age=31536000";
|
||||
add_header Strict-Transport-Security "max-age=31536000" always;
|
||||
|
||||
tcp_nodelay on;
|
||||
}
|
||||
|
18
package.json
18
package.json
@ -60,13 +60,13 @@
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.14.8",
|
||||
"@babel/core": "^7.15.0",
|
||||
"@babel/plugin-proposal-decorators": "^7.14.5",
|
||||
"@babel/plugin-transform-react-inline-elements": "^7.14.5",
|
||||
"@babel/plugin-transform-runtime": "^7.14.5",
|
||||
"@babel/preset-env": "^7.15.0",
|
||||
"@babel/preset-react": "^7.14.5",
|
||||
"@babel/runtime": "^7.14.8",
|
||||
"@babel/runtime": "^7.15.3",
|
||||
"@gamestdio/websocket": "^0.3.2",
|
||||
"@github/webauthn-json": "^0.5.7",
|
||||
"@rails/ujs": "^6.1.4",
|
||||
@ -81,7 +81,7 @@
|
||||
"babel-plugin-react-intl": "^6.2.0",
|
||||
"babel-plugin-transform-react-remove-prop-types": "^0.4.24",
|
||||
"babel-runtime": "^6.26.0",
|
||||
"blurhash": "^1.1.3",
|
||||
"blurhash": "^1.1.4",
|
||||
"classnames": "^2.3.1",
|
||||
"color-blend": "^3.0.1",
|
||||
"compression-webpack-plugin": "^6.1.1",
|
||||
@ -146,7 +146,7 @@
|
||||
"react-textarea-autosize": "^8.3.3",
|
||||
"react-toggle": "^4.1.2",
|
||||
"redis": "^3.1.2",
|
||||
"redux": "^4.1.0",
|
||||
"redux": "^4.1.1",
|
||||
"redux-immutable": "^4.0.0",
|
||||
"redux-thunk": "^2.2.0",
|
||||
"regenerator-runtime": "^0.13.9",
|
||||
@ -154,7 +154,7 @@
|
||||
"requestidlecallback": "^0.3.0",
|
||||
"reselect": "^4.0.0",
|
||||
"rimraf": "^3.0.2",
|
||||
"sass": "^1.37.0",
|
||||
"sass": "^1.38.0",
|
||||
"sass-loader": "^10.2.0",
|
||||
"stacktrace-js": "^2.0.2",
|
||||
"stringz": "^2.1.0",
|
||||
@ -171,15 +171,15 @@
|
||||
"webpack-cli": "^3.3.12",
|
||||
"webpack-merge": "^5.8.0",
|
||||
"wicg-inert": "^3.1.1",
|
||||
"ws": "^8.0.0"
|
||||
"ws": "^8.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@testing-library/jest-dom": "^5.14.1",
|
||||
"@testing-library/react": "^11.2.7",
|
||||
"@testing-library/react": "^12.0.0",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"babel-jest": "^27.0.6",
|
||||
"eslint": "^7.32.0",
|
||||
"eslint-plugin-import": "~2.23.4",
|
||||
"eslint-plugin-import": "~2.24.0",
|
||||
"eslint-plugin-jsx-a11y": "~6.4.1",
|
||||
"eslint-plugin-promise": "~5.1.0",
|
||||
"eslint-plugin-react": "~7.24.0",
|
||||
@ -189,7 +189,7 @@
|
||||
"react-test-renderer": "^16.14.0",
|
||||
"sass-lint": "^1.13.1",
|
||||
"webpack-dev-server": "^3.11.2",
|
||||
"yargs": "^17.0.1"
|
||||
"yargs": "^17.1.1"
|
||||
},
|
||||
"resolutions": {
|
||||
"kind-of": "^6.0.3"
|
||||
|
@ -546,46 +546,57 @@ describe AccountInteractions do
|
||||
end
|
||||
end
|
||||
|
||||
describe '#followers_hash' do
|
||||
describe '#remote_followers_hash' do
|
||||
let(:me) { Fabricate(:account, username: 'Me') }
|
||||
let(:remote_1) { Fabricate(:account, username: 'alice', domain: 'example.org', uri: 'https://example.org/users/alice') }
|
||||
let(:remote_2) { Fabricate(:account, username: 'bob', domain: 'example.org', uri: 'https://example.org/users/bob') }
|
||||
let(:remote_3) { Fabricate(:account, username: 'eve', domain: 'foo.org', uri: 'https://foo.org/users/eve') }
|
||||
let(:remote_3) { Fabricate(:account, username: 'instance-actor', domain: 'example.org', uri: 'https://example.org') }
|
||||
let(:remote_4) { Fabricate(:account, username: 'eve', domain: 'foo.org', uri: 'https://foo.org/users/eve') }
|
||||
|
||||
before do
|
||||
remote_1.follow!(me)
|
||||
remote_2.follow!(me)
|
||||
remote_3.follow!(me)
|
||||
remote_4.follow!(me)
|
||||
me.follow!(remote_1)
|
||||
end
|
||||
|
||||
context 'on a local user' do
|
||||
it 'returns correct hash for remote domains' do
|
||||
expect(me.remote_followers_hash('https://example.org/')).to eq '707962e297b7bd94468a21bc8e506a1bcea607a9142cd64e27c9b106b2a5f6ec'
|
||||
expect(me.remote_followers_hash('https://foo.org/')).to eq 'ccb9c18a67134cfff9d62c7f7e7eb88e6b803446c244b84265565f4eba29df0e'
|
||||
end
|
||||
|
||||
it 'invalidates cache as needed when removing or adding followers' do
|
||||
expect(me.remote_followers_hash('https://example.org/')).to eq '707962e297b7bd94468a21bc8e506a1bcea607a9142cd64e27c9b106b2a5f6ec'
|
||||
remote_1.unfollow!(me)
|
||||
expect(me.remote_followers_hash('https://example.org/')).to eq '241b00794ce9b46aa864f3220afadef128318da2659782985bac5ed5bd436bff'
|
||||
remote_1.follow!(me)
|
||||
expect(me.remote_followers_hash('https://example.org/')).to eq '707962e297b7bd94468a21bc8e506a1bcea607a9142cd64e27c9b106b2a5f6ec'
|
||||
end
|
||||
it 'returns correct hash for remote domains' do
|
||||
expect(me.remote_followers_hash('https://example.org/')).to eq '20aecbe774b3d61c25094370baf370012b9271c5b172ecedb05caff8d79ef0c7'
|
||||
expect(me.remote_followers_hash('https://foo.org/')).to eq 'ccb9c18a67134cfff9d62c7f7e7eb88e6b803446c244b84265565f4eba29df0e'
|
||||
expect(me.remote_followers_hash('https://foo.org.evil.com/')).to eq '0000000000000000000000000000000000000000000000000000000000000000'
|
||||
expect(me.remote_followers_hash('https://foo')).to eq '0000000000000000000000000000000000000000000000000000000000000000'
|
||||
end
|
||||
|
||||
context 'on a remote user' do
|
||||
it 'returns correct hash for remote domains' do
|
||||
expect(remote_1.local_followers_hash).to eq Digest::SHA256.hexdigest(ActivityPub::TagManager.instance.uri_for(me))
|
||||
end
|
||||
it 'invalidates cache as needed when removing or adding followers' do
|
||||
expect(me.remote_followers_hash('https://example.org/')).to eq '20aecbe774b3d61c25094370baf370012b9271c5b172ecedb05caff8d79ef0c7'
|
||||
remote_3.unfollow!(me)
|
||||
expect(me.remote_followers_hash('https://example.org/')).to eq '707962e297b7bd94468a21bc8e506a1bcea607a9142cd64e27c9b106b2a5f6ec'
|
||||
remote_1.unfollow!(me)
|
||||
expect(me.remote_followers_hash('https://example.org/')).to eq '241b00794ce9b46aa864f3220afadef128318da2659782985bac5ed5bd436bff'
|
||||
remote_1.follow!(me)
|
||||
expect(me.remote_followers_hash('https://example.org/')).to eq '707962e297b7bd94468a21bc8e506a1bcea607a9142cd64e27c9b106b2a5f6ec'
|
||||
end
|
||||
end
|
||||
|
||||
it 'invalidates cache as needed when removing or adding followers' do
|
||||
expect(remote_1.local_followers_hash).to eq Digest::SHA256.hexdigest(ActivityPub::TagManager.instance.uri_for(me))
|
||||
me.unfollow!(remote_1)
|
||||
expect(remote_1.local_followers_hash).to eq '0000000000000000000000000000000000000000000000000000000000000000'
|
||||
me.follow!(remote_1)
|
||||
expect(remote_1.local_followers_hash).to eq Digest::SHA256.hexdigest(ActivityPub::TagManager.instance.uri_for(me))
|
||||
end
|
||||
describe '#local_followers_hash' do
|
||||
let(:me) { Fabricate(:account, username: 'Me') }
|
||||
let(:remote_1) { Fabricate(:account, username: 'alice', domain: 'example.org', uri: 'https://example.org/users/alice') }
|
||||
|
||||
before do
|
||||
me.follow!(remote_1)
|
||||
end
|
||||
|
||||
it 'returns correct hash for local users' do
|
||||
expect(remote_1.local_followers_hash).to eq Digest::SHA256.hexdigest(ActivityPub::TagManager.instance.uri_for(me))
|
||||
end
|
||||
|
||||
it 'invalidates cache as needed when removing or adding followers' do
|
||||
expect(remote_1.local_followers_hash).to eq Digest::SHA256.hexdigest(ActivityPub::TagManager.instance.uri_for(me))
|
||||
me.unfollow!(remote_1)
|
||||
expect(remote_1.local_followers_hash).to eq '0000000000000000000000000000000000000000000000000000000000000000'
|
||||
me.follow!(remote_1)
|
||||
expect(remote_1.local_followers_hash).to eq Digest::SHA256.hexdigest(ActivityPub::TagManager.instance.uri_for(me))
|
||||
end
|
||||
end
|
||||
|
||||
|
85
spec/services/suspend_account_service_spec.rb
Normal file
85
spec/services/suspend_account_service_spec.rb
Normal file
@ -0,0 +1,85 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe SuspendAccountService, type: :service do
|
||||
shared_examples 'common behavior' do
|
||||
let!(:local_follower) { Fabricate(:user, current_sign_in_at: 1.hour.ago).account }
|
||||
let!(:list) { Fabricate(:list, account: local_follower) }
|
||||
|
||||
subject do
|
||||
-> { described_class.new.call(account) }
|
||||
end
|
||||
|
||||
before do
|
||||
allow(FeedManager.instance).to receive(:unmerge_from_home).and_return(nil)
|
||||
allow(FeedManager.instance).to receive(:unmerge_from_list).and_return(nil)
|
||||
|
||||
local_follower.follow!(account)
|
||||
list.accounts << account
|
||||
end
|
||||
|
||||
it "unmerges from local followers' feeds" do
|
||||
subject.call
|
||||
expect(FeedManager.instance).to have_received(:unmerge_from_home).with(account, local_follower)
|
||||
expect(FeedManager.instance).to have_received(:unmerge_from_list).with(account, list)
|
||||
end
|
||||
|
||||
it 'marks account as suspended' do
|
||||
is_expected.to change { account.suspended? }.from(false).to(true)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'suspending a local account' do
|
||||
def match_update_actor_request(req, account)
|
||||
json = JSON.parse(req.body)
|
||||
actor_id = ActivityPub::TagManager.instance.uri_for(account)
|
||||
json['type'] == 'Update' && json['actor'] == actor_id && json['object']['id'] == actor_id && json['object']['suspended']
|
||||
end
|
||||
|
||||
before do
|
||||
stub_request(:post, 'https://alice.com/inbox').to_return(status: 201)
|
||||
stub_request(:post, 'https://bob.com/inbox').to_return(status: 201)
|
||||
end
|
||||
|
||||
include_examples 'common behavior' do
|
||||
let!(:account) { Fabricate(:account) }
|
||||
let!(:remote_follower) { Fabricate(:account, uri: 'https://alice.com', inbox_url: 'https://alice.com/inbox', protocol: :activitypub) }
|
||||
let!(:remote_reporter) { Fabricate(:account, uri: 'https://bob.com', inbox_url: 'https://bob.com/inbox', protocol: :activitypub) }
|
||||
let!(:report) { Fabricate(:report, account: remote_reporter, target_account: account) }
|
||||
|
||||
before do
|
||||
remote_follower.follow!(account)
|
||||
end
|
||||
|
||||
it 'sends an update actor to followers and reporters' do
|
||||
subject.call
|
||||
expect(a_request(:post, remote_follower.inbox_url).with { |req| match_update_actor_request(req, account) }).to have_been_made.once
|
||||
expect(a_request(:post, remote_reporter.inbox_url).with { |req| match_update_actor_request(req, account) }).to have_been_made.once
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'suspending a remote account' do
|
||||
def match_reject_follow_request(req, account, followee)
|
||||
json = JSON.parse(req.body)
|
||||
json['type'] == 'Reject' && json['actor'] == ActivityPub::TagManager.instance.uri_for(followee) && json['object']['actor'] == account.uri
|
||||
end
|
||||
|
||||
before do
|
||||
stub_request(:post, 'https://bob.com/inbox').to_return(status: 201)
|
||||
end
|
||||
|
||||
include_examples 'common behavior' do
|
||||
let!(:account) { Fabricate(:account, domain: 'bob.com', uri: 'https://bob.com', inbox_url: 'https://bob.com/inbox', protocol: :activitypub) }
|
||||
let!(:local_followee) { Fabricate(:account) }
|
||||
|
||||
before do
|
||||
account.follow!(local_followee)
|
||||
end
|
||||
|
||||
it 'sends a reject follow' do
|
||||
subject.call
|
||||
expect(a_request(:post, account.inbox_url).with { |req| match_reject_follow_request(req, account, local_followee) }).to have_been_made.once
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
135
spec/services/unsuspend_account_service_spec.rb
Normal file
135
spec/services/unsuspend_account_service_spec.rb
Normal file
@ -0,0 +1,135 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe UnsuspendAccountService, type: :service do
|
||||
shared_examples 'common behavior' do
|
||||
let!(:local_follower) { Fabricate(:user, current_sign_in_at: 1.hour.ago).account }
|
||||
let!(:list) { Fabricate(:list, account: local_follower) }
|
||||
|
||||
subject do
|
||||
-> { described_class.new.call(account) }
|
||||
end
|
||||
|
||||
before do
|
||||
allow(FeedManager.instance).to receive(:merge_into_home).and_return(nil)
|
||||
allow(FeedManager.instance).to receive(:merge_into_list).and_return(nil)
|
||||
|
||||
local_follower.follow!(account)
|
||||
list.accounts << account
|
||||
|
||||
account.suspend!(origin: :local)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'unsuspending a local account' do
|
||||
def match_update_actor_request(req, account)
|
||||
json = JSON.parse(req.body)
|
||||
actor_id = ActivityPub::TagManager.instance.uri_for(account)
|
||||
json['type'] == 'Update' && json['actor'] == actor_id && json['object']['id'] == actor_id && !json['object']['suspended']
|
||||
end
|
||||
|
||||
before do
|
||||
stub_request(:post, 'https://alice.com/inbox').to_return(status: 201)
|
||||
stub_request(:post, 'https://bob.com/inbox').to_return(status: 201)
|
||||
end
|
||||
|
||||
it 'marks account as unsuspended' do
|
||||
is_expected.to change { account.suspended? }.from(true).to(false)
|
||||
end
|
||||
|
||||
include_examples 'common behavior' do
|
||||
let!(:account) { Fabricate(:account) }
|
||||
let!(:remote_follower) { Fabricate(:account, uri: 'https://alice.com', inbox_url: 'https://alice.com/inbox', protocol: :activitypub) }
|
||||
let!(:remote_reporter) { Fabricate(:account, uri: 'https://bob.com', inbox_url: 'https://bob.com/inbox', protocol: :activitypub) }
|
||||
let!(:report) { Fabricate(:report, account: remote_reporter, target_account: account) }
|
||||
|
||||
before do
|
||||
remote_follower.follow!(account)
|
||||
end
|
||||
|
||||
it "merges back into local followers' feeds" do
|
||||
subject.call
|
||||
expect(FeedManager.instance).to have_received(:merge_into_home).with(account, local_follower)
|
||||
expect(FeedManager.instance).to have_received(:merge_into_list).with(account, list)
|
||||
end
|
||||
|
||||
it 'sends an update actor to followers and reporters' do
|
||||
subject.call
|
||||
expect(a_request(:post, remote_follower.inbox_url).with { |req| match_update_actor_request(req, account) }).to have_been_made.once
|
||||
expect(a_request(:post, remote_reporter.inbox_url).with { |req| match_update_actor_request(req, account) }).to have_been_made.once
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'unsuspending a remote account' do
|
||||
include_examples 'common behavior' do
|
||||
let!(:account) { Fabricate(:account, domain: 'bob.com', uri: 'https://bob.com', inbox_url: 'https://bob.com/inbox', protocol: :activitypub) }
|
||||
let!(:reslove_account_service) { double }
|
||||
|
||||
before do
|
||||
allow(ResolveAccountService).to receive(:new).and_return(reslove_account_service)
|
||||
end
|
||||
|
||||
context 'when the account is not remotely suspended' do
|
||||
before do
|
||||
allow(reslove_account_service).to receive(:call).with(account).and_return(account)
|
||||
end
|
||||
|
||||
it 're-fetches the account' do
|
||||
subject.call
|
||||
expect(reslove_account_service).to have_received(:call).with(account)
|
||||
end
|
||||
|
||||
it "merges back into local followers' feeds" do
|
||||
subject.call
|
||||
expect(FeedManager.instance).to have_received(:merge_into_home).with(account, local_follower)
|
||||
expect(FeedManager.instance).to have_received(:merge_into_list).with(account, list)
|
||||
end
|
||||
|
||||
it 'marks account as unsuspended' do
|
||||
is_expected.to change { account.suspended? }.from(true).to(false)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the account is remotely suspended' do
|
||||
before do
|
||||
allow(reslove_account_service).to receive(:call).with(account) do |account|
|
||||
account.suspend!(origin: :remote)
|
||||
account
|
||||
end
|
||||
end
|
||||
|
||||
it 're-fetches the account' do
|
||||
subject.call
|
||||
expect(reslove_account_service).to have_received(:call).with(account)
|
||||
end
|
||||
|
||||
it "does not merge back into local followers' feeds" do
|
||||
subject.call
|
||||
expect(FeedManager.instance).to_not have_received(:merge_into_home).with(account, local_follower)
|
||||
expect(FeedManager.instance).to_not have_received(:merge_into_list).with(account, list)
|
||||
end
|
||||
|
||||
it 'does not mark the account as unsuspended' do
|
||||
is_expected.not_to change { account.suspended? }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the account is remotely deleted' do
|
||||
before do
|
||||
allow(reslove_account_service).to receive(:call).with(account).and_return(nil)
|
||||
end
|
||||
|
||||
it 're-fetches the account' do
|
||||
subject.call
|
||||
expect(reslove_account_service).to have_received(:call).with(account)
|
||||
end
|
||||
|
||||
it "does not merge back into local followers' feeds" do
|
||||
subject.call
|
||||
expect(FeedManager.instance).to_not have_received(:merge_into_home).with(account, local_follower)
|
||||
expect(FeedManager.instance).to_not have_received(:merge_into_list).with(account, list)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -11,7 +11,7 @@ describe ActivityPub::DeliveryWorker do
|
||||
let(:payload) { 'test' }
|
||||
|
||||
before do
|
||||
allow_any_instance_of(Account).to receive(:remote_followers_hash).with('https://example.com/').and_return('somehash')
|
||||
allow_any_instance_of(Account).to receive(:remote_followers_hash).with('https://example.com/api').and_return('somehash')
|
||||
end
|
||||
|
||||
describe 'perform' do
|
||||
|
201
yarn.lock
201
yarn.lock
@ -21,20 +21,20 @@
|
||||
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.15.0.tgz#2dbaf8b85334796cafbb0f5793a90a2fc010b176"
|
||||
integrity sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA==
|
||||
|
||||
"@babel/core@^7.1.0", "@babel/core@^7.14.8", "@babel/core@^7.7.2", "@babel/core@^7.7.5":
|
||||
version "7.14.8"
|
||||
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.14.8.tgz#20cdf7c84b5d86d83fac8710a8bc605a7ba3f010"
|
||||
integrity sha512-/AtaeEhT6ErpDhInbXmjHcUQXH0L0TEgscfcxk1qbOvLuKCa5aZT0SOOtDKFY96/CLROwbLSKyFor6idgNaU4Q==
|
||||
"@babel/core@^7.1.0", "@babel/core@^7.15.0", "@babel/core@^7.7.2", "@babel/core@^7.7.5":
|
||||
version "7.15.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.15.0.tgz#749e57c68778b73ad8082775561f67f5196aafa8"
|
||||
integrity sha512-tXtmTminrze5HEUPn/a0JtOzzfp0nk+UEXQ/tqIJo3WDGypl/2OFQEMll/zSFU8f/lfmfLXvTaORHF3cfXIQMw==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.14.5"
|
||||
"@babel/generator" "^7.14.8"
|
||||
"@babel/helper-compilation-targets" "^7.14.5"
|
||||
"@babel/helper-module-transforms" "^7.14.8"
|
||||
"@babel/generator" "^7.15.0"
|
||||
"@babel/helper-compilation-targets" "^7.15.0"
|
||||
"@babel/helper-module-transforms" "^7.15.0"
|
||||
"@babel/helpers" "^7.14.8"
|
||||
"@babel/parser" "^7.14.8"
|
||||
"@babel/parser" "^7.15.0"
|
||||
"@babel/template" "^7.14.5"
|
||||
"@babel/traverse" "^7.14.8"
|
||||
"@babel/types" "^7.14.8"
|
||||
"@babel/traverse" "^7.15.0"
|
||||
"@babel/types" "^7.15.0"
|
||||
convert-source-map "^1.7.0"
|
||||
debug "^4.1.0"
|
||||
gensync "^1.0.0-beta.2"
|
||||
@ -42,15 +42,6 @@
|
||||
semver "^6.3.0"
|
||||
source-map "^0.5.0"
|
||||
|
||||
"@babel/generator@^7.14.8":
|
||||
version "7.14.8"
|
||||
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.14.8.tgz#bf86fd6af96cf3b74395a8ca409515f89423e070"
|
||||
integrity sha512-cYDUpvIzhBVnMzRoY1fkSEhK/HmwEVwlyULYgn/tMQYd6Obag3ylCjONle3gdErfXBW61SVTlR9QR7uWlgeIkg==
|
||||
dependencies:
|
||||
"@babel/types" "^7.14.8"
|
||||
jsesc "^2.5.1"
|
||||
source-map "^0.5.0"
|
||||
|
||||
"@babel/generator@^7.15.0":
|
||||
version "7.15.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.15.0.tgz#a7d0c172e0d814974bad5aa77ace543b97917f15"
|
||||
@ -178,21 +169,7 @@
|
||||
dependencies:
|
||||
"@babel/types" "^7.14.5"
|
||||
|
||||
"@babel/helper-module-transforms@^7.14.5", "@babel/helper-module-transforms@^7.14.8":
|
||||
version "7.14.8"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.14.8.tgz#d4279f7e3fd5f4d5d342d833af36d4dd87d7dc49"
|
||||
integrity sha512-RyE+NFOjXn5A9YU1dkpeBaduagTlZ0+fccnIcAGbv1KGUlReBj7utF7oEth8IdIBQPcux0DDgW5MFBH2xu9KcA==
|
||||
dependencies:
|
||||
"@babel/helper-module-imports" "^7.14.5"
|
||||
"@babel/helper-replace-supers" "^7.14.5"
|
||||
"@babel/helper-simple-access" "^7.14.8"
|
||||
"@babel/helper-split-export-declaration" "^7.14.5"
|
||||
"@babel/helper-validator-identifier" "^7.14.8"
|
||||
"@babel/template" "^7.14.5"
|
||||
"@babel/traverse" "^7.14.8"
|
||||
"@babel/types" "^7.14.8"
|
||||
|
||||
"@babel/helper-module-transforms@^7.15.0":
|
||||
"@babel/helper-module-transforms@^7.14.5", "@babel/helper-module-transforms@^7.15.0":
|
||||
version "7.15.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.15.0.tgz#679275581ea056373eddbe360e1419ef23783b08"
|
||||
integrity sha512-RkGiW5Rer7fpXv9m1B3iHIFDZdItnO2/BLfWVW/9q7+KqQSDY5kUfQEbzdXM1MVhJGcugKV7kRrNVzNxmk7NBg==
|
||||
@ -278,11 +255,6 @@
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz#d0f0e277c512e0c938277faa85a3968c9a44c0e8"
|
||||
integrity sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==
|
||||
|
||||
"@babel/helper-validator-identifier@^7.14.8":
|
||||
version "7.14.8"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.8.tgz#32be33a756f29e278a0d644fa08a2c9e0f88a34c"
|
||||
integrity sha512-ZGy6/XQjllhYQrNw/3zfWRwZCTVSiBLZ9DHVZxn9n2gip/7ab8mv2TWlKPIBk26RwedCBoWdjLmn+t9na2Gcow==
|
||||
|
||||
"@babel/helper-validator-identifier@^7.14.9":
|
||||
version "7.14.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz#6654d171b2024f6d8ee151bf2509699919131d48"
|
||||
@ -330,12 +302,7 @@
|
||||
chalk "^2.0.0"
|
||||
js-tokens "^4.0.0"
|
||||
|
||||
"@babel/parser@^7.1.0", "@babel/parser@^7.14.5", "@babel/parser@^7.14.8", "@babel/parser@^7.7.0":
|
||||
version "7.14.8"
|
||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.14.8.tgz#66fd41666b2d7b840bd5ace7f7416d5ac60208d4"
|
||||
integrity sha512-syoCQFOoo/fzkWDeM0dLEZi5xqurb5vuyzwIMNZRNun+N/9A4cUZeQaE7dTrB8jGaKuJRBtEOajtnmw0I5hvvA==
|
||||
|
||||
"@babel/parser@^7.15.0":
|
||||
"@babel/parser@^7.1.0", "@babel/parser@^7.14.5", "@babel/parser@^7.15.0", "@babel/parser@^7.7.0":
|
||||
version "7.15.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.15.0.tgz#b6d6e29058ca369127b0eeca2a1c4b5794f1b6b9"
|
||||
integrity sha512-0v7oNOjr6YT9Z2RAOTv4T9aP+ubfx4Q/OhVtAet7PFDt0t9Oy6Jn+/rfC6b8HJ5zEqrQCiMxJfgtHpmIminmJQ==
|
||||
@ -1030,10 +997,10 @@
|
||||
dependencies:
|
||||
regenerator-runtime "^0.12.0"
|
||||
|
||||
"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.14.8", "@babel/runtime@^7.2.0", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2":
|
||||
version "7.14.8"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.14.8.tgz#7119a56f421018852694290b9f9148097391b446"
|
||||
integrity sha512-twj3L8Og5SaCRCErB4x4ajbvBIVV77CGeFglHpeg5WC5FF8TZzBWXtTJ4MqaD9QszLYTtr+IsaAL2rEUevb+eg==
|
||||
"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.15.3", "@babel/runtime@^7.2.0", "@babel/runtime@^7.3.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2":
|
||||
version "7.15.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.15.3.tgz#2e1c2880ca118e5b2f9988322bd8a7656a32502b"
|
||||
integrity sha512-OvwMLqNXkCXSz1kSm58sEsNuhqOx/fKpnUnKnFB5v8uDda5bLNEHNgKPvhDN6IU0LDcnHQ90LlJ0Q6jnyBSIBA==
|
||||
dependencies:
|
||||
regenerator-runtime "^0.13.4"
|
||||
|
||||
@ -1046,22 +1013,7 @@
|
||||
"@babel/parser" "^7.14.5"
|
||||
"@babel/types" "^7.14.5"
|
||||
|
||||
"@babel/traverse@^7.1.0", "@babel/traverse@^7.13.0", "@babel/traverse@^7.14.5", "@babel/traverse@^7.14.8", "@babel/traverse@^7.7.0":
|
||||
version "7.14.8"
|
||||
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.14.8.tgz#c0253f02677c5de1a8ff9df6b0aacbec7da1a8ce"
|
||||
integrity sha512-kexHhzCljJcFNn1KYAQ6A5wxMRzq9ebYpEDV4+WdNyr3i7O44tanbDOR/xjiG2F3sllan+LgwK+7OMk0EmydHg==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.14.5"
|
||||
"@babel/generator" "^7.14.8"
|
||||
"@babel/helper-function-name" "^7.14.5"
|
||||
"@babel/helper-hoist-variables" "^7.14.5"
|
||||
"@babel/helper-split-export-declaration" "^7.14.5"
|
||||
"@babel/parser" "^7.14.8"
|
||||
"@babel/types" "^7.14.8"
|
||||
debug "^4.1.0"
|
||||
globals "^11.1.0"
|
||||
|
||||
"@babel/traverse@^7.15.0":
|
||||
"@babel/traverse@^7.1.0", "@babel/traverse@^7.13.0", "@babel/traverse@^7.14.5", "@babel/traverse@^7.14.8", "@babel/traverse@^7.15.0", "@babel/traverse@^7.7.0":
|
||||
version "7.15.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.15.0.tgz#4cca838fd1b2a03283c1f38e141f639d60b3fc98"
|
||||
integrity sha512-392d8BN0C9eVxVWd8H6x9WfipgVH5IaIoLp23334Sc1vbKKWINnvwRpb4us0xtPaCumlwbTtIYNA0Dv/32sVFw==
|
||||
@ -1473,19 +1425,19 @@
|
||||
dependencies:
|
||||
"@sinonjs/commons" "^1.7.0"
|
||||
|
||||
"@testing-library/dom@^7.28.1":
|
||||
version "7.28.1"
|
||||
resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-7.28.1.tgz#dea78be6e1e6db32ddcb29a449e94d9700c79eb9"
|
||||
integrity sha512-acv3l6kDwZkQif/YqJjstT3ks5aaI33uxGNVIQmdKzbZ2eMKgg3EV2tB84GDdc72k3Kjhl6mO8yUt6StVIdRDg==
|
||||
"@testing-library/dom@^8.0.0":
|
||||
version "8.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-8.1.0.tgz#f8358b1883844ea569ba76b7e94582168df5370d"
|
||||
integrity sha512-kmW9alndr19qd6DABzQ978zKQ+J65gU2Rzkl8hriIetPnwpesRaK4//jEQyYh8fEALmGhomD/LBQqt+o+DL95Q==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.10.4"
|
||||
"@babel/runtime" "^7.12.5"
|
||||
"@types/aria-query" "^4.2.0"
|
||||
aria-query "^4.2.2"
|
||||
chalk "^4.1.0"
|
||||
dom-accessibility-api "^0.5.4"
|
||||
dom-accessibility-api "^0.5.6"
|
||||
lz-string "^1.4.4"
|
||||
pretty-format "^26.6.2"
|
||||
pretty-format "^27.0.2"
|
||||
|
||||
"@testing-library/jest-dom@^5.14.1":
|
||||
version "5.14.1"
|
||||
@ -1502,13 +1454,13 @@
|
||||
lodash "^4.17.15"
|
||||
redent "^3.0.0"
|
||||
|
||||
"@testing-library/react@^11.2.7":
|
||||
version "11.2.7"
|
||||
resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-11.2.7.tgz#b29e2e95c6765c815786c0bc1d5aed9cb2bf7818"
|
||||
integrity sha512-tzRNp7pzd5QmbtXNG/mhdcl7Awfu/Iz1RaVHY75zTdOkmHCuzMhRL83gWHSgOAcjS3CCbyfwUHMZgRJb4kAfpA==
|
||||
"@testing-library/react@^12.0.0":
|
||||
version "12.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-12.0.0.tgz#9aeb2264521522ab9b68f519eaf15136148f164a"
|
||||
integrity sha512-sh3jhFgEshFyJ/0IxGltRhwZv2kFKfJ3fN1vTZ6hhMXzz9ZbbcTgmDYM4e+zJv+oiVKKEWZPyqPAh4MQBI65gA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.12.5"
|
||||
"@testing-library/dom" "^7.28.1"
|
||||
"@testing-library/dom" "^8.0.0"
|
||||
|
||||
"@types/aria-query@^4.2.0":
|
||||
version "4.2.0"
|
||||
@ -2075,6 +2027,11 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0:
|
||||
"@types/color-name" "^1.1.1"
|
||||
color-convert "^2.0.1"
|
||||
|
||||
ansi-styles@^5.0.0:
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b"
|
||||
integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==
|
||||
|
||||
anymatch@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb"
|
||||
@ -2591,10 +2548,10 @@ bluebird@^3.5.5:
|
||||
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f"
|
||||
integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==
|
||||
|
||||
blurhash@^1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/blurhash/-/blurhash-1.1.3.tgz#dc325af7da836d07a0861d830bdd63694382483e"
|
||||
integrity sha512-yUhPJvXexbqbyijCIE/T2NCXcj9iNPhWmOKbPTuR/cm7Q5snXYIfnVnz6m7MWOXxODMz/Cr3UcVkRdHiuDVRDw==
|
||||
blurhash@^1.1.4:
|
||||
version "1.1.4"
|
||||
resolved "https://registry.yarnpkg.com/blurhash/-/blurhash-1.1.4.tgz#a7010ceb3019cd2c9809b17c910ebf6175d29244"
|
||||
integrity sha512-MXIPz6zwYUKayju+Uidf83KhH0vodZfeRl6Ich8Gu+KGl0JgKiFq9LsfqV7cVU5fKD/AotmduZqvOfrGKOfTaA==
|
||||
|
||||
bmp-js@^0.1.0:
|
||||
version "0.1.0"
|
||||
@ -3991,7 +3948,7 @@ doctrine@^3.0.0:
|
||||
dependencies:
|
||||
esutils "^2.0.2"
|
||||
|
||||
dom-accessibility-api@^0.5.4, dom-accessibility-api@^0.5.6:
|
||||
dom-accessibility-api@^0.5.6:
|
||||
version "0.5.6"
|
||||
resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.5.6.tgz#3f5d43b52c7a3bd68b5fb63fa47b4e4c1fdf65a9"
|
||||
integrity sha512-DplGLZd8L1lN64jlT27N9TVSESFR5STaEJvX+thCby7fuCHonfPpAlodYc3vuUYbDuDec5w8AMP7oCM5TWFsqw==
|
||||
@ -4386,33 +4343,33 @@ escope@^3.6.0:
|
||||
esrecurse "^4.1.0"
|
||||
estraverse "^4.1.1"
|
||||
|
||||
eslint-import-resolver-node@^0.3.4:
|
||||
version "0.3.4"
|
||||
resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz#85ffa81942c25012d8231096ddf679c03042c717"
|
||||
integrity sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA==
|
||||
eslint-import-resolver-node@^0.3.5:
|
||||
version "0.3.5"
|
||||
resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.5.tgz#939bbb0f74e179e757ca87f7a4a890dabed18ac4"
|
||||
integrity sha512-XMoPKjSpXbkeJ7ZZ9icLnJMTY5Mc1kZbCakHquaFsXPpyWOwK0TK6CODO+0ca54UoM9LKOxyUNnoVZRl8TeaAg==
|
||||
dependencies:
|
||||
debug "^2.6.9"
|
||||
resolve "^1.13.1"
|
||||
debug "^3.2.7"
|
||||
resolve "^1.20.0"
|
||||
|
||||
eslint-module-utils@^2.6.1:
|
||||
version "2.6.1"
|
||||
resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.6.1.tgz#b51be1e473dd0de1c5ea638e22429c2490ea8233"
|
||||
integrity sha512-ZXI9B8cxAJIH4nfkhTwcRTEAnrVfobYqwjWy/QMCZ8rHkZHFjf9yO4BzpiF9kCSfNlMG54eKigISHpX0+AaT4A==
|
||||
eslint-module-utils@^2.6.2:
|
||||
version "2.6.2"
|
||||
resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.6.2.tgz#94e5540dd15fe1522e8ffa3ec8db3b7fa7e7a534"
|
||||
integrity sha512-QG8pcgThYOuqxupd06oYTZoNOGaUdTY1PqK+oS6ElF6vs4pBdk/aYxFVQQXzcrAqp9m7cl7lb2ubazX+g16k2Q==
|
||||
dependencies:
|
||||
debug "^3.2.7"
|
||||
pkg-dir "^2.0.0"
|
||||
|
||||
eslint-plugin-import@~2.23.4:
|
||||
version "2.23.4"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.23.4.tgz#8dceb1ed6b73e46e50ec9a5bb2411b645e7d3d97"
|
||||
integrity sha512-6/wP8zZRsnQFiR3iaPFgh5ImVRM1WN5NUWfTIRqwOdeiGJlBcSk82o1FEVq8yXmy4lkIzTo7YhHCIxlU/2HyEQ==
|
||||
eslint-plugin-import@~2.24.0:
|
||||
version "2.24.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.24.0.tgz#697ffd263e24da5e84e03b282f5fb62251777177"
|
||||
integrity sha512-Kc6xqT9hiYi2cgybOc0I2vC9OgAYga5o/rAFinam/yF/t5uBqxQbauNPMC6fgb640T/89P0gFoO27FOilJ/Cqg==
|
||||
dependencies:
|
||||
array-includes "^3.1.3"
|
||||
array.prototype.flat "^1.2.4"
|
||||
debug "^2.6.9"
|
||||
doctrine "^2.1.0"
|
||||
eslint-import-resolver-node "^0.3.4"
|
||||
eslint-module-utils "^2.6.1"
|
||||
eslint-import-resolver-node "^0.3.5"
|
||||
eslint-module-utils "^2.6.2"
|
||||
find-up "^2.0.0"
|
||||
has "^1.0.3"
|
||||
is-core-module "^2.4.0"
|
||||
@ -8254,9 +8211,9 @@ path-key@^3.0.0, path-key@^3.1.0:
|
||||
integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
|
||||
|
||||
path-parse@^1.0.6:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c"
|
||||
integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==
|
||||
version "1.0.7"
|
||||
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
|
||||
integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
|
||||
|
||||
path-to-regexp@0.1.7:
|
||||
version "0.1.7"
|
||||
@ -8864,6 +8821,16 @@ pretty-format@^26.6.2:
|
||||
ansi-styles "^4.0.0"
|
||||
react-is "^17.0.1"
|
||||
|
||||
pretty-format@^27.0.2:
|
||||
version "27.0.6"
|
||||
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.0.6.tgz#ab770c47b2c6f893a21aefc57b75da63ef49a11f"
|
||||
integrity sha512-8tGD7gBIENgzqA+UBzObyWqQ5B778VIFZA/S66cclyd5YkFLYs2Js7gxDKf0MXtTc9zcS7t1xhdfcElJ3YIvkQ==
|
||||
dependencies:
|
||||
"@jest/types" "^27.0.6"
|
||||
ansi-regex "^5.0.0"
|
||||
ansi-styles "^5.0.0"
|
||||
react-is "^17.0.1"
|
||||
|
||||
process-nextick-args@~2.0.0:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
|
||||
@ -9481,10 +9448,10 @@ redux-thunk@^2.2.0:
|
||||
resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.3.0.tgz#51c2c19a185ed5187aaa9a2d08b666d0d6467622"
|
||||
integrity sha512-km6dclyFnmcvxhAcrQV2AkZmPQjzPDjgVlQtR0EQjxZPyJ0BnMf3in1ryuR8A2qU0HldVRfxYXbFSKlI3N7Slw==
|
||||
|
||||
redux@^4.0.0, redux@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/redux/-/redux-4.1.0.tgz#eb049679f2f523c379f1aff345c8612f294c88d4"
|
||||
integrity sha512-uI2dQN43zqLWCt6B/BMGRMY6db7TTY4qeHHfGeKb3EOhmOKjU3KdWvNLJyqaHRksv/ErdNH7cFZWg9jXtewy4g==
|
||||
redux@^4.0.0, redux@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/redux/-/redux-4.1.1.tgz#76f1c439bb42043f985fbd9bf21990e60bd67f47"
|
||||
integrity sha512-hZQZdDEM25UY2P493kPYuKqviVwZ58lEmGQNeQ+gXa+U0gYPUBf7NKYazbe3m+bs/DzM/ahN12DbF+NG8i0CWw==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.9.2"
|
||||
|
||||
@ -9737,7 +9704,7 @@ resolve-url@^0.2.1:
|
||||
resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
|
||||
integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=
|
||||
|
||||
resolve@^1.10.0, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.14.2, resolve@^1.18.1, resolve@^1.20.0:
|
||||
resolve@^1.10.0, resolve@^1.12.0, resolve@^1.14.2, resolve@^1.18.1, resolve@^1.20.0:
|
||||
version "1.20.0"
|
||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975"
|
||||
integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==
|
||||
@ -9902,10 +9869,10 @@ sass-loader@^10.2.0:
|
||||
schema-utils "^3.0.0"
|
||||
semver "^7.3.2"
|
||||
|
||||
sass@^1.37.0:
|
||||
version "1.37.0"
|
||||
resolved "https://registry.yarnpkg.com/sass/-/sass-1.37.0.tgz#f1b03a9d072ee9053a29d125c8130c78e92827c2"
|
||||
integrity sha512-B+Tu6cSAG8ffs/cqsZl/bgSH2pCmavDaPTYAoW8QA1qNHh/RqndNfVKuABKYkLjUQ5aq/BnCENVpE80cqdSM1w==
|
||||
sass@^1.38.0:
|
||||
version "1.38.0"
|
||||
resolved "https://registry.yarnpkg.com/sass/-/sass-1.38.0.tgz#2f3e60a1efdcdc910586fa79dc89d3399a145b4f"
|
||||
integrity sha512-WBccZeMigAGKoI+NgD7Adh0ab1HUq+6BmyBUEaGxtErbUtWUevEbdgo5EZiJQofLUGcKtlNaO2IdN73AHEua5g==
|
||||
dependencies:
|
||||
chokidar ">=3.0.0 <4.0.0"
|
||||
|
||||
@ -11816,10 +11783,10 @@ ws@^7.2.3, ws@^7.3.1:
|
||||
resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.3.tgz#160835b63c7d97bfab418fc1b8a9fced2ac01a74"
|
||||
integrity sha512-kQ/dHIzuLrS6Je9+uv81ueZomEwH0qVYstcAQ4/Z93K8zeko9gtAbttJWzoC5ukqXY1PpoouV3+VSOqEAFt5wg==
|
||||
|
||||
ws@^8.0.0:
|
||||
version "8.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ws/-/ws-8.0.0.tgz#550605d13dfc1437c9ec1396975709c6d7ffc57d"
|
||||
integrity sha512-6AcSIXpBlS0QvCVKk+3cWnWElLsA6SzC0lkQ43ciEglgXJXiCWK3/CGFEJ+Ybgp006CMibamAsqOlxE9s4AvYA==
|
||||
ws@^8.1.0:
|
||||
version "8.1.0"
|
||||
resolved "https://registry.yarnpkg.com/ws/-/ws-8.1.0.tgz#75e5ec608f66d3d3934ec6dbc4ebc8a34a68638c"
|
||||
integrity sha512-0UWlCD2s3RSclw8FN+D0zDTUyMO+1kHwJQQJzkgUh16S8d3NYON0AKCEQPffE0ez4JyRFu76QDA9KR5bOG/7jw==
|
||||
|
||||
xml-name-validator@^3.0.0:
|
||||
version "3.0.0"
|
||||
@ -11915,10 +11882,10 @@ yargs@^15.4.1:
|
||||
y18n "^4.0.0"
|
||||
yargs-parser "^18.1.2"
|
||||
|
||||
yargs@^17.0.1:
|
||||
version "17.0.1"
|
||||
resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.0.1.tgz#6a1ced4ed5ee0b388010ba9fd67af83b9362e0bb"
|
||||
integrity sha512-xBBulfCc8Y6gLFcrPvtqKz9hz8SO0l1Ni8GgDekvBX2ro0HRQImDGnikfc33cgzcYUSncapnNcZDjVFIH3f6KQ==
|
||||
yargs@^17.1.1:
|
||||
version "17.1.1"
|
||||
resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.1.1.tgz#c2a8091564bdb196f7c0a67c1d12e5b85b8067ba"
|
||||
integrity sha512-c2k48R0PwKIqKhPMWjeiF6y2xY/gPMUlro0sgxqXpbOIohWiLNXWslsootttv7E1e73QPAMQSg5FeySbVcpsPQ==
|
||||
dependencies:
|
||||
cliui "^7.0.2"
|
||||
escalade "^3.1.1"
|
||||
|
Loading…
Reference in New Issue
Block a user