@smileid/usesmileid 12.0.0-beta01 → 12.0.1
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 +15 -0
- package/README.md +701 -89
- package/dist/camera/camera_defaults.d.ts +14 -9
- package/dist/camera/camera_defaults.d.ts.map +1 -1
- package/dist/camera/camera_defaults.js +11 -9
- package/dist/camera/camera_defaults.js.map +1 -1
- package/dist/camera/orientation_degrees.d.ts +5 -6
- package/dist/camera/orientation_degrees.d.ts.map +1 -1
- package/dist/camera/orientation_degrees.js +5 -6
- package/dist/camera/orientation_degrees.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/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/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_capture_mode.d.ts +8 -0
- package/dist/core/models/document_capture_mode.d.ts.map +1 -1
- package/dist/core/models/document_capture_mode.js +24 -0
- package/dist/core/models/document_capture_mode.js.map +1 -1
- package/dist/core/models/document_type.d.ts +2 -2
- package/dist/core/models/document_type.d.ts.map +1 -1
- package/dist/core/models/document_type.js +7 -5
- 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/core/models/result.d.ts +9 -8
- package/dist/core/models/result.d.ts.map +1 -1
- package/dist/core/models/result.js +5 -6
- package/dist/core/models/result.js.map +1 -1
- 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/interceptors/smile_integrity_interceptor.d.ts +11 -0
- package/dist/data/api/interceptors/smile_integrity_interceptor.d.ts.map +1 -1
- package/dist/data/api/interceptors/smile_integrity_interceptor.js +13 -0
- package/dist/data/api/interceptors/smile_integrity_interceptor.js.map +1 -1
- package/dist/data/api/interceptors/smile_request_mac_interceptor.d.ts +8 -0
- package/dist/data/api/interceptors/smile_request_mac_interceptor.d.ts.map +1 -1
- package/dist/data/api/interceptors/smile_request_mac_interceptor.js +11 -0
- package/dist/data/api/interceptors/smile_request_mac_interceptor.js.map +1 -1
- package/dist/data/api/smile_id_api.d.ts +1 -1
- package/dist/data/api/smile_id_api.d.ts.map +1 -1
- package/dist/data/compression/compressible_asset.d.ts +41 -0
- package/dist/data/compression/compressible_asset.d.ts.map +1 -0
- package/dist/data/compression/compressible_asset.js +34 -0
- package/dist/data/compression/compressible_asset.js.map +1 -0
- package/dist/data/compression/payload_compression_config.d.ts +36 -0
- package/dist/data/compression/payload_compression_config.d.ts.map +1 -0
- package/dist/data/compression/payload_compression_config.js +52 -0
- package/dist/data/compression/payload_compression_config.js.map +1 -0
- package/dist/data/compression/payload_compression_runner.d.ts +29 -0
- package/dist/data/compression/payload_compression_runner.d.ts.map +1 -0
- package/dist/data/compression/payload_compression_runner.js +55 -0
- package/dist/data/compression/payload_compression_runner.js.map +1 -0
- package/dist/data/compression/payload_compressor.d.ts +40 -0
- package/dist/data/compression/payload_compressor.d.ts.map +1 -0
- package/dist/data/compression/payload_compressor.js +126 -0
- package/dist/data/compression/payload_compressor.js.map +1 -0
- package/dist/data/compression/uri_compressible_asset.d.ts +23 -0
- package/dist/data/compression/uri_compressible_asset.d.ts.map +1 -0
- package/dist/data/compression/uri_compressible_asset.js +77 -0
- package/dist/data/compression/uri_compressible_asset.js.map +1 -0
- package/dist/data/dsl/builder/cache_config_builder.d.ts +2 -1
- package/dist/data/dsl/builder/cache_config_builder.d.ts.map +1 -1
- package/dist/data/dsl/builder/cache_config_builder.js +2 -1
- package/dist/data/dsl/builder/cache_config_builder.js.map +1 -1
- package/dist/data/dsl/builder/config_builder.d.ts +40 -14
- package/dist/data/dsl/builder/config_builder.d.ts.map +1 -1
- package/dist/data/dsl/builder/config_builder.js +40 -14
- package/dist/data/dsl/builder/config_builder.js.map +1 -1
- package/dist/data/dsl/builder/interceptor_config_builder.d.ts +9 -7
- package/dist/data/dsl/builder/interceptor_config_builder.d.ts.map +1 -1
- package/dist/data/dsl/builder/interceptor_config_builder.js +9 -7
- package/dist/data/dsl/builder/interceptor_config_builder.js.map +1 -1
- package/dist/data/dsl/builder/retry_config_builder.d.ts +19 -4
- package/dist/data/dsl/builder/retry_config_builder.d.ts.map +1 -1
- package/dist/data/dsl/builder/retry_config_builder.js +21 -6
- package/dist/data/dsl/builder/retry_config_builder.js.map +1 -1
- package/dist/data/dsl/builder/timeout_config_builder.d.ts +4 -0
- package/dist/data/dsl/builder/timeout_config_builder.d.ts.map +1 -1
- package/dist/data/dsl/builder/timeout_config_builder.js +4 -0
- package/dist/data/dsl/builder/timeout_config_builder.js.map +1 -1
- package/dist/data/dsl/use_smile_id_network_builder.d.ts +17 -0
- package/dist/data/dsl/use_smile_id_network_builder.d.ts.map +1 -1
- package/dist/data/dsl/use_smile_id_network_builder.js +17 -0
- package/dist/data/dsl/use_smile_id_network_builder.js.map +1 -1
- package/dist/data/factory/networking_factory.d.ts.map +1 -1
- package/dist/data/factory/networking_factory.js +11 -1
- package/dist/data/factory/networking_factory.js.map +1 -1
- package/dist/data/repository/use_smile_id_repository_impl.d.ts +6 -0
- package/dist/data/repository/use_smile_id_repository_impl.d.ts.map +1 -1
- package/dist/data/repository/use_smile_id_repository_impl.js +82 -8
- package/dist/data/repository/use_smile_id_repository_impl.js.map +1 -1
- package/dist/data/security/request_canonicalizer.d.ts.map +1 -1
- package/dist/data/security/request_canonicalizer.js +14 -2
- package/dist/data/security/request_canonicalizer.js.map +1 -1
- package/dist/data/security/security_policy.d.ts +43 -0
- package/dist/data/security/security_policy.d.ts.map +1 -0
- package/dist/data/security/security_policy.js +61 -0
- package/dist/data/security/security_policy.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 +2 -2
- package/dist/data/util/retry_util.d.ts.map +1 -1
- package/dist/data/util/retry_util.js +7 -1
- package/dist/data/util/retry_util.js.map +1 -1
- package/dist/data/util/use_smile_id_token_decoder.d.ts +22 -0
- package/dist/data/util/use_smile_id_token_decoder.d.ts.map +1 -1
- package/dist/data/util/use_smile_id_token_decoder.js +58 -24
- 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 +2 -1
- package/dist/l10n/strings_en.d.ts.map +1 -1
- package/dist/l10n/strings_en.js +2 -1
- package/dist/l10n/strings_en.js.map +1 -1
- package/dist/l10n/use_smile_id_localizations.d.ts +1 -0
- package/dist/l10n/use_smile_id_localizations.d.ts.map +1 -1
- package/dist/l10n/use_smile_id_localizations.js +3 -0
- package/dist/l10n/use_smile_id_localizations.js.map +1 -1
- package/dist/metadata/builder_configuration.d.ts +44 -0
- package/dist/metadata/builder_configuration.d.ts.map +1 -0
- package/dist/metadata/builder_configuration.js +35 -0
- package/dist/metadata/builder_configuration.js.map +1 -0
- package/dist/metadata/captured_image_properties.d.ts +11 -0
- package/dist/metadata/captured_image_properties.d.ts.map +1 -0
- package/dist/metadata/captured_image_properties.js +11 -0
- package/dist/metadata/captured_image_properties.js.map +1 -0
- package/dist/metadata/device_orientation_collector.d.ts +17 -0
- package/dist/metadata/device_orientation_collector.d.ts.map +1 -0
- package/dist/metadata/device_orientation_collector.js +66 -0
- package/dist/metadata/device_orientation_collector.js.map +1 -0
- package/dist/metadata/geolocation.d.ts +20 -0
- package/dist/metadata/geolocation.d.ts.map +1 -0
- package/dist/metadata/geolocation.js +40 -0
- package/dist/metadata/geolocation.js.map +1 -0
- package/dist/metadata/metadata_configuration_mappers.d.ts +47 -0
- package/dist/metadata/metadata_configuration_mappers.d.ts.map +1 -0
- package/dist/metadata/metadata_configuration_mappers.js +178 -0
- package/dist/metadata/metadata_configuration_mappers.js.map +1 -0
- package/dist/metadata/model_configuration.d.ts +41 -0
- package/dist/metadata/model_configuration.d.ts.map +1 -0
- package/dist/metadata/model_configuration.js +44 -0
- package/dist/metadata/model_configuration.js.map +1 -0
- package/dist/metadata/optional_native_modules.d.ts +79 -3
- package/dist/metadata/optional_native_modules.d.ts.map +1 -1
- package/dist/metadata/optional_native_modules.js +108 -3
- package/dist/metadata/optional_native_modules.js.map +1 -1
- package/dist/metadata/use_smile_id_metadata.d.ts +45 -7
- package/dist/metadata/use_smile_id_metadata.d.ts.map +1 -1
- package/dist/metadata/use_smile_id_metadata.js +85 -13
- package/dist/metadata/use_smile_id_metadata.js.map +1 -1
- package/dist/metadata/use_smile_id_metadata_factory.d.ts +37 -0
- package/dist/metadata/use_smile_id_metadata_factory.d.ts.map +1 -1
- package/dist/metadata/use_smile_id_metadata_factory.js +197 -16
- package/dist/metadata/use_smile_id_metadata_factory.js.map +1 -1
- package/dist/presentation/assets/svg/document_shimmer_strings.d.ts +14 -0
- package/dist/presentation/assets/svg/document_shimmer_strings.d.ts.map +1 -0
- package/dist/presentation/assets/svg/document_shimmer_strings.js +14 -0
- package/dist/presentation/assets/svg/document_shimmer_strings.js.map +1 -0
- package/dist/presentation/assets/svg/instruction_svg_strings.d.ts +12 -4
- package/dist/presentation/assets/svg/instruction_svg_strings.d.ts.map +1 -1
- package/dist/presentation/assets/svg/instruction_svg_strings.js +19 -8
- package/dist/presentation/assets/svg/instruction_svg_strings.js.map +1 -1
- package/dist/presentation/components/helpers/enhanced_smart_selfie_animation_frames.d.ts +0 -5
- package/dist/presentation/components/helpers/enhanced_smart_selfie_animation_frames.d.ts.map +1 -1
- package/dist/presentation/components/helpers/enhanced_smart_selfie_animation_frames.js +0 -5
- package/dist/presentation/components/helpers/enhanced_smart_selfie_animation_frames.js.map +1 -1
- package/dist/presentation/components/icons/index.d.ts +24 -8
- package/dist/presentation/components/icons/index.d.ts.map +1 -1
- package/dist/presentation/components/icons/index.js +31 -11
- package/dist/presentation/components/icons/index.js.map +1 -1
- package/dist/presentation/components/use_smile_id_attribution.d.ts +1 -1
- package/dist/presentation/components/use_smile_id_button.d.ts +2 -2
- package/dist/presentation/components/use_smile_id_button.js +4 -4
- package/dist/presentation/components/use_smile_id_button.js.map +1 -1
- package/dist/presentation/components/use_smile_id_capture_content.d.ts +13 -0
- package/dist/presentation/components/use_smile_id_capture_content.d.ts.map +1 -1
- package/dist/presentation/components/use_smile_id_capture_content.js +15 -9
- package/dist/presentation/components/use_smile_id_capture_content.js.map +1 -1
- package/dist/presentation/components/use_smile_id_captured_document_image.d.ts +2 -3
- package/dist/presentation/components/use_smile_id_captured_document_image.d.ts.map +1 -1
- package/dist/presentation/components/use_smile_id_captured_document_image.js +1 -3
- package/dist/presentation/components/use_smile_id_captured_document_image.js.map +1 -1
- package/dist/presentation/components/use_smile_id_document_capture_controls.d.ts +12 -6
- package/dist/presentation/components/use_smile_id_document_capture_controls.d.ts.map +1 -1
- package/dist/presentation/components/use_smile_id_document_capture_controls.js +59 -16
- package/dist/presentation/components/use_smile_id_document_capture_controls.js.map +1 -1
- package/dist/presentation/components/use_smile_id_document_overlay.d.ts +22 -5
- package/dist/presentation/components/use_smile_id_document_overlay.d.ts.map +1 -1
- package/dist/presentation/components/use_smile_id_document_overlay.js +80 -40
- package/dist/presentation/components/use_smile_id_document_overlay.js.map +1 -1
- package/dist/presentation/components/use_smile_id_document_shimmer.d.ts +15 -0
- package/dist/presentation/components/use_smile_id_document_shimmer.d.ts.map +1 -0
- package/dist/presentation/components/use_smile_id_document_shimmer.js +23 -0
- package/dist/presentation/components/use_smile_id_document_shimmer.js.map +1 -0
- 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 +9 -6
- package/dist/presentation/components/use_smile_id_enhanced_smart_selfie_clip.js.map +1 -1
- package/dist/presentation/components/use_smile_id_guideline_thumbnail.d.ts.map +1 -1
- package/dist/presentation/components/use_smile_id_guideline_thumbnail.js +84 -1
- package/dist/presentation/components/use_smile_id_guideline_thumbnail.js.map +1 -1
- package/dist/presentation/components/use_smile_id_instructions_hero.d.ts +3 -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 +25 -5
- package/dist/presentation/components/use_smile_id_instructions_hero.js.map +1 -1
- package/dist/presentation/components/use_smile_id_oval_border_palette.d.ts.map +1 -1
- package/dist/presentation/components/use_smile_id_oval_border_palette.js +7 -3
- package/dist/presentation/components/use_smile_id_oval_border_palette.js.map +1 -1
- package/dist/presentation/flow/dsl/builder/config_builder.d.ts +28 -0
- package/dist/presentation/flow/dsl/builder/config_builder.d.ts.map +1 -1
- package/dist/presentation/flow/dsl/builder/config_builder.js +30 -0
- package/dist/presentation/flow/dsl/builder/config_builder.js.map +1 -1
- package/dist/presentation/flow/dsl/builder/ml_builder.d.ts +13 -4
- package/dist/presentation/flow/dsl/builder/ml_builder.d.ts.map +1 -1
- package/dist/presentation/flow/dsl/builder/ml_builder.js +3 -2
- package/dist/presentation/flow/dsl/builder/ml_builder.js.map +1 -1
- package/dist/presentation/flow/dsl/builder/screens_builder.d.ts +110 -12
- package/dist/presentation/flow/dsl/builder/screens_builder.d.ts.map +1 -1
- package/dist/presentation/flow/dsl/builder/screens_builder.js +110 -12
- package/dist/presentation/flow/dsl/builder/screens_builder.js.map +1 -1
- package/dist/presentation/flow/dsl/builder/theme_builder.d.ts +15 -2
- package/dist/presentation/flow/dsl/builder/theme_builder.d.ts.map +1 -1
- package/dist/presentation/flow/dsl/builder/theme_builder.js +15 -2
- package/dist/presentation/flow/dsl/builder/theme_builder.js.map +1 -1
- package/dist/presentation/flow/dsl/use_smile_id_builder.d.ts +6 -4
- package/dist/presentation/flow/dsl/use_smile_id_builder.d.ts.map +1 -1
- package/dist/presentation/flow/dsl/use_smile_id_builder.js.map +1 -1
- package/dist/presentation/flow/dsl/use_smile_id_flow_builder.d.ts +62 -36
- 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 +62 -36
- package/dist/presentation/flow/dsl/use_smile_id_flow_builder.js.map +1 -1
- package/dist/presentation/flow/flow_navigation_manager.d.ts +44 -5
- package/dist/presentation/flow/flow_navigation_manager.d.ts.map +1 -1
- package/dist/presentation/flow/flow_navigation_manager.js +148 -11
- package/dist/presentation/flow/flow_navigation_manager.js.map +1 -1
- package/dist/presentation/flow/model/instruction_guideline.d.ts +9 -0
- package/dist/presentation/flow/model/instruction_guideline.d.ts.map +1 -1
- package/dist/presentation/flow/model/instructions_defaults.d.ts +11 -2
- package/dist/presentation/flow/model/instructions_defaults.d.ts.map +1 -1
- package/dist/presentation/flow/model/instructions_defaults.js +74 -26
- 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 +48 -14
- 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_instructions_screen.js +1 -1
- package/dist/presentation/flow/screen/orchestrated_instructions_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 +3 -9
- package/dist/presentation/flow/screen/orchestrated_preview_screen.js.map +1 -1
- package/dist/presentation/flow/screen/orchestrated_processing_screen.js +3 -3
- 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 +10 -4
- package/dist/presentation/flow/use_smile_id_flow.js.map +1 -1
- package/dist/presentation/flow/validation/flow_validator.d.ts.map +1 -1
- package/dist/presentation/flow/validation/flow_validator.js +42 -20
- package/dist/presentation/flow/validation/flow_validator.js.map +1 -1
- package/dist/presentation/flow/validation/job_type_validator.d.ts.map +1 -1
- package/dist/presentation/flow/validation/job_type_validator.js +14 -0
- package/dist/presentation/flow/validation/job_type_validator.js.map +1 -1
- 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/instructions_screen_helpers.d.ts +1 -0
- package/dist/presentation/screen/helpers/instructions_screen_helpers.d.ts.map +1 -1
- package/dist/presentation/screen/helpers/instructions_screen_helpers.js +6 -2
- package/dist/presentation/screen/helpers/instructions_screen_helpers.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 +14 -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 +21 -3
- package/dist/presentation/screen/use_smile_id_capture_screen.d.ts.map +1 -1
- package/dist/presentation/screen/use_smile_id_capture_screen.js +188 -32
- 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.d.ts +2 -3
- package/dist/presentation/screen/use_smile_id_document_preview_screen.d.ts.map +1 -1
- package/dist/presentation/screen/use_smile_id_document_preview_screen.js +17 -12
- package/dist/presentation/screen/use_smile_id_document_preview_screen.js.map +1 -1
- package/dist/presentation/screen/use_smile_id_instructions_screen.d.ts +2 -0
- package/dist/presentation/screen/use_smile_id_instructions_screen.d.ts.map +1 -1
- package/dist/presentation/screen/use_smile_id_instructions_screen.js +2 -1
- package/dist/presentation/screen/use_smile_id_instructions_screen.js.map +1 -1
- package/dist/presentation/screen/use_smile_id_preview_screen.d.ts +7 -26
- package/dist/presentation/screen/use_smile_id_preview_screen.d.ts.map +1 -1
- package/dist/presentation/screen/use_smile_id_preview_screen.js +10 -20
- package/dist/presentation/screen/use_smile_id_preview_screen.js.map +1 -1
- package/dist/presentation/screen/use_smile_id_processing_screen.d.ts +2 -3
- package/dist/presentation/screen/use_smile_id_processing_screen.d.ts.map +1 -1
- package/dist/presentation/screen/use_smile_id_processing_screen.js +4 -3
- package/dist/presentation/screen/use_smile_id_processing_screen.js.map +1 -1
- package/dist/presentation/theme/theme.d.ts +1 -1
- package/dist/presentation/theme/theme.d.ts.map +1 -1
- package/dist/presentation/theme/theme.js +20 -18
- package/dist/presentation/theme/theme.js.map +1 -1
- package/dist/presentation/utils/force_max_brightness.d.ts +4 -4
- 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 +34 -7
- package/src/__tests__/dsl.test.ts +51 -1
- package/src/__tests__/react_native_mock.tsx +8 -0
- package/src/__tests__/setup_react_native.ts +17 -2
- package/src/__tests__/snapshots/__snapshots__/screens_structural.test.tsx.snap +5261 -0
- package/src/__tests__/snapshots/screens_structural.test.tsx +230 -0
- package/src/camera/__tests__/use_smile_id_camera_system.test.ts +103 -0
- package/src/camera/camera_defaults.ts +11 -9
- package/src/camera/orientation_degrees.ts +5 -6
- package/src/core/exception/__tests__/builder_validation_exceptions.test.ts +67 -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/index.ts +1 -0
- package/src/core/exception/use_smile_id_error_code.ts +1 -0
- package/src/core/models/__tests__/document_type.test.ts +7 -5
- package/src/core/models/__tests__/flow_models.test.ts +26 -0
- package/src/core/models/config.ts +22 -0
- package/src/core/models/document_capture_mode.ts +27 -0
- package/src/core/models/document_type.ts +7 -5
- package/src/core/models/global_privacy_control.ts +45 -0
- package/src/core/models/network_config.ts +2 -2
- package/src/core/models/result.ts +9 -8
- package/src/data/api/__tests__/smile_id_api.test.ts +1 -1
- package/src/data/api/interceptors/__tests__/gzip_interceptor.test.ts +83 -0
- package/src/data/api/interceptors/__tests__/smile_integrity_interceptor.test.ts +37 -1
- package/src/data/api/interceptors/__tests__/smile_request_mac_interceptor.test.ts +59 -1
- package/src/data/api/interceptors/smile_auth_interceptor.ts +3 -18
- package/src/data/api/interceptors/smile_integrity_interceptor.ts +20 -0
- package/src/data/api/interceptors/smile_request_mac_interceptor.ts +13 -0
- package/src/data/compression/__tests__/payload_compressor.test.ts +200 -0
- package/src/data/compression/__tests__/payload_compressor_real_jpeg.test.ts +226 -0
- package/src/data/compression/compressible_asset.ts +62 -0
- package/src/data/compression/payload_compression_config.ts +53 -0
- package/src/data/compression/payload_compression_runner.ts +102 -0
- package/src/data/compression/payload_compressor.ts +164 -0
- package/src/data/compression/uri_compressible_asset.ts +85 -0
- package/src/data/dsl/builder/__tests__/config_builders.test.ts +62 -0
- package/src/data/dsl/builder/cache_config_builder.ts +3 -1
- package/src/data/dsl/builder/config_builder.ts +45 -14
- package/src/data/dsl/builder/interceptor_config_builder.ts +9 -7
- package/src/data/dsl/builder/retry_config_builder.ts +27 -6
- package/src/data/dsl/builder/timeout_config_builder.ts +7 -0
- package/src/data/dsl/use_smile_id_network_builder.ts +17 -0
- 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/factory/networking_factory.ts +14 -1
- package/src/data/repository/__tests__/network_retries.test.ts +117 -0
- package/src/data/repository/__tests__/use_smile_id_repository.test.ts +1 -1
- package/src/data/repository/use_smile_id_repository_impl.ts +96 -9
- package/src/data/security/__tests__/request_canonicalizer.test.ts +132 -0
- package/src/data/security/__tests__/security_policy.test.ts +96 -0
- package/src/data/security/__tests__/smile_id_crypto_manager.test.ts +18 -0
- package/src/data/security/request_canonicalizer.ts +15 -2
- package/src/data/security/security_policy.ts +70 -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 +57 -1
- package/src/data/util/retry_util.ts +12 -3
- package/src/data/util/use_smile_id_token_decoder.ts +76 -28
- package/src/index.ts +6 -4
- package/src/l10n/strings_en.ts +2 -1
- package/src/l10n/use_smile_id_localizations.ts +3 -0
- package/src/metadata/__tests__/device_orientation_collector.test.ts +15 -0
- package/src/metadata/__tests__/metadata_configuration_mappers.test.ts +254 -0
- package/src/metadata/__tests__/metadata_configuration_objects.test.ts +86 -0
- package/src/metadata/__tests__/metadata_device_context.test.ts +147 -0
- package/src/metadata/__tests__/metadata_device_os_android.test.ts +18 -0
- package/src/metadata/__tests__/metadata_golden_fixture.json +13 -0
- package/src/metadata/__tests__/metadata_payload_golden.test.ts +193 -0
- package/src/metadata/__tests__/use_smile_id_metadata.test.ts +19 -25
- package/src/metadata/builder_configuration.ts +69 -0
- package/src/metadata/captured_image_properties.ts +10 -0
- package/src/metadata/device_orientation_collector.ts +75 -0
- package/src/metadata/geolocation.ts +46 -0
- package/src/metadata/metadata_configuration_mappers.ts +248 -0
- package/src/metadata/model_configuration.ts +68 -0
- package/src/metadata/optional_native_modules.ts +157 -3
- package/src/metadata/use_smile_id_metadata.ts +140 -17
- package/src/metadata/use_smile_id_metadata_factory.ts +211 -16
- 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 -5575
- 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/assets/svg/document_shimmer_strings.ts +17 -0
- package/src/presentation/assets/svg/instruction_svg_strings.ts +34 -12
- package/src/presentation/components/__tests__/enhanced_smart_selfie_animation_frames.test.ts +1 -3
- package/src/presentation/components/__tests__/use_smile_id_enhanced_smart_selfie_clip.test.tsx +12 -8
- package/src/presentation/components/__tests__/use_smile_id_guideline_thumbnail.test.tsx +34 -1
- package/src/presentation/components/__tests__/use_smile_id_instructions_hero.test.tsx +71 -0
- package/src/presentation/components/__tests__/use_smile_id_oval_border_palette.test.ts +7 -5
- package/src/presentation/components/helpers/enhanced_smart_selfie_animation_frames.ts +0 -6
- package/src/presentation/components/icons/index.tsx +65 -18
- package/src/presentation/components/use_smile_id_attribution.tsx +1 -1
- package/src/presentation/components/use_smile_id_button.tsx +4 -4
- package/src/presentation/components/use_smile_id_capture_content.tsx +36 -12
- package/src/presentation/components/use_smile_id_captured_document_image.tsx +3 -8
- package/src/presentation/components/use_smile_id_document_capture_controls.tsx +103 -39
- package/src/presentation/components/use_smile_id_document_overlay.tsx +134 -44
- package/src/presentation/components/use_smile_id_document_shimmer.tsx +51 -0
- package/src/presentation/components/use_smile_id_enhanced_smart_selfie_clip.tsx +9 -6
- package/src/presentation/components/use_smile_id_guideline_thumbnail.tsx +131 -2
- package/src/presentation/components/use_smile_id_instructions_hero.tsx +111 -60
- package/src/presentation/components/use_smile_id_oval_border_palette.ts +7 -3
- package/src/presentation/flow/__tests__/document_flow_navigation.test.ts +203 -4
- package/src/presentation/flow/__tests__/flow_navigation_manager.test.ts +49 -0
- package/src/presentation/flow/dsl/builder/__tests__/config_builder.test.ts +25 -0
- package/src/presentation/flow/dsl/builder/config_builder.ts +35 -0
- package/src/presentation/flow/dsl/builder/ml_builder.ts +13 -4
- package/src/presentation/flow/dsl/builder/screens_builder.ts +110 -12
- package/src/presentation/flow/dsl/builder/theme_builder.ts +19 -2
- package/src/presentation/flow/dsl/use_smile_id_builder.tsx +6 -4
- package/src/presentation/flow/dsl/use_smile_id_flow_builder.ts +62 -36
- package/src/presentation/flow/flow_navigation_manager.ts +185 -14
- package/src/presentation/flow/model/instruction_guideline.ts +6 -0
- package/src/presentation/flow/model/instructions_defaults.ts +104 -26
- package/src/presentation/flow/screen/orchestrated_capture_screen.tsx +60 -12
- package/src/presentation/flow/screen/orchestrated_consent_screen.tsx +5 -0
- package/src/presentation/flow/screen/orchestrated_instructions_screen.tsx +1 -0
- package/src/presentation/flow/screen/orchestrated_preview_screen.tsx +4 -14
- package/src/presentation/flow/screen/orchestrated_processing_screen.tsx +3 -3
- package/src/presentation/flow/use_smile_id_flow.tsx +11 -4
- package/src/presentation/flow/validation/__tests__/flow_validator.test.ts +61 -1
- package/src/presentation/flow/validation/__tests__/job_type_validator.test.ts +64 -0
- package/src/presentation/flow/validation/flow_validator.ts +55 -26
- package/src/presentation/flow/validation/job_type_validator.ts +24 -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__/instructions_screen_helpers.test.ts +15 -3
- 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 +182 -18
- package/src/presentation/screen/__tests__/use_smile_id_document_back_instructions.test.tsx +1 -1
- 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/instructions_screen_helpers.ts +7 -2
- package/src/presentation/screen/helpers/scan_state_to_overlay_state.ts +16 -13
- package/src/presentation/screen/helpers/use_capture_orientation_lock.ts +69 -7
- package/src/presentation/screen/use_smile_id_capture_screen.tsx +280 -54
- 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 +33 -23
- package/src/presentation/screen/use_smile_id_instructions_screen.tsx +4 -0
- package/src/presentation/screen/use_smile_id_preview_screen.tsx +21 -53
- package/src/presentation/screen/use_smile_id_processing_screen.tsx +8 -8
- package/src/presentation/theme/theme.ts +21 -19
- package/src/presentation/utils/__tests__/locale_utils.test.ts +46 -5
- package/src/presentation/utils/force_max_brightness.tsx +4 -4
- 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/camera/frame_processor_plugin.d.ts +0 -28
- package/dist/camera/frame_processor_plugin.d.ts.map +0 -1
- package/dist/camera/frame_processor_plugin.js +0 -21
- package/dist/camera/frame_processor_plugin.js.map +0 -1
- package/dist/camera/use_smile_id_frame_processor.d.ts +0 -38
- package/dist/camera/use_smile_id_frame_processor.d.ts.map +0 -1
- package/dist/camera/use_smile_id_frame_processor.js +0 -2
- package/dist/camera/use_smile_id_frame_processor.js.map +0 -1
- package/dist/presentation/components/use_smile_id_document_frame_glyph.d.ts +0 -17
- package/dist/presentation/components/use_smile_id_document_frame_glyph.d.ts.map +0 -1
- package/dist/presentation/components/use_smile_id_document_frame_glyph.js +0 -17
- package/dist/presentation/components/use_smile_id_document_frame_glyph.js.map +0 -1
- package/dist/presentation/components/use_smile_id_enhanced_smart_selfie_animation.d.ts +0 -24
- package/dist/presentation/components/use_smile_id_enhanced_smart_selfie_animation.d.ts.map +0 -1
- package/dist/presentation/components/use_smile_id_enhanced_smart_selfie_animation.js +0 -91
- package/dist/presentation/components/use_smile_id_enhanced_smart_selfie_animation.js.map +0 -1
- 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/dist/presentation/components/use_smile_id_instruction_card.d.ts +0 -31
- package/dist/presentation/components/use_smile_id_instruction_card.d.ts.map +0 -1
- package/dist/presentation/components/use_smile_id_instruction_card.js +0 -43
- package/dist/presentation/components/use_smile_id_instruction_card.js.map +0 -1
- package/dist/presentation/screen/helpers/use_document_orientation_lock.d.ts +0 -24
- package/dist/presentation/screen/helpers/use_document_orientation_lock.d.ts.map +0 -1
- package/dist/presentation/screen/helpers/use_document_orientation_lock.js +0 -47
- package/dist/presentation/screen/helpers/use_document_orientation_lock.js.map +0 -1
- package/src/presentation/components/use_smile_id_document_frame_glyph.tsx +0 -162
- package/src/presentation/components/use_smile_id_face_silhouette_overlay.tsx +0 -27
|
@@ -12,6 +12,29 @@ import {
|
|
|
12
12
|
mapAxiosError,
|
|
13
13
|
type UseSmileIDNetworkException,
|
|
14
14
|
} from "../../core/exception/use_smile_id_network_exception";
|
|
15
|
+
import {
|
|
16
|
+
PayloadCompressionRunner,
|
|
17
|
+
type PayloadCompressionSizes,
|
|
18
|
+
} from "../compression/payload_compression_runner";
|
|
19
|
+
import type { MetadataEntry } from "../../metadata/use_smile_id_metadata";
|
|
20
|
+
|
|
21
|
+
/** Builds the per-image original/final compressed size wire entries, omitting absent/zero sizes. */
|
|
22
|
+
function compressionSizeEntries(
|
|
23
|
+
sizes: PayloadCompressionSizes,
|
|
24
|
+
): MetadataEntry[] {
|
|
25
|
+
const entries: MetadataEntry[] = [];
|
|
26
|
+
const push = (name: string, value: number | undefined) => {
|
|
27
|
+
if (value !== undefined && value > 0)
|
|
28
|
+
entries.push({ name, value: String(value) });
|
|
29
|
+
};
|
|
30
|
+
push("selfie_original_size", sizes.selfieOriginalMb);
|
|
31
|
+
push("selfie_final_compressed_size", sizes.selfieFinalMb);
|
|
32
|
+
push("document_front_original_size", sizes.frontOriginalMb);
|
|
33
|
+
push("document_front_final_compressed_size", sizes.frontFinalMb);
|
|
34
|
+
push("document_back_original_size", sizes.backOriginalMb);
|
|
35
|
+
push("document_back_final_compressed_size", sizes.backFinalMb);
|
|
36
|
+
return entries;
|
|
37
|
+
}
|
|
15
38
|
|
|
16
39
|
/**
|
|
17
40
|
* Concrete repository.
|
|
@@ -45,9 +68,28 @@ export class UseSmileIDRepositoryImpl {
|
|
|
45
68
|
}),
|
|
46
69
|
);
|
|
47
70
|
}
|
|
71
|
+
|
|
72
|
+
// Pre-flight payload compression — best effort: shrink the captured JPEGs under the Lambda
|
|
73
|
+
// cap before transmission (runs once, outside the retry loop), but never block submission, so
|
|
74
|
+
// any compression failure ships the captured images as-is and lets the server validate. The
|
|
75
|
+
// per-image original + final compressed sizes are stamped onto the metadata for telemetry.
|
|
76
|
+
let submitted = request;
|
|
48
77
|
try {
|
|
49
|
-
const
|
|
50
|
-
|
|
78
|
+
const sizes = await this._compressPayload(request);
|
|
79
|
+
const sizeEntries = sizes ? compressionSizeEntries(sizes) : [];
|
|
80
|
+
if (sizeEntries.length > 0) {
|
|
81
|
+
submitted = {
|
|
82
|
+
...request,
|
|
83
|
+
metadata: request.metadata.withAdditionalEntries(sizeEntries),
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
} catch {
|
|
87
|
+
// Best-effort: compression is an optimization; submit the captured images as-is on failure.
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
try {
|
|
91
|
+
const response = await withRetry(this._retry, (attempt) =>
|
|
92
|
+
this._dispatch(submitted, attempt),
|
|
51
93
|
);
|
|
52
94
|
return success(response);
|
|
53
95
|
} catch (error) {
|
|
@@ -62,22 +104,67 @@ export class UseSmileIDRepositoryImpl {
|
|
|
62
104
|
}
|
|
63
105
|
}
|
|
64
106
|
|
|
107
|
+
/**
|
|
108
|
+
* Pre-flight payload compression entry — extracts the captured image URIs for the job type and
|
|
109
|
+
* compresses the bundle under the transmission cap (metadata is measured, never modified).
|
|
110
|
+
* No-op for job types that carry no captured images (Enhanced KYC / BVN).
|
|
111
|
+
*/
|
|
112
|
+
private async _compressPayload(
|
|
113
|
+
request: JobRequest,
|
|
114
|
+
): Promise<PayloadCompressionSizes | undefined> {
|
|
115
|
+
const metadataBytes = JSON.stringify(request.metadata.toEntries()).length;
|
|
116
|
+
switch (request.jobType) {
|
|
117
|
+
case JobType.smartSelfieEnrollment:
|
|
118
|
+
case JobType.smartSelfieAuthentication:
|
|
119
|
+
case JobType.biometricKyc:
|
|
120
|
+
return PayloadCompressionRunner.compress({
|
|
121
|
+
selfieImage: request.selfieImage,
|
|
122
|
+
livenessImages: request.livenessImages,
|
|
123
|
+
metadataBytes,
|
|
124
|
+
});
|
|
125
|
+
case JobType.documentVerification:
|
|
126
|
+
case JobType.enhancedDocumentVerification:
|
|
127
|
+
return PayloadCompressionRunner.compress({
|
|
128
|
+
selfieImage: request.selfieImage,
|
|
129
|
+
livenessImages: request.livenessImages,
|
|
130
|
+
frontDocument: request.frontDocument,
|
|
131
|
+
backDocument: request.backDocument,
|
|
132
|
+
metadataBytes,
|
|
133
|
+
});
|
|
134
|
+
default:
|
|
135
|
+
return undefined;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
65
139
|
private _dispatch(
|
|
66
140
|
request: Exclude<JobRequest, { jobType: typeof JobType.bvn }>,
|
|
141
|
+
attempt: number,
|
|
67
142
|
): Promise<JobSubmissionResponse> {
|
|
68
|
-
|
|
143
|
+
// Stamp how many network retries preceded this attempt onto the metadata
|
|
144
|
+
// (re-evaluated per attempt inside the retry loop). Appended as a flow-state
|
|
145
|
+
// entry so the already-appended document / config entries are preserved.
|
|
146
|
+
const stamped: typeof request =
|
|
147
|
+
attempt > 0
|
|
148
|
+
? {
|
|
149
|
+
...request,
|
|
150
|
+
metadata: request.metadata.withAdditionalEntries([
|
|
151
|
+
{ name: "network_retries", value: String(attempt) },
|
|
152
|
+
]),
|
|
153
|
+
}
|
|
154
|
+
: request;
|
|
155
|
+
switch (stamped.jobType) {
|
|
69
156
|
case JobType.smartSelfieEnrollment:
|
|
70
|
-
return this._api.smartSelfieEnrollment(
|
|
157
|
+
return this._api.smartSelfieEnrollment(stamped);
|
|
71
158
|
case JobType.smartSelfieAuthentication:
|
|
72
|
-
return this._api.smartSelfieAuthentication(
|
|
159
|
+
return this._api.smartSelfieAuthentication(stamped);
|
|
73
160
|
case JobType.enhancedKyc:
|
|
74
|
-
return this._api.enhancedKyc(
|
|
161
|
+
return this._api.enhancedKyc(stamped);
|
|
75
162
|
case JobType.biometricKyc:
|
|
76
|
-
return this._api.biometricKyc(
|
|
163
|
+
return this._api.biometricKyc(stamped);
|
|
77
164
|
case JobType.documentVerification:
|
|
78
|
-
return this._api.documentVerification(
|
|
165
|
+
return this._api.documentVerification(stamped);
|
|
79
166
|
case JobType.enhancedDocumentVerification:
|
|
80
|
-
return this._api.enhancedDocumentVerification(
|
|
167
|
+
return this._api.enhancedDocumentVerification(stamped);
|
|
81
168
|
}
|
|
82
169
|
}
|
|
83
170
|
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
|
|
3
|
+
import { RequestCanonicalizer } from "../request_canonicalizer";
|
|
4
|
+
import { SmileIDCryptoManager } from "../smile_id_crypto_manager";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Golden-vector suite for `RequestCanonicalizer`: pins the exact canonical bytes and the resulting
|
|
8
|
+
* `smileid-request-mac` for a fixed key across the shapes `canonicalize()` distinguishes. This
|
|
9
|
+
* SDK's own contract with the server, not a cross-SDK guarantee.
|
|
10
|
+
*/
|
|
11
|
+
const TIMESTAMP = "1700000000000";
|
|
12
|
+
const SIGNING_SECRET = "golden-vector-secret";
|
|
13
|
+
const cryptoManager = new SmileIDCryptoManager(SIGNING_SECRET);
|
|
14
|
+
|
|
15
|
+
const BASE_HEADERS = {
|
|
16
|
+
"smileid-token": "golden-token",
|
|
17
|
+
"smileid-request-timestamp": TIMESTAMP,
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
type FormDataPart = { fieldName: string; string?: string; uri?: string };
|
|
21
|
+
|
|
22
|
+
/** Minimal stand-in for React Native's `FormData` (only `getParts` is read). */
|
|
23
|
+
function formData(parts: readonly FormDataPart[]) {
|
|
24
|
+
return { getParts: () => parts };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function decode(bytes: Uint8Array): string {
|
|
28
|
+
return Buffer.from(bytes).toString("utf-8");
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const MULTIPART_BODY = formData([
|
|
32
|
+
{ fieldName: "country", string: "NG" },
|
|
33
|
+
{ fieldName: "allow_new_enroll", string: "true" },
|
|
34
|
+
{ fieldName: "partner_params", string: '{"job_id":"j1"}' },
|
|
35
|
+
{
|
|
36
|
+
fieldName: "selfie_image",
|
|
37
|
+
uri: "data:application/octet-stream;base64,c2VsZmll",
|
|
38
|
+
},
|
|
39
|
+
]);
|
|
40
|
+
|
|
41
|
+
// Same logical fields as MULTIPART_BODY, in reverse part order.
|
|
42
|
+
const MULTIPART_BODY_REORDERED = formData([
|
|
43
|
+
{
|
|
44
|
+
fieldName: "selfie_image",
|
|
45
|
+
uri: "data:application/octet-stream;base64,c2VsZmll",
|
|
46
|
+
},
|
|
47
|
+
{ fieldName: "partner_params", string: '{"job_id":"j1"}' },
|
|
48
|
+
{ fieldName: "allow_new_enroll", string: "true" },
|
|
49
|
+
{ fieldName: "country", string: "NG" },
|
|
50
|
+
]);
|
|
51
|
+
|
|
52
|
+
const MIXED_CASE_HEADERS = {
|
|
53
|
+
"Smileid-Token": "golden-token",
|
|
54
|
+
"SMILEID-REQUEST-TIMESTAMP": TIMESTAMP,
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
describe("RequestCanonicalizer golden vectors", () => {
|
|
58
|
+
it("(a) canonicalizes a bodyless request to the signed headers + `{}`", async () => {
|
|
59
|
+
const bytes = await RequestCanonicalizer.canonicalize(
|
|
60
|
+
BASE_HEADERS,
|
|
61
|
+
undefined,
|
|
62
|
+
);
|
|
63
|
+
expect(decode(bytes)).toBe(
|
|
64
|
+
'{"smileid-request-timestamp":"1700000000000","smileid-token":"golden-token"}{}',
|
|
65
|
+
);
|
|
66
|
+
expect(await cryptoManager.sign(TIMESTAMP, BASE_HEADERS, undefined)).toBe(
|
|
67
|
+
"qikeRL0jNa7bZKUZdoN7tY30VvVy4ol/hcMdyg4PU4w=",
|
|
68
|
+
);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it("(b) canonicalizes a raw JSON-string body the same as a bodyless request — only FormData-shaped bodies are reconstructed", async () => {
|
|
72
|
+
const bytes = await RequestCanonicalizer.canonicalize(
|
|
73
|
+
BASE_HEADERS,
|
|
74
|
+
'{"hello":"world"}',
|
|
75
|
+
);
|
|
76
|
+
// Same canonical bytes as case (a): a JSON string isn't FormData-like,
|
|
77
|
+
// so canonicalBody() falls through to the same `{}` as no body at all.
|
|
78
|
+
expect(decode(bytes)).toBe(
|
|
79
|
+
'{"smileid-request-timestamp":"1700000000000","smileid-token":"golden-token"}{}',
|
|
80
|
+
);
|
|
81
|
+
expect(
|
|
82
|
+
await cryptoManager.sign(TIMESTAMP, BASE_HEADERS, '{"hello":"world"}'),
|
|
83
|
+
).toBe("qikeRL0jNa7bZKUZdoN7tY30VvVy4ol/hcMdyg4PU4w=");
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it("(c) canonicalizes a multipart FormData body: scalar, boolean-coerced, JSON, and file parts", async () => {
|
|
87
|
+
const bytes = await RequestCanonicalizer.canonicalize(
|
|
88
|
+
BASE_HEADERS,
|
|
89
|
+
MULTIPART_BODY,
|
|
90
|
+
);
|
|
91
|
+
expect(decode(bytes)).toBe(
|
|
92
|
+
'{"smileid-request-timestamp":"1700000000000","smileid-token":"golden-token"}' +
|
|
93
|
+
'{"allow_new_enroll":true,"country":"NG","partner_params":{"job_id":"j1"},"selfie_image":"c2VsZmll"}',
|
|
94
|
+
);
|
|
95
|
+
expect(
|
|
96
|
+
await cryptoManager.sign(TIMESTAMP, BASE_HEADERS, MULTIPART_BODY),
|
|
97
|
+
).toBe("eNJqKR45aNiou4JM0yVRNYrTdhfg1VblWvsbrRndoLQ=");
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it("(d) part ordering does not change the canonical bytes or the MAC", async () => {
|
|
101
|
+
const bytes = await RequestCanonicalizer.canonicalize(
|
|
102
|
+
BASE_HEADERS,
|
|
103
|
+
MULTIPART_BODY_REORDERED,
|
|
104
|
+
);
|
|
105
|
+
expect(decode(bytes)).toBe(
|
|
106
|
+
'{"smileid-request-timestamp":"1700000000000","smileid-token":"golden-token"}' +
|
|
107
|
+
'{"allow_new_enroll":true,"country":"NG","partner_params":{"job_id":"j1"},"selfie_image":"c2VsZmll"}',
|
|
108
|
+
);
|
|
109
|
+
expect(
|
|
110
|
+
await cryptoManager.sign(
|
|
111
|
+
TIMESTAMP,
|
|
112
|
+
BASE_HEADERS,
|
|
113
|
+
MULTIPART_BODY_REORDERED,
|
|
114
|
+
),
|
|
115
|
+
).toBe("eNJqKR45aNiou4JM0yVRNYrTdhfg1VblWvsbrRndoLQ=");
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it("(e) header key casing does not change the canonical bytes or the MAC", async () => {
|
|
119
|
+
const bytes = await RequestCanonicalizer.canonicalize(
|
|
120
|
+
MIXED_CASE_HEADERS,
|
|
121
|
+
undefined,
|
|
122
|
+
);
|
|
123
|
+
// Identical to case (a): canonicalHeaders() lower-cases every header
|
|
124
|
+
// name before signing, so casing at the call site is not observable.
|
|
125
|
+
expect(decode(bytes)).toBe(
|
|
126
|
+
'{"smileid-request-timestamp":"1700000000000","smileid-token":"golden-token"}{}',
|
|
127
|
+
);
|
|
128
|
+
expect(
|
|
129
|
+
await cryptoManager.sign(TIMESTAMP, MIXED_CASE_HEADERS, undefined),
|
|
130
|
+
).toBe("qikeRL0jNa7bZKUZdoN7tY30VvVy4ol/hcMdyg4PU4w=");
|
|
131
|
+
});
|
|
132
|
+
});
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
|
|
3
|
+
import { SecurityPolicy } from "../security_policy";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Pins down the server-driven security policy bit-code mapping (the contract lives in
|
|
7
|
+
* `docs/Policy.md`):
|
|
8
|
+
* - `undefined` is fail-secure (every behaviour active).
|
|
9
|
+
* - bit 0 -> payload signing, bit 1 -> payload encryption, bit 2 -> rooted-device check,
|
|
10
|
+
* bit 3 -> device attestation (least-significant bit first).
|
|
11
|
+
* - Unrelated bits never cross-activate a behaviour.
|
|
12
|
+
*/
|
|
13
|
+
describe("SecurityPolicy", () => {
|
|
14
|
+
it("undefined bit-code is fail-secure and enables every behaviour", () => {
|
|
15
|
+
const policy = SecurityPolicy.fromBitCode(undefined);
|
|
16
|
+
|
|
17
|
+
expect(policy.isPayloadSigningActive()).toBe(true);
|
|
18
|
+
expect(policy.isPayloadEncryptionActive()).toBe(true);
|
|
19
|
+
expect(policy.isRootedDeviceCheckActive()).toBe(true);
|
|
20
|
+
expect(policy.isPlayIntegrityCheckActive()).toBe(true);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("zero bit-code disables every behaviour", () => {
|
|
24
|
+
const policy = SecurityPolicy.fromBitCode(0);
|
|
25
|
+
|
|
26
|
+
expect(policy.isPayloadSigningActive()).toBe(false);
|
|
27
|
+
expect(policy.isPayloadEncryptionActive()).toBe(false);
|
|
28
|
+
expect(policy.isRootedDeviceCheckActive()).toBe(false);
|
|
29
|
+
expect(policy.isPlayIntegrityCheckActive()).toBe(false);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it("bit 0 maps to payload signing only", () => {
|
|
33
|
+
const policy = SecurityPolicy.fromBitCode(0b0001);
|
|
34
|
+
|
|
35
|
+
expect(policy.isPayloadSigningActive()).toBe(true);
|
|
36
|
+
expect(policy.isPayloadEncryptionActive()).toBe(false);
|
|
37
|
+
expect(policy.isRootedDeviceCheckActive()).toBe(false);
|
|
38
|
+
expect(policy.isPlayIntegrityCheckActive()).toBe(false);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("bit 1 maps to payload encryption only", () => {
|
|
42
|
+
const policy = SecurityPolicy.fromBitCode(0b0010);
|
|
43
|
+
|
|
44
|
+
expect(policy.isPayloadSigningActive()).toBe(false);
|
|
45
|
+
expect(policy.isPayloadEncryptionActive()).toBe(true);
|
|
46
|
+
expect(policy.isRootedDeviceCheckActive()).toBe(false);
|
|
47
|
+
expect(policy.isPlayIntegrityCheckActive()).toBe(false);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("bit 2 maps to rooted-device check only", () => {
|
|
51
|
+
const policy = SecurityPolicy.fromBitCode(0b0100);
|
|
52
|
+
|
|
53
|
+
expect(policy.isPayloadSigningActive()).toBe(false);
|
|
54
|
+
expect(policy.isPayloadEncryptionActive()).toBe(false);
|
|
55
|
+
expect(policy.isRootedDeviceCheckActive()).toBe(true);
|
|
56
|
+
expect(policy.isPlayIntegrityCheckActive()).toBe(false);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it("bit 3 maps to play integrity check only", () => {
|
|
60
|
+
const policy = SecurityPolicy.fromBitCode(0b1000);
|
|
61
|
+
|
|
62
|
+
expect(policy.isPayloadSigningActive()).toBe(false);
|
|
63
|
+
expect(policy.isPayloadEncryptionActive()).toBe(false);
|
|
64
|
+
expect(policy.isRootedDeviceCheckActive()).toBe(false);
|
|
65
|
+
expect(policy.isPlayIntegrityCheckActive()).toBe(true);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it("combined bit-code activates exactly the set behaviours", () => {
|
|
69
|
+
// 0b1001 = payload signing (bit 0) + device attestation (bit 3).
|
|
70
|
+
const policy = SecurityPolicy.fromBitCode(0b1001);
|
|
71
|
+
|
|
72
|
+
expect(policy.isPayloadSigningActive()).toBe(true);
|
|
73
|
+
expect(policy.isPayloadEncryptionActive()).toBe(false);
|
|
74
|
+
expect(policy.isRootedDeviceCheckActive()).toBe(false);
|
|
75
|
+
expect(policy.isPlayIntegrityCheckActive()).toBe(true);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it("all four bits set activates every behaviour", () => {
|
|
79
|
+
const policy = SecurityPolicy.fromBitCode(0b1111);
|
|
80
|
+
|
|
81
|
+
expect(policy.isPayloadSigningActive()).toBe(true);
|
|
82
|
+
expect(policy.isPayloadEncryptionActive()).toBe(true);
|
|
83
|
+
expect(policy.isRootedDeviceCheckActive()).toBe(true);
|
|
84
|
+
expect(policy.isPlayIntegrityCheckActive()).toBe(true);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it("higher unmapped bits do not affect the known behaviours", () => {
|
|
88
|
+
// bit 4 (0b10000) is beyond the defined mapping; the four known behaviours stay off.
|
|
89
|
+
const policy = SecurityPolicy.fromBitCode(0b10000);
|
|
90
|
+
|
|
91
|
+
expect(policy.isPayloadSigningActive()).toBe(false);
|
|
92
|
+
expect(policy.isPayloadEncryptionActive()).toBe(false);
|
|
93
|
+
expect(policy.isRootedDeviceCheckActive()).toBe(false);
|
|
94
|
+
expect(policy.isPlayIntegrityCheckActive()).toBe(false);
|
|
95
|
+
});
|
|
96
|
+
});
|
|
@@ -2,6 +2,7 @@ import { describe, expect, it } from "vitest";
|
|
|
2
2
|
|
|
3
3
|
import { SigningCrypto, base64Encode, utf8Bytes } from "../signing_crypto";
|
|
4
4
|
import { SmileIDCryptoManager } from "../smile_id_crypto_manager";
|
|
5
|
+
import { SmileIDCryptoError } from "../smile_id_crypto_error";
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Pins down the request-signing contract:
|
|
@@ -58,6 +59,23 @@ describe("SmileIDCryptoManager", () => {
|
|
|
58
59
|
expect(mac).toBe("nW0HenQOrKH/qAwQBveK+TSXvg70oVWfD0aGGtfI1bk=");
|
|
59
60
|
});
|
|
60
61
|
|
|
62
|
+
it("wraps an unreadable file part as SmileIDCryptoError (signing fails open, never crashes)", async () => {
|
|
63
|
+
// A `file://` URI the runtime's `fetch` rejects — the same rejection a
|
|
64
|
+
// captured-image local read produces when the device is offline (Expo vs
|
|
65
|
+
// bare-RN runtimes differ here). The canonicalizer must surface it as a
|
|
66
|
+
// SmileIDCryptoError so the request-MAC interceptor's narrow catch fails
|
|
67
|
+
// open instead of letting the rejection escape and crash the submission.
|
|
68
|
+
await expect(
|
|
69
|
+
subject.sign(
|
|
70
|
+
TIMESTAMP,
|
|
71
|
+
KAT_HEADERS,
|
|
72
|
+
formData([
|
|
73
|
+
{ fieldName: "selfie_image", uri: "file:///nonexistent/selfie.jpg" },
|
|
74
|
+
]),
|
|
75
|
+
),
|
|
76
|
+
).rejects.toBeInstanceOf(SmileIDCryptoError);
|
|
77
|
+
});
|
|
78
|
+
|
|
61
79
|
it("multipart body MAC is independent of part order", async () => {
|
|
62
80
|
const headers = { "smileid-request-timestamp": TIMESTAMP };
|
|
63
81
|
const first = await subject.sign(
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { base64Encode, utf8Bytes } from "./signing_crypto";
|
|
2
|
+
import { SmileIDCryptoError } from "./smile_id_crypto_error";
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Reduces a request to the canonical bytes that get signed: the signed headers
|
|
@@ -86,8 +87,20 @@ async function canonicalBody(body: unknown): Promise<Uint8Array> {
|
|
|
86
87
|
/** File parts (a `uri`) → Base64 of bytes; JSON fields → parsed; else string with bool coercion. */
|
|
87
88
|
async function partValue(part: FormDataPart): Promise<unknown> {
|
|
88
89
|
if (part.uri != null) {
|
|
89
|
-
|
|
90
|
-
|
|
90
|
+
// Reading a file part can reject — e.g. the captured-image `file://` URI is
|
|
91
|
+
// unreadable, or the RN runtime rejects a local-file `fetch` when the device
|
|
92
|
+
// is offline (behaviour differs between the Expo and bare-RN runtimes).
|
|
93
|
+
// Surface it as a SmileIDCryptoError so the signing interceptor's narrow
|
|
94
|
+
// catch fails open (ships the request unsigned) instead of letting the
|
|
95
|
+
// rejection escape and crash the submission flow.
|
|
96
|
+
try {
|
|
97
|
+
const response = await fetch(part.uri);
|
|
98
|
+
return base64Encode(new Uint8Array(await response.arrayBuffer()));
|
|
99
|
+
} catch (cause) {
|
|
100
|
+
throw new SmileIDCryptoError(
|
|
101
|
+
`Failed to read request part "${part.fieldName}" for signing: ${String(cause)}`,
|
|
102
|
+
);
|
|
103
|
+
}
|
|
91
104
|
}
|
|
92
105
|
const value = part.string ?? "";
|
|
93
106
|
if (JSON_FIELDS.has(part.fieldName)) {
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server-driven security policy decoded from the integer `policy` bit-code carried as a top-level
|
|
3
|
+
* claim on the SmileID JWT — a sibling of the `sdk_config` claim, not nested inside it (see
|
|
4
|
+
* `decodeSecurityPolicyBitCode` and `docs/Policy.md`).
|
|
5
|
+
*
|
|
6
|
+
* Each bit toggles one SDK security behaviour, so the backend can dial protection up or down per
|
|
7
|
+
* session without shipping a new SDK build. The bit-code contract — which bit means what — is
|
|
8
|
+
* documented in `docs/Policy.md`, not here, so the four SDKs share one source of truth.
|
|
9
|
+
*
|
|
10
|
+
* **Fail-secure:** an absent (`undefined`) bit-code enables every behaviour, so a token that omits
|
|
11
|
+
* the claim — or a malformed token that fails to decode — runs with full protection rather than
|
|
12
|
+
* silently dropping security. This matches the value `undefined` produces in
|
|
13
|
+
* {@link SecurityPolicy.fromBitCode}.
|
|
14
|
+
*
|
|
15
|
+
* **Internal by design:** this class is not exported from the package entrypoint (`src/index.ts`),
|
|
16
|
+
* so it never becomes part of the partner-facing API; it exists only so the SDK can gate its own
|
|
17
|
+
* request signing and device attestation.
|
|
18
|
+
*/
|
|
19
|
+
export class SecurityPolicy {
|
|
20
|
+
private static readonly _BIT_PAYLOAD_SIGNING = 0;
|
|
21
|
+
private static readonly _BIT_PAYLOAD_ENCRYPTION = 1;
|
|
22
|
+
private static readonly _BIT_ROOTED_DEVICE_CHECK = 2;
|
|
23
|
+
private static readonly _BIT_PLAY_INTEGRITY_CHECK = 3;
|
|
24
|
+
|
|
25
|
+
// Fail-secure default for an absent bit-code: every known behaviour active.
|
|
26
|
+
private static readonly _ALL_ACTIVE =
|
|
27
|
+
(1 << SecurityPolicy._BIT_PAYLOAD_SIGNING) |
|
|
28
|
+
(1 << SecurityPolicy._BIT_PAYLOAD_ENCRYPTION) |
|
|
29
|
+
(1 << SecurityPolicy._BIT_ROOTED_DEVICE_CHECK) |
|
|
30
|
+
(1 << SecurityPolicy._BIT_PLAY_INTEGRITY_CHECK);
|
|
31
|
+
|
|
32
|
+
private readonly _bitCode: number;
|
|
33
|
+
|
|
34
|
+
private constructor(bitCode: number) {
|
|
35
|
+
this._bitCode = bitCode;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Decode a `bitCode` into a typed policy. An `undefined` code is fail-secure — every behaviour
|
|
40
|
+
* is active. For a defined code, behaviour `b` is active when bit `b` is set, least-significant
|
|
41
|
+
* bit first.
|
|
42
|
+
*/
|
|
43
|
+
static fromBitCode(bitCode: number | undefined): SecurityPolicy {
|
|
44
|
+
return new SecurityPolicy(bitCode ?? SecurityPolicy._ALL_ACTIVE);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** True when the server enabled request-payload HMAC signing for this session. */
|
|
48
|
+
isPayloadSigningActive(): boolean {
|
|
49
|
+
return this._isSet(SecurityPolicy._BIT_PAYLOAD_SIGNING);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** True when the server enabled request-payload encryption for this session. */
|
|
53
|
+
isPayloadEncryptionActive(): boolean {
|
|
54
|
+
return this._isSet(SecurityPolicy._BIT_PAYLOAD_ENCRYPTION);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** True when the server enabled the rooted / jailbroken device check for this session. */
|
|
58
|
+
isRootedDeviceCheckActive(): boolean {
|
|
59
|
+
return this._isSet(SecurityPolicy._BIT_ROOTED_DEVICE_CHECK);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** True when the server enabled device attestation for this session. */
|
|
63
|
+
isPlayIntegrityCheckActive(): boolean {
|
|
64
|
+
return this._isSet(SecurityPolicy._BIT_PLAY_INTEGRITY_CHECK);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
private _isSet(bit: number): boolean {
|
|
68
|
+
return ((this._bitCode >> bit) & 1) === 1;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* kept so the production host can diverge without touching call sites.
|
|
6
6
|
*/
|
|
7
7
|
export const SmileIDUrls = {
|
|
8
|
-
sandbox: "https://
|
|
8
|
+
sandbox: "https://testapi.smileidentity.com/",
|
|
9
9
|
production: "https://api.smileidentity.com/",
|
|
10
10
|
forConfig(useSandbox: boolean): string {
|
|
11
11
|
return useSandbox ? this.sandbox : this.production;
|
|
@@ -154,4 +154,29 @@ describe("withRetry", () => {
|
|
|
154
154
|
});
|
|
155
155
|
expect(block).toHaveBeenCalledTimes(3); // maxAttempts
|
|
156
156
|
});
|
|
157
|
+
|
|
158
|
+
it('strategy="none" never retries, even with an attempt budget', async () => {
|
|
159
|
+
// A config can carry both; the strategy wins.
|
|
160
|
+
const block = vi.fn().mockRejectedValue(makeAxiosError(503));
|
|
161
|
+
const config: RetryConfig = {
|
|
162
|
+
...exponentialConfig,
|
|
163
|
+
strategy: RetryStrategy.none,
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
await expect(withRetry(config, block)).rejects.toMatchObject({
|
|
167
|
+
response: { status: 503 },
|
|
168
|
+
});
|
|
169
|
+
expect(block).toHaveBeenCalledTimes(1);
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
it("makes one attempt and surfaces the real error when maxAttempts is 0", async () => {
|
|
173
|
+
// `attempt < 0` never ran the body, so the old code rejected with `undefined`.
|
|
174
|
+
const block = vi.fn().mockRejectedValue(makeAxiosError(503));
|
|
175
|
+
const config: RetryConfig = { ...exponentialConfig, maxAttempts: 0 };
|
|
176
|
+
|
|
177
|
+
await expect(withRetry(config, block)).rejects.toMatchObject({
|
|
178
|
+
response: { status: 503 },
|
|
179
|
+
});
|
|
180
|
+
expect(block).toHaveBeenCalledTimes(1);
|
|
181
|
+
});
|
|
157
182
|
});
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
decodeSmileIDToken,
|
|
4
|
+
decodeSecurityPolicyBitCode,
|
|
5
|
+
} from "../use_smile_id_token_decoder";
|
|
3
6
|
|
|
4
7
|
// ---------------------------------------------------------------------------
|
|
5
8
|
// Helper — mint a structurally valid JWT with a caller-supplied payload.
|
|
@@ -14,6 +17,59 @@ function makeJwt(payload: Record<string, unknown>): string {
|
|
|
14
17
|
return `eyJhbGciOiJub25lIn0.${payloadSegment}.stub-sig`;
|
|
15
18
|
}
|
|
16
19
|
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
// Security policy bit-code extraction
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
describe("decodeSecurityPolicyBitCode", () => {
|
|
24
|
+
it("parses the top-level policy bit-code alongside sdk_config", () => {
|
|
25
|
+
const token = makeJwt({
|
|
26
|
+
policy: 9,
|
|
27
|
+
sdk_config: { selfie: { quality: 85 } },
|
|
28
|
+
});
|
|
29
|
+
expect(decodeSecurityPolicyBitCode(token)).toBe(9);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it("parses the top-level policy bit-code when sdk_config is absent", () => {
|
|
33
|
+
const token = makeJwt({ policy: 0 });
|
|
34
|
+
expect(decodeSecurityPolicyBitCode(token)).toBe(0);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("returns undefined when the token omits policy", () => {
|
|
38
|
+
const token = makeJwt({ sdk_config: { selfie: { quality: 85 } } });
|
|
39
|
+
expect(decodeSecurityPolicyBitCode(token)).toBeUndefined();
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("returns undefined for a structurally invalid token", () => {
|
|
43
|
+
expect(decodeSecurityPolicyBitCode("not-a-jwt")).toBeUndefined();
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("returns undefined when policy is not a number", () => {
|
|
47
|
+
const token = makeJwt({ policy: "9" });
|
|
48
|
+
expect(decodeSecurityPolicyBitCode(token)).toBeUndefined();
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
describe("decodeSmileIDToken — partner_id claim (stamped onto the EXIF tag)", () => {
|
|
53
|
+
it("parses the canonical top-level partner_id claim", () => {
|
|
54
|
+
// The EXIF tagger keys on this, so it must be the server-canonical form (e.g. "002").
|
|
55
|
+
const token = makeJwt({
|
|
56
|
+
partner_id: "002",
|
|
57
|
+
sdk_config: { selfie: { width: 640 } },
|
|
58
|
+
});
|
|
59
|
+
expect(decodeSmileIDToken(token)?.partnerId).toBe("002");
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("leaves partnerId undefined when the claim is absent", () => {
|
|
63
|
+
const token = makeJwt({ sdk_config: { selfie: { quality: 85 } } });
|
|
64
|
+
expect(decodeSmileIDToken(token)?.partnerId).toBeUndefined();
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("leaves partnerId undefined when the claim is not a string", () => {
|
|
68
|
+
const token = makeJwt({ partner_id: 2 });
|
|
69
|
+
expect(decodeSmileIDToken(token)?.partnerId).toBeUndefined();
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
|
|
17
73
|
// ---------------------------------------------------------------------------
|
|
18
74
|
// Structural failure paths → undefined
|
|
19
75
|
// ---------------------------------------------------------------------------
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { isAxiosError } from "axios";
|
|
2
|
-
import
|
|
2
|
+
import {
|
|
3
|
+
RetryStrategy,
|
|
4
|
+
type RetryConfig,
|
|
5
|
+
} from "../../core/models/network_config";
|
|
3
6
|
|
|
4
7
|
/**
|
|
5
8
|
* Retry helper. Retries `block` until success or `maxAttempts`
|
|
@@ -13,12 +16,18 @@ import type { RetryConfig } from "../../core/models/network_config";
|
|
|
13
16
|
*/
|
|
14
17
|
export async function withRetry<T>(
|
|
15
18
|
config: RetryConfig,
|
|
16
|
-
block: () => Promise<T>,
|
|
19
|
+
block: (attempt: number) => Promise<T>,
|
|
17
20
|
): Promise<T> {
|
|
21
|
+
// Without this the loop below never runs and rejects with `undefined`.
|
|
22
|
+
if (config.strategy === RetryStrategy.none || config.maxAttempts <= 1) {
|
|
23
|
+
return block(0);
|
|
24
|
+
}
|
|
25
|
+
|
|
18
26
|
let lastError: unknown;
|
|
19
27
|
for (let attempt = 0; attempt < config.maxAttempts; attempt++) {
|
|
20
28
|
try {
|
|
21
|
-
|
|
29
|
+
// `attempt` is the number of retries that preceded this try (0 first).
|
|
30
|
+
return await block(attempt);
|
|
22
31
|
} catch (error) {
|
|
23
32
|
lastError = error;
|
|
24
33
|
if (!isRetryable(error) || attempt === config.maxAttempts - 1) {
|