From 73616b81f39bd49362f0e55b893203f544c1369f Mon Sep 17 00:00:00 2001 From: Matt Hardcastle Date: Thu, 20 Jun 2019 15:36:28 -0700 Subject: [PATCH 1/5] Fail on empty LAUNCHER_HMAC_SECRET Priot to this change there was code that attempted to verify that LAUNCHER_HMAC_SECRET was set to something. This code was broke though and didn't catch the case correctly. This change fixes the check. --- launchers/darwin/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launchers/darwin/CMakeLists.txt b/launchers/darwin/CMakeLists.txt index 4da675fcc9..9592ef69f3 100644 --- a/launchers/darwin/CMakeLists.txt +++ b/launchers/darwin/CMakeLists.txt @@ -67,7 +67,7 @@ add_executable(${PROJECT_NAME} MACOSX_BUNDLE ${src_files}) set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME ${APP_NAME} MACOSX_BUNDLE_BUNDLE_NAME ${APP_NAME}) set_from_env(LAUNCHER_HMAC_SECRET LAUNCHER_HMAC_SECRET "") -if (LAUNCHER_HMAC_SECRET STREQUAL "") +if ("${LAUNCHER_HMAC_SECRET}" STREQUAL "") message(FATAL_ERROR "LAUNCHER_HMAC_SECRET is not set") endif() From 3a5aa4194e7fe5a745a1ff17a1f6cb3ebed497db Mon Sep 17 00:00:00 2001 From: Matt Hardcastle Date: Sat, 22 Jun 2019 11:23:17 -0700 Subject: [PATCH 2/5] Pin the macOS HQ Launcher target version to 10.9 This change pins HQ Launcher's target SDK to 10.9, which is the same as the target SDK for Interface. Without this pinned value the target version defaults to whatever the OS version is on the machine that happened to build HQ Launcher. --- launchers/darwin/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/launchers/darwin/CMakeLists.txt b/launchers/darwin/CMakeLists.txt index 9592ef69f3..76d209d89d 100644 --- a/launchers/darwin/CMakeLists.txt +++ b/launchers/darwin/CMakeLists.txt @@ -1,4 +1,5 @@ cmake_minimum_required(VERSION 3.0) +set(ENV{MACOSX_DEPLOYMENT_TARGET} 10.9) project(HQLauncher) set (CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules/") set(src_files From 4d28c5fe412ae1f3df98ccf1edf1f6660211b0a5 Mon Sep 17 00:00:00 2001 From: Matt Hardcastle Date: Sat, 22 Jun 2019 11:32:36 -0700 Subject: [PATCH 3/5] Use version from Interface in macOS HQ Launcher Prior to this change the macOS HQ Launcher used the version from the settings files. Pull this information in the settings file could result in a situation where the setting file was updated, but interface wasn't. When the launcher ran a second time it would check the settings file and think Interface was updated even though it wasn't. This change resolves the issue by asking interface for its version directly. In the event that Interface doesn't response with a version number HQ Launcher knows how to interoperate HQ Launcher will fall back to using the settings file. Known Issues --- 1) Interface reports different version number formats depending on how its built. A stable interface for getting the build version from interface should be added. --- launchers/darwin/CMakeLists.txt | 2 + launchers/darwin/src/Interface.h | 8 ++ launchers/darwin/src/Interface.m | 100 ++++++++++++++++++++++ launchers/darwin/src/LatestBuildRequest.m | 25 ++++-- 4 files changed, 128 insertions(+), 7 deletions(-) create mode 100644 launchers/darwin/src/Interface.h create mode 100644 launchers/darwin/src/Interface.m diff --git a/launchers/darwin/CMakeLists.txt b/launchers/darwin/CMakeLists.txt index 76d209d89d..a3fc0dc7c1 100644 --- a/launchers/darwin/CMakeLists.txt +++ b/launchers/darwin/CMakeLists.txt @@ -27,6 +27,8 @@ set(src_files src/LatestBuildRequest.m src/OrganizationRequest.m src/OrganizationRequest.h + src/Interface.h + src/Interface.m src/ErrorViewController.h src/ErrorViewController.m src/Settings.h diff --git a/launchers/darwin/src/Interface.h b/launchers/darwin/src/Interface.h new file mode 100644 index 0000000000..c142aeecf5 --- /dev/null +++ b/launchers/darwin/src/Interface.h @@ -0,0 +1,8 @@ +#import + +@interface Interface : NSObject + +-(id _Nonnull) initWith:(NSString * _Nonnull) aPathToInterface; +-(NSInteger) getVersion:(out NSError * _Nullable * _Nonnull) anError; + +@end diff --git a/launchers/darwin/src/Interface.m b/launchers/darwin/src/Interface.m new file mode 100644 index 0000000000..b007e7faa5 --- /dev/null +++ b/launchers/darwin/src/Interface.m @@ -0,0 +1,100 @@ +#import "Interface.h" + +@implementation Interface +{ + NSString *pathTo; +} + +-(id) initWith:(NSString*)aPathToInterface +{ + [self init]; + self->pathTo = [NSString stringWithFormat:@"%@/Contents/MacOS/interface", aPathToInterface]; + return self; +} + +-(NSInteger) getVersion:(out NSError * _Nullable *) outError +{ + NSTask * interface = [[NSTask alloc] init]; + NSPipe * standardOut = [NSPipe pipe]; + + interface.launchPath = self->pathTo; + interface.arguments = @[ @"--version" ]; + interface.standardOutput = standardOut; + + NSLog(@"calling interface at %@", self->pathTo); + + if (@available(macOS 10.13, *)) { + NSError *error = nil; + if (![interface launchAndReturnError:&error]) { + *outError = [NSError errorWithDomain:@"interface" + code:-1 + userInfo:@{NSUnderlyingErrorKey: error}]; + return 0; + } + } else { + NSError *error = nil; + [interface launch]; + [interface waitUntilExit]; + if (0 != [interface terminationStatus]) { + *outError = [NSError errorWithDomain:@"interface" + code:-1 + userInfo:@{NSUnderlyingErrorKey: error}]; + return 0; + } + } + + NSFileHandle * fh = [standardOut fileHandleForReading]; + NSData * data = [fh readDataToEndOfFile]; + NSString * output = [NSString stringWithUTF8String:[data bytes]]; + if (output == nil) { + NSDictionary * userInfo = @{ + NSLocalizedDescriptionKey: NSLocalizedString(@"Couldn't start interface", nil) + }; + *outError = [NSError errorWithDomain:@"interface" + code:-1 + userInfo:userInfo]; + return 0; + } + + // Interface returns the build version as a string like this: + // "Interface 33333-DEADBEEF". This code grabs the substring + // between "Interface " and the hyphon ("-") + NSRange start = [output rangeOfString:@"Interface "]; + if (start.length == 0) { + NSDictionary * userInfo = @{ + NSLocalizedDescriptionKey: NSLocalizedString(@"Couldn't read interface's version", nil) + }; + *outError = [NSError errorWithDomain:@"interface" + code:-2 + userInfo:userInfo]; + return 0; + } + NSRange end = [output rangeOfString:@"-"]; + if (end.length == 0) { + NSDictionary * userInfo = @{ + NSLocalizedDescriptionKey: NSLocalizedString(@"Couldn't read interface's version", nil) + }; + *outError = [NSError errorWithDomain:@"interface" + code:-2 + userInfo:userInfo]; + return 0; + } + NSRange subRange = {start.length, end.location - start.length}; + NSString * versionStr; + @try { + versionStr = [output substringWithRange:subRange]; + } + @catch (NSException *) { + NSDictionary * userInfo = @{ + NSLocalizedDescriptionKey: NSLocalizedString(@"Couldn't read interface's version", nil) + }; + *outError = [NSError errorWithDomain:@"interface" + code:-2 + userInfo:userInfo]; + return 0; + } + + return versionStr.integerValue; +} + +@end diff --git a/launchers/darwin/src/LatestBuildRequest.m b/launchers/darwin/src/LatestBuildRequest.m index 5119efa8f6..21f63425ab 100644 --- a/launchers/darwin/src/LatestBuildRequest.m +++ b/launchers/darwin/src/LatestBuildRequest.m @@ -1,9 +1,22 @@ #import "LatestBuildRequest.h" #import "Launcher.h" #import "Settings.h" +#import "Interface.h" @implementation LatestBuildRequest +- (NSInteger) getCurrentVersion { + NSString* interfaceAppPath = [[Launcher.sharedLauncher getAppPath] stringByAppendingString:@"interface.app"]; + NSError * error = nil; + Interface * interface = [[Interface alloc] initWith:interfaceAppPath]; + NSInteger currentVersion = [interface getVersion:&error]; + if (currentVersion == 0 && error != nil) { + NSLog(@"can't get version from interface, falling back to settings: %@", error); + currentVersion = [Settings.sharedSettings latestBuildVersion]; + } + return currentVersion; +} + - (void) requestLatestBuildInfo { NSMutableURLRequest *request = [NSMutableURLRequest new]; [request setURL:[NSURL URLWithString:@"https://thunder.highfidelity.com/builds/api/tags/latest?format=json"]]; @@ -45,8 +58,7 @@ BOOL appDirectoryExist = [fileManager fileExistsAtPath:[[sharedLauncher getAppPath] stringByAppendingString:@"interface.app"]]; dispatch_async(dispatch_get_main_queue(), ^{ - Settings* settings = [Settings sharedSettings]; - NSInteger currentVersion = [settings latestBuildVersion]; + NSInteger currentVersion = [self getCurrentVersion]; NSLog(@"Latest Build Request -> does build directory exist: %@", appDirectoryExist ? @"TRUE" : @"FALSE"); NSLog(@"Latest Build Request -> current version: %ld", currentVersion); NSLog(@"Latest Build Request -> latest version: %ld", buildNumber.integerValue); @@ -105,11 +117,10 @@ NSDictionary* macInstallerObject = [installers objectForKey:@"mac"]; NSString* macInstallerUrl = [macInstallerObject valueForKey:@"zip_url"]; - BOOL appDirectoryExist = [fileManager fileExistsAtPath:[[sharedLauncher getAppPath] stringByAppendingString:@"interface.app"]]; - - Settings* settings = [Settings sharedSettings]; - NSInteger currentVersion = [settings latestBuildVersion]; - BOOL latestVersionAvailable = (currentVersion != buildNumber.integerValue); + NSString* interfaceAppPath = [[sharedLauncher getAppPath] stringByAppendingString:@"interface.app"]; + BOOL appDirectoryExist = [fileManager fileExistsAtPath:interfaceAppPath]; + + BOOL latestVersionAvailable = ([self getCurrentVersion] != buildNumber.integerValue); [[Settings sharedSettings] buildVersion:buildNumber.integerValue]; BOOL shouldDownloadInterface = (latestVersionAvailable || !appDirectoryExist); From 4f6e2c85f9c14ae89b303b1b0ee0800f4845e77c Mon Sep 17 00:00:00 2001 From: Matt Hardcastle Date: Sat, 22 Jun 2019 12:28:57 -0700 Subject: [PATCH 4/5] Never cache the tags API in macOS's HQ Launcher Prior to this change we used the default session while downloading the latest tags API response from Thunder. This left open the possibility that NSURLSession could cache the response, even though the server asked it not to; NSURLSession can be pretty aggressive about its caching. This change ensure no caching of the API is occurring my using an ephemeral session when calling the tags API. --- launchers/darwin/src/LatestBuildRequest.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/launchers/darwin/src/LatestBuildRequest.m b/launchers/darwin/src/LatestBuildRequest.m index 21f63425ab..7e836548af 100644 --- a/launchers/darwin/src/LatestBuildRequest.m +++ b/launchers/darwin/src/LatestBuildRequest.m @@ -23,8 +23,8 @@ [request setHTTPMethod:@"GET"]; [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; - - NSURLSession* session = [NSURLSession sharedSession]; + // We're using an ephermeral session here to ensure the tags api response is never cached. + NSURLSession * session = [NSURLSession sessionWithConfiguration:NSURLSessionConfiguration.ephemeralSessionConfiguration]; NSURLSessionDataTask* dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { From 9ae67c15b233f873b50ff3e1235054283803bbc3 Mon Sep 17 00:00:00 2001 From: Matt Hardcastle Date: Mon, 24 Jun 2019 14:27:07 -0700 Subject: [PATCH 5/5] Use old API to launch tasks on all versions of macOS --- launchers/darwin/src/Interface.m | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/launchers/darwin/src/Interface.m b/launchers/darwin/src/Interface.m index b007e7faa5..d02b66b581 100644 --- a/launchers/darwin/src/Interface.m +++ b/launchers/darwin/src/Interface.m @@ -23,24 +23,14 @@ NSLog(@"calling interface at %@", self->pathTo); - if (@available(macOS 10.13, *)) { - NSError *error = nil; - if (![interface launchAndReturnError:&error]) { - *outError = [NSError errorWithDomain:@"interface" - code:-1 - userInfo:@{NSUnderlyingErrorKey: error}]; - return 0; - } - } else { - NSError *error = nil; - [interface launch]; - [interface waitUntilExit]; - if (0 != [interface terminationStatus]) { - *outError = [NSError errorWithDomain:@"interface" - code:-1 - userInfo:@{NSUnderlyingErrorKey: error}]; - return 0; - } + NSError *error = nil; + [interface launch]; + [interface waitUntilExit]; + if (0 != [interface terminationStatus]) { + *outError = [NSError errorWithDomain:@"interface" + code:-1 + userInfo:@{NSUnderlyingErrorKey: error}]; + return 0; } NSFileHandle * fh = [standardOut fileHandleForReading];