Skip to content

Commit 281d51e

Browse files
Version 5.9.0 (#26)
Co-authored-by: Gematik <[email protected]>
1 parent 0440510 commit 281d51e

File tree

76 files changed

+8997
-13
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

76 files changed

+8997
-13
lines changed

.github/README.adoc

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,11 @@ when implementing a system that performs the communication between an iOS based
2121
and a German Health Card (elektronische Gesundheitskarte) using an NFC, Blue Tooth oder USB interface.
2222

2323
This document describes the functionalitiy and structure of OpenHealthCardKit.
24+
2425
== API Documentation
2526

2627
Generated API docs are available at https://gematik.github.io/ref-OpenHealthCardKit.
28+
2729
== Getting Started
2830

2931
OpenHealthCardKit requires Swift 5.6.
@@ -32,7 +34,7 @@ OpenHealthCardKit requires Swift 5.6.
3234

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

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

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

@@ -57,12 +59,13 @@ OpenHealthCardKit consists of the submodules
5759
- HealthCardControl
5860
- NFCCardReaderProvider
5961

60-
As a reference for each submodule see also the `IntegrationTests`.
61-
Also see a https://github.com/gematik/ref-OpenHealthCardApp-iOS[Demo App] on GitHub using this framework.
62+
As a reference for the usage of each submodule see also the `IntegrationTests`.
63+
6264
[#CardReaderProviderApi]
6365
=== CardReaderProviderApi
6466

6567
(Smart)CardReader protocols for interacting with `HealthCardAccess`.
68+
6669
[#HealthCardAccess]
6770
=== HealthCardAccess
6871
This library contains the classes for cards, commands, card file systems and error handling.
@@ -124,7 +127,7 @@ In the next example we use a `HealthCard` object representing an eGK (elektronis
124127
as one kind of a `HealthCardType` implementing the `CardType` protocol and then send the command to the card (or card's channel):
125128
[source,swift]
126129
----
127-
let healthCardResponse = try await selectEsignCommand.transmit(to: Self.healthCard)
130+
let healthCardResponse = try await selectEsignCommand.transmitAsync(to: Self.healthCard)
128131
guard healthCardResponse.responseStatus == ResponseStatus.success else {
129132
throw HealthCard.Error.operational // TO-DO: handle this or throw a meaningful Error
130133
}
@@ -199,6 +202,7 @@ readCertificate
199202
}
200203
)
201204
----
205+
202206
[#HealthCardControl]
203207
=== HealthCardControl
204208

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

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

244248
See the integration tests link:include::{integrationtestdir}/HealthCardControl/[IntegrationTests/HealthCardControl/]
245249
for more already implemented use cases.
250+
246251
[#NFCCardReaderProvider]
247252
=== NFCCardReaderProvider
248253

.gitignore

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,6 @@ fastlane/test_output
9898

9999
iOSInjectionProject/
100100

101-
CardSimulationTestKit
102-
devops
103101

104102
jenkinsfiles
105103

.spi.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
version: 1
2+
builder:
3+
configs:
4+
- documentation_targets: [HealthCardControl, HealthCardAccess, NFCCardReaderProvider, CardReaderProviderApi]

CardSimulationTestKit/.jazzy.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
output: docs
2+
author: gematik GmbH
3+
author_url: http://www.gematik.de
4+
exclude: /*/internal*
5+
# module references the 'Documentation' targets PRODUCT_NAME
6+
module: CardSimulationTestKit
7+
github_url: https://gematik.github.io
8+
theme: jony
9+
swift_build_tool: xcodebuild
10+
xcodebuild_arguments:
11+
- "-project"
12+
- 'CardSimulationTestKit.xcodeproj'
13+
- "-scheme"
14+
- 'Documentation'
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
opt_in_rules:
2+
- attributes
3+
- empty_count
4+
- force_unwrapping
5+
- unneeded_parentheses_in_closure_argument
6+
- unavailable_function
7+
- trailing_closure
8+
- strict_fileprivate
9+
- sorted_imports
10+
- sorted_first_last
11+
- single_test_class
12+
- required_enum_case
13+
- redundant_type_annotation
14+
- redundant_nil_coalescing
15+
- prohibited_super_call
16+
- override_in_extension
17+
- overridden_super_call
18+
- operator_usage_whitespace
19+
- no_extension_access_modifier
20+
- multiline_function_chains
21+
- multiline_arguments
22+
- modifier_order
23+
- missing_docs
24+
- lower_acl_than_parent
25+
- literal_expression_end_indentation
26+
- first_where
27+
- file_name
28+
- fatal_error_message
29+
- explicit_init
30+
- empty_string
31+
- discouraged_optional_collection
32+
- closure_end_indentation
33+
- file_header
34+
excluded: # paths to ignore during linting. Takes precedence over `included`.
35+
- Package.swift
36+
- .build/
37+
- vendor/
38+
- Carthage/
39+
custom_rules:
40+
nimble_fail_with_description:
41+
included: ".*Test\\.swift"
42+
name: "Fail with description"
43+
regex: "(Nimble.fail\\(\\))"
44+
message: "Failures need a description"
45+
severity: warning
46+
must_not_contain_author:
47+
included:
48+
- ".*Test\\.swift"
49+
- ".*Sources\\.swift"
50+
name: "must not contain author"
51+
regex: "(\/\/[[:space:]]*Created by)"
52+
message: "Source must not contain author"
53+
severity: warning
54+
55+
file_header:
56+
required_pattern: |
57+
\/\/
58+
\/\/ Copyright \(c\) \d{4} gematik GmbH
59+
\/\/

CardSimulationTestKit/README.adoc

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
= CardSimulationTestKit
2+
3+
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.
4+
5+
CardSimulationTestKit provides an easy-to-use interface for testing against a German Health Card Simulator.
6+
It comes bundled with
7+
8+
* `CardSimulationLoader`: loads and starts a card simulation as a Java process listening on a TCP port
9+
* `CardSimulationCardReaderProvider`: implements the `CardReaderProviderApi` interface
10+
* `CardSimulationTerminalTestCase`: provides a fully initialized and functional `HealthCard` object to send commands to and receive responses from.
11+
12+
13+
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.
14+
This guide is separated in two (2) main parts. Describing
15+
16+
. the usage of the `CardSimulation-Loader` framework (How-to) and
17+
. how to maintain the technical consideration(s) and implementation(s).
18+
19+
== Frameworks
20+
21+
=== CardSimulation-Loader
22+
23+
The sole purpose of this framework is to launch and monitor a G2-Kartensimulation Java process.
24+
For detailed usage information see the inlined documentation on `SimulationManager`
25+
and `SimulationRunner`.
26+
27+
*Starting the simulator*:
28+
29+
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.
30+
Next to checking the test-cases you also find some (example) configuration files in the _Configuration.bundle_ file.
31+
32+
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:
33+
34+
[source,Swift]
35+
----
36+
func createSimulation(
37+
configFile: URL,
38+
preprocessor manipulators: [XMLPathManipulator] = [],
39+
simulatorVersion: String = "2.7.6-352",
40+
simulatorDirectory: String = "simulator",
41+
)
42+
----
43+
44+
Note: you can specify the G2-Kartensimulation version it needs to download/use.
45+
46+
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).
47+
48+
This SimulationRunnerType instance will need a CardTerminalControllerType to expose this G2-Kartensimulation virtual `HealthCard` to the HealthCardAccess/Control realm.
49+
50+
*Example*:
51+
52+
[source,Swift]
53+
----
54+
/// Read configFile from included Resources Bundle
55+
let simulatorConfig = Bundle(for: MyClass.self)
56+
.resourceFilePath(in: "Configuration", for: "configuration_EGKG2_80276883110000017222_gema5_TCP.xml")
57+
.asURL
58+
/// Launch a G2-Kartensimulation with this configuration file
59+
let runner = try SimulationManager.shared.startSimulation(
60+
configFile: simulatorConfig,
61+
preprocessor: [
62+
XMLPathManipulatorHolder.TLVPortManipulator(port: "0"),
63+
XMLPathManipulatorHolder.RelativeToAbsolutePathManipulator(with: XMLPathManipulatorHolder.CardConfigFileXMLPath, absolutePath: simulatorConfig.deletingLastPathComponent()),
64+
XMLPathManipulatorHolder.RelativeToAbsolutePathManipulator(with: XMLPathManipulatorHolder.ChannelConfigFileXMLPath, absolutePath: simulatorConfig.deletingLastPathComponent())
65+
],
66+
waitUntilLaunched: true
67+
)
68+
69+
// ... Do amazing things with the runner
70+
71+
/// Stop the runner when done
72+
runner.stop(waitUntilTerminated: true)
73+
----
74+
75+
==== Technical overview
76+
77+
As described in the previous section(s) the CardSimulationLoader provides an easy-to-use API to launch and manage a G2-Kartensimulation.
78+
In order to achieve this we need to combine some various technologies/environments (read: Nexus <--> Java <--> Swift -> CardSimulationLoader API).
79+
80+
The main components for this project to work:
81+
82+
* Download G2-Kartensimulation Nexus artifacts
83+
* Launch and monitor Java Process
84+
85+
These two (2) steps are taken care of when using the `SimulationManager` to launch a simulation.
86+
87+
==== Maven step
88+
89+
The `SimulationManager` reads the `pom.xml` and executes a shell script to run `mvn dependency:copy-dependencies`.
90+
And puts these artifacts in the same transient environment to be cleaned (manually) by calling `SimulationManager.clean` upon
91+
finishing with the simulator(s). Reason for this is to not download the artifacts for every simulator instance in case they
92+
are launch sequentially - which is reasonable to assume.
93+
94+
==== Java process
95+
96+
When the artifacts are in place, the `SimulationRunner` creates a JavaProcess that will be launched/forked in a separate process.
97+
And monitors this process by reading/parsing the `stdout` and `stderr` to detect the tlv-port number and successful initialization.
98+
99+
To start developing the project follow the Project Setup section below 👇.
100+
101+
=== CardSimulation-CardReaderProvider
102+
103+
CardTerminalProvider for communication with G2-Kartensimulation
104+
105+
=== CardSimulationTerminalTestCase
106+
107+
CardSimulationTerminalTestCase provides a fully initialized and functional `HealthCard` object to send commands
108+
against and receive responses from.
109+
110+
== Getting Started
111+
112+
CardSimulationLoader requires Swift 5.1.
113+
114+
=== Usage
115+
116+
In your Test class, derive from the `CardSimulationTerminalTestCase` which itself is a `XCTestCase`.
117+
You then have a `HealthCard` and a `CardTerminal` object directly link to an up and running CardSimulation at your disposal.
118+
119+
[source,Swift]
120+
----
121+
final class SelectCommandIntegrationTest: CardSimulationTerminalTestCase {
122+
func testSelectRoot() {
123+
let healthCard = CardSimulationTerminalTestCase.healthCard
124+
HealthCardCommand.Select.selectRoot()
125+
.execute(on: healthCard)
126+
.run(on: Executor.trampoline)
127+
}
128+
}
129+
----
130+
131+
CardSimulationTestKit comes with various CardImage configuration files.
132+
You can choose between the following images
133+
134+
* configuration_EGK_G2_1_80276883110000095711_GuD_TCP.xml (default)
135+
* configuration_EGK_G2_1_ecc.xml
136+
* configuration_EGKG2_80276883110000017222_gema5_TCP.xml
137+
* configuration_HBA_G2_1_80276883110000205690_gema5_TCP.xml
138+
* configuration_HBAG2_80276883110000017289_gema5_TCP.xml
139+
* configuration_TLK_COS_image-kontaktlos128.xml
140+
141+
by overwriting the `class func configFile() -> URL?` like this:
142+
143+
[source,Swift]
144+
----
145+
final class SelectCommandIntegrationTest: CardSimulationTerminalTestCase {
146+
override class func configFile() -> URL? {
147+
let bundle = Bundle(for: CardSimulationTerminalTestCase.self)
148+
let path = bundle.resourceFilePath(in: "Resources", for: "Configuration/configuration_EGK_G2_1_ecc.xml")
149+
return path.asURL
150+
}
151+
}
152+
----
153+
or bring your own image:
154+
155+
[source,Swift]
156+
----
157+
final class SelectCommandIntegrationTest: CardSimulationTerminalTestCase {
158+
override class func configFile() -> URL? {
159+
// this assumes, your use a test class and have a resource bundle called "Resources2.bundle"
160+
let bundle = Bundle(for: self)
161+
let path = bundle.testResourceFilePath(in: "Resources2", for: "Configuration/configuration_EGK_G2_1_ecc.xml")
162+
return path.asURL
163+
}
164+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<key>CFBundleDevelopmentRegion</key>
6+
<string>$(DEVELOPMENT_LANGUAGE)</string>
7+
<key>CFBundleExecutable</key>
8+
<string>$(EXECUTABLE_NAME)</string>
9+
<key>CFBundleIdentifier</key>
10+
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
11+
<key>CFBundleInfoDictionaryVersion</key>
12+
<string>6.0</string>
13+
<key>CFBundleName</key>
14+
<string>$(PRODUCT_NAME)</string>
15+
<key>CFBundlePackageType</key>
16+
<string>FMWK</string>
17+
<key>CFBundleShortVersionString</key>
18+
<string>1.0</string>
19+
<key>CFBundleVersion</key>
20+
<string>1</string>
21+
</dict>
22+
</plist>
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<key>CFBundleDevelopmentRegion</key>
6+
<string>$(DEVELOPMENT_LANGUAGE)</string>
7+
<key>CFBundleExecutable</key>
8+
<string>$(EXECUTABLE_NAME)</string>
9+
<key>CFBundleIdentifier</key>
10+
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
11+
<key>CFBundleInfoDictionaryVersion</key>
12+
<string>6.0</string>
13+
<key>CFBundleName</key>
14+
<string>$(PRODUCT_NAME)</string>
15+
<key>CFBundlePackageType</key>
16+
<string>FMWK</string>
17+
<key>CFBundleShortVersionString</key>
18+
<string>1.0</string>
19+
<key>CFBundleVersion</key>
20+
<string>1</string>
21+
</dict>
22+
</plist>
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<key>CFBundleDevelopmentRegion</key>
6+
<string>$(DEVELOPMENT_LANGUAGE)</string>
7+
<key>CFBundleExecutable</key>
8+
<string>$(EXECUTABLE_NAME)</string>
9+
<key>CFBundleIdentifier</key>
10+
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
11+
<key>CFBundleInfoDictionaryVersion</key>
12+
<string>6.0</string>
13+
<key>CFBundleName</key>
14+
<string>$(PRODUCT_NAME)</string>
15+
<key>CFBundlePackageType</key>
16+
<string>FMWK</string>
17+
<key>CFBundleShortVersionString</key>
18+
<string>1.0</string>
19+
<key>CFBundleVersion</key>
20+
<string>1</string>
21+
</dict>
22+
</plist>

0 commit comments

Comments
 (0)