Skip to content

Commit

Permalink
Version 5.9.0 (#26)
Browse files Browse the repository at this point in the history
Co-authored-by: Gematik <[email protected]>
  • Loading branch information
gematik1 and Gematik-Entwicklung authored Jul 30, 2024
1 parent 0440510 commit 281d51e
Show file tree
Hide file tree
Showing 76 changed files with 8,997 additions and 13 deletions.
15 changes: 10 additions & 5 deletions .github/README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@ when implementing a system that performs the communication between an iOS based
and a German Health Card (elektronische Gesundheitskarte) using an NFC, Blue Tooth oder USB interface.

This document describes the functionalitiy and structure of OpenHealthCardKit.

== API Documentation

Generated API docs are available at https://gematik.github.io/ref-OpenHealthCardKit.

== Getting Started

OpenHealthCardKit requires Swift 5.6.
Expand All @@ -32,7 +34,7 @@ OpenHealthCardKit requires Swift 5.6.

- **Swift Package Manager:** Put this in your `Package.swift`:

`.package(url: "https://github.com/gematik/ref-OpenHealthCardKit", from: "5.6.0"),`
.package(url: "https://github.com/gematik/ref-OpenHealthCardKit", from: "5.6.0"),

- **Carthage:** Put this in your `Cartfile`:

Expand All @@ -57,12 +59,13 @@ OpenHealthCardKit consists of the submodules
- HealthCardControl
- NFCCardReaderProvider

As a reference for each submodule see also the `IntegrationTests`.
Also see a https://github.com/gematik/ref-OpenHealthCardApp-iOS[Demo App] on GitHub using this framework.
As a reference for the usage of each submodule see also the `IntegrationTests`.

[#CardReaderProviderApi]
=== CardReaderProviderApi

(Smart)CardReader protocols for interacting with `HealthCardAccess`.

[#HealthCardAccess]
=== HealthCardAccess
This library contains the classes for cards, commands, card file systems and error handling.
Expand Down Expand Up @@ -124,7 +127,7 @@ In the next example we use a `HealthCard` object representing an eGK (elektronis
as one kind of a `HealthCardType` implementing the `CardType` protocol and then send the command to the card (or card's channel):
[source,swift]
----
let healthCardResponse = try await selectEsignCommand.transmit(to: Self.healthCard)
let healthCardResponse = try await selectEsignCommand.transmitAsync(to: Self.healthCard)
guard healthCardResponse.responseStatus == ResponseStatus.success else {
throw HealthCard.Error.operational // TO-DO: handle this or throw a meaningful Error
}
Expand Down Expand Up @@ -199,6 +202,7 @@ readCertificate
}
)
----

[#HealthCardControl]
=== HealthCardControl

Expand All @@ -223,7 +227,7 @@ Take the necessary preparatory steps for signing a challenge on the Health Card,
let challenge = Data([0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8])
let format2Pin = try Format2Pin(pincode: "123456")
_ = try await Self.healthCard.verify(pin: format2Pin, type: EgkFileSystem.Pin.mrpinHome)
let signResponse = try await Self.healthCard.sign(data: challenge)
let signResponse = try await Self.healthCard.signAsync(data: challenge)
expect(signResponse.responseStatus) == ResponseStatus.success
----

Expand All @@ -243,6 +247,7 @@ let secureMessaging = try await KeyAgreement.Algorithm.idPaceEcdhGmAesCbcCmac128

See the integration tests link:include::{integrationtestdir}/HealthCardControl/[IntegrationTests/HealthCardControl/]
for more already implemented use cases.

[#NFCCardReaderProvider]
=== NFCCardReaderProvider

Expand Down
2 changes: 0 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,6 @@ fastlane/test_output

iOSInjectionProject/

CardSimulationTestKit
devops

jenkinsfiles

4 changes: 4 additions & 0 deletions .spi.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
version: 1
builder:
configs:
- documentation_targets: [HealthCardControl, HealthCardAccess, NFCCardReaderProvider, CardReaderProviderApi]
14 changes: 14 additions & 0 deletions CardSimulationTestKit/.jazzy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
output: docs
author: gematik GmbH
author_url: http://www.gematik.de
exclude: /*/internal*
# module references the 'Documentation' targets PRODUCT_NAME
module: CardSimulationTestKit
github_url: https://gematik.github.io
theme: jony
swift_build_tool: xcodebuild
xcodebuild_arguments:
- "-project"
- 'CardSimulationTestKit.xcodeproj'
- "-scheme"
- 'Documentation'
59 changes: 59 additions & 0 deletions CardSimulationTestKit/.swiftlint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
opt_in_rules:
- attributes
- empty_count
- force_unwrapping
- unneeded_parentheses_in_closure_argument
- unavailable_function
- trailing_closure
- strict_fileprivate
- sorted_imports
- sorted_first_last
- single_test_class
- required_enum_case
- redundant_type_annotation
- redundant_nil_coalescing
- prohibited_super_call
- override_in_extension
- overridden_super_call
- operator_usage_whitespace
- no_extension_access_modifier
- multiline_function_chains
- multiline_arguments
- modifier_order
- missing_docs
- lower_acl_than_parent
- literal_expression_end_indentation
- first_where
- file_name
- fatal_error_message
- explicit_init
- empty_string
- discouraged_optional_collection
- closure_end_indentation
- file_header
excluded: # paths to ignore during linting. Takes precedence over `included`.
- Package.swift
- .build/
- vendor/
- Carthage/
custom_rules:
nimble_fail_with_description:
included: ".*Test\\.swift"
name: "Fail with description"
regex: "(Nimble.fail\\(\\))"
message: "Failures need a description"
severity: warning
must_not_contain_author:
included:
- ".*Test\\.swift"
- ".*Sources\\.swift"
name: "must not contain author"
regex: "(\/\/[[:space:]]*Created by)"
message: "Source must not contain author"
severity: warning

file_header:
required_pattern: |
\/\/
\/\/ Copyright \(c\) \d{4} gematik GmbH
\/\/
164 changes: 164 additions & 0 deletions CardSimulationTestKit/README.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
= CardSimulationTestKit

NOTE: This framework rather is meant to be used for gematik-internal development purposes (since the actual CardSimulation application can neither be open sourced nor provided as of now). We publish this code anyway for further reference/usage.

CardSimulationTestKit provides an easy-to-use interface for testing against a German Health Card Simulator.
It comes bundled with

* `CardSimulationLoader`: loads and starts a card simulation as a Java process listening on a TCP port
* `CardSimulationCardReaderProvider`: implements the `CardReaderProviderApi` interface
* `CardSimulationTerminalTestCase`: provides a fully initialized and functional `HealthCard` object to send commands to and receive responses from.
The intended usage of this project is to ease integration and use the G2-Kartensimulation with Swift projects, specifically the test cases in this project.
This guide is separated in two (2) main parts. Describing

. the usage of the `CardSimulation-Loader` framework (How-to) and
. how to maintain the technical consideration(s) and implementation(s).

== Frameworks

=== CardSimulation-Loader

The sole purpose of this framework is to launch and monitor a G2-Kartensimulation Java process.
For detailed usage information see the inlined documentation on `SimulationManager`
and `SimulationRunner`.

*Starting the simulator*:

Of course the best way to find out how-to use the CardSimulation-Loader is by checking the `SimulationManagerTest` and `SimulationRunnerTest` to see their intended and tested use-cases.
Next to checking the test-cases you also find some (example) configuration files in the _Configuration.bundle_ file.

In general, you would prepare such a *card-configuration* XML as in the Configuration.bundle and pass it to the `SimulationManager.shared` by invoking its:

[source,Swift]
----
func createSimulation(
configFile: URL,
preprocessor manipulators: [XMLPathManipulator] = [],
simulatorVersion: String = "2.7.6-352",
simulatorDirectory: String = "simulator",
)
----

Note: you can specify the G2-Kartensimulation version it needs to download/use.

The returned `SimulationRunnerType` can be used to monitor the newly started G2-Kartensimulation instance. To - for instance - figure out on which TLV-port the simulator is registered, just check the `SimulationRunnerType.mode`. When `running` the TLV TCP/IP port is projected there. And for convenience reasons made available through `var tlvPort: Int?` on SimulationRunnerType(s).

This SimulationRunnerType instance will need a CardTerminalControllerType to expose this G2-Kartensimulation virtual `HealthCard` to the HealthCardAccess/Control realm.

*Example*:

[source,Swift]
----
/// Read configFile from included Resources Bundle
let simulatorConfig = Bundle(for: MyClass.self)
.resourceFilePath(in: "Configuration", for: "configuration_EGKG2_80276883110000017222_gema5_TCP.xml")
.asURL
/// Launch a G2-Kartensimulation with this configuration file
let runner = try SimulationManager.shared.startSimulation(
configFile: simulatorConfig,
preprocessor: [
XMLPathManipulatorHolder.TLVPortManipulator(port: "0"),
XMLPathManipulatorHolder.RelativeToAbsolutePathManipulator(with: XMLPathManipulatorHolder.CardConfigFileXMLPath, absolutePath: simulatorConfig.deletingLastPathComponent()),
XMLPathManipulatorHolder.RelativeToAbsolutePathManipulator(with: XMLPathManipulatorHolder.ChannelConfigFileXMLPath, absolutePath: simulatorConfig.deletingLastPathComponent())
],
waitUntilLaunched: true
)
// ... Do amazing things with the runner
/// Stop the runner when done
runner.stop(waitUntilTerminated: true)
----

==== Technical overview

As described in the previous section(s) the CardSimulationLoader provides an easy-to-use API to launch and manage a G2-Kartensimulation.
In order to achieve this we need to combine some various technologies/environments (read: Nexus <--> Java <--> Swift -> CardSimulationLoader API).

The main components for this project to work:

* Download G2-Kartensimulation Nexus artifacts
* Launch and monitor Java Process

These two (2) steps are taken care of when using the `SimulationManager` to launch a simulation.

==== Maven step

The `SimulationManager` reads the `pom.xml` and executes a shell script to run `mvn dependency:copy-dependencies`.
And puts these artifacts in the same transient environment to be cleaned (manually) by calling `SimulationManager.clean` upon
finishing with the simulator(s). Reason for this is to not download the artifacts for every simulator instance in case they
are launch sequentially - which is reasonable to assume.

==== Java process

When the artifacts are in place, the `SimulationRunner` creates a JavaProcess that will be launched/forked in a separate process.
And monitors this process by reading/parsing the `stdout` and `stderr` to detect the tlv-port number and successful initialization.

To start developing the project follow the Project Setup section below 👇.

=== CardSimulation-CardReaderProvider

CardTerminalProvider for communication with G2-Kartensimulation

=== CardSimulationTerminalTestCase

CardSimulationTerminalTestCase provides a fully initialized and functional `HealthCard` object to send commands
against and receive responses from.

== Getting Started

CardSimulationLoader requires Swift 5.1.

=== Usage

In your Test class, derive from the `CardSimulationTerminalTestCase` which itself is a `XCTestCase`.
You then have a `HealthCard` and a `CardTerminal` object directly link to an up and running CardSimulation at your disposal.

[source,Swift]
----
final class SelectCommandIntegrationTest: CardSimulationTerminalTestCase {
func testSelectRoot() {
let healthCard = CardSimulationTerminalTestCase.healthCard
HealthCardCommand.Select.selectRoot()
.execute(on: healthCard)
.run(on: Executor.trampoline)
}
}
----

CardSimulationTestKit comes with various CardImage configuration files.
You can choose between the following images

* configuration_EGK_G2_1_80276883110000095711_GuD_TCP.xml (default)
* configuration_EGK_G2_1_ecc.xml
* configuration_EGKG2_80276883110000017222_gema5_TCP.xml
* configuration_HBA_G2_1_80276883110000205690_gema5_TCP.xml
* configuration_HBAG2_80276883110000017289_gema5_TCP.xml
* configuration_TLK_COS_image-kontaktlos128.xml

by overwriting the `class func configFile() -> URL?` like this:

[source,Swift]
----
final class SelectCommandIntegrationTest: CardSimulationTerminalTestCase {
override class func configFile() -> URL? {
let bundle = Bundle(for: CardSimulationTerminalTestCase.self)
let path = bundle.resourceFilePath(in: "Resources", for: "Configuration/configuration_EGK_G2_1_ecc.xml")
return path.asURL
}
}
----
or bring your own image:

[source,Swift]
----
final class SelectCommandIntegrationTest: CardSimulationTerminalTestCase {
override class func configFile() -> URL? {
// this assumes, your use a test class and have a resource bundle called "Resources2.bundle"
let bundle = Bundle(for: self)
let path = bundle.testResourceFilePath(in: "Resources2", for: "Configuration/configuration_EGK_G2_1_ecc.xml")
return path.asURL
}
}
22 changes: 22 additions & 0 deletions CardSimulationTestKit/Resources/AEXMLExt_Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>
22 changes: 22 additions & 0 deletions CardSimulationTestKit/Resources/CardSimulationLoader_Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>
Loading

0 comments on commit 281d51e

Please sign in to comment.