diff --git a/CHANGELOG.md b/CHANGELOG.md index fec3b47..5cd6dcf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,10 @@ +## 0.3.8 + +* More fields added. + ## 0.3.7 * Pin Block, Card Entry Mode and POS Condition Code fields added. - ## 0.3.6 * Data Element (DE) for field 48. diff --git a/lib/pos.dart b/lib/pos.dart index d9d292a..b608c29 100644 --- a/lib/pos.dart +++ b/lib/pos.dart @@ -5,7 +5,6 @@ import 'dart:convert'; import 'dart:typed_data'; import 'package:convert/convert.dart'; -import 'package:iso9797/iso9797.dart' as iso9797; part 'src/bitmap.dart'; part 'src/data_element.dart'; diff --git a/lib/src/message.dart b/lib/src/message.dart index f6cb44b..97dcfd9 100644 --- a/lib/src/message.dart +++ b/lib/src/message.dart @@ -51,11 +51,8 @@ class Message { final x = Message('0300'); final now = dateTime ?? DateTime.now().toLocal(); - final am = amount.toString().padLeft(12, '0'); - final amb = hex.decode(am); - x.processCode = 0x000000; - x.set(4, amb); + x.amount = amount; x.dateTime = now; x.posConditionCode = 0x14; @@ -130,6 +127,27 @@ class Message { /// Clones the message into a new instance. Message clone() { final copy = Message(mti); + + final f52PinBlock = _f52PinBlock; + + copy._f02Pan = _f02Pan; + copy._f03ProcessCode = _f03ProcessCode; + copy._f04Amount = _f04Amount; + copy._f11Stan = _f11Stan; + copy._f1213DateTime = _f1213DateTime; + copy._f22CardEntryMode = _f22CardEntryMode; + copy._f24Nii = _f24Nii; + copy._f25POSConditionCode = _f25POSConditionCode; + copy._f35Track2 = _f35Track2; + copy._f41TerminalId = _f41TerminalId; + copy._f42MerchantId = _f42MerchantId; + copy._f48DataElement = _f48DataElement; + copy._f49Currency = _f49Currency; + copy._f52PinBlock = + f52PinBlock == null ? null : Uint8List.fromList(f52PinBlock); + copy._mac = _mac; + + copy._bmp.addAll(_bmp); copy._data.addAll(_data); return copy; @@ -178,26 +196,25 @@ class Message { /// Encodes a [Message] object to a [Uint8List]. Optionally adds MAC to the field 64. Uint8List encode({Uint8List Function(List message)? algorithm}) { - if (algorithm != null) { - final y = calcmac(algorithm); + final alg = algorithm; - mac = hex.encode(y).toUpperCase(); - } + final fmac = alg != null ? calcmac(alg) : Uint8List(8); final bdy = _body(); final bmp = _bitmap(); final mt = Uint8List.fromList(hex.decode(mti)); - final xx = mt + bmp + bdy; + final xx = mt + bmp + bdy + fmac; return Uint8List.fromList(xx); } String? _f02Pan; int? _f03ProcessCode; + int? _f04Amount; int? _f11Stan; DateTime? _f1213DateTime; int? _f22CardEntryMode; - String? _f24Nii; + int? _f24Nii; int? _f25POSConditionCode; String? _f35Track2; String? _f41TerminalId; @@ -206,7 +223,7 @@ class Message { int? _f49Currency; List? _f52PinBlock; - String? _mac; + List? _mac; /// PAN, the Card Number. /// Field 2. @@ -252,6 +269,28 @@ class Message { } } + /// Amount. + /// Field 4. + /// + /// Must be null or > 0.', + int? get amount => _f04Amount; + set amount(int? value) { + final v = value; + + assert( + v == null || v > 0, + 'Amout should be null or > 0.', + ); + + if (v == null) { + _bmp[4] = false; + _f04Amount = null; + } else { + _bmp[4] = true; + _f04Amount = value; + } + } + /// Stan. /// Field 11. /// @@ -302,7 +341,7 @@ class Message { assert( v == null || v > -1 || v < 0xffff, - 'CardEntryMode should be null or between [0x00, 0xFFFF].', + 'CardEntryMode should be null or between [0x0000, 0xFFFF].', ); if (v == null) { @@ -317,14 +356,14 @@ class Message { /// NII. /// Field 24. /// - /// Must be 4 characters. - String? get nii => _f24Nii; - set nii(String? value) { + /// Must be betweem [0x0000, 0xFFFF] characters. + int? get nii => _f24Nii; + set nii(int? value) { final v = value; assert( - v == null || v.length == 4, - 'NII should be null or 4 characters long.', + v == null || v > -1 || v < 0xffff, + 'NII should be null or between [0x0000, 0xFFFF].', ); if (v == null) { @@ -462,13 +501,13 @@ class Message { /// Field 64 or 128. /// /// Must be 16 characters. - String? get mac => _mac; - set mac(String? value) { + List? get mac => _mac; + set mac(List? value) { final v = value; assert( - v == null || v.length == 16, - 'MAC should be null or 16 characters long.', + v == null || v.length == 8, + 'MAC should be null or 8 bytes.', ); if (v == null) { @@ -484,7 +523,7 @@ class Message { final bits = >[]; final strBits = []; - for (var i = 1; i <= 64; i++) { + for (var i = 1; i < 64; i++) { if (i == 2) { final p = pan; @@ -514,6 +553,18 @@ class Message { strBits.add(h3); } + continue; + } else if (i == 4) { + final p = amount; + + if (p != null) { + final amountPadded = amount.toString().padLeft(12, '0'); + final amb = hex.decode(amountPadded); + + bits.add(amb); + strBits.add(amountPadded); + } + continue; } else if (i == 11) { final p = stan; @@ -591,10 +642,14 @@ class Message { final p = _f24Nii; if (p != null) { - final f2 = hex.decode(p); - bits.add(f2); + final bt = ByteData(2); + bt.setUint16(0, p, Endian.big); - strBits.add(p); + final f24 = bt.buffer.asUint8List(); + final s24 = hex.encode(f24); + + bits.add(f24); + strBits.add(s24); } continue; @@ -670,8 +725,8 @@ class Message { final p = mac; if (p != null) { - bits.add(hex.decode(p)); - strBits.add(p); + bits.add(p); + strBits.add(hex.encode(p)); } continue; @@ -726,7 +781,7 @@ class Message { /// Calculates the MAC for current [Message]. Uint8List calcmac(Uint8List Function(List message) algorithm) { final c = clone(); - c.mac = '0000000000000000'; + c.mac = Uint8List(8); final bmp = c._bitmap(); c.mac = null; diff --git a/lib/src/private.dart b/lib/src/private.dart index 557b6df..2a76aca 100644 --- a/lib/src/private.dart +++ b/lib/src/private.dart @@ -1,21 +1,3 @@ part of '../pos.dart'; final _json = JsonEncoder.withIndent(' '); - -/// Mac algorithm for 6th bit. -String iso9797MacAlgorithm3String(Uint8List key, Uint8List message) { - if (message.length % 8 != 0) { - final copyOfData = message.toList(); - while (copyOfData.length % 8 != 0) { - copyOfData.add(0); - } - - message = Uint8List.fromList(copyOfData); - } - - final mac = iso9797.algorithm3(key, message, iso9797.PaddingMode.method1); - final macU = mac.map((e) => e.toRadixString(16)).join().toUpperCase(); - - final result = macU.codeUnits.take(8).map((e) => e.toRadixString(16)).join(); - return result; -} diff --git a/pubspec.yaml b/pubspec.yaml index 0746a44..423cd99 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: pos description: Dart Implementation of the ISO-8583 banking protocol for Point of Sale (POS) Devices. -version: 0.3.7 +version: 0.3.8 repository: https://github.com/xclud/dart_pos homepage: https://pwa.ir @@ -8,7 +8,7 @@ environment: sdk: ">=2.12.0 <4.0.0" dependencies: - iso9797: ^0.0.2 + iso9797: ^0.0.5 convert: ^3.1.1 dev_dependencies: