Improve message result clarity

This commit is contained in:
Christoph Hagen 2023-12-08 15:43:29 +01:00
parent e76029270a
commit 7652bb24a3
3 changed files with 111 additions and 95 deletions

View File

@ -5,6 +5,8 @@ import Foundation
*/ */
enum MessageResult: UInt8 { enum MessageResult: UInt8 {
// MARK: Device status
/// The message was accepted. /// The message was accepted.
case messageAccepted = 0 case messageAccepted = 0
@ -18,13 +20,13 @@ enum MessageResult: UInt8 {
case invalidMessageSizeFromRemote = 3 case invalidMessageSizeFromRemote = 3
/// The message signature was incorrect. /// The message signature was incorrect.
case invalidSignatureByRemote = 4 case invalidSignatureFromRemote = 4
/// The server challenge of the message did not match previous messages /// The server challenge of the message did not match previous messages
case serverChallengeMismatch = 5 case invalidServerChallengeFromRemote = 5
/// The client challenge of the message did not match previous messages /// The client challenge of the message did not match previous messages
case clientChallengeMismatchFromRemote = 6 case invalidClientChallengeFromRemote = 6
/// An unexpected or unsupported message type was received /// An unexpected or unsupported message type was received
case invalidMessageTypeFromRemote = 7 case invalidMessageTypeFromRemote = 7
@ -38,52 +40,66 @@ enum MessageResult: UInt8 {
/// An invalid Url parameter was set sending a message to the device over a local connection /// An invalid Url parameter was set sending a message to the device over a local connection
case invalidUrlParameter = 10 case invalidUrlParameter = 10
/// The request took too long to complete // MARK: Server status
case deviceTimedOut = 20
case noOrInvalidBodyDataInServerRequest = 21 /// The body data posting a message was missing or of wrong length
case noOrInvalidBodyDataFromRemote = 21
/// The device is not connected to the server via web socket
case deviceNotConnected = 22
case serverNotReached = 23
case serverUrlInvalid = 24
case invalidDeviceResponseSize = 25
case invalidSignatureByDevice = 26
case noKeyAvailable = 27
case unlocked = 28
case unknownMessageResultFromDevice = 29
/// The device sent a message with an invalid client challenge
case clientChallengeMismatchFromDevice = 30
/// A valid server challenge was received
case deviceAvailable = 31
case invalidMessageTypeFromDevice = 32
/// The url session request returned an unknown response
case unexpectedUrlResponseType = 33
/// The request to the server returned an unhandled HTTP code
case unexpectedServerResponseCode = 34
/// The server produced an internal error (500)
case internalServerError = 35
/// The Sesame server behind the proxy could not be found (502)
case serviceBehindProxyUnavailable = 36
/// The server url could not be found (404)
case pathOnServerNotFound = 37
/// The header with the authentication token was missing or invalid (not a hex string) from a server request.
case missingOrInvalidAuthenticationHeader = 38
/// The authentication token for the server was invalid /// The authentication token for the server was invalid
case invalidServerAuthentication = 39 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 /// The device sent a response of invalid size
case invalidMessageSizeFromDevice = 40 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: Error {
@ -102,62 +118,62 @@ extension MessageResult: CustomStringConvertible {
return "Unexpected socket event for the device" return "Unexpected socket event for the device"
case .invalidMessageSizeFromRemote: case .invalidMessageSizeFromRemote:
return "Invalid message data from remote" return "Invalid message data from remote"
case .invalidSignatureByRemote: case .invalidSignatureFromRemote:
return "Message authentication failed" return "Message authentication failed"
case .noOrInvalidBodyDataInServerRequest: case .invalidServerChallengeFromRemote:
return "Invalid body data in server request"
case .deviceNotConnected:
return "Device not connected to server"
case .deviceTimedOut:
return "The device did not respond"
case .serverChallengeMismatch:
return "Server challenge mismatch" return "Server challenge mismatch"
case .clientChallengeMismatchFromRemote: case .invalidClientChallengeFromRemote:
return "Wrong client challenge sent" return "Wrong client challenge sent"
case .invalidMessageTypeFromRemote: case .invalidMessageTypeFromRemote:
return "Message type from remote invalid" return "Message type from remote invalid"
case .tooManyRequests: case .tooManyRequests:
return "Device busy" return "Device busy"
case .invalidUrlParameter:
return "The url parameter could not be found"
case .invalidMessageResultFromRemote: case .invalidMessageResultFromRemote:
return "Invalid message result" return "Invalid message result"
case .serverNotReached: case .invalidUrlParameter:
return "Server unavailable" return "The url parameter could not be found"
case .serverUrlInvalid:
return "Invalid server url" case .noOrInvalidBodyDataFromRemote:
case .invalidDeviceResponseSize: return "Invalid body data in server request"
return "Invalid Response size" case .invalidServerAuthenticationFromRemote:
case .invalidSignatureByDevice: return "Invalid server token"
return "Invalid device signature" case .deviceTimedOut:
case .noKeyAvailable: return "The device did not respond"
return "No key available" case .deviceNotConnected:
case .unlocked: return "Device not connected to server"
return "Unlocked" case .invalidMessageSizeFromDevice:
case .unknownMessageResultFromDevice: return "Invalid device message size"
return "Unknown message result" case .missingOrInvalidAuthenticationHeaderFromRemote:
case .deviceAvailable: return "Invalid server token format"
return "Device available"
case .clientChallengeMismatchFromDevice:
return "Device sent invalid client challenge"
case .invalidMessageTypeFromDevice:
return "Message type from device invalid"
case .unexpectedUrlResponseType:
return "Unexpected URL response"
case .unexpectedServerResponseCode:
return "Unexpected server response code"
case .internalServerError: case .internalServerError:
return "Internal server error" return "Internal server error"
case .serverUrlInvalid:
return "Invalid server url"
case .noKeyAvailable:
return "No key available"
case .serviceBehindProxyUnavailable: case .serviceBehindProxyUnavailable:
return "Service behind proxy not found" return "Service behind proxy not found"
case .pathOnServerNotFound: case .pathOnServerNotFound:
return "Invalid server path" return "Invalid server path"
case .missingOrInvalidAuthenticationHeader: case .unexpectedUrlResponseType:
return "Invalid server token format" return "Unexpected URL response"
case .invalidServerAuthentication: case .unexpectedServerResponseCode:
return "Invalid server token" return "Unexpected server response code"
case .invalidMessageSizeFromDevice: case .deviceAvailable:
return "Invalid device message size" 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"
} }
} }
} }
@ -178,13 +194,13 @@ extension MessageResult {
init(httpCode: Int) { init(httpCode: Int) {
switch httpCode { switch httpCode {
case 200: self = .messageAccepted case 200: self = .messageAccepted
case 204: self = .noOrInvalidBodyDataInServerRequest case 204: self = .noOrInvalidBodyDataFromRemote
case 403: self = .invalidServerAuthentication case 403: self = .invalidServerAuthenticationFromRemote
case 404: self = .pathOnServerNotFound case 404: self = .pathOnServerNotFound
case 408: self = .deviceTimedOut case 408: self = .deviceTimedOut
case 412: self = .deviceNotConnected case 412: self = .deviceNotConnected
case 413: self = .invalidMessageSizeFromDevice case 413: self = .invalidMessageSizeFromDevice
case 422: self = .missingOrInvalidAuthenticationHeader case 422: self = .missingOrInvalidAuthenticationHeaderFromRemote
case 429: self = .tooManyRequests case 429: self = .tooManyRequests
case 500: self = .internalServerError case 500: self = .internalServerError
case 501: self = .unexpectedServerResponseCode case 501: self = .unexpectedServerResponseCode
@ -196,14 +212,14 @@ extension MessageResult {
var statusCode: Int { var statusCode: Int {
switch self { switch self {
case .messageAccepted: return 200 // ok case .messageAccepted: return 200 // ok
case .noOrInvalidBodyDataInServerRequest: return 204 // noContent case .noOrInvalidBodyDataFromRemote: return 204 // noContent
case .invalidServerAuthentication: return 403 // forbidden case .invalidServerAuthenticationFromRemote: return 403 // forbidden
case .pathOnServerNotFound: return 404 // notFound case .pathOnServerNotFound: return 404 // notFound
case .deviceTimedOut: return 408 // requestTimeout case .deviceTimedOut: return 408 // requestTimeout
case .invalidMessageSizeFromRemote: return 411 // lengthRequired case .invalidMessageSizeFromRemote: return 411 // lengthRequired
case .deviceNotConnected: return 412 // preconditionFailed case .deviceNotConnected: return 412 // preconditionFailed
case .invalidMessageSizeFromDevice: return 413 // payloadTooLarge case .invalidMessageSizeFromDevice: return 413 // payloadTooLarge
case .missingOrInvalidAuthenticationHeader: return 422 // unprocessableEntity case .missingOrInvalidAuthenticationHeaderFromRemote: return 422 // unprocessableEntity
case .tooManyRequests: return 429 // tooManyRequests case .tooManyRequests: return 429 // tooManyRequests
case .internalServerError: return 500 // internalServerError case .internalServerError: return 500 // internalServerError
case .unexpectedServerResponseCode: return 501 // notImplemented case .unexpectedServerResponseCode: return 501 // notImplemented

View File

@ -65,10 +65,10 @@ final class DeviceManager {
func sendMessageToDevice(_ message: Data, authToken: Data, on eventLoop: EventLoop) async throws -> Data { func sendMessageToDevice(_ message: Data, authToken: Data, on eventLoop: EventLoop) async throws -> Data {
guard message.count == SignedMessage.size else { guard message.count == SignedMessage.size else {
throw MessageResult.invalidMessageSizeFromDevice throw MessageResult.invalidMessageSizeFromRemote
} }
guard SHA256.hash(data: authToken) == remoteKey else { guard SHA256.hash(data: authToken) == remoteKey else {
throw MessageResult.invalidServerAuthentication throw MessageResult.invalidServerAuthenticationFromRemote
} }
guard let socket = connection, !socket.isClosed else { guard let socket = connection, !socket.isClosed else {
connection = nil connection = nil

View File

@ -18,12 +18,12 @@ func routes(_ app: Application) {
guard let authString = request.headers.first(name: SesameHeader.authenticationHeader), guard let authString = request.headers.first(name: SesameHeader.authenticationHeader),
let authToken = Data(fromHexEncodedString: authString), let authToken = Data(fromHexEncodedString: authString),
authToken.count == SesameHeader.serverAuthenticationTokenSize else { authToken.count == SesameHeader.serverAuthenticationTokenSize else {
throw MessageResult.missingOrInvalidAuthenticationHeader throw MessageResult.missingOrInvalidAuthenticationHeaderFromRemote
} }
guard let body = request.body.data, guard let body = request.body.data,
let message = body.getData(at: 0, length: body.readableBytes) else { let message = body.getData(at: 0, length: body.readableBytes) else {
throw MessageResult.noOrInvalidBodyDataInServerRequest throw MessageResult.noOrInvalidBodyDataFromRemote
} }
let responseMessage = try await deviceManager.sendMessageToDevice(message, authToken: authToken, on: request.eventLoop) let responseMessage = try await deviceManager.sendMessageToDevice(message, authToken: authToken, on: request.eventLoop)