Skip to content

Commit 4c95559

Browse files
authored
fix(realtime): remove jwt check (#658)
* fix(realtime): remove jwt check Also: - Call `setAuth` after heartbeat - Send `x-client-info` when joining channel * fix tests * only send token if changed
1 parent 554f93c commit 4c95559

File tree

5 files changed

+50
-33
lines changed

5 files changed

+50
-33
lines changed

.swiftpm/xcode/xcshareddata/xcschemes/Realtime.xcscheme

+23-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<Scheme
33
LastUpgradeVersion = "1510"
4-
version = "1.7">
4+
version = "1.3">
55
<BuildAction
66
parallelizeBuildables = "YES"
77
buildImplicitDependencies = "YES">
@@ -26,8 +26,29 @@
2626
buildConfiguration = "Debug"
2727
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
2828
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
29-
shouldUseLaunchSchemeArgsEnv = "YES">
29+
shouldUseLaunchSchemeArgsEnv = "YES"
30+
codeCoverageEnabled = "YES"
31+
onlyGenerateCoverageForSpecifiedTargets = "YES">
32+
<CodeCoverageTargets>
33+
<BuildableReference
34+
BuildableIdentifier = "primary"
35+
BlueprintIdentifier = "Realtime"
36+
BuildableName = "Realtime"
37+
BlueprintName = "Realtime"
38+
ReferencedContainer = "container:">
39+
</BuildableReference>
40+
</CodeCoverageTargets>
3041
<Testables>
42+
<TestableReference
43+
skipped = "NO">
44+
<BuildableReference
45+
BuildableIdentifier = "primary"
46+
BlueprintIdentifier = "RealtimeTests"
47+
BuildableName = "RealtimeTests"
48+
BlueprintName = "RealtimeTests"
49+
ReferencedContainer = "container:">
50+
</BuildableReference>
51+
</TestableReference>
3152
</Testables>
3253
</TestAction>
3354
<LaunchAction

Sources/Realtime/RealtimeChannelV2.swift

+2-1
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,8 @@ public final class RealtimeChannelV2: Sendable {
104104

105105
let payload = RealtimeJoinPayload(
106106
config: joinConfig,
107-
accessToken: await socket._getAccessToken()
107+
accessToken: await socket._getAccessToken(),
108+
version: socket.options.headers[.xClientInfo]
108109
)
109110

110111
let joinRef = socket.makeRef()

Sources/Realtime/RealtimeClientV2.swift

+13-15
Original file line numberDiff line numberDiff line change
@@ -117,13 +117,18 @@ public final class RealtimeClientV2: Sendable {
117117
wsTransport: @escaping WebSocketTransport,
118118
http: any HTTPClientType
119119
) {
120+
var options = options
121+
if options.headers[.xClientInfo] == nil {
122+
options.headers[.xClientInfo] = "realtime-swift/\(version)"
123+
}
124+
120125
self.url = url
121126
self.options = options
122127
self.wsTransport = wsTransport
123128
self.http = http
124129
apikey = options.apikey
125130

126-
mutableState.withValue {
131+
mutableState.withValue { [options] in
127132
if let accessToken = options.headers[.authorization]?.split(separator: " ").last {
128133
$0.accessToken = String(accessToken)
129134
} else {
@@ -353,15 +358,15 @@ public final class RealtimeClientV2: Sendable {
353358
if Task.isCancelled {
354359
break
355360
}
356-
self?.sendHeartbeat()
361+
await self?.sendHeartbeat()
357362
}
358363
}
359364
mutableState.withValue {
360365
$0.heartbeatTask = heartbeatTask
361366
}
362367
}
363368

364-
private func sendHeartbeat() {
369+
private func sendHeartbeat() async {
365370
let pendingHeartbeatRef: String? = mutableState.withValue {
366371
if $0.pendingHeartbeatRef != nil {
367372
$0.pendingHeartbeatRef = nil
@@ -383,6 +388,7 @@ public final class RealtimeClientV2: Sendable {
383388
payload: [:]
384389
)
385390
)
391+
await setAuth()
386392
} else {
387393
options.logger?.debug("Heartbeat timeout")
388394
reconnect()
@@ -416,21 +422,13 @@ public final class RealtimeClientV2: Sendable {
416422
/// On callback used, it will set the value of the token internal to the client.
417423
/// - Parameter token: A JWT string to override the token set on the client.
418424
public func setAuth(_ token: String? = nil) async {
419-
var token = token
420-
421-
if token == nil {
422-
token = try? await options.accessToken?()
423-
}
425+
var tokenToSend = token
424426

425-
if token == nil {
426-
token = mutableState.accessToken
427+
if tokenToSend == nil {
428+
tokenToSend = try? await options.accessToken?()
427429
}
428430

429-
if let token, let payload = JWT.decodePayload(token),
430-
let exp = payload["exp"] as? TimeInterval, exp < Date().timeIntervalSince1970
431-
{
432-
options.logger?.warning(
433-
"InvalidJWTToken: Invalid value for JWT claim \"exp\" with value \(exp)")
431+
guard tokenToSend != mutableState.accessToken else {
434432
return
435433
}
436434

Sources/Realtime/RealtimeJoinConfig.swift

+2
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,12 @@ import Foundation
1010
struct RealtimeJoinPayload: Codable {
1111
var config: RealtimeJoinConfig
1212
var accessToken: String?
13+
var version: String?
1314

1415
enum CodingKeys: String, CodingKey {
1516
case config
1617
case accessToken = "access_token"
18+
case version
1719
}
1820
}
1921

Tests/RealtimeTests/RealtimeTests.swift

+10-15
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ final class RealtimeTests: XCTestCase {
113113
XCTAssertEqual(channelStatuses.value, [.unsubscribed, .subscribing, .subscribed])
114114

115115
assertInlineSnapshot(of: client.sentEvents.map(\.json), as: .json) {
116-
"""
116+
#"""
117117
[
118118
{
119119
"text" : {
@@ -147,14 +147,15 @@ final class RealtimeTests: XCTestCase {
147147
"key" : ""
148148
},
149149
"private" : false
150-
}
150+
},
151+
"version" : "realtime-swift\/0.0.0"
151152
},
152153
"ref" : "1",
153154
"topic" : "realtime:public:messages"
154155
}
155156
}
156157
]
157-
"""
158+
"""#
158159
}
159160
}
160161

@@ -199,7 +200,7 @@ final class RealtimeTests: XCTestCase {
199200
$0.event == "phx_join"
200201
}
201202
assertInlineSnapshot(of: events, as: .json) {
202-
"""
203+
#"""
203204
[
204205
{
205206
"event" : "phx_join",
@@ -218,7 +219,8 @@ final class RealtimeTests: XCTestCase {
218219
"key" : ""
219220
},
220221
"private" : false
221-
}
222+
},
223+
"version" : "realtime-swift\/0.0.0"
222224
},
223225
"ref" : "1",
224226
"topic" : "realtime:public:messages"
@@ -240,13 +242,14 @@ final class RealtimeTests: XCTestCase {
240242
"key" : ""
241243
},
242244
"private" : false
243-
}
245+
},
246+
"version" : "realtime-swift\/0.0.0"
244247
},
245248
"ref" : "2",
246249
"topic" : "realtime:public:messages"
247250
}
248251
]
249-
"""
252+
"""#
250253
}
251254
}
252255

@@ -378,14 +381,6 @@ final class RealtimeTests: XCTestCase {
378381
XCTAssertEqual(sut.mutableState.accessToken, validToken)
379382
}
380383

381-
func testSetAuthWithExpiredToken() async throws {
382-
let expiredToken =
383-
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOi02NDA5MjIxMTIwMH0.tnbZRC8vEyK3zaxPxfOjNgvpnuum18dxYlXeHJ4r7u8"
384-
await sut.setAuth(expiredToken)
385-
386-
XCTAssertNotEqual(sut.mutableState.accessToken, expiredToken)
387-
}
388-
389384
func testSetAuthWithNonJWT() async throws {
390385
let token = "sb-token"
391386
await sut.setAuth(token)

0 commit comments

Comments
 (0)