diff --git a/Example/Podfile.lock b/Example/Podfile.lock index 826f91f..dd7a0b1 100644 --- a/Example/Podfile.lock +++ b/Example/Podfile.lock @@ -31,6 +31,7 @@ PODS: - SimpleAuth/Tumblr (= 0.3.9) - SimpleAuth/Twitter (= 0.3.9) - SimpleAuth/TwitterWeb (= 0.3.9) + - SimpleAuth/MailChimp (= 0.3.9) - SimpleAuth/BoxWeb (0.3.9): - SimpleAuth/Core - SimpleAuth/Core (0.3.9): @@ -72,6 +73,8 @@ PODS: - SimpleAuth/TwitterWeb (0.3.9): - cocoa-oauth - SimpleAuth/Core + - SimpleAuth/MailChimp (0.3.9): + - SimpleAuth/Core DEPENDENCIES: - SimpleAuth (from `..`) diff --git a/Example/SimpleAuth/Providers.plist b/Example/SimpleAuth/Providers.plist index efa2451..febe0be 100644 --- a/Example/SimpleAuth/Providers.plist +++ b/Example/SimpleAuth/Providers.plist @@ -19,5 +19,6 @@ trello-web box-web onedrive-web + mailchimp diff --git a/Example/SimpleAuth/SADAppDelegate.m b/Example/SimpleAuth/SADAppDelegate.m index 98a5cb2..9db2b3a 100644 --- a/Example/SimpleAuth/SADAppDelegate.m +++ b/Example/SimpleAuth/SADAppDelegate.m @@ -88,6 +88,10 @@ - (void)configureAuthorizaionProviders { // client_id and client_secret are required SimpleAuth.configuration[@"onedrive-web"] = @{}; + + // client_id, client_secret, and redirect_uri are required + SimpleAuth.configuration[@"mailchimp"] = @{}; + } diff --git a/Pod/Providers/MailChimp/SimpleAuthMailChimpConstants.h b/Pod/Providers/MailChimp/SimpleAuthMailChimpConstants.h new file mode 100644 index 0000000..7f18aa5 --- /dev/null +++ b/Pod/Providers/MailChimp/SimpleAuthMailChimpConstants.h @@ -0,0 +1,16 @@ +// +// SimpleAuthMailChimpConstants.h +// SimpleAuth +// +// Created by Tal Kain . +// Copyright (c) 2015 Fire Place Inc. All rights reserved. +// + +#ifndef SimpleAuthMailChimpConstants_h +#define SimpleAuthMailChimpConstants_h + +FOUNDATION_EXPORT NSString *const MAIL_CHIMP_AUTHORIZE_URI; +FOUNDATION_EXPORT NSString *const MAIL_CHIMP_ACCESS_TOKEN_URI; +FOUNDATION_EXPORT NSString *const MAIL_CHIMP_META_DATA_END_POINT_URI; + +#endif /* SimpleAuthMailChimpConstants_h */ diff --git a/Pod/Providers/MailChimp/SimpleAuthMailChimpConstants.m b/Pod/Providers/MailChimp/SimpleAuthMailChimpConstants.m new file mode 100644 index 0000000..3316e74 --- /dev/null +++ b/Pod/Providers/MailChimp/SimpleAuthMailChimpConstants.m @@ -0,0 +1,13 @@ +// +// SimpleAuthMailChimpConstants.m +// SimpleAuth +// +// Created by Tal Kain . +// Copyright (c) 2015 Fire Place Inc. All rights reserved. +// + +// Based on https://apidocs.mailchimp.com/oauth2/ + +NSString *const MAIL_CHIMP_AUTHORIZE_URI = @"https://login.mailchimp.com/oauth2/authorize"; +NSString *const MAIL_CHIMP_ACCESS_TOKEN_URI = @"https://login.mailchimp.com/oauth2/token"; +NSString *const MAIL_CHIMP_META_DATA_END_POINT_URI = @"https://login.mailchimp.com/oauth2/metadata"; diff --git a/Pod/Providers/MailChimp/SimpleAuthMailChimpLoginViewController.h b/Pod/Providers/MailChimp/SimpleAuthMailChimpLoginViewController.h new file mode 100644 index 0000000..f1c24a1 --- /dev/null +++ b/Pod/Providers/MailChimp/SimpleAuthMailChimpLoginViewController.h @@ -0,0 +1,14 @@ +// +// SimpleAuthMailChimpLoginViewController.h +// SimpleAuth +// +// Created by Tal Kain . +// Based on BoxWeb's provider created by dkhamsing and FoursquareWeb's provider created by Julien Seren-Rosso +// Copyright (c) 2015 Fire Place Inc. All rights reserved. +// + +#import "SimpleAuthWebViewController.h" + +@interface SimpleAuthMailChimpLoginViewController : SimpleAuthWebViewController + +@end diff --git a/Pod/Providers/MailChimp/SimpleAuthMailChimpLoginViewController.m b/Pod/Providers/MailChimp/SimpleAuthMailChimpLoginViewController.m new file mode 100644 index 0000000..e787b76 --- /dev/null +++ b/Pod/Providers/MailChimp/SimpleAuthMailChimpLoginViewController.m @@ -0,0 +1,38 @@ +// +// SimpleAuthMailChimpLoginViewController.m +// SimpleAuth +// +// Created by Tal Kain . +// Based on BoxWeb's provider created by dkhamsing and FoursquareWeb's provider created by Julien Seren-Rosso +// Copyright (c) 2015 Fire Place Inc. All rights reserved. +// + +#import "SimpleAuthMailChimpLoginViewController.h" +#import "SimpleAuthMailChimpConstants.h" + +@implementation SimpleAuthMailChimpLoginViewController + +#pragma mark - SimpleAuthWebViewController + +- (instancetype)initWithOptions:(NSDictionary *)options requestToken:(NSDictionary *)requestToken { + if ((self = [super initWithOptions:options requestToken:requestToken])) { + self.title = @"MailChimp"; + } + return self; +} + +- (NSURLRequest *)initialRequest { + NSDictionary *parameters = @{ + @"client_id" : self.options[@"client_id"], + @"redirect_uri" : self.options[SimpleAuthRedirectURIKey], + @"response_type" : @"code" + }; + NSString *URLString = [NSString stringWithFormat:@"%@?%@", + MAIL_CHIMP_AUTHORIZE_URI, + [CMDQueryStringSerialization queryStringWithDictionary:parameters]]; + NSURL *URL = [NSURL URLWithString:URLString]; + + return [NSURLRequest requestWithURL:URL]; +} + +@end diff --git a/Pod/Providers/MailChimp/SimpleAuthMailChimpProvider.h b/Pod/Providers/MailChimp/SimpleAuthMailChimpProvider.h new file mode 100644 index 0000000..f8d00ab --- /dev/null +++ b/Pod/Providers/MailChimp/SimpleAuthMailChimpProvider.h @@ -0,0 +1,14 @@ +// +// SimpleAuthMailChimpProvider.h +// SimpleAuth +// +// Created by Tal Kain . +// Based on BoxWeb's provider created by dkhamsing and FoursquareWeb's provider created by Julien Seren-Rosso +// Copyright (c) 2015 Fire Place Inc. All rights reserved. +// + +#import "SimpleAuthProvider.h" + +@interface SimpleAuthMailChimpProvider : SimpleAuthProvider + +@end diff --git a/Pod/Providers/MailChimp/SimpleAuthMailChimpProvider.m b/Pod/Providers/MailChimp/SimpleAuthMailChimpProvider.m new file mode 100644 index 0000000..013833f --- /dev/null +++ b/Pod/Providers/MailChimp/SimpleAuthMailChimpProvider.m @@ -0,0 +1,210 @@ +// +// SimpleAuthMailChimpProvider.m +// SimpleAuth +// +// Created by Tal Kain . +// Based on BoxWeb's provider created by dkhamsing and FoursquareWeb's provider created by Julien Seren-Rosso +// Copyright (c) 2015 Fire Place Inc. All rights reserved. +// + +#import "SimpleAuthMailChimpProvider.h" +#import "SimpleAuthMailChimpLoginViewController.h" +#import "SimpleAuthMailChimpConstants.h" + +#import +#import "UIViewController+SimpleAuthAdditions.h" + +@implementation SimpleAuthMailChimpProvider + +#pragma mark - SimpleAuthProvider + ++ (NSString *)type { + return @"mailchimp"; +} + + ++ (NSDictionary *)defaultOptions { + + // Default present block + SimpleAuthInterfaceHandler presentBlock = ^(UIViewController *controller) { + UINavigationController *navigation = [[UINavigationController alloc] initWithRootViewController:controller]; + navigation.modalPresentationStyle = UIModalPresentationFormSheet; + UIViewController *presented = [UIViewController SimpleAuth_presentedViewController]; + [presented presentViewController:navigation animated:YES completion:nil]; + }; + + // Default dismiss block + SimpleAuthInterfaceHandler dismissBlock = ^(id controller) { + [controller dismissViewControllerAnimated:YES completion:nil]; + }; + + NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithDictionary:[super defaultOptions]]; + dictionary[SimpleAuthPresentInterfaceBlockKey] = presentBlock; + dictionary[SimpleAuthDismissInterfaceBlockKey] = dismissBlock; + return dictionary; +} + + +- (void)authorizeWithCompletion:(SimpleAuthRequestHandler)completion { + [[[self accessToken] + flattenMap:^(NSDictionary *response) { + NSArray *signals = @[ + [self accountWithAccessToken:response], + [RACSignal return:response] + ]; + return [self rac_liftSelector:@selector(dictionaryWithAccount:accessToken:) withSignalsFromArray:signals]; + }] + subscribeNext:^(NSDictionary *response) { + completion(response, nil); + } + error:^(NSError *error) { + completion(nil, error); + }]; +} + +#pragma mark - Private + + +- (RACSignal *)accessToken { + return [[self authorizationCode] flattenMap:^(id responseObject) { + return [self accessTokenWithAuthorizationCode:responseObject]; + }]; +} + +- (RACSignal *)authorizationCode { + return [RACSignal createSignal:^RACDisposable *(id subscriber) { + dispatch_async(dispatch_get_main_queue(), ^{ + SimpleAuthMailChimpLoginViewController *login = [[SimpleAuthMailChimpLoginViewController alloc] initWithOptions:self.options]; + login.completion = ^(UIViewController *login, NSURL *URL, NSError *error) { + SimpleAuthInterfaceHandler dismissBlock = self.options[SimpleAuthDismissInterfaceBlockKey]; + dismissBlock(login); + + // Parse URL + NSString *fragment = [URL query]; + NSDictionary *dictionary = [CMDQueryStringSerialization dictionaryWithQueryString:fragment]; + NSString *code = dictionary[@"code"]; + + // Check for error + if (![code length]) { + [subscriber sendError:error]; + return; + } + + // Send completion + [subscriber sendNext:code]; + [subscriber sendCompleted]; + }; + + SimpleAuthInterfaceHandler block = self.options[SimpleAuthPresentInterfaceBlockKey]; + block(login); + }); + return nil; + }]; +} + + +- (RACSignal *)accessTokenWithAuthorizationCode:(NSString *)code { + return [RACSignal createSignal:^RACDisposable *(id subscriber) { + + // Build parameters + NSDictionary *parameters = @{ + @"code" : code, + @"client_id" : self.options[@"client_id"], + @"client_secret" : self.options[@"client_secret"], + @"redirect_uri" : self.options[SimpleAuthRedirectURIKey], + @"grant_type" : @"authorization_code" + }; + + // Build request + NSString *query = [CMDQueryStringSerialization queryStringWithDictionary:parameters]; + NSURL *URL = [NSURL URLWithString:MAIL_CHIMP_ACCESS_TOKEN_URI]; + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL]; + [request setHTTPMethod:@"POST"]; + [request setValue:@"application/x-www-form-urlencoded; charset=utf-8" forHTTPHeaderField:@"Content-Type"]; + [request setHTTPBody:[query dataUsingEncoding:NSUTF8StringEncoding]]; + + // Run request + [NSURLConnection sendAsynchronousRequest:request queue:self.operationQueue + completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) { + NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(200, 99)]; + NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode]; + if ([indexSet containsIndex:statusCode] && data) { + NSError *parseError = nil; + NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&parseError]; + if (dictionary) { + [subscriber sendNext:dictionary]; + [subscriber sendCompleted]; + } + else { + [subscriber sendError:parseError]; + } + } + else { + [subscriber sendError:connectionError]; + } + }]; + return nil; + }]; +} + +- (RACSignal *)accountWithAccessToken:(NSDictionary *)accessToken { + return [RACSignal createSignal:^RACDisposable *(id subscriber) { + NSURL *URL = [NSURL URLWithString:MAIL_CHIMP_META_DATA_END_POINT_URI]; + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL]; + NSString *oauthCode = [NSString stringWithFormat:@"OAuth %@", accessToken[@"access_token"]]; + [request setValue:oauthCode forHTTPHeaderField:@"Authorization"]; + [NSURLConnection sendAsynchronousRequest:request queue:self.operationQueue + completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) { + NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(200, 99)]; + NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode]; + if ([indexSet containsIndex:statusCode] && data) { + NSError *parseError = nil; + NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&parseError]; + if (dictionary) { + [subscriber sendNext:dictionary]; + [subscriber sendCompleted]; + } + else { + [subscriber sendError:parseError]; + } + } + else { + [subscriber sendError:connectionError]; + } + }]; + return nil; + }]; +} + + +- (NSDictionary *)dictionaryWithAccount:(NSDictionary *)account accessToken:(NSDictionary *)accessToken { + NSMutableDictionary *dictionary = [NSMutableDictionary new]; + + // Provider + dictionary[@"provider"] = [[self class] type]; + + // Credentials + dictionary[@"credentials"] = @{ + @"token" : accessToken[@"access_token"], + @"type" : @"authorization_code", + @"expires_in": accessToken[@"expires_in"], + }; + + // User ID + dictionary[@"id"] = account[@"id"]; + + // Raw response + dictionary[@"extra"] = @{ + @"raw_info" : account + }; + + // User info + NSMutableDictionary *user = [NSMutableDictionary new]; + user[@"login"] = account[@"login"]; + user[@"name"] = account[@"name"]; + dictionary[@"info"] = user; + + return dictionary; +} + +@end diff --git a/SimpleAuth.podspec b/SimpleAuth.podspec index 6125ab9..0e12f79 100755 --- a/SimpleAuth.podspec +++ b/SimpleAuth.podspec @@ -128,4 +128,10 @@ Pod::Spec.new do |s| ss.private_header_files = 'Pod/Providers/OneDriveWeb/*.h' end + s.subspec 'MailChimp' do |ss| + ss.dependency 'SimpleAuth/Core' + ss.source_files = 'Pod/Providers/MailChimp' + ss.private_header_files = 'Pod/Providers/MailChimp/*.h' + end + end