Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature login route property #215

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion LineSDK/LineSDK/Login/LoginManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,8 @@ public class LoginManager {
permissions: Set(token.permissions),
userProfile: profile,
friendshipStatusChanged: response.friendshipStatusChanged,
IDTokenNonce: process.IDTokenNonce)
IDTokenNonce: process.IDTokenNonce
)
}
completion(result)
}
Expand Down
47 changes: 43 additions & 4 deletions LineSDK/LineSDK/Login/LoginProcess.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,17 @@ import SafariServices
/// login flows will run serially. If a flow logs in the user successfully, subsequent flows will not be
/// executed.
public class LoginProcess {

/// Represents a login route for how the auth flow is initiated.
public enum LoginRoute: String {
/// The auth flow starts with a LINE app universal link.
case appUniversalLink
/// The auth flow starts with a LINE customize URL scheme.
case appAuthScheme
/// The auth flow starts in a web page inside LINE SDK.
case webLogin
}

struct FlowParameters {
let channelID: String
let universalLinkURL: URL?
Expand Down Expand Up @@ -75,24 +86,52 @@ public class LoginProcess {
let configuration: LoginConfiguration
let scopes: Set<LoginPermission>
let parameters: LoginManager.Parameters

// Flows of login process. A flow will be `nil` until it is running, so we could tell which one should take
// responsibility to handle a url callback response.

// LINE Client app auth flow captured by LINE universal link.
var appUniversalLinkFlow: AppUniversalLinkFlow?
var appUniversalLinkFlow: AppUniversalLinkFlow? {
didSet {
if appUniversalLinkFlow != nil && loginRoute == nil {
loginRoute = .appUniversalLink
}
}
}
// LINE Client app auth flow by LINE customize URL scheme.
var appAuthSchemeFlow: AppAuthSchemeFlow?
var appAuthSchemeFlow: AppAuthSchemeFlow? {
didSet {
if appAuthSchemeFlow != nil && loginRoute == nil {
loginRoute = .appAuthScheme
}
}
}

// Web login flow with Safari View Controller or Mobile Safari
var webLoginFlow: WebLoginFlow? {
didSet {
// Dismiss safari view controller (if exists) when reset web login flow.
if webLoginFlow == nil {
oldValue?.dismiss()
}

if webLoginFlow != nil && loginRoute == nil {
loginRoute = .webLogin
}
}
}


/// Describes how the authentication flow is initiated for this login result.
///
/// If the LINE app was launched to obtain this result, the value will be either `.appUniversalLink` or
/// `.appAuthScheme`, depending on how the LINE app was opened. If authentication occurred via a web page within
/// the LINE SDK, the value will be `.webLogin`. If the authentication flow is never or not yet initiated, the value
/// will be `nil`.
///
/// This value is `nil` until the process starts the auth flow actually. You can access this value safely when an
/// auth result is retrieved.
public private(set) var loginRoute: LoginRoute?

// When we leave current app, we need to set the switching observer
// to intercept cancel event (switching back but without a token url response)
var appSwitchingObserver: AppSwitchingObserver?
Expand Down
2 changes: 2 additions & 0 deletions LineSDK/LineSDK/Login/LoginResult.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import Foundation

/// Represents a successful login.
public struct LoginResult {

/// The access token obtained by the login process.
public let accessToken: AccessToken
/// The permissions bound to the `accessToken` object by the authorization process.
Expand All @@ -48,6 +49,7 @@ extension LoginResult: Encodable {
case userProfile
case friendshipStatusChanged
case IDTokenNonce
case loginRoute
}

/// :nodoc:
Expand Down
4 changes: 3 additions & 1 deletion LineSDK/LineSDKObjC/Login/LineSDKLoginProcess.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
public class LineSDKLoginProcess: NSObject {
let _value: LoginProcess
init(_ value: LoginProcess) { _value = value }


public var loginRoute: String? { return _value.loginRoute?.rawValue }

public func stop() { _value.stop() }
}
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ - (void)testLoginResultInterface {

- (void)testLoginProcessInterface {
LineSDKLoginProcess *process = nil;
XCTAssertNil(process.loginRoute);
[process stop];
}

Expand Down
59 changes: 54 additions & 5 deletions LineSDK/LineSDKTests/Login/LoginManagerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,19 @@
import XCTest
@testable import LineSDK

let sampleFlowParameters = LoginProcess.FlowParameters(
channelID: "",
universalLinkURL: nil,
scopes: [],
pkce: .init(),
processID: "",
nonce: nil,
botPrompt: nil,
preferredWebPageLanguage: nil,
onlyWebLogin: false,
promptBotID: nil
)

class LoginManagerTests: XCTestCase, ViewControllerCompatibleTest {

var window: UIWindow!
Expand Down Expand Up @@ -60,8 +73,9 @@ class LoginManagerTests: XCTestCase, ViewControllerCompatibleTest {
configuration: LoginConfiguration.shared,
delegate: delegateStub
)

let process = LoginManager.shared.login(permissions: [.profile], in: setupViewController()) {

var process: LoginProcess!
process = LoginManager.shared.login(permissions: [.profile], in: setupViewController()) {
loginResult in
XCTAssertNotNil(loginResult.value)

Expand All @@ -74,16 +88,22 @@ class LoginManagerTests: XCTestCase, ViewControllerCompatibleTest {

// IDTokenNonce should be `nil` when `.openID` not required.
XCTAssertNil(result.IDTokenNonce)


XCTAssertEqual(process.loginRoute, .appUniversalLink)

try! AccessTokenStore.shared.removeCurrentAccessToken()
expect.fulfill()
}!


// Set a sample value for checking `loginRoute` in the result.
process.appUniversalLinkFlow = AppUniversalLinkFlow(parameter: sampleFlowParameters)

DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {

XCTAssertFalse(LoginManager.shared.isAuthorized)
XCTAssertTrue(LoginManager.shared.isAuthorizing)


// Simulate auth result
let urlString = "\(Constant.thirdPartyAppReturnURL)?code=123&state=\(process.processID)"
let handled = process.resumeOpenURL(url: URL(string: urlString)!)
XCTAssertTrue(handled)
Expand Down Expand Up @@ -173,5 +193,34 @@ class LoginManagerTests: XCTestCase, ViewControllerCompatibleTest {
waitForExpectations(timeout: 1, handler: nil)
}

func testLoginProcessRouteSetting() {
XCTContext.runActivity(named: "app universal link") { _ in
let process = LoginProcess(
configuration: .shared, scopes: [], parameters: .init(), viewController: setupViewController()
)
XCTAssertNil(process.loginRoute)
process.appUniversalLinkFlow = AppUniversalLinkFlow(parameter: sampleFlowParameters)
XCTAssertEqual(process.loginRoute, .appUniversalLink)
}

XCTContext.runActivity(named: "app auth") { _ in
let process = LoginProcess(
configuration: .shared, scopes: [], parameters: .init(), viewController: setupViewController()
)
XCTAssertNil(process.loginRoute)
process.appAuthSchemeFlow = AppAuthSchemeFlow(parameter: sampleFlowParameters)
XCTAssertEqual(process.loginRoute, .appAuthScheme)
}

XCTContext.runActivity(named: "web login") { _ in
let process = LoginProcess(
configuration: .shared, scopes: [], parameters: .init(), viewController: setupViewController()
)
XCTAssertNil(process.loginRoute)
process.webLoginFlow = WebLoginFlow(parameter: sampleFlowParameters)
XCTAssertEqual(process.loginRoute, .webLogin)
}
}

}

Loading