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

refactor: Remove core dependency #10

Merged
merged 6 commits into from
Jan 16, 2024
Merged
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
63 changes: 0 additions & 63 deletions Package.resolved
Original file line number Diff line number Diff line change
@@ -1,33 +1,6 @@
{
"object": {
"pins": [
{
"package": "Alamofire",
"repositoryURL": "https://github.com/Alamofire/Alamofire",
"state": {
"branch": null,
"revision": "3dc6a42c7727c49bf26508e29b0a0b35f9c7e1ad",
"version": "5.8.1"
}
},
{
"package": "CocoaLumberjack",
"repositoryURL": "https://github.com/CocoaLumberjack/CocoaLumberjack",
"state": {
"branch": null,
"revision": "363ed23d19a931809ea834a7d722da830353806a",
"version": "3.8.2"
}
},
{
"package": "InfomaniakCore",
"repositoryURL": "https://github.com/Infomaniak/ios-core",
"state": {
"branch": null,
"revision": "504932a51c978b6aa0bbc086054875a36241674e",
"version": "5.0.1"
}
},
{
"package": "InfomaniakDI",
"repositoryURL": "https://github.com/Infomaniak/ios-dependency-injection",
Expand All @@ -36,42 +9,6 @@
"revision": "8dc9e67e6d3d9f4f5bd02d693a7ce1f93b125bcd",
"version": "2.0.1"
}
},
{
"package": "RealmDatabase",
"repositoryURL": "https://github.com/realm/realm-core.git",
"state": {
"branch": null,
"revision": "7227d6a447821c28895daa099b6c7cd4c99d461b",
"version": "13.25.1"
}
},
{
"package": "Realm",
"repositoryURL": "https://github.com/realm/realm-swift",
"state": {
"branch": null,
"revision": "836cc4b8619886f979f8961c3f592a82b0741591",
"version": "10.45.3"
}
},
{
"package": "Sentry",
"repositoryURL": "https://github.com/getsentry/sentry-cocoa",
"state": {
"branch": null,
"revision": "3b9a8e69ca296bd8cd0e317ad7a448e5daf4a342",
"version": "8.18.0"
}
},
{
"package": "swift-log",
"repositoryURL": "https://github.com/apple/swift-log.git",
"state": {
"branch": null,
"revision": "532d8b529501fb73a2455b179e0bbb6d49b652ed",
"version": "1.5.3"
}
}
]
},
Expand Down
6 changes: 3 additions & 3 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import PackageDescription
let package = Package(
name: "InfomaniakLogin",
platforms: [
.iOS(.v13),
.iOS(.v12),
.macOS(.v11)
],
products: [
Expand All @@ -15,13 +15,13 @@ let package = Package(
targets: ["InfomaniakLogin"]),
],
dependencies: [
.package(url: "https://github.com/Infomaniak/ios-core", .upToNextMajor(from: "5.0.1")),
.package(url: "https://github.com/Infomaniak/ios-dependency-injection", .upToNextMajor(from: "2.0.0")),
],
targets: [
.target(
name: "InfomaniakLogin",
dependencies: [
.product(name: "InfomaniakCore", package: "ios-core"),
.product(name: "InfomaniakDI", package: "ios-dependency-injection"),
]),
.testTarget(
name: "InfomaniakLoginTests",
Expand Down
66 changes: 66 additions & 0 deletions Sources/InfomaniakLogin/Config.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
Copyright 2023 Infomaniak Network SA

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import Foundation

public enum AccessType: String {
/// When using `offline` accessToken has an expiration date and a refresh token is returned by the back-end
case offline
}

public enum ResponseType: String {
case code
}

public extension InfomaniakLogin {
struct Config {
let clientId: String
let loginURL: URL
let redirectURI: String
let responseType: ResponseType
let accessType: AccessType
let hashMode: String
let hashModeShort: String

/// Initializes an OAuth2 configuration for a given Infomaniak client app
///
/// - Parameters:
/// - clientId: An identifier provided by the backend.
/// - loginURL: Base URL for login calls, defaults to production. Can be replaced with preprod.
/// - redirectURI: Should match the app bundle ID.
/// - responseType: The response type, currently only supports `.code`.
/// - accessType: Use `.offline` for refresh token-based auth, `.none` or `nil` for non expiring token.
/// - hashMode: The hash mode, defaults to "SHA-256".
/// - hashModeShort: A short version of the hash mode, defaults to "S256".
public init(
PhilippeWeidmann marked this conversation as resolved.
Show resolved Hide resolved
clientId: String,
loginURL: URL = URL(string: "https://login.infomaniak.com/")!,
redirectURI: String = "\(Bundle.main.bundleIdentifier ?? "")://oauth2redirect",
responseType: ResponseType = .code,
accessType: AccessType = .offline,
hashMode: String = "SHA-256",
hashModeShort: String = "S256"
) {
self.clientId = clientId
self.loginURL = loginURL
self.redirectURI = redirectURI
self.responseType = responseType
self.accessType = accessType
self.hashMode = hashMode
self.hashModeShort = hashModeShort
}
}
}
8 changes: 5 additions & 3 deletions Sources/InfomaniakLogin/DeleteAccountViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*/

#if canImport(UIKit)
import InfomaniakCore
import InfomaniakDI
import UIKit
import WebKit

Expand All @@ -25,6 +25,8 @@ public protocol DeleteAccountDelegate: AnyObject {
}

public class DeleteAccountViewController: UIViewController {
@LazyInjectService var infomaniakLogin: InfomaniakLoginable
PhilippeWeidmann marked this conversation as resolved.
Show resolved Hide resolved

private var webView: WKWebView!
private var progressView: UIProgressView!
public var navBarColor: UIColor?
Expand All @@ -46,7 +48,7 @@ public class DeleteAccountViewController: UIViewController {
override public func viewDidLoad() {
super.viewDidLoad()

if let url = Constants.autologinUrl(to: Constants.DELETEACCOUNT_URL) {
if let url = Constants.autologinUrl(to: Constants.deleteAccountURL) {
if let accessToken = accessToken {
var request = URLRequest(url: url)
request.setValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization")
Expand Down Expand Up @@ -142,7 +144,7 @@ extension DeleteAccountViewController: WKNavigationDelegate {
) {
if let url = navigationAction.request.url {
let urlString = url.absoluteString
if urlString.starts(with: Constants.LOGIN_URL) {
if url.host == infomaniakLogin.config.loginURL.host {
decisionHandler(.allow)
dismiss(animated: true)
if !accountDeleted {
Expand Down
58 changes: 28 additions & 30 deletions Sources/InfomaniakLogin/InfomaniakLogin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,21 @@

import AuthenticationServices
import CommonCrypto
import InfomaniakCore
import InfomaniakDI
import SafariServices
import WebKit
#if canImport(UIKit)
import UIKit
#endif

public enum Constants {
public static let deleteAccountURL =
"https://manager.infomaniak.com/v3/ng/profile/user/dashboard?open-terminate-account-modal"
public static func autologinUrl(to destination: String) -> URL? {
return URL(string: "https://manager.infomaniak.com/v3/mobile_login/?url=\(destination)")
}
}

/// Login delegation
public protocol InfomaniakLoginDelegate: AnyObject {
func didCompleteLoginWith(code: String, verifier: String)
Expand All @@ -32,11 +39,14 @@ public protocol InfomaniakLoginDelegate: AnyObject {

/// Something that can authentify with Infomaniak
public protocol InfomaniakLoginable {
var config: InfomaniakLogin.Config { get }

@available(iOS 13.0, *)
func asWebAuthenticationLoginFrom(anchor: ASPresentationAnchor,
useEphemeralSession: Bool,
hideCreateAccountButton: Bool,
completion: @escaping (Result<(code: String, verifier: String), Error>) -> Void)

@available(iOS 13.0, *)
func asWebAuthenticationLoginFrom(anchor: ASPresentationAnchor,
useEphemeralSession: Bool,
hideCreateAccountButton: Bool,
Expand Down Expand Up @@ -69,9 +79,6 @@ public protocol InfomaniakTokenable {
/// Get an api token async (callback on background thread)
func getApiTokenUsing(code: String, codeVerifier: String, completion: @escaping (ApiToken?, Error?) -> Void)

/// Get an api token async from an application password (callback on background thread)
func getApiToken(username: String, applicationPassword: String, completion: @escaping (ApiToken?, Error?) -> Void)

/// Refresh api token async (callback on background thread)
func refreshToken(token: ApiToken, completion: @escaping (ApiToken?, Error?) -> Void)

Expand All @@ -93,11 +100,9 @@ class PresentationContext: NSObject, ASWebAuthenticationPresentationContextProvi
public class InfomaniakLogin: InfomaniakLoginable, InfomaniakTokenable {
let networkLogin: InfomaniakNetworkLoginable

private var delegate: InfomaniakLoginDelegate?
public let config: Config

private var clientId: String!
private var loginBaseUrl: String!
private var redirectUri: String!
private var delegate: InfomaniakLoginDelegate?

private var codeChallenge: String!
private var codeChallengeMethod: String!
Expand All @@ -118,17 +123,12 @@ public class InfomaniakLogin: InfomaniakLoginable, InfomaniakTokenable {
private var webviewTimeOutMessage: String?
#endif

public init(clientId: String,
loginUrl: String = Constants.LOGIN_URL,
redirectUri: String = "\(Bundle.main.bundleIdentifier ?? "")://oauth2redirect") {
loginBaseUrl = loginUrl
self.clientId = clientId
self.redirectUri = redirectUri
networkLogin = InfomaniakNetworkLogin(clientId: clientId,
loginUrl: loginUrl,
redirectUri: redirectUri)
public init(config: Config) {
self.config = config
networkLogin = InfomaniakNetworkLogin(config: config)
}

@available(iOS 13.0, *)
public func asWebAuthenticationLoginFrom(anchor: ASPresentationAnchor = ASPresentationAnchor(),
useEphemeralSession: Bool = false,
hideCreateAccountButton: Bool = true,
Expand All @@ -137,7 +137,7 @@ public class InfomaniakLogin: InfomaniakLoginable, InfomaniakTokenable {
generatePkceCodes()

guard let loginUrl = generateUrl(),
let callbackUrl = URL(string: redirectUri),
let callbackUrl = URL(string: config.redirectURI),
let callbackUrlScheme = callbackUrl.scheme else {
return
}
Expand All @@ -161,6 +161,7 @@ public class InfomaniakLogin: InfomaniakLoginable, InfomaniakTokenable {
session.start()
}

@available(iOS 13.0, *)
public func asWebAuthenticationLoginFrom(anchor: ASPresentationAnchor = ASPresentationAnchor(),
useEphemeralSession: Bool = false,
hideCreateAccountButton: Bool = true,
Expand All @@ -183,10 +184,6 @@ public class InfomaniakLogin: InfomaniakLoginable, InfomaniakTokenable {
networkLogin.getApiTokenUsing(code: code, codeVerifier: codeVerifier, completion: completion)
}

public func getApiToken(username: String, applicationPassword: String, completion: @escaping (ApiToken?, Error?) -> Void) {
networkLogin.getApiToken(username: username, applicationPassword: applicationPassword, completion: completion)
}

public func refreshToken(token: ApiToken, completion: @escaping (ApiToken?, Error?) -> Void) {
networkLogin.refreshToken(token: token, completion: completion)
}
Expand All @@ -210,23 +207,24 @@ public class InfomaniakLogin: InfomaniakLoginable, InfomaniakTokenable {
// MARK: - Private

private func generatePkceCodes() {
codeChallengeMethod = Constants.HASH_MODE_SHORT
codeChallengeMethod = config.hashModeShort
codeVerifier = generateCodeVerifier()
codeChallenge = generateCodeChallenge(codeVerifier: codeVerifier)
}

/// Generate the complete login URL based on parameters and base
private func generateUrl() -> URL? {
var urlComponents = URLComponents(string: loginBaseUrl)
var urlComponents = URLComponents(url: config.loginURL, resolvingAgainstBaseURL: true)
urlComponents?.path = "/authorize"
urlComponents?.queryItems = [
URLQueryItem(name: "response_type", value: Constants.RESPONSE_TYPE),
URLQueryItem(name: "access_type", value: Constants.ACCESS_TYPE),
URLQueryItem(name: "client_id", value: clientId),
URLQueryItem(name: "redirect_uri", value: redirectUri),
URLQueryItem(name: "response_type", value: config.responseType.rawValue),
URLQueryItem(name: "access_type", value: config.accessType.rawValue),
URLQueryItem(name: "client_id", value: config.clientId),
URLQueryItem(name: "redirect_uri", value: config.redirectURI),
URLQueryItem(name: "code_challenge_method", value: codeChallengeMethod),
URLQueryItem(name: "code_challenge", value: codeChallenge)
]

if hideCreateAccountButton {
urlComponents?.queryItems?.append(URLQueryItem(name: "hide_create_account", value: ""))
}
Expand Down Expand Up @@ -334,7 +332,7 @@ public extension InfomaniakLogin {
}

webViewController?.urlRequest = urlRequest
webViewController?.redirectUri = redirectUri
webViewController?.redirectUri = config.redirectURI
webViewController?.clearCookie = clearCookie
webViewController?.navBarTitle = webviewNavbarTitle
webViewController?.navBarTitleColor = webviewNavbarTitleColor
Expand Down
23 changes: 23 additions & 0 deletions Sources/InfomaniakLogin/Model/ApiDeleteToken.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
Copyright 2023 Infomaniak Network SA

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import Foundation

public class ApiDeleteToken: Codable {
let result: String
let error: String?
let data: Bool?
}
Loading
Loading