From 637cabf95fc1965a07fb6928a364a87dce2fbfb8 Mon Sep 17 00:00:00 2001
From: tsoganov
+Anname teada, et järgmise kontakti kinnitamisprotsess on edukalt lõpule viidud.
+
+Täielikud tulemused leiate manuses olevast PDF-failist.
+
+Teie registripidaja <%= registrar.name %> on palunud Teil kinnitada oma isikut, et jätkata domeeni toimingutega.
+
+Palun kinnitage oma isikut, et jätkata.
+
+Jätka eeID-ga
+
+Kontaktandmed:
+<%= render 'mailers/shared/registrant/registrant.et.html', registrant: contact, with_phone: true %>
+
+Probleemide korral pöörduge oma registripidaja poole:
+<%= render 'mailers/shared/registrar/registrar.et.html', registrar: registrar %>
+<%= render 'mailers/shared/signatures/signature.et.html' %>
+
+
+Hi <%= contact.name %>,
+
+Your registrar <%= registrar.name %> has requested that you verify your identity in order to proceed with domain actions.
+
+Please confirm your identity to continue.
+
+Continue with eeID
+
+Contact information:
+<%= render 'mailers/shared/registrant/registrant.en.html', registrant: contact, with_phone: true %>
+
+In case of problems please turn to your registrar:
+<%= render 'mailers/shared/registrar/registrar.en.html', registrar: registrar %>
+<%= render 'mailers/shared/signatures/signature.en.html' %>
\ No newline at end of file
diff --git a/app/views/mailers/contact_mailer/identification_requested.text.erb b/app/views/mailers/contact_mailer/identification_requested.text.erb
new file mode 100644
index 0000000000..a1a8e1d5f0
--- /dev/null
+++ b/app/views/mailers/contact_mailer/identification_requested.text.erb
@@ -0,0 +1,31 @@
+<%
+ contact = RegistrantPresenter.new(registrant: @contact, view: self)
+ registrar = RegistrarPresenter.new(registrar: @contact.registrar, view: self)
+%>
+Tere <%= contact.name %>,
+
+Teie registripidaja <%= registrar.name %> on palunud teil kinnitada oma isikut, et jätkata domeeni toimingutega.
+Palun kinnitage oma isikut, klõpsates alloleval lingil:
+<%= @verification_link %>
+
+Kontaktandmed:
+<%= render 'mailers/shared/registrant/registrant.et.text', registrant: contact, with_phone: true %>
+
+Palun veenduge, et muudatus on korrektne ning probleemide korral pöörduge oma registripidaja poole:
+<%= render 'mailers/shared/registrar/registrar.et.text', registrar: registrar %>
+<%= render 'mailers/shared/signatures/signature.et.text' %>
+
+----------------------------------------------------------------------------------
+
+Hi <%= contact.name %>,
+
+Your registrar <%= registrar.name %> has requested that you verify your identity in order to proceed with domain actions.
+Please confirm your identity to continue by clicking the link below:
+<%= @verification_link %>
+
+Contact information:
+<%= render 'mailers/shared/registrant/registrant.en.text', registrant: contact, with_phone: true %>
+
+In case of problems please turn to your registrar:
+<%= render 'mailers/shared/registrar/registrar.en.text', registrar: registrar %>
+<%= render 'mailers/shared/signatures/signature.en.text' %>
\ No newline at end of file
diff --git a/config/application.yml.sample b/config/application.yml.sample
index 91f6d09b03..8e35d74fee 100644
--- a/config/application.yml.sample
+++ b/config/application.yml.sample
@@ -88,6 +88,9 @@ registrant_api_auth_allowed_ips: '127.0.0.1, 0.0.0.0' #ips, separated with comma
# Accreditation Center API
accr_center_api_auth_allowed_ips: '127.0.0.1, 0.0.0.0' #ips, separated with commas
+# Webhooks
+webhook_allowed_ips: '127.0.0.1, 0.0.0.0' #ips, separated with commas
+
# Shared key for REST-WHOIS Bounces API incl. CERT
rwhois_bounces_api_shared_key: testkey
diff --git a/config/locales/contacts.en.yml b/config/locales/contacts.en.yml
index 361e63530c..86576b00c4 100644
--- a/config/locales/contacts.en.yml
+++ b/config/locales/contacts.en.yml
@@ -9,6 +9,9 @@ en:
models:
contact:
attributes:
+ base:
+ verification_exists: Contact already verified
+ verification_error: Sending identification request failed
code:
blank: "Required parameter missing - code"
too_long_contact_code: "Contact code is too long, max 100 characters"
diff --git a/config/routes.rb b/config/routes.rb
index 6652f013ed..2b12f0fda4 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -74,6 +74,7 @@
collection do
get 'check/:id', to: 'contacts#check'
get 'search(/:id)', to: 'contacts#search'
+ post 'verify/:id', to: 'contacts#verify'
end
end
end
@@ -372,6 +373,12 @@
end
end
+ namespace :eeid do
+ namespace :webhooks do
+ resources :identification_requests, only: :create
+ end
+ end
+
# To prevent users seeing the default welcome message "Welcome aboard" from Rails
root to: redirect('admin/sign_in')
end
diff --git a/db/migrate/20240924103554_add_verification_fields_to_contacts.rb b/db/migrate/20240924103554_add_verification_fields_to_contacts.rb
new file mode 100644
index 0000000000..1d4120a7be
--- /dev/null
+++ b/db/migrate/20240924103554_add_verification_fields_to_contacts.rb
@@ -0,0 +1,9 @@
+class AddVerificationFieldsToContacts < ActiveRecord::Migration[6.1]
+ disable_ddl_transaction!
+
+ def change
+ add_column :contacts, :ident_request_sent_at, :datetime
+ add_column :contacts, :verified_at, :datetime
+ add_index :contacts, :verified_at, algorithm: :concurrently
+ end
+end
diff --git a/db/structure.sql b/db/structure.sql
index 6b189b54c1..82f10a2079 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -695,6 +695,8 @@ CREATE TABLE public.contacts (
registrant_publishable boolean DEFAULT false,
checked_company_at timestamp without time zone,
company_register_status character varying
+ ident_request_sent_at timestamp without time zone,
+ verified_at timestamp without time zone
);
@@ -4263,6 +4265,13 @@ CREATE INDEX index_contacts_on_registrar_id ON public.contacts USING btree (regi
CREATE INDEX index_contacts_on_registrar_id_and_ident_type ON public.contacts USING btree (registrar_id, ident_type);
+--
+-- Name: index_contacts_on_verified_at; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX index_contacts_on_verified_at ON public.contacts USING btree (verified_at);
+
+
--
-- Name: index_csync_records_on_domain_id; Type: INDEX; Schema: public; Owner: -
--
@@ -5602,6 +5611,8 @@ INSERT INTO "schema_migrations" (version) VALUES
('20230710120154'),
('20230711083811'),
('20240816091049'),
-('20240816092636');
+('20240816092636'),
+('20240903131540'),
+('20240924103554');
diff --git a/lib/serializers/repp/contact.rb b/lib/serializers/repp/contact.rb
index 5afab98f0e..5c587e4049 100644
--- a/lib/serializers/repp/contact.rb
+++ b/lib/serializers/repp/contact.rb
@@ -18,7 +18,8 @@ def to_json(obj = contact)
json = { code: obj.code, name: obj.name, ident: ident, phone: obj.phone,
created_at: obj.created_at, auth_info: obj.auth_info, email: obj.email,
statuses: statuses, disclosed_attributes: obj.disclosed_attributes,
- registrar: registrar }
+ registrar: registrar, ident_request_sent_at: obj.ident_request_sent_at,
+ verified_at: obj.verified_at }
json[:address] = address if @show_address
if @domain_params
json[:domains] = domains
diff --git a/test/integration/eeid/identification_requests_webhook_test.rb b/test/integration/eeid/identification_requests_webhook_test.rb
new file mode 100644
index 0000000000..26bbac6cd9
--- /dev/null
+++ b/test/integration/eeid/identification_requests_webhook_test.rb
@@ -0,0 +1,63 @@
+require 'test_helper'
+
+class Eeid::IdentificationRequestsWebhookTest < ActionDispatch::IntegrationTest
+ setup do
+ @contact = contacts(:john)
+ @secret = 'valid_secret'
+ ENV['ident_service_client_secret'] = @secret
+ payload = {
+ identification_request_id: '123',
+ reference: @contact.code
+ }
+ @valid_hmac_signature = OpenSSL::HMAC.hexdigest('SHA256', @secret, payload.to_json)
+
+ adapter = ENV['shunter_default_adapter'].constantize.new
+ adapter&.clear!
+ end
+
+ test 'should verify contact with valid signature and parameters' do
+ @contact.update!(ident_request_sent_at: Time.zone.now - 1.day)
+ post '/eeid/webhooks/identification_requests', params: { identification_request_id: '123', reference: @contact.code }, as: :json, headers: { 'X-HMAC-Signature' => @valid_hmac_signature }
+
+ assert_response :ok
+ assert_equal({ 'status' => 'success' }, JSON.parse(response.body))
+ assert_not_nil @contact.reload.verified_at
+ end
+
+ test 'should return unauthorized for invalid HMAC signature' do
+ post '/eeid/webhooks/identification_requests', params: { identification_request_id: '123', reference: @contact.code }, as: :json, headers: { 'X-HMAC-Signature' => 'invalid_signature' }
+
+ assert_response :unauthorized
+ assert_equal({ 'error' => 'Invalid HMAC signature' }, JSON.parse(response.body))
+ end
+
+ test 'should return unauthorized for missing parameters' do
+ post '/eeid/webhooks/identification_requests', params: { reference: @contact.code }, as: :json, headers: { 'X-HMAC-Signature' => @valid_hmac_signature }
+
+ assert_response :unauthorized
+ assert_equal({ 'error' => 'Invalid HMAC signature' }, JSON.parse(response.body))
+ end
+
+ test 'should handle internal server error gracefully' do
+ # Simulate an error in the verify_contact method
+ Contact.stub :find_by_code, ->(_) { raise StandardError, 'Simulated error' } do
+ post '/eeid/webhooks/identification_requests', params: { identification_request_id: '123', reference: @contact.code }, as: :json, headers: { 'X-HMAC-Signature' => @valid_hmac_signature }
+
+ assert_response :internal_server_error
+ assert_equal({ 'error' => 'Internal Server Error' }, JSON.parse(response.body))
+ end
+ end
+
+ test 'returns error response if throttled' do
+ ENV['shunter_default_threshold'] = '1'
+ ENV['shunter_enabled'] = 'true'
+
+ post '/eeid/webhooks/identification_requests', params: { identification_request_id: '123', reference: @contact.code }, as: :json, headers: { 'X-HMAC-Signature' => @valid_hmac_signature }
+ post '/eeid/webhooks/identification_requests', params: { identification_request_id: '123', reference: @contact.code }, as: :json, headers: { 'X-HMAC-Signature' => @valid_hmac_signature }
+
+ assert_response :bad_request
+ assert response.body.include?(Shunter.default_error_message)
+ ENV['shunter_default_threshold'] = '10000'
+ ENV['shunter_enabled'] = 'false'
+ end
+end
diff --git a/test/integration/repp/v1/contacts/verify_test.rb b/test/integration/repp/v1/contacts/verify_test.rb
new file mode 100644
index 0000000000..3a48b45522
--- /dev/null
+++ b/test/integration/repp/v1/contacts/verify_test.rb
@@ -0,0 +1,71 @@
+require 'test_helper'
+
+class ReppV1ContactsVerifyTest < ActionDispatch::IntegrationTest
+ def setup
+ @contact = contacts(:john)
+ @user = users(:api_bestnames)
+ token = Base64.encode64("#{@user.username}:#{@user.plain_text_password}")
+ token = "Basic #{token}"
+
+ @auth_headers = { 'Authorization' => token }
+
+ adapter = ENV['shunter_default_adapter'].constantize.new
+ adapter&.clear!
+
+ stub_request(:post, %r{api/auth/v1/token}).to_return(status: 200, body: { access_token: 'token', token_type: 'Bearer', expires_in: 100 }.to_json, headers: {})
+ stub_request(:post, %r{api/ident/v1/identification_requests})
+ .with(
+ body: {
+ claims_required: [{ type: 'sub', value: "#{@contact.ident_country_code}#{@contact.ident}" }],
+ reference: @contact.code
+ }
+ ).to_return(status: 200, body: { id: '123' }.to_json, headers: {})
+ end
+
+ def test_returns_error_when_not_found
+ post '/repp/v1/contacts/verify/nonexistant:code', headers: @auth_headers
+ json = JSON.parse(response.body, symbolize_names: true)
+
+ assert_response :not_found
+ assert_equal 2303, json[:code]
+ assert_equal 'Object does not exist', json[:message]
+ end
+
+ def test_verifies_contact
+ post "/repp/v1/contacts/verify/#{@contact.code}", headers: @auth_headers
+ json = JSON.parse(response.body, symbolize_names: true)
+
+ assert_response :ok
+ assert_equal 1000, json[:code]
+ assert_equal 'Command completed successfully', json[:message]
+
+ contact = Contact.find_by(code: json[:data][:contact][:code])
+ assert contact.present?
+ assert contact.ident_request_sent_at
+ assert_nil contact.verified_at
+ end
+
+ def test_does_not_verify_already_verified_contact
+ @contact.update!(verified_at: Time.zone.now - 1.day)
+ post "/repp/v1/contacts/verify/#{@contact.code}", headers: @auth_headers
+ json = JSON.parse(response.body, symbolize_names: true)
+
+ assert_response :bad_request
+ assert_equal 'Contact already verified', json[:message]
+ end
+
+ def test_returns_error_response_if_throttled
+ ENV['shunter_default_threshold'] = '1'
+ ENV['shunter_enabled'] = 'true'
+
+ post "/repp/v1/contacts/verify/#{@contact.code}", headers: @auth_headers
+ post "/repp/v1/contacts/verify/#{@contact.code}", headers: @auth_headers
+ json = JSON.parse(response.body, symbolize_names: true)
+
+ assert_response :bad_request
+ assert_equal json[:code], 2502
+ assert response.body.include?(Shunter.default_error_message)
+ ENV['shunter_default_threshold'] = '10000'
+ ENV['shunter_enabled'] = 'false'
+ end
+end
diff --git a/test/services/identification_service_test.rb b/test/services/identification_service_test.rb
new file mode 100644
index 0000000000..a11ef7806e
--- /dev/null
+++ b/test/services/identification_service_test.rb
@@ -0,0 +1,104 @@
+# frozen_string_literal: true
+
+require 'test_helper'
+
+class IdentificationServiceTest < ActiveSupport::TestCase
+ def setup
+ @service = Eeid::IdentificationService.new
+ end
+
+ def test_create_identification_request_success
+ request_params = {
+ claims_required: [{
+ type: 'sub',
+ value: 'EE1234567'
+ }],
+ reference: '111:111'
+ }
+ response_body = { id: '123', status: 'created' }.to_json
+
+ stub_request(:post, %r{api/auth/v1/token})
+ .to_return(status: 200, body: { access_token: 'mock_token' }.to_json)
+
+ stub_request(:post, %r{api/ident/v1/identification_requests})
+ .with(
+ headers: { 'Authorization' => 'Bearer mock_token' },
+ body: request_params.to_json
+ )
+ .to_return(status: 201, body: response_body)
+
+ result = @service.create_identification_request(request_params)
+ assert_equal JSON.parse(response_body), result
+ assert_equal 'mock_token', @service.instance_variable_get(:@token)
+ end
+
+ def test_create_identification_request_failure
+ request_params = {
+ claims_required: [{
+ type: 'sub',
+ value: 'EE1234567'
+ }],
+ reference: '111:111'
+ }
+
+ stub_request(:post, %r{api/auth/v1/token})
+ .to_return(status: 200, body: { access_token: 'mock_token' }.to_json)
+
+ stub_request(:post, %r{api/ident/v1/identification_requests})
+ .with(
+ headers: { 'Authorization' => 'Bearer mock_token' },
+ body: request_params.to_json
+ )
+ .to_return(status: 400, body: { error: 'Bad Request' }.to_json)
+
+ assert_raises(Eeid::IdentError, 'Bad Request') do
+ @service.create_identification_request(request_params)
+ end
+ end
+
+ def test_get_identification_request_success
+ id = '123'
+ response_body = { id: id, status: 'completed' }.to_json
+
+ stub_request(:post, %r{api/auth/v1/token})
+ .to_return(status: 200, body: { access_token: 'mock_token' }.to_json)
+
+ stub_request(:get, %r{api/ident/v1/identification_requests/#{id}})
+ .with(headers: { 'Authorization' => 'Bearer mock_token' })
+ .to_return(status: 200, body: response_body)
+
+ result = @service.get_identification_request(id)
+ assert_equal JSON.parse(response_body), result
+ assert_equal 'mock_token', @service.instance_variable_get(:@token)
+ end
+
+ def test_get_identification_request_failure
+ id = '123'
+
+ stub_request(:post, %r{api/auth/v1/token})
+ .to_return(status: 200, body: { access_token: 'mock_token' }.to_json)
+
+ stub_request(:get, %r{api/ident/v1/identification_requests/#{id}})
+ .with(headers: { 'Authorization' => 'Bearer mock_token' })
+ .to_return(status: 404, body: { error: 'Not Found' }.to_json)
+
+ assert_raises(Eeid::IdentError, 'Not Found') do
+ @service.get_identification_request(id)
+ end
+ end
+
+ def test_authentication_needed_for_requests
+ stub_request(:post, %r{api/auth/v1/token})
+ .to_return(status: 401, body: { error: 'Invalid credentials' }.to_json)
+
+ assert_raises(Eeid::IdentError) do
+ @service.create_identification_request({ key: 'value' })
+ end
+
+ assert_raises(Eeid::IdentError) do
+ @service.get_identification_request('123')
+ end
+
+ assert_equal nil, @service.instance_variable_get(:@token)
+ end
+end
From 285fa138e6c1ad5a3e3b5bf9d70d2c45eb4f4969 Mon Sep 17 00:00:00 2001
From: tsoganov
+Kontaktandmed:
+
+
+
+Parimate soovidega, +
+<%= render 'mailers/shared/signatures/signature.et.html' %> ++We are writing to inform you that the verification process for the following contact has been successfully completed. +
++The full result can be found in the attached PDF file. +
++If you have any questions regarding the contact verification or other services in the Registrar Portal, please do not hesitate to reach out to us. +
++Best regards, +
+<%= render 'mailers/shared/signatures/signature.en.html' %> \ No newline at end of file diff --git a/app/views/mailers/registrar_mailer/contact_verified.text.erb b/app/views/mailers/registrar_mailer/contact_verified.text.erb new file mode 100644 index 0000000000..17cb6e323f --- /dev/null +++ b/app/views/mailers/registrar_mailer/contact_verified.text.erb @@ -0,0 +1,32 @@ +Tere, + +Anname teada, et järgmise kontakti kinnitamisprotsess on edukalt lõpule viidud. + +Kontaktandmed: +- Kood: <%= @contact.code %> +- Nimi: <%= @contact.name %> +- Identifikaator: <%= ident_for(@contact) %> + +Täielikke tulemusi saab vaadata kontakti lehelt registripidaja portaalis. + +Kui Teil on küsimusi seoses kontakti kinnitamise või muude teenustega registripidaja portaalis, võtke meiega ühendust. + +Parimate soovidega, +<%= render 'mailers/shared/signatures/signature.et.text' %> +--- + +Hi, + +We are writing to inform you that the verification process for the following contact has been successfully completed. + +Contact Details: +- Code: <%= @contact.code %> +- Name: <%= @contact.name %> +- Ident: <%= ident_for(@contact) %> + +The full result can be viewed on the contact page in the Registrar Portal. + +If you have any questions regarding the contact verification or other services in the Registrar Portal, please do not hesitate to reach out to us. + +Best regards, +<%= render 'mailers/shared/signatures/signature.en.text' %> \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 2b12f0fda4..3a1c538a8f 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -75,6 +75,7 @@ get 'check/:id', to: 'contacts#check' get 'search(/:id)', to: 'contacts#search' post 'verify/:id', to: 'contacts#verify' + get 'download_poi/:id', to: 'contacts#download_poi' end end end diff --git a/db/migrate/20241015071505_add_verification_id_to_contacts.rb b/db/migrate/20241015071505_add_verification_id_to_contacts.rb new file mode 100644 index 0000000000..7aff96abc4 --- /dev/null +++ b/db/migrate/20241015071505_add_verification_id_to_contacts.rb @@ -0,0 +1,5 @@ +class AddVerificationIdToContacts < ActiveRecord::Migration[6.1] + def change + add_column :contacts, :verification_id, :string + end +end diff --git a/db/structure.sql b/db/structure.sql index 82f10a2079..d73bf3ebe5 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -696,7 +696,8 @@ CREATE TABLE public.contacts ( checked_company_at timestamp without time zone, company_register_status character varying ident_request_sent_at timestamp without time zone, - verified_at timestamp without time zone + verified_at timestamp without time zone, + verification_id character varying ); @@ -5613,6 +5614,7 @@ INSERT INTO "schema_migrations" (version) VALUES ('20240816091049'), ('20240816092636'), ('20240903131540'), -('20240924103554'); +('20240924103554'), +('20241015071505'); diff --git a/test/integration/eeid/identification_requests_webhook_test.rb b/test/integration/eeid/identification_requests_webhook_test.rb index 26bbac6cd9..625cfa3a56 100644 --- a/test/integration/eeid/identification_requests_webhook_test.rb +++ b/test/integration/eeid/identification_requests_webhook_test.rb @@ -11,6 +11,15 @@ class Eeid::IdentificationRequestsWebhookTest < ActionDispatch::IntegrationTest } @valid_hmac_signature = OpenSSL::HMAC.hexdigest('SHA256', @secret, payload.to_json) + stub_request(:post, %r{api/auth/v1/token}) + .to_return( + status: 200, + body: { access_token: 'token', token_type: 'Bearer', expires_in: 100 }.to_json, headers: {} + ) + pdf_content = File.read(Rails.root.join('test/fixtures/files/legaldoc.pdf')) + stub_request(:get, %r{api/ident/v1/identification_requests}) + .to_return(status: 200, body: pdf_content, headers: { 'Content-Type' => 'application/pdf' }) + adapter = ENV['shunter_default_adapter'].constantize.new adapter&.clear! end @@ -22,6 +31,8 @@ class Eeid::IdentificationRequestsWebhookTest < ActionDispatch::IntegrationTest assert_response :ok assert_equal({ 'status' => 'success' }, JSON.parse(response.body)) assert_not_nil @contact.reload.verified_at + assert_equal @contact.verification_id, '123' + assert_notify_registrar('Successful Contact Verification') end test 'should return unauthorized for invalid HMAC signature' do @@ -29,13 +40,15 @@ class Eeid::IdentificationRequestsWebhookTest < ActionDispatch::IntegrationTest assert_response :unauthorized assert_equal({ 'error' => 'Invalid HMAC signature' }, JSON.parse(response.body)) + assert_emails 0 end test 'should return unauthorized for missing parameters' do post '/eeid/webhooks/identification_requests', params: { reference: @contact.code }, as: :json, headers: { 'X-HMAC-Signature' => @valid_hmac_signature } assert_response :unauthorized - assert_equal({ 'error' => 'Invalid HMAC signature' }, JSON.parse(response.body)) + assert_equal({ 'error' => 'Invalid HMAC signature' }, JSON.parse(response.body)) + assert_emails 0 end test 'should handle internal server error gracefully' do @@ -44,10 +57,24 @@ class Eeid::IdentificationRequestsWebhookTest < ActionDispatch::IntegrationTest post '/eeid/webhooks/identification_requests', params: { identification_request_id: '123', reference: @contact.code }, as: :json, headers: { 'X-HMAC-Signature' => @valid_hmac_signature } assert_response :internal_server_error - assert_equal({ 'error' => 'Internal Server Error' }, JSON.parse(response.body)) + assert_equal({ 'error' => 'Simulated error' }, JSON.parse(response.body)) + assert_emails 0 end end + test 'should handle error from ident response' do + stub_request(:get, %r{api/ident/v1/identification_requests}) + .to_return(status: :not_found, body: { error: 'Proof of identity not found' }.to_json, headers: { 'Content-Type' => 'application/json' }) + + @contact.update!(ident_request_sent_at: Time.zone.now - 1.day) + post '/eeid/webhooks/identification_requests', params: { identification_request_id: '123', reference: @contact.code }, as: :json, headers: { 'X-HMAC-Signature' => @valid_hmac_signature } + + assert_response :internal_server_error + assert_equal({ 'error' => 'Proof of identity not found' }, JSON.parse(response.body)) + assert_emails 0 + assert_nil @contact.reload.verified_at + end + test 'returns error response if throttled' do ENV['shunter_default_threshold'] = '1' ENV['shunter_enabled'] = 'true' @@ -60,4 +87,15 @@ class Eeid::IdentificationRequestsWebhookTest < ActionDispatch::IntegrationTest ENV['shunter_default_threshold'] = '10000' ENV['shunter_enabled'] = 'false' end + + private + + def assert_notify_registrar(subject) + assert_emails 1 + email = ActionMailer::Base.deliveries.last + assert_equal [@contact.registrar.email], email.to + assert_equal subject, email.subject + assert_equal 1, email.attachments.size + assert_equal 'proof_of_identity.pdf', email.attachments.first.filename + end end diff --git a/test/integration/repp/v1/contacts/download_poi_test.rb b/test/integration/repp/v1/contacts/download_poi_test.rb new file mode 100644 index 0000000000..1d943dc5c6 --- /dev/null +++ b/test/integration/repp/v1/contacts/download_poi_test.rb @@ -0,0 +1,72 @@ +require 'test_helper' + +class ReppV1ContactsDownloadPoiTest < ActionDispatch::IntegrationTest + def setup + @contact = contacts(:john) + @user = users(:api_bestnames) + token = Base64.encode64("#{@user.username}:#{@user.plain_text_password}") + token = "Basic #{token}" + + @auth_headers = { 'Authorization' => token } + + adapter = ENV['shunter_default_adapter'].constantize.new + adapter&.clear! + + stub_request(:post, %r{api/auth/v1/token}) + .to_return( + status: 200, + body: { access_token: 'token', token_type: 'Bearer', expires_in: 100 }.to_json, headers: {} + ) + pdf_content = File.read(Rails.root.join('test/fixtures/files/legaldoc.pdf')) + stub_request(:get, %r{api/ident/v1/identification_requests}) + .to_return(status: 200, body: pdf_content, headers: { 'Content-Type' => 'application/pdf' }) + end + + def test_returns_error_when_not_found + get '/repp/v1/contacts/download_poi/nonexistant:code', headers: @auth_headers + json = JSON.parse(response.body, symbolize_names: true) + + assert_response :not_found + assert_equal 2303, json[:code] + assert_equal 'Object does not exist', json[:message] + end + + def test_downloads_poi_for_contact + @contact.update!(verified_at: Time.zone.now - 1.day, verification_id: '123') + get "/repp/v1/contacts/download_poi/#{@contact.code}", headers: @auth_headers + + assert_response :ok + assert_equal 'application/pdf', response.headers['Content-Type'] + assert_equal "inline; filename=\"proof_of_identity_123.pdf\"; filename*=UTF-8''proof_of_identity_123.pdf", response.headers['Content-Disposition'] + assert_not_empty response.body + end + + def test_handles_non_epp_error + stub_request(:get, %r{api/ident/v1/identification_requests}) + .to_return( + status: :not_found, + body: { error: 'Proof of identity not found' }.to_json, + headers: { 'Content-Type' => 'application/json' } + ) + get "/repp/v1/contacts/download_poi/#{@contact.code}", headers: @auth_headers + json = JSON.parse(response.body, symbolize_names: true) + + assert_response :bad_request + assert_equal 'Proof of identity not found', json[:message] + end + + def test_returns_error_response_if_throttled + ENV['shunter_default_threshold'] = '1' + ENV['shunter_enabled'] = 'true' + + get "/repp/v1/contacts/download_poi/#{@contact.code}", headers: @auth_headers + get "/repp/v1/contacts/download_poi/#{@contact.code}", headers: @auth_headers + json = JSON.parse(response.body, symbolize_names: true) + + assert_response :bad_request + assert_equal json[:code], 2502 + assert response.body.include?(Shunter.default_error_message) + ENV['shunter_default_threshold'] = '10000' + ENV['shunter_enabled'] = 'false' + end +end diff --git a/test/integration/repp/v1/contacts/verify_test.rb b/test/integration/repp/v1/contacts/verify_test.rb index 3a48b45522..1d62c4b837 100644 --- a/test/integration/repp/v1/contacts/verify_test.rb +++ b/test/integration/repp/v1/contacts/verify_test.rb @@ -12,14 +12,18 @@ def setup adapter = ENV['shunter_default_adapter'].constantize.new adapter&.clear! - stub_request(:post, %r{api/auth/v1/token}).to_return(status: 200, body: { access_token: 'token', token_type: 'Bearer', expires_in: 100 }.to_json, headers: {}) + stub_request(:post, %r{api/auth/v1/token}) + .to_return( + status: 200, + body: { access_token: 'token', token_type: 'Bearer', expires_in: 100 }.to_json, headers: {} + ) stub_request(:post, %r{api/ident/v1/identification_requests}) .with( body: { claims_required: [{ type: 'sub', value: "#{@contact.ident_country_code}#{@contact.ident}" }], reference: @contact.code } - ).to_return(status: 200, body: { id: '123' }.to_json, headers: {}) + ).to_return(status: 200, body: { id: '123' }.to_json, headers: { 'Content-Type' => 'application/json' }) end def test_returns_error_when_not_found @@ -43,6 +47,20 @@ def test_verifies_contact assert contact.present? assert contact.ident_request_sent_at assert_nil contact.verified_at + assert_notify_contact('Identification requested') + end + + def test_handles_non_epp_error + stub_request(:post, %r{api/ident/v1/identification_requests}) + .to_return(status: :unprocessable_entity, body: { error: 'error' }.to_json, headers: { 'Content-Type' => 'application/json' }) + + post "/repp/v1/contacts/verify/#{@contact.code}", headers: @auth_headers + json = JSON.parse(response.body, symbolize_names: true) + + assert_response :bad_request + assert_equal 'Sending identification request failed', json[:message] + assert_nil @contact.ident_request_sent_at + assert_emails 0 end def test_does_not_verify_already_verified_contact @@ -68,4 +86,13 @@ def test_returns_error_response_if_throttled ENV['shunter_default_threshold'] = '10000' ENV['shunter_enabled'] = 'false' end + + private + + def assert_notify_contact(subject) + assert_emails 1 + email = ActionMailer::Base.deliveries.last + assert_equal [@contact.email], email.to + assert_equal subject, email.subject + end end From af46be8d0f258d153dfa49647ffb1d5751cadf35 Mon Sep 17 00:00:00 2001 From: tsoganov