vibetunnel/mac/VibeTunnel/Core/Utilities/AppleScriptSecurity.swift
Helmut Januschka f3b2022d48
Integrate screencap functionality for remote screen sharing (#209)
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2025-07-06 03:31:34 +01:00

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))\""
}
}