Skip to content

Commit

Permalink
Proper logging using OSLog.
Browse files Browse the repository at this point in the history
  • Loading branch information
jensutbult committed Nov 30, 2023
1 parent aee0d56 commit c65e5a3
Show file tree
Hide file tree
Showing 13 changed files with 121 additions and 118 deletions.
1 change: 0 additions & 1 deletion Samples/OATHSample/OATHSample/OATHListModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ class OATHListModel: ObservableObject {
}

@MainActor func startWiredConnection() {
print("startWiredConnection()")
wiredConnectionTask?.cancel()
wiredConnectionTask = Task {
do {
Expand Down
4 changes: 4 additions & 0 deletions YubiKit/YubiKit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
51BBE3EB273D1A3800DA47CC /* YubiKit.docc in Sources */ = {isa = PBXBuildFile; fileRef = 51BBE3EA273D1A3800DA47CC /* YubiKit.docc */; };
51BBE3F1273D1A3800DA47CC /* YubiKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 51BBE3E6273D1A3800DA47CC /* YubiKit.framework */; };
51BBE3F7273D1A3800DA47CC /* YubiKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 51BBE3E9273D1A3800DA47CC /* YubiKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
B401F7762B17B8DD00C541D1 /* Logger+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B401F7752B17B8DD00C541D1 /* Logger+Extensions.swift */; };
B40528332987C31E00FC33AB /* DeviceInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = B40528322987C31E00FC33AB /* DeviceInfo.swift */; };
B405283729894E7600FC33AB /* DeviceConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = B405283629894E7600FC33AB /* DeviceConfig.swift */; };
B408BA8F2948FA2100001B2F /* Stream+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B408BA8E2948FA2100001B2F /* Stream+Extensions.swift */; };
Expand Down Expand Up @@ -53,6 +54,7 @@
51BBE3E9273D1A3800DA47CC /* YubiKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = YubiKit.h; sourceTree = "<group>"; };
51BBE3EA273D1A3800DA47CC /* YubiKit.docc */ = {isa = PBXFileReference; lastKnownFileType = folder.documentationcatalog; path = YubiKit.docc; sourceTree = "<group>"; };
51BBE3F0273D1A3800DA47CC /* YubiKitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = YubiKitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
B401F7752B17B8DD00C541D1 /* Logger+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Logger+Extensions.swift"; sourceTree = "<group>"; };
B40528322987C31E00FC33AB /* DeviceInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceInfo.swift; sourceTree = "<group>"; };
B405283629894E7600FC33AB /* DeviceConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceConfig.swift; sourceTree = "<group>"; };
B408BA8E2948FA2100001B2F /* Stream+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Stream+Extensions.swift"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -170,6 +172,7 @@
B40BCB7C29422721009F39BD /* Connection+Extensions.swift */,
B408BA8E2948FA2100001B2F /* Stream+Extensions.swift */,
B4F10D4E2AFD39D600F0AFCA /* String+Extensions.swift */,
B401F7752B17B8DD00C541D1 /* Logger+Extensions.swift */,
);
path = Utilities;
sourceTree = "<group>";
Expand Down Expand Up @@ -301,6 +304,7 @@
B456E21B274FCA26004471DE /* ManagementSession.swift in Sources */,
B47FDD992939FAD100AFF70A /* ConnectionHelper.swift in Sources */,
B4451F00275FD2B5002690BB /* APDU.swift in Sources */,
B401F7762B17B8DD00C541D1 /* Logger+Extensions.swift in Sources */,
B47FDD9B293A15AE00AFF70A /* NSLock+Extensions.swift in Sources */,
B456E213274D2403004471DE /* NFCConnection.swift in Sources */,
B408BA8F2948FA2100001B2F /* Stream+Extensions.swift in Sources */,
Expand Down
6 changes: 5 additions & 1 deletion YubiKit/YubiKit/APDU.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@ import Foundation


/// Data model for encapsulating an APDU command, as defined by the ISO/IEC 7816-4 standard.
public struct APDU {
public struct APDU: CustomStringConvertible {

public var description: String {
return "APDU(cla: \(cla.hexValue), ins: \(ins.hexValue), p1: \(p1.hexValue), p2: \(p2.hexValue), command: \(data.hexEncodedString), type: \(String(describing: type))"
}

public enum ApduType {
case short
Expand Down
38 changes: 12 additions & 26 deletions YubiKit/YubiKit/LightningConnection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import Foundation
import ExternalAccessory
import OSLog

/// A connection to the YubiKey utilizing the Lightning port and External Accessory framework.
@available(iOS 16.0, *)
Expand Down Expand Up @@ -45,11 +46,12 @@ public final actor LightningConnection: Connection, InternalConnection {

// Starts lightning and wait for a connection
public static func connection() async throws -> Connection {
print("⚡️ LightningConnection, connection() called")
Logger.lightning.debug(#function)
return try await manager.connection()
}

public func close(error: Error?) async {
Logger.lightning.debug(#function)
closingHandler?()
closingContinuations.forEach { continuation in
continuation.resume(returning: error)
Expand All @@ -68,30 +70,24 @@ public final actor LightningConnection: Connection, InternalConnection {

public func connectionDidClose() async -> Error? {
if accessoryConnection == nil {
print("⚡️ LightningConnection, connectionDidClose() but no session so bailing out.")
return nil
}
return await withCheckedContinuation { continuation in
print("⚡️ LightningConnection, connectionDidClose() append closing continuation.")
closingContinuations.append(continuation)
}
}

internal func send(apdu: APDU) async throws -> Response {
print("⚡️ LightningConnection, send() \(apdu).")
guard let accessoryConnection, let outputStream = accessoryConnection.session.outputStream, let inputStream = accessoryConnection.session.inputStream else { throw "No current session" }
var data = Data([0x00]) // YLP iAP2 Signal
data.append(apdu.data)
print("\(outputStream.streamStatus)")
print("\(inputStream.streamStatus)")

try outputStream.writeToYubiKey(data: data)
while true {
try await Task.sleep(for: .seconds(commandProcessingTime))
let result = try inputStream.readFromYubiKey()
if result.isEmpty { throw "Empty result" }
let status = Response.StatusCode(data: result.subdata(in: result.count-2..<result.count))
print("⚡️ LightningConnection, result (\(status)): \(result.hexEncodedString)")

// BUG #62 - Workaround for WTX == 0x01 while status is 0x9000 (success).
if (status == .ok) || result.bytes[0] != 0x01 {
Expand All @@ -106,7 +102,7 @@ public final actor LightningConnection: Connection, InternalConnection {
}

deinit {
print("⚡️ deinit LightningConnection")
Logger.lightning.debug(#function)
}
}

Expand All @@ -118,7 +114,10 @@ fileprivate actor LightningConnectionManager {
var connectionTask: Task<LightningConnection, Error>?
func connection() async throws -> LightningConnection {
let task = Task { [connectionTask] in
connectionTask?.cancel() // Cancel any previous request for a connection
if let connectionTask {
Logger.lightning.debug("A call to connection() is already awaiting a connection, cancel it before proceeding.")
connectionTask.cancel()
}
return try await self._connection()
}
connectionTask = task
Expand All @@ -127,11 +126,11 @@ fileprivate actor LightningConnectionManager {
} onCancel: {
task.cancel()
}
Logger.lightning.debug("returned: \(String(describing: value))")
return value
}

private func _connection() async throws -> LightningConnection {
print("⚡️ LightningConnectionManager, _connection()")

if let currentConnection {
await currentConnection.close(error: nil)
Expand All @@ -145,8 +144,6 @@ fileprivate actor LightningConnectionManager {
return
}
accessoryWrapper.connection { result in
print("⚡️ LightningConnectionManager, _connection() got result: \(result), pass it to continuation: \(String(describing: continuation))")
print("⚡️ LightningConnectionManager, Task.isCancelled = \(Task.isCancelled)")
switch result {
case .success(let accessoryConnection):
let connection = LightningConnection(connection: accessoryConnection, closingHandler: { [weak self] in
Expand All @@ -161,12 +158,10 @@ fileprivate actor LightningConnectionManager {
}
case .failure(let error):
continuation.resume(throwing: error)
print("⚡️ LightningConnectionManager, remove \(String(describing: continuation)) after failure")
}
}
}
} onCancel: {
print("⚡️ LightningConnectionManager, onCancel called")
accessoryWrapper.stop()
}
}
Expand Down Expand Up @@ -223,9 +218,7 @@ fileprivate class EAAccessoryWrapper: NSObject, StreamDelegate {
private var closingHandler: ((Error?) -> Void)?

internal func connection(completion handler: @escaping (Result<AccessoryConnection, Error>) -> Void) {
print("⚡️ EAAccessoryWrapper, schedule connection()")
queue.async {
print("⚡️ EAAccessoryWrapper, connection()")
// Signal closure and cancel previous connection handlers
// Swap out old handlers to the new ones
self.closingHandler?("Closed by new call to connection()")
Expand All @@ -248,16 +241,14 @@ fileprivate class EAAccessoryWrapper: NSObject, StreamDelegate {
}

func stream(_ aStream: Stream, handle eventCode: Stream.Event) {
print("⚡️ EAAccessoryWrapper, Got stream event: \(eventCode) on stream: \(aStream)")
Logger.lightning.debug("EAAccessoryWrapper, Got stream event: \(String(describing: eventCode)) on stream: \(aStream)")
}

private func connectToKey(with accessory: EAAccessory) -> AccessoryConnection? {
print("⚡️ EAAccessoryWrapper, connectToKey()")
guard accessory.isYubiKey else { return nil }
guard let session = EASession(accessory: accessory, forProtocol: "com.yubico.ylp") else { return nil }
let connection = AccessoryConnection(accessory: accessory, session: session)
print("⚡️ EAAccessoryWrapper, connected to: \(session)")

Logger.lightning.debug("EAAccessoryWrapper, connected to: \(session)")
connection.open()
connection.session.outputStream!.delegate = self
connection.session.inputStream!.delegate = self
Expand All @@ -267,25 +258,22 @@ fileprivate class EAAccessoryWrapper: NSObject, StreamDelegate {

internal func connectionDidClose(completion handler: @escaping (Error?) -> Void) {
queue.async {
print("⚡️ EAAccessoryWrapper, connectionDidClose()")
assert(self.closingHandler == nil, "Closing completion already registered.")
self.closingHandler = handler
}
}

private func start() {
print("⚡️ EAAccessoryWrapper, start()")
self.queue.async {
NotificationCenter.default.addObserver(forName: .EAAccessoryDidConnect,
object: self.manager,
queue: nil) { [weak self] notification in
self?.queue.async {
print("⚡️ EAAccessoryWrapper, EAAccessoryDidConnect")
guard self?.state == .scanning,
self?.connectingHandler != nil,
let accessory = notification.userInfo?[EAAccessoryKey] as? EAAccessory,
let connection = self?.connectToKey(with: accessory) else { return }
print("⚡️ EAAccessoryWrapper, did connect to key")
Logger.lightning.debug("EAAccessoryWrapper, connected to: \(accessory)")
self?.state = .connected(connection)
self?.connectingHandler?(.success(connection))
self?.connectingHandler = nil
Expand All @@ -312,9 +300,7 @@ fileprivate class EAAccessoryWrapper: NSObject, StreamDelegate {
}

internal func stop() {
print("⚡️ EAAccessoryWrapper, scheduled stop() with state = \(self.state) in \(Thread.current)")
queue.async {
print("⚡️ EAAccessoryWrapper, stop() with state = \(self.state) in \(Thread.current)")
switch self.state {
case .ready:
break;
Expand Down
13 changes: 11 additions & 2 deletions YubiKit/YubiKit/Management/ManagementSession.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

import Foundation
import CryptoTokenKit
import OSLog

public enum ManagementSessionError: Error {
/// Application is not supported on this YubiKey.
Expand Down Expand Up @@ -44,7 +45,7 @@ public final actor ManagementSession: Session, InternalSession {
public nonisolated let version: Version

private init(connection: Connection) async throws {
let result = try await connection.selectApplication(application: .management)
let result = try await connection.selectApplication(.management)
guard let version = Version(withManagementResult: result) else { throw ManagementSessionError.unexpectedData }
self.version = version
self._connection = connection
Expand All @@ -53,6 +54,7 @@ public final actor ManagementSession: Session, InternalSession {
}

public static func session(withConnection connection: Connection) async throws -> ManagementSession {
Logger.management.debug(#function)
// Close active session if there is one
let internalConnection = connection as? InternalConnection
let currentSession = await internalConnection?.session()
Expand All @@ -63,13 +65,15 @@ public final actor ManagementSession: Session, InternalSession {
}

public func end() async {
Logger.management.debug(#function)
let internalConnection = await internalConnection()
await internalConnection?.setSession(nil)
await setConnection(nil)
}

/// Returns the DeviceInfo for the connected YubiKey.
public func getDeviceInfo() async throws -> DeviceInfo {
Logger.management.debug(#function)
guard let connection = _connection else { throw SessionError.noConnection }
let apdu = APDU(cla: 0, ins: 0x1d, p1: 0, p2: 0)
let data = try await connection.send(apdu: apdu)
Expand All @@ -78,18 +82,21 @@ public final actor ManagementSession: Session, InternalSession {

/// Check whether an application is supported over the specified transport.
public func isApplicationSupported(_ application: ApplicationType, overTransport transport: DeviceTransport) async throws -> Bool {
Logger.management.debug(#function)
let deviceInfo = try await getDeviceInfo()
return deviceInfo.isApplicationSupported(application, overTransport: transport)
}

/// Check whether an application is enabled over the specified transport.
public func isApplicationEnabled(_ application: ApplicationType, overTransport transport: DeviceTransport) async throws -> Bool {
Logger.management.debug(#function)
let deviceInfo = try await getDeviceInfo()
return deviceInfo.config.isApplicationEnabled(application, overTransport: transport)
}

/// Enable or disable an application over the specified transport.
public func setEnabled(_ enabled: Bool, application: ApplicationType, overTransport transport: DeviceTransport, reboot: Bool = false) async throws {
Logger.management.debug("setEnabled: \(enabled), application: \(String(describing: application)), overTransport: \(String(describing: transport)), reboot: \(reboot)")
guard let connection = _connection else { throw SessionError.noConnection }
let deviceInfo = try await getDeviceInfo()
guard enabled != deviceInfo.config.isApplicationEnabled(application, overTransport: transport) else { return }
Expand Down Expand Up @@ -121,16 +128,18 @@ public final actor ManagementSession: Session, InternalSession {

/// Disable an application over the specified transport.
public func disableApplication(_ application: ApplicationType, overTransport transport: DeviceTransport, reboot: Bool = false) async throws {
Logger.management.debug(#function)
try await setEnabled(false, application: application, overTransport: transport, reboot: reboot)
}

/// Enable an application over the specified transport.
public func enableApplication(_ application: ApplicationType, overTransport transport: DeviceTransport, reboot: Bool = false) async throws {
Logger.management.debug(#function)
try await setEnabled(true, application: application, overTransport: transport, reboot: reboot)
}

deinit {
print("deinit ManagementSession")
Logger.management.debug("deinit")
}
}

Expand Down
Loading

0 comments on commit c65e5a3

Please sign in to comment.