Skip to content

Commit

Permalink
squashed identity proof updates (mastodon#10375)
Browse files Browse the repository at this point in the history
  • Loading branch information
xgess authored and hiyuki2578 committed Oct 2, 2019
1 parent 832d2ad commit 86afc4c
Show file tree
Hide file tree
Showing 20 changed files with 214 additions and 25 deletions.
19 changes: 19 additions & 0 deletions app/controllers/api/v1/accounts/identity_proofs_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# frozen_string_literal: true

class Api::V1::Accounts::IdentityProofsController < Api::BaseController
before_action :require_user!
before_action :set_account

respond_to :json

def index
@proofs = @account.identity_proofs.active
render json: @proofs, each_serializer: REST::IdentityProofSerializer
end

private

def set_account
@account = Account.find(params[:account_id])
end
end
22 changes: 20 additions & 2 deletions app/controllers/settings/identity_proofs_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,20 @@ def new
provider_username: params[:provider_username]
)

render layout: 'auth'
if current_account.username == params[:username]
render layout: 'auth'
else
flash[:alert] = I18n.t('identity_proofs.errors.wrong_user', proving: params[:username], current: current_account.username)
redirect_to settings_identity_proofs_path
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
flash[:alert] = I18n.t('identity_proofs.errors.failed', provider: @proof.provider.capitalize)
Expand All @@ -36,10 +42,22 @@ def create
private

def check_required_params
redirect_to settings_identity_proofs_path unless [:provider, :provider_username, :token].all? { |k| params[k].present? }
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

def set_body_classes
@body_classes = ''
end
end
30 changes: 30 additions & 0 deletions app/javascript/mastodon/actions/identity_proofs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
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,
});
17 changes: 15 additions & 2 deletions app/javascript/mastodon/features/account/components/header.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ class Header extends ImmutablePureComponent {

static propTypes = {
account: ImmutablePropTypes.map,
identity_props: ImmutablePropTypes.list,
onFollow: PropTypes.func.isRequired,
onBlock: PropTypes.func.isRequired,
intl: PropTypes.object.isRequired,
Expand All @@ -81,7 +82,7 @@ class Header extends ImmutablePureComponent {
}

render () {
const { account, intl, domain } = this.props;
const { account, intl, domain, identity_proofs } = this.props;

if (!account) {
return null;
Expand Down Expand Up @@ -234,8 +235,20 @@ class Header extends ImmutablePureComponent {

<div className='account__header__extra'>
<div className='account__header__bio'>
{fields.size > 0 && (
{ (fields.size > 0 || identity_proofs.size > 0) && (
<div className='account__header__fields'>
{identity_proofs.map((proof, i) => (
<dl key={i}>
<dt dangerouslySetInnerHTML={{ __html: proof.get('provider') }} />

<dd className='verified'>
<a href={proof.get('proof_url')} target='_blank' rel='noopener'><span title={intl.formatMessage(messages.linkVerifiedOn, { date: intl.formatDate(proof.get('updated_at'), dateFormatOptions) })}>
<Icon id='check' className='verified__mark' />
</span></a>
<a href={proof.get('profile_url')} target='_blank' rel='noopener'><span dangerouslySetInnerHTML={{ __html: ' '+proof.get('provider_username') }} /></a>
</dd>
</dl>
))}
{fields.map((pair, i) => (
<dl key={i}>
<dt dangerouslySetInnerHTML={{ __html: pair.get('name_emojified') }} title={pair.get('name')} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ 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,
Expand Down Expand Up @@ -84,7 +85,7 @@ export default class Header extends ImmutablePureComponent {
}

render () {
const { account, hideTabs } = this.props;
const { account, hideTabs, identity_proofs } = this.props;

if (account === null) {
return <MissingIndicator />;
Expand All @@ -96,6 +97,7 @@ export default class Header extends ImmutablePureComponent {

<InnerHeader
account={account}
identity_proofs={identity_proofs}
onFollow={this.handleFollow}
onBlock={this.handleBlock}
onMention={this.handleMention}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { openModal } from '../../../actions/modal';
import { blockDomain, unblockDomain } from '../../../actions/domain_blocks';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import { unfollowModal } from '../../../initial_state';
import { List as ImmutableList } from 'immutable';

const messages = defineMessages({
unfollowConfirm: { id: 'confirmations.unfollow.confirm', defaultMessage: 'Unfollow' },
Expand All @@ -35,6 +36,7 @@ const makeMapStateToProps = () => {
const mapStateToProps = (state, { accountId }) => ({
account: getAccount(state, accountId),
domain: state.getIn(['meta', 'domain']),
identity_proofs: state.getIn(['identity_proofs', accountId], ImmutableList()),
});

return mapStateToProps;
Expand Down
3 changes: 3 additions & 0 deletions app/javascript/mastodon/features/account_timeline/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ 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';

const mapStateToProps = (state, { params: { accountId }, withReplies = false }) => {
const path = withReplies ? `${accountId}:with_replies` : accountId;
Expand Down Expand Up @@ -42,6 +43,7 @@ class AccountTimeline extends ImmutablePureComponent {
const { params: { accountId }, withReplies } = this.props;

this.props.dispatch(fetchAccount(accountId));
this.props.dispatch(fetchAccountIdentityProofs(accountId));
if (!withReplies) {
this.props.dispatch(expandAccountFeaturedTimeline(accountId));
}
Expand All @@ -51,6 +53,7 @@ class AccountTimeline extends ImmutablePureComponent {
componentWillReceiveProps (nextProps) {
if ((nextProps.params.accountId !== this.props.params.accountId && nextProps.params.accountId) || nextProps.withReplies !== this.props.withReplies) {
this.props.dispatch(fetchAccount(nextProps.params.accountId));
this.props.dispatch(fetchAccountIdentityProofs(nextProps.params.accountId));
if (!nextProps.withReplies) {
this.props.dispatch(expandAccountFeaturedTimeline(nextProps.params.accountId));
}
Expand Down
25 changes: 25 additions & 0 deletions app/javascript/mastodon/reducers/identity_proofs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
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;
}
};
2 changes: 2 additions & 0 deletions app/javascript/mastodon/reducers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import filters from './filters';
import conversations from './conversations';
import suggestions from './suggestions';
import polls from './polls';
import identity_proofs from './identity_proofs';

const reducers = {
dropdown_menu,
Expand All @@ -56,6 +57,7 @@ const reducers = {
notifications,
height_cache,
custom_emojis,
identity_proofs,
lists,
listEditor,
listAdder,
Expand Down
8 changes: 3 additions & 5 deletions app/javascript/styles/mastodon/containers.scss
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,10 @@
}

.logo-container {
margin: 100px auto;
margin-bottom: 50px;
margin: 100px auto 50px;

@media screen and (max-width: 400px) {
margin: 30px auto;
margin-bottom: 20px;
@media screen and (max-width: 500px) {
margin: 40px auto 0;
}

h1 {
Expand Down
9 changes: 8 additions & 1 deletion app/javascript/styles/mastodon/forms.scss
Original file line number Diff line number Diff line change
Expand Up @@ -854,13 +854,19 @@ code {
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 {
Expand All @@ -882,12 +888,13 @@ code {
height: 100%;
left: 50%;
position: absolute;
top: 0;
width: 1px;
}
}

&__row {
align-items: center;
align-items: flex-start;
display: flex;
flex-direction: row;
}
Expand Down
3 changes: 2 additions & 1 deletion app/lib/proof_provider/keybase.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# frozen_string_literal: true

class ProofProvider::Keybase
BASE_URL = 'https://keybase.io'
BASE_URL = ENV.fetch('KEYBASE_BASE_URL', 'https://keybase.io')
DOMAIN = ENV.fetch('KEYBASE_DOMAIN', Rails.configuration.x.local_domain)

class Error < StandardError; end

Expand Down
4 changes: 2 additions & 2 deletions app/lib/proof_provider/keybase/config_serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ def version
end

def domain
Rails.configuration.x.local_domain
ProofProvider::Keybase::DOMAIN
end

def display_name
Expand Down Expand Up @@ -66,6 +66,6 @@ def avatar_path
end

def contact
[Setting.site_contact_email.presence].compact
[Setting.site_contact_email.presence || 'unknown'].compact
end
end
6 changes: 1 addition & 5 deletions app/lib/proof_provider/keybase/verifier.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,10 @@ def status

def query_params
{
domain: domain,
domain: ProofProvider::Keybase::DOMAIN,
kb_username: @provider_username,
username: @local_username,
sig_hash: @token,
}
end

def domain
Rails.configuration.x.local_domain
end
end
2 changes: 1 addition & 1 deletion app/models/account_identity_proof.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class AccountIdentityProof < ApplicationRecord

scope :active, -> { where(verified: true, live: true) }

after_create_commit :queue_worker
after_commit :queue_worker, if: :saved_change_to_token?

delegate :refresh!, :on_success_path, :badge, to: :provider_instance

Expand Down
17 changes: 17 additions & 0 deletions app/serializers/rest/identity_proof_serializer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# 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
5 changes: 5 additions & 0 deletions app/views/settings/identity_proofs/new.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,10 @@

%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'
3 changes: 3 additions & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -648,10 +648,13 @@ en:
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, such as a Keybase profile. This lets other people send you encrypted messages and trust content you send them.
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}'
status: Verification status
view_proof: View proof
imports:
Expand Down
1 change: 1 addition & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,7 @@
resources :followers, only: :index, controller: 'accounts/follower_accounts'
resources :following, only: :index, controller: 'accounts/following_accounts'
resources :lists, only: :index, controller: 'accounts/lists'
resources :identity_proofs, only: :index, controller: 'accounts/identity_proofs'

member do
post :follow
Expand Down
Loading

0 comments on commit 86afc4c

Please sign in to comment.