mirror of
https://github.com/samsonjs/vibetunnel.git
synced 2026-04-27 15:17:38 +00:00
Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Peter Steinberger <steipete@gmail.com>
86 lines
3.3 KiB
Swift
86 lines
3.3 KiB
Swift
import CoreGraphics
|
|
import Foundation
|
|
|
|
/// Security utilities for AppleScript execution
|
|
enum AppleScriptSecurity {
|
|
/// Escapes a string for safe use in AppleScript
|
|
///
|
|
/// This function properly escapes all special characters that could be used
|
|
/// for AppleScript injection attacks, including:
|
|
/// - Double quotes (")
|
|
/// - Backslashes (\)
|
|
/// - Newlines and carriage returns
|
|
/// - Tabs
|
|
/// - Other control characters
|
|
///
|
|
/// - Parameter string: The string to escape
|
|
/// - Returns: The escaped string safe for use in AppleScript
|
|
static func escapeString(_ string: String) -> String {
|
|
var escaped = string
|
|
|
|
// Order matters: escape backslashes first
|
|
escaped = escaped.replacingOccurrences(of: "\\", with: "\\\\")
|
|
escaped = escaped.replacingOccurrences(of: "\"", with: "\\\"")
|
|
escaped = escaped.replacingOccurrences(of: "\n", with: "\\n")
|
|
escaped = escaped.replacingOccurrences(of: "\r", with: "\\r")
|
|
escaped = escaped.replacingOccurrences(of: "\t", with: "\\t")
|
|
|
|
// Remove any other control characters that could cause issues
|
|
let controlCharacterSet = CharacterSet.controlCharacters
|
|
escaped = escaped.components(separatedBy: controlCharacterSet)
|
|
.joined(separator: " ")
|
|
|
|
return escaped
|
|
}
|
|
|
|
/// Validates an identifier (like an application name) for safe use in AppleScript
|
|
///
|
|
/// This function ensures the identifier only contains safe characters and
|
|
/// isn't trying to inject AppleScript commands.
|
|
///
|
|
/// - Parameter identifier: The identifier to validate
|
|
/// - Returns: The validated identifier, or nil if invalid
|
|
static func validateIdentifier(_ identifier: String) -> String? {
|
|
// Allow alphanumeric, spaces, dots, hyphens, and underscores
|
|
let allowedCharacterSet =
|
|
CharacterSet(charactersIn: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 .-_")
|
|
let identifierCharacterSet = CharacterSet(charactersIn: identifier)
|
|
|
|
guard allowedCharacterSet.isSuperset(of: identifierCharacterSet) else {
|
|
return nil
|
|
}
|
|
|
|
// Additional check: ensure it doesn't contain AppleScript keywords that could be dangerous
|
|
let dangerousKeywords = ["tell", "end", "do", "script", "run", "activate", "quit", "delete", "set", "get"]
|
|
let lowercased = identifier.lowercased()
|
|
for keyword in dangerousKeywords where lowercased.contains(keyword) {
|
|
return nil
|
|
}
|
|
|
|
return identifier
|
|
}
|
|
|
|
/// Escapes a numeric value for safe use in AppleScript
|
|
///
|
|
/// - Parameter value: The numeric value
|
|
/// - Returns: The string representation of the number
|
|
static func escapeNumber(_ value: Int) -> String {
|
|
String(value)
|
|
}
|
|
|
|
/// Escapes a numeric value for safe use in AppleScript
|
|
///
|
|
/// - Parameter value: The numeric value (UInt32/CGWindowID)
|
|
/// - Returns: The string representation of the number
|
|
static func escapeNumber(_ value: UInt32) -> String {
|
|
String(value)
|
|
}
|
|
|
|
/// Creates a safe AppleScript string literal
|
|
///
|
|
/// - Parameter string: The string to make into a literal
|
|
/// - Returns: A properly quoted and escaped AppleScript string literal
|
|
static func createStringLiteral(_ string: String) -> String {
|
|
"\"\(escapeString(string))\""
|
|
}
|
|
}
|