diff --git a/Sources/App/API/Message.swift b/Sources/App/API/Message.swift index b29024c..90d2b2d 100644 --- a/Sources/App/API/Message.swift +++ b/Sources/App/API/Message.swift @@ -29,6 +29,14 @@ struct Message: Equatable, Hashable { } } +extension Message: Codable { + + enum CodingKeys: Int, CodingKey { + case mac = 1 + case content = 2 + } +} + extension Message { /** @@ -42,14 +50,17 @@ extension Message { /// The counter of the message (for freshness) let id: UInt32 + let deviceId: UInt8? + /** Create new message content. - Parameter time: The time of message creation, - Parameter id: The counter of the message */ - init(time: UInt32, id: UInt32) { + init(time: UInt32, id: UInt32, device: UInt8) { self.time = time self.id = id + self.deviceId = device } /** @@ -61,20 +72,29 @@ extension Message { */ init(decodeFrom data: T) where T.Element == UInt8 { self.time = UInt32(data: Data(data.prefix(MemoryLayout.size))) - self.id = UInt32(data: Data(data.dropFirst(MemoryLayout.size))) + self.id = UInt32(data: Data(data.dropLast().suffix(MemoryLayout.size))) + self.deviceId = data.suffix(1).last! } /// The byte length of an encoded message content static var length: Int { - MemoryLayout.size * 2 + MemoryLayout.size * 2 + 1 } /// The message content encoded to data var encoded: Data { - time.encoded + id.encoded + time.encoded + id.encoded + Data([deviceId ?? 0]) } } +} +extension Message.Content: Codable { + + enum CodingKeys: Int, CodingKey { + case time = 1 + case id = 2 + case deviceId = 3 + } } extension Message { @@ -96,6 +116,14 @@ extension Message { self.init(decodeFrom: data) } + init?(decodeFrom data: Data, index: inout Int) { + guard index + Message.length <= data.count else { + return nil + } + self.init(decodeFrom: data.advanced(by: index)) + index += Message.length + } + /// The message encoded to data var encoded: Data { mac + content.encoded diff --git a/Sources/App/API/MessageResult.swift b/Sources/App/API/MessageResult.swift index ecf41af..ccfbf71 100644 --- a/Sources/App/API/MessageResult.swift +++ b/Sources/App/API/MessageResult.swift @@ -26,6 +26,9 @@ enum MessageResult: UInt8 { /// The key was accepted by the device, and the door will be opened case messageAccepted = 7 + /// The device id is invalid + case messageDeviceInvalid = 8 + /// The request did not contain body data with the key case noBodyData = 10 @@ -61,6 +64,8 @@ extension MessageResult: CustomStringConvertible { return "Message counter invalid" case .messageAccepted: return "Message accepted" + case .messageDeviceInvalid: + return "Invalid device ID" case .noBodyData: return "No body data included in the request" case .deviceNotConnected: diff --git a/Tests/AppTests/AppTests.swift b/Tests/AppTests/AppTests.swift index 7ec1983..7d12bd8 100644 --- a/Tests/AppTests/AppTests.swift +++ b/Tests/AppTests/AppTests.swift @@ -11,7 +11,7 @@ final class AppTests: XCTestCase { } func testEncodingContent() { - let input = Message.Content(time: 1234567890, id: 23456789) + let input = Message.Content(time: 1234567890, id: 23456789, device: 0) let data = Array(input.encoded) let output = Message.Content(decodeFrom: data) XCTAssertEqual(input, output) @@ -22,7 +22,7 @@ final class AppTests: XCTestCase { func testEncodingMessage() { let input = Message(mac: Data(repeating: 42, count: 32), - content: Message.Content(time: 1234567890, id: 23456789)) + content: Message.Content(time: 1234567890, id: 23456789, device: 0)) let data = input.encoded let buffer = ByteBuffer(data: data) let output = Message(decodeFrom: buffer) @@ -31,7 +31,7 @@ final class AppTests: XCTestCase { func testSigning() throws { let key = SymmetricKey(size: .bits256) - let content = Message.Content(time: 1234567890, id: 23456789) + let content = Message.Content(time: 1234567890, id: 23456789, device: 0) let input = content.authenticate(using: key) XCTAssertTrue(input.isValid(using: key))