mirror of
https://github.com/SideStore/SideStore.git
synced 2026-02-10 23:33:29 +01:00
[AltDaemon] Replaces local socket communication with XPC
Allows AltDaemon to be launched on demand + reject any connections not made from AltStore.
This commit is contained in:
@@ -14,8 +14,4 @@ extern CFNotificationName const ALTWiredServerConnectionAvailableRequest NS_SWIF
|
||||
extern CFNotificationName const ALTWiredServerConnectionAvailableResponse NS_SWIFT_NAME(wiredServerConnectionAvailableResponse);
|
||||
extern CFNotificationName const ALTWiredServerConnectionStartRequest NS_SWIFT_NAME(wiredServerConnectionStartRequest);
|
||||
|
||||
extern CFNotificationName const ALTLocalServerConnectionAvailableRequest NS_SWIFT_NAME(localServerConnectionAvailableRequest);
|
||||
extern CFNotificationName const ALTLocalServerConnectionAvailableResponse NS_SWIFT_NAME(localServerConnectionAvailableResponse);
|
||||
extern CFNotificationName const ALTLocalServerConnectionStartRequest NS_SWIFT_NAME(localServerConnectionStartRequest);
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@@ -11,7 +11,3 @@
|
||||
CFNotificationName const ALTWiredServerConnectionAvailableRequest = CFSTR("io.altstore.Request.WiredServerConnectionAvailable");
|
||||
CFNotificationName const ALTWiredServerConnectionAvailableResponse = CFSTR("io.altstore.Response.WiredServerConnectionAvailable");
|
||||
CFNotificationName const ALTWiredServerConnectionStartRequest = CFSTR("io.altstore.Request.WiredServerConnectionStart");
|
||||
|
||||
CFNotificationName const ALTLocalServerConnectionAvailableRequest = CFSTR("io.altstore.Request.LocalServerConnectionAvailable");
|
||||
CFNotificationName const ALTLocalServerConnectionAvailableResponse = CFSTR("io.altstore.Response.LocalServerConnectionAvailable");
|
||||
CFNotificationName const ALTLocalServerConnectionStartRequest = CFSTR("io.altstore.Request.LocalServerConnectionStart");
|
||||
|
||||
150
Shared/Connections/XPCConnection.swift
Normal file
150
Shared/Connections/XPCConnection.swift
Normal file
@@ -0,0 +1,150 @@
|
||||
//
|
||||
// XPCConnection.swift
|
||||
// AltKit
|
||||
//
|
||||
// Created by Riley Testut on 6/15/20.
|
||||
// Copyright © 2020 Riley Testut. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@objc private protocol XPCConnectionProxy
|
||||
{
|
||||
func ping(completionHandler: @escaping () -> Void)
|
||||
func receive(_ data: Data, completionHandler: @escaping (Bool, Error?) -> Void)
|
||||
}
|
||||
|
||||
extension XPCConnection
|
||||
{
|
||||
public static let machServiceName = "cy:io.altstore.altdaemon"
|
||||
}
|
||||
|
||||
public class XPCConnection: NSObject, Connection
|
||||
{
|
||||
public let xpcConnection: NSXPCConnection
|
||||
|
||||
private let queue = DispatchQueue(label: "io.altstore.XPCConnection")
|
||||
private let dispatchGroup = DispatchGroup()
|
||||
private var semaphore: DispatchSemaphore?
|
||||
private var buffer = Data(capacity: 1024)
|
||||
|
||||
private var error: Error?
|
||||
|
||||
public init(_ xpcConnection: NSXPCConnection = .makeConnection(machServiceName: XPCConnection.machServiceName))
|
||||
{
|
||||
let proxyInterface = NSXPCInterface(with: XPCConnectionProxy.self)
|
||||
xpcConnection.remoteObjectInterface = proxyInterface
|
||||
xpcConnection.exportedInterface = proxyInterface
|
||||
|
||||
self.xpcConnection = xpcConnection
|
||||
|
||||
super.init()
|
||||
|
||||
xpcConnection.interruptionHandler = {
|
||||
self.error = ALTServerError(.lostConnection)
|
||||
}
|
||||
|
||||
xpcConnection.exportedObject = self
|
||||
xpcConnection.resume()
|
||||
}
|
||||
|
||||
deinit
|
||||
{
|
||||
self.disconnect()
|
||||
}
|
||||
}
|
||||
|
||||
private extension XPCConnection
|
||||
{
|
||||
func makeProxy(errorHandler: @escaping (Error) -> Void) -> XPCConnectionProxy
|
||||
{
|
||||
let proxy = self.xpcConnection.remoteObjectProxyWithErrorHandler { (error) in
|
||||
print("Error messaging remote object proxy:", error)
|
||||
self.error = error
|
||||
errorHandler(error)
|
||||
} as! XPCConnectionProxy
|
||||
|
||||
return proxy
|
||||
}
|
||||
}
|
||||
|
||||
public extension XPCConnection
|
||||
{
|
||||
func connect(completionHandler: @escaping (Result<Void, Error>) -> Void)
|
||||
{
|
||||
let proxy = self.makeProxy { (error) in
|
||||
completionHandler(.failure(error))
|
||||
}
|
||||
|
||||
proxy.ping {
|
||||
completionHandler(.success(()))
|
||||
}
|
||||
}
|
||||
|
||||
func disconnect()
|
||||
{
|
||||
self.xpcConnection.invalidate()
|
||||
}
|
||||
|
||||
func __send(_ data: Data, completionHandler: @escaping (Bool, Error?) -> Void)
|
||||
{
|
||||
guard self.error == nil else { return completionHandler(false, self.error) }
|
||||
|
||||
let proxy = self.makeProxy { (error) in
|
||||
completionHandler(false, error)
|
||||
}
|
||||
|
||||
proxy.receive(data) { (success, error) in
|
||||
completionHandler(success, error)
|
||||
}
|
||||
}
|
||||
|
||||
func __receiveData(expectedSize: Int, completionHandler: @escaping (Data?, Error?) -> Void)
|
||||
{
|
||||
guard self.error == nil else { return completionHandler(nil, self.error) }
|
||||
|
||||
self.queue.async {
|
||||
let copiedBuffer = self.buffer // Copy buffer to prevent runtime crashes.
|
||||
guard copiedBuffer.count >= expectedSize else {
|
||||
self.semaphore = DispatchSemaphore(value: 0)
|
||||
DispatchQueue.global().async {
|
||||
_ = self.semaphore?.wait(timeout: .now() + 1.0)
|
||||
self.__receiveData(expectedSize: expectedSize, completionHandler: completionHandler)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
let data = copiedBuffer.prefix(expectedSize)
|
||||
self.buffer = copiedBuffer.dropFirst(expectedSize)
|
||||
|
||||
completionHandler(data, nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension XPCConnection
|
||||
{
|
||||
override public var description: String {
|
||||
return "\(self.xpcConnection.endpoint) (XPC)"
|
||||
}
|
||||
}
|
||||
|
||||
extension XPCConnection: XPCConnectionProxy
|
||||
{
|
||||
fileprivate func ping(completionHandler: @escaping () -> Void)
|
||||
{
|
||||
completionHandler()
|
||||
}
|
||||
|
||||
fileprivate func receive(_ data: Data, completionHandler: @escaping (Bool, Error?) -> Void)
|
||||
{
|
||||
self.queue.async {
|
||||
self.buffer.append(data)
|
||||
|
||||
self.semaphore?.signal()
|
||||
self.semaphore = nil
|
||||
|
||||
completionHandler(true, nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
33
Shared/Extensions/NSXPCConnection+MachServices.swift
Normal file
33
Shared/Extensions/NSXPCConnection+MachServices.swift
Normal file
@@ -0,0 +1,33 @@
|
||||
//
|
||||
// NSXPCConnection+MachServices.swift
|
||||
// AltStore
|
||||
//
|
||||
// Created by Riley Testut on 9/22/20.
|
||||
// Copyright © 2020 Riley Testut. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@objc private protocol XPCPrivateAPI
|
||||
{
|
||||
init(machServiceName: String)
|
||||
init(machServiceName: String, options: NSXPCConnection.Options)
|
||||
}
|
||||
|
||||
public extension NSXPCConnection
|
||||
{
|
||||
class func makeConnection(machServiceName: String) -> NSXPCConnection
|
||||
{
|
||||
let connection = unsafeBitCast(self, to: XPCPrivateAPI.Type.self).init(machServiceName: machServiceName, options: .privileged)
|
||||
return unsafeBitCast(connection, to: NSXPCConnection.self)
|
||||
}
|
||||
}
|
||||
|
||||
public extension NSXPCListener
|
||||
{
|
||||
class func makeListener(machServiceName: String) -> NSXPCListener
|
||||
{
|
||||
let listener = unsafeBitCast(self, to: XPCPrivateAPI.Type.self).init(machServiceName: machServiceName)
|
||||
return unsafeBitCast(listener, to: NSXPCListener.self)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user