feat: add TILogging module and TINetworking error logging
This commit is contained in:
parent
c0189dc7ae
commit
ecfb83bafa
|
|
@ -3,7 +3,9 @@
|
|||
### 1.45.0
|
||||
|
||||
- **Added**: `SingleValueStorage` implementations + `AppInstallLifetimeSingleValueStorage` for automatically removing keychain items on app reinstall.
|
||||
- **Added**: `TILogging` with error logging types
|
||||
- **Update**: `DefaultRecoverableJsonNetworkService` supports iOS 12.
|
||||
- **Update**: `DefaultFingerprintsProvider` now uses `SingleValueStorage`
|
||||
|
||||
### 1.44.0
|
||||
|
||||
|
|
|
|||
|
|
@ -68,7 +68,12 @@ let package = Package(
|
|||
// MARK: - Utils
|
||||
|
||||
.target(name: "TISwiftUtils", path: "TISwiftUtils/Sources"),
|
||||
.target(name: "TIFoundationUtils", dependencies: ["TISwiftUtils"], path: "TIFoundationUtils", exclude: ["TIFoundationUtils.app"]),
|
||||
|
||||
.target(name: "TIFoundationUtils",
|
||||
dependencies: ["TISwiftUtils"],
|
||||
path: "TIFoundationUtils",
|
||||
exclude: ["TIFoundationUtils.app"],
|
||||
plugins: [.plugin(name: "TISwiftLintPlugin")]),
|
||||
|
||||
.target(name: "TIKeychainUtils",
|
||||
dependencies: ["TIFoundationUtils", "KeychainAccess"],
|
||||
|
|
@ -79,11 +84,12 @@ let package = Package(
|
|||
.target(name: "TITableKitUtils", dependencies: ["TIUIElements", "TableKit"], path: "TITableKitUtils/Sources"),
|
||||
.target(name: "TIDeeplink", dependencies: ["TIFoundationUtils"], path: "TIDeeplink", exclude: ["TIDeeplink.app"]),
|
||||
.target(name: "TIDeveloperUtils", dependencies: ["TISwiftUtils", "TIUIKitCore", "TIUIElements"], path: "TIDeveloperUtils/Sources"),
|
||||
.target(name: "TILogging", path: "TILogging/Sources", plugins: ["TISwiftLintPlugin"]),
|
||||
|
||||
// MARK: - Networking
|
||||
|
||||
.target(name: "TINetworking",
|
||||
dependencies: ["TIFoundationUtils", "Alamofire"],
|
||||
dependencies: ["TIFoundationUtils", "Alamofire", "TILogging"],
|
||||
path: "TINetworking/Sources",
|
||||
plugins: [.plugin(name: "TISwiftLintPlugin")]),
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ struct SwiftLintPlugin: BuildToolPlugin {
|
|||
let swiftlintExecutablePath = try context.tool(named: "swiftlint").path
|
||||
|
||||
return [
|
||||
.prebuildCommand(displayName: "SwiftLint linting...",
|
||||
.prebuildCommand(displayName: "SwiftLint linting \(target.name)...",
|
||||
executable: swiftlintScriptPath,
|
||||
arguments: [
|
||||
swiftlintExecutablePath,
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ open class DefaultEncryptedTokenKeyStorage: SingleValueAuthKeychainStorage<Data>
|
|||
}
|
||||
}
|
||||
|
||||
let setValueClosure: SetValueClosure = { keychain, value, storageKey in
|
||||
let storeValueClosure: StoreValueClosure = { keychain, value, storageKey in
|
||||
do {
|
||||
return .success(try keychain.set(value, key: storageKey.rawValue))
|
||||
} catch {
|
||||
|
|
@ -67,6 +67,6 @@ open class DefaultEncryptedTokenKeyStorage: SingleValueAuthKeychainStorage<Data>
|
|||
settingsStorage: settingsStorage,
|
||||
storageKey: encryptedTokenKeyStorageKey,
|
||||
getValueClosure: getValueClosure,
|
||||
setValueClosure: setValueClosure)
|
||||
storeValueClosure: storeValueClosure)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ open class DefaultEncryptedTokenStorage: SingleValueAuthKeychainStorage<StringEn
|
|||
}
|
||||
}
|
||||
|
||||
let setValueClosure: SetValueClosure = { keychain, value, storageKey in
|
||||
let storeValueClosure: StoreValueClosure = { keychain, value, storageKey in
|
||||
do {
|
||||
return .success(try keychain.set(value.asStorableData(), key: storageKey.rawValue))
|
||||
} catch {
|
||||
|
|
@ -63,6 +63,6 @@ open class DefaultEncryptedTokenStorage: SingleValueAuthKeychainStorage<StringEn
|
|||
settingsStorage: settingsStorage,
|
||||
storageKey: encryptedTokenStorageKey,
|
||||
getValueClosure: getValueClosure,
|
||||
setValueClosure: setValueClosure)
|
||||
storeValueClosure: storeValueClosure)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,14 +38,14 @@ open class SingleValueAuthKeychainStorage<ValueType>: BaseSingleValueKeychainSto
|
|||
settingsStorage: AuthSettingsStorage = DefaultAuthSettingsStorage(),
|
||||
storageKey: StorageKey<ValueType>,
|
||||
getValueClosure: @escaping GetValueClosure,
|
||||
setValueClosure: @escaping SetValueClosure) {
|
||||
storeValueClosure: @escaping StoreValueClosure) {
|
||||
|
||||
self.settingsStorage = settingsStorage
|
||||
|
||||
super.init(keychain: keychain,
|
||||
storageKey: storageKey,
|
||||
getValueClosure: getValueClosure,
|
||||
setValueClosure: setValueClosure)
|
||||
storeValueClosure: storeValueClosure)
|
||||
}
|
||||
|
||||
// MARK: - SingleValueStorage
|
||||
|
|
|
|||
|
|
@ -0,0 +1,64 @@
|
|||
//
|
||||
// Copyright (c) 2023 Touch Instinct
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the Software), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
public struct AnySingleValueStorage<ValueType, ErrorType: Error>: SingleValueStorage {
|
||||
public typealias HasValueClosure = () -> Bool
|
||||
public typealias GetValueClosure = () -> Result<ValueType, ErrorType>
|
||||
public typealias StoreValueClosure = (ValueType) -> Result<Void, ErrorType>
|
||||
public typealias DeleteValueClosure = () -> Result<Void, ErrorType>
|
||||
|
||||
private let hasValueClosure: HasValueClosure
|
||||
private let deleteValueClosure: DeleteValueClosure
|
||||
private let getValueClosure: GetValueClosure
|
||||
private let storeValueClosure: StoreValueClosure
|
||||
|
||||
public init<Storage: SingleValueStorage>(storage: Storage)
|
||||
where Storage.ValueType == ValueType, Storage.ErrorType == ErrorType {
|
||||
|
||||
self.hasValueClosure = storage.hasStoredValue
|
||||
self.deleteValueClosure = storage.deleteValue
|
||||
self.getValueClosure = storage.getValue
|
||||
self.storeValueClosure = storage.store
|
||||
}
|
||||
|
||||
public func hasStoredValue() -> Bool {
|
||||
hasValueClosure()
|
||||
}
|
||||
|
||||
public func store(value: ValueType) -> Result<Void, ErrorType> {
|
||||
storeValueClosure(value)
|
||||
}
|
||||
|
||||
public func getValue() -> Result<ValueType, ErrorType> {
|
||||
getValueClosure()
|
||||
}
|
||||
|
||||
public func deleteValue() -> Result<Void, ErrorType> {
|
||||
deleteValueClosure()
|
||||
}
|
||||
}
|
||||
|
||||
public extension SingleValueStorage {
|
||||
func eraseToAnySingleValueStorate() -> AnySingleValueStorage<ValueType, ErrorType> {
|
||||
AnySingleValueStorage(storage: self)
|
||||
}
|
||||
}
|
||||
|
|
@ -20,8 +20,6 @@
|
|||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
import TIFoundationUtils
|
||||
|
||||
open class AppInstallLifetimeSingleValueStorage<Storage: SingleValueStorage>: SingleValueStorage
|
||||
where Storage.ErrorType == StorageError {
|
||||
|
||||
|
|
@ -26,13 +26,13 @@ open class BaseSingleValueDefaultsStorage<ValueType>: BaseSingleValueStorage<Val
|
|||
public init(defaults: UserDefaults,
|
||||
storageKey: StorageKey<ValueType>,
|
||||
getValueClosure: @escaping GetValueClosure,
|
||||
setValueClosure: @escaping SetValueClosure) {
|
||||
storeValueClosure: @escaping StoreValueClosure) {
|
||||
|
||||
super.init(storage: defaults,
|
||||
storageKey: storageKey,
|
||||
hasValueClosure: { .success($0.object(forKey: $1.rawValue) != nil) },
|
||||
deleteValueClosure: { .success($0.removeObject(forKey: $1.rawValue)) },
|
||||
getValueClosure: getValueClosure,
|
||||
setValueClosure: setValueClosure)
|
||||
storeValueClosure: storeValueClosure)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
open class BaseSingleValueStorage<ValueType, StorageType>: SingleValueStorage {
|
||||
public typealias HasValueClosure = (StorageType, StorageKey<ValueType>) -> Result<Bool, StorageError>
|
||||
public typealias GetValueClosure = (StorageType, StorageKey<ValueType>) -> Result<ValueType, StorageError>
|
||||
public typealias SetValueClosure = (StorageType, ValueType, StorageKey<ValueType>) -> Result<Void, StorageError>
|
||||
public typealias StoreValueClosure = (StorageType, ValueType, StorageKey<ValueType>) -> Result<Void, StorageError>
|
||||
public typealias DeleteValueClosure = (StorageType, StorageKey<ValueType>) -> Result<Void, StorageError>
|
||||
|
||||
public let storage: StorageType
|
||||
|
|
@ -31,21 +31,21 @@ open class BaseSingleValueStorage<ValueType, StorageType>: SingleValueStorage {
|
|||
public let hasValueClosure: HasValueClosure
|
||||
public let deleteValueClosure: DeleteValueClosure
|
||||
public let getValueClosure: GetValueClosure
|
||||
public let setValueClosure: SetValueClosure
|
||||
public let storeValueClosure: StoreValueClosure
|
||||
|
||||
public init(storage: StorageType,
|
||||
storageKey: StorageKey<ValueType>,
|
||||
hasValueClosure: @escaping HasValueClosure,
|
||||
deleteValueClosure: @escaping DeleteValueClosure,
|
||||
getValueClosure: @escaping GetValueClosure,
|
||||
setValueClosure: @escaping SetValueClosure) {
|
||||
storeValueClosure: @escaping StoreValueClosure) {
|
||||
|
||||
self.storage = storage
|
||||
self.storageKey = storageKey
|
||||
self.hasValueClosure = hasValueClosure
|
||||
self.deleteValueClosure = deleteValueClosure
|
||||
self.getValueClosure = getValueClosure
|
||||
self.setValueClosure = setValueClosure
|
||||
self.storeValueClosure = storeValueClosure
|
||||
}
|
||||
|
||||
// MARK: - SingleValueStorage
|
||||
|
|
@ -55,14 +55,14 @@ open class BaseSingleValueStorage<ValueType, StorageType>: SingleValueStorage {
|
|||
}
|
||||
|
||||
open func store(value: ValueType) -> Result<Void, StorageError> {
|
||||
setValueClosure(storage, value, storageKey)
|
||||
storeValueClosure(storage, value, storageKey)
|
||||
}
|
||||
|
||||
open func getValue() -> Result<ValueType, StorageError> {
|
||||
getValueClosure(storage, storageKey)
|
||||
}
|
||||
|
||||
public func deleteValue() -> Result<Void, StorageError> {
|
||||
open func deleteValue() -> Result<Void, StorageError> {
|
||||
deleteValueClosure(storage, storageKey)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,6 @@ public final class StringValueDefaultsStorage: BaseSingleValueDefaultsStorage<St
|
|||
super.init(defaults: defaults,
|
||||
storageKey: storageKey,
|
||||
getValueClosure: getValueClosure,
|
||||
setValueClosure: { .success($0.set($1, forKey: $2.rawValue)) })
|
||||
storeValueClosure: { .success($0.set($1, forKey: $2.rawValue)) })
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ open class BaseSingleValueKeychainStorage<ValueType>: BaseSingleValueStorage<Val
|
|||
public init(keychain: Keychain,
|
||||
storageKey: StorageKey<ValueType>,
|
||||
getValueClosure: @escaping GetValueClosure,
|
||||
setValueClosure: @escaping SetValueClosure) {
|
||||
storeValueClosure: @escaping StoreValueClosure) {
|
||||
|
||||
let hasValueClosure: HasValueClosure = { keychain, storageKey in
|
||||
Result { try keychain.contains(storageKey.rawValue) }
|
||||
|
|
@ -44,6 +44,6 @@ open class BaseSingleValueKeychainStorage<ValueType>: BaseSingleValueStorage<Val
|
|||
hasValueClosure: hasValueClosure,
|
||||
deleteValueClosure: deleteValueClosure,
|
||||
getValueClosure: getValueClosure,
|
||||
setValueClosure: setValueClosure)
|
||||
storeValueClosure: storeValueClosure)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ public final class StringValueKeychainStorage: BaseSingleValueKeychainStorage<St
|
|||
}
|
||||
}
|
||||
|
||||
let setValueClosure: SetValueClosure = { keychain, value, storageKey in
|
||||
let storeValueClosure: StoreValueClosure = { keychain, value, storageKey in
|
||||
do {
|
||||
return .success(try keychain.set(value, key: storageKey.rawValue))
|
||||
} catch {
|
||||
|
|
@ -48,6 +48,6 @@ public final class StringValueKeychainStorage: BaseSingleValueKeychainStorage<St
|
|||
super.init(keychain: keychain,
|
||||
storageKey: storageKey,
|
||||
getValueClosure: getValueClosure,
|
||||
setValueClosure: setValueClosure)
|
||||
storeValueClosure: storeValueClosure)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
//
|
||||
// Copyright (c) 2023 Touch Instinct
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the Software), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
import os
|
||||
|
||||
open class DefaultOSLogErrorLogger: ErrorLogger {
|
||||
public var log: OSLog
|
||||
|
||||
public init(log: OSLog) {
|
||||
self.log = log
|
||||
}
|
||||
|
||||
public convenience init(subsystem: String, category: String) {
|
||||
self.init(log: OSLog(subsystem: subsystem, category: category))
|
||||
}
|
||||
|
||||
open func log(error: Error, file: StaticString, line: Int) {
|
||||
os_log("%{public}s:%{public}d %{public}s",
|
||||
log: log,
|
||||
type: .error,
|
||||
file.debugDescription,
|
||||
line,
|
||||
error.localizedDescription)
|
||||
}
|
||||
}
|
||||
|
|
@ -20,6 +20,8 @@
|
|||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
public protocol FingerprintsSecureStorage {
|
||||
var knownPins: [String: Set<String>] { get set }
|
||||
import Foundation
|
||||
|
||||
public protocol ErrorLogger {
|
||||
func log(error: Error, file: StaticString, line: Int)
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'TILogging'
|
||||
s.version = '1.45.0'
|
||||
s.summary = 'Logging for TI libraries.'
|
||||
s.homepage = 'https://git.svc.touchin.ru/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name
|
||||
s.license = { :type => 'MIT', :file => 'LICENSE' }
|
||||
s.author = { 'petropavel13' => 'ivan.smolin@touchin.ru' }
|
||||
s.source = { :git => 'https://git.svc.touchin.ru/TouchInstinct/LeadKit.git', :tag => s.version.to_s }
|
||||
|
||||
s.ios.deployment_target = '11.0'
|
||||
s.swift_versions = ['5.7']
|
||||
|
||||
s.source_files = s.name + '/Sources/**/*'
|
||||
|
||||
end
|
||||
|
|
@ -45,6 +45,6 @@ public struct CALayerDrawingOperation: DrawingOperation {
|
|||
|
||||
context.concatenate(offsetTransform)
|
||||
layer.render(in: context)
|
||||
offsetTransform.concatenating(offsetTransform.inverted())
|
||||
context.concatenate(offsetTransform.inverted())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,33 +20,64 @@
|
|||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
import TIFoundationUtils
|
||||
import TILogging
|
||||
|
||||
open class DefaultFingerprintsProvider: FingerprintsProvider {
|
||||
public var secureStorage: FingerprintsSecureStorage
|
||||
public var settingsStorage: FingerprintsSettingsStorage
|
||||
public typealias FingerprintsMapping = [String: Set<String>]
|
||||
|
||||
public init(secureStorage: FingerprintsSecureStorage,
|
||||
settingsStorage: FingerprintsSettingsStorage,
|
||||
bundledFingerprints: [String: Set<String>]) {
|
||||
public var secureStorage: AnySingleValueStorage<FingerprintsMapping, StorageError>
|
||||
public var bundledFingerprints: FingerprintsMapping
|
||||
public var errorLogger: ErrorLogger
|
||||
|
||||
self.secureStorage = secureStorage
|
||||
self.settingsStorage = settingsStorage
|
||||
public init<Storage: SingleValueStorage>(secureStorage: Storage,
|
||||
bundledFingerprints: FingerprintsMapping,
|
||||
errorLogger: ErrorLogger = TINetworkingLogger(category: "Fingerprints"))
|
||||
where Storage.ValueType == FingerprintsMapping, Storage.ErrorType == StorageError {
|
||||
|
||||
if settingsStorage.shouldResetFingerprints {
|
||||
self.secureStorage.knownPins = bundledFingerprints
|
||||
self.settingsStorage.shouldResetFingerprints = false
|
||||
} else {
|
||||
self.secureStorage.knownPins.merge(bundledFingerprints) { storedFingerprints, bundleFingerprints in
|
||||
storedFingerprints.union(bundleFingerprints)
|
||||
self.secureStorage = secureStorage.eraseToAnySingleValueStorate()
|
||||
self.bundledFingerprints = bundledFingerprints
|
||||
self.errorLogger = errorLogger
|
||||
|
||||
let fingerprintsUpdateResult = secureStorage
|
||||
.getValue()
|
||||
.map {
|
||||
$0.merging(bundledFingerprints) { storedFingerprints, bundleFingerprints in
|
||||
storedFingerprints.union(bundleFingerprints)
|
||||
}
|
||||
}
|
||||
.flatMap {
|
||||
secureStorage.store(value: $0)
|
||||
}
|
||||
|
||||
if case let .failure(storageError) = fingerprintsUpdateResult {
|
||||
errorLogger.log(error: storageError, file: #file, line: #line)
|
||||
}
|
||||
}
|
||||
|
||||
public func fingerprints(forHost host: String) -> Set<String> {
|
||||
secureStorage.knownPins[host] ?? []
|
||||
open func fingerprints(forHost host: String) -> Set<String> {
|
||||
(try? secureStorage
|
||||
.getValue()
|
||||
.flatMapError { _ -> Result<FingerprintsMapping, StorageError> in
|
||||
.success(bundledFingerprints)
|
||||
}
|
||||
.get())?[host] ?? []
|
||||
}
|
||||
|
||||
public func add(fingerprints: [String], forHost host: String) {
|
||||
let pinsForHost = (secureStorage.knownPins[host] ?? []).union(fingerprints)
|
||||
secureStorage.knownPins.updateValue(pinsForHost, forKey: host)
|
||||
open func add(fingerprints: Set<String>, forHost host: String) {
|
||||
let fingerprintsUpdateResult = secureStorage
|
||||
.getValue()
|
||||
.map {
|
||||
$0.merging([host: fingerprints]) { storedFingerprints, addedFingerprints in
|
||||
storedFingerprints.union(addedFingerprints)
|
||||
}
|
||||
}
|
||||
.flatMap {
|
||||
secureStorage.store(value: $0)
|
||||
}
|
||||
|
||||
if case let .failure(storageError) = fingerprintsUpdateResult {
|
||||
errorLogger.log(error: storageError, file: #file, line: #line)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,29 +23,16 @@
|
|||
import TIFoundationUtils
|
||||
import Foundation
|
||||
|
||||
open class DefaultFingerprintsSettingsStorage: FingerprintsSettingsStorage {
|
||||
open class FingerprintsReinstallChecker: AppReinstallChecker {
|
||||
public enum Defaults {
|
||||
public static var shouldResetFingerprintsKey: StorageKey<Bool> {
|
||||
.init(rawValue: "shouldResetFingerprints")
|
||||
}
|
||||
}
|
||||
|
||||
private let reinstallChecker: AppReinstallChecker
|
||||
public override init(defaultsStorage: UserDefaults = .standard,
|
||||
storageKey: StorageKey<Bool> = Defaults.shouldResetFingerprintsKey) {
|
||||
|
||||
// MARK: - PinCodeSettingsStorage
|
||||
|
||||
open var shouldResetFingerprints: Bool {
|
||||
get {
|
||||
reinstallChecker.isAppFirstRun
|
||||
}
|
||||
set {
|
||||
reinstallChecker.isAppFirstRun = newValue
|
||||
}
|
||||
}
|
||||
|
||||
public init(defaultsStorage: UserDefaults = .standard,
|
||||
storageKey: StorageKey<Bool> = Defaults.shouldResetFingerprintsKey) {
|
||||
|
||||
self.reinstallChecker = AppReinstallChecker(defaultsStorage: defaultsStorage, storageKey: storageKey)
|
||||
super.init(defaultsStorage: defaultsStorage, storageKey: storageKey)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,5 +22,5 @@
|
|||
|
||||
public protocol FingerprintsProvider {
|
||||
func fingerprints(forHost host: String) -> Set<String>
|
||||
func add(fingerprints: [String], forHost host: String)
|
||||
func add(fingerprints: Set<String>, forHost host: String)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// Copyright (c) 2022 Touch Instinct
|
||||
// Copyright (c) 2023 Touch Instinct
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the Software), to deal
|
||||
|
|
@ -20,7 +20,11 @@
|
|||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
public protocol FingerprintsSettingsStorage {
|
||||
/// Should be true by default (on app first run)
|
||||
var shouldResetFingerprints: Bool { get set }
|
||||
import TILogging
|
||||
import os
|
||||
|
||||
public final class TINetworkingLogger: DefaultOSLogErrorLogger {
|
||||
public init(category: String) {
|
||||
super.init(log: OSLog(subsystem: "TINetworking", category: category))
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
TILogging
|
||||
TISwiftUtils
|
||||
TIPagination
|
||||
TIFoundationUtils
|
||||
|
|
|
|||
Loading…
Reference in New Issue