bysquare 1.3.3 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +67 -53
- package/lib/cli.js +17 -22
- package/lib/generate.d.ts +14 -13
- package/lib/generate.js +107 -114
- package/lib/index.d.ts +3 -3
- package/lib/index.js +3 -24
- package/lib/parse.d.ts +6 -11
- package/lib/parse.js +116 -164
- package/lib/types.d.ts +117 -225
- package/lib/types.js +221 -259
- package/package.json +36 -35
package/lib/parse.d.ts
CHANGED
|
@@ -1,21 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
import { ParsedModel } from "./index";
|
|
1
|
+
import { DataModel } from "./index.js";
|
|
3
2
|
/**
|
|
4
3
|
* @see 3.14. Generating by square Code
|
|
5
4
|
*/
|
|
6
|
-
export declare function
|
|
5
|
+
export declare function buildModel(qr: string): DataModel;
|
|
7
6
|
/**
|
|
8
7
|
* @see 3.16. Decoding client data from QR Code 2005 symbol
|
|
9
8
|
*/
|
|
10
|
-
export declare function parse(qr: string): Promise<
|
|
9
|
+
export declare function parse(qr: string): Promise<DataModel>;
|
|
11
10
|
/**
|
|
12
|
-
*
|
|
13
|
-
*/
|
|
14
|
-
export declare function inverseAlphanumericConversion(qr: string): Buffer;
|
|
15
|
-
/**
|
|
16
|
-
* Simple binary header detector
|
|
11
|
+
* Detect if qr string contains bysquare header.
|
|
17
12
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
13
|
+
* Bysquare header does not have too much information, therefore it is
|
|
14
|
+
* not very reliable, there is room for improvement for the future.
|
|
20
15
|
*/
|
|
21
16
|
export declare function detect(qr: string): boolean;
|
package/lib/parse.js
CHANGED
|
@@ -1,163 +1,128 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
})
|
|
10
|
-
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
-
if (mod && mod.__esModule) return mod;
|
|
20
|
-
var result = {};
|
|
21
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
-
__setModuleDefault(result, mod);
|
|
23
|
-
return result;
|
|
24
|
-
};
|
|
25
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.detect = exports.inverseAlphanumericConversion = exports.parse = exports.assemble = void 0;
|
|
27
|
-
const lzma = __importStar(require("lzma-native"));
|
|
28
|
-
const index_1 = require("./index");
|
|
29
|
-
const FIELD_INVOICE = 0;
|
|
30
|
-
const FIELD_PAYMENT_COUNT = 1;
|
|
31
|
-
const FIELD_PAYMENT_OPTIONS = 2;
|
|
32
|
-
const FIELD_BANK_ACCOUNT_COUNT = 11;
|
|
1
|
+
import lzma from "lzma-native";
|
|
2
|
+
import { base32hex } from "rfc4648";
|
|
3
|
+
import { PaymentOptions } from "./index.js";
|
|
4
|
+
function cleanEmptyProps(obj) {
|
|
5
|
+
Object.keys(obj).forEach((key) => {
|
|
6
|
+
if (typeof obj[key] === 'undefined') {
|
|
7
|
+
delete obj[key];
|
|
8
|
+
}
|
|
9
|
+
});
|
|
10
|
+
}
|
|
33
11
|
/**
|
|
34
12
|
* @see 3.14. Generating by square Code
|
|
35
13
|
*/
|
|
36
|
-
function
|
|
37
|
-
const
|
|
14
|
+
export function buildModel(qr) {
|
|
15
|
+
const intermediate = qr
|
|
38
16
|
.split("\t")
|
|
39
17
|
/** The end of the qr-string might contain a NULL-terminated string */
|
|
40
18
|
.map((entry) => entry.replace("\x00", ""));
|
|
41
|
-
const invoiceId =
|
|
19
|
+
const invoiceId = intermediate.shift();
|
|
42
20
|
const output = {
|
|
43
21
|
invoiceId: invoiceId?.length ? invoiceId : undefined,
|
|
44
22
|
payments: []
|
|
45
23
|
};
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
const
|
|
51
|
-
const
|
|
52
|
-
const
|
|
53
|
-
const
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
variableSymbol: variableSymbol?.length ? variableSymbol : undefined,
|
|
60
|
-
constantSymbol: constantSymbol?.length ? constantSymbol : undefined,
|
|
61
|
-
specificSymbol: specificSymbol?.length ? specificSymbol : undefined,
|
|
62
|
-
originatorsReferenceInformation: originatorsReferenceInformation?.length ? originatorsReferenceInformation : undefined,
|
|
63
|
-
paymentNote: paymentNote?.length ? paymentNote : undefined,
|
|
24
|
+
const paymentslen = Number(intermediate.shift());
|
|
25
|
+
for (let i = 0; i < paymentslen; i++) {
|
|
26
|
+
const paymentOptions = intermediate.shift();
|
|
27
|
+
const ammount = intermediate.shift();
|
|
28
|
+
const currency = intermediate.shift();
|
|
29
|
+
const dueDate = intermediate.shift();
|
|
30
|
+
const variables = intermediate.shift();
|
|
31
|
+
const constants = intermediate.shift();
|
|
32
|
+
const specifics = intermediate.shift();
|
|
33
|
+
const originatorRefInfo = intermediate.shift();
|
|
34
|
+
const paymentNote = intermediate.shift();
|
|
35
|
+
let payment = {
|
|
36
|
+
type: Number(paymentOptions),
|
|
64
37
|
bankAccounts: [],
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
38
|
+
amount: ammount?.length ? Number(ammount) : undefined,
|
|
39
|
+
currencyCode: currency,
|
|
40
|
+
paymentDueDate: dueDate?.length ? dueDate : undefined,
|
|
41
|
+
variableSymbol: variables?.length ? variables : undefined,
|
|
42
|
+
constantSymbol: constants?.length ? constants : undefined,
|
|
43
|
+
specificSymbol: specifics?.length ? specifics : undefined,
|
|
44
|
+
originatorRefInfo: originatorRefInfo?.length ? originatorRefInfo : undefined,
|
|
45
|
+
paymentNote: paymentNote?.length ? paymentNote : undefined,
|
|
46
|
+
};
|
|
47
|
+
const accountslen = Number(intermediate.shift());
|
|
48
|
+
for (let j = 0; j < accountslen; j++) {
|
|
49
|
+
const iban = intermediate.shift();
|
|
50
|
+
if (iban === undefined || iban.length === 0) {
|
|
73
51
|
throw new Error("Missing IBAN");
|
|
74
52
|
}
|
|
75
|
-
|
|
53
|
+
const bic = intermediate.shift();
|
|
54
|
+
const account = {
|
|
76
55
|
iban: iban,
|
|
77
|
-
bic: bic?.length ? bic : undefined
|
|
78
|
-
}
|
|
56
|
+
bic: bic?.length ? bic : undefined,
|
|
57
|
+
};
|
|
58
|
+
cleanEmptyProps(account);
|
|
59
|
+
payment.bankAccounts.push(account);
|
|
79
60
|
}
|
|
80
|
-
|
|
81
|
-
|
|
61
|
+
intermediate.shift(); // StandingOrderExt
|
|
62
|
+
intermediate.shift(); // DirectDebitExt
|
|
63
|
+
// narrowing payment type
|
|
64
|
+
switch (payment.type) {
|
|
65
|
+
case PaymentOptions.PaymentOrder:
|
|
82
66
|
break;
|
|
83
|
-
case
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
day: day?.length ? Number(day) : undefined,
|
|
91
|
-
month: month?.length ? Number(month) : undefined,
|
|
92
|
-
periodicity: periodicity?.length ? periodicity : undefined,
|
|
93
|
-
lastDate: lastDate?.length ? lastDate : undefined
|
|
67
|
+
case PaymentOptions.StandingOrder:
|
|
68
|
+
payment = {
|
|
69
|
+
...payment,
|
|
70
|
+
day: Number(intermediate.shift()),
|
|
71
|
+
month: Number(intermediate.shift()),
|
|
72
|
+
periodicity: intermediate.shift(),
|
|
73
|
+
lastDate: intermediate.shift()
|
|
94
74
|
};
|
|
95
75
|
break;
|
|
96
|
-
case
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
specificSymbol: specificSymbol.length ? specificSymbol : undefined,
|
|
107
|
-
originatorsReferenceInformation: originatorsReferenceInformation.length ? originatorsReferenceInformation : undefined,
|
|
108
|
-
mandateId: mandateId.length ? mandateId : undefined,
|
|
109
|
-
creditorId: creditorId.length ? creditorId : undefined,
|
|
110
|
-
contractId: contractId.length ? contractId : undefined,
|
|
111
|
-
maxAmount: maxAmount.length ? Number(maxAmount) : undefined,
|
|
112
|
-
validTillDate: validTillDate.length ? validTillDate : undefined
|
|
76
|
+
case PaymentOptions.DirectDebit:
|
|
77
|
+
payment = {
|
|
78
|
+
...payment,
|
|
79
|
+
directDebitScheme: Number(intermediate.shift()),
|
|
80
|
+
directDebitType: Number(intermediate.shift()),
|
|
81
|
+
mandateId: intermediate.shift(),
|
|
82
|
+
creditorId: intermediate.shift(),
|
|
83
|
+
contractId: intermediate.shift(),
|
|
84
|
+
maxAmount: Number(intermediate.shift()),
|
|
85
|
+
validTillDate: intermediate.shift()
|
|
113
86
|
};
|
|
114
|
-
default:
|
|
115
|
-
throw new Error("Unknown payment option");
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
/** Beneficiary list bysquare v1.1 */
|
|
119
|
-
for (let i = 0; i < paymentsCount; i++) {
|
|
120
|
-
let beneficiary = [];
|
|
121
|
-
const offset = (i || 1) * (2 * bankAccountsCount) - 2;
|
|
122
|
-
switch (paymentOptions) {
|
|
123
|
-
case index_1.PaymentOptions.PaymentOrder:
|
|
124
|
-
beneficiary = fields.slice(16 + offset, 20 + offset);
|
|
125
87
|
break;
|
|
126
|
-
|
|
127
|
-
beneficiary = fields.slice(20 + offset, 24 + offset);
|
|
128
|
-
break;
|
|
129
|
-
case index_1.PaymentOptions.DirectDebit:
|
|
130
|
-
beneficiary = fields.slice(25 + offset, 29 + offset);
|
|
88
|
+
default:
|
|
131
89
|
break;
|
|
132
90
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
91
|
+
cleanEmptyProps(payment);
|
|
92
|
+
output.payments.push(payment);
|
|
93
|
+
}
|
|
94
|
+
for (let i = 0; i < paymentslen; i++) {
|
|
95
|
+
const name = intermediate.shift();
|
|
96
|
+
const addressLine1 = intermediate.shift();
|
|
97
|
+
const addressLine2 = intermediate.shift();
|
|
98
|
+
if (Boolean(name) || Boolean(addressLine1) || Boolean(addressLine2)) {
|
|
99
|
+
const beneficiary = {
|
|
100
|
+
name: name?.length ? name : undefined,
|
|
101
|
+
street: addressLine1?.length ? addressLine1 : undefined,
|
|
102
|
+
city: addressLine2?.length ? addressLine2 : undefined,
|
|
103
|
+
};
|
|
104
|
+
cleanEmptyProps(beneficiary);
|
|
105
|
+
output.payments[i].beneficiary = beneficiary;
|
|
143
106
|
}
|
|
144
|
-
output.payments[i].beneficiary = {
|
|
145
|
-
name: name?.length ? name : undefined,
|
|
146
|
-
addressLine1: addressLine1?.length ? addressLine1 : undefined,
|
|
147
|
-
addressLine2: addressLine2?.length ? addressLine2 : undefined
|
|
148
|
-
};
|
|
149
107
|
}
|
|
150
108
|
return output;
|
|
151
109
|
}
|
|
152
|
-
exports.assemble = assemble;
|
|
153
110
|
/**
|
|
154
111
|
* @see 3.16. Decoding client data from QR Code 2005 symbol
|
|
155
112
|
*/
|
|
156
|
-
function parse(qr) {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
113
|
+
export function parse(qr) {
|
|
114
|
+
try {
|
|
115
|
+
var decoded = base32hex.parse(qr, {
|
|
116
|
+
out: Buffer,
|
|
117
|
+
loose: true
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
throw new Error("Unable to parse QR");
|
|
122
|
+
}
|
|
123
|
+
// const bysquareHeader = decoded.subarray(0, 2)
|
|
124
|
+
// const compressionHeader = decoded.subarray(2, 4)
|
|
125
|
+
const compressedData = decoded.subarray(4);
|
|
161
126
|
// @ts-ignore: Missing decored types
|
|
162
127
|
const decoder = lzma.createStream("rawDecoder", {
|
|
163
128
|
synchronous: true,
|
|
@@ -166,57 +131,44 @@ function parse(qr) {
|
|
|
166
131
|
});
|
|
167
132
|
return new Promise((resolve, reject) => {
|
|
168
133
|
decoder
|
|
169
|
-
.on("error", reject)
|
|
170
134
|
.on("data", (decompress) => {
|
|
171
|
-
const
|
|
172
|
-
const tabbed = decompress.
|
|
173
|
-
|
|
174
|
-
resolve(model);
|
|
135
|
+
// const crc32: Buffer = decompress.subarray(0, 4)
|
|
136
|
+
const tabbed = decompress.subarray(4).toString();
|
|
137
|
+
resolve(buildModel(tabbed));
|
|
175
138
|
})
|
|
139
|
+
.on("error", reject)
|
|
176
140
|
.write(compressedData, (error) => {
|
|
177
141
|
error && reject(error);
|
|
178
142
|
decoder.end();
|
|
179
143
|
});
|
|
180
144
|
});
|
|
181
145
|
}
|
|
182
|
-
exports.parse = parse;
|
|
183
146
|
/**
|
|
184
|
-
*
|
|
185
|
-
*/
|
|
186
|
-
function inverseAlphanumericConversion(qr) {
|
|
187
|
-
const binary = [...qr].reduce((acc, char) => {
|
|
188
|
-
acc += index_1.SUBST.indexOf(char).toString(2).padStart(5, "0");
|
|
189
|
-
return acc;
|
|
190
|
-
}, "");
|
|
191
|
-
let bytes = [];
|
|
192
|
-
for (let nth = 0, leftCount = 0; binary.length > leftCount; nth++) {
|
|
193
|
-
/** string representation of 8-bits */
|
|
194
|
-
const slice = binary.slice(leftCount, (leftCount += 8));
|
|
195
|
-
const byte = parseInt(slice, 2);
|
|
196
|
-
bytes[nth] = byte;
|
|
197
|
-
}
|
|
198
|
-
return Buffer.from(bytes);
|
|
199
|
-
}
|
|
200
|
-
exports.inverseAlphanumericConversion = inverseAlphanumericConversion;
|
|
201
|
-
/**
|
|
202
|
-
* Simple binary header detector
|
|
147
|
+
* Detect if qr string contains bysquare header.
|
|
203
148
|
*
|
|
204
|
-
*
|
|
205
|
-
*
|
|
149
|
+
* Bysquare header does not have too much information, therefore it is
|
|
150
|
+
* not very reliable, there is room for improvement for the future.
|
|
206
151
|
*/
|
|
207
|
-
function detect(qr) {
|
|
208
|
-
|
|
209
|
-
|
|
152
|
+
export function detect(qr) {
|
|
153
|
+
try {
|
|
154
|
+
var parsed = base32hex.parse(qr, {
|
|
155
|
+
out: Buffer,
|
|
156
|
+
loose: true
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
catch {
|
|
160
|
+
throw new Error("Unable to parse QR string, invalid data");
|
|
161
|
+
}
|
|
162
|
+
if (parsed.byteLength < 2) {
|
|
210
163
|
return false;
|
|
211
164
|
}
|
|
212
|
-
const headerBysquare =
|
|
165
|
+
const headerBysquare = parsed.subarray(0, 2);
|
|
213
166
|
return [...headerBysquare.toString("hex")]
|
|
214
167
|
.map((nibble) => parseInt(nibble, 16))
|
|
215
168
|
.every((nibble, index) => {
|
|
216
|
-
if (
|
|
169
|
+
if ( /** version */index === 1) {
|
|
217
170
|
return 0 >= nibble && nibble <= 1;
|
|
218
171
|
}
|
|
219
172
|
return 0 <= nibble && nibble <= 15;
|
|
220
173
|
});
|
|
221
174
|
}
|
|
222
|
-
exports.detect = detect;
|