TF-250 Basic structure

This commit is contained in:
Zbigniew Cisiński 2024-03-21 00:40:59 +01:00
parent d223770737
commit 02ed735ac0
68 changed files with 2374 additions and 42 deletions

View File

@ -108,6 +108,7 @@ public extension TintColor {
}
}
#if os(iOS)
var color: UIColor {
let bundle = Bundle(for: CountdownTimer.self)
switch self {
@ -124,4 +125,5 @@ public extension TintColor {
case .brown: return UIColor(named: "tintBrownColor", in: bundle, compatibleWith: nil)!
}
}
#endif
}

View File

@ -18,7 +18,11 @@
//
import UIKit
#if os(iOS)
import Common
#elseif os(watchOS)
import CommonWatch
#endif
public protocol IconDescriptionDatabase: AnyObject {
func name(for iconTypeID: IconTypeID) -> String?

View File

@ -18,7 +18,11 @@
//
import Foundation
#if os(iOS)
import Common
#elseif os(watchOS)
import CommonWatch
#endif
// swiftlint:disable all
final class IconDescriptionDatabaseGenerated {

View File

@ -18,7 +18,11 @@
//
import UIKit
#if os(iOS)
import Common
#elseif os(watchOS)
import CommonWatch
#endif
public protocol ServiceDefinitionDatabase: AnyObject {
func listAll() -> [ServiceDefinition]

View File

@ -18,7 +18,11 @@
//
import UIKit
#if os(iOS)
import Common
#elseif os(watchOS)
import CommonWatch
#endif
// swiftlint:disable all
final class ServiceDefinitionDatabaseGenerated {

View File

@ -20,7 +20,11 @@
import Foundation
import CryptoKit
import CommonCrypto
#if os(iOS)
import Common
#elseif os(watchOS)
import CommonWatch
#endif
public final class ExchangeFileEncryption {
public struct EncryptionResult {

View File

@ -18,7 +18,11 @@
//
import Foundation
#if os(iOS)
import Common
#elseif os(watchOS)
import CommonWatch
#endif
public final class LocalKeyEncryption: CommonLocalKeyEncryption {
private let encryption = KeyEncryption(

View File

@ -0,0 +1,54 @@
//
// This file is part of the 2FAS iOS app (https://github.com/twofas/2fas-ios)
// Copyright © 2024 Two Factor Authentication Service, Inc.
// Contributed by Zbigniew Cisiński. All rights reserved.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>
//
import Foundation
extension Protection.CodeType: RawRepresentable {
private enum Keys {
static let PIN4 = "PIN4"
static let PIN6 = "PIN6"
}
public typealias RawValue = String
public init?(rawValue: String) {
if rawValue == Keys.PIN4 {
self = .PIN4
} else if rawValue == Keys.PIN6 {
self = .PIN6
} else {
return nil
}
}
public var rawValue: String {
switch self {
case .PIN4: return Keys.PIN4
case .PIN6: return Keys.PIN6
}
}
}
public extension Protection.CodeType {
var intValue: Int {
switch self {
case .PIN4: return 4
case .PIN6: return 6
}
}
}

View File

@ -18,12 +18,16 @@
//
import Foundation
#if os(iOS)
import Common
#elseif os(watchOS)
import CommonWatch
#endif
public final class Protection {
public typealias PIN = String
public enum CodeType {
public enum CodeType: CaseIterable {
case PIN4
case PIN6
}
@ -32,7 +36,7 @@ public final class Protection {
let PINvalue: PIN
let codeType: CodeType
}
#if os(iOS)
private let encryptedStorage: LocalEncryptedStorage
public let biometricAuth: BiometricAuth
@ -53,40 +57,15 @@ public final class Protection {
migrationHandler = MigrationHandler(storage: encryptedStorage)
migrationHandler.migrateIfNeeded()
}
#elseif os(watchOS)
// private let encryptedStorage: LocalEncryptedStorage
// public let codeStorage: CodeStorage
public let localKeyEncryption: CommonLocalKeyEncryption
//
public init() {
// encryptedStorage = LocalEncryptedStorage(defaults: UserDefaults(suiteName: Config.suiteName)!)
// codeStorage = CodeStorage(storage: encryptedStorage)
localKeyEncryption = LocalKeyEncryption()
}
#endif
}
extension Protection.CodeType: RawRepresentable {
private enum Keys {
static let PIN4 = "PIN4"
static let PIN6 = "PIN6"
}
public typealias RawValue = String
public init?(rawValue: String) {
if rawValue == Keys.PIN4 {
self = .PIN4
} else if rawValue == Keys.PIN6 {
self = .PIN6
} else {
return nil
}
}
public var rawValue: String {
switch self {
case .PIN4: return Keys.PIN4
case .PIN6: return Keys.PIN6
}
}
}
public extension Protection.CodeType {
var intValue: Int {
switch self {
case .PIN4: return 4
case .PIN6: return 6
}
}
}
extension Protection.CodeType: CaseIterable {}

View File

@ -18,7 +18,11 @@
//
import Foundation
#if os(iOS)
import Common
#elseif os(watchOS)
import CommonWatch
#endif
import CloudKit
final class ClearHandler {

View File

@ -19,7 +19,11 @@
import Foundation
import CloudKit
#if os(iOS)
import Common
#elseif os(watchOS)
import CommonWatch
#endif
enum CloudAvailabilityStatus {
case available

View File

@ -18,7 +18,11 @@
//
import UIKit
#if os(iOS)
import Common
#elseif os(watchOS)
import CommonWatch
#endif
public enum CloudCurrentState: Equatable {
public enum NotAvailableReason: Equatable {
@ -52,10 +56,12 @@ public protocol CloudHandlerType: AnyObject {
typealias SecretSyncError = (String) -> Void
func registerForStateChange(_ listener: @escaping CloudHandlerStateListener, with id: String)
#if os(iOS)
func didReceiveRemoteNotification(
userInfo: [AnyHashable: Any],
fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void
)
#endif
func unregisterForStateChange(id: String)
var userToggledState: UserToggledState? { get set }
@ -211,6 +217,7 @@ final class CloudHandler: CloudHandlerType {
}
}
#if os(iOS)
func didReceiveRemoteNotification(
userInfo: [AnyHashable: Any],
fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void
@ -224,6 +231,7 @@ final class CloudHandler: CloudHandlerType {
return
}
}
#endif
var isConnected: Bool {
switch currentState {

View File

@ -19,8 +19,12 @@
import Foundation
import CloudKit
import Common
#if os(iOS)
import UIKit
import Common
#elseif os(watchOS)
import CommonWatch
#endif
final class CloudKit {
typealias DeletedEntries = ([(name: String, type: String)]) -> Void
@ -474,6 +478,7 @@ final class CloudKit {
zoneUpdated = false
DispatchQueue.main.async {
#if os(iOS)
if UIApplication.shared.applicationState == .background {
self.abortSync?()
self.syncTokenHandler.prepare()
@ -482,6 +487,7 @@ final class CloudKit {
self.operation = nil
return
}
#endif
if !self.deletedRecords.isEmpty {
Log("CloudKit - deletedRecords not empty", module: .cloudSync)

View File

@ -0,0 +1,98 @@
//
// This file is part of the 2FAS iOS app (https://github.com/twofas/2fas-ios)
// Copyright © 2023 Two Factor Authentication Service, Inc.
// Contributed by Zbigniew Cisiński. All rights reserved.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>
//
import Foundation
import CommonWatch
final class CommonItemHandler {
init() {
// commonSectionHandler.commonDidCreate = { [weak self] sectionID in
// Log("CommonItemHandler - commonSectionHandler - commonDidCreate", module: .cloudSync)
// self?.logHandler.log(entityID: sectionID, actionType: .created, kind: .section)
// }
// commonSectionHandler.commonDidModify = { [weak self] sectionIDs in
// Log("CommonItemHandler - commonSectionHandler - commonDidModify", module: .cloudSync)
// sectionIDs.forEach {
// self?.logHandler.log(entityID: $0, actionType: .modified, kind: .section)
// }
// }
// commonSectionHandler.commonDidDelete = { [weak self] sectionID in
// Log("CommonItemHandler - commonSectionHandler - commonDidDelete", module: .cloudSync)
// self?.logHandler.log(entityID: sectionID, actionType: .deleted, kind: .section)
// }
//
// commonServiceHandler.commonDidCreate = { [weak self] secret in
// Log("CommonItemHandler - commonServiceHandler - commonDidCreate", module: .cloudSync)
// self?.logHandler.log(entityID: secret, actionType: .created, kind: .service2)
// }
// commonServiceHandler.commonDidModify = { [weak self] secrets in
// Log("CommonItemHandler - commonServiceHandler - commonDidModify", module: .cloudSync)
// secrets.forEach {
// self?.logHandler.log(entityID: $0, actionType: .modified, kind: .service2)
// }
// }
// commonServiceHandler.commonDidDelete = { [weak self] secret in
// Log("CommonItemHandler - commonServiceHandler - commonDidDelete", module: .cloudSync)
// self?.logHandler.log(entityID: secret, actionType: .deleted, kind: .service2)
// }
}
func logFirstImport() {
// logHandler.logFirstImport(entityIDs: commonSectionHandler.getAllSections().map { $0.sectionID }, kind: .section)
// logHandler.logFirstImport(entityIDs: commonServiceHandler.getAllServices().map { $0.secret }, kind: .service2)
// logHandler.logFirstImport(entityIDs: [Info.id], kind: .info)
}
func setItems(_ items: [RecordType: [Any]]) -> Bool {
// var newDataWasSet = false
//
// if let sections = items[.section] as? [CommonSectionData] {
// Log("CommonItemHandler: sections (\(sections.count))")
// let value = commonSectionHandler.setSections(sections)
// newDataWasSet = newDataWasSet || value
// }
//
// if let services = items[.service2] as? [ServiceData] {
// Log("CommonItemHandler: services (\(services.count))")
// let value = commonServiceHandler.setServices(services)
// newDataWasSet = newDataWasSet || value
// }
//
// return newDataWasSet
false
}
func setItemsFromMigration(_ serviceDataToAppend: [ServiceData]) {
// Log("CommonItemHandler: setting items from migration (\(serviceDataToAppend.count))")
// itemsToAppend = serviceDataToAppend
}
func getAllItems() -> [RecordType: [Any]] {
// let sections = commonSectionHandler.getAllSections()
// let services = commonServiceHandler.getAllServices() + itemsToAppend
// itemsToAppend = []
// var value = [RecordType: [Any]]()
// value[.section] = sections
// value[.service2] = services
// value[.info] = [Info()]
// return value
[:]
}
}

View File

@ -19,7 +19,11 @@
import Foundation
import CloudKit
#if os(iOS)
import Common
#elseif os(watchOS)
import CommonWatch
#endif
enum InfoEntryKey: String {
case version

View File

@ -19,8 +19,13 @@
import Foundation
import CloudKit
#if os(iOS)
import Common
import Protection
#elseif os(watchOS)
import CommonWatch
import ProtectionWatch
#endif
final class ItemHandler {
typealias SecretError = (String) -> Void

View File

@ -0,0 +1,126 @@
//
// This file is part of the 2FAS iOS app (https://github.com/twofas/2fas-ios)
// Copyright © 2023 Two Factor Authentication Service, Inc.
// Contributed by Zbigniew Cisiński. All rights reserved.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>
//
import Foundation
import CloudKit
import CommonWatch
import ContentWatch
final class ItemHandlerMigrationProxy {
var newerVersion: (() -> Void)?
var cloudEncrypted: (() -> Void)?
private let itemHandler: ItemHandler
private var isFirstStart = false
private var deletedEntries: [EntityOfKind] = []
private var updatedCreated: [CKRecord] = []
private var itemsToDelete: [CKRecord.ID] = []
private var itemsToAdd: [ServiceData] = []
init(itemHandler: ItemHandler) {
self.itemHandler = itemHandler
}
func firstStart() {
Log("Migration proxy - first start!", module: .cloudSync)
isFirstStart = true
}
}
extension ItemHandlerMigrationProxy: ItemHandling {
func commit() {
Log("Migration proxy - commit", module: .cloudSync)
if isFirstStart {
if let infoRecord = updatedCreated.first(where: { RecordType(rawValue: $0.recordType) == .info }) {
let info = InfoRecord(record: infoRecord)
if info.version > Info().version {
Log("Migration proxy - newer version! Aborting...", module: .cloudSync)
newerVersion?()
return
}
if let encryption = Info.Encryption(rawValue: info.encryption), encryption == .user {
Log("Migration proxy - cloud encrypted! Aborting...", module: .cloudSync)
cloudEncrypted?()
return
}
}
isFirstStart = false
}
itemHandler.deleteEntries(deletedEntries)
itemHandler.updateOrCreate(with: updatedCreated)
deletedEntries = []
updatedCreated = []
}
func purge() {
itemHandler.purge()
}
func itemsToDeleteAfterMigration() -> [CKRecord.ID] {
let list = itemsToDelete
itemsToDelete = []
return list
}
func servicesToAppend() -> [ServiceData] {
let services = itemsToAdd
itemsToAdd = []
return services
}
func listAllCommonItems() -> [RecordType: [Any]] {
itemHandler.listAllCommonItems()
}
func findItemsRecordIDs(for items: [EntityOfKind], zoneID: CKRecordZone.ID) -> [CKRecord.ID] {
itemHandler.findItemsRecordIDs(for: items, zoneID: zoneID)
}
func filterDeleted(from items: [RecordType: [Any]], deleted: [EntityOfKind]) -> [RecordType: [Any]] {
itemHandler.filterDeleted(from: items, deleted: deleted)
}
func findItem(for item: Any, type: RecordType, in items: [RecordType: [Any]]) -> CommonDataIndex? {
itemHandler.findItem(for: item, type: type, in: items)
}
func findItemForEntryID(_ entryID: String, type: RecordType, in items: [RecordType: [Any]]) -> CommonDataIndex? {
itemHandler.findItemForEntryID(entryID, type: type, in: items)
}
func record(for type: RecordType, item: Any, modifiedData from: [RecordType: [Any]]) -> CKRecord? {
itemHandler.record(for: type, item: item, modifiedData: from)
}
func record(for type: RecordType, item: Any, index: Int, zoneID: CKRecordZone.ID, allItems: [Any]) -> CKRecord? {
itemHandler.record(for: type, item: item, index: index, zoneID: zoneID, allItems: allItems)
}
func deleteEntries(_ entries: [EntityOfKind]) {
deletedEntries = entries
}
func updateOrCreate(with entries: [CKRecord]) {
updatedCreated = entries
}
}

View File

@ -19,7 +19,11 @@
import Foundation
import CoreData
#if os(iOS)
import Common
#elseif os(watchOS)
import CommonWatch
#endif
@objc(LogEntity)
final class LogEntity: NSManagedObject {

View File

@ -18,7 +18,11 @@
//
import Foundation
#if os(iOS)
import Common
#elseif os(watchOS)
import CommonWatch
#endif
import CoreData
public enum LogActionType: String {

View File

@ -19,7 +19,11 @@
import Foundation
import CloudKit
#if os(iOS)
import Common
#elseif os(watchOS)
import CommonWatch
#endif
enum CloudKitAction {
enum Reason {

View File

@ -19,7 +19,11 @@
import Foundation
import CoreData
#if os(iOS)
import Common
#elseif os(watchOS)
import CommonWatch
#endif
@objc(DynamicTypesEntityMigrationPolicySync)
final class DynamicTypesEntityMigrationPolicySync: NSEntityMigrationPolicy {

View File

@ -18,7 +18,11 @@
//
import Foundation
#if os(iOS)
import Common
#elseif os(watchOS)
import CommonWatch
#endif
extension ServiceData {
var comparisionDate: Date {

View File

@ -18,7 +18,11 @@
//
import Foundation
#if os(iOS)
import Common
#elseif os(watchOS)
import CommonWatch
#endif
enum SecretValidation {
private static let maxLenght: Int = 255

View File

@ -18,8 +18,12 @@
//
import Foundation
import Common
import CryptoKit
#if os(iOS)
import Common
#elseif os(watchOS)
import CommonWatch
#endif
enum iCloudIdentifier {
private static let v2Identifier = "_V2"

View File

@ -19,7 +19,11 @@
import Foundation
import CoreData
#if os(iOS)
import Common
#elseif os(watchOS)
import CommonWatch
#endif
@objc(SectionCacheEntity)
final class SectionCacheEntity: NSManagedObject {

View File

@ -18,7 +18,11 @@
//
import Foundation
#if os(iOS)
import Common
#elseif os(watchOS)
import CommonWatch
#endif
import CoreData
final class SectionHandler {

View File

@ -19,7 +19,11 @@
import Foundation
import CoreData
#if os(iOS)
import Common
#elseif os(watchOS)
import CommonWatch
#endif
@objc(ServiceCacheEntity)
final class ServiceCacheEntity: NSManagedObject {

View File

@ -18,7 +18,11 @@
//
import Foundation
#if os(iOS)
import Common
#elseif os(watchOS)
import CommonWatch
#endif
extension ServiceCacheEntity {
var serviceData: ServiceData {

View File

@ -18,9 +18,14 @@
//
import Foundation
import Common
import CoreData
#if os(iOS)
import Common
import Protection
#elseif os(watchOS)
import CommonWatch
import ProtectionWatch
#endif
final class ServiceHandler {
private let coreDataStack: CoreDataStack

View File

@ -19,7 +19,11 @@
import Foundation
import CloudKit
#if os(iOS)
import Common
#elseif os(watchOS)
import CommonWatch
#endif
enum ServiceEntryKey: String {
case name

View File

@ -19,7 +19,11 @@
import Foundation
import CloudKit
#if os(iOS)
import Common
#elseif os(watchOS)
import CommonWatch
#endif
enum ServiceEntryKey2: String {
case name

View File

@ -18,7 +18,11 @@
//
import UIKit
#if os(iOS)
import Common
#elseif os(watchOS)
import CommonWatch
#endif
import CloudKit
final class SyncHandler {
@ -32,7 +36,9 @@ final class SyncHandler {
private var timeOffset: Int = 0
#if os(iOS)
private var fromNotificationCompletionHandler: ((UIBackgroundFetchResult) -> Void)?
#endif
typealias OtherError = (NSError) -> Void
@ -91,6 +97,7 @@ final class SyncHandler {
cloudKit.deleteAllEntries = { [weak self] in self?.itemHandler.purge() }
}
#if os(iOS)
func didReceiveRemoteNotification(
userInfo: [AnyHashable: Any],
fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void
@ -106,6 +113,7 @@ final class SyncHandler {
fromNotificationCompletionHandler = completionHandler
synchronize()
}
#endif
func firstStart() {
Log("SyncHandler - first start!", module: .cloudSync)
@ -357,6 +365,7 @@ final class SyncHandler {
return
}
#if os(iOS)
if let fromNotificationCompletionHandler {
if didSetNewData {
fromNotificationCompletionHandler(.newData)
@ -365,14 +374,17 @@ final class SyncHandler {
}
self.fromNotificationCompletionHandler = nil
}
#endif
finishedSync?()
}
private func handleNotificationCompletionHandlerError() {
#if os(iOS)
Log("Sync Handler: handleNotificationCompletionHandlerError", module: .cloudSync)
fromNotificationCompletionHandler?(.failed)
fromNotificationCompletionHandler = nil
#endif
}
private func resetStack() {

View File

@ -0,0 +1,97 @@
//
// This file is part of the 2FAS iOS app (https://github.com/twofas/2fas-ios)
// Copyright © 2023 Two Factor Authentication Service, Inc.
// Contributed by Zbigniew Cisiński. All rights reserved.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>
//
import Foundation
import CloudKit
import CommonWatch
public enum SyncInstanceWatch {
private static var cloudHandler: CloudHandlerType!
public static func initialize() {
let logHandler = LogHandler(coreDataStack: coreDataStack)
let sectionHandler = SectionHandler(coreDataStack: coreDataStack)
let serviceHandler = ServiceHandler(coreDataStack: coreDataStack)
let infoHandler = InfoHandler()
let commonItemHandler = CommonItemHandler()
let cloudKit = CloudKit()
let itemHandler = ItemHandler(
sectionHandler: sectionHandler,
serviceHandler: serviceHandler,
infoHandler: infoHandler,
logHandler: logHandler
)
let itemHandlerMigrationProxy = ItemHandlerMigrationProxy(
itemHandler: itemHandler
)
let syncHandler = SyncHandler(
itemHandler: itemHandlerMigrationProxy,
commonItemHandler: commonItemHandler,
logHandler: logHandler,
cloudKit: cloudKit
)
let cloudAvailability = CloudAvailability(container: syncHandler.container)
cloudHandler = CloudHandler(
cloudAvailability: cloudAvailability,
syncHandler: syncHandler,
itemHandler: itemHandler,
itemHandlerMigrationProxy: itemHandlerMigrationProxy,
cloudKit: cloudKit
)
coreDataStack.performInBackground { context in
Log("Migrating if needed. Trigger value \(context.hasChanges)", module: .cloudSync)
}
}
public static func getCloudHandler() -> CloudHandlerType { cloudHandler }
private static let coreDataStack = CoreDataStack(
readOnly: false,
name: "Sync",
bundle: Bundle(for: SyncHandler.self),
migrator: CoreDataMigrator(
momdSubdirectory: "Sync",
versions: [
CoreDataMigrationVersion(rawValue: "Sync"),
CoreDataMigrationVersion(rawValue: "Sync2"),
CoreDataMigrationVersion(rawValue: "Sync3"),
CoreDataMigrationVersion(rawValue: "Sync4"),
CoreDataMigrationVersion(rawValue: "Sync5")
]) { _, toVersion in
if toVersion.rawValue == "Sync5" {
Log("Migrating to Sync5!", module: .cloudSync)
SyncInstanceWatch.cloudHandler.resetStateBeforeSync()
}
}
)
}
private final class CommonServiceHandlerImpl: CommonServiceHandler {
var commonDidDelete: CommonDidDelete?
var commonDidModify: CommonDidModify?
var commonDidCreate: CommonDidCreate?
func setServices(_ servicesservices: [ServiceData]) -> Bool {
false
}
func getAllServices() -> [ServiceData] {
[]
}
}

View File

@ -19,7 +19,11 @@
import Foundation
import CloudKit
#if os(iOS)
import Common
#elseif os(watchOS)
import CommonWatch
#endif
final class SyncTokenHandler {
private var databaseChangeToken: CKServerChangeToken?

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1530"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"
buildArchitectures = "Automatic">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "C274C9E42BAB8B92008E7212"
BuildableName = "CommonWatch.framework"
BlueprintName = "CommonWatch"
ReferencedContainer = "container:TwoFAS.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "C274C9E42BAB8B92008E7212"
BuildableName = "CommonWatch.framework"
BlueprintName = "CommonWatch"
ReferencedContainer = "container:TwoFAS.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1530"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"
buildArchitectures = "Automatic">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "C274CA242BAB8BE3008E7212"
BuildableName = "ContentWatch.framework"
BlueprintName = "ContentWatch"
ReferencedContainer = "container:TwoFAS.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "C274CA242BAB8BE3008E7212"
BuildableName = "ContentWatch.framework"
BlueprintName = "ContentWatch"
ReferencedContainer = "container:TwoFAS.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1530"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"
buildArchitectures = "Automatic">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "C274CA582BAB8C3F008E7212"
BuildableName = "ProtectionWatch.framework"
BlueprintName = "ProtectionWatch"
ReferencedContainer = "container:TwoFAS.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "C274CA582BAB8C3F008E7212"
BuildableName = "ProtectionWatch.framework"
BlueprintName = "ProtectionWatch"
ReferencedContainer = "container:TwoFAS.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1530"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"
buildArchitectures = "Automatic">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "C274C98C2BAB89C7008E7212"
BuildableName = "SyncWatch.framework"
BlueprintName = "SyncWatch"
ReferencedContainer = "container:TwoFAS.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "C274C98C2BAB89C7008E7212"
BuildableName = "SyncWatch.framework"
BlueprintName = "SyncWatch"
ReferencedContainer = "container:TwoFAS.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -0,0 +1,94 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1530"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"
buildArchitectures = "Automatic">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "C274C9CC2BAB8ABB008E7212"
BuildableName = "TwoFASWatch Watch App.app"
BlueprintName = "TwoFASWatch Watch App"
ReferencedContainer = "container:TwoFAS.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "C23666721FB2644900989ACA"
BuildableName = "TwoFAS.app"
BlueprintName = "TwoFAS"
ReferencedContainer = "container:TwoFAS.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES"
launchAutomaticallySubstyle = "8">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "C274C9CC2BAB8ABB008E7212"
BuildableName = "TwoFASWatch Watch App.app"
BlueprintName = "TwoFASWatch Watch App"
ReferencedContainer = "container:TwoFAS.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES"
launchAutomaticallySubstyle = "8">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "C274C9CC2BAB8ABB008E7212"
BuildableName = "TwoFASWatch Watch App.app"
BlueprintName = "TwoFASWatch Watch App"
ReferencedContainer = "container:TwoFAS.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -0,0 +1,92 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1530"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"
buildArchitectures = "Automatic">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "C274C9CC2BAB8ABB008E7212"
BuildableName = "TwoFASWatch Watch App.app"
BlueprintName = "TwoFASWatch Watch App"
ReferencedContainer = "container:TwoFAS.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "C23666721FB2644900989ACA"
BuildableName = "TwoFAS.app"
BlueprintName = "TwoFAS"
ReferencedContainer = "container:TwoFAS.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "C274C9CC2BAB8ABB008E7212"
BuildableName = "TwoFASWatch Watch App.app"
BlueprintName = "TwoFASWatch Watch App"
ReferencedContainer = "container:TwoFAS.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "C274C9CC2BAB8ABB008E7212"
BuildableName = "TwoFASWatch Watch App.app"
BlueprintName = "TwoFASWatch Watch App"
ReferencedContainer = "container:TwoFAS.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -0,0 +1,11 @@
{
"colors" : [
{
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,13 @@
{
"images" : [
{
"idiom" : "universal",
"platform" : "watchos",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,52 @@
//
// This file is part of the 2FAS iOS app (https://github.com/twofas/2fas-ios)
// Copyright © 2024 Two Factor Authentication Service, Inc.
// Contributed by Zbigniew Cisiński. All rights reserved.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>
//
import SwiftUI
import SyncWatch
import ProtectionWatch
import CommonWatch
struct ContentView: View {
@State var syncStstus = "Hello, world!"
var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundStyle(.tint)
Text(syncStstus)
}
.padding()
.task {
let protection = Protection()
EncryptionHolder.initialize(with: protection.localKeyEncryption)
SyncInstanceWatch.initialize()
let handler = SyncInstanceWatch.getCloudHandler()
handler.registerForStateChange({ state in
syncStstus = "\(state)"
}, with: "listener!")
handler.enable()
handler.synchronize()
}
}
}
#Preview {
ContentView()
}

View File

@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>aps-environment</key>
<string>development</string>
<key>com.apple.developer.icloud-container-identifiers</key>
<array>
<string>iCloud.com.twofas.org.Vault</string>
</array>
<key>com.apple.developer.icloud-services</key>
<array>
<string>CloudKit</string>
</array>
<key>com.apple.developer.ubiquity-kvstore-identifier</key>
<string>$(TeamIdentifierPrefix)$(CFBundleIdentifier)</string>
<key>com.apple.security.application-groups</key>
<array>
<string>group.twofas.com</string>
</array>
</dict>
</plist>

View File

@ -0,0 +1,29 @@
//
// This file is part of the 2FAS iOS app (https://github.com/twofas/2fas-ios)
// Copyright © 2024 Two Factor Authentication Service, Inc.
// Contributed by Zbigniew Cisiński. All rights reserved.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>
//
import SwiftUI
@main
struct TwoFASWatch_Watch_AppApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}