123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522 |
- /*
- * ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- #import "ServiceCom.h"
- #import "AuthtokenCopy.h"
- #import "Network.h"
- #import "NodeStatus.h"
- @import AppKit;
- @interface ServiceCom (Private)
- - (NSString*)key;
- @end
- @implementation ServiceCom
- + (ServiceCom*)sharedInstance {
- static ServiceCom *sc = nil;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- sc = [[ServiceCom alloc] init];
- });
- return sc;
- }
- - (id)init
- {
- self = [super init];
- if(self) {
- baseURL = @"http://127.0.0.1:9993";
- session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration ephemeralSessionConfiguration]];
- _isQuitting = NO;
- _resetKey = NO;
- }
- return self;
- }
- - (NSString*)key:(NSError* __autoreleasing *)err
- {
- static NSString *k = nil;
- static NSUInteger resetCount = 0;
-
- @synchronized (self) {
- if (_isQuitting) {
- return @"";
- }
-
- if (_resetKey && k != nil) {
- k = nil;
- ++resetCount;
- NSLog(@"ResetCount: %lu", (unsigned long)resetCount);
- if (resetCount > 10) {
- [[NSOperationQueue mainQueue] addOperationWithBlock:^{
- NSAlert *alert = [NSAlert alertWithMessageText:@"Error obtaining Auth Token"
- defaultButton:@"Quit"
- alternateButton:@"Retry"
- otherButton:nil
- informativeTextWithFormat:@"Please ensure ZeroTier is installed correctly"];
- alert.alertStyle = NSCriticalAlertStyle;
-
- NSModalResponse res;
- if (!_isQuitting) {
- res = [alert runModal];
- }
- else {
- return;
- }
-
- if(res == 1) {
- _isQuitting = YES;
- [NSApp performSelector:@selector(terminate:) withObject:nil afterDelay:0.0];
- }
- }];
- return @"";
- }
- }
- if (k == nil) {
- NSError *error = nil;
- NSURL *appSupportDir = [[NSFileManager defaultManager] URLForDirectory:NSApplicationSupportDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:false error:&error];
- if (error) {
- NSLog(@"Error: %@", error);
- return @"";
- }
- appSupportDir = [[appSupportDir URLByAppendingPathComponent:@"ZeroTier"] URLByAppendingPathComponent:@"One"];
- NSURL *authtokenURL = [appSupportDir URLByAppendingPathComponent:@"authtoken.secret"];
- if (!_resetKey && [[NSFileManager defaultManager] fileExistsAtPath:[authtokenURL path]]) {
- k = [NSString stringWithContentsOfURL:authtokenURL
- encoding:NSUTF8StringEncoding
- error:&error];
-
- k = [k stringByReplacingOccurrencesOfString:@"\n" withString:@""];
- if (error) {
- NSLog(@"Error: %@", error);
- k = nil;
- *err = error;
- return @"";
- }
- }
- else {
- _resetKey = NO;
- NSURL *sysAppSupportDir = [[NSFileManager defaultManager] URLForDirectory:NSApplicationSupportDirectory inDomain:NSSystemDomainMask appropriateForURL:nil create:false error:nil];
- sysAppSupportDir = [[sysAppSupportDir URLByAppendingPathComponent:@"ZeroTier"] URLByAppendingPathComponent:@"One"];
- NSURL *sysAuthtokenURL = [sysAppSupportDir URLByAppendingPathComponent:@"authtoken.secret"];
- if(![[NSFileManager defaultManager] fileExistsAtPath:[sysAuthtokenURL path]]) {
- }
- [[NSFileManager defaultManager] createDirectoryAtURL:appSupportDir
- withIntermediateDirectories:YES
- attributes:nil
- error:&error];
- if (error) {
- NSLog(@"Error: %@", error);
- *err = error;
- k = nil;
- return @"";
- }
- AuthorizationRef authRef;
- OSStatus status = AuthorizationCreate(nil, nil, kAuthorizationFlagDefaults, &authRef);
- if (status != errAuthorizationSuccess) {
- NSLog(@"Authorization Failed! %d", status);
- NSDictionary *userInfo = @{
- NSLocalizedDescriptionKey: NSLocalizedString(@"Couldn't create AuthorizationRef", nil),
- };
- *err = [NSError errorWithDomain:@"com.zerotier.one" code:-1 userInfo:userInfo];
- return @"";
- }
- AuthorizationItem authItem;
- authItem.name = kAuthorizationRightExecute;
- authItem.valueLength = 0;
- authItem.flags = 0;
- AuthorizationRights authRights;
- authRights.count = 1;
- authRights.items = &authItem;
- AuthorizationFlags authFlags = kAuthorizationFlagDefaults |
- kAuthorizationFlagInteractionAllowed |
- kAuthorizationFlagPreAuthorize |
- kAuthorizationFlagExtendRights;
- status = AuthorizationCopyRights(authRef, &authRights, nil, authFlags, nil);
- if (status != errAuthorizationSuccess) {
- NSLog(@"Authorization Failed! %d", status);
- NSDictionary *userInfo = @{
- NSLocalizedDescriptionKey: NSLocalizedString(@"Couldn't copy authorization rights", nil),
- };
- *err = [NSError errorWithDomain:@"com.zerotier.one" code:-1 userInfo:userInfo];
- return @"";
- }
- NSString *localKey = getAdminAuthToken(authRef);
- AuthorizationFree(authRef, kAuthorizationFlagDestroyRights);
- if (localKey != nil && [localKey lengthOfBytesUsingEncoding:NSUTF8StringEncoding] > 0) {
- k = localKey;
- [localKey writeToURL:authtokenURL
- atomically:YES
- encoding:NSUTF8StringEncoding
- error:&error];
- if (error) {
- NSLog(@"Error writing token to disk: %@", error);
- *err = error;
- }
- }
- }
- }
- if (k == nil) {
- NSDictionary *userInfo = @{
- NSLocalizedDescriptionKey: NSLocalizedString(@"Unknown error finding authorization key", nil),
- };
- *err = [NSError errorWithDomain:@"com.zerotier.one" code:-1 userInfo:userInfo];
- return @"";
- }
- }
- return k;
- }
- - (void)getNetworklist:(void (^)(NSArray<Network *> *))completionHandler error:(NSError *__autoreleasing*)error
- {
- NSString* key = [self key:error];
- if(*error) {
- return;
- }
- NSString *urlString = [[baseURL stringByAppendingString:@"/network?auth="] stringByAppendingString:key];
- NSURL *url = [NSURL URLWithString:urlString];
- NSURLSessionDataTask *task =
- [session dataTaskWithURL:url
- completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable err) {
- if (err) {
- [[NSOperationQueue mainQueue] addOperationWithBlock:^{
- NSAlert *alert = [NSAlert alertWithError:err];
- alert.alertStyle = NSCriticalAlertStyle;
- [alert addButtonWithTitle:@"Quit"];
- [alert addButtonWithTitle:@"Retry"];
- NSModalResponse res;
- if (!_isQuitting) {
- res = [alert runModal];
- }
- else {
- return;
- }
- if(res == NSAlertFirstButtonReturn) {
- [NSApp performSelector:@selector(terminate:) withObject:nil afterDelay:0.0];
- _isQuitting = YES;
- }
- }];
- return;
- }
- NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response;
- NSInteger status = [httpResponse statusCode];
- NSError *err2;
- if (status == 200) {
- NSArray *json = [NSJSONSerialization JSONObjectWithData:data
- options:0
- error:&err2];
- if (err) {
- NSLog(@"Error fetching network list: %@", err2);
- [[NSOperationQueue mainQueue] addOperationWithBlock:^{
- NSAlert *alert = [NSAlert alertWithError:err2];
- alert.alertStyle = NSCriticalAlertStyle;
- [alert addButtonWithTitle:@"Quit"];
- [alert addButtonWithTitle:@"Retry"];
- NSModalResponse res;
- if (!_isQuitting) {
- res = [alert runModal];
- }
- else {
- return;
- }
- if(res == NSAlertFirstButtonReturn) {
- _isQuitting = YES;
- [NSApp performSelector:@selector(terminate:) withObject:nil afterDelay:0.0];
- }
- }];
- return;
- }
- NSMutableArray<Network*> *networks = [[NSMutableArray<Network*> alloc] init];
- for(NSDictionary *dict in json) {
- [networks addObject:[[Network alloc] initWithJsonData:dict]];
- }
- completionHandler(networks);
- }
- else if (status == 401) {
- self->_resetKey = YES;
- }
- }];
- [task resume];
- }
- - (void)getNodeStatus:(void (^)(NodeStatus*))completionHandler error:(NSError*__autoreleasing*)error
- {
- NSString *key = [self key:error];
- if(*error) {
- return;
- }
- NSString *urlString = [[baseURL stringByAppendingString:@"/status?auth="] stringByAppendingString:key];
- NSURL *url = [NSURL URLWithString:urlString];
- NSURLSessionDataTask *task =
- [session dataTaskWithURL:url
- completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable err) {
- if(err) {
- [[NSOperationQueue mainQueue] addOperationWithBlock:^{
- NSAlert *alert = [NSAlert alertWithError:err];
- alert.alertStyle = NSCriticalAlertStyle;
- [alert addButtonWithTitle:@"Quit"];
- [alert addButtonWithTitle:@"Retry"];
- NSModalResponse res;
- if (!_isQuitting) {
- res = [alert runModal];
- }
- else {
- return;
- }
- if(res == NSAlertFirstButtonReturn) {
- [NSApp performSelector:@selector(terminate:) withObject:nil afterDelay:0.0];
- _isQuitting = YES;
- }
- }];
- return;
- }
- NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response;
- NSInteger status = [httpResponse statusCode];
- NSError *err2;
- if(status == 200) {
- NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data
- options:0
- error:&err2];
- if(err2) {
- NSLog(@"Error fetching node status: %@", err2);
- [[NSOperationQueue mainQueue] addOperationWithBlock:^{
- NSAlert *alert = [NSAlert alertWithError:err2];
- alert.alertStyle = NSCriticalAlertStyle;
- [alert addButtonWithTitle:@"Quit"];
- [alert addButtonWithTitle:@"Retry"];
- NSModalResponse res;
- if (!_isQuitting) {
- res = [alert runModal];
- }
- else {
- return;
- }
- if(res == NSAlertFirstButtonReturn) {
- [NSApp performSelector:@selector(terminate:) withObject:nil afterDelay:0.0];
- _isQuitting = YES;
- }
- }];
- return;
- }
- NodeStatus *status = [[NodeStatus alloc] initWithJsonData:json];
- completionHandler(status);
- }
- else if (status == 401) {
- self->_resetKey = YES;
- }
- }];
- [task resume];
- }
- - (void)joinNetwork:(NSString*)networkId
- allowManaged:(BOOL)allowManaged
- allowGlobal:(BOOL)allowGlobal
- allowDefault:(BOOL)allowDefault
- allowDNS:(BOOL)allowDNS
- error:(NSError *__autoreleasing*)error
- {
- NSString *key = [self key:error];
- if(*error) {
- return;
- }
- NSString *urlString = [[[[baseURL stringByAppendingString:@"/network/"]
- stringByAppendingString:networkId]
- stringByAppendingString:@"?auth="]
- stringByAppendingString:key];
- NSURL *url = [NSURL URLWithString:urlString];
- NSMutableDictionary *jsonDict = [NSMutableDictionary dictionary];
- [jsonDict setObject:[NSNumber numberWithBool:allowManaged] forKey:@"allowManaged"];
- [jsonDict setObject:[NSNumber numberWithBool:allowGlobal] forKey:@"allowGlobal"];
- [jsonDict setObject:[NSNumber numberWithBool:allowDefault] forKey:@"allowDefault"];
- [jsonDict setObject:[NSNumber numberWithBool:allowDNS] forKey:@"allowDNS"];
- NSError *err = nil;
- NSData *json = [NSJSONSerialization dataWithJSONObject:jsonDict
- options:0
- error:&err];
- if(err) {
- NSLog(@"Error creating json data: %@", err);
- *error = err;
- return;
- }
- NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
- request.HTTPMethod = @"POST";
- request.HTTPBody = json;
- [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
- NSURLSessionDataTask *task =
- [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable err) {
- if(err) {
- NSLog(@"Error posting join request: %@", err);
- [[NSOperationQueue mainQueue] addOperationWithBlock:^{
- NSAlert *alert = [NSAlert alertWithError:err];
- alert.alertStyle = NSCriticalAlertStyle;
- [alert addButtonWithTitle:@"Quit"];
- [alert addButtonWithTitle:@"Retry"];
- NSModalResponse res;
- if (!_isQuitting) {
- res = [alert runModal];
- }
- else {
- return;
- }
- if(res == NSAlertFirstButtonReturn) {
- [NSApp performSelector:@selector(terminate:) withObject:nil afterDelay:0.0];
- _isQuitting = YES;
- }
- }];
- }
- NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response;
- NSInteger status = [httpResponse statusCode];
- if(status == 200) {
- NSLog(@"join ok");
- }
- else if (status == 401) {
- self->_resetKey = YES;
- }
- else {
- NSLog(@"join error: %ld", (long)status);
- }
- }];
- [task resume];
- }
- - (void)leaveNetwork:(NSString*)networkId error:(NSError*__autoreleasing*)error
- {
- NSString *key = [self key:error];
- if(*error) {
- return;
- }
- NSString *urlString = [[[[baseURL stringByAppendingString:@"/network/"]
- stringByAppendingString:networkId]
- stringByAppendingString:@"?auth="]
- stringByAppendingString:key];
- NSURL *url = [NSURL URLWithString:urlString];
- NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
- request.HTTPMethod = @"DELETE";
- NSURLSessionDataTask *task =
- [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable err) {
- if(err) {
- NSLog(@"Error posting delete request: %@", err);
- [[NSOperationQueue mainQueue] addOperationWithBlock:^{
- NSAlert *alert = [NSAlert alertWithError:err];
- alert.alertStyle = NSCriticalAlertStyle;
- [alert addButtonWithTitle:@"Quit"];
- [alert addButtonWithTitle:@"Retry"];
- NSModalResponse res;
- if (!_isQuitting) {
- res = [alert runModal];
- }
- else {
- return;
- }
- if(res == NSAlertFirstButtonReturn) {
- [NSApp performSelector:@selector(terminate:) withObject:nil afterDelay:0.0];
- _isQuitting = YES;
- }
- }];
- return;
- }
- NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response;
- NSInteger status = httpResponse.statusCode;
- if(status == 200) {
- NSLog(@"leave ok");
- }
- else if (status == 401) {
- self->_resetKey = YES;
- }
- else {
- NSLog(@"leave error: %ld", status);
- }
- }];
- [task resume];
- }
- @end
|