Bankkarte: IBAN pruefen + BIC/Bank offline aus Bundesbank-BLZ ausfuellen
Neuer Button "BIC & Bank aus IBAN abrufen" im Bankkarten-Modal fuellt BIC + Banknamen automatisch und validiert dabei die IBAN-Pruefziffer (mod-97). Leeres IBAN-Feld -> OK-Messagebox statt Anfrage. Datenschutzfreundlich/offline: kein Dritt-Dienst. Nachschlag im eigenen Backend ueber die Bundesbank-Bankleitzahlendatei (bankdata-germany) + ibantools fuer die Pruefziffer. Die IBAN verlaesst nie den Server; zurueck kommen nur oeffentliche Bankverzeichnis-Daten. Endpoint: POST /api/bank-cards/iban-lookup (nur eingeloggt). Wartung: bankdata-germany/ibantools ~quartalsweise per npm update ziehen. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Generated
+17
@@ -12,6 +12,7 @@
|
||||
"@types/cookie-parser": "^1.4.10",
|
||||
"adm-zip": "^0.5.16",
|
||||
"archiver": "^7.0.1",
|
||||
"bankdata-germany": "^2.2602.0",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"cookie-parser": "^1.4.7",
|
||||
"cors": "^2.8.5",
|
||||
@@ -21,6 +22,7 @@
|
||||
"express-rate-limit": "^8.4.0",
|
||||
"express-validator": "^7.2.0",
|
||||
"helmet": "^8.1.0",
|
||||
"ibantools": "^4.5.4",
|
||||
"imapflow": "^1.2.8",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"mailparser": "^3.9.3",
|
||||
@@ -984,6 +986,15 @@
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
|
||||
},
|
||||
"node_modules/bankdata-germany": {
|
||||
"version": "2.2602.0",
|
||||
"resolved": "https://registry.npmjs.org/bankdata-germany/-/bankdata-germany-2.2602.0.tgz",
|
||||
"integrity": "sha512-3iBD/cIKHZsmAaQIYEMsORhvMjILDTJ4gDQJYNVm+YXCzA5U96mUoB7KBy01rtwpFt/rKrNuCVNc8KZVx+jwpQ==",
|
||||
"license": "MIT OR MPL-2.0",
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/bare-events": {
|
||||
"version": "2.8.2",
|
||||
"resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.8.2.tgz",
|
||||
@@ -1992,6 +2003,12 @@
|
||||
"url": "https://opencollective.com/express"
|
||||
}
|
||||
},
|
||||
"node_modules/ibantools": {
|
||||
"version": "4.5.4",
|
||||
"resolved": "https://registry.npmjs.org/ibantools/-/ibantools-4.5.4.tgz",
|
||||
"integrity": "sha512-6jX1gh4aH6XH+o0ey+wtkMTzkcvsEta7DakIOZSng9voZYpMw3U+gK1+tZChk3aRcPcloEt0NOzksjaRZiqXbw==",
|
||||
"license": "MIT or MPL-2.0"
|
||||
},
|
||||
"node_modules/iconv-lite": {
|
||||
"version": "0.4.24",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
"@types/cookie-parser": "^1.4.10",
|
||||
"adm-zip": "^0.5.16",
|
||||
"archiver": "^7.0.1",
|
||||
"bankdata-germany": "^2.2602.0",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"cookie-parser": "^1.4.7",
|
||||
"cors": "^2.8.5",
|
||||
@@ -33,6 +34,7 @@
|
||||
"express-rate-limit": "^8.4.0",
|
||||
"express-validator": "^7.2.0",
|
||||
"helmet": "^8.1.0",
|
||||
"ibantools": "^4.5.4",
|
||||
"imapflow": "^1.2.8",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"mailparser": "^3.9.3",
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
import { Response } from 'express';
|
||||
import { isValidIBAN } from 'ibantools';
|
||||
import { bankDataByIBAN } from 'bankdata-germany';
|
||||
import { ApiResponse, AuthRequest } from '../types/index.js';
|
||||
|
||||
/**
|
||||
* IBAN-Lookup: prüft die Prüfziffer (mod-97, offline über ibantools) und liefert
|
||||
* – für deutsche IBANs – BIC und Banknamen aus der Bundesbank-Bankleitzahlen-
|
||||
* datei (offline über bankdata-germany). Die IBAN verlässt NICHT den Server; es
|
||||
* findet KEIN externer Request statt. Zurückgegeben werden nur öffentliche
|
||||
* Bankverzeichnis-Daten (BIC/Name), keine kundenbezogenen Informationen.
|
||||
*
|
||||
* Antwortformen (immer HTTP 200, sofern eine IBAN übergeben wurde):
|
||||
* { valid: false } → Prüfziffer falsch (Tippfehler)
|
||||
* { valid: true, bic, bankName, blz } → gültig + DE-Bank gefunden
|
||||
* { valid: true, bic: null, bankName: null } → gültig, aber keine DE-Bankdaten
|
||||
* (Nicht-DE-IBAN oder unbekannte BLZ)
|
||||
*/
|
||||
export async function lookupIban(req: AuthRequest, res: Response): Promise<void> {
|
||||
try {
|
||||
const raw = typeof req.body?.iban === 'string' ? req.body.iban : '';
|
||||
const iban = raw.replace(/\s+/g, '').toUpperCase();
|
||||
|
||||
if (!iban) {
|
||||
res.status(400).json({ success: false, error: 'Feld IBAN ist erforderlich.' } as ApiResponse);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isValidIBAN(iban)) {
|
||||
res.json({ success: true, data: { valid: false, iban } } as ApiResponse);
|
||||
return;
|
||||
}
|
||||
|
||||
const country = iban.slice(0, 2);
|
||||
const bank = country === 'DE' ? bankDataByIBAN(iban) : null;
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: {
|
||||
valid: true,
|
||||
iban,
|
||||
country,
|
||||
bic: bank?.bic ?? null,
|
||||
bankName: bank?.bankName ?? null,
|
||||
blz: bank?.blz ?? null,
|
||||
},
|
||||
} as ApiResponse);
|
||||
} catch (error) {
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Fehler beim IBAN-Nachschlagen',
|
||||
} as ApiResponse);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,14 @@
|
||||
import { Router } from 'express';
|
||||
import * as customerController from '../controllers/customer.controller.js';
|
||||
import * as bankLookupController from '../controllers/bankLookup.controller.js';
|
||||
import { authenticate, requirePermission } from '../middleware/auth.js';
|
||||
|
||||
const router = Router();
|
||||
|
||||
// IBAN-Prüfung + BIC/Bank-Nachschlag (offline, Bundesbank-BLZ). Liefert nur
|
||||
// öffentliche Bankverzeichnis-Daten – reicht daher ein eingeloggter Nutzer.
|
||||
router.post('/iban-lookup', authenticate, bankLookupController.lookupIban);
|
||||
|
||||
router.put('/:id', authenticate, requirePermission('customers:update'), customerController.updateBankCard);
|
||||
router.delete('/:id', authenticate, requirePermission('customers:delete'), customerController.deleteBankCard);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user