Reorder methods in BITAuthenticator and enforce code style

This commit is contained in:
Lukas Spieß
2016-04-11 23:32:51 +02:00
parent 80cd0eaf58
commit 8f83de2dbb

View File

@@ -41,22 +41,22 @@
#include <sys/stat.h>
static NSString* const kBITAuthenticatorUUIDKey = @"BITAuthenticatorUUIDKey";
static NSString* const kBITAuthenticatorIdentifierKey = @"BITAuthenticatorIdentifierKey";
static NSString* const kBITAuthenticatorIdentifierTypeKey = @"BITAuthenticatorIdentifierTypeKey";
static NSString* const kBITAuthenticatorLastAuthenticatedVersionKey = @"BITAuthenticatorLastAuthenticatedVersionKey";
static NSString* const kBITAuthenticatorUserEmailKey = @"BITAuthenticatorUserEmailKey";
static NSString *const kBITAuthenticatorUUIDKey = @"BITAuthenticatorUUIDKey";
static NSString *const kBITAuthenticatorIdentifierKey = @"BITAuthenticatorIdentifierKey";
static NSString *const kBITAuthenticatorIdentifierTypeKey = @"BITAuthenticatorIdentifierTypeKey";
static NSString *const kBITAuthenticatorLastAuthenticatedVersionKey = @"BITAuthenticatorLastAuthenticatedVersionKey";
static NSString *const kBITAuthenticatorUserEmailKey = @"BITAuthenticatorUserEmailKey";
//deprecated
static NSString* const kBITAuthenticatorAuthTokenKey = @"BITAuthenticatorAuthTokenKey";
static NSString* const kBITAuthenticatorAuthTokenTypeKey = @"BITAuthenticatorAuthTokenTypeKey";
static NSString *const kBITAuthenticatorAuthTokenKey = @"BITAuthenticatorAuthTokenKey";
static NSString *const kBITAuthenticatorAuthTokenTypeKey = @"BITAuthenticatorAuthTokenTypeKey";
typedef unsigned int bit_uint32;
static unsigned char kBITPNGHeader[8] = {137, 80, 78, 71, 13, 10, 26, 10};
static unsigned char kBITPNGEndChunk[4] = {0x49, 0x45, 0x4e, 0x44};
@interface BITAuthenticator ()
@interface BITAuthenticator()
@property (nonatomic, assign) BOOL isSetup;
@@ -71,7 +71,7 @@ static unsigned char kBITPNGEndChunk[4] = {0x49, 0x45, 0x4e, 0x44};
- (instancetype)initWithAppIdentifier:(NSString *)appIdentifier appEnvironment:(BITEnvironment)environment {
self = [super initWithAppIdentifier:appIdentifier appEnvironment:environment];
if( self ) {
if (self) {
_webpageURL = [NSURL URLWithString:@"https://rink.hockeyapp.net/"];
_identificationType = BITAuthenticatorIdentificationTypeAnonymous;
@@ -87,36 +87,19 @@ static unsigned char kBITPNGEndChunk[4] = {0x49, 0x45, 0x4e, 0x44};
}
#pragma mark - BITHockeyBaseManager overrides
- (void)startManager {
//disabled in TestFlight and the AppStore
if(self.appEnvironment != BITEnvironmentOther) return;
if (self.appEnvironment != BITEnvironmentOther) { return; }
self.isSetup = YES;
}
#pragma mark -
/**
* This method has to be called on the main queue
*/
- (void)dismissAuthenticationControllerAnimated:(BOOL)animated completion:(void (^)(void))completion {
if (!_authenticationController) return;
UIViewController *presentingViewController = [_authenticationController presentingViewController];
// If there is no presenting view controller just remove view
if (presentingViewController) {
[_authenticationController dismissViewControllerAnimated:animated completion:completion];
} else {
[_authenticationController.navigationController.view removeFromSuperview];
if (completion) {
completion();
}
}
self.authenticationController = nil;
}
- (void)authenticateInstallation {
//disabled in TestFlight and the AppStore
if(self.appEnvironment != BITEnvironmentOther) return;
if (self.appEnvironment != BITEnvironmentOther) { return; }
// make sure this is called after startManager so all modules are fully setup
if (!_isSetup) {
@@ -136,10 +119,10 @@ static unsigned char kBITPNGEndChunk[4] = {0x49, 0x45, 0x4e, 0x44};
[self registerObservers];
}
- (void) authenticate {
- (void)authenticate {
[self identifyWithCompletion:^(BOOL identified, NSError *error) {
if(identified) {
if([self needsValidation]) {
if (identified) {
if ([self needsValidation]) {
[self validate];
} else {
[self dismissAuthenticationControllerAnimated:YES completion:nil];
@@ -150,56 +133,33 @@ static unsigned char kBITPNGEndChunk[4] = {0x49, 0x45, 0x4e, 0x44};
}];
}
- (BOOL) needsValidation {
if(BITAuthenticatorIdentificationTypeAnonymous == self.identificationType) {
return NO;
}
if(NO == self.restrictApplicationUsage) {
return NO;
}
if(self.restrictionEnforcementFrequency == BITAuthenticatorAppRestrictionEnforcementOnFirstLaunch &&
![self.executableUUID isEqualToString:self.lastAuthenticatedVersion]) {
return YES;
}
if(NO == self.isValidated && self.restrictionEnforcementFrequency == BITAuthenticatorAppRestrictionEnforcementOnAppActive) {
return YES;
}
return NO;
}
- (void)alertOnFailureStoringTokenInKeychain {
if ([[UIApplication sharedApplication] applicationState] != UIApplicationStateActive) {
return;
}
NSLog(@"[HockeySDK] ERROR: The authentication token could not be stored due to a keychain error. This is most likely a signing or keychain entitlement issue!");
}
#pragma mark - Identification
- (void)identifyWithCompletion:(void (^)(BOOL identified, NSError *))completion {
if(_authenticationController) {
if (_authenticationController) {
BITHockeyLog(@"Authentication controller already visible. Ignoring identify request");
if(completion) completion(NO, nil);
if (completion) { completion(NO, nil); }
return;
}
//first check if the stored identification type matches the one currently configured
NSString *storedTypeString = [self stringValueFromKeychainForKey:kBITAuthenticatorIdentifierTypeKey];
NSString *configuredTypeString = [self.class stringForIdentificationType:self.identificationType];
if(storedTypeString && ![storedTypeString isEqualToString:configuredTypeString]) {
if (storedTypeString && ![storedTypeString isEqualToString:configuredTypeString]) {
BITHockeyLog(@"Identification type mismatch for stored auth-token. Resetting.");
[self storeInstallationIdentifier:nil withType:BITAuthenticatorIdentificationTypeAnonymous];
}
NSString *identification = [self installationIdentifier];
if(identification) {
if (identification) {
self.identified = YES;
if(completion) completion(YES, nil);
if (completion) { completion(YES, nil); }
return;
}
[self processFullSizeImage];
if (self.identified) {
if(completion) completion(YES, nil);
if (completion) { completion(YES, nil); }
return;
}
@@ -209,7 +169,7 @@ static unsigned char kBITPNGEndChunk[4] = {0x49, 0x45, 0x4e, 0x44};
case BITAuthenticatorIdentificationTypeAnonymous:
[self storeInstallationIdentifier:bit_UUID() withType:BITAuthenticatorIdentificationTypeAnonymous];
self.identified = YES;
if(completion) completion(YES, nil);
if (completion) { completion(YES, nil); }
return;
break;
case BITAuthenticatorIdentificationTypeHockeyAppUser:
@@ -230,11 +190,11 @@ static unsigned char kBITPNGEndChunk[4] = {0x49, 0x45, 0x4e, 0x44};
viewController.tableViewTitle = BITHockeyLocalizedString(@"HockeyAuthenticationViewControllerWebAuthLoginDescription");
break;
case BITAuthenticatorIdentificationTypeHockeyAppEmail:
if(nil == self.authenticationSecret) {
if (nil == self.authenticationSecret) {
NSError *error = [NSError errorWithDomain:kBITAuthenticatorErrorDomain
code:BITAuthenticatorAuthorizationSecretMissing
userInfo:@{NSLocalizedDescriptionKey : @"For email identification, the authentication secret must be set"}];
if(completion) completion(NO, error);
userInfo:@{NSLocalizedDescriptionKey:@"For email identification, the authentication secret must be set"}];
if (completion) { completion(NO, error); }
return;
}
viewController = [[BITAuthenticationViewController alloc] initWithDelegate:self];
@@ -243,7 +203,7 @@ static unsigned char kBITPNGEndChunk[4] = {0x49, 0x45, 0x4e, 0x44};
break;
}
if([self.delegate respondsToSelector:@selector(authenticator:willShowAuthenticationController:)]) {
if ([self.delegate respondsToSelector:@selector(authenticator:willShowAuthenticationController:)]) {
[self.delegate authenticator:self willShowAuthenticationController:viewController];
}
@@ -259,10 +219,27 @@ static unsigned char kBITPNGEndChunk[4] = {0x49, 0x45, 0x4e, 0x44};
#pragma mark - Validation
- (void) validate {
- (BOOL)needsValidation {
if (BITAuthenticatorIdentificationTypeAnonymous == self.identificationType) {
return NO;
}
if (NO == self.restrictApplicationUsage) {
return NO;
}
if (self.restrictionEnforcementFrequency == BITAuthenticatorAppRestrictionEnforcementOnFirstLaunch &&
![self.executableUUID isEqualToString:self.lastAuthenticatedVersion]) {
return YES;
}
if (NO == self.isValidated && self.restrictionEnforcementFrequency == BITAuthenticatorAppRestrictionEnforcementOnAppActive) {
return YES;
}
return NO;
}
- (void)validate {
[self validateWithCompletion:^(BOOL validated, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
if(validated) {
if (validated) {
[self dismissAuthenticationControllerAnimated:YES completion:nil];
} else {
BITHockeyLog(@"Validation failed with error: %@", error);
@@ -305,22 +282,22 @@ static unsigned char kBITPNGEndChunk[4] = {0x49, 0x45, 0x4e, 0x44};
}];
}
- (void) validateWithCompletion:(void (^)(BOOL validated, NSError *))completion {
- (void)validateWithCompletion:(void (^)(BOOL validated, NSError *))completion {
BOOL requirementsFulfilled = YES;
NSError *error = nil;
switch(self.identificationType) {
switch (self.identificationType) {
case BITAuthenticatorIdentificationTypeAnonymous: {
error = [NSError errorWithDomain:kBITAuthenticatorErrorDomain
code:BITAuthenticatorErrorUnknown
userInfo:@{NSLocalizedDescriptionKey : @"Anonymous users can't be validated"}];
userInfo:@{NSLocalizedDescriptionKey:@"Anonymous users can't be validated"}];
requirementsFulfilled = NO;
break;
}
case BITAuthenticatorIdentificationTypeHockeyAppEmail:
if(nil == self.authenticationSecret) {
if (nil == self.authenticationSecret) {
error = [NSError errorWithDomain:kBITAuthenticatorErrorDomain
code:BITAuthenticatorAuthorizationSecretMissing
userInfo:@{NSLocalizedDescriptionKey : @"For email validation, the authentication secret must be set"}];
userInfo:@{NSLocalizedDescriptionKey:@"For email validation, the authentication secret must be set"}];
requirementsFulfilled = NO;
break;
}
@@ -328,16 +305,16 @@ static unsigned char kBITPNGEndChunk[4] = {0x49, 0x45, 0x4e, 0x44};
case BITAuthenticatorIdentificationTypeDevice:
case BITAuthenticatorIdentificationTypeHockeyAppUser:
case BITAuthenticatorIdentificationTypeWebAuth:
if(nil == self.installationIdentifier) {
if (nil == self.installationIdentifier) {
error = [NSError errorWithDomain:kBITAuthenticatorErrorDomain
code:BITAuthenticatorNotIdentified
userInfo:@{NSLocalizedDescriptionKey : @"Make sure to identify the installation first"}];
userInfo:@{NSLocalizedDescriptionKey:@"Make sure to identify the installation first"}];
requirementsFulfilled = NO;
}
break;
}
if(NO == requirementsFulfilled) {
if(completion) {
if (NO == requirementsFulfilled) {
if (completion) {
completion(NO, error);
}
return;
@@ -345,7 +322,7 @@ static unsigned char kBITPNGEndChunk[4] = {0x49, 0x45, 0x4e, 0x44};
NSString *validationPath = [NSString stringWithFormat:@"api/3/apps/%@/identity/validate", self.encodedAppIdentifier];
__weak typeof (self) weakSelf = self;
__weak typeof(self) weakSelf = self;
if ([BITHockeyHelper isURLSessionSupported]) {
NSURLRequest *request = [self.hockeyAppClient requestWithMethod:@"GET" path:validationPath parameters:[self validationParameters]];
@@ -353,28 +330,28 @@ static unsigned char kBITPNGEndChunk[4] = {0x49, 0x45, 0x4e, 0x44};
__block NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfiguration];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request
completionHandler: ^(NSData *data, NSURLResponse *response, NSError *error) {
typeof (self) strongSelf = weakSelf;
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
typeof(self) strongSelf = weakSelf;
[session finishTasksAndInvalidate];
[strongSelf handleValidationResponseWithData:data error:error completion:completion];
}];
[task resume];
}else{
} else {
[self.hockeyAppClient getPath:validationPath
parameters:[self validationParameters]
completion:^(BITHTTPOperation *operation, NSData* responseData, NSError *error) {
typeof (self) strongSelf = weakSelf;
completion:^(BITHTTPOperation *operation, NSData *responseData, NSError *error) {
typeof(self) strongSelf = weakSelf;
[strongSelf handleValidationResponseWithData:responseData error:error completion:completion];
}];
}
}
- (void)handleValidationResponseWithData:(NSData *)responseData error:(NSError *)error completion:(void (^)(BOOL validated, NSError *))completion {
if(nil == responseData) {
NSDictionary *userInfo = @{NSLocalizedDescriptionKey : BITHockeyLocalizedString(@"HockeyAuthenticationFailedAuthenticate")};
if(error) {
if (nil == responseData) {
NSDictionary *userInfo = @{NSLocalizedDescriptionKey:BITHockeyLocalizedString(@"HockeyAuthenticationFailedAuthenticate")};
if (error) {
NSMutableDictionary *dict = [userInfo mutableCopy];
dict[NSUnderlyingErrorKey] = error;
userInfo = dict;
@@ -383,28 +360,28 @@ static unsigned char kBITPNGEndChunk[4] = {0x49, 0x45, 0x4e, 0x44};
code:BITAuthenticatorNetworkError
userInfo:userInfo];
self.validated = NO;
if(completion) { completion(NO, error); }
if (completion) { completion(NO, error); }
} else {
NSError *validationParseError = nil;
BOOL valid = [self.class isValidationResponseValid:responseData error:&validationParseError];
self.validated = valid;
if(valid) {
if (valid) {
[self setLastAuthenticatedVersion:self.executableUUID];
}
if(completion) { completion(valid, validationParseError); }
if (completion) { completion(valid, validationParseError); }
}
}
- (NSDictionary*)validationParameters {
- (NSDictionary *)validationParameters {
NSParameterAssert(self.installationIdentifier);
NSParameterAssert(self.installationIdentifierParameterString);
NSString *installString = bit_appAnonID(NO);
if (installString) {
return @{self.installationIdentifierParameterString : self.installationIdentifier, @"install_string": installString};
return @{self.installationIdentifierParameterString:self.installationIdentifier, @"install_string":installString};
}
return @{self.installationIdentifierParameterString : self.installationIdentifier};
return @{self.installationIdentifierParameterString:self.installationIdentifier};
}
+ (BOOL)isValidationResponseValid:(id)response error:(NSError **)error {
@@ -414,58 +391,82 @@ static unsigned char kBITPNGEndChunk[4] = {0x49, 0x45, 0x4e, 0x44};
id jsonObject = [NSJSONSerialization JSONObjectWithData:response
options:0
error:&jsonParseError];
if(nil == jsonObject) {
if(error) {
if (nil == jsonObject) {
if (error) {
*error = [NSError errorWithDomain:kBITAuthenticatorErrorDomain
code:BITAuthenticatorAPIServerReturnedInvalidResponse
userInfo:@{NSLocalizedDescriptionKey : BITHockeyLocalizedString(@"HockeyAuthenticationFailedAuthenticate")}];
userInfo:@{NSLocalizedDescriptionKey:BITHockeyLocalizedString(@"HockeyAuthenticationFailedAuthenticate")}];
}
return NO;
}
if(![jsonObject isKindOfClass:[NSDictionary class]]) {
if(error) {
if (![jsonObject isKindOfClass:[NSDictionary class]]) {
if (error) {
*error = [NSError errorWithDomain:kBITAuthenticatorErrorDomain
code:BITAuthenticatorAPIServerReturnedInvalidResponse
userInfo:@{NSLocalizedDescriptionKey : BITHockeyLocalizedString(@"HockeyAuthenticationFailedAuthenticate")}];
userInfo:@{NSLocalizedDescriptionKey:BITHockeyLocalizedString(@"HockeyAuthenticationFailedAuthenticate")}];
}
return NO;
}
NSString *status = jsonObject[@"status"];
if([status isEqualToString:@"not authorized"]) {
if(error) {
if ([status isEqualToString:@"not authorized"]) {
if (error) {
*error = [NSError errorWithDomain:kBITAuthenticatorErrorDomain
code:BITAuthenticatorNotAuthorized
userInfo:@{NSLocalizedDescriptionKey : BITHockeyLocalizedString(@"HockeyAuthenticationNotMember")}];
userInfo:@{NSLocalizedDescriptionKey:BITHockeyLocalizedString(@"HockeyAuthenticationNotMember")}];
}
return NO;
} else if([status isEqualToString:@"not found"]) {
if(error) {
} else if ([status isEqualToString:@"not found"]) {
if (error) {
*error = [NSError errorWithDomain:kBITAuthenticatorErrorDomain
code:BITAuthenticatorUnknownApplicationID
userInfo:@{NSLocalizedDescriptionKey : BITHockeyLocalizedString(@"HockeyAuthenticationContactDeveloper")}];
userInfo:@{NSLocalizedDescriptionKey:BITHockeyLocalizedString(@"HockeyAuthenticationContactDeveloper")}];
}
return NO;
} else if([status isEqualToString:@"validated"]) {
} else if ([status isEqualToString:@"validated"]) {
return YES;
} else {
if(error) {
if (error) {
*error = [NSError errorWithDomain:kBITAuthenticatorErrorDomain
code:BITAuthenticatorAPIServerReturnedInvalidResponse
userInfo:@{NSLocalizedDescriptionKey : BITHockeyLocalizedString(@"HockeyAuthenticationFailedAuthenticate")}];
userInfo:@{NSLocalizedDescriptionKey:BITHockeyLocalizedString(@"HockeyAuthenticationFailedAuthenticate")}];
}
return NO;
}
}
#pragma mark - AuthenticationViewController Helper
/**
* This method has to be called on the main queue
*/
- (void)dismissAuthenticationControllerAnimated:(BOOL)animated completion:(void (^)(void))completion {
if (!_authenticationController) { return; }
UIViewController *presentingViewController = [_authenticationController presentingViewController];
// If there is no presenting view controller just remove view
if (presentingViewController) {
[_authenticationController dismissViewControllerAnimated:animated completion:completion];
} else {
[_authenticationController.navigationController.view removeFromSuperview];
if (completion) {
completion();
}
}
self.authenticationController = nil;
}
#pragma mark - AuthenticationViewControllerDelegate
- (void)authenticationViewController:(UIViewController *)viewController
handleAuthenticationWithEmail:(NSString *)email
password:(NSString *)password
completion:(void (^)(BOOL, NSError *))completion {
NSParameterAssert(email && email.length);
NSParameterAssert(self.identificationType == BITAuthenticatorIdentificationTypeHockeyAppEmail || (password && password.length));
NSURLRequest* request = [self requestForAuthenticationEmail:email password:password];
NSURLRequest *request = [self requestForAuthenticationEmail:email password:password];
[self authenticationViewController:viewController handleAuthenticationWithEmail:email request:request completion:completion];
}
@@ -474,38 +475,52 @@ static unsigned char kBITPNGEndChunk[4] = {0x49, 0x45, 0x4e, 0x44};
handleAuthenticationWithEmail:(NSString *)email
request:(NSURLRequest *)request
completion:(void (^)(BOOL, NSError *))completion {
__weak typeof (self) weakSelf = self;
if([BITHockeyHelper isURLSessionSupported]) {
__weak typeof(self) weakSelf = self;
if ([BITHockeyHelper isURLSessionSupported]) {
NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
__block NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfiguration];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request
completionHandler: ^(NSData *data, NSURLResponse *response, NSError *error) {
typeof (self) strongSelf = weakSelf;
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*) response;
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
typeof(self) strongSelf = weakSelf;
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
[session finishTasksAndInvalidate];
[strongSelf handleAuthenticationWithResponse:httpResponse email:email data:data completion:completion];
}];
[task resume];
}else{
} else {
BITHTTPOperation *operation = [self.hockeyAppClient operationWithURLRequest:request
completion:^(BITHTTPOperation *operation, NSData* responseData, NSError *error) {
typeof (self) strongSelf = weakSelf;
[strongSelf handleAuthenticationWithResponse:operation.response email:email data:responseData completion:completion];
completion:^(BITHTTPOperation *operation, NSData *responseData, NSError *error) {
typeof(self) strongSelf = weakSelf;
[strongSelf handleAuthenticationWithResponse:operation.response
email:email
data:responseData
completion:completion];
}];
[self.hockeyAppClient enqeueHTTPOperation:operation];
}
}
- (void)handleAuthenticationWithResponse:(NSHTTPURLResponse *)response email:(NSString *)email data:(NSData *)data completion:(void (^)(BOOL, NSError *))completion{
- (void)authenticationViewControllerDidTapWebButton:(UIViewController *)viewController {
NSURL *url = [self deviceAuthenticationURL];
if (url) {
[[UIApplication sharedApplication] openURL:url];
}
}
#pragma mark - Networking
- (void)handleAuthenticationWithResponse:(NSHTTPURLResponse *)response email:(NSString *)email data:(NSData *)data completion:(void (^)(BOOL, NSError *))completion {
NSError *authParseError = nil;
NSString *authToken = [self.class authenticationTokenFromURLResponse:response
data:data
error:&authParseError];
BOOL identified;
if(authToken) {
if (authToken) {
identified = YES;
[self storeInstallationIdentifier:authToken withType:self.identificationType];
[self dismissAuthenticationControllerAnimated:YES completion:nil];
@@ -519,13 +534,13 @@ static unsigned char kBITPNGEndChunk[4] = {0x49, 0x45, 0x4e, 0x44};
}
self.identified = identified;
if (completion) { completion(identified, authParseError); }
if(self.identificationCompletion) {
if (self.identificationCompletion) {
self.identificationCompletion(identified, authParseError);
self.identificationCompletion = nil;
}
}
- (NSURLRequest *) requestForAuthenticationEmail:(NSString*) email password:(NSString*) password {
- (NSURLRequest *)requestForAuthenticationEmail:(NSString *)email password:(NSString *)password {
NSString *authenticationPath = [self authenticationPath];
NSMutableDictionary *params = [NSMutableDictionary dictionary];
@@ -534,19 +549,19 @@ static unsigned char kBITPNGEndChunk[4] = {0x49, 0x45, 0x4e, 0x44};
params[@"install_string"] = installString;
}
if(BITAuthenticatorIdentificationTypeHockeyAppEmail == self.identificationType) {
if (BITAuthenticatorIdentificationTypeHockeyAppEmail == self.identificationType) {
NSString *authCode = BITHockeyMD5([NSString stringWithFormat:@"%@%@",
self.authenticationSecret ? : @"",
email ? : @""]);
self.authenticationSecret ?: @"",
email ?: @""]);
params[@"email"] = email ? : @"";
params[@"email"] = email ?: @"";
params[@"authcode"] = authCode.lowercaseString;
}
NSMutableURLRequest *request = [self.hockeyAppClient requestWithMethod:@"POST"
path:authenticationPath
parameters:params];
if(BITAuthenticatorIdentificationTypeHockeyAppUser == self.identificationType) {
if (BITAuthenticatorIdentificationTypeHockeyAppUser == self.identificationType) {
NSString *authStr = [NSString stringWithFormat:@"%@:%@", email, password];
NSData *authData = [authStr dataUsingEncoding:NSUTF8StringEncoding];
NSString *authValue = [NSString stringWithFormat:@"Basic %@", bit_base64String(authData, authData.length)];
@@ -556,31 +571,31 @@ static unsigned char kBITPNGEndChunk[4] = {0x49, 0x45, 0x4e, 0x44};
return request;
}
- (NSString *) authenticationPath {
if(BITAuthenticatorIdentificationTypeHockeyAppUser == self.identificationType) {
- (NSString *)authenticationPath {
if (BITAuthenticatorIdentificationTypeHockeyAppUser == self.identificationType) {
return [NSString stringWithFormat:@"api/3/apps/%@/identity/authorize", self.encodedAppIdentifier];
} else {
return [NSString stringWithFormat:@"api/3/apps/%@/identity/check", self.encodedAppIdentifier];
}
}
+ (NSString *) authenticationTokenFromURLResponse:(NSHTTPURLResponse*) urlResponse data:(NSData*) data error:(NSError **) error {
if(nil == urlResponse) {
if(error) {
+ (NSString *)authenticationTokenFromURLResponse:(NSHTTPURLResponse *)urlResponse data:(NSData *)data error:(NSError **)error {
if (nil == urlResponse) {
if (error) {
*error = [NSError errorWithDomain:kBITAuthenticatorErrorDomain
code:BITAuthenticatorAPIServerReturnedInvalidResponse
userInfo:@{ NSLocalizedDescriptionKey : BITHockeyLocalizedString(@"HockeyAuthenticationFailedAuthenticate")}];
userInfo:@{NSLocalizedDescriptionKey:BITHockeyLocalizedString(@"HockeyAuthenticationFailedAuthenticate")}];
}
return nil;
}
switch (urlResponse.statusCode) {
case 401:
if(error) {
if (error) {
*error = [NSError errorWithDomain:kBITAuthenticatorErrorDomain
code:BITAuthenticatorNotAuthorized
userInfo:@{
NSLocalizedDescriptionKey : BITHockeyLocalizedString(@"HockeyAuthenticationWrongEmailPassword")
NSLocalizedDescriptionKey:BITHockeyLocalizedString(@"HockeyAuthenticationWrongEmailPassword")
}];
}
break;
@@ -589,15 +604,15 @@ static unsigned char kBITPNGEndChunk[4] = {0x49, 0x45, 0x4e, 0x44};
//Do nothing, handled below
break;
default:
if(error) {
if (error) {
*error = [NSError errorWithDomain:kBITAuthenticatorErrorDomain
code:BITAuthenticatorAPIServerReturnedInvalidResponse
userInfo:@{ NSLocalizedDescriptionKey : BITHockeyLocalizedString(@"HockeyAuthenticationFailedAuthenticate")}];
userInfo:@{NSLocalizedDescriptionKey:BITHockeyLocalizedString(@"HockeyAuthenticationFailedAuthenticate")}];
}
break;
}
if(200 != urlResponse.statusCode && 404 != urlResponse.statusCode) {
if (200 != urlResponse.statusCode && 404 != urlResponse.statusCode) {
//make sure we have an error created if user wanted to have one
NSParameterAssert(nil == error || *error);
return nil;
@@ -608,10 +623,10 @@ static unsigned char kBITPNGEndChunk[4] = {0x49, 0x45, 0x4e, 0x44};
options:0
error:&jsonParseError];
//no json or unexpected json
if(nil == jsonObject || ![jsonObject isKindOfClass:[NSDictionary class]]) {
if(error) {
NSDictionary *userInfo = @{NSLocalizedDescriptionKey: BITHockeyLocalizedString(@"HockeyAuthenticationFailedAuthenticate")};
if(jsonParseError) {
if (nil == jsonObject || ![jsonObject isKindOfClass:[NSDictionary class]]) {
if (error) {
NSDictionary *userInfo = @{NSLocalizedDescriptionKey:BITHockeyLocalizedString(@"HockeyAuthenticationFailedAuthenticate")};
if (jsonParseError) {
NSMutableDictionary *userInfoMutable = [userInfo mutableCopy];
userInfoMutable[NSUnderlyingErrorKey] = jsonParseError;
userInfo = userInfoMutable;
@@ -625,23 +640,23 @@ static unsigned char kBITPNGEndChunk[4] = {0x49, 0x45, 0x4e, 0x44};
NSString *status = jsonObject[@"status"];
NSString *authToken = nil;
if([status isEqualToString:@"identified"]) {
if ([status isEqualToString:@"identified"]) {
authToken = jsonObject[@"iuid"];
} else if([status isEqualToString:@"authorized"]) {
} else if ([status isEqualToString:@"authorized"]) {
authToken = jsonObject[@"auid"];
} else if([status isEqualToString:@"not authorized"]) {
if(error) {
} else if ([status isEqualToString:@"not authorized"]) {
if (error) {
*error = [NSError errorWithDomain:kBITAuthenticatorErrorDomain
code:BITAuthenticatorNotAuthorized
userInfo:@{NSLocalizedDescriptionKey: BITHockeyLocalizedString(@"HockeyAuthenticationNotMember")}];
userInfo:@{NSLocalizedDescriptionKey:BITHockeyLocalizedString(@"HockeyAuthenticationNotMember")}];
}
}
//if no error is set yet, but error parameter is given, return a generic error
if(nil == authToken && error && nil == *error) {
if (nil == authToken && error && nil == *error) {
*error = [NSError errorWithDomain:kBITAuthenticatorErrorDomain
code:BITAuthenticatorAPIServerReturnedInvalidResponse
userInfo:@{NSLocalizedDescriptionKey: BITHockeyLocalizedString(@"HockeyAuthenticationFailedAuthenticate")}];
userInfo:@{NSLocalizedDescriptionKey:BITHockeyLocalizedString(@"HockeyAuthenticationFailedAuthenticate")}];
}
return authToken;
}
@@ -667,21 +682,14 @@ static unsigned char kBITPNGEndChunk[4] = {0x49, 0x45, 0x4e, 0x44};
return url;
}
- (void)authenticationViewControllerDidTapWebButton:(UIViewController *)viewController {
NSURL *url = [self deviceAuthenticationURL];
if(url) {
[[UIApplication sharedApplication] openURL:url];
}
}
- (BOOL) handleOpenURL:(NSURL *) url
sourceApplication:(NSString *) sourceApplication
annotation:(id) annotation {
- (BOOL)handleOpenURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation {
//check if this URL was meant for us, if not return NO so the user can
//handle it
NSString *const kAuthorizationHost = @"authorize";
NSString *urlScheme = self.urlScheme ? : [NSString stringWithFormat:@"ha%@", self.appIdentifier];
if(!([[url scheme] isEqualToString:urlScheme] && [[url host] isEqualToString:kAuthorizationHost])) {
NSString *urlScheme = self.urlScheme ?: [NSString stringWithFormat:@"ha%@", self.appIdentifier];
if (!([[url scheme] isEqualToString:urlScheme] && [[url host] isEqualToString:kAuthorizationHost])) {
BITHockeyLog(@"URL scheme for authentication doesn't match!");
return NO;
}
@@ -692,7 +700,7 @@ static unsigned char kBITPNGEndChunk[4] = {0x49, 0x45, 0x4e, 0x44};
case BITAuthenticatorIdentificationTypeWebAuth: {
NSString *email = nil;
[self.class email:&email andIUID:&installationIdentifier fromOpenURL:url];
if(email) {
if (email) {
BOOL success = [self addStringValueToKeychain:email forKey:kBITAuthenticatorUserEmailKey];
if (!success) {
[self alertOnFailureStoringTokenInKeychain];
@@ -714,14 +722,14 @@ static unsigned char kBITPNGEndChunk[4] = {0x49, 0x45, 0x4e, 0x44};
return NO;
}
if(installationIdentifier){
if (installationIdentifier) {
BITHockeyLog(@"Authentication succeeded.");
if(NO == self.restrictApplicationUsage) {
if (NO == self.restrictApplicationUsage) {
[self dismissAuthenticationControllerAnimated:YES completion:nil];
}
[self storeInstallationIdentifier:installationIdentifier withType:self.identificationType];
self.identified = YES;
if(self.identificationCompletion) {
if (self.identificationCompletion) {
self.identificationCompletion(YES, nil);
self.identificationCompletion = nil;
}
@@ -730,10 +738,10 @@ static unsigned char kBITPNGEndChunk[4] = {0x49, 0x45, 0x4e, 0x44};
BITHockeyLog(@"Resetting authentication token");
[self storeInstallationIdentifier:nil withType:self.identificationType];
self.identified = NO;
if(self.identificationCompletion) {
if (self.identificationCompletion) {
NSError *error = [NSError errorWithDomain:kBITAuthenticatorErrorDomain
code:BITAuthenticatorErrorUnknown
userInfo:@{NSLocalizedDescriptionKey : localizedErrorDescription}];
userInfo:@{NSLocalizedDescriptionKey:localizedErrorDescription}];
self.identificationCompletion(NO, error);
self.identificationCompletion = nil;
}
@@ -741,14 +749,14 @@ static unsigned char kBITPNGEndChunk[4] = {0x49, 0x45, 0x4e, 0x44};
return YES;
}
+ (NSString *) UDIDFromOpenURL:(NSURL *) url annotation:(id) annotation {
+ (NSString *)UDIDFromOpenURL:(NSURL *)url annotation:(id)annotation {
NSString *query = [url query];
NSString *udid = nil;
//there should actually only one
static NSString * const UDIDQuerySpecifier = @"udid";
for(NSString *queryComponents in [query componentsSeparatedByString:@"&"]) {
static NSString *const UDIDQuerySpecifier = @"udid";
for (NSString *queryComponents in [query componentsSeparatedByString:@"&"]) {
NSArray *parameterComponents = [queryComponents componentsSeparatedByString:@"="];
if(2 == parameterComponents.count && [parameterComponents[0] isEqualToString:UDIDQuerySpecifier]) {
if (2 == parameterComponents.count && [parameterComponents[0] isEqualToString:UDIDQuerySpecifier]) {
udid = parameterComponents[1];
break;
}
@@ -756,16 +764,16 @@ static unsigned char kBITPNGEndChunk[4] = {0x49, 0x45, 0x4e, 0x44};
return udid;
}
+ (void) email:(NSString**) email andIUID:(NSString**) iuid fromOpenURL:(NSURL *) url {
+ (void)email:(NSString **)email andIUID:(NSString **)iuid fromOpenURL:(NSURL *)url {
NSString *query = [url query];
//there should actually only one
static NSString * const EmailQuerySpecifier = @"email";
static NSString * const IUIDQuerySpecifier = @"iuid";
for(NSString *queryComponents in [query componentsSeparatedByString:@"&"]) {
static NSString *const EmailQuerySpecifier = @"email";
static NSString *const IUIDQuerySpecifier = @"iuid";
for (NSString *queryComponents in [query componentsSeparatedByString:@"&"]) {
NSArray *parameterComponents = [queryComponents componentsSeparatedByString:@"="];
if(email && 2 == parameterComponents.count && [parameterComponents[0] isEqualToString:EmailQuerySpecifier]) {
if (email && 2 == parameterComponents.count && [parameterComponents[0] isEqualToString:EmailQuerySpecifier]) {
*email = parameterComponents[1];
} else if(iuid && 2 == parameterComponents.count && [parameterComponents[0] isEqualToString:IUIDQuerySpecifier]) {
} else if (iuid && 2 == parameterComponents.count && [parameterComponents[0] isEqualToString:IUIDQuerySpecifier]) {
*iuid = parameterComponents[1];
}
}
@@ -773,7 +781,15 @@ static unsigned char kBITPNGEndChunk[4] = {0x49, 0x45, 0x4e, 0x44};
#pragma mark - Private helpers
- (void) cleanupInternalStorage {
- (void)alertOnFailureStoringTokenInKeychain {
if ([[UIApplication sharedApplication] applicationState] != UIApplicationStateActive) {
return;
}
NSLog(@"[HockeySDK] ERROR: The authentication token could not be stored due to a keychain error. This is most likely a signing or keychain entitlement issue!");
}
- (void)cleanupInternalStorage {
[self removeKeyFromKeychain:kBITAuthenticatorIdentifierTypeKey];
[self removeKeyFromKeychain:kBITAuthenticatorIdentifierKey];
[self removeKeyFromKeychain:kBITAuthenticatorUUIDKey];
@@ -789,7 +805,7 @@ static unsigned char kBITPNGEndChunk[4] = {0x49, 0x45, 0x4e, 0x44};
#ifdef BIT_INTERNAL_DEBUG
NSString* path = [[NSBundle mainBundle] pathForResource:@"iTunesArtwork" ofType:@"png"];
#else
NSString* path = [[[NSBundle mainBundle] bundlePath] stringByAppendingString:@"/../iTunesArtwork"];
NSString *path = [[[NSBundle mainBundle] bundlePath] stringByAppendingString:@"/../iTunesArtwork"];
#endif
struct stat fs;
@@ -851,7 +867,7 @@ static unsigned char kBITPNGEndChunk[4] = {0x49, 0x45, 0x4e, 0x44};
}
}
if (!memcmp(name, kBITPNGEndChunk, 4)){
if (!memcmp(name, kBITPNGEndChunk, 4)) {
chunk_index = 128;
}
}
@@ -872,43 +888,45 @@ static unsigned char kBITPNGEndChunk[4] = {0x49, 0x45, 0x4e, 0x44};
}
}
#pragma mark - KVO
- (void) registerObservers {
#pragma mark - NSNotification
- (void)registerObservers {
__weak typeof(self) weakSelf = self;
if(nil == self.appDidBecomeActiveObserver) {
if (nil == self.appDidBecomeActiveObserver) {
self.appDidBecomeActiveObserver = [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidBecomeActiveNotification
object:nil
queue:NSOperationQueue.mainQueue
usingBlock:^(NSNotification *note) {
typeof(self) strongSelf = weakSelf;
[strongSelf applicationDidBecomeActive:note];
}];
object:nil
queue:NSOperationQueue.mainQueue
usingBlock:^(NSNotification *note) {
typeof(self) strongSelf = weakSelf;
[strongSelf applicationDidBecomeActive:note];
}];
}
if(nil == self.appDidEnterBackgroundObserver) {
if (nil == self.appDidEnterBackgroundObserver) {
self.appDidEnterBackgroundObserver = [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidEnterBackgroundNotification
object:nil
queue:NSOperationQueue.mainQueue
usingBlock:^(NSNotification *note) {
typeof(self) strongSelf = weakSelf;
[strongSelf applicationDidEnterBackground:note];
}];
object:nil
queue:NSOperationQueue.mainQueue
usingBlock:^(NSNotification *note) {
typeof(self) strongSelf = weakSelf;
[strongSelf applicationDidEnterBackground:note];
}];
}
}
- (void) unregisterObservers {
if(self.appDidBecomeActiveObserver) {
- (void)unregisterObservers {
if (self.appDidBecomeActiveObserver) {
[[NSNotificationCenter defaultCenter] removeObserver:self.appDidBecomeActiveObserver];
self.appDidBecomeActiveObserver = nil;
}
if(self.appDidEnterBackgroundObserver) {
if (self.appDidEnterBackgroundObserver) {
[[NSNotificationCenter defaultCenter] removeObserver:self.appDidEnterBackgroundObserver];
self.appDidEnterBackgroundObserver = nil;
}
}
#pragma mark - Property overrides
- (void)storeInstallationIdentifier:(NSString *)installationIdentifier withType:(BITAuthenticatorIdentificationType) type {
if(nil == installationIdentifier) {
- (void)storeInstallationIdentifier:(NSString *)installationIdentifier withType:(BITAuthenticatorIdentificationType)type {
if (nil == installationIdentifier) {
[self removeKeyFromKeychain:kBITAuthenticatorIdentifierKey];
[self removeKeyFromKeychain:kBITAuthenticatorIdentifierTypeKey];
} else {
@@ -924,14 +942,14 @@ static unsigned char kBITPNGEndChunk[4] = {0x49, 0x45, 0x4e, 0x44};
}
}
- (NSString*) installationIdentifier {
- (NSString *)installationIdentifier {
NSString *identifier = [self stringValueFromKeychainForKey:kBITAuthenticatorIdentifierKey];
return identifier;
}
- (void)setLastAuthenticatedVersion:(NSString *)lastAuthenticatedVersion {
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
if(nil == lastAuthenticatedVersion){
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if (nil == lastAuthenticatedVersion) {
[defaults removeObjectForKey:kBITAuthenticatorLastAuthenticatedVersionKey];
} else {
[defaults setObject:lastAuthenticatedVersion
@@ -945,28 +963,36 @@ static unsigned char kBITPNGEndChunk[4] = {0x49, 0x45, 0x4e, 0x44};
}
- (NSString *)installationIdentifierParameterString {
switch(self.identificationType) {
switch (self.identificationType) {
case BITAuthenticatorIdentificationTypeHockeyAppEmail:
case BITAuthenticatorIdentificationTypeWebAuth:
return @"iuid";
case BITAuthenticatorIdentificationTypeHockeyAppUser: return @"auid";
case BITAuthenticatorIdentificationTypeDevice: return @"udid";
case BITAuthenticatorIdentificationTypeAnonymous: return @"uuid";
case BITAuthenticatorIdentificationTypeHockeyAppUser:
return @"auid";
case BITAuthenticatorIdentificationTypeDevice:
return @"udid";
case BITAuthenticatorIdentificationTypeAnonymous:
return @"uuid";
}
}
+ (NSString *)stringForIdentificationType:(BITAuthenticatorIdentificationType) identificationType {
switch(identificationType) {
case BITAuthenticatorIdentificationTypeHockeyAppEmail: return @"iuid";
case BITAuthenticatorIdentificationTypeWebAuth: return @"webAuth";
case BITAuthenticatorIdentificationTypeHockeyAppUser: return @"auid";
case BITAuthenticatorIdentificationTypeDevice: return @"udid";
case BITAuthenticatorIdentificationTypeAnonymous: return @"uuid";
+ (NSString *)stringForIdentificationType:(BITAuthenticatorIdentificationType)identificationType {
switch (identificationType) {
case BITAuthenticatorIdentificationTypeHockeyAppEmail:
return @"iuid";
case BITAuthenticatorIdentificationTypeWebAuth:
return @"webAuth";
case BITAuthenticatorIdentificationTypeHockeyAppUser:
return @"auid";
case BITAuthenticatorIdentificationTypeDevice:
return @"udid";
case BITAuthenticatorIdentificationTypeAnonymous:
return @"uuid";
}
}
- (void)setIdentificationType:(BITAuthenticatorIdentificationType)identificationType {
if(_identificationType != identificationType) {
if (_identificationType != identificationType) {
_identificationType = identificationType;
self.identified = NO;
self.validated = NO;
@@ -986,12 +1012,13 @@ static unsigned char kBITPNGEndChunk[4] = {0x49, 0x45, 0x4e, 0x44};
}
#pragma mark - Application Lifecycle
- (void)applicationDidBecomeActive:(NSNotification *)note {
[self authenticate];
}
- (void)applicationDidEnterBackground:(NSNotification *)note {
if(BITAuthenticatorAppRestrictionEnforcementOnAppActive == self.restrictionEnforcementFrequency) {
if (BITAuthenticatorAppRestrictionEnforcementOnAppActive == self.restrictionEnforcementFrequency) {
self.validated = NO;
}
}