From ada8a046bd0263c92c7e9b531d3e853b0e62c76c Mon Sep 17 00:00:00 2001 From: Marten Rebane Date: Fri, 9 Jan 2026 15:55:13 +0200 Subject: [PATCH] Add User-Agent support --- .../UI/ShareViewController.swift | 1 + Modules/CommonsLib/Package.swift | 4 - .../Domain/Model/ConfigurationViewModel.swift | 9 ++- .../Loader/ConfigurationLoader.swift | 25 ++++-- .../Loader/ConfigurationLoaderProtocol.swift | 12 ++- .../CentralConfigurationRepository.swift | 24 ++++-- ...ntralConfigurationRepositoryProtocol.swift | 17 +++- .../Repository/ConfigurationRepository.swift | 22 +++++- .../ConfigurationRepositoryProtocol.swift | 12 ++- .../Service/CentralConfigurationService.swift | 54 +++++++------ .../CentralConfigurationServiceProtocol.swift | 17 +++- .../ConfigLib/DI/ConfigLibContainer.swift | 1 - .../Model/ConfigurationViewModelTests.swift | 29 ++++--- .../Loader/ConfigurationLoaderTests.swift | 54 ++++++++----- .../CentralConfigurationRepositoryTests.swift | 30 ++++--- .../ConfigurationRepositoryTests.swift | 29 +++++-- .../CentralConfigurationServiceTests.swift | 22 +++--- .../Shared/TestRSAKeyGenerator.swift | 1 + .../Tests/Mocks/TestConfigurationSetup.swift | 2 +- Modules/CryptoLib/Package.swift | 1 + .../CryptoObjCWrapper/Conf/CDoc2Setting.swift | 1 + .../CryptoObjCWrapper/Domain/CdocInfo.swift | 2 +- .../Sources/CryptoSwift/Ldap/OpenLdap.swift | 1 + Modules/IdCardLib/Package.swift | 4 +- .../IdCardLib/CardActions/CardReaderNFC.swift | 2 +- .../CardActions/CardReaderiR301.swift | 2 +- .../Extensions/NFCISO7816Tag+Extensions.swift | 2 +- .../Operations/UsbReaderConnection.swift | 2 +- .../include/Conf/DigiDocConfWrapper.h | 2 +- .../include/Conf/DigiDocConfWrapper.mm | 9 ++- .../Domain/Conf/DigiDocConf.swift | 25 ++++-- .../Conf/DigiDocConfTests.swift | 14 +++- .../Container/ContainerWrapperTests.swift | 11 ++- .../SignedContainerTests.swift | 2 +- .../Service/MobileIdSignService.swift | 59 ++++++++------ .../Service/MobileIdSignServiceProtocol.swift | 9 ++- .../Service/SmartIdSignService.swift | 55 +++++++------ .../Service/SmartIdSignServiceProtocol.swift | 9 ++- .../CommonsTestShared/File/TestFileUtil.swift | 13 ++-- .../Url/MockURLProtocol.swift | 10 ++- .../Sources/UtilsLib}/Bundle/BundleUtil.swift | 0 .../UtilsLib/DI/UtilsLibContainer.swift | 4 + .../Extensions/SessionExtensions.swift | 2 +- .../Sources/UtilsLib}/Logging/Loggable.swift | 0 .../Logging/LoggingConfiguration.swift | 0 .../UtilsLib}/Logging/LoggingSystem.swift | 0 .../UtilsLib/Model/UserAgentDiagnostics.swift | 26 +++++++ .../Sources/UtilsLib}/System/SystemUtil.swift | 0 .../UtilsLib/User-Agent/UserAgentUtil.swift | 78 +++++++++++++++++++ .../User-Agent/UserAgentUtilProtocol.swift | 28 +++++++ .../Bundle/BundleUtilTests.swift | 4 +- .../System/SystemUtilTests.swift | 5 +- .../User-Agent/UserAgentUtilTests.swift | 61 +++++++++++++++ RIADigiDoc/DI/AppContainer.swift | 16 ++-- .../Domain/Preferences/KeychainStore.swift | 2 +- RIADigiDoc/Info.plist | 5 ++ RIADigiDoc/LibrarySetup.swift | 13 +++- .../UI/Component/HomeView/HomeHeader.swift | 2 +- .../InfoView/InfoHeaderTextComponent.swift | 2 +- .../ViewModel/AdvancedSettingsViewModel.swift | 1 + .../ViewModel/DiagnosticsViewModel.swift | 10 ++- .../ViewModel/EncryptRecipientViewModel.swift | 1 + .../EncryptionSettingsViewModel.swift | 1 + RIADigiDoc/ViewModel/InitViewModel.swift | 2 +- .../ViewModel/LanguageChooserViewModel.swift | 2 +- .../MobileIDSmartIDSettingsViewModel.swift | 1 + .../ViewModel/MyEid/MyEidRootViewModel.swift | 1 + .../ViewModel/ProxySettingsViewModel.swift | 22 +++++- .../ViewModel/RecentDocumentsViewModel.swift | 1 + .../ViewModel/SignatureDetailViewModel.swift | 2 +- .../ActionMethodSelectionViewModel.swift | 2 +- .../Signing/MobileId/MobileIdViewModel.swift | 52 +++++++++---- .../ViewModel/Signing/NFC/NFCViewModel.swift | 1 + .../RoleAndAddress/RoleViewModel.swift | 1 + .../RootView/SigningRootViewModel.swift | 2 +- .../Signing/SmartId/SmartIdViewModel.swift | 50 ++++++++---- .../AdvancedSettingsRepositoryTests.swift | 1 + .../ViewModel/DiagnosticsViewModelTests.swift | 7 +- .../ProxySettingsViewModelTests.swift | 15 +++- .../RecentDocumentsViewModelTests.swift | 8 -- .../MobileId/MobileIdViewModelTests.swift | 6 +- .../SmartId/SmartIdViewModelTests.swift | 5 +- 82 files changed, 757 insertions(+), 285 deletions(-) rename Modules/{CommonsLib/Sources/CommonsLib => UtilsLib/Sources/UtilsLib}/Bundle/BundleUtil.swift (100%) rename Modules/{CommonsLib/Sources/CommonsLib => UtilsLib/Sources/UtilsLib}/Logging/Loggable.swift (100%) rename Modules/{CommonsLib/Sources/CommonsLib => UtilsLib/Sources/UtilsLib}/Logging/LoggingConfiguration.swift (100%) rename Modules/{CommonsLib/Sources/CommonsLib => UtilsLib/Sources/UtilsLib}/Logging/LoggingSystem.swift (100%) create mode 100644 Modules/UtilsLib/Sources/UtilsLib/Model/UserAgentDiagnostics.swift rename Modules/{CommonsLib/Sources/CommonsLib => UtilsLib/Sources/UtilsLib}/System/SystemUtil.swift (100%) create mode 100644 Modules/UtilsLib/Sources/UtilsLib/User-Agent/UserAgentUtil.swift create mode 100644 Modules/UtilsLib/Sources/UtilsLib/User-Agent/UserAgentUtilProtocol.swift rename Modules/{CommonsLib/Tests/CommonsLibTests => UtilsLib/Tests/UtilsLibTests}/Bundle/BundleUtilTests.swift (97%) rename Modules/{CommonsLib/Tests/CommonsLibTests => UtilsLib/Tests/UtilsLibTests}/System/SystemUtilTests.swift (95%) create mode 100644 Modules/UtilsLib/Tests/UtilsLibTests/User-Agent/UserAgentUtilTests.swift diff --git a/Extensions/FileImportShareExtension/UI/ShareViewController.swift b/Extensions/FileImportShareExtension/UI/ShareViewController.swift index e5c1ac4c..0de9a8a2 100644 --- a/Extensions/FileImportShareExtension/UI/ShareViewController.swift +++ b/Extensions/FileImportShareExtension/UI/ShareViewController.swift @@ -22,6 +22,7 @@ import UIKit import SwiftUI import UniformTypeIdentifiers import FactoryKit +import UtilsLib class ShareViewController: UIViewController, Sendable, Loggable { let viewModel = Container.shared.shareViewModel() diff --git a/Modules/CommonsLib/Package.swift b/Modules/CommonsLib/Package.swift index b6c698c9..297717fc 100644 --- a/Modules/CommonsLib/Package.swift +++ b/Modules/CommonsLib/Package.swift @@ -36,10 +36,6 @@ let package = Package( name: "CommonsLibMocks", dependencies: ["CommonsLib"], path: "Tests/Mocks/Generated" - ), - .testTarget( - name: "CommonsLibTests", - dependencies: ["CommonsLib"], ) ] ) diff --git a/Modules/ConfigLib/Sources/ConfigLib/Configuration/Domain/Model/ConfigurationViewModel.swift b/Modules/ConfigLib/Sources/ConfigLib/Configuration/Domain/Model/ConfigurationViewModel.swift index 00a11b3d..bb3466c6 100644 --- a/Modules/ConfigLib/Sources/ConfigLib/Configuration/Domain/Model/ConfigurationViewModel.swift +++ b/Modules/ConfigLib/Sources/ConfigLib/Configuration/Domain/Model/ConfigurationViewModel.swift @@ -37,11 +37,16 @@ class ConfigurationViewModel: Loggable { self.fileManager = fileManager } - func fetchConfiguration(lastUpdate: TimeInterval, proxyInfo: ProxyInfo) async { + func fetchConfiguration( + lastUpdate: TimeInterval, + proxyInfo: ProxyInfo, + userAgent: String + ) async { do { guard let updates = try await repository.getCentralConfigurationUpdates( cacheDir: Directories.getConfigDirectory(fileManager: fileManager), - proxyInfo: proxyInfo + proxyInfo: proxyInfo, + userAgent: userAgent ) else { ConfigurationViewModel.logger().error("No configuration updates available.") return diff --git a/Modules/ConfigLib/Sources/ConfigLib/Configuration/Loader/ConfigurationLoader.swift b/Modules/ConfigLib/Sources/ConfigLib/Configuration/Loader/ConfigurationLoader.swift index 8524facf..5e3e3923 100644 --- a/Modules/ConfigLib/Sources/ConfigLib/Configuration/Loader/ConfigurationLoader.swift +++ b/Modules/ConfigLib/Sources/ConfigLib/Configuration/Loader/ConfigurationLoader.swift @@ -57,7 +57,11 @@ public actor ConfigurationLoader: ConfigurationLoaderProtocol, Loggable { self.bundle = bundle ?? Bundle.module } - public func initConfiguration(cacheDir: URL, proxyInfo: ProxyInfo) async throws { + public func initConfiguration( + cacheDir: URL, + proxyInfo: ProxyInfo, + userAgent: String + ) async throws { ConfigurationLoader.logger().debug("Initializing configuration") if !fileManager.fileExists(atPath: cacheDir.resolvedPath) { @@ -71,7 +75,11 @@ public actor ConfigurationLoader: ConfigurationLoaderProtocol, Loggable { if try await shouldCheckForUpdates() { ConfigurationLoader.logger().debug("Checking for configuration updates...") - try await loadCentralConfiguration(cacheDir: cacheDir, proxyInfo: proxyInfo) + try await loadCentralConfiguration( + cacheDir: cacheDir, + proxyInfo: proxyInfo, + userAgent: userAgent + ) } ConfigurationLoader.logger().debug("Finished initializing configuration") @@ -261,7 +269,8 @@ public actor ConfigurationLoader: ConfigurationLoaderProtocol, Loggable { public func loadCentralConfiguration( cacheDir: URL?, - proxyInfo: ProxyInfo + proxyInfo: ProxyInfo, + userAgent: String ) async throws { let configDir = try cacheDir ?? Directories.getConfigDirectory(fileManager: fileManager) @@ -277,17 +286,21 @@ public actor ConfigurationLoader: ConfigurationLoaderProtocol, Loggable { var centralSignature = "" centralSignature = try await centralConfigurationRepository.fetchSignature( - proxyInfo: proxyInfo + proxyInfo: proxyInfo, + userAgent: userAgent ).trimmingCharacters(in: .whitespaces) if !centralSignature.isEmpty && currentSignature != centralSignature.data(using: .utf8) { ConfigurationLoader.logger().debug("Found new configuration") let centralConfig = try await centralConfigurationRepository.fetchConfiguration( - proxyInfo: proxyInfo + proxyInfo: proxyInfo, + userAgent: userAgent ) + let centralPublicKey = try await centralConfigurationRepository.fetchPublicKey( - proxyInfo: proxyInfo + proxyInfo: proxyInfo, + userAgent: userAgent ) let centralConfigurationProvider = try JSONDecoder().decode( diff --git a/Modules/ConfigLib/Sources/ConfigLib/Configuration/Loader/ConfigurationLoaderProtocol.swift b/Modules/ConfigLib/Sources/ConfigLib/Configuration/Loader/ConfigurationLoaderProtocol.swift index f2455c1b..05ca9fba 100644 --- a/Modules/ConfigLib/Sources/ConfigLib/Configuration/Loader/ConfigurationLoaderProtocol.swift +++ b/Modules/ConfigLib/Sources/ConfigLib/Configuration/Loader/ConfigurationLoaderProtocol.swift @@ -22,7 +22,11 @@ import CommonsLib /// @mockable public protocol ConfigurationLoaderProtocol: Sendable { - func initConfiguration(cacheDir: URL, proxyInfo: ProxyInfo) async throws + func initConfiguration( + cacheDir: URL, + proxyInfo: ProxyInfo, + userAgent: String + ) async throws func loadConfigurationProperty() async throws -> ConfigurationProperty @@ -30,7 +34,11 @@ public protocol ConfigurationLoaderProtocol: Sendable { func loadDefaultConfiguration(cacheDir: URL?) async throws - func loadCentralConfiguration(cacheDir: URL?, proxyInfo: ProxyInfo) async throws + func loadCentralConfiguration( + cacheDir: URL?, + proxyInfo: ProxyInfo, + userAgent: String + ) async throws func shouldCheckForUpdates() async throws -> Bool diff --git a/Modules/ConfigLib/Sources/ConfigLib/Configuration/Repository/CentralConfigurationRepository.swift b/Modules/ConfigLib/Sources/ConfigLib/Configuration/Repository/CentralConfigurationRepository.swift index 90b98435..11ff461a 100644 --- a/Modules/ConfigLib/Sources/ConfigLib/Configuration/Repository/CentralConfigurationRepository.swift +++ b/Modules/ConfigLib/Sources/ConfigLib/Configuration/Repository/CentralConfigurationRepository.swift @@ -28,21 +28,33 @@ public struct CentralConfigurationRepository: CentralConfigurationRepositoryProt self.centralConfigurationService = centralConfigurationService } - public func fetchConfiguration(proxyInfo: ProxyInfo) async throws -> String { + public func fetchConfiguration( + proxyInfo: ProxyInfo, + userAgent: String + ) async throws -> String { return try await centralConfigurationService.fetchConfiguration( - proxyInfo: proxyInfo + proxyInfo: proxyInfo, + userAgent: userAgent ) } - public func fetchPublicKey(proxyInfo: ProxyInfo) async throws -> String { + public func fetchPublicKey( + proxyInfo: ProxyInfo, + userAgent: String + ) async throws -> String { return try await centralConfigurationService.fetchPublicKey( - proxyInfo: proxyInfo + proxyInfo: proxyInfo, + userAgent: userAgent ) } - public func fetchSignature(proxyInfo: ProxyInfo) async throws -> String { + public func fetchSignature( + proxyInfo: ProxyInfo, + userAgent: String + ) async throws -> String { return try await centralConfigurationService.fetchSignature( - proxyInfo: proxyInfo + proxyInfo: proxyInfo, + userAgent: userAgent ) } } diff --git a/Modules/ConfigLib/Sources/ConfigLib/Configuration/Repository/CentralConfigurationRepositoryProtocol.swift b/Modules/ConfigLib/Sources/ConfigLib/Configuration/Repository/CentralConfigurationRepositoryProtocol.swift index f728d6a4..b09f0af2 100644 --- a/Modules/ConfigLib/Sources/ConfigLib/Configuration/Repository/CentralConfigurationRepositoryProtocol.swift +++ b/Modules/ConfigLib/Sources/ConfigLib/Configuration/Repository/CentralConfigurationRepositoryProtocol.swift @@ -22,7 +22,18 @@ import Foundation /// @mockable public protocol CentralConfigurationRepositoryProtocol: Sendable { - func fetchConfiguration(proxyInfo: ProxyInfo) async throws -> String - func fetchPublicKey(proxyInfo: ProxyInfo) async throws -> String - func fetchSignature(proxyInfo: ProxyInfo) async throws -> String + func fetchConfiguration( + proxyInfo: ProxyInfo, + userAgent: String + ) async throws -> String + + func fetchPublicKey( + proxyInfo: ProxyInfo, + userAgent: String + ) async throws -> String + + func fetchSignature( + proxyInfo: ProxyInfo, + userAgent: String + ) async throws -> String } diff --git a/Modules/ConfigLib/Sources/ConfigLib/Configuration/Repository/ConfigurationRepository.swift b/Modules/ConfigLib/Sources/ConfigLib/Configuration/Repository/ConfigurationRepository.swift index dfdd3912..25c96497 100644 --- a/Modules/ConfigLib/Sources/ConfigLib/Configuration/Repository/ConfigurationRepository.swift +++ b/Modules/ConfigLib/Sources/ConfigLib/Configuration/Repository/ConfigurationRepository.swift @@ -47,24 +47,38 @@ public actor ConfigurationRepository: ConfigurationRepositoryProtocol { public func getCentralConfiguration( cacheDir: URL?, - proxyInfo: ProxyInfo + proxyInfo: ProxyInfo, + userAgent: String ) async throws -> ConfigurationProvider? { let configDir = try cacheDir ?? Directories.getConfigDirectory(fileManager: fileManager) - try await configurationLoader.loadCentralConfiguration(cacheDir: configDir, proxyInfo: proxyInfo) + try await configurationLoader + .loadCentralConfiguration( + cacheDir: configDir, + proxyInfo: proxyInfo, + userAgent: userAgent + ) + return await getConfiguration() } public func getCentralConfigurationUpdates( cacheDir: URL?, - proxyInfo: ProxyInfo + proxyInfo: ProxyInfo, + userAgent: String ) async throws -> AsyncThrowingStream< ConfigurationProvider?, Error >? { let configDir = try cacheDir ?? Directories.getConfigDirectory(fileManager: fileManager) - try await configurationLoader.loadCentralConfiguration(cacheDir: configDir, proxyInfo: proxyInfo) + try await configurationLoader + .loadCentralConfiguration( + cacheDir: configDir, + proxyInfo: proxyInfo, + userAgent: userAgent + ) + return await getConfigurationUpdates() } diff --git a/Modules/ConfigLib/Sources/ConfigLib/Configuration/Repository/ConfigurationRepositoryProtocol.swift b/Modules/ConfigLib/Sources/ConfigLib/Configuration/Repository/ConfigurationRepositoryProtocol.swift index 5e97a5e4..fcbd2e56 100644 --- a/Modules/ConfigLib/Sources/ConfigLib/Configuration/Repository/ConfigurationRepositoryProtocol.swift +++ b/Modules/ConfigLib/Sources/ConfigLib/Configuration/Repository/ConfigurationRepositoryProtocol.swift @@ -24,16 +24,20 @@ import Foundation public protocol ConfigurationRepositoryProtocol: Sendable { func getConfiguration() async -> ConfigurationProvider? - func getCentralConfiguration(cacheDir: URL?, proxyInfo: ProxyInfo) async throws -> ConfigurationProvider? + func getCentralConfiguration( + cacheDir: URL?, + proxyInfo: ProxyInfo, + userAgent: String + ) async throws -> ConfigurationProvider? - func observeConfigurationUpdates( - ) async -> AsyncThrowingStream? + func observeConfigurationUpdates() async -> AsyncThrowingStream? func getConfigurationUpdates() async -> AsyncThrowingStream? func getCentralConfigurationUpdates( cacheDir: URL?, - proxyInfo: ProxyInfo + proxyInfo: ProxyInfo, + userAgent: String ) async throws -> AsyncThrowingStream< ConfigurationProvider?, Error diff --git a/Modules/ConfigLib/Sources/ConfigLib/Configuration/Service/CentralConfigurationService.swift b/Modules/ConfigLib/Sources/ConfigLib/Configuration/Service/CentralConfigurationService.swift index 4a08971b..62bbcd7f 100644 --- a/Modules/ConfigLib/Sources/ConfigLib/Configuration/Service/CentralConfigurationService.swift +++ b/Modules/ConfigLib/Sources/ConfigLib/Configuration/Service/CentralConfigurationService.swift @@ -20,28 +20,28 @@ import Foundation import Alamofire import CommonsLib +import UtilsLib public actor CentralConfigurationService: CentralConfigurationServiceProtocol, Loggable { - private let userAgent: String private let configurationProperty: ConfigurationProperty private let session: Session? public init( - userAgent: String, configurationProperty: ConfigurationProperty, session: Session? = nil ) { - self.userAgent = userAgent self.configurationProperty = configurationProperty self.session = session } public func fetchConfiguration( proxyInfo: ProxyInfo, + userAgent: String ) async throws -> String { let session = self.session ?? constructHttpClient( defaultTimeout: CommonsLib.Constants.Configuration.DefaultTimeout, - proxyInfo: proxyInfo + proxyInfo: proxyInfo, + userAgent: userAgent ) let url = "\(await configurationProperty.centralConfigurationServiceUrl)/config.json" @@ -61,11 +61,13 @@ public actor CentralConfigurationService: CentralConfigurationServiceProtocol, L } public func fetchPublicKey( - proxyInfo: ProxyInfo + proxyInfo: ProxyInfo, + userAgent: String ) async throws -> String { let session = self.session ?? constructHttpClient( defaultTimeout: CommonsLib.Constants.Configuration.DefaultTimeout, - proxyInfo: proxyInfo + proxyInfo: proxyInfo, + userAgent: userAgent ) let url = "\(await configurationProperty.centralConfigurationServiceUrl)/config.ecpub" @@ -85,11 +87,13 @@ public actor CentralConfigurationService: CentralConfigurationServiceProtocol, L } public func fetchSignature( - proxyInfo: ProxyInfo + proxyInfo: ProxyInfo, + userAgent: String ) async throws -> String { let session = self.session ?? constructHttpClient( defaultTimeout: CommonsLib.Constants.Configuration.DefaultTimeout, - proxyInfo: proxyInfo + proxyInfo: proxyInfo, + userAgent: userAgent ) let url = "\(await configurationProperty.centralConfigurationServiceUrl)/config.ecc" @@ -115,43 +119,37 @@ public actor CentralConfigurationService: CentralConfigurationServiceProtocol, L defaultTimeout: TimeInterval, proxyInfo: ProxyInfo, customConfiguration: URLSessionConfiguration? = nil, + userAgent: String ) -> Session { - let interceptor = constructAlamofireRequestInterceptor() + let retryInterceptor = constructAlamofireRetryRequestInterceptor() let configuration = customConfiguration ?? { - let config = URLSessionConfiguration.default + let config = URLSessionConfiguration.af.default config.timeoutIntervalForRequest = defaultTimeout config.timeoutIntervalForResource = defaultTimeout + + var headers = config.httpAdditionalHeaders ?? [:] + headers["User-Agent"] = userAgent + headers["Content-Type"] = "application/json; charset=utf-8" + headers["Cache-Control"] = "no-cache" + headers["Pragma"] = "no-cache" + config.httpAdditionalHeaders = headers return config }() return Session.withProxy( proxyInfo: proxyInfo, configuration: configuration, - interceptor: interceptor + interceptor: retryInterceptor ) } - private func constructAlamofireRequestInterceptor() -> RequestInterceptor { - return CustomRequestInterceptor(userAgent: userAgent) + private func constructAlamofireRetryRequestInterceptor() -> RequestInterceptor { + return RetryRequestInterceptor() } } -struct CustomRequestInterceptor: RequestInterceptor { - - private let userAgent: String - - init(userAgent: String) { - self.userAgent = userAgent - } - - // swiftlint:disable:next unused_parameter - func adapt(_ request: URLRequest, for session: Session, completion: @escaping (Result) -> Void) { - var modifiedRequest = request - modifiedRequest.setValue(userAgent, forHTTPHeaderField: "User-Agent") - - completion(.success(modifiedRequest)) - } +struct RetryRequestInterceptor: RequestInterceptor { // swiftlint:disable:next blanket_disable_command // swiftlint:disable unused_parameter diff --git a/Modules/ConfigLib/Sources/ConfigLib/Configuration/Service/CentralConfigurationServiceProtocol.swift b/Modules/ConfigLib/Sources/ConfigLib/Configuration/Service/CentralConfigurationServiceProtocol.swift index 75942beb..fd8e2f78 100644 --- a/Modules/ConfigLib/Sources/ConfigLib/Configuration/Service/CentralConfigurationServiceProtocol.swift +++ b/Modules/ConfigLib/Sources/ConfigLib/Configuration/Service/CentralConfigurationServiceProtocol.swift @@ -23,7 +23,18 @@ import Foundation /// @mockable public protocol CentralConfigurationServiceProtocol: Sendable { - func fetchConfiguration(proxyInfo: ProxyInfo) async throws -> String - func fetchPublicKey(proxyInfo: ProxyInfo) async throws -> String - func fetchSignature(proxyInfo: ProxyInfo) async throws -> String + func fetchConfiguration( + proxyInfo: ProxyInfo, + userAgent: String + ) async throws -> String + + func fetchPublicKey( + proxyInfo: ProxyInfo, + userAgent: String + ) async throws -> String + + func fetchSignature( + proxyInfo: ProxyInfo, + userAgent: String + ) async throws -> String } diff --git a/Modules/ConfigLib/Sources/ConfigLib/DI/ConfigLibContainer.swift b/Modules/ConfigLib/Sources/ConfigLib/DI/ConfigLibContainer.swift index 872b03fd..5e8b268e 100644 --- a/Modules/ConfigLib/Sources/ConfigLib/DI/ConfigLibContainer.swift +++ b/Modules/ConfigLib/Sources/ConfigLib/DI/ConfigLibContainer.swift @@ -42,7 +42,6 @@ extension Container { public var centralConfigurationService: Factory { self { CentralConfigurationService( - userAgent: "", configurationProperty: self.configurationProperty(), session: nil ) } diff --git a/Modules/ConfigLib/Tests/ConfigLibTests/Configuration/Domain/Model/ConfigurationViewModelTests.swift b/Modules/ConfigLib/Tests/ConfigLibTests/Configuration/Domain/Model/ConfigurationViewModelTests.swift index 767ae2f3..a23d206b 100644 --- a/Modules/ConfigLib/Tests/ConfigLibTests/Configuration/Domain/Model/ConfigurationViewModelTests.swift +++ b/Modules/ConfigLib/Tests/ConfigLibTests/Configuration/Domain/Model/ConfigurationViewModelTests.swift @@ -44,11 +44,11 @@ struct ConfigurationViewModelTests { @Test func fetchConfiguration_successUpdatingConfigurationWhenNoLastUpdateTime() async throws { - mockRepository.getCentralConfigurationUpdatesHandler = { _, _ in + mockRepository.getCentralConfigurationUpdatesHandler = { _, _, _ in return mockAsyncStream(configProvider: mockConfigProvider) } - await viewModel.fetchConfiguration(lastUpdate: 0, proxyInfo: ProxyInfo()) + await viewModel.fetchConfiguration(lastUpdate: 0, proxyInfo: ProxyInfo(), userAgent: "TestUserAgent") let configuration = await viewModel.configuration @@ -59,11 +59,11 @@ struct ConfigurationViewModelTests { func fetchConfiguration_successUpdatingConfigurationWhenBeforeLastUpdateTime() async throws { let configProvider = try TestConfigurationProvider.mockConfigurationProvider(configurationUpdateDate: nil) - mockRepository.getCentralConfigurationUpdatesHandler = { _, _ in + mockRepository.getCentralConfigurationUpdatesHandler = { _, _, _ in return mockAsyncStream(configProvider: configProvider) } - await viewModel.fetchConfiguration(lastUpdate: -1, proxyInfo: ProxyInfo()) + await viewModel.fetchConfiguration(lastUpdate: -1, proxyInfo: ProxyInfo(), userAgent: "TestUserAgent") let configuration = await viewModel.configuration @@ -77,13 +77,13 @@ struct ConfigurationViewModelTests { return nil } - mockRepository.getCentralConfigurationUpdatesHandler = { _, _ in + mockRepository.getCentralConfigurationUpdatesHandler = { _, _, _ in return nil } let currentConf = await viewModel.getConfiguration() - await viewModel.fetchConfiguration(lastUpdate: 0, proxyInfo: ProxyInfo()) + await viewModel.fetchConfiguration(lastUpdate: 0, proxyInfo: ProxyInfo(), userAgent: "TestUserAgent") let unchangedConf = await viewModel.getConfiguration() @@ -95,11 +95,16 @@ struct ConfigurationViewModelTests { @Test func fetchConfiguration_doesNotUpdateConfigurationWhenLastUpdateIsNewer() async throws { - mockRepository.getCentralConfigurationUpdatesHandler = { _, _ in + mockRepository.getCentralConfigurationUpdatesHandler = { _, _, _ in return mockAsyncStream(configProvider: mockConfigProvider) } - await viewModel.fetchConfiguration(lastUpdate: Date().timeIntervalSince1970, proxyInfo: ProxyInfo()) + await viewModel + .fetchConfiguration( + lastUpdate: Date().timeIntervalSince1970, + proxyInfo: ProxyInfo(), + userAgent: "TestUserAgent" + ) await #expect(viewModel.configuration == nil) } @@ -107,7 +112,7 @@ struct ConfigurationViewModelTests { @Test func getConfiguration_noUpdatesReturnedWhenConfigurationUpdateNil() async throws { - mockRepository.getCentralConfigurationUpdatesHandler = { _, _ in + mockRepository.getCentralConfigurationUpdatesHandler = { _, _, _ in return nil } @@ -135,7 +140,7 @@ struct ConfigurationViewModelTests { continuation.finish(throwing: ConfigurationLoaderError.configurationNotFound) } - mockRepository.getCentralConfigurationUpdatesHandler = { _, _ in + mockRepository.getCentralConfigurationUpdatesHandler = { _, _, _ in return asyncStream } @@ -152,7 +157,7 @@ struct ConfigurationViewModelTests { continuation.finish() } - mockRepository.getCentralConfigurationUpdatesHandler = { _, _ in + mockRepository.getCentralConfigurationUpdatesHandler = { _, _, _ in return asyncStream } @@ -167,7 +172,7 @@ struct ConfigurationViewModelTests { continuation.finish() } - mockRepository.getCentralConfigurationUpdatesHandler = { _, _ in + mockRepository.getCentralConfigurationUpdatesHandler = { _, _, _ in return asyncStream } diff --git a/Modules/ConfigLib/Tests/ConfigLibTests/Configuration/Loader/ConfigurationLoaderTests.swift b/Modules/ConfigLib/Tests/ConfigLibTests/Configuration/Loader/ConfigurationLoaderTests.swift index 3b02a9dd..cc32b1a5 100644 --- a/Modules/ConfigLib/Tests/ConfigLibTests/Configuration/Loader/ConfigurationLoaderTests.swift +++ b/Modules/ConfigLib/Tests/ConfigLibTests/Configuration/Loader/ConfigurationLoaderTests.swift @@ -75,9 +75,9 @@ struct ConfigurationLoaderTests { mockConfigurationProperties.setConfigurationLastCheckDateHandler = { _ in } mockConfigurationProperties.setConfigurationUpdatedDateHandler = { _ in } - mockCentralConfigurationRepository.fetchConfigurationHandler = { _ in configurationResponse } - mockCentralConfigurationRepository.fetchPublicKeyHandler = { _ in "some key" } - mockCentralConfigurationRepository.fetchSignatureHandler = { _ in "some signature" } + mockCentralConfigurationRepository.fetchConfigurationHandler = { _, _ in configurationResponse } + mockCentralConfigurationRepository.fetchPublicKeyHandler = { _, _ in "some key" } + mockCentralConfigurationRepository.fetchSignatureHandler = { _, _ in "some signature" } let mockCacheDir = URL(fileURLWithPath: "/mock/cache/dir") mockFileManager.urlsHandler = { directory, domain in @@ -122,7 +122,11 @@ struct ConfigurationLoaderTests { return nil } - try await configurationLoader.initConfiguration(cacheDir: mockCacheDir, proxyInfo: ProxyInfo()) + try await configurationLoader.initConfiguration( + cacheDir: mockCacheDir, + proxyInfo: ProxyInfo(), + userAgent: "TestUserAgent" + ) defer { try? FileManager.default.removeItem(at: cacheDir) @@ -149,9 +153,9 @@ struct ConfigurationLoaderTests { mockConfigurationProperties.setConfigurationLastCheckDateHandler = { _ in } mockConfigurationProperties.setConfigurationUpdatedDateHandler = { _ in } - mockCentralConfigurationRepository.fetchConfigurationHandler = { _ in configurationResponse } - mockCentralConfigurationRepository.fetchPublicKeyHandler = { _ in "some key" } - mockCentralConfigurationRepository.fetchSignatureHandler = { _ in "some signature" } + mockCentralConfigurationRepository.fetchConfigurationHandler = { _, _ in configurationResponse } + mockCentralConfigurationRepository.fetchPublicKeyHandler = { _, _ in "some key" } + mockCentralConfigurationRepository.fetchSignatureHandler = { _, _ in "some signature" } let cacheDirURL = FileManager.default.urls( for: .cachesDirectory, @@ -345,13 +349,17 @@ struct ConfigurationLoaderTests { mockConfigurationProperties.setConfigurationLastCheckDateHandler = { _ in } mockConfigurationProperties.setConfigurationUpdatedDateHandler = { _ in } - mockCentralConfigurationRepository.fetchConfigurationHandler = { _ in configurationResponse } - mockCentralConfigurationRepository.fetchPublicKeyHandler = { _ in "some key" } - mockCentralConfigurationRepository.fetchSignatureHandler = { _ in "some signature" } + mockCentralConfigurationRepository.fetchConfigurationHandler = { _, _ in configurationResponse } + mockCentralConfigurationRepository.fetchPublicKeyHandler = { _, _ in "some key" } + mockCentralConfigurationRepository.fetchSignatureHandler = { _, _ in "some signature" } let mockCacheDir = URL(fileURLWithPath: "/mock/cache/dir") - try await configurationLoader.initConfiguration(cacheDir: mockCacheDir, proxyInfo: ProxyInfo()) + try await configurationLoader.initConfiguration( + cacheDir: mockCacheDir, + proxyInfo: ProxyInfo(), + userAgent: "TestUserAgent" + ) mockFileManager.urlsHandler = { directory, domain in guard directory == .cachesDirectory, domain == .userDomainMask else { @@ -634,13 +642,17 @@ struct ConfigurationLoaderTests { mockConfigurationProperties.setConfigurationLastCheckDateHandler = { _ in } mockConfigurationProperties.setConfigurationUpdatedDateHandler = { _ in } - mockCentralConfigurationRepository.fetchConfigurationHandler = { _ in configurationResponse } - mockCentralConfigurationRepository.fetchPublicKeyHandler = { _ in "publicKey" } - mockCentralConfigurationRepository.fetchSignatureHandler = { _ in "validSignature" } + mockCentralConfigurationRepository.fetchConfigurationHandler = { _, _ in configurationResponse } + mockCentralConfigurationRepository.fetchPublicKeyHandler = { _, _ in "publicKey" } + mockCentralConfigurationRepository.fetchSignatureHandler = { _, _ in "validSignature" } mockConfigurationCache.getCachedFileHandler = { _, _ in signatureFile } - try await configurationLoader.loadCentralConfiguration(cacheDir: nil, proxyInfo: ProxyInfo()) + try await configurationLoader.loadCentralConfiguration( + cacheDir: nil, + proxyInfo: ProxyInfo(), + userAgent: "TestUserAgent" + ) await #expect(configurationLoader.getConfiguration() != nil) #expect( @@ -697,12 +709,16 @@ struct ConfigurationLoaderTests { mockConfigurationCache.getCachedFileHandler = { _, _ in signatureFile } - mockCentralConfigurationRepository.fetchConfigurationHandler = { _ in configurationResponse } - mockCentralConfigurationRepository.fetchPublicKeyHandler = { _ in "some key" } - mockCentralConfigurationRepository.fetchSignatureHandler = { _ in "some signature" } + mockCentralConfigurationRepository.fetchConfigurationHandler = { _, _ in configurationResponse } + mockCentralConfigurationRepository.fetchPublicKeyHandler = { _, _ in "some key" } + mockCentralConfigurationRepository.fetchSignatureHandler = { _, _ in "some signature" } await #expect(throws: ConfigurationLoaderError.configurationVerificationFailed) { - try await configurationLoader.loadCentralConfiguration(cacheDir: nil, proxyInfo: ProxyInfo()) + try await configurationLoader.loadCentralConfiguration( + cacheDir: nil, + proxyInfo: ProxyInfo(), + userAgent: "TestUserAgent" + ) } } diff --git a/Modules/ConfigLib/Tests/ConfigLibTests/Configuration/Repository/CentralConfigurationRepositoryTests.swift b/Modules/ConfigLib/Tests/ConfigLibTests/Configuration/Repository/CentralConfigurationRepositoryTests.swift index 57055634..181e5ebc 100644 --- a/Modules/ConfigLib/Tests/ConfigLibTests/Configuration/Repository/CentralConfigurationRepositoryTests.swift +++ b/Modules/ConfigLib/Tests/ConfigLibTests/Configuration/Repository/CentralConfigurationRepositoryTests.swift @@ -37,9 +37,9 @@ struct CentralConfigurationRepositoryTests { func fetchConfiguration_success() async throws { let expectedConfiguration = "MockConfiguration" - mockConfigurationService.fetchConfigurationHandler = { _ in expectedConfiguration } + mockConfigurationService.fetchConfigurationHandler = { _, _ in expectedConfiguration } - let result = try await repository.fetchConfiguration(proxyInfo: ProxyInfo()) + let result = try await repository.fetchConfiguration(proxyInfo: ProxyInfo(), userAgent: "TestUserAgent") #expect(expectedConfiguration == result) #expect(mockConfigurationService.fetchConfigurationCallCount == 1) @@ -49,9 +49,9 @@ struct CentralConfigurationRepositoryTests { func fetchPublicKey_success() async throws { let expectedPublicKey = "MockPublicKey" - mockConfigurationService.fetchPublicKeyHandler = { _ in expectedPublicKey } + mockConfigurationService.fetchPublicKeyHandler = { _, _ in expectedPublicKey } - let result = try await repository.fetchPublicKey(proxyInfo: ProxyInfo()) + let result = try await repository.fetchPublicKey(proxyInfo: ProxyInfo(), userAgent: "TestUserAgent") #expect(expectedPublicKey == result) #expect(mockConfigurationService.fetchPublicKeyCallCount == 1) @@ -61,9 +61,9 @@ struct CentralConfigurationRepositoryTests { func fetchSignature_success() async throws { let expectedSignature = "MockSignature" - mockConfigurationService.fetchSignatureHandler = { _ in expectedSignature } + mockConfigurationService.fetchSignatureHandler = { _, _ in expectedSignature } - let result = try await repository.fetchSignature(proxyInfo: ProxyInfo()) + let result = try await repository.fetchSignature(proxyInfo: ProxyInfo(), userAgent: "TestUserAgent") #expect(expectedSignature == result) #expect(mockConfigurationService.fetchSignatureCallCount == 1) @@ -73,9 +73,11 @@ struct CentralConfigurationRepositoryTests { func fetchConfiguration_throwsErrorWhenFetchingFails() async throws { let expectedError = NSError(domain: "Test", code: 1, userInfo: nil) - mockConfigurationService.fetchConfigurationHandler = { _ in throw expectedError } + mockConfigurationService.fetchConfigurationHandler = { _, _ in throw expectedError } - await #expect(throws: (any Error).self) { try await repository.fetchConfiguration(proxyInfo: ProxyInfo()) } + await #expect(throws: (any Error).self) { + try await repository.fetchConfiguration(proxyInfo: ProxyInfo(), userAgent: "TestUserAgent") + } #expect(mockConfigurationService.fetchConfigurationCallCount == 1) } @@ -83,9 +85,11 @@ struct CentralConfigurationRepositoryTests { func fetchPublicKey_throwsErrorWhenFetchingFails() async throws { let expectedError = NSError(domain: "Test", code: 2, userInfo: nil) - mockConfigurationService.fetchPublicKeyHandler = { _ in throw expectedError } + mockConfigurationService.fetchPublicKeyHandler = { _, _ in throw expectedError } - await #expect(throws: (any Error).self) { try await repository.fetchPublicKey(proxyInfo: ProxyInfo()) } + await #expect(throws: (any Error).self) { + try await repository.fetchPublicKey(proxyInfo: ProxyInfo(), userAgent: "TestUserAgent") + } #expect(mockConfigurationService.fetchPublicKeyCallCount == 1) } @@ -93,9 +97,11 @@ struct CentralConfigurationRepositoryTests { func fetchSignature_throwsErrorWhenFetchingFails() async throws { let expectedError = NSError(domain: "Test", code: 3, userInfo: nil) - mockConfigurationService.fetchSignatureHandler = { _ in throw expectedError } + mockConfigurationService.fetchSignatureHandler = { _, _ in throw expectedError } - await #expect(throws: (any Error).self) { try await repository.fetchSignature(proxyInfo: ProxyInfo()) } + await #expect(throws: (any Error).self) { + try await repository.fetchSignature(proxyInfo: ProxyInfo(), userAgent: "TestUserAgent") + } #expect(mockConfigurationService.fetchSignatureCallCount == 1) } } diff --git a/Modules/ConfigLib/Tests/ConfigLibTests/Configuration/Repository/ConfigurationRepositoryTests.swift b/Modules/ConfigLib/Tests/ConfigLibTests/Configuration/Repository/ConfigurationRepositoryTests.swift index a64f24d8..ebffccfb 100644 --- a/Modules/ConfigLib/Tests/ConfigLibTests/Configuration/Repository/ConfigurationRepositoryTests.swift +++ b/Modules/ConfigLib/Tests/ConfigLibTests/Configuration/Repository/ConfigurationRepositoryTests.swift @@ -84,10 +84,14 @@ struct ConfigurationRepositoryTests { let expectedConfiguration = try TestConfigurationProvider.mockConfigurationProvider() let mockCacheDir = URL(fileURLWithPath: "/mock/cache/dir") - mockConfigurationLoader.loadCentralConfigurationHandler = { _, _ in } + mockConfigurationLoader.loadCentralConfigurationHandler = { _, _, _ in } mockConfigurationLoader.getConfigurationHandler = { expectedConfiguration } - let configuration = try await repository.getCentralConfiguration(cacheDir: mockCacheDir, proxyInfo: ProxyInfo()) + let configuration = try await repository.getCentralConfiguration( + cacheDir: mockCacheDir, + proxyInfo: ProxyInfo(), + userAgent: "TestUserAgent" + ) #expect(expectedConfiguration.tslUrl == configuration?.tslUrl) #expect(mockConfigurationLoader.loadCentralConfigurationArgValues.first?.cacheDir == mockCacheDir) @@ -98,10 +102,14 @@ struct ConfigurationRepositoryTests { func getCentralConfiguration_returnConfigurationThatUsesDefaultConfiguration() async throws { let expectedConfiguration = try TestConfigurationProvider.mockConfigurationProvider() - mockConfigurationLoader.loadCentralConfigurationHandler = { _, _ in } + mockConfigurationLoader.loadCentralConfigurationHandler = { _, _, _ in } mockConfigurationLoader.getConfigurationHandler = { expectedConfiguration } - let configuration = try await repository.getCentralConfiguration(cacheDir: nil, proxyInfo: ProxyInfo()) + let configuration = try await repository.getCentralConfiguration( + cacheDir: nil, + proxyInfo: ProxyInfo(), + userAgent: "TestUserAgent" + ) let isCorrectDirectory = try mockConfigurationLoader.loadCentralConfigurationArgValues.first?.cacheDir == Directories.getConfigDirectory(fileManager: mockFileManager) @@ -120,12 +128,13 @@ struct ConfigurationRepositoryTests { continuation.finish() } - mockConfigurationLoader.loadCentralConfigurationHandler = { _, _ in } + mockConfigurationLoader.loadCentralConfigurationHandler = { _, _, _ in } mockConfigurationLoader.getConfigurationUpdatesHandler = { _ in stream } let resultStream = try await repository.getCentralConfigurationUpdates( cacheDir: mockCacheDir, - proxyInfo: ProxyInfo() + proxyInfo: ProxyInfo(), + userAgent: "TestUserAgent" ) #expect(resultStream != nil) @@ -154,10 +163,14 @@ struct ConfigurationRepositoryTests { continuation.finish() } - mockConfigurationLoader.loadCentralConfigurationHandler = { _, _ in } + mockConfigurationLoader.loadCentralConfigurationHandler = { _, _, _ in } mockConfigurationLoader.getConfigurationUpdatesHandler = { _ in stream } - let resultStream = try await repository.getCentralConfigurationUpdates(cacheDir: nil, proxyInfo: ProxyInfo()) + let resultStream = try await repository.getCentralConfigurationUpdates( + cacheDir: nil, + proxyInfo: ProxyInfo(), + userAgent: "TestUserAgent" + ) #expect(resultStream != nil) diff --git a/Modules/ConfigLib/Tests/ConfigLibTests/Configuration/Service/CentralConfigurationServiceTests.swift b/Modules/ConfigLib/Tests/ConfigLibTests/Configuration/Service/CentralConfigurationServiceTests.swift index 1eecef15..48808f5a 100644 --- a/Modules/ConfigLib/Tests/ConfigLibTests/Configuration/Service/CentralConfigurationServiceTests.swift +++ b/Modules/ConfigLib/Tests/ConfigLibTests/Configuration/Service/CentralConfigurationServiceTests.swift @@ -61,7 +61,6 @@ struct CentralConfigurationServiceTests { } let service = CentralConfigurationService( - userAgent: "TestUserAgent", configurationProperty: ConfigurationProperty( centralConfigurationServiceUrl: "https://someUrl.abc/config", updateInterval: 3600, @@ -71,7 +70,11 @@ struct CentralConfigurationServiceTests { session: session ) - let result = try await service.fetchConfiguration(proxyInfo: ProxyInfo()) + let result = try await service.fetchConfiguration( + proxyInfo: ProxyInfo(), + userAgent: "CentralConfigurationServiceTests" + ) + #expect(result == "{\"configKey\": \"configValue\"}") } @@ -95,7 +98,6 @@ struct CentralConfigurationServiceTests { } let errorService = CentralConfigurationService( - userAgent: "TestUserAgent", configurationProperty: ConfigurationProperty( centralConfigurationServiceUrl: "https://someUrl.abc/error/", updateInterval: 3600, @@ -106,7 +108,7 @@ struct CentralConfigurationServiceTests { ) await #expect(throws: Error.self) { - try await errorService.fetchConfiguration(proxyInfo: ProxyInfo()) + try await errorService.fetchConfiguration(proxyInfo: ProxyInfo(), userAgent: "TestUserAgent") } } @@ -131,7 +133,6 @@ struct CentralConfigurationServiceTests { } let service = CentralConfigurationService( - userAgent: "TestUserAgent", configurationProperty: ConfigurationProperty( centralConfigurationServiceUrl: "https://someUrl.abc/config", updateInterval: 3600, @@ -141,7 +142,7 @@ struct CentralConfigurationServiceTests { session: session ) - let fetchedPublicKey = try await service.fetchPublicKey(proxyInfo: ProxyInfo()) + let fetchedPublicKey = try await service.fetchPublicKey(proxyInfo: ProxyInfo(), userAgent: "TestUserAgent") #expect(fetchedPublicKey == String(data: mockData, encoding: .utf8)) } @@ -165,7 +166,6 @@ struct CentralConfigurationServiceTests { } let errorService = CentralConfigurationService( - userAgent: "TestUserAgent", configurationProperty: ConfigurationProperty( centralConfigurationServiceUrl: "https://someUrl.abc/error/", updateInterval: 3600, @@ -176,7 +176,7 @@ struct CentralConfigurationServiceTests { ) await #expect(throws: Error.self) { - try await errorService.fetchPublicKey(proxyInfo: ProxyInfo()) + try await errorService.fetchPublicKey(proxyInfo: ProxyInfo(), userAgent: "TestUserAgent") } } @@ -201,7 +201,6 @@ struct CentralConfigurationServiceTests { } let service = CentralConfigurationService( - userAgent: "TestUserAgent", configurationProperty: ConfigurationProperty( centralConfigurationServiceUrl: "https://someUrl.abc/config", updateInterval: 3600, @@ -211,7 +210,7 @@ struct CentralConfigurationServiceTests { session: session ) - let fetchedSignature = try await service.fetchSignature(proxyInfo: ProxyInfo()) + let fetchedSignature = try await service.fetchSignature(proxyInfo: ProxyInfo(), userAgent: "TestUserAgent") #expect(fetchedSignature == String(data: mockData, encoding: .utf8)) } @@ -235,7 +234,6 @@ struct CentralConfigurationServiceTests { } let errorService = CentralConfigurationService( - userAgent: "TestUserAgent", configurationProperty: ConfigurationProperty( centralConfigurationServiceUrl: "https://someUrl.abc/error/", updateInterval: 3600, @@ -246,7 +244,7 @@ struct CentralConfigurationServiceTests { ) await #expect(throws: Error.self) { - try await errorService.fetchSignature(proxyInfo: ProxyInfo()) + try await errorService.fetchSignature(proxyInfo: ProxyInfo(), userAgent: "TestUserAgent") } } } diff --git a/Modules/ConfigLib/Tests/ConfigLibTests/Configuration/Shared/TestRSAKeyGenerator.swift b/Modules/ConfigLib/Tests/ConfigLibTests/Configuration/Shared/TestRSAKeyGenerator.swift index 72250d5d..f49daed9 100644 --- a/Modules/ConfigLib/Tests/ConfigLibTests/Configuration/Shared/TestRSAKeyGenerator.swift +++ b/Modules/ConfigLib/Tests/ConfigLibTests/Configuration/Shared/TestRSAKeyGenerator.swift @@ -21,6 +21,7 @@ import CommonsLib import Foundation import Testing import Security +import UtilsLib @testable import ConfigLib struct TestRSAKeyGenerator: Loggable { diff --git a/Modules/ConfigLib/Tests/Mocks/TestConfigurationSetup.swift b/Modules/ConfigLib/Tests/Mocks/TestConfigurationSetup.swift index 3e5db084..31747f33 100644 --- a/Modules/ConfigLib/Tests/Mocks/TestConfigurationSetup.swift +++ b/Modules/ConfigLib/Tests/Mocks/TestConfigurationSetup.swift @@ -45,7 +45,7 @@ public struct TestConfigurationSetup { return mockAsyncStream(configProvider: mockConfig) } - configurationRepository.getCentralConfigurationUpdatesHandler = { [configProvider] _, _ async throws in + configurationRepository.getCentralConfigurationUpdatesHandler = { [configProvider] _, _, _ async throws in guard let mockConfig = configProvider else { return AsyncThrowingStream { continuation in continuation.yield(nil) diff --git a/Modules/CryptoLib/Package.swift b/Modules/CryptoLib/Package.swift index fbe413b4..6a58c85e 100644 --- a/Modules/CryptoLib/Package.swift +++ b/Modules/CryptoLib/Package.swift @@ -40,6 +40,7 @@ let package = Package( "CommonsLib", "ConfigLib", "IdCardLib", + "UtilsLib", .product(name: "FactoryKit", package: "Factory") ], path: "Sources/CryptoObjCWrapper", diff --git a/Modules/CryptoLib/Sources/CryptoObjCWrapper/Conf/CDoc2Setting.swift b/Modules/CryptoLib/Sources/CryptoObjCWrapper/Conf/CDoc2Setting.swift index c8736e48..bd0a67ab 100644 --- a/Modules/CryptoLib/Sources/CryptoObjCWrapper/Conf/CDoc2Setting.swift +++ b/Modules/CryptoLib/Sources/CryptoObjCWrapper/Conf/CDoc2Setting.swift @@ -20,6 +20,7 @@ import Foundation import CommonsLib import ConfigLib +import UtilsLib public final class CDoc2Setting: NSObject, Sendable, Loggable { @objc @MainActor static public var isEncryptionEnabled: Bool = Constants.CryptoDefaultValues.encryptionUseCdoc2 diff --git a/Modules/CryptoLib/Sources/CryptoObjCWrapper/Domain/CdocInfo.swift b/Modules/CryptoLib/Sources/CryptoObjCWrapper/Domain/CdocInfo.swift index 79a1e734..e747809d 100644 --- a/Modules/CryptoLib/Sources/CryptoObjCWrapper/Domain/CdocInfo.swift +++ b/Modules/CryptoLib/Sources/CryptoObjCWrapper/Domain/CdocInfo.swift @@ -17,8 +17,8 @@ * */ -import CommonsLib import Foundation +import UtilsLib @objc public final class CdocInfo: NSObject, Loggable { public let format: String diff --git a/Modules/CryptoLib/Sources/CryptoSwift/Ldap/OpenLdap.swift b/Modules/CryptoLib/Sources/CryptoSwift/Ldap/OpenLdap.swift index 443716f0..8579eb0b 100644 --- a/Modules/CryptoLib/Sources/CryptoSwift/Ldap/OpenLdap.swift +++ b/Modules/CryptoLib/Sources/CryptoSwift/Ldap/OpenLdap.swift @@ -23,6 +23,7 @@ import CommonsLib import LDAP import ASN1Decoder import Foundation +import UtilsLib final public class OpenLdap: OpenLdapProtocol, Loggable { private let ldapConfiguration: LdapConfigurationProtocol diff --git a/Modules/IdCardLib/Package.swift b/Modules/IdCardLib/Package.swift index d05eab11..2eac7b05 100644 --- a/Modules/IdCardLib/Package.swift +++ b/Modules/IdCardLib/Package.swift @@ -16,7 +16,7 @@ let package = Package( .package(url: "https://github.com/apple/swift-asn1.git", exact: .init(1, 4, 0)), .package(url: "https://github.com/apple/swift-certificates.git", exact: .init(1, 7, 0)), .package(url: "https://github.com/leif-ibsen/SwiftECC.git", exact: .init(5, 5, 0)), - .package(path: "../CommonsLib") + .package(path: "../UtilsLib") ], targets: [ .target( @@ -38,7 +38,7 @@ let package = Package( "Digest", "SwiftECC", "iR301", - "CommonsLib" + "UtilsLib" ], path: "Sources/IdCardLib", swiftSettings: [ diff --git a/Modules/IdCardLib/Sources/IdCardLib/CardActions/CardReaderNFC.swift b/Modules/IdCardLib/Sources/IdCardLib/CardActions/CardReaderNFC.swift index 2291e7f5..5348a0f3 100644 --- a/Modules/IdCardLib/Sources/IdCardLib/CardActions/CardReaderNFC.swift +++ b/Modules/IdCardLib/Sources/IdCardLib/CardActions/CardReaderNFC.swift @@ -17,7 +17,7 @@ * */ -import CommonsLib +import UtilsLib import CoreNFC import CommonCrypto import CryptoTokenKit diff --git a/Modules/IdCardLib/Sources/IdCardLib/CardActions/CardReaderiR301.swift b/Modules/IdCardLib/Sources/IdCardLib/CardActions/CardReaderiR301.swift index 4890b361..c13fcf99 100644 --- a/Modules/IdCardLib/Sources/IdCardLib/CardActions/CardReaderiR301.swift +++ b/Modules/IdCardLib/Sources/IdCardLib/CardActions/CardReaderiR301.swift @@ -17,8 +17,8 @@ * */ -import CommonsLib import iR301 +import UtilsLib class CardReaderiR301: CardReader, Loggable { let atr: Bytes diff --git a/Modules/IdCardLib/Sources/IdCardLib/Extensions/NFCISO7816Tag+Extensions.swift b/Modules/IdCardLib/Sources/IdCardLib/Extensions/NFCISO7816Tag+Extensions.swift index 5708f3a5..3e011fb9 100644 --- a/Modules/IdCardLib/Sources/IdCardLib/Extensions/NFCISO7816Tag+Extensions.swift +++ b/Modules/IdCardLib/Sources/IdCardLib/Extensions/NFCISO7816Tag+Extensions.swift @@ -17,7 +17,7 @@ * */ -import CommonsLib +import UtilsLib import CoreNFC import CryptoTokenKit diff --git a/Modules/IdCardLib/Sources/IdCardLib/Operations/UsbReaderConnection.swift b/Modules/IdCardLib/Sources/IdCardLib/Operations/UsbReaderConnection.swift index a9268d64..015f0e95 100644 --- a/Modules/IdCardLib/Sources/IdCardLib/Operations/UsbReaderConnection.swift +++ b/Modules/IdCardLib/Sources/IdCardLib/Operations/UsbReaderConnection.swift @@ -17,7 +17,7 @@ * */ -import CommonsLib +import UtilsLib import Foundation import iR301 diff --git a/Modules/LibdigidocLib/Sources/LibdigidocObjC/include/Conf/DigiDocConfWrapper.h b/Modules/LibdigidocLib/Sources/LibdigidocObjC/include/Conf/DigiDocConfWrapper.h index 50155baf..2f860959 100644 --- a/Modules/LibdigidocLib/Sources/LibdigidocObjC/include/Conf/DigiDocConfWrapper.h +++ b/Modules/LibdigidocLib/Sources/LibdigidocObjC/include/Conf/DigiDocConfWrapper.h @@ -30,7 +30,7 @@ NS_ASSUME_NONNULL_BEGIN @interface DigiDocConfWrapper : NSObject -- (void)initWithConf:(DigiDocConfig *)conf completion:(void (^)(BOOL, NSError * _Nullable))completion; +- (void)initWithConf:(DigiDocConfig *)conf userAgent:(NSString *)userAgent completion:(void (^)(BOOL, NSError * _Nullable))completion; - (void)updateConfiguration:(DigiDocConfig *)conf; - (void)setSiVaUrl:(NSURL * _Nullable)url; - (void)addSiVaCert:(NSData * _Nullable)cert; diff --git a/Modules/LibdigidocLib/Sources/LibdigidocObjC/include/Conf/DigiDocConfWrapper.mm b/Modules/LibdigidocLib/Sources/LibdigidocObjC/include/Conf/DigiDocConfWrapper.mm index 520a01e2..14ee7068 100644 --- a/Modules/LibdigidocLib/Sources/LibdigidocObjC/include/Conf/DigiDocConfWrapper.mm +++ b/Modules/LibdigidocLib/Sources/LibdigidocObjC/include/Conf/DigiDocConfWrapper.mm @@ -229,13 +229,14 @@ static void withCurrentConf(Func&& fn) { } public: - static void initConf(DigiDocConfig *conf, void (^completion)(NSError * _Nullable error)) { + static void initConf(DigiDocConfig *conf, NSString *userAgent, void (^completion)(NSError * _Nullable error)) { dispatch_async(dispatch_get_main_queue(), ^{ NSError *error = nil; try { + std::string userAgentInfo = userAgent.UTF8String; DigiDocConfCurrent *currentConf = new DigiDocConfCurrent(conf); digidoc::Conf::init(currentConf); - digidoc::initialize("RIA DigiDoc 3.0", "RIA DigiDoc"); + digidoc::initialize(userAgentInfo, userAgentInfo); } catch (const digidoc::Exception &e) { std::vector causes = e.causes(); NSDictionary *userInfo = @{ @@ -318,11 +319,11 @@ - (instancetype)init { return self; } -- (void)initWithConf:(DigiDocConfig *)conf completion:(void (^)(BOOL, NSError * _Nullable))completion { +- (void)initWithConf:(DigiDocConfig *)conf userAgent:(NSString *)userAgent completion:(void (^)(BOOL, NSError * _Nullable))completion { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSError *error = nil; try { - DigiDocConfWrapperImpl::initConf(conf, ^(NSError *error) { + DigiDocConfWrapperImpl::initConf(conf, userAgent, ^(NSError *error) { if (error) { error = [NSError errorWithDomain:@"LibdigidocLib" code:1 diff --git a/Modules/LibdigidocLib/Sources/LibdigidocSwift/Domain/Conf/DigiDocConf.swift b/Modules/LibdigidocLib/Sources/LibdigidocSwift/Domain/Conf/DigiDocConf.swift index 5b109d20..b266b445 100644 --- a/Modules/LibdigidocLib/Sources/LibdigidocSwift/Domain/Conf/DigiDocConf.swift +++ b/Modules/LibdigidocLib/Sources/LibdigidocSwift/Domain/Conf/DigiDocConf.swift @@ -40,11 +40,13 @@ public struct DigiDocConf: DigiDocConfProtocol, Loggable { sivaOption: ServicesSettingsOption? = nil, sivaUrl: URL? = nil, sivaCert: Data? = nil, - proxyInfo: ProxyInfo? = nil + proxyInfo: ProxyInfo? = nil, + userAgent: String ) async throws { try await sharedInitializer.initializeDigiDoc( configuration: configuration, - isLoggingEnabled: isLoggingEnabled + isLoggingEnabled: isLoggingEnabled, + userAgent: userAgent ) if let tsaOption { @@ -187,7 +189,11 @@ public actor DigiDocInitializer: Loggable { self.fileManager = fileManager } - func initializeDigiDoc(configuration: ConfigurationProvider? = nil, isLoggingEnabled: Bool) async throws { + func initializeDigiDoc( + configuration: ConfigurationProvider? = nil, + isLoggingEnabled: Bool, + userAgent: String + ) async throws { guard !isInitialized else { throw DigiDocError.alreadyInitialized @@ -202,11 +208,15 @@ public actor DigiDocInitializer: Loggable { logFile: overrideLogFile(), tslCache: overrideTSLCache(), configurationProvider: customConf - ) + ), + userAgent: userAgent ) } else { digidocConf.logLevel = overrideLogLevel(logLevel: logLevel) - try await initDigiDoc(conf: digidocConf) + try await initDigiDoc( + conf: digidocConf, + userAgent: userAgent + ) } isInitialized = true } @@ -298,10 +308,11 @@ public actor DigiDocInitializer: Loggable { private func initDigiDoc( conf digiDocConf: DigiDocConfig, - digidocConfWrapper: DigiDocConfWrapper = DigiDocConfWrapper() + digidocConfWrapper: DigiDocConfWrapper = DigiDocConfWrapper(), + userAgent: String ) async throws { do { - let isInitialized = try await digidocConfWrapper.initWithConf(digiDocConf) + let isInitialized = try await digidocConfWrapper.initWithConf(digiDocConf, userAgent: userAgent) guard isInitialized, DigiDocConfWrapper.sharedInstance() != nil else { throw DigiDocError.initializationFailed( diff --git a/Modules/LibdigidocLib/Tests/LibdigidocLibTests/LibdigidocSwift/Conf/DigiDocConfTests.swift b/Modules/LibdigidocLib/Tests/LibdigidocLibTests/LibdigidocSwift/Conf/DigiDocConfTests.swift index 2a4764c6..0603fa21 100644 --- a/Modules/LibdigidocLib/Tests/LibdigidocLibTests/LibdigidocSwift/Conf/DigiDocConfTests.swift +++ b/Modules/LibdigidocLib/Tests/LibdigidocLibTests/LibdigidocSwift/Conf/DigiDocConfTests.swift @@ -43,17 +43,25 @@ final class DigiDocConfTests { try await mockConfigurationLoader.initConfiguration( cacheDir: URL(fileURLWithPath: "/mock/path"), - proxyInfo: ProxyInfo() + proxyInfo: ProxyInfo(), + userAgent: "TestUserAgent" ) } @Test func initDigiDoc_successAndReInitialization() async { do { - try await DigiDocConf.initDigiDoc(configuration: configurationProvider) + try await DigiDocConf.initDigiDoc( + configuration: configurationProvider, + userAgent: "TestUserAgent" + ) + #expect(true) - try await DigiDocConf.initDigiDoc(configuration: configurationProvider) + try await DigiDocConf.initDigiDoc( + configuration: configurationProvider, + userAgent: "TestUserAgent" + ) Issue.record("Expected DigiDocError.alreadyInitialized to be thrown") return diff --git a/Modules/LibdigidocLib/Tests/LibdigidocLibTests/LibdigidocSwift/Container/ContainerWrapperTests.swift b/Modules/LibdigidocLib/Tests/LibdigidocLibTests/LibdigidocSwift/Container/ContainerWrapperTests.swift index 5071150a..cadf9e57 100644 --- a/Modules/LibdigidocLib/Tests/LibdigidocLibTests/LibdigidocSwift/Container/ContainerWrapperTests.swift +++ b/Modules/LibdigidocLib/Tests/LibdigidocLibTests/LibdigidocSwift/Container/ContainerWrapperTests.swift @@ -55,8 +55,15 @@ struct ContainerWrapperTests { configurationProvider = try TestConfigurationProviderUtil.getConfigurationProvider() do { - try await DigiDocConf.initDigiDoc(configuration: configurationProvider) - try await DigiDocConf.initDigiDoc(configuration: configurationProvider) + try await DigiDocConf.initDigiDoc( + configuration: configurationProvider, + userAgent: "TestUserAgent" + ) + + try await DigiDocConf.initDigiDoc( + configuration: configurationProvider, + userAgent: "TestUserAgent" + ) } catch let error as DigiDocError { switch error { case .alreadyInitialized: diff --git a/Modules/LibdigidocLib/Tests/LibdigidocLibTests/LibdigidocSwift/SignedContainerTests.swift b/Modules/LibdigidocLib/Tests/LibdigidocLibTests/LibdigidocSwift/SignedContainerTests.swift index 69716fa0..12f7dcbc 100644 --- a/Modules/LibdigidocLib/Tests/LibdigidocLibTests/LibdigidocSwift/SignedContainerTests.swift +++ b/Modules/LibdigidocLib/Tests/LibdigidocLibTests/LibdigidocSwift/SignedContainerTests.swift @@ -49,7 +49,7 @@ final class SignedContainerTests { configurationProvider = try TestConfigurationProviderUtil.getConfigurationProvider() do { - try await DigiDocConf.initDigiDoc(configuration: configurationProvider) + try await DigiDocConf.initDigiDoc(configuration: configurationProvider, userAgent: "TestUserAgent") } catch let error as DigiDocError { switch error { case .alreadyInitialized: diff --git a/Modules/MobileIdLib/Sources/MobileIdLib/Service/MobileIdSignService.swift b/Modules/MobileIdLib/Sources/MobileIdLib/Service/MobileIdSignService.swift index 480825ea..244131b1 100644 --- a/Modules/MobileIdLib/Sources/MobileIdLib/Service/MobileIdSignService.swift +++ b/Modules/MobileIdLib/Sources/MobileIdLib/Service/MobileIdSignService.swift @@ -34,7 +34,8 @@ actor MobileIdSignService: MobileIdSignServiceProtocol, Loggable { phoneNumber: String, nationalIdentityNumber: String, trustedCertificates: [SecCertificate], - proxyInfo: ProxyInfo + proxyInfo: ProxyInfo, + userAgent: String ) async throws -> MobileIdCertificateResponse { let request = MobileIdCertificateRequest( relyingPartyName: relyingPartyName, @@ -48,7 +49,8 @@ actor MobileIdSignService: MobileIdSignServiceProtocol, Loggable { method: .post, parameters: request, trustedCertificates: trustedCertificates, - proxyInfo: proxyInfo + proxyInfo: proxyInfo, + userAgent: userAgent ) } @@ -65,7 +67,8 @@ actor MobileIdSignService: MobileIdSignServiceProtocol, Loggable { displayText: String, displayTextFormat: String, trustedCertificates: [SecCertificate], - proxyInfo: ProxyInfo + proxyInfo: ProxyInfo, + userAgent: String ) async throws -> MobileIdSignatureResponse { let request = MobileIdSignatureRequest( certificateRequest: .init( @@ -86,16 +89,19 @@ actor MobileIdSignService: MobileIdSignServiceProtocol, Loggable { method: .post, parameters: request, trustedCertificates: trustedCertificates, - proxyInfo: proxyInfo + proxyInfo: proxyInfo, + userAgent: userAgent ) } + // swiftlint:disable:next function_parameter_count public func getSessionRequest( url: String, sessionId: String, pollingTimeout: Int, trustedCertificates: [SecCertificate], - proxyInfo: ProxyInfo + proxyInfo: ProxyInfo, + userAgent: String ) async throws -> MobileIdSessionResponse { let pollingTimeoutMs = pollingTimeout * 1000 @@ -105,7 +111,8 @@ actor MobileIdSignService: MobileIdSignServiceProtocol, Loggable { method: .get, parameters: ["timeoutMs": pollingTimeoutMs], trustedCertificates: trustedCertificates, - proxyInfo: proxyInfo + proxyInfo: proxyInfo, + userAgent: userAgent ) if let response = sessionResponse, @@ -128,7 +135,8 @@ actor MobileIdSignService: MobileIdSignServiceProtocol, Loggable { method: HTTPMethod, parameters: P? = nil, trustedCertificates: [SecCertificate], - proxyInfo: ProxyInfo + proxyInfo: ProxyInfo, + userAgent: String ) async throws -> T { let encoder: ParameterEncoder = method == .get ? URLEncodedFormParameterEncoder.default : @@ -138,16 +146,15 @@ actor MobileIdSignService: MobileIdSignServiceProtocol, Loggable { let session = try await ensureSession( url: url, trustedCertificates: trustedCertificates, - proxyInfo: proxyInfo + proxyInfo: proxyInfo, + userAgent: userAgent ) - let headers = MobileIdSignService.defaultHeaders() let response = await session.request( url, method: method, parameters: parameters, - encoder: encoder, - headers: headers + encoder: encoder ) .validate() .serializingDecodable(T.self) @@ -174,7 +181,8 @@ actor MobileIdSignService: MobileIdSignServiceProtocol, Loggable { private func ensureSession( url: String, trustedCertificates: [SecCertificate], - proxyInfo: ProxyInfo + proxyInfo: ProxyInfo, + userAgent: String ) async throws -> Session { if currentProxy == proxyInfo { if let existing = session { return existing } @@ -191,33 +199,34 @@ actor MobileIdSignService: MobileIdSignServiceProtocol, Loggable { let newSession = MobileIdSignService.createAlamofireSession( host: host, - trustedCertificates: trustedCertificates, - proxyInfo: proxyInfo + proxyInfo: proxyInfo, + userAgent: userAgent, + trustedCertificates: trustedCertificates ) session = newSession return newSession } - private static func defaultHeaders() -> HTTPHeaders { - [ - .contentType("application/json; charset=utf-8"), - .init(name: "Cache-Control", value: "no-cache"), - .init(name: "Pragma", value: "no-cache") - ] - } - private static func createAlamofireSession( host: String, - trustedCertificates: [SecCertificate], - proxyInfo: ProxyInfo + proxyInfo: ProxyInfo, + userAgent: String, + trustedCertificates: [SecCertificate] ) -> Session { let evaluators = [host: PinnedCertificatesTrustEvaluator(certificates: trustedCertificates)] - let config = URLSessionConfiguration.default + let config = URLSessionConfiguration.af.default config.timeoutIntervalForRequest = TimeInterval(Constants.Signing.Timeout) config.timeoutIntervalForResource = TimeInterval(Constants.Signing.Timeout) config.requestCachePolicy = .reloadIgnoringLocalAndRemoteCacheData config.urlCache = nil + var headers = config.httpAdditionalHeaders ?? [:] + headers["User-Agent"] = userAgent + headers["Content-Type"] = "application/json; charset=utf-8" + headers["Cache-Control"] = "no-cache" + headers["Pragma"] = "no-cache" + config.httpAdditionalHeaders = headers + return Session.withProxy( proxyInfo: proxyInfo, configuration: config, diff --git a/Modules/MobileIdLib/Sources/MobileIdLib/Service/MobileIdSignServiceProtocol.swift b/Modules/MobileIdLib/Sources/MobileIdLib/Service/MobileIdSignServiceProtocol.swift index 87392783..4e9a4a16 100644 --- a/Modules/MobileIdLib/Sources/MobileIdLib/Service/MobileIdSignServiceProtocol.swift +++ b/Modules/MobileIdLib/Sources/MobileIdLib/Service/MobileIdSignServiceProtocol.swift @@ -31,7 +31,8 @@ public protocol MobileIdSignServiceProtocol: Sendable { phoneNumber: String, nationalIdentityNumber: String, trustedCertificates: [SecCertificate], - proxyInfo: ProxyInfo + proxyInfo: ProxyInfo, + userAgent: String ) async throws -> MobileIdCertificateResponse func getSignatureRequest( @@ -46,7 +47,8 @@ public protocol MobileIdSignServiceProtocol: Sendable { displayText: String, displayTextFormat: String, trustedCertificates: [SecCertificate], - proxyInfo: ProxyInfo + proxyInfo: ProxyInfo, + userAgent: String ) async throws -> MobileIdSignatureResponse func getSessionRequest( @@ -54,7 +56,8 @@ public protocol MobileIdSignServiceProtocol: Sendable { sessionId: String, pollingTimeout: Int, trustedCertificates: [SecCertificate], - proxyInfo: ProxyInfo + proxyInfo: ProxyInfo, + userAgent: String ) async throws -> MobileIdSessionResponse func getVerificationCode(hash: Data) async -> String? diff --git a/Modules/SmartIdLib/Sources/SmartIdLib/Service/SmartIdSignService.swift b/Modules/SmartIdLib/Sources/SmartIdLib/Service/SmartIdSignService.swift index a72ae9ef..6e7b9599 100644 --- a/Modules/SmartIdLib/Sources/SmartIdLib/Service/SmartIdSignService.swift +++ b/Modules/SmartIdLib/Sources/SmartIdLib/Service/SmartIdSignService.swift @@ -35,7 +35,8 @@ public actor SmartIdSignService: SmartIdSignServiceProtocol, Loggable { country: String, nationalIdentityNumber: String, trustedCertificates: [SecCertificate], - proxyInfo: ProxyInfo + proxyInfo: ProxyInfo, + userAgent: String ) async throws -> SmartIdSessionIdResponse { let request = SmartIdCertificateRequest( relyingPartyName: relyingPartyName, @@ -49,7 +50,8 @@ public actor SmartIdSignService: SmartIdSignServiceProtocol, Loggable { method: .post, parameters: request, trustedCertificates: trustedCertificates, - proxyInfo: proxyInfo + proxyInfo: proxyInfo, + userAgent: userAgent ) } @@ -64,7 +66,8 @@ public actor SmartIdSignService: SmartIdSignServiceProtocol, Loggable { allowedInteractionsOrderType: String, displayText200: String, trustedCertificates: [SecCertificate], - proxyInfo: ProxyInfo + proxyInfo: ProxyInfo, + userAgent: String ) async throws -> SmartIdSessionIdResponse { let request = SmartIdSignatureRequest( relyingPartyName: relyingPartyName, @@ -82,16 +85,19 @@ public actor SmartIdSignService: SmartIdSignServiceProtocol, Loggable { method: .post, parameters: request, trustedCertificates: trustedCertificates, - proxyInfo: proxyInfo + proxyInfo: proxyInfo, + userAgent: userAgent ) } + // swiftlint:disable:next function_parameter_count public func getSessionRequest( url: String, sessionId: String, pollingTimeout: Int, trustedCertificates: [SecCertificate], - proxyInfo: ProxyInfo + proxyInfo: ProxyInfo, + userAgent: String ) async throws -> SmartIdSessionResponse { let pollingTimeoutMs = pollingTimeout * 1000 @@ -101,7 +107,8 @@ public actor SmartIdSignService: SmartIdSignServiceProtocol, Loggable { method: .get, parameters: ["timeoutMs": pollingTimeoutMs], trustedCertificates: trustedCertificates, - proxyInfo: proxyInfo + proxyInfo: proxyInfo, + userAgent: userAgent ) if let response = sessionResponse, @@ -123,7 +130,8 @@ public actor SmartIdSignService: SmartIdSignServiceProtocol, Loggable { method: HTTPMethod, parameters: P? = nil, trustedCertificates: [SecCertificate], - proxyInfo: ProxyInfo + proxyInfo: ProxyInfo, + userAgent: String ) async throws -> T { return try await withCheckedThrowingContinuation { continuation in Task { @@ -135,16 +143,15 @@ public actor SmartIdSignService: SmartIdSignServiceProtocol, Loggable { let session = try await ensureSession( url: url, trustedCertificates: trustedCertificates, - proxyInfo: proxyInfo + proxyInfo: proxyInfo, + userAgent: userAgent ) - let headers = SmartIdSignService.defaultHeaders() let response = await session.request( url, method: method, parameters: parameters, - encoder: encoder, - headers: headers + encoder: encoder ) .validate() .serializingDecodable(T.self) @@ -191,18 +198,11 @@ public actor SmartIdSignService: SmartIdSignServiceProtocol, Loggable { } } - private static func defaultHeaders() -> HTTPHeaders { - [ - .contentType("application/json; charset=utf-8"), - .init(name: "Cache-Control", value: "no-cache"), - .init(name: "Pragma", value: "no-cache") - ] - } - private func ensureSession( url: String, trustedCertificates: [SecCertificate], - proxyInfo: ProxyInfo + proxyInfo: ProxyInfo, + userAgent: String, ) async throws -> Session { if currentProxy == proxyInfo { if let existing = session { return existing } @@ -220,7 +220,8 @@ public actor SmartIdSignService: SmartIdSignServiceProtocol, Loggable { let newSession = SmartIdSignService.createAlamofireSession( host: host, trustedCertificates: trustedCertificates, - proxyInfo: proxyInfo + proxyInfo: proxyInfo, + userAgent: userAgent ) session = newSession @@ -230,16 +231,24 @@ public actor SmartIdSignService: SmartIdSignServiceProtocol, Loggable { private static func createAlamofireSession( host: String, trustedCertificates: [SecCertificate], - proxyInfo: ProxyInfo + proxyInfo: ProxyInfo, + userAgent: String ) -> Session { let evaluators = [host: PinnedCertificatesTrustEvaluator(certificates: trustedCertificates)] - let config = URLSessionConfiguration.default + let config = URLSessionConfiguration.af.default config.timeoutIntervalForRequest = TimeInterval(Constants.Signing.Timeout) config.timeoutIntervalForResource = TimeInterval(Constants.Signing.Timeout) config.requestCachePolicy = .reloadIgnoringLocalAndRemoteCacheData config.urlCache = nil + var headers = config.httpAdditionalHeaders ?? [:] + headers["User-Agent"] = userAgent + headers["Content-Type"] = "application/json; charset=utf-8" + headers["Cache-Control"] = "no-cache" + headers["Pragma"] = "no-cache" + config.httpAdditionalHeaders = headers + return Session.withProxy( proxyInfo: proxyInfo, configuration: config, diff --git a/Modules/SmartIdLib/Sources/SmartIdLib/Service/SmartIdSignServiceProtocol.swift b/Modules/SmartIdLib/Sources/SmartIdLib/Service/SmartIdSignServiceProtocol.swift index e01570cd..e38eeba4 100644 --- a/Modules/SmartIdLib/Sources/SmartIdLib/Service/SmartIdSignServiceProtocol.swift +++ b/Modules/SmartIdLib/Sources/SmartIdLib/Service/SmartIdSignServiceProtocol.swift @@ -31,7 +31,8 @@ public protocol SmartIdSignServiceProtocol: Sendable { country: String, nationalIdentityNumber: String, trustedCertificates: [SecCertificate], - proxyInfo: ProxyInfo + proxyInfo: ProxyInfo, + userAgent: String ) async throws -> SmartIdSessionIdResponse func getSignatureRequest( @@ -44,7 +45,8 @@ public protocol SmartIdSignServiceProtocol: Sendable { allowedInteractionsOrderType: String, displayText200: String, trustedCertificates: [SecCertificate], - proxyInfo: ProxyInfo + proxyInfo: ProxyInfo, + userAgent: String ) async throws -> SmartIdSessionIdResponse func getSessionRequest( @@ -52,7 +54,8 @@ public protocol SmartIdSignServiceProtocol: Sendable { sessionId: String, pollingTimeout: Int, trustedCertificates: [SecCertificate], - proxyInfo: ProxyInfo + proxyInfo: ProxyInfo, + userAgent: String ) async throws -> SmartIdSessionResponse func getVerificationCode(digest: Data) async -> String diff --git a/Modules/Test/CommonsTestShared/Sources/CommonsTestShared/File/TestFileUtil.swift b/Modules/Test/CommonsTestShared/Sources/CommonsTestShared/File/TestFileUtil.swift index 46a6bb05..7f4240b7 100644 --- a/Modules/Test/CommonsTestShared/Sources/CommonsTestShared/File/TestFileUtil.swift +++ b/Modules/Test/CommonsTestShared/Sources/CommonsTestShared/File/TestFileUtil.swift @@ -18,17 +18,20 @@ */ import Foundation +import OSLog import FactoryKit import CommonsLib -public struct TestFileUtil: Loggable { - private static let bundleIdentifier = Bundle.main.bundleIdentifier ?? "ee.ria.digidoc" +public struct TestFileUtil { + private static let logger = Logger(subsystem: "ee.ria.digidoc.CommonsTestShared", category: "TestFileUtil") + + private static let bundleIdentifier = Bundle.main.bundleIdentifier ?? "ee.ria.digidoc" public init() {} public static func getURL(string: String) throws -> URL { guard let url = URL(string: string) else { - TestFileUtil.logger().error("'\(string)' is not a valid URL") + TestFileUtil.logger.error("'\(string)' is not a valid URL") throw URLError(.badURL) } return url @@ -51,7 +54,7 @@ public struct TestFileUtil: Loggable { ) } } catch { - logger().error( + TestFileUtil.logger.error( "Unable to create temporary file directory or remove existing file: \(error.localizedDescription)" ) } @@ -78,7 +81,7 @@ public struct TestFileUtil: Loggable { ) if !isCreated { - logger().error( + TestFileUtil.logger.error( "Unable to create file at path: \(tempFileDirectory.standardizedFileURL.path(percentEncoded: false))" ) } diff --git a/Modules/Test/CommonsTestShared/Sources/CommonsTestShared/Url/MockURLProtocol.swift b/Modules/Test/CommonsTestShared/Sources/CommonsTestShared/Url/MockURLProtocol.swift index 8ccb2f8d..a4116c78 100644 --- a/Modules/Test/CommonsTestShared/Sources/CommonsTestShared/Url/MockURLProtocol.swift +++ b/Modules/Test/CommonsTestShared/Sources/CommonsTestShared/Url/MockURLProtocol.swift @@ -19,11 +19,13 @@ // swiftlint:disable static_over_final_class unused_parameter -import CommonsLib import Foundation +import OSLog import Alamofire public final class MockURLProtocol: URLProtocol { + private static let logger = Logger(subsystem: "ee.ria.digidoc.CommonsTestShared", category: "MockURLProtocol") + public typealias Handler = @Sendable (URLRequest) throws -> (HTTPURLResponse, Data) static let handlerKey = "MockURLProtocol.HandlerKey" @@ -56,7 +58,9 @@ public final class MockURLProtocol: URLProtocol { public override func stopLoading() { } } -final class MockInterceptor: RequestInterceptor, Loggable { +final class MockInterceptor: RequestInterceptor { + private static let logger = Logger(subsystem: "ee.ria.digidoc.CommonsTestShared", category: "MockInterceptor") + let handler: MockURLProtocol.Handler init(handler: @escaping MockURLProtocol.Handler) { @@ -71,7 +75,7 @@ final class MockInterceptor: RequestInterceptor, Loggable { let mutableRequest = (urlRequest as NSURLRequest).mutableCopy() as? NSMutableURLRequest guard let request = mutableRequest else { - MockInterceptor.logger().error("Unable to get mutable URLRequest") + MockInterceptor.logger.error("Unable to get mutable URLRequest") return } diff --git a/Modules/CommonsLib/Sources/CommonsLib/Bundle/BundleUtil.swift b/Modules/UtilsLib/Sources/UtilsLib/Bundle/BundleUtil.swift similarity index 100% rename from Modules/CommonsLib/Sources/CommonsLib/Bundle/BundleUtil.swift rename to Modules/UtilsLib/Sources/UtilsLib/Bundle/BundleUtil.swift diff --git a/Modules/UtilsLib/Sources/UtilsLib/DI/UtilsLibContainer.swift b/Modules/UtilsLib/Sources/UtilsLib/DI/UtilsLibContainer.swift index caf80db3..fd8474b4 100644 --- a/Modules/UtilsLib/Sources/UtilsLib/DI/UtilsLibContainer.swift +++ b/Modules/UtilsLib/Sources/UtilsLib/DI/UtilsLibContainer.swift @@ -54,4 +54,8 @@ extension Container { public var notificationUtil: Factory { self { @MainActor in NotificationUtil() } } + + public var userAgentUtil: Factory { + self { UserAgentUtil() } + } } diff --git a/Modules/UtilsLib/Sources/UtilsLib/Extensions/SessionExtensions.swift b/Modules/UtilsLib/Sources/UtilsLib/Extensions/SessionExtensions.swift index d141fbda..3a751a17 100644 --- a/Modules/UtilsLib/Sources/UtilsLib/Extensions/SessionExtensions.swift +++ b/Modules/UtilsLib/Sources/UtilsLib/Extensions/SessionExtensions.swift @@ -29,7 +29,7 @@ extension Session { interceptor: RequestInterceptor? = nil, serverTrustManager: ServerTrustManager? = nil ) -> Session { - let configuration = configuration ?? URLSessionConfiguration.default + let configuration = configuration ?? URLSessionConfiguration.af.default if proxyInfo.option != .disabled, !proxyInfo.host.isEmpty { configuration.requestCachePolicy = URLRequest.CachePolicy.reloadIgnoringLocalCacheData diff --git a/Modules/CommonsLib/Sources/CommonsLib/Logging/Loggable.swift b/Modules/UtilsLib/Sources/UtilsLib/Logging/Loggable.swift similarity index 100% rename from Modules/CommonsLib/Sources/CommonsLib/Logging/Loggable.swift rename to Modules/UtilsLib/Sources/UtilsLib/Logging/Loggable.swift diff --git a/Modules/CommonsLib/Sources/CommonsLib/Logging/LoggingConfiguration.swift b/Modules/UtilsLib/Sources/UtilsLib/Logging/LoggingConfiguration.swift similarity index 100% rename from Modules/CommonsLib/Sources/CommonsLib/Logging/LoggingConfiguration.swift rename to Modules/UtilsLib/Sources/UtilsLib/Logging/LoggingConfiguration.swift diff --git a/Modules/CommonsLib/Sources/CommonsLib/Logging/LoggingSystem.swift b/Modules/UtilsLib/Sources/UtilsLib/Logging/LoggingSystem.swift similarity index 100% rename from Modules/CommonsLib/Sources/CommonsLib/Logging/LoggingSystem.swift rename to Modules/UtilsLib/Sources/UtilsLib/Logging/LoggingSystem.swift diff --git a/Modules/UtilsLib/Sources/UtilsLib/Model/UserAgentDiagnostics.swift b/Modules/UtilsLib/Sources/UtilsLib/Model/UserAgentDiagnostics.swift new file mode 100644 index 00000000..17b98051 --- /dev/null +++ b/Modules/UtilsLib/Sources/UtilsLib/Model/UserAgentDiagnostics.swift @@ -0,0 +1,26 @@ +/* + * Copyright 2017 - 2025 Riigi Infosüsteemi Amet + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +import Foundation + +public enum UserAgentDiagnostics: Sendable { + case none + case devices + case nfc +} diff --git a/Modules/CommonsLib/Sources/CommonsLib/System/SystemUtil.swift b/Modules/UtilsLib/Sources/UtilsLib/System/SystemUtil.swift similarity index 100% rename from Modules/CommonsLib/Sources/CommonsLib/System/SystemUtil.swift rename to Modules/UtilsLib/Sources/UtilsLib/System/SystemUtil.swift diff --git a/Modules/UtilsLib/Sources/UtilsLib/User-Agent/UserAgentUtil.swift b/Modules/UtilsLib/Sources/UtilsLib/User-Agent/UserAgentUtil.swift new file mode 100644 index 00000000..e707a897 --- /dev/null +++ b/Modules/UtilsLib/Sources/UtilsLib/User-Agent/UserAgentUtil.swift @@ -0,0 +1,78 @@ +/* + * Copyright 2017 - 2025 Riigi Infosüsteemi Amet + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +import Foundation +import UIKit +import ExternalAccessory + +public struct UserAgentUtil: UserAgentUtilProtocol { + + public func userAgent( + diagnostics: UserAgentDiagnostics = .none, + language: String + ) -> String { + var components: [String] = [ + appIdentifier(), + osInfo(), + languageInfo(language: language) + ] + + switch diagnostics { + case .none: + break + + case .devices: + if let devicesInfo = devicesInfo() { + components.append(devicesInfo) + } + + case .nfc: + components.append("NFC: true") + } + + return components.joined(separator: " ") + } + + private func appIdentifier() -> String { + "riadigidoc/\(appVersion())" + } + + private func osInfo() -> String { + "(iOS \(SystemUtil.getOSVersion()))" + } + + private func languageInfo(language: String) -> String { + return "Lang: \(language)" + } + + private func appVersion() -> String { + return BundleUtil.getAppVersion() + } + + private func devicesInfo() -> String? { + let devices = EAAccessoryManager.shared() + .connectedAccessories + .map { + "\($0.manufacturer) \($0.name) (\($0.modelNumber))" + } + + guard !devices.isEmpty else { return nil } + return "Devices: \(devices.joined(separator: ", "))" + } +} diff --git a/Modules/UtilsLib/Sources/UtilsLib/User-Agent/UserAgentUtilProtocol.swift b/Modules/UtilsLib/Sources/UtilsLib/User-Agent/UserAgentUtilProtocol.swift new file mode 100644 index 00000000..0516cee5 --- /dev/null +++ b/Modules/UtilsLib/Sources/UtilsLib/User-Agent/UserAgentUtilProtocol.swift @@ -0,0 +1,28 @@ +/* + * Copyright 2017 - 2025 Riigi Infosüsteemi Amet + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +import Foundation + +/// @mockable +public protocol UserAgentUtilProtocol: Sendable { + func userAgent( + diagnostics: UserAgentDiagnostics, + language: String + ) -> String +} diff --git a/Modules/CommonsLib/Tests/CommonsLibTests/Bundle/BundleUtilTests.swift b/Modules/UtilsLib/Tests/UtilsLibTests/Bundle/BundleUtilTests.swift similarity index 97% rename from Modules/CommonsLib/Tests/CommonsLibTests/Bundle/BundleUtilTests.swift rename to Modules/UtilsLib/Tests/UtilsLibTests/Bundle/BundleUtilTests.swift index 446ee50a..017548e5 100644 --- a/Modules/CommonsLib/Tests/CommonsLibTests/Bundle/BundleUtilTests.swift +++ b/Modules/UtilsLib/Tests/UtilsLibTests/Bundle/BundleUtilTests.swift @@ -20,9 +20,9 @@ import Foundation import Testing -@testable import CommonsLib +@testable import UtilsLib -final class BundleUtilTests { +struct BundleUtilTests { @Test func getBundleIdentifier_success() { diff --git a/Modules/CommonsLib/Tests/CommonsLibTests/System/SystemUtilTests.swift b/Modules/UtilsLib/Tests/UtilsLibTests/System/SystemUtilTests.swift similarity index 95% rename from Modules/CommonsLib/Tests/CommonsLibTests/System/SystemUtilTests.swift rename to Modules/UtilsLib/Tests/UtilsLibTests/System/SystemUtilTests.swift index 823f0688..0c743df2 100644 --- a/Modules/CommonsLib/Tests/CommonsLibTests/System/SystemUtilTests.swift +++ b/Modules/UtilsLib/Tests/UtilsLibTests/System/SystemUtilTests.swift @@ -20,9 +20,10 @@ import Foundation import Testing -@testable import CommonsLib +@testable import UtilsLib + +struct SystemUtilTests { -final class SystemUtilTests { @Test func getOSVersion_success() { let osVersion = SystemUtil.getOSVersion() diff --git a/Modules/UtilsLib/Tests/UtilsLibTests/User-Agent/UserAgentUtilTests.swift b/Modules/UtilsLib/Tests/UtilsLibTests/User-Agent/UserAgentUtilTests.swift new file mode 100644 index 00000000..52d8380b --- /dev/null +++ b/Modules/UtilsLib/Tests/UtilsLibTests/User-Agent/UserAgentUtilTests.swift @@ -0,0 +1,61 @@ +/* + * Copyright 2017 - 2025 Riigi Infosüsteemi Amet + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +import Foundation +import Testing + +@testable import UtilsLib + +struct UserAgentUtilTests { + + @Test( + "User-Agent contains expected info", + arguments: [ + (UserAgentDiagnostics.none, "en"), + (UserAgentDiagnostics.devices, "en"), + (UserAgentDiagnostics.nfc, "en"), + (UserAgentDiagnostics.none, "ee"), + (UserAgentDiagnostics.devices, "ee"), + (UserAgentDiagnostics.nfc, "ee") + ] + ) + func userAgent_containsExpectedUserAgentInfo(diagnostics: UserAgentDiagnostics, language: String) { + let userAgentUtil = UserAgentUtil() + + let userAgent = userAgentUtil.userAgent(diagnostics: diagnostics, language: language) + + #expect(userAgent.starts(with: "riadigidoc/")) + #expect(userAgent.contains("(iOS ")) + #expect(userAgent.contains("Lang: \(language)")) + + switch diagnostics { + case .none: + #expect(!userAgent.contains("Devices:")) + #expect(!userAgent.contains("NFC:")) + + case .devices: + #expect(userAgent.contains("Devices:") || !userAgent.contains("Devices:")) + #expect(!userAgent.contains("NFC:")) + + case .nfc: + #expect(!userAgent.contains("Devices:")) + #expect(userAgent.contains("NFC: true")) + } + } +} diff --git a/RIADigiDoc/DI/AppContainer.swift b/RIADigiDoc/DI/AppContainer.swift index 4633a0fa..0863aaec 100644 --- a/RIADigiDoc/DI/AppContainer.swift +++ b/RIADigiDoc/DI/AppContainer.swift @@ -37,7 +37,8 @@ extension Container { advancedSettingsRepository: self.advancedSettingsRepository(), keychainStore: self.keychainStore(), proxyUtil: self.proxyUtil(), - cryptoSetup: self.cryptoSetup() + cryptoSetup: self.cryptoSetup(), + userAgentUtil: self.userAgentUtil() ) } .shared @@ -250,7 +251,8 @@ extension Container { configurationRepository: self.configurationRepository(), tslUtil: self.tslUtil(), dataStore: self.dataStore(), - proxyUtil: self.proxyUtil() + proxyUtil: self.proxyUtil(), + userAgentUtil: self.userAgentUtil() ) } } @@ -317,7 +319,9 @@ extension Container { var proxySettingsViewModel: Factory { self { @MainActor in ProxySettingsViewModel( - proxyUtil: self.proxyUtil() + proxyUtil: self.proxyUtil(), + userAgentUtil: self.userAgentUtil(), + dataStore: self.dataStore() ) } } @@ -392,7 +396,8 @@ extension Container { mobileIdSignService: self.mobileIdSignService(), certificateUtil: self.certificateUtil(), dataStore: self.dataStore(), - proxyUtil: self.proxyUtil() + proxyUtil: self.proxyUtil(), + userAgentUtil: self.userAgentUtil() ) } } @@ -406,7 +411,8 @@ extension Container { certificateUtil: self.certificateUtil(), notificationUtil: self.notificationUtil(), dataStore: self.dataStore(), - proxyUtil: self.proxyUtil() + proxyUtil: self.proxyUtil(), + userAgentUtil: self.userAgentUtil() ) } } diff --git a/RIADigiDoc/Domain/Preferences/KeychainStore.swift b/RIADigiDoc/Domain/Preferences/KeychainStore.swift index e0138452..daa610a0 100644 --- a/RIADigiDoc/Domain/Preferences/KeychainStore.swift +++ b/RIADigiDoc/Domain/Preferences/KeychainStore.swift @@ -17,7 +17,7 @@ * */ -import CommonsLib +import UtilsLib import Foundation public actor KeychainStore: KeychainStoreProtocol, Loggable { diff --git a/RIADigiDoc/Info.plist b/RIADigiDoc/Info.plist index 9f64709c..49faa2bb 100644 --- a/RIADigiDoc/Info.plist +++ b/RIADigiDoc/Info.plist @@ -961,5 +961,10 @@ + UISupportedExternalAccessoryProtocols + + com.ftsafe.bR301 + com.ftsafe.iR301 + diff --git a/RIADigiDoc/LibrarySetup.swift b/RIADigiDoc/LibrarySetup.swift index fc5524d8..c698540a 100644 --- a/RIADigiDoc/LibrarySetup.swift +++ b/RIADigiDoc/LibrarySetup.swift @@ -36,6 +36,7 @@ actor LibrarySetup: Loggable { private let keychainStore: KeychainStoreProtocol private let proxyUtil: ProxyUtilProtocol private let cryptoSetup: CryptoSetupProtocol + private let userAgentUtil: UserAgentUtilProtocol init( configurationLoader: ConfigurationLoaderProtocol, @@ -46,7 +47,8 @@ actor LibrarySetup: Loggable { advancedSettingsRepository: AdvancedSettingsRepositoryProtocol, keychainStore: KeychainStoreProtocol, proxyUtil: ProxyUtilProtocol, - cryptoSetup: CryptoSetupProtocol + cryptoSetup: CryptoSetupProtocol, + userAgentUtil: UserAgentUtilProtocol ) { self.configurationLoader = configurationLoader self.configurationRepository = configurationRepository @@ -57,6 +59,7 @@ actor LibrarySetup: Loggable { self.keychainStore = keychainStore self.proxyUtil = proxyUtil self.cryptoSetup = cryptoSetup + self.userAgentUtil = userAgentUtil } func setupLibraries() async { @@ -65,6 +68,8 @@ actor LibrarySetup: Loggable { do { let proxyInfo = await proxyUtil.getProxyInfo() + let appLanguage = await dataStore.getSelectedLanguage() + let userAgent = userAgentUtil.userAgent(diagnostics: .none, language: appLanguage) try DigiDocConf.observeConfigurationUpdates( configurationRepository: configurationRepository @@ -85,7 +90,8 @@ actor LibrarySetup: Loggable { do { try await configurationLoader.initConfiguration( cacheDir: configDirectory, - proxyInfo: proxyInfo + proxyInfo: proxyInfo, + userAgent: userAgent ) } catch { LibrarySetup.logger().error("Unable to initialize configuration: \(error)") @@ -100,7 +106,8 @@ actor LibrarySetup: Loggable { sivaOption: getSiVaOption(), sivaUrl: getSiVaUrl(), sivaCert: getSiVaCert(), - proxyInfo: proxyInfo + proxyInfo: proxyInfo, + userAgent: userAgent ) LibrarySetup.logger().info("Libdigidocpp initialized successfully") diff --git a/RIADigiDoc/UI/Component/HomeView/HomeHeader.swift b/RIADigiDoc/UI/Component/HomeView/HomeHeader.swift index 68cb7607..e2f6092b 100644 --- a/RIADigiDoc/UI/Component/HomeView/HomeHeader.swift +++ b/RIADigiDoc/UI/Component/HomeView/HomeHeader.swift @@ -18,7 +18,7 @@ */ import SwiftUI -import CommonsLib +import UtilsLib import FactoryKit struct HomeHeader: View { diff --git a/RIADigiDoc/UI/Component/InfoView/InfoHeaderTextComponent.swift b/RIADigiDoc/UI/Component/InfoView/InfoHeaderTextComponent.swift index 0ff8f5a8..efb8fed3 100644 --- a/RIADigiDoc/UI/Component/InfoView/InfoHeaderTextComponent.swift +++ b/RIADigiDoc/UI/Component/InfoView/InfoHeaderTextComponent.swift @@ -18,7 +18,7 @@ */ import SwiftUI -import CommonsLib +import UtilsLib import FactoryKit struct InfoHeaderTextComponent: View { diff --git a/RIADigiDoc/ViewModel/AdvancedSettingsViewModel.swift b/RIADigiDoc/ViewModel/AdvancedSettingsViewModel.swift index 8926f299..5eebd4f2 100644 --- a/RIADigiDoc/ViewModel/AdvancedSettingsViewModel.swift +++ b/RIADigiDoc/ViewModel/AdvancedSettingsViewModel.swift @@ -21,6 +21,7 @@ import CommonsLib import ConfigLib import Foundation import LibdigidocLibSwift +import UtilsLib @Observable @MainActor diff --git a/RIADigiDoc/ViewModel/DiagnosticsViewModel.swift b/RIADigiDoc/ViewModel/DiagnosticsViewModel.swift index 1a783c69..94c2f2c6 100644 --- a/RIADigiDoc/ViewModel/DiagnosticsViewModel.swift +++ b/RIADigiDoc/ViewModel/DiagnosticsViewModel.swift @@ -45,6 +45,7 @@ class DiagnosticsViewModel: DiagnosticsViewModelProtocol, Loggable { private let tslUtil: TSLUtilProtocol private let dataStore: DataStoreProtocol private let proxyUtil: ProxyUtilProtocol + private let userAgentUtil: UserAgentUtilProtocol private var configurationObservationTask: Task? @@ -55,7 +56,8 @@ class DiagnosticsViewModel: DiagnosticsViewModelProtocol, Loggable { configurationRepository: ConfigurationRepositoryProtocol, tslUtil: TSLUtilProtocol, dataStore: DataStoreProtocol, - proxyUtil: ProxyUtilProtocol + proxyUtil: ProxyUtilProtocol, + userAgentUtil: UserAgentUtilProtocol ) { self.containerWrapper = containerWrapper self.fileManager = fileManager @@ -64,6 +66,7 @@ class DiagnosticsViewModel: DiagnosticsViewModelProtocol, Loggable { self.tslUtil = tslUtil self.dataStore = dataStore self.proxyUtil = proxyUtil + self.userAgentUtil = userAgentUtil configurationObservationTask = Task { await observeConfigurationUpdates() @@ -297,9 +300,12 @@ class DiagnosticsViewModel: DiagnosticsViewModelProtocol, Loggable { CommonsLib.Constants.Configuration.CacheConfigFolder ) let proxyInfo = await proxyUtil.getProxyInfo() + let appLanguage = await dataStore.getSelectedLanguage() + let userAgent = userAgentUtil.userAgent(diagnostics: .none, language: appLanguage) try await configurationLoader.loadCentralConfiguration( cacheDir: configDirectory, - proxyInfo: proxyInfo + proxyInfo: proxyInfo, + userAgent: userAgent ) return true } catch { diff --git a/RIADigiDoc/ViewModel/EncryptRecipientViewModel.swift b/RIADigiDoc/ViewModel/EncryptRecipientViewModel.swift index 8803759a..a5711f8b 100644 --- a/RIADigiDoc/ViewModel/EncryptRecipientViewModel.swift +++ b/RIADigiDoc/ViewModel/EncryptRecipientViewModel.swift @@ -22,6 +22,7 @@ import FactoryKit import CommonsLib import CryptoSwift import CryptoObjCWrapper +import UtilsLib @Observable @MainActor diff --git a/RIADigiDoc/ViewModel/EncryptionSettingsViewModel.swift b/RIADigiDoc/ViewModel/EncryptionSettingsViewModel.swift index 182243e6..1913e87b 100644 --- a/RIADigiDoc/ViewModel/EncryptionSettingsViewModel.swift +++ b/RIADigiDoc/ViewModel/EncryptionSettingsViewModel.swift @@ -20,6 +20,7 @@ import CommonsLib import ConfigLib import Foundation +import UtilsLib @Observable @MainActor diff --git a/RIADigiDoc/ViewModel/InitViewModel.swift b/RIADigiDoc/ViewModel/InitViewModel.swift index ae97bfd4..971195ea 100644 --- a/RIADigiDoc/ViewModel/InitViewModel.swift +++ b/RIADigiDoc/ViewModel/InitViewModel.swift @@ -17,7 +17,7 @@ * */ -import CommonsLib +import UtilsLib import Foundation @MainActor diff --git a/RIADigiDoc/ViewModel/LanguageChooserViewModel.swift b/RIADigiDoc/ViewModel/LanguageChooserViewModel.swift index 8d0c9731..4c742ce0 100644 --- a/RIADigiDoc/ViewModel/LanguageChooserViewModel.swift +++ b/RIADigiDoc/ViewModel/LanguageChooserViewModel.swift @@ -17,7 +17,7 @@ * */ -import CommonsLib +import UtilsLib import Foundation @Observable diff --git a/RIADigiDoc/ViewModel/MobileIDSmartIDSettingsViewModel.swift b/RIADigiDoc/ViewModel/MobileIDSmartIDSettingsViewModel.swift index f8526fc6..4565c5c0 100644 --- a/RIADigiDoc/ViewModel/MobileIDSmartIDSettingsViewModel.swift +++ b/RIADigiDoc/ViewModel/MobileIDSmartIDSettingsViewModel.swift @@ -19,6 +19,7 @@ import CommonsLib import Foundation +import UtilsLib @Observable @MainActor diff --git a/RIADigiDoc/ViewModel/MyEid/MyEidRootViewModel.swift b/RIADigiDoc/ViewModel/MyEid/MyEidRootViewModel.swift index 6814f329..850b8f1b 100644 --- a/RIADigiDoc/ViewModel/MyEid/MyEidRootViewModel.swift +++ b/RIADigiDoc/ViewModel/MyEid/MyEidRootViewModel.swift @@ -20,6 +20,7 @@ import CommonsLib import Foundation import Observation +import UtilsLib @Observable @MainActor diff --git a/RIADigiDoc/ViewModel/ProxySettingsViewModel.swift b/RIADigiDoc/ViewModel/ProxySettingsViewModel.swift index b455abb5..5af71208 100644 --- a/RIADigiDoc/ViewModel/ProxySettingsViewModel.swift +++ b/RIADigiDoc/ViewModel/ProxySettingsViewModel.swift @@ -21,6 +21,7 @@ import Alamofire import CommonsLib import Foundation import LibdigidocLibSwift +import UtilsLib @Observable @MainActor @@ -30,11 +31,17 @@ class ProxySettingsViewModel: ProxySettingsViewModelProtocol, Loggable { // MARK: - Dependencies private let proxyUtil: ProxyUtilProtocol + private let userAgentUtil: UserAgentUtilProtocol + private let dataStore: DataStoreProtocol init( - proxyUtil: ProxyUtilProtocol + proxyUtil: ProxyUtilProtocol, + userAgentUtil: UserAgentUtilProtocol, + dataStore: DataStoreProtocol ) { self.proxyUtil = proxyUtil + self.userAgentUtil = userAgentUtil + self.dataStore = dataStore Task { await loadSettings() @@ -75,7 +82,18 @@ class ProxySettingsViewModel: ProxySettingsViewModelProtocol, Loggable { let url = "https://id.eesti.ee/config.json" let session = session ?? Session.withProxy(proxyInfo: requestProxyInfo) - let response = await session.request(url) + let appLanguage = await dataStore.getSelectedLanguage() + let userAgent = userAgentUtil.userAgent( + diagnostics: .none, + language: appLanguage + ) + + let response = await session.request( + url, + headers: [ + .userAgent(userAgent) + ] + ) .validate() .serializingData() .response diff --git a/RIADigiDoc/ViewModel/RecentDocumentsViewModel.swift b/RIADigiDoc/ViewModel/RecentDocumentsViewModel.swift index 53033671..80b5c601 100644 --- a/RIADigiDoc/ViewModel/RecentDocumentsViewModel.swift +++ b/RIADigiDoc/ViewModel/RecentDocumentsViewModel.swift @@ -20,6 +20,7 @@ import Foundation import FactoryKit import CommonsLib +import UtilsLib @Observable @MainActor diff --git a/RIADigiDoc/ViewModel/SignatureDetailViewModel.swift b/RIADigiDoc/ViewModel/SignatureDetailViewModel.swift index 4ed362d9..c5f5585d 100644 --- a/RIADigiDoc/ViewModel/SignatureDetailViewModel.swift +++ b/RIADigiDoc/ViewModel/SignatureDetailViewModel.swift @@ -17,7 +17,7 @@ * */ -import CommonsLib +import UtilsLib import Foundation import X509 diff --git a/RIADigiDoc/ViewModel/Signing/ActionMethod/ActionMethodSelectionViewModel.swift b/RIADigiDoc/ViewModel/Signing/ActionMethod/ActionMethodSelectionViewModel.swift index ac8e9342..e3f9164b 100644 --- a/RIADigiDoc/ViewModel/Signing/ActionMethod/ActionMethodSelectionViewModel.swift +++ b/RIADigiDoc/ViewModel/Signing/ActionMethod/ActionMethodSelectionViewModel.swift @@ -17,7 +17,7 @@ * */ -import CommonsLib +import UtilsLib import Foundation @Observable diff --git a/RIADigiDoc/ViewModel/Signing/MobileId/MobileIdViewModel.swift b/RIADigiDoc/ViewModel/Signing/MobileId/MobileIdViewModel.swift index a70f26f1..ed824960 100644 --- a/RIADigiDoc/ViewModel/Signing/MobileId/MobileIdViewModel.swift +++ b/RIADigiDoc/ViewModel/Signing/MobileId/MobileIdViewModel.swift @@ -49,19 +49,22 @@ class MobileIdViewModel: MobileIdViewModelProtocol, Loggable { private let certificateUtil: CertificateUtilProtocol private let dataStore: DataStoreProtocol private let proxyUtil: ProxyUtilProtocol + private let userAgentUtil: UserAgentUtilProtocol init( configurationRepository: ConfigurationRepositoryProtocol, mobileIdSignService: MobileIdSignServiceProtocol, certificateUtil: CertificateUtilProtocol, dataStore: DataStoreProtocol, - proxyUtil: ProxyUtilProtocol + proxyUtil: ProxyUtilProtocol, + userAgentUtil: UserAgentUtilProtocol ) { self.configurationRepository = configurationRepository self.mobileIdSignService = mobileIdSignService self.certificateUtil = certificateUtil self.dataStore = dataStore self.proxyUtil = proxyUtil + self.userAgentUtil = userAgentUtil } func isSigningEnabled( @@ -131,6 +134,12 @@ class MobileIdViewModel: MobileIdViewModelProtocol, Loggable { let proxyInfo = await proxyUtil.getProxyInfo() + MobileIdViewModel.logger().debug("Mobile-ID: Getting language") + let appLanguage = await dataStore.getSelectedLanguage() + + MobileIdViewModel.logger().debug("Mobile-ID: Getting User-Agent") + let userAgent = userAgentUtil.userAgent(diagnostics: .none, language: appLanguage) + let containerFile: URL do { containerFile = try await getContainerFile(signedContainer: signedContainer) @@ -147,7 +156,8 @@ class MobileIdViewModel: MobileIdViewModelProtocol, Loggable { phoneNumber: phoneNumber, personalCode: personalCode, trustedCertificates: trustedCertificates, - proxyInfo: proxyInfo + proxyInfo: proxyInfo, + userAgent: userAgent ) } catch { MobileIdViewModel.logger().debug("Mobile-ID: Unable to request certificate or get cert from response") @@ -161,7 +171,8 @@ class MobileIdViewModel: MobileIdViewModelProtocol, Loggable { cert: cert, containerFile: containerFile, roleData: roleData, - signedContainer: signedContainer + signedContainer: signedContainer, + userAgent: userAgent ) } catch { MobileIdViewModel.logger().debug("Mobile-ID: Unable to prepare signature for signing") @@ -180,9 +191,6 @@ class MobileIdViewModel: MobileIdViewModelProtocol, Loggable { controlCode = verificationCode - MobileIdViewModel.logger().debug("Mobile-ID: Getting language") - let language = await dataStore.getSelectedLanguage() - let sessionId: String do { sessionId = try await requestSignature( @@ -190,9 +198,10 @@ class MobileIdViewModel: MobileIdViewModelProtocol, Loggable { phoneNumber: phoneNumber, personalCode: personalCode, hash: hash, - language: language, + language: appLanguage, trustedCertificates: trustedCertificates, - proxyInfo: proxyInfo + proxyInfo: proxyInfo, + userAgent: userAgent ) } catch { MobileIdViewModel.logger().debug("Mobile-ID: Unable to request signature") @@ -206,7 +215,8 @@ class MobileIdViewModel: MobileIdViewModelProtocol, Loggable { midUrl: midUrl, sessionId: sessionId, trustedCertificates: trustedCertificates, - proxyInfo: proxyInfo + proxyInfo: proxyInfo, + userAgent: userAgent ) } catch { MobileIdViewModel.logger().debug( @@ -238,12 +248,14 @@ class MobileIdViewModel: MobileIdViewModelProtocol, Loggable { await dataStore.getIsRoleAndAddressEnabled() } + // swiftlint:disable:next function_parameter_count private func requestCertificate( midUrl: URL, phoneNumber: String, personalCode: String, trustedCertificates: [SecCertificate], - proxyInfo: ProxyInfo + proxyInfo: ProxyInfo, + userAgent: String ) async throws -> Data { MobileIdViewModel.logger().debug("Mobile-ID: Getting certificate") let certResponse = try await mobileIdSignService @@ -254,7 +266,8 @@ class MobileIdViewModel: MobileIdViewModelProtocol, Loggable { phoneNumber: phoneNumber, nationalIdentityNumber: personalCode, trustedCertificates: trustedCertificates, - proxyInfo: proxyInfo + proxyInfo: proxyInfo, + userAgent: userAgent ) guard let certData = Data( @@ -276,7 +289,8 @@ class MobileIdViewModel: MobileIdViewModelProtocol, Loggable { hash: Data, language: String, trustedCertificates: [SecCertificate], - proxyInfo: ProxyInfo + proxyInfo: ProxyInfo, + userAgent: String ) async throws -> String { MobileIdViewModel.logger().debug("Mobile-ID: Getting signature") let signatureResponse = try await mobileIdSignService.getSignatureRequest( @@ -291,7 +305,8 @@ class MobileIdViewModel: MobileIdViewModelProtocol, Loggable { displayText: NSLocalizedString("Sign document", comment: ""), displayTextFormat: Constants.MobileId.DisplayTextFormat, trustedCertificates: trustedCertificates, - proxyInfo: proxyInfo + proxyInfo: proxyInfo, + userAgent: userAgent ) MobileIdViewModel.logger().debug("Mobile-ID: Getting sessionID") @@ -308,7 +323,8 @@ class MobileIdViewModel: MobileIdViewModelProtocol, Loggable { midUrl: URL, sessionId: String, trustedCertificates: [SecCertificate], - proxyInfo: ProxyInfo + proxyInfo: ProxyInfo, + userAgent: String ) async throws -> Data { MobileIdViewModel.logger().debug("Mobile-ID: Getting session request") let sessionResponse = try await mobileIdSignService.getSessionRequest( @@ -316,7 +332,8 @@ class MobileIdViewModel: MobileIdViewModelProtocol, Loggable { sessionId: sessionId, pollingTimeout: Constants.Signing.DefaultTimeout, trustedCertificates: trustedCertificates, - proxyInfo: proxyInfo + proxyInfo: proxyInfo, + userAgent: userAgent ) guard let signatureData = sessionResponse.signature?.value else { @@ -330,7 +347,8 @@ class MobileIdViewModel: MobileIdViewModelProtocol, Loggable { cert: Data, containerFile: URL, roleData: RoleData, - signedContainer: SignedContainerProtocol + signedContainer: SignedContainerProtocol, + userAgent: String ) async throws -> Data { MobileIdViewModel.logger().debug( "Mobile-ID: Preparing signature. Calculating hash" @@ -340,7 +358,7 @@ class MobileIdViewModel: MobileIdViewModelProtocol, Loggable { cert: cert, containerPath: containerFile, roleData: roleData, - userAgent: "" + userAgent: userAgent ) } diff --git a/RIADigiDoc/ViewModel/Signing/NFC/NFCViewModel.swift b/RIADigiDoc/ViewModel/Signing/NFC/NFCViewModel.swift index 181235cd..a4190b85 100644 --- a/RIADigiDoc/ViewModel/Signing/NFC/NFCViewModel.swift +++ b/RIADigiDoc/ViewModel/Signing/NFC/NFCViewModel.swift @@ -20,6 +20,7 @@ import Foundation import LibdigidocLibSwift import CommonsLib +import UtilsLib @Observable @MainActor diff --git a/RIADigiDoc/ViewModel/Signing/RoleAndAddress/RoleViewModel.swift b/RIADigiDoc/ViewModel/Signing/RoleAndAddress/RoleViewModel.swift index 72f14edc..659df1c7 100644 --- a/RIADigiDoc/ViewModel/Signing/RoleAndAddress/RoleViewModel.swift +++ b/RIADigiDoc/ViewModel/Signing/RoleAndAddress/RoleViewModel.swift @@ -19,6 +19,7 @@ import Foundation import CommonsLib +import UtilsLib @Observable @MainActor diff --git a/RIADigiDoc/ViewModel/Signing/RootView/SigningRootViewModel.swift b/RIADigiDoc/ViewModel/Signing/RootView/SigningRootViewModel.swift index 8743cc29..11587364 100644 --- a/RIADigiDoc/ViewModel/Signing/RootView/SigningRootViewModel.swift +++ b/RIADigiDoc/ViewModel/Signing/RootView/SigningRootViewModel.swift @@ -17,7 +17,7 @@ * */ -import CommonsLib +import UtilsLib import Foundation import Observation diff --git a/RIADigiDoc/ViewModel/Signing/SmartId/SmartIdViewModel.swift b/RIADigiDoc/ViewModel/Signing/SmartId/SmartIdViewModel.swift index 7fcf2a4a..c836eb2c 100644 --- a/RIADigiDoc/ViewModel/Signing/SmartId/SmartIdViewModel.swift +++ b/RIADigiDoc/ViewModel/Signing/SmartId/SmartIdViewModel.swift @@ -51,6 +51,7 @@ class SmartIdViewModel: SmartIdViewModelProtocol, Loggable { private let notificationUtil: NotificationUtilProtocol private let dataStore: DataStoreProtocol private let proxyUtil: ProxyUtilProtocol + private let userAgentUtil: UserAgentUtilProtocol init( configurationRepository: ConfigurationRepositoryProtocol, @@ -58,7 +59,8 @@ class SmartIdViewModel: SmartIdViewModelProtocol, Loggable { certificateUtil: CertificateUtilProtocol, notificationUtil: NotificationUtilProtocol, dataStore: DataStoreProtocol, - proxyUtil: ProxyUtilProtocol + proxyUtil: ProxyUtilProtocol, + userAgentUtil: UserAgentUtilProtocol ) { self.configurationRepository = configurationRepository self.smartIdSignService = smartIdSignService @@ -66,6 +68,7 @@ class SmartIdViewModel: SmartIdViewModelProtocol, Loggable { self.notificationUtil = notificationUtil self.dataStore = dataStore self.proxyUtil = proxyUtil + self.userAgentUtil = userAgentUtil } func appDidEnterBackground() { @@ -140,6 +143,12 @@ class SmartIdViewModel: SmartIdViewModelProtocol, Loggable { let proxyInfo = await proxyUtil.getProxyInfo() + SmartIdViewModel.logger().debug("Smart-ID: Getting language") + let appLanguage = await dataStore.getSelectedLanguage() + + SmartIdViewModel.logger().debug("Smart-ID: Getting User-Agent") + let userAgent = userAgentUtil.userAgent(diagnostics: .none, language: appLanguage) + let containerFile: URL do { containerFile = try await getContainerFile(signedContainer: signedContainer) @@ -159,7 +168,8 @@ class SmartIdViewModel: SmartIdViewModelProtocol, Loggable { personalCode: personalCode, pollingTimeout: Constants.Signing.DefaultTimeout, trustedCertificates: trustedCertificates, - proxyInfo: proxyInfo + proxyInfo: proxyInfo, + userAgent: userAgent ) } catch { SmartIdViewModel.logger().debug("Smart-ID: Unable to request certificate or get response") @@ -181,7 +191,8 @@ class SmartIdViewModel: SmartIdViewModelProtocol, Loggable { cert: cert, containerFile: containerFile, roleData: roleData, - signedContainer: signedContainer + signedContainer: signedContainer, + userAgent: userAgent ) } catch { SmartIdViewModel.logger().debug("Smart-ID: Unable to prepare signature for signing") @@ -229,7 +240,8 @@ class SmartIdViewModel: SmartIdViewModelProtocol, Loggable { displayText: NSLocalizedString("Sign document", comment: ""), pollingTimeout: Constants.Signing.DefaultTimeout, trustedCertificates: trustedCertificates, - proxyInfo: proxyInfo + proxyInfo: proxyInfo, + userAgent: userAgent ) } catch { endBackgroundTask() @@ -291,7 +303,8 @@ class SmartIdViewModel: SmartIdViewModelProtocol, Loggable { personalCode: String, pollingTimeout: Int, trustedCertificates: [SecCertificate], - proxyInfo: ProxyInfo + proxyInfo: ProxyInfo, + userAgent: String ) async throws -> SmartIdSessionResponse { SmartIdViewModel.logger().debug("Smart-ID: Getting certificate") let certResponse = try await smartIdSignService @@ -302,7 +315,8 @@ class SmartIdViewModel: SmartIdViewModelProtocol, Loggable { country: getCountry(smartIdCountry: country), nationalIdentityNumber: personalCode, trustedCertificates: trustedCertificates, - proxyInfo: proxyInfo + proxyInfo: proxyInfo, + userAgent: userAgent ) guard let sessionId = certResponse.sessionID else { @@ -316,7 +330,8 @@ class SmartIdViewModel: SmartIdViewModelProtocol, Loggable { sessionId: sessionId, pollingTimout: pollingTimeout, trustedCertificates: trustedCertificates, - proxyInfo: proxyInfo + proxyInfo: proxyInfo, + userAgent: userAgent ) } @@ -330,7 +345,8 @@ class SmartIdViewModel: SmartIdViewModelProtocol, Loggable { displayText: String, pollingTimeout: Int, trustedCertificates: [SecCertificate], - proxyInfo: ProxyInfo + proxyInfo: ProxyInfo, + userAgent: String ) async throws -> Data { SmartIdViewModel.logger().debug("Smart-ID: Getting signature") @@ -345,7 +361,8 @@ class SmartIdViewModel: SmartIdViewModelProtocol, Loggable { allowedInteractionsOrderType: allowedInteractionsOrderType, displayText200: displayText, trustedCertificates: trustedCertificates, - proxyInfo: proxyInfo + proxyInfo: proxyInfo, + userAgent: userAgent ) guard let sessionId = certResponse.sessionID else { @@ -359,7 +376,8 @@ class SmartIdViewModel: SmartIdViewModelProtocol, Loggable { sessionId: sessionId, pollingTimout: pollingTimeout, trustedCertificates: trustedCertificates, - proxyInfo: proxyInfo + proxyInfo: proxyInfo, + userAgent: userAgent ) guard let signature = sessionResponse.signature?.value else { @@ -382,12 +400,14 @@ class SmartIdViewModel: SmartIdViewModelProtocol, Loggable { } } + // swiftlint:disable:next function_parameter_count private func requestSession( sidUrl: String, sessionId: String, pollingTimout: Int, trustedCertificates: [SecCertificate], - proxyInfo: ProxyInfo + proxyInfo: ProxyInfo, + userAgent: String ) async throws -> SmartIdSessionResponse { SmartIdViewModel.logger().debug("Smart-ID: Getting session") return try await smartIdSignService.getSessionRequest( @@ -395,7 +415,8 @@ class SmartIdViewModel: SmartIdViewModelProtocol, Loggable { sessionId: sessionId, pollingTimeout: pollingTimout, trustedCertificates: trustedCertificates, - proxyInfo: proxyInfo + proxyInfo: proxyInfo, + userAgent: userAgent ) } @@ -424,7 +445,8 @@ class SmartIdViewModel: SmartIdViewModelProtocol, Loggable { cert: Data, containerFile: URL, roleData: RoleData, - signedContainer: SignedContainerProtocol + signedContainer: SignedContainerProtocol, + userAgent: String ) async throws -> Data { SmartIdViewModel.logger().debug( "Smart-ID: Preparing signature. Calculating hash" @@ -434,7 +456,7 @@ class SmartIdViewModel: SmartIdViewModelProtocol, Loggable { cert: cert, containerPath: containerFile, roleData: roleData, - userAgent: "" + userAgent: userAgent ) } diff --git a/RIADigiDocTests/Repository/AdvancedSettings/AdvancedSettingsRepositoryTests.swift b/RIADigiDocTests/Repository/AdvancedSettings/AdvancedSettingsRepositoryTests.swift index b1de4217..f9c6b025 100644 --- a/RIADigiDocTests/Repository/AdvancedSettings/AdvancedSettingsRepositoryTests.swift +++ b/RIADigiDocTests/Repository/AdvancedSettings/AdvancedSettingsRepositoryTests.swift @@ -22,6 +22,7 @@ import CommonsLibMocks import CommonsTestShared import Foundation import Testing +import UtilsLib struct AdvancedSettingsRepositoryTests { private let mockFileManager: FileManagerProtocolMock diff --git a/RIADigiDocTests/ViewModel/DiagnosticsViewModelTests.swift b/RIADigiDocTests/ViewModel/DiagnosticsViewModelTests.swift index 252bbcdf..8b8b52b7 100644 --- a/RIADigiDocTests/ViewModel/DiagnosticsViewModelTests.swift +++ b/RIADigiDocTests/ViewModel/DiagnosticsViewModelTests.swift @@ -40,6 +40,7 @@ final class DiagnosticsViewModelTests { private let mockTSLUtil: TSLUtilProtocolMock private let mockDataStore: DataStoreProtocolMock private let mockProxyUtil: ProxyUtilProtocolMock + private let mockUserAgentUtil: UserAgentUtilProtocolMock let mockConfigProvider: ConfigurationProvider? @@ -51,6 +52,7 @@ final class DiagnosticsViewModelTests { mockTSLUtil = TSLUtilProtocolMock() mockDataStore = DataStoreProtocolMock() mockProxyUtil = ProxyUtilProtocolMock() + mockUserAgentUtil = UserAgentUtilProtocolMock() mockConfigProvider = try TestConfigurationProvider.mockConfigurationProvider() TestConfigurationSetup.configureMocks( @@ -67,7 +69,8 @@ final class DiagnosticsViewModelTests { configurationRepository: mockConfigurationRepository, tslUtil: mockTSLUtil, dataStore: mockDataStore, - proxyUtil: mockProxyUtil + proxyUtil: mockProxyUtil, + userAgentUtil: mockUserAgentUtil ) } @@ -322,7 +325,7 @@ final class DiagnosticsViewModelTests { @Test func updateConfiguration_returnsFalseOnFailure() async throws { - mockConfigurationLoader.loadCentralConfigurationHandler = { _, _ in + mockConfigurationLoader.loadCentralConfigurationHandler = { _, _, _ in throw NSError(domain: "TestError", code: 1, userInfo: nil) } await #expect(throws: Never.self) { diff --git a/RIADigiDocTests/ViewModel/ProxySettingsViewModelTests.swift b/RIADigiDocTests/ViewModel/ProxySettingsViewModelTests.swift index d992da71..41326b83 100644 --- a/RIADigiDocTests/ViewModel/ProxySettingsViewModelTests.swift +++ b/RIADigiDocTests/ViewModel/ProxySettingsViewModelTests.swift @@ -22,19 +22,28 @@ import CommonsLib import CommonsTestShared import Foundation import Testing +import UtilsLibMocks @MainActor final class ProxySettingsViewModelTests { - private let viewModel: ProxySettingsViewModel! + private let mockProxyUtil: ProxyUtilProtocolMock + private let mockUserAgentUtil: UserAgentUtilProtocolMock + private let mockDataStore: DataStoreProtocolMock - private let mockProxyUtil: ProxyUtilProtocolMock! + private let viewModel: ProxySettingsViewModel init() { mockProxyUtil = ProxyUtilProtocolMock() + mockUserAgentUtil = UserAgentUtilProtocolMock() + mockDataStore = DataStoreProtocolMock() mockProxyUtil.getProxyInfoHandler = { ProxyInfo() } - viewModel = ProxySettingsViewModel(proxyUtil: mockProxyUtil) + viewModel = ProxySettingsViewModel( + proxyUtil: mockProxyUtil, + userAgentUtil: mockUserAgentUtil, + dataStore: mockDataStore + ) } @Test diff --git a/RIADigiDocTests/ViewModel/RecentDocumentsViewModelTests.swift b/RIADigiDocTests/ViewModel/RecentDocumentsViewModelTests.swift index 3aa5136e..66bd4ea0 100644 --- a/RIADigiDocTests/ViewModel/RecentDocumentsViewModelTests.swift +++ b/RIADigiDocTests/ViewModel/RecentDocumentsViewModelTests.swift @@ -57,14 +57,6 @@ class RecentDocumentsViewModelTests { return [file1, file2, invalidFile] } -// mockFileManager.attributesOfItemHandler = { path in -// if path == file1.resolvedPath || path == file2.resolvedPath { -// return [.modificationDate: Date()] -// } -// -// throw NSError(domain: NSCocoaErrorDomain, code: NSFileReadNoSuchFileError, userInfo: nil) -// } - mockFileManager.fileExistsAtPathHandler = { _, _ in true } mockFileInspector.lastOpenedHandler = { _ in Date() } diff --git a/RIADigiDocTests/ViewModel/Signing/MobileId/MobileIdViewModelTests.swift b/RIADigiDocTests/ViewModel/Signing/MobileId/MobileIdViewModelTests.swift index c1d9bb6d..803ab900 100644 --- a/RIADigiDocTests/ViewModel/Signing/MobileId/MobileIdViewModelTests.swift +++ b/RIADigiDocTests/ViewModel/Signing/MobileId/MobileIdViewModelTests.swift @@ -22,6 +22,7 @@ import Testing import ConfigLibMocks import MobileIdLib import MobileIdLibMocks +import UtilsLibMocks @MainActor struct MobileIdViewModelTests { @@ -31,6 +32,7 @@ struct MobileIdViewModelTests { private let mockCertificatUtil: CertificateUtilProtocolMock private let mockDataStore: DataStoreProtocolMock private let mockProxyUtil: ProxyUtilProtocolMock + private let mockUserAgentUtil: UserAgentUtilProtocolMock private let viewModel: MobileIdViewModel @@ -40,13 +42,15 @@ struct MobileIdViewModelTests { self.mockCertificatUtil = CertificateUtilProtocolMock() self.mockDataStore = DataStoreProtocolMock() self.mockProxyUtil = ProxyUtilProtocolMock() + self.mockUserAgentUtil = UserAgentUtilProtocolMock() viewModel = MobileIdViewModel( configurationRepository: mockConfigurationRepository, mobileIdSignService: mockMobileIdSignService, certificateUtil: mockCertificatUtil, dataStore: mockDataStore, - proxyUtil: mockProxyUtil + proxyUtil: mockProxyUtil, + userAgentUtil: mockUserAgentUtil ) } diff --git a/RIADigiDocTests/ViewModel/Signing/SmartId/SmartIdViewModelTests.swift b/RIADigiDocTests/ViewModel/Signing/SmartId/SmartIdViewModelTests.swift index 9fb0e8b5..5f22765e 100644 --- a/RIADigiDocTests/ViewModel/Signing/SmartId/SmartIdViewModelTests.swift +++ b/RIADigiDocTests/ViewModel/Signing/SmartId/SmartIdViewModelTests.swift @@ -33,6 +33,7 @@ struct SmartIdViewModelTests { private let mockNotificationUtil: NotificationUtilProtocolMock private let mockDataStore: DataStoreProtocolMock private let mockProxyUtil: ProxyUtilProtocolMock + private let mockUserAgentUtil: UserAgentUtilProtocolMock private let viewModel: SmartIdViewModel @@ -43,6 +44,7 @@ struct SmartIdViewModelTests { self.mockNotificationUtil = NotificationUtilProtocolMock() self.mockDataStore = DataStoreProtocolMock() self.mockProxyUtil = ProxyUtilProtocolMock() + self.mockUserAgentUtil = UserAgentUtilProtocolMock() viewModel = SmartIdViewModel( configurationRepository: mockConfigurationRepository, @@ -50,7 +52,8 @@ struct SmartIdViewModelTests { certificateUtil: mockCertificatUtil, notificationUtil: mockNotificationUtil, dataStore: mockDataStore, - proxyUtil: mockProxyUtil + proxyUtil: mockProxyUtil, + userAgentUtil: mockUserAgentUtil ) }