├── .ruby-version ├── Source ├── Other │ ├── en.lproj │ │ └── InfoPlist.strings │ ├── ReverseAuthExample-Prefix.pch │ ├── main.m │ └── ReverseAuthExample-Info.plist └── Classes │ ├── TWTViewController.h │ ├── TWTAppDelegate.h │ ├── TWTAppDelegate.m │ ├── TWTSignedRequest.h │ ├── TWTAPIManager.h │ ├── TWTSignedRequest.m │ ├── TWTAPIManager.m │ └── TWTViewController.m ├── Resources └── twitter.png ├── back-to-the-future.jpg ├── Podfile ├── ReverseAuthSampleApp └── Images.xcassets │ ├── AppIcon.appiconset │ ├── AppIcon-29x29.png │ ├── AppIcon-80x80.png │ ├── AppIcon-120x120.png │ ├── AppIcon-180x180.png │ └── Contents.json │ └── LaunchImage.launchimage │ ├── Default@2x.png │ ├── Default-568h@2x.png │ ├── Default-750x1334.png │ ├── Default-Retina5.5HD.png │ └── Contents.json ├── .gitignore ├── ReverseAuthExample.xcworkspace ├── contents.xcworkspacedata └── xcshareddata │ └── ReverseAuthExample.xccheckout ├── Makefile ├── LICENSE ├── README.md └── ReverseAuthExample.xcodeproj └── project.pbxproj /.ruby-version: -------------------------------------------------------------------------------- 1 | 2.3.1 2 | -------------------------------------------------------------------------------- /Source/Other/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Resources/twitter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seancook/TWReverseAuthExample/HEAD/Resources/twitter.png -------------------------------------------------------------------------------- /back-to-the-future.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seancook/TWReverseAuthExample/HEAD/back-to-the-future.jpg -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '6.0' 3 | 4 | target 'ReverseAuth' do 5 | pod 'Base64' 6 | pod 'OAuthCore' 7 | end 8 | 9 | -------------------------------------------------------------------------------- /ReverseAuthSampleApp/Images.xcassets/AppIcon.appiconset/AppIcon-29x29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seancook/TWReverseAuthExample/HEAD/ReverseAuthSampleApp/Images.xcassets/AppIcon.appiconset/AppIcon-29x29.png -------------------------------------------------------------------------------- /ReverseAuthSampleApp/Images.xcassets/AppIcon.appiconset/AppIcon-80x80.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seancook/TWReverseAuthExample/HEAD/ReverseAuthSampleApp/Images.xcassets/AppIcon.appiconset/AppIcon-80x80.png -------------------------------------------------------------------------------- /ReverseAuthSampleApp/Images.xcassets/AppIcon.appiconset/AppIcon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seancook/TWReverseAuthExample/HEAD/ReverseAuthSampleApp/Images.xcassets/AppIcon.appiconset/AppIcon-120x120.png -------------------------------------------------------------------------------- /ReverseAuthSampleApp/Images.xcassets/AppIcon.appiconset/AppIcon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seancook/TWReverseAuthExample/HEAD/ReverseAuthSampleApp/Images.xcassets/AppIcon.appiconset/AppIcon-180x180.png -------------------------------------------------------------------------------- /ReverseAuthSampleApp/Images.xcassets/LaunchImage.launchimage/Default@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seancook/TWReverseAuthExample/HEAD/ReverseAuthSampleApp/Images.xcassets/LaunchImage.launchimage/Default@2x.png -------------------------------------------------------------------------------- /ReverseAuthSampleApp/Images.xcassets/LaunchImage.launchimage/Default-568h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seancook/TWReverseAuthExample/HEAD/ReverseAuthSampleApp/Images.xcassets/LaunchImage.launchimage/Default-568h@2x.png -------------------------------------------------------------------------------- /ReverseAuthSampleApp/Images.xcassets/LaunchImage.launchimage/Default-750x1334.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seancook/TWReverseAuthExample/HEAD/ReverseAuthSampleApp/Images.xcassets/LaunchImage.launchimage/Default-750x1334.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.swp 3 | *~.nib 4 | 5 | build/ 6 | 7 | *.pbxuser 8 | *.perspective 9 | *.perspectivev3 10 | xcuserdata/ 11 | project.xcworkspace/ 12 | 13 | Pods 14 | Podfile.lock 15 | 16 | .ruby-version 17 | -------------------------------------------------------------------------------- /ReverseAuthSampleApp/Images.xcassets/LaunchImage.launchimage/Default-Retina5.5HD.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seancook/TWReverseAuthExample/HEAD/ReverseAuthSampleApp/Images.xcassets/LaunchImage.launchimage/Default-Retina5.5HD.png -------------------------------------------------------------------------------- /Source/Other/ReverseAuthExample-Prefix.pch: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #ifndef __IPHONE_7_0 4 | #warning "This project was designed to be built with iOS7." 5 | #endif 6 | 7 | #ifdef __OBJC__ 8 | #import 9 | #import 10 | #endif 11 | 12 | -------------------------------------------------------------------------------- /ReverseAuthExample.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PROJECT := ReverseAuth 2 | WORKSPACE := $(PROJECT)Example.xcworkspace 3 | SCHEME := $(PROJECT) 4 | 5 | default: check-xctool 6 | xctool -workspace $(WORKSPACE) -scheme $(SCHEME) 7 | 8 | check-xctool: 9 | @which xctool > /dev/null 10 | 11 | clean: check-xctool 12 | xctool -workspace $(WORKSPACE) -scheme $(SCHEME) clean 13 | 14 | .PHONY: clean default 15 | -------------------------------------------------------------------------------- /ReverseAuthSampleApp/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "29x29", 5 | "idiom" : "iphone", 6 | "filename" : "AppIcon-29x29.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "idiom" : "iphone", 11 | "size" : "29x29", 12 | "scale" : "3x" 13 | }, 14 | { 15 | "size" : "40x40", 16 | "idiom" : "iphone", 17 | "filename" : "AppIcon-80x80.png", 18 | "scale" : "2x" 19 | }, 20 | { 21 | "idiom" : "iphone", 22 | "size" : "40x40", 23 | "scale" : "3x" 24 | }, 25 | { 26 | "size" : "60x60", 27 | "idiom" : "iphone", 28 | "filename" : "AppIcon-120x120.png", 29 | "scale" : "2x" 30 | }, 31 | { 32 | "size" : "60x60", 33 | "idiom" : "iphone", 34 | "filename" : "AppIcon-180x180.png", 35 | "scale" : "3x" 36 | } 37 | ], 38 | "info" : { 39 | "version" : 1, 40 | "author" : "xcode" 41 | } 42 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 2 | 3 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 4 | 5 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 6 | 7 | -------------------------------------------------------------------------------- /ReverseAuthSampleApp/Images.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "extent" : "full-screen", 5 | "idiom" : "iphone", 6 | "subtype" : "736h", 7 | "filename" : "Default-Retina5.5HD.png", 8 | "minimum-system-version" : "8.0", 9 | "orientation" : "portrait", 10 | "scale" : "3x" 11 | }, 12 | { 13 | "extent" : "full-screen", 14 | "idiom" : "iphone", 15 | "subtype" : "667h", 16 | "filename" : "Default-750x1334.png", 17 | "minimum-system-version" : "8.0", 18 | "orientation" : "portrait", 19 | "scale" : "2x" 20 | }, 21 | { 22 | "orientation" : "portrait", 23 | "idiom" : "iphone", 24 | "extent" : "full-screen", 25 | "minimum-system-version" : "7.0", 26 | "filename" : "Default@2x.png", 27 | "scale" : "2x" 28 | }, 29 | { 30 | "extent" : "full-screen", 31 | "idiom" : "iphone", 32 | "subtype" : "retina4", 33 | "filename" : "Default-568h@2x.png", 34 | "minimum-system-version" : "7.0", 35 | "orientation" : "portrait", 36 | "scale" : "2x" 37 | } 38 | ], 39 | "info" : { 40 | "version" : 1, 41 | "author" : "xcode" 42 | } 43 | } -------------------------------------------------------------------------------- /Source/Classes/TWTViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // TWTViewController.h 3 | // ReverseAuthExample 4 | // 5 | // Copyright (c) 2011-2016 Sean Cook 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a 8 | // copy of this software and associated documentation files (the 9 | // "Software"), to deal in the Software without restriction, including 10 | // without limitation the rights to use, copy, modify, merge, publish, 11 | // distribute, sublicense, and/or sell copies of the Software, and to permit 12 | // persons to whom the Software is furnished to do so, subject to the 13 | // following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included 16 | // in all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 21 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 22 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 23 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 24 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | // 26 | 27 | @import UIKit; 28 | 29 | @interface TWTViewController : UIViewController 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /Source/Other/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // TWiOSReverseAuthExample 4 | // 5 | // Copyright (c) 2011-2016 Sean Cook 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a 8 | // copy of this software and associated documentation files (the 9 | // "Software"), to deal in the Software without restriction, including 10 | // without limitation the rights to use, copy, modify, merge, publish, 11 | // distribute, sublicense, and/or sell copies of the Software, and to permit 12 | // persons to whom the Software is furnished to do so, subject to the 13 | // following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included 16 | // in all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 21 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 22 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 23 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 24 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | // 26 | 27 | #import 28 | 29 | #import "TWTAppDelegate.h" 30 | 31 | int main(int argc, char *argv[]) 32 | { 33 | @autoreleasepool { 34 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([TWTAppDelegate class])); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Source/Classes/TWTAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // TWTAppDelegate.h 3 | // ReverseAuthExample 4 | // 5 | // Copyright (c) 2011-2016 Sean Cook 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a 8 | // copy of this software and associated documentation files (the 9 | // "Software"), to deal in the Software without restriction, including 10 | // without limitation the rights to use, copy, modify, merge, publish, 11 | // distribute, sublicense, and/or sell copies of the Software, and to permit 12 | // persons to whom the Software is furnished to do so, subject to the 13 | // following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included 16 | // in all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 21 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 22 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 23 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 24 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | // 26 | 27 | @import UIKit; 28 | 29 | @class TWTViewController; 30 | 31 | @interface TWTAppDelegate : UIResponder 32 | 33 | @property (strong, nonatomic) UIWindow *window; 34 | 35 | @property (strong, nonatomic) TWTViewController *viewController; 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /ReverseAuthExample.xcworkspace/xcshareddata/ReverseAuthExample.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | FB5AA608-2B0F-441A-BA4D-A597C1B9AD53 9 | IDESourceControlProjectName 10 | ReverseAuthExample 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | D7929EA114C24334861F87C6937CDA9631F46E80 14 | github.com:seancook/TWReverseAuthExample.git 15 | 16 | IDESourceControlProjectPath 17 | ReverseAuthExample.xcworkspace 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | D7929EA114C24334861F87C6937CDA9631F46E80 21 | .. 22 | 23 | IDESourceControlProjectURL 24 | github.com:seancook/TWReverseAuthExample.git 25 | IDESourceControlProjectVersion 26 | 111 27 | IDESourceControlProjectWCCIdentifier 28 | D7929EA114C24334861F87C6937CDA9631F46E80 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | D7929EA114C24334861F87C6937CDA9631F46E80 36 | IDESourceControlWCCName 37 | TWReverseAuthExample 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /Source/Other/ReverseAuthExample-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIconFiles 12 | 13 | ic_twitterapi.png 14 | ic_twitterapi@2x.png 15 | 16 | CFBundleIcons 17 | 18 | CFBundleIcons~ipad 19 | 20 | CFBundleIdentifier 21 | $(PRODUCT_BUNDLE_IDENTIFIER) 22 | CFBundleInfoDictionaryVersion 23 | 6.0 24 | CFBundleName 25 | ${PRODUCT_NAME} 26 | CFBundlePackageType 27 | APPL 28 | CFBundleShortVersionString 29 | 1.0 30 | CFBundleSignature 31 | ???? 32 | CFBundleVersion 33 | 1.0 34 | LSRequiresIPhoneOS 35 | 36 | NOTE: 37 | THIS IS FOR EXAMPLE PURPOSES ONLY. DO NOT SHIP YOUR CONSUMER KEYS AS PLAIN TEXT IN YOUR INFO.PLIST! 38 | TWITTER_CONSUMER_KEY 39 | 40 | TWITTER_CONSUMER_SECRET 41 | 42 | UIPrerenderedIcon 43 | 44 | UIStatusBarHidden 45 | 46 | UIStatusBarStyle 47 | UIStatusBarStyleBlackOpaque 48 | UISupportedInterfaceOrientations 49 | 50 | UIInterfaceOrientationPortrait 51 | UIInterfaceOrientationLandscapeLeft 52 | UIInterfaceOrientationLandscapeRight 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /Source/Classes/TWTAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // TWTAppDelegate.m 3 | // ReverseAuthExample 4 | // 5 | // Copyright (c) 2011-2016 Sean Cook 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a 8 | // copy of this software and associated documentation files (the 9 | // "Software"), to deal in the Software without restriction, including 10 | // without limitation the rights to use, copy, modify, merge, publish, 11 | // distribute, sublicense, and/or sell copies of the Software, and to permit 12 | // persons to whom the Software is furnished to do so, subject to the 13 | // following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included 16 | // in all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 21 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 22 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 23 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 24 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | // 26 | 27 | #import "TWTAppDelegate.h" 28 | #import "TWTViewController.h" 29 | 30 | @implementation TWTAppDelegate 31 | 32 | @synthesize window = _window; 33 | @synthesize viewController = _viewController; 34 | 35 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 36 | { 37 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 38 | self.viewController = [[TWTViewController alloc] initWithNibName:nil bundle:nil]; 39 | self.window.rootViewController = self.viewController; 40 | [self.window makeKeyAndVisible]; 41 | return YES; 42 | } 43 | 44 | @end 45 | -------------------------------------------------------------------------------- /Source/Classes/TWTSignedRequest.h: -------------------------------------------------------------------------------- 1 | // 2 | // TWTSignedRequest.h 3 | // ReverseAuthExample 4 | // 5 | // Copyright (c) 2011-2016 Sean Cook 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a 8 | // copy of this software and associated documentation files (the 9 | // "Software"), to deal in the Software without restriction, including 10 | // without limitation the rights to use, copy, modify, merge, publish, 11 | // distribute, sublicense, and/or sell copies of the Software, and to permit 12 | // persons to whom the Software is furnished to do so, subject to the 13 | // following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included 16 | // in all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 21 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 22 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 23 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 24 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | // 26 | 27 | @import Foundation; 28 | 29 | typedef NS_ENUM(NSInteger, TWTSignedRequestMethod) { 30 | TWSignedRequestMethodGET, 31 | TWSignedRequestMethodPOST, 32 | TWSignedRequestMethodDELETE 33 | }; 34 | 35 | typedef void(^TWTSignedRequestHandler) (NSData *data, NSURLResponse *response, NSError *error); 36 | 37 | @interface TWTSignedRequest : NSObject 38 | 39 | @property (nonatomic, copy) NSString *authToken; 40 | @property (nonatomic, copy) NSString *authTokenSecret; 41 | 42 | // Creates a new request 43 | - (instancetype)initWithURL:(NSURL *)url parameters:(NSDictionary *)parameters requestMethod:(TWTSignedRequestMethod)requestMethod; 44 | 45 | // Perform the request, and notify handler of results 46 | - (void)performRequestWithHandler:(TWTSignedRequestHandler)handler; 47 | 48 | // You should ensure that you obfuscate your keys before shipping 49 | + (NSString *)consumerKey; 50 | + (NSString *)consumerSecret; 51 | @end 52 | -------------------------------------------------------------------------------- /Source/Classes/TWTAPIManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // TWTAPIManager.h 3 | // ReverseAuthExample 4 | // 5 | // Copyright (c) 2011-2016 Sean Cook 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a 8 | // copy of this software and associated documentation files (the 9 | // "Software"), to deal in the Software without restriction, including 10 | // without limitation the rights to use, copy, modify, merge, publish, 11 | // distribute, sublicense, and/or sell copies of the Software, and to permit 12 | // persons to whom the Software is furnished to do so, subject to the 13 | // following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included 16 | // in all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 21 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 22 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 23 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 24 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | // 26 | 27 | @import Foundation; 28 | 29 | @class ACAccount; 30 | 31 | typedef void(^ReverseAuthResponseHandler)(NSData *responseData, NSError *error); 32 | 33 | @interface TWTAPIManager : NSObject 34 | 35 | /** 36 | * Obtains the access token and secret for |account|. 37 | * 38 | * There are two steps required for Reverse Auth: 39 | * 40 | * The first sends a signed request that *you* must sign to Twitter to obtain 41 | * an Authorization: header. You sign the request with your own OAuth keys. 42 | * All apps have access to Reverse Auth by default, so there are no special 43 | * permissions required. 44 | * 45 | * The second step uses SLRequest to sign and send the response to step 1 back 46 | * to Twitter. The response to this request, if everything worked, will 47 | * include an user's access token and secret which can then 48 | * be used in conjunction with your consumer key and secret to make 49 | * authenticated calls to Twitter. 50 | */ 51 | - (void)performReverseAuthForAccount:(ACAccount *)account withHandler:(ReverseAuthResponseHandler)handler; 52 | 53 | /** 54 | * Returns true if there are local Twitter accounts available. 55 | */ 56 | + (BOOL)isLocalTwitterAccountAvailable; 57 | 58 | /** 59 | * Returns true if the Info.plist is configured properly. 60 | */ 61 | + (BOOL)hasAppKeys; 62 | 63 | @end 64 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ReverseAuthExample 2 | 3 | ### iOS 11 ### 4 | ![Back to the future](./back-to-the-future.jpg) 5 | 6 | It appears that [Twitter accounts will not be available via Accounts.framework in iOS 11](https://developer.apple.com/documentation/accounts/acaccounttype/account_type_identifiers?changes=latest_minor). If you need reverse auth, start migrating your apps to [Twitter Kit](https://dev.twitter.com/twitterkit/ios/overview) _today_. Seriously, just do it. 7 | 8 | ## Summary 9 | 10 | This project illustrates how to use the Twitter API's reverse\_auth endpoint to obtain a user's access token and secret for your application's consumer key and secret. 11 | 12 | __Note:__ I created this project prior to the launch of [Twitter Fabric](https://www.fabric.io). I ~~am~~ was previously a Product Manager for Fabric, and that product includes reverse auth as well as many other useful features that I've helped developers with over the years. If you're looking for a full-featured Twitter SDK, I highly recommend taking a look at that project. 13 | 14 | The latest version of this project can be found at [github](https://github.com/seancook/TWReverseAuthExample). 15 | 16 | ### To see the demo in action: 17 | 18 | This project uses [cocoapods](https://www.cocoapods.org) to manage its dependencies. 19 | 20 | 1. Get the code: 21 | ```sh 22 | git clone https://github.com/seancook/TWReverseAuthExample.git 23 | cd TWReverseAuthExample 24 | pod install 25 | open ReverseAuthExample.xcworkspace 26 | ``` 27 | 28 | 2. Add your application's consumer key and secret to TWiOSReverseAuthExample-Info.plist under the `TWITTER_CONSUMER_KEY` and `TWITTER_CONSUMER_SECRET` keys, respectively. 29 | 30 | **Note: Including your consumer secret in a mobile app is a bad idea.** 31 | 32 | 3. Build and run. Click the button labeled "Perform Token Exchange" to execute the token exchange. 33 | 34 | ## Author 35 | 36 | This example was created by Sean Cook ([@theSeanCook](http://twitter.com/theSeanCook)). 37 | 38 | ### License 39 | 40 | Copyright (c) 2011-2017 Sean Cook 41 | 42 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 43 | 44 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 45 | 46 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 47 | 48 | ### Twitter Marks 49 | 50 | The use of the Twitter logos is governed by the [Guidelines for Use of the Twitter Trademark](https://support.twitter.com/articles/77641-guidelines-for-use-of-the-twitter-trademark) 51 | 52 | ### Memory Management Style 53 | 54 | Automatic Reference Counting (ARC) 55 | -------------------------------------------------------------------------------- /Source/Classes/TWTSignedRequest.m: -------------------------------------------------------------------------------- 1 | // 2 | // TWTSignedRequest.m 3 | // ReverseAuthExample 4 | // 5 | // Copyright (c) 2011-2016 Sean Cook 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a 8 | // copy of this software and associated documentation files (the 9 | // "Software"), to deal in the Software without restriction, including 10 | // without limitation the rights to use, copy, modify, merge, publish, 11 | // distribute, sublicense, and/or sell copies of the Software, and to permit 12 | // persons to whom the Software is furnished to do so, subject to the 13 | // following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included 16 | // in all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 21 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 22 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 23 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 24 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | // 26 | 27 | #import 28 | #import "TWTSignedRequest.h" 29 | 30 | #define TW_HTTP_METHOD_GET @"GET" 31 | #define TW_HTTP_METHOD_POST @"POST" 32 | #define TW_HTTP_METHOD_DELETE @"DELETE" 33 | #define TW_HTTP_HEADER_AUTHORIZATION @"Authorization" 34 | #define TW_CONSUMER_KEY @"TWITTER_CONSUMER_KEY" 35 | #define TW_CONSUMER_SECRET @"TWITTER_CONSUMER_SECRET" 36 | 37 | #define REQUEST_TIMEOUT_INTERVAL 8 38 | 39 | static NSString *gTWConsumerKey; 40 | static NSString *gTWConsumerSecret; 41 | 42 | @interface TWTSignedRequest() 43 | { 44 | NSURL *_url; 45 | NSDictionary *_parameters; 46 | TWTSignedRequestMethod _signedRequestMethod; 47 | NSOperationQueue *_signedRequestQueue; 48 | } 49 | 50 | @end 51 | 52 | @implementation TWTSignedRequest 53 | 54 | - (instancetype)initWithURL:(NSURL *)url parameters:(NSDictionary *)parameters requestMethod:(TWTSignedRequestMethod)requestMethod 55 | { 56 | self = [super init]; 57 | if (self) { 58 | _url = url; 59 | _parameters = parameters; 60 | _signedRequestMethod = requestMethod; 61 | _signedRequestQueue = [[NSOperationQueue alloc] init]; 62 | } 63 | return self; 64 | } 65 | 66 | - (NSURLRequest *)_buildRequest 67 | { 68 | NSString *method; 69 | 70 | switch (_signedRequestMethod) { 71 | case TWSignedRequestMethodPOST: 72 | method = TW_HTTP_METHOD_POST; 73 | break; 74 | case TWSignedRequestMethodDELETE: 75 | method = TW_HTTP_METHOD_DELETE; 76 | break; 77 | case TWSignedRequestMethodGET: 78 | default: 79 | method = TW_HTTP_METHOD_GET; 80 | } 81 | 82 | // Build our parameter string 83 | NSMutableString *paramsAsString = [[NSMutableString alloc] init]; 84 | [_parameters enumerateKeysAndObjectsUsingBlock: 85 | ^(id key, id obj, BOOL *stop) { 86 | [paramsAsString appendFormat:@"%@=%@&", key, obj]; 87 | }]; 88 | 89 | // Create the authorization header and attach to our request 90 | NSData *bodyData = [paramsAsString dataUsingEncoding:NSUTF8StringEncoding]; 91 | NSString *authorizationHeader = OAuthorizationHeader(_url, method, bodyData, [TWTSignedRequest consumerKey], [TWTSignedRequest consumerSecret], _authToken, _authTokenSecret); 92 | NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:_url]; 93 | [request setTimeoutInterval:REQUEST_TIMEOUT_INTERVAL]; 94 | request.HTTPMethod = method; 95 | [request setValue:authorizationHeader forHTTPHeaderField:TW_HTTP_HEADER_AUTHORIZATION]; 96 | request.HTTPBody = bodyData; 97 | 98 | return request; 99 | } 100 | 101 | - (void)performRequestWithHandler:(TWTSignedRequestHandler)handler 102 | { 103 | NSURLRequest *request = [self _buildRequest]; 104 | [NSURLConnection sendAsynchronousRequest:request queue:_signedRequestQueue completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) { 105 | handler(data, response, connectionError); 106 | }]; 107 | } 108 | 109 | // OBFUSCATE YOUR KEYS! 110 | + (NSString *)consumerKey 111 | { 112 | if (!gTWConsumerKey) { 113 | NSBundle* bundle = [NSBundle mainBundle]; 114 | gTWConsumerKey = bundle.infoDictionary[TW_CONSUMER_KEY]; 115 | } 116 | 117 | return gTWConsumerKey; 118 | } 119 | 120 | // OBFUSCATE YOUR KEYS! 121 | + (NSString *)consumerSecret 122 | { 123 | if (!gTWConsumerSecret) { 124 | NSBundle* bundle = [NSBundle mainBundle]; 125 | gTWConsumerSecret = bundle.infoDictionary[TW_CONSUMER_SECRET]; 126 | } 127 | 128 | return gTWConsumerSecret; 129 | } 130 | 131 | @end 132 | -------------------------------------------------------------------------------- /Source/Classes/TWTAPIManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // TWTAPIManager.m 3 | // ReverseAuthExample 4 | // 5 | // Copyright (c) 2011-2016 Sean Cook 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a 8 | // copy of this software and associated documentation files (the 9 | // "Software"), to deal in the Software without restriction, including 10 | // without limitation the rights to use, copy, modify, merge, publish, 11 | // distribute, sublicense, and/or sell copies of the Software, and to permit 12 | // persons to whom the Software is furnished to do so, subject to the 13 | // following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included 16 | // in all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 21 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 22 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 23 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 24 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | // 26 | 27 | @import Accounts; 28 | @import Social; 29 | @import Twitter; 30 | 31 | #import "OAuth+Additions.h" 32 | #import "TWTAPIManager.h" 33 | #import "TWTSignedRequest.h" 34 | 35 | #define TWT_API_ROOT @"https://api.twitter.com" 36 | #define TWT_X_AUTH_MODE_KEY @"x_auth_mode" 37 | #define TWT_X_AUTH_MODE_REVERSE_AUTH @"reverse_auth" 38 | #define TWT_X_AUTH_MODE_CLIENT_AUTH @"client_auth" 39 | #define TWT_X_AUTH_REVERSE_PARMS @"x_reverse_auth_parameters" 40 | #define TWT_X_AUTH_REVERSE_TARGET @"x_reverse_auth_target" 41 | #define TWT_OAUTH_URL_REQUEST_TOKEN TWT_API_ROOT "/oauth/request_token" 42 | #define TWT_OAUTH_URL_AUTH_TOKEN TWT_API_ROOT "/oauth/access_token" 43 | 44 | typedef void(^TWTAPIHandler)(NSData *data, NSError *error); 45 | 46 | @implementation TWTAPIManager 47 | 48 | /** 49 | * Ensures that we have a consumer key and secret configured 50 | */ 51 | + (BOOL)hasAppKeys 52 | { 53 | return ([TWTSignedRequest consumerKey].length && [TWTSignedRequest consumerSecret].length); 54 | } 55 | 56 | /** 57 | * Returns true if there are local Twitter accounts available for use. 58 | * 59 | * NOTE: The system will report an account as being present even if the 60 | * account's tokens are no longer valid. For extra protection, you should 61 | * verify the user's credentials with a call to /1.1/accounts/verify_credentials 62 | */ 63 | + (BOOL)isLocalTwitterAccountAvailable 64 | { 65 | return [SLComposeViewController isAvailableForServiceType:SLServiceTypeTwitter]; 66 | } 67 | 68 | /** 69 | * Returns a generic self-signing request that can be used to perform Twitter 70 | * API requests. 71 | * 72 | * @param url The URL of the endpoint to retrieve 73 | * @param dict The API parameters to include with the request 74 | * @param requestMethod The HTTP method to use 75 | */ 76 | - (SLRequest *)requestWithUrl:(NSURL *)url parameters:(NSDictionary *)dict requestMethod:(SLRequestMethod)requestMethod 77 | { 78 | return [SLRequest requestForServiceType:SLServiceTypeTwitter requestMethod:requestMethod URL:url parameters:dict]; 79 | } 80 | 81 | /** 82 | * Performs Reverse Auth for the given account. 83 | * 84 | * Responsible for dispatching the result of the call, either sucess or error. 85 | * 86 | * @param account The local account for which we wish to exchange tokens 87 | * @param handler The block to call upon completion. Will be called on the 88 | * main thread. 89 | */ 90 | - (void)performReverseAuthForAccount:(ACAccount *)account withHandler:(TWTAPIHandler)handler 91 | { 92 | [self _step1WithCompletion:^(NSData *data, NSError *error) { 93 | if (!data) { 94 | dispatch_async(dispatch_get_main_queue(), ^{ 95 | handler(nil, error); 96 | }); 97 | } 98 | else { 99 | NSString *signedReverseAuthSignature = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; 100 | [self _step2WithAccount:account signature:signedReverseAuthSignature andHandler:^(NSData *responseData, NSError *error2) { 101 | dispatch_async(dispatch_get_main_queue(), ^{ 102 | handler(responseData, error2); 103 | }); 104 | }]; 105 | } 106 | }]; 107 | } 108 | 109 | /** 110 | * The second stage of Reverse Auth. 111 | * 112 | * In this step, we send our signed authorization header to Twitter in a 113 | * request that is signed by iOS. 114 | * 115 | * @param account The local account for which we wish to exchange tokens 116 | * @param signedReverseAuthSignature The Authorization: header returned from 117 | * a successful step 1 118 | * @param completion The block to call when finished. Can be called on any 119 | * thread. 120 | */ 121 | - (void)_step2WithAccount:(ACAccount *)account signature:(NSString *)signedReverseAuthSignature andHandler:(TWTAPIHandler)completion 122 | { 123 | NSDictionary *step2Params = @{TWT_X_AUTH_REVERSE_TARGET: [TWTSignedRequest consumerKey], TWT_X_AUTH_REVERSE_PARMS: signedReverseAuthSignature}; 124 | NSURL *authTokenURL = [NSURL URLWithString:TWT_OAUTH_URL_AUTH_TOKEN]; 125 | SLRequest *step2Request = [self requestWithUrl:authTokenURL parameters:step2Params requestMethod:SLRequestMethodPOST]; 126 | step2Request.account = account; 127 | [step2Request performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) { 128 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 129 | completion(responseData, error); 130 | }); 131 | }]; 132 | } 133 | 134 | /** 135 | * The first stage of Reverse Auth. 136 | * 137 | * In this step, we sign and send a request to Twitter to obtain an 138 | * Authorization: header which we will use in Step 2. 139 | * 140 | * @param completion The block to call when finished. Can be called on any thread. 141 | */ 142 | - (void)_step1WithCompletion:(TWTAPIHandler)completion 143 | { 144 | NSURL *url = [NSURL URLWithString:TWT_OAUTH_URL_REQUEST_TOKEN]; 145 | NSDictionary *params = @{TWT_X_AUTH_MODE_KEY: TWT_X_AUTH_MODE_REVERSE_AUTH}; 146 | TWTSignedRequest *step1Request = [[TWTSignedRequest alloc] initWithURL:url parameters:params requestMethod:TWSignedRequestMethodPOST]; 147 | [step1Request performRequestWithHandler:^(NSData *data, NSURLResponse *response, NSError *error) { 148 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 149 | completion(data, error); 150 | }); 151 | }]; 152 | } 153 | 154 | @end 155 | -------------------------------------------------------------------------------- /Source/Classes/TWTViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // TWTViewController.m 3 | // ReverseAuthExample 4 | // 5 | // Copyright (c) 2011-2016 Sean Cook 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a 8 | // copy of this software and associated documentation files (the 9 | // "Software"), to deal in the Software without restriction, including 10 | // without limitation the rights to use, copy, modify, merge, publish, 11 | // distribute, sublicense, and/or sell copies of the Software, and to permit 12 | // persons to whom the Software is furnished to do so, subject to the 13 | // following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included 16 | // in all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 21 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 22 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 23 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 24 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | // 26 | 27 | @import Accounts; 28 | 29 | #import 30 | #import "TWTAPIManager.h" 31 | #import "TWTSignedRequest.h" 32 | #import "TWTViewController.h" 33 | 34 | #define ERROR_TITLE_MSG @"Whoa there cowboy" 35 | #define ERROR_NO_ACCOUNTS @"You must add a Twitter account in Settings.app to use this demo." 36 | #define ERROR_PERM_ACCESS @"We weren't granted access to the user's accounts" 37 | #define ERROR_NO_KEYS @"You need to add your Twitter app keys to Info.plist to use this demo.\nPlease see README.md for more info." 38 | #define ERROR_OK @"OK" 39 | 40 | #define ONE_FOURTH_OF(_X) floorf(0.25f * (float)_X) 41 | #define THREE_FOURTHS_OF(_X) floorf(3.f * ONE_FOURTH_OF(_X)) 42 | 43 | @interface TWTViewController() 44 | 45 | @property (nonatomic, strong) ACAccountStore *accountStore; 46 | @property (nonatomic, strong) TWTAPIManager *apiManager; 47 | @property (nonatomic, strong) NSArray *accounts; 48 | @property (nonatomic, strong) UIButton *reverseAuthBtn; 49 | 50 | @end 51 | 52 | @implementation TWTViewController 53 | 54 | #pragma mark - UIViewController 55 | 56 | - (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 57 | { 58 | self = [super initWithNibName:nil bundle:nil]; 59 | if (self) { 60 | _accountStore = [[ACAccountStore alloc] init]; 61 | _apiManager = [[TWTAPIManager alloc] init]; 62 | } 63 | return self; 64 | } 65 | 66 | - (void)loadView 67 | { 68 | CGRect appFrame = [UIScreen mainScreen].applicationFrame; 69 | 70 | CGRect buttonFrame = appFrame; 71 | buttonFrame.origin.y = THREE_FOURTHS_OF(appFrame.size.height); 72 | buttonFrame.size.height = 44.0f; 73 | buttonFrame = CGRectInset(buttonFrame, 20, 0); 74 | 75 | UIView *view = [[UIView alloc] initWithFrame:appFrame]; 76 | view.backgroundColor = [UIColor colorWithWhite:0.502f alpha:1.000]; 77 | 78 | UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"twitter.png"]]; 79 | [view addSubview:imageView]; 80 | [imageView sizeToFit]; 81 | imageView.center = view.center; 82 | 83 | CGRect imageFrame = imageView.frame; 84 | imageFrame.origin.y = ONE_FOURTH_OF(appFrame.size.height); 85 | imageView.frame = imageFrame; 86 | 87 | _reverseAuthBtn = [UIButton buttonWithType:UIButtonTypeRoundedRect]; 88 | [_reverseAuthBtn setTitle:@"Perform Token Exchange" forState:UIControlStateNormal]; 89 | [_reverseAuthBtn addTarget:self action:@selector(performReverseAuth:) forControlEvents:UIControlEventTouchUpInside]; 90 | _reverseAuthBtn.frame = buttonFrame; 91 | [_reverseAuthBtn setEnabled:NO]; 92 | [_reverseAuthBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; 93 | [view addSubview:_reverseAuthBtn]; 94 | 95 | self.view = view; 96 | } 97 | 98 | - (void)viewWillAppear:(BOOL)animated 99 | { 100 | [super viewWillAppear:animated]; 101 | [self _refreshTwitterAccounts]; 102 | } 103 | 104 | - (void)viewDidLoad 105 | { 106 | [super viewDidLoad]; 107 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_refreshTwitterAccounts) name:ACAccountStoreDidChangeNotification object:nil]; 108 | } 109 | 110 | - (void)dealloc 111 | { 112 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 113 | } 114 | 115 | #pragma mark - UIActionSheetDelegate 116 | 117 | - (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex 118 | { 119 | if (buttonIndex != actionSheet.cancelButtonIndex) { 120 | [_apiManager performReverseAuthForAccount:_accounts[(NSUInteger)buttonIndex] withHandler:^(NSData *responseData, NSError *error) { 121 | if (responseData) { 122 | NSString *responseStr = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding]; 123 | NSArray *parts = [responseStr componentsSeparatedByString:@"&"]; 124 | NSString *lined = [parts componentsJoinedByString:@"\n"]; 125 | 126 | dispatch_async(dispatch_get_main_queue(), ^{ 127 | UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Success!" message:lined delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; 128 | [alert show]; 129 | }); 130 | } 131 | else { 132 | NSLog(@"Reverse Auth process failed. Error returned was: %@\n", error.localizedDescription); 133 | } 134 | }]; 135 | } 136 | } 137 | 138 | #pragma mark - Private 139 | 140 | - (void)_displayAlertWithMessage:(NSString *)message 141 | { 142 | UIAlertView *alert = [[UIAlertView alloc] initWithTitle:ERROR_TITLE_MSG message:message delegate:nil cancelButtonTitle:ERROR_OK otherButtonTitles:nil]; 143 | [alert show]; 144 | } 145 | 146 | /** 147 | * Checks for the current Twitter configuration on the device / simulator. 148 | * 149 | * First, we check to make sure that we've got keys to work with inside Info.plist (see README) 150 | * 151 | * Then we check to see if the device has accounts available via +[TWAPIManager isLocalTwitterAccountAvailable]. 152 | * 153 | * Next, we ask the user for permission to access his/her accounts. 154 | * 155 | * Upon completion, the button to continue will be displayed, or the user will be presented with a status message. 156 | */ 157 | - (void)_refreshTwitterAccounts 158 | { 159 | if (![TWTAPIManager hasAppKeys]) { 160 | [self _displayAlertWithMessage:ERROR_NO_KEYS]; 161 | } 162 | else if (![TWTAPIManager isLocalTwitterAccountAvailable]) { 163 | [self _displayAlertWithMessage:ERROR_NO_ACCOUNTS]; 164 | } 165 | else { 166 | [self _obtainAccessToAccountsWithBlock:^(BOOL granted) { 167 | dispatch_async(dispatch_get_main_queue(), ^{ 168 | if (granted) { 169 | self->_reverseAuthBtn.enabled = YES; 170 | } 171 | else { 172 | [self _displayAlertWithMessage:ERROR_PERM_ACCESS]; 173 | } 174 | }); 175 | }]; 176 | } 177 | } 178 | 179 | - (void)_obtainAccessToAccountsWithBlock:(void (^)(BOOL))block 180 | { 181 | ACAccountType *twitterType = [_accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter]; 182 | ACAccountStoreRequestAccessCompletionHandler handler = ^(BOOL granted, NSError *error) { 183 | if (granted) { 184 | self.accounts = [self->_accountStore accountsWithAccountType:twitterType]; 185 | } 186 | 187 | block(granted); 188 | }; 189 | [_accountStore requestAccessToAccountsWithType:twitterType options:NULL completion:handler]; 190 | } 191 | 192 | /** 193 | * Handles the button press that initiates the token exchange. 194 | * 195 | * We check the current configuration inside -[UIViewController viewDidAppear]. 196 | */ 197 | - (void)performReverseAuth:(id)sender 198 | { 199 | UIActionSheet *sheet = [[UIActionSheet alloc] initWithTitle:@"Choose an Account" delegate:self cancelButtonTitle:nil destructiveButtonTitle:nil otherButtonTitles:nil]; 200 | for (ACAccount *acct in _accounts) { 201 | [sheet addButtonWithTitle:acct.username]; 202 | } 203 | sheet.cancelButtonIndex = [sheet addButtonWithTitle:@"Cancel"]; 204 | [sheet showInView:self.view]; 205 | } 206 | 207 | @end 208 | -------------------------------------------------------------------------------- /ReverseAuthExample.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 101D382BB13FFB4C8A9D04A5 /* libPods-ReverseAuth.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 40D28D909FB7C45C90247CDA /* libPods-ReverseAuth.a */; }; 11 | CDAACAA31610E5D9006E4808 /* TWTAPIManager.m in Sources */ = {isa = PBXBuildFile; fileRef = CD40A1FF1610E3060051AE3D /* TWTAPIManager.m */; }; 12 | CDAACAA51610E5D9006E4808 /* TWTAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = CD40A2011610E3060051AE3D /* TWTAppDelegate.m */; }; 13 | CDAACAA71610E5D9006E4808 /* TWTSignedRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = CD40A2031610E3060051AE3D /* TWTSignedRequest.m */; settings = {COMPILER_FLAGS = "-D'TWITTER_CONSUMER_KEY=@\"$(TWITTER_CONSUMER_KEY)\"' -D'TWITTER_CONSUMER_SECRET=@\"$(TWITTER_CONSUMER_SECRET)\"'"; }; }; 14 | CDAACAA91610E5D9006E4808 /* TWTViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = CD40A2051610E3060051AE3D /* TWTViewController.m */; }; 15 | CDAACAAA1610E5D9006E4808 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = CD40A2091610E3060051AE3D /* main.m */; }; 16 | CDAACAB81610E606006E4808 /* twitter.png in Resources */ = {isa = PBXBuildFile; fileRef = CD40A1EF1610E0DC0051AE3D /* twitter.png */; }; 17 | CDC57C191A6D689300818A34 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CDC57C181A6D689300818A34 /* Images.xcassets */; }; 18 | /* End PBXBuildFile section */ 19 | 20 | /* Begin PBXFileReference section */ 21 | 1E6DCD59D4CA0F1F1DE36A43 /* Pods-ReverseAuth.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ReverseAuth.debug.xcconfig"; path = "Pods/Target Support Files/Pods-ReverseAuth/Pods-ReverseAuth.debug.xcconfig"; sourceTree = ""; }; 22 | 40D28D909FB7C45C90247CDA /* libPods-ReverseAuth.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-ReverseAuth.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 23 | 64A50000A443A54FC433C3CF /* Pods-ReverseAuth.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ReverseAuth.release.xcconfig"; path = "Pods/Target Support Files/Pods-ReverseAuth/Pods-ReverseAuth.release.xcconfig"; sourceTree = ""; }; 24 | CD14C12214B3A92B00B8A188 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; lineEnding = 0; path = README.md; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.markdown; }; 25 | CD21A6191610E4EA002E73B7 /* ReverseAuthExample-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "ReverseAuthExample-Info.plist"; sourceTree = ""; }; 26 | CD21A61A1610E4EA002E73B7 /* ReverseAuthExample-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ReverseAuthExample-Prefix.pch"; sourceTree = ""; }; 27 | CD40A1EF1610E0DC0051AE3D /* twitter.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = twitter.png; sourceTree = ""; }; 28 | CD40A1FE1610E3060051AE3D /* TWTAPIManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = TWTAPIManager.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 29 | CD40A1FF1610E3060051AE3D /* TWTAPIManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = TWTAPIManager.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 30 | CD40A2001610E3060051AE3D /* TWTAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = TWTAppDelegate.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 31 | CD40A2011610E3060051AE3D /* TWTAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = TWTAppDelegate.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 32 | CD40A2021610E3060051AE3D /* TWTSignedRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = TWTSignedRequest.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 33 | CD40A2031610E3060051AE3D /* TWTSignedRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = TWTSignedRequest.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 34 | CD40A2041610E3060051AE3D /* TWTViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = TWTViewController.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 35 | CD40A2051610E3060051AE3D /* TWTViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = TWTViewController.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 36 | CD40A2081610E3060051AE3D /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 37 | CD40A2091610E3060051AE3D /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = main.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 38 | CDAACA691610E55A006E4808 /* ReverseAuth.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ReverseAuth.app; sourceTree = BUILT_PRODUCTS_DIR; }; 39 | CDAACA6D1610E55A006E4808 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 40 | CDC57C181A6D689300818A34 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = ReverseAuthSampleApp/Images.xcassets; sourceTree = SOURCE_ROOT; }; 41 | CDF37960142291940071ABF7 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 42 | CDF37962142291940071ABF7 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 43 | CDF379951422931E0071ABF7 /* Twitter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Twitter.framework; path = System/Library/Frameworks/Twitter.framework; sourceTree = SDKROOT; }; 44 | CDF37997142293220071ABF7 /* Accounts.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accounts.framework; path = System/Library/Frameworks/Accounts.framework; sourceTree = SDKROOT; }; 45 | CDF53BCA160BC8C500AD69A6 /* Social.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Social.framework; path = System/Library/Frameworks/Social.framework; sourceTree = SDKROOT; }; 46 | /* End PBXFileReference section */ 47 | 48 | /* Begin PBXFrameworksBuildPhase section */ 49 | CDAACA661610E55A006E4808 /* Frameworks */ = { 50 | isa = PBXFrameworksBuildPhase; 51 | buildActionMask = 2147483647; 52 | files = ( 53 | 101D382BB13FFB4C8A9D04A5 /* libPods-ReverseAuth.a in Frameworks */, 54 | ); 55 | runOnlyForDeploymentPostprocessing = 0; 56 | }; 57 | /* End PBXFrameworksBuildPhase section */ 58 | 59 | /* Begin PBXGroup section */ 60 | CA5AA358EF2049DF4C142652 /* Pods */ = { 61 | isa = PBXGroup; 62 | children = ( 63 | 1E6DCD59D4CA0F1F1DE36A43 /* Pods-ReverseAuth.debug.xcconfig */, 64 | 64A50000A443A54FC433C3CF /* Pods-ReverseAuth.release.xcconfig */, 65 | ); 66 | name = Pods; 67 | sourceTree = ""; 68 | }; 69 | CD40A1E91610E0DC0051AE3D /* Resources */ = { 70 | isa = PBXGroup; 71 | children = ( 72 | CDC57C181A6D689300818A34 /* Images.xcassets */, 73 | CD40A1EF1610E0DC0051AE3D /* twitter.png */, 74 | ); 75 | path = Resources; 76 | sourceTree = ""; 77 | }; 78 | CD40A1FC1610E3060051AE3D /* Source */ = { 79 | isa = PBXGroup; 80 | children = ( 81 | CD40A1FD1610E3060051AE3D /* Classes */, 82 | CD40A2061610E3060051AE3D /* Other */, 83 | ); 84 | path = Source; 85 | sourceTree = ""; 86 | }; 87 | CD40A1FD1610E3060051AE3D /* Classes */ = { 88 | isa = PBXGroup; 89 | children = ( 90 | CD40A1FE1610E3060051AE3D /* TWTAPIManager.h */, 91 | CD40A1FF1610E3060051AE3D /* TWTAPIManager.m */, 92 | CD40A2001610E3060051AE3D /* TWTAppDelegate.h */, 93 | CD40A2011610E3060051AE3D /* TWTAppDelegate.m */, 94 | CD40A2021610E3060051AE3D /* TWTSignedRequest.h */, 95 | CD40A2031610E3060051AE3D /* TWTSignedRequest.m */, 96 | CD40A2041610E3060051AE3D /* TWTViewController.h */, 97 | CD40A2051610E3060051AE3D /* TWTViewController.m */, 98 | ); 99 | path = Classes; 100 | sourceTree = ""; 101 | }; 102 | CD40A2061610E3060051AE3D /* Other */ = { 103 | isa = PBXGroup; 104 | children = ( 105 | CD21A6191610E4EA002E73B7 /* ReverseAuthExample-Info.plist */, 106 | CD21A61A1610E4EA002E73B7 /* ReverseAuthExample-Prefix.pch */, 107 | CD40A2071610E3060051AE3D /* InfoPlist.strings */, 108 | CD40A2091610E3060051AE3D /* main.m */, 109 | ); 110 | path = Other; 111 | sourceTree = ""; 112 | }; 113 | CDF37951142291940071ABF7 = { 114 | isa = PBXGroup; 115 | children = ( 116 | CD14C12214B3A92B00B8A188 /* README.md */, 117 | CD40A1FC1610E3060051AE3D /* Source */, 118 | CD40A1E91610E0DC0051AE3D /* Resources */, 119 | CDF3795D142291940071ABF7 /* Products */, 120 | CDF3795F142291940071ABF7 /* Frameworks */, 121 | CA5AA358EF2049DF4C142652 /* Pods */, 122 | ); 123 | indentWidth = 4; 124 | sourceTree = ""; 125 | tabWidth = 4; 126 | usesTabs = 0; 127 | }; 128 | CDF3795D142291940071ABF7 /* Products */ = { 129 | isa = PBXGroup; 130 | children = ( 131 | CDAACA691610E55A006E4808 /* ReverseAuth.app */, 132 | ); 133 | name = Products; 134 | sourceTree = ""; 135 | }; 136 | CDF3795F142291940071ABF7 /* Frameworks */ = { 137 | isa = PBXGroup; 138 | children = ( 139 | CDF53BCA160BC8C500AD69A6 /* Social.framework */, 140 | CDF37997142293220071ABF7 /* Accounts.framework */, 141 | CDF379951422931E0071ABF7 /* Twitter.framework */, 142 | CDF37960142291940071ABF7 /* UIKit.framework */, 143 | CDF37962142291940071ABF7 /* Foundation.framework */, 144 | CDAACA6D1610E55A006E4808 /* CoreGraphics.framework */, 145 | 40D28D909FB7C45C90247CDA /* libPods-ReverseAuth.a */, 146 | ); 147 | name = Frameworks; 148 | sourceTree = ""; 149 | }; 150 | /* End PBXGroup section */ 151 | 152 | /* Begin PBXNativeTarget section */ 153 | CDAACA681610E55A006E4808 /* ReverseAuth */ = { 154 | isa = PBXNativeTarget; 155 | buildConfigurationList = CDAACA9C1610E55A006E4808 /* Build configuration list for PBXNativeTarget "ReverseAuth" */; 156 | buildPhases = ( 157 | DBCE45A090A726FAC52BEB26 /* [CP] Check Pods Manifest.lock */, 158 | CDAACA651610E55A006E4808 /* Sources */, 159 | CDAACA661610E55A006E4808 /* Frameworks */, 160 | CDAACA671610E55A006E4808 /* Resources */, 161 | 39B3C7CAA670F09AE60AF14F /* Warn for TODO and FIXME comments */, 162 | 1F013D32EEAD8811A36A48FB /* Set version number */, 163 | 648718B979ECF30E6D798266 /* [CP] Embed Pods Frameworks */, 164 | 395F618BC9AD2FDEF9FAE16E /* [CP] Copy Pods Resources */, 165 | ); 166 | buildRules = ( 167 | ); 168 | dependencies = ( 169 | ); 170 | name = ReverseAuth; 171 | productName = ReverseAuth; 172 | productReference = CDAACA691610E55A006E4808 /* ReverseAuth.app */; 173 | productType = "com.apple.product-type.application"; 174 | }; 175 | /* End PBXNativeTarget section */ 176 | 177 | /* Begin PBXProject section */ 178 | CDF37953142291940071ABF7 /* Project object */ = { 179 | isa = PBXProject; 180 | attributes = { 181 | LastUpgradeCheck = 0700; 182 | ORGANIZATIONNAME = ""; 183 | }; 184 | buildConfigurationList = CDF37956142291940071ABF7 /* Build configuration list for PBXProject "ReverseAuthExample" */; 185 | compatibilityVersion = "Xcode 3.2"; 186 | developmentRegion = English; 187 | hasScannedForEncodings = 0; 188 | knownRegions = ( 189 | en, 190 | ); 191 | mainGroup = CDF37951142291940071ABF7; 192 | productRefGroup = CDF3795D142291940071ABF7 /* Products */; 193 | projectDirPath = ""; 194 | projectRoot = ""; 195 | targets = ( 196 | CDAACA681610E55A006E4808 /* ReverseAuth */, 197 | ); 198 | }; 199 | /* End PBXProject section */ 200 | 201 | /* Begin PBXResourcesBuildPhase section */ 202 | CDAACA671610E55A006E4808 /* Resources */ = { 203 | isa = PBXResourcesBuildPhase; 204 | buildActionMask = 2147483647; 205 | files = ( 206 | CDC57C191A6D689300818A34 /* Images.xcassets in Resources */, 207 | CDAACAB81610E606006E4808 /* twitter.png in Resources */, 208 | ); 209 | runOnlyForDeploymentPostprocessing = 0; 210 | }; 211 | /* End PBXResourcesBuildPhase section */ 212 | 213 | /* Begin PBXShellScriptBuildPhase section */ 214 | 1F013D32EEAD8811A36A48FB /* Set version number */ = { 215 | isa = PBXShellScriptBuildPhase; 216 | buildActionMask = 2147483647; 217 | files = ( 218 | ); 219 | inputPaths = ( 220 | ); 221 | name = "Set version number"; 222 | outputPaths = ( 223 | ); 224 | runOnlyForDeploymentPostprocessing = 0; 225 | shellPath = /bin/sh; 226 | shellScript = "git=$(sh /etc/profile; which git)\ngit_release_version=$(\"$git\" describe --tags --always --abbrev=0)\nnumber_of_commits=$(\"$git\" rev-list master | wc -l | tr -d ' ')\ntarget_plist=\"$TARGET_BUILD_DIR/$INFOPLIST_PATH\"\ndsym_plist=\"$DWARF_DSYM_FOLDER_PATH/$DWARF_DSYM_FILE_NAME/Contents/Info.plist\"\n\nfor plist in \"$target_plist\" \"$dsym_plist\"; do\n if [ -f \"$plist\" ]; then\n /usr/libexec/PlistBuddy -c \"Set :CFBundleVersion $number_of_commits\" \"$plist\"\n /usr/libexec/PlistBuddy -c \"Set :CFBundleShortVersionString ${git_release_version#*v}\" \"$plist\"\n fi\ndone\n"; 227 | }; 228 | 395F618BC9AD2FDEF9FAE16E /* [CP] Copy Pods Resources */ = { 229 | isa = PBXShellScriptBuildPhase; 230 | buildActionMask = 2147483647; 231 | files = ( 232 | ); 233 | inputPaths = ( 234 | ); 235 | name = "[CP] Copy Pods Resources"; 236 | outputPaths = ( 237 | ); 238 | runOnlyForDeploymentPostprocessing = 0; 239 | shellPath = /bin/sh; 240 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-ReverseAuth/Pods-ReverseAuth-resources.sh\"\n"; 241 | showEnvVarsInLog = 0; 242 | }; 243 | 39B3C7CAA670F09AE60AF14F /* Warn for TODO and FIXME comments */ = { 244 | isa = PBXShellScriptBuildPhase; 245 | buildActionMask = 2147483647; 246 | files = ( 247 | ); 248 | inputPaths = ( 249 | ); 250 | name = "Warn for TODO and FIXME comments"; 251 | outputPaths = ( 252 | ); 253 | runOnlyForDeploymentPostprocessing = 0; 254 | shellPath = /bin/sh; 255 | shellScript = "KEYWORDS=\"TODO:|FIXME:|\\?\\?\\?:|\\!\\!\\!:\"\nFILE_EXTENSIONS=\"swift|h|m|mm|c|cpp\"\nfind -E \"${SRCROOT}\" -ipath \"${SRCROOT}/pods\" -prune -o \\( -regex \".*\\.($FILE_EXTENSIONS)$\" \\) -print0 | xargs -0 egrep --with-filename --line-number --only-matching \"($KEYWORDS).*\\$\" | perl -p -e \"s/($KEYWORDS)/ warning: \\$1/\"\n"; 256 | }; 257 | 648718B979ECF30E6D798266 /* [CP] Embed Pods Frameworks */ = { 258 | isa = PBXShellScriptBuildPhase; 259 | buildActionMask = 2147483647; 260 | files = ( 261 | ); 262 | inputPaths = ( 263 | ); 264 | name = "[CP] Embed Pods Frameworks"; 265 | outputPaths = ( 266 | ); 267 | runOnlyForDeploymentPostprocessing = 0; 268 | shellPath = /bin/sh; 269 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-ReverseAuth/Pods-ReverseAuth-frameworks.sh\"\n"; 270 | showEnvVarsInLog = 0; 271 | }; 272 | DBCE45A090A726FAC52BEB26 /* [CP] Check Pods Manifest.lock */ = { 273 | isa = PBXShellScriptBuildPhase; 274 | buildActionMask = 2147483647; 275 | files = ( 276 | ); 277 | inputPaths = ( 278 | ); 279 | name = "[CP] Check Pods Manifest.lock"; 280 | outputPaths = ( 281 | ); 282 | runOnlyForDeploymentPostprocessing = 0; 283 | shellPath = /bin/sh; 284 | shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; 285 | showEnvVarsInLog = 0; 286 | }; 287 | /* End PBXShellScriptBuildPhase section */ 288 | 289 | /* Begin PBXSourcesBuildPhase section */ 290 | CDAACA651610E55A006E4808 /* Sources */ = { 291 | isa = PBXSourcesBuildPhase; 292 | buildActionMask = 2147483647; 293 | files = ( 294 | CDAACAA31610E5D9006E4808 /* TWTAPIManager.m in Sources */, 295 | CDAACAA51610E5D9006E4808 /* TWTAppDelegate.m in Sources */, 296 | CDAACAA71610E5D9006E4808 /* TWTSignedRequest.m in Sources */, 297 | CDAACAA91610E5D9006E4808 /* TWTViewController.m in Sources */, 298 | CDAACAAA1610E5D9006E4808 /* main.m in Sources */, 299 | ); 300 | runOnlyForDeploymentPostprocessing = 0; 301 | }; 302 | /* End PBXSourcesBuildPhase section */ 303 | 304 | /* Begin PBXVariantGroup section */ 305 | CD40A2071610E3060051AE3D /* InfoPlist.strings */ = { 306 | isa = PBXVariantGroup; 307 | children = ( 308 | CD40A2081610E3060051AE3D /* en */, 309 | ); 310 | name = InfoPlist.strings; 311 | sourceTree = ""; 312 | }; 313 | /* End PBXVariantGroup section */ 314 | 315 | /* Begin XCBuildConfiguration section */ 316 | CDAACA9D1610E55A006E4808 /* Debug */ = { 317 | isa = XCBuildConfiguration; 318 | baseConfigurationReference = 1E6DCD59D4CA0F1F1DE36A43 /* Pods-ReverseAuth.debug.xcconfig */; 319 | buildSettings = { 320 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 321 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 322 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 323 | CLANG_CXX_LIBRARY = "libc++"; 324 | CLANG_ENABLE_MODULES = YES; 325 | CLANG_WARN_EMPTY_BODY = YES; 326 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 327 | CODE_SIGN_IDENTITY = "iPhone Developer"; 328 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 329 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 330 | GCC_PREFIX_HEADER = "Source/Other/ReverseAuthExample-Prefix.pch"; 331 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 332 | INFOPLIST_FILE = "Source/Other/ReverseAuthExample-Info.plist"; 333 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 334 | PRODUCT_BUNDLE_IDENTIFIER = com.seancook.ios.ReverseAuth; 335 | PRODUCT_NAME = "$(TARGET_NAME)"; 336 | PROVISIONING_PROFILE = ""; 337 | WRAPPER_EXTENSION = app; 338 | }; 339 | name = Debug; 340 | }; 341 | CDAACA9E1610E55A006E4808 /* Release */ = { 342 | isa = XCBuildConfiguration; 343 | baseConfigurationReference = 64A50000A443A54FC433C3CF /* Pods-ReverseAuth.release.xcconfig */; 344 | buildSettings = { 345 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 346 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 347 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 348 | CLANG_CXX_LIBRARY = "libc++"; 349 | CLANG_ENABLE_MODULES = YES; 350 | CLANG_WARN_EMPTY_BODY = YES; 351 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 352 | CODE_SIGN_IDENTITY = "iPhone Developer"; 353 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 354 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 355 | GCC_PREFIX_HEADER = "Source/Other/ReverseAuthExample-Prefix.pch"; 356 | GCC_TREAT_WARNINGS_AS_ERRORS = YES; 357 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 358 | INFOPLIST_FILE = "Source/Other/ReverseAuthExample-Info.plist"; 359 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 360 | PRODUCT_BUNDLE_IDENTIFIER = com.seancook.ios.ReverseAuth; 361 | PRODUCT_NAME = "$(TARGET_NAME)"; 362 | PROVISIONING_PROFILE = ""; 363 | WRAPPER_EXTENSION = app; 364 | }; 365 | name = Release; 366 | }; 367 | CDF3798D142291940071ABF7 /* Debug */ = { 368 | isa = XCBuildConfiguration; 369 | buildSettings = { 370 | CLANG_ENABLE_MODULES = YES; 371 | CLANG_ENABLE_OBJC_ARC = YES; 372 | CLANG_WARN_BOOL_CONVERSION = YES; 373 | CLANG_WARN_CONSTANT_CONVERSION = YES; 374 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 375 | CLANG_WARN_EMPTY_BODY = YES; 376 | CLANG_WARN_ENUM_CONVERSION = YES; 377 | CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES; 378 | CLANG_WARN_INT_CONVERSION = YES; 379 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 380 | CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; 381 | CLANG_WARN_UNREACHABLE_CODE = YES; 382 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 383 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 384 | COPY_PHASE_STRIP = NO; 385 | ENABLE_STRICT_OBJC_MSGSEND = YES; 386 | ENABLE_TESTABILITY = YES; 387 | GCC_NO_COMMON_BLOCKS = YES; 388 | GCC_PREPROCESSOR_DEFINITIONS = ( 389 | "DEBUG=1", 390 | "$(inherited)", 391 | ); 392 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0; 393 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 394 | GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES; 395 | GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; 396 | GCC_WARN_ABOUT_MISSING_NEWLINE = YES; 397 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 398 | GCC_WARN_CHECK_SWITCH_STATEMENTS = YES; 399 | GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; 400 | GCC_WARN_MISSING_PARENTHESES = YES; 401 | GCC_WARN_PEDANTIC = NO; 402 | GCC_WARN_SHADOW = YES; 403 | GCC_WARN_SIGN_COMPARE = YES; 404 | GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES; 405 | GCC_WARN_UNDECLARED_SELECTOR = YES; 406 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 407 | GCC_WARN_UNUSED_FUNCTION = YES; 408 | GCC_WARN_UNUSED_LABEL = YES; 409 | GCC_WARN_UNUSED_VALUE = YES; 410 | GCC_WARN_UNUSED_VARIABLE = YES; 411 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 412 | ONLY_ACTIVE_ARCH = YES; 413 | OTHER_CFLAGS = ""; 414 | SDKROOT = iphoneos; 415 | VALIDATE_PRODUCT = NO; 416 | }; 417 | name = Debug; 418 | }; 419 | CDF3798E142291940071ABF7 /* Release */ = { 420 | isa = XCBuildConfiguration; 421 | buildSettings = { 422 | CLANG_ENABLE_MODULES = YES; 423 | CLANG_ENABLE_OBJC_ARC = YES; 424 | CLANG_WARN_BOOL_CONVERSION = YES; 425 | CLANG_WARN_CONSTANT_CONVERSION = YES; 426 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 427 | CLANG_WARN_EMPTY_BODY = YES; 428 | CLANG_WARN_ENUM_CONVERSION = YES; 429 | CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES; 430 | CLANG_WARN_INT_CONVERSION = YES; 431 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 432 | CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; 433 | CLANG_WARN_UNREACHABLE_CODE = YES; 434 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 435 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 436 | COPY_PHASE_STRIP = YES; 437 | ENABLE_STRICT_OBJC_MSGSEND = YES; 438 | GCC_NO_COMMON_BLOCKS = YES; 439 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0; 440 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 441 | GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES; 442 | GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; 443 | GCC_WARN_ABOUT_MISSING_NEWLINE = YES; 444 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 445 | GCC_WARN_CHECK_SWITCH_STATEMENTS = YES; 446 | GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; 447 | GCC_WARN_MISSING_PARENTHESES = YES; 448 | GCC_WARN_PEDANTIC = NO; 449 | GCC_WARN_SHADOW = YES; 450 | GCC_WARN_SIGN_COMPARE = YES; 451 | GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES; 452 | GCC_WARN_UNDECLARED_SELECTOR = YES; 453 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 454 | GCC_WARN_UNUSED_FUNCTION = YES; 455 | GCC_WARN_UNUSED_LABEL = YES; 456 | GCC_WARN_UNUSED_VALUE = YES; 457 | GCC_WARN_UNUSED_VARIABLE = YES; 458 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 459 | OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; 460 | SDKROOT = iphoneos; 461 | VALIDATE_PRODUCT = NO; 462 | }; 463 | name = Release; 464 | }; 465 | /* End XCBuildConfiguration section */ 466 | 467 | /* Begin XCConfigurationList section */ 468 | CDAACA9C1610E55A006E4808 /* Build configuration list for PBXNativeTarget "ReverseAuth" */ = { 469 | isa = XCConfigurationList; 470 | buildConfigurations = ( 471 | CDAACA9D1610E55A006E4808 /* Debug */, 472 | CDAACA9E1610E55A006E4808 /* Release */, 473 | ); 474 | defaultConfigurationIsVisible = 0; 475 | defaultConfigurationName = Release; 476 | }; 477 | CDF37956142291940071ABF7 /* Build configuration list for PBXProject "ReverseAuthExample" */ = { 478 | isa = XCConfigurationList; 479 | buildConfigurations = ( 480 | CDF3798D142291940071ABF7 /* Debug */, 481 | CDF3798E142291940071ABF7 /* Release */, 482 | ); 483 | defaultConfigurationIsVisible = 0; 484 | defaultConfigurationName = Release; 485 | }; 486 | /* End XCConfigurationList section */ 487 | }; 488 | rootObject = CDF37953142291940071ABF7 /* Project object */; 489 | } 490 | --------------------------------------------------------------------------------