Skip to content

Commit

Permalink
Release version 5.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
Team Mobile Schorsch committed Nov 27, 2024
1 parent ac09bb4 commit a7932fd
Show file tree
Hide file tree
Showing 17 changed files with 426 additions and 132 deletions.
2 changes: 1 addition & 1 deletion .jazzy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ xcodebuild_arguments:
- "-scheme"
- GiniHealthAPILibrary
- "-destination"
- platform=iOS Simulator,OS=17.2,name=iPhone 14
- platform=iOS Simulator,OS=17.5,name=iPhone 15
author: Gini GmbH
author_url: https://gini.net
module: GiniHealthAPILibrary
Expand Down
9 changes: 1 addition & 8 deletions Documentation/source/Installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,7 @@ Once you have your Swift package set up, adding `GiniHealthAPILibrary` as a depe

```swift
dependencies: [
.package(url: "https://github.com/gini/health-api-library-ios.git", .exact("4.3.1"))
]
```

In case that you want to use the certificate pinning in the library, add `GiniHealthAPILibraryPinning`:
```swift
dependencies: [
.package(url: "https://github.com/gini/health-api-library-pinning-ios.git", .exact("4.3.1"))
.package(url: "https://github.com/gini/health-api-library-ios.git", .exact("5.0.0"))
]
```

Expand Down
6 changes: 2 additions & 4 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import PackageDescription

let package = Package(
name: "GiniHealthAPILibrary",
defaultLocalization: "en",
platforms: [.iOS(.v12)],
products: [
// Products define the executables and libraries a package produces, and make them visible to other packages.
Expand All @@ -24,9 +25,6 @@ let package = Package(
dependencies: []),
.testTarget(
name: "GiniHealthAPILibraryTests",
dependencies: ["GiniHealthAPILibrary"],
resources: [
.process("Resources")
]),
dependencies: ["GiniHealthAPILibrary"])
]
)
21 changes: 13 additions & 8 deletions Sources/GiniHealthAPILibrary/Documents/APIMethod.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,19 @@ import Foundation
enum APIMethod: ResourceMethod {

case createDocument(fileName: String?,
docType: Document.DocType?,
mimeSubType: String,
documentType: Document.TypeV2?)
case documents(limit: Int?, offset: Int?)
docType: Document.DocType?,
mimeSubType: MimeSubtype,
documentType: Document.TypeV2?)
case documents(limit: Int?,
offset: Int?)
case document(id: String)
case composite
case errorReport(forDocumentWithId: String,
summary: String?, description: String?)
summary: String?,
description: String?)
case extractions(forDocumentId: String)
case extraction(withLabel: String, documentId: String)
case extraction(withLabel: String,
documentId: String)
case feedback(forDocumentId: String)
case layout(forDocumentId: String)
case partial
Expand All @@ -29,8 +32,10 @@ enum APIMethod: ResourceMethod {
case paymentProviders
case createPaymentRequest
case paymentRequest(id: String)
case paymentRequests(limit: Int?, offset: Int?)
case paymentRequests(limit: Int?,
offset: Int?)
case file(urlString: String)
case payment(id: String)
case pdfWithQRCode(paymentRequestId: String)
case pdfWithQRCode(paymentRequestId: String,
mimeSubtype: MimeSubtype)
}
76 changes: 49 additions & 27 deletions Sources/GiniHealthAPILibrary/Documents/APIResource.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@ public enum APIDomain {

}

enum MimeSubtype: String {
case pdf = "qr+pdf"
case png = "qr+png"
case json = "json"
case jpeg = "jpeg"
}

struct APIResource<T: Decodable>: Resource {
var fullUrlString: String?

Expand Down Expand Up @@ -104,39 +111,54 @@ struct APIResource<T: Decodable>: Resource {
return urlString
case .payment(let id):
return "/paymentRequests/\(id)/payment"
case .pdfWithQRCode(paymentRequestId: let paymentRequestId):
case .pdfWithQRCode(let paymentRequestId, _):
return "/paymentRequests/\(paymentRequestId)"
}
}

var defaultHeaders: HTTPHeaders {
// Define common headers
let acceptHeader = ["Accept": ContentType.content(
version: apiVersion,
subtype: nil,
mimeSubtype: MimeSubtype.json.rawValue
).value]

// Helper method to construct Content-Type header
func contentTypeHeader(subtype: String?, mimeSubtype: String) -> HTTPHeaders {
return ["Content-Type": ContentType.content(
version: apiVersion,
subtype: subtype,
mimeSubtype: mimeSubtype
).value]
}

switch method {
case .createDocument(_, _, let mimeSubType, let documentType):
return ["Accept": ContentType.content(version: apiVersion,
subtype: nil,
mimeSubtype: "json").value,
"Content-Type": ContentType.content(version: apiVersion,
subtype: documentType?.name,
mimeSubtype: mimeSubType).value
]
case .file(_):
return [:]
case .paymentProviders, .paymentProvider(_), .paymentRequests(_, _) :
return ["Accept": ContentType.content(version: apiVersion,
subtype: nil,
mimeSubtype: "json").value]
case .pdfWithQRCode(_):
return ["Accept": ContentType.content(version: apiVersion,
subtype: nil,
mimeSubtype: "qr+pdf").value]
default:
return ["Accept": ContentType.content(version: apiVersion,
subtype: nil,
mimeSubtype: "json").value,
"Content-Type": ContentType.content(version: apiVersion,
subtype: nil,
mimeSubtype: "json").value
]
case .createDocument(_, _, let mimeSubType, let documentType):
return acceptHeader.merging(contentTypeHeader(
subtype: documentType?.name,
mimeSubtype: mimeSubType.rawValue
)) { _, new in new }

case .file(_):
return [:]

case .paymentProviders, .paymentProvider(_), .paymentRequests(_, _):
return acceptHeader

case .pdfWithQRCode(_, let mimeSubtype):
return ["Accept": ContentType.content(
version: apiVersion,
subtype: nil,
mimeSubtype: mimeSubtype.rawValue
).value]

default:
// Default headers for other cases
return acceptHeader.merging(contentTypeHeader(
subtype: nil,
mimeSubtype: MimeSubtype.json.rawValue
)) { _, new in new }
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ extension Data {
}
}

func isImage() -> Bool {
public func isImage() -> Bool {
return UIImage(data: self) != nil
}

Expand Down
41 changes: 41 additions & 0 deletions Sources/GiniHealthAPILibrary/Documents/Core/GiniHealthAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,47 @@ extension GiniHealthAPI {
self.sessionDelegate = sessionDelegate
}

/**
* Creates a Gini Health API Library with certificate pinning configuration.
*
* - Parameter client: The Gini Health API client credentials
* - Parameter api: The Gini Health API that the library interacts with. `APIDomain.default` by default
* - Parameter userApi: The Gini User API that the library interacts with. `UserDomain.default` by default
* - Parameter pinningConfig: Configuration for certificate pinning. Format ["PinnedDomains" : ["PublicKeyHashes"]]
* - Parameter logLevel: The log level. `LogLevel.none` by default.
*/
public init(client: Client,
api: APIDomain = .default,
userApi: UserDomain = .default,
pinningConfig: [String: [String]],
logLevel: LogLevel = .none) {
self.init(client: client,
api: api,
userApi: userApi,
logLevel: logLevel,
sessionDelegate: GiniSessionDelegate(pinningConfig: pinningConfig))
}

/**
* Creates a Gini Health API Library to be used with a transparent proxy and a custom api access token source and certificate pinning configuration.
*
* - Parameter customApiDomain: A custom api domain string.
* - Parameter alternativeTokenSource: A protocol for using custom api access token
* - Parameter pinningConfig: Configuration for certificate pinning. Format ["PinnedDomains" : ["PublicKeyHashes"]]
* - Parameter logLevel: The log level. `LogLevel.none` by default.
*/
public init(customApiDomain: String,
alternativeTokenSource: AlternativeTokenSource,
apiVersion: Int,
pinningConfig: [String: [String]],
logLevel: LogLevel = .none) {
self.init(customApiDomain: customApiDomain,
alternativeTokenSource: alternativeTokenSource,
apiVersion: apiVersion,
logLevel: logLevel,
sessionDelegate: GiniSessionDelegate(pinningConfig: pinningConfig))
}

public func build() -> GiniHealthAPI {
// Save client information
save(client)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//
// GiniSessionDelegate.swift
//
//
// Copyright © 2024 Gini GmbH. All rights reserved.
//

import Foundation

/// A delegate for URLSession that implements SSL pinning using the provided SSLPinningManager.
class GiniSessionDelegate: NSObject, URLSessionDelegate {

/// The manager responsible for validating SSL certificates.
private let pinningManager: SSLPinningManager

/// Initializes the GiniSessionDelegate with a given SSL pinning configuration.
///
/// - Parameter pinningConfig: A dictionary containing the pinning configuration, typically mapping domain names to their expected certificate fingerprints.
internal init(pinningConfig: [String: [String]]) {
self.pinningManager = SSLPinningManager(pinningConfig: pinningConfig)
}

/// Handles the URLSession authentication challenge by delegating the validation to the pinning manager.
///
/// - Parameters:
/// - session: The URLSession that received the challenge.
/// - challenge: The authentication challenge that needs to be handled.
/// - completionHandler: A completion handler that must be called with the disposition and credential to use for the challenge.
func urlSession(_ session: URLSession,
didReceive challenge: URLAuthenticationChallenge,
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
pinningManager.validate(challenge: challenge, completionHandler: completionHandler)
}
}
Loading

0 comments on commit a7932fd

Please sign in to comment.