macOS Cocoa应用程序是否可以删除由另一个应用程序创建的系统首选项中的网络扩展项?
我正在尝试改进使用网络扩展框架的macOS VPN客户端。之前的开发人员使用了一个非常复杂的设置,它是一个特权嵌入式应用程序来控制网络扩展代码,导致了一个三层通信,这减慢了连接时间,我想删除它。我已经成功地删除了这一层,现在我的应用程序拥有personalVPN权限,并直接负责网络扩展代码。除了一个细节,一切都很好。升级到最新版本的应用程序的用户仍将找到以前由嵌入式helper应用程序创建的网络扩展条目。我可以通过编程方式从新版本的应用程序中删除这些条目吗?可能属于某个组的应用之间存在某种权限?这个问题也与钥匙链条目有关,但我将在另一个问题中发布 在处理应用程序自己的网元条目时,要添加/删除的代码可以描述如下:macOS Cocoa应用程序是否可以删除由另一个应用程序创建的系统首选项中的网络扩展项?,macos,cocoa,networkextension,Macos,Cocoa,Networkextension,我正在尝试改进使用网络扩展框架的macOS VPN客户端。之前的开发人员使用了一个非常复杂的设置,它是一个特权嵌入式应用程序来控制网络扩展代码,导致了一个三层通信,这减慢了连接时间,我想删除它。我已经成功地删除了这一层,现在我的应用程序拥有personalVPN权限,并直接负责网络扩展代码。除了一个细节,一切都很好。升级到最新版本的应用程序的用户仍将找到以前由嵌入式helper应用程序创建的网络扩展条目。我可以通过编程方式从新版本的应用程序中删除这些条目吗?可能属于某个组的应用之间存在某种权限?
//
// ViewController.m
// Network Extension Test
//
// Created by Alfonso Tesauro.
//
#import "ViewController.h"
#import <NetworkExtension/NetworkExtension.h>
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)setRepresentedObject:(id)representedObject {
[super setRepresentedObject:representedObject];
// Update the view, if already loaded.
}
- (IBAction)userDidSelectAddButton:(id)sender {
NEVPNManager *manager = [NEVPNManager sharedManager];
manager.protocolConfiguration = [self protocolConfiguration];
[manager loadFromPreferencesWithCompletionHandler:^(NSError * _Nullable error) {
NSLog(@"Here we are");
[manager saveToPreferencesWithCompletionHandler:^(NSError * _Nullable error) {
NSLog(@"Here we are");
}];
}];
}
- (IBAction)userDidSelectRemoveButton:(id)sender {
NEVPNManager *manager = [NEVPNManager sharedManager];
manager.protocolConfiguration = [self protocolConfiguration];
[manager loadFromPreferencesWithCompletionHandler:^(NSError * _Nullable error) {
[manager removeFromPreferencesWithCompletionHandler:^(NSError * _Nullable error) {
NSLog(@"Here we are");
}];
}];
}
#define USERNAME @"alfonso.tesauro@test.com"
#define KEY_PASSWORD @"alfonso.tesauro@test.com"
#define PASSWORD @"alfonso.tesauro@test.com"
#define VPN_SERVER @"alfonso.tesauro@test.com"
#define KEY_SHARED_SECRET @"alfonso.tesauro@test.com"
#define SHARED_SECRET @"alfonso.tesauro@test.com"
#define LOCAL_IDENTIFIER @"alfonso.tesauro@test.com"
#define REMOTE_IDENTIFIER @"alfonso.tesauro@test.com"
- (NEVPNProtocolIKEv2 *)protocolConfiguration {
NEVPNProtocolIKEv2 *protocol = [[NEVPNProtocolIKEv2 alloc] init];
protocol.username = USERNAME;
NSData *passwdRef = [self getData:KEY_PASSWORD];
if (passwdRef == nil) {
[self storeData:KEY_PASSWORD data:[PASSWORD dataUsingEncoding:NSUTF8StringEncoding]];
passwdRef = [self getData:PASSWORD];
NSLog(@"passwdRef: %@", [[NSString alloc] initWithData:passwdRef encoding:NSUTF8StringEncoding]);
}
protocol.passwordReference = passwdRef;
protocol.serverAddress = VPN_SERVER;
protocol.authenticationMethod = NEVPNIKEAuthenticationMethodSharedSecret;
NSData *sharedSecretRef = [self getData:KEY_SHARED_SECRET];
if (sharedSecretRef == nil) {
[self storeData:KEY_SHARED_SECRET data:[SHARED_SECRET dataUsingEncoding:NSUTF8StringEncoding]];
sharedSecretRef = [self getData:KEY_SHARED_SECRET];
NSLog(@"sharedSecretRef: %@", [[NSString alloc] initWithData:sharedSecretRef encoding:NSUTF8StringEncoding]);
}
protocol.sharedSecretReference = sharedSecretRef;
protocol.localIdentifier = LOCAL_IDENTIFIER;
protocol.remoteIdentifier = REMOTE_IDENTIFIER;
protocol.useExtendedAuthentication = YES;
protocol.disconnectOnSleep = NO;
return protocol;
}
#pragma mark - Keychain methods
- (void) storeData: (NSString * )key data:(NSData *)data {
NSLog(@"Store Data");
NSMutableDictionary * dict = [[NSMutableDictionary alloc] init];
[dict setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
NSData *encodedKey = [key dataUsingEncoding:NSUTF8StringEncoding];
[dict setObject:encodedKey forKey:(__bridge id)kSecAttrGeneric];
[dict setObject:encodedKey forKey:(__bridge id)kSecAttrAccount];
[dict setObject:@"VPN" forKey:(__bridge id)kSecAttrService];
[dict setObject:(__bridge id)kSecAttrAccessibleAlwaysThisDeviceOnly forKey:(__bridge id)kSecAttrAccessible];
[dict setObject:data forKey:(__bridge id)kSecValueData];
OSStatus status = SecItemAdd((__bridge CFDictionaryRef)dict, NULL);
if(errSecSuccess != status) {
NSLog(@"Unable add item with key =%@ error:%d",key,(int)status);
}
}
- (NSData *) getData: (NSString *)key {
NSMutableDictionary * dict = [[NSMutableDictionary alloc] init];
[dict setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
NSData *encodedKey = [key dataUsingEncoding:NSUTF8StringEncoding];
[dict setObject:encodedKey forKey:(__bridge id)kSecAttrGeneric];
[dict setObject:encodedKey forKey:(__bridge id)kSecAttrAccount];
[dict setObject:@"VPN" forKey:(__bridge id)kSecAttrService];
[dict setObject:(__bridge id)kSecAttrAccessibleAlwaysThisDeviceOnly forKey:(__bridge id)kSecAttrAccessible];
[dict setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit];
[dict setObject:(id)kCFBooleanTrue forKey:(__bridge id)kSecReturnPersistentRef];
CFTypeRef result = NULL;
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)dict,&result);
if( status != errSecSuccess) {
NSLog(@"Unable to fetch item for key %@ with error:%d",key,(int)status);
return nil;
}
NSData *resultData = (__bridge NSData *)result;
return resultData;
}
- (BOOL) removeData: (NSString *) key {
NSMutableDictionary * dict = [[NSMutableDictionary alloc] init];
[dict setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
NSData *encodedKey = [key dataUsingEncoding:NSUTF8StringEncoding];
[dict setObject:encodedKey forKey:(__bridge id)kSecAttrGeneric];
[dict setObject:encodedKey forKey:(__bridge id)kSecAttrAccount];
[dict setObject:@"VPN" forKey:(__bridge id)kSecAttrService];
[dict setObject:(__bridge id)kSecAttrAccessibleAlwaysThisDeviceOnly forKey:(__bridge id)kSecAttrAccessible];
OSStatus status = SecItemDelete((__bridge CFDictionaryRef)dict);
if( status != errSecSuccess) {
NSLog(@"Unable to fetch item for key %@ with error:%d",key,(int)status);
return NO;
}
return YES;
}
@end
//
//ViewController.m
//网络扩展测试
//
//由阿方索·特萨罗创作。
//
#导入“ViewController.h”
#进口
@实现视图控制器
-(无效)viewDidLoad{
[超级视图下载];
//加载视图后执行任何其他设置。
}
-(void)setRepresentedObject:(id)representedObject{
[super-setRepresentedObject:representedObject];
//更新视图(如果已加载)。
}
-(iAction)userDidSelectAddButton:(id)发件人{
NEVPNManager*manager=[NEVPNManager-sharedManager];
manager.protocolConfiguration=[self protocolConfiguration];
[manager loadFromPreferencesWithCompletionHandler:^(n错误*\u可为空错误){
NSLog(“我们到了”);
[manager saveToPreferencesWithCompletionHandler:^(n错误*\u可为空错误){
NSLog(“我们到了”);
}];
}];
}
-(iAction)userDidSelectRemoveButton:(id)发件人{
NEVPNManager*manager=[NEVPNManager-sharedManager];
manager.protocolConfiguration=[self protocolConfiguration];
[manager loadFromPreferencesWithCompletionHandler:^(n错误*\u可为空错误){
[manager removeFromPreferencesWithCompletionHandler:^(n错误*\u可为空错误){
NSLog(“我们到了”);
}];
}];
}
#定义用户名@“alfonso”。tesauro@test.com"
#定义密钥密码@“alfonso”。tesauro@test.com"
#定义密码@“alfonso”。tesauro@test.com"
#定义VPN_服务器@“alfonso”。tesauro@test.com"
#定义密钥共享密钥@“alfonso”。tesauro@test.com"
#定义共享的_SECRET@“alfonso”。tesauro@test.com"
#定义本地_标识符@“alfonso”。tesauro@test.com"
#定义远程_标识符@“alfonso”。tesauro@test.com"
-(NEVPNProtocolIKEv2*)协议配置{
NEVPNProtocolIKEv2*协议=[[NEVPNProtocolIKEv2 alloc]init];
protocol.username=用户名;
NSData*passwdRef=[self-getData:KEY_-PASSWORD];
如果(passwdRef==nil){
[self-storeData:KEY_密码数据:[密码数据使用编码:NSUTF8StringEncoding];
passwdRef=[self-getData:PASSWORD];
NSLog(@“passwdRef:%@,[[NSString alloc]initWithData:passwdRef编码:NSUTF8StringEncoding]);
}
protocol.passwordReference=passwdRef;
protocol.serverAddress=VPN\u服务器;
protocol.authenticationMethod=NEVPNIKEAuthenticationMethodSharedSecret;
NSData*sharedSecretRef=[self-getData:KEY\u SHARED\u SECRET];
if(sharedSecretRef==nil){
[self-storeData:KEY_SHARED_SECRET data:[SHARED_SECRET dataUsingEncoding:NSUTF8StringEncoding];
sharedSecretRef=[self-getData:KEY\u SHARED\u SECRET];
NSLog(@“sharedSecretRef:%@,[[NSString alloc]initWithData:sharedSecretRef编码:NSUTF8StringEncoding]);
}
protocol.sharedSecretReference=sharedSecretRef;
protocol.localIdentifier=本地_标识符;
protocol.remoteIdentifier=远程\u标识符;
protocol.useExtendedAuthentication=是;
protocol.disconnectOnSleep=否;
返回协议;
}
#pragma标记-键链方法
-(void)storeData:(NSString*)键数据:(NSData*)数据{
NSLog(“存储数据”);
NSMutableDictionary*dict=[[NSMutableDictionary alloc]init];
[dict setObject:(uu桥id)kSecClassGenericPassword forKey:(uu桥id)kSecClass];
NSData*encodedKey=[密钥数据使用编码:NSUTF8StringEncoding];
[dict setObject:encodedKey-forKey:(u桥id)kSecAttrGeneric];
[dict setObject:encodedKey-forKey:(__桥id)kSecAttrAccount];
[dict setObject:@“VPN”forKey:(u桥id)kSecAttrService];
[dict setObject:(uu桥id)ksecataccessibleAllways此设备仅forKey:(uu桥id)ksecataccessible];
[dict setObject:data forKey:(_桥id)kSecValueData];
OSStatus status=SecItemAdd((uu桥CFDictionaryRef)dict,NULL);
if(errSecSuccess!=状态){
NSLog(@“无法添加密钥为%@的项错误:%d”,密钥,(int)状态);
}
}
-(NSData*)getData:(NSString*)键{
NSMutableDictionary*dict=[[NSMutableDictionary alloc]init];
[dict setObject:(uu桥id)kSecClassGenericPassword forKey:(uu桥id)kSecClass];
NSData*encodedKey=[密钥数据使用编码:NSUTF8StringEncoding];
[dict setObject:encodedKey-forKey:(u桥id)kSecAttrGeneric];
[dict setObject:encodedKey-forKey:(__桥id)kSecAttrAccount];
[dict setObject:@“VPN”forKey:(u桥id)kSecAttrService];
[dict setObject:(uu桥id)ksecataccessibleAllways此设备仅forKey:(uu桥id)ksecataccessible];
[dict setObject:(uu桥id)kSecMatchLimitOne forKey:(uu桥id)kSecMatchLimit];
[dict setObject:(id)kCFBooleanTrue forKey:(_桥id)kSecReturnPersistentRef];
CFTypeRef结果=NULL;
OSStatus状态=SecItemCopyMatching