From c74ce06b24e936531f690cd9695b64d0dd1cbfbb Mon Sep 17 00:00:00 2001 From: Guilherme Souza Date: Fri, 7 Feb 2025 08:32:20 -0300 Subject: [PATCH 1/3] fix(realtime): remove jwt check Also: - Call `setAuth` after heartbeat - Send `x-client-info` when joining channel --- Sources/Realtime/RealtimeChannelV2.swift | 3 ++- Sources/Realtime/RealtimeClientV2.swift | 20 +++++++++----------- Sources/Realtime/RealtimeJoinConfig.swift | 2 ++ 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/Sources/Realtime/RealtimeChannelV2.swift b/Sources/Realtime/RealtimeChannelV2.swift index 50c1958ea..714122416 100644 --- a/Sources/Realtime/RealtimeChannelV2.swift +++ b/Sources/Realtime/RealtimeChannelV2.swift @@ -104,7 +104,8 @@ public final class RealtimeChannelV2: Sendable { let payload = RealtimeJoinPayload( config: joinConfig, - accessToken: await socket._getAccessToken() + accessToken: await socket._getAccessToken(), + version: socket.options.headers[.xClientInfo] ) let joinRef = socket.makeRef() diff --git a/Sources/Realtime/RealtimeClientV2.swift b/Sources/Realtime/RealtimeClientV2.swift index 34a019405..c731eec41 100644 --- a/Sources/Realtime/RealtimeClientV2.swift +++ b/Sources/Realtime/RealtimeClientV2.swift @@ -117,13 +117,18 @@ public final class RealtimeClientV2: Sendable { wsTransport: @escaping WebSocketTransport, http: any HTTPClientType ) { + var options = options + if options.headers[.xClientInfo] == nil { + options.headers[.xClientInfo] = "realtime-swift/\(version)" + } + self.url = url self.options = options self.wsTransport = wsTransport self.http = http apikey = options.apikey - mutableState.withValue { + mutableState.withValue { [options] in if let accessToken = options.headers[.authorization]?.split(separator: " ").last { $0.accessToken = String(accessToken) } else { @@ -353,7 +358,7 @@ public final class RealtimeClientV2: Sendable { if Task.isCancelled { break } - self?.sendHeartbeat() + await self?.sendHeartbeat() } } mutableState.withValue { @@ -361,7 +366,7 @@ public final class RealtimeClientV2: Sendable { } } - private func sendHeartbeat() { + private func sendHeartbeat() async { let pendingHeartbeatRef: String? = mutableState.withValue { if $0.pendingHeartbeatRef != nil { $0.pendingHeartbeatRef = nil @@ -383,6 +388,7 @@ public final class RealtimeClientV2: Sendable { payload: [:] ) ) + await setAuth() } else { options.logger?.debug("Heartbeat timeout") reconnect() @@ -426,14 +432,6 @@ public final class RealtimeClientV2: Sendable { token = mutableState.accessToken } - if let token, let payload = JWT.decodePayload(token), - let exp = payload["exp"] as? TimeInterval, exp < Date().timeIntervalSince1970 - { - options.logger?.warning( - "InvalidJWTToken: Invalid value for JWT claim \"exp\" with value \(exp)") - return - } - mutableState.withValue { [token] in $0.accessToken = token } diff --git a/Sources/Realtime/RealtimeJoinConfig.swift b/Sources/Realtime/RealtimeJoinConfig.swift index 06b0a4920..a617757f2 100644 --- a/Sources/Realtime/RealtimeJoinConfig.swift +++ b/Sources/Realtime/RealtimeJoinConfig.swift @@ -10,10 +10,12 @@ import Foundation struct RealtimeJoinPayload: Codable { var config: RealtimeJoinConfig var accessToken: String? + var version: String? enum CodingKeys: String, CodingKey { case config case accessToken = "access_token" + case version } } From 778cd26e6031de39f17e3390c6da795e188aab93 Mon Sep 17 00:00:00 2001 From: Guilherme Souza Date: Fri, 7 Feb 2025 08:54:11 -0300 Subject: [PATCH 2/3] fix tests --- .../xcshareddata/xcschemes/Realtime.xcscheme | 25 +++++++++++++++++-- Tests/RealtimeTests/RealtimeTests.swift | 25 ++++++++----------- 2 files changed, 33 insertions(+), 17 deletions(-) diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/Realtime.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/Realtime.xcscheme index cfe75c360..3e3a8bb81 100644 --- a/.swiftpm/xcode/xcshareddata/xcschemes/Realtime.xcscheme +++ b/.swiftpm/xcode/xcshareddata/xcschemes/Realtime.xcscheme @@ -1,7 +1,7 @@ + version = "1.3"> @@ -26,8 +26,29 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - shouldUseLaunchSchemeArgsEnv = "YES"> + shouldUseLaunchSchemeArgsEnv = "YES" + codeCoverageEnabled = "YES" + onlyGenerateCoverageForSpecifiedTargets = "YES"> + + + + + + + + Date: Fri, 7 Feb 2025 08:58:13 -0300 Subject: [PATCH 3/3] only send token if changed --- Sources/Realtime/RealtimeClientV2.swift | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Sources/Realtime/RealtimeClientV2.swift b/Sources/Realtime/RealtimeClientV2.swift index c731eec41..e82d8fe1e 100644 --- a/Sources/Realtime/RealtimeClientV2.swift +++ b/Sources/Realtime/RealtimeClientV2.swift @@ -422,14 +422,14 @@ public final class RealtimeClientV2: Sendable { /// On callback used, it will set the value of the token internal to the client. /// - Parameter token: A JWT string to override the token set on the client. public func setAuth(_ token: String? = nil) async { - var token = token + var tokenToSend = token - if token == nil { - token = try? await options.accessToken?() + if tokenToSend == nil { + tokenToSend = try? await options.accessToken?() } - if token == nil { - token = mutableState.accessToken + guard tokenToSend != mutableState.accessToken else { + return } mutableState.withValue { [token] in