Added or extended value objects for Bank, Customer and Product; fixed tests
This commit is contained in:
parent
9ac4af58ff
commit
b4ba9a0bcf
|
@ -1,12 +1,9 @@
|
|||
package net.dankito.fints
|
||||
|
||||
import net.dankito.fints.messages.MessageBuilder
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.Dialogsprache
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.KundensystemID
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.KundensystemStatusWerte
|
||||
import net.dankito.fints.model.AccountCredentials
|
||||
import net.dankito.fints.model.BankInfo
|
||||
import net.dankito.fints.model.ProductInfo
|
||||
import net.dankito.fints.model.BankData
|
||||
import net.dankito.fints.model.CustomerData
|
||||
import net.dankito.fints.model.ProductData
|
||||
import net.dankito.fints.util.IBase64Service
|
||||
import net.dankito.utils.web.client.IWebClient
|
||||
import net.dankito.utils.web.client.OkHttpWebClient
|
||||
|
@ -21,31 +18,28 @@ open class FinTsClient(
|
|||
) {
|
||||
|
||||
|
||||
fun getAnonymousBankInfo(bankInfo: BankInfo, productInfo: ProductInfo) {
|
||||
val requestBody = messageBuilder.createAnonymousDialogInitMessage(bankInfo.countryCode, bankInfo.bankCode,
|
||||
productInfo.productName, productInfo.productVersion)
|
||||
fun getAnonymousBankInfo(bank: BankData, product: ProductData) {
|
||||
val requestBody = messageBuilder.createAnonymousDialogInitMessage(bank, product)
|
||||
|
||||
val response = getResponseForMessage(requestBody, bankInfo)
|
||||
val response = getResponseForMessage(requestBody, bank)
|
||||
|
||||
handleResponse(response)
|
||||
}
|
||||
|
||||
fun getBankInfo(credentials: AccountCredentials, bankInfo: BankInfo, productInfo: ProductInfo) {
|
||||
val requestBody = messageBuilder.createDialogInitMessage(bankInfo.countryCode, bankInfo.bankCode,
|
||||
credentials.customerId, KundensystemID.PinTan, KundensystemStatusWerte.Benoetigt, 0, 0, Dialogsprache.German,
|
||||
productInfo.productName, productInfo.productVersion)
|
||||
fun getBankInfo(bank: BankData, customer: CustomerData, product: ProductData) {
|
||||
val requestBody = messageBuilder.createDialogInitMessage(bank, customer, product)
|
||||
|
||||
val response = getResponseForMessage(requestBody, bankInfo)
|
||||
val response = getResponseForMessage(requestBody, bank)
|
||||
|
||||
handleResponse(response)
|
||||
}
|
||||
|
||||
|
||||
protected open fun getResponseForMessage(requestBody: String, bankInfo: BankInfo): WebClientResponse {
|
||||
protected open fun getResponseForMessage(requestBody: String, bank: BankData): WebClientResponse {
|
||||
val encodedRequestBody = base64Service.encode(requestBody)
|
||||
|
||||
return webClient.post(
|
||||
RequestParameters(bankInfo.finTsServerAddress, encodedRequestBody, "application/octet-stream")
|
||||
RequestParameters(bank.finTs3ServerAddress, encodedRequestBody, "application/octet-stream")
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
package net.dankito.fints.messages
|
||||
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.*
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.signatur.Sicherheitsfunktion
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.Nachrichtennummer
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.tan.TanProcess
|
||||
import net.dankito.fints.messages.nachrichten.Nachricht
|
||||
import net.dankito.fints.messages.segmente.ISegmentNumberGenerator
|
||||
import net.dankito.fints.messages.segmente.Segment
|
||||
import net.dankito.fints.messages.segmente.SegmentNumberGenerator
|
||||
import net.dankito.fints.messages.segmente.implementierte.*
|
||||
import net.dankito.fints.model.BankData
|
||||
import net.dankito.fints.model.CustomerData
|
||||
import net.dankito.fints.model.ProductData
|
||||
import net.dankito.fints.util.FinTsUtils
|
||||
|
||||
|
||||
|
@ -33,56 +35,43 @@ open class MessageBuilder(protected val generator: ISegmentNumberGenerator = Seg
|
|||
*
|
||||
* Bei anonymen Dialogen werden Nachrichten weder signiert, noch können sie verschlüsselt und komprimiert werden.
|
||||
*/
|
||||
open fun createAnonymousDialogInitMessage(
|
||||
bankCountryCode: Int,
|
||||
bankCode: String,
|
||||
productName: String,
|
||||
productVersion: String
|
||||
): String {
|
||||
open fun createAnonymousDialogInitMessage(bank: BankData, product: ProductData): String {
|
||||
|
||||
val customerId = KundenID.Anonymous
|
||||
/**
|
||||
* Wenn eine Synchronisierung der Kundensystem-ID durchgeführt wird, ist als Identifizierung der Partei ‚0’ einzustellen.
|
||||
*/
|
||||
|
||||
return createMessage(false, false, bankCountryCode, bankCode, customerId, listOf(
|
||||
IdentifikationsSegment(generator.resetSegmentNumber(1), bankCountryCode, bankCode, customerId, KundensystemID.Anonymous, KundensystemStatusWerte.NichtBenoetigt),
|
||||
Verarbeitungsvorbereitung(generator.getNextSegmentNumber(), BPDVersion.VersionNotReceivedYet, UPDVersion.VersionNotReceivedYet, Dialogsprache.Default, productName, productVersion)
|
||||
val customer = CustomerData.Anonymous
|
||||
|
||||
return createMessage(false, false, bank, customer, listOf(
|
||||
IdentifikationsSegment(generator.resetSegmentNumber(1), bank, customer),
|
||||
Verarbeitungsvorbereitung(generator.getNextSegmentNumber(), bank, customer, product)
|
||||
))
|
||||
}
|
||||
|
||||
open fun createDialogInitMessage(
|
||||
bankCountryCode: Int,
|
||||
bankCode: String,
|
||||
customerId: String,
|
||||
customerSystemId: String,
|
||||
status: KundensystemStatusWerte,
|
||||
bpdVersion: Int,
|
||||
updVersion: Int,
|
||||
language: Dialogsprache,
|
||||
productName: String,
|
||||
productVersion: String
|
||||
): String {
|
||||
open fun createDialogInitMessage(bank: BankData, customer: CustomerData, product: ProductData): String {
|
||||
|
||||
return createMessage(true, true, bankCountryCode, bankCode, customerId, listOf(
|
||||
IdentifikationsSegment(generator.resetSegmentNumber(2), bankCountryCode, bankCode, customerId, customerSystemId, status),
|
||||
Verarbeitungsvorbereitung(generator.getNextSegmentNumber(), bpdVersion, updVersion, language, productName, productVersion),
|
||||
return createMessage(true, true, bank, customer, listOf(
|
||||
IdentifikationsSegment(generator.resetSegmentNumber(2), bank, customer),
|
||||
Verarbeitungsvorbereitung(generator.getNextSegmentNumber(), bank, customer, product),
|
||||
ZweiSchrittTanEinreichung(generator.getNextSegmentNumber(), TanProcess.TanProcess4, "HKIDN")
|
||||
))
|
||||
}
|
||||
|
||||
|
||||
open fun createMessage(signMessage: Boolean, encryptMessage: Boolean, bankCountryCode: Int, bankCode: String, customerId: String,
|
||||
open fun createMessage(signMessage: Boolean, encryptMessage: Boolean, bank: BankData, customer: CustomerData,
|
||||
payloadSegments: List<Segment>): String {
|
||||
|
||||
var payload = payloadSegments
|
||||
val partyIdentification = "0"
|
||||
val date = utils.formatDateTodayAsInt()
|
||||
val time = utils.formatTimeNowAsInt()
|
||||
|
||||
if (signMessage) {
|
||||
payload = signPayload(2, partyIdentification, date, time, bankCountryCode, bankCode, customerId, payload)
|
||||
payload = signPayload(2, bank, customer, date, time, payload)
|
||||
}
|
||||
|
||||
if (encryptMessage) {
|
||||
payload = encryptPayload(partyIdentification, date, time, bankCountryCode, bankCode, customerId, payload)
|
||||
payload = encryptPayload(bank, customer, date, time, payload)
|
||||
}
|
||||
|
||||
val formattedPayload = formatPayload(payload)
|
||||
|
@ -99,37 +88,33 @@ open class MessageBuilder(protected val generator: ISegmentNumberGenerator = Seg
|
|||
}
|
||||
|
||||
|
||||
protected open fun signPayload(headerSegmentNumber: Int, partyIdentification: String, date: Int, time: Int,
|
||||
bankCountryCode: Int, bankCode: String, customerId: String,
|
||||
protected open fun signPayload(headerSegmentNumber: Int, bank: BankData, customer: CustomerData, date: Int, time: Int,
|
||||
payloadSegments: List<Segment>): List<Segment> {
|
||||
val controlReference = "1" // TODO
|
||||
|
||||
val signatureHeader = PinTanSignaturkopf(
|
||||
headerSegmentNumber,
|
||||
Sicherheitsfunktion.PIN_TAN_911, // TODO
|
||||
bank,
|
||||
customer,
|
||||
controlReference,
|
||||
"0",
|
||||
utils.formatDateTodayAsInt(),
|
||||
utils.formatTimeNowAsInt(),
|
||||
bankCountryCode,
|
||||
bankCode,
|
||||
customerId
|
||||
date,
|
||||
time
|
||||
)
|
||||
|
||||
val signatureClosing = Signaturabschluss(
|
||||
generator.getNextSegmentNumber(),
|
||||
controlReference,
|
||||
"12345" // TODO
|
||||
customer.pin
|
||||
)
|
||||
|
||||
return listOf(signatureHeader, *payloadSegments.toTypedArray(), signatureClosing)
|
||||
}
|
||||
|
||||
|
||||
private fun encryptPayload(partyIdentification: String, date: Int, time: Int,
|
||||
bankCountryCode: Int, bankCode: String, customerId: String, payload: List<Segment>): List<Segment> {
|
||||
private fun encryptPayload(bank: BankData, customer: CustomerData, date: Int, time: Int,
|
||||
payload: List<Segment>): List<Segment> {
|
||||
|
||||
val encryptionHeader = PinTanVerschluesselungskopf(partyIdentification, date, time, bankCountryCode, bankCode, customerId)
|
||||
val encryptionHeader = PinTanVerschluesselungskopf(bank, customer, date, time)
|
||||
|
||||
val encryptedData = VerschluesselteDaten(formatPayload(payload) + Nachricht.SegmentSeparator)
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package net.dankito.fints.messages.datenelemente.implementierte
|
||||
package net.dankito.fints.messages.datenelemente.abgeleiteteformate
|
||||
|
||||
import net.dankito.fints.messages.Existenzstatus
|
||||
import net.dankito.fints.messages.datenelemente.basisformate.ZiffernDatenelement
|
|
@ -9,7 +9,7 @@ import net.dankito.fints.messages.datenelemente.Datenelement
|
|||
*
|
||||
* It simply gets, prefixed by '@<payload_length>@', appended to VerschluesselteDaten segment header
|
||||
*/
|
||||
class PinTanVerschluesselteDatenDatenelement(val payload: String) : Datenelement(Existenzstatus.Mandatory) {
|
||||
open class PinTanVerschluesselteDatenDatenelement(val payload: String) : Datenelement(Existenzstatus.Mandatory) {
|
||||
|
||||
override fun format(): String {
|
||||
return "@${payload.length}@" + payload
|
||||
|
|
|
@ -11,6 +11,9 @@ import net.dankito.fints.messages.datenelemente.abgeleiteteformate.Identifikatio
|
|||
open class IdentifizierungDerPartei(identification: String) : Identifikation(identification, Existenzstatus.Optional) {
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Wenn eine Synchronisierung der Kundensystem-ID durchgeführt wird, ist als Identifizierung der Partei ‚0’ einzustellen.
|
||||
*/
|
||||
const val SynchronizingCustomerSystemId = "0"
|
||||
}
|
||||
|
||||
|
|
|
@ -1,13 +1,17 @@
|
|||
package net.dankito.fints.messages.datenelementgruppen.implementierte
|
||||
|
||||
import net.dankito.fints.messages.Existenzstatus
|
||||
import net.dankito.fints.messages.datenelemente.abgeleiteteformate.Laenderkennzeichen
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.Kreditinstitutscode
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.Laenderkennzeichen
|
||||
import net.dankito.fints.messages.datenelementgruppen.Datenelementgruppe
|
||||
|
||||
|
||||
open class Kreditinstitutskennung(bankCountryCode: Int, bankCode: String)
|
||||
open class Kreditinstitutskennung @JvmOverloads constructor(
|
||||
bankCountryCode: Int,
|
||||
bankCode: String,
|
||||
existenzstatus: Existenzstatus = Existenzstatus.Mandatory
|
||||
)
|
||||
: Datenelementgruppe(listOf(
|
||||
Laenderkennzeichen(bankCountryCode, Existenzstatus.Mandatory),
|
||||
Kreditinstitutscode(bankCode, Existenzstatus.Mandatory)
|
||||
), Existenzstatus.Mandatory)
|
||||
), existenzstatus)
|
|
@ -1,43 +0,0 @@
|
|||
package net.dankito.fints.messages.nachrichten.implementierte
|
||||
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.Dialogsprache
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.KundensystemStatusWerte
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.Nachrichtennummer.Companion.FirstMessageNumber
|
||||
import net.dankito.fints.messages.nachrichten.Nachricht
|
||||
import net.dankito.fints.messages.segmente.implementierte.IdentifikationsSegment
|
||||
import net.dankito.fints.messages.segmente.implementierte.Nachrichtenabschluss
|
||||
import net.dankito.fints.messages.segmente.implementierte.Nachrichtenkopf
|
||||
import net.dankito.fints.messages.segmente.implementierte.Verarbeitungsvorbereitung
|
||||
|
||||
|
||||
open class Dialoginitialisierung(
|
||||
messageSize: Int, // TODO: how to get / calculate size? (give each Segment, Dataelement, ... a size value?)
|
||||
bankCountryCode: Int,
|
||||
bankCode: String,
|
||||
customerId: String,
|
||||
customerSystemId: String,
|
||||
bpdVersion: Int,
|
||||
updVersion: Int,
|
||||
language: Dialogsprache,
|
||||
productName: String,
|
||||
productVersion: String
|
||||
)
|
||||
: Nachricht(listOf(
|
||||
Nachrichtenkopf(1, messageSize, "0", FirstMessageNumber),
|
||||
IdentifikationsSegment(2, bankCountryCode, bankCode, customerId, customerSystemId, KundensystemStatusWerte.NichtBenoetigt), // TODO: KundensystemStatusWerte
|
||||
Verarbeitungsvorbereitung(3, bpdVersion, updVersion, language, productName, productVersion),
|
||||
Nachrichtenabschluss(4, FirstMessageNumber)
|
||||
)) {
|
||||
|
||||
/**
|
||||
* Zur Einleitung des Prozesses der Gewährleistung einer starken Kun-
|
||||
denauthentifizierung gemäß [PSD2] muss bei TAN-Verfahren ein HKTAN-
|
||||
Segment ab Segmentversion #6 eingestellt werden, wenn ein Kreditinstitut
|
||||
die Verwendung von HKTAN #6 unterstützt (BPD). Wenn HKTAN #6
|
||||
nicht gesendet wird, kann der Dialog vom Institut mit dem Rückmeldungs-
|
||||
code 9075 – Dialog abgebrochen - Starke Authentifizierung
|
||||
erforderlich abgewiesen werden.
|
||||
|
||||
*/
|
||||
|
||||
}
|
|
@ -4,24 +4,22 @@ import net.dankito.fints.messages.Existenzstatus
|
|||
import net.dankito.fints.messages.datenelemente.implementierte.KundenID
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.KundensystemID
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.KundensystemStatus
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.KundensystemStatusWerte
|
||||
import net.dankito.fints.messages.datenelementgruppen.implementierte.Kreditinstitutskennung
|
||||
import net.dankito.fints.messages.datenelementgruppen.implementierte.Segmentkopf
|
||||
import net.dankito.fints.messages.segmente.Segment
|
||||
import net.dankito.fints.model.BankData
|
||||
import net.dankito.fints.model.CustomerData
|
||||
|
||||
|
||||
open class IdentifikationsSegment(
|
||||
segmentNumber: Int,
|
||||
bankCountryCode: Int,
|
||||
bankCode: String,
|
||||
customerId: String,
|
||||
customerSystemId: String,
|
||||
status: KundensystemStatusWerte
|
||||
bank: BankData,
|
||||
customer: CustomerData
|
||||
|
||||
) : Segment(listOf(
|
||||
Segmentkopf("HKIDN", 2, segmentNumber),
|
||||
Kreditinstitutskennung(bankCountryCode, bankCode),
|
||||
KundenID(customerId),
|
||||
KundensystemID(customerSystemId),
|
||||
KundensystemStatus(status, Existenzstatus.Mandatory)
|
||||
Kreditinstitutskennung(bank.countryCode, bank.bankCode),
|
||||
KundenID(customer.customerId),
|
||||
KundensystemID(customer.customerSystemId),
|
||||
KundensystemStatus(customer.customerSystemStatus, Existenzstatus.Mandatory)
|
||||
), Existenzstatus.Mandatory)
|
|
@ -1,36 +1,30 @@
|
|||
package net.dankito.fints.messages.segmente.implementierte
|
||||
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.signatur.*
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.signatur.OperationsmodusKodiert
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.signatur.Schluesselnummer
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.signatur.Schluesselversion
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.signatur.SignaturalgorithmusKodiert
|
||||
import net.dankito.fints.model.BankData
|
||||
import net.dankito.fints.model.CustomerData
|
||||
|
||||
|
||||
open class PinTanSignaturkopf(
|
||||
segmentNumber: Int,
|
||||
securityFunction: Sicherheitsfunktion,
|
||||
bank: BankData,
|
||||
customer: CustomerData,
|
||||
securityControlReference: String,
|
||||
/**
|
||||
* Wenn eine Synchronisierung der Kundensystem-ID durchgeführt wird, ist als Identifizierung der Partei ‚0’ einzustellen.
|
||||
*/
|
||||
partyIdentification: String,
|
||||
date: Int,
|
||||
time: Int,
|
||||
bankCountryCode: Int,
|
||||
bankCode: String,
|
||||
userIdentification: String
|
||||
time: Int
|
||||
|
||||
) : Signaturkopf(
|
||||
segmentNumber,
|
||||
Sicherheitsverfahren.PIN_TAN_Verfahren,
|
||||
VersionDesSicherheitsverfahrens.PIN_Zwei_Schritt,
|
||||
securityFunction,
|
||||
bank,
|
||||
customer,
|
||||
securityControlReference,
|
||||
partyIdentification,
|
||||
date,
|
||||
time,
|
||||
SignaturalgorithmusKodiert.FinTsMockValue,
|
||||
OperationsmodusKodiert.FinTsMockValue,
|
||||
bankCountryCode,
|
||||
bankCode,
|
||||
userIdentification,
|
||||
Schluesselnummer.FinTsMockValue,
|
||||
Schluesselversion.FinTsMockValue
|
||||
)
|
|
@ -1,27 +1,26 @@
|
|||
package net.dankito.fints.messages.segmente.implementierte
|
||||
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.encryption.Komprimierungsfunktion
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.signatur.*
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.signatur.OperationsmodusKodiert
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.signatur.Schluesselart
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.signatur.Schluesselnummer
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.signatur.Schluesselversion
|
||||
import net.dankito.fints.model.BankData
|
||||
import net.dankito.fints.model.CustomerData
|
||||
|
||||
|
||||
open class PinTanVerschluesselungskopf(
|
||||
partyIdentification: String,
|
||||
bank: BankData,
|
||||
customer: CustomerData,
|
||||
date: Int,
|
||||
time: Int,
|
||||
bankCountryCode: Int,
|
||||
bankCode: String,
|
||||
userIdentification: String
|
||||
time: Int
|
||||
|
||||
) : Verschluesselungskopf(
|
||||
Sicherheitsverfahren.PIN_TAN_Verfahren,
|
||||
VersionDesSicherheitsverfahrens.PIN_Zwei_Schritt,
|
||||
partyIdentification,
|
||||
bank,
|
||||
customer,
|
||||
date,
|
||||
time,
|
||||
OperationsmodusKodiert.FinTsMockValue,
|
||||
bankCountryCode,
|
||||
bankCode,
|
||||
userIdentification,
|
||||
Schluesselart.Chiffrierschluessel,
|
||||
Schluesselnummer.FinTsMockValue,
|
||||
Schluesselversion.FinTsMockValue,
|
||||
|
|
|
@ -5,6 +5,8 @@ import net.dankito.fints.messages.datenelemente.implementierte.signatur.*
|
|||
import net.dankito.fints.messages.datenelementgruppen.implementierte.Segmentkopf
|
||||
import net.dankito.fints.messages.datenelementgruppen.implementierte.signatur.*
|
||||
import net.dankito.fints.messages.segmente.Segment
|
||||
import net.dankito.fints.model.BankData
|
||||
import net.dankito.fints.model.CustomerData
|
||||
|
||||
|
||||
/**
|
||||
|
@ -22,36 +24,28 @@ import net.dankito.fints.messages.segmente.Segment
|
|||
*/
|
||||
open class Signaturkopf(
|
||||
segmentNumber: Int,
|
||||
method: Sicherheitsverfahren,
|
||||
version: VersionDesSicherheitsverfahrens,
|
||||
securityFunction: Sicherheitsfunktion,
|
||||
bank: BankData,
|
||||
customer: CustomerData,
|
||||
securityControlReference: String,
|
||||
/**
|
||||
* Wenn eine Synchronisierung der Kundensystem-ID durchgeführt wird, ist als Identifizierung der Partei ‚0’ einzustellen.
|
||||
*/
|
||||
partyIdentification: String,
|
||||
date: Int,
|
||||
time: Int,
|
||||
algorithm: Signaturalgorithmus,
|
||||
mode: Operationsmodus,
|
||||
bankCountryCode: Int,
|
||||
bankCode: String,
|
||||
userIdentification: String,
|
||||
keyNumber: Int,
|
||||
keyVersion: Int
|
||||
|
||||
) : Segment(listOf(
|
||||
Segmentkopf("HNSHK", 4, segmentNumber), // allowed
|
||||
Sicherheitsprofil(method, version), // allowed: method: RAH, PIN;
|
||||
SicherheitsfunktionKodiert(securityFunction), // allowed: 1, 2
|
||||
Sicherheitsprofil(customer.securityMethod!!, customer.version!!), // allowed: method: RAH, PIN;
|
||||
SicherheitsfunktionKodiert(customer.selectedTanProcedure?.securityFunction!!), // allowed: 1, 2
|
||||
Sicherheitskontrollreferenz(securityControlReference), // allowed: <>0
|
||||
BereichDerSicherheitsapplikationKodiert(BereichDerSicherheitsapplikation.SignaturkopfUndHBCINutzdaten), // allowed: 1 ?
|
||||
RolleDesSicherheitslieferantenKodiert(), // allowed: 1
|
||||
SicherheitsidentifikationDetails(partyIdentification),
|
||||
SicherheitsidentifikationDetails(customer.partyIdentification),
|
||||
// "Bei softwarebasierten Verfahren wird die Sicherheitsreferenznummer auf Basis des DE Kundensystem-ID und des DE Benutzerkennung der DEG Schlüsselnamen verwaltet.
|
||||
Sicherheitsreferenznummer(1), // TODO: is this always 1?
|
||||
SicherheitsdatumUndUhrzeit(date, time),
|
||||
HashalgorithmusDatenelementgruppe(),
|
||||
SignaturalgorithmusDatenelementgruppe(algorithm, mode),
|
||||
Schluesselname(bankCountryCode, bankCode, userIdentification, Schluesselart.Signierschluessel, keyNumber, keyVersion)
|
||||
Schluesselname(bank.countryCode, bank.bankCode, customer.customerId, Schluesselart.Signierschluessel, keyNumber, keyVersion)
|
||||
), Existenzstatus.Mandatory)
|
|
@ -4,20 +4,21 @@ import net.dankito.fints.messages.Existenzstatus
|
|||
import net.dankito.fints.messages.datenelemente.implementierte.*
|
||||
import net.dankito.fints.messages.datenelementgruppen.implementierte.Segmentkopf
|
||||
import net.dankito.fints.messages.segmente.Segment
|
||||
import net.dankito.fints.model.BankData
|
||||
import net.dankito.fints.model.CustomerData
|
||||
import net.dankito.fints.model.ProductData
|
||||
|
||||
|
||||
open class Verarbeitungsvorbereitung(
|
||||
segmentNumber: Int,
|
||||
bpdVersion: Int,
|
||||
updVersion: Int,
|
||||
language: Dialogsprache,
|
||||
productName: String,
|
||||
productVersion: String
|
||||
bank: BankData,
|
||||
customer: CustomerData,
|
||||
product: ProductData
|
||||
) : Segment(listOf(
|
||||
Segmentkopf("HKVVB", 3, segmentNumber),
|
||||
BPDVersion(bpdVersion, Existenzstatus.Mandatory),
|
||||
UPDVersion(updVersion, Existenzstatus.Mandatory),
|
||||
DialogspracheDatenelement(language, Existenzstatus.Mandatory),
|
||||
Produktbezeichnung(productName, Existenzstatus.Mandatory),
|
||||
Produktversion(productVersion, Existenzstatus.Mandatory)
|
||||
BPDVersion(bank.bpdVersion, Existenzstatus.Mandatory),
|
||||
UPDVersion(customer.updVersion, Existenzstatus.Mandatory),
|
||||
DialogspracheDatenelement(customer.selectedLanguage, Existenzstatus.Mandatory),
|
||||
Produktbezeichnung(product.name, Existenzstatus.Mandatory),
|
||||
Produktversion(product.version, Existenzstatus.Mandatory)
|
||||
), Existenzstatus.Mandatory)
|
|
@ -12,6 +12,8 @@ import net.dankito.fints.messages.datenelementgruppen.implementierte.signatur.Si
|
|||
import net.dankito.fints.messages.datenelementgruppen.implementierte.signatur.SicherheitsidentifikationDetails
|
||||
import net.dankito.fints.messages.datenelementgruppen.implementierte.signatur.Sicherheitsprofil
|
||||
import net.dankito.fints.messages.segmente.Segment
|
||||
import net.dankito.fints.model.BankData
|
||||
import net.dankito.fints.model.CustomerData
|
||||
|
||||
|
||||
/**
|
||||
|
@ -31,15 +33,11 @@ import net.dankito.fints.messages.segmente.Segment
|
|||
* Dieses Feld darf nicht belegt werden.
|
||||
*/
|
||||
open class Verschluesselungskopf(
|
||||
method: Sicherheitsverfahren,
|
||||
version: VersionDesSicherheitsverfahrens,
|
||||
partyIdentification: String,
|
||||
bank: BankData,
|
||||
customer: CustomerData,
|
||||
date: Int,
|
||||
time: Int,
|
||||
mode: Operationsmodus,
|
||||
bankCountryCode: Int,
|
||||
bankCode: String,
|
||||
userIdentification: String,
|
||||
key: Schluesselart,
|
||||
keyNumber: Int,
|
||||
keyVersion: Int,
|
||||
|
@ -47,13 +45,13 @@ open class Verschluesselungskopf(
|
|||
|
||||
) : Segment(listOf(
|
||||
Segmentkopf("HNVSK", 3, 998),
|
||||
Sicherheitsprofil(method, version),
|
||||
Sicherheitsprofil(customer.securityMethod!!, customer.version!!),
|
||||
SicherheitsfunktionKodiert(Sicherheitsfunktion.Klartext), // allowed: 4
|
||||
RolleDesSicherheitslieferantenKodiert(), // allowed: 1, 4
|
||||
SicherheitsidentifikationDetails(partyIdentification),
|
||||
SicherheitsidentifikationDetails(customer.partyIdentification),
|
||||
SicherheitsdatumUndUhrzeit(date, time),
|
||||
VerschluesselungsalgorithmusDatenelementgruppe(mode),
|
||||
Schluesselname(bankCountryCode, bankCode, userIdentification, key, keyNumber, keyVersion),
|
||||
Schluesselname(bank.countryCode, bank.bankCode, customer.customerId, key, keyNumber, keyVersion),
|
||||
KomprimierungsfunktionDatenelement(algorithm),
|
||||
// Certificate not applicapable for PIN/TAN; it should be also fine to write nothing at all and therefore leave NotAllowedDatenelement away
|
||||
NotAllowedDatenelement() // Zertifikat is actually a Datenelementgruppe, not a Datenelement
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
package net.dankito.fints.model
|
||||
|
||||
|
||||
open class AccountCredentials @JvmOverloads constructor(
|
||||
val bankCode: String,
|
||||
val customerId: String,
|
||||
val pin: String,
|
||||
val userId: String = customerId
|
||||
)
|
|
@ -0,0 +1,19 @@
|
|||
package net.dankito.fints.model
|
||||
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.Dialogsprache
|
||||
|
||||
|
||||
open class BankData(
|
||||
val bankCode: String,
|
||||
val countryCode: Int,
|
||||
var finTs3ServerAddress: String,
|
||||
var bpdVersion: Int = 0,
|
||||
var supportedLanguages: List<Dialogsprache> = listOf()
|
||||
) {
|
||||
|
||||
|
||||
override fun toString(): String {
|
||||
return bankCode
|
||||
}
|
||||
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
package net.dankito.fints.model
|
||||
|
||||
|
||||
open class BankInfo(
|
||||
val bankCode: String,
|
||||
val countryCode: Int,
|
||||
val finTsServerAddress: String
|
||||
)
|
|
@ -0,0 +1,35 @@
|
|||
package net.dankito.fints.model
|
||||
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.Dialogsprache
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.KundenID
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.KundensystemID
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.KundensystemStatusWerte
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.signatur.IdentifizierungDerPartei
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.signatur.Sicherheitsverfahren
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.signatur.VersionDesSicherheitsverfahrens
|
||||
|
||||
|
||||
open class CustomerData(
|
||||
val customerId: String,
|
||||
var pin: String,
|
||||
val userId: String = customerId,
|
||||
var updVersion: Int = 0,
|
||||
var availableTanProcedures: List<TanProcedure> = listOf(),
|
||||
var selectedTanProcedure: TanProcedure? = null,
|
||||
var securityMethod: Sicherheitsverfahren = Sicherheitsverfahren.PIN_TAN_Verfahren,
|
||||
var version: VersionDesSicherheitsverfahrens = VersionDesSicherheitsverfahrens.PIN_Zwei_Schritt,
|
||||
var selectedLanguage: Dialogsprache = Dialogsprache.Default,
|
||||
var customerSystemId: String = KundensystemID.Anonymous,
|
||||
var customerSystemStatus: KundensystemStatusWerte = KundensystemStatusWerte.Benoetigt,
|
||||
var partyIdentification: String = IdentifizierungDerPartei.SynchronizingCustomerSystemId
|
||||
) {
|
||||
|
||||
companion object {
|
||||
val Anonymous = CustomerData(KundenID.Anonymous, "", customerSystemStatus = KundensystemStatusWerte.NichtBenoetigt)
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return customerId
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package net.dankito.fints.model
|
||||
|
||||
|
||||
open class ProductData(
|
||||
val name: String,
|
||||
val version: String
|
||||
) {
|
||||
|
||||
override fun toString(): String {
|
||||
return "$name $version"
|
||||
}
|
||||
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
package net.dankito.fints.model
|
||||
|
||||
|
||||
open class ProductInfo(
|
||||
val productName: String,
|
||||
val productVersion: String
|
||||
)
|
|
@ -0,0 +1,16 @@
|
|||
package net.dankito.fints.model
|
||||
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.signatur.Sicherheitsfunktion
|
||||
|
||||
|
||||
open class TanProcedure(
|
||||
val displayName: String,
|
||||
val securityFunction: Sicherheitsfunktion,
|
||||
val type: TanProcedureType
|
||||
) {
|
||||
|
||||
override fun toString(): String {
|
||||
return "$displayName ($type, ${securityFunction.code}"
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package net.dankito.fints.model
|
||||
|
||||
|
||||
enum class TanProcedureType {
|
||||
|
||||
EnterTan,
|
||||
|
||||
ChipTan,
|
||||
|
||||
ChipTanQrCode,
|
||||
|
||||
SmsTan,
|
||||
|
||||
PushTan
|
||||
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package net.dankito.fints
|
||||
|
||||
import net.dankito.fints.messages.datenelemente.abgeleiteteformate.Laenderkennzeichen
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.Dialogsprache
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.signatur.Sicherheitsfunktion
|
||||
import net.dankito.fints.model.*
|
||||
|
||||
|
||||
abstract class FinTsTestBase {
|
||||
|
||||
companion object {
|
||||
const val BankCode = "12345678"
|
||||
|
||||
val Bank = BankData(BankCode, Laenderkennzeichen.Germany, "")
|
||||
|
||||
const val CustomerId = "0987654321"
|
||||
|
||||
const val Pin = "12345"
|
||||
|
||||
val Language = Dialogsprache.German
|
||||
|
||||
val SecurityFunction = Sicherheitsfunktion.PIN_TAN_911
|
||||
|
||||
const val ControlReference = "1"
|
||||
|
||||
val Customer = CustomerData(CustomerId, Pin, selectedTanProcedure = TanProcedure("chipTAN-optisch", SecurityFunction, TanProcedureType.ChipTan), selectedLanguage = Language)
|
||||
|
||||
const val ProductName = "FinTS-TestClient25Stellen"
|
||||
|
||||
const val ProductVersion = "1"
|
||||
|
||||
val Product = ProductData(ProductName, ProductVersion)
|
||||
|
||||
const val Date = 19880327
|
||||
|
||||
const val Time = 182752
|
||||
}
|
||||
|
||||
|
||||
protected open fun normalizeBinaryData(message: String): String {
|
||||
return message.replace(0.toChar(), ' ')
|
||||
}
|
||||
|
||||
}
|
|
@ -1,39 +1,13 @@
|
|||
package net.dankito.fints.messages
|
||||
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.Dialogsprache
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.KundensystemID
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.KundensystemStatusWerte
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.Laenderkennzeichen
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.signatur.Sicherheitsfunktion
|
||||
import net.dankito.fints.FinTsTestBase
|
||||
import net.dankito.fints.util.FinTsUtils
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.Test
|
||||
import java.util.*
|
||||
|
||||
|
||||
class MessageBuilderTest {
|
||||
|
||||
companion object {
|
||||
const val BankCode = "12345678"
|
||||
|
||||
const val CustomerId = "0987654321"
|
||||
|
||||
const val Pin = "12345"
|
||||
|
||||
const val Date = 19880327
|
||||
|
||||
const val Time = 182752
|
||||
|
||||
val Language = Dialogsprache.German
|
||||
|
||||
val SecurityFunction = Sicherheitsfunktion.PIN_TAN_911
|
||||
|
||||
const val ControlReference = "1"
|
||||
|
||||
const val ProductName = "FinTS-TestClient25Stellen"
|
||||
|
||||
const val ProductVersion = "1"
|
||||
}
|
||||
class MessageBuilderTest : FinTsTestBase() {
|
||||
|
||||
private val underTest = MessageBuilder(utils = object : FinTsUtils() {
|
||||
override fun formatDate(date: Date): String {
|
||||
|
@ -50,8 +24,7 @@ class MessageBuilderTest {
|
|||
fun createAnonymousDialogInitMessage() {
|
||||
|
||||
// given
|
||||
val underTest = underTest.createAnonymousDialogInitMessage(
|
||||
Laenderkennzeichen.Germany, BankCode, ProductName, ProductVersion)
|
||||
val underTest = underTest.createAnonymousDialogInitMessage(Bank, Product)
|
||||
|
||||
// when
|
||||
val result = underTest.format()
|
||||
|
@ -69,9 +42,7 @@ class MessageBuilderTest {
|
|||
fun createDialogInitMessage() {
|
||||
|
||||
// given
|
||||
val underTest = underTest.createDialogInitMessage(Laenderkennzeichen.Germany, BankCode, CustomerId,
|
||||
KundensystemID.PinTan, KundensystemStatusWerte.Benoetigt, 0, 0, Language,
|
||||
ProductName, ProductVersion)
|
||||
val underTest = underTest.createDialogInitMessage(Bank, Customer, Product)
|
||||
|
||||
// when
|
||||
val result = underTest.format()
|
||||
|
@ -89,8 +60,4 @@ class MessageBuilderTest {
|
|||
))
|
||||
}
|
||||
|
||||
protected open fun normalizeBinaryData(message: String): String {
|
||||
return message.replace(0.toChar(), ' ')
|
||||
}
|
||||
|
||||
}
|
|
@ -1,26 +1,23 @@
|
|||
package net.dankito.fints.messages.segmente.implementierte
|
||||
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.KundenID
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.KundensystemID
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.KundensystemStatusWerte
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.Laenderkennzeichen
|
||||
import net.dankito.fints.FinTsTestBase
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.Test
|
||||
|
||||
|
||||
class IdentifikationsSegmentTest {
|
||||
class IdentifikationsSegmentTest : FinTsTestBase() {
|
||||
|
||||
@Test
|
||||
fun format() {
|
||||
|
||||
// given
|
||||
val underTest = IdentifikationsSegment(2, Laenderkennzeichen.Germany, "12345678", KundenID.Anonymous, KundensystemID.Anonymous, KundensystemStatusWerte.NichtBenoetigt)
|
||||
val underTest = IdentifikationsSegment(2, Bank, Customer)
|
||||
|
||||
// when
|
||||
val result = underTest.format()
|
||||
|
||||
// then
|
||||
assertThat(result).isEqualTo("HKIDN:2:2+280:12345678+9999999999+0+0")
|
||||
assertThat(result).isEqualTo("HKIDN:2:2+280:12345678+0987654321+0+1")
|
||||
}
|
||||
|
||||
}
|
|
@ -1,36 +1,26 @@
|
|||
package net.dankito.fints.messages.segmente.implementierte
|
||||
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.Laenderkennzeichen
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.signatur.IdentifizierungDerPartei
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.signatur.Sicherheitsfunktion
|
||||
import net.dankito.fints.FinTsTestBase
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.Test
|
||||
|
||||
|
||||
class SignaturkopfTest {
|
||||
class SignaturkopfTest : FinTsTestBase() {
|
||||
|
||||
@Test
|
||||
fun format() {
|
||||
|
||||
// given
|
||||
val securityFunction = Sicherheitsfunktion.PIN_TAN_911
|
||||
val controlReference = "1902675680"
|
||||
val partyIdentification = IdentifizierungDerPartei.SynchronizingCustomerSystemId
|
||||
val date = 20191002
|
||||
val time = 212757
|
||||
val bankCode = "12345678"
|
||||
val customerId = "0987654321"
|
||||
val keyNumber = 0
|
||||
val keyVersion = 0
|
||||
|
||||
val underTest = PinTanSignaturkopf(2, securityFunction, controlReference, partyIdentification,
|
||||
date, time, Laenderkennzeichen.Germany, bankCode, customerId)
|
||||
val underTest = PinTanSignaturkopf(2, Bank, Customer,
|
||||
controlReference, Date, Time)
|
||||
|
||||
// when
|
||||
val result = underTest.format()
|
||||
|
||||
// then
|
||||
assertThat(result).isEqualTo("HNSHK:2:4+PIN:2+${securityFunction.code}+$controlReference+1+1+1::0+1+1:$date:$time+1:999:1+6:10:16+280:$bankCode:$customerId:S:$keyNumber:$keyVersion")
|
||||
assertThat(result).isEqualTo("HNSHK:2:4+PIN:2+${SecurityFunction.code}+$controlReference+1+1+1::0+1+1:$Date:$Time+1:999:1+6:10:16+280:$BankCode:$CustomerId:S:0:0")
|
||||
}
|
||||
|
||||
}
|
|
@ -1,30 +1,24 @@
|
|||
package net.dankito.fints.messages.segmente.implementierte
|
||||
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.Laenderkennzeichen
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.signatur.IdentifizierungDerPartei
|
||||
import net.dankito.fints.FinTsTestBase
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.Test
|
||||
|
||||
class VerschluesselungskopfTest {
|
||||
|
||||
class VerschluesselungskopfTest : FinTsTestBase() {
|
||||
|
||||
@Test
|
||||
fun format() {
|
||||
|
||||
// given
|
||||
val partyIdentification = IdentifizierungDerPartei.SynchronizingCustomerSystemId
|
||||
val date = 20191002
|
||||
val time = 212757
|
||||
val bankCode = "12345678"
|
||||
val customerId = "0987654321"
|
||||
|
||||
val underTest = PinTanVerschluesselungskopf(partyIdentification, date, time,
|
||||
Laenderkennzeichen.Germany, bankCode, customerId)
|
||||
val underTest = PinTanVerschluesselungskopf(Bank, Customer, Date, Time)
|
||||
|
||||
// when
|
||||
val result = underTest.format()
|
||||
|
||||
// then
|
||||
assertThat(result).isEqualTo("HNVSK:998:3+PIN:2+998+1+1::0+1:$date:$time+2:2:13:@8@ :5:1+280:$bankCode:$customerId:V:0:0+0")
|
||||
assertThat(normalizeBinaryData(result)).isEqualTo("HNVSK:998:3+PIN:2+998+1+1::0+1:$Date:$Time+2:16:14:@8@ :5:1+280:$BankCode:$CustomerId:V:0:0+0+")
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue