1
+ import NIOConcurrencyHelpers
1
2
import Vapor
2
3
3
- extension Request . JWT {
4
- public var apple : Apple {
4
+ public extension Request . JWT {
5
+ var apple : Apple {
5
6
. init( _jwt: self )
6
7
}
7
8
8
- public struct Apple {
9
+ struct Apple : Sendable {
9
10
public let _jwt : Request . JWT
10
11
11
- public func verify( applicationIdentifier: String ? = nil ) -> EventLoopFuture < AppleIdentityToken > {
12
+ public func verify(
13
+ applicationIdentifier: String ? = nil
14
+ ) async throws -> AppleIdentityToken {
12
15
guard let token = self . _jwt. _request. headers. bearerAuthorization? . token else {
13
16
self . _jwt. _request. logger. error ( " Request is missing JWT bearer header. " )
14
- return self . _jwt . _request . eventLoop . makeFailedFuture ( Abort ( . unauthorized) )
17
+ throw Abort ( . unauthorized)
15
18
}
16
- return self . verify ( token, applicationIdentifier: applicationIdentifier)
19
+ return try await self . verify ( token, applicationIdentifier: applicationIdentifier)
17
20
}
18
21
19
- public func verify( _ message: String , applicationIdentifier: String ? = nil ) -> EventLoopFuture < AppleIdentityToken > {
20
- self . verify ( [ UInt8] ( message. utf8) , applicationIdentifier: applicationIdentifier)
22
+ public func verify(
23
+ _ message: String ,
24
+ applicationIdentifier: String ? = nil
25
+ ) async throws -> AppleIdentityToken {
26
+ try await self . verify ( [ UInt8] ( message. utf8) , applicationIdentifier: applicationIdentifier)
21
27
}
22
28
23
- public func verify< Message> ( _ message: Message , applicationIdentifier: String ? = nil ) -> EventLoopFuture < AppleIdentityToken >
24
- where Message: DataProtocol
25
- {
26
- self . _jwt. _request. application. jwt. apple. signers (
27
- on: self . _jwt. _request
28
- ) . flatMapThrowing { signers in
29
- let token = try signers. verify ( message, as: AppleIdentityToken . self)
30
- if let applicationIdentifier = applicationIdentifier ?? self . _jwt. _request. application. jwt. apple. applicationIdentifier {
31
- try token. audience. verifyIntendedAudience ( includes: applicationIdentifier)
32
- }
33
- return token
29
+ public func verify(
30
+ _ message: some DataProtocol & Sendable ,
31
+ applicationIdentifier: String ? = nil
32
+ ) async throws -> AppleIdentityToken {
33
+ let keys = try await self . _jwt. _request. application. jwt. apple. keys ( on: self . _jwt. _request)
34
+ let token = try await keys. verify ( message, as: AppleIdentityToken . self)
35
+ if let applicationIdentifier = applicationIdentifier ?? self . _jwt. _request. application. jwt. apple. applicationIdentifier {
36
+ try token. audience. verifyIntendedAudience ( includes: applicationIdentifier)
34
37
}
38
+ return token
35
39
}
36
40
}
37
41
}
38
42
39
- extension Application . JWT {
40
- public var apple : Apple {
43
+ public extension Application . JWT {
44
+ var apple : Apple {
41
45
. init( _jwt: self )
42
46
}
43
47
44
- public struct Apple {
48
+ struct Apple : Sendable {
45
49
public let _jwt : Application . JWT
46
50
47
- public func signers( on request: Request ) -> EventLoopFuture < JWTSigners > {
48
- self . jwks. get ( on: request) . flatMapThrowing {
49
- let signers = JWTSigners ( )
50
- try signers. use ( jwks: $0)
51
- return signers
52
- }
51
+ public func keys( on request: Request ) async throws -> JWTKeyCollection {
52
+ try await JWTKeyCollection ( ) . add ( jwks: jwks. get ( on: request) . get ( ) )
53
53
}
54
54
55
55
public var jwks : EndpointCache < JWKS > {
@@ -69,12 +69,31 @@ extension Application.JWT {
69
69
typealias Value = Storage
70
70
}
71
71
72
- private final class Storage {
72
+ private final class Storage : Sendable {
73
+ private struct SendableBox : Sendable {
74
+ var applicationIdentifier : String ?
75
+ }
76
+
73
77
let jwks : EndpointCache < JWKS >
74
- var applicationIdentifier : String ?
78
+ private let sendableBox : NIOLockedValueBox < SendableBox >
79
+
80
+ var applicationIdentifier : String ? {
81
+ get {
82
+ self . sendableBox. withLockedValue { box in
83
+ box. applicationIdentifier
84
+ }
85
+ }
86
+ set {
87
+ self . sendableBox. withLockedValue { box in
88
+ box. applicationIdentifier = newValue
89
+ }
90
+ }
91
+ }
92
+
75
93
init ( ) {
76
94
self . jwks = . init( uri: " https://appleid.apple.com/auth/keys " )
77
- self . applicationIdentifier = nil
95
+ let box = SendableBox ( applicationIdentifier: nil )
96
+ self . sendableBox = . init( box)
78
97
}
79
98
}
80
99
0 commit comments