mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-08-07 08:01:10 +00:00
redo BITAuthenticator interface
given the good feedback we got, this is take 2 of the BITAuthenticator interface. It's simplified, cleaned up and now allows full control over the authentication process. Major changes: * manual mode Authenticator provides the bits to show the viewController to identify the user as well as to trigger validation on behalf of the developer. * process separation identification and app-usage-restriction are now 2 completely separated things. * public identifier Authenticator now allows the developer to query parts of the information, e.g. the UDID or the user's emailaddy once identified
This commit is contained in:
parent
5ac00ff174
commit
c2c6558687
@ -54,14 +54,12 @@
|
|||||||
*/
|
*/
|
||||||
@property (nonatomic, assign) BOOL requirePassword;
|
@property (nonatomic, assign) BOOL requirePassword;
|
||||||
|
|
||||||
/** configure if user can skip authentication or not
|
|
||||||
*
|
|
||||||
* defaults to YES
|
|
||||||
*/
|
|
||||||
@property (nonatomic, assign) BOOL showsSkipButton;
|
|
||||||
|
|
||||||
@property (nonatomic, weak) id<BITAuthenticationViewControllerDelegate> delegate;
|
@property (nonatomic, weak) id<BITAuthenticationViewControllerDelegate> delegate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* allows to pre-fill the email-addy
|
||||||
|
*/
|
||||||
|
@property (nonatomic, copy) NSString* email;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -69,13 +67,6 @@
|
|||||||
*/
|
*/
|
||||||
@protocol BITAuthenticationViewControllerDelegate<NSObject>
|
@protocol BITAuthenticationViewControllerDelegate<NSObject>
|
||||||
|
|
||||||
/**
|
|
||||||
* called then the user skipped the auth-dialgo
|
|
||||||
*
|
|
||||||
* @param viewController the delegating viewcontroller
|
|
||||||
*/
|
|
||||||
- (void) authenticationViewControllerDidSkip:(UIViewController*) viewController;
|
|
||||||
|
|
||||||
- (void) authenticationViewControllerDidTapWebButton:(UIViewController*) viewController;
|
- (void) authenticationViewControllerDidTapWebButton:(UIViewController*) viewController;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -34,9 +34,9 @@
|
|||||||
|
|
||||||
@interface BITAuthenticationViewController ()<UITextFieldDelegate> {
|
@interface BITAuthenticationViewController ()<UITextFieldDelegate> {
|
||||||
UIStatusBarStyle _statusBarStyle;
|
UIStatusBarStyle _statusBarStyle;
|
||||||
|
__weak UITextField *_emailField;
|
||||||
}
|
}
|
||||||
|
|
||||||
@property (nonatomic, copy) NSString *email;
|
|
||||||
@property (nonatomic, copy) NSString *password;
|
@property (nonatomic, copy) NSString *password;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@ -48,7 +48,6 @@
|
|||||||
if (self) {
|
if (self) {
|
||||||
self.title = BITHockeyLocalizedString(@"HockeyAuthenticatorViewControllerTitle");
|
self.title = BITHockeyLocalizedString(@"HockeyAuthenticatorViewControllerTitle");
|
||||||
_delegate = delegate;
|
_delegate = delegate;
|
||||||
_showsSkipButton = YES;
|
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
@ -85,22 +84,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - Property overrides
|
#pragma mark - Property overrides
|
||||||
- (void)setShowsSkipButton:(BOOL)showsSkipButton {
|
|
||||||
if(_showsSkipButton != showsSkipButton) {
|
|
||||||
_showsSkipButton = showsSkipButton;
|
|
||||||
[self updateBarButtons];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) updateBarButtons {
|
- (void) updateBarButtons {
|
||||||
if(self.showsSkipButton) {
|
|
||||||
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:BITHockeyLocalizedString(@"Skip")
|
|
||||||
style:UIBarButtonItemStyleBordered
|
|
||||||
target:self
|
|
||||||
action:@selector(dismissAction:)];
|
|
||||||
} else {
|
|
||||||
self.navigationItem.leftBarButtonItem = nil;
|
|
||||||
}
|
|
||||||
if(self.showsLoginViaWebButton) {
|
if(self.showsLoginViaWebButton) {
|
||||||
self.navigationItem.rightBarButtonItem = nil;
|
self.navigationItem.rightBarButtonItem = nil;
|
||||||
} else {
|
} else {
|
||||||
@ -149,6 +134,13 @@
|
|||||||
- (IBAction) handleWebLoginButton:(id)sender {
|
- (IBAction) handleWebLoginButton:(id)sender {
|
||||||
[self.delegate authenticationViewControllerDidTapWebButton:self];
|
[self.delegate authenticationViewControllerDidTapWebButton:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)setEmail:(NSString *)email {
|
||||||
|
_email = email;
|
||||||
|
if(self.isViewLoaded) {
|
||||||
|
_emailField.text = email;
|
||||||
|
}
|
||||||
|
}
|
||||||
#pragma mark - UIViewController Rotation
|
#pragma mark - UIViewController Rotation
|
||||||
|
|
||||||
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orientation {
|
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orientation {
|
||||||
@ -222,6 +214,7 @@
|
|||||||
if (0 == [indexPath row]) {
|
if (0 == [indexPath row]) {
|
||||||
textField.placeholder = BITHockeyLocalizedString(@"HockeyAuthenticationViewControllerEmailPlaceholder");
|
textField.placeholder = BITHockeyLocalizedString(@"HockeyAuthenticationViewControllerEmailPlaceholder");
|
||||||
textField.text = self.email;
|
textField.text = self.email;
|
||||||
|
_emailField = textField;
|
||||||
|
|
||||||
textField.keyboardType = UIKeyboardTypeEmailAddress;
|
textField.keyboardType = UIKeyboardTypeEmailAddress;
|
||||||
if ([self requirePassword])
|
if ([self requirePassword])
|
||||||
@ -296,10 +289,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - Actions
|
#pragma mark - Actions
|
||||||
- (void)dismissAction:(id)sender {
|
|
||||||
[self.delegate authenticationViewControllerDidSkip:self];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)saveAction:(id)sender {
|
- (void)saveAction:(id)sender {
|
||||||
[self setLoginUIEnabled:NO];
|
[self setLoginUIEnabled:NO];
|
||||||
|
|
||||||
|
@ -31,122 +31,83 @@
|
|||||||
#import "BITHockeyBaseManager.h"
|
#import "BITHockeyBaseManager.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Auth types
|
* Identification Types
|
||||||
*/
|
*/
|
||||||
typedef NS_ENUM(NSUInteger, BITAuthenticatorAuthType) {
|
typedef NS_ENUM(NSUInteger, BITAuthenticatorIdentificationType) {
|
||||||
|
/**
|
||||||
|
* Assigns this app an anonymous user id
|
||||||
|
*/
|
||||||
|
BITAuthenticatorIdentificationTypeAnonymous,
|
||||||
/**
|
/**
|
||||||
* Ask for the HockeyApp account email
|
* Ask for the HockeyApp account email
|
||||||
*/
|
*/
|
||||||
BITAuthenticatorAuthTypeEmail,
|
BITAuthenticatorIdentificationTypeHockeyAppEmail,
|
||||||
/**
|
/**
|
||||||
* Ask for the HockeyApp account email and password
|
* Ask for the HockeyApp account by email and password
|
||||||
*/
|
*/
|
||||||
BITAuthenticatorAuthTypeEmailAndPassword,
|
BITAuthenticatorIdentificationTypeHockeyAppUser,
|
||||||
/**
|
/**
|
||||||
* Request the device UDID
|
* Identifies the current device
|
||||||
*/
|
*/
|
||||||
BITAuthenticatorAuthTypeUDIDProvider
|
BITAuthenticatorIdentificationTypeDevice,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validation types
|
* BITAuthenticatorAppRestrictionEnforcementFrequency
|
||||||
|
* Specifies how often the Authenticator checks if the user is allowed to use
|
||||||
|
* use this app.
|
||||||
*/
|
*/
|
||||||
typedef NS_ENUM(NSUInteger, BITAuthenticatorValidationType) {
|
typedef NS_ENUM(NSUInteger, BITAuthenticatorAppRestrictionEnforcementFrequency) {
|
||||||
/**
|
/**
|
||||||
* Never validate if the user is allowed to run the app
|
* Check if the user is allowed to use the app the first time a version is started
|
||||||
*/
|
*/
|
||||||
BITAuthenticatorValidationTypeNever = 0,
|
BITAuthenticatorAppRestrictionEnforcementOnFirstLaunch,
|
||||||
/**
|
/**
|
||||||
* Optionally validate if the user is authorized; user can skip the process
|
* Check if the user is allowed to use the app everytime the app becomes active
|
||||||
*/
|
*/
|
||||||
BITAuthenticatorValidationTypeOptional,
|
BITAuthenticatorAppRestrictionEnforcementOnAppActive,
|
||||||
/**
|
|
||||||
* Check if the user is authenticated at the first time a new version is started
|
|
||||||
*/
|
|
||||||
BITAuthenticatorValidationTypeOnFirstLaunch,
|
|
||||||
/**
|
|
||||||
* Check if the user is authenticated everytime the app becomes active
|
|
||||||
*/
|
|
||||||
BITAuthenticatorValidationTypeOnAppActive,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef void(^tAuthenticationCompletion)(NSString* authenticationToken, NSError *error);
|
|
||||||
typedef void(^tValidationCompletion)(BOOL validated, NSError *error);
|
|
||||||
|
|
||||||
@protocol BITAuthenticatorDelegate;
|
@protocol BITAuthenticatorDelegate;
|
||||||
|
|
||||||
/**
|
|
||||||
* Authenticator module used to identify and optionally authenticate the current app user
|
|
||||||
*
|
|
||||||
* This is the HockeySDK module for handling authentication when using Ad-Hoc or Enterprise provisioning profiles.
|
|
||||||
* This module allows you to make sure the current app installation is done on an authorized device by choosing from
|
|
||||||
* various authentication and validation mechanisms which provide different levels of authentication.
|
|
||||||
*
|
|
||||||
* This does not provide DRM or copy protection in any form. Each authentication type and validation type provide
|
|
||||||
* a different level of user authorization. Validation is the process of checking against the HockeyApp server if
|
|
||||||
* the provided/existing authorization is still valid.
|
|
||||||
*
|
|
||||||
* This module automatically disables itself when running in an App Store build by default!
|
|
||||||
*
|
|
||||||
* Authentication is a 2 step process:
|
|
||||||
*
|
|
||||||
* 1. authenticate:
|
|
||||||
* a token is acquired depending on the `authenticationType`
|
|
||||||
* 2. validation:
|
|
||||||
* the acquired token from step 1 is validated depending the `validationType`
|
|
||||||
*
|
|
||||||
* There are currently 3 ways of authentication (`BITAuthenticatorAuthType`):
|
|
||||||
*
|
|
||||||
* 1. authenticate the user via email only (`BITAuthenticatorAuthTypeEmail`)
|
|
||||||
* 2. authenticate the user via email & password (`BITAuthenticatorAuthTypeEmailAndPassword`)
|
|
||||||
* 3. authenticate the device via its UDID (_Default_) (`BITAuthenticatorAuthTypeUDIDProvider`)
|
|
||||||
*
|
|
||||||
* There are currently 4 ways of validation (`BITAuthenticatorValidationType`):
|
|
||||||
*
|
|
||||||
* 1. never (_Default_) (`BITAuthenticatorValidationTypeNever`)
|
|
||||||
* 2. optional (`BITAuthenticatorValidationTypeOptional`)
|
|
||||||
* 3. on first launch of a new app version (`BITAuthenticatorValidationTypeOnFirstLaunch`)
|
|
||||||
* 4. every time the app becomes active (needs internet connection) (`BITAuthenticatorValidationTypeOnAppActive`)
|
|
||||||
*
|
|
||||||
* We have created a detailed guide on how to use this class: [Authenticating Users on iOS](HowTo-Authenticating-Users-on-iOS)
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@interface BITAuthenticator : BITHockeyBaseManager
|
@interface BITAuthenticator : BITHockeyBaseManager
|
||||||
|
|
||||||
#pragma mark - Configuration
|
#pragma mark - Configuration
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines the authentication mechanism to be used
|
* Defines the identification mechanism to be used
|
||||||
*
|
*
|
||||||
* The values are listed here: `BITAuthenticatorAuthType`:
|
* _Default_: `BITAuthenticatorIdentificationTypeAnonymous`
|
||||||
*
|
*
|
||||||
* 1. `BITAuthenticatorAuthTypeEmail`: authenticate the user via email only
|
* @see BITAuthenticatorIdentificationType
|
||||||
* 2. `BITAuthenticatorAuthTypeEmailAndPassword`: authenticate the user via email & password
|
|
||||||
* 3. `BITAuthenticatorAuthTypeUDIDProvider`: authenticate the device via its UDID (_Default_)
|
|
||||||
*
|
|
||||||
* _Default_: `BITAuthenticatorAuthTypeUDIDProvider`
|
|
||||||
*
|
|
||||||
* @see BITAuthenticatorAuthType
|
|
||||||
*/
|
*/
|
||||||
@property (nonatomic, assign) BITAuthenticatorAuthType authenticationType;
|
@property (nonatomic, assign) BITAuthenticatorIdentificationType identificationType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines the validation mechanism to be used
|
* Defines if the BITAuthenticator automatically identifies the user and also
|
||||||
|
* checks if he's still allowed to use the app (depending on `restrictApplicationUsage`)
|
||||||
*
|
*
|
||||||
* The values are listed here: `BITAuthenticatorValidationType`:
|
* _Default_: `YES`
|
||||||
*
|
*
|
||||||
* 1. `BITAuthenticatorValidationTypeNever`: never (_Default_)
|
|
||||||
* 2. `BITAuthenticatorValidationTypeOptional`: optional
|
|
||||||
* 3. `BITAuthenticatorValidationTypeOnFirstLaunch`: on first launch of a new app version
|
|
||||||
* 4. `BITAuthenticatorValidationTypeOnAppActive`: every time the app becomes active (needs internet connection)
|
|
||||||
*
|
|
||||||
* _Default_: `BITAuthenticatorValidationTypeNever`
|
|
||||||
*
|
|
||||||
* @see BITAuthenticatorValidationType
|
|
||||||
*/
|
*/
|
||||||
@property (nonatomic, assign) BITAuthenticatorValidationType validationType;
|
@property (nonatomic, assign) BOOL automaticMode;
|
||||||
|
|
||||||
@property (nonatomic, weak) id<BITAuthenticatorDelegate> delegate;
|
/**
|
||||||
|
* Enables or disables checking if the user is allowed to run this app
|
||||||
|
*
|
||||||
|
* _Default_: `YES`
|
||||||
|
*/
|
||||||
|
@property (nonatomic, assign) BOOL restrictApplicationUsage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines how often the BITAuthenticator checks if the user is allowed
|
||||||
|
* to run this application
|
||||||
|
*
|
||||||
|
* _Default_: `BITAuthenticatorAppRestrictionEnforcementOnFirstLaunch`
|
||||||
|
*
|
||||||
|
* @see BITAuthenticatorAppRestrictionEnforcementFrequency
|
||||||
|
*/
|
||||||
|
@property (nonatomic, assign) BITAuthenticatorAppRestrictionEnforcementFrequency restrictionEnforcementFrequency;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The authentication secret from HockeyApp. To find the right secret, click on your app on the HockeyApp dashboard,
|
* The authentication secret from HockeyApp. To find the right secret, click on your app on the HockeyApp dashboard,
|
||||||
@ -156,8 +117,13 @@ typedef void(^tValidationCompletion)(BOOL validated, NSError *error);
|
|||||||
*/
|
*/
|
||||||
@property (nonatomic, copy) NSString *authenticationSecret;
|
@property (nonatomic, copy) NSString *authenticationSecret;
|
||||||
|
|
||||||
#pragma mark - UDID auth
|
/**
|
||||||
|
* Delegate that can be used to do any last minute configurations on the presented viewController.
|
||||||
|
*/
|
||||||
|
@property (nonatomic, weak) id<BITAuthenticatorDelegate> delegate;
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark - UDID auth
|
||||||
/**
|
/**
|
||||||
* baseURL of the webpage the user is redirected to if authenticationType is BITAuthenticatorAuthTypeUDIDProvider
|
* baseURL of the webpage the user is redirected to if authenticationType is BITAuthenticatorAuthTypeUDIDProvider
|
||||||
* defaults to https://rink.hockeyapp.net
|
* defaults to https://rink.hockeyapp.net
|
||||||
@ -193,6 +159,46 @@ typedef void(^tValidationCompletion)(BOOL validated, NSError *error);
|
|||||||
sourceApplication:(NSString *) sourceApplication
|
sourceApplication:(NSString *) sourceApplication
|
||||||
annotation:(id) annotation;
|
annotation:(id) annotation;
|
||||||
|
|
||||||
|
#pragma mark - Authentication
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Identifies the user according to the type specified in `identificationType`
|
||||||
|
* If the BITAuthenticator is in manual mode, it's your responsibility to call
|
||||||
|
* this method. Depending on the `identificationType`, this method
|
||||||
|
* might present a viewController to let the user enter his/her credentials.
|
||||||
|
* If the Authenticator is in auto-mode, this is called by the authenticator itself
|
||||||
|
* once needed.
|
||||||
|
*/
|
||||||
|
- (void) identifyWithCompletion:(void(^)(BOOL identified, NSError *error)) completion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns YES if this app is identified according to the setting in `identificationType`
|
||||||
|
*/
|
||||||
|
@property (nonatomic, assign, readonly, getter = isIdentified) BOOL identified;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates if the identified user is allowed to run this application. This checks
|
||||||
|
* with the HockeyApp backend and calls the completion-block once completed.
|
||||||
|
* If the BITAuthenticator is in manual mode, it's your responsibility to call
|
||||||
|
* this method. If the application is not yet identified, validation is not possible
|
||||||
|
* and the completion-block is called with an error set.
|
||||||
|
* If the Authenticator is in auto-mode, this is called by the authenticator itself
|
||||||
|
* once needed.
|
||||||
|
*/
|
||||||
|
- (void) validateWithCompletion:(void(^)(BOOL validated, NSError *error)) completion;
|
||||||
|
|
||||||
|
@property (nonatomic, assign, readonly, getter = isValidated) BOOL validated;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* removes all previously stored authentication tokens, UDIDs, etc
|
||||||
|
*/
|
||||||
|
- (void) cleanupInternalStorage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* can be used by the application to identify the user.
|
||||||
|
* returns different values depending on `identificationType`.
|
||||||
|
*/
|
||||||
|
- (NSString*) publicInstallationIdentifier;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
#pragma mark - Protocol
|
#pragma mark - Protocol
|
||||||
@ -204,13 +210,12 @@ typedef void(^tValidationCompletion)(BOOL validated, NSError *error);
|
|||||||
|
|
||||||
@optional
|
@optional
|
||||||
/**
|
/**
|
||||||
* If the authentication (or validation) needs to authenticate the user,
|
* If the authentication (or validation) needs to identify the user,
|
||||||
* this delegate method is called with the viewController that we'll present.
|
* this delegate method is called with the viewController that we'll present.
|
||||||
*
|
*
|
||||||
* @param authenticator authenticator object
|
* @param authenticator authenticator object
|
||||||
* @param viewController viewcontroller used to authenticate the user
|
* @param viewController viewcontroller used to identify the user
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
- (void) authenticator:(BITAuthenticator *)authenticator willShowAuthenticationController:(UIViewController*) viewController;
|
- (void) authenticator:(BITAuthenticator *)authenticator willShowAuthenticationController:(UIViewController*) viewController;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -35,10 +35,16 @@
|
|||||||
#import "BITHockeyAppClient.h"
|
#import "BITHockeyAppClient.h"
|
||||||
#import "BITHockeyHelper.h"
|
#import "BITHockeyHelper.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";
|
||||||
|
|
||||||
|
//deprecated
|
||||||
static NSString* const kBITAuthenticatorAuthTokenKey = @"BITAuthenticatorAuthTokenKey";
|
static NSString* const kBITAuthenticatorAuthTokenKey = @"BITAuthenticatorAuthTokenKey";
|
||||||
static NSString* const kBITAuthenticatorAuthTokenTypeKey = @"BITAuthenticatorAuthTokenTypeKey";
|
static NSString* const kBITAuthenticatorAuthTokenTypeKey = @"BITAuthenticatorAuthTokenTypeKey";
|
||||||
static NSString* const kBITAuthenticatorLastAuthenticatedVersionKey = @"BITAuthenticatorLastAuthenticatedVersionKey";
|
|
||||||
static NSString* const kBITAuthenticatorDidSkipOptionalLogin = @"BITAuthenticatorDidSkipOptionalLogin";
|
|
||||||
|
|
||||||
@implementation BITAuthenticator {
|
@implementation BITAuthenticator {
|
||||||
id _appDidBecomeActiveObserver;
|
id _appDidBecomeActiveObserver;
|
||||||
@ -55,8 +61,10 @@ static NSString* const kBITAuthenticatorDidSkipOptionalLogin = @"BITAuthenticato
|
|||||||
if( self ) {
|
if( self ) {
|
||||||
_webpageURL = [NSURL URLWithString:@"https://rink.hockeyapp.net/"];
|
_webpageURL = [NSURL URLWithString:@"https://rink.hockeyapp.net/"];
|
||||||
|
|
||||||
_authenticationType = BITAuthenticatorAuthTypeUDIDProvider;
|
_identificationType = BITAuthenticatorIdentificationTypeAnonymous;
|
||||||
_validationType = BITAuthenticatorValidationTypeNever;
|
_automaticMode = YES;
|
||||||
|
_restrictApplicationUsage = NO;
|
||||||
|
_restrictionEnforcementFrequency = BITAuthenticatorAppRestrictionEnforcementOnFirstLaunch;
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
@ -68,7 +76,7 @@ static NSString* const kBITAuthenticatorDidSkipOptionalLogin = @"BITAuthenticato
|
|||||||
|
|
||||||
switch ([[UIApplication sharedApplication] applicationState]) {
|
switch ([[UIApplication sharedApplication] applicationState]) {
|
||||||
case UIApplicationStateActive:
|
case UIApplicationStateActive:
|
||||||
[self triggerAuthentication];
|
[self authenticate];
|
||||||
break;
|
break;
|
||||||
case UIApplicationStateBackground:
|
case UIApplicationStateBackground:
|
||||||
case UIApplicationStateInactive:
|
case UIApplicationStateInactive:
|
||||||
@ -80,65 +88,162 @@ static NSString* const kBITAuthenticatorDidSkipOptionalLogin = @"BITAuthenticato
|
|||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark -
|
#pragma mark -
|
||||||
- (void) triggerAuthentication {
|
- (void) authenticate {
|
||||||
switch (self.validationType) {
|
//when running in manual mode, we don't actually do anything ourselves
|
||||||
case BITAuthenticatorValidationTypeOnAppActive:
|
if(!self.automaticMode) return;
|
||||||
[self validateInstallationWithCompletion:[self defaultValidationCompletionBlock]];
|
|
||||||
break;
|
|
||||||
case BITAuthenticatorValidationTypeOnFirstLaunch:
|
|
||||||
if(![self.lastAuthenticatedVersion isEqualToString:self.executableUUID]) {
|
|
||||||
self.installationIdentificationValidated = NO;
|
|
||||||
[self validateInstallationWithCompletion:[self defaultValidationCompletionBlock]];
|
|
||||||
} else {
|
|
||||||
self.installationIdentificationValidated = YES;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case BITAuthenticatorValidationTypeOptional:
|
|
||||||
if(NO == self.didSkipOptionalLogin) {
|
|
||||||
[self validateInstallationWithCompletion:[self defaultValidationCompletionBlock]];
|
|
||||||
} else {
|
|
||||||
self.installationIdentificationValidated = YES;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case BITAuthenticatorValidationTypeNever:
|
|
||||||
self.installationIdentificationValidated = YES;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark -
|
[self identifyWithCompletion:^(BOOL identified, NSError *error) {
|
||||||
- (NSString *)installationIdentification {
|
if(identified) {
|
||||||
NSString *authToken = self.authenticationToken;
|
if([self needsValidation]) {
|
||||||
if(authToken) {
|
[self validateWithCompletion:^(BOOL validated, NSError *error) {
|
||||||
return authToken;
|
if(validated) {
|
||||||
}
|
[_authenticationController dismissViewControllerAnimated:YES completion:nil];
|
||||||
return bit_appAnonID();
|
_authenticationController = nil;
|
||||||
}
|
|
||||||
|
|
||||||
- (NSString*) installationIdentificationType {
|
|
||||||
NSString *authToken = self.authenticationToken;
|
|
||||||
if(nil == authToken) {
|
|
||||||
return @"udid";
|
|
||||||
} else {
|
} else {
|
||||||
return [self authenticationTokenType];
|
[self storeInstallationIdentifier:nil withType:self.identificationType];
|
||||||
}
|
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:nil
|
||||||
}
|
message:error.localizedDescription
|
||||||
|
delegate:nil
|
||||||
#pragma mark - Validation
|
cancelButtonTitle:BITHockeyLocalizedString(@"HockeyOK")
|
||||||
- (void) validateInstallationWithCompletion:(tValidationCompletion) completion {
|
otherButtonTitles:nil];
|
||||||
if(nil == self.authenticationToken) {
|
[alertView show];
|
||||||
[self authenticateWithCompletion:^(NSString *authenticationToken, NSError *error) {
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
if(nil == authenticationToken) {
|
[self authenticate];
|
||||||
//if authentication fails, there's nothing to validate
|
});
|
||||||
NSError *error = [NSError errorWithDomain:kBITAuthenticatorErrorDomain
|
|
||||||
code:BITAuthenticatorNotAuthorized
|
|
||||||
userInfo:nil];
|
|
||||||
if(completion) completion(NO, error);
|
|
||||||
} else {
|
|
||||||
if(completion) completion(YES, nil);
|
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
} else {
|
} else {
|
||||||
|
[_authenticationController dismissViewControllerAnimated:YES completion:nil];
|
||||||
|
_authenticationController = nil;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
BITHockeyLog(@"Failed to identify. Error: %@", error);
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL) needsValidation {
|
||||||
|
if(BITAuthenticatorIdentificationTypeAnonymous == self.identificationType) {
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
if(NO == self.restrictApplicationUsage) {
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
if(YES == self.isValidated) {
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
if(self.restrictionEnforcementFrequency == BITAuthenticatorAppRestrictionEnforcementOnFirstLaunch &&
|
||||||
|
![self.executableUUID isEqualToString:self.lastAuthenticatedVersion]) {
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
if(self.restrictionEnforcementFrequency == BITAuthenticatorAppRestrictionEnforcementOnAppActive) {
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
- (void) identifyWithCompletion:(void (^)(BOOL identified, NSError *))completion {
|
||||||
|
if(_authenticationController) {
|
||||||
|
BITHockeyLog(@"Authentication controller already visible. Ingoring identify request");
|
||||||
|
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]) {
|
||||||
|
BITHockeyLog(@"Identification type mismatch for stored auth-token. Resetting.");
|
||||||
|
[self storeInstallationIdentifier:nil withType:BITAuthenticatorIdentificationTypeAnonymous];
|
||||||
|
}
|
||||||
|
|
||||||
|
NSString *identification = [self installationIdentifier];
|
||||||
|
|
||||||
|
if(identification) {
|
||||||
|
self.identified = YES;
|
||||||
|
if(completion) completion(YES, nil);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//it's not identified yet, do it now
|
||||||
|
BITAuthenticationViewController *viewController = nil;
|
||||||
|
switch (self.identificationType) {
|
||||||
|
case BITAuthenticatorIdentificationTypeAnonymous:
|
||||||
|
[self storeInstallationIdentifier:bit_UUID() withType:BITAuthenticatorIdentificationTypeAnonymous];
|
||||||
|
self.identified = YES;
|
||||||
|
if(completion) completion(YES, nil);
|
||||||
|
return;
|
||||||
|
break;
|
||||||
|
case BITAuthenticatorIdentificationTypeHockeyAppUser:
|
||||||
|
viewController = [[BITAuthenticationViewController alloc] initWithDelegate:self];
|
||||||
|
viewController.requirePassword = YES;
|
||||||
|
break;
|
||||||
|
case BITAuthenticatorIdentificationTypeDevice:
|
||||||
|
viewController = [[BITAuthenticationViewController alloc] initWithDelegate:self];
|
||||||
|
viewController.requirePassword = NO;
|
||||||
|
viewController.showsLoginViaWebButton = YES;
|
||||||
|
break;
|
||||||
|
case BITAuthenticatorIdentificationTypeHockeyAppEmail:
|
||||||
|
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);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
viewController = [[BITAuthenticationViewController alloc] initWithDelegate:self];
|
||||||
|
viewController.requirePassword = NO;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if([self.delegate respondsToSelector:@selector(authenticator:willShowAuthenticationController:)]) {
|
||||||
|
[self.delegate authenticator:self willShowAuthenticationController:viewController];
|
||||||
|
}
|
||||||
|
|
||||||
|
NSAssert(viewController, @"ViewController should've been created");
|
||||||
|
|
||||||
|
viewController.email = [self stringValueFromKeychainForKey:kBITAuthenticatorUserEmailKey];
|
||||||
|
_authenticationController = viewController;
|
||||||
|
_identificationCompletion = completion;
|
||||||
|
[self showView:viewController];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Validation
|
||||||
|
- (void) validateWithCompletion:(void (^)(BOOL validated, NSError *))completion {
|
||||||
|
BOOL requirementsFulfilled = YES;
|
||||||
|
NSError *error = nil;
|
||||||
|
switch(self.identificationType) {
|
||||||
|
case BITAuthenticatorIdentificationTypeAnonymous: {
|
||||||
|
error = [NSError errorWithDomain:kBITAuthenticatorErrorDomain
|
||||||
|
code:BITAuthenticatorErrorUnknown
|
||||||
|
userInfo:@{NSLocalizedDescriptionKey : @"Anonymous users can't be validated"}];
|
||||||
|
requirementsFulfilled = NO;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BITAuthenticatorIdentificationTypeHockeyAppEmail:
|
||||||
|
if(nil == self.authenticationSecret) {
|
||||||
|
error = [NSError errorWithDomain:kBITAuthenticatorErrorDomain
|
||||||
|
code:BITAuthenticatorAuthorizationSecretMissing
|
||||||
|
userInfo:@{NSLocalizedDescriptionKey : @"For email validation, the authentication secret must be set"}];
|
||||||
|
requirementsFulfilled = NO;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
//no break
|
||||||
|
case BITAuthenticatorIdentificationTypeDevice:
|
||||||
|
case BITAuthenticatorIdentificationTypeHockeyAppUser:
|
||||||
|
if(nil == self.installationIdentifier) {
|
||||||
|
error = [NSError errorWithDomain:kBITAuthenticatorErrorDomain
|
||||||
|
code:BITAuthenticatorNotIdentified
|
||||||
|
userInfo:@{NSLocalizedDescriptionKey : @"Make sure to identify the installation first"}];
|
||||||
|
requirementsFulfilled = NO;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(NO == requirementsFulfilled) {
|
||||||
|
if(completion) {
|
||||||
|
completion(NO, error);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
NSString *validationPath = [NSString stringWithFormat:@"api/3/apps/%@/identity/validate", self.encodedAppIdentifier];
|
NSString *validationPath = [NSString stringWithFormat:@"api/3/apps/%@/identity/validate", self.encodedAppIdentifier];
|
||||||
__weak typeof (self) weakSelf = self;
|
__weak typeof (self) weakSelf = self;
|
||||||
[self.hockeyAppClient getPath:validationPath
|
[self.hockeyAppClient getPath:validationPath
|
||||||
@ -153,24 +258,24 @@ static NSString* const kBITAuthenticatorDidSkipOptionalLogin = @"BITAuthenticato
|
|||||||
NSError *error = [NSError errorWithDomain:kBITAuthenticatorErrorDomain
|
NSError *error = [NSError errorWithDomain:kBITAuthenticatorErrorDomain
|
||||||
code:BITAuthenticatorNetworkError
|
code:BITAuthenticatorNetworkError
|
||||||
userInfo:userInfo];
|
userInfo:userInfo];
|
||||||
[strongSelf validationFailedWithError:error completion:completion];
|
self.validated = NO;
|
||||||
|
if(completion) completion(NO, error);
|
||||||
} else {
|
} else {
|
||||||
NSError *validationParseError = nil;
|
NSError *validationParseError = nil;
|
||||||
BOOL isValidated = [strongSelf.class isValidationResponseValid:responseData error:&validationParseError];
|
BOOL valid = [strongSelf.class isValidationResponseValid:responseData error:&validationParseError];
|
||||||
if(isValidated) {
|
strongSelf.validated = valid;
|
||||||
[strongSelf validationSucceededWithCompletion:completion];
|
if(valid) {
|
||||||
} else {
|
[self setLastAuthenticatedVersion:self.executableUUID];
|
||||||
[strongSelf validationFailedWithError:validationParseError completion:completion];
|
|
||||||
}
|
}
|
||||||
|
if(completion) completion(valid, validationParseError);
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSDictionary*) validationParameters {
|
- (NSDictionary*) validationParameters {
|
||||||
NSParameterAssert(self.authenticationToken);
|
NSParameterAssert(self.installationIdentifier);
|
||||||
NSParameterAssert(self.installationIdentificationType);
|
NSParameterAssert(self.installationIdentifierTypeString);
|
||||||
return @{self.installationIdentificationType : self.authenticationToken};
|
return @{self.installationIdentifierTypeString : self.installationIdentifier};
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (BOOL) isValidationResponseValid:(id) response error:(NSError **) error {
|
+ (BOOL) isValidationResponseValid:(id) response error:(NSError **) error {
|
||||||
@ -224,105 +329,13 @@ static NSString* const kBITAuthenticatorDidSkipOptionalLogin = @"BITAuthenticato
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - Authentication
|
|
||||||
|
|
||||||
- (void)authenticateWithCompletion:(tAuthenticationCompletion)completion {
|
|
||||||
if(_authenticationController) {
|
|
||||||
BITHockeyLog(@"Already authenticating. Ignoring request");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(_authenticationType == BITAuthenticatorAuthTypeEmail && (nil == _authenticationSecret || !_authenticationSecret.length)) {
|
|
||||||
if(completion) {
|
|
||||||
NSError *error = [NSError errorWithDomain:kBITAuthenticatorErrorDomain
|
|
||||||
code:BITAuthenticatorAuthorizationSecretMissing
|
|
||||||
userInfo:@{NSLocalizedDescriptionKey: @"HockeyAuthenticationAuthSecretMissing"}];
|
|
||||||
completion(nil, error);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
BITAuthenticationViewController *viewController = [[BITAuthenticationViewController alloc] initWithDelegate:self];
|
|
||||||
switch (self.authenticationType) {
|
|
||||||
case BITAuthenticatorAuthTypeEmailAndPassword:
|
|
||||||
viewController.requirePassword = YES;
|
|
||||||
break;
|
|
||||||
case BITAuthenticatorAuthTypeEmail:
|
|
||||||
viewController.requirePassword = NO;
|
|
||||||
break;
|
|
||||||
case BITAuthenticatorAuthTypeUDIDProvider:
|
|
||||||
viewController.requirePassword = NO;
|
|
||||||
viewController.showsLoginViaWebButton = YES;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (self.validationType) {
|
|
||||||
case BITAuthenticatorValidationTypeNever:
|
|
||||||
case BITAuthenticatorValidationTypeOptional:
|
|
||||||
viewController.showsSkipButton = YES;
|
|
||||||
break;
|
|
||||||
case BITAuthenticatorValidationTypeOnAppActive:
|
|
||||||
case BITAuthenticatorValidationTypeOnFirstLaunch:
|
|
||||||
viewController.showsSkipButton = NO;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if([self.delegate respondsToSelector:@selector(authenticator:willShowAuthenticationController:)]) {
|
|
||||||
[self.delegate authenticator:self willShowAuthenticationController:viewController];
|
|
||||||
}
|
|
||||||
|
|
||||||
_authenticationController = viewController;
|
|
||||||
_authenticationCompletionBlock = completion;
|
|
||||||
[self showView:viewController];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) didAuthenticateWithToken:(NSString*) token {
|
|
||||||
[_authenticationController dismissViewControllerAnimated:YES completion:nil];
|
|
||||||
_authenticationController = nil;
|
|
||||||
[self setAuthenticationToken:token withType:[self.class stringForAuthenticationType:self.authenticationType]];
|
|
||||||
self.installationIdentificationValidated = YES;
|
|
||||||
self.lastAuthenticatedVersion = [self executableUUID];
|
|
||||||
if(self.authenticationCompletionBlock) {
|
|
||||||
self.authenticationCompletionBlock(self.authenticationToken, nil);
|
|
||||||
self.authenticationCompletionBlock = nil;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (NSString*) stringForAuthenticationType:(BITAuthenticatorAuthType) authType {
|
|
||||||
switch (authType) {
|
|
||||||
case BITAuthenticatorAuthTypeEmail: return @"iuid";
|
|
||||||
case BITAuthenticatorAuthTypeEmailAndPassword: return @"auid";
|
|
||||||
case BITAuthenticatorAuthTypeUDIDProvider:
|
|
||||||
//fallthrough
|
|
||||||
default:
|
|
||||||
return @"udid";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#pragma mark - AuthenticationViewControllerDelegate
|
#pragma mark - AuthenticationViewControllerDelegate
|
||||||
- (void) authenticationViewControllerDidSkip:(UIViewController *)viewController {
|
|
||||||
[viewController dismissViewControllerAnimated:YES completion:nil];
|
|
||||||
|
|
||||||
_authenticationController = nil;
|
|
||||||
[self setAuthenticationToken:nil withType:nil];
|
|
||||||
if(self.validationType == BITAuthenticatorValidationTypeOptional) {
|
|
||||||
self.didSkipOptionalLogin = YES;
|
|
||||||
self.installationIdentificationValidated = YES;
|
|
||||||
}
|
|
||||||
NSError *error = [NSError errorWithDomain:kBITAuthenticatorErrorDomain
|
|
||||||
code:BITAuthenticatorAuthenticationCancelled
|
|
||||||
userInfo:nil];
|
|
||||||
if(self.authenticationCompletionBlock) {
|
|
||||||
self.authenticationCompletionBlock(self.authenticationToken, error);
|
|
||||||
self.authenticationCompletionBlock = nil;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)authenticationViewController:(UIViewController *)viewController
|
- (void)authenticationViewController:(UIViewController *)viewController
|
||||||
handleAuthenticationWithEmail:(NSString *)email
|
handleAuthenticationWithEmail:(NSString *)email
|
||||||
password:(NSString *)password
|
password:(NSString *)password
|
||||||
completion:(void (^)(BOOL, NSError *))completion {
|
completion:(void (^)(BOOL, NSError *))completion {
|
||||||
NSParameterAssert(email && email.length);
|
NSParameterAssert(email && email.length);
|
||||||
NSParameterAssert(self.authenticationType == BITAuthenticatorAuthTypeEmail || (password && password.length));
|
NSParameterAssert(self.identificationType == BITAuthenticatorIdentificationTypeHockeyAppEmail || (password && password.length));
|
||||||
NSURLRequest* request = [self requestForAuthenticationEmail:email password:password];
|
NSURLRequest* request = [self requestForAuthenticationEmail:email password:password];
|
||||||
__weak typeof (self) weakSelf = self;
|
__weak typeof (self) weakSelf = self;
|
||||||
BITHTTPOperation *operation = [self.hockeyAppClient operationWithURLRequest:request
|
BITHTTPOperation *operation = [self.hockeyAppClient operationWithURLRequest:request
|
||||||
@ -332,12 +345,23 @@ static NSString* const kBITAuthenticatorDidSkipOptionalLogin = @"BITAuthenticato
|
|||||||
NSString *authToken = [strongSelf.class authenticationTokenFromURLResponse:operation.response
|
NSString *authToken = [strongSelf.class authenticationTokenFromURLResponse:operation.response
|
||||||
data:responseData
|
data:responseData
|
||||||
error:&authParseError];
|
error:&authParseError];
|
||||||
if(nil == authToken) {
|
BOOL identified;
|
||||||
completion(NO, authParseError);
|
if(authToken) {
|
||||||
|
identified = YES;
|
||||||
|
[strongSelf storeInstallationIdentifier:authToken withType:strongSelf.identificationType];
|
||||||
|
[strongSelf->_authenticationController dismissViewControllerAnimated:YES
|
||||||
|
completion:nil];
|
||||||
|
strongSelf->_authenticationController = nil;
|
||||||
|
[self addStringValueToKeychain:email forKey:kBITAuthenticatorUserEmailKey];
|
||||||
} else {
|
} else {
|
||||||
//no need to call completion, we're dismissing it anyways
|
identified = NO;
|
||||||
[self didAuthenticateWithToken:authToken];
|
}
|
||||||
}}];
|
self.identified = identified;
|
||||||
|
completion(identified, authParseError);
|
||||||
|
if(strongSelf.identificationCompletion) strongSelf.identificationCompletion(identified, authParseError);
|
||||||
|
strongSelf.identificationCompletion = nil;
|
||||||
|
|
||||||
|
}];
|
||||||
[self.hockeyAppClient enqeueHTTPOperation:operation];
|
[self.hockeyAppClient enqeueHTTPOperation:operation];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -345,7 +369,7 @@ static NSString* const kBITAuthenticatorDidSkipOptionalLogin = @"BITAuthenticato
|
|||||||
NSString *authenticationPath = [self authenticationPath];
|
NSString *authenticationPath = [self authenticationPath];
|
||||||
NSDictionary *params = nil;
|
NSDictionary *params = nil;
|
||||||
|
|
||||||
if(BITAuthenticatorAuthTypeEmail == self.authenticationType) {
|
if(BITAuthenticatorIdentificationTypeHockeyAppEmail == self.identificationType) {
|
||||||
NSString *authCode = BITHockeyMD5([NSString stringWithFormat:@"%@%@",
|
NSString *authCode = BITHockeyMD5([NSString stringWithFormat:@"%@%@",
|
||||||
self.authenticationSecret ? : @"",
|
self.authenticationSecret ? : @"",
|
||||||
email ? : @""]);
|
email ? : @""]);
|
||||||
@ -358,7 +382,7 @@ static NSString* const kBITAuthenticatorDidSkipOptionalLogin = @"BITAuthenticato
|
|||||||
NSMutableURLRequest *request = [self.hockeyAppClient requestWithMethod:@"POST"
|
NSMutableURLRequest *request = [self.hockeyAppClient requestWithMethod:@"POST"
|
||||||
path:authenticationPath
|
path:authenticationPath
|
||||||
parameters:params];
|
parameters:params];
|
||||||
if(BITAuthenticatorAuthTypeEmailAndPassword == self.authenticationType) {
|
if(BITAuthenticatorIdentificationTypeHockeyAppUser == self.identificationType) {
|
||||||
NSString *authStr = [NSString stringWithFormat:@"%@:%@", email, password];
|
NSString *authStr = [NSString stringWithFormat:@"%@:%@", email, password];
|
||||||
NSData *authData = [authStr dataUsingEncoding:NSASCIIStringEncoding];
|
NSData *authData = [authStr dataUsingEncoding:NSASCIIStringEncoding];
|
||||||
NSString *authValue = [NSString stringWithFormat:@"Basic %@", bit_base64String(authData, authData.length)];
|
NSString *authValue = [NSString stringWithFormat:@"Basic %@", bit_base64String(authData, authData.length)];
|
||||||
@ -368,14 +392,13 @@ static NSString* const kBITAuthenticatorDidSkipOptionalLogin = @"BITAuthenticato
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (NSString *) authenticationPath {
|
- (NSString *) authenticationPath {
|
||||||
if(BITAuthenticatorAuthTypeEmailAndPassword == self.authenticationType) {
|
if(BITAuthenticatorIdentificationTypeHockeyAppUser == self.identificationType) {
|
||||||
return [NSString stringWithFormat:@"api/3/apps/%@/identity/authorize", self.encodedAppIdentifier];
|
return [NSString stringWithFormat:@"api/3/apps/%@/identity/authorize", self.encodedAppIdentifier];
|
||||||
} else {
|
} else {
|
||||||
return [NSString stringWithFormat:@"api/3/apps/%@/identity/check", self.encodedAppIdentifier];
|
return [NSString stringWithFormat:@"api/3/apps/%@/identity/check", self.encodedAppIdentifier];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
+ (NSString *) authenticationTokenFromURLResponse:(NSHTTPURLResponse*) urlResponse data:(NSData*) data error:(NSError **) error {
|
+ (NSString *) authenticationTokenFromURLResponse:(NSHTTPURLResponse*) urlResponse data:(NSData*) data error:(NSError **) error {
|
||||||
NSParameterAssert(urlResponse);
|
NSParameterAssert(urlResponse);
|
||||||
if(nil == urlResponse) {
|
if(nil == urlResponse) {
|
||||||
@ -412,7 +435,7 @@ static NSString* const kBITAuthenticatorDidSkipOptionalLogin = @"BITAuthenticato
|
|||||||
}
|
}
|
||||||
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
|
//make sure we have an error created if user wanted to have one
|
||||||
NSParameterAssert(0 == error || *error);
|
NSParameterAssert(nil == error || *error);
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -475,18 +498,27 @@ static NSString* const kBITAuthenticatorDidSkipOptionalLogin = @"BITAuthenticato
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(udid){
|
if(udid){
|
||||||
[self setAuthenticationToken:udid withType:[self.class stringForAuthenticationType:BITAuthenticatorAuthTypeUDIDProvider]];
|
if(NO == self.restrictApplicationUsage) {
|
||||||
[self validateInstallationWithCompletion:^(BOOL validated, NSError *error) {
|
|
||||||
if(validated) {
|
|
||||||
[_authenticationController dismissViewControllerAnimated:YES completion:nil];
|
[_authenticationController dismissViewControllerAnimated:YES completion:nil];
|
||||||
_authenticationController = nil;
|
_authenticationController = nil;
|
||||||
} else {
|
|
||||||
//TODO: show why validation failed
|
|
||||||
}
|
}
|
||||||
}];
|
[self storeInstallationIdentifier:udid withType:BITAuthenticatorIdentificationTypeDevice];
|
||||||
|
self.identified = YES;
|
||||||
|
if(self.identificationCompletion) {
|
||||||
|
self.identificationCompletion(YES, nil);
|
||||||
|
self.identificationCompletion = nil;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
//reset auth-token
|
//reset token
|
||||||
[self setAuthenticationToken:nil withType:nil];
|
[self storeInstallationIdentifier:nil withType:BITAuthenticatorIdentificationTypeDevice];
|
||||||
|
self.identified = NO;
|
||||||
|
if(self.identificationCompletion) {
|
||||||
|
NSError *error = [NSError errorWithDomain:kBITAuthenticatorErrorDomain
|
||||||
|
code:BITAuthenticatorErrorUnknown
|
||||||
|
userInfo:@{NSLocalizedDescriptionKey : @"Failed to retrieve UDID from URL"}];
|
||||||
|
self.identificationCompletion(NO, error);
|
||||||
|
self.identificationCompletion = nil;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
@ -517,32 +549,20 @@ static NSString* const kBITAuthenticatorDidSkipOptionalLogin = @"BITAuthenticato
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - Validation Pseudo-Delegate
|
|
||||||
- (void)validationFailedWithError:(NSError *)validationError completion:(tValidationCompletion) completion{
|
|
||||||
if(completion) {
|
|
||||||
completion(NO, validationError);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)validationSucceededWithCompletion:(tValidationCompletion) completion {
|
|
||||||
self.installationIdentificationValidated = YES;
|
|
||||||
if(completion) {
|
|
||||||
completion(YES, nil);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - Private helpers
|
#pragma mark - Private helpers
|
||||||
- (UIDevice *)currentDevice {
|
|
||||||
return _currentDevice ? : [UIDevice currentDevice];;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) cleanupInternalStorage {
|
- (void) cleanupInternalStorage {
|
||||||
|
[self removeKeyFromKeychain:kBITAuthenticatorIdentifierTypeKey];
|
||||||
|
[self removeKeyFromKeychain:kBITAuthenticatorIdentifierKey];
|
||||||
|
[self removeKeyFromKeychain:kBITAuthenticatorUUIDKey];
|
||||||
|
[self removeKeyFromKeychain:kBITAuthenticatorUserEmailKey];
|
||||||
|
[self setLastAuthenticatedVersion:nil];
|
||||||
|
|
||||||
|
//cleanup values stored from 3.5 Beta1..Beta3
|
||||||
[self removeKeyFromKeychain:kBITAuthenticatorAuthTokenKey];
|
[self removeKeyFromKeychain:kBITAuthenticatorAuthTokenKey];
|
||||||
[self removeKeyFromKeychain:kBITAuthenticatorAuthTokenTypeKey];
|
[self removeKeyFromKeychain:kBITAuthenticatorAuthTokenTypeKey];
|
||||||
[[NSUserDefaults standardUserDefaults] removeObjectForKey:kBITAuthenticatorDidSkipOptionalLogin];
|
|
||||||
[self setLastAuthenticatedVersion:nil];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma mark - KVO
|
||||||
- (void) registerObservers {
|
- (void) registerObservers {
|
||||||
__weak typeof(self) weakSelf = self;
|
__weak typeof(self) weakSelf = self;
|
||||||
if(nil == _appDidBecomeActiveObserver) {
|
if(nil == _appDidBecomeActiveObserver) {
|
||||||
@ -577,38 +597,23 @@ static NSString* const kBITAuthenticatorDidSkipOptionalLogin = @"BITAuthenticato
|
|||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - Property overrides
|
#pragma mark - Property overrides
|
||||||
- (void)setAuthenticationToken:(NSString *)authenticationToken withType:(NSString*) authenticationTokenType {
|
- (void)storeInstallationIdentifier:(NSString *)installationIdentifier withType:(BITAuthenticatorIdentificationType) type {
|
||||||
NSParameterAssert(nil == authenticationToken || nil != authenticationTokenType);
|
if(nil == installationIdentifier) {
|
||||||
if(![self.authenticationToken isEqualToString:authenticationToken] || ![self.authenticationTokenType isEqualToString:authenticationTokenType]) {
|
[self removeKeyFromKeychain:kBITAuthenticatorIdentifierKey];
|
||||||
[self willChangeValueForKey:@"installationIdentification"];
|
[self removeKeyFromKeychain:kBITAuthenticatorIdentifierTypeKey];
|
||||||
if(nil == authenticationToken) {
|
|
||||||
[self removeKeyFromKeychain:kBITAuthenticatorAuthTokenKey];
|
|
||||||
[self removeKeyFromKeychain:kBITAuthenticatorAuthTokenTypeKey];
|
|
||||||
} else {
|
} else {
|
||||||
[self addStringValueToKeychainForThisDeviceOnly:authenticationToken forKey:kBITAuthenticatorAuthTokenKey];
|
BOOL success = [self addStringValueToKeychainForThisDeviceOnly:installationIdentifier
|
||||||
[self addStringValueToKeychainForThisDeviceOnly:authenticationTokenType forKey:kBITAuthenticatorAuthTokenTypeKey];
|
forKey:kBITAuthenticatorIdentifierKey];
|
||||||
}
|
NSParameterAssert(success);
|
||||||
[self didChangeValueForKey:@"installationIdentification"];
|
success = [self addStringValueToKeychainForThisDeviceOnly:[self.class stringForIdentificationType:type]
|
||||||
|
forKey:kBITAuthenticatorIdentifierTypeKey];
|
||||||
|
NSParameterAssert(success);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSString *)authenticationToken {
|
- (NSString*) installationIdentifier {
|
||||||
NSString *authToken = [self stringValueFromKeychainForKey:kBITAuthenticatorAuthTokenKey];
|
NSString *identifier = [self stringValueFromKeychainForKey:kBITAuthenticatorIdentifierKey];
|
||||||
if(nil == authToken) return nil;
|
return identifier;
|
||||||
|
|
||||||
//check if the auth token matches the current setting
|
|
||||||
if(![self.authenticationTokenType isEqualToString:[self.class stringForAuthenticationType:self.authenticationType]]) {
|
|
||||||
BITHockeyLog(@"Auth type mismatch for stored auth-token. Resetting.");
|
|
||||||
[self removeKeyFromKeychain:kBITAuthenticatorAuthTokenKey];
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
return authToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSString *)authenticationTokenType {
|
|
||||||
NSString *authTokenType = [self stringValueFromKeychainForKey:kBITAuthenticatorAuthTokenTypeKey];
|
|
||||||
return authTokenType;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setLastAuthenticatedVersion:(NSString *)lastAuthenticatedVersion {
|
- (void)setLastAuthenticatedVersion:(NSString *)lastAuthenticatedVersion {
|
||||||
@ -626,46 +631,46 @@ static NSString* const kBITAuthenticatorDidSkipOptionalLogin = @"BITAuthenticato
|
|||||||
return [[NSUserDefaults standardUserDefaults] objectForKey:kBITAuthenticatorLastAuthenticatedVersionKey];
|
return [[NSUserDefaults standardUserDefaults] objectForKey:kBITAuthenticatorLastAuthenticatedVersionKey];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setDidSkipOptionalLogin:(BOOL)didSkipOptionalLogin {
|
- (NSString *)installationIdentifierTypeString {
|
||||||
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
|
return [self.class stringForIdentificationType:self.identificationType];
|
||||||
if(NO == didSkipOptionalLogin){
|
}
|
||||||
[defaults removeObjectForKey:kBITAuthenticatorDidSkipOptionalLogin];
|
|
||||||
} else {
|
+ (NSString *)stringForIdentificationType:(BITAuthenticatorIdentificationType) identificationType {
|
||||||
[defaults setObject:@(YES)
|
switch(identificationType) {
|
||||||
forKey:kBITAuthenticatorDidSkipOptionalLogin];
|
case BITAuthenticatorIdentificationTypeHockeyAppEmail: return @"iuid";
|
||||||
[defaults synchronize];
|
case BITAuthenticatorIdentificationTypeHockeyAppUser: return @"auid";
|
||||||
|
case BITAuthenticatorIdentificationTypeDevice: return @"udid";
|
||||||
|
case BITAuthenticatorIdentificationTypeAnonymous: return @"uuid";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)didSkipOptionalLogin {
|
- (void)setIdentificationType:(BITAuthenticatorIdentificationType)identificationType {
|
||||||
return [[NSUserDefaults standardUserDefaults] objectForKey:kBITAuthenticatorDidSkipOptionalLogin];
|
if(_identificationType != identificationType) {
|
||||||
|
_identificationType = identificationType;
|
||||||
|
self.identified = NO;
|
||||||
|
self.validated = NO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString *)publicInstallationIdentifier {
|
||||||
|
switch (self.identificationType) {
|
||||||
|
case BITAuthenticatorIdentificationTypeHockeyAppEmail:
|
||||||
|
case BITAuthenticatorIdentificationTypeHockeyAppUser:
|
||||||
|
return [self stringValueFromKeychainForKey:kBITAuthenticatorUserEmailKey];
|
||||||
|
case BITAuthenticatorIdentificationTypeAnonymous:
|
||||||
|
case BITAuthenticatorIdentificationTypeDevice:
|
||||||
|
return [self stringValueFromKeychainForKey:kBITAuthenticatorIdentifierKey];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - Application Lifecycle
|
#pragma mark - Application Lifecycle
|
||||||
- (void)applicationDidBecomeActive:(NSNotification *)note {
|
- (void)applicationDidBecomeActive:(NSNotification *)note {
|
||||||
[self triggerAuthentication];
|
[self authenticate];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)applicationWillResignActive:(NSNotification *)note {
|
- (void)applicationWillResignActive:(NSNotification *)note {
|
||||||
if(BITAuthenticatorValidationTypeOnAppActive == self.validationType) {
|
if(BITAuthenticatorAppRestrictionEnforcementOnAppActive == self.restrictionEnforcementFrequency) {
|
||||||
self.installationIdentificationValidated = NO;
|
self.validated = NO;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark -
|
|
||||||
- (tValidationCompletion) defaultValidationCompletionBlock {
|
|
||||||
return ^(BOOL validated, NSError *error) {
|
|
||||||
switch (self.validationType) {
|
|
||||||
case BITAuthenticatorValidationTypeNever:
|
|
||||||
case BITAuthenticatorValidationTypeOptional:
|
|
||||||
break;
|
|
||||||
case BITAuthenticatorValidationTypeOnAppActive:
|
|
||||||
case BITAuthenticatorValidationTypeOnFirstLaunch:
|
|
||||||
if(!validated) {
|
|
||||||
[self authenticateWithCompletion:nil];
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
@end
|
@end
|
||||||
|
@ -42,71 +42,22 @@
|
|||||||
*/
|
*/
|
||||||
@property (nonatomic, strong) BITHockeyAppClient *hockeyAppClient;
|
@property (nonatomic, strong) BITHockeyAppClient *hockeyAppClient;
|
||||||
|
|
||||||
#pragma mark - Identification
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides an identification for the current app installation
|
|
||||||
*
|
|
||||||
* During Alpha and Beta-phase HockeyApp tries to uniquely identify each app installation
|
|
||||||
* to provide better error reporting & analytics. If authenticator is configured to login
|
|
||||||
* (@see BITAuthenticatorValidationType), this identifier is retrieved from HockeyApp. In case
|
|
||||||
* it is disabled, it returns the vendorIdentifier provided by UIKit.
|
|
||||||
* KVO'able
|
|
||||||
*
|
|
||||||
* @return a string identifying this app installation
|
|
||||||
*/
|
|
||||||
@property (nonatomic, readonly) NSString *installationIdentification;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specifies if the installationIdentification has been validated
|
|
||||||
*
|
|
||||||
* Depending on authenticationType and validationType this flag switches between
|
|
||||||
* YES/NO during application runtime. If it's YES, the installationIdentification has been
|
|
||||||
* validated (either against the backend on app launch / initial run of this version) or validation
|
|
||||||
* is not required. The flag is first updated (and stays NO) until the manager has been started.
|
|
||||||
* KVO'able
|
|
||||||
*/
|
|
||||||
@property (nonatomic, readwrite) BOOL installationIdentificationValidated;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specifies the type of installation identification for the current app installation
|
|
||||||
*/
|
|
||||||
@property (nonatomic, readonly) NSString *installationIdentificationType;
|
|
||||||
|
|
||||||
#pragma mark -
|
#pragma mark -
|
||||||
|
|
||||||
//can be set for testing
|
|
||||||
@property (nonatomic) UIDevice *currentDevice;
|
|
||||||
|
|
||||||
#pragma mark -
|
|
||||||
/**
|
|
||||||
* if set, this serves as the installationIdentifier.
|
|
||||||
* This is retrieved from the hockeyApp backend
|
|
||||||
* @see installationIdentification
|
|
||||||
*/
|
|
||||||
@property (nonatomic, readonly) NSString *authenticationToken;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* store the authentication token with the given type
|
|
||||||
* if authToken is not nil, authentikationTokenType must also be non nil
|
|
||||||
*
|
|
||||||
* @param authenticationToken The authentication token
|
|
||||||
* @param authenticationTokenType The authentication token type
|
|
||||||
*/
|
|
||||||
- (void)setAuthenticationToken:(NSString *)authenticationToken withType:(NSString*) authenticationTokenType;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* holds the identifier of the last version that was authenticated
|
* holds the identifier of the last version that was authenticated
|
||||||
* only used if validation is set BITAuthenticatorValidationTypeOnFirstLaunch
|
* only used if validation is set BITAuthenticatorValidationTypeOnFirstLaunch
|
||||||
*/
|
*/
|
||||||
@property (nonatomic, copy) NSString *lastAuthenticatedVersion;
|
@property (nonatomic, copy) NSString *lastAuthenticatedVersion;
|
||||||
|
|
||||||
@property (nonatomic, copy) tAuthenticationCompletion authenticationCompletionBlock;
|
/**
|
||||||
|
* return the string used to identify this app against the HockeyApp backend.
|
||||||
|
*/
|
||||||
|
@property (nonatomic, copy, readonly) NSString *installationIdentifierTypeString;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* removes all previously stored authentication tokens, UDIDs, etc
|
* returns the string used to identify this app against the HockeyApp backend.
|
||||||
*/
|
*/
|
||||||
- (void) cleanupInternalStorage;
|
@property (nonatomic, copy, readonly) NSString *installationIdentifier;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* method registered as observer for applicationWillBecomeInactive events
|
* method registered as observer for applicationWillBecomeInactive events
|
||||||
@ -122,49 +73,14 @@
|
|||||||
*/
|
*/
|
||||||
- (void) applicationDidBecomeActive:(NSNotification*) note;
|
- (void) applicationDidBecomeActive:(NSNotification*) note;
|
||||||
|
|
||||||
/**
|
@property (nonatomic, copy) void(^identificationCompletion)(BOOL identified, NSError* error);
|
||||||
* once the user skipped the optional login, this is set to YES
|
|
||||||
* (and thus the optional login should never be shown again)
|
|
||||||
* persisted to disk. Defaults to NO
|
|
||||||
*/
|
|
||||||
@property (nonatomic, assign) BOOL didSkipOptionalLogin;
|
|
||||||
|
|
||||||
#pragma mark - Authentication
|
#pragma mark - Overrides
|
||||||
/**
|
@property (nonatomic, assign, readwrite, getter = isIdentified) BOOL identified;
|
||||||
* Authenticate this app installation
|
@property (nonatomic, assign, readwrite, getter = isValidated) BOOL validated;
|
||||||
*
|
|
||||||
* Depending on 'authenticationType', this tries to authenticate the app installation
|
|
||||||
* against the HockeyApp server.
|
|
||||||
* You should not need to call this, as it's done automatically once the manager has
|
|
||||||
* been started, depending on validationType.
|
|
||||||
*
|
|
||||||
* @param completion if nil, success/failure is reported via the delegate, if not nil, the
|
|
||||||
* delegate methods are not called.
|
|
||||||
*/
|
|
||||||
- (void) authenticateWithCompletion:(tAuthenticationCompletion) completion;
|
|
||||||
|
|
||||||
#pragma mark - Internal Auth callbacks
|
#pragma mark - Testing
|
||||||
- (void) didAuthenticateWithToken:(NSString*) token;
|
- (void) storeInstallationIdentifier:(NSString*) identifier withType:(BITAuthenticatorIdentificationType) type;
|
||||||
|
- (BOOL) needsValidation;
|
||||||
#pragma mark - Validation
|
- (void) authenticate;
|
||||||
/**
|
|
||||||
* Validate the app installation
|
|
||||||
*
|
|
||||||
* Depending on @see validationType, this is called by the manager after the app becomes active
|
|
||||||
* and tries to revalidate the installation.
|
|
||||||
* You should not need to call this, as it's done automatically once the manager has
|
|
||||||
* been started, depending on validationType.
|
|
||||||
*
|
|
||||||
* @param completion if nil, success/failure is reported via the delegate, if not nil, the
|
|
||||||
* delegate methods are not called
|
|
||||||
*/
|
|
||||||
- (void) validateInstallationWithCompletion:(tValidationCompletion) completion;
|
|
||||||
|
|
||||||
|
|
||||||
#pragma mark - Validation callbacks
|
|
||||||
- (void) validationSucceededWithCompletion:(tValidationCompletion) completion;
|
|
||||||
- (void) validationFailedWithError:(NSError *) validationError completion:(tValidationCompletion) completion;
|
|
||||||
|
|
||||||
#pragma mark - Helpers for testing
|
|
||||||
- (tValidationCompletion) defaultValidationCompletionBlock;
|
|
||||||
@end
|
@end
|
||||||
|
@ -210,7 +210,7 @@
|
|||||||
// start Authenticator
|
// start Authenticator
|
||||||
if (![self isAppStoreEnvironment]) {
|
if (![self isAppStoreEnvironment]) {
|
||||||
// hook into manager with kvo!
|
// hook into manager with kvo!
|
||||||
[_authenticator addObserver:self forKeyPath:@"installationIdentificationValidated" options:0 context:nil];
|
[_authenticator addObserver:self forKeyPath:@"identified" options:0 context:nil];
|
||||||
|
|
||||||
BITHockeyLog(@"INFO: Start Authenticator");
|
BITHockeyLog(@"INFO: Start Authenticator");
|
||||||
if (_serverURL) {
|
if (_serverURL) {
|
||||||
@ -226,7 +226,7 @@
|
|||||||
|| [[self class] isJMCPresent]
|
|| [[self class] isJMCPresent]
|
||||||
#endif /* HOCKEYSDK_FEATURE_JIRA_MOBILE_CONNECT */
|
#endif /* HOCKEYSDK_FEATURE_JIRA_MOBILE_CONNECT */
|
||||||
) {
|
) {
|
||||||
if ([self.authenticator installationIdentificationValidated]) {
|
if ([self.authenticator isIdentified]) {
|
||||||
[self invokeStartUpdateManager];
|
[self invokeStartUpdateManager];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -283,11 +283,11 @@
|
|||||||
|
|
||||||
#if HOCKEYSDK_FEATURE_UPDATES
|
#if HOCKEYSDK_FEATURE_UPDATES
|
||||||
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
|
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
|
||||||
if ([keyPath isEqualToString:@"installationIdentificationValidated"] &&
|
if ([keyPath isEqualToString:@"identified"] &&
|
||||||
[object valueForKey:@"installationIdentificationValidated"] ) {
|
[object valueForKey:@"isIdentified"] ) {
|
||||||
if ((![self isAppStoreEnvironment] && ![self isUpdateManagerDisabled])) {
|
if ((![self isAppStoreEnvironment] && ![self isUpdateManagerDisabled])) {
|
||||||
BOOL isValidated = [(NSNumber *)[object valueForKey:@"installationIdentificationValidated"] boolValue];
|
BOOL identified = [(NSNumber *)[object valueForKey:@"isIdentified"] boolValue];
|
||||||
if (isValidated) {
|
if (identified) {
|
||||||
[self invokeStartUpdateManager];
|
[self invokeStartUpdateManager];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -330,9 +330,9 @@
|
|||||||
[_updateManager setServerURL:_serverURL];
|
[_updateManager setServerURL:_serverURL];
|
||||||
}
|
}
|
||||||
if (_authenticator) {
|
if (_authenticator) {
|
||||||
[_updateManager setInstallationIdentification:[self.authenticator installationIdentification]];
|
[_updateManager setInstallationIdentification:[self.authenticator installationIdentifier]];
|
||||||
[_updateManager setInstallationIdentificationType:[self.authenticator installationIdentificationType]];
|
[_updateManager setInstallationIdentificationType:[self.authenticator installationIdentifierTypeString]];
|
||||||
[_updateManager setInstallationIdentificationValidated:[self.authenticator installationIdentificationValidated]];
|
[_updateManager setInstallationIdentified:[self.authenticator isIdentified]];
|
||||||
}
|
}
|
||||||
[_updateManager performSelector:@selector(startManager) withObject:nil afterDelay:0.5f];
|
[_updateManager performSelector:@selector(startManager) withObject:nil afterDelay:0.5f];
|
||||||
}
|
}
|
||||||
|
@ -535,7 +535,7 @@ typedef NS_ENUM(NSInteger, BITUpdateAlertViewTag) {
|
|||||||
- (void)checkForUpdate {
|
- (void)checkForUpdate {
|
||||||
if (![self isAppStoreEnvironment] && ![self isUpdateManagerDisabled]) {
|
if (![self isAppStoreEnvironment] && ![self isUpdateManagerDisabled]) {
|
||||||
if ([self expiryDateReached]) return;
|
if ([self expiryDateReached]) return;
|
||||||
if (![self installationIdentificationValidated]) return;
|
if (![self installationIdentified]) return;
|
||||||
|
|
||||||
if (self.isUpdateAvailable && [self hasNewerMandatoryVersion]) {
|
if (self.isUpdateAvailable && [self hasNewerMandatoryVersion]) {
|
||||||
[self showCheckForUpdateAlert];
|
[self showCheckForUpdateAlert];
|
||||||
@ -881,12 +881,6 @@ typedef NS_ENUM(NSInteger, BITUpdateAlertViewTag) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setInstallationIdentificationValidated:(BOOL)installationIdentificationValidated {
|
|
||||||
if (installationIdentificationValidated != _installationIdentificationValidated) {
|
|
||||||
_installationIdentificationValidated = installationIdentificationValidated;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setInstallationIdentification:(NSString *)installationIdentification {
|
- (void)setInstallationIdentification:(NSString *)installationIdentification {
|
||||||
if (![_installationIdentification isEqualToString:installationIdentification]) {
|
if (![_installationIdentification isEqualToString:installationIdentification]) {
|
||||||
if (installationIdentification) {
|
if (installationIdentification) {
|
||||||
|
@ -64,7 +64,7 @@
|
|||||||
|
|
||||||
@property (nonatomic, strong) NSString *installationIdentificationType;
|
@property (nonatomic, strong) NSString *installationIdentificationType;
|
||||||
|
|
||||||
@property (nonatomic) BOOL installationIdentificationValidated;
|
@property (nonatomic) BOOL installationIdentified;
|
||||||
|
|
||||||
// if YES, the API will return an existing JMC config
|
// if YES, the API will return an existing JMC config
|
||||||
// if NO, the API will return only version information
|
// if NO, the API will return only version information
|
||||||
|
@ -174,10 +174,6 @@ typedef NS_ENUM(NSInteger, BITAuthenticatorReason) {
|
|||||||
* Not Authorized
|
* Not Authorized
|
||||||
*/
|
*/
|
||||||
BITAuthenticatorNotAuthorized,
|
BITAuthenticatorNotAuthorized,
|
||||||
/**
|
|
||||||
* Authorization cancelled
|
|
||||||
*/
|
|
||||||
BITAuthenticatorAuthenticationCancelled,
|
|
||||||
/**
|
/**
|
||||||
* Unknown Application ID (configuration error)
|
* Unknown Application ID (configuration error)
|
||||||
*/
|
*/
|
||||||
@ -186,6 +182,10 @@ typedef NS_ENUM(NSInteger, BITAuthenticatorReason) {
|
|||||||
* Authorization secret missing
|
* Authorization secret missing
|
||||||
*/
|
*/
|
||||||
BITAuthenticatorAuthorizationSecretMissing,
|
BITAuthenticatorAuthorizationSecretMissing,
|
||||||
|
/**
|
||||||
|
* Not yet identified
|
||||||
|
*/
|
||||||
|
BITAuthenticatorNotIdentified,
|
||||||
};
|
};
|
||||||
extern NSString *const __attribute__((unused)) kBITAuthenticatorErrorDomain;
|
extern NSString *const __attribute__((unused)) kBITAuthenticatorErrorDomain;
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#import "BITAuthenticator_Private.h"
|
#import "BITAuthenticator_Private.h"
|
||||||
#import "BITHTTPOperation.h"
|
#import "BITHTTPOperation.h"
|
||||||
#import "BITTestHelper.h"
|
#import "BITTestHelper.h"
|
||||||
|
#import "BITHockeyAppClient.h"
|
||||||
|
|
||||||
@interface MyDevice : NSObject
|
@interface MyDevice : NSObject
|
||||||
- (NSString*) uniqueIdentifier;
|
- (NSString*) uniqueIdentifier;
|
||||||
@ -56,7 +57,6 @@ static void *kInstallationIdentification = &kInstallationIdentification;
|
|||||||
[super setUp];
|
[super setUp];
|
||||||
|
|
||||||
_sut = [[BITAuthenticator alloc] initWithAppIdentifier:nil isAppStoreEnvironment:NO];
|
_sut = [[BITAuthenticator alloc] initWithAppIdentifier:nil isAppStoreEnvironment:NO];
|
||||||
_sut.authenticationType = BITAuthenticatorAuthTypeEmailAndPassword;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)tearDown {
|
- (void)tearDown {
|
||||||
@ -88,12 +88,6 @@ static void *kInstallationIdentification = &kInstallationIdentification;
|
|||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - Persistence Tests
|
#pragma mark - Persistence Tests
|
||||||
- (void) testThatAuthenticationTokenIsPersisted {
|
|
||||||
[_sut setAuthenticationToken:@"SuperToken" withType:@"udid"];
|
|
||||||
_sut = [[BITAuthenticator alloc] initWithAppIdentifier:nil isAppStoreEnvironment:YES];
|
|
||||||
assertThat(_sut.authenticationToken, equalTo(@"SuperToken"));
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) testThatLastAuthenticatedVersionIsPersisted {
|
- (void) testThatLastAuthenticatedVersionIsPersisted {
|
||||||
_sut.lastAuthenticatedVersion = @"1.2.1";
|
_sut.lastAuthenticatedVersion = @"1.2.1";
|
||||||
_sut = [[BITAuthenticator alloc] initWithAppIdentifier:nil isAppStoreEnvironment:YES];
|
_sut = [[BITAuthenticator alloc] initWithAppIdentifier:nil isAppStoreEnvironment:YES];
|
||||||
@ -101,224 +95,206 @@ static void *kInstallationIdentification = &kInstallationIdentification;
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void) testThatCleanupWorks {
|
- (void) testThatCleanupWorks {
|
||||||
[_sut setAuthenticationToken:@"MyToken" withType:@"udid"];
|
|
||||||
_sut.lastAuthenticatedVersion = @"1.2";
|
_sut.lastAuthenticatedVersion = @"1.2";
|
||||||
[_sut setDidSkipOptionalLogin:YES];
|
|
||||||
|
|
||||||
[_sut cleanupInternalStorage];
|
[_sut cleanupInternalStorage];
|
||||||
|
|
||||||
assertThat(_sut.authenticationToken, equalTo(nil));
|
|
||||||
assertThat(_sut.lastAuthenticatedVersion, equalTo(nil));
|
assertThat(_sut.lastAuthenticatedVersion, equalTo(nil));
|
||||||
assertThat(_sut.installationIdentificationType, equalTo(@"udid"));
|
assertThat(_sut.installationIdentifier, equalTo(nil));
|
||||||
assertThatBool(_sut.didSkipOptionalLogin, equalToBool(NO));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) testThatSkipLoginIsPersisted {
|
#pragma mark - Initial defaults
|
||||||
[_sut setDidSkipOptionalLogin:YES];
|
- (void) testDefaultValues {
|
||||||
_sut = [[BITAuthenticator alloc] initWithAppIdentifier:nil isAppStoreEnvironment:YES];
|
assertThatBool(_sut.automaticMode, equalToBool(YES));
|
||||||
assertThatBool(_sut.didSkipOptionalLogin, equalToBool(YES));
|
assertThatBool(_sut.restrictApplicationUsage, equalToBool(NO));
|
||||||
[_sut setDidSkipOptionalLogin:NO];
|
assertThatBool(_sut.isIdentified, equalToBool(NO));
|
||||||
_sut = [[BITAuthenticator alloc] initWithAppIdentifier:nil isAppStoreEnvironment:YES];
|
assertThatBool(_sut.isValidated, equalToBool(NO));
|
||||||
assertThatBool(_sut.didSkipOptionalLogin, equalToBool(NO));
|
assertThat(_sut.authenticationSecret, equalTo(nil));
|
||||||
}
|
assertThat(_sut.installationIdentifier, equalTo(nil));
|
||||||
|
assertThat(_sut.installationIdentifierTypeString, equalTo(@"uuid"));
|
||||||
#pragma mark - Identification Tests
|
|
||||||
- (void) testIdentificationReturnsTheVendorIdentifierIfAvailable {
|
|
||||||
STAssertEqualObjects([_sut installationIdentification], [[UIDevice currentDevice] identifierForVendor].UUIDString,
|
|
||||||
@"Freshly initialized, it should return the vendor identifier");
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) testIdentificationReturnsTheAuthTokenIfSet {
|
|
||||||
[_sut setAuthenticationType:BITAuthenticatorAuthTypeUDIDProvider];
|
|
||||||
[_sut setAuthenticationToken:@"PeterPan" withType:@"udid"];
|
|
||||||
assertThat(_sut.installationIdentification, equalTo(@"PeterPan"));
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - authentication tests
|
|
||||||
- (void) testThatAuthenticateWithTypeEmailShowsAViewController {
|
|
||||||
id delegateMock = mockProtocol(@protocol(BITAuthenticatorDelegate));
|
|
||||||
_sut.delegate = delegateMock;
|
|
||||||
_sut.authenticationSecret = @"myscret";
|
|
||||||
_sut.authenticationType = BITAuthenticatorAuthTypeEmail;
|
|
||||||
|
|
||||||
[_sut authenticateWithCompletion:nil];
|
|
||||||
|
|
||||||
[verifyCount(delegateMock, times(1)) authenticator:_sut willShowAuthenticationController:(id)anything()];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) testThatAuthenticateWithTypeEmailShowsAViewControllerOnlyIfAuthenticationSecretIsSet {
|
|
||||||
id delegateMock = mockProtocol(@protocol(BITAuthenticatorDelegate));
|
|
||||||
_sut.delegate = delegateMock;
|
|
||||||
_sut.authenticationSecret = nil;
|
|
||||||
_sut.authenticationType = BITAuthenticatorAuthTypeEmail;
|
|
||||||
|
|
||||||
[_sut authenticateWithCompletion:nil];
|
|
||||||
|
|
||||||
[verifyCount(delegateMock, times(0)) authenticator:_sut willShowAuthenticationController:(id)anything()];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
- (void) testThatAuthenticateWithTypeEmailAndPasswordShowsAViewController {
|
|
||||||
id delegateMock = mockProtocol(@protocol(BITAuthenticatorDelegate));
|
|
||||||
_sut.delegate = delegateMock;
|
|
||||||
_sut.authenticationType = BITAuthenticatorAuthTypeEmailAndPassword;
|
|
||||||
|
|
||||||
[_sut authenticateWithCompletion:nil];
|
|
||||||
|
|
||||||
[verifyCount(delegateMock, times(1)) authenticator:_sut willShowAuthenticationController:(id)anything()];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma mark - General identification tests
|
||||||
- (void) testThatIsDoesntShowMoreThanOneAuthenticationController {
|
- (void) testThatIsDoesntShowMoreThanOneAuthenticationController {
|
||||||
id delegateMock = mockProtocol(@protocol(BITAuthenticatorDelegate));
|
id delegateMock = mockProtocol(@protocol(BITAuthenticatorDelegate));
|
||||||
_sut.delegate = delegateMock;
|
_sut.delegate = delegateMock;
|
||||||
_sut.authenticationType = BITAuthenticatorAuthTypeEmailAndPassword;
|
_sut.identificationType = BITAuthenticatorIdentificationTypeDevice;
|
||||||
|
|
||||||
[_sut authenticateWithCompletion:nil];
|
[_sut identifyWithCompletion:nil];
|
||||||
[_sut authenticateWithCompletion:nil];
|
[_sut identifyWithCompletion:nil];
|
||||||
[_sut authenticateWithCompletion:nil];
|
[_sut identifyWithCompletion:nil];
|
||||||
|
|
||||||
[verifyCount(delegateMock, times(1)) authenticator:_sut willShowAuthenticationController:(id)anything()];
|
[verifyCount(delegateMock, times(1)) authenticator:_sut willShowAuthenticationController:(id)anything()];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) testThatSuccessfulAuthenticationStoresTheToken {
|
- (void) testThatChangingIdentificationTypeResetsIdentifiedFlag {
|
||||||
|
_sut.identified = YES;
|
||||||
|
_sut.identificationType = BITAuthenticatorIdentificationTypeHockeyAppUser;
|
||||||
|
assertThatBool(_sut.identified, equalToBool(NO));
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) testThatAfterChangingIdentificationTypeIdentificationIsRedone {
|
||||||
|
[_sut storeInstallationIdentifier:@"meh" withType:BITAuthenticatorIdentificationTypeHockeyAppEmail];
|
||||||
|
_sut.identified = YES;
|
||||||
|
_sut.identificationType = BITAuthenticatorIdentificationTypeHockeyAppUser;
|
||||||
|
[_sut identifyWithCompletion:nil];
|
||||||
|
assertThatBool(_sut.identified, equalToBool(NO));
|
||||||
|
assertThat(_sut.installationIdentifier, nilValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) testThatIdentifyingAnAlreadyIdentifiedInstanceDoesNothing {
|
||||||
id delegateMock = mockProtocol(@protocol(BITAuthenticatorDelegate));
|
id delegateMock = mockProtocol(@protocol(BITAuthenticatorDelegate));
|
||||||
_sut.delegate = delegateMock;
|
_sut.delegate = delegateMock;
|
||||||
|
|
||||||
//this will prepare everything and show the viewcontroller
|
_sut.identificationType = BITAuthenticatorIdentificationTypeHockeyAppEmail;
|
||||||
[_sut authenticateWithCompletion:nil];
|
[_sut storeInstallationIdentifier:@"meh" withType:BITAuthenticatorIdentificationTypeHockeyAppEmail];
|
||||||
//fake delegate call from the viewcontroller
|
_sut.identified = YES;
|
||||||
[_sut didAuthenticateWithToken:@"SuperToken"];
|
|
||||||
|
|
||||||
assertThat(_sut.authenticationToken, equalTo(@"SuperToken"));
|
[_sut identifyWithCompletion:nil];
|
||||||
}
|
|
||||||
|
|
||||||
- (void) testThatSuccessfulAuthenticationCallsTheBlock {
|
|
||||||
id delegateMock = mockProtocol(@protocol(BITAuthenticatorDelegate));
|
|
||||||
_sut.delegate = delegateMock;
|
|
||||||
[_sut setAuthenticationToken:@"Test" withType:@"adid"];
|
|
||||||
__block BOOL didAuthenticate = NO;
|
|
||||||
[_sut authenticateWithCompletion:^(NSString *authenticationToken, NSError *error) {
|
|
||||||
if(authenticationToken) didAuthenticate = YES;
|
|
||||||
}];
|
|
||||||
[_sut didAuthenticateWithToken:@"SuperToken"];
|
|
||||||
|
|
||||||
assertThatBool(didAuthenticate, equalToBool(YES));
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) testThatCancelledAuthenticationSetsProperError {
|
|
||||||
id delegateMock = mockProtocol(@protocol(BITAuthenticatorDelegate));
|
|
||||||
_sut.delegate = delegateMock;
|
|
||||||
|
|
||||||
//this will prepare everything and show the viewcontroller
|
|
||||||
__block BOOL didAuthenticateCalled = NO;
|
|
||||||
__block NSError *authenticationError = nil;
|
|
||||||
[_sut authenticateWithCompletion:^(NSString *authenticationToken, NSError *error) {
|
|
||||||
didAuthenticateCalled = YES;
|
|
||||||
authenticationError = error;
|
|
||||||
}];
|
|
||||||
|
|
||||||
//fake delegate call from the viewcontroller
|
|
||||||
[_sut authenticationViewControllerDidSkip:nil];
|
|
||||||
|
|
||||||
assertThatBool(didAuthenticateCalled, equalToBool(YES));
|
|
||||||
assertThat(authenticationError, equalTo([NSError errorWithDomain:kBITAuthenticatorErrorDomain
|
|
||||||
code:BITAuthenticatorAuthenticationCancelled
|
|
||||||
userInfo:nil]));
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) testThatCancelledAuthenticationResetsTheToken {
|
|
||||||
id delegateMock = mockProtocol(@protocol(BITAuthenticatorDelegate));
|
|
||||||
_sut.delegate = delegateMock;
|
|
||||||
[_sut setAuthenticationToken:@"Meh" withType:@"bdid"];
|
|
||||||
|
|
||||||
//this will prepare everything and show the viewcontroller
|
|
||||||
[_sut authenticateWithCompletion:nil];
|
|
||||||
//fake delegate call from the viewcontroller
|
|
||||||
[_sut authenticationViewControllerDidSkip:nil];
|
|
||||||
|
|
||||||
assertThat(_sut.authenticationToken, equalTo(nil));
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) testThatKVOWorksOnApplicationIdentification {
|
|
||||||
//this will prepare everything and show the viewcontroller
|
|
||||||
[_sut authenticateWithCompletion:nil];
|
|
||||||
|
|
||||||
[_sut addObserver:self forKeyPath:@"installationIdentification"
|
|
||||||
options:0
|
|
||||||
context:kInstallationIdentification];
|
|
||||||
|
|
||||||
//fake delegate call from the viewcontroller
|
|
||||||
[_sut authenticationViewControllerDidSkip:nil];
|
|
||||||
assertThatBool(_KVOCalled, equalToBool(YES));
|
|
||||||
[_sut removeObserver:self forKeyPath:@"installationIdentification"];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
|
|
||||||
if(kInstallationIdentification == context) {
|
|
||||||
_KVOCalled = YES;
|
|
||||||
} else {
|
|
||||||
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - InstallationIdentificationType
|
|
||||||
- (void) testThatEmailAuthSetsTheProperInstallationIdentificationType {
|
|
||||||
_sut.authenticationType = BITAuthenticatorAuthTypeEmail;
|
|
||||||
//fake delegate call from the viewcontroller
|
|
||||||
[_sut didAuthenticateWithToken:@"SuperToken"];
|
|
||||||
|
|
||||||
assertThat(_sut.installationIdentificationType, equalTo(@"iuid"));
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) testThatPasswordAuthSetsTheProperInstallationIdentificationType {
|
|
||||||
_sut.authenticationType = BITAuthenticatorAuthTypeEmailAndPassword;
|
|
||||||
//fake delegate call from the viewcontroller
|
|
||||||
[_sut didAuthenticateWithToken:@"SuperToken"];
|
|
||||||
|
|
||||||
assertThat(_sut.installationIdentificationType, equalTo(@"auid"));
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) testThatUDIDAuthSetsTheProperInstallationIdentificationType {
|
|
||||||
_sut.authenticationType = BITAuthenticatorAuthTypeUDIDProvider;
|
|
||||||
//fake delegate call from the viewcontroller
|
|
||||||
[_sut didAuthenticateWithToken:@"SuperToken"];
|
|
||||||
|
|
||||||
assertThat(_sut.installationIdentificationType, equalTo(@"udid"));
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) testThatDefaultAuthReturnsProperInstallationIdentificationType {
|
|
||||||
_sut.authenticationType = BITAuthenticatorAuthTypeEmailAndPassword;
|
|
||||||
//fake delegate call from the viewcontroller
|
|
||||||
[_sut authenticationViewControllerDidSkip:nil];
|
|
||||||
|
|
||||||
assertThat(_sut.installationIdentificationType, equalTo(@"udid"));
|
|
||||||
}
|
|
||||||
#pragma mark - validation tests
|
|
||||||
- (void) testThatValidationWithoutTokenWantsToShowTheAuthenticationViewController {
|
|
||||||
id delegateMock = mockProtocol(@protocol(BITAuthenticatorDelegate));
|
|
||||||
_sut.delegate = delegateMock;
|
|
||||||
_sut.validationType = BITAuthenticatorValidationTypeOptional;
|
|
||||||
|
|
||||||
[_sut validateInstallationWithCompletion:nil];
|
|
||||||
|
|
||||||
[verify(delegateMock) authenticator:_sut willShowAuthenticationController:(id)anything()];
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - Lifetime checks
|
|
||||||
- (void) testThatValidationDoesntTriggerIfDisabled {
|
|
||||||
id delegateMock = mockProtocol(@protocol(BITAuthenticatorDelegate));
|
|
||||||
_sut.delegate = delegateMock;
|
|
||||||
_sut.validationType = BITAuthenticatorValidationTypeNever;
|
|
||||||
|
|
||||||
[_sut startManager];
|
|
||||||
|
|
||||||
[verifyCount(delegateMock, never()) authenticator:_sut willShowAuthenticationController:(id)anything()];
|
[verifyCount(delegateMock, never()) authenticator:_sut willShowAuthenticationController:(id)anything()];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) testThatValidationTriggersOnStart {
|
|
||||||
|
#pragma mark - Anonymous identification type
|
||||||
|
- (void) testAnonymousIdentification {
|
||||||
|
_sut.identificationType = BITAuthenticatorIdentificationTypeAnonymous;
|
||||||
|
assertThatBool(_sut.isIdentified, equalToBool(NO));
|
||||||
|
[_sut identifyWithCompletion:^(BOOL identified, NSError *error) {
|
||||||
|
assertThatBool(identified, equalToBool(YES));
|
||||||
|
assertThat(error, equalTo(nil));
|
||||||
|
}];
|
||||||
|
assertThatBool(_sut.isIdentified, equalToBool(YES));
|
||||||
|
assertThat(_sut.installationIdentifier, notNilValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
//anoynmous users can't be validated
|
||||||
|
- (void) testAnonymousValidation {
|
||||||
|
_sut.identificationType = BITAuthenticatorIdentificationTypeAnonymous;
|
||||||
|
assertThatBool(_sut.isValidated, equalToBool(NO));
|
||||||
|
[_sut validateWithCompletion:^(BOOL validated, NSError *error) {
|
||||||
|
assertThatBool(_sut.validated, equalToBool(NO));
|
||||||
|
assertThat(error, notNilValue());
|
||||||
|
}];
|
||||||
|
assertThatBool(_sut.isValidated, equalToBool(NO));
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Device identification type
|
||||||
|
- (void) testDeviceIdentificationShowsViewController {
|
||||||
|
_sut.identificationType = BITAuthenticatorIdentificationTypeDevice;
|
||||||
id delegateMock = mockProtocol(@protocol(BITAuthenticatorDelegate));
|
id delegateMock = mockProtocol(@protocol(BITAuthenticatorDelegate));
|
||||||
_sut.delegate = delegateMock;
|
_sut.delegate = delegateMock;
|
||||||
_sut.validationType = BITAuthenticatorValidationTypeOnFirstLaunch;
|
|
||||||
|
[_sut identifyWithCompletion:nil];
|
||||||
|
|
||||||
|
[verifyCount(delegateMock, times(1)) authenticator:_sut willShowAuthenticationController:(id)anything()];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Email identification type
|
||||||
|
- (void) testEmailIdentificationFailsWithMissingSecret {
|
||||||
|
_sut.identificationType = BITAuthenticatorIdentificationTypeHockeyAppEmail;
|
||||||
|
[_sut identifyWithCompletion:^(BOOL identified, NSError *error) {
|
||||||
|
assertThatBool(identified, equalToBool(NO));
|
||||||
|
assertThat(error, notNilValue());
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) testEmailIdentificationShowsViewController {
|
||||||
|
_sut.identificationType = BITAuthenticatorIdentificationTypeHockeyAppEmail;
|
||||||
|
_sut.authenticationSecret = @"mySecret";
|
||||||
|
id delegateMock = mockProtocol(@protocol(BITAuthenticatorDelegate));
|
||||||
|
_sut.delegate = delegateMock;
|
||||||
|
|
||||||
|
[_sut identifyWithCompletion:nil];
|
||||||
|
|
||||||
|
[verifyCount(delegateMock, times(1)) authenticator:_sut willShowAuthenticationController:(id)anything()];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) testEmailValidationFailsWithMissingSecret {
|
||||||
|
_sut.identificationType = BITAuthenticatorIdentificationTypeHockeyAppEmail;
|
||||||
|
[_sut validateWithCompletion:^(BOOL validated, NSError *error) {
|
||||||
|
assertThatBool(validated, equalToBool(NO));
|
||||||
|
assertThat(error, notNilValue());
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) testThatEmailIdentificationQueuesAnOperation {
|
||||||
|
id httpClientMock = mock(BITHockeyAppClient.class);
|
||||||
|
_sut.hockeyAppClient = httpClientMock;
|
||||||
|
_sut.identificationType = BITAuthenticatorIdentificationTypeHockeyAppEmail;
|
||||||
|
[_sut storeInstallationIdentifier:@"meh" withType:BITAuthenticatorIdentificationTypeHockeyAppEmail];
|
||||||
|
_sut.authenticationSecret = @"double";
|
||||||
|
[_sut authenticationViewController:nil
|
||||||
|
handleAuthenticationWithEmail:@"stephan@dd.de"
|
||||||
|
password:@"nopass"
|
||||||
|
completion:nil];
|
||||||
|
[verify(httpClientMock) enqeueHTTPOperation:anything()];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - User identification type
|
||||||
|
- (void) testUserIdentificationShowsViewController {
|
||||||
|
_sut.identificationType = BITAuthenticatorIdentificationTypeHockeyAppUser;
|
||||||
|
id delegateMock = mockProtocol(@protocol(BITAuthenticatorDelegate));
|
||||||
|
_sut.delegate = delegateMock;
|
||||||
|
|
||||||
|
[_sut identifyWithCompletion:nil];
|
||||||
|
|
||||||
|
[verifyCount(delegateMock, times(1)) authenticator:_sut willShowAuthenticationController:(id)anything()];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark - Generic validation tests
|
||||||
|
- (void) testThatValidationFailsIfNotIdentified {
|
||||||
|
_sut.identified = NO;
|
||||||
|
_sut.identificationType = BITAuthenticatorIdentificationTypeHockeyAppUser;
|
||||||
|
[_sut validateWithCompletion:^(BOOL validated, NSError *error) {
|
||||||
|
assertThatBool(validated, equalToBool(NO));
|
||||||
|
assertThatInt(error.code, equalToInt(BITAuthenticatorNotIdentified));
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) testThatValidationCreatesAGETRequest {
|
||||||
|
id httpClientMock = mock(BITHockeyAppClient.class);
|
||||||
|
_sut.hockeyAppClient = httpClientMock;
|
||||||
|
_sut.identificationType = BITAuthenticatorIdentificationTypeHockeyAppEmail;
|
||||||
|
[_sut storeInstallationIdentifier:@"meh" withType:BITAuthenticatorIdentificationTypeHockeyAppEmail];
|
||||||
|
_sut.authenticationSecret = @"double";
|
||||||
|
[_sut validateWithCompletion:nil];
|
||||||
|
[verify(httpClientMock) getPath:(id)anything()
|
||||||
|
parameters:(id)anything()
|
||||||
|
completion:(id)anything()];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Authentication
|
||||||
|
- (void) testThatEnabledRestrictionTriggersValidation {
|
||||||
|
id clientMock = mock(BITHockeyAppClient.class);
|
||||||
|
_sut.hockeyAppClient = clientMock;
|
||||||
|
_sut.authenticationSecret = @"sekret";
|
||||||
|
_sut.restrictApplicationUsage = YES;
|
||||||
|
_sut.identificationType = BITAuthenticatorIdentificationTypeHockeyAppEmail;
|
||||||
|
[_sut storeInstallationIdentifier:@"asd" withType:BITAuthenticatorIdentificationTypeHockeyAppEmail];
|
||||||
|
[_sut authenticate];
|
||||||
|
|
||||||
|
[verify(clientMock) getPath:(id)anything() parameters:(id)anything() completion:(id)anything()];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) testThatDisabledRestrictionDoesntTriggerValidation {
|
||||||
|
id clientMock = mock(BITHockeyAppClient.class);
|
||||||
|
_sut.hockeyAppClient = clientMock;
|
||||||
|
_sut.authenticationSecret = @"sekret";
|
||||||
|
_sut.restrictApplicationUsage = NO;
|
||||||
|
_sut.identificationType = BITAuthenticatorIdentificationTypeHockeyAppEmail;
|
||||||
|
[_sut storeInstallationIdentifier:@"asd" withType:BITAuthenticatorIdentificationTypeHockeyAppEmail];
|
||||||
|
[_sut authenticate];
|
||||||
|
|
||||||
|
[verifyCount(clientMock, never()) getPath:(id)anything() parameters:(id)anything() completion:(id)anything()];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Lifetime checks
|
||||||
|
- (void) testThatAuthenticationTriggersOnStart {
|
||||||
|
id delegateMock = mockProtocol(@protocol(BITAuthenticatorDelegate));
|
||||||
|
_sut.delegate = delegateMock;
|
||||||
|
_sut.identificationType = BITAuthenticatorIdentificationTypeDevice;
|
||||||
|
|
||||||
[_sut startManager];
|
[_sut startManager];
|
||||||
|
|
||||||
@ -328,135 +304,44 @@ static void *kInstallationIdentification = &kInstallationIdentification;
|
|||||||
- (void) testThatValidationTriggersOnDidBecomeActive {
|
- (void) testThatValidationTriggersOnDidBecomeActive {
|
||||||
id delegateMock = mockProtocol(@protocol(BITAuthenticatorDelegate));
|
id delegateMock = mockProtocol(@protocol(BITAuthenticatorDelegate));
|
||||||
_sut.delegate = delegateMock;
|
_sut.delegate = delegateMock;
|
||||||
_sut.validationType = BITAuthenticatorValidationTypeOnAppActive;
|
_sut.identificationType = BITAuthenticatorIdentificationTypeDevice;
|
||||||
|
_sut.restrictApplicationUsage = YES;
|
||||||
|
|
||||||
[_sut applicationDidBecomeActive:nil];
|
[_sut applicationDidBecomeActive:nil];
|
||||||
|
|
||||||
[verify(delegateMock) authenticator:_sut willShowAuthenticationController:(id)anything()];
|
[verify(delegateMock) authenticator:_sut willShowAuthenticationController:(id)anything()];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma mark - Validation helper checks
|
||||||
- (void) testThatValidationTriggersOnNewVersion {
|
- (void) testThatValidationTriggersOnNewVersion {
|
||||||
id delegateMock = mockProtocol(@protocol(BITAuthenticatorDelegate));
|
_sut.restrictApplicationUsage = YES;
|
||||||
_sut.delegate = delegateMock;
|
_sut.restrictionEnforcementFrequency = BITAuthenticatorAppRestrictionEnforcementOnFirstLaunch;
|
||||||
_sut.validationType = BITAuthenticatorValidationTypeOnFirstLaunch;
|
_sut.validated = YES;
|
||||||
_sut.lastAuthenticatedVersion = @"111xxx";
|
_sut.lastAuthenticatedVersion = @"111xxx";
|
||||||
|
assertThatBool(_sut.needsValidation, equalToBool(YES));
|
||||||
[_sut startManager];
|
|
||||||
|
|
||||||
[verify(delegateMock) authenticator:_sut willShowAuthenticationController:(id)anything()];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) testThatValidationDoesNotTriggerOnSameVersion {
|
- (void) testThatValidationDoesNotTriggerOnSameVersion {
|
||||||
id delegateMock = mockProtocol(@protocol(BITAuthenticatorDelegate));
|
_sut.restrictApplicationUsage = YES;
|
||||||
_sut.delegate = delegateMock;
|
_sut.restrictionEnforcementFrequency = BITAuthenticatorAppRestrictionEnforcementOnFirstLaunch;
|
||||||
_sut.validationType = BITAuthenticatorValidationTypeOnFirstLaunch;
|
_sut.validated = YES;
|
||||||
_sut.lastAuthenticatedVersion = _sut.executableUUID;
|
_sut.lastAuthenticatedVersion = _sut.executableUUID;
|
||||||
|
assertThatBool(_sut.needsValidation, equalToBool(NO));
|
||||||
[_sut startManager];
|
|
||||||
|
|
||||||
[verifyCount(delegateMock, never()) authenticator:_sut willShowAuthenticationController:(id)anything()];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) testThatFailedValidationCallsTheCompletionBlock {
|
|
||||||
id delegateMock = mockProtocol(@protocol(BITAuthenticatorDelegate));
|
|
||||||
_sut.delegate = delegateMock;
|
|
||||||
_sut.validationType = BITAuthenticatorValidationTypeOnFirstLaunch;
|
|
||||||
|
|
||||||
__block BOOL validated = YES;
|
|
||||||
__block NSError *error = nil;
|
|
||||||
tValidationCompletion completion = ^(BOOL validated_, NSError *error_) {
|
|
||||||
validated = validated_;
|
|
||||||
error = error_;
|
|
||||||
};
|
|
||||||
[_sut validateInstallationWithCompletion:completion];
|
|
||||||
[_sut validationFailedWithError:[NSError errorWithDomain:kBITAuthenticatorErrorDomain code:0 userInfo:nil]
|
|
||||||
completion:completion];
|
|
||||||
|
|
||||||
assertThatBool(validated, equalToBool(NO));
|
|
||||||
assertThat(error, notNilValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) testThatFailedRequiredValidationShowsAuthenticationViewController {
|
|
||||||
id delegateMock = mockProtocol(@protocol(BITAuthenticatorDelegate));
|
|
||||||
_sut.delegate = delegateMock;
|
|
||||||
_sut.validationType = BITAuthenticatorValidationTypeOnAppActive;
|
|
||||||
|
|
||||||
[_sut validationFailedWithError:[NSError errorWithDomain:kBITAuthenticatorErrorDomain code:0 userInfo:nil]
|
|
||||||
completion:_sut.defaultValidationCompletionBlock];
|
|
||||||
[verifyCount(delegateMock, times(1)) authenticator:_sut willShowAuthenticationController:(id)anything()];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) testThatFailedOptionalValidationDoesNotShowAuthenticationViewController {
|
|
||||||
id delegateMock = mockProtocol(@protocol(BITAuthenticatorDelegate));
|
|
||||||
_sut.delegate = delegateMock;
|
|
||||||
_sut.validationType = BITAuthenticatorValidationTypeOptional;
|
|
||||||
|
|
||||||
[_sut validationFailedWithError:nil
|
|
||||||
completion:_sut.defaultValidationCompletionBlock];
|
|
||||||
[verifyCount(delegateMock, never()) authenticator:_sut willShowAuthenticationController:(id)anything()];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) testThatSuccessValidationCallsTheCompletionBlock {
|
|
||||||
id delegateMock = mockProtocol(@protocol(BITAuthenticatorDelegate));
|
|
||||||
_sut.delegate = delegateMock;
|
|
||||||
_sut.validationType = BITAuthenticatorValidationTypeOnFirstLaunch;
|
|
||||||
|
|
||||||
__block BOOL validated = NO;
|
|
||||||
__block NSError *error = nil;
|
|
||||||
tValidationCompletion completion = ^(BOOL validated_, NSError *error_) {
|
|
||||||
validated = validated_;
|
|
||||||
error = error_;
|
|
||||||
};
|
|
||||||
[_sut validateInstallationWithCompletion:completion];
|
|
||||||
[_sut validationSucceededWithCompletion:completion];
|
|
||||||
|
|
||||||
assertThatBool(validated, equalToBool(YES));
|
|
||||||
assertThat(error, nilValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) testThatAuthTokenIsResettingWhenVendorIdentifierChanged {
|
|
||||||
MyDeviceWithIdentifierForVendor *device = [MyDeviceWithIdentifierForVendor new];
|
|
||||||
_sut.currentDevice = (id)device;
|
|
||||||
[_sut didAuthenticateWithToken:@"SuperToken"];
|
|
||||||
NSString *ident = [_sut installationIdentification];
|
|
||||||
assertThat(ident, equalTo(@"SuperToken"));
|
|
||||||
device.identifierForVendor = [NSUUID UUID];
|
|
||||||
ident = [_sut installationIdentification];
|
|
||||||
assertThat(ident, isNot(equalTo(@"SuperToken")));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - Test installationIdentificationValidated Flag
|
#pragma mark - Test installationIdentificationValidated Flag
|
||||||
- (void) testThatFlagIsResetOnFailedValidation {
|
|
||||||
_sut.validationType = BITAuthenticatorValidationTypeOnFirstLaunch;
|
|
||||||
assertThatBool(_sut.installationIdentificationValidated, equalToBool(NO));
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) testThatFlagIsSetOnFailedValidation {
|
|
||||||
_sut.validationType = BITAuthenticatorValidationTypeOnFirstLaunch;
|
|
||||||
[_sut validationSucceededWithCompletion:nil];
|
|
||||||
assertThatBool(_sut.installationIdentificationValidated, equalToBool(YES));
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) testThatApplicationBackgroundingResetsValidatedFlagInValidationTypeOnAppActive {
|
- (void) testThatApplicationBackgroundingResetsValidatedFlagInValidationTypeOnAppActive {
|
||||||
_sut.validationType = BITAuthenticatorValidationTypeOnAppActive;
|
_sut.restrictionEnforcementFrequency = BITAuthenticatorAppRestrictionEnforcementOnAppActive;
|
||||||
//trigger flag set to YES
|
_sut.validated = YES;
|
||||||
[_sut validationSucceededWithCompletion:nil];
|
|
||||||
[_sut applicationWillResignActive:nil];
|
[_sut applicationWillResignActive:nil];
|
||||||
assertThatBool(_sut.installationIdentificationValidated, equalToBool(NO));
|
assertThatBool(_sut.isValidated, equalToBool(NO));
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) testThatApplicationBackgroundingKeepValidatedFlag {
|
- (void) testThatApplicationBackgroundingKeepValidatedFlag {
|
||||||
_sut.validationType = BITAuthenticatorValidationTypeOnFirstLaunch;
|
_sut.restrictApplicationUsage = BITAuthenticatorAppRestrictionEnforcementOnFirstLaunch;
|
||||||
//trigger flag set to YES
|
_sut.validated = YES;
|
||||||
[_sut validationSucceededWithCompletion:nil];
|
|
||||||
[_sut applicationWillResignActive:nil];
|
[_sut applicationWillResignActive:nil];
|
||||||
assertThatBool(_sut.installationIdentificationValidated, equalToBool(YES));
|
assertThatBool(_sut.isValidated, equalToBool(YES));
|
||||||
}
|
|
||||||
|
|
||||||
- (void) testThatInitialAuthSetsValidatedFlag {
|
|
||||||
_sut.validationType = BITAuthenticatorValidationTypeOnFirstLaunch;
|
|
||||||
[_sut didAuthenticateWithToken:@"MyToken"];
|
|
||||||
assertThatBool(_sut.installationIdentificationValidated, equalToBool(YES));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user