From 4723c985025df756b73a276ea05f9bbed5dca19e Mon Sep 17 00:00:00 2001 From: Christoph Hagen Date: Wed, 13 Apr 2022 14:55:22 +0200 Subject: [PATCH] Extract shared code --- Sesame.xcodeproj/project.pbxproj | 26 ++-- .../UserInterfaceState.xcuserstate | Bin 48308 -> 53576 bytes .../xcschemes/xcschememanagement.plist | 2 +- Sesame/{ => API}/DeviceResponse.swift | 22 +++- Sesame/{ => API}/Message+Extensions.swift | 16 +-- Sesame/API/Message.swift | 122 ++++++++++++++++++ Sesame/{ => API}/MessageResult.swift | 0 Sesame/API/RouteAPI.swift | 16 +++ Sesame/Client.swift | 4 +- Sesame/Message.swift | 78 ----------- 10 files changed, 186 insertions(+), 100 deletions(-) rename Sesame/{ => API}/DeviceResponse.swift (67%) rename Sesame/{ => API}/Message+Extensions.swift (84%) create mode 100644 Sesame/API/Message.swift rename Sesame/{ => API}/MessageResult.swift (100%) create mode 100644 Sesame/API/RouteAPI.swift delete mode 100644 Sesame/Message.swift diff --git a/Sesame.xcodeproj/project.pbxproj b/Sesame.xcodeproj/project.pbxproj index 703d792..cfa6890 100644 --- a/Sesame.xcodeproj/project.pbxproj +++ b/Sesame.xcodeproj/project.pbxproj @@ -12,7 +12,6 @@ 884A45BB279F48C300D6E650 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 884A45BA279F48C300D6E650 /* Assets.xcassets */; }; 884A45BE279F48C300D6E650 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 884A45BD279F48C300D6E650 /* Preview Assets.xcassets */; }; 884A45C5279F4BBE00D6E650 /* KeyManagement.swift in Sources */ = {isa = PBXBuildFile; fileRef = 884A45C4279F4BBE00D6E650 /* KeyManagement.swift */; }; - 884A45C727A429EF00D6E650 /* ShareSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 884A45C627A429EF00D6E650 /* ShareSheet.swift */; }; 884A45C927A43D7900D6E650 /* ClientState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 884A45C827A43D7900D6E650 /* ClientState.swift */; }; 884A45CB27A464C000D6E650 /* SymmetricKey+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 884A45CA27A464C000D6E650 /* SymmetricKey+Extensions.swift */; }; 884A45CD27A465F500D6E650 /* Client.swift in Sources */ = {isa = PBXBuildFile; fileRef = 884A45CC27A465F500D6E650 /* Client.swift */; }; @@ -22,6 +21,7 @@ E24EE77727FF95C00011CFD2 /* NIOCore in Frameworks */ = {isa = PBXBuildFile; productRef = E24EE77627FF95C00011CFD2 /* NIOCore */; }; E24EE77927FF95E00011CFD2 /* Message.swift in Sources */ = {isa = PBXBuildFile; fileRef = E24EE77827FF95E00011CFD2 /* Message.swift */; }; E24EE77B280058240011CFD2 /* Message+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E24EE77A280058240011CFD2 /* Message+Extensions.swift */; }; + E2C5C1DB2806FE8900769EF6 /* RouteAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2C5C1DA2806FE8900769EF6 /* RouteAPI.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -31,7 +31,6 @@ 884A45BA279F48C300D6E650 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 884A45BD279F48C300D6E650 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 884A45C4279F4BBE00D6E650 /* KeyManagement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyManagement.swift; sourceTree = ""; }; - 884A45C627A429EF00D6E650 /* ShareSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareSheet.swift; sourceTree = ""; }; 884A45C827A43D7900D6E650 /* ClientState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientState.swift; sourceTree = ""; }; 884A45CA27A464C000D6E650 /* SymmetricKey+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SymmetricKey+Extensions.swift"; sourceTree = ""; }; 884A45CC27A465F500D6E650 /* Client.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Client.swift; sourceTree = ""; }; @@ -40,6 +39,7 @@ E24EE77327FF95920011CFD2 /* DeviceResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceResponse.swift; sourceTree = ""; }; E24EE77827FF95E00011CFD2 /* Message.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Message.swift; sourceTree = ""; }; E24EE77A280058240011CFD2 /* Message+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Message+Extensions.swift"; sourceTree = ""; }; + E2C5C1DA2806FE8900769EF6 /* RouteAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RouteAPI.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -73,20 +73,16 @@ 884A45B5279F48C100D6E650 /* Sesame */ = { isa = PBXGroup; children = ( + E2C5C1D92806FE4A00769EF6 /* API */, 884A45B6279F48C100D6E650 /* SesameApp.swift */, - E24EE77827FF95E00011CFD2 /* Message.swift */, - E24EE77A280058240011CFD2 /* Message+Extensions.swift */, 884A45B8279F48C100D6E650 /* ContentView.swift */, 884A45CC27A465F500D6E650 /* Client.swift */, - 884A45CE27A5402D00D6E650 /* MessageResult.swift */, 884A45C827A43D7900D6E650 /* ClientState.swift */, - 884A45C627A429EF00D6E650 /* ShareSheet.swift */, 884A45C4279F4BBE00D6E650 /* KeyManagement.swift */, - E24EE77327FF95920011CFD2 /* DeviceResponse.swift */, 884A45CA27A464C000D6E650 /* SymmetricKey+Extensions.swift */, + E24EE77127FDCCC00011CFD2 /* Data+Extensions.swift */, 884A45BA279F48C300D6E650 /* Assets.xcassets */, 884A45BC279F48C300D6E650 /* Preview Content */, - E24EE77127FDCCC00011CFD2 /* Data+Extensions.swift */, ); path = Sesame; sourceTree = ""; @@ -99,6 +95,18 @@ path = "Preview Content"; sourceTree = ""; }; + E2C5C1D92806FE4A00769EF6 /* API */ = { + isa = PBXGroup; + children = ( + E24EE77327FF95920011CFD2 /* DeviceResponse.swift */, + E24EE77827FF95E00011CFD2 /* Message.swift */, + 884A45CE27A5402D00D6E650 /* MessageResult.swift */, + E2C5C1DA2806FE8900769EF6 /* RouteAPI.swift */, + E24EE77A280058240011CFD2 /* Message+Extensions.swift */, + ); + path = API; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -177,6 +185,7 @@ files = ( 884A45CF27A5402D00D6E650 /* MessageResult.swift in Sources */, 884A45B9279F48C100D6E650 /* ContentView.swift in Sources */, + E2C5C1DB2806FE8900769EF6 /* RouteAPI.swift in Sources */, 884A45CD27A465F500D6E650 /* Client.swift in Sources */, E24EE77B280058240011CFD2 /* Message+Extensions.swift in Sources */, E24EE77227FDCCC00011CFD2 /* Data+Extensions.swift in Sources */, @@ -186,7 +195,6 @@ 884A45C927A43D7900D6E650 /* ClientState.swift in Sources */, 884A45B7279F48C100D6E650 /* SesameApp.swift in Sources */, 884A45C5279F4BBE00D6E650 /* KeyManagement.swift in Sources */, - 884A45C727A429EF00D6E650 /* ShareSheet.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Sesame.xcodeproj/project.xcworkspace/xcuserdata/ch.xcuserdatad/UserInterfaceState.xcuserstate b/Sesame.xcodeproj/project.xcworkspace/xcuserdata/ch.xcuserdatad/UserInterfaceState.xcuserstate index 11df39e65f26ee30ba01ecceec6f25ff55433370..e737ffad157d3e1eba90918a218e7b65f78c44d6 100644 GIT binary patch literal 53576 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 literal 48308 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 diff --git a/Sesame.xcodeproj/xcuserdata/ch.xcuserdatad/xcschemes/xcschememanagement.plist b/Sesame.xcodeproj/xcuserdata/ch.xcuserdatad/xcschemes/xcschememanagement.plist index 14b438d..db32b40 100644 --- a/Sesame.xcodeproj/xcuserdata/ch.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Sesame.xcodeproj/xcuserdata/ch.xcuserdatad/xcschemes/xcschememanagement.plist @@ -70,7 +70,7 @@ Sesame.xcscheme_^#shared#^_ orderHint - 1 + 0 diff --git a/Sesame/DeviceResponse.swift b/Sesame/API/DeviceResponse.swift similarity index 67% rename from Sesame/DeviceResponse.swift rename to Sesame/API/DeviceResponse.swift index 78cda5b..10e3749 100644 --- a/Sesame/DeviceResponse.swift +++ b/Sesame/API/DeviceResponse.swift @@ -1,29 +1,37 @@ import Foundation import NIOCore - +/** + Encapsulates a response from a device. + */ struct DeviceResponse { + /// Shorthand property for a timeout event. static var deviceTimedOut: DeviceResponse { .init(event: .deviceTimedOut) } + /// Shorthand property for a disconnected event. static var deviceNotConnected: DeviceResponse { .init(event: .deviceNotConnected) } + /// Shorthand property for an unexpected socket event. static var unexpectedSocketEvent: DeviceResponse { .init(event: .unexpectedSocketEvent) } + /// Shorthand property for an invalid message. static var invalidMessageData: DeviceResponse { .init(event: .invalidMessageData) } + /// Shorthand property for missing body data. static var noBodyData: DeviceResponse { .init(event: .noBodyData) } + /// Shorthand property for a busy connection static var operationInProgress: DeviceResponse { .init(event: .operationInProgress) } @@ -34,6 +42,13 @@ struct DeviceResponse { /// The index of the next key to use let response: Message? + /** + Decode a message from a buffer. + + The buffer must contain `Message.length+1` bytes. The first byte denotes the event type, + the remaining bytes contain the message. + - Parameter buffer: The buffer where the message bytes are stored + */ init?(_ buffer: ByteBuffer) { guard let byte = buffer.getBytes(at: 0, length: 1) else { print("No bytes received from device") @@ -51,11 +66,16 @@ struct DeviceResponse { self.response = Message(decodeFrom: data) } + /** + Create a response from an event without a message from the device. + - Parameter event: The response from the device. + */ init(event: MessageResult) { self.event = event self.response = nil } + /// Get the reponse encoded in bytes. var encoded: Data { guard let message = response else { return Data([event.rawValue]) diff --git a/Sesame/Message+Extensions.swift b/Sesame/API/Message+Extensions.swift similarity index 84% rename from Sesame/Message+Extensions.swift rename to Sesame/API/Message+Extensions.swift index 1e8f4df..38fb2b9 100644 --- a/Sesame/Message+Extensions.swift +++ b/Sesame/API/Message+Extensions.swift @@ -1,21 +1,19 @@ -// -// Message+Extensions.swift -// Sesame -// -// Created by CH on 08.04.22. -// - import Foundation + +#if canImport(CryptoKit) import CryptoKit +#else +import Crypto +#endif extension Message { static var length: Int { - SHA256Digest.byteCount + Content.length + SHA256.byteCount + Content.length } init(decodeFrom data: T) where T.Element == UInt8 { - let count = SHA256Digest.byteCount + let count = SHA256.byteCount self.mac = Data(data.prefix(count)) self.content = .init(decodeFrom: Array(data.dropFirst(count))) } diff --git a/Sesame/API/Message.swift b/Sesame/API/Message.swift new file mode 100644 index 0000000..60ede14 --- /dev/null +++ b/Sesame/API/Message.swift @@ -0,0 +1,122 @@ +import Foundation +import NIOCore + +/** + An authenticated message to or from the device. + */ +struct Message: Equatable, Hashable { + + /** + The message content without authentication. + */ + struct Content: Equatable, Hashable { + + /// The time of message creation, in UNIX time (seconds since 1970) + let time: UInt32 + + /// The counter of the message (for freshness) + let id: UInt32 + + /** + Create new message content. + - Parameter time: The time of message creation, + - Parameter id: The counter of the message + */ + init(time: UInt32, id: UInt32) { + self.time = time + self.id = id + } + + /** + Decode message content from data. + + The data consists of two `UInt32` encoded in big endian format (MSB at index 0) + - Warning: The sequence must contain at least 8 bytes, or the function will crash. + - Parameter data: The sequence containing the bytes. + */ + init(decodeFrom data: T) where T.Element == UInt8 { + self.time = UInt32(data: data.prefix(MemoryLayout.size)) + self.id = UInt32(data: data.dropFirst(MemoryLayout.size)) + } + + /// The byte length of an encoded message content + static var length: Int { + MemoryLayout.size * 2 + } + + /// The message content encoded to data + var encoded: Data { + time.encoded + id.encoded + } + + /// The message content encoded to bytes + var bytes: [UInt8] { + time.bytes + id.bytes + } + } + + /// The message authentication code for the message (32 bytes) + let mac: Data + + /// The message content + let content: Content + + /** + Create an authenticated message + - Parameter mac: The message authentication code + - Parameter content: The message content + */ + init(mac: Data, content: Content) { + self.mac = mac + self.content = content + } + + /** + Decode a message from a byte buffer. + The buffer must contain at least `Message.length` bytes, or it will return `nil`. + - Parameter buffer: The buffer containing the bytes. + */ + init?(decodeFrom buffer: ByteBuffer) { + guard let data = buffer.getBytes(at: 0, length: Message.length) else { + return nil + } + self.init(decodeFrom: data) + } + + /// The message encoded to data + var encoded: Data { + mac + content.encoded + } + + /// The message encoded to bytes + var bytes: [UInt8] { + Array(mac) + content.bytes + } +} + + extension UInt32 { + + /** + Create a value from a big-endian data representation (MSB first) + - Note: The data must contain exactly four bytes. + */ + init(data: T) where T.Element == UInt8 { + self = data + .reversed() + .enumerated() + .map { UInt32($0.element) << ($0.offset * 8) } + .reduce(0, +) + } + + /// The value encoded to a big-endian representation + var encoded: Data { + .init(bytes) + } + + /// The value encoded to a big-endian byte array + var bytes: [UInt8] { + (0..<4).reversed().map { + UInt8((self >> ($0*8)) & 0xFF) + } + } +} diff --git a/Sesame/MessageResult.swift b/Sesame/API/MessageResult.swift similarity index 100% rename from Sesame/MessageResult.swift rename to Sesame/API/MessageResult.swift diff --git a/Sesame/API/RouteAPI.swift b/Sesame/API/RouteAPI.swift new file mode 100644 index 0000000..22e90f0 --- /dev/null +++ b/Sesame/API/RouteAPI.swift @@ -0,0 +1,16 @@ +import Foundation + +/** + The active urls on the server, for the device and the remote to connect + */ +enum RouteAPI: String { + + /// Check the device status + case getDeviceStatus = "status" + + /// Send a message to the server, to relay to the device + case postMessage = "message" + + /// Open a socket between the device and the server + case socket = "listen" +} diff --git a/Sesame/Client.swift b/Sesame/Client.swift index c1fb623..74106c9 100644 --- a/Sesame/Client.swift +++ b/Sesame/Client.swift @@ -19,7 +19,7 @@ struct Client { } func deviceStatus() async -> ClientState { - let url = server.appendingPathComponent("status") + let url = server.appendingPathComponent(RouteAPI.getDeviceStatus.rawValue) let request = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalCacheData) let response = await integerReponse(to: request) switch response { @@ -42,7 +42,7 @@ struct Client { } func send(_ message: Message) async throws -> (state: ClientState, response: Message?) { - let url = server.appendingPathComponent("message") + let url = server.appendingPathComponent(RouteAPI.postMessage.rawValue) var request = URLRequest(url: url) request.httpBody = message.encoded request.httpMethod = "POST" diff --git a/Sesame/Message.swift b/Sesame/Message.swift deleted file mode 100644 index 415c818..0000000 --- a/Sesame/Message.swift +++ /dev/null @@ -1,78 +0,0 @@ -import Foundation -import NIOCore - -struct Message: Equatable, Hashable { - - struct Content: Equatable, Hashable { - - let time: UInt32 - - let id: UInt32 - - init(time: UInt32, id: UInt32) { - self.time = time - self.id = id - } - - init(decodeFrom data: T) where T.Element == UInt8 { - self.time = UInt32(data: data.prefix(4)) - self.id = UInt32(data: data.dropFirst(4)) - } - - static var length: Int { - MemoryLayout.size * 2 - } - - var encoded: Data { - time.encoded + id.encoded - } - - var bytes: [UInt8] { - time.bytes + id.bytes - } - } - - let mac: Data - - let content: Content - - init(mac: Data, content: Content) { - self.mac = mac - self.content = content - } - - init?(decodeFrom buffer: ByteBuffer) { - guard let data = buffer.getBytes(at: 0, length: Message.length) else { - return nil - } - self.init(decodeFrom: data) - } - - var encoded: Data { - mac + content.encoded - } - - var bytes: [UInt8] { - Array(mac) + content.bytes - } -} - - extension UInt32 { - - init(data: T) where T.Element == UInt8 { - self = data - .enumerated() - .map { UInt32($0.element) << ($0.offset * 8) } - .reduce(0, +) - } - - var encoded: Data { - .init(bytes) - } - - var bytes: [UInt8] { - (0..<4).map { - UInt8((self >> ($0*8)) & 0xFF) - } - } -}