diff --git a/Example/Podfile b/Example/Podfile new file mode 100644 index 0000000..8482d15 --- /dev/null +++ b/Example/Podfile @@ -0,0 +1,3 @@ +source 'https://github.com/CocoaPods/Specs.git' +platform :ios, '6.0' +pod 'SimpleAuth', :path => '..' diff --git a/Example/Podfile.lock b/Example/Podfile.lock new file mode 100644 index 0000000..826f91f --- /dev/null +++ b/Example/Podfile.lock @@ -0,0 +1,91 @@ +PODS: + - CMDQueryStringSerialization (0.3.2): + - ISO8601 + - cocoa-oauth (0.0.1): + - NSData+Base64 (~> 1.0) + - ISO8601 (0.1.3) + - NSData+Base64 (1.0.0) + - ReactiveCocoa (2.5): + - ReactiveCocoa/UI (= 2.5) + - ReactiveCocoa/Core (2.5): + - ReactiveCocoa/no-arc + - ReactiveCocoa/no-arc (2.5) + - ReactiveCocoa/UI (2.5): + - ReactiveCocoa/Core + - SimpleAuth (0.3.9): + - SimpleAuth/BoxWeb (= 0.3.9) + - SimpleAuth/Core (= 0.3.9) + - SimpleAuth/DropboxWeb (= 0.3.9) + - SimpleAuth/Facebook (= 0.3.9) + - SimpleAuth/FacebookWeb (= 0.3.9) + - SimpleAuth/FoursquareWeb (= 0.3.9) + - SimpleAuth/GoogleWeb (= 0.3.9) + - SimpleAuth/Instagram (= 0.3.9) + - SimpleAuth/LinkedInWeb (= 0.3.9) + - SimpleAuth/Meetup (= 0.3.9) + - SimpleAuth/OneDriveWeb (= 0.3.9) + - SimpleAuth/SinaWeiboWeb (= 0.3.9) + - SimpleAuth/Strava (= 0.3.9) + - SimpleAuth/Trello (= 0.3.9) + - SimpleAuth/TripIt (= 0.3.9) + - SimpleAuth/Tumblr (= 0.3.9) + - SimpleAuth/Twitter (= 0.3.9) + - SimpleAuth/TwitterWeb (= 0.3.9) + - SimpleAuth/BoxWeb (0.3.9): + - SimpleAuth/Core + - SimpleAuth/Core (0.3.9): + - CMDQueryStringSerialization + - ReactiveCocoa + - SimpleAuth/DropboxWeb (0.3.9): + - SimpleAuth/Core + - SimpleAuth/Facebook (0.3.9): + - SimpleAuth/Core + - SimpleAuth/FacebookWeb (0.3.9): + - SimpleAuth/Core + - SimpleAuth/FoursquareWeb (0.3.9): + - SimpleAuth/Core + - SimpleAuth/GoogleWeb (0.3.9): + - SimpleAuth/Core + - SimpleAuth/Instagram (0.3.9): + - SimpleAuth/Core + - SimpleAuth/LinkedInWeb (0.3.9): + - SimpleAuth/Core + - SimpleAuth/Meetup (0.3.9): + - SimpleAuth/Core + - SimpleAuth/OneDriveWeb (0.3.9): + - SimpleAuth/Core + - SimpleAuth/SinaWeiboWeb (0.3.9): + - SimpleAuth/Core + - SimpleAuth/Strava (0.3.9): + - SimpleAuth/Core + - SimpleAuth/Trello (0.3.9): + - SimpleAuth/Core + - SimpleAuth/TripIt (0.3.9): + - cocoa-oauth + - SimpleAuth/Core + - SimpleAuth/Tumblr (0.3.9): + - cocoa-oauth + - SimpleAuth/Core + - SimpleAuth/Twitter (0.3.9): + - cocoa-oauth + - SimpleAuth/Core + - SimpleAuth/TwitterWeb (0.3.9): + - cocoa-oauth + - SimpleAuth/Core + +DEPENDENCIES: + - SimpleAuth (from `..`) + +EXTERNAL SOURCES: + SimpleAuth: + :path: ".." + +SPEC CHECKSUMS: + CMDQueryStringSerialization: 03c5d9847a4eaa2b3e4e439ce1ae24f914cc7fe1 + cocoa-oauth: 1200a2170276a62a975f2786d505dab6e2db1fa8 + ISO8601: 8805b6cd6b2d0f7e594f7c5b50e8b00b51695ac0 + NSData+Base64: 4e84902c4db907a15673474677e57763ef3903e4 + ReactiveCocoa: e2db045570aa97c695e7aa97c2bcab222ae51f4a + SimpleAuth: bc7d594f90711a7e6ef7624dce5aa8c8b09770ab + +COCOAPODS: 0.36.4 diff --git a/Example/SimpleAuth.xcodeproj/project.pbxproj b/Example/SimpleAuth.xcodeproj/project.pbxproj new file mode 100644 index 0000000..d8cb11a --- /dev/null +++ b/Example/SimpleAuth.xcodeproj/project.pbxproj @@ -0,0 +1,363 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 3B491B8819E1D7CF0073EBEE /* Providers.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B491B8719E1D7CF0073EBEE /* Providers.plist */; }; + 3B629D9E19DE1F6E00BDF072 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3B629D9D19DE1F6E00BDF072 /* LaunchScreen.xib */; }; + 3B629DA019DE238100BDF072 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3B629D9F19DE238100BDF072 /* Images.xcassets */; }; + 3B658435188892FE00D59100 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 3B658433188892FE00D59100 /* InfoPlist.strings */; }; + 3B658437188892FE00D59100 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B658436188892FE00D59100 /* main.m */; }; + 3B65843B188892FE00D59100 /* SADAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B65843A188892FE00D59100 /* SADAppDelegate.m */; }; + 3B6584581888931F00D59100 /* SADProviderListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B6584571888931F00D59100 /* SADProviderListViewController.m */; }; + 49A81211250784928A11669C /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0D4998CFA03844FB99EE78AA /* libPods.a */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 0A3609D93D7B90B3BBADBC21 /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = ""; }; + 0D4998CFA03844FB99EE78AA /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 3B491B8719E1D7CF0073EBEE /* Providers.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Providers.plist; sourceTree = ""; }; + 3B629D9719DE1F2500BDF072 /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = LICENSE; path = ../LICENSE; sourceTree = ""; }; + 3B629D9819DE1F2500BDF072 /* Readme.markdown */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; name = Readme.markdown; path = ../Readme.markdown; sourceTree = ""; }; + 3B629D9919DE1F2500BDF072 /* SimpleAuth.podspec */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = SimpleAuth.podspec; path = ../SimpleAuth.podspec; sourceTree = ""; }; + 3B629D9D19DE1F6E00BDF072 /* LaunchScreen.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = LaunchScreen.xib; sourceTree = ""; }; + 3B629D9F19DE238100BDF072 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; + 3B658429188892FD00D59100 /* SimpleAuth.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SimpleAuth.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 3B658432188892FE00D59100 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 3B658434188892FE00D59100 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; + 3B658436188892FE00D59100 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 3B658438188892FE00D59100 /* Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Prefix.pch; sourceTree = ""; }; + 3B658439188892FE00D59100 /* SADAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SADAppDelegate.h; sourceTree = ""; }; + 3B65843A188892FE00D59100 /* SADAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SADAppDelegate.m; sourceTree = ""; }; + 3B6584571888931F00D59100 /* SADProviderListViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SADProviderListViewController.m; sourceTree = ""; }; + 3B6584591888933200D59100 /* SADProviderListViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SADProviderListViewController.h; sourceTree = ""; }; + DB25F6FCDF8BA7A12A786310 /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 3B658426188892FD00D59100 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 49A81211250784928A11669C /* libPods.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 3B629D9619DE1F1100BDF072 /* Podspec Metadata */ = { + isa = PBXGroup; + children = ( + 3B629D9819DE1F2500BDF072 /* Readme.markdown */, + 3B629D9919DE1F2500BDF072 /* SimpleAuth.podspec */, + 3B629D9719DE1F2500BDF072 /* LICENSE */, + ); + name = "Podspec Metadata"; + sourceTree = ""; + }; + 3B658430188892FE00D59100 /* SimpleAuth */ = { + isa = PBXGroup; + children = ( + 3B658439188892FE00D59100 /* SADAppDelegate.h */, + 3B65843A188892FE00D59100 /* SADAppDelegate.m */, + 3B6584591888933200D59100 /* SADProviderListViewController.h */, + 3B6584571888931F00D59100 /* SADProviderListViewController.m */, + 3B658432188892FE00D59100 /* Info.plist */, + 3B658433188892FE00D59100 /* InfoPlist.strings */, + 3B658436188892FE00D59100 /* main.m */, + 3B658438188892FE00D59100 /* Prefix.pch */, + 3B629D9D19DE1F6E00BDF072 /* LaunchScreen.xib */, + 3B629D9F19DE238100BDF072 /* Images.xcassets */, + 3B491B8719E1D7CF0073EBEE /* Providers.plist */, + ); + path = SimpleAuth; + sourceTree = ""; + }; + 3BB324FB182ABC8B00ACB555 = { + isa = PBXGroup; + children = ( + 3B629D9619DE1F1100BDF072 /* Podspec Metadata */, + 3B658430188892FE00D59100 /* SimpleAuth */, + 3BB32506182ABC8B00ACB555 /* Frameworks */, + 3BB32505182ABC8B00ACB555 /* Products */, + E41F3FB2B4E976B36518620C /* Pods */, + ); + sourceTree = ""; + }; + 3BB32505182ABC8B00ACB555 /* Products */ = { + isa = PBXGroup; + children = ( + 3B658429188892FD00D59100 /* SimpleAuth.app */, + ); + name = Products; + sourceTree = ""; + }; + 3BB32506182ABC8B00ACB555 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 0D4998CFA03844FB99EE78AA /* libPods.a */, + ); + name = Frameworks; + sourceTree = ""; + }; + E41F3FB2B4E976B36518620C /* Pods */ = { + isa = PBXGroup; + children = ( + DB25F6FCDF8BA7A12A786310 /* Pods.debug.xcconfig */, + 0A3609D93D7B90B3BBADBC21 /* Pods.release.xcconfig */, + ); + name = Pods; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 3B658428188892FD00D59100 /* SimpleAuth */ = { + isa = PBXNativeTarget; + buildConfigurationList = 3B658455188892FE00D59100 /* Build configuration list for PBXNativeTarget "SimpleAuth" */; + buildPhases = ( + 5058F26A0CF747BBE0A2CFCD /* Check Pods Manifest.lock */, + 3B658425188892FD00D59100 /* Sources */, + 3B658426188892FD00D59100 /* Frameworks */, + 3B658427188892FD00D59100 /* Resources */, + 2BC7B9E1175D6A6215258514 /* Copy Pods Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = SimpleAuth; + productName = SimpleAuthDemo; + productReference = 3B658429188892FD00D59100 /* SimpleAuth.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 3BB324FC182ABC8B00ACB555 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0600; + ORGANIZATIONNAME = "Byliner, Inc"; + }; + buildConfigurationList = 3BB324FF182ABC8B00ACB555 /* Build configuration list for PBXProject "SimpleAuth" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 3BB324FB182ABC8B00ACB555; + productRefGroup = 3BB32505182ABC8B00ACB555 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 3B658428188892FD00D59100 /* SimpleAuth */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 3B658427188892FD00D59100 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 3B629D9E19DE1F6E00BDF072 /* LaunchScreen.xib in Resources */, + 3B629DA019DE238100BDF072 /* Images.xcassets in Resources */, + 3B658435188892FE00D59100 /* InfoPlist.strings in Resources */, + 3B491B8819E1D7CF0073EBEE /* Providers.plist in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 2BC7B9E1175D6A6215258514 /* Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + 5058F26A0CF747BBE0A2CFCD /* Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Check Pods Manifest.lock"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + 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"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 3B658425188892FD00D59100 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 3B6584581888931F00D59100 /* SADProviderListViewController.m in Sources */, + 3B658437188892FE00D59100 /* main.m in Sources */, + 3B65843B188892FE00D59100 /* SADAppDelegate.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 3B658433188892FE00D59100 /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 3B658434188892FE00D59100 /* en */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 3B658451188892FE00D59100 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = DB25F6FCDF8BA7A12A786310 /* Pods.debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = SimpleAuth/Prefix.pch; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "${PODS_ROOT}/Headers/Public/SimpleAuth", + ); + INFOPLIST_FILE = SimpleAuth/Info.plist; + PRODUCT_NAME = "$(TARGET_NAME)"; + WRAPPER_EXTENSION = app; + }; + name = Debug; + }; + 3B658452188892FE00D59100 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 0A3609D93D7B90B3BBADBC21 /* Pods.release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = SimpleAuth/Prefix.pch; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "${PODS_ROOT}/Headers/Public/SimpleAuth", + ); + INFOPLIST_FILE = SimpleAuth/Info.plist; + PRODUCT_NAME = "$(TARGET_NAME)"; + WRAPPER_EXTENSION = app; + }; + name = Release; + }; + 3BB32525182ABC8C00ACB555 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 6.0; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + }; + name = Debug; + }; + 3BB32526182ABC8C00ACB555 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = YES; + ENABLE_NS_ASSERTIONS = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 6.0; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 3B658455188892FE00D59100 /* Build configuration list for PBXNativeTarget "SimpleAuth" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 3B658451188892FE00D59100 /* Debug */, + 3B658452188892FE00D59100 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 3BB324FF182ABC8B00ACB555 /* Build configuration list for PBXProject "SimpleAuth" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 3BB32525182ABC8C00ACB555 /* Debug */, + 3BB32526182ABC8C00ACB555 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 3BB324FC182ABC8B00ACB555 /* Project object */; +} diff --git a/Example/SimpleAuth.xcodeproj/xcshareddata/xcschemes/SimpleAuth.xcscheme b/Example/SimpleAuth.xcodeproj/xcshareddata/xcschemes/SimpleAuth.xcscheme new file mode 100644 index 0000000..a4d3dc4 --- /dev/null +++ b/Example/SimpleAuth.xcodeproj/xcshareddata/xcschemes/SimpleAuth.xcscheme @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Example/SimpleAuth.xcworkspace/contents.xcworkspacedata b/Example/SimpleAuth.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..aea7705 --- /dev/null +++ b/Example/SimpleAuth.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/Example/SimpleAuth/Images.xcassets/AppIcon.appiconset/Artboard 1.png b/Example/SimpleAuth/Images.xcassets/AppIcon.appiconset/Artboard 1.png new file mode 100644 index 0000000..0b2853d Binary files /dev/null and b/Example/SimpleAuth/Images.xcassets/AppIcon.appiconset/Artboard 1.png differ diff --git a/Example/SimpleAuth/Images.xcassets/AppIcon.appiconset/Artboard 2.png b/Example/SimpleAuth/Images.xcassets/AppIcon.appiconset/Artboard 2.png new file mode 100644 index 0000000..19c792e Binary files /dev/null and b/Example/SimpleAuth/Images.xcassets/AppIcon.appiconset/Artboard 2.png differ diff --git a/Example/SimpleAuth/Images.xcassets/AppIcon.appiconset/Artboard 3.png b/Example/SimpleAuth/Images.xcassets/AppIcon.appiconset/Artboard 3.png new file mode 100644 index 0000000..a1d3aa4 Binary files /dev/null and b/Example/SimpleAuth/Images.xcassets/AppIcon.appiconset/Artboard 3.png differ diff --git a/Example/SimpleAuth/Images.xcassets/AppIcon.appiconset/Artboard 4.png b/Example/SimpleAuth/Images.xcassets/AppIcon.appiconset/Artboard 4.png new file mode 100644 index 0000000..b3dc5f4 Binary files /dev/null and b/Example/SimpleAuth/Images.xcassets/AppIcon.appiconset/Artboard 4.png differ diff --git a/Example/SimpleAuth/Images.xcassets/AppIcon.appiconset/Contents.json b/Example/SimpleAuth/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..d47d7b5 --- /dev/null +++ b/Example/SimpleAuth/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,60 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "size" : "57x57", + "idiom" : "iphone", + "filename" : "Artboard 1.png", + "scale" : "1x" + }, + { + "size" : "57x57", + "idiom" : "iphone", + "filename" : "Artboard 2.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Artboard 3.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Artboard 4.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + }, + "properties" : { + "pre-rendered" : true + } +} \ No newline at end of file diff --git a/SimpleAuthDemo/SimpleAuthDemo-Info.plist b/Example/SimpleAuth/Info.plist similarity index 90% rename from SimpleAuthDemo/SimpleAuthDemo-Info.plist rename to Example/SimpleAuth/Info.plist index cea3f85..f48f6a5 100644 --- a/SimpleAuthDemo/SimpleAuthDemo-Info.plist +++ b/Example/SimpleAuth/Info.plist @@ -24,6 +24,8 @@ 1.0 LSRequiresIPhoneOS + UILaunchStoryboardName + LaunchScreen UIRequiredDeviceCapabilities armv7 @@ -31,8 +33,6 @@ UISupportedInterfaceOrientations UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight diff --git a/Example/SimpleAuth/LaunchScreen.xib b/Example/SimpleAuth/LaunchScreen.xib new file mode 100644 index 0000000..0309b81 --- /dev/null +++ b/Example/SimpleAuth/LaunchScreen.xib @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SimpleAuthDemo/SimpleAuthDemo-Prefix.pch b/Example/SimpleAuth/Prefix.pch similarity index 100% rename from SimpleAuthDemo/SimpleAuthDemo-Prefix.pch rename to Example/SimpleAuth/Prefix.pch diff --git a/Example/SimpleAuth/Providers.plist b/Example/SimpleAuth/Providers.plist new file mode 100644 index 0000000..efa2451 --- /dev/null +++ b/Example/SimpleAuth/Providers.plist @@ -0,0 +1,23 @@ + + + + + twitter + twitter-web + facebook + facebook-web + instagram + dropbox-web + tumblr + foursquare-web + meetup + linkedin-web + sinaweibo-web + google-web + strava-web + tripit + trello-web + box-web + onedrive-web + + diff --git a/SimpleAuthDemo/SADAppDelegate.h b/Example/SimpleAuth/SADAppDelegate.h similarity index 74% rename from SimpleAuthDemo/SADAppDelegate.h rename to Example/SimpleAuth/SADAppDelegate.h index b6e16fc..d1de658 100644 --- a/SimpleAuthDemo/SADAppDelegate.h +++ b/Example/SimpleAuth/SADAppDelegate.h @@ -3,7 +3,7 @@ // SimpleAuthDemo // // Created by Caleb Davenport on 1/16/14. -// Copyright (c) 2014 Seesaw Decisions Corporation. All rights reserved. +// Copyright (c) 2014 Byliner, Inc. All rights reserved. // @interface SADAppDelegate : UIResponder diff --git a/SimpleAuthDemo/SADAppDelegate.m b/Example/SimpleAuth/SADAppDelegate.m similarity index 50% rename from SimpleAuthDemo/SADAppDelegate.m rename to Example/SimpleAuth/SADAppDelegate.m index 0072723..98a5cb2 100644 --- a/SimpleAuthDemo/SADAppDelegate.m +++ b/Example/SimpleAuth/SADAppDelegate.m @@ -3,13 +3,13 @@ // SimpleAuthDemo // // Created by Caleb Davenport on 1/16/14. -// Copyright (c) 2014 Seesaw Decisions Corporation. All rights reserved. +// Copyright (c) 2014 Byliner, Inc. All rights reserved. // #import "SADAppDelegate.h" #import "SADProviderListViewController.h" -#import "SimpleAuth.h" +#import @implementation SADAppDelegate @@ -51,6 +51,43 @@ - (void)configureAuthorizaionProviders { // app_id is required SimpleAuth.configuration[@"facebook"] = @{}; + SimpleAuth.configuration[@"facebook-web"] = @{}; + + // client_id and redirect_uri are required + SimpleAuth.configuration[@"meetup"] = @{}; + + // consumer_key and consumer_secret are required + SimpleAuth.configuration[@"tumblr"] = @{}; + + // client_id and redirect_uri are required + SimpleAuth.configuration[@"foursquare-web"] = @{}; + + // client_id and redirect_uri are required + SimpleAuth.configuration[@"dropbox-web"] = @{}; + + // client_id, client_secret, and redirect_uri are required + SimpleAuth.configuration[@"linkedin-web"] = @{}; + + // client_id, client_secret, and redirect_uri are required + SimpleAuth.configuration[@"trello-web"] = @{}; + + // client_id and client_secret are required + SimpleAuth.configuration[@"sinaweibo-web"] = @{}; + + // client_id and client_secret are required + SimpleAuth.configuration[@"google-web"] = @{}; + + // client_id, client_secret and redirect_uri are required + SimpleAuth.configuration[@"strava-web"] = @{}; + + // consumer_key and consumer_secret are required + SimpleAuth.configuration[@"tripit"] = @{}; + + // client_id and client_secret are required + SimpleAuth.configuration[@"box-web"] = @{}; + + // client_id and client_secret are required + SimpleAuth.configuration[@"onedrive-web"] = @{}; } diff --git a/SimpleAuthDemo/SADProviderListViewController.h b/Example/SimpleAuth/SADProviderListViewController.h similarity index 70% rename from SimpleAuthDemo/SADProviderListViewController.h rename to Example/SimpleAuth/SADProviderListViewController.h index 0da0e3b..cdafd9e 100644 --- a/SimpleAuthDemo/SADProviderListViewController.h +++ b/Example/SimpleAuth/SADProviderListViewController.h @@ -3,7 +3,7 @@ // SimpleAuth // // Created by Caleb Davenport on 1/16/14. -// Copyright (c) 2014 Seesaw Decisions Corporation. All rights reserved. +// Copyright (c) 2014 Byliner, Inc. All rights reserved. // @interface SADProviderListViewController : UITableViewController diff --git a/SimpleAuthDemo/SADProviderListViewController.m b/Example/SimpleAuth/SADProviderListViewController.m similarity index 90% rename from SimpleAuthDemo/SADProviderListViewController.m rename to Example/SimpleAuth/SADProviderListViewController.m index 12dd167..eaebd01 100644 --- a/SimpleAuthDemo/SADProviderListViewController.m +++ b/Example/SimpleAuth/SADProviderListViewController.m @@ -3,12 +3,12 @@ // SimpleAuth // // Created by Caleb Davenport on 1/16/14. -// Copyright (c) 2014 Seesaw Decisions Corporation. All rights reserved. +// Copyright (c) 2014 Byliner, Inc. All rights reserved. // #import "SADProviderListViewController.h" -#import "SimpleAuth.h" +#import @interface SADProviderListViewController () @@ -42,12 +42,8 @@ + (NSArray *)providers { static dispatch_once_t token; static NSArray *array; dispatch_once(&token, ^{ - array = @[ - @"twitter", - @"twitter-web", - @"facebook", - @"instagram" - ]; + NSURL *URL = [[NSBundle mainBundle] URLForResource:@"Providers" withExtension:@"plist"]; + array = [NSArray arrayWithContentsOfURL:URL]; }); return array; } @@ -59,12 +55,10 @@ - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 1; } - - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return [[[self class] providers] count]; } - - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath]; cell.textLabel.text = [[self class] providers][indexPath.row]; diff --git a/SimpleAuthDemo/en.lproj/InfoPlist.strings b/Example/SimpleAuth/en.lproj/InfoPlist.strings similarity index 100% rename from SimpleAuthDemo/en.lproj/InfoPlist.strings rename to Example/SimpleAuth/en.lproj/InfoPlist.strings diff --git a/SimpleAuthDemo/main.m b/Example/SimpleAuth/main.m similarity index 80% rename from SimpleAuthDemo/main.m rename to Example/SimpleAuth/main.m index 687b406..6d4d235 100644 --- a/SimpleAuthDemo/main.m +++ b/Example/SimpleAuth/main.m @@ -3,7 +3,7 @@ // SimpleAuthDemo // // Created by Caleb Davenport on 1/16/14. -// Copyright (c) 2014 Seesaw Decisions Corporation. All rights reserved. +// Copyright (c) 2014 Byliner, Inc. All rights reserved. // #import diff --git a/LICENSE b/LICENSE index d1e81ae..bf8388b 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2013 Seesaw Decisions Corporation +Copyright (c) 2013-2014 Byliner, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/Pod/Core/ACAccountStore+SimpleAuth.h b/Pod/Core/ACAccountStore+SimpleAuth.h new file mode 100644 index 0000000..ada2a73 --- /dev/null +++ b/Pod/Core/ACAccountStore+SimpleAuth.h @@ -0,0 +1,35 @@ +// +// ACAccountStore+SimpleAuth.h +// SimpleAuth +// +// Created by Caleb Davenport on 1/25/14. +// Copyright (c) 2014 Seesaw Decisions Corporation. All rights reserved. +// + +@import Accounts; +@class RACSignal; + +@interface ACAccountStore (SimpleAuth) + +/** + Access a shared account store instance. + + @return A shared account store. + */ ++ (instancetype)SimpleAuth_sharedAccountStore; + +/** + Creates and returns a signal that sends next with all system accounts of the + given type. This is a convenience wrapper for + `-[ACAccountStore requestAccessToAccountsWithType:options:completion:]`. + + @return A signal that sends next with all system accounts of the given type. + + @param typeIdentifier Value passed to + `-[ACAccountStore accountTypeWithAccountTypeIdentifier:]` + @param options Value passed to + `-[ACAccountStore requestAccessToAccountsWithType:options:completion:]`. + */ ++ (RACSignal *)SimpleAuth_accountsWithTypeIdentifier:(NSString *)typeIdentifier options:(NSDictionary *)options; + +@end diff --git a/Pod/Core/ACAccountStore+SimpleAuth.m b/Pod/Core/ACAccountStore+SimpleAuth.m new file mode 100644 index 0000000..1a242fd --- /dev/null +++ b/Pod/Core/ACAccountStore+SimpleAuth.m @@ -0,0 +1,57 @@ +// +// ACAccountStore+SimpleAuth.m +// SimpleAuth +// +// Created by Caleb Davenport on 1/25/14. +// Copyright (c) 2014 Seesaw Decisions Corporation. All rights reserved. +// + +#import "ACAccountStore+SimpleAuth.h" +#import "SimpleAuthDefines.h" +#import + +@implementation ACAccountStore (SimpleAuth) + ++ (instancetype)SimpleAuth_sharedAccountStore { + static dispatch_once_t token; + static ACAccountStore *store; + dispatch_once(&token, ^{ + store = [ACAccountStore new]; + }); + return store; +} + + ++ (RACSignal *)SimpleAuth_accountsWithTypeIdentifier:(NSString *)typeIdentifier options:(NSDictionary *)options { + return [RACSignal createSignal:^RACDisposable *(id subscriber) { + ACAccountStore *store = [self SimpleAuth_sharedAccountStore]; + ACAccountType *type = [store accountTypeWithAccountTypeIdentifier:typeIdentifier]; + [store requestAccessToAccountsWithType:type options:options completion:^(BOOL granted, NSError *accountsError) { + if (granted) { + NSArray *accounts = [store accountsWithAccountType:type]; + NSUInteger numberOfAccounts = [accounts count]; + if (numberOfAccounts == 0) { + NSDictionary *dictionary = @{ + NSUnderlyingErrorKey: accountsError ?: [[NSError alloc] initWithDomain:ACErrorDomain code:ACErrorAccountNotFound userInfo:nil] + }; + NSError *error = [NSError errorWithDomain:SimpleAuthErrorDomain code:SimpleAuthErrorAccounts userInfo:dictionary]; + [subscriber sendError:error]; + } + else { + [subscriber sendNext:accounts]; + [subscriber sendCompleted]; + } + } + else { + NSDictionary *dictionary = @{ + NSUnderlyingErrorKey: accountsError ?: [[NSError alloc] initWithDomain:ACErrorDomain code:ACErrorPermissionDenied userInfo:nil] + }; + NSError *error = [NSError errorWithDomain:SimpleAuthErrorDomain code:SimpleAuthErrorAccounts userInfo:dictionary]; + [subscriber sendError:error]; + } + }]; + return nil; + }]; +} + +@end diff --git a/Pod/Core/NSObject+SimpleAuthAdditions.h b/Pod/Core/NSObject+SimpleAuthAdditions.h new file mode 100644 index 0000000..e1bf5d8 --- /dev/null +++ b/Pod/Core/NSObject+SimpleAuthAdditions.h @@ -0,0 +1,15 @@ +// +// NSObject+SimpleAuthAdditions.h +// SimpleAuth +// +// Created by Caleb Davenport on 1/20/14. +// Copyright (c) 2014 Byliner, Inc. All rights reserved. +// + +static inline BOOL SimpleAuthClassIsSubclassOfClass(Class classOne, Class classTwo); + +@interface NSObject (SimpleAuthAdditions) + ++ (void)SimpleAuth_enumerateSubclassesWithBlock:(void (^) (Class klass, BOOL *stop))block; + +@end diff --git a/Pod/Core/NSObject+SimpleAuthAdditions.m b/Pod/Core/NSObject+SimpleAuthAdditions.m new file mode 100644 index 0000000..1a196ac --- /dev/null +++ b/Pod/Core/NSObject+SimpleAuthAdditions.m @@ -0,0 +1,44 @@ +// +// NSObject+SimpleAuthAdditions.m +// SimpleAuth +// +// Created by Caleb Davenport on 1/20/14. +// Copyright (c) 2014 Byliner, Inc. All rights reserved. +// + +#import "NSObject+SimpleAuthAdditions.h" + +#import + +@implementation NSObject (SimpleAuthAdditions) + ++ (void)SimpleAuth_enumerateSubclassesWithBlock:(void (^) (Class klass, BOOL *stop))block { + int numberOfClasses = objc_getClassList(NULL, 0); + Class allClasses[numberOfClasses]; + objc_getClassList(allClasses, numberOfClasses); + for (int i = 0; i < numberOfClasses; i++) { + Class klass = allClasses[i]; + if (SimpleAuthClassIsSubclassOfClass(klass, self)) { + BOOL stop = NO; + block(klass, &stop); + if (stop) { + return; + } + } + } +} + +@end + +static inline BOOL SimpleAuthClassIsSubclassOfClass(Class classOne, Class classTwo) { + Class superclass = class_getSuperclass(classOne); + if (superclass == classTwo) { + return YES; + } + else if (superclass == Nil) { + return NO; + } + else { + return SimpleAuthClassIsSubclassOfClass(superclass, classTwo); + } +} diff --git a/SimpleAuth/SimpleAuth-Prefix.pch b/Pod/Core/SimpleAuth-Prefix.pch similarity index 71% rename from SimpleAuth/SimpleAuth-Prefix.pch rename to Pod/Core/SimpleAuth-Prefix.pch index 9e80850..e2e9bda 100644 --- a/SimpleAuth/SimpleAuth-Prefix.pch +++ b/Pod/Core/SimpleAuth-Prefix.pch @@ -3,7 +3,7 @@ // SimpleAuth // // Created by Caleb Davenport on 11/6/13. -// Copyright (c) 2013 Seesaw Decisions Corporation. All rights reserved. +// Copyright (c) 2013-2014 Byliner, Inc. All rights reserved. // #ifdef __OBJC__ diff --git a/Pod/Core/SimpleAuth.h b/Pod/Core/SimpleAuth.h new file mode 100644 index 0000000..38edcea --- /dev/null +++ b/Pod/Core/SimpleAuth.h @@ -0,0 +1,58 @@ +// +// SimpleAuth.h +// SimpleAuth +// +// Created by Caleb Davenport on 11/6/13. +// Copyright (c) 2013-2014 Byliner, Inc. All rights reserved. +// + +@import Foundation; +#import "SimpleAuthDefines.h" + +@interface SimpleAuth : NSObject + +/** + Set options used to configure each provider. Things like access tokens and + OAuth redirect URLs should be set here. Every provider should document the + options that it accepts. These options override a provider's default options, + and options passed to +authorize:options:completion: likewise override these. + + @return A mutable dictionary whose string keys correspond to provider types + and values are dictionaries that are passed on to a provider during an + authorization operation. + + @see +authorize:options:completion: + */ ++ (NSMutableDictionary *)configuration; + +/** + Perform authorization with the given provider and all previously configured + and default provider options. + + @param completion Called on the main queue when the operation is complete. + + @see +authorize:options:completion: + */ ++ (void)authorize:(NSString *)provider completion:(SimpleAuthRequestHandler)completion; + +/** + Perform an authorization with the given provider. Options provided here will + be applied on top of any configured or default provider options. + + @param completion Called on the main queue when the operation is complete. + + @see +configuration + @see +authorize:completion: + */ ++ (void)authorize:(NSString *)provider options:(NSDictionary *)options completion:(SimpleAuthRequestHandler)completion; + +/** + Determine whether the provider can handle the callback URL or not. + + @return A boolean specifying if the provider handles the specified URL. + + @param url The callback URL. + */ ++ (BOOL)handleCallback:(NSURL *)url; + +@end diff --git a/SimpleAuth/SimpleAuth.m b/Pod/Core/SimpleAuth.m similarity index 64% rename from SimpleAuth/SimpleAuth.m rename to Pod/Core/SimpleAuth.m index 0754d0d..3037b4f 100644 --- a/SimpleAuth/SimpleAuth.m +++ b/Pod/Core/SimpleAuth.m @@ -3,20 +3,25 @@ // SimpleAuth // // Created by Caleb Davenport on 11/6/13. -// Copyright (c) 2013 Seesaw Decisions Corporation. All rights reserved. +// Copyright (c) 2013-2014 Byliner, Inc. All rights reserved. // +#import "SimpleAuth.h" #import "SimpleAuthProvider.h" +#import "SimpleAuthSingleSignOnProvider.h" +#import "NSObject+SimpleAuthAdditions.h" -NSString * const SimpleAuthErrorDomain = @"SimpleAuthErrorDomain"; -NSString * const SimpleAuthPresentInterfaceBlockKey = @"present_interface_block"; -NSString * const SimpleAuthDismissInterfaceBlockKey = @"dismiss_interface_block"; -NSString * const SimpleAuthRedirectURIKey = @"redirect_uri"; - -NSInteger const SimpleAuthUserCancelledErrorCode = NSUserCancelledError; +static SimpleAuthProvider *__currentProvider = nil; @implementation SimpleAuth +#pragma mark - NSObject + ++ (void)initialize { + [self loadProviders]; +} + + #pragma mark - Public + (NSMutableDictionary *)configuration { @@ -49,23 +54,32 @@ + (void)authorize:(NSString *)type options:(NSDictionary *)options completion:(S [resolvedOptions addEntriesFromDictionary:options]; // Create the provider and run authorization - SimpleAuthProvider *provider = [(SimpleAuthProvider *)[klass alloc] initWithOptions:resolvedOptions]; - [provider authorizeWithCompletion:^(id responseObject, NSError *error) { + __currentProvider = [(SimpleAuthProvider *)[klass alloc] initWithOptions:resolvedOptions]; + [__currentProvider authorizeWithCompletion:^(id responseObject, NSError *error) { dispatch_async(dispatch_get_main_queue(), ^{ completion(responseObject, error); }); - [provider class]; // Kepp the provider around until the callback is complete }]; } ++ (BOOL)handleCallback:(NSURL *)URL { + NSParameterAssert(URL != nil); + + NSAssert(__currentProvider != nil, @"There is no provider waiting for single sign on callback."); + NSAssert([__currentProvider conformsToProtocol:@protocol(SimpleAuthSingleSignOnProvider)], @"The current provider does not handle single sign on."); + + return [(id)__currentProvider handleCallback:URL]; +} + + #pragma mark - Internal + (void)registerProviderClass:(Class)klass { NSMutableDictionary *providers = [self providers]; NSString *type = [klass type]; if (providers[type]) { - NSLog(@"[SimpleAuth] Warning: multiple attempts to register profider: %@", type); + NSLog(@"[SimpleAuth] Warning: multiple attempts to register provider for type: %@", type); return; } providers[type] = klass; @@ -83,4 +97,11 @@ + (NSMutableDictionary *)providers { return providers; } + ++ (void)loadProviders { + [SimpleAuthProvider SimpleAuth_enumerateSubclassesWithBlock:^(Class klass, BOOL *stop) { + [self registerProviderClass:klass]; + }]; +} + @end diff --git a/Pod/Core/SimpleAuthDefines.h b/Pod/Core/SimpleAuthDefines.h new file mode 100644 index 0000000..c67383c --- /dev/null +++ b/Pod/Core/SimpleAuthDefines.h @@ -0,0 +1,87 @@ +// +// SimpleAuthDefines.h +// SimpleAuth +// +// Created by Caleb Davenport on 11/30/14. +// Copyright (c) 2013-2015 Caleb Davenport. All rights reserved. +// + +@import Foundation; + +/** + Authentication error domain. + */ +extern NSString *const SimpleAuthErrorDomain; + +/** + The corresponding value is an HTTP staus code if the error was a network + related error. + */ +extern NSString *const SimpleAuthErrorStatusCodeKey; + +/** + Error codes for errors in the `SimpleAuthErrorDomain`. + */ +typedef NS_ENUM(NSUInteger, SimpleAuthError) { + + /** + The user cancelled authentication. + */ + SimpleAuthErrorUserCancelled = 100, + + /* + An error that occurred as the result of a failed network operation. + */ + SimpleAuthErrorNetwork, + + /** + An error that originated in Accounts.framework. + */ + SimpleAuthErrorAccounts, + + /** + Returned if SimpleAuth was able to parse response data. + */ + SimpleAuthErrorInvalidData +}; + +/** + Called when authorization either completes with a response or fails with an + error. Should an error occur, response object will be nil. + + @param responseObject The authorization response, or nil if an error occurred. + @param error An error. + + @see +authorize:completion: + @see +authorize:options:completion: + */ +typedef void (^SimpleAuthRequestHandler) (id responseObject, NSError *error); + +extern NSString *const SimpleAuthPresentInterfaceBlockKey; +extern NSString *const SimpleAuthDismissInterfaceBlockKey; + +/** + Called when a user interface element must be presented to continue + authorization. This could be a UIViewController for web login, or a + UIActionSheet for system login. All providers will have default + implementations for the appropriate callback types. You can customize provider + behavior by providing your own blocks. This will be called on the main + thread. + + @see SimpleAuthPresentInterfaceBlockKey + @see SimpleAuthDismissInterfaceBlockKey + @see +configuration + @see +authorize:options:completion: + + @param userInterfaceElement An element that is about to be presented or + dismissed. + */ +typedef void (^SimpleAuthInterfaceHandler) (id userInterfaceElement); + +/** + Key used to define the redirect URI for OAuth style providers. + + @see +configuration + @see +authorize:options:completion: + */ +extern NSString *const SimpleAuthRedirectURIKey; diff --git a/Pod/Core/SimpleAuthDefines.m b/Pod/Core/SimpleAuthDefines.m new file mode 100644 index 0000000..321868e --- /dev/null +++ b/Pod/Core/SimpleAuthDefines.m @@ -0,0 +1,15 @@ +// +// SimpleAuthDefines.m +// SimpleAuth +// +// Created by Caleb Davenport on 11/30/14. +// Copyright (c) 2013-2015 Caleb Davenport. All rights reserved. +// + +#import "SimpleAuthDefines.h" + +NSString *const SimpleAuthErrorDomain = @"SimpleAuthErrorDomain"; +NSString *const SimpleAuthErrorStatusCodeKey = @"SimpleAuthErrorStatusCode"; +NSString *const SimpleAuthPresentInterfaceBlockKey = @"present_interface_block"; +NSString *const SimpleAuthDismissInterfaceBlockKey = @"dismiss_interface_block"; +NSString *const SimpleAuthRedirectURIKey = @"redirect_uri"; diff --git a/SimpleAuth/SimpleAuthProvider.h b/Pod/Core/SimpleAuthProvider.h similarity index 78% rename from SimpleAuth/SimpleAuthProvider.h rename to Pod/Core/SimpleAuthProvider.h index 8537714..a531d37 100644 --- a/SimpleAuth/SimpleAuthProvider.h +++ b/Pod/Core/SimpleAuthProvider.h @@ -3,11 +3,13 @@ // SimpleAuth // // Created by Caleb Davenport on 11/6/13. -// Copyright (c) 2013 Seesaw Decisions Corporation. All rights reserved. +// Copyright (c) 2013-2014 Byliner, Inc. All rights reserved. // #import "SimpleAuth.h" +#import + @interface SimpleAuthProvider : NSObject @property (nonatomic, readonly, copy) NSDictionary *options; diff --git a/SimpleAuth/SimpleAuthProvider.m b/Pod/Core/SimpleAuthProvider.m similarity index 82% rename from SimpleAuth/SimpleAuthProvider.m rename to Pod/Core/SimpleAuthProvider.m index fa9a089..e1ec723 100644 --- a/SimpleAuth/SimpleAuthProvider.m +++ b/Pod/Core/SimpleAuthProvider.m @@ -3,7 +3,7 @@ // SimpleAuth // // Created by Caleb Davenport on 11/6/13. -// Copyright (c) 2013 Seesaw Decisions Corporation. All rights reserved. +// Copyright (c) 2013-2014 Byliner, Inc. All rights reserved. // #import "SimpleAuthProvider.h" @@ -16,20 +16,19 @@ @interface SimpleAuthProvider () @implementation SimpleAuthProvider -@synthesize operationQueue = _operationQueue; +#pragma mark - Properties -#pragma mark - Public +@synthesize operationQueue = _operationQueue; -+ (NSString *)type { - [self doesNotRecognizeSelector:_cmd]; - return nil; +- (NSOperationQueue *)operationQueue { + if (!_operationQueue) { + _operationQueue = [[NSOperationQueue alloc] init]; + } + return _operationQueue; } -+ (NSDictionary *)defaultOptions { - return @{}; -} - +#pragma mark - Initializers - (instancetype)initWithOptions:(NSDictionary *)options { if ((self = [super init])) { @@ -39,18 +38,19 @@ - (instancetype)initWithOptions:(NSDictionary *)options { } -- (void)authorizeWithCompletion:(SimpleAuthRequestHandler)completion { +#pragma mark - Public + ++ (NSString *)type { [self doesNotRecognizeSelector:_cmd]; + return nil; } ++ (NSDictionary *)defaultOptions { + return @{}; +} -#pragma mark - Accessors - -- (NSOperationQueue *)operationQueue { - if (!_operationQueue) { - _operationQueue = [NSOperationQueue new]; - } - return _operationQueue; +- (void)authorizeWithCompletion:(SimpleAuthRequestHandler)completion { + [self doesNotRecognizeSelector:_cmd]; } @end diff --git a/Pod/Core/SimpleAuthSingleSignOnProvider.h b/Pod/Core/SimpleAuthSingleSignOnProvider.h new file mode 100644 index 0000000..6ec2aed --- /dev/null +++ b/Pod/Core/SimpleAuthSingleSignOnProvider.h @@ -0,0 +1,13 @@ +// +// SimpleAuthSingleSignOnProvider.h +// SimpleAuth +// +// Created by Julien Seren-Rosso on 14/02/2014. +// Copyright (c) 2014 Byliner, Inc. All rights reserved. +// + +@protocol SimpleAuthSingleSignOnProvider + +- (BOOL)handleCallback:(NSURL *)URL; + +@end diff --git a/Pod/Core/SimpleAuthUtilities.h b/Pod/Core/SimpleAuthUtilities.h new file mode 100644 index 0000000..7338b25 --- /dev/null +++ b/Pod/Core/SimpleAuthUtilities.h @@ -0,0 +1,11 @@ +// +// SimpleAuthUtilities.h +// SimpleAuth +// +// Created by Caleb Davenport on 10/7/14. +// Copyright (c) 2013-2014 Byliner, Inc. All rights reserved. +// + +@import Foundation; + +NSString *SimpleAuthLocalizedString(NSString *key); diff --git a/Pod/Core/SimpleAuthUtilities.m b/Pod/Core/SimpleAuthUtilities.m new file mode 100644 index 0000000..a4fc9d5 --- /dev/null +++ b/Pod/Core/SimpleAuthUtilities.m @@ -0,0 +1,17 @@ +// +// SimpleAuthUtilities.m +// SimpleAuth +// +// Created by Caleb Davenport on 10/7/14. +// Copyright (c) 2013-2014 Byliner, Inc. All rights reserved. +// + +#import "SimpleAuthUtilities.h" +#import "SimpleAuth.h" + +NSString *SimpleAuthLocalizedString(NSString *key) { + NSBundle *mainBundle = [NSBundle bundleForClass:[SimpleAuth class]]; + NSURL *resourcesBundleURL = [mainBundle URLForResource:@"SimpleAuth" withExtension:@"bundle"]; + NSBundle *resourcesBundle = [NSBundle bundleWithURL:resourcesBundleURL]; + return NSLocalizedStringFromTableInBundle(key, nil, resourcesBundle, nil); +} diff --git a/Pod/Core/ios/SimpleAuthWebViewController.h b/Pod/Core/ios/SimpleAuthWebViewController.h new file mode 100644 index 0000000..d55e14e --- /dev/null +++ b/Pod/Core/ios/SimpleAuthWebViewController.h @@ -0,0 +1,53 @@ +// +// SimpleAuthWebViewController.h +// SimpleAuth +// +// Created by Caleb Davenport on 11/7/13. +// Copyright (c) 2013-2014 Byliner, Inc. All rights reserved. +// + +#import "SimpleAuth.h" + +#import + +typedef void (^SimpleAuthWebViewControllerCompletionHandler) (UIViewController *controller, NSURL *URL, NSError *error); + +@interface SimpleAuthWebViewController : UIViewController + +@property (nonatomic, readonly) UIWebView *webView; +@property (nonatomic, readonly, copy) NSDictionary *options; +@property (nonatomic, readonly, copy) NSDictionary *requestToken; +@property (nonatomic, copy) SimpleAuthWebViewControllerCompletionHandler completion; + +/** + Initializes a basic web login view controller. + @param options Providers should pass their options along here. + @see -initWithOptions:requestToken: + */ +- (instancetype)initWithOptions:(NSDictionary *)options; + +/** + Initializes a web login view controller for an OAuth 1 style provider. + @param options Providers should pass their options along here. + @param requestToken Token obtained through the OAuth 1 flow. + @see -initWithOptions: + */ +- (instancetype)initWithOptions:(NSDictionary *)options requestToken:(NSDictionary *)requestToken; + +/** + Subclasses should override this to provide the request that will be loaded the + first time that the web view appears. + @return A URL request. + */ +- (NSURLRequest *)initialRequest; + +/** + Subclasses may override this to determine if the a given URL is the desired + redirect URL. The default implementation of this method checks the given URL + agains the value provided in options. + @param URL The URL to inspect. + @return `YES` if the URL is the desired redirect URL, `NO` if it is not. + */ +- (BOOL)isTargetRedirectURL:(NSURL *)URL; + +@end diff --git a/SimpleAuth/SimpleAuthWebViewController.m b/Pod/Core/ios/SimpleAuthWebViewController.m similarity index 61% rename from SimpleAuth/SimpleAuthWebViewController.m rename to Pod/Core/ios/SimpleAuthWebViewController.m index a9f86ee..33f0ec9 100644 --- a/SimpleAuth/SimpleAuthWebViewController.m +++ b/Pod/Core/ios/SimpleAuthWebViewController.m @@ -3,19 +3,21 @@ // SimpleAuth // // Created by Caleb Davenport on 11/7/13. -// Copyright (c) 2013 Seesaw Decisions Corporation. All rights reserved. +// Copyright (c) 2013-2014 Byliner, Inc. All rights reserved. // #import "SimpleAuthWebViewController.h" -#import "SimpleAuth.h" @interface SimpleAuthWebViewController () @property (nonatomic, copy) NSDictionary *options; +@property (nonatomic, copy) NSDictionary *requestToken; @end -@implementation SimpleAuthWebViewController +@implementation SimpleAuthWebViewController { + BOOL _hasInitialLoad; +} @synthesize webView = _webView; @@ -29,20 +31,39 @@ - (void)viewDidLoad { } +- (void)viewDidAppear:(BOOL)animated { + [super viewDidAppear:animated]; + + if (!_hasInitialLoad) { + _hasInitialLoad = YES; + NSURLRequest *request = [self initialRequest]; + request = [[self class] canonicalRequestForRequest:request]; + [self.webView loadRequest:request]; + } +} + + #pragma mark - Public -- (instancetype)initWithOptions:(NSDictionary *)options { +- (instancetype)initWithOptions:(NSDictionary *)options requestToken:(NSDictionary *)requestToken { if ((self = [super init])) { self.options = options; + self.requestToken = requestToken; self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self - action:@selector(dismiss)]; + action:@selector(cancel)]; } return self; } +- (instancetype)initWithOptions:(NSDictionary *)options { + self = [self initWithOptions:options requestToken:nil]; + return self; +} + + - (BOOL)isTargetRedirectURL:(NSURL *)URL { NSString *targetURLString = [self.options[SimpleAuthRedirectURIKey] lowercaseString]; NSString *actualURLString = [[URL absoluteString] lowercaseString]; @@ -55,9 +76,24 @@ - (id)responseObjectFromRedirectURL:(NSURL *)URL { } -- (void)dismiss { - SimpleAuthInterfaceHandler block = self.options[SimpleAuthDismissInterfaceBlockKey]; - block(self); +- (void)cancel { + NSError *error = [NSError errorWithDomain:SimpleAuthErrorDomain code:SimpleAuthErrorUserCancelled userInfo:nil]; + self.completion(self, nil, error); +} + + +- (NSURLRequest *)initialRequest { + [self doesNotRecognizeSelector:_cmd]; + return nil; +} + + +#pragma mark - Private + ++ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request { + NSMutableURLRequest *mutableRequest = [request mutableCopy]; + [mutableRequest setCachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData]; + return mutableRequest; } diff --git a/SimpleAuth/UIViewController+SimpleAuthAdditions.h b/Pod/Core/ios/UIViewController+SimpleAuthAdditions.h similarity index 58% rename from SimpleAuth/UIViewController+SimpleAuthAdditions.h rename to Pod/Core/ios/UIViewController+SimpleAuthAdditions.h index 6296a1a..6b4a805 100644 --- a/SimpleAuth/UIViewController+SimpleAuthAdditions.h +++ b/Pod/Core/ios/UIViewController+SimpleAuthAdditions.h @@ -3,11 +3,11 @@ // SimpleAuth // // Created by Caleb Davenport on 11/14/13. -// Copyright (c) 2013 Seesaw Decisions Corporation. All rights reserved. +// Copyright (c) 2013-2014 Byliner, Inc. All rights reserved. // @interface UIViewController (SimpleAuthAdditions) -+ (instancetype)sa_presentedViewController; ++ (instancetype)SimpleAuth_presentedViewController; @end diff --git a/SimpleAuth/UIViewController+SimpleAuthAdditions.m b/Pod/Core/ios/UIViewController+SimpleAuthAdditions.m similarity index 72% rename from SimpleAuth/UIViewController+SimpleAuthAdditions.m rename to Pod/Core/ios/UIViewController+SimpleAuthAdditions.m index 4b24945..80cd8e4 100644 --- a/SimpleAuth/UIViewController+SimpleAuthAdditions.m +++ b/Pod/Core/ios/UIViewController+SimpleAuthAdditions.m @@ -3,7 +3,7 @@ // SimpleAuth // // Created by Caleb Davenport on 11/14/13. -// Copyright (c) 2013 Seesaw Decisions Corporation. All rights reserved. +// Copyright (c) 2013-2014 Byliner, Inc. All rights reserved. // #import "UIViewController+SimpleAuthAdditions.h" @@ -11,8 +11,8 @@ @implementation UIViewController (SimpleAuthAdditions) -+ (instancetype)sa_presentedViewController { - UIWindow *window = [UIWindow sa_mainWindow]; ++ (instancetype)SimpleAuth_presentedViewController { + UIWindow *window = [UIWindow SimpleAuth_mainWindow]; UIViewController *controller = window.rootViewController; while (controller.presentedViewController) { controller = controller.presentedViewController; diff --git a/SimpleAuth/UIWindow+SimpleAuthAdditions.h b/Pod/Core/ios/UIWindow+SimpleAuthAdditions.h similarity index 59% rename from SimpleAuth/UIWindow+SimpleAuthAdditions.h rename to Pod/Core/ios/UIWindow+SimpleAuthAdditions.h index 8515052..66729af 100644 --- a/SimpleAuth/UIWindow+SimpleAuthAdditions.h +++ b/Pod/Core/ios/UIWindow+SimpleAuthAdditions.h @@ -3,11 +3,11 @@ // SimpleAuth // // Created by Caleb Davenport on 11/14/13. -// Copyright (c) 2013 Seesaw Decisions Corporation. All rights reserved. +// Copyright (c) 2013-2014 Byliner, Inc. All rights reserved. // @interface UIWindow (SimpleAuthAdditions) -+ (instancetype)sa_mainWindow; ++ (instancetype)SimpleAuth_mainWindow; @end diff --git a/SimpleAuth/UIWindow+SimpleAuthAdditions.m b/Pod/Core/ios/UIWindow+SimpleAuthAdditions.m similarity index 71% rename from SimpleAuth/UIWindow+SimpleAuthAdditions.m rename to Pod/Core/ios/UIWindow+SimpleAuthAdditions.m index 7853006..6f7ae4a 100644 --- a/SimpleAuth/UIWindow+SimpleAuthAdditions.m +++ b/Pod/Core/ios/UIWindow+SimpleAuthAdditions.m @@ -3,14 +3,14 @@ // SimpleAuth // // Created by Caleb Davenport on 11/14/13. -// Copyright (c) 2013 Seesaw Decisions Corporation. All rights reserved. +// Copyright (c) 2013-2014 Byliner, Inc. All rights reserved. // #import "UIWindow+SimpleAuthAdditions.h" @implementation UIWindow (SimpleAuthAdditions) -+ (instancetype)sa_mainWindow { ++ (instancetype)SimpleAuth_mainWindow { return [[[UIApplication sharedApplication] delegate] window]; } diff --git a/Pod/Providers/BoxWeb/SimpleAuthBoxWebLoginViewController.h b/Pod/Providers/BoxWeb/SimpleAuthBoxWebLoginViewController.h new file mode 100755 index 0000000..34c8dd6 --- /dev/null +++ b/Pod/Providers/BoxWeb/SimpleAuthBoxWebLoginViewController.h @@ -0,0 +1,13 @@ +// +// SimpleAuthBoxWebLoginViewController.h +// SimpleAuth +// +// Created by dkhamsing on 3/26/15. +// Copyright (c) 2015 dkhamsing. All rights reserved. +// + +#import "SimpleAuthWebViewController.h" + +@interface SimpleAuthBoxWebLoginViewController : SimpleAuthWebViewController + +@end diff --git a/Pod/Providers/BoxWeb/SimpleAuthBoxWebLoginViewController.m b/Pod/Providers/BoxWeb/SimpleAuthBoxWebLoginViewController.m new file mode 100755 index 0000000..686a33b --- /dev/null +++ b/Pod/Providers/BoxWeb/SimpleAuthBoxWebLoginViewController.m @@ -0,0 +1,37 @@ +// +// SimpleAuthBoxWebLoginViewController.m +// SimpleAuth +// +// Created by dkhamsing on 3/26/15. +// Copyright (c) 2015 dkhamsing. All rights reserved. +// + +#import "SimpleAuthBoxWebLoginViewController.h" + +@implementation SimpleAuthBoxWebLoginViewController + +#pragma mark - SimpleAuthWebViewController + +- (instancetype)initWithOptions:(NSDictionary *)options requestToken:(NSDictionary *)requestToken { + if ((self = [super initWithOptions:options requestToken:requestToken])) { + self.title = @"Box"; + } + return self; +} + + +- (NSURLRequest *)initialRequest { + NSDictionary *parameters = @{ + @"client_id" : self.options[@"client_id"], + @"redirect_uri" : self.options[SimpleAuthRedirectURIKey], + @"response_type" : @"code" + }; + NSString *URLString = [NSString stringWithFormat: + @"https://api.box.com/oauth2/authorize?%@", + [CMDQueryStringSerialization queryStringWithDictionary:parameters]]; + NSURL *URL = [NSURL URLWithString:URLString]; + + return [NSURLRequest requestWithURL:URL]; +} + +@end diff --git a/Pod/Providers/BoxWeb/SimpleAuthBoxWebProvider.h b/Pod/Providers/BoxWeb/SimpleAuthBoxWebProvider.h new file mode 100755 index 0000000..6b8062d --- /dev/null +++ b/Pod/Providers/BoxWeb/SimpleAuthBoxWebProvider.h @@ -0,0 +1,13 @@ +// +// SimpleAuthBoxWebProvider.h +// SimpleAuth +// +// Created by dkhamsing on 3/26/15. +// Copyright (c) 2015 dkhamsing. All rights reserved. +// + +#import "SimpleAuthProvider.h" + +@interface SimpleAuthBoxWebProvider : SimpleAuthProvider + +@end diff --git a/Pod/Providers/BoxWeb/SimpleAuthBoxWebProvider.m b/Pod/Providers/BoxWeb/SimpleAuthBoxWebProvider.m new file mode 100755 index 0000000..93017bd --- /dev/null +++ b/Pod/Providers/BoxWeb/SimpleAuthBoxWebProvider.m @@ -0,0 +1,223 @@ +// +// SimpleAuthBoxWebProvider.m +// SimpleAuth +// +// Created by dkhamsing on 3/26/15. +// Copyright (c) 2015 dkhamsing. All rights reserved. +// + +#import "SimpleAuthBoxWebProvider.h" +#import "SimpleAuthBoxWebLoginViewController.h" + +#import +#import "UIViewController+SimpleAuthAdditions.h" + +@implementation SimpleAuthBoxWebProvider + +#pragma mark - Initializers + +- (instancetype)initWithOptions:(NSDictionary *)options { + NSMutableDictionary *mutableOptions = [NSMutableDictionary dictionaryWithDictionary:options]; + mutableOptions[SimpleAuthRedirectURIKey] = [NSString stringWithFormat:@"boxsdk-%@://boxsdkoauth2redirect", options[@"client_id"]]; + self = [super initWithOptions:[mutableOptions copy]]; + return self; +} + + +#pragma mark - SimpleAuthProvider + ++ (NSString *)type { + return @"box-web"; +} + + ++ (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 *)authorizationCode { + return [RACSignal createSignal:^RACDisposable *(id subscriber) { + dispatch_async(dispatch_get_main_queue(), ^{ + SimpleAuthBoxWebLoginViewController *login = [[SimpleAuthBoxWebLoginViewController 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:@"https://api.box.com/oauth2/token"]; + 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 *)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.box.com/2.0/users/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 new]; + + // Provider + dictionary[@"provider"] = [[self class] type]; + + // Credentials + dictionary[@"credentials"] = @{ + @"token" : accessToken[@"access_token"], + @"type" : accessToken[@"token_type"], + @"expires_in": accessToken[@"expires_in"], + @"refresh_token": accessToken[@"refresh_token"], + }; + + // 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/Pod/Providers/DropboxWeb/SimpleAuthDropboxWebLoginViewController.h b/Pod/Providers/DropboxWeb/SimpleAuthDropboxWebLoginViewController.h new file mode 100644 index 0000000..e426e80 --- /dev/null +++ b/Pod/Providers/DropboxWeb/SimpleAuthDropboxWebLoginViewController.h @@ -0,0 +1,13 @@ +// +// SimpleAuthDropboxWebLoginViewController.h +// SimpleAuth +// +// Created by Caleb Davenport on 1/23/14. +// Copyright (c) 2014 Byliner, Inc. All rights reserved. +// + +#import "SimpleAuthWebViewController.h" + +@interface SimpleAuthDropboxWebLoginViewController : SimpleAuthWebViewController + +@end diff --git a/Pod/Providers/DropboxWeb/SimpleAuthDropboxWebLoginViewController.m b/Pod/Providers/DropboxWeb/SimpleAuthDropboxWebLoginViewController.m new file mode 100644 index 0000000..69f68c0 --- /dev/null +++ b/Pod/Providers/DropboxWeb/SimpleAuthDropboxWebLoginViewController.m @@ -0,0 +1,37 @@ +// +// SimpleAuthDropboxWebLoginViewController.m +// SimpleAuth +// +// Created by Caleb Davenport on 1/23/14. +// Copyright (c) 2014 Byliner, Inc. All rights reserved. +// + +#import "SimpleAuthDropboxWebLoginViewController.h" + +@implementation SimpleAuthDropboxWebLoginViewController + +#pragma mark - SimpleAuthWebViewController + +- (instancetype)initWithOptions:(NSDictionary *)options requestToken:(NSDictionary *)requestToken { + if ((self = [super initWithOptions:options requestToken:requestToken])) { + self.title = @"Dropbox"; + } + return self; +} + + +- (NSURLRequest *)initialRequest { + NSDictionary *parameters = @{ + @"client_id" : self.options[@"client_id"], + @"redirect_uri" : self.options[SimpleAuthRedirectURIKey], + @"response_type" : @"token" + }; + NSString *URLString = [NSString stringWithFormat: + @"https://www.dropbox.com/1/oauth2/authorize?%@", + [CMDQueryStringSerialization queryStringWithDictionary:parameters]]; + NSURL *URL = [NSURL URLWithString:URLString]; + + return [NSURLRequest requestWithURL:URL]; +} + +@end diff --git a/Pod/Providers/DropboxWeb/SimpleAuthDropboxWebProvider.h b/Pod/Providers/DropboxWeb/SimpleAuthDropboxWebProvider.h new file mode 100644 index 0000000..b06ee0b --- /dev/null +++ b/Pod/Providers/DropboxWeb/SimpleAuthDropboxWebProvider.h @@ -0,0 +1,13 @@ +// +// SimpleAuthDropboxWebProvider.h +// SimpleAuth +// +// Created by Caleb Davenport on 1/23/14. +// Copyright (c) 2014 Byliner, Inc. All rights reserved. +// + +#import "SimpleAuthProvider.h" + +@interface SimpleAuthDropboxWebProvider : SimpleAuthProvider + +@end diff --git a/Pod/Providers/DropboxWeb/SimpleAuthDropboxWebProvider.m b/Pod/Providers/DropboxWeb/SimpleAuthDropboxWebProvider.m new file mode 100644 index 0000000..bfdd5f1 --- /dev/null +++ b/Pod/Providers/DropboxWeb/SimpleAuthDropboxWebProvider.m @@ -0,0 +1,160 @@ +// +// SimpleAuthDropboxWebProvider.m +// SimpleAuth +// +// Created by Caleb Davenport on 1/23/14. +// Copyright (c) 2014 Byliner, Inc. All rights reserved. +// + +#import "SimpleAuthDropboxWebProvider.h" +#import "SimpleAuthDropboxWebLoginViewController.h" + +#import +#import "UIViewController+SimpleAuthAdditions.h" + +@implementation SimpleAuthDropboxWebProvider + +#pragma mark - SimpleAuthProvider + ++ (NSString *)type { + return @"dropbox-web"; +} + + ++ (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 [RACSignal createSignal:^RACDisposable *(id subscriber) { + dispatch_async(dispatch_get_main_queue(), ^{ + SimpleAuthDropboxWebLoginViewController *login = [[SimpleAuthDropboxWebLoginViewController alloc] initWithOptions:self.options]; + + login.completion = ^(UIViewController *controller, NSURL *URL, NSError *error) { + SimpleAuthInterfaceHandler block = self.options[SimpleAuthDismissInterfaceBlockKey]; + block(controller); + + // Parse URL + NSString *fragment = [URL fragment]; + NSDictionary *dictionary = [CMDQueryStringSerialization dictionaryWithQueryString:fragment]; + id token = dictionary[@"access_token"]; + + // Check for error + if (!token) { + [subscriber sendError:error]; + return; + } + + // Send completion + [subscriber sendNext:dictionary]; + [subscriber sendCompleted]; + }; + + SimpleAuthInterfaceHandler block = self.options[SimpleAuthPresentInterfaceBlockKey]; + block(login); + }); + return nil; + }]; +} + + +- (RACSignal *)accountWithAccessToken:(NSDictionary *)accessToken { + return [RACSignal createSignal:^RACDisposable *(id subscriber) { + NSDictionary *parameters = @{ @"access_token" : accessToken[@"access_token"] }; + NSString *URLString = [NSString stringWithFormat: + @"https://api.dropbox.com/1/account/info?%@", + [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 new]; + + // Provider + dictionary[@"provider"] = [[self class] type]; + + // Credentials + dictionary[@"credentials"] = @{ + @"token" : accessToken[@"access_token"], + @"type" : accessToken[@"token_type"] + }; + + // User ID + dictionary[@"uid"] = account[@"uid"]; + + // Raw response + dictionary[@"extra"] = @{ + @"raw_info" : account + }; + + // User info + NSMutableDictionary *user = [NSMutableDictionary new]; + user[@"email"] = account[@"email"]; + user[@"name"] = account[@"display_name"]; + dictionary[@"info"] = user; + + return dictionary; +} + +@end diff --git a/Pod/Providers/Facebook/SimpleAuthFacebookProvider.h b/Pod/Providers/Facebook/SimpleAuthFacebookProvider.h new file mode 100644 index 0000000..389f1ca --- /dev/null +++ b/Pod/Providers/Facebook/SimpleAuthFacebookProvider.h @@ -0,0 +1,13 @@ +// +// SimpleAuthFacebookProvider.h +// SimpleAuth +// +// Created by Caleb Davenport on 11/6/13. +// Copyright (c) 2013-2014 Byliner, Inc. All rights reserved. +// + +#import "SimpleAuthProvider.h" + +@interface SimpleAuthFacebookProvider : SimpleAuthProvider + +@end diff --git a/Pod/Providers/Facebook/SimpleAuthFacebookProvider.m b/Pod/Providers/Facebook/SimpleAuthFacebookProvider.m new file mode 100644 index 0000000..a9cd267 --- /dev/null +++ b/Pod/Providers/Facebook/SimpleAuthFacebookProvider.m @@ -0,0 +1,154 @@ +// +// SimpleAuthFacebookProvider.m +// SimpleAuth +// +// Created by Caleb Davenport on 11/6/13. +// Copyright (c) 2013-2014 Byliner, Inc. All rights reserved. +// + +#import "SimpleAuthFacebookProvider.h" +#import "ACAccountStore+SimpleAuth.h" +#import +@import Social; + +@implementation SimpleAuthFacebookProvider + +#pragma mark - SimpleAuthProvider + ++ (NSString *)type { + return @"facebook"; +} + ++ (NSDictionary *)defaultOptions { + return @{ + @"permissions" : @[ @"email" ], + @"audience" : @[ ACFacebookAudienceOnlyMe ] + }; +} + +- (void)authorizeWithCompletion:(SimpleAuthRequestHandler)completion { + [[[[self systemAccount] + flattenMap:^RACStream *(ACAccount *account) { + NSArray *signals = @[ + [self remoteAccountWithSystemAccount:account], + [RACSignal return:account] + ]; + return [self rac_liftSelector:@selector(responseDictionaryWithRemoteAccount:systemAccount:) withSignalsFromArray:signals]; + }] + deliverOn:[RACScheduler mainThreadScheduler]] + subscribeNext:^(NSDictionary *response) { + completion(response, nil); + } + error:^(NSError *error) { + completion(nil, error); + }]; +} + + +#pragma mark - Private + +- (RACSignal *)allSystemAccounts { + NSDictionary *options = @{ + ACFacebookAppIdKey : self.options[@"app_id"], + ACFacebookPermissionsKey : self.options[@"permissions"], + ACFacebookAudienceKey: self.options[@"audience"] + }; + return [ACAccountStore SimpleAuth_accountsWithTypeIdentifier:ACAccountTypeIdentifierFacebook options:options]; +} + +- (RACSignal *)systemAccount { + return [[self allSystemAccounts] map:^(NSArray *accounts) { + return [accounts lastObject]; + }]; +} + +- (RACSignal *)remoteAccountWithSystemAccount:(ACAccount *)account { + return [RACSignal createSignal:^RACDisposable *(id subscriber) { + NSURL *URL = [NSURL URLWithString:@"https://graph.facebook.com/me"]; + SLRequest *request = [SLRequest requestForServiceType:SLServiceTypeFacebook requestMethod:SLRequestMethodGET URL:URL parameters:nil]; + request.account = account; + [request performRequestWithHandler:^(NSData *data, NSHTTPURLResponse *response, NSError *connectionError) { + NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(200, 99)]; + NSInteger statusCode = [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 { + NSMutableDictionary *dictionary = [NSMutableDictionary new]; + if (parseError) { + dictionary[NSUnderlyingErrorKey] = parseError; + } + NSError *error = [NSError errorWithDomain:SimpleAuthErrorDomain code:SimpleAuthErrorInvalidData userInfo:dictionary]; + [subscriber sendNext:error]; + } + } + else { + NSMutableDictionary *dictionary = [NSMutableDictionary new]; + if (connectionError) { + dictionary[NSUnderlyingErrorKey] = connectionError; + } + dictionary[SimpleAuthErrorStatusCodeKey] = @(statusCode); + NSError *error = [NSError errorWithDomain:SimpleAuthErrorDomain code:SimpleAuthErrorNetwork userInfo:dictionary]; + [subscriber sendError:error]; + } + }]; + return nil; + }]; +} + +- (NSDictionary *)responseDictionaryWithRemoteAccount:(NSDictionary *)remoteAccount systemAccount:(ACAccount *)systemAccount { + return @{ + @"provider": [[self class] type], + @"credentials": [self credentialsDictionaryWithRemoteAccount:remoteAccount systemAccount:systemAccount], + @"uid": remoteAccount[@"id"], + @"extra": [self extraDictionaryWithRemoteAccount:remoteAccount systemAccount:systemAccount], + @"info": [self infoDictionaryWithRemoteAccount:remoteAccount systemAccount:systemAccount] + }; +} + +- (NSDictionary *)credentialsDictionaryWithRemoteAccount:(NSDictionary *)remoteAccount systemAccount:(ACAccount *)systemAccount { + return @{ + @"token": systemAccount.credential.oauthToken + }; +} + +- (NSDictionary *)extraDictionaryWithRemoteAccount:(NSDictionary *)remoteAccount systemAccount:(ACAccount *)systemAccount { + return @{ + @"raw_info": remoteAccount, + @"account": systemAccount + }; +} + +- (NSDictionary *)infoDictionaryWithRemoteAccount:(NSDictionary *)remoteAccount systemAccount:(ACAccount *)systemAccount { + NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init]; + + dictionary[@"name"] = remoteAccount[@"name"]; + dictionary[@"first_name"] = remoteAccount[@"first_name"]; + dictionary[@"last_name"] = remoteAccount[@"last_name"]; + dictionary[@"verified"] = remoteAccount[@"verified"] ?: @NO; + + id email = remoteAccount[@"email"]; + if (email) { + dictionary[@"email"] = email; + } + + id location = remoteAccount[@"location"][@"name"]; + if (location) { + dictionary[@"location"] = location; + } + + dictionary[@"urls"] = @{ + @"Facebook": remoteAccount[@"link"] + }; + + NSString *avatar = [NSString stringWithFormat:@"https://graph.facebook.com/%@/picture?type=large", remoteAccount[@"id"]]; + dictionary[@"image"] = avatar; + + return dictionary; +} + +@end diff --git a/Pod/Providers/FacebookWeb/SimpleAuthFaceBookWebProvider.h b/Pod/Providers/FacebookWeb/SimpleAuthFaceBookWebProvider.h new file mode 100644 index 0000000..856bebd --- /dev/null +++ b/Pod/Providers/FacebookWeb/SimpleAuthFaceBookWebProvider.h @@ -0,0 +1,13 @@ +// +// SimpleAuthFaceBookWebProvider.h +// SimpleAuth +// +// Created by Caleb Davenport on 1/22/14. +// Copyright (c) 2014 Byliner, Inc. All rights reserved. +// + +#import "SimpleAuthProvider.h" + +@interface SimpleAuthFaceBookWebProvider : SimpleAuthProvider + +@end diff --git a/Pod/Providers/FacebookWeb/SimpleAuthFaceBookWebProvider.m b/Pod/Providers/FacebookWeb/SimpleAuthFaceBookWebProvider.m new file mode 100644 index 0000000..411cfdf --- /dev/null +++ b/Pod/Providers/FacebookWeb/SimpleAuthFaceBookWebProvider.m @@ -0,0 +1,193 @@ +// +// SimpleAuthFaceBookWebProvider.m +// SimpleAuth +// +// Created by Caleb Davenport on 1/22/14. +// Copyright (c) 2014 Byliner, Inc. All rights reserved. +// + +#import "SimpleAuthFaceBookWebProvider.h" +#import "SimpleAuthFacebookWebLoginViewController.h" + +#import "UIViewController+SimpleAuthAdditions.h" +#import + +@implementation SimpleAuthFaceBookWebProvider + +#pragma mark - SimpleAuthProvider + ++ (NSString *)type { + return @"facebook-web"; +} + + ++ (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; + dictionary[SimpleAuthRedirectURIKey] = @"https://www.facebook.com/connect/login_success.html"; + dictionary[@"permissions"] = @[ @"email" ]; + 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:^(id x) { + completion(x, nil); + } + error:^(NSError *error) { + completion(nil, error); + }]; +} + + +#pragma mark - Private + +- (RACSignal *)accessToken { + return [RACSignal createSignal:^RACDisposable *(id subscriber) { + dispatch_async(dispatch_get_main_queue(), ^{ + SimpleAuthFacebookWebLoginViewController *login = [[SimpleAuthFacebookWebLoginViewController alloc] initWithOptions:self.options]; + + login.completion = ^(UIViewController *controller, NSURL *URL, NSError *error) { + SimpleAuthInterfaceHandler block = self.options[SimpleAuthDismissInterfaceBlockKey]; + block(controller); + + // Parse URL + NSString *fragment = [URL fragment]; + NSDictionary *dictionary = [CMDQueryStringSerialization dictionaryWithQueryString:fragment]; + id token = dictionary[@"access_token"]; + id expiration = dictionary[@"expires_in"]; + + // Check for error + if (!token || !expiration) { + [subscriber sendError:error]; + return; + } + + // Send completion + [subscriber sendNext:dictionary]; + [subscriber sendCompleted]; + }; + + SimpleAuthInterfaceHandler block = self.options[SimpleAuthPresentInterfaceBlockKey]; + block(login); + }); + return nil; + }]; +} + + +- (RACSignal *)accountWithAccessToken:(NSDictionary *)accessToken { + return [RACSignal createSignal:^RACDisposable *(id subscriber) { + NSDictionary *parameters = @{ @"access_token" : accessToken[@"access_token"] }; + NSString *URLString = [NSString stringWithFormat: + @"https://graph.facebook.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 { + NSMutableDictionary *dictionary = [NSMutableDictionary new]; + if (parseError) { + dictionary[NSUnderlyingErrorKey] = parseError; + } + NSError *error = [NSError errorWithDomain:SimpleAuthErrorDomain code:SimpleAuthErrorInvalidData userInfo:dictionary]; + [subscriber sendNext:error]; + } + } + else { + NSMutableDictionary *dictionary = [NSMutableDictionary new]; + if (connectionError) { + dictionary[NSUnderlyingErrorKey] = connectionError; + } + dictionary[SimpleAuthErrorStatusCodeKey] = @(statusCode); + NSError *error = [NSError errorWithDomain:SimpleAuthErrorDomain code:SimpleAuthErrorNetwork userInfo:dictionary]; + [subscriber sendError:error]; + } + }]; + return nil; + }]; +} + + +- (NSDictionary *)dictionaryWithAccount:(NSDictionary *)account accessToken:(NSDictionary *)accessToken { + NSMutableDictionary *dictionary = [NSMutableDictionary new]; + + // Provider + dictionary[@"provider"] = [[self class] type]; + + // Credentials + NSTimeInterval expiresAtInterval = [accessToken[@"expires_in"] doubleValue]; + NSDate *expiresAtDate = [NSDate dateWithTimeIntervalSinceNow:expiresAtInterval]; + dictionary[@"credentials"] = @{ + @"token" : accessToken[@"access_token"], + @"expires_at" : expiresAtDate + }; + + // User ID + dictionary[@"uid"] = account[@"id"]; + + // Raw response + dictionary[@"extra"] = @{ + @"raw_info" : account + }; + + // Profile image + NSString *avatar = [NSString stringWithFormat:@"https://graph.facebook.com/%@/picture?type=large", account[@"id"]]; + + // Location + NSString *location = account[@"location"][@"name"]; + + // User info + NSMutableDictionary *user = [NSMutableDictionary new]; + if (account[@"email"]) { + user[@"email"] = account[@"email"]; + } + user[@"name"] = account[@"name"]; + user[@"first_name"] = account[@"first_name"]; + user[@"last_name"] = account[@"last_name"]; + user[@"image"] = avatar; + if (location) { + user[@"location"] = location; + } + user[@"verified"] = account[@"verified"] ?: @NO; + user[@"urls"] = @{ + @"Facebook" : account[@"link"], + }; + dictionary[@"info"] = user; + + return dictionary; +} + +@end diff --git a/Pod/Providers/FacebookWeb/SimpleAuthFacebookWebLoginViewController.h b/Pod/Providers/FacebookWeb/SimpleAuthFacebookWebLoginViewController.h new file mode 100644 index 0000000..e0f5445 --- /dev/null +++ b/Pod/Providers/FacebookWeb/SimpleAuthFacebookWebLoginViewController.h @@ -0,0 +1,13 @@ +// +// SimpleAuthFacebookWebLoginViewController.h +// SimpleAuth +// +// Created by Caleb Davenport on 1/22/14. +// Copyright (c) 2014 Byliner, Inc. All rights reserved. +// + +#import "SimpleAuthWebViewController.h" + +@interface SimpleAuthFacebookWebLoginViewController : SimpleAuthWebViewController + +@end diff --git a/Pod/Providers/FacebookWeb/SimpleAuthFacebookWebLoginViewController.m b/Pod/Providers/FacebookWeb/SimpleAuthFacebookWebLoginViewController.m new file mode 100644 index 0000000..fe3dc35 --- /dev/null +++ b/Pod/Providers/FacebookWeb/SimpleAuthFacebookWebLoginViewController.m @@ -0,0 +1,38 @@ +// +// SimpleAuthFacebookWebLoginViewController.m +// SimpleAuth +// +// Created by Caleb Davenport on 1/22/14. +// Copyright (c) 2014 Byliner, Inc. All rights reserved. +// + +#import "SimpleAuthFacebookWebLoginViewController.h" + +@implementation SimpleAuthFacebookWebLoginViewController + +#pragma mark - SimpleAuthWebViewController + +- (instancetype)initWithOptions:(NSDictionary *)options requestToken:(NSDictionary *)requestToken { + if ((self = [super initWithOptions:options requestToken:requestToken])) { + self.title = @"Facebook"; + } + return self; +} + + +- (NSURLRequest *)initialRequest { + NSDictionary *parameters = @{ + @"client_id" : self.options[@"app_id"], + @"redirect_uri" : self.options[SimpleAuthRedirectURIKey], + @"response_type" : @"token", + @"scope" : [self.options[@"permissions"] componentsJoinedByString:@","] + }; + NSString *URLString = [NSString stringWithFormat: + @"https://www.facebook.com/dialog/oauth?%@", + [CMDQueryStringSerialization queryStringWithDictionary:parameters]]; + NSURL *URL = [NSURL URLWithString:URLString]; + + return [NSURLRequest requestWithURL:URL]; +} + +@end diff --git a/Pod/Providers/FoursquareWeb/SimpleAuthFoursquareWebLoginViewController.h b/Pod/Providers/FoursquareWeb/SimpleAuthFoursquareWebLoginViewController.h new file mode 100644 index 0000000..71945a2 --- /dev/null +++ b/Pod/Providers/FoursquareWeb/SimpleAuthFoursquareWebLoginViewController.h @@ -0,0 +1,13 @@ +// +// SimpleAuthFoursquareWebLoginViewController.h +// SimpleAuth +// +// Created by Julien Seren-Rosso on 23/01/2014. +// Copyright (c) 2014 Byliner, Inc. All rights reserved. +// + +#import "SimpleAuthWebViewController.h" + +@interface SimpleAuthFoursquareWebLoginViewController : SimpleAuthWebViewController + +@end diff --git a/Pod/Providers/FoursquareWeb/SimpleAuthFoursquareWebLoginViewController.m b/Pod/Providers/FoursquareWeb/SimpleAuthFoursquareWebLoginViewController.m new file mode 100644 index 0000000..2d91121 --- /dev/null +++ b/Pod/Providers/FoursquareWeb/SimpleAuthFoursquareWebLoginViewController.m @@ -0,0 +1,36 @@ +// +// SimpleAuthFoursquareWebLoginViewController.m +// SimpleAuth +// +// Created by Julien Seren-Rosso on 23/01/2014. +// Copyright (c) 2014 Byliner, Inc. All rights reserved. +// + +#import "SimpleAuthFoursquareWebLoginViewController.h" + +@implementation SimpleAuthFoursquareWebLoginViewController + +#pragma mark - SimpleAuthWebViewController + +- (instancetype)initWithOptions:(NSDictionary *)options requestToken:(NSDictionary *)requestToken { + if ((self = [super initWithOptions:options requestToken:requestToken])) { + self.title = @"Foursquare"; + } + return self; +} + + +- (NSURLRequest *)initialRequest { + NSDictionary *parameters = @{ + @"client_id" : self.options[@"client_id"], + @"redirect_uri" : self.options[SimpleAuthRedirectURIKey], + @"response_type" : @"token" + }; + NSString *URLString = [NSString stringWithFormat: + @"https://foursquare.com/oauth2/authenticate?%@", + [CMDQueryStringSerialization queryStringWithDictionary:parameters]]; + NSURL *URL = [NSURL URLWithString:URLString]; + + return [NSURLRequest requestWithURL:URL]; +} +@end diff --git a/Pod/Providers/FoursquareWeb/SimpleAuthFoursquareWebProvider.h b/Pod/Providers/FoursquareWeb/SimpleAuthFoursquareWebProvider.h new file mode 100644 index 0000000..05e5879 --- /dev/null +++ b/Pod/Providers/FoursquareWeb/SimpleAuthFoursquareWebProvider.h @@ -0,0 +1,13 @@ +// +// SimpleAuthFoursquareWebProvider.h +// SimpleAuth +// +// Created by Julien Seren-Rosso on 23/01/2014. +// Copyright (c) 2014 Byliner, Inc. All rights reserved. +// + +#import "SimpleAuthProvider.h" + +@interface SimpleAuthFoursquareWebProvider : SimpleAuthProvider + +@end diff --git a/Pod/Providers/FoursquareWeb/SimpleAuthFoursquareWebProvider.m b/Pod/Providers/FoursquareWeb/SimpleAuthFoursquareWebProvider.m new file mode 100644 index 0000000..090de65 --- /dev/null +++ b/Pod/Providers/FoursquareWeb/SimpleAuthFoursquareWebProvider.m @@ -0,0 +1,188 @@ +// +// SimpleAuthFoursquareWebProvider.m +// SimpleAuth +// +// Created by Julien Seren-Rosso on 23/01/2014. +// Copyright (c) 2014 Byliner, Inc. All rights reserved. +// + +#import "SimpleAuthFoursquareWebProvider.h" +#import "SimpleAuthFoursquareWebLoginViewController.h" + +#import +#import "UIViewController+SimpleAuthAdditions.h" + +@implementation SimpleAuthFoursquareWebProvider + +#pragma mark - SimpleAuthProvider + ++ (NSString *)type { + return @"foursquare-web"; +} + + ++ (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; + return options; +} + + +- (void)authorizeWithCompletion:(SimpleAuthRequestHandler)completion { + [[[self accessToken] + flattenMap:^RACStream *(NSString *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 [RACSignal createSignal:^RACDisposable *(id subscriber) { + dispatch_async(dispatch_get_main_queue(), ^{ + SimpleAuthFoursquareWebLoginViewController *login = [[SimpleAuthFoursquareWebLoginViewController alloc] initWithOptions:self.options]; + login.completion = ^(UIViewController *login, NSURL *URL, NSError *error) { + SimpleAuthInterfaceHandler dismissBlock = self.options[SimpleAuthDismissInterfaceBlockKey]; + dismissBlock(login); + + // Parse URL + NSString *fragment = [URL fragment]; + NSDictionary *dictionary = [CMDQueryStringSerialization dictionaryWithQueryString:fragment]; + NSString *token = dictionary[@"access_token"]; + + // Check for error + if (![token length]) { + [subscriber sendError:error]; + return; + } + + // Send completion + [subscriber sendNext:token]; + [subscriber sendCompleted]; + }; + + SimpleAuthInterfaceHandler block = self.options[SimpleAuthPresentInterfaceBlockKey]; + block(login); + }); + return nil; + }]; +} + + +- (RACSignal *)accountWithAccessToken:(NSString *)accessToken { + return [RACSignal createSignal:^RACDisposable *(id subscriber) { + NSDictionary *parameters = @{ @"oauth_token" : accessToken }; + NSString *query = [CMDQueryStringSerialization queryStringWithDictionary:parameters]; + NSString *URLString = [NSString stringWithFormat:@"https://api.foursquare.com/v2/users/self?v=20140210&%@", query]; + 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:(NSString *)accessToken { + NSMutableDictionary *dictionary = [NSMutableDictionary new]; + NSDictionary *userData = account[@"response"][@"user"]; + + // Provider + dictionary[@"provider"] = [[self class] type]; + + // Credentials + dictionary[@"credentials"] = @{ + @"token" : accessToken + }; + + // User ID + dictionary[@"uid"] = userData[@"id"]; + + // Raw response + dictionary[@"extra"] = @{ + @"raw_info" : userData + }; + + // User info + NSMutableDictionary *user = [NSMutableDictionary new]; + if (userData[@"contact"][@"email"]) { + user[@"email"] = userData[@"contact"][@"email"]; + } + + if (userData[@"firstName"]) { + user[@"first_name"] = userData[@"firstName"]; + } + + if (userData[@"lastName"]) { + user[@"last_name"] = userData[@"lastName"]; + } + + user[@"name"] = [NSString stringWithFormat:@"%@ %@", user[@"first_name"], user[@"last_name"]]; + + user[@"gender"] = userData[@"gender"]; + + if ([userData[@"photo"] isKindOfClass:NSDictionary.class]) { + user[@"image"] = [NSString stringWithFormat:@"%@500x500%@", userData[@"photo"][@"prefix"], userData[@"photo"][@"suffix"]]; + } else if ([userData[@"photo"] isKindOfClass:NSString.class]) { + user[@"image"] = userData[@"photo"]; + } + + if (userData[@"photo"]) { + user[@"photo"] = userData[@"photo"]; + } + if (userData[@"homeCity"]) { + NSString *homecity = [[userData[@"homeCity"] componentsSeparatedByString:@","] firstObject]; + user[@"location"] = homecity; + } + user[@"urls"] = @{ + @"Foursquare" : [NSString stringWithFormat:@"https://foursquare.com/user/%@", userData[@"id"]], + }; + dictionary[@"info"] = user; + + return dictionary; +} + + +@end diff --git a/Pod/Providers/GoogleWeb/SimpleAuthGoogleWebLoginViewController.h b/Pod/Providers/GoogleWeb/SimpleAuthGoogleWebLoginViewController.h new file mode 100644 index 0000000..ea0f037 --- /dev/null +++ b/Pod/Providers/GoogleWeb/SimpleAuthGoogleWebLoginViewController.h @@ -0,0 +1,13 @@ +// +// SimpleAuthGoogleWebLoginViewController.h +// SimpleAuth +// +// Created by Ramon Vicente on 2/24/15. +// Copyright (c) 2015 UMOBI. All rights reserved. +// + +#import "SimpleAuthWebViewController.h" + +@interface SimpleAuthGoogleWebLoginViewController : SimpleAuthWebViewController + +@end diff --git a/Pod/Providers/GoogleWeb/SimpleAuthGoogleWebLoginViewController.m b/Pod/Providers/GoogleWeb/SimpleAuthGoogleWebLoginViewController.m new file mode 100644 index 0000000..146ad6c --- /dev/null +++ b/Pod/Providers/GoogleWeb/SimpleAuthGoogleWebLoginViewController.m @@ -0,0 +1,38 @@ +// +// SimpleAuthGoogleWebLoginViewController.m +// SimpleAuth +// +// Created by Ramon Vicente on 2/24/15. +// Copyright (c) 2015 UMOBI. All rights reserved. +// + +#import "SimpleAuthGoogleWebLoginViewController.h" + +@implementation SimpleAuthGoogleWebLoginViewController + +#pragma mark - SimpleAuthWebViewController + +- (instancetype)initWithOptions:(NSDictionary *)options requestToken:(NSDictionary *)requestToken { + if ((self = [super initWithOptions:options requestToken:requestToken])) { + self.title = @"Google +"; + } + return self; +} + + +- (NSURLRequest *)initialRequest { + NSDictionary *parameters = @{ + @"client_id" : self.options[@"client_id"], + @"redirect_uri" : self.options[SimpleAuthRedirectURIKey], + @"response_type" : @"code", + @"scope" : self.options[@"scope"] + }; + NSString *URLString = [NSString stringWithFormat: + @"https://accounts.google.com/o/oauth2/auth?%@", + [CMDQueryStringSerialization queryStringWithDictionary:parameters]]; + NSURL *URL = [NSURL URLWithString:URLString]; + + return [NSURLRequest requestWithURL:URL]; +} + +@end diff --git a/Pod/Providers/GoogleWeb/SimpleAuthGoogleWebProvider.h b/Pod/Providers/GoogleWeb/SimpleAuthGoogleWebProvider.h new file mode 100644 index 0000000..781d819 --- /dev/null +++ b/Pod/Providers/GoogleWeb/SimpleAuthGoogleWebProvider.h @@ -0,0 +1,13 @@ +// +// SimpleAuthGoogleWebProvider.h +// SimpleAuth +// +// Created by Ramon Vicente on 2/24/15. +// Copyright (c) 2015 UMOBI. All rights reserved. +// + +#import "SimpleAuthProvider.h" + +@interface SimpleAuthGoogleWebProvider : SimpleAuthProvider + +@end diff --git a/Pod/Providers/GoogleWeb/SimpleAuthGoogleWebProvider.m b/Pod/Providers/GoogleWeb/SimpleAuthGoogleWebProvider.m new file mode 100644 index 0000000..3bf070d --- /dev/null +++ b/Pod/Providers/GoogleWeb/SimpleAuthGoogleWebProvider.m @@ -0,0 +1,196 @@ +// +// SimpleAuthGoogleWebProvider.m +// SimpleAuth +// +// Created by Ramon Vicente on 2/24/15. +// Copyright (c) 2015 UMOBI. All rights reserved. +// + +#import "SimpleAuthGoogleWebProvider.h" +#import "SimpleAuthGoogleWebLoginViewController.h" + +#import "UIViewController+SimpleAuthAdditions.h" + +@implementation SimpleAuthGoogleWebProvider + +#pragma mark - SimpleAuthProvider + ++ (NSString *)type { + return @"google-web"; +} + ++ (NSDictionary *)defaultOptions { + + // Default present block + SimpleAuthInterfaceHandler presentBlock = ^(UIViewController *controller) { + UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:controller]; + navigationController.modalPresentationStyle = UIModalPresentationFormSheet; + UIViewController *presentedViewController = [UIViewController SimpleAuth_presentedViewController]; + [presentedViewController presentViewController:navigationController + animated:YES + completion:nil]; + }; + + // Default dismiss block + SimpleAuthInterfaceHandler dismissBlock = ^(id viewController) { + [viewController dismissViewControllerAnimated:YES + completion:nil]; + }; + + NSMutableDictionary *options = [NSMutableDictionary dictionaryWithDictionary:[super defaultOptions]]; + options[SimpleAuthPresentInterfaceBlockKey] = presentBlock; + options[SimpleAuthDismissInterfaceBlockKey] = dismissBlock; + options[SimpleAuthRedirectURIKey] = @"http://localhost"; + options[@"scope"] = @"email openid profile"; + return options; +} + +- (void)authorizeWithCompletion:(SimpleAuthRequestHandler)completion { + dispatch_async(dispatch_get_main_queue(), ^{ + SimpleAuthGoogleWebLoginViewController *loginViewController = [[SimpleAuthGoogleWebLoginViewController alloc] initWithOptions:self.options]; + loginViewController.completion = ^(UIViewController *viewController, NSURL *URL, NSError *error) { + SimpleAuthInterfaceHandler dismissBlock = self.options[SimpleAuthDismissInterfaceBlockKey]; + dismissBlock(viewController); + + NSString *query = [URL query]; + NSDictionary *dictionary = [CMDQueryStringSerialization dictionaryWithQueryString:query]; + NSString *code = dictionary[@"code"]; + if ([code length] > 0) { + [self userWithCode:code + completion:completion]; + } else { + completion(nil, error); + } + }; + SimpleAuthInterfaceHandler block = self.options[SimpleAuthPresentInterfaceBlockKey]; + block(loginViewController); + }); +} + +#pragma mark - Private +- (void)userWithCode:(NSString *)code completion:(SimpleAuthRequestHandler)completion +{ + NSDictionary *parameters = @{ @"code" : code, + @"client_id" : self.options[@"client_id"], + @"client_secret" : self.options[@"client_secret"], + @"redirect_uri": self.options[@"redirect_uri"], + @"grant_type": @"authorization_code"}; + + NSString *data = [CMDQueryStringSerialization queryStringWithDictionary:parameters]; + + NSString *URLString = [NSString stringWithFormat:@"https://accounts.google.com/o/oauth2/token"]; + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:URLString]]; + [request setHTTPMethod:@"POST"]; + [request setHTTPBody:[data dataUsingEncoding:NSUTF8StringEncoding]]; + + [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; + NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:data + options:kNilOptions + error:&parseError]; + NSString *token = dictionary[@"access_token"]; + if ([token length] > 0) { + + NSDictionary *credentials = @{ + @"access_token" : token, + @"expires" : [NSDate dateWithTimeIntervalSinceNow:[dictionary[@"expires_in"] doubleValue]], + @"token_type" : @"bearer", + @"id_token": dictionary[@"id_token"] + }; + + [self userWithCredentials:credentials + completion:completion]; + } else { + completion(nil, parseError); + } + + } else { + completion(nil, connectionError); + } + }]; +} + +- (void)userWithCredentials:(NSDictionary *)credentials completion:(SimpleAuthRequestHandler)completion { + + NSString *URLString = [NSString stringWithFormat:@"https://www.googleapis.com/userinfo/v2/me"]; + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:URLString]]; + + [request setValue:[NSString stringWithFormat:@"Bearer %@", credentials[@"access_token"]] 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; + NSDictionary *userInfo = [NSJSONSerialization JSONObjectWithData:data + options:kNilOptions + error:&parseError]; + if (userInfo) { + completion ([self dictionaryWithAccount:userInfo credentials:credentials], nil); + } else { + completion(nil, parseError); + } + } else { + completion(nil, connectionError); + } + }]; +} + +- (NSDictionary *)dictionaryWithAccount:(NSDictionary *)account + credentials:(NSDictionary *)credentials +{ + NSMutableDictionary *dictionary = [NSMutableDictionary dictionary]; + + // Provider + dictionary[@"provider"] = [[self class] type]; + + // Credentials + dictionary[@"credentials"] = @{ + @"token" : credentials[@"access_token"], + @"expires_at" : credentials[@"expires"] + }; + + // User ID + dictionary[@"uid"] = account[@"id"]; + + // Raw response + dictionary[@"extra"] = @{ + @"raw_info" : account + }; + + // Location + NSString *location = account[@"location"][@"name"]; + + // User info + NSMutableDictionary *user = [NSMutableDictionary new]; + if (account[@"email"]) { + user[@"email"] = account[@"email"]; + } + user[@"name"] = account[@"name"]; + user[@"first_name"] = account[@"given_name"]; + user[@"last_name"] = account[@"family_name"]; + user[@"gender"] = account[@"gender"]; + + user[@"image"] = account[@"picture"]; + if (location) { + user[@"location"] = location; + } + user[@"verified"] = account[@"verified_email"] ? @YES : @NO; + user[@"urls"] = @{ + @"Google +" : account[@"link"], + }; + + dictionary[@"info"] = user; + + return dictionary; +} + +@end diff --git a/Providers/Instagram/SimpleAuthInstagramLoginViewController.h b/Pod/Providers/Instagram/SimpleAuthInstagramLoginViewController.h similarity index 76% rename from Providers/Instagram/SimpleAuthInstagramLoginViewController.h rename to Pod/Providers/Instagram/SimpleAuthInstagramLoginViewController.h index 0984517..18d8cb0 100644 --- a/Providers/Instagram/SimpleAuthInstagramLoginViewController.h +++ b/Pod/Providers/Instagram/SimpleAuthInstagramLoginViewController.h @@ -3,7 +3,7 @@ // SimpleAuth // // Created by Caleb Davenport on 11/7/13. -// Copyright (c) 2013 Seesaw Decisions Corporation. All rights reserved. +// Copyright (c) 2013-2014 Byliner, Inc. All rights reserved. // #import "SimpleAuthWebViewController.h" diff --git a/Pod/Providers/Instagram/SimpleAuthInstagramLoginViewController.m b/Pod/Providers/Instagram/SimpleAuthInstagramLoginViewController.m new file mode 100644 index 0000000..439f0ab --- /dev/null +++ b/Pod/Providers/Instagram/SimpleAuthInstagramLoginViewController.m @@ -0,0 +1,39 @@ +// +// SimpleAuthInstagramLoginViewController.m +// SimpleAuthInstagram +// +// Created by Caleb Davenport on 11/7/13. +// Copyright (c) 2013-2014 Byliner, Inc. All rights reserved. +// + +#import "SimpleAuthInstagramLoginViewController.h" + +@implementation SimpleAuthInstagramLoginViewController + +#pragma mark - SimpleAuthWebViewController + +- (instancetype)initWithOptions:(NSDictionary *)options requestToken:(NSDictionary *)requestToken { + if ((self = [super initWithOptions:options requestToken:requestToken])) { + self.title = @"Instagram"; + } + return self; +} + + +- (NSURLRequest *)initialRequest { + NSMutableDictionary *parameters = [NSMutableDictionary new]; + parameters[@"client_id"] = self.options[@"client_id"]; + parameters[@"redirect_uri"] = self.options[SimpleAuthRedirectURIKey]; + parameters[@"response_type"] = @"token"; + if (self.options[@"scope"]) { + parameters[@"scope"] = [self.options[@"scope"] componentsJoinedByString:@" "]; + } + NSString *URLString = [NSString stringWithFormat: + @"https://instagram.com/oauth/authorize/?%@", + [CMDQueryStringSerialization queryStringWithDictionary:parameters]]; + NSURL *URL = [NSURL URLWithString:URLString]; + + return [NSURLRequest requestWithURL:URL]; +} + +@end diff --git a/Providers/Instagram/SimpleAuthInstagramProvider.h b/Pod/Providers/Instagram/SimpleAuthInstagramProvider.h similarity index 72% rename from Providers/Instagram/SimpleAuthInstagramProvider.h rename to Pod/Providers/Instagram/SimpleAuthInstagramProvider.h index d4f9c53..855a12a 100644 --- a/Providers/Instagram/SimpleAuthInstagramProvider.h +++ b/Pod/Providers/Instagram/SimpleAuthInstagramProvider.h @@ -3,7 +3,7 @@ // SimpleAuth // // Created by Caleb Davenport on 11/7/13. -// Copyright (c) 2013 Seesaw Decisions Corporation. All rights reserved. +// Copyright (c) 2013-2014 Byliner, Inc. All rights reserved. // #import "SimpleAuthProvider.h" diff --git a/Providers/Instagram/SimpleAuthInstagramProvider.m b/Pod/Providers/Instagram/SimpleAuthInstagramProvider.m similarity index 73% rename from Providers/Instagram/SimpleAuthInstagramProvider.m rename to Pod/Providers/Instagram/SimpleAuthInstagramProvider.m index f23588c..d8c1227 100644 --- a/Providers/Instagram/SimpleAuthInstagramProvider.m +++ b/Pod/Providers/Instagram/SimpleAuthInstagramProvider.m @@ -3,28 +3,17 @@ // SimpleAuth // // Created by Caleb Davenport on 11/7/13. -// Copyright (c) 2013 Seesaw Decisions Corporation. All rights reserved. +// Copyright (c) 2013-2014 Byliner, Inc. All rights reserved. // #import "SimpleAuthInstagramProvider.h" #import "SimpleAuthInstagramLoginViewController.h" #import "UIViewController+SimpleAuthAdditions.h" - -#import #import @implementation SimpleAuthInstagramProvider -#pragma mark - NSObject - -+ (void)load { - @autoreleasepool { - [SimpleAuth registerProviderClass:self]; - } -} - - #pragma mark - SimpleAuthProvider + (NSString *)type { @@ -38,7 +27,7 @@ + (NSDictionary *)defaultOptions { SimpleAuthInterfaceHandler presentBlock = ^(UIViewController *controller) { UINavigationController *navigation = [[UINavigationController alloc] initWithRootViewController:controller]; navigation.modalPresentationStyle = UIModalPresentationFormSheet; - UIViewController *presented = [UIViewController sa_presentedViewController]; + UIViewController *presented = [UIViewController SimpleAuth_presentedViewController]; [presented presentViewController:navigation animated:YES completion:nil]; }; @@ -76,30 +65,31 @@ - (void)authorizeWithCompletion:(SimpleAuthRequestHandler)completion { - (RACSignal *)accessToken { return [RACSignal createSignal:^RACDisposable *(id subscriber) { - SimpleAuthInstagramLoginViewController *login = [[SimpleAuthInstagramLoginViewController alloc] initWithOptions:self.options]; - login.completion = ^(UIViewController *login, NSURL *URL, NSError *error) { - SimpleAuthInterfaceHandler dismissBlock = self.options[SimpleAuthDismissInterfaceBlockKey]; - dismissBlock(login); - - // Parse URL - NSString *fragment = [URL fragment]; - NSDictionary *dictionary = [NSDictionary sam_dictionaryWithFormEncodedString:fragment]; - NSString *token = dictionary[@"access_token"]; + dispatch_async(dispatch_get_main_queue(), ^{ + SimpleAuthInstagramLoginViewController *login = [[SimpleAuthInstagramLoginViewController alloc] initWithOptions:self.options]; + login.completion = ^(UIViewController *login, NSURL *URL, NSError *error) { + SimpleAuthInterfaceHandler dismissBlock = self.options[SimpleAuthDismissInterfaceBlockKey]; + dismissBlock(login); + + // Parse URL + NSString *fragment = [URL fragment]; + NSDictionary *dictionary = [CMDQueryStringSerialization dictionaryWithQueryString:fragment]; + NSString *token = dictionary[@"access_token"]; + + // Check for error + if (![token length]) { + [subscriber sendError:error]; + return; + } + + // Send completion + [subscriber sendNext:token]; + [subscriber sendCompleted]; + }; - // Check for error - if (![token length]) { - [subscriber sendError:nil]; - return; - } - - // Send completion - [subscriber sendNext:token]; - [subscriber sendCompleted]; - }; - - SimpleAuthInterfaceHandler block = self.options[SimpleAuthPresentInterfaceBlockKey]; - block(login); - + SimpleAuthInterfaceHandler block = self.options[SimpleAuthPresentInterfaceBlockKey]; + block(login); + }); return nil; }]; } @@ -108,7 +98,7 @@ - (RACSignal *)accessToken { - (RACSignal *)accountWithAccessToken:(NSString *)accessToken { return [RACSignal createSignal:^RACDisposable *(id subscriber) { NSDictionary *parameters = @{ @"access_token" : accessToken }; - NSString *query = [parameters sam_stringWithFormEncodedComponents]; + NSString *query = [CMDQueryStringSerialization queryStringWithDictionary:parameters]; NSString *URLString = [NSString stringWithFormat:@"https://api.instagram.com/v1/users/self?%@", query]; NSURL *URL = [NSURL URLWithString:URLString]; NSURLRequest *request = [NSURLRequest requestWithURL:URL]; @@ -153,8 +143,10 @@ - (NSDictionary *)dictionaryWithAccount:(NSDictionary *)account accessToken:(NSS // User ID dictionary[@"uid"] = data[@"id"]; - // Raw response - dictionary[@"raw_info"] = account; + // Extra + dictionary[@"extra"] = @{ + @"raw_info" : account + }; // User info NSMutableDictionary *user = [NSMutableDictionary new]; diff --git a/Pod/Providers/LinkedIn/SimpleAuthLinkedInWebLoginViewController.h b/Pod/Providers/LinkedIn/SimpleAuthLinkedInWebLoginViewController.h new file mode 100644 index 0000000..3574ba6 --- /dev/null +++ b/Pod/Providers/LinkedIn/SimpleAuthLinkedInWebLoginViewController.h @@ -0,0 +1,13 @@ +// +// SimpleAuthLinkedInWebLoginViewController.h +// SimpleAuth +// +// Created by Abhishek Sheth on 24/01/14. +// Copyright (c) 2014 Byliner, Inc. All rights reserved. +// + +#import "SimpleAuthWebViewController.h" + +@interface SimpleAuthLinkedInWebLoginViewController : SimpleAuthWebViewController + +@end diff --git a/Pod/Providers/LinkedIn/SimpleAuthLinkedInWebLoginViewController.m b/Pod/Providers/LinkedIn/SimpleAuthLinkedInWebLoginViewController.m new file mode 100644 index 0000000..d32d061 --- /dev/null +++ b/Pod/Providers/LinkedIn/SimpleAuthLinkedInWebLoginViewController.m @@ -0,0 +1,45 @@ +// +// SimpleAuthLinkedInWebLoginViewController.m +// SimpleAuth +// +// Created by Abhishek Sheth on 24/01/14. +// Copyright (c) 2014 Byliner, Inc. All rights reserved. +// + +#import "SimpleAuthLinkedInWebLoginViewController.h" + +@interface SimpleAuthLinkedInWebLoginViewController () + +@end + +@implementation SimpleAuthLinkedInWebLoginViewController + +#pragma mark - SimpleAuthWebViewController + +- (instancetype)initWithOptions:(NSDictionary *)options requestToken:(NSDictionary *)requestToken { + if ((self = [super initWithOptions:options requestToken:requestToken])) { + self.title = @"LinkedIn"; + } + return self; +} + + +- (NSURLRequest *)initialRequest { + NSDictionary *parameters = @{ + @"client_id" : self.options[@"client_id"], + @"redirect_uri" : self.options[SimpleAuthRedirectURIKey], + @"response_type" : @"code", + @"state" : [[NSProcessInfo processInfo] globallyUniqueString] + }; + + NSString *URLString = [NSString stringWithFormat: + @"https://www.linkedin.com/uas/oauth2/authorization?%@", + [CMDQueryStringSerialization queryStringWithDictionary:parameters]]; + NSURL *URL = [NSURL URLWithString:URLString]; + + return [NSURLRequest requestWithURL:URL]; +} + + + +@end diff --git a/Pod/Providers/LinkedIn/SimpleAuthLinkedInWebProvider.h b/Pod/Providers/LinkedIn/SimpleAuthLinkedInWebProvider.h new file mode 100644 index 0000000..65e5f3a --- /dev/null +++ b/Pod/Providers/LinkedIn/SimpleAuthLinkedInWebProvider.h @@ -0,0 +1,13 @@ +// +// SimpleAuthLinkedInProvider.h +// SimpleAuth +// +// Created by Abhishek Sheth on 24/01/14. +// Copyright (c) 2014 Byliner, Inc. All rights reserved. +// + +#import "SimpleAuthProvider.h" + +@interface SimpleAuthLinkedInWebProvider : SimpleAuthProvider + +@end diff --git a/Pod/Providers/LinkedIn/SimpleAuthLinkedInWebProvider.m b/Pod/Providers/LinkedIn/SimpleAuthLinkedInWebProvider.m new file mode 100644 index 0000000..ad889c6 --- /dev/null +++ b/Pod/Providers/LinkedIn/SimpleAuthLinkedInWebProvider.m @@ -0,0 +1,225 @@ +// +// SimpleAuthLinkedInProvider.m +// SimpleAuth +// +// Created by Abhishek Sheth on 24/01/14. +// Copyright (c) 2014 Byliner, Inc. All rights reserved. +// + +#import "SimpleAuthLinkedInWebProvider.h" +#import "SimpleAuthLinkedInWebLoginViewController.h" + +#import +#import "UIViewController+SimpleAuthAdditions.h" + +@implementation SimpleAuthLinkedInWebProvider + +#pragma mark - SimpleAuthProvider + ++ (NSString *)type { + return @"linkedin-web"; +} + + ++ (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; + 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(), ^{ + SimpleAuthLinkedInWebLoginViewController *login = [[SimpleAuthLinkedInWebLoginViewController 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 request + NSDictionary *parameters = @{ + @"code" : code, + @"client_id" : self.options[@"client_id"], + @"client_secret" : self.options[@"client_secret"], + @"redirect_uri" : self.options[@"redirect_uri"], + @"grant_type" : @"authorization_code" + }; + NSString *query = [CMDQueryStringSerialization queryStringWithDictionary:parameters]; + NSURL *URL = [NSURL URLWithString:@"https://api.linkedin.com/uas/oauth2/accessToken"]; + 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 *)accessToken { + return [[self authorizationCode] flattenMap:^(id responseObject) { + return [self accessTokenWithAuthorizationCode:responseObject]; + }]; +} + + +- (RACSignal *)accountWithAccessToken:(NSDictionary *)accessToken { + return [RACSignal createSignal:^RACDisposable *(id subscriber) { + NSDictionary *parameters = @{ + @"oauth2_access_token" : accessToken[@"access_token"], + @"format" : @"json" + }; + // field_selectors control the fields that LinkedIn returns for the user object. If none specified, LinkedIn returns a minimal set. + NSString *URLString; + if (self.options[@"field_selectors"]) + { + URLString = [NSString stringWithFormat: + @"https://api.linkedin.com/v1/people/~:(%@)?%@", + [self.options[@"field_selectors"] componentsJoinedByString:@","], + [CMDQueryStringSerialization queryStringWithDictionary:parameters]]; + } + else + { + URLString = [NSString stringWithFormat: + @"https://api.linkedin.com/v1/people/~?%@", + [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 new]; + + // Provider + dictionary[@"provider"] = [[self class] type]; + + // Credentials + NSTimeInterval expiresAtInterval = [accessToken[@"expires_in"] doubleValue]; + NSDate *expiresAtDate = [NSDate dateWithTimeIntervalSinceNow:expiresAtInterval]; + dictionary[@"credentials"] = @{ + @"token" : accessToken[@"access_token"], + @"expires_at" : expiresAtDate + }; + + // User ID + //dictionary[@"uid"] = account[@"id"]; + + // Raw response + dictionary[@"raw_info"] = account; + + // User info + NSMutableDictionary *user = [NSMutableDictionary new]; + user[@"first_name"] = account[@"firstName"]; + user[@"last_name"] = account[@"lastName"]; + user[@"headline"] = account[@"headline"]; + dictionary[@"user_info"] = user; + + return dictionary; +} + +@end diff --git a/Pod/Providers/Meetup/SimpleAuthMeetupLoginViewController.h b/Pod/Providers/Meetup/SimpleAuthMeetupLoginViewController.h new file mode 100644 index 0000000..eb6d8e6 --- /dev/null +++ b/Pod/Providers/Meetup/SimpleAuthMeetupLoginViewController.h @@ -0,0 +1,13 @@ +// +// SimpleAuthMeetupLoginViewController.h +// SimpleAuth +// +// Created by Mouhcine El Amine on 17/01/14. +// Copyright (c) 2014 Byliner, Inc. All rights reserved. +// + +#import "SimpleAuthWebViewController.h" + +@interface SimpleAuthMeetupLoginViewController : SimpleAuthWebViewController + +@end diff --git a/Pod/Providers/Meetup/SimpleAuthMeetupLoginViewController.m b/Pod/Providers/Meetup/SimpleAuthMeetupLoginViewController.m new file mode 100644 index 0000000..c6f6944 --- /dev/null +++ b/Pod/Providers/Meetup/SimpleAuthMeetupLoginViewController.m @@ -0,0 +1,38 @@ +// +// SimpleAuthMeetupLoginViewController.m +// SimpleAuth +// +// Created by Mouhcine El Amine on 17/01/14. +// Copyright (c) 2014 Byliner, Inc. All rights reserved. +// + +#import "SimpleAuthMeetupLoginViewController.h" + +@implementation SimpleAuthMeetupLoginViewController + +#pragma mark - SimpleAuthWebViewController + +- (instancetype)initWithOptions:(NSDictionary *)options requestToken:(NSDictionary *)requestToken { + if ((self = [super initWithOptions:options requestToken:requestToken])) { + self.title = @"Meetup"; + } + return self; +} + + +- (NSURLRequest *)initialRequest { + NSDictionary *parameters = @{ + @"client_id" : self.options[@"client_id"], + @"redirect_uri" : self.options[SimpleAuthRedirectURIKey], + @"response_type" : @"token", + @"scope" : @"ageless" + }; + NSString *URLString = [NSString stringWithFormat: + @"https://secure.meetup.com/oauth2/authorize?%@", + [CMDQueryStringSerialization queryStringWithDictionary:parameters]]; + NSURL *URL = [NSURL URLWithString:URLString]; + + return [NSURLRequest requestWithURL:URL]; +} + +@end diff --git a/Pod/Providers/Meetup/SimpleAuthMeetupProvider.h b/Pod/Providers/Meetup/SimpleAuthMeetupProvider.h new file mode 100644 index 0000000..2fdaaef --- /dev/null +++ b/Pod/Providers/Meetup/SimpleAuthMeetupProvider.h @@ -0,0 +1,13 @@ +// +// SimpleAuthMeetupProvider.h +// SimpleAuth +// +// Created by Mouhcine El Amine on 17/01/14. +// Copyright (c) 2014 Byliner, Inc. All rights reserved. +// + +#import "SimpleAuthProvider.h" + +@interface SimpleAuthMeetupProvider : SimpleAuthProvider + +@end diff --git a/Pod/Providers/Meetup/SimpleAuthMeetupProvider.m b/Pod/Providers/Meetup/SimpleAuthMeetupProvider.m new file mode 100644 index 0000000..44afc98 --- /dev/null +++ b/Pod/Providers/Meetup/SimpleAuthMeetupProvider.m @@ -0,0 +1,118 @@ +// +// SimpleAuthMeetupProvider.m +// SimpleAuth +// +// Created by Mouhcine El Amine on 17/01/14. +// Copyright (c) 2014 Byliner, Inc. All rights reserved. +// + +#import "SimpleAuthMeetupProvider.h" +#import "SimpleAuthMeetupLoginViewController.h" + +#import "UIViewController+SimpleAuthAdditions.h" + +@implementation SimpleAuthMeetupProvider + +#pragma mark - SimpleAuthProvider + ++ (NSString *)type { + return @"meetup"; +} + ++ (NSDictionary *)defaultOptions { + + // Default present block + SimpleAuthInterfaceHandler presentBlock = ^(UIViewController *controller) { + UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:controller]; + navigationController.modalPresentationStyle = UIModalPresentationFormSheet; + UIViewController *presentedViewController = [UIViewController SimpleAuth_presentedViewController]; + [presentedViewController presentViewController:navigationController + animated:YES + completion:nil]; + }; + + // Default dismiss block + SimpleAuthInterfaceHandler dismissBlock = ^(id viewController) { + [viewController dismissViewControllerAnimated:YES + completion:nil]; + }; + + NSMutableDictionary *options = [NSMutableDictionary dictionaryWithDictionary:[super defaultOptions]]; + options[SimpleAuthPresentInterfaceBlockKey] = presentBlock; + options[SimpleAuthDismissInterfaceBlockKey] = dismissBlock; + return options; +} + +- (void)authorizeWithCompletion:(SimpleAuthRequestHandler)completion { + dispatch_async(dispatch_get_main_queue(), ^{ + SimpleAuthMeetupLoginViewController *loginViewController = [[SimpleAuthMeetupLoginViewController alloc] initWithOptions:self.options]; + loginViewController.completion = ^(UIViewController *viewController, NSURL *URL, NSError *error) { + SimpleAuthInterfaceHandler dismissBlock = self.options[SimpleAuthDismissInterfaceBlockKey]; + dismissBlock(viewController); + + NSString *fragment = [URL fragment]; + NSDictionary *dictionary = [CMDQueryStringSerialization dictionaryWithQueryString:fragment]; + NSString *token = dictionary[@"access_token"]; + if ([token length] > 0) { + NSDictionary *credentials = @{@"token": token, + @"type" : @"bearer", + @"expireDate" : [NSDate dateWithTimeIntervalSinceNow:[dictionary[@"expires_in"] doubleValue]]}; + [self userWithCredentials:credentials + completion:completion]; + } else { + completion(nil, error); + } + }; + SimpleAuthInterfaceHandler block = self.options[SimpleAuthPresentInterfaceBlockKey]; + block(loginViewController); + }); +} + +#pragma mark - Private + +- (void)userWithCredentials:(NSDictionary *)credentials completion:(SimpleAuthRequestHandler)completion { + NSDictionary *parameters = @{ @"member_id" : @"self" }; + NSString *query = [CMDQueryStringSerialization queryStringWithDictionary:parameters]; + NSString *URLString = [NSString stringWithFormat:@"https://api.meetup.com/2/members?%@", query]; + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:URLString]]; + [request setValue:[NSString stringWithFormat:@"Bearer %@", credentials[@"token"]] 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; + NSDictionary *responseDictionary = [NSJSONSerialization JSONObjectWithData:data + options:kNilOptions + error:&parseError]; + if (responseDictionary) { + NSDictionary *rawInfo = [responseDictionary[@"results"] firstObject]; + completion ([self dictionaryWithAccount:rawInfo credentials:credentials], nil); + } else { + completion(nil, parseError); + } + } else { + completion(nil, connectionError); + } + }]; +} + +- (NSDictionary *)dictionaryWithAccount:(NSDictionary *)account + credentials:(NSDictionary *)credentials +{ + NSMutableDictionary *dictionary = [NSMutableDictionary dictionary]; + dictionary[@"provider"] = [[self class] type]; + dictionary[@"credentials"] = [NSDictionary dictionaryWithDictionary:credentials]; + dictionary[@"uid"] = account[@"id"]; + dictionary[@"raw_info"] = account; + NSMutableDictionary *user = [NSMutableDictionary dictionary]; + user[@"name"] = account[@"name"]; + NSDictionary *photoDictionary = account[@"photo"]; + if (photoDictionary) { + user[@"image"] = photoDictionary[@"photo_link"]; + } + return dictionary; +} + +@end diff --git a/Pod/Providers/OneDriveWeb/SimpleAuthOneDriveWebLoginViewController.h b/Pod/Providers/OneDriveWeb/SimpleAuthOneDriveWebLoginViewController.h new file mode 100755 index 0000000..e4a00de --- /dev/null +++ b/Pod/Providers/OneDriveWeb/SimpleAuthOneDriveWebLoginViewController.h @@ -0,0 +1,13 @@ +// +// SimpleAuthOneDriveWebLoginViewController.h +// SimpleAuth +// +// Created by dkhamsing on 3/31/15. +// Copyright (c) 2015 dkhamsing. All rights reserved. +// + +#import "SimpleAuthWebViewController.h" + +@interface SimpleAuthOneDriveWebLoginViewController : SimpleAuthWebViewController + +@end diff --git a/Pod/Providers/OneDriveWeb/SimpleAuthOneDriveWebLoginViewController.m b/Pod/Providers/OneDriveWeb/SimpleAuthOneDriveWebLoginViewController.m new file mode 100755 index 0000000..1ed6aea --- /dev/null +++ b/Pod/Providers/OneDriveWeb/SimpleAuthOneDriveWebLoginViewController.m @@ -0,0 +1,45 @@ +// +// SimpleAuthOneDriveWebLoginViewController.m +// SimpleAuth +// +// Created by dkhamsing on 3/31/15. +// Copyright (c) 2015 dkhamsing. All rights reserved. +// + +#import "SimpleAuthOneDriveWebLoginViewController.h" + +@implementation SimpleAuthOneDriveWebLoginViewController + +#pragma mark - SimpleAuthWebViewController + +- (instancetype)initWithOptions:(NSDictionary *)options requestToken:(NSDictionary *)requestToken { + if ((self = [super initWithOptions:options requestToken:requestToken])) { + self.title = @"OneDrive"; + } + return self; +} + + +- (NSURLRequest *)initialRequest { + NSDictionary *parameters = @{ + @"client_id" : self.options[@"client_id"], + @"response_type" : @"code", + @"scope":self.options[@"scope"] + }; + NSString *URLString = [NSString stringWithFormat: + @"https://login.live.com/oauth20_authorize.srf?%@", + [CMDQueryStringSerialization queryStringWithDictionary:parameters]]; + + NSURL *URL = [NSURL URLWithString:URLString]; + + return [NSURLRequest requestWithURL:URL]; +} + + +- (BOOL)isTargetRedirectURL:(NSURL *)URL { + NSRange range = [URL.absoluteString rangeOfString:@"?code=" options:NSCaseInsensitiveSearch]; + return range.location != NSNotFound; +} + + +@end diff --git a/Pod/Providers/OneDriveWeb/SimpleAuthOneDriveWebProvider.h b/Pod/Providers/OneDriveWeb/SimpleAuthOneDriveWebProvider.h new file mode 100755 index 0000000..73479c6 --- /dev/null +++ b/Pod/Providers/OneDriveWeb/SimpleAuthOneDriveWebProvider.h @@ -0,0 +1,13 @@ +// +// SimpleAuthOneDriveWebProvider.h +// SimpleAuth +// +// Created by dkhamsing on 3/31/15. +// Copyright (c) 2015 dkhamsing. All rights reserved. +// + +#import "SimpleAuthProvider.h" + +@interface SimpleAuthOneDriveWebProvider : SimpleAuthProvider + +@end diff --git a/Pod/Providers/OneDriveWeb/SimpleAuthOneDriveWebProvider.m b/Pod/Providers/OneDriveWeb/SimpleAuthOneDriveWebProvider.m new file mode 100755 index 0000000..ad09a9f --- /dev/null +++ b/Pod/Providers/OneDriveWeb/SimpleAuthOneDriveWebProvider.m @@ -0,0 +1,221 @@ +// +// SimpleAuthOneDriveWebProvider.m +// SimpleAuth +// +// Created by dkhamsing on 3/31/15. +// Copyright (c) 2015 dkhamsing. All rights reserved. +// + +#import "SimpleAuthOneDriveWebProvider.h" +#import "SimpleAuthOneDriveWebLoginViewController.h" + +#import +#import "UIViewController+SimpleAuthAdditions.h" + +@implementation SimpleAuthOneDriveWebProvider + +- (instancetype)initWithOptions:(NSDictionary *)options { + NSMutableDictionary *mutableOptions = [NSMutableDictionary dictionaryWithDictionary:options]; + mutableOptions[SimpleAuthRedirectURIKey] = @""; + self = [super initWithOptions:[mutableOptions copy]]; + return self; +} + +#pragma mark - SimpleAuthProvider + ++ (NSString *)type { + return @"onedrive-web"; +} + + ++ (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; + dictionary[@"scope"] = @"wl.signin wl.offline_access onedrive.readwrite"; + 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 *)authorizationCode { + return [RACSignal createSignal:^RACDisposable *(id subscriber) { + dispatch_async(dispatch_get_main_queue(), ^{ + SimpleAuthOneDriveWebLoginViewController *login = [[SimpleAuthOneDriveWebLoginViewController 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 request + NSDictionary *parameters = @{ + @"code" : code, + @"client_id" : self.options[@"client_id"], + @"client_secret" : self.options[@"client_secret"], + @"redirect_uri": @"", + @"grant_type" : @"authorization_code" + }; + + NSString *query = [CMDQueryStringSerialization queryStringWithDictionary:parameters]; + NSURL *URL = [NSURL URLWithString:@"https://login.live.com/oauth20_token.srf"]; + 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 *)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://apis.live.net/v5.0/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 new]; + + // Provider + dictionary[@"provider"] = [[self class] type]; + + // Credentials + dictionary[@"credentials"] = @{ + @"token" : accessToken[@"access_token"], + @"type" : accessToken[@"token_type"], + @"expires_in": accessToken[@"expires_in"], + @"refresh_token": accessToken[@"refresh_token"], + @"user_id": accessToken[@"user_id"], + }; + + // User ID + dictionary[@"id"] = account[@"id"]; + + // Raw response + dictionary[@"extra"] = @{ + @"raw_info" : account + }; + + // User info + NSMutableDictionary *user = [NSMutableDictionary new]; + user[@"name"] = account[@"name"]; + dictionary[@"info"] = user; + + return dictionary; +} + +@end diff --git a/Pod/Providers/SinaWeiboWeb/SimpleAuthSinaWeiboWebLoginViewController.h b/Pod/Providers/SinaWeiboWeb/SimpleAuthSinaWeiboWebLoginViewController.h new file mode 100644 index 0000000..42b168d --- /dev/null +++ b/Pod/Providers/SinaWeiboWeb/SimpleAuthSinaWeiboWebLoginViewController.h @@ -0,0 +1,13 @@ +// +// SimpleAuthSinaWeiboWebLoginViewController.h +// SimpleAuth +// +// Created by Alexander Schuch on 17/02/14. +// Copyright (c) 2014 Byliner, Inc. All rights reserved. +// + +#import "SimpleAuthWebViewController.h" + +@interface SimpleAuthSinaWeiboWebLoginViewController : SimpleAuthWebViewController + +@end diff --git a/Pod/Providers/SinaWeiboWeb/SimpleAuthSinaWeiboWebLoginViewController.m b/Pod/Providers/SinaWeiboWeb/SimpleAuthSinaWeiboWebLoginViewController.m new file mode 100644 index 0000000..8159473 --- /dev/null +++ b/Pod/Providers/SinaWeiboWeb/SimpleAuthSinaWeiboWebLoginViewController.m @@ -0,0 +1,45 @@ +// +// SimpleAuthSinaWeiboWebLoginViewController.m +// SimpleAuth +// +// Created by Alexander Schuch on 17/02/14. +// Copyright (c) 2014 Byliner, Inc. All rights reserved. +// + +#import "SimpleAuthSinaWeiboWebLoginViewController.h" + +@interface SimpleAuthSinaWeiboWebLoginViewController () + +@end + +@implementation SimpleAuthSinaWeiboWebLoginViewController + +#pragma mark - SimpleAuthWebViewController + +- (instancetype)initWithOptions:(NSDictionary *)options requestToken:(NSDictionary *)requestToken { + if ((self = [super initWithOptions:options requestToken:requestToken])) { + self.title = @"Sina Weibo"; + } + return self; +} + + +- (NSURLRequest *)initialRequest { + NSString *language = [[NSLocale preferredLanguages] objectAtIndex:0]; + + NSDictionary *parameters = @{ + @"client_id" : self.options[@"client_id"], + @"redirect_uri" : self.options[SimpleAuthRedirectURIKey], + @"state" : [[NSProcessInfo processInfo] globallyUniqueString], + @"display": @"mobile", + @"language": language + }; + + NSString *parameterString = [CMDQueryStringSerialization queryStringWithDictionary:parameters]; + NSString *URLString = [NSString stringWithFormat:@"https://api.weibo.com/oauth2/authorize?%@", parameterString]; + NSURL *URL = [NSURL URLWithString:URLString]; + + return [NSURLRequest requestWithURL:URL]; +} + +@end diff --git a/Pod/Providers/SinaWeiboWeb/SimpleAuthSinaWeiboWebProvider.h b/Pod/Providers/SinaWeiboWeb/SimpleAuthSinaWeiboWebProvider.h new file mode 100644 index 0000000..b01bf08 --- /dev/null +++ b/Pod/Providers/SinaWeiboWeb/SimpleAuthSinaWeiboWebProvider.h @@ -0,0 +1,13 @@ +// +// SimpleAuthSinaWeiboWebProvider.h +// SimpleAuth +// +// Created by Alexander Schuch on 17/02/14. +// Copyright (c) 2014 Byliner, Inc. All rights reserved. +// + +#import "SimpleAuthProvider.h" + +@interface SimpleAuthSinaWeiboWebProvider : SimpleAuthProvider + +@end diff --git a/Pod/Providers/SinaWeiboWeb/SimpleAuthSinaWeiboWebProvider.m b/Pod/Providers/SinaWeiboWeb/SimpleAuthSinaWeiboWebProvider.m new file mode 100644 index 0000000..fe9f963 --- /dev/null +++ b/Pod/Providers/SinaWeiboWeb/SimpleAuthSinaWeiboWebProvider.m @@ -0,0 +1,215 @@ +// +// SimpleAuthSinaWeiboWebProvider.m +// SimpleAuth +// +// Created by Alexander Schuch on 17/02/14. +// Copyright (c) 2014 Byliner, Inc. All rights reserved. +// + +#import "SimpleAuthSinaWeiboWebProvider.h" +#import "SimpleAuthSinaWeiboWebLoginViewController.h" + +#import +#import "UIViewController+SimpleAuthAdditions.h" + +@implementation SimpleAuthSinaWeiboWebProvider + +#pragma mark - SimpleAuthProvider + ++ (NSString *)type { + return @"sinaweibo-web"; +} + ++ (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(), ^{ + SimpleAuthSinaWeiboWebLoginViewController *login = [[SimpleAuthSinaWeiboWebLoginViewController 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 request + 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" + }; + NSString *query = [CMDQueryStringSerialization queryStringWithDictionary:parameters]; + NSURL *URL = [NSURL URLWithString:@"https://api.weibo.com/oauth2/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"], + @"uid": accessToken[@"uid"] + }; + NSString *URLString = [NSString stringWithFormat:@"https://api.weibo.com/2/users/show.json?%@", + [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 + NSTimeInterval expiresAtInterval = [accessToken[@"expires_in"] doubleValue]; + NSDate *expiresAtDate = [NSDate dateWithTimeIntervalSinceNow:expiresAtInterval]; + dictionary[@"credentials"] = @{ + @"token" : accessToken[@"access_token"], + @"expires_at" : expiresAtDate + }; + + // User ID + dictionary[@"uid"] = account[@"id"]; + + // Raw response + dictionary[@"raw_info"] = account; + + // User info + NSMutableDictionary *user = [NSMutableDictionary new]; + user[@"screen_name"] = account[@"screen_name"]; + user[@"name"] = account[@"name"]; + user[@"location"] = account[@"location"]; + user[@"description"] = account[@"description"]; + user[@"gender"] = account[@"gender"]; + user[@"image"] = account[@"avatar_large"]; + dictionary[@"user_info"] = user; + + return dictionary; +} + +@end diff --git a/Pod/Providers/Strava/SimpleAuthStravaWebLoginViewController.h b/Pod/Providers/Strava/SimpleAuthStravaWebLoginViewController.h new file mode 100644 index 0000000..457b563 --- /dev/null +++ b/Pod/Providers/Strava/SimpleAuthStravaWebLoginViewController.h @@ -0,0 +1,13 @@ +// +// SimpleAuthStravaWebLoginViewController.h +// SimpleAuth +// +// Created by Ben Stahl on 7/27/14. +// Copyright (c) 2014 Byliner, Inc. All rights reserved. +// + +#import "SimpleAuthWebViewController.h" + +@interface SimpleAuthStravaWebLoginViewController : SimpleAuthWebViewController + +@end diff --git a/Pod/Providers/Strava/SimpleAuthStravaWebLoginViewController.m b/Pod/Providers/Strava/SimpleAuthStravaWebLoginViewController.m new file mode 100644 index 0000000..f02ed12 --- /dev/null +++ b/Pod/Providers/Strava/SimpleAuthStravaWebLoginViewController.m @@ -0,0 +1,40 @@ +// +// SimpleAuthStravaWebLoginViewController.m +// SimpleAuth +// +// Created by Ben Stahl on 7/27/14. +// Copyright (c) 2014 Byliner, Inc. All rights reserved. +// + +#import "SimpleAuthStravaWebLoginViewController.h" + +@implementation SimpleAuthStravaWebLoginViewController + + +#pragma mark - SimpleAuthWebViewController + +- (instancetype)initWithOptions:(NSDictionary *)options requestToken:(NSDictionary *)requestToken { + if ((self = [super initWithOptions:options requestToken:requestToken])) { + self.title = @"Strava"; + } + 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"; + if (self.options[@"scope"]) { + parameters[@"scope"] = [self.options[@"scope"] componentsJoinedByString:@" "]; + } + NSString *URLString = [NSString stringWithFormat: + @"https://www.strava.com/oauth/authorize?%@", + [CMDQueryStringSerialization queryStringWithDictionary:parameters]]; + NSURL *URL = [NSURL URLWithString:URLString]; + + return [NSURLRequest requestWithURL:URL]; +} + +@end diff --git a/Pod/Providers/Strava/SimpleAuthStravaWebProvider.h b/Pod/Providers/Strava/SimpleAuthStravaWebProvider.h new file mode 100644 index 0000000..5eb70bb --- /dev/null +++ b/Pod/Providers/Strava/SimpleAuthStravaWebProvider.h @@ -0,0 +1,13 @@ +// +// SimpleAuthStravaWebProvider.h +// SimpleAuth +// +// Created by Ben Stahl on 7/27/14. +// Copyright (c) 2014 Byliner, Inc. All rights reserved. +// + +#import "SimpleAuthProvider.h" + +@interface SimpleAuthStravaWebProvider : SimpleAuthProvider + +@end diff --git a/Pod/Providers/Strava/SimpleAuthStravaWebProvider.m b/Pod/Providers/Strava/SimpleAuthStravaWebProvider.m new file mode 100644 index 0000000..0026c06 --- /dev/null +++ b/Pod/Providers/Strava/SimpleAuthStravaWebProvider.m @@ -0,0 +1,212 @@ +// +// SimpleAuthStravaWebProvider.m +// SimpleAuth +// +// Created by Ben Stahl on 7/27/14. +// Copyright (c) 2014 Byliner, Inc. All rights reserved. +// + +#import "SimpleAuthStravaWebProvider.h" +#import "SimpleAuthStravaWebLoginViewController.h" + +#import +#import "UIViewController+SimpleAuthAdditions.h" + +@implementation SimpleAuthStravaWebProvider + +#pragma mark - SimpleAuthProvider + ++ (NSString *)type { + return @"strava-web"; +} + ++ (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(), ^{ + SimpleAuthStravaWebLoginViewController *login = [[SimpleAuthStravaWebLoginViewController 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 request + NSDictionary *parameters = @{ + @"code" : code, + @"client_id" : self.options[@"client_id"], + @"client_secret" : self.options[@"client_secret"], + @"redirect_uri" : self.options[SimpleAuthRedirectURIKey], + }; + NSString *query = [CMDQueryStringSerialization queryStringWithDictionary:parameters]; + NSURL *URL = [NSURL URLWithString:@"https://www.strava.com/oauth/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://www.strava.com/api/v3/athlete?%@", + [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[@"raw_info"] = account; + + // User info + NSMutableDictionary *user = [NSMutableDictionary new]; + user[@"email"] = account[@"email"]; + if (user[@"firstName"]) { + user[@"first_name"] = user[@"firstname"]; + } + if (user[@"lastName"]) { + user[@"last_name"] = user[@"lastname"]; + } + user[@"gender"] = account[@"sex"]; + user[@"image"] = account[@"profile"]; + user[@"location"] = account[@"city"]; + dictionary[@"info"] = user; + + return dictionary; +} + + +@end diff --git a/Pod/Providers/Trello/SimpleAuthTrelloLoginViewController.h b/Pod/Providers/Trello/SimpleAuthTrelloLoginViewController.h new file mode 100755 index 0000000..7ddfe8d --- /dev/null +++ b/Pod/Providers/Trello/SimpleAuthTrelloLoginViewController.h @@ -0,0 +1,13 @@ +// +// SimpleAuthTrelloLoginViewController.h +// SimpleAuth +// +// Created by Damiano Buscemi on 22/08/14. +// Copyright (c) 2014 Crispy Bacon, S.r.l. All rights reserved. +// + +#import "SimpleAuthWebViewController.h" + +@interface SimpleAuthTrelloLoginViewController : SimpleAuthWebViewController + +@end diff --git a/Pod/Providers/Trello/SimpleAuthTrelloLoginViewController.m b/Pod/Providers/Trello/SimpleAuthTrelloLoginViewController.m new file mode 100755 index 0000000..7c9a35a --- /dev/null +++ b/Pod/Providers/Trello/SimpleAuthTrelloLoginViewController.m @@ -0,0 +1,46 @@ +// +// SimpleAuthTrelloLoginViewController.m +// SimpleAuth +// +// Created by Damiano Buscemi on 22/08/14. +// Copyright (c) 2014 Crispy Bacon, S.r.l. All rights reserved. +// + +#import "SimpleAuthTrelloLoginViewController.h" + +@interface SimpleAuthTrelloLoginViewController () + +@end + +@implementation SimpleAuthTrelloLoginViewController + +#pragma mark - SimpleAuthWebViewController + +- (instancetype)initWithOptions:(NSDictionary *)options requestToken:(NSDictionary *)requestToken { + if ((self = [super initWithOptions:options requestToken:requestToken])) { + self.title = @"Trello"; + } + return self; +} + + +- (NSURLRequest *)initialRequest { + NSMutableDictionary *parameters = [NSMutableDictionary new]; + parameters[@"key"] = self.options[@"key"]; + parameters[@"response_type"] = @"token"; + parameters[@"expiration"] = @"30days"; + parameters[@"callback_method"] = @"fragment"; + parameters[@"return_url"] = self.options[SimpleAuthRedirectURIKey]; + parameters[@"name"] = self.options[@"name"]; + if (self.options[@"scope"]) { + parameters[@"scope"] = [self.options[@"scope"] componentsJoinedByString:@" "]; + } + NSString *URLString = [NSString stringWithFormat: + @"https://trello.com/1/authorize/?%@", + [CMDQueryStringSerialization queryStringWithDictionary:parameters]]; + NSURL *URL = [NSURL URLWithString:URLString]; + + return [NSURLRequest requestWithURL:URL]; +} + +@end diff --git a/Pod/Providers/Trello/SimpleAuthTrelloProvider.h b/Pod/Providers/Trello/SimpleAuthTrelloProvider.h new file mode 100755 index 0000000..9839f14 --- /dev/null +++ b/Pod/Providers/Trello/SimpleAuthTrelloProvider.h @@ -0,0 +1,13 @@ +// +// SimpleAuthTrelloProvider.h +// SimpleAuth +// +// Created by Damiano Buscemi on 22/08/14. +// Copyright (c) 2014 Crispy Bacon, S.r.l. All rights reserved. +// + +#import "SimpleAuthProvider.h" + +@interface SimpleAuthTrelloProvider : SimpleAuthProvider + +@end diff --git a/Pod/Providers/Trello/SimpleAuthTrelloProvider.m b/Pod/Providers/Trello/SimpleAuthTrelloProvider.m new file mode 100755 index 0000000..ab896da --- /dev/null +++ b/Pod/Providers/Trello/SimpleAuthTrelloProvider.m @@ -0,0 +1,161 @@ +// +// SimpleAuthTrelloProvider.m +// SimpleAuth +// +// Created by Damiano Buscemi on 22/08/14. +// Copyright (c) 2014 Crispy Bacon, S.r.l. All rights reserved. +// + +#import "SimpleAuthTrelloProvider.h" +#import "SimpleAuthTrelloLoginViewController.h" + +#import +#import "UIViewController+SimpleAuthAdditions.h" + +@implementation SimpleAuthTrelloProvider + +#pragma mark - SimpleAuthProvider + ++ (NSString *)type { + return @"trello-web"; +} + ++ (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] = @"simple-auth://trello-web.auth"; + return options; +} + + +- (void)authorizeWithCompletion:(SimpleAuthRequestHandler)completion { + [[[self accessToken] + flattenMap:^RACStream *(NSString *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 [RACSignal createSignal:^RACDisposable *(id subscriber) { + dispatch_async(dispatch_get_main_queue(), ^{ + SimpleAuthTrelloLoginViewController *login = [[SimpleAuthTrelloLoginViewController alloc] initWithOptions:self.options]; + login.completion = ^(UIViewController *login, NSURL *URL, NSError *error) { + SimpleAuthInterfaceHandler dismissBlock = self.options[SimpleAuthDismissInterfaceBlockKey]; + dismissBlock(login); + + // Parse URL + NSString *fragment = [URL fragment]; + NSDictionary *dictionary = [CMDQueryStringSerialization dictionaryWithQueryString:fragment]; + NSString *token = dictionary[@"token"]; + + // Check for error + if (![token length]) { + [subscriber sendError:error]; + return; + } + + // Send completion + [subscriber sendNext:token]; + [subscriber sendCompleted]; + }; + + SimpleAuthInterfaceHandler block = self.options[SimpleAuthPresentInterfaceBlockKey]; + block(login); + }); + return nil; + }]; +} + + +- (RACSignal *)accountWithAccessToken:(NSString *)accessToken { + return [RACSignal createSignal:^RACDisposable *(id subscriber) { + NSDictionary *parameters = @{ @"token" : accessToken , @"key" : self.options[@"key"] }; + NSString *query = [CMDQueryStringSerialization queryStringWithDictionary:parameters]; + NSString *URLString = [NSString stringWithFormat:@"https://trello.com/1/members/me?%@", query]; + 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; + }]; +} + + +#pragma mark - Private + +- (NSDictionary *)dictionaryWithAccount:(NSDictionary *)account accessToken:(NSString *)accessToken { + NSMutableDictionary *dictionary = [NSMutableDictionary new]; + NSDictionary *data = account; + + // Provider + dictionary[@"provider"] = [[self class] type]; + + // Credentials + dictionary[@"credentials"] = @{ + @"token" : accessToken + }; + + // User ID + dictionary[@"uid"] = data[@"id"]; + + // Extra + dictionary[@"extra"] = @{ + @"raw_info" : account + }; + + // User info + NSMutableDictionary *user = [NSMutableDictionary new]; + user[@"name"] = data[@"fullName"]; + user[@"username"] = data[@"username"]; + user[@"avatarHash"] = data[@"avatarHash"]; + dictionary[@"user_info"] = user; + + return dictionary; +} + +@end diff --git a/Pod/Providers/TripIt/SimpleAuthTripItLoginViewController.h b/Pod/Providers/TripIt/SimpleAuthTripItLoginViewController.h new file mode 100755 index 0000000..87ca24b --- /dev/null +++ b/Pod/Providers/TripIt/SimpleAuthTripItLoginViewController.h @@ -0,0 +1,13 @@ +// +// SimpleAuthTripItLoginViewController.h +// SimpleAuth +// +// Created by Mark Krenek on 8/15/14. +// Copyright (c) 2014 Mark Krenek. All rights reserved. +// + +#import "SimpleAuthWebViewController.h" + +@interface SimpleAuthTripItLoginViewController : SimpleAuthWebViewController + +@end diff --git a/Pod/Providers/TripIt/SimpleAuthTripItLoginViewController.m b/Pod/Providers/TripIt/SimpleAuthTripItLoginViewController.m new file mode 100755 index 0000000..fe9772f --- /dev/null +++ b/Pod/Providers/TripIt/SimpleAuthTripItLoginViewController.m @@ -0,0 +1,36 @@ +// +// SimpleAuthTripItLoginViewController.m +// SimpleAuth +// +// Created by Mark Krenek on 8/15/14. +// Copyright (c) 2014 Mark Krenek. All rights reserved. +// + +#import "SimpleAuthTripItLoginViewController.h" + +@implementation SimpleAuthTripItLoginViewController + +#pragma mark - SimpleAuthWebViewController + +- (instancetype)initWithOptions:(NSDictionary *)options requestToken:(NSDictionary *)requestToken { + if ((self = [super initWithOptions:options requestToken:requestToken])) { + self.title = @"TripIt"; + } + return self; +} + + +- (NSURLRequest *)initialRequest { + NSDictionary *parameters = @{ + @"oauth_token" : self.requestToken[@"oauth_token"], + @"oauth_callback" : self.options[SimpleAuthRedirectURIKey], + }; + NSString *URLString = [NSString stringWithFormat: + @"https://m.tripit.com/oauth/authorize?%@", + [CMDQueryStringSerialization queryStringWithDictionary:parameters]]; + NSURL *URL = [NSURL URLWithString:URLString]; + + return [NSURLRequest requestWithURL:URL]; +} + +@end diff --git a/Pod/Providers/TripIt/SimpleAuthTripItProvider.h b/Pod/Providers/TripIt/SimpleAuthTripItProvider.h new file mode 100755 index 0000000..699ce5a --- /dev/null +++ b/Pod/Providers/TripIt/SimpleAuthTripItProvider.h @@ -0,0 +1,13 @@ +// +// SimpleAuthTripItProvider.h +// SimpleAuth +// +// Created by Mark Krenek on 8/15/14. +// Copyright (c) 2014 Mark Krenek. All rights reserved. +// + +#import "SimpleAuthProvider.h" + +@interface SimpleAuthTripItProvider : SimpleAuthProvider + +@end diff --git a/Pod/Providers/TripIt/SimpleAuthTripItProvider.m b/Pod/Providers/TripIt/SimpleAuthTripItProvider.m new file mode 100755 index 0000000..b1650e8 --- /dev/null +++ b/Pod/Providers/TripIt/SimpleAuthTripItProvider.m @@ -0,0 +1,273 @@ +// +// SimpleAuthTripItProvider.m +// SimpleAuth +// +// Created by Mark Krenek on 8/15/14. +// Copyright (c) 2014 Mark Krenek. All rights reserved. +// + +#import "SimpleAuthTripItProvider.h" +#import "SimpleAuthTripItLoginViewController.h" + +#import "UIViewController+SimpleAuthAdditions.h" +#import +#import + +@implementation SimpleAuthTripItProvider + +#pragma mark - SimpleAuthProvider + ++ (NSString *)type { + return @"tripit"; +} + + ++ (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; + dictionary[SimpleAuthRedirectURIKey] = @"simple-auth://tripit.auth"; + return dictionary; +} + + +- (void)authorizeWithCompletion:(SimpleAuthRequestHandler)completion { + [[[[[self requestToken] + flattenMap:^(NSDictionary *response) { + NSArray *signals = @[ + [RACSignal return:response], + [self authenticateWithRequestToken:response] + ]; + return [RACSignal zip:signals]; + }] + flattenMap:^(RACTuple *response) { + return [self accessTokenWithRequestToken:response.first authenticationResponse:response.second]; + }] + 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 *)requestToken { + return [RACSignal createSignal:^RACDisposable *(id subscriber) { + NSDictionary *parameters = @{ @"oauth_callback" : self.options[SimpleAuthRedirectURIKey] }; + NSURLRequest *request = [GCOAuth + URLRequestForPath:@"/oauth/request_token" + POSTParameters:parameters + scheme:@"https" + host:@"api.tripit.com" + consumerKey:self.options[@"consumer_key"] + consumerSecret:self.options[@"consumer_secret"] + accessToken:nil + tokenSecret:nil]; + [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) { + NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + NSDictionary *dictionary = [CMDQueryStringSerialization dictionaryWithQueryString:string]; + [subscriber sendNext:dictionary]; + [subscriber sendCompleted]; + } + else { + [subscriber sendError:connectionError]; + } + }]; + return nil; + }]; +} + + +- (RACSignal *)authenticateWithRequestToken:(NSDictionary *)requestToken { + return [RACSignal createSignal:^RACDisposable *(id subscriber) { + dispatch_async(dispatch_get_main_queue(), ^{ + SimpleAuthTripItLoginViewController *login = [[SimpleAuthTripItLoginViewController alloc] initWithOptions:self.options requestToken:requestToken]; + + login.completion = ^(UIViewController *controller, NSURL *URL, NSError *error) { + SimpleAuthInterfaceHandler block = self.options[SimpleAuthDismissInterfaceBlockKey]; + block(controller); + + // Parse URL + NSString *query = [URL query]; + NSDictionary *dictionary = [CMDQueryStringSerialization dictionaryWithQueryString:query]; + NSString *token = dictionary[@"oauth_token"]; + + // Check for error + if (![token length]) { + [subscriber sendError:error]; + return; + } + + // Send completion + [subscriber sendNext:dictionary]; + [subscriber sendCompleted]; + }; + + SimpleAuthInterfaceHandler block = self.options[SimpleAuthPresentInterfaceBlockKey]; + block(login); + }); + return nil; + }]; +} + + +- (RACSignal *)accessTokenWithRequestToken:(NSDictionary *)requestToken authenticationResponse:(NSDictionary *)authenticationResponse { + return [RACSignal createSignal:^RACDisposable *(id subscriber) { + NSDictionary *parameters = @{ }; + NSURLRequest *request = [GCOAuth + URLRequestForPath:@"/oauth/access_token" + POSTParameters:parameters + scheme:@"https" + host:@"api.tripit.com" + consumerKey:self.options[@"consumer_key"] + consumerSecret:self.options[@"consumer_secret"] + accessToken:authenticationResponse[@"oauth_token"] + tokenSecret:requestToken[@"oauth_token_secret"]]; + [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) { + NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + NSDictionary *dictionary = [CMDQueryStringSerialization dictionaryWithQueryString:string]; + [subscriber sendNext:dictionary]; + [subscriber sendCompleted]; + } + else { + [subscriber sendError:connectionError]; + } + }]; + return nil; + }]; +} + + +- (RACSignal *)accountWithAccessToken:(NSDictionary *)accessToken { + return [RACSignal createSignal:^RACDisposable *(id subscriber) { + NSDictionary* parameters = @{ @"format" : @"json" }; + NSURLRequest *request = [GCOAuth + URLRequestForPath:@"/v1/get/profile" + GETParameters:parameters + scheme:@"https" + host:@"api.tripit.com" + consumerKey:self.options[@"consumer_key"] + consumerSecret:self.options[@"consumer_secret"] + accessToken:accessToken[@"oauth_token"] + tokenSecret:accessToken[@"oauth_token_secret"]]; + [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]; + + // { + // "timestamp": "1408218794", + // "num_bytes": "6329", + // "Profile": { + // "@attributes": { + // "ref": "ABCDEFGHIJKL" + // }, + // "ProfileEmailAddresses": { + // "ProfileEmailAddress": { + // "address": "johndoe@example.com", + // "is_auto_import": "false", + // "is_confirmed": "true", + // "is_primary": "true", + // "is_auto_inbox_eligible": "false" + // } + // }, + // "NotificationSettings": {}, + // "is_client": "true", + // "is_pro": "false", + // "screen_name": "johndoe", + // "public_display_name": "John Joe", + // "profile_url": "people/johdoe", + // "alerts_feed_url": "https://www.tripit.com/feed/alerts/private/ABCDEFG/alerts.atom", + // "ical_url": "webcal://www.tripit.com/feed/ical/private/ABCDEFG/tripit.ics" + // } + // } + + // Provider + dictionary[@"provider"] = [[self class] type]; + + // Credentials + dictionary[@"credentials"] = @{ + @"token" : accessToken[@"oauth_token"], + @"secret" : accessToken[@"oauth_token_secret"] + }; + + // User ID + [dictionary setValue:account[@"Profile"][@"@attributes"][@"ref"] // Yes, attributes is prefixed with an @ + forKey:@"uid"]; + + // Extra + dictionary[@"extra"] = @{ + @"raw_info" : account, + }; + + // User info + NSMutableDictionary *user = [NSMutableDictionary new]; + [user setValue:[account valueForKeyPath:@"Profile.screen_name"] + forKey:@"nickname"]; + + [user setValue:[account valueForKeyPath:@"Profile.public_display_name"] + forKey:@"name"]; + + [user setValue:[account valueForKeyPath:@"Profile.ProfileEmailAddresses.ProfileEmailAddress.address"] + forKey:@"email"]; + + dictionary[@"info"] = user; + + return dictionary; +} + +@end diff --git a/Pod/Providers/Tumblr/SimpleAuthTumblrLoginViewController.h b/Pod/Providers/Tumblr/SimpleAuthTumblrLoginViewController.h new file mode 100644 index 0000000..ea404ee --- /dev/null +++ b/Pod/Providers/Tumblr/SimpleAuthTumblrLoginViewController.h @@ -0,0 +1,13 @@ +// +// SimpleAuthTumblrLoginViewController.h +// SimpleAuth +// +// Created by Caleb Davenport on 1/16/14. +// Copyright (c) 2014 Byliner, Inc. All rights reserved. +// + +#import "SimpleAuthWebViewController.h" + +@interface SimpleAuthTumblrLoginViewController : SimpleAuthWebViewController + +@end diff --git a/Pod/Providers/Tumblr/SimpleAuthTumblrLoginViewController.m b/Pod/Providers/Tumblr/SimpleAuthTumblrLoginViewController.m new file mode 100644 index 0000000..74e5fc9 --- /dev/null +++ b/Pod/Providers/Tumblr/SimpleAuthTumblrLoginViewController.m @@ -0,0 +1,35 @@ +// +// SimpleAuthTumblrLoginViewController.m +// SimpleAuth +// +// Created by Caleb Davenport on 1/16/14. +// Copyright (c) 2014 Byliner, Inc. All rights reserved. +// + +#import "SimpleAuthTumblrLoginViewController.h" + +@implementation SimpleAuthTumblrLoginViewController + +#pragma mark - SimpleAuthWebViewController + +- (instancetype)initWithOptions:(NSDictionary *)options requestToken:(NSDictionary *)requestToken { + if ((self = [super initWithOptions:options requestToken:requestToken])) { + self.title = @"tumblr"; + } + return self; +} + + +- (NSURLRequest *)initialRequest { + NSDictionary *parameters = @{ + @"oauth_token" : self.requestToken[@"oauth_token"], + }; + NSString *URLString = [NSString stringWithFormat: + @"http://www.tumblr.com/oauth/authorize?%@", + [CMDQueryStringSerialization queryStringWithDictionary:parameters]]; + NSURL *URL = [NSURL URLWithString:URLString]; + + return [NSURLRequest requestWithURL:URL]; +} + +@end diff --git a/Pod/Providers/Tumblr/SimpleAuthTumblrProvider.h b/Pod/Providers/Tumblr/SimpleAuthTumblrProvider.h new file mode 100644 index 0000000..5c57e00 --- /dev/null +++ b/Pod/Providers/Tumblr/SimpleAuthTumblrProvider.h @@ -0,0 +1,13 @@ +// +// SimpleAuthTumblrProvider.h +// SimpleAuth +// +// Created by Caleb Davenport on 1/16/14. +// Copyright (c) 2014 Byliner, Inc. All rights reserved. +// + +#import "SimpleAuthProvider.h" + +@interface SimpleAuthTumblrProvider : SimpleAuthProvider + +@end diff --git a/Pod/Providers/Tumblr/SimpleAuthTumblrProvider.m b/Pod/Providers/Tumblr/SimpleAuthTumblrProvider.m new file mode 100644 index 0000000..fee76f2 --- /dev/null +++ b/Pod/Providers/Tumblr/SimpleAuthTumblrProvider.m @@ -0,0 +1,255 @@ +// +// SimpleAuthTumblrProvider.m +// SimpleAuth +// +// Created by Caleb Davenport on 1/16/14. +// Copyright (c) 2014 Byliner, Inc. All rights reserved. +// + +#import "SimpleAuthTumblrProvider.h" +#import "SimpleAuthTumblrLoginViewController.h" + +#import "UIViewController+SimpleAuthAdditions.h" +#import +#import + +@implementation SimpleAuthTumblrProvider + +#pragma mark - SimpleAuthProvider + ++ (NSString *)type { + return @"tumblr"; +} + + ++ (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; + dictionary[SimpleAuthRedirectURIKey] = @"simple-auth://tumblr.auth"; + return dictionary; +} + + +- (void)authorizeWithCompletion:(SimpleAuthRequestHandler)completion { + [[[[[self requestToken] + flattenMap:^(NSDictionary *response) { + NSArray *signals = @[ + [RACSignal return:response], + [self authenticateWithRequestToken:response] + ]; + return [RACSignal zip:signals]; + }] + flattenMap:^(RACTuple *response) { + return [self accessTokenWithRequestToken:response.first authenticationResponse:response.second]; + }] + 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 *)requestToken { + return [RACSignal createSignal:^RACDisposable *(id subscriber) { + NSDictionary *parameters = @{ @"oauth_callback" : self.options[SimpleAuthRedirectURIKey] }; + NSURLRequest *request = [GCOAuth + URLRequestForPath:@"/oauth/request_token" + POSTParameters:parameters + scheme:@"https" + host:@"www.tumblr.com" + consumerKey:self.options[@"consumer_key"] + consumerSecret:self.options[@"consumer_secret"] + accessToken:nil + tokenSecret:nil]; + [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) { + NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + NSDictionary *dictionary = [CMDQueryStringSerialization dictionaryWithQueryString:string]; + [subscriber sendNext:dictionary]; + [subscriber sendCompleted]; + } + else { + [subscriber sendError:connectionError]; + } + }]; + return nil; + }]; +} + + +- (RACSignal *)authenticateWithRequestToken:(NSDictionary *)requestToken { + return [RACSignal createSignal:^RACDisposable *(id subscriber) { + dispatch_async(dispatch_get_main_queue(), ^{ + SimpleAuthTumblrLoginViewController *login = [[SimpleAuthTumblrLoginViewController alloc] initWithOptions:self.options requestToken:requestToken]; + + login.completion = ^(UIViewController *controller, NSURL *URL, NSError *error) { + SimpleAuthInterfaceHandler block = self.options[SimpleAuthDismissInterfaceBlockKey]; + block(controller); + + // Parse URL + NSString *query = [URL query]; + NSDictionary *dictionary = [CMDQueryStringSerialization dictionaryWithQueryString:query]; + NSString *token = dictionary[@"oauth_token"]; + NSString *verifier = dictionary[@"oauth_verifier"]; + + // Check for error + if (![token length] || ![verifier length]) { + [subscriber sendError:error]; + return; + } + + // Send completion + [subscriber sendNext:dictionary]; + [subscriber sendCompleted]; + }; + + SimpleAuthInterfaceHandler block = self.options[SimpleAuthPresentInterfaceBlockKey]; + block(login); + }); + return nil; + }]; +} + + +- (RACSignal *)accessTokenWithRequestToken:(NSDictionary *)requestToken authenticationResponse:(NSDictionary *)authenticationResponse { + return [RACSignal createSignal:^RACDisposable *(id subscriber) { + NSDictionary *parameters = @{ @"oauth_verifier" : authenticationResponse[@"oauth_verifier"] }; + NSURLRequest *request = [GCOAuth + URLRequestForPath:@"/oauth/access_token" + POSTParameters:parameters + scheme:@"https" + host:@"www.tumblr.com" + consumerKey:self.options[@"consumer_key"] + consumerSecret:self.options[@"consumer_secret"] + accessToken:authenticationResponse[@"oauth_token"] + tokenSecret:requestToken[@"oauth_token_secret"]]; + [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) { + NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + NSDictionary *dictionary = [CMDQueryStringSerialization dictionaryWithQueryString:string]; + [subscriber sendNext:dictionary]; + [subscriber sendCompleted]; + } + else { + [subscriber sendError:connectionError]; + } + }]; + return nil; + }]; +} + + +- (RACSignal *)accountWithAccessToken:(NSDictionary *)accessToken { + return [RACSignal createSignal:^RACDisposable *(id subscriber) { + NSURLRequest *request = [GCOAuth + URLRequestForPath:@"/v2/user/info" + GETParameters:nil + scheme:@"https" + host:@"api.tumblr.com" + consumerKey:self.options[@"consumer_key"] + consumerSecret:self.options[@"consumer_secret"] + accessToken:accessToken[@"oauth_token"] + tokenSecret:accessToken[@"oauth_token_secret"]]; + [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) { + dictionary = dictionary[@"response"][@"user"]; + [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[@"oauth_token"], + @"secret" : accessToken[@"oauth_token_secret"] + }; + + // User ID + dictionary[@"uid"] = account[@"name"]; + + // Extra + dictionary[@"extra"] = @{ + @"raw_info" : account, + }; + + // Blogs + NSArray *blogs = account[@"blogs"]; + blogs = [[blogs.rac_sequence map:^(NSDictionary *dictionary) { + return [dictionary dictionaryWithValuesForKeys:@[ @"name", @"url", @"title" ]]; + }] array]; + + // Profile image + NSString *blogURLString = blogs[0][@"url"]; + NSURL *blogURL = [NSURL URLWithString:blogURLString]; + NSString *host = [blogURL host]; + NSString *avatar = [NSString stringWithFormat:@"https://api.tumblr.com/v2/blog/%@/avatar", host]; + + // User info + NSMutableDictionary *user = [NSMutableDictionary new]; + user[@"nickname"] = account[@"name"]; + user[@"name"] = account[@"name"]; + user[@"blogs"] = blogs; + user[@"image"] = avatar; + dictionary[@"info"] = user; + + return dictionary; +} + +@end diff --git a/Pod/Providers/Twitter/SimpleAuthTwitterProvider.h b/Pod/Providers/Twitter/SimpleAuthTwitterProvider.h new file mode 100644 index 0000000..ba74888 --- /dev/null +++ b/Pod/Providers/Twitter/SimpleAuthTwitterProvider.h @@ -0,0 +1,13 @@ +// +// SimpleAuthTwitterProvider.h +// SimpleAuth +// +// Created by Caleb Davenport on 11/6/13. +// Copyright (c) 2013-2014 Byliner, Inc. All rights reserved. +// + +#import "SimpleAuthProvider.h" + +@interface SimpleAuthTwitterProvider : SimpleAuthProvider + +@end diff --git a/Pod/Providers/Twitter/SimpleAuthTwitterProvider.m b/Pod/Providers/Twitter/SimpleAuthTwitterProvider.m new file mode 100644 index 0000000..e640480 --- /dev/null +++ b/Pod/Providers/Twitter/SimpleAuthTwitterProvider.m @@ -0,0 +1,274 @@ +// +// SimpleAuthTwitterProvider.m +// SimpleAuth +// +// Created by Caleb Davenport on 11/6/13. +// Copyright (c) 2013-2014 Byliner, Inc. All rights reserved. +// + +#import "SimpleAuthTwitterProvider.h" + +#import "UIWindow+SimpleAuthAdditions.h" +#import "ACAccountStore+SimpleAuth.h" +#import "SimpleAuthUtilities.h" +#import +#import + +@import Social; + +@implementation SimpleAuthTwitterProvider + +#pragma mark - SimpleAuthProvider + ++ (NSString *)type { + return @"twitter"; +} + + ++ (NSDictionary *)defaultOptions { + void (^actionSheetBlock) (UIActionSheet *) = ^(UIActionSheet *sheet) { + UIWindow *window = [UIWindow SimpleAuth_mainWindow]; + [sheet showInView:window]; + }; + + NSMutableDictionary *options = [NSMutableDictionary dictionaryWithDictionary:[super defaultOptions]]; + options[SimpleAuthPresentInterfaceBlockKey] = actionSheetBlock; + + return options; +} + + +- (void)authorizeWithCompletion:(SimpleAuthRequestHandler)completion { + [[[self systemAccount] + flattenMap:^(ACAccount *account) { + NSArray *signals = @[ + [RACSignal return:account], + [self remoteAccountWithSystemAccount:account], + [self accessTokenWithSystemAccount:account] + ]; + return [self rac_liftSelector:@selector(dictionaryWithSystemAccount:remoteAccount:accessToken:) withSignalsFromArray:signals]; + }] + subscribeNext:^(NSDictionary *response) { + completion(response, nil); + } + error:^(NSError *error) { + completion(nil, error); + }]; +} + + +#pragma mark - Private + +- (RACSignal *)allSystemAccounts { + return [ACAccountStore SimpleAuth_accountsWithTypeIdentifier:ACAccountTypeIdentifierTwitter options:nil]; +} + + +- (RACSignal *)systemAccount { + return [[self allSystemAccounts] flattenMap:^RACStream *(NSArray *accounts) { + if ([accounts count] == 1) { + ACAccount *account = [accounts lastObject]; + return [RACSignal return:account]; + } + else { + return [self systemAccountFromAccounts:accounts]; + } + }]; +} + + +- (RACSignal *)systemAccountFromAccounts:(NSArray *)accounts { + return [RACSignal createSignal:^RACDisposable *(id subscriber) { + dispatch_async(dispatch_get_main_queue(), ^{ + UIActionSheet *sheet = [UIActionSheet new]; + for (ACAccount *account in accounts) { + NSString *title = [NSString stringWithFormat:@"@%@", account.username]; + [sheet addButtonWithTitle:title]; + } + sheet.actionSheetStyle = UIActionSheetStyleBlackTranslucent; + sheet.cancelButtonIndex = [sheet addButtonWithTitle:SimpleAuthLocalizedString(@"CANCEL")]; + + SEL s = @selector(actionSheet:clickedButtonAtIndex:); + Protocol *p = @protocol(UIActionSheetDelegate); + [[sheet rac_signalForSelector:s fromProtocol:p] subscribeNext:^(RACTuple *tuple) { + RACTupleUnpack(UIActionSheet *sheet, NSNumber *number) = tuple; + NSInteger index = [number integerValue]; + if (index == sheet.cancelButtonIndex) { + NSError *error = [NSError errorWithDomain:SimpleAuthErrorDomain code:SimpleAuthErrorUserCancelled userInfo:nil]; + [subscriber sendError:error]; + } + else { + ACAccount *account = accounts[index]; + [subscriber sendNext:account]; + [subscriber sendCompleted]; + } + }]; + + sheet.delegate = (id)sheet; + SimpleAuthInterfaceHandler block = self.options[SimpleAuthPresentInterfaceBlockKey]; + block(sheet); + }); + return nil; + }]; +} + + +- (RACSignal *)reverseAuthRequestToken { + return [RACSignal createSignal:^RACDisposable *(id subscriber) { + NSDictionary *parameters = @{ @"x_auth_mode" : @"reverse_auth" }; + NSURLRequest *request = [GCOAuth + URLRequestForPath:@"/oauth/request_token" + POSTParameters:parameters + scheme:@"https" + host:@"api.twitter.com" + consumerKey:self.options[@"consumer_key"] + consumerSecret:self.options[@"consumer_secret"] + accessToken:nil + tokenSecret:nil]; + [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) { + NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + [subscriber sendNext:string]; + [subscriber sendCompleted]; + } + else { + NSMutableDictionary *dictionary = [NSMutableDictionary new]; + if (connectionError) { + dictionary[NSUnderlyingErrorKey] = connectionError; + } + dictionary[SimpleAuthErrorStatusCodeKey] = @(statusCode); + NSError *error = [NSError errorWithDomain:SimpleAuthErrorDomain code:SimpleAuthErrorNetwork userInfo:dictionary]; + [subscriber sendError:error]; + } + }]; + return nil; + }]; +} + + +- (RACSignal *)accessTokenWithSystemAccount:(ACAccount *)account { + return [[self reverseAuthRequestToken] flattenMap:^(NSString *token) { + return [self accessTokenWithReverseAuthRequestToken:token account:account]; + }]; +} + + +- (RACSignal *)remoteAccountWithSystemAccount:(ACAccount *)account { + return [RACSignal createSignal:^RACDisposable *(id subscriber) { + NSURL *URL = [NSURL URLWithString:@"https://api.twitter.com/1.1/account/verify_credentials.json"]; + SLRequest *request = [SLRequest requestForServiceType:SLServiceTypeTwitter requestMethod:SLRequestMethodGET URL:URL parameters:nil]; + request.account = account; + [request performRequestWithHandler:^(NSData *data, NSHTTPURLResponse *response, NSError *connectionError) { + NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(200, 99)]; + NSInteger statusCode = [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 { + NSMutableDictionary *dictionary = [NSMutableDictionary new]; + if (parseError) { + dictionary[NSUnderlyingErrorKey] = parseError; + } + NSError *error = [NSError errorWithDomain:SimpleAuthErrorDomain code:SimpleAuthErrorInvalidData userInfo:dictionary]; + [subscriber sendNext:error]; + } + } + else { + NSMutableDictionary *dictionary = [NSMutableDictionary new]; + if (connectionError) { + dictionary[NSUnderlyingErrorKey] = connectionError; + } + dictionary[SimpleAuthErrorStatusCodeKey] = @(statusCode); + NSError *error = [NSError errorWithDomain:SimpleAuthErrorDomain code:SimpleAuthErrorNetwork userInfo:dictionary]; + [subscriber sendError:error]; + } + }]; + return nil; + }]; +} + + +- (RACSignal *)accessTokenWithReverseAuthRequestToken:(NSString *)token account:(ACAccount *)account { + return [RACSignal createSignal:^RACDisposable *(id subscriber) { + NSURL *URL = [NSURL URLWithString:@"https://api.twitter.com/oauth/access_token"]; + NSDictionary *parameters = @{ + @"x_reverse_auth_parameters" : token, + @"x_reverse_auth_target" : self.options[@"consumer_key"] + }; + SLRequest *request = [SLRequest requestForServiceType:SLServiceTypeTwitter requestMethod:SLRequestMethodPOST URL:URL parameters:parameters]; + request.account = account; + [request performRequestWithHandler:^(NSData *data, NSHTTPURLResponse *response, NSError *connectionError) { + NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(200, 99)]; + NSInteger statusCode = [response statusCode]; + if ([indexSet containsIndex:statusCode] && data) { + NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + NSDictionary *dictionary = [CMDQueryStringSerialization dictionaryWithQueryString:string]; + [subscriber sendNext:dictionary]; + [subscriber sendCompleted]; + } + else { + NSMutableDictionary *dictionary = [NSMutableDictionary new]; + if (connectionError) { + dictionary[NSUnderlyingErrorKey] = connectionError; + } + dictionary[SimpleAuthErrorStatusCodeKey] = @(statusCode); + NSError *error = [NSError errorWithDomain:SimpleAuthErrorDomain code:SimpleAuthErrorNetwork userInfo:dictionary]; + [subscriber sendError:error]; + } + }]; + return nil; + }]; +} + + +- (NSDictionary *)dictionaryWithSystemAccount:(ACAccount *)systemAccount remoteAccount:(NSDictionary *)remoteAccount accessToken:(NSDictionary *)accessToken { + NSMutableDictionary *dictionary = [NSMutableDictionary new]; + + // Provider + dictionary[@"provider"] = [[self class] type]; + + // Credentials + dictionary[@"credentials"] = @{ + @"token" : accessToken[@"oauth_token"], + @"secret" : accessToken[@"oauth_token_secret"] + }; + + // User ID + dictionary[@"uid"] = remoteAccount[@"id"]; + + // Extra + dictionary[@"extra"] = @{ + @"raw_info" : remoteAccount, + @"account" : systemAccount + }; + + // Profile image + NSString *avatar = remoteAccount[@"profile_image_url_https"]; + avatar = [avatar stringByReplacingOccurrencesOfString:@"_normal" withString:@""]; + + // Profile + NSString *profile = [NSString stringWithFormat:@"https://twitter.com/%@", remoteAccount[@"screen_name"]]; + + // User info + NSMutableDictionary *user = [NSMutableDictionary new]; + user[@"nickname"] = remoteAccount[@"screen_name"]; + user[@"name"] = remoteAccount[@"name"]; + user[@"location"] = remoteAccount[@"location"]; + user[@"image"] = avatar; + user[@"description"] = remoteAccount[@"description"]; + user[@"urls"] = @{ + @"Twitter" : profile, + @"Website" : remoteAccount[@"url"] + }; + dictionary[@"info"] = user; + + return dictionary; +} + +@end diff --git a/Providers/TwitterWeb/SimpleAuthTwitterWebLoginViewController.h b/Pod/Providers/TwitterWeb/SimpleAuthTwitterWebLoginViewController.h similarity index 58% rename from Providers/TwitterWeb/SimpleAuthTwitterWebLoginViewController.h rename to Pod/Providers/TwitterWeb/SimpleAuthTwitterWebLoginViewController.h index ffe218e..b2a5d1d 100644 --- a/Providers/TwitterWeb/SimpleAuthTwitterWebLoginViewController.h +++ b/Pod/Providers/TwitterWeb/SimpleAuthTwitterWebLoginViewController.h @@ -3,13 +3,11 @@ // SimpleAuth // // Created by Caleb Davenport on 1/15/14. -// Copyright (c) 2014 Seesaw Decisions Corporation. All rights reserved. +// Copyright (c) 2014 Byliner, Inc. All rights reserved. // #import "SimpleAuthWebViewController.h" @interface SimpleAuthTwitterWebLoginViewController : SimpleAuthWebViewController -- (instancetype)initWithOptions:(NSDictionary *)options requestToken:(NSDictionary *)requestToken; - @end diff --git a/Providers/TwitterWeb/SimpleAuthTwitterWebLoginViewController.m b/Pod/Providers/TwitterWeb/SimpleAuthTwitterWebLoginViewController.m similarity index 50% rename from Providers/TwitterWeb/SimpleAuthTwitterWebLoginViewController.m rename to Pod/Providers/TwitterWeb/SimpleAuthTwitterWebLoginViewController.m index f568f88..bf258bf 100644 --- a/Providers/TwitterWeb/SimpleAuthTwitterWebLoginViewController.m +++ b/Pod/Providers/TwitterWeb/SimpleAuthTwitterWebLoginViewController.m @@ -3,47 +3,34 @@ // SimpleAuth // // Created by Caleb Davenport on 1/15/14. -// Copyright (c) 2014 Seesaw Decisions Corporation. All rights reserved. +// Copyright (c) 2014 Byliner, Inc. All rights reserved. // #import "SimpleAuthTwitterWebLoginViewController.h" -#import - -@interface SimpleAuthTwitterWebLoginViewController () +@implementation SimpleAuthTwitterWebLoginViewController -@property (nonatomic, copy) NSDictionary *requestToken; +#pragma mark - SimpleAuthWebViewController -@end - -@implementation SimpleAuthTwitterWebLoginViewController +- (instancetype)initWithOptions:(NSDictionary *)options requestToken:(NSDictionary *)requestToken { + if ((self = [super initWithOptions:options requestToken:requestToken])) { + self.title = @"Twitter"; + } + return self; +} -#pragma mark - UIViewController -- (void)viewDidAppear:(BOOL)animated { - [super viewDidAppear:animated]; - +- (NSURLRequest *)initialRequest { NSDictionary *parameters = @{ @"oauth_token" : self.requestToken[@"oauth_token"], + @"force_login": @"true" }; NSString *URLString = [NSString stringWithFormat: @"https://api.twitter.com/oauth/authenticate?%@", - [parameters sam_stringWithFormEncodedComponents]]; + [CMDQueryStringSerialization queryStringWithDictionary:parameters]]; NSURL *URL = [NSURL URLWithString:URLString]; - NSURLRequest *request = [NSURLRequest requestWithURL:URL]; - [self.webView loadRequest:request]; -} - - -#pragma mark - Public - -- (instancetype)initWithOptions:(NSDictionary *)options requestToken:(NSDictionary *)requestToken { - if ((self = [super initWithOptions:options])) { - self.requestToken = requestToken; - self.title = @"Twitter"; - } - return self; + return [NSURLRequest requestWithURL:URL]; } @end diff --git a/Providers/TwitterWeb/SimpleAuthTwitterWebProvider.h b/Pod/Providers/TwitterWeb/SimpleAuthTwitterWebProvider.h similarity index 73% rename from Providers/TwitterWeb/SimpleAuthTwitterWebProvider.h rename to Pod/Providers/TwitterWeb/SimpleAuthTwitterWebProvider.h index 6d50e38..901de1d 100644 --- a/Providers/TwitterWeb/SimpleAuthTwitterWebProvider.h +++ b/Pod/Providers/TwitterWeb/SimpleAuthTwitterWebProvider.h @@ -3,7 +3,7 @@ // SimpleAuth // // Created by Caleb Davenport on 1/15/14. -// Copyright (c) 2014 Seesaw Decisions Corporation. All rights reserved. +// Copyright (c) 2014 Byliner, Inc. All rights reserved. // #import "SimpleAuthProvider.h" diff --git a/Providers/TwitterWeb/SimpleAuthTwitterWebProvider.m b/Pod/Providers/TwitterWeb/SimpleAuthTwitterWebProvider.m similarity index 68% rename from Providers/TwitterWeb/SimpleAuthTwitterWebProvider.m rename to Pod/Providers/TwitterWeb/SimpleAuthTwitterWebProvider.m index 7fe9de6..4171caa 100644 --- a/Providers/TwitterWeb/SimpleAuthTwitterWebProvider.m +++ b/Pod/Providers/TwitterWeb/SimpleAuthTwitterWebProvider.m @@ -3,29 +3,20 @@ // SimpleAuth // // Created by Caleb Davenport on 1/15/14. -// Copyright (c) 2014 Seesaw Decisions Corporation. All rights reserved. +// Copyright (c) 2014 Byliner, Inc. All rights reserved. // #import "SimpleAuthTwitterWebProvider.h" #import "SimpleAuthTwitterWebLoginViewController.h" #import "UIViewController+SimpleAuthAdditions.h" - #import #import -#import @implementation SimpleAuthTwitterWebProvider #pragma mark - SimpleAuthProvider -+ (void)load { - @autoreleasepool { - [SimpleAuth registerProviderClass:self]; - } -} - - + (NSString *)type { return @"twitter-web"; } @@ -37,7 +28,7 @@ + (NSDictionary *)defaultOptions { SimpleAuthInterfaceHandler presentBlock = ^(UIViewController *controller) { UINavigationController *navigation = [[UINavigationController alloc] initWithRootViewController:controller]; navigation.modalPresentationStyle = UIModalPresentationFormSheet; - UIViewController *presented = [UIViewController sa_presentedViewController]; + UIViewController *presented = [UIViewController SimpleAuth_presentedViewController]; [presented presentViewController:navigation animated:YES completion:nil]; }; @@ -92,17 +83,22 @@ - (RACSignal *)requestToken { consumerSecret:self.options[@"consumer_secret"] accessToken:nil tokenSecret:nil]; - [NSURLConnection sendAsynchronousRequest:request queue:self.operationQueue - completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) { + [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) { NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; - NSDictionary *dictionary = [NSDictionary sam_dictionaryWithFormEncodedString:string]; + NSDictionary *dictionary = [CMDQueryStringSerialization dictionaryWithQueryString:string]; [subscriber sendNext:dictionary]; [subscriber sendCompleted]; } else { + NSMutableDictionary *dictionary = [NSMutableDictionary new]; + if (connectionError) { + dictionary[NSUnderlyingErrorKey] = connectionError; + } + dictionary[SimpleAuthErrorStatusCodeKey] = @(statusCode); + NSError *error = [NSError errorWithDomain:SimpleAuthErrorDomain code:SimpleAuthErrorNetwork userInfo:dictionary]; [subscriber sendError:error]; } }]; @@ -113,32 +109,33 @@ - (RACSignal *)requestToken { - (RACSignal *)authenticateWithRequestToken:(NSDictionary *)requestToken { return [RACSignal createSignal:^RACDisposable *(id subscriber) { - SimpleAuthTwitterWebLoginViewController *login = [[SimpleAuthTwitterWebLoginViewController alloc] initWithOptions:self.options requestToken:requestToken]; - - login.completion = ^(UIViewController *controller, NSURL *URL, NSError *error) { - SimpleAuthInterfaceHandler block = self.options[SimpleAuthDismissInterfaceBlockKey]; - block(controller); + dispatch_async(dispatch_get_main_queue(), ^{ + SimpleAuthTwitterWebLoginViewController *login = [[SimpleAuthTwitterWebLoginViewController alloc] initWithOptions:self.options requestToken:requestToken]; - // Parse URL - NSString *query = [URL query]; - NSDictionary *dictionary = [NSDictionary sam_dictionaryWithFormEncodedString:query]; - NSString *token = dictionary[@"oauth_token"]; - NSString *verifier = dictionary[@"oauth_verifier"]; + login.completion = ^(UIViewController *controller, NSURL *URL, NSError *error) { + SimpleAuthInterfaceHandler block = self.options[SimpleAuthDismissInterfaceBlockKey]; + block(controller); + + // Parse URL + NSString *query = [URL query]; + NSDictionary *dictionary = [CMDQueryStringSerialization dictionaryWithQueryString:query]; + NSString *token = dictionary[@"oauth_token"]; + NSString *verifier = dictionary[@"oauth_verifier"]; + + // Check for error + if (![token length] || ![verifier length]) { + [subscriber sendError:error]; + return; + } + + // Send completion + [subscriber sendNext:dictionary]; + [subscriber sendCompleted]; + }; - // Check for error - if (![token length] || ![verifier length]) { - [subscriber sendError:nil]; - return; - } - - // Send completion - [subscriber sendNext:dictionary]; - [subscriber sendCompleted]; - }; - - SimpleAuthInterfaceHandler block = self.options[SimpleAuthPresentInterfaceBlockKey]; - block(login); - + SimpleAuthInterfaceHandler block = self.options[SimpleAuthPresentInterfaceBlockKey]; + block(login); + }); return nil; }]; } @@ -156,18 +153,23 @@ - (RACSignal *)accessTokenWithAuthenticationResponse:(NSDictionary *)authenticat consumerSecret:self.options[@"consumer_secret"] accessToken:authenticationResponse[@"oauth_token"] tokenSecret:nil]; - [NSURLConnection sendAsynchronousRequest:request queue:self.operationQueue - completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) { + [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) { NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; - NSDictionary *dictinoary = [NSDictionary sam_dictionaryWithFormEncodedString:string]; - [subscriber sendNext:dictinoary]; + NSDictionary *dictionary = [CMDQueryStringSerialization dictionaryWithQueryString:string]; + [subscriber sendNext:dictionary]; [subscriber sendCompleted]; } else { - [subscriber sendError:connectionError]; + NSMutableDictionary *dictionary = [NSMutableDictionary new]; + if (connectionError) { + dictionary[NSUnderlyingErrorKey] = connectionError; + } + dictionary[SimpleAuthErrorStatusCodeKey] = @(statusCode); + NSError *error = [NSError errorWithDomain:SimpleAuthErrorDomain code:SimpleAuthErrorNetwork userInfo:dictionary]; + [subscriber sendError:error]; } }]; return nil; @@ -186,8 +188,7 @@ - (RACSignal *)accountWithAccessToken:(NSDictionary *)accessToken { consumerSecret:self.options[@"consumer_secret"] accessToken:accessToken[@"oauth_token"] tokenSecret:accessToken[@"oauth_token_secret"]]; - [NSURLConnection sendAsynchronousRequest:request queue:self.operationQueue - completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) { + [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) { @@ -198,11 +199,22 @@ - (RACSignal *)accountWithAccessToken:(NSDictionary *)accessToken { [subscriber sendCompleted]; } else { - [subscriber sendError:parseError]; + NSMutableDictionary *dictionary = [NSMutableDictionary new]; + if (parseError) { + dictionary[NSUnderlyingErrorKey] = parseError; + } + NSError *error = [NSError errorWithDomain:SimpleAuthErrorDomain code:SimpleAuthErrorInvalidData userInfo:dictionary]; + [subscriber sendNext:error]; } } else { - [subscriber sendError:connectionError]; + NSMutableDictionary *dictionary = [NSMutableDictionary new]; + if (connectionError) { + dictionary[NSUnderlyingErrorKey] = connectionError; + } + dictionary[SimpleAuthErrorStatusCodeKey] = @(statusCode); + NSError *error = [NSError errorWithDomain:SimpleAuthErrorDomain code:SimpleAuthErrorNetwork userInfo:dictionary]; + [subscriber sendError:error]; } }]; return nil; diff --git a/Pod/Resources/en.lproj/Localizable.strings b/Pod/Resources/en.lproj/Localizable.strings new file mode 100644 index 0000000..0c3b7e6 --- /dev/null +++ b/Pod/Resources/en.lproj/Localizable.strings @@ -0,0 +1,10 @@ +/* + SimpleAuth.strings + SimpleAuth + + Created by Caleb Davenport on 10/7/14. + Copyright (c) 2013-2014 Byliner, Inc. All rights reserved. +*/ + +// General strings +"CANCEL" = "Cancel"; diff --git a/Podfile b/Podfile deleted file mode 100644 index c1f9133..0000000 --- a/Podfile +++ /dev/null @@ -1,3 +0,0 @@ -platform :ios, '6.0' - -podspec name: 'SimpleAuth' \ No newline at end of file diff --git a/Podfile.lock b/Podfile.lock deleted file mode 100644 index dde1df2..0000000 --- a/Podfile.lock +++ /dev/null @@ -1,24 +0,0 @@ -PODS: - - cocoa-oauth (0.0.1): - - NSData+Base64 (~> 1.0) - - NSData+Base64 (1.0.0) - - ReactiveCocoa (2.2): - - ReactiveCocoa/Core - - ReactiveCocoa/no-arc - - ReactiveCocoa/Core (2.2): - - ReactiveCocoa/no-arc - - ReactiveCocoa/no-arc (2.2) - - SAMCategories (0.4.0) - -DEPENDENCIES: - - cocoa-oauth - - ReactiveCocoa - - SAMCategories - -SPEC CHECKSUMS: - cocoa-oauth: 8f4c8b77c77ac660de37f8125557c4ec09b0118a - NSData+Base64: 4819562faee4544e3cf5703f2139820b09732b28 - ReactiveCocoa: 5b340678dc3168d6c9a2ca70fb83df683c08ca02 - SAMCategories: fb35d723e2d29b70afdd7efabfd1f99d4d1fe7f5 - -COCOAPODS: 0.29.0 diff --git a/Providers/Facebook/SimpleAuthFacebookProvider.h b/Providers/Facebook/SimpleAuthFacebookProvider.h deleted file mode 100644 index 46e6fd1..0000000 --- a/Providers/Facebook/SimpleAuthFacebookProvider.h +++ /dev/null @@ -1,13 +0,0 @@ -// -// SimpleAuthFacebookProvider.h -// SimpleAuth -// -// Created by Caleb Davenport on 11/6/13. -// Copyright (c) 2013 Seesaw Decisions Corporation. All rights reserved. -// - -#import "SimpleAuthSystemProvider.h" - -@interface SimpleAuthFacebookProvider : SimpleAuthSystemProvider - -@end diff --git a/Providers/Facebook/SimpleAuthFacebookProvider.m b/Providers/Facebook/SimpleAuthFacebookProvider.m deleted file mode 100644 index 3baa9ab..0000000 --- a/Providers/Facebook/SimpleAuthFacebookProvider.m +++ /dev/null @@ -1,172 +0,0 @@ -// -// SimpleAuthFacebookProvider.m -// SimpleAuth -// -// Created by Caleb Davenport on 11/6/13. -// Copyright (c) 2013 Seesaw Decisions Corporation. All rights reserved. -// - -#import "SimpleAuthFacebookProvider.h" - -#import -#import - -@implementation SimpleAuthFacebookProvider - -#pragma mark - NSObject - -+ (void)load { - @autoreleasepool { - [SimpleAuth registerProviderClass:self]; - } -} - - -#pragma mark - SimpleAuthProvider - -+ (NSString *)type { - return @"facebook"; -} - - -+ (NSDictionary *)defaultOptions { - return @{ - @"permissions" : @[ @"email" ] - }; -} - - -- (void)authorizeWithCompletion:(SimpleAuthRequestHandler)completion { - [[[self systemAccount] - flattenMap:^RACStream *(ACAccount *account) { - NSArray *signals = @[ - [self remoteAccountWithSystemAccount:account], - [RACSignal return:account] - ]; - return [self rac_liftSelector:@selector(dictionaryWithRemoteAccount:systemAccount:) withSignalsFromArray:signals]; - }] - subscribeNext:^(NSDictionary *response) { - completion(response, nil); - } - error:^(NSError *error) { - completion(nil, error); - }]; -} - - -#pragma mark - Private - -- (RACSignal *)systemAccounts { - return [RACSignal createSignal:^RACDisposable *(id subscriber) { - ACAccountStore *store = [[self class] accountStore]; - ACAccountType *type = [store accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierFacebook]; - NSDictionary *options = @{ - ACFacebookAppIdKey : self.options[@"app_id"], - ACFacebookPermissionsKey : self.options[@"permissions"] - }; - [store requestAccessToAccountsWithType:type options:options completion:^(BOOL granted, NSError *error) { - if (granted) { - NSArray *accounts = [store accountsWithAccountType:type]; - NSUInteger numberOfAccounts = [accounts count]; - if (numberOfAccounts == 0) { - error = (error ?: [[NSError alloc] initWithDomain:ACErrorDomain code:ACErrorAccountNotFound userInfo:nil]); - [subscriber sendError:error]; - } - else { - [subscriber sendNext:accounts]; - [subscriber sendCompleted]; - } - } - else { - error = (error ?: [[NSError alloc] initWithDomain:ACErrorDomain code:ACErrorPermissionDenied userInfo:nil]); - [subscriber sendError:error]; - } - }]; - return nil; - }]; -} - - -- (RACSignal *)systemAccount { - return [[self systemAccounts] flattenMap:^RACStream *(NSArray *accounts) { - ACAccount *account = [accounts lastObject]; - return [RACSignal return:account]; - }]; -} - - -- (RACSignal *)remoteAccountWithSystemAccount:(ACAccount *)account { - return [RACSignal createSignal:^RACDisposable *(id subscriber) { - NSURL *URL = [NSURL URLWithString:@"https://graph.facebook.com/me"]; - SLRequest *request = [SLRequest requestForServiceType:SLServiceTypeFacebook requestMethod:SLRequestMethodGET URL:URL parameters:nil]; - request.account = account; - [request performRequestWithHandler:^(NSData *data, NSHTTPURLResponse *response, NSError *connectionError) { - NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(200, 99)]; - NSInteger statusCode = [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 *)dictionaryWithRemoteAccount:(NSDictionary *)remoteAccount systemAccount:(ACAccount *)systemAccount { - NSMutableDictionary *dictionary = [NSMutableDictionary new]; - - // Provider - dictionary[@"provider"] = [[self class] type]; - - // Credentials - dictionary[@"credentials"] = @{ - @"token" : systemAccount.credential.oauthToken - }; - - // User ID - dictionary[@"uid"] = remoteAccount[@"id"]; - - // Raw response - dictionary[@"extra"] = @{ - @"raw_info" : remoteAccount, - @"account" : systemAccount - }; - - // Profile image - NSString *avatar = [NSString stringWithFormat:@"https://graph.facebook.com/%@/picture?type=large", remoteAccount[@"id"]]; - - // Location - NSString *location = remoteAccount[@"location"][@"name"]; - - // User info - NSMutableDictionary *user = [NSMutableDictionary new]; - user[@"nickname"] = remoteAccount[@"username"]; - user[@"email"] = remoteAccount[@"email"]; - user[@"name"] = remoteAccount[@"name"]; - user[@"first_name"] = remoteAccount[@"first_name"]; - user[@"last_name"] = remoteAccount[@"last_name"]; - user[@"image"] = avatar; - if (location) { - user[@"location"] = location; - } - user[@"verified"] = remoteAccount[@"verified"]; - user[@"urls"] = @{ - @"Facebook" : remoteAccount[@"link"], - }; - dictionary[@"info"] = user; - - return dictionary; -} - -@end diff --git a/Providers/Instagram/SimpleAuthInstagramLoginViewController.m b/Providers/Instagram/SimpleAuthInstagramLoginViewController.m deleted file mode 100644 index 00f055c..0000000 --- a/Providers/Instagram/SimpleAuthInstagramLoginViewController.m +++ /dev/null @@ -1,48 +0,0 @@ -// -// SimpleAuthInstagramLoginViewController.m -// SimpleAuthInstagram -// -// Created by Caleb Davenport on 11/7/13. -// Copyright (c) 2013 Seesaw Decisions Corporation. All rights reserved. -// - -#import "SimpleAuthInstagramLoginViewController.h" -#import "SimpleAuth.h" - -#import - -@interface SimpleAuthInstagramLoginViewController () - -@end - -@implementation SimpleAuthInstagramLoginViewController - -#pragma mark - UIViewController - -- (void)viewDidAppear:(BOOL)animated { - [super viewDidAppear:animated]; - - NSDictionary *parameters = @{ - @"client_id" : self.options[@"client_id"], - @"redirect_uri" : self.options[SimpleAuthRedirectURIKey], - @"response_type" : @"token" - }; - NSString *URLString = [NSString stringWithFormat: - @"https://instagram.com/oauth/authorize/?%@", - [parameters sam_stringWithFormEncodedComponents]]; - NSURL *URL = [NSURL URLWithString:URLString]; - - NSURLRequest *request = [NSURLRequest requestWithURL:URL]; - [self.webView loadRequest:request]; -} - -#pragma mark - SimpleAuthWebViewController - -- (instancetype)initWithOptions:(NSDictionary *)options { - if ((self = [super initWithOptions:options])) { - self.title = @"Instagram"; - } - return self; -} - -@end diff --git a/Providers/Twitter/SimpleAuthTwitterProvider.h b/Providers/Twitter/SimpleAuthTwitterProvider.h deleted file mode 100644 index 2aa2730..0000000 --- a/Providers/Twitter/SimpleAuthTwitterProvider.h +++ /dev/null @@ -1,13 +0,0 @@ -// -// SimpleAuthTwitterProvider.h -// SimpleAuth -// -// Created by Caleb Davenport on 11/6/13. -// Copyright (c) 2013 Seesaw Decisions Corporation. All rights reserved. -// - -#import "SimpleAuthSystemProvider.h" - -@interface SimpleAuthTwitterProvider : SimpleAuthSystemProvider - -@end diff --git a/Providers/Twitter/SimpleAuthTwitterProvider.m b/Providers/Twitter/SimpleAuthTwitterProvider.m deleted file mode 100644 index ae573a9..0000000 --- a/Providers/Twitter/SimpleAuthTwitterProvider.m +++ /dev/null @@ -1,297 +0,0 @@ -// -// SimpleAuthTwitterProvider.m -// SimpleAuth -// -// Created by Caleb Davenport on 11/6/13. -// Copyright (c) 2013 Seesaw Decisions Corporation. All rights reserved. -// - -#import "SimpleAuthTwitterProvider.h" - -#import "UIWindow+SimpleAuthAdditions.h" - -#import -#import -#import - -@implementation SimpleAuthTwitterProvider - -#pragma mark - NSObject - -+ (void)load { - @autoreleasepool { - [SimpleAuth registerProviderClass:self]; - } -} - - -#pragma mark - SimpleAuthProvider - -+ (NSString *)type { - return @"twitter"; -} - - -+ (NSDictionary *)defaultOptions { - void (^actionSheetBlock) (UIActionSheet *) = ^(UIActionSheet *sheet) { - UIWindow *window = [UIWindow sa_mainWindow]; - [sheet showInView:window]; - }; - - NSMutableDictionary *options = [NSMutableDictionary dictionaryWithDictionary:[super defaultOptions]]; - options[SimpleAuthPresentInterfaceBlockKey] = actionSheetBlock; - - return options; -} - - -#pragma mark - SimpleAuthSystemProvider - -- (void)authorizeWithSystemAccount:(ACAccount *)account completion:(SimpleAuthRequestHandler)completion { - RACSignal *accountSignal = [self twitterAccountWithAccount:account]; - RACSignal *accessTokenSignal = [self accessTokenWithAccount:account]; - RACSignal *zipSignal = [RACSignal zip:@[ accountSignal, accessTokenSignal ] reduce:^(NSDictionary *accountDictionary, NSDictionary *accessTokenDictionary) { - return [self responseWithAccount:account accountDictionary:accountDictionary accessTokenDictionary:accessTokenDictionary]; - }]; - [[zipSignal deliverOn:[RACScheduler mainThreadScheduler]] - subscribeNext:^(NSDictionary *dictionary) { - completion(dictionary, nil); - } - error:^(NSError *error) { - completion(nil, error); - }]; -} - - -- (void)loadSystemAccount:(SimpleAuthSystemAccountHandler)completion { - [[[self selectedTwitterAccount] - deliverOn:[RACScheduler mainThreadScheduler]] - subscribeNext:^(ACAccount *account) { - completion(account, nil); - } - error:^(NSError *error) { - completion(nil, error); - }]; -} - - -#pragma mark - Private - -- (RACSignal *)allTwitterAccounts { - return [RACSignal createSignal:^RACDisposable *(id subscriber) { - ACAccountStore *store = [[self class] accountStore]; - ACAccountType *type = [store accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter]; - [store requestAccessToAccountsWithType:type options:nil completion:^(BOOL granted, NSError *error) { - if (granted) { - NSArray *accounts = [store accountsWithAccountType:type]; - NSUInteger numberOfAccounts = [accounts count]; - if (numberOfAccounts) { - [subscriber sendNext:accounts]; - [subscriber sendCompleted]; - } - else { - [subscriber sendError:(error ?: [[NSError alloc] initWithDomain:ACErrorDomain code:ACErrorAccountNotFound userInfo:nil])]; - } - } - else { - [subscriber sendError:(error ?: [[NSError alloc] initWithDomain:ACErrorDomain code:ACErrorPermissionDenied userInfo:nil])]; - } - }]; - return nil; - }]; -} - - -- (RACSignal *)selectedTwitterAccount { - return [[self allTwitterAccounts] flattenMap:^RACStream *(NSArray *accounts) { - if ([accounts count] == 1) { - ACAccount *account = [accounts lastObject]; - return [RACSignal return:account]; - } - else { - return [self twitterAccountFromAccounts:accounts]; - } - }]; -} - - -- (RACSignal *)twitterAccountFromAccounts:(NSArray *)accounts { - return [RACSignal createSignal:^RACDisposable *(id subscriber) { - dispatch_async(dispatch_get_main_queue(), ^{ - UIActionSheet *sheet = [UIActionSheet new]; - for (ACAccount *account in accounts) { - NSString *title = [NSString stringWithFormat:@"@%@", account.username]; - [sheet addButtonWithTitle:title]; - } - sheet.actionSheetStyle = UIActionSheetStyleBlackTranslucent; - sheet.cancelButtonIndex = [sheet addButtonWithTitle:NSLocalizedString(@"GENERAL_CANCEL", nil)]; - - SEL s = @selector(actionSheet:clickedButtonAtIndex:); - Protocol *p = @protocol(UIActionSheetDelegate); - [[sheet rac_signalForSelector:s fromProtocol:p] subscribeNext:^(RACTuple *tuple) { - RACTupleUnpack(UIActionSheet *sheet, NSNumber *number) = tuple; - NSInteger index = [number integerValue]; - if (index == sheet.cancelButtonIndex) { - NSError *error = [NSError errorWithDomain:SimpleAuthErrorDomain code:SimpleAuthUserCancelledErrorCode userInfo:nil]; - [subscriber sendError:error]; - } - else { - ACAccount *account = accounts[index]; - [subscriber sendNext:account]; - [subscriber sendCompleted]; - } - }]; - - sheet.delegate = (id)sheet; - void (^block) (UIActionSheet *) = self.options[@"action_sheet_block"]; - block(sheet); - }); - return nil; - }]; -} - - -- (RACSignal *)requestTokenWithParameters:(NSDictionary *)parameters { - return [RACSignal createSignal:^RACDisposable *(id subscriber) { - NSURLRequest *request = [GCOAuth - URLRequestForPath:@"/oauth/request_token" - POSTParameters:parameters - scheme:@"https" - host:@"api.twitter.com" - consumerKey:self.options[@"consumer_key"] - consumerSecret:self.options[@"consumer_secret"] - accessToken:nil - tokenSecret:nil]; - [NSURLConnection - sendAsynchronousRequest:request - queue:[NSOperationQueue mainQueue] - completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) { - NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode]; - if (statusCode == 200 && data) { - NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; - [subscriber sendNext:string]; - [subscriber sendCompleted]; - } - else { - [subscriber sendError:error]; - } - }]; - return nil; - }]; -} - - -- (RACSignal *)accessTokenWithAccount:(ACAccount *)account { - return [[self reverseAuthRequestToken] flattenMap:^(NSString *token) { - return [self accessTokenWithReverseAuthRequestToken:token account:account]; - }]; -} - - -- (RACSignal *)twitterAccountWithAccount:(ACAccount *)account { - return [RACSignal createSignal:^RACDisposable *(id subscriber) { - NSURL *URL = [NSURL URLWithString:@"https://api.twitter.com/1.1/account/verify_credentials.json"]; - SLRequest *request = [SLRequest - requestForServiceType:SLServiceTypeTwitter - requestMethod:SLRequestMethodGET - URL:URL - parameters:nil]; - request.account = account; - [request performRequestWithHandler:^(NSData *data, NSHTTPURLResponse *response, NSError *error) { - NSInteger statusCode = [response statusCode]; - if (statusCode == 200 && data) { - NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil]; - [subscriber sendNext:dictionary]; - [subscriber sendCompleted]; - } - else { - [subscriber sendError:error]; - } - }]; - return nil; - }]; -} - - -- (RACSignal *)reverseAuthRequestToken { - return [self requestTokenWithParameters:@{ - @"x_auth_mode" : @"reverse_auth" - }]; -} - - -- (RACSignal *)accessTokenWithReverseAuthRequestToken:(NSString *)token account:(ACAccount *)account { - return [RACSignal createSignal:^RACDisposable *(id subscriber) { - NSURL *URL = [NSURL URLWithString:@"https://api.twitter.com/oauth/access_token"]; - NSDictionary *parameters = @{ - @"x_reverse_auth_parameters" : token, - @"x_reverse_auth_target" : self.options[@"consumer_key"] - }; - SLRequest *request = [SLRequest - requestForServiceType:SLServiceTypeTwitter - requestMethod:SLRequestMethodPOST - URL:URL - parameters:parameters]; - request.account = account; - [request performRequestWithHandler:^(NSData *data, NSHTTPURLResponse *response, NSError *error) { - NSInteger statusCode = [response statusCode]; - if (statusCode == 200 && data) { - NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; - NSDictionary *dictionary = [NSDictionary sam_dictionaryWithFormEncodedString:string]; - [subscriber sendNext:dictionary]; - [subscriber sendCompleted]; - } - else { - [subscriber sendError:error]; - } - }]; - return nil; - }]; -} - - -- (NSDictionary *)responseWithAccount:(ACAccount *)account accountDictionary:(NSDictionary *)accountDictionary accessTokenDictionary:(NSDictionary *)accessToken { - NSMutableDictionary *dictionary = [NSMutableDictionary new]; - - // Provider - dictionary[@"provider"] = [[self class] type]; - - // Credentials - dictionary[@"credentials"] = @{ - @"token" : accessToken[@"oauth_token"], - @"secret" : accessToken[@"oauth_token_secret"] - }; - - // User ID - dictionary[@"uid"] = accountDictionary[@"id"]; - - // Extra - dictionary[@"extra"] = @{ - @"raw_info" : accountDictionary, - @"account" : account - }; - - // Profile image - NSString *avatar = accountDictionary[@"profile_image_url_https"]; - avatar = [avatar stringByReplacingOccurrencesOfString:@"_normal" withString:@""]; - - // Profile - NSString *profile = [NSString stringWithFormat:@"https://twitter.com/%@", accountDictionary[@"screen_name"]]; - - // User info - NSMutableDictionary *user = [NSMutableDictionary new]; - user[@"nickname"] = accountDictionary[@"screen_name"]; - user[@"name"] = accountDictionary[@"name"]; - user[@"location"] = accountDictionary[@"location"]; - user[@"image"] = avatar; - user[@"description"] = accountDictionary[@"description"]; - user[@"urls"] = @{ - @"Twitter" : profile, - @"Website" : accountDictionary[@"url"] - }; - dictionary[@"info"] = user; - - return dictionary; -} - -@end diff --git a/Readme.markdown b/Readme.markdown index 538122b..2a88cc2 100644 --- a/Readme.markdown +++ b/Readme.markdown @@ -1,19 +1,21 @@ # SimpleAuth -SimpleAuth is designed to do the hard work of social account login on iOS. It has a small set of public APIs backed by a set of "providers" that implement the functionality needed to communicate with various social services. You can read more about it [here](http://blog.calebd.me/introducing-simpleauth). +SimpleAuth is designed to do the hard work of social account login on iOS. It has a small set of public APIs backed by a set of "providers" that implement the functionality needed to communicate with various social services. SimpleAuth currently has the following providers: -- Facebook (system) -- Twitter (system) -- Instagram -- Twitter web - -I also have plans to provide: - -- Twitter xauth -- Facebook web -- Tumblr +- [Twitter](https://github.com/calebd/SimpleAuth/wiki/Twitter) +- [Facebook](https://github.com/calebd/SimpleAuth/wiki/Facebook) +- [Instagram](https://github.com/calebd/SimpleAuth/wiki/Instagram) +- [Tumblr](https://github.com/calebd/SimpleAuth/wiki/Tumblr) +- [Dropbox](https://github.com/calebd/SimpleAuth/wiki/Dropbox) +- [Foursquare](https://github.com/calebd/SimpleAuth/wiki/Foursquare) +- [Meetup](https://github.com/calebd/SimpleAuth/wiki/Meetup) +- [LinkedIn](https://github.com/calebd/SimpleAuth/wiki/LinkedIn) +- [Sina Weibo](https://github.com/calebd/SimpleAuth/wiki/SinaWeibo) +- [Google](https://github.com/calebd/SimpleAuth/wiki/Google) +- [Box](https://github.com/calebd/SimpleAuth/wiki/Box) +- [OneDrive](https://github.com/calebd/SimpleAuth/wiki/OneDrive) ## Installing @@ -30,36 +32,26 @@ to your `Podfile`. Configuring and using SimpleAuth is easy: -````objc +````swift // Somewhere in your app boot process -SimpleAuth.configuration[@"twitter"] = @{ - @"consumer_key" : @"KEY", - @"consumer_secret" : @"SECRET" -}; +SimpleAuth.configuration()["twitter"] = [ + "consumer_key": "KEY", + "consumer_secret": "SECRET" +] ```` -````objc +````swift // Authorize -- (void)loginWithTwitter { - [SimpleAuth authorize:@"twitter" completion:^(id responseObject, NSError *error) { - NSLog(@"%@", responseObject); - }]; +func loginWithTwitter() { + SimpleAuth.authorize("twitter", completion: { responseObject, error in + println("Twitter login response: \(responseObject)") + }) } ```` ## Implementing a Provider -The API for creating providers is pretty simple. Providers should be stored in `Providers/` and have an appropriately named folder and sub spec. There are a handful of methods you'll need to implement: - -Register your provider with SimpleAuth: - -````objc -+ (void)load { - @autoreleasepool { - [SimpleAuth registerProviderClass:self]; - } -} -```` +The API for creating providers is pretty simple. Be sure to look at `SimpleAuthProvider` and `SimpleAuthWebLoginViewController`. These classes will help you simplify your authentiction process. Providers should be stored in `Pod/Providers/` and have an appropriately named folder and sub spec. All providers are automatically registered with the framework. There are a handful of methods you'll need to implement: Let SimpleAuth know what type of provider you are registering: @@ -98,3 +90,10 @@ SimpleAuth is released under the MIT license. ## Thanks Special thanks to my friend [@soffes](https://twitter.com/soffes) for advising on the SimpleAuth API design. + +### Contributors + +- [kornifex](https://github.com/kornifex): Foursquare provider +- [mouhcine](https://github.com/mouhcine): Meetup provider +- [iamabhiee](https://github.com/iamabhiee): LinkedIn provider +- [aschuch](https://github.com/aschuch): Sina Weibo provider diff --git a/SimpleAuth.podspec b/SimpleAuth.podspec old mode 100644 new mode 100755 index 42f11b1..6125ab9 --- a/SimpleAuth.podspec +++ b/SimpleAuth.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'SimpleAuth' - s.version = '0.3.0' + s.version = '0.3.9' s.summary = 'Simple social authentication for iOS.' s.homepage = 'https://github.com/calebd/SimpleAuth' s.license = { :type => 'MIT', :file => 'LICENSE' } @@ -8,43 +8,124 @@ Pod::Spec.new do |s| s.source = { :git => 'https://github.com/calebd/SimpleAuth.git', :tag => "v#{s.version}" } s.requires_arc = true s.platform = :ios, '6.0' - + s.subspec 'Core' do |ss| - ss.source_files = 'SimpleAuth/**/*.{h,m}' - ss.public_header_files = 'SimpleAuth/SipmleAuth.h' + ss.source_files = 'Pod/Core' + ss.public_header_files = 'Pod/Core/SimpleAuth.h', 'Pod/Core/SimpleAuthDefines.h' ss.dependency 'ReactiveCocoa' - ss.dependency 'SAMCategories' + ss.dependency 'CMDQueryStringSerialization' + + ss.ios.frameworks = 'UIKit' + ss.ios.source_files = 'Pod/Core/ios' + ss.ios.resource_bundle = { 'SimpleAuth' => [ 'Pod/Resources/*.lproj' ] } end - + s.subspec 'Twitter' do |ss| ss.dependency 'SimpleAuth/Core' - - ss.source_files = 'Providers/Twitter/**/*.{h,m}' - ss.frameworks = 'Accounts', 'Social', 'UIKit' - ss.dependency 'cocoa-oauth' + ss.frameworks = 'Accounts', 'Social' + ss.source_files = 'Pod/Providers/Twitter' + ss.private_header_files = 'Pod/Providers/Twitter/*.h' end - + s.subspec 'Facebook' do |ss| ss.dependency 'SimpleAuth/Core' - - ss.source_files = 'Providers/Facebook/**/*.{h,m}' ss.frameworks = 'Accounts', 'Social' + ss.source_files = 'Pod/Providers/Facebook' + ss.private_header_files = 'Pod/Providers/Facebook/*.h' + end + + s.subspec 'FacebookWeb' do |ss| + ss.dependency 'SimpleAuth/Core' + ss.source_files = 'Pod/Providers/FacebookWeb' + ss.private_header_files = 'Pod/Providers/FacebookWeb/*.h' end - + s.subspec 'Instagram' do |ss| ss.dependency 'SimpleAuth/Core' - - ss.source_files = 'Providers/Instagram/**/*.{h,m}' - ss.frameworks = 'UIKit' + ss.source_files = 'Pod/Providers/Instagram' + ss.private_header_files = 'Pod/Providers/Instagram/*.h' end - + s.subspec 'TwitterWeb' do |ss| ss.dependency 'SimpleAuth/Core' - - ss.source_files = 'Providers/TwitterWeb/**/*.{h,m}' - ss.frameworks = 'UIKit' - ss.dependency 'cocoa-oauth' + ss.source_files = 'Pod/Providers/TwitterWeb' + ss.private_header_files = 'Pod/Providers/TwitterWeb/*.h' + end + + s.subspec 'Meetup' do |ss| + ss.dependency 'SimpleAuth/Core' + ss.source_files = 'Pod/Providers/Meetup' + ss.private_header_files = 'Pod/Providers/Meetup/*.h' + end + + s.subspec 'Tumblr' do |ss| + ss.dependency 'SimpleAuth/Core' + ss.dependency 'cocoa-oauth' + ss.source_files = 'Pod/Providers/Tumblr' + ss.private_header_files = 'Pod/Providers/Tumblr/*.h' + end + + s.subspec 'FoursquareWeb' do |ss| + ss.dependency 'SimpleAuth/Core' + ss.source_files = 'Pod/Providers/FoursquareWeb' + ss.private_header_files = 'Pod/Providers/FoursquareWeb/*.h' + end + + s.subspec 'DropboxWeb' do |ss| + ss.dependency 'SimpleAuth/Core' + ss.source_files = 'Pod/Providers/DropboxWeb' + ss.private_header_files = 'Pod/Providers/DropboxWeb/*.h' + end + + s.subspec 'LinkedInWeb' do |ss| + ss.dependency 'SimpleAuth/Core' + ss.source_files = 'Pod/Providers/LinkedIn' + ss.private_header_files = 'Pod/Providers/LinkedIn/*.h' + end + + s.subspec 'SinaWeiboWeb' do |ss| + ss.dependency 'SimpleAuth/Core' + ss.source_files = 'Pod/Providers/SinaWeiboWeb' + ss.private_header_files = 'Pod/Providers/SinaWeiboWeb/*.h' + end + + s.subspec 'GoogleWeb' do |ss| + ss.dependency 'SimpleAuth/Core' + ss.source_files = 'Pod/Providers/GoogleWeb' + ss.private_header_files = 'Pod/Providers/GoogleWeb/*.h' + end + + s.subspec 'TripIt' do |ss| + ss.dependency 'SimpleAuth/Core' + ss.dependency 'cocoa-oauth' + ss.source_files = 'Pod/Providers/TripIt' + ss.private_header_files = 'Pod/Providers/TripIt/*.h' + end + + s.subspec 'Trello' do |ss| + ss.dependency 'SimpleAuth/Core' + ss.source_files = 'Pod/Providers/Trello' + ss.private_header_files = 'Pod/Providers/Trello/*.h' + end + + s.subspec 'Strava' do |ss| + ss.dependency 'SimpleAuth/Core' + ss.source_files = 'Pod/Providers/Strava' + ss.private_header_files = 'Pod/Providers/Strava/*.h' + end + + s.subspec 'BoxWeb' do |ss| + ss.dependency 'SimpleAuth/Core' + ss.source_files = 'Pod/Providers/BoxWeb' + ss.private_header_files = 'Pod/Providers/BoxWeb/*.h' + end + + s.subspec 'OneDriveWeb' do |ss| + ss.dependency 'SimpleAuth/Core' + ss.source_files = 'Pod/Providers/OneDriveWeb' + ss.private_header_files = 'Pod/Providers/OneDriveWeb/*.h' end -end \ No newline at end of file + +end diff --git a/SimpleAuth.xcodeproj/project.pbxproj b/SimpleAuth.xcodeproj/project.pbxproj deleted file mode 100644 index f6d5750..0000000 --- a/SimpleAuth.xcodeproj/project.pbxproj +++ /dev/null @@ -1,598 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 3B52BB911887088400C73329 /* SimpleAuthTwitterProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B52BB901887088400C73329 /* SimpleAuthTwitterProvider.m */; }; - 3B52BB9518871F6200C73329 /* SimpleAuthFacebookProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B52BB9418871F6200C73329 /* SimpleAuthFacebookProvider.m */; }; - 3B52BB9B188731A300C73329 /* SimpleAuthInstagramLoginViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B52BB98188731A300C73329 /* SimpleAuthInstagramLoginViewController.m */; }; - 3B52BB9C188731A300C73329 /* SimpleAuthInstagramProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B52BB9A188731A300C73329 /* SimpleAuthInstagramProvider.m */; }; - 3B658435188892FE00D59100 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 3B658433188892FE00D59100 /* InfoPlist.strings */; }; - 3B658437188892FE00D59100 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B658436188892FE00D59100 /* main.m */; }; - 3B65843B188892FE00D59100 /* SADAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B65843A188892FE00D59100 /* SADAppDelegate.m */; }; - 3B65843D188892FE00D59100 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3B65843C188892FE00D59100 /* Images.xcassets */; }; - 3B6584581888931F00D59100 /* SADProviderListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B6584571888931F00D59100 /* SADProviderListViewController.m */; }; - 3B65845C188895E400D59100 /* libSimpleAuth.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3BB32504182ABC8B00ACB555 /* libSimpleAuth.a */; }; - 3B8C408E188792A9007DC578 /* SimpleAuthTwitterWebProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B8C408D188792A9007DC578 /* SimpleAuthTwitterWebProvider.m */; }; - 3B8C409118879347007DC578 /* SimpleAuthTwitterWebLoginViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B8C409018879347007DC578 /* SimpleAuthTwitterWebLoginViewController.m */; }; - 3B9AB064182AC2710011FB9E /* SimpleAuthProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B9AB063182AC2710011FB9E /* SimpleAuthProvider.m */; }; - 3B9AB06E182ACCBB0011FB9E /* SimpleAuthSystemProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B9AB06D182ACCBB0011FB9E /* SimpleAuthSystemProvider.m */; }; - 3BB3250F182ABC8B00ACB555 /* SimpleAuth.m in Sources */ = {isa = PBXBuildFile; fileRef = 3BB3250E182ABC8B00ACB555 /* SimpleAuth.m */; }; - 3C0A5393182C4217002C050C /* SimpleAuthWebViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3C0A5392182C4217002C050C /* SimpleAuthWebViewController.m */; }; - 3C611F451835352200D87E45 /* UIWindow+SimpleAuthAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 3C611F441835352200D87E45 /* UIWindow+SimpleAuthAdditions.m */; }; - 3C611F48183535A400D87E45 /* UIViewController+SimpleAuthAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 3C611F47183535A400D87E45 /* UIViewController+SimpleAuthAdditions.m */; }; - F435E27FC62B4584BF9DBF2C /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0D4998CFA03844FB99EE78AA /* libPods.a */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 3B65845A1888947500D59100 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 3BB324FC182ABC8B00ACB555 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 3BB32503182ABC8B00ACB555; - remoteInfo = SimpleAuth; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXFileReference section */ - 0D4998CFA03844FB99EE78AA /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; }; - 0FCEF85A832046CDB0CCBF25 /* Pods.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.xcconfig; path = Pods/Pods.xcconfig; sourceTree = ""; }; - 3B52BB8F1887088400C73329 /* SimpleAuthTwitterProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SimpleAuthTwitterProvider.h; sourceTree = ""; }; - 3B52BB901887088400C73329 /* SimpleAuthTwitterProvider.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SimpleAuthTwitterProvider.m; sourceTree = ""; }; - 3B52BB9318871F6200C73329 /* SimpleAuthFacebookProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SimpleAuthFacebookProvider.h; sourceTree = ""; }; - 3B52BB9418871F6200C73329 /* SimpleAuthFacebookProvider.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SimpleAuthFacebookProvider.m; sourceTree = ""; }; - 3B52BB97188731A300C73329 /* SimpleAuthInstagramLoginViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SimpleAuthInstagramLoginViewController.h; sourceTree = ""; }; - 3B52BB98188731A300C73329 /* SimpleAuthInstagramLoginViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SimpleAuthInstagramLoginViewController.m; sourceTree = ""; }; - 3B52BB99188731A300C73329 /* SimpleAuthInstagramProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SimpleAuthInstagramProvider.h; sourceTree = ""; }; - 3B52BB9A188731A300C73329 /* SimpleAuthInstagramProvider.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SimpleAuthInstagramProvider.m; sourceTree = ""; }; - 3B658429188892FD00D59100 /* SimpleAuthDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SimpleAuthDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 3B65842A188892FE00D59100 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; - 3B65842C188892FE00D59100 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; - 3B65842E188892FE00D59100 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; - 3B658432188892FE00D59100 /* SimpleAuthDemo-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "SimpleAuthDemo-Info.plist"; sourceTree = ""; }; - 3B658434188892FE00D59100 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; - 3B658436188892FE00D59100 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; - 3B658438188892FE00D59100 /* SimpleAuthDemo-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SimpleAuthDemo-Prefix.pch"; sourceTree = ""; }; - 3B658439188892FE00D59100 /* SADAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SADAppDelegate.h; sourceTree = ""; }; - 3B65843A188892FE00D59100 /* SADAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SADAppDelegate.m; sourceTree = ""; }; - 3B65843C188892FE00D59100 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; - 3B658443188892FE00D59100 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; - 3B6584571888931F00D59100 /* SADProviderListViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SADProviderListViewController.m; sourceTree = ""; }; - 3B6584591888933200D59100 /* SADProviderListViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SADProviderListViewController.h; sourceTree = ""; }; - 3B8C408C188792A9007DC578 /* SimpleAuthTwitterWebProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SimpleAuthTwitterWebProvider.h; sourceTree = ""; }; - 3B8C408D188792A9007DC578 /* SimpleAuthTwitterWebProvider.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SimpleAuthTwitterWebProvider.m; sourceTree = ""; }; - 3B8C408F18879347007DC578 /* SimpleAuthTwitterWebLoginViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SimpleAuthTwitterWebLoginViewController.h; sourceTree = ""; }; - 3B8C409018879347007DC578 /* SimpleAuthTwitterWebLoginViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SimpleAuthTwitterWebLoginViewController.m; sourceTree = ""; }; - 3B9AB062182AC2710011FB9E /* SimpleAuthProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SimpleAuthProvider.h; sourceTree = ""; }; - 3B9AB063182AC2710011FB9E /* SimpleAuthProvider.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SimpleAuthProvider.m; sourceTree = ""; }; - 3B9AB06C182ACCBB0011FB9E /* SimpleAuthSystemProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SimpleAuthSystemProvider.h; sourceTree = ""; }; - 3B9AB06D182ACCBB0011FB9E /* SimpleAuthSystemProvider.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SimpleAuthSystemProvider.m; sourceTree = ""; }; - 3BB32504182ABC8B00ACB555 /* libSimpleAuth.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libSimpleAuth.a; sourceTree = BUILT_PRODUCTS_DIR; }; - 3BB3250B182ABC8B00ACB555 /* SimpleAuth-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SimpleAuth-Prefix.pch"; sourceTree = ""; }; - 3BB3250C182ABC8B00ACB555 /* SimpleAuth.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SimpleAuth.h; sourceTree = ""; }; - 3BB3250E182ABC8B00ACB555 /* SimpleAuth.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SimpleAuth.m; sourceTree = ""; }; - 3C0A5391182C4217002C050C /* SimpleAuthWebViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SimpleAuthWebViewController.h; sourceTree = ""; }; - 3C0A5392182C4217002C050C /* SimpleAuthWebViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SimpleAuthWebViewController.m; sourceTree = ""; }; - 3C611F431835352200D87E45 /* UIWindow+SimpleAuthAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIWindow+SimpleAuthAdditions.h"; sourceTree = ""; }; - 3C611F441835352200D87E45 /* UIWindow+SimpleAuthAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIWindow+SimpleAuthAdditions.m"; sourceTree = ""; }; - 3C611F46183535A400D87E45 /* UIViewController+SimpleAuthAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIViewController+SimpleAuthAdditions.h"; sourceTree = ""; }; - 3C611F47183535A400D87E45 /* UIViewController+SimpleAuthAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIViewController+SimpleAuthAdditions.m"; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 3B658426188892FD00D59100 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 3B65845C188895E400D59100 /* libSimpleAuth.a in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 681A563A05114C23AD83043F /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - F435E27FC62B4584BF9DBF2C /* libPods.a in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 3B52BB8D1887088400C73329 /* Providers */ = { - isa = PBXGroup; - children = ( - 3B52BB9218871F6200C73329 /* Facebook */, - 3B52BB8E1887088400C73329 /* Twitter */, - 3B8C408B18879296007DC578 /* TwitterWeb */, - 3B52BB96188731A300C73329 /* Instagram */, - ); - path = Providers; - sourceTree = ""; - }; - 3B52BB8E1887088400C73329 /* Twitter */ = { - isa = PBXGroup; - children = ( - 3B52BB8F1887088400C73329 /* SimpleAuthTwitterProvider.h */, - 3B52BB901887088400C73329 /* SimpleAuthTwitterProvider.m */, - ); - path = Twitter; - sourceTree = ""; - }; - 3B52BB9218871F6200C73329 /* Facebook */ = { - isa = PBXGroup; - children = ( - 3B52BB9318871F6200C73329 /* SimpleAuthFacebookProvider.h */, - 3B52BB9418871F6200C73329 /* SimpleAuthFacebookProvider.m */, - ); - path = Facebook; - sourceTree = ""; - }; - 3B52BB96188731A300C73329 /* Instagram */ = { - isa = PBXGroup; - children = ( - 3B52BB99188731A300C73329 /* SimpleAuthInstagramProvider.h */, - 3B52BB9A188731A300C73329 /* SimpleAuthInstagramProvider.m */, - 3B52BB97188731A300C73329 /* SimpleAuthInstagramLoginViewController.h */, - 3B52BB98188731A300C73329 /* SimpleAuthInstagramLoginViewController.m */, - ); - path = Instagram; - sourceTree = ""; - }; - 3B658430188892FE00D59100 /* SimpleAuthDemo */ = { - isa = PBXGroup; - children = ( - 3B658439188892FE00D59100 /* SADAppDelegate.h */, - 3B65843A188892FE00D59100 /* SADAppDelegate.m */, - 3B6584591888933200D59100 /* SADProviderListViewController.h */, - 3B6584571888931F00D59100 /* SADProviderListViewController.m */, - 3B65843C188892FE00D59100 /* Images.xcassets */, - 3B658431188892FE00D59100 /* Supporting Files */, - ); - path = SimpleAuthDemo; - sourceTree = ""; - }; - 3B658431188892FE00D59100 /* Supporting Files */ = { - isa = PBXGroup; - children = ( - 3B658432188892FE00D59100 /* SimpleAuthDemo-Info.plist */, - 3B658433188892FE00D59100 /* InfoPlist.strings */, - 3B658436188892FE00D59100 /* main.m */, - 3B658438188892FE00D59100 /* SimpleAuthDemo-Prefix.pch */, - ); - name = "Supporting Files"; - sourceTree = ""; - }; - 3B8C408B18879296007DC578 /* TwitterWeb */ = { - isa = PBXGroup; - children = ( - 3B8C408C188792A9007DC578 /* SimpleAuthTwitterWebProvider.h */, - 3B8C408D188792A9007DC578 /* SimpleAuthTwitterWebProvider.m */, - 3B8C408F18879347007DC578 /* SimpleAuthTwitterWebLoginViewController.h */, - 3B8C409018879347007DC578 /* SimpleAuthTwitterWebLoginViewController.m */, - ); - path = TwitterWeb; - sourceTree = ""; - }; - 3B8F11B8182AC0E50035C4EA /* Providers */ = { - isa = PBXGroup; - children = ( - 3B9AB062182AC2710011FB9E /* SimpleAuthProvider.h */, - 3B9AB063182AC2710011FB9E /* SimpleAuthProvider.m */, - 3B9AB06C182ACCBB0011FB9E /* SimpleAuthSystemProvider.h */, - 3B9AB06D182ACCBB0011FB9E /* SimpleAuthSystemProvider.m */, - ); - name = Providers; - sourceTree = ""; - }; - 3BB324FB182ABC8B00ACB555 = { - isa = PBXGroup; - children = ( - 3BB32509182ABC8B00ACB555 /* SimpleAuth */, - 3B52BB8D1887088400C73329 /* Providers */, - 3B658430188892FE00D59100 /* SimpleAuthDemo */, - 3BB32506182ABC8B00ACB555 /* Frameworks */, - 3BB32505182ABC8B00ACB555 /* Products */, - 0FCEF85A832046CDB0CCBF25 /* Pods.xcconfig */, - ); - sourceTree = ""; - }; - 3BB32505182ABC8B00ACB555 /* Products */ = { - isa = PBXGroup; - children = ( - 3BB32504182ABC8B00ACB555 /* libSimpleAuth.a */, - 3B658429188892FD00D59100 /* SimpleAuthDemo.app */, - ); - name = Products; - sourceTree = ""; - }; - 3BB32506182ABC8B00ACB555 /* Frameworks */ = { - isa = PBXGroup; - children = ( - 0D4998CFA03844FB99EE78AA /* libPods.a */, - 3B65842A188892FE00D59100 /* Foundation.framework */, - 3B65842C188892FE00D59100 /* CoreGraphics.framework */, - 3B65842E188892FE00D59100 /* UIKit.framework */, - 3B658443188892FE00D59100 /* XCTest.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - 3BB32509182ABC8B00ACB555 /* SimpleAuth */ = { - isa = PBXGroup; - children = ( - 3BB3250C182ABC8B00ACB555 /* SimpleAuth.h */, - 3BB3250E182ABC8B00ACB555 /* SimpleAuth.m */, - 3B8F11B8182AC0E50035C4EA /* Providers */, - 3C0A5390182C4206002C050C /* View Controllers */, - 3C611F421835350800D87E45 /* Categories */, - 3BB3250A182ABC8B00ACB555 /* Supporting Files */, - ); - path = SimpleAuth; - sourceTree = ""; - }; - 3BB3250A182ABC8B00ACB555 /* Supporting Files */ = { - isa = PBXGroup; - children = ( - 3BB3250B182ABC8B00ACB555 /* SimpleAuth-Prefix.pch */, - ); - name = "Supporting Files"; - sourceTree = ""; - }; - 3C0A5390182C4206002C050C /* View Controllers */ = { - isa = PBXGroup; - children = ( - 3C0A5391182C4217002C050C /* SimpleAuthWebViewController.h */, - 3C0A5392182C4217002C050C /* SimpleAuthWebViewController.m */, - ); - name = "View Controllers"; - sourceTree = ""; - }; - 3C611F421835350800D87E45 /* Categories */ = { - isa = PBXGroup; - children = ( - 3C611F431835352200D87E45 /* UIWindow+SimpleAuthAdditions.h */, - 3C611F441835352200D87E45 /* UIWindow+SimpleAuthAdditions.m */, - 3C611F46183535A400D87E45 /* UIViewController+SimpleAuthAdditions.h */, - 3C611F47183535A400D87E45 /* UIViewController+SimpleAuthAdditions.m */, - ); - name = Categories; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 3B658428188892FD00D59100 /* SimpleAuthDemo */ = { - isa = PBXNativeTarget; - buildConfigurationList = 3B658455188892FE00D59100 /* Build configuration list for PBXNativeTarget "SimpleAuthDemo" */; - buildPhases = ( - 3B658425188892FD00D59100 /* Sources */, - 3B658426188892FD00D59100 /* Frameworks */, - 3B658427188892FD00D59100 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 3B65845B1888947500D59100 /* PBXTargetDependency */, - ); - name = SimpleAuthDemo; - productName = SimpleAuthDemo; - productReference = 3B658429188892FD00D59100 /* SimpleAuthDemo.app */; - productType = "com.apple.product-type.application"; - }; - 3BB32503182ABC8B00ACB555 /* SimpleAuth */ = { - isa = PBXNativeTarget; - buildConfigurationList = 3BB32527182ABC8C00ACB555 /* Build configuration list for PBXNativeTarget "SimpleAuth" */; - buildPhases = ( - 5220918F16EE4E09993F918E /* Check Pods Manifest.lock */, - 3BB32500182ABC8B00ACB555 /* Sources */, - 681A563A05114C23AD83043F /* Frameworks */, - 7F931EDAAC5648DA9D804C83 /* Copy Pods Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = SimpleAuth; - productName = SimpleAuth; - productReference = 3BB32504182ABC8B00ACB555 /* libSimpleAuth.a */; - productType = "com.apple.product-type.library.static"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 3BB324FC182ABC8B00ACB555 /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 0500; - ORGANIZATIONNAME = "Seesaw Decisions Corporation"; - }; - buildConfigurationList = 3BB324FF182ABC8B00ACB555 /* Build configuration list for PBXProject "SimpleAuth" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - en, - ); - mainGroup = 3BB324FB182ABC8B00ACB555; - productRefGroup = 3BB32505182ABC8B00ACB555 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 3BB32503182ABC8B00ACB555 /* SimpleAuth */, - 3B658428188892FD00D59100 /* SimpleAuthDemo */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 3B658427188892FD00D59100 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 3B658435188892FE00D59100 /* InfoPlist.strings in Resources */, - 3B65843D188892FE00D59100 /* Images.xcassets in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 5220918F16EE4E09993F918E /* Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Check Pods Manifest.lock"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - 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"; - showEnvVarsInLog = 0; - }; - 7F931EDAAC5648DA9D804C83 /* Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Copy Pods Resources"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Pods-resources.sh\"\n"; - showEnvVarsInLog = 0; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 3B658425188892FD00D59100 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 3B6584581888931F00D59100 /* SADProviderListViewController.m in Sources */, - 3B658437188892FE00D59100 /* main.m in Sources */, - 3B65843B188892FE00D59100 /* SADAppDelegate.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 3BB32500182ABC8B00ACB555 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 3B8C408E188792A9007DC578 /* SimpleAuthTwitterWebProvider.m in Sources */, - 3B8C409118879347007DC578 /* SimpleAuthTwitterWebLoginViewController.m in Sources */, - 3B52BB9518871F6200C73329 /* SimpleAuthFacebookProvider.m in Sources */, - 3B9AB064182AC2710011FB9E /* SimpleAuthProvider.m in Sources */, - 3B52BB9B188731A300C73329 /* SimpleAuthInstagramLoginViewController.m in Sources */, - 3C0A5393182C4217002C050C /* SimpleAuthWebViewController.m in Sources */, - 3B9AB06E182ACCBB0011FB9E /* SimpleAuthSystemProvider.m in Sources */, - 3C611F48183535A400D87E45 /* UIViewController+SimpleAuthAdditions.m in Sources */, - 3B52BB911887088400C73329 /* SimpleAuthTwitterProvider.m in Sources */, - 3B52BB9C188731A300C73329 /* SimpleAuthInstagramProvider.m in Sources */, - 3C611F451835352200D87E45 /* UIWindow+SimpleAuthAdditions.m in Sources */, - 3BB3250F182ABC8B00ACB555 /* SimpleAuth.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 3B65845B1888947500D59100 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 3BB32503182ABC8B00ACB555 /* SimpleAuth */; - targetProxy = 3B65845A1888947500D59100 /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin PBXVariantGroup section */ - 3B658433188892FE00D59100 /* InfoPlist.strings */ = { - isa = PBXVariantGroup; - children = ( - 3B658434188892FE00D59100 /* en */, - ); - name = InfoPlist.strings; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 3B658451188892FE00D59100 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "SimpleAuthDemo/SimpleAuthDemo-Prefix.pch"; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - INFOPLIST_FILE = "SimpleAuthDemo/SimpleAuthDemo-Info.plist"; - OTHER_LDFLAGS = ( - "-ObjC", - "-all_load", - ); - PRODUCT_NAME = "$(TARGET_NAME)"; - WRAPPER_EXTENSION = app; - }; - name = Debug; - }; - 3B658452188892FE00D59100 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "SimpleAuthDemo/SimpleAuthDemo-Prefix.pch"; - INFOPLIST_FILE = "SimpleAuthDemo/SimpleAuthDemo-Info.plist"; - OTHER_LDFLAGS = ( - "-ObjC", - "-all_load", - ); - PRODUCT_NAME = "$(TARGET_NAME)"; - WRAPPER_EXTENSION = app; - }; - name = Release; - }; - 3BB32525182ABC8C00ACB555 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_SYMBOLS_PRIVATE_EXTERN = NO; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 7.0; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - }; - name = Debug; - }; - 3BB32526182ABC8C00ACB555 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = YES; - ENABLE_NS_ASSERTIONS = NO; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 7.0; - SDKROOT = iphoneos; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 3BB32528182ABC8C00ACB555 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 0FCEF85A832046CDB0CCBF25 /* Pods.xcconfig */; - buildSettings = { - DSTROOT = /tmp/SimpleAuth.dst; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "SimpleAuth/SimpleAuth-Prefix.pch"; - OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SKIP_INSTALL = YES; - }; - name = Debug; - }; - 3BB32529182ABC8C00ACB555 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 0FCEF85A832046CDB0CCBF25 /* Pods.xcconfig */; - buildSettings = { - DSTROOT = /tmp/SimpleAuth.dst; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "SimpleAuth/SimpleAuth-Prefix.pch"; - OTHER_LDFLAGS = "-ObjC"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SKIP_INSTALL = YES; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 3B658455188892FE00D59100 /* Build configuration list for PBXNativeTarget "SimpleAuthDemo" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 3B658451188892FE00D59100 /* Debug */, - 3B658452188892FE00D59100 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 3BB324FF182ABC8B00ACB555 /* Build configuration list for PBXProject "SimpleAuth" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 3BB32525182ABC8C00ACB555 /* Debug */, - 3BB32526182ABC8C00ACB555 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 3BB32527182ABC8C00ACB555 /* Build configuration list for PBXNativeTarget "SimpleAuth" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 3BB32528182ABC8C00ACB555 /* Debug */, - 3BB32529182ABC8C00ACB555 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 3BB324FC182ABC8B00ACB555 /* Project object */; -} diff --git a/SimpleAuth/SimpleAuth.h b/SimpleAuth/SimpleAuth.h deleted file mode 100644 index 5d2ad9b..0000000 --- a/SimpleAuth/SimpleAuth.h +++ /dev/null @@ -1,103 +0,0 @@ -// -// SimpleAuth.h -// SimpleAuth -// -// Created by Caleb Davenport on 11/6/13. -// Copyright (c) 2013 Seesaw Decisions Corporation. All rights reserved. -// - -extern NSString * const SimpleAuthErrorDomain; -extern NSInteger const SimpleAuthUserCancelledErrorCode; - -/** - Called when authorization either completes with a response or fails with an - error. Should an error occur, response object will be nil. - - @param responseObject The authorization response, or nil if an error occurred. - @param error An error. - - @see +authorize:completion: - @see +authorize:options:completion: - */ -typedef void (^SimpleAuthRequestHandler) (id responseObject, NSError *error); - -extern NSString * const SimpleAuthPresentInterfaceBlockKey; -extern NSString * const SimpleAuthDismissInterfaceBlockKey; - -/** - Called when a user interface element must be presented to continue - authorization. This could be a UIViewController for web login, or a - UIActionSheet for system login. All providers will have default - implementations for the appropriate callback types. You can customize provider - behavior by providing your own blocks. This will be called on the main - thread. - - @see SimpleAuthPresentInterfaceBlockKey - @see SimpleAuthDismissInterfaceBlockKey - @see +configuration - @see +authorize:options:completion: - - @param userInterfaceElement An element that is about to be presented or - dismissed. - */ -typedef void (^SimpleAuthInterfaceHandler) (id userInterfaceElement); - -/** - Key used to define the redirect URI for OAuth style providers. - - @see +configuration - @see +authorize:options:completion: - */ -extern NSString * const SimpleAuthRedirectURIKey; - -extern NSString * const SimpleAuthBeginActivityBlockKey; -extern NSString * const SimpleAuthEndActivityBlockKey; - -@interface SimpleAuth : NSObject - -/** - Set options used to configure each provider. Things like access tokens and - OAuth redirect URLs should be set here. Every provider should document the - options that it accepts. These options override a provider's default options, - and options passed to +authorize:options:completion: likewise override these. - - @return A mutable dictionary whose string keys correspond to provider types - and values are dictionaries that are passed on to a provider during an - authorization operation. - - @see +authorize:options:completion: - */ -+ (NSMutableDictionary *)configuration; - -/** - Register a class as a provider. Ideally, this would be a subclass of - SimpleAuthProvider but it doesn't necessarily have to be. Minimally, it must - have the same interface as the SimpleAuthProvider class. Multiple calls to - this with classes that return the same provider type will be ignored. - - @param klass The class to register. - */ -+ (void)registerProviderClass:(Class)klass; - -/** - Perform authorization with the given provider and all previously configured - and default provider options. - - @param completion Called on the main queue when the operation is complete. - - @see +authorize:options:completion: - */ -+ (void)authorize:(NSString *)provider completion:(SimpleAuthRequestHandler)completion; - -/** - Perform an authorization with the given provider. Options provided here will - be applied on top of any configured or default provider options. - - @param completion Called on the main queue when the operation is complete. - - @see +configuration - @see +authorize:completion: - */ -+ (void)authorize:(NSString *)provider options:(NSDictionary *)options completion:(SimpleAuthRequestHandler)completion; - -@end diff --git a/SimpleAuth/SimpleAuthSystemProvider.h b/SimpleAuth/SimpleAuthSystemProvider.h deleted file mode 100644 index e54fd78..0000000 --- a/SimpleAuth/SimpleAuthSystemProvider.h +++ /dev/null @@ -1,24 +0,0 @@ -// -// SimpleAuthSystemProvider.h -// SimpleAuth -// -// Created by Caleb Davenport on 11/6/13. -// Copyright (c) 2013 Seesaw Decisions Corporation. All rights reserved. -// - -#import "SimpleAuthProvider.h" - -@import Accounts; -@import Social; - -typedef void (^SimpleAuthSystemAccountHandler) (ACAccount *account, NSError *error); - -@interface SimpleAuthSystemProvider : SimpleAuthProvider - -+ (ACAccountStore *)accountStore; - -- (void)loadSystemAccount:(SimpleAuthSystemAccountHandler)completion; - -- (void)authorizeWithSystemAccount:(ACAccount *)account completion:(SimpleAuthRequestHandler)completion; - -@end diff --git a/SimpleAuth/SimpleAuthSystemProvider.m b/SimpleAuth/SimpleAuthSystemProvider.m deleted file mode 100644 index c85c013..0000000 --- a/SimpleAuth/SimpleAuthSystemProvider.m +++ /dev/null @@ -1,49 +0,0 @@ -// -// SimpleAuthSystemProvider.m -// SimpleAuth -// -// Created by Caleb Davenport on 11/6/13. -// Copyright (c) 2013 Seesaw Decisions Corporation. All rights reserved. -// - -#import "SimpleAuthSystemProvider.h" - -@import Accounts; - -@implementation SimpleAuthSystemProvider - -#pragma mark - SimpleAuthProvider - -- (void)authorizeWithCompletion:(SimpleAuthRequestHandler)completion { - [self loadSystemAccount:^(ACAccount *account, NSError *error) { - if (!account) { - completion(nil, error); - return; - } - [self authorizeWithSystemAccount:account completion:completion]; - }]; -} - - -#pragma mark - Public - -+ (ACAccountStore *)accountStore { - static dispatch_once_t token; - static ACAccountStore *store; - dispatch_once(&token, ^{ - store = [[ACAccountStore alloc] init]; - }); - return store; -} - - -- (void)loadSystemAccount:(SimpleAuthSystemAccountHandler)completion { - [self doesNotRecognizeSelector:_cmd]; -} - - -- (void)authorizeWithSystemAccount:(ACAccount *)account completion:(SimpleAuthRequestHandler)completion { - [self doesNotRecognizeSelector:_cmd]; -} - -@end diff --git a/SimpleAuth/SimpleAuthTwitterUtilities.h b/SimpleAuth/SimpleAuthTwitterUtilities.h deleted file mode 100644 index ed13c13..0000000 --- a/SimpleAuth/SimpleAuthTwitterUtilities.h +++ /dev/null @@ -1,13 +0,0 @@ -// -// SimpleAuthTwitterUtilities.h -// SimpleAuth -// -// Created by Caleb Davenport on 1/16/14. -// Copyright (c) 2014 Seesaw Decisions Corporation. All rights reserved. -// - -#import - -@interface SimpleAuthTwitterUtilities : NSObject - -@end diff --git a/SimpleAuth/SimpleAuthTwitterUtilities.m b/SimpleAuth/SimpleAuthTwitterUtilities.m deleted file mode 100644 index f021a4d..0000000 --- a/SimpleAuth/SimpleAuthTwitterUtilities.m +++ /dev/null @@ -1,13 +0,0 @@ -// -// SimpleAuthTwitterUtilities.m -// SimpleAuth -// -// Created by Caleb Davenport on 1/16/14. -// Copyright (c) 2014 Seesaw Decisions Corporation. All rights reserved. -// - -#import "SimpleAuthTwitterUtilities.h" - -@implementation SimpleAuthTwitterUtilities - -@end diff --git a/SimpleAuth/SimpleAuthWebViewController.h b/SimpleAuth/SimpleAuthWebViewController.h deleted file mode 100644 index b5e77b9..0000000 --- a/SimpleAuth/SimpleAuthWebViewController.h +++ /dev/null @@ -1,23 +0,0 @@ -// -// SimpleAuthWebViewController.h -// SimpleAuth -// -// Created by Caleb Davenport on 11/7/13. -// Copyright (c) 2013 Seesaw Decisions Corporation. All rights reserved. -// - -typedef void (^SimpleAuthWebViewControllerCompletionHandler) (UIViewController *controller, NSURL *URL, NSError *error); - -@interface SimpleAuthWebViewController : UIViewController - -@property (nonatomic, readonly) UIWebView *webView; -@property (nonatomic, readonly, copy) NSDictionary *options; -@property (nonatomic, copy) SimpleAuthWebViewControllerCompletionHandler completion; - -- (instancetype)initWithOptions:(NSDictionary *)options; - -- (BOOL)isTargetRedirectURL:(NSURL *)URL; - -- (void)dismiss; - -@end diff --git a/SimpleAuthDemo/Images.xcassets/AppIcon.appiconset/Contents.json b/SimpleAuthDemo/Images.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index a396706..0000000 --- a/SimpleAuthDemo/Images.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "images" : [ - { - "idiom" : "iphone", - "size" : "29x29", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "40x40", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "60x60", - "scale" : "2x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/SimpleAuthDemo/Images.xcassets/LaunchImage.launchimage/Contents.json b/SimpleAuthDemo/Images.xcassets/LaunchImage.launchimage/Contents.json deleted file mode 100644 index c79ebd3..0000000 --- a/SimpleAuthDemo/Images.xcassets/LaunchImage.launchimage/Contents.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "images" : [ - { - "orientation" : "portrait", - "idiom" : "iphone", - "extent" : "full-screen", - "minimum-system-version" : "7.0", - "scale" : "2x" - }, - { - "orientation" : "portrait", - "idiom" : "iphone", - "subtype" : "retina4", - "extent" : "full-screen", - "minimum-system-version" : "7.0", - "scale" : "2x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file