Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ let package = Package(
.package(url: "https://github.com/vapor/jwt-kit.git", from: "4.13.5"),
// Only used for DocC generation
.package(url: "https://github.com/apple/swift-docc-plugin.git", from: "1.3.0"),
// Local uniffi bindings
.package(path: "../rust-sdks/livekit-uniffi"),
],
targets: [
.target(
Expand All @@ -39,6 +41,7 @@ let package = Package(
.product(name: "DequeModule", package: "swift-collections"),
.product(name: "OrderedCollections", package: "swift-collections"),
.product(name: "JWTKit", package: "jwt-kit"),
.product(name: "LiveKitFFI", package: "livekit-uniffi"),
"LKObjCHelpers",
],
exclude: [
Expand Down
3 changes: 3 additions & 0 deletions Package@swift-6.0.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ let package = Package(
.package(url: "https://github.com/vapor/jwt-kit.git", from: "4.13.5"),
// Only used for DocC generation
.package(url: "https://github.com/apple/swift-docc-plugin.git", from: "1.3.0"),
// Local uniffi bindings
.package(path: "../rust-sdks/livekit-uniffi"),
],
targets: [
.target(
Expand All @@ -40,6 +42,7 @@ let package = Package(
.product(name: "DequeModule", package: "swift-collections"),
.product(name: "OrderedCollections", package: "swift-collections"),
.product(name: "JWTKit", package: "jwt-kit"),
.product(name: "LiveKitFFI", package: "livekit-uniffi"),
"LKObjCHelpers",
],
exclude: [
Expand Down
61 changes: 55 additions & 6 deletions Sources/LiveKit/Support/Logger.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import OSLog
internal import LiveKitWebRTC
internal import LiveKitFFI

// MARK: - Logger

Expand Down Expand Up @@ -108,6 +109,7 @@ public struct PrintLogger: Logger {
/// A logger that logs to OSLog
/// - Parameter minLevel: The minimum level to log
/// - Parameter rtc: Whether to log WebRTC output
/// - Parameter ffi: Whether to log Rust FFI output
open class OSLogger: Logger, @unchecked Sendable {
private static let subsystem = "io.livekit.sdk"

Expand All @@ -118,15 +120,15 @@ open class OSLogger: Logger, @unchecked Sendable {

private let minLevel: LogLevel

public init(minLevel: LogLevel = .info, rtc: Bool = false) {
public init(minLevel: LogLevel = .info, rtc: Bool = false, ffi: Bool = true) {
self.minLevel = minLevel

guard rtc else { return }
if rtc {
startRTCLogForwarding(minLevel: minLevel)
}

let rtcLog = OSLog(subsystem: Self.subsystem, category: "WebRTC")
rtcLogger.severity = minLevel.rtcSeverity
rtcLogger.start { message, severity in
os_log("%{public}@", log: rtcLog, type: severity.osLogType, message)
if ffi {
startFFILogForwarding(minLevel: minLevel)
}
}

Expand Down Expand Up @@ -171,6 +173,33 @@ open class OSLogger: Logger, @unchecked Sendable {
os_log("%{public}@", log: getOSLog(for: type), type: level.osLogType, "\(type).\(function) \(message)\(metadata)")
}
}

private func startRTCLogForwarding(minLevel: LogLevel) {
let rtcLog = OSLog(subsystem: Self.subsystem, category: "WebRTC")

rtcLogger.severity = minLevel.rtcSeverity
rtcLogger.start { message, severity in
os_log("%{public}@", log: rtcLog, type: severity.osLogType, message)
}
}

private func startFFILogForwarding(minLevel: LogLevel) {
Task(priority: .utility) { [weak self] in
guard self != nil else { return } // don't initialize global level when releasing
logForwardBootstrap(level: minLevel.logForwardFilter)

let ffiLog = OSLog(subsystem: Self.subsystem, category: "FFI")
let ffiStream = AsyncStream(unfolding: logForwardReceive)

for await entry in ffiStream {
guard self != nil else { return }

let message = "\(entry.target) \(entry.message)"

os_log("%{public}@", log: ffiLog, type: entry.level.osLogType, message)
}
}
}
}

// MARK: - Loggable
Expand Down Expand Up @@ -236,6 +265,15 @@ public enum LogLevel: Int, Sendable, Comparable, CustomStringConvertible {
}
}

var logForwardFilter: LogForwardFilter {
switch self {
case .debug: .debug
case .info: .info
case .warning: .warn
case .error: .error
}
}

@inlinable
public static func < (lhs: LogLevel, rhs: LogLevel) -> Bool {
lhs.rawValue < rhs.rawValue
Expand Down Expand Up @@ -263,3 +301,14 @@ extension LKRTCLoggingSeverity {
}
}
}

extension LogForwardLevel {
var osLogType: OSLogType {
switch self {
case .error: .error
case .warn: .default
case .info: .info
case .debug, .trace: .debug
}
}
}
28 changes: 18 additions & 10 deletions Sources/LiveKit/Token/CachingTokenSource.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* limitations under the License.
*/

internal import LiveKitFFI
import Foundation

/// A token source that caches credentials from any other ``TokenSourceConfigurable`` using a configurable store.
Expand Down Expand Up @@ -148,20 +149,27 @@ public extension TokenSourceResponse {
return false
}

do {
try jwt.nbf.verifyNotBefore()
try jwt.exp.verifyNotExpired(currentDate: Date().addingTimeInterval(tolerance))
} catch {
return false
}

return true
return jwt.nbf.verifyNotBefore() && jwt.exp.verifyNotExpired(currentDate: Date().addingTimeInterval(tolerance))
}

/// Extracts the JWT payload from the participant token.
///
/// - Returns: The JWT payload if successfully parsed, nil otherwise
internal func jwt() -> LiveKitJWTPayload? {
LiveKitJWTPayload.fromUnverified(token: participantToken)
internal func jwt() -> Claims? {
try? tokenClaimsFromUnverified(token: participantToken)
}
}

private extension UInt64 {
var asDate: Date {
Date(timeIntervalSince1970: TimeInterval(self))
}

func verifyNotBefore(currentDate: Date = Date()) -> Bool {
currentDate >= asDate
}

func verifyNotExpired(currentDate: Date = Date()) -> Bool {
currentDate < asDate
}
}
107 changes: 0 additions & 107 deletions Sources/LiveKit/Token/JWT.swift

This file was deleted.

39 changes: 36 additions & 3 deletions Tests/LiveKitCoreTests/Token/TokenSourceTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#if canImport(LiveKitTestSupport)
import LiveKitTestSupport
#endif
import LiveKitFFI

class TokenSourceTests: LKTestCase {
actor MockValidJWTSource: TokenSourceConfigurable {
Expand All @@ -38,7 +39,23 @@ class TokenSourceTests: LKTestCase {
identity: options.participantIdentity ?? "test-identity"
)
tokenGenerator.name = options.participantName ?? participantName
tokenGenerator.videoGrant = LiveKitJWTPayload.VideoGrant(room: options.roomName ?? "test-room", roomJoin: true)
tokenGenerator.videoGrants = VideoGrants(
roomCreate: false,
roomList: false,
roomRecord: false,
roomAdmin: false,
roomJoin: true,
room: options.roomName ?? "test-room",
destinationRoom: "",
canPublish: false,
canSubscribe: false,
canPublishData: false,
canPublishSources: [],
canUpdateOwnMetadata: false,
ingressAdmin: false,
hidden: false,
recorder: false
)

let token = try tokenGenerator.sign()

Expand Down Expand Up @@ -74,10 +91,26 @@ class TokenSourceTests: LKTestCase {
apiKey: "test-api-key",
apiSecret: "test-api-secret",
identity: options.participantIdentity ?? "test-identity",
ttl: -60
ttl: 0
)
tokenGenerator.name = options.participantName ?? "test-participant"
tokenGenerator.videoGrant = LiveKitJWTPayload.VideoGrant(room: options.roomName ?? "test-room", roomJoin: true)
tokenGenerator.videoGrants = VideoGrants(
roomCreate: false,
roomList: false,
roomRecord: false,
roomAdmin: false,
roomJoin: true,
room: options.roomName ?? "test-room",
destinationRoom: "",
canPublish: false,
canSubscribe: false,
canPublishData: false,
canPublishSources: [],
canUpdateOwnMetadata: false,
ingressAdmin: false,
hidden: false,
recorder: false
)

let token = try tokenGenerator.sign()

Expand Down
25 changes: 19 additions & 6 deletions Tests/LiveKitTestSupport/Room.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/

@testable import LiveKit
import LiveKitFFI

public struct RoomTestingOptions {
public let delegate: RoomDelegate?
Expand Down Expand Up @@ -78,12 +79,24 @@ public extension LKTestCase {
apiSecret: apiSecret,
identity: identity)

tokenGenerator.videoGrant = LiveKitJWTPayload.VideoGrant(room: room,
roomJoin: true,
canPublish: canPublish,
canSubscribe: canSubscribe,
canPublishData: canPublishData,
canPublishSources: canPublishSources.map(String.init))
tokenGenerator.videoGrants = VideoGrants(
roomCreate: false,
roomList: false,
roomRecord: false,
roomAdmin: false,
roomJoin: true,
room: room,
destinationRoom: "",
canPublish: canPublish,
canSubscribe: canSubscribe,
canPublishData: canPublishData,
canPublishSources: canPublishSources.map(String.init),
canUpdateOwnMetadata: false,
ingressAdmin: false,
hidden: false,
recorder: false
)

return try tokenGenerator.sign()
}

Expand Down
Loading
Loading