├── .gitignore ├── .swift-version ├── .swiftlint.yml ├── CONTRIBUTING.md ├── Cartfile ├── Cartfile.resolved ├── Example └── OhMyAuthDemo │ ├── OhMyAuthDemo.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata │ ├── OhMyAuthDemo.xcworkspace │ └── contents.xcworkspacedata │ ├── OhMyAuthDemo │ ├── Base.lproj │ │ └── LaunchScreen.storyboard │ ├── Info.plist │ ├── Resources │ │ └── Assets.xcassets │ │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ └── Sources │ │ ├── AppDelegate.swift │ │ └── ViewController.swift │ ├── Podfile │ └── Podfile.lock ├── LICENSE.md ├── OhMyAuth.podspec ├── OhMyAuth.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── xcshareddata │ └── xcschemes │ ├── OhMyAuth-Mac.xcscheme │ └── OhMyAuth-iOS.xcscheme ├── OhMyAuth ├── Info-Mac.plist └── Info-iOS.plist ├── OhMyAuthTests ├── Info-Mac.plist ├── Info-iOS.plist ├── LockerTests.swift ├── NetworkRequestableTests.swift └── ServiceTests.swift ├── README.md ├── Sources ├── Mac │ └── Mac.swift ├── Shared │ ├── AuthConfig.swift │ ├── AuthContainer.swift │ ├── AuthService.swift │ ├── Library │ │ ├── BrowserWebView.swift │ │ ├── Error.swift │ │ └── Result.swift │ ├── Locker │ │ ├── KeychainLocker.swift │ │ ├── Keys.swift │ │ ├── Lockable.swift │ │ ├── SuiteDefaultsLocker.swift │ │ └── UserDefaultsLocker.swift │ ├── Networking │ │ ├── NetworkRequests.swift │ │ ├── NetworkTasks.swift │ │ └── Networking.swift │ ├── Protocols │ │ ├── NetworkRequestable.swift │ │ ├── NetworkTaskable.swift │ │ └── WebViewable.swift │ └── Utils.swift └── iOS │ ├── SafariWebView.swift │ └── UIApplication+OhMyAuth.swift ├── bin ├── bootstrap └── bootstrap-if-needed └── circle.yml /.gitignore: -------------------------------------------------------------------------------- 1 | # OS X 2 | .DS_Store 3 | .AppleDouble 4 | .LSOverride 5 | Icon 6 | ._* 7 | .Spotlight-V100 8 | .Trashes 9 | 10 | # Xcode 11 | # 12 | build/ 13 | *.pbxuser 14 | !default.pbxuser 15 | *.mode1v3 16 | !default.mode1v3 17 | *.mode2v3 18 | !default.mode2v3 19 | *.perspectivev3 20 | !default.perspectivev3 21 | xcuserdata 22 | *.xccheckout 23 | *.moved-aside 24 | DerivedData 25 | *.hmap 26 | *.ipa 27 | *.xcuserstate 28 | 29 | # CocoaPods 30 | Pods 31 | 32 | # Carthage 33 | Carthage 34 | 35 | # SPM 36 | .build/ 37 | -------------------------------------------------------------------------------- /.swift-version: -------------------------------------------------------------------------------- 1 | 4.0 2 | -------------------------------------------------------------------------------- /.swiftlint.yml: -------------------------------------------------------------------------------- 1 | included: # paths to include during linting. `--path` is ignored if present. 2 | - Sources 3 | excluded: # paths to ignore during linting. Takes precedence over `included`. 4 | - Carthage 5 | - Pods 6 | disabled_rules: 7 | - type_name 8 | 9 | # configurable rules can be customized from this configuration file 10 | # binary rules can set their severity level 11 | force_cast: warning # implicitly 12 | force_try: 13 | severity: warning # explicitly 14 | # rules that have both warning and error levels, can set just the warning level 15 | # implicitly 16 | line_length: 200 17 | # they can set both implicitly with an array 18 | type_body_length: 19 | - 300 # warning 20 | - 400 # error 21 | # or they can set both explicitly 22 | file_length: 23 | warning: 500 24 | error: 1200 25 | # naming rules can set warnings/errors for min_length and max_length 26 | # additionally they can set excluded names 27 | type_name: 28 | min_length: 3 # only warning 29 | max_length: # warning and error 30 | warning: 40 31 | error: 50 32 | excluded: iPhone # excluded via string 33 | variable_name: 34 | min_length: # only min_length 35 | error: 2 # only error 36 | excluded: # excluded via string array 37 | - x 38 | - y 39 | - id 40 | - URL 41 | - GlobalAPIKey 42 | reporter: "xcode" # reporter type (xcode, json, csv, checkstyle) 43 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | GitHub Issues is for reporting bugs, discussing features and general feedback in **OhMyAuth**. Be sure to check our [documentation](http://cocoadocs.org/docsets/OhMyAuth), [FAQ](https://github.com/hyperoslo/OhMyAuth/wiki/FAQ) and [past issues](https://github.com/hyperoslo/OhMyAuth/issues?state=closed) before opening any new issues. 2 | 3 | If you are posting about a crash in your application, a stack trace is helpful, but additional context, in the form of code and explanation, is necessary to be of any use. 4 | -------------------------------------------------------------------------------- /Cartfile: -------------------------------------------------------------------------------- 1 | github "hyperoslo/Keychains" ~> 2.0 2 | github "auth0/JWTDecode.swift" ~> 2.0 3 | -------------------------------------------------------------------------------- /Cartfile.resolved: -------------------------------------------------------------------------------- 1 | github "auth0/JWTDecode.swift" "2.1.1" 2 | github "hyperoslo/Keychains" "2.0.0" 3 | -------------------------------------------------------------------------------- /Example/OhMyAuthDemo/OhMyAuthDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 37B6B38BA8CD858EA61616FA /* Pods_OhMyAuthDemo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D7F6F47DABBCBD65397EBF87 /* Pods_OhMyAuthDemo.framework */; }; 11 | D5ED739B1C64B82B003772EF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D5ED73931C64B82B003772EF /* LaunchScreen.storyboard */; }; 12 | D5ED739D1C64B82B003772EF /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D5ED73971C64B82B003772EF /* Assets.xcassets */; }; 13 | D5ED739E1C64B82B003772EF /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5ED73991C64B82B003772EF /* AppDelegate.swift */; }; 14 | D5ED739F1C64B82B003772EF /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5ED739A1C64B82B003772EF /* ViewController.swift */; }; 15 | /* End PBXBuildFile section */ 16 | 17 | /* Begin PBXFileReference section */ 18 | 23434E81791780719B85759A /* Pods-OhMyAuthDemo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OhMyAuthDemo.release.xcconfig"; path = "Pods/Target Support Files/Pods-OhMyAuthDemo/Pods-OhMyAuthDemo.release.xcconfig"; sourceTree = ""; }; 19 | ACED75C531255E80DE0146C9 /* Pods-OhMyAuthDemo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OhMyAuthDemo.debug.xcconfig"; path = "Pods/Target Support Files/Pods-OhMyAuthDemo/Pods-OhMyAuthDemo.debug.xcconfig"; sourceTree = ""; }; 20 | D0FD06562CFE3A8EE67E8372 /* Pods.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 21 | D5C7F7401C3BC9CE008CDDBA /* OhMyAuthDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = OhMyAuthDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 22 | D5ED73941C64B82B003772EF /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 23 | D5ED73951C64B82B003772EF /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 24 | D5ED73971C64B82B003772EF /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 25 | D5ED73991C64B82B003772EF /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 26 | D5ED739A1C64B82B003772EF /* ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 27 | D7F6F47DABBCBD65397EBF87 /* Pods_OhMyAuthDemo.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_OhMyAuthDemo.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 28 | /* End PBXFileReference section */ 29 | 30 | /* Begin PBXFrameworksBuildPhase section */ 31 | D5C7F73D1C3BC9CE008CDDBA /* Frameworks */ = { 32 | isa = PBXFrameworksBuildPhase; 33 | buildActionMask = 2147483647; 34 | files = ( 35 | 37B6B38BA8CD858EA61616FA /* Pods_OhMyAuthDemo.framework in Frameworks */, 36 | ); 37 | runOnlyForDeploymentPostprocessing = 0; 38 | }; 39 | /* End PBXFrameworksBuildPhase section */ 40 | 41 | /* Begin PBXGroup section */ 42 | A20DF62A54EB3D2C4543E8F2 /* Frameworks */ = { 43 | isa = PBXGroup; 44 | children = ( 45 | D0FD06562CFE3A8EE67E8372 /* Pods.framework */, 46 | D7F6F47DABBCBD65397EBF87 /* Pods_OhMyAuthDemo.framework */, 47 | ); 48 | name = Frameworks; 49 | sourceTree = ""; 50 | }; 51 | C5778A46BE86F79C3770C401 /* Pods */ = { 52 | isa = PBXGroup; 53 | children = ( 54 | ACED75C531255E80DE0146C9 /* Pods-OhMyAuthDemo.debug.xcconfig */, 55 | 23434E81791780719B85759A /* Pods-OhMyAuthDemo.release.xcconfig */, 56 | ); 57 | name = Pods; 58 | sourceTree = ""; 59 | }; 60 | D5C7F7371C3BC9CE008CDDBA = { 61 | isa = PBXGroup; 62 | children = ( 63 | D5ED73921C64B82B003772EF /* OhMyAuthDemo */, 64 | D5C7F7411C3BC9CE008CDDBA /* Products */, 65 | A20DF62A54EB3D2C4543E8F2 /* Frameworks */, 66 | C5778A46BE86F79C3770C401 /* Pods */, 67 | ); 68 | sourceTree = ""; 69 | }; 70 | D5C7F7411C3BC9CE008CDDBA /* Products */ = { 71 | isa = PBXGroup; 72 | children = ( 73 | D5C7F7401C3BC9CE008CDDBA /* OhMyAuthDemo.app */, 74 | ); 75 | name = Products; 76 | sourceTree = ""; 77 | }; 78 | D5ED73921C64B82B003772EF /* OhMyAuthDemo */ = { 79 | isa = PBXGroup; 80 | children = ( 81 | D5ED73931C64B82B003772EF /* LaunchScreen.storyboard */, 82 | D5ED73951C64B82B003772EF /* Info.plist */, 83 | D5ED73961C64B82B003772EF /* Resources */, 84 | D5ED73981C64B82B003772EF /* Sources */, 85 | ); 86 | path = OhMyAuthDemo; 87 | sourceTree = ""; 88 | }; 89 | D5ED73961C64B82B003772EF /* Resources */ = { 90 | isa = PBXGroup; 91 | children = ( 92 | D5ED73971C64B82B003772EF /* Assets.xcassets */, 93 | ); 94 | path = Resources; 95 | sourceTree = ""; 96 | }; 97 | D5ED73981C64B82B003772EF /* Sources */ = { 98 | isa = PBXGroup; 99 | children = ( 100 | D5ED73991C64B82B003772EF /* AppDelegate.swift */, 101 | D5ED739A1C64B82B003772EF /* ViewController.swift */, 102 | ); 103 | path = Sources; 104 | sourceTree = ""; 105 | }; 106 | /* End PBXGroup section */ 107 | 108 | /* Begin PBXNativeTarget section */ 109 | D5C7F73F1C3BC9CE008CDDBA /* OhMyAuthDemo */ = { 110 | isa = PBXNativeTarget; 111 | buildConfigurationList = D5C7F7521C3BC9CE008CDDBA /* Build configuration list for PBXNativeTarget "OhMyAuthDemo" */; 112 | buildPhases = ( 113 | 80ED7AD7213D26F81A472768 /* [CP] Check Pods Manifest.lock */, 114 | D5C7F73C1C3BC9CE008CDDBA /* Sources */, 115 | D5C7F73D1C3BC9CE008CDDBA /* Frameworks */, 116 | D5C7F73E1C3BC9CE008CDDBA /* Resources */, 117 | E81402D4C73B0395FCB08142 /* [CP] Embed Pods Frameworks */, 118 | 6F431A4B96DC7A966075E08C /* [CP] Copy Pods Resources */, 119 | ); 120 | buildRules = ( 121 | ); 122 | dependencies = ( 123 | ); 124 | name = OhMyAuthDemo; 125 | productName = OhMyAuthDemo; 126 | productReference = D5C7F7401C3BC9CE008CDDBA /* OhMyAuthDemo.app */; 127 | productType = "com.apple.product-type.application"; 128 | }; 129 | /* End PBXNativeTarget section */ 130 | 131 | /* Begin PBXProject section */ 132 | D5C7F7381C3BC9CE008CDDBA /* Project object */ = { 133 | isa = PBXProject; 134 | attributes = { 135 | LastSwiftUpdateCheck = 0720; 136 | LastUpgradeCheck = 0720; 137 | ORGANIZATIONNAME = "Hyper Interaktiv AS"; 138 | TargetAttributes = { 139 | D5C7F73F1C3BC9CE008CDDBA = { 140 | CreatedOnToolsVersion = 7.2; 141 | LastSwiftMigration = 0800; 142 | }; 143 | }; 144 | }; 145 | buildConfigurationList = D5C7F73B1C3BC9CE008CDDBA /* Build configuration list for PBXProject "OhMyAuthDemo" */; 146 | compatibilityVersion = "Xcode 3.2"; 147 | developmentRegion = English; 148 | hasScannedForEncodings = 0; 149 | knownRegions = ( 150 | en, 151 | Base, 152 | ); 153 | mainGroup = D5C7F7371C3BC9CE008CDDBA; 154 | productRefGroup = D5C7F7411C3BC9CE008CDDBA /* Products */; 155 | projectDirPath = ""; 156 | projectRoot = ""; 157 | targets = ( 158 | D5C7F73F1C3BC9CE008CDDBA /* OhMyAuthDemo */, 159 | ); 160 | }; 161 | /* End PBXProject section */ 162 | 163 | /* Begin PBXResourcesBuildPhase section */ 164 | D5C7F73E1C3BC9CE008CDDBA /* Resources */ = { 165 | isa = PBXResourcesBuildPhase; 166 | buildActionMask = 2147483647; 167 | files = ( 168 | D5ED739D1C64B82B003772EF /* Assets.xcassets in Resources */, 169 | D5ED739B1C64B82B003772EF /* LaunchScreen.storyboard in Resources */, 170 | ); 171 | runOnlyForDeploymentPostprocessing = 0; 172 | }; 173 | /* End PBXResourcesBuildPhase section */ 174 | 175 | /* Begin PBXShellScriptBuildPhase section */ 176 | 6F431A4B96DC7A966075E08C /* [CP] Copy Pods Resources */ = { 177 | isa = PBXShellScriptBuildPhase; 178 | buildActionMask = 2147483647; 179 | files = ( 180 | ); 181 | inputPaths = ( 182 | ); 183 | name = "[CP] Copy Pods Resources"; 184 | outputPaths = ( 185 | ); 186 | runOnlyForDeploymentPostprocessing = 0; 187 | shellPath = /bin/sh; 188 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-OhMyAuthDemo/Pods-OhMyAuthDemo-resources.sh\"\n"; 189 | showEnvVarsInLog = 0; 190 | }; 191 | 80ED7AD7213D26F81A472768 /* [CP] Check Pods Manifest.lock */ = { 192 | isa = PBXShellScriptBuildPhase; 193 | buildActionMask = 2147483647; 194 | files = ( 195 | ); 196 | inputPaths = ( 197 | ); 198 | name = "[CP] Check Pods Manifest.lock"; 199 | outputPaths = ( 200 | ); 201 | runOnlyForDeploymentPostprocessing = 0; 202 | shellPath = /bin/sh; 203 | shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; 204 | showEnvVarsInLog = 0; 205 | }; 206 | E81402D4C73B0395FCB08142 /* [CP] Embed Pods Frameworks */ = { 207 | isa = PBXShellScriptBuildPhase; 208 | buildActionMask = 2147483647; 209 | files = ( 210 | ); 211 | inputPaths = ( 212 | ); 213 | name = "[CP] Embed Pods Frameworks"; 214 | outputPaths = ( 215 | ); 216 | runOnlyForDeploymentPostprocessing = 0; 217 | shellPath = /bin/sh; 218 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-OhMyAuthDemo/Pods-OhMyAuthDemo-frameworks.sh\"\n"; 219 | showEnvVarsInLog = 0; 220 | }; 221 | /* End PBXShellScriptBuildPhase section */ 222 | 223 | /* Begin PBXSourcesBuildPhase section */ 224 | D5C7F73C1C3BC9CE008CDDBA /* Sources */ = { 225 | isa = PBXSourcesBuildPhase; 226 | buildActionMask = 2147483647; 227 | files = ( 228 | D5ED739F1C64B82B003772EF /* ViewController.swift in Sources */, 229 | D5ED739E1C64B82B003772EF /* AppDelegate.swift in Sources */, 230 | ); 231 | runOnlyForDeploymentPostprocessing = 0; 232 | }; 233 | /* End PBXSourcesBuildPhase section */ 234 | 235 | /* Begin PBXVariantGroup section */ 236 | D5ED73931C64B82B003772EF /* LaunchScreen.storyboard */ = { 237 | isa = PBXVariantGroup; 238 | children = ( 239 | D5ED73941C64B82B003772EF /* Base */, 240 | ); 241 | name = LaunchScreen.storyboard; 242 | sourceTree = ""; 243 | }; 244 | /* End PBXVariantGroup section */ 245 | 246 | /* Begin XCBuildConfiguration section */ 247 | D5C7F7501C3BC9CE008CDDBA /* Debug */ = { 248 | isa = XCBuildConfiguration; 249 | buildSettings = { 250 | ALWAYS_SEARCH_USER_PATHS = NO; 251 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 252 | CLANG_CXX_LIBRARY = "libc++"; 253 | CLANG_ENABLE_MODULES = YES; 254 | CLANG_ENABLE_OBJC_ARC = YES; 255 | CLANG_WARN_BOOL_CONVERSION = YES; 256 | CLANG_WARN_CONSTANT_CONVERSION = YES; 257 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 258 | CLANG_WARN_EMPTY_BODY = YES; 259 | CLANG_WARN_ENUM_CONVERSION = YES; 260 | CLANG_WARN_INT_CONVERSION = YES; 261 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 262 | CLANG_WARN_UNREACHABLE_CODE = YES; 263 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 264 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 265 | COPY_PHASE_STRIP = NO; 266 | DEBUG_INFORMATION_FORMAT = dwarf; 267 | ENABLE_STRICT_OBJC_MSGSEND = YES; 268 | ENABLE_TESTABILITY = YES; 269 | GCC_C_LANGUAGE_STANDARD = gnu99; 270 | GCC_DYNAMIC_NO_PIC = NO; 271 | GCC_NO_COMMON_BLOCKS = YES; 272 | GCC_OPTIMIZATION_LEVEL = 0; 273 | GCC_PREPROCESSOR_DEFINITIONS = ( 274 | "DEBUG=1", 275 | "$(inherited)", 276 | ); 277 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 278 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 279 | GCC_WARN_UNDECLARED_SELECTOR = YES; 280 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 281 | GCC_WARN_UNUSED_FUNCTION = YES; 282 | GCC_WARN_UNUSED_VARIABLE = YES; 283 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 284 | MTL_ENABLE_DEBUG_INFO = YES; 285 | ONLY_ACTIVE_ARCH = YES; 286 | SDKROOT = iphoneos; 287 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 288 | }; 289 | name = Debug; 290 | }; 291 | D5C7F7511C3BC9CE008CDDBA /* Release */ = { 292 | isa = XCBuildConfiguration; 293 | buildSettings = { 294 | ALWAYS_SEARCH_USER_PATHS = NO; 295 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 296 | CLANG_CXX_LIBRARY = "libc++"; 297 | CLANG_ENABLE_MODULES = YES; 298 | CLANG_ENABLE_OBJC_ARC = YES; 299 | CLANG_WARN_BOOL_CONVERSION = YES; 300 | CLANG_WARN_CONSTANT_CONVERSION = YES; 301 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 302 | CLANG_WARN_EMPTY_BODY = YES; 303 | CLANG_WARN_ENUM_CONVERSION = YES; 304 | CLANG_WARN_INT_CONVERSION = YES; 305 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 306 | CLANG_WARN_UNREACHABLE_CODE = YES; 307 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 308 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 309 | COPY_PHASE_STRIP = NO; 310 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 311 | ENABLE_NS_ASSERTIONS = NO; 312 | ENABLE_STRICT_OBJC_MSGSEND = YES; 313 | GCC_C_LANGUAGE_STANDARD = gnu99; 314 | GCC_NO_COMMON_BLOCKS = YES; 315 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 316 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 317 | GCC_WARN_UNDECLARED_SELECTOR = YES; 318 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 319 | GCC_WARN_UNUSED_FUNCTION = YES; 320 | GCC_WARN_UNUSED_VARIABLE = YES; 321 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 322 | MTL_ENABLE_DEBUG_INFO = NO; 323 | SDKROOT = iphoneos; 324 | VALIDATE_PRODUCT = YES; 325 | }; 326 | name = Release; 327 | }; 328 | D5C7F7531C3BC9CE008CDDBA /* Debug */ = { 329 | isa = XCBuildConfiguration; 330 | baseConfigurationReference = ACED75C531255E80DE0146C9 /* Pods-OhMyAuthDemo.debug.xcconfig */; 331 | buildSettings = { 332 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 333 | INFOPLIST_FILE = OhMyAuthDemo/Info.plist; 334 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 335 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 336 | PRODUCT_BUNDLE_IDENTIFIER = no.hyper.OhMyAuthDemo; 337 | PRODUCT_NAME = OhMyAuthDemo; 338 | SWIFT_VERSION = 3.0; 339 | }; 340 | name = Debug; 341 | }; 342 | D5C7F7541C3BC9CE008CDDBA /* Release */ = { 343 | isa = XCBuildConfiguration; 344 | baseConfigurationReference = 23434E81791780719B85759A /* Pods-OhMyAuthDemo.release.xcconfig */; 345 | buildSettings = { 346 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 347 | INFOPLIST_FILE = OhMyAuthDemo/Info.plist; 348 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 349 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 350 | PRODUCT_BUNDLE_IDENTIFIER = no.hyper.OhMyAuthDemo; 351 | PRODUCT_NAME = OhMyAuthDemo; 352 | SWIFT_VERSION = 3.0; 353 | }; 354 | name = Release; 355 | }; 356 | /* End XCBuildConfiguration section */ 357 | 358 | /* Begin XCConfigurationList section */ 359 | D5C7F73B1C3BC9CE008CDDBA /* Build configuration list for PBXProject "OhMyAuthDemo" */ = { 360 | isa = XCConfigurationList; 361 | buildConfigurations = ( 362 | D5C7F7501C3BC9CE008CDDBA /* Debug */, 363 | D5C7F7511C3BC9CE008CDDBA /* Release */, 364 | ); 365 | defaultConfigurationIsVisible = 0; 366 | defaultConfigurationName = Release; 367 | }; 368 | D5C7F7521C3BC9CE008CDDBA /* Build configuration list for PBXNativeTarget "OhMyAuthDemo" */ = { 369 | isa = XCConfigurationList; 370 | buildConfigurations = ( 371 | D5C7F7531C3BC9CE008CDDBA /* Debug */, 372 | D5C7F7541C3BC9CE008CDDBA /* Release */, 373 | ); 374 | defaultConfigurationIsVisible = 0; 375 | defaultConfigurationName = Release; 376 | }; 377 | /* End XCConfigurationList section */ 378 | }; 379 | rootObject = D5C7F7381C3BC9CE008CDDBA /* Project object */; 380 | } 381 | -------------------------------------------------------------------------------- /Example/OhMyAuthDemo/OhMyAuthDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example/OhMyAuthDemo/OhMyAuthDemo.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Example/OhMyAuthDemo/OhMyAuthDemo/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Example/OhMyAuthDemo/OhMyAuthDemo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /Example/OhMyAuthDemo/OhMyAuthDemo/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Example/OhMyAuthDemo/OhMyAuthDemo/Sources/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import OhMyAuth 3 | 4 | @UIApplicationMain 5 | class AppDelegate: UIResponder, UIApplicationDelegate { 6 | 7 | var window: UIWindow? 8 | 9 | lazy var navigationController: UINavigationController = { [unowned self] in 10 | let controller = UINavigationController(rootViewController: self.viewController) 11 | return controller 12 | }() 13 | 14 | lazy var viewController: ViewController = { 15 | let controller = ViewController() 16 | return controller 17 | }() 18 | 19 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 20 | window = UIWindow(frame: UIScreen.main.bounds) 21 | window?.rootViewController = navigationController 22 | window?.makeKeyAndVisible() 23 | 24 | return true 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Example/OhMyAuthDemo/OhMyAuthDemo/Sources/ViewController.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import OhMyAuth 3 | 4 | class ViewController: UIViewController { 5 | 6 | override func viewDidLoad() { 7 | super.viewDidLoad() 8 | view.backgroundColor = UIColor.white 9 | } 10 | } 11 | 12 | -------------------------------------------------------------------------------- /Example/OhMyAuthDemo/Podfile: -------------------------------------------------------------------------------- 1 | use_frameworks! 2 | 3 | platform :ios, '9.0' 4 | 5 | target 'OhMyAuthDemo' do 6 | pod 'OhMyAuth', path: '../../' 7 | pod 'Keychain', git: 'https://github.com/hyperoslo/Keychain', branch: 'swift-3' 8 | end 9 | 10 | 11 | -------------------------------------------------------------------------------- /Example/OhMyAuthDemo/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Alamofire (4.0.1) 3 | - JWTDecode (2.0.0) 4 | - Keychain (1.0.0) 5 | - OhMyAuth (0.2.0): 6 | - Alamofire 7 | - JWTDecode 8 | - Keychain 9 | - Sugar 10 | - Sugar (2.0.0) 11 | 12 | DEPENDENCIES: 13 | - Keychain (from `https://github.com/hyperoslo/Keychain`, branch `swift-3`) 14 | - OhMyAuth (from `../../`) 15 | 16 | EXTERNAL SOURCES: 17 | Keychain: 18 | :branch: swift-3 19 | :git: https://github.com/hyperoslo/Keychain 20 | OhMyAuth: 21 | :path: "../../" 22 | 23 | CHECKOUT OPTIONS: 24 | Keychain: 25 | :commit: aba620997062a2082a9d1a57fb5c81e4e0fe79df 26 | :git: https://github.com/hyperoslo/Keychain 27 | 28 | SPEC CHECKSUMS: 29 | Alamofire: 7682d43245de14874acd142ec137b144aa1dd335 30 | JWTDecode: 178e47e5d28d3abcff778bacced8342858cd6cb5 31 | Keychain: b82fa1a6c20666b74014e7549f53bae6c75d617f 32 | OhMyAuth: e10e5ab7a2a3d77c8e056b0d2aa495b9cefec19c 33 | Sugar: f45b46cae3d198222a042b9ecf1ce3d44ab8e764 34 | 35 | PODFILE CHECKSUM: 7f8782da16423e699fffc2709c9ad698a0408f64 36 | 37 | COCOAPODS: 1.1.0.rc.3 38 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Licensed under the **MIT** license 2 | 3 | > Copyright (c) 2015 Hyper Interaktiv AS 4 | > 5 | > Permission is hereby granted, free of charge, to any person obtaining 6 | > a copy of this software and associated documentation files (the 7 | > "Software"), to deal in the Software without restriction, including 8 | > without limitation the rights to use, copy, modify, merge, publish, 9 | > distribute, sublicense, and/or sell copies of the Software, and to 10 | > permit persons to whom the Software is furnished to do so, subject to 11 | > the following conditions: 12 | > 13 | > The above copyright notice and this permission notice shall be 14 | > included in all copies or substantial portions of the Software. 15 | > 16 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | > EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | > MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | > IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | > CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | > TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | > SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /OhMyAuth.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "OhMyAuth" 3 | s.summary = "Simple OAuth2 library with a support of multiple services." 4 | s.version = "2.0.0" 5 | s.homepage = "https://github.com/hyperoslo/OhMyAuth" 6 | s.license = 'MIT' 7 | s.author = { "Hyper Interaktiv AS" => "ios@hyper.no" } 8 | s.source = { 9 | :git => "https://github.com/hyperoslo/OhMyAuth.git", 10 | :tag => s.version.to_s 11 | } 12 | s.social_media_url = 'https://twitter.com/hyperoslo' 13 | 14 | s.ios.deployment_target = '9.0' 15 | s.osx.deployment_target = '10.11' 16 | 17 | s.requires_arc = true 18 | s.ios.source_files = 'Sources/{iOS,Shared}/**/*' 19 | s.osx.source_files = 'Sources/{Mac,Shared}/**/*' 20 | 21 | s.ios.frameworks = 'UIKit', 'Foundation' 22 | s.osx.frameworks = 'Cocoa', 'Foundation' 23 | 24 | s.dependency 'Keychains', '~> 2.0' 25 | s.dependency 'JWTDecode', '~> 2.0' 26 | 27 | s.pod_target_xcconfig = { 'SWIFT_VERSION' => '4.0' } 28 | end 29 | -------------------------------------------------------------------------------- /OhMyAuth.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 5255FEBC1FB457FA004D012B /* NetworkRequestableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5255FEBB1FB457FA004D012B /* NetworkRequestableTests.swift */; }; 11 | 5255FEBD1FB457FA004D012B /* NetworkRequestableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5255FEBB1FB457FA004D012B /* NetworkRequestableTests.swift */; }; 12 | 922A1E591DC28A680088A7E7 /* Networking.swift in Sources */ = {isa = PBXBuildFile; fileRef = 922A1E581DC28A680088A7E7 /* Networking.swift */; }; 13 | 922A1E5A1DC28A680088A7E7 /* Networking.swift in Sources */ = {isa = PBXBuildFile; fileRef = 922A1E581DC28A680088A7E7 /* Networking.swift */; }; 14 | 923CA22C1DC144290016B791 /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 923CA22B1DC144290016B791 /* Utils.swift */; }; 15 | 923CA22D1DC144290016B791 /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 923CA22B1DC144290016B791 /* Utils.swift */; }; 16 | D20836171EF7D0A8004ED8E0 /* Keychains.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D20836161EF7D0A8004ED8E0 /* Keychains.framework */; }; 17 | D20836181EF7D0FB004ED8E0 /* JWTDecode.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D59575EA1C641F14000CD22B /* JWTDecode.framework */; }; 18 | D208361A1EF7D0FB004ED8E0 /* Keychains.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D20836191EF7D0FB004ED8E0 /* Keychains.framework */; }; 19 | D20A12A51E769648000DB14C /* ServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20A12A41E769648000DB14C /* ServiceTests.swift */; }; 20 | D20A12A61E769648000DB14C /* ServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20A12A41E769648000DB14C /* ServiceTests.swift */; }; 21 | D20D5C441DEEF474000CEAAB /* KeychainLocker.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20D5C401DEEF474000CEAAB /* KeychainLocker.swift */; }; 22 | D20D5C451DEEF474000CEAAB /* KeychainLocker.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20D5C401DEEF474000CEAAB /* KeychainLocker.swift */; }; 23 | D20D5C461DEEF474000CEAAB /* Lockable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20D5C411DEEF474000CEAAB /* Lockable.swift */; }; 24 | D20D5C471DEEF474000CEAAB /* Lockable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20D5C411DEEF474000CEAAB /* Lockable.swift */; }; 25 | D20D5C481DEEF474000CEAAB /* SuiteDefaultsLocker.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20D5C421DEEF474000CEAAB /* SuiteDefaultsLocker.swift */; }; 26 | D20D5C491DEEF474000CEAAB /* SuiteDefaultsLocker.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20D5C421DEEF474000CEAAB /* SuiteDefaultsLocker.swift */; }; 27 | D20D5C4A1DEEF474000CEAAB /* UserDefaultsLocker.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20D5C431DEEF474000CEAAB /* UserDefaultsLocker.swift */; }; 28 | D20D5C4B1DEEF474000CEAAB /* UserDefaultsLocker.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20D5C431DEEF474000CEAAB /* UserDefaultsLocker.swift */; }; 29 | D20D5C4D1DEEF4AE000CEAAB /* Keys.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20D5C4C1DEEF4AE000CEAAB /* Keys.swift */; }; 30 | D20D5C4E1DEEF4AE000CEAAB /* Keys.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20D5C4C1DEEF4AE000CEAAB /* Keys.swift */; }; 31 | D2DD2AB41DEEFF2900AFF5BA /* LockerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2DD2AB31DEEFF2900AFF5BA /* LockerTests.swift */; }; 32 | D2DD2AB51DEEFF2900AFF5BA /* LockerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2DD2AB31DEEFF2900AFF5BA /* LockerTests.swift */; }; 33 | D51D955D1C6252DD00D78EF3 /* AuthConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = D51D955C1C6252DD00D78EF3 /* AuthConfig.swift */; }; 34 | D51D95621C62536E00D78EF3 /* AuthContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D51D95611C62536E00D78EF3 /* AuthContainer.swift */; }; 35 | D51D95651C6253B200D78EF3 /* NetworkRequests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D51D95641C6253B200D78EF3 /* NetworkRequests.swift */; }; 36 | D51D956E1C62B82400D78EF3 /* NetworkRequests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D51D95641C6253B200D78EF3 /* NetworkRequests.swift */; }; 37 | D51D95701C62B82400D78EF3 /* AuthConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = D51D955C1C6252DD00D78EF3 /* AuthConfig.swift */; }; 38 | D51D95721C62B82400D78EF3 /* AuthContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D51D95611C62536E00D78EF3 /* AuthContainer.swift */; }; 39 | D51D95751C62BAF000D78EF3 /* NetworkTasks.swift in Sources */ = {isa = PBXBuildFile; fileRef = D51D95741C62BAF000D78EF3 /* NetworkTasks.swift */; }; 40 | D51D95761C62BAF000D78EF3 /* NetworkTasks.swift in Sources */ = {isa = PBXBuildFile; fileRef = D51D95741C62BAF000D78EF3 /* NetworkTasks.swift */; }; 41 | D529C2CD1C620B1900B6FA6B /* JWTDecode.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D529C2C91C620B1900B6FA6B /* JWTDecode.framework */; }; 42 | D595759F1C63538B000CD22B /* Result.swift in Sources */ = {isa = PBXBuildFile; fileRef = D595759E1C63538B000CD22B /* Result.swift */; }; 43 | D59575A71C63558D000CD22B /* Error.swift in Sources */ = {isa = PBXBuildFile; fileRef = D59575A61C63558D000CD22B /* Error.swift */; }; 44 | D59575A81C63558D000CD22B /* Error.swift in Sources */ = {isa = PBXBuildFile; fileRef = D59575A61C63558D000CD22B /* Error.swift */; }; 45 | D59575AB1C63CF3C000CD22B /* AuthService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D59575AA1C63CF3C000CD22B /* AuthService.swift */; }; 46 | D59575AC1C63CF3C000CD22B /* AuthService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D59575AA1C63CF3C000CD22B /* AuthService.swift */; }; 47 | D59575CD1C640C0A000CD22B /* SafariWebView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D59575CC1C640C0A000CD22B /* SafariWebView.swift */; }; 48 | D59575D21C640E4C000CD22B /* BrowserWebView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D59575D11C640E4C000CD22B /* BrowserWebView.swift */; }; 49 | D59575D31C640E50000CD22B /* BrowserWebView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D59575D11C640E4C000CD22B /* BrowserWebView.swift */; }; 50 | D59575DB1C641DBF000CD22B /* UIApplication+OhMyAuth.swift in Sources */ = {isa = PBXBuildFile; fileRef = D59575DA1C641DBF000CD22B /* UIApplication+OhMyAuth.swift */; }; 51 | D59575E11C641E3D000CD22B /* NetworkRequestable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D59575DE1C641E3D000CD22B /* NetworkRequestable.swift */; }; 52 | D59575E21C641E3D000CD22B /* NetworkTaskable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D59575DF1C641E3D000CD22B /* NetworkTaskable.swift */; }; 53 | D59575E31C641E3D000CD22B /* WebViewable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D59575E01C641E3D000CD22B /* WebViewable.swift */; }; 54 | D59575E41C641E4C000CD22B /* NetworkRequestable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D59575DE1C641E3D000CD22B /* NetworkRequestable.swift */; }; 55 | D59575E51C641E4C000CD22B /* NetworkTaskable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D59575DF1C641E3D000CD22B /* NetworkTaskable.swift */; }; 56 | D59575E61C641E4C000CD22B /* WebViewable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D59575E01C641E3D000CD22B /* WebViewable.swift */; }; 57 | D59575E71C641E4C000CD22B /* Result.swift in Sources */ = {isa = PBXBuildFile; fileRef = D595759E1C63538B000CD22B /* Result.swift */; }; 58 | D5B2E8AA1C3A780C00C0327D /* OhMyAuth.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D5B2E89F1C3A780C00C0327D /* OhMyAuth.framework */; }; 59 | D5C6294A1C3A7FAA007F7B7C /* OhMyAuth.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D5C629401C3A7FAA007F7B7C /* OhMyAuth.framework */; }; 60 | D5C629851C3A893F007F7B7C /* Mac.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5C629841C3A893F007F7B7C /* Mac.swift */; }; 61 | /* End PBXBuildFile section */ 62 | 63 | /* Begin PBXContainerItemProxy section */ 64 | D5B2E8AB1C3A780C00C0327D /* PBXContainerItemProxy */ = { 65 | isa = PBXContainerItemProxy; 66 | containerPortal = D5B2E8961C3A780C00C0327D /* Project object */; 67 | proxyType = 1; 68 | remoteGlobalIDString = D5B2E89E1C3A780C00C0327D; 69 | remoteInfo = OhMyAuth; 70 | }; 71 | D5C6294B1C3A7FAA007F7B7C /* PBXContainerItemProxy */ = { 72 | isa = PBXContainerItemProxy; 73 | containerPortal = D5B2E8961C3A780C00C0327D /* Project object */; 74 | proxyType = 1; 75 | remoteGlobalIDString = D5C6293F1C3A7FAA007F7B7C; 76 | remoteInfo = "OhMyAuth-Mac"; 77 | }; 78 | /* End PBXContainerItemProxy section */ 79 | 80 | /* Begin PBXFileReference section */ 81 | 5255FEBB1FB457FA004D012B /* NetworkRequestableTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkRequestableTests.swift; sourceTree = ""; }; 82 | 922A1E581DC28A680088A7E7 /* Networking.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Networking.swift; sourceTree = ""; }; 83 | 923CA22B1DC144290016B791 /* Utils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Utils.swift; sourceTree = ""; }; 84 | D20836161EF7D0A8004ED8E0 /* Keychains.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Keychains.framework; path = Carthage/Build/iOS/Keychains.framework; sourceTree = ""; }; 85 | D20836191EF7D0FB004ED8E0 /* Keychains.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Keychains.framework; path = Carthage/Build/Mac/Keychains.framework; sourceTree = ""; }; 86 | D20A12A41E769648000DB14C /* ServiceTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ServiceTests.swift; sourceTree = ""; }; 87 | D20D5C401DEEF474000CEAAB /* KeychainLocker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeychainLocker.swift; sourceTree = ""; }; 88 | D20D5C411DEEF474000CEAAB /* Lockable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Lockable.swift; sourceTree = ""; }; 89 | D20D5C421DEEF474000CEAAB /* SuiteDefaultsLocker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SuiteDefaultsLocker.swift; sourceTree = ""; }; 90 | D20D5C431DEEF474000CEAAB /* UserDefaultsLocker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserDefaultsLocker.swift; sourceTree = ""; }; 91 | D20D5C4C1DEEF4AE000CEAAB /* Keys.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Keys.swift; sourceTree = ""; }; 92 | D2DD2AB31DEEFF2900AFF5BA /* LockerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LockerTests.swift; sourceTree = ""; }; 93 | D51D955C1C6252DD00D78EF3 /* AuthConfig.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthConfig.swift; sourceTree = ""; }; 94 | D51D95611C62536E00D78EF3 /* AuthContainer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthContainer.swift; sourceTree = ""; }; 95 | D51D95641C6253B200D78EF3 /* NetworkRequests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkRequests.swift; sourceTree = ""; }; 96 | D51D95741C62BAF000D78EF3 /* NetworkTasks.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkTasks.swift; sourceTree = ""; }; 97 | D529C2C91C620B1900B6FA6B /* JWTDecode.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JWTDecode.framework; path = Carthage/Build/iOS/JWTDecode.framework; sourceTree = ""; }; 98 | D529C2CA1C620B1900B6FA6B /* Keychain.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Keychain.framework; path = Carthage/Build/iOS/Keychain.framework; sourceTree = ""; }; 99 | D595759E1C63538B000CD22B /* Result.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Result.swift; sourceTree = ""; }; 100 | D59575A61C63558D000CD22B /* Error.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Error.swift; sourceTree = ""; }; 101 | D59575AA1C63CF3C000CD22B /* AuthService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthService.swift; sourceTree = ""; }; 102 | D59575CC1C640C0A000CD22B /* SafariWebView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SafariWebView.swift; sourceTree = ""; }; 103 | D59575D11C640E4C000CD22B /* BrowserWebView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BrowserWebView.swift; sourceTree = ""; }; 104 | D59575DA1C641DBF000CD22B /* UIApplication+OhMyAuth.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIApplication+OhMyAuth.swift"; sourceTree = ""; }; 105 | D59575DE1C641E3D000CD22B /* NetworkRequestable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkRequestable.swift; sourceTree = ""; }; 106 | D59575DF1C641E3D000CD22B /* NetworkTaskable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkTaskable.swift; sourceTree = ""; }; 107 | D59575E01C641E3D000CD22B /* WebViewable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebViewable.swift; sourceTree = ""; }; 108 | D59575E91C641F14000CD22B /* Alamofire.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Alamofire.framework; path = Carthage/Build/Mac/Alamofire.framework; sourceTree = ""; }; 109 | D59575EA1C641F14000CD22B /* JWTDecode.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JWTDecode.framework; path = Carthage/Build/Mac/JWTDecode.framework; sourceTree = ""; }; 110 | D59575EB1C641F14000CD22B /* Keychain.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Keychain.framework; path = Carthage/Build/Mac/Keychain.framework; sourceTree = ""; }; 111 | D59575EC1C641F14000CD22B /* Sugar.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Sugar.framework; path = Carthage/Build/Mac/Sugar.framework; sourceTree = ""; }; 112 | D5B2E89F1C3A780C00C0327D /* OhMyAuth.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = OhMyAuth.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 113 | D5B2E8A91C3A780C00C0327D /* OhMyAuthTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = OhMyAuthTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 114 | D5C629401C3A7FAA007F7B7C /* OhMyAuth.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = OhMyAuth.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 115 | D5C629491C3A7FAA007F7B7C /* OhMyAuthTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = OhMyAuthTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 116 | D5C629841C3A893F007F7B7C /* Mac.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Mac.swift; sourceTree = ""; }; 117 | D5ED73791C64B1E4003772EF /* Info-iOS.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info-iOS.plist"; sourceTree = ""; }; 118 | D5ED737A1C64B1E4003772EF /* Info-Mac.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info-Mac.plist"; sourceTree = ""; }; 119 | D5ED737C1C64B1E4003772EF /* Info-iOS.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info-iOS.plist"; sourceTree = ""; }; 120 | D5ED737D1C64B1E4003772EF /* Info-Mac.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info-Mac.plist"; sourceTree = ""; }; 121 | /* End PBXFileReference section */ 122 | 123 | /* Begin PBXFrameworksBuildPhase section */ 124 | D5B2E89B1C3A780C00C0327D /* Frameworks */ = { 125 | isa = PBXFrameworksBuildPhase; 126 | buildActionMask = 2147483647; 127 | files = ( 128 | D20836171EF7D0A8004ED8E0 /* Keychains.framework in Frameworks */, 129 | D529C2CD1C620B1900B6FA6B /* JWTDecode.framework in Frameworks */, 130 | ); 131 | runOnlyForDeploymentPostprocessing = 0; 132 | }; 133 | D5B2E8A61C3A780C00C0327D /* Frameworks */ = { 134 | isa = PBXFrameworksBuildPhase; 135 | buildActionMask = 2147483647; 136 | files = ( 137 | D5B2E8AA1C3A780C00C0327D /* OhMyAuth.framework in Frameworks */, 138 | ); 139 | runOnlyForDeploymentPostprocessing = 0; 140 | }; 141 | D5C6293C1C3A7FAA007F7B7C /* Frameworks */ = { 142 | isa = PBXFrameworksBuildPhase; 143 | buildActionMask = 2147483647; 144 | files = ( 145 | D208361A1EF7D0FB004ED8E0 /* Keychains.framework in Frameworks */, 146 | D20836181EF7D0FB004ED8E0 /* JWTDecode.framework in Frameworks */, 147 | ); 148 | runOnlyForDeploymentPostprocessing = 0; 149 | }; 150 | D5C629461C3A7FAA007F7B7C /* Frameworks */ = { 151 | isa = PBXFrameworksBuildPhase; 152 | buildActionMask = 2147483647; 153 | files = ( 154 | D5C6294A1C3A7FAA007F7B7C /* OhMyAuth.framework in Frameworks */, 155 | ); 156 | runOnlyForDeploymentPostprocessing = 0; 157 | }; 158 | /* End PBXFrameworksBuildPhase section */ 159 | 160 | /* Begin PBXGroup section */ 161 | D20836151EF7D0A8004ED8E0 /* Frameworks */ = { 162 | isa = PBXGroup; 163 | children = ( 164 | D20836191EF7D0FB004ED8E0 /* Keychains.framework */, 165 | D20836161EF7D0A8004ED8E0 /* Keychains.framework */, 166 | ); 167 | name = Frameworks; 168 | sourceTree = ""; 169 | }; 170 | D20D5C3F1DEEF474000CEAAB /* Locker */ = { 171 | isa = PBXGroup; 172 | children = ( 173 | D20D5C401DEEF474000CEAAB /* KeychainLocker.swift */, 174 | D20D5C411DEEF474000CEAAB /* Lockable.swift */, 175 | D20D5C421DEEF474000CEAAB /* SuiteDefaultsLocker.swift */, 176 | D20D5C431DEEF474000CEAAB /* UserDefaultsLocker.swift */, 177 | D20D5C4C1DEEF4AE000CEAAB /* Keys.swift */, 178 | ); 179 | path = Locker; 180 | sourceTree = ""; 181 | }; 182 | D51D95631C62539C00D78EF3 /* Networking */ = { 183 | isa = PBXGroup; 184 | children = ( 185 | 922A1E581DC28A680088A7E7 /* Networking.swift */, 186 | D51D95641C6253B200D78EF3 /* NetworkRequests.swift */, 187 | D51D95741C62BAF000D78EF3 /* NetworkTasks.swift */, 188 | ); 189 | path = Networking; 190 | sourceTree = ""; 191 | }; 192 | D529C2D01C620B2E00B6FA6B /* Frameworks-iOS */ = { 193 | isa = PBXGroup; 194 | children = ( 195 | D529C2C91C620B1900B6FA6B /* JWTDecode.framework */, 196 | D529C2CA1C620B1900B6FA6B /* Keychain.framework */, 197 | ); 198 | name = "Frameworks-iOS"; 199 | sourceTree = ""; 200 | }; 201 | D595759D1C635384000CD22B /* Library */ = { 202 | isa = PBXGroup; 203 | children = ( 204 | D59575A61C63558D000CD22B /* Error.swift */, 205 | D595759E1C63538B000CD22B /* Result.swift */, 206 | D59575D11C640E4C000CD22B /* BrowserWebView.swift */, 207 | ); 208 | path = Library; 209 | sourceTree = ""; 210 | }; 211 | D59575DD1C641E3D000CD22B /* Protocols */ = { 212 | isa = PBXGroup; 213 | children = ( 214 | D59575DE1C641E3D000CD22B /* NetworkRequestable.swift */, 215 | D59575DF1C641E3D000CD22B /* NetworkTaskable.swift */, 216 | D59575E01C641E3D000CD22B /* WebViewable.swift */, 217 | ); 218 | path = Protocols; 219 | sourceTree = ""; 220 | }; 221 | D59575F11C641F1E000CD22B /* Frameworks-Mac */ = { 222 | isa = PBXGroup; 223 | children = ( 224 | D59575E91C641F14000CD22B /* Alamofire.framework */, 225 | D59575EA1C641F14000CD22B /* JWTDecode.framework */, 226 | D59575EB1C641F14000CD22B /* Keychain.framework */, 227 | D59575EC1C641F14000CD22B /* Sugar.framework */, 228 | ); 229 | name = "Frameworks-Mac"; 230 | sourceTree = ""; 231 | }; 232 | D5B2E8951C3A780C00C0327D = { 233 | isa = PBXGroup; 234 | children = ( 235 | D5C629691C3A809D007F7B7C /* Sources */, 236 | D5ED73781C64B1E4003772EF /* OhMyAuth */, 237 | D5ED737B1C64B1E4003772EF /* OhMyAuthTests */, 238 | D5B2E8A01C3A780C00C0327D /* Products */, 239 | D529C2D01C620B2E00B6FA6B /* Frameworks-iOS */, 240 | D59575F11C641F1E000CD22B /* Frameworks-Mac */, 241 | D20836151EF7D0A8004ED8E0 /* Frameworks */, 242 | ); 243 | sourceTree = ""; 244 | }; 245 | D5B2E8A01C3A780C00C0327D /* Products */ = { 246 | isa = PBXGroup; 247 | children = ( 248 | D5B2E89F1C3A780C00C0327D /* OhMyAuth.framework */, 249 | D5B2E8A91C3A780C00C0327D /* OhMyAuthTests.xctest */, 250 | D5C629401C3A7FAA007F7B7C /* OhMyAuth.framework */, 251 | D5C629491C3A7FAA007F7B7C /* OhMyAuthTests.xctest */, 252 | ); 253 | name = Products; 254 | sourceTree = ""; 255 | }; 256 | D5C629691C3A809D007F7B7C /* Sources */ = { 257 | isa = PBXGroup; 258 | children = ( 259 | D5C6296A1C3A809D007F7B7C /* iOS */, 260 | D5C6296C1C3A809D007F7B7C /* Mac */, 261 | D5C6296E1C3A809D007F7B7C /* Shared */, 262 | ); 263 | path = Sources; 264 | sourceTree = ""; 265 | }; 266 | D5C6296A1C3A809D007F7B7C /* iOS */ = { 267 | isa = PBXGroup; 268 | children = ( 269 | D59575CC1C640C0A000CD22B /* SafariWebView.swift */, 270 | D59575DA1C641DBF000CD22B /* UIApplication+OhMyAuth.swift */, 271 | ); 272 | path = iOS; 273 | sourceTree = ""; 274 | }; 275 | D5C6296C1C3A809D007F7B7C /* Mac */ = { 276 | isa = PBXGroup; 277 | children = ( 278 | D5C629841C3A893F007F7B7C /* Mac.swift */, 279 | ); 280 | path = Mac; 281 | sourceTree = ""; 282 | }; 283 | D5C6296E1C3A809D007F7B7C /* Shared */ = { 284 | isa = PBXGroup; 285 | children = ( 286 | D20D5C3F1DEEF474000CEAAB /* Locker */, 287 | D51D955C1C6252DD00D78EF3 /* AuthConfig.swift */, 288 | D51D95611C62536E00D78EF3 /* AuthContainer.swift */, 289 | D59575AA1C63CF3C000CD22B /* AuthService.swift */, 290 | D595759D1C635384000CD22B /* Library */, 291 | D51D95631C62539C00D78EF3 /* Networking */, 292 | D59575DD1C641E3D000CD22B /* Protocols */, 293 | 923CA22B1DC144290016B791 /* Utils.swift */, 294 | ); 295 | path = Shared; 296 | sourceTree = ""; 297 | }; 298 | D5ED73781C64B1E4003772EF /* OhMyAuth */ = { 299 | isa = PBXGroup; 300 | children = ( 301 | D5ED73791C64B1E4003772EF /* Info-iOS.plist */, 302 | D5ED737A1C64B1E4003772EF /* Info-Mac.plist */, 303 | ); 304 | path = OhMyAuth; 305 | sourceTree = ""; 306 | }; 307 | D5ED737B1C64B1E4003772EF /* OhMyAuthTests */ = { 308 | isa = PBXGroup; 309 | children = ( 310 | D5ED737C1C64B1E4003772EF /* Info-iOS.plist */, 311 | D5ED737D1C64B1E4003772EF /* Info-Mac.plist */, 312 | D2DD2AB31DEEFF2900AFF5BA /* LockerTests.swift */, 313 | D20A12A41E769648000DB14C /* ServiceTests.swift */, 314 | 5255FEBB1FB457FA004D012B /* NetworkRequestableTests.swift */, 315 | ); 316 | path = OhMyAuthTests; 317 | sourceTree = ""; 318 | }; 319 | /* End PBXGroup section */ 320 | 321 | /* Begin PBXHeadersBuildPhase section */ 322 | D5B2E89C1C3A780C00C0327D /* Headers */ = { 323 | isa = PBXHeadersBuildPhase; 324 | buildActionMask = 2147483647; 325 | files = ( 326 | ); 327 | runOnlyForDeploymentPostprocessing = 0; 328 | }; 329 | D5C6293D1C3A7FAA007F7B7C /* Headers */ = { 330 | isa = PBXHeadersBuildPhase; 331 | buildActionMask = 2147483647; 332 | files = ( 333 | ); 334 | runOnlyForDeploymentPostprocessing = 0; 335 | }; 336 | /* End PBXHeadersBuildPhase section */ 337 | 338 | /* Begin PBXNativeTarget section */ 339 | D5B2E89E1C3A780C00C0327D /* OhMyAuth-iOS */ = { 340 | isa = PBXNativeTarget; 341 | buildConfigurationList = D5B2E8B31C3A780C00C0327D /* Build configuration list for PBXNativeTarget "OhMyAuth-iOS" */; 342 | buildPhases = ( 343 | D5B2E89A1C3A780C00C0327D /* Sources */, 344 | D5B2E89B1C3A780C00C0327D /* Frameworks */, 345 | D5B2E89C1C3A780C00C0327D /* Headers */, 346 | D5B2E89D1C3A780C00C0327D /* Resources */, 347 | D529C2C51C620AAF00B6FA6B /* Copy frameworks with Carthage */, 348 | ); 349 | buildRules = ( 350 | ); 351 | dependencies = ( 352 | ); 353 | name = "OhMyAuth-iOS"; 354 | productName = OhMyAuth; 355 | productReference = D5B2E89F1C3A780C00C0327D /* OhMyAuth.framework */; 356 | productType = "com.apple.product-type.framework"; 357 | }; 358 | D5B2E8A81C3A780C00C0327D /* OhMyAuth-iOS-Tests */ = { 359 | isa = PBXNativeTarget; 360 | buildConfigurationList = D5B2E8B61C3A780C00C0327D /* Build configuration list for PBXNativeTarget "OhMyAuth-iOS-Tests" */; 361 | buildPhases = ( 362 | D5B2E8A51C3A780C00C0327D /* Sources */, 363 | D5B2E8A61C3A780C00C0327D /* Frameworks */, 364 | D5B2E8A71C3A780C00C0327D /* Resources */, 365 | ); 366 | buildRules = ( 367 | ); 368 | dependencies = ( 369 | D5B2E8AC1C3A780C00C0327D /* PBXTargetDependency */, 370 | ); 371 | name = "OhMyAuth-iOS-Tests"; 372 | productName = OhMyAuthTests; 373 | productReference = D5B2E8A91C3A780C00C0327D /* OhMyAuthTests.xctest */; 374 | productType = "com.apple.product-type.bundle.unit-test"; 375 | }; 376 | D5C6293F1C3A7FAA007F7B7C /* OhMyAuth-Mac */ = { 377 | isa = PBXNativeTarget; 378 | buildConfigurationList = D5C629511C3A7FAA007F7B7C /* Build configuration list for PBXNativeTarget "OhMyAuth-Mac" */; 379 | buildPhases = ( 380 | D5C6293B1C3A7FAA007F7B7C /* Sources */, 381 | D5C6293C1C3A7FAA007F7B7C /* Frameworks */, 382 | D5C6293D1C3A7FAA007F7B7C /* Headers */, 383 | D5C6293E1C3A7FAA007F7B7C /* Resources */, 384 | D59575E81C641ED4000CD22B /* Copy frameworks with Carthage */, 385 | ); 386 | buildRules = ( 387 | ); 388 | dependencies = ( 389 | ); 390 | name = "OhMyAuth-Mac"; 391 | productName = "OhMyAuth-Mac"; 392 | productReference = D5C629401C3A7FAA007F7B7C /* OhMyAuth.framework */; 393 | productType = "com.apple.product-type.framework"; 394 | }; 395 | D5C629481C3A7FAA007F7B7C /* OhMyAuth-Mac-Tests */ = { 396 | isa = PBXNativeTarget; 397 | buildConfigurationList = D5C629541C3A7FAA007F7B7C /* Build configuration list for PBXNativeTarget "OhMyAuth-Mac-Tests" */; 398 | buildPhases = ( 399 | D5C629451C3A7FAA007F7B7C /* Sources */, 400 | D5C629461C3A7FAA007F7B7C /* Frameworks */, 401 | D5C629471C3A7FAA007F7B7C /* Resources */, 402 | ); 403 | buildRules = ( 404 | ); 405 | dependencies = ( 406 | D5C6294C1C3A7FAA007F7B7C /* PBXTargetDependency */, 407 | ); 408 | name = "OhMyAuth-Mac-Tests"; 409 | productName = "OhMyAuth-MacTests"; 410 | productReference = D5C629491C3A7FAA007F7B7C /* OhMyAuthTests.xctest */; 411 | productType = "com.apple.product-type.bundle.unit-test"; 412 | }; 413 | /* End PBXNativeTarget section */ 414 | 415 | /* Begin PBXProject section */ 416 | D5B2E8961C3A780C00C0327D /* Project object */ = { 417 | isa = PBXProject; 418 | attributes = { 419 | LastSwiftUpdateCheck = 0720; 420 | LastUpgradeCheck = 1000; 421 | ORGANIZATIONNAME = "Hyper Interaktiv AS"; 422 | TargetAttributes = { 423 | D5B2E89E1C3A780C00C0327D = { 424 | CreatedOnToolsVersion = 7.2; 425 | }; 426 | D5B2E8A81C3A780C00C0327D = { 427 | CreatedOnToolsVersion = 7.2; 428 | LastSwiftMigration = 0810; 429 | }; 430 | D5C6293F1C3A7FAA007F7B7C = { 431 | CreatedOnToolsVersion = 7.2; 432 | LastSwiftMigration = 0800; 433 | }; 434 | D5C629481C3A7FAA007F7B7C = { 435 | CreatedOnToolsVersion = 7.2; 436 | LastSwiftMigration = 0810; 437 | }; 438 | }; 439 | }; 440 | buildConfigurationList = D5B2E8991C3A780C00C0327D /* Build configuration list for PBXProject "OhMyAuth" */; 441 | compatibilityVersion = "Xcode 3.2"; 442 | developmentRegion = English; 443 | hasScannedForEncodings = 0; 444 | knownRegions = ( 445 | en, 446 | ); 447 | mainGroup = D5B2E8951C3A780C00C0327D; 448 | productRefGroup = D5B2E8A01C3A780C00C0327D /* Products */; 449 | projectDirPath = ""; 450 | projectRoot = ""; 451 | targets = ( 452 | D5B2E89E1C3A780C00C0327D /* OhMyAuth-iOS */, 453 | D5C6293F1C3A7FAA007F7B7C /* OhMyAuth-Mac */, 454 | D5B2E8A81C3A780C00C0327D /* OhMyAuth-iOS-Tests */, 455 | D5C629481C3A7FAA007F7B7C /* OhMyAuth-Mac-Tests */, 456 | ); 457 | }; 458 | /* End PBXProject section */ 459 | 460 | /* Begin PBXResourcesBuildPhase section */ 461 | D5B2E89D1C3A780C00C0327D /* Resources */ = { 462 | isa = PBXResourcesBuildPhase; 463 | buildActionMask = 2147483647; 464 | files = ( 465 | ); 466 | runOnlyForDeploymentPostprocessing = 0; 467 | }; 468 | D5B2E8A71C3A780C00C0327D /* Resources */ = { 469 | isa = PBXResourcesBuildPhase; 470 | buildActionMask = 2147483647; 471 | files = ( 472 | ); 473 | runOnlyForDeploymentPostprocessing = 0; 474 | }; 475 | D5C6293E1C3A7FAA007F7B7C /* Resources */ = { 476 | isa = PBXResourcesBuildPhase; 477 | buildActionMask = 2147483647; 478 | files = ( 479 | ); 480 | runOnlyForDeploymentPostprocessing = 0; 481 | }; 482 | D5C629471C3A7FAA007F7B7C /* Resources */ = { 483 | isa = PBXResourcesBuildPhase; 484 | buildActionMask = 2147483647; 485 | files = ( 486 | ); 487 | runOnlyForDeploymentPostprocessing = 0; 488 | }; 489 | /* End PBXResourcesBuildPhase section */ 490 | 491 | /* Begin PBXShellScriptBuildPhase section */ 492 | D529C2C51C620AAF00B6FA6B /* Copy frameworks with Carthage */ = { 493 | isa = PBXShellScriptBuildPhase; 494 | buildActionMask = 2147483647; 495 | files = ( 496 | ); 497 | inputPaths = ( 498 | "$(SRCROOT)/Carthage/Build/iOS/Keychains.framework", 499 | "$(SRCROOT)/Carthage/Build/iOS/JWTDecode.framework", 500 | ); 501 | name = "Copy frameworks with Carthage"; 502 | outputPaths = ( 503 | ); 504 | runOnlyForDeploymentPostprocessing = 0; 505 | shellPath = /bin/sh; 506 | shellScript = "/usr/local/bin/carthage copy-frameworks"; 507 | }; 508 | D59575E81C641ED4000CD22B /* Copy frameworks with Carthage */ = { 509 | isa = PBXShellScriptBuildPhase; 510 | buildActionMask = 2147483647; 511 | files = ( 512 | ); 513 | inputPaths = ( 514 | "$(SRCROOT)/Carthage/Build/iOS/Keychains.framework", 515 | "$(SRCROOT)/Carthage/Build/iOS/JWTDecode.framework", 516 | ); 517 | name = "Copy frameworks with Carthage"; 518 | outputPaths = ( 519 | ); 520 | runOnlyForDeploymentPostprocessing = 0; 521 | shellPath = /bin/sh; 522 | shellScript = "/usr/local/bin/carthage copy-frameworks"; 523 | }; 524 | /* End PBXShellScriptBuildPhase section */ 525 | 526 | /* Begin PBXSourcesBuildPhase section */ 527 | D5B2E89A1C3A780C00C0327D /* Sources */ = { 528 | isa = PBXSourcesBuildPhase; 529 | buildActionMask = 2147483647; 530 | files = ( 531 | D595759F1C63538B000CD22B /* Result.swift in Sources */, 532 | D59575CD1C640C0A000CD22B /* SafariWebView.swift in Sources */, 533 | 922A1E591DC28A680088A7E7 /* Networking.swift in Sources */, 534 | D59575AB1C63CF3C000CD22B /* AuthService.swift in Sources */, 535 | D20D5C4A1DEEF474000CEAAB /* UserDefaultsLocker.swift in Sources */, 536 | D20D5C481DEEF474000CEAAB /* SuiteDefaultsLocker.swift in Sources */, 537 | D51D95651C6253B200D78EF3 /* NetworkRequests.swift in Sources */, 538 | D59575E31C641E3D000CD22B /* WebViewable.swift in Sources */, 539 | D59575A71C63558D000CD22B /* Error.swift in Sources */, 540 | D20D5C4D1DEEF4AE000CEAAB /* Keys.swift in Sources */, 541 | D59575E21C641E3D000CD22B /* NetworkTaskable.swift in Sources */, 542 | 923CA22C1DC144290016B791 /* Utils.swift in Sources */, 543 | D51D955D1C6252DD00D78EF3 /* AuthConfig.swift in Sources */, 544 | D20D5C461DEEF474000CEAAB /* Lockable.swift in Sources */, 545 | D59575D21C640E4C000CD22B /* BrowserWebView.swift in Sources */, 546 | D20D5C441DEEF474000CEAAB /* KeychainLocker.swift in Sources */, 547 | D59575DB1C641DBF000CD22B /* UIApplication+OhMyAuth.swift in Sources */, 548 | D51D95621C62536E00D78EF3 /* AuthContainer.swift in Sources */, 549 | D59575E11C641E3D000CD22B /* NetworkRequestable.swift in Sources */, 550 | D51D95751C62BAF000D78EF3 /* NetworkTasks.swift in Sources */, 551 | ); 552 | runOnlyForDeploymentPostprocessing = 0; 553 | }; 554 | D5B2E8A51C3A780C00C0327D /* Sources */ = { 555 | isa = PBXSourcesBuildPhase; 556 | buildActionMask = 2147483647; 557 | files = ( 558 | D2DD2AB41DEEFF2900AFF5BA /* LockerTests.swift in Sources */, 559 | D20A12A51E769648000DB14C /* ServiceTests.swift in Sources */, 560 | 5255FEBC1FB457FA004D012B /* NetworkRequestableTests.swift in Sources */, 561 | ); 562 | runOnlyForDeploymentPostprocessing = 0; 563 | }; 564 | D5C6293B1C3A7FAA007F7B7C /* Sources */ = { 565 | isa = PBXSourcesBuildPhase; 566 | buildActionMask = 2147483647; 567 | files = ( 568 | D5C629851C3A893F007F7B7C /* Mac.swift in Sources */, 569 | D59575E71C641E4C000CD22B /* Result.swift in Sources */, 570 | 922A1E5A1DC28A680088A7E7 /* Networking.swift in Sources */, 571 | D59575D31C640E50000CD22B /* BrowserWebView.swift in Sources */, 572 | D51D95701C62B82400D78EF3 /* AuthConfig.swift in Sources */, 573 | D59575AC1C63CF3C000CD22B /* AuthService.swift in Sources */, 574 | D20D5C4E1DEEF4AE000CEAAB /* Keys.swift in Sources */, 575 | D20D5C471DEEF474000CEAAB /* Lockable.swift in Sources */, 576 | D51D956E1C62B82400D78EF3 /* NetworkRequests.swift in Sources */, 577 | 923CA22D1DC144290016B791 /* Utils.swift in Sources */, 578 | D51D95721C62B82400D78EF3 /* AuthContainer.swift in Sources */, 579 | D59575E51C641E4C000CD22B /* NetworkTaskable.swift in Sources */, 580 | D59575A81C63558D000CD22B /* Error.swift in Sources */, 581 | D20D5C4B1DEEF474000CEAAB /* UserDefaultsLocker.swift in Sources */, 582 | D59575E61C641E4C000CD22B /* WebViewable.swift in Sources */, 583 | D59575E41C641E4C000CD22B /* NetworkRequestable.swift in Sources */, 584 | D20D5C491DEEF474000CEAAB /* SuiteDefaultsLocker.swift in Sources */, 585 | D20D5C451DEEF474000CEAAB /* KeychainLocker.swift in Sources */, 586 | D51D95761C62BAF000D78EF3 /* NetworkTasks.swift in Sources */, 587 | ); 588 | runOnlyForDeploymentPostprocessing = 0; 589 | }; 590 | D5C629451C3A7FAA007F7B7C /* Sources */ = { 591 | isa = PBXSourcesBuildPhase; 592 | buildActionMask = 2147483647; 593 | files = ( 594 | D2DD2AB51DEEFF2900AFF5BA /* LockerTests.swift in Sources */, 595 | D20A12A61E769648000DB14C /* ServiceTests.swift in Sources */, 596 | 5255FEBD1FB457FA004D012B /* NetworkRequestableTests.swift in Sources */, 597 | ); 598 | runOnlyForDeploymentPostprocessing = 0; 599 | }; 600 | /* End PBXSourcesBuildPhase section */ 601 | 602 | /* Begin PBXTargetDependency section */ 603 | D5B2E8AC1C3A780C00C0327D /* PBXTargetDependency */ = { 604 | isa = PBXTargetDependency; 605 | target = D5B2E89E1C3A780C00C0327D /* OhMyAuth-iOS */; 606 | targetProxy = D5B2E8AB1C3A780C00C0327D /* PBXContainerItemProxy */; 607 | }; 608 | D5C6294C1C3A7FAA007F7B7C /* PBXTargetDependency */ = { 609 | isa = PBXTargetDependency; 610 | target = D5C6293F1C3A7FAA007F7B7C /* OhMyAuth-Mac */; 611 | targetProxy = D5C6294B1C3A7FAA007F7B7C /* PBXContainerItemProxy */; 612 | }; 613 | /* End PBXTargetDependency section */ 614 | 615 | /* Begin XCBuildConfiguration section */ 616 | D5B2E8B11C3A780C00C0327D /* Debug */ = { 617 | isa = XCBuildConfiguration; 618 | buildSettings = { 619 | ALWAYS_SEARCH_USER_PATHS = NO; 620 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 621 | CLANG_CXX_LIBRARY = "libc++"; 622 | CLANG_ENABLE_MODULES = YES; 623 | CLANG_ENABLE_OBJC_ARC = YES; 624 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 625 | CLANG_WARN_BOOL_CONVERSION = YES; 626 | CLANG_WARN_COMMA = YES; 627 | CLANG_WARN_CONSTANT_CONVERSION = YES; 628 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 629 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 630 | CLANG_WARN_EMPTY_BODY = YES; 631 | CLANG_WARN_ENUM_CONVERSION = YES; 632 | CLANG_WARN_INFINITE_RECURSION = YES; 633 | CLANG_WARN_INT_CONVERSION = YES; 634 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 635 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 636 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 637 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 638 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 639 | CLANG_WARN_STRICT_PROTOTYPES = YES; 640 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 641 | CLANG_WARN_UNREACHABLE_CODE = YES; 642 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 643 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 644 | COPY_PHASE_STRIP = NO; 645 | CURRENT_PROJECT_VERSION = 1; 646 | DEBUG_INFORMATION_FORMAT = dwarf; 647 | ENABLE_STRICT_OBJC_MSGSEND = YES; 648 | ENABLE_TESTABILITY = YES; 649 | GCC_C_LANGUAGE_STANDARD = gnu99; 650 | GCC_DYNAMIC_NO_PIC = NO; 651 | GCC_NO_COMMON_BLOCKS = YES; 652 | GCC_OPTIMIZATION_LEVEL = 0; 653 | GCC_PREPROCESSOR_DEFINITIONS = ( 654 | "DEBUG=1", 655 | "$(inherited)", 656 | ); 657 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 658 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 659 | GCC_WARN_UNDECLARED_SELECTOR = YES; 660 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 661 | GCC_WARN_UNUSED_FUNCTION = YES; 662 | GCC_WARN_UNUSED_VARIABLE = YES; 663 | IPHONEOS_DEPLOYMENT_TARGET = 9.2; 664 | MTL_ENABLE_DEBUG_INFO = YES; 665 | ONLY_ACTIVE_ARCH = YES; 666 | SDKROOT = iphoneos; 667 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 668 | SWIFT_VERSION = 4.0; 669 | TARGETED_DEVICE_FAMILY = "1,2"; 670 | VERSIONING_SYSTEM = "apple-generic"; 671 | VERSION_INFO_PREFIX = ""; 672 | }; 673 | name = Debug; 674 | }; 675 | D5B2E8B21C3A780C00C0327D /* Release */ = { 676 | isa = XCBuildConfiguration; 677 | buildSettings = { 678 | ALWAYS_SEARCH_USER_PATHS = NO; 679 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 680 | CLANG_CXX_LIBRARY = "libc++"; 681 | CLANG_ENABLE_MODULES = YES; 682 | CLANG_ENABLE_OBJC_ARC = YES; 683 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 684 | CLANG_WARN_BOOL_CONVERSION = YES; 685 | CLANG_WARN_COMMA = YES; 686 | CLANG_WARN_CONSTANT_CONVERSION = YES; 687 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 688 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 689 | CLANG_WARN_EMPTY_BODY = YES; 690 | CLANG_WARN_ENUM_CONVERSION = YES; 691 | CLANG_WARN_INFINITE_RECURSION = YES; 692 | CLANG_WARN_INT_CONVERSION = YES; 693 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 694 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 695 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 696 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 697 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 698 | CLANG_WARN_STRICT_PROTOTYPES = YES; 699 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 700 | CLANG_WARN_UNREACHABLE_CODE = YES; 701 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 702 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 703 | COPY_PHASE_STRIP = NO; 704 | CURRENT_PROJECT_VERSION = 1; 705 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 706 | ENABLE_NS_ASSERTIONS = NO; 707 | ENABLE_STRICT_OBJC_MSGSEND = YES; 708 | GCC_C_LANGUAGE_STANDARD = gnu99; 709 | GCC_NO_COMMON_BLOCKS = YES; 710 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 711 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 712 | GCC_WARN_UNDECLARED_SELECTOR = YES; 713 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 714 | GCC_WARN_UNUSED_FUNCTION = YES; 715 | GCC_WARN_UNUSED_VARIABLE = YES; 716 | IPHONEOS_DEPLOYMENT_TARGET = 9.2; 717 | MTL_ENABLE_DEBUG_INFO = NO; 718 | SDKROOT = iphoneos; 719 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 720 | SWIFT_VERSION = 4.0; 721 | TARGETED_DEVICE_FAMILY = "1,2"; 722 | VALIDATE_PRODUCT = YES; 723 | VERSIONING_SYSTEM = "apple-generic"; 724 | VERSION_INFO_PREFIX = ""; 725 | }; 726 | name = Release; 727 | }; 728 | D5B2E8B41C3A780C00C0327D /* Debug */ = { 729 | isa = XCBuildConfiguration; 730 | buildSettings = { 731 | CLANG_ENABLE_MODULES = YES; 732 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 733 | DEFINES_MODULE = YES; 734 | DYLIB_COMPATIBILITY_VERSION = 1; 735 | DYLIB_CURRENT_VERSION = 1; 736 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 737 | FRAMEWORK_SEARCH_PATHS = ( 738 | "$(inherited)", 739 | "$(PROJECT_DIR)/Carthage/Build/iOS", 740 | ); 741 | INFOPLIST_FILE = "$(SRCROOT)/OhMyAuth/Info-iOS.plist"; 742 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 743 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 744 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 745 | PRODUCT_BUNDLE_IDENTIFIER = "no.hyper.OhMyAuth-iOS"; 746 | PRODUCT_NAME = OhMyAuth; 747 | SKIP_INSTALL = YES; 748 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 749 | }; 750 | name = Debug; 751 | }; 752 | D5B2E8B51C3A780C00C0327D /* Release */ = { 753 | isa = XCBuildConfiguration; 754 | buildSettings = { 755 | CLANG_ENABLE_MODULES = YES; 756 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 757 | DEFINES_MODULE = YES; 758 | DYLIB_COMPATIBILITY_VERSION = 1; 759 | DYLIB_CURRENT_VERSION = 1; 760 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 761 | FRAMEWORK_SEARCH_PATHS = ( 762 | "$(inherited)", 763 | "$(PROJECT_DIR)/Carthage/Build/iOS", 764 | ); 765 | INFOPLIST_FILE = "$(SRCROOT)/OhMyAuth/Info-iOS.plist"; 766 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 767 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 768 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 769 | PRODUCT_BUNDLE_IDENTIFIER = "no.hyper.OhMyAuth-iOS"; 770 | PRODUCT_NAME = OhMyAuth; 771 | SKIP_INSTALL = YES; 772 | }; 773 | name = Release; 774 | }; 775 | D5B2E8B71C3A780C00C0327D /* Debug */ = { 776 | isa = XCBuildConfiguration; 777 | buildSettings = { 778 | CLANG_ENABLE_MODULES = YES; 779 | FRAMEWORK_SEARCH_PATHS = ( 780 | "$(inherited)", 781 | "$(PROJECT_DIR)/Carthage/Build/iOS", 782 | ); 783 | INFOPLIST_FILE = "$(SRCROOT)/OhMyAuthTests/Info-iOS.plist"; 784 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)"; 785 | PRODUCT_BUNDLE_IDENTIFIER = no.hyper.OhMyAuthTests; 786 | PRODUCT_NAME = OhMyAuthTests; 787 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 788 | }; 789 | name = Debug; 790 | }; 791 | D5B2E8B81C3A780C00C0327D /* Release */ = { 792 | isa = XCBuildConfiguration; 793 | buildSettings = { 794 | CLANG_ENABLE_MODULES = YES; 795 | FRAMEWORK_SEARCH_PATHS = ( 796 | "$(inherited)", 797 | "$(PROJECT_DIR)/Carthage/Build/iOS", 798 | ); 799 | INFOPLIST_FILE = "$(SRCROOT)/OhMyAuthTests/Info-iOS.plist"; 800 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks $(FRAMEWORK_SEARCH_PATHS)"; 801 | PRODUCT_BUNDLE_IDENTIFIER = no.hyper.OhMyAuthTests; 802 | PRODUCT_NAME = OhMyAuthTests; 803 | }; 804 | name = Release; 805 | }; 806 | D5C629521C3A7FAA007F7B7C /* Debug */ = { 807 | isa = XCBuildConfiguration; 808 | buildSettings = { 809 | CLANG_ENABLE_MODULES = YES; 810 | CODE_SIGN_IDENTITY = ""; 811 | COMBINE_HIDPI_IMAGES = YES; 812 | DEFINES_MODULE = YES; 813 | DYLIB_COMPATIBILITY_VERSION = 1; 814 | DYLIB_CURRENT_VERSION = 1; 815 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 816 | FRAMEWORK_SEARCH_PATHS = ( 817 | "$(inherited)", 818 | "$(PROJECT_DIR)/Carthage/Build/Mac", 819 | ); 820 | FRAMEWORK_VERSION = A; 821 | INFOPLIST_FILE = "$(SRCROOT)/OhMyAuth/Info-Mac.plist"; 822 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 823 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; 824 | MACOSX_DEPLOYMENT_TARGET = 10.11; 825 | PRODUCT_BUNDLE_IDENTIFIER = "no.hyper.OhMyAuth-Mac"; 826 | PRODUCT_NAME = OhMyAuth; 827 | SDKROOT = macosx; 828 | SKIP_INSTALL = YES; 829 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 830 | }; 831 | name = Debug; 832 | }; 833 | D5C629531C3A7FAA007F7B7C /* Release */ = { 834 | isa = XCBuildConfiguration; 835 | buildSettings = { 836 | CLANG_ENABLE_MODULES = YES; 837 | CODE_SIGN_IDENTITY = ""; 838 | COMBINE_HIDPI_IMAGES = YES; 839 | DEFINES_MODULE = YES; 840 | DYLIB_COMPATIBILITY_VERSION = 1; 841 | DYLIB_CURRENT_VERSION = 1; 842 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 843 | FRAMEWORK_SEARCH_PATHS = ( 844 | "$(inherited)", 845 | "$(PROJECT_DIR)/Carthage/Build/Mac", 846 | ); 847 | FRAMEWORK_VERSION = A; 848 | INFOPLIST_FILE = "$(SRCROOT)/OhMyAuth/Info-Mac.plist"; 849 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 850 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; 851 | MACOSX_DEPLOYMENT_TARGET = 10.11; 852 | PRODUCT_BUNDLE_IDENTIFIER = "no.hyper.OhMyAuth-Mac"; 853 | PRODUCT_NAME = OhMyAuth; 854 | SDKROOT = macosx; 855 | SKIP_INSTALL = YES; 856 | }; 857 | name = Release; 858 | }; 859 | D5C629551C3A7FAA007F7B7C /* Debug */ = { 860 | isa = XCBuildConfiguration; 861 | buildSettings = { 862 | CLANG_ENABLE_MODULES = YES; 863 | CODE_SIGN_IDENTITY = "-"; 864 | COMBINE_HIDPI_IMAGES = YES; 865 | FRAMEWORK_SEARCH_PATHS = ( 866 | "$(inherited)", 867 | "$(PROJECT_DIR)/Carthage/Build/Mac", 868 | ); 869 | INFOPLIST_FILE = "$(SRCROOT)/OhMyAuthTests/Info-Mac.plist"; 870 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks $(FRAMEWORK_SEARCH_PATHS)"; 871 | MACOSX_DEPLOYMENT_TARGET = 10.11; 872 | PRODUCT_BUNDLE_IDENTIFIER = "no.hyper.OhMyAuth-MacTests"; 873 | PRODUCT_NAME = OhMyAuthTests; 874 | SDKROOT = macosx; 875 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 876 | }; 877 | name = Debug; 878 | }; 879 | D5C629561C3A7FAA007F7B7C /* Release */ = { 880 | isa = XCBuildConfiguration; 881 | buildSettings = { 882 | CLANG_ENABLE_MODULES = YES; 883 | CODE_SIGN_IDENTITY = "-"; 884 | COMBINE_HIDPI_IMAGES = YES; 885 | FRAMEWORK_SEARCH_PATHS = ( 886 | "$(inherited)", 887 | "$(PROJECT_DIR)/Carthage/Build/Mac", 888 | ); 889 | INFOPLIST_FILE = "$(SRCROOT)/OhMyAuthTests/Info-Mac.plist"; 890 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks $(FRAMEWORK_SEARCH_PATHS)"; 891 | MACOSX_DEPLOYMENT_TARGET = 10.11; 892 | PRODUCT_BUNDLE_IDENTIFIER = "no.hyper.OhMyAuth-MacTests"; 893 | PRODUCT_NAME = OhMyAuthTests; 894 | SDKROOT = macosx; 895 | }; 896 | name = Release; 897 | }; 898 | /* End XCBuildConfiguration section */ 899 | 900 | /* Begin XCConfigurationList section */ 901 | D5B2E8991C3A780C00C0327D /* Build configuration list for PBXProject "OhMyAuth" */ = { 902 | isa = XCConfigurationList; 903 | buildConfigurations = ( 904 | D5B2E8B11C3A780C00C0327D /* Debug */, 905 | D5B2E8B21C3A780C00C0327D /* Release */, 906 | ); 907 | defaultConfigurationIsVisible = 0; 908 | defaultConfigurationName = Release; 909 | }; 910 | D5B2E8B31C3A780C00C0327D /* Build configuration list for PBXNativeTarget "OhMyAuth-iOS" */ = { 911 | isa = XCConfigurationList; 912 | buildConfigurations = ( 913 | D5B2E8B41C3A780C00C0327D /* Debug */, 914 | D5B2E8B51C3A780C00C0327D /* Release */, 915 | ); 916 | defaultConfigurationIsVisible = 0; 917 | defaultConfigurationName = Release; 918 | }; 919 | D5B2E8B61C3A780C00C0327D /* Build configuration list for PBXNativeTarget "OhMyAuth-iOS-Tests" */ = { 920 | isa = XCConfigurationList; 921 | buildConfigurations = ( 922 | D5B2E8B71C3A780C00C0327D /* Debug */, 923 | D5B2E8B81C3A780C00C0327D /* Release */, 924 | ); 925 | defaultConfigurationIsVisible = 0; 926 | defaultConfigurationName = Release; 927 | }; 928 | D5C629511C3A7FAA007F7B7C /* Build configuration list for PBXNativeTarget "OhMyAuth-Mac" */ = { 929 | isa = XCConfigurationList; 930 | buildConfigurations = ( 931 | D5C629521C3A7FAA007F7B7C /* Debug */, 932 | D5C629531C3A7FAA007F7B7C /* Release */, 933 | ); 934 | defaultConfigurationIsVisible = 0; 935 | defaultConfigurationName = Release; 936 | }; 937 | D5C629541C3A7FAA007F7B7C /* Build configuration list for PBXNativeTarget "OhMyAuth-Mac-Tests" */ = { 938 | isa = XCConfigurationList; 939 | buildConfigurations = ( 940 | D5C629551C3A7FAA007F7B7C /* Debug */, 941 | D5C629561C3A7FAA007F7B7C /* Release */, 942 | ); 943 | defaultConfigurationIsVisible = 0; 944 | defaultConfigurationName = Release; 945 | }; 946 | /* End XCConfigurationList section */ 947 | }; 948 | rootObject = D5B2E8961C3A780C00C0327D /* Project object */; 949 | } 950 | -------------------------------------------------------------------------------- /OhMyAuth.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /OhMyAuth.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /OhMyAuth.xcodeproj/xcshareddata/xcschemes/OhMyAuth-Mac.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 65 | 71 | 72 | 73 | 74 | 75 | 76 | 82 | 83 | 89 | 90 | 91 | 92 | 94 | 95 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /OhMyAuth.xcodeproj/xcshareddata/xcschemes/OhMyAuth-iOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 65 | 71 | 72 | 73 | 74 | 75 | 76 | 82 | 83 | 89 | 90 | 91 | 92 | 94 | 95 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /OhMyAuth/Info-Mac.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSHumanReadableCopyright 24 | Copyright © 2016 Hyper Interaktiv AS. All rights reserved. 25 | NSPrincipalClass 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /OhMyAuth/Info-iOS.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /OhMyAuthTests/Info-Mac.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /OhMyAuthTests/Info-iOS.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /OhMyAuthTests/LockerTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | import OhMyAuth 3 | 4 | class LockerTests: XCTestCase { 5 | 6 | func testLockerWithName() { 7 | let locker = UserDefaultsLocker(name: "app") 8 | XCTAssertEqual(locker.name, "app") 9 | print(locker.service) 10 | } 11 | 12 | func testLockerWithService() { 13 | let locker = UserDefaultsLocker(name: "app") 14 | locker.service = "service" 15 | XCTAssertEqual(locker.service, "service") 16 | } 17 | 18 | func testUserDefaultsLocker() { 19 | let locker = UserDefaultsLocker(name: "app") 20 | locker.service = "service" 21 | 22 | let uuid = NSUUID().uuidString 23 | locker.accessToken = uuid 24 | 25 | XCTAssertEqual(locker.accessToken, uuid) 26 | 27 | XCTAssertEqual(locker.generateKey(Keys.accessToken), "app-service-\(Keys.accessToken)") 28 | XCTAssertEqual(locker.generateKey(Keys.expiryDate), "app-service-\(Keys.expiryDate)") 29 | XCTAssertEqual(locker.generateKey("custom-key"), "app-service-custom-key") 30 | } 31 | 32 | func testSuiteLocker() { 33 | let suiteName = "group.com.hyper.OhMyAuth" 34 | let locker = SuiteDefaultsLocker(name: "app", suiteName: suiteName) 35 | 36 | XCTAssertEqual(locker.suiteName, suiteName) 37 | XCTAssertEqual(locker.generateKey(Keys.accessToken), "app-\(suiteName)-\(Keys.accessToken)") 38 | XCTAssertEqual(locker.generateKey(Keys.expiryDate), "app-\(suiteName)-\(Keys.expiryDate)") 39 | XCTAssertEqual(locker.generateKey("custom-key"), "app-\(suiteName)-custom-key") 40 | 41 | locker.saveInDefaults("custom-key", "custom-value" as AnyObject) 42 | XCTAssertEqual(locker.getFromDefaults("custom-key"), "custom-value") 43 | } 44 | 45 | func testMigration() { 46 | let locker1 = UserDefaultsLocker(name: "app") 47 | let locker2 = SuiteDefaultsLocker(name: "app", suiteName: "group.com.hyper.OhMyAuth") 48 | 49 | let uuid = NSUUID().uuidString 50 | locker1.accessToken = uuid 51 | 52 | locker2.migrate(from: locker1) 53 | 54 | XCTAssertNil(locker1.accessToken) 55 | XCTAssertEqual(locker2.accessToken, uuid) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /OhMyAuthTests/NetworkRequestableTests.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | @testable import OhMyAuth 4 | 5 | final class NetworkRequestableTests: XCTestCase { 6 | func testSuccessfulResult() throws { 7 | let networking = NetworkingMock(configuration: .default) 8 | networking.data = try JSONSerialization.data(withJSONObject: [:], options: []) 9 | networking.response = HTTPURLResponse() 10 | 11 | var result: Result? 12 | let request = RequestMock() 13 | request.start(using: networking) { result = $0 } 14 | 15 | switch result { 16 | case .some(.success(let object)): 17 | // Since we get an untyped object from the API, we need to use reflection for verification 18 | XCTAssertEqual(String(reflecting: object), String(reflecting: [:])) 19 | default: 20 | XCTFail("Unexpected result: \(String(describing: result))") 21 | } 22 | } 23 | 24 | func testOfflineErrorReturnedAsResult() { 25 | let networking = NetworkingMock(configuration: .default) 26 | networking.error = NSError( 27 | domain: NSURLErrorDomain, 28 | code: URLError.notConnectedToInternet.rawValue, 29 | userInfo: nil 30 | ) 31 | 32 | var result: Result? 33 | let request = RequestMock() 34 | request.start(using: networking) { result = $0 } 35 | 36 | switch result { 37 | case .some(.failure(let error as NSError)): 38 | XCTAssertEqual(error.code, URLError.notConnectedToInternet.rawValue) 39 | default: 40 | XCTFail("Unexpected result: \(String(describing: result))") 41 | } 42 | } 43 | } 44 | 45 | private extension NetworkRequestableTests { 46 | struct RequestMock: NetworkRequestable { 47 | let url = URL(string: "https://www.hyper.no")! 48 | let parameters = [String: Any]() 49 | let headers = [String: String]() 50 | } 51 | 52 | class NetworkingMock: Networking { 53 | var data: Data? 54 | var response: URLResponse? 55 | var error: Error? 56 | 57 | override func post(url: URL, parameters: [String : Any], headers: [String : String], completion: @escaping ((Data?, URLResponse?, Error?) -> Void)) { 58 | completion(data, response, error) 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /OhMyAuthTests/ServiceTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import OhMyAuth 3 | 4 | class ServiceTests: XCTestCase { 5 | 6 | class LockerMock: Lockable { 7 | var accessToken: String? 8 | var refreshToken: String? 9 | var tokenType: String? 10 | var expiryDate: Date? 11 | var userName: String? 12 | var userUPN: String? 13 | 14 | required init(name: String) { 15 | 16 | } 17 | 18 | func clear() { 19 | 20 | } 21 | 22 | @discardableResult func synchronize() -> Bool { 23 | return false 24 | } 25 | } 26 | 27 | var locker: LockerMock! 28 | var config: AuthConfig! 29 | var service: AuthService! 30 | 31 | override func setUp() { 32 | super.setUp() 33 | 34 | locker = LockerMock(name: "locker") 35 | config = AuthConfig(clientId: "", accessTokenUrl: URL(string: "http://testservice.no")!) 36 | config.minimumValidity = 5 37 | service = AuthService(name: "service", config: config, locker: locker) 38 | } 39 | 40 | func testBeforeExpiredDate() { 41 | locker.expiryDate = Date(timeIntervalSinceNow: 1) 42 | XCTAssertTrue(service.tokenIsExpired) 43 | 44 | locker.expiryDate = Date(timeIntervalSinceNow: 2) 45 | XCTAssertTrue(service.tokenIsExpired) 46 | 47 | locker.expiryDate = Date(timeIntervalSinceNow: 5) 48 | XCTAssertTrue(service.tokenIsExpired) 49 | 50 | locker.expiryDate = Date(timeIntervalSinceNow: 6) 51 | XCTAssertFalse(service.tokenIsExpired) 52 | } 53 | 54 | func testExactExpiredDate() { 55 | locker.expiryDate = Date() 56 | XCTAssertTrue(service.tokenIsExpired) 57 | } 58 | 59 | func testAfterExpiredDate() { 60 | locker.expiryDate = Date(timeIntervalSinceNow: -1) 61 | XCTAssertTrue(service.tokenIsExpired) 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OhMyAuth 2 | 3 | ⚠️ DEPRECATED, NO LONGER MAINTAINED 4 | 5 | [![CI Status](https://circleci.com/gh/hyperoslo/OhMyAuth.png)](https://circleci.com/gh/hyperoslo/OhMyAuth) 6 | [![Version](https://img.shields.io/cocoapods/v/OhMyAuth.svg?style=flat)](http://cocoadocs.org/docsets/OhMyAuth) 7 | [![Carthage Compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) 8 | [![License](https://img.shields.io/cocoapods/l/OhMyAuth.svg?style=flat)](http://cocoadocs.org/docsets/OhMyAuth) 9 | [![Platform](https://img.shields.io/cocoapods/p/OhMyAuth.svg?style=flat)](http://cocoadocs.org/docsets/OhMyAuth) 10 | 11 | ## Description 12 | 13 | Simple `OAuth2` library with a support of multiple services. 14 | 15 | ## Usage 16 | 17 | - Setup: 18 | ```swift 19 | let config = AuthConfig( 20 | clientId: "client-id", 21 | accessTokenUrl: NSURL(string: "access-token-url")!, 22 | accessGrantType: "authorization_code", 23 | authorizeURL: NSURL(string: "authorise-url")!, 24 | changeUserURL: NSURL(string: "change-user-url")!, 25 | redirectURI: "yourapp://auth") 26 | 27 | config.extraAccessTokenParameters = ["resource": "resource"] 28 | config.extraRefreshTokenParameters = ["resource": "resource"] 29 | 30 | let service = AuthService(name: "service", config: config) 31 | AuthContainer.addService(service) 32 | ``` 33 | 34 | - Safari app will be opened by default for authorization, if it's iOS9 and you'd 35 | like to use `SFSafariViewController`, there is a ready-to-use class for you: 36 | ```swift 37 | // SFSafariViewController will be presented on top of provided controller 38 | service.config.webView = SafariWebView(viewController: viewController) 39 | ``` 40 | 41 | - Show a login web page: 42 | ```swift 43 | AuthContainer.serviceNamed("service")?.authorize() 44 | ``` 45 | 46 | - Handle response. If you use `SafariWebView` it will be dismissed ***automagically***: 47 | ```swift 48 | func application(app: UIApplication, openURL url: NSURL, options: [String : AnyObject]) -> Bool { 49 | AuthContainer.serviceNamed("service")?.accessToken(URL: url) { accessToken, error in 50 | if let accessToken = accessToken where error == nil { 51 | // User is logged in!!! 52 | } 53 | } 54 | } 55 | ``` 56 | 57 | - Get an access token to include it in the each request. If token is about to 58 | expire it will be refreshed ***automagically***, so you always get an active 59 | token is the completion closure: 60 | ```swift 61 | AuthContainer.serviceNamed("service")?.accessToken(completion) 62 | ``` 63 | 64 | - If you need to change user and have a separate URL for that: 65 | ```swift 66 | AuthContainer.serviceNamed("service")?.changeUser() 67 | ``` 68 | 69 | - If you don't have authorisation by code, but by username and password, 70 | there is a flow: 71 | ```swift 72 | let config = AuthConfig( 73 | clientId: "client-id", 74 | accessTokenUrl: NSURL(string: "access-token-url")!, 75 | accessGrantType: "password") 76 | 77 | let service = AuthService(name: "service", config: config) 78 | AuthContainer.addService(service) 79 | 80 | let parameters = ["username": "weirdo", "password": "123456"] 81 | service.accessToken(parameters: parameters) { accessToken, error in 82 | // Ready! 83 | } 84 | ``` 85 | 86 | - If you need to get your tokens, expiry date, username, user UPN: 87 | ```swift 88 | let accessToken = AuthContainer.serviceNamed("service")?.locker.accessToken 89 | let userUPN = AuthContainer.serviceNamed("service")?.locker.userUPN 90 | ``` 91 | 92 | And yeah, you could add as many auth services as you want if you have some 93 | crazy setup in the app. Just register a new one with a different name: 94 | ```swift 95 | let service = AuthService(name: "another-service", config: config) 96 | ``` 97 | 98 | ## Author 99 | 100 | Hyper Interaktiv AS, ios@hyper.no 101 | 102 | ## Installation 103 | 104 | **OhMyAuth** is available through [CocoaPods](http://cocoapods.org). To install 105 | it, simply add the following line to your Podfile: 106 | 107 | ```ruby 108 | pod 'OhMyAuth' 109 | ``` 110 | 111 | **OhMyAuth** is also available through [Carthage](https://github.com/Carthage/Carthage). 112 | To install just write into your Cartfile: 113 | 114 | ```ruby 115 | github "hyperoslo/OhMyAuth" 116 | ``` 117 | 118 | ## Author 119 | 120 | Hyper Interaktiv AS, ios@hyper.no 121 | 122 | ## Contributing 123 | 124 | We would love you to contribute to **OhMyAuth**, check the [CONTRIBUTING](https://github.com/hyperoslo/OhMyAuth/blob/master/CONTRIBUTING.md) file for more info. 125 | 126 | ## License 127 | 128 | **OhMyAuth** is available under the MIT license. See the [LICENSE](https://github.com/hyperoslo/OhMyAuth/blob/master/LICENSE.md) file for more info. 129 | -------------------------------------------------------------------------------- /Sources/Mac/Mac.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | -------------------------------------------------------------------------------- /Sources/Shared/AuthConfig.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | @objc open class AuthConfig: NSObject { 4 | 5 | public static var networking: Networking = Networking(configuration: URLSessionConfiguration.default) 6 | 7 | open var clientId: String 8 | open var accessGrantType: String 9 | open var accessTokenUrl: URL 10 | open var authorizeURL: URL? 11 | open var changeUserURL: URL? 12 | open var deauthorizeURL: URL? 13 | open var redirectURI: String? 14 | open var minimumValidity: TimeInterval = 5 * 60 15 | open var checkExpiry = true 16 | 17 | open var expiryDate: (_ data: [String : AnyObject]) -> Date? = { data -> Date? in 18 | var date: Date? 19 | 20 | if let expiresIn = data["expires_in"] as? Double { 21 | date = Date(timeIntervalSinceNow: expiresIn) 22 | } 23 | 24 | return date 25 | } 26 | 27 | open var extraAccessTokenParameters = [String: String]() 28 | open var extraRefreshTokenParameters = [String: String]() 29 | 30 | open var webView: WebViewable = BrowserWebView() 31 | 32 | let refreshGrantType = "refresh_token" 33 | var name = "OhMyAuth" 34 | 35 | open var headers: [String: String] = [:] 36 | 37 | var sharedParameters: [String: String] { 38 | var parameters = ["client_id" : clientId] 39 | 40 | if let redirectURI = redirectURI { 41 | parameters["redirect_uri"] = redirectURI 42 | } 43 | 44 | return parameters 45 | } 46 | 47 | var accessTokenParameters: [String: String] { 48 | var parameters = sharedParameters 49 | parameters["grant_type"] = accessGrantType 50 | 51 | extraAccessTokenParameters.forEach { key, value in 52 | parameters[key] = value 53 | } 54 | 55 | return parameters 56 | } 57 | 58 | var refreshTokenParameters: [String: String] { 59 | var parameters = sharedParameters 60 | parameters["grant_type"] = refreshGrantType 61 | 62 | extraRefreshTokenParameters.forEach { key, value in 63 | parameters[key] = value 64 | } 65 | 66 | return parameters 67 | } 68 | 69 | // MARK: - Initialization 70 | 71 | public init(clientId: String, accessTokenUrl: URL, accessGrantType: String = "authorization_code", 72 | authorizeURL: URL? = nil, changeUserURL: URL? = nil, redirectURI: String? = nil, headers: [String: String] = [:]) { 73 | self.clientId = clientId 74 | self.accessGrantType = accessGrantType 75 | self.accessTokenUrl = accessTokenUrl 76 | self.authorizeURL = authorizeURL 77 | self.changeUserURL = changeUserURL 78 | self.redirectURI = redirectURI 79 | self.headers = headers 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /Sources/Shared/AuthContainer.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | @objc open class AuthContainer: NSObject { 4 | 5 | static var services = [String: AuthService]() 6 | 7 | // MARK: - Services 8 | 9 | public static func addService(_ service: AuthService) { 10 | services[service.name] = service 11 | } 12 | 13 | public static func serviceNamed(_ name: String) -> AuthService? { 14 | return services[name] 15 | } 16 | 17 | // MARK: - Helpers 18 | 19 | public static func locker(_ serviceName: String) -> Lockable? { 20 | return serviceNamed(serviceName)?.locker 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Sources/Shared/AuthService.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | @objc open class AuthService: NSObject { 4 | 5 | public typealias Completion = (String?, Error?) -> Void 6 | 7 | public let name: String 8 | public let config: AuthConfig 9 | public var locker: Lockable 10 | 11 | fileprivate var pendingTokenCompletions = [Completion]() 12 | fileprivate var executing = false 13 | fileprivate let tokenQueue = DispatchQueue(label: "OhMyAuth.AuthService.TokenQueue") 14 | 15 | open var tokenIsExpired: Bool { 16 | guard let expiryDate = locker.expiryDate else { 17 | return true 18 | } 19 | 20 | let expiredTime = expiryDate.timeIntervalSince1970 21 | let timeNow = Date().timeIntervalSince1970 + config.minimumValidity 22 | let expired = timeNow >= expiredTime 23 | 24 | return expired 25 | } 26 | 27 | // MARK: - Initialization 28 | 29 | public init(name: String, config: AuthConfig, locker: Lockable? = nil) { 30 | self.name = name 31 | self.config = config 32 | self.config.name = name 33 | 34 | if let locker = locker { 35 | self.locker = locker 36 | } else { 37 | self.locker = KeychainLocker(name: name) 38 | } 39 | } 40 | 41 | // MARK: - Authorization 42 | 43 | open func authorize() -> Bool { 44 | guard let URL = config.authorizeURL else { return false } 45 | 46 | locker.clear() 47 | config.webView.open(URL) 48 | 49 | return true 50 | } 51 | 52 | open func changeUser() -> Bool { 53 | guard let URL = config.changeUserURL else { return false } 54 | 55 | locker.clear() 56 | config.webView.open(URL) 57 | 58 | return true 59 | } 60 | 61 | open func deauthorize(_ completion: () -> ()) -> Bool { 62 | guard let URL = config.deauthorizeURL else { return false } 63 | 64 | locker.clear() 65 | config.webView.open(URL) 66 | completion() 67 | 68 | return true 69 | } 70 | 71 | // MARK: - Tokens 72 | 73 | open func accessToken(_ force: Bool = false, completion: @escaping Completion) { 74 | tokenQueue.async(flags: .barrier, execute: { [weak self] in 75 | guard let weakSelf = self else { 76 | completion(nil, OhMyAuthError.authServiceDeallocated.toNSError()) 77 | return 78 | } 79 | 80 | guard force || (weakSelf.tokenIsExpired && weakSelf.config.checkExpiry) else { 81 | completion(weakSelf.locker.accessToken, nil) 82 | return 83 | } 84 | 85 | weakSelf.pendingTokenCompletions.append(completion) 86 | 87 | guard !weakSelf.executing else { return } 88 | 89 | weakSelf.refreshToken() { [weak self] accessToken, error in 90 | guard let weakSelf = self else { 91 | completion(nil, OhMyAuthError.authServiceDeallocated.toNSError()) 92 | return 93 | } 94 | 95 | weakSelf.tokenQueue.async(flags: .barrier, execute: { [weak self] in 96 | guard let weakSelf = self else { 97 | completion(nil, OhMyAuthError.authServiceDeallocated.toNSError()) 98 | return 99 | } 100 | 101 | weakSelf.pendingTokenCompletions.forEach { completion in 102 | completion(accessToken, error) 103 | } 104 | 105 | weakSelf.pendingTokenCompletions = [] 106 | }) 107 | } 108 | }) 109 | } 110 | 111 | open func accessToken(URL: Foundation.URL, completion: @escaping Completion) -> Bool { 112 | guard let redirectURI = config.redirectURI, 113 | let URLComponents = URLComponents(url: URL, resolvingAgainstBaseURL: false), 114 | let code = URLComponents.queryItems?.filter({ $0.name == "code" }).first?.value 115 | , URL.absoluteString.hasPrefix(redirectURI) 116 | else { 117 | completion(nil, OhMyAuthError.codeParameterNotFound.toNSError()) 118 | return false 119 | } 120 | 121 | accessToken(parameters: ["code" : code as AnyObject]) { [weak self] accessToken, error in 122 | completion(accessToken, error) 123 | self?.config.webView.close?() 124 | } 125 | 126 | return true 127 | } 128 | 129 | open func accessToken(parameters: [String: Any], completion: @escaping Completion) { 130 | let request = AccessTokenRequest(config: config, parameters: parameters) 131 | executeRequest(request, completion: completion) 132 | } 133 | 134 | open func refreshToken(_ completion: @escaping Completion) { 135 | guard let token = locker.refreshToken else { 136 | completion(nil, OhMyAuthError.noRefreshTokenFound.toNSError()) 137 | return 138 | } 139 | 140 | let request = RefreshTokenRequest(config: config, refreshToken: token) 141 | executeRequest(request, completion: completion) 142 | } 143 | 144 | open func cancel() { 145 | AuthConfig.networking.session.getTasksWithCompletionHandler { dataTasks, uploadTasks, downloadTasks in 146 | dataTasks.forEach { $0.cancel() } 147 | uploadTasks.forEach { $0.cancel() } 148 | downloadTasks.forEach { $0.cancel() } 149 | } 150 | } 151 | 152 | // MARK: - Helpers 153 | 154 | func executeRequest(_ request: NetworkRequestable, completion: @escaping Completion) { 155 | guard !executing else { 156 | completion(nil, OhMyAuthError.tokenRequestAlreadyStarted.toNSError()) 157 | return 158 | } 159 | 160 | executing = true 161 | 162 | TokenNetworkTask(locker: locker, config: config).execute(request) { [weak self] result in 163 | guard let weakSelf = self else { 164 | completion(nil, OhMyAuthError.authServiceDeallocated.toNSError()) 165 | return 166 | } 167 | 168 | weakSelf.executing = false 169 | 170 | switch result { 171 | case .failure(let error): 172 | completion(nil, error) 173 | case .success(let accessToken): 174 | completion(accessToken, nil) 175 | } 176 | } 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /Sources/Shared/Library/BrowserWebView.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | #if os(OSX) 4 | import Cocoa 5 | #else 6 | import UIKit 7 | #endif 8 | 9 | @objc open class BrowserWebView: NSObject, WebViewable { 10 | 11 | open func open(_ URL: Foundation.URL) { 12 | #if os(iOS) 13 | UIApplication.shared.openURL(URL) 14 | #elseif os(OSX) 15 | NSWorkspace.shared.open(URL) 16 | #endif 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Sources/Shared/Library/Error.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | @objc public enum OhMyAuthError: Int { 4 | case codeParameterNotFound = -1 5 | case noConfigFound = -2 6 | case noRefreshTokenFound = -3 7 | case tokenRequestFailed = -4 8 | case tokenRequestAlreadyStarted = -5 9 | case authServiceDeallocated = -6 10 | case internalError = -7 11 | 12 | // MARK: - Helpers 13 | 14 | public var defaultMessage: String { 15 | var message: String 16 | 17 | switch self { 18 | case .codeParameterNotFound: 19 | message = "Code parameter not found" 20 | case .noConfigFound: 21 | message = "No token or login config provided" 22 | case .noRefreshTokenFound: 23 | message = "No refresh token in locker" 24 | case .tokenRequestFailed: 25 | message = "Token request error" 26 | case .tokenRequestAlreadyStarted: 27 | message = "Token request has already been started" 28 | case .authServiceDeallocated: 29 | message = "AuthService has been deallocated" 30 | case .internalError: 31 | message = "Internal error" 32 | } 33 | 34 | return message 35 | } 36 | 37 | public func toNSError(_ message: String? = nil, userInfo: [String: Any] = [:]) -> NSError { 38 | let text = message ?? defaultMessage 39 | let domain = "OhMyAuth" 40 | 41 | NSLog("\(domain): \(text)") 42 | 43 | var dictionary = userInfo 44 | dictionary[NSLocalizedDescriptionKey] = text as AnyObject? 45 | 46 | return NSError(domain: domain, 47 | code: rawValue, 48 | userInfo: dictionary) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Sources/Shared/Library/Result.swift: -------------------------------------------------------------------------------- 1 | enum Result { 2 | case success(T) 3 | case failure(Error?) 4 | } 5 | -------------------------------------------------------------------------------- /Sources/Shared/Locker/KeychainLocker.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import Keychains 3 | 4 | @objc open class KeychainLocker: UserDefaultsLocker { 5 | 6 | // MARK: - Keychain 7 | 8 | open override var accessToken: String? { 9 | get { return getFromKeychain(Keys.accessToken) } 10 | set { saveInKeychain(Keys.accessToken, newValue) } 11 | } 12 | 13 | open override var refreshToken: String? { 14 | get { return getFromKeychain(Keys.refreshToken) } 15 | set { saveInKeychain(Keys.refreshToken, newValue) } 16 | } 17 | 18 | open override var tokenType: String? { 19 | get { return getFromKeychain(Keys.tokenType) } 20 | set { saveInKeychain(Keys.tokenType, newValue) } 21 | } 22 | 23 | // MARK: - Helpers 24 | 25 | func getFromKeychain(_ key: String) -> String? { 26 | let namedKey = generateKey(key) 27 | let password = Keychain.password(forAccount: namedKey, service: service) 28 | 29 | if let password = password, !password.isEmpty { 30 | return password 31 | } 32 | 33 | return nil 34 | } 35 | 36 | func saveInKeychain(_ key: String, _ value: String?) { 37 | let namedKey = generateKey(key) 38 | 39 | if let value = value { 40 | Keychain.setPassword(value, forAccount: namedKey, service: service) 41 | } else { 42 | Keychain.deletePassword(forAccount: namedKey, service: service) 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Sources/Shared/Locker/Keys.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct Keys { 4 | 5 | public static let accessToken = "AccessToken" 6 | public static let refreshToken = "RefreshToken" 7 | public static let tokenType = "TokenType" 8 | public static let expiryDate = "ExpiryDate" 9 | public static let userName = "UserName" 10 | public static let userUPN = "UserUPN" 11 | } 12 | -------------------------------------------------------------------------------- /Sources/Shared/Locker/Lockable.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | @objc public protocol Lockable { 4 | var accessToken: String? { get set } 5 | var refreshToken: String? { get set } 6 | var tokenType: String? { get set } 7 | var expiryDate: Date? { get set } 8 | var userName: String? { get set } 9 | var userUPN: String? { get set } 10 | 11 | init(name: String) 12 | func clear() 13 | @discardableResult func synchronize() -> Bool 14 | } 15 | 16 | public extension Lockable { 17 | 18 | public func migrate(from locker: Lockable) { 19 | accessToken = locker.accessToken 20 | refreshToken = locker.refreshToken 21 | tokenType = locker.tokenType 22 | expiryDate = locker.expiryDate 23 | userName = locker.userName 24 | userUPN = locker.userUPN 25 | 26 | locker.clear() 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Sources/Shared/Locker/SuiteDefaultsLocker.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | @objc open class SuiteDefaultsLocker: NSObject, Lockable { 4 | 5 | public let name: String 6 | public let suiteName: String 7 | public let userDefaults: UserDefaults! 8 | 9 | public init(name: String, suiteName: String) { 10 | self.name = name 11 | self.suiteName = suiteName 12 | self.userDefaults = UserDefaults(suiteName: suiteName) 13 | } 14 | 15 | public required init(name: String) { 16 | self.name = name 17 | self.suiteName = name 18 | self.userDefaults = UserDefaults(suiteName: suiteName) 19 | } 20 | 21 | // MARK: - Getters and setters 22 | 23 | open var accessToken: String? { 24 | get { return getFromDefaults(Keys.accessToken) } 25 | set { saveInDefaults(Keys.accessToken, newValue as AnyObject?) } 26 | } 27 | 28 | open var refreshToken: String? { 29 | get { return getFromDefaults(Keys.refreshToken) } 30 | set { saveInDefaults(Keys.refreshToken, newValue as AnyObject?) } 31 | } 32 | 33 | open var tokenType: String? { 34 | get { return getFromDefaults(Keys.tokenType) } 35 | set { saveInDefaults(Keys.tokenType, newValue as AnyObject?) } 36 | } 37 | 38 | open var expiryDate: Date? { 39 | get { return getFromDefaults(Keys.expiryDate) as Date? } 40 | set { saveInDefaults(Keys.expiryDate, newValue as AnyObject?) } 41 | } 42 | 43 | open var userName: String? { 44 | get { return getFromDefaults(Keys.userName) as String? } 45 | set { saveInDefaults(Keys.userName, newValue as AnyObject?) } 46 | } 47 | 48 | open var userUPN: String? { 49 | get { return getFromDefaults(Keys.userUPN) as String? } 50 | set { saveInDefaults(Keys.userUPN, newValue as AnyObject?) } 51 | } 52 | 53 | // MARK: - Helpers 54 | 55 | open func synchronize() -> Bool { 56 | return userDefaults.synchronize() 57 | } 58 | 59 | public func getFromDefaults(_ key: String) -> T? { 60 | let namedKey = generateKey(key) 61 | return userDefaults.object(forKey: namedKey) as? T 62 | } 63 | 64 | public func saveInDefaults(_ key: String, _ value: AnyObject?) { 65 | let namedKey = generateKey(key) 66 | 67 | if let value = value { 68 | userDefaults.set(value, forKey: namedKey) 69 | } else { 70 | userDefaults.removeObject(forKey: namedKey) 71 | } 72 | } 73 | 74 | public func generateKey(_ key: String) -> String { 75 | return "\(name)-\(suiteName)-\(key)" 76 | } 77 | 78 | // MARK: - Clear 79 | 80 | open func clear() { 81 | accessToken = nil 82 | refreshToken = nil 83 | tokenType = nil 84 | expiryDate = nil 85 | userName = nil 86 | userUPN = nil 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /Sources/Shared/Locker/UserDefaultsLocker.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | @objc open class UserDefaultsLocker: NSObject, Lockable { 4 | 5 | public let name: String 6 | public var service: String = Application.name 7 | public let userDefaults = UserDefaults.standard 8 | 9 | public required init(name: String) { 10 | self.name = name 11 | } 12 | 13 | // MARK: - Getters and setters 14 | 15 | open var accessToken: String? { 16 | get { return getFromDefaults(Keys.accessToken) } 17 | set { saveInDefaults(Keys.accessToken, newValue as AnyObject?) } 18 | } 19 | 20 | open var refreshToken: String? { 21 | get { return getFromDefaults(Keys.refreshToken) } 22 | set { saveInDefaults(Keys.refreshToken, newValue as AnyObject?) } 23 | } 24 | 25 | open var tokenType: String? { 26 | get { return getFromDefaults(Keys.tokenType) } 27 | set { saveInDefaults(Keys.tokenType, newValue as AnyObject?) } 28 | } 29 | 30 | open var expiryDate: Date? { 31 | get { return getFromDefaults(Keys.expiryDate) as Date? } 32 | set { saveInDefaults(Keys.expiryDate, newValue as AnyObject?) } 33 | } 34 | 35 | open var userName: String? { 36 | get { return getFromDefaults(Keys.userName) as String? } 37 | set { saveInDefaults(Keys.userName, newValue as AnyObject?) } 38 | } 39 | 40 | open var userUPN: String? { 41 | get { return getFromDefaults(Keys.userUPN) as String? } 42 | set { saveInDefaults(Keys.userUPN, newValue as AnyObject?) } 43 | } 44 | 45 | // MARK: - Helpers 46 | 47 | open func synchronize() -> Bool { 48 | return userDefaults.synchronize() 49 | } 50 | 51 | func getFromDefaults(_ key: String) -> T? { 52 | let namedKey = generateKey(key) 53 | return userDefaults.object(forKey: namedKey) as? T 54 | } 55 | 56 | func saveInDefaults(_ key: String, _ value: AnyObject?) { 57 | let namedKey = generateKey(key) 58 | 59 | if let value = value { 60 | userDefaults.set(value, forKey: namedKey) 61 | } else { 62 | userDefaults.removeObject(forKey: namedKey) 63 | } 64 | } 65 | 66 | public func generateKey(_ key: String) -> String { 67 | return "\(name)-\(service)-\(key)" 68 | } 69 | 70 | // MARK: - Clear 71 | 72 | open func clear() { 73 | accessToken = nil 74 | refreshToken = nil 75 | tokenType = nil 76 | expiryDate = nil 77 | userName = nil 78 | userUPN = nil 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /Sources/Shared/Networking/NetworkRequests.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | struct AccessTokenRequest: NetworkRequestable { 4 | let url: URL 5 | var parameters: [String: Any] 6 | var headers: [String: String] 7 | 8 | init(config: AuthConfig, parameters: [String: Any]) { 9 | url = config.accessTokenUrl 10 | 11 | self.parameters = config.accessTokenParameters 12 | self.headers = config.headers 13 | 14 | parameters.forEach { key, value in 15 | self.parameters[key] = value 16 | } 17 | } 18 | } 19 | 20 | struct RefreshTokenRequest: NetworkRequestable { 21 | let url: URL 22 | var parameters: [String: Any] 23 | var headers: [String: String] 24 | 25 | init(config: AuthConfig, refreshToken: String) { 26 | url = config.accessTokenUrl 27 | parameters = config.refreshTokenParameters 28 | parameters["refresh_token"] = refreshToken 29 | self.headers = config.headers 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Sources/Shared/Networking/NetworkTasks.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import JWTDecode 3 | 4 | struct TokenNetworkTask: NetworkTaskable, NetworkQueueable { 5 | 6 | let locker: Lockable 7 | let config: AuthConfig 8 | 9 | // MARK: - Initialization 10 | 11 | init(locker: Lockable, config: AuthConfig) { 12 | self.locker = locker 13 | self.config = config 14 | } 15 | 16 | // MARK: - Processing 17 | 18 | func process(_ data: [String : AnyObject]) throws -> String { 19 | guard let accessToken = data["access_token"] as? String else { 20 | locker.clear() 21 | NSLog("\(data)") 22 | throw OhMyAuthError.tokenRequestFailed.toNSError(userInfo: data) 23 | } 24 | 25 | if let refreshToken = data["refresh_token"] as? String { 26 | locker.refreshToken = refreshToken 27 | } 28 | 29 | guard let expiryDate = config.expiryDate(data) else { 30 | locker.clear() 31 | NSLog("\(data)") 32 | throw OhMyAuthError.tokenRequestFailed.toNSError() 33 | } 34 | 35 | locker.accessToken = accessToken 36 | locker.expiryDate = expiryDate 37 | locker.tokenType = data["token_type"] as? String 38 | 39 | if let jwtString = data["id_token"] as? String { 40 | do { 41 | let payload = try decode(jwt: jwtString) 42 | 43 | if let name = payload.body["name"] as? String { 44 | locker.userName = name 45 | } 46 | 47 | if let upn = payload.body["upn"] as? String { 48 | locker.userUPN = upn 49 | } 50 | } catch {} 51 | } 52 | 53 | locker.synchronize() 54 | 55 | return accessToken 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Sources/Shared/Networking/Networking.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | open class Networking { 4 | public let session: URLSession 5 | 6 | public init(configuration: URLSessionConfiguration) { 7 | session = URLSession(configuration: configuration, delegate: nil, delegateQueue: OperationQueue.main) 8 | } 9 | 10 | open func post(url: URL, parameters: [String: Any], headers: [String: String], completion: @escaping ((Data?, URLResponse?, Error?) -> Void)) { 11 | var request = URLRequest(url: url) 12 | 13 | headers.forEach { (key, value) in 14 | request.setValue(value, forHTTPHeaderField: key) 15 | } 16 | 17 | if request.value(forHTTPHeaderField: "Content-Type") == nil { 18 | request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") 19 | } 20 | 21 | request.httpMethod = "POST" 22 | 23 | request.httpBody = QueryBuilder() 24 | .buildQuery(from: parameters) 25 | .data(using: String.Encoding.utf8, allowLossyConversion: false) 26 | 27 | let task = session.dataTask(with: request) { (data, response, error) in 28 | completion(data, response, error) 29 | } 30 | 31 | task.resume() 32 | } 33 | } 34 | 35 | // https://github.com/hyperoslo/Malibu/blob/master/Sources/Helpers/QueryBuilder.swift 36 | fileprivate struct QueryBuilder { 37 | 38 | typealias Component = (String, String) 39 | 40 | let escapingCharacters = ":#[]@!$&'()*+,;=" 41 | 42 | init() {} 43 | 44 | func buildQuery(from parameters: [String: Any]) -> String { 45 | return buildComponents(from: parameters).map({ "\($0)=\($1)" }).joined(separator: "&") 46 | } 47 | 48 | func buildComponents(from parameters: [String: Any]) -> [Component] { 49 | var components: [Component] = [] 50 | 51 | for key in parameters.keys.sorted(by: <) { 52 | guard let value = parameters[key] else { 53 | continue 54 | } 55 | 56 | components += buildComponents(key: key, value: value) 57 | } 58 | 59 | return components 60 | } 61 | 62 | func buildComponents(key: String, value: Any) -> [Component] { 63 | var components: [Component] = [] 64 | 65 | if let dictionary = value as? [String: Any] { 66 | dictionary.forEach { nestedKey, value in 67 | components += buildComponents(key: "\(key)[\(nestedKey)]", value: value) 68 | } 69 | } else if let array = value as? [Any] { 70 | array.forEach { value in 71 | components += buildComponents(key: "\(key)[]", value: value) 72 | } 73 | } else if let bool = value as? Bool { 74 | components.append((escape(key), escape((bool ? "1" : "0")))) 75 | } else { 76 | components.append((escape(key), escape("\(value)"))) 77 | } 78 | 79 | return components 80 | } 81 | 82 | func escape(_ string: String) -> String { 83 | guard let allowedCharacters = (CharacterSet.urlQueryAllowed as NSCharacterSet).mutableCopy() as? NSMutableCharacterSet else { 84 | return string 85 | } 86 | 87 | allowedCharacters.removeCharacters(in: escapingCharacters) 88 | 89 | return string.addingPercentEncoding( 90 | withAllowedCharacters: allowedCharacters as CharacterSet) ?? string 91 | } 92 | } 93 | 94 | -------------------------------------------------------------------------------- /Sources/Shared/Protocols/NetworkRequestable.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | protocol NetworkRequestable { 4 | var url: URL { get } 5 | var parameters: [String: Any] { get } 6 | var headers: [String: String] { get } 7 | } 8 | 9 | extension NetworkRequestable { 10 | 11 | func start(using networking: Networking = AuthConfig.networking, completion: @escaping (_ result: Result) -> Void) { 12 | networking.post(url: url, parameters: parameters, headers: headers) { (data, response, error) in 13 | guard error == nil 14 | else { 15 | if let error = error { 16 | completion(Result.failure(error)) 17 | } else { 18 | completion(Result.failure(OhMyAuthError.internalError.toNSError())) 19 | } 20 | 21 | return 22 | } 23 | 24 | guard let response = response as? HTTPURLResponse else { 25 | completion(Result.failure(OhMyAuthError.internalError.toNSError())) 26 | return 27 | } 28 | 29 | guard let data = data, 30 | let jsonObject = try? JSONSerialization.jsonObject(with: data, options: .allowFragments), 31 | let json = jsonObject as? [String: Any] 32 | else { 33 | completion(Result.failure(OhMyAuthError.internalError.toNSError())) 34 | return 35 | } 36 | 37 | if response.statusCode != 401 { 38 | completion(Result.success(json)) 39 | } else { 40 | var userInfo: [String: Any] = json 41 | userInfo["statusCode"] = response.statusCode 42 | 43 | completion(.failure(OhMyAuthError.tokenRequestFailed.toNSError(userInfo: userInfo))) 44 | } 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Sources/Shared/Protocols/NetworkTaskable.swift: -------------------------------------------------------------------------------- 1 | protocol NetworkQueueable {} 2 | 3 | protocol NetworkTaskable { 4 | associatedtype Input 5 | associatedtype Output 6 | 7 | func process(_ data: Input) throws -> Output 8 | } 9 | 10 | extension NetworkTaskable { 11 | 12 | func execute(_ request: NetworkRequestable, completion: @escaping (Result) -> Void) { 13 | request.start { result in 14 | switch result { 15 | case .success(let data): 16 | guard let data = data as? Input else { 17 | completion(.failure(OhMyAuthError.tokenRequestFailed.toNSError())) 18 | return 19 | } 20 | 21 | do { 22 | let output = try self.process(data) 23 | completion(.success(output)) 24 | } catch { 25 | completion(.failure(error)) 26 | } 27 | case .failure(let error): 28 | completion(.failure(error)) 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Sources/Shared/Protocols/WebViewable.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | @objc public protocol WebViewable { 4 | func open(_ URL: URL) 5 | @objc optional func close() 6 | } 7 | 8 | -------------------------------------------------------------------------------- /Sources/Shared/Utils.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | struct Application { 4 | 5 | static var name: String { 6 | guard let infoDictionary = Bundle.main.infoDictionary, 7 | let value = infoDictionary["CFBundleDisplayName"] as? String 8 | else { return "" } 9 | 10 | return value 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Sources/iOS/SafariWebView.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import SafariServices 3 | 4 | @available(iOS 9, *) 5 | @objc public class SafariWebView: NSObject, WebViewable { 6 | 7 | public var animated: Bool 8 | let viewController: UIViewController 9 | 10 | public init(viewController: UIViewController, animated: Bool = true) { 11 | self.viewController = viewController 12 | self.animated = animated 13 | } 14 | 15 | public func open(_ url: URL) { 16 | let webViewController = SFSafariViewController(url: url) 17 | viewController.present(webViewController, animated: animated, completion: nil) 18 | } 19 | 20 | public func close() { 21 | DispatchQueue.main.async { 22 | UIApplication.presentedViewController()?.dismiss(animated: true, completion: nil) 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Sources/iOS/UIApplication+OhMyAuth.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | extension UIApplication { 4 | 5 | class func presentedViewController(rootController: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? { 6 | 7 | if let navigationController = rootController as? UINavigationController { 8 | return presentedViewController(rootController: navigationController.visibleViewController) 9 | } 10 | 11 | if let tabBarController = rootController as? UITabBarController { 12 | if let selectedController = tabBarController.selectedViewController { 13 | return presentedViewController(rootController: selectedController) 14 | } 15 | } 16 | 17 | if let presented = rootController?.presentedViewController { 18 | return presentedViewController(rootController: presented) 19 | } 20 | 21 | return rootController 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /bin/bootstrap: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | carthage bootstrap 4 | cp Cartfile.resolved Carthage 5 | -------------------------------------------------------------------------------- /bin/bootstrap-if-needed: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if ! cmp -s Cartfile.resolved Carthage/Cartfile.resolved; then 4 | bin/bootstrap 5 | fi 6 | -------------------------------------------------------------------------------- /circle.yml: -------------------------------------------------------------------------------- 1 | machine: 2 | xcode: 3 | version: "9.0" 4 | 5 | dependencies: 6 | override: 7 | - bin/bootstrap-if-needed 8 | cache_directories: 9 | - "Carthage" 10 | 11 | test: 12 | override: 13 | - set -o pipefail && xcodebuild -project OhMyAuth.xcodeproj -scheme "OhMyAuth-Mac" -sdk macosx clean build 14 | - set -o pipefail && xcodebuild -project OhMyAuth.xcodeproj -scheme "OhMyAuth-Mac" -sdk macosx -enableCodeCoverage YES test 15 | - set -o pipefail && xcodebuild -project OhMyAuth.xcodeproj -scheme "OhMyAuth-iOS" -sdk iphonesimulator clean build 16 | - set -o pipefail && xcodebuild -project OhMyAuth.xcodeproj -scheme "OhMyAuth-iOS" -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 8,OS=11.0.1' -enableCodeCoverage YES test --------------------------------------------------------------------------------