import Foundation /** A result from sending a key to the device. */ enum MessageResult: UInt8 { // MARK: Device status /// The message was accepted. case messageAccepted = 0 /// The web socket received text while waiting for binary data. case textReceived = 1 /// An unexpected socket event occured while performing the exchange. case unexpectedSocketEvent = 2 /// The received message size is invalid. case invalidMessageSizeFromRemote = 3 /// The message signature was incorrect. case invalidSignatureFromRemote = 4 /// The server challenge of the message did not match previous messages case invalidServerChallengeFromRemote = 5 /// The client challenge of the message did not match previous messages case invalidClientChallengeFromRemote = 6 /// An unexpected or unsupported message type was received case invalidMessageTypeFromRemote = 7 /// A message is already being processed case tooManyRequests = 8 /// The received message result was not ``messageAccepted`` case invalidMessageResultFromRemote = 9 /// An invalid Url parameter was set sending a message to the device over a local connection case invalidUrlParameter = 10 // MARK: Server status /// The body data posting a message was missing or of wrong length case noOrInvalidBodyDataFromRemote = 21 /// The authentication token for the server was invalid case invalidServerAuthenticationFromRemote = 22 /// The request took too long to complete case deviceTimedOut = 23 /// The device is not connected to the server via web socket case deviceNotConnected = 24 /// The device sent a response of invalid size case invalidMessageSizeFromDevice = 25 /// The header with the authentication token was missing or invalid (not a hex string) from a server request. case missingOrInvalidAuthenticationHeaderFromRemote = 26 /// The server produced an internal error (500) case internalServerError = 27 // MARK: Remote status /// The url string is not a valid url case serverUrlInvalid = 31 /// The device key or auth token is missing for a request. case noKeyAvailable = 32 /// The Sesame server behind the proxy could not be found (502) case serviceBehindProxyUnavailable = 33 /// The server url could not be found (404) case pathOnServerNotFound = 34 /// The url session request returned an unknown response case unexpectedUrlResponseType = 35 /// The request to the server returned an unhandled HTTP code case unexpectedServerResponseCode = 36 /// A valid server challenge was received case deviceAvailable = 37 case invalidSignatureByDevice = 38 case invalidMessageTypeFromDevice = 39 case unknownMessageResultFromDevice = 40 /// The device sent a message with an invalid client challenge case invalidClientChallengeFromDevice = 41 /// The device used an invalid server challenge in a response case invalidServerChallengeFromDevice = 42 /// The unlock process was successfully completed case unlocked = 43 } extension MessageResult: Error { } extension MessageResult: CustomStringConvertible { var description: String { switch self { case .messageAccepted: return "Message accepted" case .textReceived: return "The device received unexpected text" case .unexpectedSocketEvent: return "Unexpected socket event for the device" case .invalidMessageSizeFromRemote: return "Invalid message data from remote" case .invalidSignatureFromRemote: return "Message authentication failed" case .invalidServerChallengeFromRemote: return "Server challenge mismatch" case .invalidClientChallengeFromRemote: return "Wrong client challenge sent" case .invalidMessageTypeFromRemote: return "Message type from remote invalid" case .tooManyRequests: return "Device busy" case .invalidMessageResultFromRemote: return "Invalid message result" case .invalidUrlParameter: return "The url parameter could not be found" case .noOrInvalidBodyDataFromRemote: return "Invalid body data in server request" case .invalidServerAuthenticationFromRemote: return "Invalid server token" case .deviceTimedOut: return "The device did not respond" case .deviceNotConnected: return "Device not connected to server" case .invalidMessageSizeFromDevice: return "Invalid device message size" case .missingOrInvalidAuthenticationHeaderFromRemote: return "Invalid server token format" case .internalServerError: return "Internal server error" case .serverUrlInvalid: return "Invalid server url" case .noKeyAvailable: return "No key available" case .serviceBehindProxyUnavailable: return "Service behind proxy not found" case .pathOnServerNotFound: return "Invalid server path" case .unexpectedUrlResponseType: return "Unexpected URL response" case .unexpectedServerResponseCode: return "Unexpected server response code" case .deviceAvailable: return "Device available" case .invalidSignatureByDevice: return "Invalid device signature" case .invalidMessageTypeFromDevice: return "Message type from device invalid" case .unknownMessageResultFromDevice: return "Unknown message result" case .invalidClientChallengeFromDevice: return "Device sent invalid client challenge" case .invalidServerChallengeFromDevice: return "Invalid" case .unlocked: return "Unlocked" } } } extension MessageResult: Codable { } extension MessageResult { var encoded: Data { Data([rawValue]) } } extension MessageResult { init(httpCode: Int) { switch httpCode { case 200: self = .messageAccepted case 204: self = .noOrInvalidBodyDataFromRemote case 403: self = .invalidServerAuthenticationFromRemote case 404: self = .pathOnServerNotFound case 408: self = .deviceTimedOut case 412: self = .deviceNotConnected case 413: self = .invalidMessageSizeFromDevice case 422: self = .missingOrInvalidAuthenticationHeaderFromRemote case 429: self = .tooManyRequests case 500: self = .internalServerError case 501: self = .unexpectedServerResponseCode case 502: self = .serviceBehindProxyUnavailable default: self = .unexpectedServerResponseCode } } var statusCode: Int { switch self { case .messageAccepted: return 200 // ok case .noOrInvalidBodyDataFromRemote: return 204 // noContent case .invalidServerAuthenticationFromRemote: return 403 // forbidden case .pathOnServerNotFound: return 404 // notFound case .deviceTimedOut: return 408 // requestTimeout case .invalidMessageSizeFromRemote: return 411 // lengthRequired case .deviceNotConnected: return 412 // preconditionFailed case .invalidMessageSizeFromDevice: return 413 // payloadTooLarge case .missingOrInvalidAuthenticationHeaderFromRemote: return 422 // unprocessableEntity case .tooManyRequests: return 429 // tooManyRequests case .internalServerError: return 500 // internalServerError case .unexpectedServerResponseCode: return 501 // notImplemented case .serviceBehindProxyUnavailable: return 502 // badGateway default: return 501 // == unexpectedServerResponseCode } } }