Skip to content

Commit a65c312

Browse files
committed
Adding Remote Access (#305)
1 parent 1c66270 commit a65c312

14 files changed

+525
-13
lines changed
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
//
2+
// CommandPayload.swift
3+
// BushelKit
4+
//
5+
// Created by Leo Dion.
6+
// Copyright © 2024 BrightDigit.
7+
//
8+
// Permission is hereby granted, free of charge, to any person
9+
// obtaining a copy of this software and associated documentation
10+
// files (the "Software"), to deal in the Software without
11+
// restriction, including without limitation the rights to use,
12+
// copy, modify, merge, publish, distribute, sublicense, and/or
13+
// sell copies of the Software, and to permit persons to whom the
14+
// Software is furnished to do so, subject to the following
15+
// conditions:
16+
//
17+
// The above copyright notice and this permission notice shall be
18+
// included in all copies or substantial portions of the Software.
19+
//
20+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21+
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22+
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23+
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24+
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25+
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26+
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27+
// OTHER DEALINGS IN THE SOFTWARE.
28+
//
29+
30+
public import Foundation
31+
32+
/// Command payload types
33+
public enum CommandPayload: Codable, Sendable {
34+
/// System command payload
35+
case system(SystemCommand)
36+
/// Remote access command payload
37+
case remote(RemoteAccessCommand)
38+
/// Security command payload
39+
case security(SecurityCommand)
40+
/// File operation payload (placeholder for future use)
41+
case file(String)
42+
/// Network operation payload (placeholder for future use)
43+
case network(String)
44+
/// Clipboard operation payload (placeholder for future use)
45+
case clipboard(String)
46+
}

Sources/BushelHarvestCore/CommandProtocol.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ public protocol HarvestCommandProtocol: Codable, Sendable {
8888
/// - `.network` - Network operations like connection management and data transfer
8989
/// - `.clipboard` - Clipboard operations for copy/paste functionality between host and guest
9090
/// - `.remote` - Remote debugging and development tools operations
91+
/// - `.security` - Security operations like authentication, authorization, and access control
9192
public enum CommandCategory: String, Codable, Sendable {
9293
/// System-level operations (shutdown, status, configuration, etc.)
9394
case system
@@ -103,4 +104,7 @@ public enum CommandCategory: String, Codable, Sendable {
103104

104105
/// Remote debugging and development operations (SSH, debugging tools, etc.)
105106
case remote
107+
108+
/// Security operations (authentication, authorization, access control, etc.)
109+
case security
106110
}

Sources/BushelHarvestCore/HarvestCommand.swift

Lines changed: 136 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,18 +33,15 @@ public import Foundation
3333
///
3434
/// Represents a concrete command that can be executed as part of the Harvest
3535
/// protocol. This is the standard implementation of `HarvestCommandProtocol`
36-
/// that provides basic command functionality with an ID and category.
36+
/// that provides complete command functionality with ID, category, payload, and metadata.
3737
///
3838
/// ## Usage
3939
/// ```swift
40-
/// // Create a system command
41-
/// let systemCommand = HarvestCommand(category: .system)
40+
/// // Create a system ping command
41+
/// let pingCommand = HarvestCommand.system(.ping)
4242
///
43-
/// // Create a file command with custom ID
44-
/// let fileCommand = HarvestCommand(
45-
/// id: UUID(),
46-
/// category: .file
47-
/// )
43+
/// // Create an SSH enable command
44+
/// let sshCommand = HarvestCommand.remote(.ssh(.enable))
4845
/// ```
4946
///
5047
/// ## Command Categories
@@ -54,6 +51,7 @@ public import Foundation
5451
/// - `.network` - Network operations (connect, transfer, etc.)
5552
/// - `.clipboard` - Clipboard operations (copy, paste, etc.)
5653
/// - `.remote` - Remote debugging and development operations
54+
/// - `.security` - Security operations (authentication, authorization, etc.)
5755
///
5856
/// For custom command implementations, consider extending `HarvestCommandProtocol`
5957
/// directly rather than subclassing this struct.
@@ -66,17 +64,144 @@ public struct HarvestCommand: HarvestCommandProtocol {
6664

6765
/// Category that this command belongs to
6866
///
69-
/// Used for organizing commands and potentially implementing
67+
/// Used for organizing commands and implementing
7068
/// category-specific authorization or routing logic.
7169
public let category: CommandCategory
70+
71+
/// Command payload containing the specific command data
72+
public let payload: CommandPayload
73+
74+
/// Target machine identifier (optional)
75+
public let machineID: UInt64?
76+
77+
/// Timestamp when the command was created
78+
public let timestamp: Date
79+
80+
/// Command version for compatibility checking
81+
public let version: Int
82+
83+
/// Additional metadata for command processing
84+
public var metadata: [String: String]?
85+
86+
/// Human-readable name of the command
87+
public var name: String {
88+
switch payload {
89+
case .system(let systemCmd):
90+
switch systemCmd {
91+
case .ping: return "system.ping"
92+
case .status: return "system.status"
93+
case .shutdown: return "system.shutdown"
94+
case .restart: return "system.restart"
95+
}
96+
case .remote(let remoteCmd):
97+
switch remoteCmd {
98+
case .ssh(let sshCmd):
99+
switch sshCmd {
100+
case .enable: return "remote.ssh.enable"
101+
case .disable: return "remote.ssh.disable"
102+
case .status: return "remote.ssh.status"
103+
}
104+
case .status: return "remote.status"
105+
}
106+
case .security(let securityCmd):
107+
switch securityCmd {
108+
case .authenticate: return "security.authenticate"
109+
case .authorize: return "security.authorize"
110+
case .status: return "security.status"
111+
}
112+
case .file: return "file.operation"
113+
case .network: return "network.operation"
114+
case .clipboard: return "clipboard.operation"
115+
}
116+
}
72117

73118
/// Creates a new Harvest command
74119
///
75120
/// - Parameters:
76121
/// - id: Unique identifier for the command. Defaults to a new UUID.
77122
/// - category: The category this command belongs to
78-
public init(id: UUID = UUID(), category: CommandCategory) {
123+
/// - payload: The command payload data
124+
/// - machineID: Optional target machine identifier
125+
/// - timestamp: Creation timestamp. Defaults to current time.
126+
/// - version: Command version for compatibility checking. Defaults to 1.
127+
/// - metadata: Additional metadata for command processing. Defaults to nil.
128+
public init(
129+
id: UUID = UUID(),
130+
category: CommandCategory,
131+
payload: CommandPayload,
132+
machineID: UInt64? = nil,
133+
timestamp: Date = Date(),
134+
version: Int = 1,
135+
metadata: [String: String]? = nil
136+
) {
79137
self.id = id
80138
self.category = category
139+
self.payload = payload
140+
self.machineID = machineID
141+
self.timestamp = timestamp
142+
self.version = version
143+
self.metadata = metadata
144+
}
145+
146+
// MARK: - Static Factory Methods
147+
148+
/// Creates a system command
149+
/// - Parameter command: The system command to create
150+
/// - Returns: A new HarvestCommand with system category
151+
public static func system(_ command: SystemCommand) -> HarvestCommand {
152+
return HarvestCommand(
153+
category: .system,
154+
payload: .system(command)
155+
)
156+
}
157+
158+
/// Creates a remote access command
159+
/// - Parameter command: The remote access command to create
160+
/// - Returns: A new HarvestCommand with remote category
161+
public static func remote(_ command: RemoteAccessCommand) -> HarvestCommand {
162+
return HarvestCommand(
163+
category: .remote,
164+
payload: .remote(command)
165+
)
166+
}
167+
168+
/// Creates a security command
169+
/// - Parameter command: The security command to create
170+
/// - Returns: A new HarvestCommand with security category
171+
public static func security(_ command: SecurityCommand) -> HarvestCommand {
172+
return HarvestCommand(
173+
category: .security,
174+
payload: .security(command)
175+
)
176+
}
177+
178+
/// Creates a file operation command
179+
/// - Parameter operation: The file operation description
180+
/// - Returns: A new HarvestCommand with file category
181+
public static func file(_ operation: String) -> HarvestCommand {
182+
return HarvestCommand(
183+
category: .file,
184+
payload: .file(operation)
185+
)
186+
}
187+
188+
/// Creates a network operation command
189+
/// - Parameter operation: The network operation description
190+
/// - Returns: A new HarvestCommand with network category
191+
public static func network(_ operation: String) -> HarvestCommand {
192+
return HarvestCommand(
193+
category: .network,
194+
payload: .network(operation)
195+
)
196+
}
197+
198+
/// Creates a clipboard operation command
199+
/// - Parameter operation: The clipboard operation description
200+
/// - Returns: A new HarvestCommand with clipboard category
201+
public static func clipboard(_ operation: String) -> HarvestCommand {
202+
return HarvestCommand(
203+
category: .clipboard,
204+
payload: .clipboard(operation)
205+
)
81206
}
82-
}
207+
}

Sources/BushelHarvestCore/HarvestResponse.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,15 +78,20 @@ public struct HarvestResponse: Codable, Sendable {
7878
/// structure with additional error fields in future iterations.
7979
public let success: Bool
8080

81+
/// Response payload containing the result data
82+
public let payload: ResponsePayload?
83+
8184
/// Creates a new Harvest response
8285
///
8386
/// - Parameters:
8487
/// - requestId: The ID of the request this response corresponds to
8588
/// - timestamp: When the response was created. Defaults to current time.
8689
/// - success: Whether the request processing was successful
87-
public init(requestId: UUID, timestamp: Date = Date(), success: Bool) {
90+
/// - payload: Optional response payload data
91+
public init(requestId: UUID, timestamp: Date = Date(), success: Bool, payload: ResponsePayload? = nil) {
8892
self.requestId = requestId
8993
self.timestamp = timestamp
9094
self.success = success
95+
self.payload = payload
9196
}
9297
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
//
2+
// RemoteAccess.swift
3+
// BushelKit
4+
//
5+
// Created by Leo Dion.
6+
// Copyright © 2024 BrightDigit.
7+
//
8+
// Permission is hereby granted, free of charge, to any person
9+
// obtaining a copy of this software and associated documentation
10+
// files (the "Software"), to deal in the Software without
11+
// restriction, including without limitation the rights to use,
12+
// copy, modify, merge, publish, distribute, sublicense, and/or
13+
// sell copies of the Software, and to permit persons to whom the
14+
// Software is furnished to do so, subject to the following
15+
// conditions:
16+
//
17+
// The above copyright notice and this permission notice shall be
18+
// included in all copies or substantial portions of the Software.
19+
//
20+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21+
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22+
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23+
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24+
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25+
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26+
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27+
// OTHER DEALINGS IN THE SOFTWARE.
28+
//
29+
30+
public import Foundation
31+
32+
/// Remote access information
33+
public struct RemoteAccess: Codable, Sendable {
34+
public let ssh: SSHStatus
35+
36+
public init(ssh: SSHStatus) {
37+
self.ssh = ssh
38+
}
39+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//
2+
// RemoteAccessCommand.swift
3+
// BushelKit
4+
//
5+
// Created by Leo Dion.
6+
// Copyright © 2024 BrightDigit.
7+
//
8+
// Permission is hereby granted, free of charge, to any person
9+
// obtaining a copy of this software and associated documentation
10+
// files (the "Software"), to deal in the Software without
11+
// restriction, including without limitation the rights to use,
12+
// copy, modify, merge, publish, distribute, sublicense, and/or
13+
// sell copies of the Software, and to permit persons to whom the
14+
// Software is furnished to do so, subject to the following
15+
// conditions:
16+
//
17+
// The above copyright notice and this permission notice shall be
18+
// included in all copies or substantial portions of the Software.
19+
//
20+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21+
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22+
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23+
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24+
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25+
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26+
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27+
// OTHER DEALINGS IN THE SOFTWARE.
28+
//
29+
30+
public import Foundation
31+
32+
/// Remote access command operations
33+
public enum RemoteAccessCommand: Codable, Sendable {
34+
/// SSH-related commands
35+
case ssh(SSHCommand)
36+
/// Remote access status request
37+
case status
38+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
//
2+
// RemoteStatusData.swift
3+
// BushelKit
4+
//
5+
// Created by Leo Dion.
6+
// Copyright © 2024 BrightDigit.
7+
//
8+
// Permission is hereby granted, free of charge, to any person
9+
// obtaining a copy of this software and associated documentation
10+
// files (the "Software"), to deal in the Software without
11+
// restriction, including without limitation the rights to use,
12+
// copy, modify, merge, publish, distribute, sublicense, and/or
13+
// sell copies of the Software, and to permit persons to whom the
14+
// Software is furnished to do so, subject to the following
15+
// conditions:
16+
//
17+
// The above copyright notice and this permission notice shall be
18+
// included in all copies or substantial portions of the Software.
19+
//
20+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21+
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22+
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23+
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24+
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25+
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26+
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27+
// OTHER DEALINGS IN THE SOFTWARE.
28+
//
29+
30+
public import Foundation
31+
32+
/// Remote status response data
33+
public struct RemoteStatusData: Codable, Sendable {
34+
public let access: RemoteAccess
35+
36+
public init(access: RemoteAccess) {
37+
self.access = access
38+
}
39+
}

0 commit comments

Comments
 (0)