@smileid/usesmileid 12.0.0 → 12.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/README.md +1 -1
- package/dist/camera/camera_defaults.d.ts +2 -0
- package/dist/camera/camera_defaults.d.ts.map +1 -1
- package/dist/camera/camera_defaults.js +2 -0
- package/dist/camera/camera_defaults.js.map +1 -1
- package/dist/core/exception/agent_mode_with_enhanced_liveness_exception.d.ts +11 -0
- package/dist/core/exception/agent_mode_with_enhanced_liveness_exception.d.ts.map +1 -0
- package/dist/core/exception/agent_mode_with_enhanced_liveness_exception.js +17 -0
- package/dist/core/exception/agent_mode_with_enhanced_liveness_exception.js.map +1 -0
- package/dist/core/exception/capture_validation_exceptions.d.ts +1 -0
- package/dist/core/exception/capture_validation_exceptions.d.ts.map +1 -1
- package/dist/core/exception/capture_validation_exceptions.js +1 -0
- package/dist/core/exception/capture_validation_exceptions.js.map +1 -1
- package/dist/core/exception/flow_exceptions.d.ts +4 -2
- package/dist/core/exception/flow_exceptions.d.ts.map +1 -1
- package/dist/core/exception/flow_exceptions.js +3 -2
- package/dist/core/exception/flow_exceptions.js.map +1 -1
- package/dist/core/exception/index.d.ts +1 -0
- package/dist/core/exception/index.d.ts.map +1 -1
- package/dist/core/exception/index.js +1 -0
- package/dist/core/exception/index.js.map +1 -1
- package/dist/core/exception/missing_job_type_exception.d.ts +1 -3
- package/dist/core/exception/missing_job_type_exception.d.ts.map +1 -1
- package/dist/core/exception/missing_job_type_exception.js +2 -4
- package/dist/core/exception/missing_job_type_exception.js.map +1 -1
- package/dist/core/exception/use_smile_id_error_code.d.ts +1 -0
- package/dist/core/exception/use_smile_id_error_code.d.ts.map +1 -1
- package/dist/core/exception/use_smile_id_error_code.js +1 -0
- package/dist/core/exception/use_smile_id_error_code.js.map +1 -1
- package/dist/core/models/config.d.ts +19 -0
- package/dist/core/models/config.d.ts.map +1 -1
- package/dist/core/models/document_type.d.ts +1 -1
- package/dist/core/models/document_type.d.ts.map +1 -1
- package/dist/core/models/document_type.js +2 -2
- package/dist/core/models/document_type.js.map +1 -1
- package/dist/core/models/global_privacy_control.d.ts +36 -0
- package/dist/core/models/global_privacy_control.d.ts.map +1 -0
- package/dist/core/models/global_privacy_control.js +39 -0
- package/dist/core/models/global_privacy_control.js.map +1 -0
- package/dist/core/models/network_config.d.ts +2 -2
- package/dist/core/models/network_config.js +2 -2
- package/dist/data/api/interceptors/smile_auth_interceptor.d.ts.map +1 -1
- package/dist/data/api/interceptors/smile_auth_interceptor.js +3 -17
- package/dist/data/api/interceptors/smile_auth_interceptor.js.map +1 -1
- package/dist/data/api/smile_id_api.d.ts +5 -1
- package/dist/data/api/smile_id_api.d.ts.map +1 -1
- package/dist/data/api/smile_id_api.js +30 -27
- package/dist/data/api/smile_id_api.js.map +1 -1
- package/dist/data/dsl/builder/retry_config_builder.d.ts +4 -4
- package/dist/data/dsl/builder/retry_config_builder.d.ts.map +1 -1
- package/dist/data/dsl/builder/retry_config_builder.js +6 -6
- package/dist/data/dsl/builder/retry_config_builder.js.map +1 -1
- package/dist/data/model/job_request.d.ts +28 -12
- package/dist/data/model/job_request.d.ts.map +1 -1
- package/dist/data/model/token_payload.d.ts +78 -0
- package/dist/data/model/token_payload.d.ts.map +1 -0
- package/dist/data/model/token_payload.js +132 -0
- package/dist/data/model/token_payload.js.map +1 -0
- package/dist/data/model/user_details_payload.d.ts +39 -0
- package/dist/data/model/user_details_payload.d.ts.map +1 -0
- package/dist/data/model/user_details_payload.js +53 -0
- package/dist/data/model/user_details_payload.js.map +1 -0
- package/dist/data/smile_id_urls.d.ts +1 -1
- package/dist/data/smile_id_urls.js +1 -1
- package/dist/data/smile_id_urls.js.map +1 -1
- package/dist/data/util/retry_util.d.ts +1 -1
- package/dist/data/util/retry_util.d.ts.map +1 -1
- package/dist/data/util/retry_util.js +5 -0
- package/dist/data/util/retry_util.js.map +1 -1
- package/dist/data/util/use_smile_id_token_decoder.d.ts +15 -3
- package/dist/data/util/use_smile_id_token_decoder.d.ts.map +1 -1
- package/dist/data/util/use_smile_id_token_decoder.js +20 -8
- package/dist/data/util/use_smile_id_token_decoder.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/l10n/strings_en.d.ts +4 -1
- package/dist/l10n/strings_en.d.ts.map +1 -1
- package/dist/l10n/strings_en.js +4 -1
- package/dist/l10n/strings_en.js.map +1 -1
- package/dist/l10n/use_smile_id_localizations.d.ts +10 -0
- package/dist/l10n/use_smile_id_localizations.d.ts.map +1 -1
- package/dist/l10n/use_smile_id_localizations.js +59 -3
- package/dist/l10n/use_smile_id_localizations.js.map +1 -1
- package/dist/metadata/builder_configuration.d.ts +5 -0
- package/dist/metadata/builder_configuration.d.ts.map +1 -1
- package/dist/metadata/builder_configuration.js +1 -0
- package/dist/metadata/builder_configuration.js.map +1 -1
- package/dist/metadata/metadata_configuration_mappers.d.ts +2 -3
- package/dist/metadata/metadata_configuration_mappers.d.ts.map +1 -1
- package/dist/metadata/metadata_configuration_mappers.js +13 -6
- package/dist/metadata/metadata_configuration_mappers.js.map +1 -1
- package/dist/metadata/use_smile_id_metadata_factory.d.ts.map +1 -1
- package/dist/metadata/use_smile_id_metadata_factory.js +14 -5
- package/dist/metadata/use_smile_id_metadata_factory.js.map +1 -1
- package/dist/presentation/components/use_smile_id_button.d.ts.map +1 -1
- package/dist/presentation/components/use_smile_id_button.js +8 -2
- package/dist/presentation/components/use_smile_id_button.js.map +1 -1
- package/dist/presentation/components/use_smile_id_enhanced_smart_selfie_clip.d.ts +5 -2
- package/dist/presentation/components/use_smile_id_enhanced_smart_selfie_clip.d.ts.map +1 -1
- package/dist/presentation/components/use_smile_id_enhanced_smart_selfie_clip.js +8 -3
- package/dist/presentation/components/use_smile_id_enhanced_smart_selfie_clip.js.map +1 -1
- package/dist/presentation/components/use_smile_id_instructions_hero.d.ts.map +1 -1
- package/dist/presentation/components/use_smile_id_instructions_hero.js +8 -3
- package/dist/presentation/components/use_smile_id_instructions_hero.js.map +1 -1
- package/dist/presentation/flow/dsl/builder/config_builder.d.ts +16 -0
- package/dist/presentation/flow/dsl/builder/config_builder.d.ts.map +1 -1
- package/dist/presentation/flow/dsl/builder/config_builder.js +18 -0
- package/dist/presentation/flow/dsl/builder/config_builder.js.map +1 -1
- package/dist/presentation/flow/dsl/builder/screens_builder.d.ts +6 -12
- package/dist/presentation/flow/dsl/builder/screens_builder.d.ts.map +1 -1
- package/dist/presentation/flow/dsl/builder/screens_builder.js +7 -12
- package/dist/presentation/flow/dsl/builder/screens_builder.js.map +1 -1
- package/dist/presentation/flow/dsl/use_smile_id_flow_builder.d.ts.map +1 -1
- package/dist/presentation/flow/dsl/use_smile_id_flow_builder.js +23 -1
- package/dist/presentation/flow/dsl/use_smile_id_flow_builder.js.map +1 -1
- package/dist/presentation/flow/flow_navigation_manager.d.ts +22 -3
- package/dist/presentation/flow/flow_navigation_manager.d.ts.map +1 -1
- package/dist/presentation/flow/flow_navigation_manager.js +84 -46
- package/dist/presentation/flow/flow_navigation_manager.js.map +1 -1
- package/dist/presentation/flow/model/instructions_defaults.d.ts.map +1 -1
- package/dist/presentation/flow/model/instructions_defaults.js +1 -1
- package/dist/presentation/flow/model/instructions_defaults.js.map +1 -1
- package/dist/presentation/flow/screen/orchestrated_capture_screen.d.ts.map +1 -1
- package/dist/presentation/flow/screen/orchestrated_capture_screen.js +13 -3
- package/dist/presentation/flow/screen/orchestrated_capture_screen.js.map +1 -1
- package/dist/presentation/flow/screen/orchestrated_consent_screen.d.ts.map +1 -1
- package/dist/presentation/flow/screen/orchestrated_consent_screen.js +3 -1
- package/dist/presentation/flow/screen/orchestrated_consent_screen.js.map +1 -1
- package/dist/presentation/flow/screen/orchestrated_preview_screen.d.ts.map +1 -1
- package/dist/presentation/flow/screen/orchestrated_preview_screen.js +0 -8
- package/dist/presentation/flow/screen/orchestrated_preview_screen.js.map +1 -1
- package/dist/presentation/flow/screen/orchestrated_processing_screen.d.ts.map +1 -1
- package/dist/presentation/flow/screen/orchestrated_processing_screen.js +25 -5
- package/dist/presentation/flow/screen/orchestrated_processing_screen.js.map +1 -1
- package/dist/presentation/flow/use_smile_id_flow.d.ts.map +1 -1
- package/dist/presentation/flow/use_smile_id_flow.js +45 -12
- package/dist/presentation/flow/use_smile_id_flow.js.map +1 -1
- package/dist/presentation/flow/validation/flow_validator.d.ts +16 -2
- package/dist/presentation/flow/validation/flow_validator.d.ts.map +1 -1
- package/dist/presentation/flow/validation/flow_validator.js +61 -47
- package/dist/presentation/flow/validation/flow_validator.js.map +1 -1
- package/dist/presentation/flow/validation/job_type_validator.d.ts +7 -0
- package/dist/presentation/flow/validation/job_type_validator.d.ts.map +1 -1
- package/dist/presentation/flow/validation/job_type_validator.js +52 -27
- package/dist/presentation/flow/validation/job_type_validator.js.map +1 -1
- package/dist/presentation/flow/validation/user_details_validator.d.ts +9 -0
- package/dist/presentation/flow/validation/user_details_validator.d.ts.map +1 -0
- package/dist/presentation/flow/validation/user_details_validator.js +40 -0
- package/dist/presentation/flow/validation/user_details_validator.js.map +1 -0
- package/dist/presentation/screen/helpers/capture_screen_helpers.d.ts.map +1 -1
- package/dist/presentation/screen/helpers/capture_screen_helpers.js +1 -0
- package/dist/presentation/screen/helpers/capture_screen_helpers.js.map +1 -1
- package/dist/presentation/screen/helpers/capture_ui_state.d.ts +6 -6
- package/dist/presentation/screen/helpers/capture_ui_state.d.ts.map +1 -1
- package/dist/presentation/screen/helpers/capture_ui_state.js +19 -19
- package/dist/presentation/screen/helpers/capture_ui_state.js.map +1 -1
- package/dist/presentation/screen/helpers/ess_turn_haptics.d.ts +2 -2
- package/dist/presentation/screen/helpers/ess_turn_haptics.d.ts.map +1 -1
- package/dist/presentation/screen/helpers/ess_turn_haptics.js +6 -6
- package/dist/presentation/screen/helpers/ess_turn_haptics.js.map +1 -1
- package/dist/presentation/screen/helpers/scan_state_to_overlay_state.d.ts +5 -5
- package/dist/presentation/screen/helpers/scan_state_to_overlay_state.d.ts.map +1 -1
- package/dist/presentation/screen/helpers/scan_state_to_overlay_state.js +11 -11
- package/dist/presentation/screen/helpers/scan_state_to_overlay_state.js.map +1 -1
- package/dist/presentation/screen/helpers/use_capture_orientation_lock.d.ts +13 -3
- package/dist/presentation/screen/helpers/use_capture_orientation_lock.d.ts.map +1 -1
- package/dist/presentation/screen/helpers/use_capture_orientation_lock.js +48 -6
- package/dist/presentation/screen/helpers/use_capture_orientation_lock.js.map +1 -1
- package/dist/presentation/screen/use_smile_id_capture_screen.d.ts +4 -2
- package/dist/presentation/screen/use_smile_id_capture_screen.d.ts.map +1 -1
- package/dist/presentation/screen/use_smile_id_capture_screen.js +90 -23
- package/dist/presentation/screen/use_smile_id_capture_screen.js.map +1 -1
- package/dist/presentation/screen/use_smile_id_consent_screen.d.ts +7 -0
- package/dist/presentation/screen/use_smile_id_consent_screen.d.ts.map +1 -1
- package/dist/presentation/screen/use_smile_id_consent_screen.js +6 -5
- package/dist/presentation/screen/use_smile_id_consent_screen.js.map +1 -1
- package/dist/presentation/screen/use_smile_id_document_back_instructions.d.ts.map +1 -1
- package/dist/presentation/screen/use_smile_id_document_back_instructions.js +5 -13
- package/dist/presentation/screen/use_smile_id_document_back_instructions.js.map +1 -1
- package/dist/presentation/screen/use_smile_id_document_preview_screen.js +1 -1
- package/dist/presentation/screen/use_smile_id_document_preview_screen.js.map +1 -1
- package/dist/presentation/screen/use_smile_id_preview_screen.d.ts +1 -21
- package/dist/presentation/screen/use_smile_id_preview_screen.d.ts.map +1 -1
- package/dist/presentation/screen/use_smile_id_preview_screen.js +3 -14
- package/dist/presentation/screen/use_smile_id_preview_screen.js.map +1 -1
- package/dist/presentation/screen/use_smile_id_processing_screen.js +1 -1
- package/dist/presentation/screen/use_smile_id_processing_screen.js.map +1 -1
- package/dist/presentation/utils/locale_utils.d.ts +10 -4
- package/dist/presentation/utils/locale_utils.d.ts.map +1 -1
- package/dist/presentation/utils/locale_utils.js +13 -5
- package/dist/presentation/utils/locale_utils.js.map +1 -1
- package/dist/testing/fake_face_analyzer.d.ts +43 -0
- package/dist/testing/fake_face_analyzer.d.ts.map +1 -0
- package/dist/testing/fake_face_analyzer.js +52 -0
- package/dist/testing/fake_face_analyzer.js.map +1 -0
- package/dist/testing/index.d.ts +5 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +7 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/scenario_expectations.d.ts +28 -0
- package/dist/testing/scenario_expectations.d.ts.map +1 -0
- package/dist/testing/scenario_expectations.js +65 -0
- package/dist/testing/scenario_expectations.js.map +1 -0
- package/dist/testing/scenario_loader.d.ts +11 -0
- package/dist/testing/scenario_loader.d.ts.map +1 -0
- package/dist/testing/scenario_loader.js +64 -0
- package/dist/testing/scenario_loader.js.map +1 -0
- package/dist/testing/scripted_scan_results.d.ts +17 -0
- package/dist/testing/scripted_scan_results.d.ts.map +1 -0
- package/dist/testing/scripted_scan_results.js +52 -0
- package/dist/testing/scripted_scan_results.js.map +1 -0
- package/package.json +11 -4
- package/src/__tests__/dsl.test.ts +51 -1
- package/src/__tests__/react_native_mock.tsx +22 -0
- package/src/__tests__/setup_react_native.ts +17 -2
- package/src/__tests__/snapshots/__snapshots__/screens_structural.test.tsx.snap +5267 -0
- package/src/__tests__/snapshots/screens_structural.test.tsx +230 -0
- package/src/camera/__tests__/camera_permissions.test.ts +72 -0
- package/src/camera/__tests__/camera_system_focus.test.ts +173 -0
- package/src/camera/__tests__/use_smile_id_camera_preview.test.tsx +461 -0
- package/src/camera/__tests__/use_smile_id_camera_system.test.ts +103 -0
- package/src/camera/__tests__/use_smile_id_frame_stream_hook.test.tsx +229 -0
- package/src/camera/camera_defaults.ts +3 -0
- package/src/core/exception/__tests__/builder_validation_exceptions.test.ts +81 -0
- package/src/core/exception/agent_mode_with_enhanced_liveness_exception.ts +20 -0
- package/src/core/exception/capture_validation_exceptions.ts +1 -0
- package/src/core/exception/flow_exceptions.test.ts +10 -0
- package/src/core/exception/flow_exceptions.ts +3 -2
- package/src/core/exception/index.ts +1 -0
- package/src/core/exception/missing_job_type_exception.ts +2 -4
- package/src/core/exception/use_smile_id_error_code.ts +1 -0
- package/src/core/models/__tests__/document_type.test.ts +2 -2
- package/src/core/models/__tests__/flow_models.test.ts +26 -0
- package/src/core/models/config.ts +22 -0
- package/src/core/models/document_type.ts +2 -2
- package/src/core/models/global_privacy_control.ts +45 -0
- package/src/core/models/network_config.ts +2 -2
- package/src/data/api/__tests__/smile_id_api.test.ts +275 -1
- package/src/data/api/interceptors/__tests__/credential_header_redaction.test.ts +144 -0
- package/src/data/api/interceptors/__tests__/gzip_interceptor.test.ts +83 -0
- package/src/data/api/interceptors/smile_auth_interceptor.ts +3 -18
- package/src/data/api/smile_id_api.ts +36 -49
- package/src/data/compression/__tests__/payload_compressor_real_jpeg.test.ts +6 -2
- package/src/data/dsl/__tests__/use_smile_id_network_builder.test.ts +157 -0
- package/src/data/dsl/builder/__tests__/config_builders.test.ts +62 -0
- package/src/data/dsl/builder/retry_config_builder.ts +6 -6
- package/src/data/factory/__tests__/retry_gzip_mac_composition.test.ts +163 -0
- package/src/data/factory/__tests__/signed_job_submission_headers.test.ts +1 -1
- package/src/data/model/__tests__/token_payload.test.ts +224 -0
- package/src/data/model/__tests__/user_details_payload.test.ts +100 -0
- package/src/data/model/job_request.ts +27 -12
- package/src/data/model/token_payload.ts +182 -0
- package/src/data/model/user_details_payload.ts +84 -0
- package/src/data/repository/__tests__/network_retries.test.ts +1 -1
- package/src/data/repository/__tests__/repository_dispatch.test.ts +366 -0
- package/src/data/repository/__tests__/use_smile_id_repository.test.ts +1 -1
- package/src/data/security/__tests__/request_canonicalizer.test.ts +132 -0
- package/src/data/security/__tests__/signing_crypto.test.ts +203 -0
- package/src/data/smile_id_urls.ts +1 -1
- package/src/data/util/__tests__/retry_util.test.ts +25 -0
- package/src/data/util/__tests__/use_smile_id_token_decoder.test.ts +179 -0
- package/src/data/util/retry_util.ts +9 -1
- package/src/data/util/use_smile_id_token_decoder.ts +29 -8
- package/src/index.ts +6 -4
- package/src/l10n/__tests__/use_smile_id_localizations.test.ts +122 -5
- package/src/l10n/__tests__/use_smile_id_localizations_provider.test.tsx +112 -0
- package/src/l10n/__tests__/use_smile_id_localizations_surface.test.ts +231 -0
- package/src/l10n/strings_en.ts +5 -1
- package/src/l10n/use_smile_id_localizations.ts +80 -3
- package/src/metadata/__tests__/device_orientation_sampling.test.ts +165 -0
- package/src/metadata/__tests__/geolocation.test.ts +150 -0
- package/src/metadata/__tests__/metadata_configuration_mappers.test.ts +39 -0
- package/src/metadata/__tests__/metadata_configuration_objects.test.ts +2 -1
- package/src/metadata/__tests__/metadata_device_context.test.ts +3 -3
- package/src/metadata/__tests__/metadata_device_os_android.test.ts +18 -0
- package/src/metadata/__tests__/metadata_golden_fixture.json +1 -1
- package/src/metadata/__tests__/metadata_payload_golden.test.ts +4 -4
- package/src/metadata/__tests__/optional_native_modules.test.ts +234 -0
- package/src/metadata/__tests__/use_smile_id_metadata.test.ts +1 -1
- package/src/metadata/__tests__/use_smile_id_metadata_factory.test.ts +615 -0
- package/src/metadata/builder_configuration.ts +6 -0
- package/src/metadata/metadata_configuration_mappers.ts +21 -7
- package/src/metadata/use_smile_id_metadata_factory.ts +17 -6
- package/src/presentation/assets/si_document_green_book_hero_animation.json +1 -4668
- package/src/presentation/assets/si_document_hero_animation.json +1 -4799
- package/src/presentation/assets/si_document_hero_back_animation.json +1 -2039
- package/src/presentation/assets/si_document_passport_hero_animation.json +1 -14491
- package/src/presentation/assets/si_ess_all_directions_hero_animation.json +1 -0
- package/src/presentation/assets/si_ess_animation_all_directions.json +1 -6589
- package/src/presentation/assets/si_selfie_hero_animation.json +1 -1439
- package/src/presentation/assets/si_smile_to_capture_animation.json +1 -1439
- package/src/presentation/components/__tests__/use_smile_id_content_card.test.tsx +112 -0
- package/src/presentation/components/__tests__/use_smile_id_enhanced_smart_selfie_clip.test.tsx +9 -4
- package/src/presentation/components/__tests__/use_smile_id_face_oval_image.test.tsx +190 -0
- package/src/presentation/components/__tests__/use_smile_id_instructions_hero.test.tsx +44 -0
- package/src/presentation/components/__tests__/use_smile_id_learn_more_content.test.tsx +159 -0
- package/src/presentation/components/__tests__/use_smile_id_processing_center_indicator.test.tsx +88 -0
- package/src/presentation/components/use_smile_id_button.tsx +7 -2
- package/src/presentation/components/use_smile_id_enhanced_smart_selfie_clip.tsx +9 -3
- package/src/presentation/components/use_smile_id_instructions_hero.tsx +10 -0
- package/src/presentation/flow/__tests__/document_flow_navigation.test.ts +3 -3
- package/src/presentation/flow/__tests__/flow_navigation_manager.test.ts +372 -1
- package/src/presentation/flow/__tests__/use_smile_id_flow.test.tsx +651 -0
- package/src/presentation/flow/dsl/__tests__/use_smile_id_builder_component.test.tsx +120 -0
- package/src/presentation/flow/dsl/builder/__tests__/config_builder.test.ts +25 -0
- package/src/presentation/flow/dsl/builder/config_builder.ts +21 -0
- package/src/presentation/flow/dsl/builder/screens_builder.ts +7 -12
- package/src/presentation/flow/dsl/use_smile_id_flow_builder.ts +27 -1
- package/src/presentation/flow/flow_navigation_manager.ts +108 -93
- package/src/presentation/flow/graph/__tests__/screen_renderer.test.tsx +102 -0
- package/src/presentation/flow/model/instructions_defaults.ts +1 -1
- package/src/presentation/flow/screen/__tests__/orchestrated_capture_screen.test.tsx +836 -0
- package/src/presentation/flow/screen/__tests__/orchestrated_consent_screen.test.tsx +165 -0
- package/src/presentation/flow/screen/__tests__/orchestrated_instructions_screen.test.tsx +163 -0
- package/src/presentation/flow/screen/__tests__/orchestrated_preview_screen.test.tsx +224 -0
- package/src/presentation/flow/screen/__tests__/orchestrated_processing_screen.test.tsx +338 -0
- package/src/presentation/flow/screen/orchestrated_capture_screen.tsx +18 -3
- package/src/presentation/flow/screen/orchestrated_consent_screen.tsx +5 -0
- package/src/presentation/flow/screen/orchestrated_preview_screen.tsx +0 -12
- package/src/presentation/flow/screen/orchestrated_processing_screen.tsx +42 -5
- package/src/presentation/flow/use_smile_id_flow.tsx +63 -12
- package/src/presentation/flow/validation/__tests__/flow_validator.test.ts +219 -1
- package/src/presentation/flow/validation/__tests__/job_type_validator.test.ts +200 -0
- package/src/presentation/flow/validation/flow_validator.ts +85 -57
- package/src/presentation/flow/validation/job_type_validator.ts +73 -39
- package/src/presentation/flow/validation/user_details_validator.ts +53 -0
- package/src/presentation/screen/__tests__/capture_ui_state.test.ts +66 -47
- package/src/presentation/screen/__tests__/ess_turn_haptics.test.ts +15 -11
- package/src/presentation/screen/__tests__/feedback_copy_table.test.ts +145 -0
- package/src/presentation/screen/__tests__/scan_state_to_overlay_state.test.ts +47 -27
- package/src/presentation/screen/__tests__/use_smile_id_capture_screen.test.tsx +524 -14
- package/src/presentation/screen/__tests__/use_smile_id_document_back_instructions.test.tsx +4 -2
- package/src/presentation/screen/__tests__/use_smile_id_permission_screen.test.tsx +68 -0
- package/src/presentation/screen/__tests__/use_smile_id_preview_screen.test.tsx +10 -40
- package/src/presentation/screen/helpers/__tests__/use_capture_orientation_lock.test.tsx +212 -0
- package/src/presentation/screen/helpers/capture_screen_helpers.ts +1 -0
- package/src/presentation/screen/helpers/capture_ui_state.ts +27 -27
- package/src/presentation/screen/helpers/ess_turn_haptics.ts +9 -9
- package/src/presentation/screen/helpers/scan_state_to_overlay_state.ts +13 -13
- package/src/presentation/screen/helpers/use_capture_orientation_lock.ts +69 -7
- package/src/presentation/screen/use_smile_id_capture_screen.tsx +107 -28
- package/src/presentation/screen/use_smile_id_consent_screen.tsx +16 -5
- package/src/presentation/screen/use_smile_id_document_back_instructions.tsx +14 -23
- package/src/presentation/screen/use_smile_id_document_preview_screen.tsx +1 -1
- package/src/presentation/screen/use_smile_id_preview_screen.tsx +13 -45
- package/src/presentation/screen/use_smile_id_processing_screen.tsx +1 -1
- package/src/presentation/theme/__tests__/use_use_smile_id_fonts.test.tsx +166 -0
- package/src/presentation/utils/__tests__/locale_utils.test.ts +46 -5
- package/src/presentation/utils/locale_utils.ts +13 -4
- package/src/testing/__tests__/fake_face_analyzer.test.ts +42 -0
- package/src/testing/__tests__/scenario_expectations.test.ts +110 -0
- package/src/testing/__tests__/scenario_loader.test.ts +64 -0
- package/src/testing/fake_face_analyzer.ts +82 -0
- package/src/testing/index.ts +15 -0
- package/src/testing/scenario_expectations.ts +87 -0
- package/src/testing/scenario_loader.ts +83 -0
- package/src/testing/scripted_scan_results.ts +66 -0
- package/dist/presentation/components/use_smile_id_face_silhouette_overlay.d.ts +0 -15
- package/dist/presentation/components/use_smile_id_face_silhouette_overlay.d.ts.map +0 -1
- package/dist/presentation/components/use_smile_id_face_silhouette_overlay.js +0 -19
- package/dist/presentation/components/use_smile_id_face_silhouette_overlay.js.map +0 -1
- package/src/presentation/components/use_smile_id_face_silhouette_overlay.tsx +0 -27
|
@@ -39,6 +39,7 @@ import type {
|
|
|
39
39
|
ConsentInformation,
|
|
40
40
|
UserDetails,
|
|
41
41
|
} from "../../../core/models/params";
|
|
42
|
+
import type { TokenPayload } from "../../model/token_payload";
|
|
42
43
|
import { UseSmileIDMetadata } from "../../../metadata/use_smile_id_metadata";
|
|
43
44
|
|
|
44
45
|
type RecordedCall = {
|
|
@@ -109,7 +110,7 @@ const consent: ConsentInformation = Object.freeze({
|
|
|
109
110
|
// builds this and it travels on every `JobRequest`; the API
|
|
110
111
|
// serializes `request.metadata` as the `metadata` multipart part.
|
|
111
112
|
const metadata = new UseSmileIDMetadata({
|
|
112
|
-
sdkVersion: "12.0.
|
|
113
|
+
sdkVersion: "12.0.2",
|
|
113
114
|
sdk: "react-native-expo",
|
|
114
115
|
deviceOs: "",
|
|
115
116
|
deviceModel: "",
|
|
@@ -1071,6 +1072,279 @@ describe("SmileIDAPI response-body parse failures", () => {
|
|
|
1071
1072
|
});
|
|
1072
1073
|
});
|
|
1073
1074
|
|
|
1075
|
+
describe("SmileIDAPI — token-provided user details & consent (wire)", () => {
|
|
1076
|
+
const livenessImages: readonly string[] = [
|
|
1077
|
+
"file:///l1.jpg",
|
|
1078
|
+
"file:///l2.jpg",
|
|
1079
|
+
"file:///l3.jpg",
|
|
1080
|
+
"file:///l4.jpg",
|
|
1081
|
+
"file:///l5.jpg",
|
|
1082
|
+
"file:///l6.jpg",
|
|
1083
|
+
"file:///l7.jpg",
|
|
1084
|
+
];
|
|
1085
|
+
|
|
1086
|
+
const fullUserDetails: UserDetails = {
|
|
1087
|
+
givenNames: "John",
|
|
1088
|
+
lastName: "Doe",
|
|
1089
|
+
email: "john@example.test",
|
|
1090
|
+
phoneNumber: "+254700000000",
|
|
1091
|
+
};
|
|
1092
|
+
|
|
1093
|
+
function tokenPayload(overrides: Partial<TokenPayload> = {}): TokenPayload {
|
|
1094
|
+
return {
|
|
1095
|
+
hasGivenNames: false,
|
|
1096
|
+
hasLastName: false,
|
|
1097
|
+
hasEmail: false,
|
|
1098
|
+
hasPhoneNumber: false,
|
|
1099
|
+
...overrides,
|
|
1100
|
+
};
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
const fullBinding = tokenPayload({
|
|
1104
|
+
hasGivenNames: true,
|
|
1105
|
+
hasLastName: true,
|
|
1106
|
+
hasEmail: true,
|
|
1107
|
+
hasPhoneNumber: true,
|
|
1108
|
+
});
|
|
1109
|
+
|
|
1110
|
+
const completeTokenConsent = {
|
|
1111
|
+
granted: true,
|
|
1112
|
+
grantedAt: "2026-01-01T09:00:00.000Z",
|
|
1113
|
+
noticeLanguage: "EN",
|
|
1114
|
+
noticePrivacyPolicyUrl: "https://partner.test/privacy",
|
|
1115
|
+
} as const;
|
|
1116
|
+
|
|
1117
|
+
function enrollmentRequest(
|
|
1118
|
+
overrides: Partial<SmartSelfieEnrollmentRequest> = {},
|
|
1119
|
+
): SmartSelfieEnrollmentRequest {
|
|
1120
|
+
return {
|
|
1121
|
+
jobType: JobType.smartSelfieEnrollment,
|
|
1122
|
+
selfieImage: "file:///selfie.jpg",
|
|
1123
|
+
livenessImages,
|
|
1124
|
+
consent,
|
|
1125
|
+
metadata,
|
|
1126
|
+
expectedLivenessImageCount: 7,
|
|
1127
|
+
userDetails: fullUserDetails,
|
|
1128
|
+
enhanced: false,
|
|
1129
|
+
...overrides,
|
|
1130
|
+
};
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1133
|
+
it("a partial user_details payload sends only its remaining fields", async () => {
|
|
1134
|
+
// Assembly already dropped the token-bound names (token always wins);
|
|
1135
|
+
// only email/phone ride the wire.
|
|
1136
|
+
const { api, calls } = makeApi();
|
|
1137
|
+
await api.smartSelfieEnrollment(
|
|
1138
|
+
enrollmentRequest({
|
|
1139
|
+
userDetails: {
|
|
1140
|
+
email: "john@example.test",
|
|
1141
|
+
phoneNumber: "+254700000000",
|
|
1142
|
+
},
|
|
1143
|
+
}),
|
|
1144
|
+
);
|
|
1145
|
+
const parts = partsByName(calls[0]!.body);
|
|
1146
|
+
const parsed = JSON.parse(await readJsonPart(parts["user_details"]![0]));
|
|
1147
|
+
expect(parsed).toEqual({
|
|
1148
|
+
email: "john@example.test",
|
|
1149
|
+
phone_number: "+254700000000",
|
|
1150
|
+
});
|
|
1151
|
+
});
|
|
1152
|
+
|
|
1153
|
+
it("omits the user_details part when the request carries no userDetails", async () => {
|
|
1154
|
+
const { api, calls } = makeApi();
|
|
1155
|
+
const { userDetails: _details, ...withoutUserDetails } =
|
|
1156
|
+
enrollmentRequest();
|
|
1157
|
+
await api.smartSelfieEnrollment({
|
|
1158
|
+
...withoutUserDetails,
|
|
1159
|
+
tokenPayload: fullBinding,
|
|
1160
|
+
});
|
|
1161
|
+
const parts = partsByName(calls[0]!.body);
|
|
1162
|
+
expect(parts["user_details"]).toBeUndefined();
|
|
1163
|
+
});
|
|
1164
|
+
|
|
1165
|
+
it("an empty user_details payload omits the part entirely", async () => {
|
|
1166
|
+
const { api, calls } = makeApi();
|
|
1167
|
+
await api.smartSelfieEnrollment(enrollmentRequest({ userDetails: {} }));
|
|
1168
|
+
const parts = partsByName(calls[0]!.body);
|
|
1169
|
+
expect(parts["user_details"]).toBeUndefined();
|
|
1170
|
+
});
|
|
1171
|
+
|
|
1172
|
+
it("omits the consent part when the request carries no consent (token-complete path)", async () => {
|
|
1173
|
+
const { api, calls } = makeApi();
|
|
1174
|
+
const { consent: _consent, ...withoutConsent } = enrollmentRequest();
|
|
1175
|
+
await api.smartSelfieEnrollment({
|
|
1176
|
+
...withoutConsent,
|
|
1177
|
+
tokenPayload: {
|
|
1178
|
+
...tokenPayload(),
|
|
1179
|
+
consent: completeTokenConsent,
|
|
1180
|
+
},
|
|
1181
|
+
});
|
|
1182
|
+
const parts = partsByName(calls[0]!.body);
|
|
1183
|
+
expect(parts["consent"]).toBeUndefined();
|
|
1184
|
+
// The metadata part is unconditional — it must survive the omission.
|
|
1185
|
+
expect(parts["metadata"]).toBeDefined();
|
|
1186
|
+
});
|
|
1187
|
+
|
|
1188
|
+
it("sends a local consent in full even when the token also binds consent", async () => {
|
|
1189
|
+
// Server merges per-subfield with the token winning; the SDK never
|
|
1190
|
+
// trims a locally captured / preset consent.
|
|
1191
|
+
const { api, calls } = makeApi();
|
|
1192
|
+
await api.smartSelfieEnrollment(
|
|
1193
|
+
enrollmentRequest({
|
|
1194
|
+
tokenPayload: {
|
|
1195
|
+
...tokenPayload(),
|
|
1196
|
+
consent: completeTokenConsent,
|
|
1197
|
+
},
|
|
1198
|
+
}),
|
|
1199
|
+
);
|
|
1200
|
+
const parts = partsByName(calls[0]!.body);
|
|
1201
|
+
const parsed = JSON.parse(await readJsonPart(parts["consent"]![0]));
|
|
1202
|
+
expect(parsed).toEqual({
|
|
1203
|
+
granted: true,
|
|
1204
|
+
granted_at: "2026-04-30T00:00:00.000Z",
|
|
1205
|
+
notice_language: "EN",
|
|
1206
|
+
notice_privacy_policy_url: "https://example.test/p",
|
|
1207
|
+
});
|
|
1208
|
+
});
|
|
1209
|
+
|
|
1210
|
+
it("regression: without a tokenPayload the parts are identical to today", async () => {
|
|
1211
|
+
const { api, calls } = makeApi();
|
|
1212
|
+
await api.smartSelfieEnrollment(enrollmentRequest());
|
|
1213
|
+
const parts = partsByName(calls[0]!.body);
|
|
1214
|
+
const userDetailsParsed = JSON.parse(
|
|
1215
|
+
await readJsonPart(parts["user_details"]![0]),
|
|
1216
|
+
);
|
|
1217
|
+
expect(userDetailsParsed).toEqual({
|
|
1218
|
+
given_names: "John",
|
|
1219
|
+
last_name: "Doe",
|
|
1220
|
+
email: "john@example.test",
|
|
1221
|
+
phone_number: "+254700000000",
|
|
1222
|
+
});
|
|
1223
|
+
const consentParsed = JSON.parse(await readJsonPart(parts["consent"]![0]));
|
|
1224
|
+
expect(consentParsed).toEqual({
|
|
1225
|
+
granted: true,
|
|
1226
|
+
granted_at: "2026-04-30T00:00:00.000Z",
|
|
1227
|
+
notice_language: "EN",
|
|
1228
|
+
notice_privacy_policy_url: "https://example.test/p",
|
|
1229
|
+
});
|
|
1230
|
+
});
|
|
1231
|
+
|
|
1232
|
+
it("keeps the stripped user_details part an untagged text form field", async () => {
|
|
1233
|
+
const { api, calls } = makeApi();
|
|
1234
|
+
await api.smartSelfieEnrollment(
|
|
1235
|
+
enrollmentRequest({
|
|
1236
|
+
tokenPayload: tokenPayload({ hasGivenNames: true }),
|
|
1237
|
+
}),
|
|
1238
|
+
);
|
|
1239
|
+
const parts = partsByName(calls[0]!.body);
|
|
1240
|
+
expectNoJsonContentType(parts["user_details"]![0]);
|
|
1241
|
+
});
|
|
1242
|
+
|
|
1243
|
+
// Every endpoint routes user_details / consent through the same
|
|
1244
|
+
// helpers — pin the omission behavior across all six.
|
|
1245
|
+
const omissionSubmissions: ReadonlyArray<{
|
|
1246
|
+
readonly endpoint: string;
|
|
1247
|
+
readonly submit: (api: SmileIDAPI) => Promise<unknown>;
|
|
1248
|
+
}> = [
|
|
1249
|
+
{
|
|
1250
|
+
endpoint: "/v3/registration",
|
|
1251
|
+
submit: (api) =>
|
|
1252
|
+
api.smartSelfieEnrollment({
|
|
1253
|
+
jobType: JobType.smartSelfieEnrollment,
|
|
1254
|
+
selfieImage: "file:///selfie.jpg",
|
|
1255
|
+
livenessImages,
|
|
1256
|
+
enhanced: false,
|
|
1257
|
+
metadata,
|
|
1258
|
+
expectedLivenessImageCount: 7,
|
|
1259
|
+
tokenPayload: { ...fullBinding, consent: completeTokenConsent },
|
|
1260
|
+
}),
|
|
1261
|
+
},
|
|
1262
|
+
{
|
|
1263
|
+
endpoint: "/v3/authentication",
|
|
1264
|
+
submit: (api) =>
|
|
1265
|
+
api.smartSelfieAuthentication({
|
|
1266
|
+
jobType: JobType.smartSelfieAuthentication,
|
|
1267
|
+
selfieImage: "file:///selfie.jpg",
|
|
1268
|
+
livenessImages,
|
|
1269
|
+
userId: "user-1",
|
|
1270
|
+
enhanced: false,
|
|
1271
|
+
metadata,
|
|
1272
|
+
expectedLivenessImageCount: 7,
|
|
1273
|
+
tokenPayload: { ...fullBinding, consent: completeTokenConsent },
|
|
1274
|
+
}),
|
|
1275
|
+
},
|
|
1276
|
+
{
|
|
1277
|
+
endpoint: "/v3/enhanced_kyc",
|
|
1278
|
+
submit: (api) =>
|
|
1279
|
+
api.enhancedKyc({
|
|
1280
|
+
jobType: JobType.enhancedKyc,
|
|
1281
|
+
params: { idType: "NATIONAL_ID", idNumber: "1", country: "KE" },
|
|
1282
|
+
metadata,
|
|
1283
|
+
tokenPayload: { ...fullBinding, consent: completeTokenConsent },
|
|
1284
|
+
}),
|
|
1285
|
+
},
|
|
1286
|
+
{
|
|
1287
|
+
endpoint: "/v3/biometric_kyc",
|
|
1288
|
+
submit: (api) =>
|
|
1289
|
+
api.biometricKyc({
|
|
1290
|
+
jobType: JobType.biometricKyc,
|
|
1291
|
+
selfieImage: "file:///selfie.jpg",
|
|
1292
|
+
livenessImages,
|
|
1293
|
+
params: {
|
|
1294
|
+
idType: "NATIONAL_ID",
|
|
1295
|
+
idNumber: "1",
|
|
1296
|
+
country: "KE",
|
|
1297
|
+
useEnrolledImage: false,
|
|
1298
|
+
},
|
|
1299
|
+
metadata,
|
|
1300
|
+
expectedLivenessImageCount: 7,
|
|
1301
|
+
tokenPayload: { ...fullBinding, consent: completeTokenConsent },
|
|
1302
|
+
}),
|
|
1303
|
+
},
|
|
1304
|
+
{
|
|
1305
|
+
endpoint: "/v3/document_verification",
|
|
1306
|
+
submit: (api) =>
|
|
1307
|
+
api.documentVerification({
|
|
1308
|
+
jobType: JobType.documentVerification,
|
|
1309
|
+
selfieImage: "file:///selfie.jpg",
|
|
1310
|
+
livenessImages,
|
|
1311
|
+
frontDocument: "file:///front.jpg",
|
|
1312
|
+
country: "KE",
|
|
1313
|
+
metadata,
|
|
1314
|
+
expectedLivenessImageCount: 7,
|
|
1315
|
+
tokenPayload: { ...fullBinding, consent: completeTokenConsent },
|
|
1316
|
+
}),
|
|
1317
|
+
},
|
|
1318
|
+
{
|
|
1319
|
+
endpoint: "/v3/enhanced_document_verification",
|
|
1320
|
+
submit: (api) =>
|
|
1321
|
+
api.enhancedDocumentVerification({
|
|
1322
|
+
jobType: JobType.enhancedDocumentVerification,
|
|
1323
|
+
selfieImage: "file:///selfie.jpg",
|
|
1324
|
+
livenessImages,
|
|
1325
|
+
frontDocument: "file:///front.jpg",
|
|
1326
|
+
country: "KE",
|
|
1327
|
+
idType: "NATIONAL_ID",
|
|
1328
|
+
metadata,
|
|
1329
|
+
expectedLivenessImageCount: 7,
|
|
1330
|
+
tokenPayload: { ...fullBinding, consent: completeTokenConsent },
|
|
1331
|
+
}),
|
|
1332
|
+
},
|
|
1333
|
+
];
|
|
1334
|
+
|
|
1335
|
+
for (const { endpoint, submit } of omissionSubmissions) {
|
|
1336
|
+
it(`${endpoint} omits user_details and consent on the token-complete path`, async () => {
|
|
1337
|
+
const { api, calls } = makeApi();
|
|
1338
|
+
await submit(api);
|
|
1339
|
+
expect(calls[0]!.url).toBe(endpoint);
|
|
1340
|
+
const parts = partsByName(calls[0]!.body);
|
|
1341
|
+
expect(parts["user_details"]).toBeUndefined();
|
|
1342
|
+
expect(parts["consent"]).toBeUndefined();
|
|
1343
|
+
expect(parts["metadata"]).toBeDefined();
|
|
1344
|
+
});
|
|
1345
|
+
}
|
|
1346
|
+
});
|
|
1347
|
+
|
|
1074
1348
|
describe("SmileIDAPI signed job opt-in (request MAC + attestation)", () => {
|
|
1075
1349
|
// An endpoint missing the opt-in flags ships an unsigned job the
|
|
1076
1350
|
// server rejects — while the interceptors' own tests stay green.
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import axios, { AxiosHeaders, type InternalAxiosRequestConfig } from "axios";
|
|
2
|
+
import { describe, expect, it, vi, beforeEach, afterEach } from "vitest";
|
|
3
|
+
|
|
4
|
+
import { LogLevel } from "../../../../core/models/network_config";
|
|
5
|
+
import { LoggingConfigBuilder } from "../../../dsl/builder/config_builder";
|
|
6
|
+
import { InterceptorConfigBuilder } from "../../../dsl/builder/interceptor_config_builder";
|
|
7
|
+
import { attachLoggingInterceptor } from "../logging_interceptor";
|
|
8
|
+
|
|
9
|
+
const CANONICAL_CREDENTIAL_HEADERS: ReadonlyArray<
|
|
10
|
+
readonly [name: string, value: string]
|
|
11
|
+
> = [
|
|
12
|
+
["SmileID-Token", "secret-jwt-value"],
|
|
13
|
+
["smileid-partner-id", "secret-partner-002"],
|
|
14
|
+
["SmileID-Api-Key", "secret-api-key"],
|
|
15
|
+
["smileid-device-nonce", "secret-nonce"],
|
|
16
|
+
["Authorization", "Bearer secret-bearer"],
|
|
17
|
+
["Cookie", "session=secret-cookie"],
|
|
18
|
+
["Set-Cookie", "session=secret-set-cookie"],
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
function requestHeaders(): AxiosHeaders {
|
|
22
|
+
const headers = new AxiosHeaders();
|
|
23
|
+
for (const [name, value] of CANONICAL_CREDENTIAL_HEADERS) {
|
|
24
|
+
headers.set(name, value);
|
|
25
|
+
}
|
|
26
|
+
headers.set("Content-Type", "multipart/form-data");
|
|
27
|
+
return headers;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function invokeRequestFulfilled(
|
|
31
|
+
client: ReturnType<typeof axios.create>,
|
|
32
|
+
): InternalAxiosRequestConfig {
|
|
33
|
+
const handlers = (
|
|
34
|
+
client.interceptors.request as unknown as {
|
|
35
|
+
handlers: {
|
|
36
|
+
fulfilled?: (
|
|
37
|
+
config: InternalAxiosRequestConfig,
|
|
38
|
+
) => InternalAxiosRequestConfig;
|
|
39
|
+
}[];
|
|
40
|
+
}
|
|
41
|
+
).handlers;
|
|
42
|
+
const lastHandler = handlers[handlers.length - 1];
|
|
43
|
+
if (typeof lastHandler?.fulfilled !== "function") {
|
|
44
|
+
throw new Error("No fulfilled request handler found");
|
|
45
|
+
}
|
|
46
|
+
return lastHandler.fulfilled({
|
|
47
|
+
method: "post",
|
|
48
|
+
baseURL: "https://testapi.smileidentity.com",
|
|
49
|
+
url: "/v2/submit-job",
|
|
50
|
+
headers: requestHeaders(),
|
|
51
|
+
} as InternalAxiosRequestConfig);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
describe("credential headers under the partner-facing logging config", () => {
|
|
55
|
+
let client: ReturnType<typeof axios.create>;
|
|
56
|
+
let consoleLogSpy: ReturnType<typeof vi.spyOn>;
|
|
57
|
+
|
|
58
|
+
beforeEach(() => {
|
|
59
|
+
client = axios.create();
|
|
60
|
+
consoleLogSpy = vi.spyOn(console, "log").mockImplementation(() => {});
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
afterEach(() => {
|
|
64
|
+
consoleLogSpy.mockRestore();
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
function printedOutput(): string {
|
|
68
|
+
return consoleLogSpy.mock.calls
|
|
69
|
+
.map((call) => call.map((arg) => JSON.stringify(arg)).join(" "))
|
|
70
|
+
.join("\n");
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const configurations: ReadonlyArray<
|
|
74
|
+
readonly [label: string, attach: (client_: typeof client) => void]
|
|
75
|
+
> = [
|
|
76
|
+
[
|
|
77
|
+
"network { config { logging { } } } at default redactHeaders",
|
|
78
|
+
(client_) => {
|
|
79
|
+
const builder = new LoggingConfigBuilder();
|
|
80
|
+
builder.level = LogLevel.headers;
|
|
81
|
+
attachLoggingInterceptor(client_, builder.build());
|
|
82
|
+
},
|
|
83
|
+
],
|
|
84
|
+
[
|
|
85
|
+
"network { interceptors { logging() } } at default redactHeaders",
|
|
86
|
+
(client_) => {
|
|
87
|
+
const interceptors = new InterceptorConfigBuilder();
|
|
88
|
+
interceptors
|
|
89
|
+
.logging((l) => {
|
|
90
|
+
l.level = LogLevel.headers;
|
|
91
|
+
})
|
|
92
|
+
.attach(client_);
|
|
93
|
+
},
|
|
94
|
+
],
|
|
95
|
+
];
|
|
96
|
+
|
|
97
|
+
for (const [label, attach] of configurations) {
|
|
98
|
+
it(`masks every credential header — ${label}`, () => {
|
|
99
|
+
attach(client);
|
|
100
|
+
invokeRequestFulfilled(client);
|
|
101
|
+
|
|
102
|
+
const output = printedOutput();
|
|
103
|
+
expect(output).not.toBe("");
|
|
104
|
+
for (const [name, value] of CANONICAL_CREDENTIAL_HEADERS) {
|
|
105
|
+
expect(output, `${name} leaked its value`).not.toContain(value);
|
|
106
|
+
}
|
|
107
|
+
expect(output).toContain("multipart/form-data");
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it(`keeps the header names visible so the audit trail survives — ${label}`, () => {
|
|
111
|
+
attach(client);
|
|
112
|
+
invokeRequestFulfilled(client);
|
|
113
|
+
|
|
114
|
+
const output = printedOutput().toLowerCase();
|
|
115
|
+
for (const [name] of CANONICAL_CREDENTIAL_HEADERS) {
|
|
116
|
+
expect(output, `${name} was dropped entirely`).toContain(
|
|
117
|
+
name.toLowerCase(),
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
it("does not print headers at the default verbosity", () => {
|
|
124
|
+
const builder = new LoggingConfigBuilder();
|
|
125
|
+
attachLoggingInterceptor(client, builder.build());
|
|
126
|
+
invokeRequestFulfilled(client);
|
|
127
|
+
|
|
128
|
+
expect(printedOutput()).not.toContain("headers");
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it("unions the partner's list with the always-redact set rather than replacing it", () => {
|
|
132
|
+
const builder = new LoggingConfigBuilder();
|
|
133
|
+
builder.level = LogLevel.headers;
|
|
134
|
+
builder.redactHeaders = ["content-type"];
|
|
135
|
+
attachLoggingInterceptor(client, builder.build());
|
|
136
|
+
invokeRequestFulfilled(client);
|
|
137
|
+
|
|
138
|
+
const output = printedOutput();
|
|
139
|
+
expect(output).not.toContain("multipart/form-data");
|
|
140
|
+
for (const [, value] of CANONICAL_CREDENTIAL_HEADERS) {
|
|
141
|
+
expect(output).not.toContain(value);
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
});
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import axios, { AxiosHeaders, type InternalAxiosRequestConfig } from "axios";
|
|
3
|
+
|
|
4
|
+
import { createGzipInterceptor } from "../gzip_interceptor";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Pins `createGzipInterceptor`'s wire shape: it stamps `Accept-Encoding: gzip` on every request
|
|
8
|
+
* (never reading `config.data`), leaves the body unmodified (no compression, no Content-Type/
|
|
9
|
+
* Length), never sets `Content-Encoding`, and overwrites any existing `Accept-Encoding`.
|
|
10
|
+
*/
|
|
11
|
+
describe("createGzipInterceptor", () => {
|
|
12
|
+
function attachAndRun(
|
|
13
|
+
config: InternalAxiosRequestConfig,
|
|
14
|
+
): Promise<InternalAxiosRequestConfig> {
|
|
15
|
+
const client = axios.create();
|
|
16
|
+
createGzipInterceptor().attach(client);
|
|
17
|
+
const handlers = (
|
|
18
|
+
client.interceptors.request as unknown as {
|
|
19
|
+
handlers: {
|
|
20
|
+
fulfilled?: (
|
|
21
|
+
cfg: InternalAxiosRequestConfig,
|
|
22
|
+
) => InternalAxiosRequestConfig | Promise<InternalAxiosRequestConfig>;
|
|
23
|
+
}[];
|
|
24
|
+
}
|
|
25
|
+
).handlers;
|
|
26
|
+
const fulfilled = handlers[handlers.length - 1]?.fulfilled;
|
|
27
|
+
if (!fulfilled) throw new Error("gzip interceptor did not register");
|
|
28
|
+
return Promise.resolve(fulfilled(config));
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
it("stamps Accept-Encoding: gzip on a bodyless request", async () => {
|
|
32
|
+
const result = await attachAndRun({
|
|
33
|
+
headers: new AxiosHeaders(),
|
|
34
|
+
} as InternalAxiosRequestConfig);
|
|
35
|
+
|
|
36
|
+
expect(result.headers.get("Accept-Encoding")).toBe("gzip");
|
|
37
|
+
expect(result.data).toBeUndefined();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("stamps the header without touching a JSON string body", async () => {
|
|
41
|
+
const result = await attachAndRun({
|
|
42
|
+
headers: new AxiosHeaders(),
|
|
43
|
+
data: '{"hello":"world"}',
|
|
44
|
+
} as InternalAxiosRequestConfig);
|
|
45
|
+
|
|
46
|
+
expect(result.headers.get("Accept-Encoding")).toBe("gzip");
|
|
47
|
+
// The body is not compressed or otherwise transformed.
|
|
48
|
+
expect(result.data).toBe('{"hello":"world"}');
|
|
49
|
+
expect(result.headers.get("Content-Type")).toBeUndefined();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("stamps the header without touching a multipart FormData body", async () => {
|
|
53
|
+
// A minimal FormData-like stand-in; the interceptor never inspects
|
|
54
|
+
// `config.data`'s shape, so this is enough to prove pass-through.
|
|
55
|
+
const formData = { getParts: () => [] };
|
|
56
|
+
const result = await attachAndRun({
|
|
57
|
+
headers: new AxiosHeaders(),
|
|
58
|
+
data: formData,
|
|
59
|
+
} as unknown as InternalAxiosRequestConfig);
|
|
60
|
+
|
|
61
|
+
expect(result.headers.get("Accept-Encoding")).toBe("gzip");
|
|
62
|
+
expect(result.data).toBe(formData);
|
|
63
|
+
expect(result.headers.get("Content-Type")).toBeUndefined();
|
|
64
|
+
expect(result.headers.get("Content-Length")).toBeUndefined();
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("never stamps Content-Encoding — the request body itself is never compressed", async () => {
|
|
68
|
+
const result = await attachAndRun({
|
|
69
|
+
headers: new AxiosHeaders(),
|
|
70
|
+
data: '{"hello":"world"}',
|
|
71
|
+
} as InternalAxiosRequestConfig);
|
|
72
|
+
|
|
73
|
+
expect(result.headers.get("Content-Encoding")).toBeUndefined();
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("overwrites an Accept-Encoding value set by an earlier interceptor", async () => {
|
|
77
|
+
const result = await attachAndRun({
|
|
78
|
+
headers: new AxiosHeaders({ "Accept-Encoding": "identity" }),
|
|
79
|
+
} as InternalAxiosRequestConfig);
|
|
80
|
+
|
|
81
|
+
expect(result.headers.get("Accept-Encoding")).toBe("gzip");
|
|
82
|
+
});
|
|
83
|
+
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AxiosInstance, InternalAxiosRequestConfig } from "axios";
|
|
2
|
-
import {
|
|
2
|
+
import { sourceSdkIdentifier } from "@smileid/usesmileid_bridge";
|
|
3
3
|
|
|
4
4
|
import type { PartnerConfig } from "../../../core/models/network_config";
|
|
5
5
|
import { currentRequestTimestamp } from "../../security/request_timestamp";
|
|
@@ -26,22 +26,7 @@ import type { TokenHolder } from "../auth/token_holder";
|
|
|
26
26
|
* by the next outgoing request.
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
|
-
const SDK_VERSION = "12.0.
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Source-SDK identifier, suffixed with the runtime platform so the server can
|
|
33
|
-
* attribute the request and resolve the matching per-SDK signing secret.
|
|
34
|
-
*/
|
|
35
|
-
function sourceSdk(): string {
|
|
36
|
-
switch (Platform.OS) {
|
|
37
|
-
case "android":
|
|
38
|
-
return "react-native-expo (android)";
|
|
39
|
-
case "ios":
|
|
40
|
-
return "react-native-expo (iOS)";
|
|
41
|
-
default:
|
|
42
|
-
return "react-native-expo";
|
|
43
|
-
}
|
|
44
|
-
}
|
|
29
|
+
const SDK_VERSION = "12.0.2"; // x-release-please-version
|
|
45
30
|
|
|
46
31
|
export type SmileAuthInterceptorOptions = {
|
|
47
32
|
readonly partnerConfig: PartnerConfig;
|
|
@@ -73,7 +58,7 @@ export class SmileAuthInterceptor {
|
|
|
73
58
|
config: InternalAxiosRequestConfig,
|
|
74
59
|
): Promise<InternalAxiosRequestConfig> {
|
|
75
60
|
config.headers.set("smileid-token", this._tokenHolder.current);
|
|
76
|
-
config.headers.set("smileid-source-sdk",
|
|
61
|
+
config.headers.set("smileid-source-sdk", sourceSdkIdentifier());
|
|
77
62
|
config.headers.set("smileid-source-sdk-version", SDK_VERSION);
|
|
78
63
|
config.headers.set("smileid-partner-id", this._partnerConfig.partnerId);
|
|
79
64
|
if (this._partnerConfig.callbackUrl) {
|