Remove Keybase integration (#17045)
parent
12b3ff6c6d
commit
7de0ee7aba
@ -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
|
|
@ -1,60 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
class Settings::IdentityProofsController < Settings::BaseController
|
|
||||||
before_action :check_required_params, 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_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
|
|
@ -1,9 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module WellKnown
|
|
||||||
class KeybaseProofConfigController < ActionController::Base
|
|
||||||
def show
|
|
||||||
render json: {}, serializer: ProofProvider::Keybase::ConfigSerializer, root: 'keybase_config'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -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,
|
|
||||||
});
|
|
@ -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;
|
|
||||||
}
|
|
||||||
};
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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') }
|
|
@ -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
|
|
@ -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'
|
|
@ -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
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
Loading…
Reference in new issue