Distinguish SSH route admission from Telnet target admission and wire Telnet access and automatic Wake hooks. Await entitlement resolution for manual Wake and duplication before host or credential mutation. Use explicit protocol-extension forwarding overloads so existential single-argument calls cannot bypass the concrete admission witness. Remove dead paywall state and update obsolete quota/date test fixtures. Validation: 81 focused macOS and 58 focused iOS tests passed.
68 lines
2.0 KiB
Swift
68 lines
2.0 KiB
Swift
import Foundation
|
|
import TermindDomain
|
|
|
|
import struct TermindDomain.Host
|
|
|
|
public nonisolated enum HostUseCase: Hashable, Sendable {
|
|
case preferredTerminal
|
|
case sshTerminal
|
|
case telnetTerminal
|
|
case sftp
|
|
case jumpHost
|
|
case metrics
|
|
case portForwarding
|
|
case snippetExecution
|
|
case keyExport
|
|
|
|
public var protocolRequirement: HostProtocolRequirement {
|
|
switch self {
|
|
case .preferredTerminal: .anyTerminal
|
|
case .telnetTerminal: .telnet
|
|
case .sshTerminal, .sftp, .jumpHost, .metrics, .portForwarding, .snippetExecution, .keyExport: .ssh
|
|
}
|
|
}
|
|
|
|
public func accessProtocol(for host: Host) -> HostTerminalProtocol {
|
|
switch self {
|
|
case .preferredTerminal: host.preferredTerminalProtocol ?? .ssh
|
|
case .telnetTerminal: .telnet
|
|
default: .ssh
|
|
}
|
|
}
|
|
}
|
|
|
|
public nonisolated struct HostProtocolUnavailableError: LocalizedError, Equatable, Sendable {
|
|
public var useCase: HostUseCase
|
|
|
|
public init(useCase: HostUseCase) { self.useCase = useCase }
|
|
|
|
public var errorDescription: String? {
|
|
switch useCase.protocolRequirement {
|
|
case .anyTerminal: String(localized: "No terminal protocol is enabled for this Host.")
|
|
case .ssh: String(localized: "SSH is disabled for this Host.")
|
|
case .telnet: String(localized: "Telnet is disabled for this Host.")
|
|
}
|
|
}
|
|
}
|
|
|
|
public nonisolated struct HostLibrarySnapshot: Equatable, Sendable {
|
|
public var hosts: [Host]
|
|
public var groups: [HostGroup]
|
|
|
|
public static let empty = HostLibrarySnapshot(hosts: [], groups: [])
|
|
public init(hosts: [Host], groups: [HostGroup]) {
|
|
self.hosts = hosts
|
|
self.groups = groups
|
|
}
|
|
|
|
}
|
|
|
|
@MainActor
|
|
public protocol HostRepository: AnyObject {
|
|
func snapshot() throws -> RepositoryChange<HostLibrarySnapshot>
|
|
func refresh() throws
|
|
func requestHostDeletion(_ hostID: Host.ID) throws
|
|
func clearReferencesForDeletedHost(_ hostID: Host.ID) throws
|
|
func finalizeHostDeletion(_ hostID: Host.ID) throws
|
|
}
|