Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add preliminary TLS support - needs fleshing out #111

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
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
19 changes: 13 additions & 6 deletions Sources/RediStack/RedisConnection+Configuration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import Atomics
import NIOCore
import NIOConcurrencyHelpers
import NIOPosix
import NIOSSL
import Logging
import struct Foundation.URL
import protocol Foundation.LocalizedError
Expand Down Expand Up @@ -52,13 +53,15 @@ extension RedisConnection {
public var port: Int? { self.address.port }
/// The user name used to authenticate connections with.
/// - Warning: This property should only be provided if you are running against Redis 6 or higher.
public let username: String?
public var username: String?
/// The password used to authenticate the connection.
public let password: String?
public var password: String?
/// The initial database index that the connection should use.
public let initialDatabase: Int?
public var initialDatabase: Int?
/// The logger prototype that will be used by the connection by default when generating logs.
public let defaultLogger: Logger
public var defaultLogger: Logger

public var tlsConfiguration: TLSConfiguration?

internal let address: SocketAddress

Expand Down Expand Up @@ -186,12 +189,16 @@ extension RedisConnection {

let databaseID = Int(url.lastPathComponent)

try self.init(
var config = try Self(
address: try .makeAddressResolvingHost(host, port: url.port ?? Self.defaultPort),
password: url.password,
initialDatabase: databaseID,
defaultLogger: defaultLogger
)

config.tlsConfiguration = .clientDefault

self = config
}

private static func validateRedisURL(_ url: URL) throws {
Expand All @@ -200,7 +207,7 @@ extension RedisConnection {
!scheme.isEmpty
else { throw ValidationError.missingURLScheme }

guard scheme == "redis" else { throw ValidationError.invalidURLScheme }
guard scheme == "redis" || scheme == "rediss" else { throw ValidationError.invalidURLScheme }

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we also add valkey scheme?

Copy link
Member Author

@Joannis Joannis Dec 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where can I read more about valkey being a scheme?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it completely compatible with redis?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
guard scheme == "redis" || scheme == "rediss" else { throw ValidationError.invalidURLScheme }
guard scheme == "redis" || scheme == "rediss" || scheme == "valkey" else { throw ValidationError.invalidURLScheme }

}
}
}
Expand Down
30 changes: 28 additions & 2 deletions Sources/RediStack/RedisConnection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import Logging
import Metrics
import NIOCore
import NIOConcurrencyHelpers
import NIOSSL
import NIOPosix

extension RedisConnection {
Expand Down Expand Up @@ -55,9 +56,34 @@ extension RedisConnection {
boundEventLoop eventLoop: EventLoop,
configuredTCPClient client: ClientBootstrap? = nil
) -> EventLoopFuture<RedisConnection> {
let client = client ?? .makeRedisTCPClient(group: eventLoop)
let bootstrap: ClientBootstrap
if let client {
bootstrap = client
} else if let tlsConfiguration = config.tlsConfiguration {
bootstrap = ClientBootstrap(group: eventLoop)
.channelOption(
ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEADDR),
value: 1
)
.channelInitializer { channel in
do {
try channel.pipeline.syncOperations.addHandler(
NIOSSLClientHandler(
context: NIOSSLContext(configuration: tlsConfiguration),
serverHostname: config.hostname
)
)
} catch {
return eventLoop.makeFailedFuture(error)
}

return channel.pipeline.addBaseRedisHandlers()
}
} else {
bootstrap = .makeRedisTCPClient(group: eventLoop)
}

return client
return bootstrap
.connect(to: config.address)
.flatMap {
let connection = RedisConnection(configuredRESPChannel: $0, backgroundLogger: config.defaultLogger)
Expand Down