142 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
			
		
		
	
	
			142 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
# frozen_string_literal: true
 | 
						|
 | 
						|
# == Schema Information
 | 
						|
#
 | 
						|
# Table name: fasp_providers
 | 
						|
#
 | 
						|
#  id                      :bigint(8)        not null, primary key
 | 
						|
#  base_url                :string           not null
 | 
						|
#  capabilities            :jsonb            not null
 | 
						|
#  confirmed               :boolean          default(FALSE), not null
 | 
						|
#  contact_email           :string
 | 
						|
#  fediverse_account       :string
 | 
						|
#  name                    :string           not null
 | 
						|
#  privacy_policy          :jsonb
 | 
						|
#  provider_public_key_pem :string           not null
 | 
						|
#  remote_identifier       :string           not null
 | 
						|
#  server_private_key_pem  :string           not null
 | 
						|
#  sign_in_url             :string
 | 
						|
#  created_at              :datetime         not null
 | 
						|
#  updated_at              :datetime         not null
 | 
						|
#
 | 
						|
class Fasp::Provider < ApplicationRecord
 | 
						|
  include DebugConcern
 | 
						|
 | 
						|
  has_many :fasp_debug_callbacks, inverse_of: :fasp_provider, class_name: 'Fasp::DebugCallback', dependent: :delete_all
 | 
						|
 | 
						|
  validates :name, presence: true
 | 
						|
  validates :base_url, presence: true, url: true
 | 
						|
  validates :provider_public_key_pem, presence: true
 | 
						|
  validates :remote_identifier, presence: true
 | 
						|
 | 
						|
  before_create :create_keypair
 | 
						|
  after_commit :update_remote_capabilities
 | 
						|
 | 
						|
  def capabilities
 | 
						|
    read_attribute(:capabilities).map do |attributes|
 | 
						|
      Fasp::Capability.new(attributes)
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  def capabilities_attributes=(attributes)
 | 
						|
    capability_objects = attributes.values.map { |a| Fasp::Capability.new(a) }
 | 
						|
    self[:capabilities] = capability_objects.map(&:attributes)
 | 
						|
  end
 | 
						|
 | 
						|
  def enabled_capabilities
 | 
						|
    capabilities.select(&:enabled).map(&:id)
 | 
						|
  end
 | 
						|
 | 
						|
  def capability?(capability_name)
 | 
						|
    return false unless confirmed?
 | 
						|
 | 
						|
    capabilities.present? && capabilities.any? do |capability|
 | 
						|
      capability.id == capability_name
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  def capability_enabled?(capability_name)
 | 
						|
    return false unless confirmed?
 | 
						|
 | 
						|
    capabilities.present? && capabilities.any? do |capability|
 | 
						|
      capability.id == capability_name && capability.enabled
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  def server_private_key
 | 
						|
    @server_private_key ||= OpenSSL::PKey.read(server_private_key_pem)
 | 
						|
  end
 | 
						|
 | 
						|
  def server_public_key_base64
 | 
						|
    Base64.strict_encode64(server_private_key.raw_public_key)
 | 
						|
  end
 | 
						|
 | 
						|
  def provider_public_key_base64=(string)
 | 
						|
    return if string.blank?
 | 
						|
 | 
						|
    self.provider_public_key_pem =
 | 
						|
      OpenSSL::PKey.new_raw_public_key(
 | 
						|
        'ed25519',
 | 
						|
        Base64.strict_decode64(string)
 | 
						|
      ).public_to_pem
 | 
						|
  end
 | 
						|
 | 
						|
  def provider_public_key
 | 
						|
    @provider_public_key ||= OpenSSL::PKey.read(provider_public_key_pem)
 | 
						|
  end
 | 
						|
 | 
						|
  def provider_public_key_raw
 | 
						|
    provider_public_key.raw_public_key
 | 
						|
  end
 | 
						|
 | 
						|
  def provider_public_key_fingerprint
 | 
						|
    OpenSSL::Digest.base64digest('sha256', provider_public_key_raw)
 | 
						|
  end
 | 
						|
 | 
						|
  def url(path)
 | 
						|
    base = base_url
 | 
						|
    base = base.chomp('/') if path.start_with?('/')
 | 
						|
    "#{base}#{path}"
 | 
						|
  end
 | 
						|
 | 
						|
  def update_info!(confirm: false)
 | 
						|
    self.confirmed = true if confirm
 | 
						|
    provider_info = Fasp::Request.new(self).get('/provider_info')
 | 
						|
    assign_attributes(
 | 
						|
      privacy_policy: provider_info['privacyPolicy'],
 | 
						|
      capabilities: provider_info['capabilities'],
 | 
						|
      sign_in_url: provider_info['signInUrl'],
 | 
						|
      contact_email: provider_info['contactEmail'],
 | 
						|
      fediverse_account: provider_info['fediverseAccount']
 | 
						|
    )
 | 
						|
    save!
 | 
						|
  end
 | 
						|
 | 
						|
  private
 | 
						|
 | 
						|
  def create_keypair
 | 
						|
    self.server_private_key_pem ||=
 | 
						|
      OpenSSL::PKey.generate_key('ed25519').private_to_pem
 | 
						|
  end
 | 
						|
 | 
						|
  def update_remote_capabilities
 | 
						|
    return unless saved_change_to_attribute?(:capabilities)
 | 
						|
 | 
						|
    old, current = saved_change_to_attribute(:capabilities)
 | 
						|
    old ||= []
 | 
						|
    current.each do |capability|
 | 
						|
      update_remote_capability(capability) if capability.key?('enabled') && !old.include?(capability)
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  def update_remote_capability(capability)
 | 
						|
    version, = capability['version'].split('.')
 | 
						|
    path = "/capabilities/#{capability['id']}/#{version}/activation"
 | 
						|
    if capability['enabled']
 | 
						|
      Fasp::Request.new(self).post(path)
 | 
						|
    else
 | 
						|
      Fasp::Request.new(self).delete(path)
 | 
						|
    end
 | 
						|
  end
 | 
						|
end
 |