Skip to content

Commit

Permalink
Reintroduce support for Linux
Browse files Browse the repository at this point in the history
  • Loading branch information
mikenachbaur-okta committed Aug 13, 2024
1 parent a307d86 commit 1619320
Show file tree
Hide file tree
Showing 28 changed files with 214 additions and 71 deletions.
5 changes: 4 additions & 1 deletion .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@ env:
jobs:
SwiftBuild:
name: Swift Unit Tests
runs-on: macos-latest-large
strategy:
matrix:
os: [macos-latest-large, ubuntu-latest]
runs-on: ${{ matrix.os }}
timeout-minutes: 10
steps:
- name: Get swift version
Expand Down
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ var package = Package(
.tvOS(.v12),
.watchOS(.v7),
.visionOS(.v1),
.macOS(.v10_13),
.macOS(.v10_15),
.macCatalyst(.v13)
],
products: [
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ Only the last 4 major platform versions are officially supported, unless there a
| watchOS | 7.0 | 7.0 |
| visionOS | 1.0 | 1.0 |
| macCatalyst | 13.0 | 13.0 |
| macOS | 12.0 | 10.13 |
| macOS | 12.0 | 10.15 |

Once a platform version becomes unsupported, dropping support for it will not be considered a breaking change and will be done in a minor release. For example, iOS 13 will cease to be supported when iOS 18 gets released, and might be dropped in a minor release.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public final class SDKVersion: Sendable {
/// The calculated user agent string that will be included in outgoing network requests.
public private(set) static var userAgent: String = ""

private static let lock = UnfairLock()
private static let lock = Lock()
fileprivate static var sdkVersions: [SDKVersion] = []

/// Register a new SDK library component to be added to the ``userAgent`` value.
Expand Down
4 changes: 2 additions & 2 deletions Sources/AuthFoundation/OAuth2/Configuration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,11 @@ extension OAuth2Client {

// Ensure the base URL contains a trailing slash in its path, so request paths can be safely appended.
if !relativeURL.lastPathComponent.isEmpty {
relativeURL.appendPathComponent("")
relativeURL = relativeURL.appendingComponent("")
}

self.baseURL = baseURL
self.discoveryURL = discoveryURL ?? relativeURL.appendingPathComponent(".well-known/openid-configuration")
self.discoveryURL = discoveryURL ?? relativeURL.appendingComponent(".well-known/openid-configuration")
self.clientId = clientId
self.scopes = scopes
self.authentication = authentication
Expand Down
4 changes: 2 additions & 2 deletions Sources/AuthFoundation/OAuth2/OAuth2Client.swift
Original file line number Diff line number Diff line change
Expand Up @@ -543,14 +543,14 @@ public final class OAuth2Client {
// MARK: Private properties / methods
private let delegates = DelegateCollection<OAuth2ClientDelegate>()

private let refreshLock = UnfairLock()
private let refreshLock = Lock()
private(set) lazy var refreshQueue: DispatchQueue = {
DispatchQueue(label: "com.okta.refreshQueue.\(baseURL.host ?? "unknown")",
qos: .userInitiated,
attributes: .concurrent)
}()

private let configurationLock = UnfairLock()
private let configurationLock = Lock()
private lazy var configurationQueue: DispatchQueue = {
DispatchQueue(label: "com.okta.configurationQueue.\(baseURL.host ?? "unknown")",
qos: .userInitiated,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@

import Foundation

#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS)
#if canImport(LocalAuthentication) && !os(tvOS)
import LocalAuthentication
#else
Expand Down Expand Up @@ -161,4 +160,3 @@ final class UserDefaultsTokenStorage: TokenStorage {
userDefaults.synchronize()
}
}
#endif
2 changes: 1 addition & 1 deletion Sources/AuthFoundation/User Management/Credential.swift
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ public final class Credential: Equatable, OAuth2ClientDelegate {
}

tokenObserver = NotificationCenter.default.addObserver(forName: .tokenRefreshFailed,
object: token,
object: nil,
queue: nil) { [weak self] notification in
guard let self = self,
token == self.token
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,11 @@ final class CredentialCoordinatorImpl: CredentialCoordinator {
}

static func defaultTokenStorage() -> TokenStorage {
#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS)
KeychainTokenStorage()
#else
#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS)
KeychainTokenStorage()
#else
UserDefaultsTokenStorage()
#endif
#endif
}

static func defaultCredentialDataSource() -> CredentialDataSource {
Expand Down
10 changes: 5 additions & 5 deletions Sources/AuthFoundation/Utilities/JSONValue.swift
Original file line number Diff line number Diff line change
Expand Up @@ -251,13 +251,13 @@ extension JSON: Codable {

fileprivate extension NSNumber {
var isFloatingPoint: Bool {
let type = CFNumberGetType(self as CFNumber)
switch type {
case .floatType, .float32Type, .float64Type, .cgFloatType, .doubleType:
if strcmp(objCType, "f") == 0 ||
strcmp(objCType, "d") == 0
{
return true
default:
return false
}

return false
}
}

Expand Down
104 changes: 104 additions & 0 deletions Sources/AuthFoundation/Utilities/Lock.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
//
// Copyright (c) 2023-Present, Okta, Inc. and/or its affiliates. All rights reserved.
// The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
//
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and limitations under the License.
//

import Foundation

#if canImport(Darwin)
import Darwin
#elseif canImport(Glibc)
import Glibc
#elseif canImport(Musl)
import Musl
#elseif canImport(Bionic)
import Bionic
#else
#error("Unsupported platform")
#endif

// **Note:** It would be preferable to use OSAllocatedUnfairLock for this, but this would mean dropping support for older OS versions. While this approach is safe, OSAllocatedUnfairLock provides more features we might need in the future.
//
// If the minimum supported version of this SDK is to increase in the future, this class should be removed and replaced with OSAllocatedUnfairLock.
final class Lock: NSLocking {
#if canImport(Darwin)
private typealias LockType = os_unfair_lock
#elseif canImport(Glibc) || canImport(Musl) || canImport(Bionic)
private typealias LockType = pthread_mutex_t
#else
#error("Unsupported platform")
#endif

private let _lock: UnsafeMutablePointer<LockType> = {
let result = UnsafeMutablePointer<LockType>.allocate(capacity: 1)

#if canImport(Darwin)
result.initialize(to: os_unfair_lock())
#elseif canImport(Glibc) || canImport(Musl) || canImport(Bionic)
let status = pthread_mutex_init(result, nil)
precondition(status == 0, "pthread_mutex_init failed")
#else
#error("Unsupported platform")
#endif

return result
}()

deinit {
#if canImport(Glibc) || canImport(Musl) || canImport(Bionic)
let status = pthread_mutex_destroy(_lock)
precondition(status == 0, "pthread_mutex_destroy failed")
#endif
_lock.deinitialize(count: 1)
_lock.deallocate()
}

func lock() {
#if canImport(Darwin)
os_unfair_lock_lock(_lock)
#elseif canImport(Glibc) || canImport(Musl) || canImport(Bionic)
let status = pthread_mutex_lock(_lock)
precondition(status == 0, "pthread_mutex_lock failed")
#else
#error("Unsupported platform")
#endif
}

func tryLock() -> Bool {
#if canImport(Darwin)
return os_unfair_lock_trylock(_lock)
#elseif canImport(Glibc) || canImport(Musl) || canImport(Bionic)
return pthread_mutex_trylock(_lock) == 0
#else
#error("Unsupported platform")
#endif
}

func unlock() {
#if canImport(Darwin)
os_unfair_lock_unlock(_lock)
#elseif canImport(Glibc) || canImport(Musl) || canImport(Bionic)
let status = pthread_mutex_unlock(_lock)
precondition(status == 0, "pthread_mutex_unlock failed")
#else
#error("Unsupported platform")
#endif
}

#if !canImport(Darwin)
func withLock<T>(_ body: () throws -> T) rethrows -> T {
self.lock()
defer {
self.unlock()
}
return try body()
}
#endif
}
6 changes: 5 additions & 1 deletion Sources/AuthFoundation/Utilities/TimeCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@

import Foundation

#if os(Linux)
import FoundationNetworking
#endif

/// Protocol used to return dates and times coordinated against trusted sources.
///
/// This can be used to customize the behavior of how dates and times are calculated, when used on devices that may have skewed or incorrect clocks.
Expand Down Expand Up @@ -53,7 +57,7 @@ class DefaultTimeCoordinator: TimeCoordinator, OAuth2ClientDelegate {
Date.coordinator = DefaultTimeCoordinator()
}

private let lock = UnfairLock()
private let lock = Lock()
private var _offset: TimeInterval
private(set) var offset: TimeInterval {
get { lock.withLock { _offset } }
Expand Down
33 changes: 33 additions & 0 deletions Sources/AuthFoundation/Utilities/URL+InternalExtensions.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//
// Copyright (c) 2024-Present, Okta, Inc. and/or its affiliates. All rights reserved.
// The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
//
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and limitations under the License.
//

import Foundation

extension URL {
@inlinable
// Workaround to address a known bug with URL.appendingPathComponent on Linux.
// https://github.com/apple/swift-corelibs-foundation/issues/4849
func appendingComponent(_ component: String) -> URL {

Check failure on line 19 in Sources/AuthFoundation/Utilities/URL+InternalExtensions.swift

View workflow job for this annotation

GitHub Actions / SwiftLint

Attributes should be on their own lines in functions and types, but on the same line as variables and imports (attributes)
#if os(Linux)
var components = URLComponents(url: self, resolvingAgainstBaseURL: true)!

Check warning on line 21 in Sources/AuthFoundation/Utilities/URL+InternalExtensions.swift

View workflow job for this annotation

GitHub Actions / SwiftLint

Force unwrapping should be avoided (force_unwrapping)
if !components.path.hasSuffix("/") {
components.path.append("/")
}
components.path.append(component)
return components.url!

Check warning on line 26 in Sources/AuthFoundation/Utilities/URL+InternalExtensions.swift

View workflow job for this annotation

GitHub Actions / SwiftLint

Force unwrapping should be avoided (force_unwrapping)
#else
var result = self
result.appendPathComponent(component)
return result
#endif
}
}
41 changes: 0 additions & 41 deletions Sources/AuthFoundation/Utilities/UnsafeLock.swift

This file was deleted.

4 changes: 4 additions & 0 deletions Sources/OktaOAuth2/Authentication/SessionTokenFlow.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@
import Foundation
import AuthFoundation

#if os(Linux)
import FoundationNetworking
#endif

/// An authentication flow class that exchanges a Session Token for access tokens.
///
/// This flow is typically used in conjunction with the [classic Okta native authentication library](https://github.com/okta/okta-auth-swift). For native authentication using the Okta Identity Engine (OIE), please use the [Okta IDX library](https://github.com/okta/okta-idx-swift).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import Foundation

// TODO: Remove on the next major release.
#if canImport(UIKit) || canImport(AppKit)
extension WebAuthentication {
@available(*, deprecated, renamed: "signIn(from:options:completion:)")
public final func signIn(from window: WindowAnchor?,
Expand Down Expand Up @@ -127,3 +128,4 @@ extension WebAuthentication {
try await signOut(from: window, token: token, options: options(from: additionalParameters))
}
}
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

import Foundation

#if canImport(UIKit) || canImport(AppKit)
#if !SWIFT_PACKAGE
private let sharedLocalizationBundle: Bundle = {
Bundle(for: WebAuthentication.self)
Expand All @@ -27,3 +28,4 @@ extension Bundle {
#endif
}
}
#endif
2 changes: 2 additions & 0 deletions Sources/WebAuthenticationUI/Internal/Options+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import Foundation
import OktaOAuth2

#if canImport(UIKit) || canImport(AppKit)
extension WebAuthentication.Option {
var queryItems: [String: String] {
switch self {
Expand Down Expand Up @@ -81,3 +82,4 @@ extension Collection where Element == WebAuthentication.Option {
return .init(state: state, maxAge: maxAge)
}
}
#endif
2 changes: 2 additions & 0 deletions Sources/WebAuthenticationUI/Version.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
import Foundation
import AuthFoundation

#if canImport(UIKit) || canImport(AppKit)
// swiftlint:disable identifier_name
@_documentation(visibility: private)
public let Version = SDKVersion(sdk: "okta-webauthenticationui-swift", version: "1.8.2")
// swiftlint:enable identifier_name
#endif
Loading

0 comments on commit 1619320

Please sign in to comment.