Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 13 additions & 6 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,23 @@ let package = Package(
name: "OAuthKit",
targets: ["OAuthKit"])
],
dependencies: [
// Android / Linux Dependencies
.package(url: "https://github.com/apple/swift-crypto.git", from: .init(4, 5, 0))
],
targets: [
.target(
name: "OAuthKit",
dependencies: [
.product(name: "Crypto",
package: "swift-crypto",
condition: .when(platforms: [.android, .linux])
)
],
linkerSettings: [
.linkedFramework("CryptoKit"),
.linkedFramework("LocalAuthentication", .when(
platforms: [.iOS]
)),
.linkedFramework("Network"),
.linkedFramework("Security")
.linkedFramework("LocalAuthentication",
.when(platforms: [.iOS])
),
]
),
.testTarget(
Expand Down
13 changes: 13 additions & 0 deletions Sources/OAuthKit/Extensions/Data+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@
// Created by Kevin McKee
//

#if canImport(CryptoKit)
import CryptoKit
#else
import Crypto
#endif
import Foundation

extension Data {
Expand Down Expand Up @@ -43,7 +47,16 @@ extension Data {
/// - Returns: an array of cryptographically secure random bytes
static func secureRandom(count: Int = 32) -> Data {
var bytes = [UInt8](repeating: 0, count: count)
#if canImport(CryptoKit)
// Apple
_ = SecRandomCopyBytes(kSecRandomDefault, bytes.count, &bytes)
#else
// Android / Linux
var generator = SystemRandomNumberGenerator()
for i in 0..<count {
bytes[i] = UInt8.random(in: 0...255, using: &generator)
}
#endif
return Data(bytes: &bytes, count: bytes.count)
}
}
4 changes: 4 additions & 0 deletions Sources/OAuthKit/Extensions/Digest+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@
// Created by Kevin McKee
//

#if canImport(CryptoKit)
import CryptoKit
#else
import Crypto
#endif
import Foundation

extension Digest {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
//
// Created by Kevin McKee
//

#if canImport(SwiftUI)
import SwiftUI

public extension EnvironmentValues {
Expand All @@ -21,3 +21,4 @@ struct OAuthKey: @preconcurrency EnvironmentKey {
/// The default OAuth instance that is loaded into the environment.
@MainActor static let defaultValue: OAuth = .init(.main)
}
#endif
4 changes: 4 additions & 0 deletions Sources/OAuthKit/Extensions/String+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@
// Created by Kevin McKee
//

#if canImport(CryptoKit)
import CryptoKit
#else
import Crypto
#endif
import Foundation

extension String {
Expand Down
4 changes: 4 additions & 0 deletions Sources/OAuthKit/Extensions/URL+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@
// Created by Kevin McKee
//

#if canImport(CryptoKit)
import CryptoKit
#else
import Crypto
#endif
import Foundation

extension URL {
Expand Down
3 changes: 3 additions & 0 deletions Sources/OAuthKit/Extensions/URLRequest+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
//

import Foundation
#if canImport(FoundationNetworking)
import FoundationNetworking
#endif

private let authHeader = "Authorization"

Expand Down
3 changes: 3 additions & 0 deletions Sources/OAuthKit/Extensions/URLResponse+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
//

import Foundation
#if canImport(FoundationNetworking)
import FoundationNetworking
#endif

public extension URLResponse {

Expand Down
4 changes: 4 additions & 0 deletions Sources/OAuthKit/Extensions/UUID+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@
// Created by Kevin McKee
//

#if canImport(CryptoKit)
import CryptoKit
#else
import Crypto
#endif
import Foundation

extension UUID {
Expand Down
24 changes: 24 additions & 0 deletions Sources/OAuthKit/Keychain/Keychain.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
//

import Foundation
#if canImport(Security)
import Security
#endif

/// The default application tag to use.
private let defaultApplicationTag = "oauthkit"
Expand All @@ -33,6 +35,7 @@ class Keychain: @unchecked Sendable {
/// Queries the keychain for keys.
var keys: [String] {

#if canImport(Security)
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecReturnAttributes as String: true,
Expand All @@ -56,6 +59,10 @@ class Keychain: @unchecked Sendable {
}

return results.filter{ $0.starts(with: applicationTag)}.sorted{ $0 < $1}
#else
// TODO: Android / Linux storage
return []
#endif
}

/// Sets the value for the specified key.
Expand All @@ -69,6 +76,7 @@ class Keychain: @unchecked Sendable {
lock.lock()
defer { lock.unlock() }

#if canImport(Security)
let account = accountKey(key)
deleteNoLock(account)

Expand All @@ -81,6 +89,10 @@ class Keychain: @unchecked Sendable {

let status = SecItemAdd(query as CFDictionary, nil)
return status == errSecSuccess
#else
// TODO: Android / Linux storage
return false
#endif
}

/// Fetches a storeed value from the keychain with the specified key and attempts to decode it from the implied generic.
Expand All @@ -93,6 +105,7 @@ class Keychain: @unchecked Sendable {

let account = accountKey(key)

#if canImport(Security)
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecMatchLimit as String: kSecMatchLimitOne,
Expand All @@ -111,6 +124,11 @@ class Keychain: @unchecked Sendable {

let value = try? decoder.decode(T.self, from: data)
return value

#else
// TODO: Android / Linux storage
return nil
#endif
}

/// Clears the keychain
Expand Down Expand Up @@ -147,12 +165,18 @@ class Keychain: @unchecked Sendable {
/// - Returns: true if able to delete from the keychain, otherwise false
@discardableResult
private func deleteNoLock(_ key: String) -> Bool {

#if canImport(Security)
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: key
]
let status = SecItemDelete(query as CFDictionary)
return status == noErr
#else
// TODO: Android / Linux storage
return false
#endif
}

/// Builds the account key by prefixing the specified key with the application tag.
Expand Down
10 changes: 10 additions & 0 deletions Sources/OAuthKit/Network/NetworkMonitor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
// Created by Kevin McKee
//

#if canImport(Network)
import Network
#endif
import Observation

/// An `Observable` type that publishes network reachability information.
Expand All @@ -16,8 +18,10 @@ public final class NetworkMonitor: Sendable {
// The shared singleton network monitor.
public static let shared: NetworkMonitor = .init()

#if canImport(Network)
@ObservationIgnored
private let pathMonitor = NWPathMonitor()
#endif

/// Flag indicating if monitoring is currently active or not.
public private(set) var isMonitoring = false
Expand All @@ -39,18 +43,24 @@ public final class NetworkMonitor: Sendable {

/// Starts the network monitor (conforms to AsyncSequence).
public func start() async {
#if canImport(Network)
guard !isMonitoring else { return }
isMonitoring.toggle()
for await path in pathMonitor {
handle(path: path)
}
#endif
}

#if canImport(Network)

/// Handles the snapshot view of the network path state.
/// - Parameter path: the snapshot view of the network path state
private func handle(path: NWPath) {
onWifi = path.usesInterfaceType(.wifi)
onCellular = path.usesInterfaceType(.cellular)
onWiredEthernet = path.usesInterfaceType(.wiredEthernet)
}

#endif
}
3 changes: 3 additions & 0 deletions Sources/OAuthKit/OAuth+Request.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
//

import Foundation
#if canImport(FoundationNetworking)
import FoundationNetworking
#endif

private let httpPost = "POST"
private let httpAcceptHeaderField = "Accept"
Expand Down
3 changes: 3 additions & 0 deletions Sources/OAuthKit/OAuth.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
// Created by Kevin McKee
//
import Foundation
#if canImport(FoundationNetworking)
import FoundationNetworking
#endif
#if canImport(LocalAuthentication)
import LocalAuthentication
#endif
Expand Down
Loading