diff --git a/.env.nanobox b/.env.nanobox
index d61673836b0..ad941c947c8 100644
--- a/.env.nanobox
+++ b/.env.nanobox
@@ -13,7 +13,7 @@ DB_PORT=5432
# DATABASE_URL=postgresql://$DATA_DB_USER:$DATA_DB_PASS@$DATA_DB_HOST/gonano
-# Optional ElasticSearch configuration
+# Optional Elasticsearch configuration
ES_ENABLED=true
ES_HOST=$DATA_ELASTIC_HOST
ES_PORT=9200
diff --git a/.env.production.sample b/.env.production.sample
index 86f770e7860..13e89b40d27 100644
--- a/.env.production.sample
+++ b/.env.production.sample
@@ -56,7 +56,7 @@ DB_PASS=
DB_PORT=5432
-# ElasticSearch (optional)
+# Elasticsearch (optional)
# ------------------------
#ES_ENABLED=true
#ES_HOST=localhost
@@ -65,6 +65,7 @@ DB_PORT=5432
#ES_USER=elastic
#ES_PASS=password
+
# Secrets
# -------
# Generate each with the `RAILS_ENV=production bundle exec rake secret` task (`docker-compose run --rm web bundle exec rake secret` if you use docker compose)
diff --git a/Gemfile b/Gemfile
index 9f358bab6ae..f949ef9ec25 100644
--- a/Gemfile
+++ b/Gemfile
@@ -26,7 +26,7 @@ gem 'blurhash', '~> 0.1'
gem 'active_model_serializers', '~> 0.10'
gem 'addressable', '~> 2.8'
-gem 'bootsnap', '~> 1.9.1', require: false
+gem 'bootsnap', '~> 1.9.2', require: false
gem 'browser'
gem 'charlock_holmes', '~> 0.7.7'
gem 'iso-639'
diff --git a/Gemfile.lock b/Gemfile.lock
index 198abd8e3fd..a1807e37ce2 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -104,7 +104,7 @@ GEM
debug_inspector (>= 0.0.1)
blurhash (0.1.5)
ffi (~> 1.14)
- bootsnap (1.9.1)
+ bootsnap (1.9.3)
msgpack (~> 1.0)
brakeman (5.1.2)
browser (4.2.0)
@@ -599,7 +599,7 @@ GEM
sprockets (3.7.2)
concurrent-ruby (~> 1.0)
rack (> 1, < 3)
- sprockets-rails (3.4.0)
+ sprockets-rails (3.4.1)
actionpack (>= 5.2)
activesupport (>= 5.2)
sprockets (>= 3.0.0)
@@ -690,7 +690,7 @@ DEPENDENCIES
better_errors (~> 2.9)
binding_of_caller (~> 1.0)
blurhash (~> 0.1)
- bootsnap (~> 1.9.1)
+ bootsnap (~> 1.9.2)
brakeman (~> 5.1)
browser
bullet (~> 6.1)
diff --git a/app/controllers/admin/statuses_controller.rb b/app/controllers/admin/statuses_controller.rb
index 58a0eb84ca7..b3fd4c42465 100644
--- a/app/controllers/admin/statuses_controller.rb
+++ b/app/controllers/admin/statuses_controller.rb
@@ -14,7 +14,7 @@ module Admin
@statuses = @account.statuses.where(visibility: [:public, :unlisted])
if params[:media]
- @statuses.merge!(Status.joins(:media_attachments).merge(@account.media_attachments.reorder(nil)).group(:id)).reorder('statuses.id desc')
+ @statuses = @statuses.merge(Status.joins(:media_attachments).merge(@account.media_attachments.reorder(nil)).group(:id)).reorder('statuses.id desc')
end
@statuses = @statuses.preload(:media_attachments, :mentions).page(params[:page]).per(PER_PAGE)
diff --git a/app/controllers/api/proofs_controller.rb b/app/controllers/api/proofs_controller.rb
deleted file mode 100644
index dd32cd577bf..00000000000
--- a/app/controllers/api/proofs_controller.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-# frozen_string_literal: true
-
-class Api::ProofsController < Api::BaseController
- include AccountOwnedConcern
-
- skip_before_action :require_authenticated_user!
-
- before_action :set_provider
-
- def index
- render json: @account, serializer: @provider.serializer_class
- end
-
- private
-
- def set_provider
- @provider = ProofProvider.find(params[:provider]) || raise(ActiveRecord::RecordNotFound)
- end
-
- def username_param
- params[:username]
- end
-end
diff --git a/app/controllers/api/v1/accounts/identity_proofs_controller.rb b/app/controllers/api/v1/accounts/identity_proofs_controller.rb
index 4b5f6902c7d..48f293f47a3 100644
--- a/app/controllers/api/v1/accounts/identity_proofs_controller.rb
+++ b/app/controllers/api/v1/accounts/identity_proofs_controller.rb
@@ -5,8 +5,7 @@ class Api::V1::Accounts::IdentityProofsController < Api::BaseController
before_action :set_account
def index
- @proofs = @account.suspended? ? [] : @account.identity_proofs.active
- render json: @proofs, each_serializer: REST::IdentityProofSerializer
+ render json: []
end
private
diff --git a/app/controllers/settings/identity_proofs_controller.rb b/app/controllers/settings/identity_proofs_controller.rb
deleted file mode 100644
index 4618c78836b..00000000000
--- a/app/controllers/settings/identity_proofs_controller.rb
+++ /dev/null
@@ -1,65 +0,0 @@
-# frozen_string_literal: true
-
-class Settings::IdentityProofsController < Settings::BaseController
- before_action :check_required_params, only: :new
- before_action :check_enabled, only: :new
-
- def index
- @proofs = AccountIdentityProof.where(account: current_account).order(provider: :asc, provider_username: :asc)
- @proofs.each(&:refresh!)
- end
-
- def new
- @proof = current_account.identity_proofs.new(
- token: params[:token],
- provider: params[:provider],
- provider_username: params[:provider_username]
- )
-
- if current_account.username.casecmp(params[:username]).zero?
- render layout: 'auth'
- else
- redirect_to settings_identity_proofs_path, alert: I18n.t('identity_proofs.errors.wrong_user', proving: params[:username], current: current_account.username)
- end
- end
-
- def create
- @proof = current_account.identity_proofs.where(provider: resource_params[:provider], provider_username: resource_params[:provider_username]).first_or_initialize(resource_params)
- @proof.token = resource_params[:token]
-
- if @proof.save
- PostStatusService.new.call(current_user.account, text: post_params[:status_text]) if publish_proof?
- redirect_to @proof.on_success_path(params[:user_agent])
- else
- redirect_to settings_identity_proofs_path, alert: I18n.t('identity_proofs.errors.failed', provider: @proof.provider.capitalize)
- end
- end
-
- def destroy
- @proof = current_account.identity_proofs.find(params[:id])
- @proof.destroy!
- redirect_to settings_identity_proofs_path, success: I18n.t('identity_proofs.removed')
- end
-
- private
-
- def check_enabled
- not_found unless Setting.enable_keybase
- end
-
- def check_required_params
- redirect_to settings_identity_proofs_path unless [:provider, :provider_username, :username, :token].all? { |k| params[k].present? }
- end
-
- def resource_params
- params.require(:account_identity_proof).permit(:provider, :provider_username, :token)
- end
-
- def publish_proof?
- ActiveModel::Type::Boolean.new.cast(post_params[:post_status])
- end
-
- def post_params
- params.require(:account_identity_proof).permit(:post_status, :status_text)
- end
-end
diff --git a/app/controllers/well_known/keybase_proof_config_controller.rb b/app/controllers/well_known/keybase_proof_config_controller.rb
deleted file mode 100644
index 03232df2d38..00000000000
--- a/app/controllers/well_known/keybase_proof_config_controller.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# frozen_string_literal: true
-
-module WellKnown
- class KeybaseProofConfigController < ActionController::Base
- before_action :check_enabled
-
- def show
- render json: {}, serializer: ProofProvider::Keybase::ConfigSerializer, root: 'keybase_config'
- end
-
- private
-
- def check_enabled
- head 404 unless Setting.enable_keybase
- end
- end
-end
diff --git a/app/javascript/mastodon/actions/identity_proofs.js b/app/javascript/mastodon/actions/identity_proofs.js
deleted file mode 100644
index 10398395660..00000000000
--- a/app/javascript/mastodon/actions/identity_proofs.js
+++ /dev/null
@@ -1,31 +0,0 @@
-import api from '../api';
-
-export const IDENTITY_PROOFS_ACCOUNT_FETCH_REQUEST = 'IDENTITY_PROOFS_ACCOUNT_FETCH_REQUEST';
-export const IDENTITY_PROOFS_ACCOUNT_FETCH_SUCCESS = 'IDENTITY_PROOFS_ACCOUNT_FETCH_SUCCESS';
-export const IDENTITY_PROOFS_ACCOUNT_FETCH_FAIL = 'IDENTITY_PROOFS_ACCOUNT_FETCH_FAIL';
-
-export const fetchAccountIdentityProofs = accountId => (dispatch, getState) => {
- dispatch(fetchAccountIdentityProofsRequest(accountId));
-
- api(getState).get(`/api/v1/accounts/${accountId}/identity_proofs`)
- .then(({ data }) => dispatch(fetchAccountIdentityProofsSuccess(accountId, data)))
- .catch(err => dispatch(fetchAccountIdentityProofsFail(accountId, err)));
-};
-
-export const fetchAccountIdentityProofsRequest = id => ({
- type: IDENTITY_PROOFS_ACCOUNT_FETCH_REQUEST,
- id,
-});
-
-export const fetchAccountIdentityProofsSuccess = (accountId, identity_proofs) => ({
- type: IDENTITY_PROOFS_ACCOUNT_FETCH_SUCCESS,
- accountId,
- identity_proofs,
-});
-
-export const fetchAccountIdentityProofsFail = (accountId, err) => ({
- type: IDENTITY_PROOFS_ACCOUNT_FETCH_FAIL,
- accountId,
- err,
- skipNotFound: true,
-});
diff --git a/app/javascript/mastodon/components/status.js b/app/javascript/mastodon/components/status.js
index 96e6a6c8d2f..9955046c048 100644
--- a/app/javascript/mastodon/components/status.js
+++ b/app/javascript/mastodon/components/status.js
@@ -146,7 +146,11 @@ class Status extends ImmutablePureComponent {
this.handleHotkeyOpen();
}
- handleAccountClick = e => {
+ handlePrependAccountClick = e => {
+ this.handleAccountClick(e, false);
+ }
+
+ handleAccountClick = (e, proper = true) => {
if (e && (e.button !== 0 || e.ctrlKey || e.metaKey)) {
return;
}
@@ -155,7 +159,7 @@ class Status extends ImmutablePureComponent {
e.preventDefault();
}
- this.handleHotkeyOpenProfile();
+ this._openProfile(proper);
}
handleExpandedToggle = () => {
@@ -244,8 +248,12 @@ class Status extends ImmutablePureComponent {
}
handleHotkeyOpenProfile = () => {
+ this._openProfile();
+ }
+
+ _openProfile = (proper = true) => {
const { router } = this.context;
- const status = this._properStatus();
+ const status = proper ? this._properStatus() : this.props.status;
if (!router) {
return;
@@ -349,7 +357,7 @@ class Status extends ImmutablePureComponent {
prepend = (
);
diff --git a/app/javascript/mastodon/features/account/components/header.js b/app/javascript/mastodon/features/account/components/header.js
index 4d0a828c70d..48ec49d8148 100644
--- a/app/javascript/mastodon/features/account/components/header.js
+++ b/app/javascript/mastodon/features/account/components/header.js
@@ -123,7 +123,7 @@ class Header extends ImmutablePureComponent {
}
render () {
- const { account, intl, domain, identity_proofs } = this.props;
+ const { account, intl, domain } = this.props;
if (!account) {
return null;
@@ -297,20 +297,8 @@ class Header extends ImmutablePureComponent {
- {(fields.size > 0 || identity_proofs.size > 0) && (
+ {fields.size > 0 && (
- {identity_proofs.map((proof, i) => (
-
-
-
- -
-
-
-
-
-
-
- ))}
{fields.map((pair, i) => (
diff --git a/app/javascript/mastodon/features/account_timeline/components/header.js b/app/javascript/mastodon/features/account_timeline/components/header.js
index 17b693600e5..33bea4c1799 100644
--- a/app/javascript/mastodon/features/account_timeline/components/header.js
+++ b/app/javascript/mastodon/features/account_timeline/components/header.js
@@ -11,7 +11,6 @@ export default class Header extends ImmutablePureComponent {
static propTypes = {
account: ImmutablePropTypes.map,
- identity_proofs: ImmutablePropTypes.list,
onFollow: PropTypes.func.isRequired,
onBlock: PropTypes.func.isRequired,
onMention: PropTypes.func.isRequired,
@@ -92,7 +91,7 @@ export default class Header extends ImmutablePureComponent {
}
render () {
- const { account, hideTabs, identity_proofs } = this.props;
+ const { account, hideTabs } = this.props;
if (account === null) {
return null;
@@ -104,7 +103,6 @@ export default class Header extends ImmutablePureComponent {
{
const mapStateToProps = (state, { accountId }) => ({
account: getAccount(state, accountId),
domain: state.getIn(['meta', 'domain']),
- identity_proofs: state.getIn(['identity_proofs', accountId], ImmutableList()),
});
return mapStateToProps;
diff --git a/app/javascript/mastodon/features/account_timeline/index.js b/app/javascript/mastodon/features/account_timeline/index.js
index 20f1dba9f5b..37df2818b19 100644
--- a/app/javascript/mastodon/features/account_timeline/index.js
+++ b/app/javascript/mastodon/features/account_timeline/index.js
@@ -12,7 +12,6 @@ import ColumnBackButton from '../../components/column_back_button';
import { List as ImmutableList } from 'immutable';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { FormattedMessage } from 'react-intl';
-import { fetchAccountIdentityProofs } from '../../actions/identity_proofs';
import MissingIndicator from 'mastodon/components/missing_indicator';
import TimelineHint from 'mastodon/components/timeline_hint';
import { me } from 'mastodon/initial_state';
@@ -80,7 +79,6 @@ class AccountTimeline extends ImmutablePureComponent {
const { accountId, withReplies, dispatch } = this.props;
dispatch(fetchAccount(accountId));
- dispatch(fetchAccountIdentityProofs(accountId));
if (!withReplies) {
dispatch(expandAccountFeaturedTimeline(accountId));
diff --git a/app/javascript/mastodon/features/hashtag_timeline/containers/column_settings_container.js b/app/javascript/mastodon/features/hashtag_timeline/containers/column_settings_container.js
index 5914bbeaf78..a4f71f8a392 100644
--- a/app/javascript/mastodon/features/hashtag_timeline/containers/column_settings_container.js
+++ b/app/javascript/mastodon/features/hashtag_timeline/containers/column_settings_container.js
@@ -11,21 +11,22 @@ const mapStateToProps = (state, { columnId }) => {
return {};
}
- return { settings: columns.get(index).get('params') };
+ return {
+ settings: columns.get(index).get('params'),
+ onLoad (value) {
+ return api(() => state).get('/api/v2/search', { params: { q: value, type: 'hashtags' } }).then(response => {
+ return (response.data.hashtags || []).map((tag) => {
+ return { value: tag.name, label: `#${tag.name}` };
+ });
+ });
+ },
+ };
};
const mapDispatchToProps = (dispatch, { columnId }) => ({
onChange (key, value) {
dispatch(changeColumnParams(columnId, key, value));
},
-
- onLoad (value) {
- return api().get('/api/v2/search', { params: { q: value, type: 'hashtags' } }).then(response => {
- return (response.data.hashtags || []).map((tag) => {
- return { value: tag.name, label: `#${tag.name}` };
- });
- });
- },
});
export default connect(mapStateToProps, mapDispatchToProps)(ColumnSettings);
diff --git a/app/javascript/mastodon/reducers/identity_proofs.js b/app/javascript/mastodon/reducers/identity_proofs.js
deleted file mode 100644
index 58af0a5faaa..00000000000
--- a/app/javascript/mastodon/reducers/identity_proofs.js
+++ /dev/null
@@ -1,25 +0,0 @@
-import { Map as ImmutableMap, fromJS } from 'immutable';
-import {
- IDENTITY_PROOFS_ACCOUNT_FETCH_REQUEST,
- IDENTITY_PROOFS_ACCOUNT_FETCH_SUCCESS,
- IDENTITY_PROOFS_ACCOUNT_FETCH_FAIL,
-} from '../actions/identity_proofs';
-
-const initialState = ImmutableMap();
-
-export default function identityProofsReducer(state = initialState, action) {
- switch(action.type) {
- case IDENTITY_PROOFS_ACCOUNT_FETCH_REQUEST:
- return state.set('isLoading', true);
- case IDENTITY_PROOFS_ACCOUNT_FETCH_FAIL:
- return state.set('isLoading', false);
- case IDENTITY_PROOFS_ACCOUNT_FETCH_SUCCESS:
- return state.update(identity_proofs => identity_proofs.withMutations(map => {
- map.set('isLoading', false);
- map.set('loaded', true);
- map.set(action.accountId, fromJS(action.identity_proofs));
- }));
- default:
- return state;
- }
-};
diff --git a/app/javascript/mastodon/reducers/index.js b/app/javascript/mastodon/reducers/index.js
index e518c8228ab..53e2dd681ee 100644
--- a/app/javascript/mastodon/reducers/index.js
+++ b/app/javascript/mastodon/reducers/index.js
@@ -32,7 +32,6 @@ import filters from './filters';
import conversations from './conversations';
import suggestions from './suggestions';
import polls from './polls';
-import identity_proofs from './identity_proofs';
import trends from './trends';
import missed_updates from './missed_updates';
import announcements from './announcements';
@@ -69,7 +68,6 @@ const reducers = {
notifications,
height_cache,
custom_emojis,
- identity_proofs,
lists,
listEditor,
listAdder,
diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss
index c239d4c7813..3343e9bd38b 100644
--- a/app/javascript/styles/mastodon/components.scss
+++ b/app/javascript/styles/mastodon/components.scss
@@ -3922,7 +3922,8 @@ a.status-card.compact:hover {
}
&__multi-value__label,
- &__input {
+ &__input,
+ &__input-container {
color: $darker-text-color;
}
diff --git a/app/javascript/styles/mastodon/forms.scss b/app/javascript/styles/mastodon/forms.scss
index 5b71b6334ee..65f53471d77 100644
--- a/app/javascript/styles/mastodon/forms.scss
+++ b/app/javascript/styles/mastodon/forms.scss
@@ -999,68 +999,6 @@ code {
}
}
-.connection-prompt {
- margin-bottom: 25px;
-
- .fa-link {
- background-color: darken($ui-base-color, 4%);
- border-radius: 100%;
- font-size: 24px;
- padding: 10px;
- }
-
- &__column {
- align-items: center;
- display: flex;
- flex: 1;
- flex-direction: column;
- flex-shrink: 1;
- max-width: 50%;
-
- &-sep {
- align-self: center;
- flex-grow: 0;
- overflow: visible;
- position: relative;
- z-index: 1;
- }
-
- p {
- word-break: break-word;
- }
- }
-
- .account__avatar {
- margin-bottom: 20px;
- }
-
- &__connection {
- background-color: lighten($ui-base-color, 8%);
- box-shadow: 0 0 15px rgba($base-shadow-color, 0.2);
- border-radius: 4px;
- padding: 25px 10px;
- position: relative;
- text-align: center;
-
- &::after {
- background-color: darken($ui-base-color, 4%);
- content: '';
- display: block;
- height: 100%;
- left: 50%;
- position: absolute;
- top: 0;
- width: 1px;
- }
- }
-
- &__row {
- align-items: flex-start;
- display: flex;
- flex-direction: row;
- }
-}
-
.input.user_confirm_password,
.input.user_website {
&:not(.field_with_errors) {
diff --git a/app/lib/activitypub/adapter.rb b/app/lib/activitypub/adapter.rb
index ef00a4e2eba..d8b0c63b256 100644
--- a/app/lib/activitypub/adapter.rb
+++ b/app/lib/activitypub/adapter.rb
@@ -19,7 +19,6 @@ class ActivityPub::Adapter < ActiveModelSerializers::Adapter::Base
atom_uri: { 'ostatus' => 'http://ostatus.org#', 'atomUri' => 'ostatus:atomUri' },
conversation: { 'ostatus' => 'http://ostatus.org#', 'inReplyToAtomUri' => 'ostatus:inReplyToAtomUri', 'conversation' => 'ostatus:conversation' },
focal_point: { 'toot' => 'http://joinmastodon.org/ns#', 'focalPoint' => { '@container' => '@list', '@id' => 'toot:focalPoint' } },
- identity_proof: { 'toot' => 'http://joinmastodon.org/ns#', 'IdentityProof' => 'toot:IdentityProof' },
blurhash: { 'toot' => 'http://joinmastodon.org/ns#', 'blurhash' => 'toot:blurhash' },
discoverable: { 'toot' => 'http://joinmastodon.org/ns#', 'discoverable' => 'toot:discoverable' },
voters_count: { 'toot' => 'http://joinmastodon.org/ns#', 'votersCount' => 'toot:votersCount' },
diff --git a/app/lib/proof_provider.rb b/app/lib/proof_provider.rb
deleted file mode 100644
index 102c50f4f9e..00000000000
--- a/app/lib/proof_provider.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-# frozen_string_literal: true
-
-module ProofProvider
- SUPPORTED_PROVIDERS = %w(keybase).freeze
-
- def self.find(identifier, proof = nil)
- case identifier
- when 'keybase'
- ProofProvider::Keybase.new(proof)
- end
- end
-end
diff --git a/app/lib/proof_provider/keybase.rb b/app/lib/proof_provider/keybase.rb
deleted file mode 100644
index 8e51d714646..00000000000
--- a/app/lib/proof_provider/keybase.rb
+++ /dev/null
@@ -1,69 +0,0 @@
-# frozen_string_literal: true
-
-class ProofProvider::Keybase
- BASE_URL = ENV.fetch('KEYBASE_BASE_URL', 'https://keybase.io')
- DOMAIN = ENV.fetch('KEYBASE_DOMAIN', Rails.configuration.x.web_domain)
-
- class Error < StandardError; end
-
- class ExpectedProofLiveError < Error; end
-
- class UnexpectedResponseError < Error; end
-
- def initialize(proof = nil)
- @proof = proof
- end
-
- def serializer_class
- ProofProvider::Keybase::Serializer
- end
-
- def worker_class
- ProofProvider::Keybase::Worker
- end
-
- def validate!
- unless @proof.token&.size == 66
- @proof.errors.add(:base, I18n.t('identity_proofs.errors.keybase.invalid_token'))
- return
- end
-
- # Do not perform synchronous validation for remote accounts
- return if @proof.provider_username.blank? || !@proof.account.local?
-
- if verifier.valid?
- @proof.verified = true
- @proof.live = false
- else
- @proof.errors.add(:base, I18n.t('identity_proofs.errors.keybase.verification_failed', kb_username: @proof.provider_username))
- end
- end
-
- def refresh!
- worker_class.new.perform(@proof)
- rescue ProofProvider::Keybase::Error
- nil
- end
-
- def on_success_path(user_agent = nil)
- verifier.on_success_path(user_agent)
- end
-
- def badge
- @badge ||= ProofProvider::Keybase::Badge.new(@proof.account.username, @proof.provider_username, @proof.token, domain)
- end
-
- def verifier
- @verifier ||= ProofProvider::Keybase::Verifier.new(@proof.account.username, @proof.provider_username, @proof.token, domain)
- end
-
- private
-
- def domain
- if @proof.account.local?
- DOMAIN
- else
- @proof.account.domain
- end
- end
-end
diff --git a/app/lib/proof_provider/keybase/badge.rb b/app/lib/proof_provider/keybase/badge.rb
deleted file mode 100644
index f587b1cc744..00000000000
--- a/app/lib/proof_provider/keybase/badge.rb
+++ /dev/null
@@ -1,45 +0,0 @@
-# frozen_string_literal: true
-
-class ProofProvider::Keybase::Badge
- include RoutingHelper
-
- def initialize(local_username, provider_username, token, domain)
- @local_username = local_username
- @provider_username = provider_username
- @token = token
- @domain = domain
- end
-
- def proof_url
- "#{ProofProvider::Keybase::BASE_URL}/#{@provider_username}/sigchain\##{@token}"
- end
-
- def profile_url
- "#{ProofProvider::Keybase::BASE_URL}/#{@provider_username}"
- end
-
- def icon_url
- "#{ProofProvider::Keybase::BASE_URL}/#{@provider_username}/proof_badge/#{@token}?username=#{@local_username}&domain=#{@domain}"
- end
-
- def avatar_url
- Rails.cache.fetch("proof_providers/keybase/#{@provider_username}/avatar_url", expires_in: 5.minutes) { remote_avatar_url } || default_avatar_url
- end
-
- private
-
- def remote_avatar_url
- request = Request.new(:get, "#{ProofProvider::Keybase::BASE_URL}/_/api/1.0/user/pic_url.json", params: { username: @provider_username })
-
- request.perform do |res|
- json = Oj.load(res.body_with_limit, mode: :strict)
- json['pic_url'] if json.is_a?(Hash)
- end
- rescue Oj::ParseError, HTTP::Error, OpenSSL::SSL::SSLError
- nil
- end
-
- def default_avatar_url
- asset_pack_path('media/images/proof_providers/keybase.png')
- end
-end
diff --git a/app/lib/proof_provider/keybase/config_serializer.rb b/app/lib/proof_provider/keybase/config_serializer.rb
deleted file mode 100644
index c6c364d316f..00000000000
--- a/app/lib/proof_provider/keybase/config_serializer.rb
+++ /dev/null
@@ -1,76 +0,0 @@
-# frozen_string_literal: true
-
-class ProofProvider::Keybase::ConfigSerializer < ActiveModel::Serializer
- include RoutingHelper
- include ActionView::Helpers::TextHelper
-
- attributes :version, :domain, :display_name, :username,
- :brand_color, :logo, :description, :prefill_url,
- :profile_url, :check_url, :check_path, :avatar_path,
- :contact
-
- def version
- 1
- end
-
- def domain
- ProofProvider::Keybase::DOMAIN
- end
-
- def display_name
- Setting.site_title
- end
-
- def logo
- {
- svg_black: full_asset_url(asset_pack_path('media/images/logo_transparent_black.svg')),
- svg_white: full_asset_url(asset_pack_path('media/images/logo_transparent_white.svg')),
- svg_full: full_asset_url(asset_pack_path('media/images/logo.svg')),
- svg_full_darkmode: full_asset_url(asset_pack_path('media/images/logo.svg')),
- }
- end
-
- def brand_color
- '#282c37'
- end
-
- def description
- strip_tags(Setting.site_short_description.presence || I18n.t('about.about_mastodon_html'))
- end
-
- def username
- { min: 1, max: 30, re: '[a-z0-9_]+([a-z0-9_.-]+[a-z0-9_]+)?' }
- end
-
- def prefill_url
- params = {
- provider: 'keybase',
- token: '%{sig_hash}',
- provider_username: '%{kb_username}',
- username: '%{username}',
- user_agent: '%{kb_ua}',
- }
-
- CGI.unescape(new_settings_identity_proof_url(params))
- end
-
- def profile_url
- CGI.unescape(short_account_url('%{username}'))
- end
-
- def check_url
- CGI.unescape(api_proofs_url(username: '%{username}', provider: 'keybase'))
- end
-
- def check_path
- ['signatures']
- end
-
- def avatar_path
- ['avatar']
- end
-
- def contact
- [Setting.site_contact_email.presence || 'unknown'].compact
- end
-end
diff --git a/app/lib/proof_provider/keybase/serializer.rb b/app/lib/proof_provider/keybase/serializer.rb
deleted file mode 100644
index d29283600ef..00000000000
--- a/app/lib/proof_provider/keybase/serializer.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-# frozen_string_literal: true
-
-class ProofProvider::Keybase::Serializer < ActiveModel::Serializer
- include RoutingHelper
-
- attribute :avatar
-
- has_many :identity_proofs, key: :signatures
-
- def avatar
- full_asset_url(object.avatar_original_url)
- end
-
- class AccountIdentityProofSerializer < ActiveModel::Serializer
- attributes :sig_hash, :kb_username
-
- def sig_hash
- object.token
- end
-
- def kb_username
- object.provider_username
- end
- end
-end
diff --git a/app/lib/proof_provider/keybase/verifier.rb b/app/lib/proof_provider/keybase/verifier.rb
deleted file mode 100644
index af69b1bfc84..00000000000
--- a/app/lib/proof_provider/keybase/verifier.rb
+++ /dev/null
@@ -1,59 +0,0 @@
-# frozen_string_literal: true
-
-class ProofProvider::Keybase::Verifier
- def initialize(local_username, provider_username, token, domain)
- @local_username = local_username
- @provider_username = provider_username
- @token = token
- @domain = domain
- end
-
- def valid?
- request = Request.new(:get, "#{ProofProvider::Keybase::BASE_URL}/_/api/1.0/sig/proof_valid.json", params: query_params)
-
- request.perform do |res|
- json = Oj.load(res.body_with_limit, mode: :strict)
-
- if json.is_a?(Hash)
- json.fetch('proof_valid', false)
- else
- false
- end
- end
- rescue Oj::ParseError, HTTP::Error, OpenSSL::SSL::SSLError
- false
- end
-
- def on_success_path(user_agent = nil)
- url = Addressable::URI.parse("#{ProofProvider::Keybase::BASE_URL}/_/proof_creation_success")
- url.query_values = query_params.merge(kb_ua: user_agent || 'unknown')
- url.to_s
- end
-
- def status
- request = Request.new(:get, "#{ProofProvider::Keybase::BASE_URL}/_/api/1.0/sig/proof_live.json", params: query_params)
-
- request.perform do |res|
- raise ProofProvider::Keybase::UnexpectedResponseError unless res.code == 200
-
- json = Oj.load(res.body_with_limit, mode: :strict)
-
- raise ProofProvider::Keybase::UnexpectedResponseError unless json.is_a?(Hash) && json.key?('proof_valid') && json.key?('proof_live')
-
- json
- end
- rescue Oj::ParseError, HTTP::Error, OpenSSL::SSL::SSLError
- raise ProofProvider::Keybase::UnexpectedResponseError
- end
-
- private
-
- def query_params
- {
- domain: @domain,
- kb_username: @provider_username,
- username: @local_username,
- sig_hash: @token,
- }
- end
-end
diff --git a/app/lib/proof_provider/keybase/worker.rb b/app/lib/proof_provider/keybase/worker.rb
deleted file mode 100644
index bcdd18cc561..00000000000
--- a/app/lib/proof_provider/keybase/worker.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-# frozen_string_literal: true
-
-class ProofProvider::Keybase::Worker
- include Sidekiq::Worker
-
- sidekiq_options queue: 'pull', retry: 20, unique: :until_executed
-
- sidekiq_retry_in do |count, exception|
- # Retry aggressively when the proof is valid but not live in Keybase.
- # This is likely because Keybase just hasn't noticed the proof being
- # served from here yet.
-
- if exception.class == ProofProvider::Keybase::ExpectedProofLiveError
- case count
- when 0..2 then 0.seconds
- when 2..6 then 1.second
- end
- end
- end
-
- def perform(proof_id)
- proof = proof_id.is_a?(AccountIdentityProof) ? proof_id : AccountIdentityProof.find(proof_id)
- status = proof.provider_instance.verifier.status
-
- # If Keybase thinks the proof is valid, and it exists here in Mastodon,
- # then it should be live. Keybase just has to notice that it's here
- # and then update its state. That might take a couple seconds.
- raise ProofProvider::Keybase::ExpectedProofLiveError if status['proof_valid'] && !status['proof_live']
-
- proof.update!(verified: status['proof_valid'], live: status['proof_live'])
- end
-end
diff --git a/app/models/account_identity_proof.rb b/app/models/account_identity_proof.rb
deleted file mode 100644
index 10b66cccf9b..00000000000
--- a/app/models/account_identity_proof.rb
+++ /dev/null
@@ -1,46 +0,0 @@
-# frozen_string_literal: true
-# == Schema Information
-#
-# Table name: account_identity_proofs
-#
-# id :bigint(8) not null, primary key
-# account_id :bigint(8)
-# provider :string default(""), not null
-# provider_username :string default(""), not null
-# token :text default(""), not null
-# verified :boolean default(FALSE), not null
-# live :boolean default(FALSE), not null
-# created_at :datetime not null
-# updated_at :datetime not null
-#
-
-class AccountIdentityProof < ApplicationRecord
- belongs_to :account
-
- validates :provider, inclusion: { in: ProofProvider::SUPPORTED_PROVIDERS }
- validates :provider_username, format: { with: /\A[a-z0-9_]+\z/i }, length: { minimum: 2, maximum: 30 }
- validates :provider_username, uniqueness: { scope: [:account_id, :provider] }
- validates :token, format: { with: /\A[a-f0-9]+\z/ }, length: { maximum: 66 }
-
- validate :validate_with_provider, if: :token_changed?
-
- scope :active, -> { where(verified: true, live: true) }
-
- after_commit :queue_worker, if: :saved_change_to_token?
-
- delegate :refresh!, :on_success_path, :badge, to: :provider_instance
-
- def provider_instance
- @provider_instance ||= ProofProvider.find(provider, self)
- end
-
- private
-
- def queue_worker
- provider_instance.worker_class.perform_async(id)
- end
-
- def validate_with_provider
- provider_instance.validate!
- end
-end
diff --git a/app/models/concerns/account_associations.rb b/app/models/concerns/account_associations.rb
index f2a4eae7728..f9e7a3bea77 100644
--- a/app/models/concerns/account_associations.rb
+++ b/app/models/concerns/account_associations.rb
@@ -7,8 +7,7 @@ module AccountAssociations
# Local users
has_one :user, inverse_of: :account, dependent: :destroy
- # Identity proofs
- has_many :identity_proofs, class_name: 'AccountIdentityProof', dependent: :destroy, inverse_of: :account
+ # E2EE
has_many :devices, dependent: :destroy, inverse_of: :account
# Timelines
diff --git a/app/models/concerns/account_merging.rb b/app/models/concerns/account_merging.rb
index 8d37c6e5679..119773e6b97 100644
--- a/app/models/concerns/account_merging.rb
+++ b/app/models/concerns/account_merging.rb
@@ -13,7 +13,7 @@ module AccountMerging
owned_classes = [
Status, StatusPin, MediaAttachment, Poll, Report, Tombstone, Favourite,
- Follow, FollowRequest, Block, Mute, AccountIdentityProof,
+ Follow, FollowRequest, Block, Mute,
AccountModerationNote, AccountPin, AccountStat, ListAccount,
PollVote, Mention, AccountDeletionRequest, AccountNote, FollowRecommendationSuppression
]
diff --git a/app/models/form/admin_settings.rb b/app/models/form/admin_settings.rb
index 0276ec058e1..3202d1fc246 100644
--- a/app/models/form/admin_settings.rb
+++ b/app/models/form/admin_settings.rb
@@ -27,7 +27,6 @@ class Form::AdminSettings
custom_css
profile_directory
hide_followers_count
- enable_keybase
flavour_and_skin
thumbnail
hero
@@ -53,7 +52,6 @@ class Form::AdminSettings
preview_sensitive_media
profile_directory
hide_followers_count
- enable_keybase
show_reblogs_in_public_timelines
show_replies_in_public_timelines
trends
diff --git a/app/serializers/activitypub/actor_serializer.rb b/app/serializers/activitypub/actor_serializer.rb
index a7d948976fb..48707aa16c1 100644
--- a/app/serializers/activitypub/actor_serializer.rb
+++ b/app/serializers/activitypub/actor_serializer.rb
@@ -6,8 +6,7 @@ class ActivityPub::ActorSerializer < ActivityPub::Serializer
context :security
context_extensions :manually_approves_followers, :featured, :also_known_as,
- :moved_to, :property_value, :identity_proof,
- :discoverable, :olm, :suspended
+ :moved_to, :property_value, :discoverable, :olm, :suspended
attributes :id, :type, :following, :followers,
:inbox, :outbox, :featured, :featured_tags,
@@ -143,7 +142,7 @@ class ActivityPub::ActorSerializer < ActivityPub::Serializer
end
def virtual_attachments
- object.suspended? ? [] : (object.fields + object.identity_proofs.active)
+ object.suspended? ? [] : object.fields
end
def moved_to
diff --git a/app/serializers/rest/identity_proof_serializer.rb b/app/serializers/rest/identity_proof_serializer.rb
deleted file mode 100644
index 0e7415935a0..00000000000
--- a/app/serializers/rest/identity_proof_serializer.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# frozen_string_literal: true
-
-class REST::IdentityProofSerializer < ActiveModel::Serializer
- attributes :provider, :provider_username, :updated_at, :proof_url, :profile_url
-
- def proof_url
- object.badge.proof_url
- end
-
- def profile_url
- object.badge.profile_url
- end
-
- def provider
- object.provider.capitalize
- end
-end
diff --git a/app/services/activitypub/process_account_service.rb b/app/services/activitypub/process_account_service.rb
index 4ab6912e5d4..ec5140720fe 100644
--- a/app/services/activitypub/process_account_service.rb
+++ b/app/services/activitypub/process_account_service.rb
@@ -27,7 +27,6 @@ class ActivityPub::ProcessAccountService < BaseService
create_account if @account.nil?
update_account
process_tags
- process_attachments
process_duplicate_accounts! if @options[:verified_webfinger]
else
@@ -301,23 +300,6 @@ class ActivityPub::ProcessAccountService < BaseService
end
end
- def process_attachments
- return if @json['attachment'].blank?
-
- previous_proofs = @account.identity_proofs.to_a
- current_proofs = []
-
- as_array(@json['attachment']).each do |attachment|
- next unless equals_or_includes?(attachment['type'], 'IdentityProof')
- current_proofs << process_identity_proof(attachment)
- end
-
- previous_proofs.each do |previous_proof|
- next if current_proofs.any? { |current_proof| current_proof.id == previous_proof.id }
- previous_proof.delete
- end
- end
-
def process_emoji(tag)
return if skip_download?
return if tag['name'].blank? || tag['icon'].blank? || tag['icon']['url'].blank?
@@ -334,12 +316,4 @@ class ActivityPub::ProcessAccountService < BaseService
emoji.image_remote_url = image_url
emoji.save
end
-
- def process_identity_proof(attachment)
- provider = attachment['signatureAlgorithm']
- provider_username = attachment['name']
- token = attachment['signatureValue']
-
- @account.identity_proofs.where(provider: provider, provider_username: provider_username).find_or_create_by(provider: provider, provider_username: provider_username, token: token)
- end
end
diff --git a/app/services/delete_account_service.rb b/app/services/delete_account_service.rb
index ac571d7e29d..0e3fedfe731 100644
--- a/app/services/delete_account_service.rb
+++ b/app/services/delete_account_service.rb
@@ -17,7 +17,6 @@ class DeleteAccountService < BaseService
domain_blocks
featured_tags
follow_requests
- identity_proofs
list_accounts
migrations
mute_relationships
@@ -45,7 +44,6 @@ class DeleteAccountService < BaseService
domain_blocks
featured_tags
follow_requests
- identity_proofs
list_accounts
migrations
mute_relationships
diff --git a/app/views/accounts/_bio.html.haml b/app/views/accounts/_bio.html.haml
index efc26d1366c..e8a49a1aa4a 100644
--- a/app/views/accounts/_bio.html.haml
+++ b/app/views/accounts/_bio.html.haml
@@ -1,16 +1,8 @@
-- proofs = account.identity_proofs.active
- fields = account.fields
.public-account-bio
- - unless fields.empty? && proofs.empty?
+ - unless fields.empty?
.account__header__fields
- - proofs.each do |proof|
- %dl
- %dt= proof.provider.capitalize
- %dd.verified
- = link_to fa_icon('check'), proof.badge.proof_url, class: 'verified__mark', title: t('accounts.link_verified_on', date: l(proof.updated_at))
- = link_to proof.provider_username, proof.badge.profile_url
-
- fields.each do |field|
%dl
%dt.emojify{ title: field.name }= Formatter.instance.format_field(account, field.name, custom_emojify: true)
diff --git a/app/views/admin/accounts/show.html.haml b/app/views/admin/accounts/show.html.haml
index 66eb4934275..2b6e28e8ddc 100644
--- a/app/views/admin/accounts/show.html.haml
+++ b/app/views/admin/accounts/show.html.haml
@@ -8,20 +8,12 @@
= render 'application/card', account: @account
- account = @account
-- proofs = account.identity_proofs.active
- fields = account.fields
-- unless fields.empty? && proofs.empty? && account.note.blank?
+- unless fields.empty? && account.note.blank?
.admin-account-bio
- - unless fields.empty? && proofs.empty?
+ - unless fields.empty?
%div
.account__header__fields
- - proofs.each do |proof|
- %dl
- %dt= proof.provider.capitalize
- %dd.verified
- = link_to fa_icon('check'), proof.badge.proof_url, class: 'verified__mark', title: t('accounts.link_verified_on', date: l(proof.updated_at))
- = link_to proof.provider_username, proof.badge.profile_url
-
- fields.each do |field|
%dl
%dt.emojify{ title: field.name }= Formatter.instance.format_field(account, field.name, custom_emojify: true)
diff --git a/app/views/admin/settings/edit.html.haml b/app/views/admin/settings/edit.html.haml
index 373811ea3b8..b9daae8f05b 100644
--- a/app/views/admin/settings/edit.html.haml
+++ b/app/views/admin/settings/edit.html.haml
@@ -89,9 +89,6 @@
.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')
- .fields-group
- = f.input :enable_keybase, as: :boolean, wrapper: :with_label, label: t('admin.settings.enable_keybase.title'), hint: t('admin.settings.enable_keybase.desc_html')
-
.fields-group
= f.input :show_reblogs_in_public_timelines, as: :boolean, wrapper: :with_label, label: t('admin.settings.show_reblogs_in_public_timelines.title'), hint: t('admin.settings.show_reblogs_in_public_timelines.desc_html')
diff --git a/app/views/settings/identity_proofs/_proof.html.haml b/app/views/settings/identity_proofs/_proof.html.haml
deleted file mode 100644
index 14e8e91be37..00000000000
--- a/app/views/settings/identity_proofs/_proof.html.haml
+++ /dev/null
@@ -1,21 +0,0 @@
-%tr
- %td
- = link_to proof.badge.profile_url, class: 'name-tag' do
- = image_tag proof.badge.avatar_url, width: 15, height: 15, alt: '', class: 'avatar'
- %span.username
- = proof.provider_username
- %span= "(#{proof.provider.capitalize})"
-
- %td
- - if proof.live?
- %span.positive-hint
- = fa_icon 'check-circle fw'
- = t('identity_proofs.active')
- - else
- %span.negative-hint
- = fa_icon 'times-circle fw'
- = t('identity_proofs.inactive')
-
- %td
- = table_link_to 'external-link', t('identity_proofs.view_proof'), proof.badge.proof_url if proof.badge.proof_url
- = table_link_to 'trash', t('identity_proofs.remove'), settings_identity_proof_path(proof), method: :delete, data: { confirm: t('admin.accounts.are_you_sure') }
diff --git a/app/views/settings/identity_proofs/index.html.haml b/app/views/settings/identity_proofs/index.html.haml
deleted file mode 100644
index d0ea03ecd0e..00000000000
--- a/app/views/settings/identity_proofs/index.html.haml
+++ /dev/null
@@ -1,17 +0,0 @@
-- content_for :page_title do
- = t('settings.identity_proofs')
-
-%p= t('identity_proofs.explanation_html')
-
-- unless @proofs.empty?
- %hr.spacer/
-
- .table-wrapper
- %table.table
- %thead
- %tr
- %th= t('identity_proofs.identity')
- %th= t('identity_proofs.status')
- %th
- %tbody
- = render partial: 'settings/identity_proofs/proof', collection: @proofs, as: :proof
diff --git a/app/views/settings/identity_proofs/new.html.haml b/app/views/settings/identity_proofs/new.html.haml
deleted file mode 100644
index 5e4e9895d16..00000000000
--- a/app/views/settings/identity_proofs/new.html.haml
+++ /dev/null
@@ -1,36 +0,0 @@
-- content_for :page_title do
- = t('identity_proofs.authorize_connection_prompt')
-
-.form-container
- .oauth-prompt
- %h2= t('identity_proofs.authorize_connection_prompt')
-
- = simple_form_for @proof, url: settings_identity_proofs_url, html: { method: :post } do |f|
- = f.input :provider, as: :hidden
- = f.input :provider_username, as: :hidden
- = f.input :token, as: :hidden
-
- = hidden_field_tag :user_agent, params[:user_agent]
-
- .connection-prompt
- .connection-prompt__row.connection-prompt__connection
- .connection-prompt__column
- = image_tag current_account.avatar.url(:original), size: 96, class: 'account__avatar'
-
- %p= t('identity_proofs.i_am_html', username: content_tag(:strong,current_account.username), service: site_hostname)
-
- .connection-prompt__column.connection-prompt__column-sep
- = fa_icon 'link'
-
- .connection-prompt__column
- = image_tag @proof.badge.avatar_url, size: 96, class: 'account__avatar'
-
- %p= t('identity_proofs.i_am_html', username: content_tag(:strong, @proof.provider_username), service: @proof.provider.capitalize)
-
- .connection-prompt__post
- = f.input :post_status, label: t('identity_proofs.publicize_checkbox'), as: :boolean, wrapper: :with_label, :input_html => { checked: true }
-
- = f.input :status_text, as: :text, input_html: { value: t('identity_proofs.publicize_toot', username: @proof.provider_username, service: @proof.provider.capitalize, url: @proof.badge.proof_url), rows: 4 }
-
- = f.button :button, t('identity_proofs.authorize'), type: :submit
- = link_to t('simple_form.no'), settings_identity_proofs_url, class: 'button negative'
diff --git a/config/initializers/chewy.rb b/config/initializers/chewy.rb
index fbbcbbcde07..f303fc54d3a 100644
--- a/config/initializers/chewy.rb
+++ b/config/initializers/chewy.rb
@@ -17,7 +17,7 @@ Chewy.settings = {
}
# We use our own async strategy even outside the request-response
-# cycle, which takes care of checking if ElasticSearch is enabled
+# cycle, which takes care of checking if Elasticsearch is enabled
# or not. However, mind that for the Rails console, the :urgent
# strategy is set automatically with no way to override it.
Chewy.root_strategy = :custom_sidekiq
@@ -32,8 +32,8 @@ module Chewy
end
end
-# ElasticSearch uses Faraday internally. Faraday interprets the
+# Elasticsearch uses Faraday internally. Faraday interprets the
# http_proxy env variable by default which leads to issues when
# Mastodon is run with hidden services enabled, because
-# ElasticSearch is *not* supposed to be accessed through a proxy
+# Elasticsearch is *not* supposed to be accessed through a proxy
Faraday.ignore_env_proxy = true
diff --git a/config/locales-glitch/en.yml b/config/locales-glitch/en.yml
index 6268727a785..5cc2625fc66 100644
--- a/config/locales-glitch/en.yml
+++ b/config/locales-glitch/en.yml
@@ -1,8 +1,6 @@
---
en:
admin:
- dashboard:
- keybase: Keybase integration
settings:
enable_keybase:
desc_html: Allow your users to prove their identity via keybase
diff --git a/config/locales-glitch/es.yml b/config/locales-glitch/es.yml
index 7e8de156001..ad942a0c080 100644
--- a/config/locales-glitch/es.yml
+++ b/config/locales-glitch/es.yml
@@ -1,8 +1,6 @@
---
es:
admin:
- dashboard:
- keybase: Integración con keybase
settings:
enable_keybase:
desc_html: Permite a tus usuarixs comprobar su identidad por medio de keybase
@@ -22,4 +20,4 @@ es:
generic:
use_this: Usar
settings:
- flavours: Ediciones
\ No newline at end of file
+ flavours: Ediciones
diff --git a/config/locales-glitch/ja.yml b/config/locales-glitch/ja.yml
index 2be4e9ea04f..3ecb46ccdc0 100644
--- a/config/locales-glitch/ja.yml
+++ b/config/locales-glitch/ja.yml
@@ -1,8 +1,6 @@
---
ja:
admin:
- dashboard:
- keybase: Keybase統合
settings:
enable_keybase:
desc_html: Keybaseにより身元の証明が可能となります
diff --git a/config/locales-glitch/ko.yml b/config/locales-glitch/ko.yml
index ae7f091bb00..aef10f67791 100644
--- a/config/locales-glitch/ko.yml
+++ b/config/locales-glitch/ko.yml
@@ -1,8 +1,6 @@
---
ko:
admin:
- dashboard:
- keybase: 키베이스 연동
settings:
enable_keybase:
desc_html: 사용자들이 키베이스를 통해 개인 신원을 증명할 수 있도록 허용
diff --git a/config/locales-glitch/zh-CN.yml b/config/locales-glitch/zh-CN.yml
index ea1db3eb9e7..37a8307e8e5 100644
--- a/config/locales-glitch/zh-CN.yml
+++ b/config/locales-glitch/zh-CN.yml
@@ -1,8 +1,6 @@
---
zh-CN:
admin:
- dashboard:
- keybase: Keybase 集成
settings:
enable_keybase:
desc_html: 允许你的用户使用 Keybase 证明身份
diff --git a/config/locales/en.yml b/config/locales/en.yml
index c98b828015e..1aa96ba0f72 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -985,26 +985,6 @@ en:
other: Something isn't quite right yet! Please review %{count} errors below
html_validator:
invalid_markup: 'contains invalid HTML markup: %{error}'
- identity_proofs:
- active: Active
- authorize: Yes, authorize
- authorize_connection_prompt: Authorize this cryptographic connection?
- errors:
- failed: The cryptographic connection failed. Please try again from %{provider}.
- keybase:
- invalid_token: Keybase tokens are hashes of signatures and must be 66 hex characters
- verification_failed: Keybase does not recognize this token as a signature of Keybase user %{kb_username}. Please retry from Keybase.
- wrong_user: Cannot create a proof for %{proving} while logged in as %{current}. Log in as %{proving} and try again.
- explanation_html: Here you can cryptographically connect your other identities from other platforms, such as Keybase. This lets other people send you encrypted messages on those platforms and allows them to trust that the content you send them comes from you.
- i_am_html: I am %{username} on %{service}.
- identity: Identity
- inactive: Inactive
- publicize_checkbox: 'And toot this:'
- publicize_toot: 'It is proven! I am %{username} on %{service}: %{url}'
- remove: Remove proof from account
- removed: Successfully removed proof from account
- status: Verification status
- view_proof: View proof
imports:
errors:
over_rows_processing_limit: contains more than %{count} rows
@@ -1279,7 +1259,6 @@ en:
edit_profile: Edit profile
export: Data export
featured_tags: Featured hashtags
- identity_proofs: Identity proofs
import: Import
import_and_export: Import and export
migrate: Account migration
diff --git a/config/navigation.rb b/config/navigation.rb
index 846d76c48be..53ee3d6c12b 100644
--- a/config/navigation.rb
+++ b/config/navigation.rb
@@ -7,7 +7,6 @@ SimpleNavigation::Configuration.run do |navigation|
n.item :profile, safe_join([fa_icon('user fw'), t('settings.profile')]), settings_profile_url, if: -> { current_user.functional? } do |s|
s.item :profile, safe_join([fa_icon('pencil fw'), t('settings.appearance')]), settings_profile_url
s.item :featured_tags, safe_join([fa_icon('hashtag fw'), t('settings.featured_tags')]), settings_featured_tags_url
- s.item :identity_proofs, safe_join([fa_icon('key fw'), t('settings.identity_proofs')]), settings_identity_proofs_path, highlights_on: %r{/settings/identity_proofs*}, if: proc { current_account.identity_proofs.exists? }
end
n.item :preferences, safe_join([fa_icon('cog fw'), t('settings.preferences')]), settings_preferences_url, if: -> { current_user.functional? } do |s|
diff --git a/config/routes.rb b/config/routes.rb
index 09d625abdd4..19d87e6d5ce 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -25,7 +25,6 @@ Rails.application.routes.draw do
get '.well-known/nodeinfo', to: 'well_known/nodeinfo#index', as: :nodeinfo, defaults: { format: 'json' }
get '.well-known/webfinger', to: 'well_known/webfinger#show', as: :webfinger
get '.well-known/change-password', to: redirect('/auth/edit')
- get '.well-known/keybase-proof-config', to: 'well_known/keybase_proof_config#show'
get '/nodeinfo/2.0', to: 'well_known/nodeinfo#show', as: :nodeinfo_schema
@@ -146,8 +145,6 @@ Rails.application.routes.draw do
resource :confirmation, only: [:new, :create]
end
- resources :identity_proofs, only: [:index, :new, :create, :destroy]
-
resources :applications, except: [:edit] do
member do
post :regenerate
@@ -334,9 +331,6 @@ Rails.application.routes.draw do
# OEmbed
get '/oembed', to: 'oembed#show', as: :oembed
- # Identity proofs
- get :proofs, to: 'proofs#index'
-
# JSON / REST API
namespace :v1 do
resources :statuses, only: [:create, :show, :destroy] do
diff --git a/config/settings.yml b/config/settings.yml
index 953e7b3eb21..0942098226c 100644
--- a/config/settings.yml
+++ b/config/settings.yml
@@ -33,7 +33,6 @@ defaults: &defaults
system_emoji_font: false
noindex: false
hide_followers_count: false
- enable_keybase: true
flavour: 'glitch'
skin: 'default'
aggregate_reblogs: true
diff --git a/db/post_migrate/20211126000907_drop_account_identity_proofs.rb b/db/post_migrate/20211126000907_drop_account_identity_proofs.rb
new file mode 100644
index 00000000000..44a6f1f08c3
--- /dev/null
+++ b/db/post_migrate/20211126000907_drop_account_identity_proofs.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+class DropAccountIdentityProofs < ActiveRecord::Migration[5.2]
+ disable_ddl_transaction!
+
+ def up
+ drop_table :account_identity_proofs
+ end
+
+ def down
+ raise ActiveRecord::IrreversibleMigration
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index e476f2e9892..edadeba1f3e 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 2021_11_23_212714) do
+ActiveRecord::Schema.define(version: 2021_11_26_000907) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -51,18 +51,6 @@ ActiveRecord::Schema.define(version: 2021_11_23_212714) do
t.index ["account_id", "domain"], name: "index_account_domain_blocks_on_account_id_and_domain", unique: true
end
- create_table "account_identity_proofs", force: :cascade do |t|
- t.bigint "account_id"
- t.string "provider", default: "", null: false
- t.string "provider_username", default: "", null: false
- t.text "token", default: "", null: false
- t.boolean "verified", default: false, null: false
- t.boolean "live", default: false, null: false
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.index ["account_id", "provider", "provider_username"], name: "index_account_proofs_on_account_and_provider_and_username", unique: true
- end
-
create_table "account_migrations", force: :cascade do |t|
t.bigint "account_id"
t.string "acct", default: "", null: false
@@ -1012,7 +1000,6 @@ ActiveRecord::Schema.define(version: 2021_11_23_212714) do
add_foreign_key "account_conversations", "conversations", on_delete: :cascade
add_foreign_key "account_deletion_requests", "accounts", on_delete: :cascade
add_foreign_key "account_domain_blocks", "accounts", name: "fk_206c6029bd", on_delete: :cascade
- add_foreign_key "account_identity_proofs", "accounts", on_delete: :cascade
add_foreign_key "account_migrations", "accounts", column: "target_account_id", on_delete: :nullify
add_foreign_key "account_migrations", "accounts", on_delete: :cascade
add_foreign_key "account_moderation_notes", "accounts"
diff --git a/lib/mastodon/search_cli.rb b/lib/mastodon/search_cli.rb
index 2d1ca1c0542..6ad9d7b6a94 100644
--- a/lib/mastodon/search_cli.rb
+++ b/lib/mastodon/search_cli.rb
@@ -17,10 +17,11 @@ module Mastodon
].freeze
option :concurrency, type: :numeric, default: 2, aliases: [:c], desc: 'Workload will be split between this number of threads'
+ option :batch_size, type: :numeric, default: 1_000, aliases: [:b], desc: 'Number of records in each batch'
option :only, type: :array, enum: %w(accounts tags statuses), desc: 'Only process these indices'
- desc 'deploy', 'Create or upgrade ElasticSearch indices and populate them'
+ desc 'deploy', 'Create or upgrade Elasticsearch indices and populate them'
long_desc <<~LONG_DESC
- If ElasticSearch is empty, this command will create the necessary indices
+ If Elasticsearch is empty, this command will create the necessary indices
and then import data from the database into those indices.
This command will also upgrade indices if the underlying schema has been
@@ -35,6 +36,11 @@ module Mastodon
exit(1)
end
+ if options[:batch_size] < 1
+ say('Cannot run with this batch_size setting, must be at least 1', :red)
+ exit(1)
+ end
+
indices = begin
if options[:only]
options[:only].map { |str| "#{str.camelize}Index".constantize }
@@ -73,7 +79,7 @@ module Mastodon
# is uneconomical. So we only ever add.
indices.each do |index|
progress.title = "Importing #{index} "
- batch_size = 1_000
+ batch_size = options[:batch_size]
slice_size = (batch_size / options[:concurrency]).ceil
index.adapter.default_scope.reorder(nil).find_in_batches(batch_size: batch_size) do |batch|
diff --git a/lib/mastodon/statuses_cli.rb b/lib/mastodon/statuses_cli.rb
index 8a18a3b2f23..f841529e051 100644
--- a/lib/mastodon/statuses_cli.rb
+++ b/lib/mastodon/statuses_cli.rb
@@ -6,6 +6,7 @@ require_relative 'cli_helper'
module Mastodon
class StatusesCLI < Thor
+ include CLIHelper
include ActionView::Helpers::NumberHelper
def self.exit_on_failure?
@@ -15,6 +16,8 @@ module Mastodon
option :days, type: :numeric, default: 90
option :clean_followed, type: :boolean
option :skip_media_remove, type: :boolean
+ option :vacuum, type: :boolean, default: false, desc: 'Reduce the file size and update the statistics. This option locks the table for a long time, so run it offline'
+ option :batch_size, type: :numeric, default: 1_000, aliases: [:b], desc: 'Number of records in each batch'
desc 'remove', 'Remove unreferenced statuses'
long_desc <<~LONG_DESC
Remove statuses that are not referenced by local user activity, such as
@@ -25,52 +28,89 @@ module Mastodon
indices before commencing, and removes them afterward.
LONG_DESC
def remove
+ if options[:batch_size] < 1
+ say('Cannot run with this batch_size setting, must be at least 1', :red)
+ exit(1)
+ end
+
say('Creating temporary database indices...')
- ActiveRecord::Base.connection.add_index(:accounts, :id, name: :index_accounts_local, where: 'domain is null', algorithm: :concurrently) unless ActiveRecord::Base.connection.index_name_exists?(:accounts, :index_accounts_local)
- ActiveRecord::Base.connection.add_index(:status_pins, :status_id, name: :index_status_pins_status_id, algorithm: :concurrently) unless ActiveRecord::Base.connection.index_name_exists?(:status_pins, :index_status_pins_status_id)
- ActiveRecord::Base.connection.add_index(:media_attachments, :remote_url, name: :index_media_attachments_remote_url, where: 'remote_url is not null', algorithm: :concurrently) unless ActiveRecord::Base.connection.index_name_exists?(:media_attachments, :index_media_attachments_remote_url)
+ ActiveRecord::Base.connection.add_index(:accounts, :id, name: :index_accounts_local, where: 'domain is null', algorithm: :concurrently, if_not_exists: true)
+ ActiveRecord::Base.connection.add_index(:status_pins, :status_id, name: :index_status_pins_status_id, algorithm: :concurrently, if_not_exists: true)
+ ActiveRecord::Base.connection.add_index(:media_attachments, :remote_url, name: :index_media_attachments_remote_url, where: 'remote_url is not null', algorithm: :concurrently, if_not_exists: true)
max_id = Mastodon::Snowflake.id_at(options[:days].days.ago)
start_at = Time.now.to_f
+ say('Extract the deletion target... This might take a while...')
+
+ ActiveRecord::Base.connection.create_table('statuses_to_be_deleted', temporary: true)
+
+ # Skip accounts followed by local accounts
+ clean_followed_sql = 'AND NOT EXISTS (SELECT 1 FROM follows WHERE statuses.account_id = follows.target_account_id)' unless options[:clean_followed]
+
+ ActiveRecord::Base.connection.exec_insert(<<-SQL.squish, 'SQL', [[nil, max_id]])
+ INSERT INTO statuses_to_be_deleted (id)
+ SELECT statuses.id FROM statuses WHERE deleted_at IS NULL AND NOT local AND uri IS NOT NULL AND (id < $1)
+ AND NOT EXISTS (SELECT 1 FROM statuses AS statuses1 WHERE statuses.id = statuses1.in_reply_to_id)
+ AND NOT EXISTS (SELECT 1 FROM statuses AS statuses1 WHERE statuses1.id = statuses.reblog_of_id AND (statuses1.uri IS NULL OR statuses1.local))
+ AND NOT EXISTS (SELECT 1 FROM statuses AS statuses1 WHERE statuses.id = statuses1.reblog_of_id AND (statuses1.uri IS NULL OR statuses1.local OR statuses1.id >= $1))
+ AND NOT EXISTS (SELECT 1 FROM status_pins WHERE statuses.id = status_id)
+ AND NOT EXISTS (SELECT 1 FROM mentions WHERE statuses.id = mentions.status_id AND mentions.account_id IN (SELECT accounts.id FROM accounts WHERE domain IS NULL))
+ AND NOT EXISTS (SELECT 1 FROM favourites WHERE statuses.id = favourites.status_id AND favourites.account_id IN (SELECT accounts.id FROM accounts WHERE domain IS NULL))
+ AND NOT EXISTS (SELECT 1 FROM bookmarks WHERE statuses.id = bookmarks.status_id AND bookmarks.account_id IN (SELECT accounts.id FROM accounts WHERE domain IS NULL))
+ #{clean_followed_sql}
+ SQL
+
+ say('Removing temporary database indices to restore write performance...')
+
+ ActiveRecord::Base.connection.remove_index(:accounts, name: :index_accounts_local, if_exists: true)
+ ActiveRecord::Base.connection.remove_index(:status_pins, name: :index_status_pins_status_id, if_exists: true)
+
say('Beginning removal... This might take a while...')
- scope = Status.remote.where('id < ?', max_id)
- # Skip reblogs of local statuses
- scope = scope.where('reblog_of_id NOT IN (SELECT statuses1.id FROM statuses AS statuses1 WHERE statuses1.id = statuses.reblog_of_id AND (statuses1.uri IS NULL OR statuses1.local))')
- # Skip statuses that are pinned on profiles
- scope = scope.where('id NOT IN (SELECT status_pins.status_id FROM status_pins WHERE statuses.id = status_id)')
- # Skip statuses that mention local accounts
- scope = scope.where('id NOT IN (SELECT mentions.status_id FROM mentions WHERE statuses.id = mentions.status_id AND mentions.account_id IN (SELECT accounts.id FROM accounts WHERE domain IS NULL))')
- # Skip statuses which have replies
- scope = scope.where('id NOT IN (SELECT statuses1.in_reply_to_id FROM statuses AS statuses1 WHERE statuses.id = statuses1.in_reply_to_id)')
- # Skip statuses reblogged by local accounts or with recent boosts
- scope = scope.where('id NOT IN (SELECT statuses1.reblog_of_id FROM statuses AS statuses1 WHERE statuses.id = statuses1.reblog_of_id AND (statuses1.uri IS NULL OR statuses1.local OR statuses1.id >= ?))', max_id)
- # Skip statuses favourited by local users
- scope = scope.where('id NOT IN (SELECT favourites.status_id FROM favourites WHERE statuses.id = favourites.status_id AND favourites.account_id IN (SELECT accounts.id FROM accounts WHERE domain IS NULL))')
- # Skip statuses bookmarked by local users
- scope = scope.where('id NOT IN (SELECT bookmarks.status_id FROM bookmarks WHERE statuses.id = bookmarks.status_id)')
-
- unless options[:clean_followed]
- # Skip accounts followed by local accounts
- scope = scope.where('account_id NOT IN (SELECT follows.target_account_id FROM follows WHERE statuses.account_id = follows.target_account_id)')
+ klass = Class.new(ApplicationRecord) do |c|
+ c.table_name = 'statuses_to_be_deleted'
end
- scope.in_batches.delete_all
+ Object.const_set('StatusToBeDeleted', klass)
+
+ scope = StatusToBeDeleted
+ processed = 0
+ removed = 0
+ progress = create_progress_bar(scope.count.fdiv(options[:batch_size]).ceil)
+
+ scope.reorder(nil).in_batches(of: options[:batch_size]) do |relation|
+ ids = relation.pluck(:id)
+ processed += ids.count
+ removed += Status.unscoped.where(id: ids).delete_all
+ progress.increment
+ end
+
+ progress.stop
+
+ if options[:vacuum]
+ say('Run VACUUM and ANALYZE to statuses...')
+
+ ActiveRecord::Base.connection.execute('VACUUM FULL ANALYZE statuses')
+ else
+ say('Run ANALYZE to statuses...')
+
+ ActiveRecord::Base.connection.execute('ANALYZE statuses')
+ end
unless options[:skip_media_remove]
say('Beginning removal of now-orphaned media attachments to free up disk space...')
Scheduler::MediaCleanupScheduler.new.perform
end
- say("Done after #{Time.now.to_f - start_at}s", :green)
+ say("Done after #{Time.now.to_f - start_at}s, removed #{removed} out of #{processed} statuses.", :green)
ensure
say('Removing temporary database indices to restore write performance...')
- ActiveRecord::Base.connection.remove_index(:accounts, name: :index_accounts_local) if ActiveRecord::Base.connection.index_name_exists?(:accounts, :index_accounts_local)
- ActiveRecord::Base.connection.remove_index(:status_pins, name: :index_status_pins_status_id) if ActiveRecord::Base.connection.index_name_exists?(:status_pins, :index_status_pins_status_id)
- ActiveRecord::Base.connection.remove_index(:media_attachments, name: :index_media_attachments_remote_url) if ActiveRecord::Base.connection.index_name_exists?(:media_attachments, :index_media_attachments_remote_url)
+ ActiveRecord::Base.connection.remove_index(:accounts, name: :index_accounts_local, if_exists: true)
+ ActiveRecord::Base.connection.remove_index(:status_pins, name: :index_status_pins_status_id, if_exists: true)
+ ActiveRecord::Base.connection.remove_index(:media_attachments, name: :index_media_attachments_remote_url, if_exists: true)
end
end
end
diff --git a/package.json b/package.json
index 2ca57473217..eb2617e802e 100644
--- a/package.json
+++ b/package.json
@@ -62,7 +62,7 @@
"private": true,
"dependencies": {
"@babel/core": "^7.16.0",
- "@babel/plugin-proposal-decorators": "^7.16.0",
+ "@babel/plugin-proposal-decorators": "^7.16.4",
"@babel/plugin-transform-react-inline-elements": "^7.16.0",
"@babel/plugin-transform-runtime": "^7.16.0",
"@babel/preset-env": "^7.16.0",
@@ -153,7 +153,7 @@
"regenerator-runtime": "^0.13.9",
"rellax": "^1.12.1",
"requestidlecallback": "^0.3.0",
- "reselect": "^4.1.2",
+ "reselect": "^4.1.4",
"rimraf": "^3.0.2",
"sass": "^1.43.4",
"sass-loader": "^10.2.0",
@@ -183,7 +183,7 @@
"eslint-plugin-import": "~2.25.3",
"eslint-plugin-jsx-a11y": "~6.5.1",
"eslint-plugin-promise": "~5.1.1",
- "eslint-plugin-react": "~7.27.0",
+ "eslint-plugin-react": "~7.27.1",
"jest": "^27.3.1",
"raf": "^3.4.1",
"react-intl-translations-manager": "^5.0.3",
diff --git a/spec/controllers/admin/statuses_controller_spec.rb b/spec/controllers/admin/statuses_controller_spec.rb
index d9690d83f22..e388caae205 100644
--- a/spec/controllers/admin/statuses_controller_spec.rb
+++ b/spec/controllers/admin/statuses_controller_spec.rb
@@ -8,6 +8,9 @@ describe Admin::StatusesController do
let!(:status) { Fabricate(:status, account: account) }
let(:media_attached_status) { Fabricate(:status, account: account, sensitive: !sensitive) }
let!(:media_attachment) { Fabricate(:media_attachment, account: account, status: media_attached_status) }
+ let(:last_media_attached_status) { Fabricate(:status, account: account, sensitive: !sensitive) }
+ let!(:last_media_attachment) { Fabricate(:media_attachment, account: account, status: last_media_attached_status) }
+ let!(:last_status) { Fabricate(:status, account: account) }
let(:sensitive) { true }
before do
@@ -19,7 +22,8 @@ describe Admin::StatusesController do
get :index, params: { account_id: account.id }
statuses = assigns(:statuses).to_a
- expect(statuses.size).to eq 2
+ expect(statuses.size).to eq 4
+ expect(statuses.first.id).to eq last_status.id
expect(response).to have_http_status(200)
end
@@ -27,7 +31,8 @@ describe Admin::StatusesController do
get :index, params: { account_id: account.id, media: true }
statuses = assigns(:statuses).to_a
- expect(statuses.size).to eq 1
+ expect(statuses.size).to eq 2
+ expect(statuses.first.id).to eq last_media_attached_status.id
expect(response).to have_http_status(200)
end
end
diff --git a/spec/controllers/api/proofs_controller_spec.rb b/spec/controllers/api/proofs_controller_spec.rb
deleted file mode 100644
index 2fe6150052c..00000000000
--- a/spec/controllers/api/proofs_controller_spec.rb
+++ /dev/null
@@ -1,93 +0,0 @@
-require 'rails_helper'
-
-describe Api::ProofsController do
- let(:alice) { Fabricate(:account, username: 'alice') }
-
- before do
- stub_request(:get, 'https://keybase.io/_/api/1.0/sig/proof_valid.json?domain=cb6e6126.ngrok.io&kb_username=crypto_alice&sig_hash=111111111111111111111111111111111111111111111111111111111111111111&username=alice').to_return(status: 200, body: '{"proof_valid":true,"proof_live":false}')
- stub_request(:get, 'https://keybase.io/_/api/1.0/sig/proof_live.json?domain=cb6e6126.ngrok.io&kb_username=crypto_alice&sig_hash=111111111111111111111111111111111111111111111111111111111111111111&username=alice').to_return(status: 200, body: '{"proof_valid":true,"proof_live":true}')
- stub_request(:get, 'https://keybase.io/_/api/1.0/sig/proof_valid.json?domain=cb6e6126.ngrok.io&kb_username=hidden_alice&sig_hash=222222222222222222222222222222222222222222222222222222222222222222&username=alice').to_return(status: 200, body: '{"proof_valid":true,"proof_live":true}')
- stub_request(:get, 'https://keybase.io/_/api/1.0/sig/proof_live.json?domain=cb6e6126.ngrok.io&kb_username=hidden_alice&sig_hash=222222222222222222222222222222222222222222222222222222222222222222&username=alice').to_return(status: 200, body: '{"proof_valid":true,"proof_live":true}')
- end
-
- describe 'GET #index' do
- describe 'with a non-existent username' do
- it '404s' do
- get :index, params: { username: 'nonexistent', provider: 'keybase' }
-
- expect(response).to have_http_status(:not_found)
- end
- end
-
- describe 'with a user that has no proofs' do
- it 'is an empty list of signatures' do
- get :index, params: { username: alice.username, provider: 'keybase' }
-
- expect(body_as_json[:signatures]).to eq []
- end
- end
-
- describe 'with a user that has a live, valid proof' do
- let(:token1) { '111111111111111111111111111111111111111111111111111111111111111111' }
- let(:kb_name1) { 'crypto_alice' }
-
- before do
- Fabricate(:account_identity_proof, account: alice, verified: true, live: true, token: token1, provider_username: kb_name1)
- end
-
- it 'is a list with that proof in it' do
- get :index, params: { username: alice.username, provider: 'keybase' }
-
- expect(body_as_json[:signatures]).to eq [
- { kb_username: kb_name1, sig_hash: token1 },
- ]
- end
-
- describe 'add one that is neither live nor valid' do
- let(:token2) { '222222222222222222222222222222222222222222222222222222222222222222' }
- let(:kb_name2) { 'hidden_alice' }
-
- before do
- Fabricate(:account_identity_proof, account: alice, verified: false, live: false, token: token2, provider_username: kb_name2)
- end
-
- it 'is a list with both proofs' do
- get :index, params: { username: alice.username, provider: 'keybase' }
-
- expect(body_as_json[:signatures]).to eq [
- { kb_username: kb_name1, sig_hash: token1 },
- { kb_username: kb_name2, sig_hash: token2 },
- ]
- end
- end
- end
-
- describe 'a user that has an avatar' do
- let(:alice) { Fabricate(:account, username: 'alice', avatar: attachment_fixture('avatar.gif')) }
-
- context 'and a proof' do
- let(:token1) { '111111111111111111111111111111111111111111111111111111111111111111' }
- let(:kb_name1) { 'crypto_alice' }
-
- before do
- Fabricate(:account_identity_proof, account: alice, verified: true, live: true, token: token1, provider_username: kb_name1)
- get :index, params: { username: alice.username, provider: 'keybase' }
- end
-
- it 'has two keys: signatures and avatar' do
- expect(body_as_json.keys).to match_array [:signatures, :avatar]
- end
-
- it 'has the correct signatures' do
- expect(body_as_json[:signatures]).to eq [
- { kb_username: kb_name1, sig_hash: token1 },
- ]
- end
-
- it 'has the correct avatar url' do
- expect(body_as_json[:avatar]).to match "https://cb6e6126.ngrok.io#{alice.avatar.url}"
- end
- end
- end
- end
-end
diff --git a/spec/controllers/settings/identity_proofs_controller_spec.rb b/spec/controllers/settings/identity_proofs_controller_spec.rb
deleted file mode 100644
index 16f2362278a..00000000000
--- a/spec/controllers/settings/identity_proofs_controller_spec.rb
+++ /dev/null
@@ -1,186 +0,0 @@
-require 'rails_helper'
-
-describe Settings::IdentityProofsController do
- include RoutingHelper
- render_views
-
- let(:user) { Fabricate(:user) }
- let(:valid_token) { '1'*66 }
- let(:kbname) { 'kbuser' }
- let(:provider) { 'keybase' }
- let(:findable_id) { Faker::Number.number(digits: 5) }
- let(:unfindable_id) { Faker::Number.number(digits: 5) }
- let(:new_proof_params) do
- { provider: provider, provider_username: kbname, token: valid_token, username: user.account.username }
- end
- let(:status_text) { "i just proved that i am also #{kbname} on #{provider}." }
- let(:status_posting_params) do
- { post_status: '0', status_text: status_text }
- end
- let(:postable_params) do
- { account_identity_proof: new_proof_params.merge(status_posting_params) }
- end
-
- before do
- allow_any_instance_of(ProofProvider::Keybase::Verifier).to receive(:status) { { 'proof_valid' => true, 'proof_live' => true } }
- sign_in user, scope: :user
- end
-
- describe 'new proof creation' do
- context 'GET #new' do
- before do
- allow_any_instance_of(ProofProvider::Keybase::Badge).to receive(:avatar_url) { full_pack_url('media/images/void.png') }
- end
-
- context 'with all of the correct params' do
- it 'renders the template' do
- get :new, params: new_proof_params
- expect(response).to render_template(:new)
- end
- end
-
- context 'without any params' do
- it 'redirects to :index' do
- get :new, params: {}
- expect(response).to redirect_to settings_identity_proofs_path
- end
- end
-
- context 'with params to prove a different, not logged-in user' do
- let(:wrong_user_params) { new_proof_params.merge(username: 'someone_else') }
-
- it 'shows a helpful alert' do
- get :new, params: wrong_user_params
- expect(flash[:alert]).to eq I18n.t('identity_proofs.errors.wrong_user', proving: 'someone_else', current: user.account.username)
- end
- end
-
- context 'with params to prove the same username cased differently' do
- let(:capitalized_username) { new_proof_params.merge(username: user.account.username.upcase) }
-
- it 'renders the new template' do
- get :new, params: capitalized_username
- expect(response).to render_template(:new)
- end
- end
- end
-
- context 'POST #create' do
- context 'when saving works' do
- before do
- allow(ProofProvider::Keybase::Worker).to receive(:perform_async)
- allow_any_instance_of(ProofProvider::Keybase::Verifier).to receive(:valid?) { true }
- allow_any_instance_of(AccountIdentityProof).to receive(:on_success_path) { root_url }
- end
-
- it 'serializes a ProofProvider::Keybase::Worker' do
- expect(ProofProvider::Keybase::Worker).to receive(:perform_async)
- post :create, params: postable_params
- end
-
- it 'delegates redirection to the proof provider' do
- expect_any_instance_of(AccountIdentityProof).to receive(:on_success_path)
- post :create, params: postable_params
- expect(response).to redirect_to root_url
- end
-
- it 'does not post a status' do
- expect(PostStatusService).not_to receive(:new)
- post :create, params: postable_params
- end
-
- context 'and the user has requested to post a status' do
- let(:postable_params_with_status) do
- postable_params.tap { |p| p[:account_identity_proof][:post_status] = '1' }
- end
-
- it 'posts a status' do
- expect_any_instance_of(PostStatusService).to receive(:call).with(user.account, text: status_text)
-
- post :create, params: postable_params_with_status
- end
- end
- end
-
- context 'when saving fails' do
- before do
- allow_any_instance_of(ProofProvider::Keybase::Verifier).to receive(:valid?) { false }
- end
-
- it 'redirects to :index' do
- post :create, params: postable_params
- expect(response).to redirect_to settings_identity_proofs_path
- end
-
- it 'flashes a helpful message' do
- post :create, params: postable_params
- expect(flash[:alert]).to eq I18n.t('identity_proofs.errors.failed', provider: 'Keybase')
- end
- end
-
- context 'it can also do an update if the provider and username match an existing proof' do
- before do
- allow_any_instance_of(ProofProvider::Keybase::Verifier).to receive(:valid?) { true }
- allow(ProofProvider::Keybase::Worker).to receive(:perform_async)
- Fabricate(:account_identity_proof, account: user.account, provider: provider, provider_username: kbname)
- allow_any_instance_of(AccountIdentityProof).to receive(:on_success_path) { root_url }
- end
-
- it 'calls update with the new token' do
- expect_any_instance_of(AccountIdentityProof).to receive(:save) do |proof|
- expect(proof.token).to eq valid_token
- end
-
- post :create, params: postable_params
- end
- end
- end
- end
-
- describe 'GET #index' do
- context 'with no existing proofs' do
- it 'shows the helpful explanation' do
- get :index
- expect(response.body).to match I18n.t('identity_proofs.explanation_html')
- end
- end
-
- context 'with two proofs' do
- before do
- allow_any_instance_of(ProofProvider::Keybase::Verifier).to receive(:valid?) { true }
- @proof1 = Fabricate(:account_identity_proof, account: user.account)
- @proof2 = Fabricate(:account_identity_proof, account: user.account)
- allow_any_instance_of(AccountIdentityProof).to receive(:badge) { double(avatar_url: '', profile_url: '', proof_url: '') }
- allow_any_instance_of(AccountIdentityProof).to receive(:refresh!) {}
- end
-
- it 'has the first proof username on the page' do
- get :index
- expect(response.body).to match /#{Regexp.quote(@proof1.provider_username)}/
- end
-
- it 'has the second proof username on the page' do
- get :index
- expect(response.body).to match /#{Regexp.quote(@proof2.provider_username)}/
- end
- end
- end
-
- describe 'DELETE #destroy' do
- before do
- allow_any_instance_of(ProofProvider::Keybase::Verifier).to receive(:valid?) { true }
- @proof1 = Fabricate(:account_identity_proof, account: user.account)
- allow_any_instance_of(AccountIdentityProof).to receive(:badge) { double(avatar_url: '', profile_url: '', proof_url: '') }
- allow_any_instance_of(AccountIdentityProof).to receive(:refresh!) {}
- delete :destroy, params: { id: @proof1.id }
- end
-
- it 'redirects to :index' do
- expect(response).to redirect_to settings_identity_proofs_path
- end
-
- it 'removes the proof' do
- expect(AccountIdentityProof.where(id: @proof1.id).count).to eq 0
- end
- end
-end
diff --git a/spec/controllers/well_known/keybase_proof_config_controller_spec.rb b/spec/controllers/well_known/keybase_proof_config_controller_spec.rb
deleted file mode 100644
index 00f251c3c67..00000000000
--- a/spec/controllers/well_known/keybase_proof_config_controller_spec.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-require 'rails_helper'
-
-describe WellKnown::KeybaseProofConfigController, type: :controller do
- render_views
-
- describe 'GET #show' do
- it 'renders json' do
- get :show
-
- expect(response).to have_http_status(200)
- expect(response.media_type).to eq 'application/json'
- expect { JSON.parse(response.body) }.not_to raise_exception
- end
- end
-end
diff --git a/spec/fabricators/account_identity_proof_fabricator.rb b/spec/fabricators/account_identity_proof_fabricator.rb
deleted file mode 100644
index 7b932fa9687..00000000000
--- a/spec/fabricators/account_identity_proof_fabricator.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-Fabricator(:account_identity_proof) do
- account
- provider 'keybase'
- provider_username { sequence(:provider_username) { |i| "#{Faker::Lorem.characters(number: 15)}" } }
- token { sequence(:token) { |i| "#{i}#{Faker::Crypto.sha1()*2}"[0..65] } }
- verified false
- live false
-end
diff --git a/spec/lib/proof_provider/keybase/verifier_spec.rb b/spec/lib/proof_provider/keybase/verifier_spec.rb
deleted file mode 100644
index 0081a735df0..00000000000
--- a/spec/lib/proof_provider/keybase/verifier_spec.rb
+++ /dev/null
@@ -1,82 +0,0 @@
-require 'rails_helper'
-
-describe ProofProvider::Keybase::Verifier do
- let(:my_domain) { Rails.configuration.x.local_domain }
-
- let(:keybase_proof) do
- local_proof = AccountIdentityProof.new(
- provider: 'Keybase',
- provider_username: 'cryptoalice',
- token: '11111111111111111111111111'
- )
-
- described_class.new('alice', 'cryptoalice', '11111111111111111111111111', my_domain)
- end
-
- let(:query_params) do
- "domain=#{my_domain}&kb_username=cryptoalice&sig_hash=11111111111111111111111111&username=alice"
- end
-
- describe '#valid?' do
- let(:base_url) { 'https://keybase.io/_/api/1.0/sig/proof_valid.json' }
-
- context 'when valid' do
- before do
- json_response_body = '{"status":{"code":0,"name":"OK"},"proof_valid":true}'
- stub_request(:get, "#{base_url}?#{query_params}").to_return(status: 200, body: json_response_body)
- end
-
- it 'calls out to keybase and returns true' do
- expect(keybase_proof.valid?).to eq true
- end
- end
-
- context 'when invalid' do
- before do
- json_response_body = '{"status":{"code":0,"name":"OK"},"proof_valid":false}'
- stub_request(:get, "#{base_url}?#{query_params}").to_return(status: 200, body: json_response_body)
- end
-
- it 'calls out to keybase and returns false' do
- expect(keybase_proof.valid?).to eq false
- end
- end
-
- context 'with an unexpected api response' do
- before do
- json_response_body = '{"status":{"code":100,"desc":"wrong size hex_id","fields":{"sig_hash":"wrong size hex_id"},"name":"INPUT_ERROR"}}'
- stub_request(:get, "#{base_url}?#{query_params}").to_return(status: 200, body: json_response_body)
- end
-
- it 'swallows the error and returns false' do
- expect(keybase_proof.valid?).to eq false
- end
- end
- end
-
- describe '#status' do
- let(:base_url) { 'https://keybase.io/_/api/1.0/sig/proof_live.json' }
-
- context 'with a normal response' do
- before do
- json_response_body = '{"status":{"code":0,"name":"OK"},"proof_live":false,"proof_valid":true}'
- stub_request(:get, "#{base_url}?#{query_params}").to_return(status: 200, body: json_response_body)
- end
-
- it 'calls out to keybase and returns the status fields as proof_valid and proof_live' do
- expect(keybase_proof.status).to include({ 'proof_valid' => true, 'proof_live' => false })
- end
- end
-
- context 'with an unexpected keybase response' do
- before do
- json_response_body = '{"status":{"code":100,"desc":"missing non-optional field sig_hash","fields":{"sig_hash":"missing non-optional field sig_hash"},"name":"INPUT_ERROR"}}'
- stub_request(:get, "#{base_url}?#{query_params}").to_return(status: 200, body: json_response_body)
- end
-
- it 'raises a ProofProvider::Keybase::UnexpectedResponseError' do
- expect { keybase_proof.status }.to raise_error ProofProvider::Keybase::UnexpectedResponseError
- end
- end
- end
-end
diff --git a/spec/services/activitypub/process_account_service_spec.rb b/spec/services/activitypub/process_account_service_spec.rb
index 1b1d878a7e6..7728b9ba829 100644
--- a/spec/services/activitypub/process_account_service_spec.rb
+++ b/spec/services/activitypub/process_account_service_spec.rb
@@ -30,51 +30,6 @@ RSpec.describe ActivityPub::ProcessAccountService, type: :service do
end
end
- context 'identity proofs' do
- let(:payload) do
- {
- id: 'https://foo.test',
- type: 'Actor',
- inbox: 'https://foo.test/inbox',
- attachment: [
- { type: 'IdentityProof', name: 'Alice', signatureAlgorithm: 'keybase', signatureValue: 'a' * 66 },
- ],
- }.with_indifferent_access
- end
-
- it 'parses out of attachment' do
- allow(ProofProvider::Keybase::Worker).to receive(:perform_async)
-
- account = subject.call('alice', 'example.com', payload)
-
- expect(account.identity_proofs.count).to eq 1
-
- proof = account.identity_proofs.first
-
- expect(proof.provider).to eq 'keybase'
- expect(proof.provider_username).to eq 'Alice'
- expect(proof.token).to eq 'a' * 66
- end
-
- it 'removes no longer present proofs' do
- allow(ProofProvider::Keybase::Worker).to receive(:perform_async)
-
- account = Fabricate(:account, username: 'alice', domain: 'example.com')
- old_proof = Fabricate(:account_identity_proof, account: account, provider: 'keybase', provider_username: 'Bob', token: 'b' * 66)
-
- subject.call('alice', 'example.com', payload)
-
- expect(account.identity_proofs.count).to eq 1
- expect(account.identity_proofs.find_by(id: old_proof.id)).to be_nil
- end
-
- it 'queues a validity check on the proof' do
- allow(ProofProvider::Keybase::Worker).to receive(:perform_async)
- account = subject.call('alice', 'example.com', payload)
- expect(ProofProvider::Keybase::Worker).to have_received(:perform_async)
- end
- end
-
context 'when account is not suspended' do
let!(:account) { Fabricate(:account, username: 'alice', domain: 'example.com') }
diff --git a/yarn.lock b/yarn.lock
index cc66e828e91..22e18f39ca7 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -327,10 +327,10 @@
"@babel/helper-plugin-utils" "^7.14.5"
"@babel/plugin-syntax-class-static-block" "^7.14.5"
-"@babel/plugin-proposal-decorators@^7.16.0":
- version "7.16.0"
- resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.16.0.tgz#515db5f6891611c0d176b63ede0844fbd9be797b"
- integrity sha512-ttvhKuVnQwoNQrcTd1oe6o49ahaZ1kns1fsJKzTVOaS/FJDJoK4qzgVS68xzJhYUMgTnbXW6z/T6rlP3lL7tJw==
+"@babel/plugin-proposal-decorators@^7.16.4":
+ version "7.16.4"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.16.4.tgz#9b35ce0716425a93b978e79099e5f7ba217c1364"
+ integrity sha512-RESBNX16eNqnBeEVR5sCJpnW0mHiNLNNvGA8PrRuK/4ZJ4TO+6bHleRUuGQYDERVySOKtOhSya/C4MIhwAMAgg==
dependencies:
"@babel/helper-create-class-features-plugin" "^7.16.0"
"@babel/helper-plugin-utils" "^7.14.5"
@@ -4263,10 +4263,10 @@ eslint-plugin-promise@~5.1.1:
resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-5.1.1.tgz#9674d11c056d1bafac38e4a3a9060be740988d90"
integrity sha512-XgdcdyNzHfmlQyweOPTxmc7pIsS6dE4MvwhXWMQ2Dxs1XAL2GJDilUsjWen6TWik0aSI+zD/PqocZBblcm9rdA==
-eslint-plugin-react@~7.27.0:
- version "7.27.0"
- resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.27.0.tgz#f952c76517a3915b81c7788b220b2b4c96703124"
- integrity sha512-0Ut+CkzpppgFtoIhdzi2LpdpxxBvgFf99eFqWxJnUrO7mMe0eOiNpou6rvNYeVVV6lWZvTah0BFne7k5xHjARg==
+eslint-plugin-react@~7.27.1:
+ version "7.27.1"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.27.1.tgz#469202442506616f77a854d91babaae1ec174b45"
+ integrity sha512-meyunDjMMYeWr/4EBLTV1op3iSG3mjT/pz5gti38UzfM4OPpNc2m0t2xvKCOMU5D6FSdd34BIMFOvQbW+i8GAA==
dependencies:
array-includes "^3.1.4"
array.prototype.flatmap "^1.2.5"
@@ -9266,10 +9266,10 @@ requires-port@^1.0.0:
resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=
-reselect@^4.1.2:
- version "4.1.2"
- resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.1.2.tgz#7bf642992d143d4f3b0f2dca8aa52018808a1d51"
- integrity sha512-wg60ebcPOtxcptIUfrr7Jt3h4BR86cCW3R7y4qt65lnNb4yz4QgrXcbSioVsIOYguyz42+XTHIyJ5TEruzkFgQ==
+reselect@^4.1.4:
+ version "4.1.4"
+ resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.1.4.tgz#66df0aff41b6ee0f51e2cc17cfaf2c1995916f32"
+ integrity sha512-i1LgXw8DKSU5qz1EV0ZIKz4yIUHJ7L3bODh+Da6HmVSm9vdL/hG7IpbgzQ3k2XSirzf8/eI7OMEs81gb1VV2fQ==
resolve-cwd@^2.0.0:
version "2.0.0"