remote: add password authentication

This commit is contained in:
osy 2024-02-12 12:07:41 -08:00
parent d966e1c584
commit c3939e3214
4 changed files with 37 additions and 7 deletions

View File

@ -171,9 +171,9 @@ private struct ServerConnectView: View {
} header: {
Text("Host")
}
if !server.fingerprint.isEmpty {
let fingerprint = (server.fingerprint ^ remoteClient.fingerprint).hexString()
if !fingerprint.isEmpty {
Section {
let fingerprint = (server.fingerprint ^ remoteClient.fingerprint).hexString()
if #available(iOS 16.4, *) {
Text(fingerprint).monospaced()
} else {

View File

@ -111,7 +111,14 @@ actor UTMRemoteClient {
try Task.checkCancellation()
let peer = Peer(connection: connection, localInterface: local)
let remote = Remote(peer: peer, host: host)
let device = try await remote.handshake()
let (isAuthenticated, device) = try await remote.handshake(password: server.password)
if !isAuthenticated {
if server.password == nil {
throw ConnectionError.passwordRequired
} else {
throw ConnectionError.passwordInvalid
}
}
self.server = remote
await state.setConnected(true)
if !server.shouldSavePassword {
@ -313,13 +320,13 @@ extension UTMRemoteClient {
peer.close()
}
func handshake() async throws -> MacDevice {
let reply = try await _handshake(parameters: .init(version: UTMRemoteMessageServer.version))
func handshake(password: String?) async throws -> (isAuthenticated: Bool, device: MacDevice) {
let reply = try await _handshake(parameters: .init(version: UTMRemoteMessageServer.version, password: password))
guard reply.version == UTMRemoteMessageServer.version else {
throw ClientError.versionMismatch
}
capabilities = reply.capabilities
return MacDevice(model: reply.model)
return (isAuthenticated: reply.isAuthenticated, device: MacDevice(model: reply.model))
}
func listVirtualMachines() async throws -> [M.ListVirtualMachines.Information] {

View File

@ -52,10 +52,12 @@ extension UTMRemoteMessageServer {
struct Request: Serializable, Codable {
let version: Int
let password: String?
}
struct Reply: Serializable, Codable {
let version: Int
let isAuthenticated: Bool
let capabilities: UTMCapabilities
let model: String
}

View File

@ -38,6 +38,12 @@ actor UTMRemoteServer {
cancellables = set
}
@Setting("ServerAutostart") private var isServerAutostart: Bool = false
@Setting("ServerExternal") private var isServerExternal: Bool = false
@Setting("ServerPort") private var serverPort: Int = 0
@Setting("ServerPasswordRequired") private var isServerPasswordRequired: Bool = false
@Setting("ServerPassword") private var serverPassword: String = ""
@MainActor
init(data: UTMData) {
let _state = State()
@ -549,6 +555,7 @@ extension UTMRemoteServer {
private let server: UTMRemoteServer
private let client: UTMRemoteServer.Remote
private var isAuthenticated: Bool = false
private var data: UTMData {
server.data
@ -560,6 +567,9 @@ extension UTMRemoteServer {
}
func handle(message: M, data: Data) async throws -> Data {
guard isAuthenticated || message == .serverHandshake else {
throw ServerError.notAuthenticated
}
switch message {
case .serverHandshake:
return try await _handshake(parameters: .decode(data)).encode()
@ -609,7 +619,15 @@ extension UTMRemoteServer {
}
private func _handshake(parameters: M.ServerHandshake.Request) async throws -> M.ServerHandshake.Reply {
return .init(version: UTMRemoteMessageServer.version, capabilities: .current, model: MacDevice.current.model)
let serverPassword = await server.serverPassword
if await server.isServerPasswordRequired && !serverPassword.isEmpty {
if serverPassword == parameters.password {
isAuthenticated = true
}
} else {
isAuthenticated = true
}
return .init(version: UTMRemoteMessageServer.version, isAuthenticated: isAuthenticated, capabilities: .current, model: MacDevice.current.model)
}
private func _listVirtualMachines(parameters: M.ListVirtualMachines.Request) async throws -> M.ListVirtualMachines.Reply {
@ -760,6 +778,7 @@ extension UTMRemoteServer {
extension UTMRemoteServer {
enum ServerError: LocalizedError {
case silentError(Error)
case notAuthenticated
case versionMismatch
case notFound(UUID)
case invalidBackend
@ -769,6 +788,8 @@ extension UTMRemoteServer {
switch self {
case .silentError(let error):
return error.localizedDescription
case .notAuthenticated:
return NSLocalizedString("Not authenticated.", comment: "UTMRemoteServer")
case .versionMismatch:
return NSLocalizedString("The client interface version does not match the server.", comment: "UTMRemoteServer")
case .notFound(let id):