Skip to content

Commit 1e61e55

Browse files
authored
Refine JSON implementation for mutability, type safety, and performance (#248)
* Refine JSON implementation for mutability, type safety, and performance * Working with WebAuthn, IDX, and JWT generation necessitates JSON mutability * Avoid using sys functions (sleep/usleep) for tests
1 parent b794672 commit 1e61e55

91 files changed

Lines changed: 2351 additions & 1156 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<Scheme
3+
LastUpgradeVersion = "1640"
4+
version = "1.3">
5+
<BuildAction
6+
parallelizeBuildables = "YES"
7+
buildImplicitDependencies = "YES">
8+
<BuildActionEntries>
9+
<BuildActionEntry
10+
buildForTesting = "YES"
11+
buildForRunning = "YES"
12+
buildForProfiling = "YES"
13+
buildForArchiving = "YES"
14+
buildForAnalyzing = "YES">
15+
<BuildableReference
16+
BuildableIdentifier = "primary"
17+
BlueprintIdentifier = "CommonSupport"
18+
BuildableName = "CommonSupport"
19+
BlueprintName = "CommonSupport"
20+
ReferencedContainer = "container:">
21+
</BuildableReference>
22+
</BuildActionEntry>
23+
<BuildActionEntry
24+
buildForTesting = "YES"
25+
buildForRunning = "NO"
26+
buildForProfiling = "NO"
27+
buildForArchiving = "NO"
28+
buildForAnalyzing = "NO">
29+
<BuildableReference
30+
BuildableIdentifier = "primary"
31+
BlueprintIdentifier = "CommonSupportTests"
32+
BuildableName = "CommonSupportTests"
33+
BlueprintName = "CommonSupportTests"
34+
ReferencedContainer = "container:">
35+
</BuildableReference>
36+
</BuildActionEntry>
37+
</BuildActionEntries>
38+
</BuildAction>
39+
<TestAction
40+
buildConfiguration = "Debug"
41+
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
42+
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
43+
shouldUseLaunchSchemeArgsEnv = "YES"
44+
codeCoverageEnabled = "YES"
45+
onlyGenerateCoverageForSpecifiedTargets = "YES">
46+
<CodeCoverageTargets>
47+
<BuildableReference
48+
BuildableIdentifier = "primary"
49+
BlueprintIdentifier = "CommonSupport"
50+
BuildableName = "CommonSupport"
51+
BlueprintName = "CommonSupport"
52+
ReferencedContainer = "container:">
53+
</BuildableReference>
54+
</CodeCoverageTargets>
55+
<Testables>
56+
<TestableReference
57+
skipped = "NO"
58+
testExecutionOrdering = "random">
59+
<BuildableReference
60+
BuildableIdentifier = "primary"
61+
BlueprintIdentifier = "CommonSupportTests"
62+
BuildableName = "CommonSupportTests"
63+
BlueprintName = "CommonSupportTests"
64+
ReferencedContainer = "container:">
65+
</BuildableReference>
66+
</TestableReference>
67+
</Testables>
68+
</TestAction>
69+
<LaunchAction
70+
buildConfiguration = "Debug"
71+
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
72+
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
73+
launchStyle = "0"
74+
useCustomWorkingDirectory = "NO"
75+
ignoresPersistentStateOnLaunch = "NO"
76+
debugDocumentVersioning = "YES"
77+
debugServiceExtension = "internal"
78+
allowLocationSimulation = "YES">
79+
</LaunchAction>
80+
<ProfileAction
81+
buildConfiguration = "Release"
82+
shouldUseLaunchSchemeArgsEnv = "YES"
83+
savedToolIdentifier = ""
84+
useCustomWorkingDirectory = "NO"
85+
debugDocumentVersioning = "YES">
86+
<MacroExpansion>
87+
<BuildableReference
88+
BuildableIdentifier = "primary"
89+
BlueprintIdentifier = "CommonSupport"
90+
BuildableName = "CommonSupport"
91+
BlueprintName = "CommonSupport"
92+
ReferencedContainer = "container:">
93+
</BuildableReference>
94+
</MacroExpansion>
95+
</ProfileAction>
96+
<AnalyzeAction
97+
buildConfiguration = "Debug">
98+
</AnalyzeAction>
99+
<ArchiveAction
100+
buildConfiguration = "Release"
101+
revealArchiveInOrganizer = "YES">
102+
</ArchiveAction>
103+
</Scheme>
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<Scheme
3+
LastUpgradeVersion = "1640"
4+
version = "1.7">
5+
<BuildAction
6+
parallelizeBuildables = "YES"
7+
buildImplicitDependencies = "YES"
8+
buildArchitectures = "Automatic">
9+
<BuildActionEntries>
10+
<BuildActionEntry
11+
buildForTesting = "YES"
12+
buildForRunning = "YES"
13+
buildForProfiling = "YES"
14+
buildForArchiving = "YES"
15+
buildForAnalyzing = "YES">
16+
<BuildableReference
17+
BuildableIdentifier = "primary"
18+
BlueprintIdentifier = "JSON"
19+
BuildableName = "JSON"
20+
BlueprintName = "JSON"
21+
ReferencedContainer = "container:">
22+
</BuildableReference>
23+
</BuildActionEntry>
24+
</BuildActionEntries>
25+
</BuildAction>
26+
<TestAction
27+
buildConfiguration = "Debug"
28+
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
29+
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
30+
shouldUseLaunchSchemeArgsEnv = "YES"
31+
codeCoverageEnabled = "YES"
32+
onlyGenerateCoverageForSpecifiedTargets = "YES">
33+
<CodeCoverageTargets>
34+
<BuildableReference
35+
BuildableIdentifier = "primary"
36+
BlueprintIdentifier = "JSON"
37+
BuildableName = "JSON"
38+
BlueprintName = "JSON"
39+
ReferencedContainer = "container:">
40+
</BuildableReference>
41+
</CodeCoverageTargets>
42+
<Testables>
43+
<TestableReference
44+
skipped = "NO"
45+
testExecutionOrdering = "random">
46+
<BuildableReference
47+
BuildableIdentifier = "primary"
48+
BlueprintIdentifier = "JSONTests"
49+
BuildableName = "JSONTests"
50+
BlueprintName = "JSONTests"
51+
ReferencedContainer = "container:">
52+
</BuildableReference>
53+
</TestableReference>
54+
</Testables>
55+
</TestAction>
56+
<LaunchAction
57+
buildConfiguration = "Debug"
58+
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
59+
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
60+
launchStyle = "0"
61+
useCustomWorkingDirectory = "NO"
62+
ignoresPersistentStateOnLaunch = "NO"
63+
debugDocumentVersioning = "YES"
64+
debugServiceExtension = "internal"
65+
allowLocationSimulation = "YES">
66+
</LaunchAction>
67+
<ProfileAction
68+
buildConfiguration = "Release"
69+
shouldUseLaunchSchemeArgsEnv = "YES"
70+
savedToolIdentifier = ""
71+
useCustomWorkingDirectory = "NO"
72+
debugDocumentVersioning = "YES">
73+
<MacroExpansion>
74+
<BuildableReference
75+
BuildableIdentifier = "primary"
76+
BlueprintIdentifier = "JSON"
77+
BuildableName = "JSON"
78+
BlueprintName = "JSON"
79+
ReferencedContainer = "container:">
80+
</BuildableReference>
81+
</MacroExpansion>
82+
</ProfileAction>
83+
<AnalyzeAction
84+
buildConfiguration = "Debug">
85+
</AnalyzeAction>
86+
<ArchiveAction
87+
buildConfiguration = "Release"
88+
revealArchiveInOrganizer = "YES">
89+
</ArchiveAction>
90+
</Scheme>

Sources/AuthFoundation/Debugging/APIRequestObserver.swift

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,6 @@ import OSLog
2424
import CommonSupport
2525
#endif
2626

27-
#if !COCOAPODS
28-
import CommonSupport
29-
#endif
30-
3127
#if compiler(<6.0)
3228
extension OSLog: @unchecked Sendable {}
3329
#endif

Sources/AuthFoundation/JWT/Extensions/ClaimConvertable+Extensions.swift

Lines changed: 67 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,83 @@
1212

1313
import Foundation
1414

15+
extension JSON {
16+
var payload: [String: any Sendable] {
17+
get {
18+
value.anyValue as? [String: any Sendable] ?? [:]
19+
}
20+
set { value.anyValue = newValue }
21+
}
22+
}
23+
1524
@_documentation(visibility: private)
1625
extension String: ClaimConvertable {}
1726

1827
@_documentation(visibility: private)
19-
extension Bool: ClaimConvertable {}
28+
extension Bool: ClaimConvertable {
29+
public static func convert(from value: Any?) -> Self? {
30+
if let value = value as? Bool {
31+
return value
32+
}
33+
34+
if let value = value as? Int,
35+
value == 0 || value == 1
36+
{
37+
return value == 1
38+
}
39+
40+
return nil
41+
}
42+
}
2043

2144
@_documentation(visibility: private)
22-
extension Int: ClaimConvertable {}
45+
extension Int: ClaimConvertable {
46+
public static func convert(from value: Any?) -> Self? {
47+
if let value = value as? Int {
48+
return value
49+
}
50+
51+
if let value = value as? Double {
52+
return Int(value)
53+
}
54+
55+
return nil
56+
}
57+
}
2358

2459
@_documentation(visibility: private)
25-
extension Double: ClaimConvertable {}
60+
extension Double: ClaimConvertable {
61+
public static func convert(from value: Any?) -> Self? {
62+
if let value = value as? Double {
63+
return value
64+
}
65+
66+
if let value = value as? Int {
67+
return Double(value)
68+
}
69+
70+
return nil
71+
}
72+
}
2673

2774
@_documentation(visibility: private)
28-
extension Float: ClaimConvertable {}
75+
extension Float: ClaimConvertable {
76+
public static func convert(from value: Any?) -> Self? {
77+
if let value = value as? Float {
78+
return value
79+
}
80+
81+
if let value = value as? Double {
82+
return Float(value)
83+
}
84+
85+
if let value = value as? Int {
86+
return Float(value)
87+
}
88+
89+
return nil
90+
}
91+
}
2992

3093
@_documentation(visibility: private)
3194
extension JWTClaim: ClaimConvertable {}

Sources/AuthFoundation/JWT/JWK.swift

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,6 @@ import Foundation
1616
import CommonSupport
1717
#endif
1818

19-
#if !COCOAPODS
20-
import CommonSupport
21-
#endif
22-
2319
/// Describes an individual key from an authorization server, which can be used to validate tokens or encrypt content.
2420
///
2521
/// > Warning: At this time, this class only supports RSA Public Keys.

Sources/AuthFoundation/JWT/JWT.swift

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@
1212

1313
import Foundation
1414

15+
#if !COCOAPODS
16+
@_exported import JSON
17+
#endif
18+
1519
/// Represents the contents of a JWT token, providing access to its payload contents.
1620
public struct JWT: RawRepresentable, Sendable, Codable, HasClaims, Expires {
1721
public typealias ClaimType = JWTClaim
@@ -93,25 +97,21 @@ public struct JWT: RawRepresentable, Sendable, Codable, HasClaims, Expires {
9397
else { throw JWTError.invalidBase64Encoding }
9498

9599
self.header = try JSONDecoder().decode(JWT.Header.self, from: headerData)
96-
guard let payload = try JSONSerialization.jsonObject(with: payloadData,
97-
options: []) as? [String: any Sendable]
98-
else {
99-
throw JWTError.badTokenStructure
100-
}
101-
102-
self.payload = payload
100+
self.body = try JSON(payloadData)
103101

104102
if components.count == 3 {
105103
self.signature = components[2]
106104
}
107105
}
108106

109107
/// Raw paylaod of claims, as a dictionary representation.
110-
public var payload: [String: any Sendable]
108+
public var body: JSON
111109

112110
/// Signature of the JWT token.
113111
public var signature: String?
114112

113+
public var payload: [String: any Sendable] { body.payload }
114+
115115
static func tokenComponents(from token: String) -> [String] {
116116
token
117117
.components(separatedBy: ".")

0 commit comments

Comments
 (0)