mirror of
https://github.com/sparkle-project/Sparkle.git
synced 2025-11-01 15:34:38 +00:00
142 lines
4.3 KiB
Objective-C
142 lines
4.3 KiB
Objective-C
//
|
|
// AgentConnection.m
|
|
// Sparkle
|
|
//
|
|
// Created by Mayur Pawashe on 7/17/16.
|
|
// Copyright © 2016 Sparkle Project. All rights reserved.
|
|
//
|
|
|
|
#import "AgentConnection.h"
|
|
#import "SPUMessageTypes.h"
|
|
#import "SPUInstallerAgentProtocol.h"
|
|
#import "SUInstallerAgentInitiationProtocol.h"
|
|
#import "SUCodeSigningVerifier.h"
|
|
#import "SULog.h"
|
|
|
|
|
|
#include "AppKitPrevention.h"
|
|
|
|
@interface AgentConnection () <NSXPCListenerDelegate, SUInstallerAgentInitiationProtocol>
|
|
|
|
@end
|
|
|
|
@implementation AgentConnection
|
|
{
|
|
NSXPCListener *_xpcListener;
|
|
NSXPCConnection *_activeConnection;
|
|
__weak id<AgentConnectionDelegate> _delegate;
|
|
}
|
|
|
|
@synthesize agent = _agent;
|
|
@synthesize connected = _connected;
|
|
@synthesize invalidationError = _invalidationError;
|
|
|
|
- (instancetype)initWithHostBundleIdentifier:(NSString *)bundleIdentifier delegate:(id<AgentConnectionDelegate>)delegate
|
|
{
|
|
self = [super init];
|
|
if (self != nil) {
|
|
// Agents should always be the one that connect to daemons due to how mach bootstraps work
|
|
// For this reason, we are the ones that are creating a listener, not the agent
|
|
_xpcListener = [[NSXPCListener alloc] initWithMachServiceName:SPUProgressAgentServiceNameForBundleIdentifier(bundleIdentifier)];
|
|
_xpcListener.delegate = self;
|
|
_delegate = delegate;
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void)startListener
|
|
{
|
|
[_xpcListener resume];
|
|
}
|
|
|
|
- (void)invalidate
|
|
{
|
|
_delegate = nil;
|
|
|
|
[_activeConnection invalidate];
|
|
// Don't need to set _activeConnection to nil, we don't expect new connections
|
|
|
|
[_xpcListener invalidate];
|
|
_xpcListener = nil;
|
|
}
|
|
|
|
- (BOOL)listener:(NSXPCListener *)__unused listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection
|
|
{
|
|
if (_activeConnection != nil) {
|
|
SULog(SULogLevelError, @"Error: Rejecting new connection for agent due already having an active connection");
|
|
|
|
[newConnection invalidate];
|
|
return NO;
|
|
}
|
|
|
|
// Hardening but not critical for security
|
|
NSError *validationError = nil;
|
|
SUValidateConnectionStatus validationStatus = [SUCodeSigningVerifier validateConnection:newConnection error:&validationError];
|
|
switch (validationStatus) {
|
|
case SUValidateConnectionStatusSetCodeSigningRequirementSuccess:
|
|
break;
|
|
case SUValidateConnectionStatusSetNoRequirementSuccess:
|
|
break;
|
|
case SUValidateConnectionStatusAPIFailure:
|
|
case SUValidateConnectionStatusCodeSigningRequirementFailure:
|
|
case SUValidateConectionNoSupportedValidationMethodFailure:
|
|
SULog(SULogLevelError, @"Error: Rejecting new connection for agent due to failing validation of XPC connection with status %lu and error: %@", validationStatus, validationError.localizedDescription);
|
|
|
|
[newConnection invalidate];
|
|
return NO;
|
|
}
|
|
|
|
newConnection.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(SUInstallerAgentInitiationProtocol)];
|
|
newConnection.exportedObject = self;
|
|
|
|
newConnection.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(SPUInstallerAgentProtocol)];
|
|
|
|
_activeConnection = newConnection;
|
|
|
|
__weak __typeof__(self) weakSelf = self;
|
|
newConnection.interruptionHandler = ^{
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
__typeof__(self) strongSelf = weakSelf;
|
|
if (strongSelf != nil) {
|
|
[strongSelf->_activeConnection invalidate];
|
|
}
|
|
});
|
|
};
|
|
|
|
newConnection.invalidationHandler = ^{
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
__typeof__(self) strongSelf = weakSelf;
|
|
if (strongSelf != nil) {
|
|
[strongSelf->_delegate agentConnectionDidInvalidate];
|
|
}
|
|
});
|
|
};
|
|
|
|
_agent = newConnection.remoteObjectProxy;
|
|
[newConnection resume];
|
|
|
|
return YES;
|
|
}
|
|
|
|
- (void)connectionDidInitiateWithReply:(void (^)(void))acknowledgement
|
|
{
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
self->_connected = YES;
|
|
|
|
[self->_delegate agentConnectionDidInitiate];
|
|
});
|
|
|
|
if (acknowledgement != NULL) {
|
|
acknowledgement();
|
|
}
|
|
}
|
|
|
|
- (void)connectionWillInvalidateWithError:(NSError *)error
|
|
{
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
self->_invalidationError = error;
|
|
});
|
|
}
|
|
|
|
@end
|