Skip to content

Commit

Permalink
added files from previous project, added podspec
Browse files Browse the repository at this point in the history
  • Loading branch information
edjiang committed May 11, 2016
1 parent 836617a commit d0f5bdc
Show file tree
Hide file tree
Showing 7 changed files with 294 additions and 0 deletions.
35 changes: 35 additions & 0 deletions Simplicity.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@
/* Begin PBXBuildFile section */
DF74EC341CE2A8BB008F16BF /* Simplicity.h in Headers */ = {isa = PBXBuildFile; fileRef = DF74EC331CE2A8BB008F16BF /* Simplicity.h */; settings = {ATTRIBUTES = (Public, ); }; };
DF74EC3F1CE2A943008F16BF /* LICENSE in Resources */ = {isa = PBXBuildFile; fileRef = DF74EC3E1CE2A943008F16BF /* LICENSE */; };
DF74EC411CE2AC2F008F16BF /* LoginProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF74EC401CE2AC2F008F16BF /* LoginProvider.swift */; };
DF74EC431CE2AC45008F16BF /* OAuth2LoginProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF74EC421CE2AC45008F16BF /* OAuth2LoginProvider.swift */; };
DF74EC451CE2AC54008F16BF /* Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF74EC441CE2AC54008F16BF /* Helpers.swift */; };
DF74EC471CE2AC6F008F16BF /* Simplicity.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF74EC461CE2AC6F008F16BF /* Simplicity.swift */; };
DF74EC4A1CE2ACF0008F16BF /* Facebook.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF74EC491CE2ACF0008F16BF /* Facebook.swift */; };
DF74EC4C1CE2AD19008F16BF /* Stormpath.podspec in Resources */ = {isa = PBXBuildFile; fileRef = DF74EC4B1CE2AD19008F16BF /* Stormpath.podspec */; };
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
Expand All @@ -18,6 +24,12 @@
DF74EC3B1CE2A919008F16BF /* .gitignore */ = {isa = PBXFileReference; lastKnownFileType = text; path = .gitignore; sourceTree = "<group>"; };
DF74EC3C1CE2A936008F16BF /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
DF74EC3E1CE2A943008F16BF /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = "<group>"; };
DF74EC401CE2AC2F008F16BF /* LoginProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginProvider.swift; sourceTree = "<group>"; };
DF74EC421CE2AC45008F16BF /* OAuth2LoginProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OAuth2LoginProvider.swift; sourceTree = "<group>"; };
DF74EC441CE2AC54008F16BF /* Helpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Helpers.swift; sourceTree = "<group>"; };
DF74EC461CE2AC6F008F16BF /* Simplicity.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Simplicity.swift; sourceTree = "<group>"; };
DF74EC491CE2ACF0008F16BF /* Facebook.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Facebook.swift; path = LoginProviders/Facebook.swift; sourceTree = "<group>"; };
DF74EC4B1CE2AD19008F16BF /* Stormpath.podspec */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Stormpath.podspec; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand All @@ -34,6 +46,7 @@
DF74EC261CE2A8BB008F16BF = {
isa = PBXGroup;
children = (
DF74EC4B1CE2AD19008F16BF /* Stormpath.podspec */,
DF74EC3E1CE2A943008F16BF /* LICENSE */,
DF74EC3C1CE2A936008F16BF /* README.md */,
DF74EC3B1CE2A919008F16BF /* .gitignore */,
Expand All @@ -53,12 +66,25 @@
DF74EC321CE2A8BB008F16BF /* Simplicity */ = {
isa = PBXGroup;
children = (
DF74EC481CE2ACB8008F16BF /* LoginProviders */,
DF74EC331CE2A8BB008F16BF /* Simplicity.h */,
DF74EC351CE2A8BB008F16BF /* Info.plist */,
DF74EC401CE2AC2F008F16BF /* LoginProvider.swift */,
DF74EC421CE2AC45008F16BF /* OAuth2LoginProvider.swift */,
DF74EC441CE2AC54008F16BF /* Helpers.swift */,
DF74EC461CE2AC6F008F16BF /* Simplicity.swift */,
);
path = Simplicity;
sourceTree = "<group>";
};
DF74EC481CE2ACB8008F16BF /* LoginProviders */ = {
isa = PBXGroup;
children = (
DF74EC491CE2ACF0008F16BF /* Facebook.swift */,
);
name = LoginProviders;
sourceTree = "<group>";
};
/* End PBXGroup section */

/* Begin PBXHeadersBuildPhase section */
Expand Down Expand Up @@ -128,6 +154,7 @@
buildActionMask = 2147483647;
files = (
DF74EC3F1CE2A943008F16BF /* LICENSE in Resources */,
DF74EC4C1CE2AD19008F16BF /* Stormpath.podspec in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand All @@ -138,6 +165,11 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
DF74EC411CE2AC2F008F16BF /* LoginProvider.swift in Sources */,
DF74EC451CE2AC54008F16BF /* Helpers.swift in Sources */,
DF74EC4A1CE2ACF0008F16BF /* Facebook.swift in Sources */,
DF74EC471CE2AC6F008F16BF /* Simplicity.swift in Sources */,
DF74EC431CE2AC45008F16BF /* OAuth2LoginProvider.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -238,6 +270,7 @@
DF74EC391CE2A8BB008F16BF /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
Expand All @@ -248,12 +281,14 @@
PRODUCT_BUNDLE_IDENTIFIER = com.stormpath.Simplicity;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
DF74EC3A1CE2A8BB008F16BF /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
Expand Down
57 changes: 57 additions & 0 deletions Simplicity/Helpers.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
//
// Helpers.swift
// Simplicity
//
// Created by Edward Jiang on 5/10/16.
// Copyright © 2016 Stormpath. All rights reserved.
//

import Foundation

class Helpers {
static func registeredURLSchemes(matching closure: String -> Bool) -> [String] {
guard let urlTypes = NSBundle.mainBundle().infoDictionary?["CFBundleURLTypes"] as? [[String: AnyObject]] else {
return [String]()
}

// Convert the complex dictionary into an array of URL schemes
let urlSchemes = urlTypes.flatMap({($0["CFBundleURLSchemes"] as? [String])?.first })

return urlSchemes.flatMap({closure($0) ? $0 : nil})
}

static func queryString(parts: [String: String]) -> String? {
return parts.map { $0 + "=" + $1 }.joinWithSeparator("&").stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet())
}
}

extension NSURL {
/// Dictionary with key/value pairs from the URL fragment
var fragmentDictionary: [String: String] {
return dictionaryFromFormEncodedString(fragment)
}

/// Dictionary with key/value pairs from the URL query string
var queryDictionary: [String: String] {
return dictionaryFromFormEncodedString(query)
}

private func dictionaryFromFormEncodedString(input: String?) -> [String: String] {
var result = [String: String]()

guard let input = input else {
return result
}
let inputPairs = input.componentsSeparatedByString("&")

for pair in inputPairs {
let split = pair.componentsSeparatedByString("=")
if split.count == 2 {
if let key = split[0].stringByRemovingPercentEncoding, value = split[1].stringByRemovingPercentEncoding {
result[key] = value
}
}
}
return result
}
}
17 changes: 17 additions & 0 deletions Simplicity/LoginProvider.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//
// LoginProvider.swift
// Simplicity
//
// Created by Edward Jiang on 5/10/16.
// Copyright © 2016 Stormpath. All rights reserved.
//

import Foundation

public protocol LoginProvider {
var authorizationURL: NSURL { get }
var urlScheme: String { get }

func linkHandler(url: NSURL, callback: ExternalLoginCallback?)

}
64 changes: 64 additions & 0 deletions Simplicity/LoginProviders/Facebook.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
//
// Facebook.swift
// Simplicity
//
// Created by Edward Jiang on 5/10/16.
// Copyright © 2016 Stormpath. All rights reserved.
//

import Foundation

public class FacebookLoginProvider: OAuth2LoginProvider {
public var scopes = Set<String>()
public var urlScheme: String

public var state = arc4random_uniform(10000000)
public var clientId: String
public var grantType: OAuth2GrantType = .Custom


public var authorizationURL: NSURL {
// Auth_type is re-request since we need to ask for email scope again if
// people decline the email permission. If it gets annoying because
// people keep asking for more scopes, we can change this.

let query = ["client_id": clientId,
"redirect_uri": urlScheme + "://authorize",
"response_type": "token",
"scope": scopes.joinWithSeparator(" "),
"auth_type": "rerequest",
"state": String(state)]

let queryString = Helpers.queryString(query)!

return NSURL(string: "https://www.facebook.com/dialog/oauth?\(queryString)")!
}

public func linkHandler(url: NSURL, callback: ExternalLoginCallback?) {
if(url.queryDictionary["error"] != nil) {
// We are not even going to callback, because the user never started
// the login process in the first place. Error is always because
// people cancelled the FB login according to https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow
return
}

// Get the access token, and check that the state is the same
guard let accessToken = url.fragmentDictionary["access_token"] where url.fragmentDictionary["state"] == "\(state)" else {
callback?(authToken: nil, error: nil)
return
}

callback?(authToken: accessToken, error: nil)
}

public init?() {
// Search for URL Scheme, error if not there

guard let urlScheme = Helpers.registeredURLSchemes(matching: {$0.hasPrefix("fb")}).first,
range = urlScheme.rangeOfString("\\d+", options: .RegularExpressionSearch) else {
return nil
}
self.urlScheme = urlScheme
self.clientId = urlScheme.substringWithRange(range)
}
}
30 changes: 30 additions & 0 deletions Simplicity/OAuth2LoginProvider.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//
// OAuth2LoginProvider.swift
// Simplicity
//
// Created by Edward Jiang on 5/10/16.
// Copyright © 2016 Stormpath. All rights reserved.
//

import Foundation

public protocol OAuth2LoginProvider: LoginProvider {
var clientId: String { get }
var scopes: Set<String> { get set }
var grantType: OAuth2GrantType { get }
}

public protocol OAuth2Scopes {
var set: Set<String> { get set }
var string: String { get }
}

public extension OAuth2Scopes {
public var string: String {
return set.joinWithSeparator(" ")
}
}

public enum OAuth2GrantType {
case AuthorizationCode, Implicit, Custom
}
49 changes: 49 additions & 0 deletions Simplicity/Simplicity.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//
// Simplicity.swift
// Simplicity
//
// Created by Edward Jiang on 5/10/16.
// Copyright © 2016 Stormpath. All rights reserved.
//

import UIKit
import SafariServices

public typealias ExternalLoginCallback = (authToken: String?, error: NSError?) -> Void

public class LoginManager: NSObject {
static var currentLoginProvider: LoginProvider?
static var callback: ExternalLoginCallback?
static var safari: UIViewController?

public static func login(loginProvider: LoginProvider, callback: ExternalLoginCallback? = nil) {
self.currentLoginProvider = loginProvider
self.callback = callback

presentSafariView(loginProvider.authorizationURL)
}

/// Deep link handler (iOS9)
public static func application(app: UIApplication, openURL url: NSURL, options: [String : AnyObject]) -> Bool {
if url.scheme != currentLoginProvider?.urlScheme {
return false
}
currentLoginProvider?.linkHandler(url, callback: callback)

return true
}

/// Deep link handler (<iOS9)
public static func application(application: UIApplication, openURL url: NSURL, sourceApplication: String?, annotation: AnyObject) -> Bool {
return self.application(application, openURL: url, options: [String: AnyObject]())
}

static func presentSafariView(url: NSURL) {
if #available(iOS 9, *) {
safari = SFSafariViewController(URL: url)
UIApplication.sharedApplication().delegate?.window??.rootViewController?.presentViewController(safari!, animated: true, completion: nil)
} else {
UIApplication.sharedApplication().openURL(url)
}
}
}
42 changes: 42 additions & 0 deletions Stormpath.podspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#
# Be sure to run `pod lib lint Simplicity.podspec' to ensure this is a
# valid spec before submitting.
#
# Any lines starting with a # are optional, but their use is encouraged
# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html
#

Pod::Spec.new do |s|
s.name = "Simplicity"
s.version = "0.1.0"
s.summary = "A framework for authenticating with external providers on iOS"

# This description is used to generate tags and improve search results.
# * Think: What does it do? Why did you write it? What is the focus?
# * Try to keep it short, snappy and to the point.
# * Write the description between the DESC delimiters below.
# * Finally, don't worry about the indent, CocoaPods strips it!

s.description = <<-DESC
A framework for authenticating with external providers on iOS
DESC

s.homepage = "https://github.com/SimplicityMobile/Simplicity"
# s.screenshots = "www.example.com/screenshots_1", "www.example.com/screenshots_2"
s.license = 'Apache2'
s.author = { "Edward Jiang" => "[email protected]" }
s.source = { :git => "https://github.com/SimplicityMobile/Simplicity.git", :tag => s.version.to_s }
# s.social_media_url = 'https://twitter.com/<TWITTER_USERNAME>'

s.ios.deployment_target = '8.0'

s.source_files = 'Simplicity/**/*.swift'

# s.resource_bundles = {
# 'Simplicity' => ['Simplicity/Assets/*.png']
# }

s.public_header_files = 'Simplicity/**/*.h'
# s.frameworks = 'UIKit', 'MapKit'
# s.dependency 'AFNetworking', '~> 2.3'
end

0 comments on commit d0f5bdc

Please sign in to comment.