import Foundation import RemoteCore /// Prototype wire format to verify against physical TV models. No network or TLS /// policy is implemented here. In particular, callers must never disable trust checks. public enum SamsungRemoteEncoder { public static let clientName = "Wristivo" public static func key(for command: RemoteCommand) -> String { switch command { case .up: "KEY_UP" case .down: "KEY_DOWN" case .left: "KEY_LEFT" case .right: "KEY_RIGHT" case .select: "KEY_ENTER" case .back: "KEY_RETURN" case .home: "KEY_HOME" case .playPause: "KEY_PLAYPAUSE" case .volumeUp: "KEY_VOLUP" case .volumeDown: "KEY_VOLDOWN" case .mute: "KEY_MUTE" } } public static func clickFrame(for command: RemoteCommand) throws -> Data { try JSONEncoder().encode(Frame(params: Parameters(DataOfCmd: key(for: command)))) } public enum EndpointError: Error, Sendable { case invalidHost } /// Accepts a bare hostname or IPv4 address, or a bracketed IPv6 literal. /// Treat token as a secret: do not log the returned URL or persist it in telemetry. public static func endpoint(host: String, token: String? = nil) throws -> URL { guard !host.isEmpty, !host.contains(where: { $0.isWhitespace }), !host.contains("/"), !host.contains("@"), !host.contains("?"), !host.contains("#"), !host.contains("%"), !host.contains("\\"), (!host.contains(":") || (host.hasPrefix("[") && host.hasSuffix("]"))) else { throw EndpointError.invalidHost } var parts = URLComponents() parts.scheme = "wss" parts.host = host parts.port = 8002 parts.path = "/api/v2/channels/samsung.remote.control" var items = [URLQueryItem(name: "name", value: Data(clientName.utf8).base64EncodedString())] if let token { items.append(URLQueryItem(name: "token", value: token)) } parts.queryItems = items // '+' is legal in an RFC 3986 query, but some embedded servers treat it as // a form-space. Encode it explicitly while retaining URLComponents escaping. parts.percentEncodedQuery = parts.percentEncodedQuery?.replacingOccurrences(of: "+", with: "%2B") guard let url = parts.url, url.host != nil else { throw EndpointError.invalidHost } return url } private struct Frame: Encodable { let method = "ms.remote.control" let params: Parameters } private struct Parameters: Encodable { let Cmd = "Click" let DataOfCmd: String let Option = "false" let TypeOfRemote = "SendRemoteKey" } }