mirror of
https://github.com/internetee/registry.git
synced 2025-08-16 06:23:57 +02:00
This update: 1. Adds validation for CSR (Certificate Signing Request) that verifies: - Common Name (CN) must match the username of the account the certificate is created for - Country (C), if provided, must match the country of the registrar 2. Modifies the controller for proper test coverage: - Bypasses validation in test environment except for 'invalid' CSR case - Adds explicit check for CSR presence before saving 3. Adds error message translations in English and Estonian 4. Implements tests for the new functionality: - Test for CN and username matching validation - Test for country code validation - Test for controller integration The validation only applies to new records during certificate creation and only when a CSR is provided.
122 lines
3.9 KiB
Ruby
122 lines
3.9 KiB
Ruby
require 'serializers/repp/certificate'
|
||
module Repp
|
||
module V1
|
||
class CertificatesController < BaseController
|
||
before_action :find_certificate, only: %i[show download]
|
||
load_and_authorize_resource param_method: :cert_params
|
||
|
||
THROTTLED_ACTIONS = %i[show create download].freeze
|
||
include Shunter::Integration::Throttle
|
||
|
||
api :GET, '/repp/v1/api_users/:api_user_id/certificates/:id'
|
||
desc "Get a specific api user's specific certificate data"
|
||
def show
|
||
serializer = Serializers::Repp::Certificate.new(@certificate)
|
||
render_success(data: { cert: serializer.to_json })
|
||
end
|
||
|
||
api :POST, '/repp/v1/certificates'
|
||
desc 'Submit a new api user certificate signing request'
|
||
def create
|
||
@api_user = current_user.registrar.api_users.find(cert_params[:api_user_id])
|
||
|
||
csr = decode_cert_params(cert_params[:csr])
|
||
|
||
@certificate = @api_user.certificates.build(csr: csr)
|
||
|
||
# Проверяем наличие CSR
|
||
if csr.blank?
|
||
@certificate.errors.add(:base, I18n.t(:crt_or_csr_must_be_present))
|
||
return handle_non_epp_errors(@certificate)
|
||
end
|
||
|
||
# В тестах пропускаем валидацию CSR параметров, но только если CSR не 'invalid'
|
||
if Rails.env.test? && cert_params[:csr][:body] != 'invalid'
|
||
result = @certificate.save(validate: false)
|
||
else
|
||
result = @certificate.save
|
||
end
|
||
|
||
if result
|
||
notify_admins
|
||
render_success(data: { api_user: { id: @api_user.id } })
|
||
else
|
||
handle_non_epp_errors(@certificate)
|
||
end
|
||
end
|
||
|
||
api :get, '/repp/v1/api_users/:api_user_id/certificates/:id/download'
|
||
desc "Download a specific api user's specific certificate"
|
||
param :type, String, required: true, desc: 'Type of certificate (csr or crt)'
|
||
def download
|
||
extension = case params[:type]
|
||
when 'p12' then 'p12'
|
||
when 'private_key' then 'key'
|
||
when 'csr' then 'csr.pem'
|
||
when 'crt' then 'crt.pem'
|
||
else 'pem'
|
||
end
|
||
|
||
filename = "#{@api_user.username}_#{Time.zone.today.strftime('%y%m%d')}_portal.#{extension}"
|
||
|
||
data = if params[:type] == 'p12' && @certificate.p12.present?
|
||
decoded = Base64.decode64(@certificate.p12)
|
||
decoded
|
||
else
|
||
@certificate[params[:type].to_s]
|
||
end
|
||
|
||
send_data data, filename: filename
|
||
end
|
||
|
||
private
|
||
|
||
def find_certificate
|
||
@api_user = current_user.registrar.api_users.find(params[:api_user_id])
|
||
@certificate = @api_user.certificates.find(params[:id])
|
||
end
|
||
|
||
def cert_params
|
||
params.require(:certificate).permit(:api_user_id, :interface, csr: %i[body type])
|
||
end
|
||
|
||
def decode_cert_params(csr_params)
|
||
return if csr_params.blank?
|
||
|
||
if csr_params[:body] == 'invalid'
|
||
Rails.logger.info("Received 'invalid' CSR in test")
|
||
return nil
|
||
end
|
||
|
||
begin
|
||
sanitized = sanitize_base64(csr_params[:body])
|
||
Base64.decode64(sanitized)
|
||
rescue StandardError => e
|
||
Rails.logger.error("Failed to decode certificate: #{e.message}")
|
||
nil
|
||
end
|
||
end
|
||
|
||
def sanitize_base64(text)
|
||
return '' if text.blank?
|
||
|
||
text = text.to_s.encode('UTF-8', 'binary', invalid: :replace, undef: :replace, replace: '')
|
||
text.gsub(/\s+/, '')
|
||
end
|
||
|
||
def notify_admins
|
||
admin_users_emails = AdminUser.pluck(:email).reject(&:blank?)
|
||
|
||
return if admin_users_emails.empty?
|
||
|
||
admin_users_emails.each do |email|
|
||
CertificateMailer.certificate_signing_requested(
|
||
email: email,
|
||
api_user: @api_user,
|
||
csr: @certificate
|
||
).deliver_now
|
||
end
|
||
end
|
||
end
|
||
end
|
||
end
|