Skip to content

Commit

Permalink
Merge pull request #3 from k-angama/bugfix/redirect-uri-mode-sandbox
Browse files Browse the repository at this point in the history
Fix error invalid redirect URL
  • Loading branch information
k-angama authored Jan 12, 2024
2 parents 4ae683f + c02d5e3 commit 44532a3
Show file tree
Hide file tree
Showing 15 changed files with 147 additions and 51 deletions.
8 changes: 2 additions & 6 deletions Example/LinkyAPIExample.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,6 @@
25306AC82A38733400F45EDC /* LinkyAPIExampleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25306AC72A38733400F45EDC /* LinkyAPIExampleTests.swift */; };
25306AD22A38733400F45EDC /* LinkyAPIExampleUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25306AD12A38733400F45EDC /* LinkyAPIExampleUITests.swift */; };
25306AD42A38733400F45EDC /* LinkyAPIExampleUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25306AD32A38733400F45EDC /* LinkyAPIExampleUITestsLaunchTests.swift */; };
2553F12D2B03D4C600CC3CCD /* env.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 2553F12B2B03D25400CC3CCD /* env.xcconfig */; };
2553F12E2B03D4C700CC3CCD /* env.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 2553F12B2B03D25400CC3CCD /* env.xcconfig */; };
2553F12F2B03D4C700CC3CCD /* env.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 2553F12B2B03D25400CC3CCD /* env.xcconfig */; };
257640F12A444E7600723503 /* LinkyAPI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 257640F02A444E7600723503 /* LinkyAPI.framework */; };
257640F22A444E7600723503 /* LinkyAPI.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 257640F02A444E7600723503 /* LinkyAPI.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
2595FF862AFBD64B00C2582D /* Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2595FF852AFBD64B00C2582D /* Environment.swift */; };
Expand Down Expand Up @@ -312,7 +309,6 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
2553F12D2B03D4C600CC3CCD /* env.xcconfig in Resources */,
25306ABD2A38733400F45EDC /* LaunchScreen.storyboard in Resources */,
25306ABA2A38733400F45EDC /* Assets.xcassets in Resources */,
25306AB82A38733200F45EDC /* Main.storyboard in Resources */,
Expand All @@ -323,15 +319,13 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
2553F12E2B03D4C700CC3CCD /* env.xcconfig in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
25306ACB2A38733400F45EDC /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
2553F12F2B03D4C700CC3CCD /* env.xcconfig in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -410,6 +404,7 @@
/* Begin XCBuildConfiguration section */
25306AD52A38733400F45EDC /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 2553F12B2B03D25400CC3CCD /* env.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
Expand Down Expand Up @@ -470,6 +465,7 @@
};
25306AD62A38733400F45EDC /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 2553F12B2B03D25400CC3CCD /* env.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
Expand Down
2 changes: 1 addition & 1 deletion Example/LinkyAPIExample/AuthorizationViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class AuthorizationViewController: UIViewController {
clientId: Env.clientID,
clientSecret: Env.clientSecret,
redirectURI: URL(string: Env.redirectURI)!,
mode: .sandbox(prm: .client7(.prm2)),
mode: .sandbox(prm: .client1(.prm1)),
duration: .day(value: 1)
)
linkyAuth = LinkyAuthorization(configuration: configuration)
Expand Down
6 changes: 3 additions & 3 deletions LinkyAPI.podspec
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

Pod::Spec.new do |s|
s.name = 'LinkyAPI'
s.version = '1.0.0'
s.version = '1.0.1'
s.swift_version = "5.0"
s.summary = 'API for Linky smart meters.'

Expand All @@ -17,8 +17,8 @@ DESC

s.ios.deployment_target = '16.4'

s.source_files = 'LinkyAPI/**/*.{swift}'
s.exclude_files = 'LinkyAPI/LinkyAPITests/**/*.{swift}'
s.source_files = 'Sources/LinkyAPI/**/*.{swift}'
s.exclude_files = 'Tests/LinkyAPITests/**/*.{swift}'

s.frameworks = 'UIKit'

Expand Down
50 changes: 30 additions & 20 deletions LinkyAPI/LinkyAPI.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
The LinkyAPI Swift Library is a Swift package that provides a convenient way to access Linky's electricity consumption and production data through Enedis API. This library simplifies the process of obtaining user authorization, fetching consumption data.


## Reatures
## Features

- API authorization process.
- Retrieval of daily consumption, average power consumed, maximum consumption power, daily production, and average power produced.
Expand Down
2 changes: 1 addition & 1 deletion Sources/LinkyAPI/Authorization/LinkyAuthorization.swift
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ public class LinkyAuthorization {

internal func displayWebViewScreen() {
let nc = UINavigationController(
rootViewController: WebViewController(
rootViewController: LinkyWebViewController(
configuration: configuration,
account: account,
block: handleResponse)
Expand Down
2 changes: 1 addition & 1 deletion Sources/LinkyAPI/Common/Constants.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ struct Constants {
static let usagePointId = "usage_point_id"
static let nameDuration = "duration"
static let nameResponseType = "response_type"
static let nameRedirectURI = "redirect_URI"
// static let nameRedirectURI = "redirect_URI"

// Value Query
static let valueResponseType = "code"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,13 @@ extension String {
formatter.dateFormat = self.count == 10 ? "YYYY-MM-dd" : "YYYY-MM-dd HH:mm:ss"
return formatter.date(from: self) ?? Date.now
}

func formatURL() -> String? {
let url = URL(string: self)
let host = url?.host
if host == nil {
let url = URL(string: "https://\(self)")
return url?.host
}
return host
}
}
20 changes: 20 additions & 0 deletions Sources/LinkyAPI/Common/Extentions/LinkyURL+Extentions.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// LinkyURL+Extentions.swift
// LinkyAPI
//
// Created by Karim Angama on 12/01/2024.
//

import Foundation

extension URL {
func formatted() -> URL? {
if(self.scheme == nil) {
return URL(string: "https://\(self)")
}
if(self.host == nil) {
return nil
}
return self
}
}
2 changes: 1 addition & 1 deletion Sources/LinkyAPI/Configuration/LinkyConfiguration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public struct LinkyConfiguration {
URLQueryItem(name: Constants.Config.nameState, value: state),
URLQueryItem(name: Constants.Config.nameDuration, value: duration.durationCode),
URLQueryItem(name: Constants.Config.nameResponseType, value: Constants.Config.valueResponseType),
//URLQueryItem(name: Constants.Config.nameRedirectURI, value: redirectURI.absoluteString),
// URLQueryItem(name: Constants.Config.nameRedirectURI, value: redirectURI.absoluteString),
]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import UIKit
import WebKit


class WebViewController: UIViewController {
class LinkyWebViewController: UIViewController {

typealias WebViewBlock = (_ usagePointsId: String?, _ state: String?, _ error: Error?) -> Void
var configuration: LinkyConfiguration!
Expand Down Expand Up @@ -71,15 +71,22 @@ class WebViewController: UIViewController {

internal func handleWebViewResponse(_ response: HTTPURLResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {

guard let redirectURI = configuration.redirectURI.formatted() else {
fatalError("LinkyAPI - Redirect URI format is invalid")
}

var url = response.url
switch configuration.mode {
case .sandbox(prm: let client):
url = URL(string: "http://\(configuration.redirectURI)?state=\(configuration.state)&usage_point_id=\(client.prm)")
url = redirectURI
.appending(queryItems: [URLQueryItem(name: "state", value: configuration.state)])
.appending(queryItems: [URLQueryItem(name: "usage_point_id", value: client.prm)])

case .production: break
}

if let host = url?.host,
host.contains(configuration.redirectURI.absoluteString) && response.statusCode == 200 {
if let host = url?.host, let hostRedirectURI = redirectURI.host,
host.contains(hostRedirectURI) && response.statusCode == 200 {

guard let url = url,
let urlComps = URLComponents(url: url, resolvingAgainstBaseURL: false),
Expand Down Expand Up @@ -135,7 +142,7 @@ class WebViewController: UIViewController {
}


extension WebViewController: WKUIDelegate, WKNavigationDelegate {
extension LinkyWebViewController: WKUIDelegate, WKNavigationDelegate {

func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
indicator.stopAnimating()
Expand Down
33 changes: 33 additions & 0 deletions Tests/LinkyAPITests/LinkyURLFormatted.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//
// LinkyURLFormatted.swift
// LinkyAPITests
//
// Created by Karim Angama on 12/01/2024.
//

import XCTest
@testable import LinkyAPI

final class LinkyURLFormatted: XCTestCase {

func testURLFormattedWithHostAndPath() throws {
let url = URL(string: "https://fake.url-redirect.com/test/")?.formatted()
XCTAssertEqual(url?.absoluteString, "https://fake.url-redirect.com/test/")
}

func testURLFormattedWithHost() throws {
let url = URL(string: "https://fake.url-redirect.com")?.formatted()
XCTAssertEqual(url?.absoluteString, "https://fake.url-redirect.com")
}

func testURLFormattedWithoutHost() throws {
let url = URL(string: "fake.url-redirect.com")?.formatted()
XCTAssertEqual(url?.absoluteString, "https://fake.url-redirect.com")
}

func testInvalidURLFormatted() throws {
let url = URL(string: "monApp://")?.formatted()
XCTAssertEqual(url?.absoluteString, nil)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ import XCTest
@testable import LinkyAPI
import WebKit

final class WebViewControllerTests: XCTestCase {
final class LinkyWebViewControllerTests: XCTestCase {

let clientId = "832d-451c-9005"
let clientSecret = "AfGT8-4f6d-a345-1208"

var webViewController: WebViewController!
var webViewController: LinkyWebViewController!
var linkyConfig: LinkyConfiguration!
var accountMock: LinkyAccount!

Expand All @@ -36,7 +36,7 @@ final class WebViewControllerTests: XCTestCase {

func testWhenIndicatorViewIsDisplayed() throws {

webViewController = WebViewController(configuration: linkyConfig, account: accountMock) { usagePointsId, state, error in }
webViewController = LinkyWebViewController(configuration: linkyConfig, account: accountMock) { usagePointsId, state, error in }
webViewController.loadView()

XCTAssertEqual(webViewController.indicator.isAnimating, true)
Expand All @@ -51,7 +51,7 @@ final class WebViewControllerTests: XCTestCase {

let exp = XCTestExpectation(description: "Success closure should be executed")

webViewController = WebViewController(configuration: linkyConfig, account: accountMock) { usagePointsId, state, error in }
webViewController = LinkyWebViewController(configuration: linkyConfig, account: accountMock) { usagePointsId, state, error in }
let response = HTTPURLResponse(
url: URL(string: "fake.url-redirect.com")!,
statusCode: 200,
Expand All @@ -72,7 +72,7 @@ final class WebViewControllerTests: XCTestCase {
let exp = XCTestExpectation(description: "Success closure should be executed")
exp.expectedFulfillmentCount = 2

webViewController = WebViewController(configuration: linkyConfig, account: accountMock) { usagePointsId, state, error in
webViewController = LinkyWebViewController(configuration: linkyConfig, account: accountMock) { usagePointsId, state, error in
let error = error as! LinkyAuthorizationError
XCTAssertEqual(error, LinkyAuthorizationError.badRequest)
XCTAssertEqual(usagePointsId, nil)
Expand All @@ -98,7 +98,7 @@ final class WebViewControllerTests: XCTestCase {

let exp = XCTestExpectation(description: "Success closure should be executed")
exp.expectedFulfillmentCount = 2
webViewController = WebViewController(configuration: linkyConfig, account: accountMock) { usagePointsId, state, error in
webViewController = LinkyWebViewController(configuration: linkyConfig, account: accountMock) { usagePointsId, state, error in
let error = error as! LinkyAuthorizationError
XCTAssertEqual(error, LinkyAuthorizationError.technicalError)
XCTAssertEqual(usagePointsId, nil)
Expand All @@ -125,7 +125,7 @@ final class WebViewControllerTests: XCTestCase {

let exp = XCTestExpectation(description: "Success closure should be executed")
exp.expectedFulfillmentCount = 2
webViewController = WebViewController(configuration: linkyConfig, account: accountMock) { usagePointsId, state, error in
webViewController = LinkyWebViewController(configuration: linkyConfig, account: accountMock) { usagePointsId, state, error in
let error = error as! LinkyAuthorizationError
XCTAssertEqual(error, LinkyAuthorizationError.apiError)
exp.fulfill()
Expand All @@ -150,7 +150,7 @@ final class WebViewControllerTests: XCTestCase {
let pointsId = "5757GF6457G"
let exp = XCTestExpectation(description: "Success closure should be executed")
exp.expectedFulfillmentCount = 2
webViewController = WebViewController(configuration: linkyConfig, account: accountMock) { [weak self] usagePointsId, state, error in
webViewController = LinkyWebViewController(configuration: linkyConfig, account: accountMock) { [weak self] usagePointsId, state, error in
let error = error as? LinkyAuthorizationError
XCTAssertEqual(error, nil)
XCTAssertEqual(usagePointsId, pointsId)
Expand All @@ -177,7 +177,7 @@ final class WebViewControllerTests: XCTestCase {

let exp = XCTestExpectation(description: "Success closure should be executed")
exp.expectedFulfillmentCount = 2
webViewController = WebViewController(configuration: linkyConfig, account: accountMock) { usagePointsId, state, error in
webViewController = LinkyWebViewController(configuration: linkyConfig, account: accountMock) { usagePointsId, state, error in
let error = error as? LinkyAuthorizationError
XCTAssertEqual(error, LinkyAuthorizationError.apiError)
XCTAssertEqual(usagePointsId, nil)
Expand All @@ -204,7 +204,7 @@ final class WebViewControllerTests: XCTestCase {
let pointsId = "azert"
let exp = XCTestExpectation(description: "Success closure should be executed")
accountMock.setUsagePointsId(pointsId)
webViewController = WebViewController(configuration: linkyConfig, account: accountMock) { [weak self] usagePointsId, state, error in
webViewController = LinkyWebViewController(configuration: linkyConfig, account: accountMock) { [weak self] usagePointsId, state, error in
let error = error as? LinkyAuthorizationError
XCTAssertEqual(error, nil)
XCTAssertEqual(usagePointsId, pointsId)
Expand Down Expand Up @@ -235,7 +235,7 @@ final class WebViewControllerTests: XCTestCase {

let exp = XCTestExpectation(description: "Success closure should be executed")
exp.expectedFulfillmentCount = 2
webViewController = WebViewController(configuration: linkyConfig, account: accountMock) { usagePointsId, state, error in
webViewController = LinkyWebViewController(configuration: linkyConfig, account: accountMock) { usagePointsId, state, error in
let error = error as? LinkyAuthorizationError
XCTAssertEqual(error, nil)
XCTAssertEqual(usagePointsId, pointsId)
Expand All @@ -252,5 +252,27 @@ final class WebViewControllerTests: XCTestCase {
wait(for: [exp], timeout: 3)

}

func testInvalidRedirectURL() throws {

let linkyConfig = LinkyConfiguration(
clientId: clientId,
clientSecret: clientSecret,
redirectURI: URL(string: "fake://")!,
mode: .sandbox(prm: .client1(.prm1))
)

webViewController = LinkyWebViewController(
configuration: linkyConfig,
account: accountMock,
block: { usagePointsId, state, error in })

expectFatalError(expectedMessage: "LinkyAPI - Redirect URI format is invalid") {
self.webViewController.handleWebViewResponse(HTTPURLResponse()) { navigationResponsePolicy in
//
}
}

}

}

0 comments on commit 44532a3

Please sign in to comment.