Skip to content

Commit f86cd91

Browse files
committed
Refactor OATHSample
1 parent 88f5844 commit f86cd91

File tree

9 files changed

+371
-247
lines changed

9 files changed

+371
-247
lines changed

Samples/OATHSample/OATHSample.xcodeproj/project.pbxproj

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@
1111
51A1AC10273D537500F999A4 /* OATHListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51A1AC0F273D537500F999A4 /* OATHListView.swift */; };
1212
51A1AC12273D537800F999A4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 51A1AC11273D537800F999A4 /* Assets.xcassets */; };
1313
51A1AC15273D537800F999A4 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 51A1AC14273D537800F999A4 /* Preview Assets.xcassets */; };
14+
6C54A5412E40BA1E00409BD5 /* ConnectionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C54A5402E40BA1E00409BD5 /* ConnectionManager.swift */; };
1415
6C8465302DADB11200788FB7 /* YubiKit in Frameworks */ = {isa = PBXBuildFile; productRef = 6C84652F2DADB11200788FB7 /* YubiKit */; };
1516
6C8465332DADB13300788FB7 /* YubiKit in Frameworks */ = {isa = PBXBuildFile; productRef = 6C8465322DADB13300788FB7 /* YubiKit */; };
16-
B41B61882743FE18004C37BF /* OATHListModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B41B61872743FE18004C37BF /* OATHListModel.swift */; };
1717
B456E217274E750D004471DE /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B456E216274E750D004471DE /* SettingsView.swift */; };
18-
B456E219274FC967004471DE /* SettingsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B456E218274FC967004471DE /* SettingsModel.swift */; };
18+
B456E219274FC967004471DE /* Model.swift in Sources */ = {isa = PBXBuildFile; fileRef = B456E218274FC967004471DE /* Model.swift */; };
1919
B4F937582B5150D60007D394 /* YubiKit in Frameworks */ = {isa = PBXBuildFile; productRef = B4F937572B5150D60007D394 /* YubiKit */; };
2020
/* End PBXBuildFile section */
2121

@@ -26,12 +26,12 @@
2626
51A1AC11273D537800F999A4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
2727
51A1AC14273D537800F999A4 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
2828
51A1AC29273D5D0A00F999A4 /* YubiKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = YubiKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
29-
B41B61872743FE18004C37BF /* OATHListModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OATHListModel.swift; sourceTree = "<group>"; };
29+
6C54A5402E40BA1E00409BD5 /* ConnectionManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionManager.swift; sourceTree = "<group>"; };
3030
B4451EFB275F924D002690BB /* OATHSample.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = OATHSample.entitlements; sourceTree = "<group>"; };
3131
B4451EFC275F924D002690BB /* ExternalAccessory.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ExternalAccessory.framework; path = System/Library/Frameworks/ExternalAccessory.framework; sourceTree = SDKROOT; };
3232
B4451EFE275F940E002690BB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
3333
B456E216274E750D004471DE /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = "<group>"; };
34-
B456E218274FC967004471DE /* SettingsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsModel.swift; sourceTree = "<group>"; };
34+
B456E218274FC967004471DE /* Model.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Model.swift; sourceTree = "<group>"; };
3535
/* End PBXFileReference section */
3636

3737
/* Begin PBXFrameworksBuildPhase section */
@@ -72,9 +72,9 @@
7272
B4451EFB275F924D002690BB /* OATHSample.entitlements */,
7373
51A1AC0D273D537500F999A4 /* OATHSampleApp.swift */,
7474
51A1AC0F273D537500F999A4 /* OATHListView.swift */,
75-
B41B61872743FE18004C37BF /* OATHListModel.swift */,
7675
B456E216274E750D004471DE /* SettingsView.swift */,
77-
B456E218274FC967004471DE /* SettingsModel.swift */,
76+
B456E218274FC967004471DE /* Model.swift */,
77+
6C54A5402E40BA1E00409BD5 /* ConnectionManager.swift */,
7878
51A1AC11273D537800F999A4 /* Assets.xcassets */,
7979
51A1AC13273D537800F999A4 /* Preview Content */,
8080
);
@@ -176,9 +176,9 @@
176176
isa = PBXSourcesBuildPhase;
177177
buildActionMask = 2147483647;
178178
files = (
179-
B456E219274FC967004471DE /* SettingsModel.swift in Sources */,
179+
B456E219274FC967004471DE /* Model.swift in Sources */,
180+
6C54A5412E40BA1E00409BD5 /* ConnectionManager.swift in Sources */,
180181
B456E217274E750D004471DE /* SettingsView.swift in Sources */,
181-
B41B61882743FE18004C37BF /* OATHListModel.swift in Sources */,
182182
51A1AC10273D537500F999A4 /* OATHListView.swift in Sources */,
183183
51A1AC0E273D537500F999A4 /* OATHSampleApp.swift in Sources */,
184184
);
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
// Copyright Yubico AB
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
import Foundation
16+
import SwiftUI
17+
import YubiKit
18+
19+
@MainActor
20+
final class ConnectionManager: ObservableObject {
21+
22+
static let shared = ConnectionManager()
23+
24+
@Published private(set) var wiredConnection: SmartCardConnection?
25+
#if os(iOS)
26+
@Published private(set) var nfcConnection: NFCSmartCardConnection?
27+
#endif
28+
29+
@Published var error: Error?
30+
31+
private var wiredConnectionTask: Task<Void, Never>?
32+
33+
private init() {
34+
startWiredConnection()
35+
}
36+
37+
private func startWiredConnection() {
38+
wiredConnectionTask = Task { @MainActor in
39+
while !Task.isCancelled {
40+
do {
41+
error = nil
42+
guard !Task.isCancelled else { return }
43+
44+
let newConnection = try await WiredSmartCardConnection.connection()
45+
guard !Task.isCancelled else { return }
46+
47+
wiredConnection = newConnection
48+
49+
let closeError = await newConnection.connectionDidClose()
50+
51+
wiredConnection = nil
52+
53+
if let closeError = closeError {
54+
error = closeError
55+
}
56+
} catch {
57+
if error is CancellationError { return }
58+
self.error = error
59+
}
60+
}
61+
}
62+
}
63+
64+
#if os(iOS)
65+
func requestNFCConnection() async {
66+
error = nil
67+
68+
do {
69+
nfcConnection = try await NFCSmartCardConnection.connection() as? NFCSmartCardConnection
70+
} catch {
71+
self.error = error
72+
}
73+
}
74+
75+
func closeNFCConnection(message: String? = nil) async {
76+
error = nil
77+
78+
await nfcConnection?.close(message: message)
79+
}
80+
#endif
81+
}
82+
83+
extension SmartCardConnection {
84+
var connectionType: String {
85+
switch self {
86+
case _ as NFCSmartCardConnection:
87+
return "NFC"
88+
case _ as LightningSmartCardConnection:
89+
return "Lightning"
90+
case _ as SmartCardConnection:
91+
return "USB"
92+
default:
93+
return "Unknown"
94+
}
95+
}
96+
}
97+
98+
extension Optional where Wrapped == SmartCardConnection {
99+
var connectionType: String {
100+
guard let connection = self else {
101+
return "No Connection"
102+
}
103+
104+
return connection.connectionType
105+
}
106+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// Copyright Yubico AB
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
import Foundation
16+
import YubiKit
17+
18+
struct Account: Identifiable {
19+
var id = UUID()
20+
let label: String
21+
let code: String?
22+
let issuer: String?
23+
let type: OATHSession.CredentialType
24+
}
25+
26+
@MainActor
27+
class Model: ObservableObject {
28+
29+
@Published private(set) var accounts = [Account]()
30+
@Published private(set) var keyVersion: String?
31+
@Published private(set) var connectionType: String?
32+
@Published var error: Error?
33+
34+
func update(using connection: SmartCardConnection) async {
35+
await calculateCodes(using: connection)
36+
await getKeyVersion(using: connection)
37+
connectionType = connection.connectionType
38+
}
39+
40+
func clear() {
41+
accounts = []
42+
keyVersion = nil
43+
connectionType = nil
44+
}
45+
46+
private func getKeyVersion(using connection: SmartCardConnection) async {
47+
do {
48+
let session = try await ManagementSession.session(withConnection: connection)
49+
self.keyVersion = session.version.description
50+
} catch {
51+
self.error = error
52+
}
53+
}
54+
55+
private func calculateCodes(using connection: SmartCardConnection) async {
56+
do {
57+
let session = try await OATHSession.session(withConnection: connection)
58+
let result = try await session.calculateCodes()
59+
accounts = result.map { credential, code in
60+
Account(
61+
label: credential.label,
62+
code: code?.code,
63+
issuer: credential.issuer,
64+
type: credential.type
65+
)
66+
}
67+
} catch {
68+
self.error = error
69+
}
70+
}
71+
}

Samples/OATHSample/OATHSample/OATHListModel.swift

Lines changed: 0 additions & 118 deletions
This file was deleted.

0 commit comments

Comments
 (0)