From 8fb363fed735afa72eb27ff801dc53c07297ad90 Mon Sep 17 00:00:00 2001 From: Martin Pilch Date: Sat, 2 May 2015 18:46:39 +0200 Subject: [PATCH 1/2] Added Vimeo provider --- .../SimpleAuthVimeoLoginViewController.h | 13 ++ .../SimpleAuthVimeoLoginViewController.m | 40 ++++ Pod/Providers/Vimeo/SimpleAuthVimeoProvider.h | 13 ++ Pod/Providers/Vimeo/SimpleAuthVimeoProvider.m | 211 ++++++++++++++++++ SimpleAuth.podspec | 5 + 5 files changed, 282 insertions(+) create mode 100644 Pod/Providers/Vimeo/SimpleAuthVimeoLoginViewController.h create mode 100644 Pod/Providers/Vimeo/SimpleAuthVimeoLoginViewController.m create mode 100644 Pod/Providers/Vimeo/SimpleAuthVimeoProvider.h create mode 100644 Pod/Providers/Vimeo/SimpleAuthVimeoProvider.m diff --git a/Pod/Providers/Vimeo/SimpleAuthVimeoLoginViewController.h b/Pod/Providers/Vimeo/SimpleAuthVimeoLoginViewController.h new file mode 100644 index 0000000..c011795 --- /dev/null +++ b/Pod/Providers/Vimeo/SimpleAuthVimeoLoginViewController.h @@ -0,0 +1,13 @@ +// +// SimpleAuthVimeoLoginViewController.h +// SimpleAuth +// +// Created by Martin Pilch on 21/4/15. +// Copyright (c) 2015 Martin Pilch, All rights reserved. +// + +#import "SimpleAuthWebViewController.h" + +@interface SimpleAuthVimeoLoginViewController : SimpleAuthWebViewController + +@end diff --git a/Pod/Providers/Vimeo/SimpleAuthVimeoLoginViewController.m b/Pod/Providers/Vimeo/SimpleAuthVimeoLoginViewController.m new file mode 100644 index 0000000..898c318 --- /dev/null +++ b/Pod/Providers/Vimeo/SimpleAuthVimeoLoginViewController.m @@ -0,0 +1,40 @@ +// +// SimpleAuthVimeoLoginViewController.m +// SimpleAuthVimeo +// +// Created by Martin Pilch on 21/4/15. +// Copyright (c) 2015 Martin Pilch, All rights reserved. +// + +#import "SimpleAuthVimeoLoginViewController.h" + +@implementation SimpleAuthVimeoLoginViewController + +#pragma mark - SimpleAuthWebViewController + +- (instancetype)initWithOptions:(NSDictionary *)options requestToken:(NSDictionary *)requestToken { + if ((self = [super initWithOptions:options requestToken:requestToken])) { + self.title = @"Vimeo"; + } + return self; +} + + +- (NSURLRequest *)initialRequest { + NSMutableDictionary *parameters = [NSMutableDictionary new]; + parameters[@"client_id"] = self.options[@"client_id"]; + parameters[@"redirect_uri"] = self.options[SimpleAuthRedirectURIKey]; + parameters[@"response_type"] = @"code"; + parameters[@"state"] = self.options[@"state"]; + if (self.options[@"scope"]) { + parameters[@"scope"] = [self.options[@"scope"] componentsJoinedByString:@" "]; + } + NSString *URLString = [NSString stringWithFormat: + @"https://api.vimeo.com/oauth/authorize?%@", + [CMDQueryStringSerialization queryStringWithDictionary:parameters]]; + NSURL *URL = [NSURL URLWithString:URLString]; + + return [NSURLRequest requestWithURL:URL]; +} + +@end diff --git a/Pod/Providers/Vimeo/SimpleAuthVimeoProvider.h b/Pod/Providers/Vimeo/SimpleAuthVimeoProvider.h new file mode 100644 index 0000000..ecd411f --- /dev/null +++ b/Pod/Providers/Vimeo/SimpleAuthVimeoProvider.h @@ -0,0 +1,13 @@ +// +// SimpleAuthVimeoProvider.h +// SimpleAuth +// +// Created by Martin Pilch on 21/4/15. +// Copyright (c) 2015 Martin Pilch, All rights reserved. +// + +#import "SimpleAuthProvider.h" + +@interface SimpleAuthVimeoProvider : SimpleAuthProvider + +@end diff --git a/Pod/Providers/Vimeo/SimpleAuthVimeoProvider.m b/Pod/Providers/Vimeo/SimpleAuthVimeoProvider.m new file mode 100644 index 0000000..2d0dc48 --- /dev/null +++ b/Pod/Providers/Vimeo/SimpleAuthVimeoProvider.m @@ -0,0 +1,211 @@ +// +// SimpleAuthVimeoProvider.m +// SimpleAuth +// +// Created by Martin Pilch on 21/4/15. +// Copyright (c) 2015 Martin Pilch, All rights reserved. +// + +#import "SimpleAuthVimeoProvider.h" +#import "SimpleAuthVimeoLoginViewController.h" + +#import "UIViewController+SimpleAuthAdditions.h" +#import + +@implementation SimpleAuthVimeoProvider + +#pragma mark - SimpleAuthProvider + ++ (NSString *)type { + return @"dribbble"; +} + ++ (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 *options = [NSMutableDictionary dictionaryWithDictionary:[super defaultOptions]]; + options[SimpleAuthPresentInterfaceBlockKey] = presentBlock; + options[SimpleAuthDismissInterfaceBlockKey] = dismissBlock; + options[SimpleAuthRedirectURIKey] = @"http://"; + + return options; +} + + +- (void)authorizeWithCompletion:(SimpleAuthRequestHandler)completion { + [[[self accessToken] + flattenMap:^(id responseObject) { + NSArray *signals = @[ + [self accountWithAccessToken:responseObject], + [RACSignal return:responseObject] + ]; + return [self rac_liftSelector:@selector(dictionaryWithAccount:accessToken:) withSignalsFromArray:signals]; + }] + subscribeNext:^(id responseObject) { + completion(responseObject, nil); + } + error:^(NSError *error) { + completion(nil, error); + }]; +} + +#pragma mark - Private + +- (RACSignal *)authorizationCode { + return [RACSignal createSignal:^RACDisposable *(id subscriber) { + dispatch_async(dispatch_get_main_queue(), ^{ + SimpleAuthVimeoLoginViewController *login = [[SimpleAuthVimeoLoginViewController 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"]; + NSString *state = dictionary[@"state"]; + + // Check for error + if (![code length]) { + [subscriber sendError:error]; + return; + } + + if (![state isEqualToString:self.options["state"]]) { + [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 request + NSDictionary *parameters = @{ + @"code" : code, + @"grant_type" : @"authorization_code", + @"redirect_uri" : self.options[SimpleAuthRedirectURIKey], + }; + NSString *query = [CMDQueryStringSerialization queryStringWithDictionary:parameters]; + NSURL *URL = [NSURL URLWithString:@"https://api.vimeo.com/oauth/access_token"]; + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL]; + request.HTTPMethod = @"POST"; + request.HTTPBody = [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 *)accessToken { + return [[self authorizationCode] flattenMap:^(id responseObject) { + return [self accessTokenWithAuthorizationCode:responseObject]; + }]; +} + +- (RACSignal *)accountWithAccessToken:(NSDictionary *)accessToken { + return [RACSignal createSignal:^RACDisposable *(id subscriber) { + NSDictionary *parameters = @{ + @"access_token" : accessToken[@"access_token"], + }; + NSString *URLString = [NSString stringWithFormat:@"https://api.vimeo.com/me?%@", + [CMDQueryStringSerialization queryStringWithDictionary:parameters]]; + NSURL *URL = [NSURL URLWithString:URLString]; + NSURLRequest *request = [NSURLRequest requestWithURL:URL]; + [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 dictionary]; + + // Provider + dictionary[@"provider"] = [[self class] type]; + + // Credentials + dictionary[@"credentials"] = @{@"token" : accessToken[@"access_token"]}; + + // User ID + dictionary[@"uid"] = account[@"id"]; + + // Raw response + dictionary[@"extra"] = @{ + @"raw_info" : account + }; + + // User info + NSMutableDictionary *user = [NSMutableDictionary new]; + user[@"name"] = account[@"name"]; + user[@"username"] = account[@"username"]; + user[@"image"] = account[@"avatar_url"]; + dictionary[@"info"] = user; + + return dictionary; +} + +@end diff --git a/SimpleAuth.podspec b/SimpleAuth.podspec index 4a9df8f..fa9027c 100755 --- a/SimpleAuth.podspec +++ b/SimpleAuth.podspec @@ -128,4 +128,9 @@ Pod::Spec.new do |s| ss.private_header_files = 'Pod/Providers/OneDriveWeb/*.h' end + s.subspec 'Vimeo' do |ss| + ss.dependency 'SimpleAuth/Core' + ss.source_files = 'Pod/Providers/Vimeo' + ss.private_header_files = 'Pod/Providers/Vimeo/*.h' + end end From 157454c24f0425c750c298207bfd833befcf3870 Mon Sep 17 00:00:00 2001 From: Martin Pilch Date: Sat, 2 May 2015 18:46:48 +0200 Subject: [PATCH 2/2] Vimeo provider added to example --- Example/SimpleAuth/Providers.plist | 1 + Example/SimpleAuth/SADAppDelegate.m | 3 +++ 2 files changed, 4 insertions(+) diff --git a/Example/SimpleAuth/Providers.plist b/Example/SimpleAuth/Providers.plist index efa2451..62ab846 100644 --- a/Example/SimpleAuth/Providers.plist +++ b/Example/SimpleAuth/Providers.plist @@ -19,5 +19,6 @@ trello-web box-web onedrive-web + vimeo diff --git a/Example/SimpleAuth/SADAppDelegate.m b/Example/SimpleAuth/SADAppDelegate.m index 98a5cb2..6b4e9ca 100644 --- a/Example/SimpleAuth/SADAppDelegate.m +++ b/Example/SimpleAuth/SADAppDelegate.m @@ -88,6 +88,9 @@ - (void)configureAuthorizaionProviders { // client_id and client_secret are required SimpleAuth.configuration[@"onedrive-web"] = @{}; + + // client_id and redirect_uri are required + SimpleAuth.configuration[@"vimeo"] = @{}; }