Added or extended value objects for Bank, Customer and Product; fixed tests

This commit is contained in:
dankl 2019-10-05 02:27:24 +02:00 committed by dankito
parent 9ac4af58ff
commit b4ba9a0bcf
26 changed files with 269 additions and 275 deletions

View File

@ -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")
)
}

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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"
}

View File

@ -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)

View File

@ -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.
*/
}

View File

@ -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)

View File

@ -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
)

View File

@ -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,

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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
)

View File

@ -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
}
}

View File

@ -1,8 +0,0 @@
package net.dankito.fints.model
open class BankInfo(
val bankCode: String,
val countryCode: Int,
val finTsServerAddress: String
)

View File

@ -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
}
}

View File

@ -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"
}
}

View File

@ -1,7 +0,0 @@
package net.dankito.fints.model
open class ProductInfo(
val productName: String,
val productVersion: String
)

View File

@ -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}"
}
}

View File

@ -0,0 +1,16 @@
package net.dankito.fints.model
enum class TanProcedureType {
EnterTan,
ChipTan,
ChipTanQrCode,
SmsTan,
PushTan
}

View File

@ -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(), ' ')
}
}

View File

@ -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(), ' ')
}
}

View File

@ -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")
}
}

View File

@ -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")
}
}

View File

@ -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+")
}
}