@bayarkit/testing 0.0.0-stage → 0.1.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 +27 -2
- package/dist/cli/2c2p.d.ts +4 -0
- package/dist/cli/2c2p.d.ts.map +1 -0
- package/dist/cli/2c2p.js +7 -0
- package/dist/cli/2c2p.js.map +1 -0
- package/dist/cli/bayarcash.d.ts +4 -0
- package/dist/cli/bayarcash.d.ts.map +1 -0
- package/dist/cli/bayarcash.js +11 -0
- package/dist/cli/bayarcash.js.map +1 -0
- package/dist/cli/billplz.d.ts +4 -0
- package/dist/cli/billplz.d.ts.map +1 -0
- package/dist/cli/billplz.js +11 -0
- package/dist/cli/billplz.js.map +1 -0
- package/dist/cli/chip.d.ts +4 -0
- package/dist/cli/chip.d.ts.map +1 -0
- package/dist/cli/chip.js +7 -0
- package/dist/cli/chip.js.map +1 -0
- package/dist/cli/curlec.d.ts +4 -0
- package/dist/cli/curlec.d.ts.map +1 -0
- package/dist/cli/curlec.js +11 -0
- package/dist/cli/curlec.js.map +1 -0
- package/dist/cli/eghl.d.ts +4 -0
- package/dist/cli/eghl.d.ts.map +1 -0
- package/dist/cli/eghl.js +7 -0
- package/dist/cli/eghl.js.map +1 -0
- package/dist/cli/fiuu.d.ts +4 -0
- package/dist/cli/fiuu.d.ts.map +1 -0
- package/dist/cli/fiuu.js +17 -0
- package/dist/cli/fiuu.js.map +1 -0
- package/dist/cli/gkash.d.ts +4 -0
- package/dist/cli/gkash.d.ts.map +1 -0
- package/dist/cli/gkash.js +7 -0
- package/dist/cli/gkash.js.map +1 -0
- package/dist/cli/hitpay.d.ts +4 -0
- package/dist/cli/hitpay.d.ts.map +1 -0
- package/dist/cli/hitpay.js +7 -0
- package/dist/cli/hitpay.js.map +1 -0
- package/dist/cli/ipay88.d.ts +4 -0
- package/dist/cli/ipay88.d.ts.map +1 -0
- package/dist/cli/ipay88.js +7 -0
- package/dist/cli/ipay88.js.map +1 -0
- package/dist/cli/senangpay.d.ts +4 -0
- package/dist/cli/senangpay.d.ts.map +1 -0
- package/dist/cli/senangpay.js +17 -0
- package/dist/cli/senangpay.js.map +1 -0
- package/dist/cli/stripe.d.ts +4 -0
- package/dist/cli/stripe.d.ts.map +1 -0
- package/dist/cli/stripe.js +7 -0
- package/dist/cli/stripe.js.map +1 -0
- package/dist/cli/toyyibpay.d.ts +4 -0
- package/dist/cli/toyyibpay.d.ts.map +1 -0
- package/dist/cli/toyyibpay.js +7 -0
- package/dist/cli/toyyibpay.js.map +1 -0
- package/dist/cli/types.d.ts +7 -0
- package/dist/cli/types.d.ts.map +1 -0
- package/dist/cli/types.js +2 -0
- package/dist/cli/types.js.map +1 -0
- package/dist/cli/xendit.d.ts +4 -0
- package/dist/cli/xendit.d.ts.map +1 -0
- package/dist/cli/xendit.js +7 -0
- package/dist/cli/xendit.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +46 -0
- package/dist/cli.js.map +1 -0
- package/dist/conformance.d.ts +13 -0
- package/dist/conformance.d.ts.map +1 -0
- package/dist/conformance.js +166 -0
- package/dist/conformance.js.map +1 -0
- package/dist/control.d.ts +6 -0
- package/dist/control.d.ts.map +1 -0
- package/dist/control.js +46 -0
- package/dist/control.js.map +1 -0
- package/dist/fakes/2c2p.d.ts +21 -0
- package/dist/fakes/2c2p.d.ts.map +1 -0
- package/dist/fakes/2c2p.js +287 -0
- package/dist/fakes/2c2p.js.map +1 -0
- package/dist/fakes/bayarcash.d.ts +15 -0
- package/dist/fakes/bayarcash.d.ts.map +1 -0
- package/dist/fakes/bayarcash.js +133 -0
- package/dist/fakes/bayarcash.js.map +1 -0
- package/dist/fakes/billplz.d.ts +20 -0
- package/dist/fakes/billplz.d.ts.map +1 -0
- package/dist/fakes/billplz.js +233 -0
- package/dist/fakes/billplz.js.map +1 -0
- package/dist/fakes/chip.d.ts +18 -0
- package/dist/fakes/chip.d.ts.map +1 -0
- package/dist/fakes/chip.js +227 -0
- package/dist/fakes/chip.js.map +1 -0
- package/dist/fakes/curlec.d.ts +30 -0
- package/dist/fakes/curlec.d.ts.map +1 -0
- package/dist/fakes/curlec.js +396 -0
- package/dist/fakes/curlec.js.map +1 -0
- package/dist/fakes/eghl.d.ts +36 -0
- package/dist/fakes/eghl.d.ts.map +1 -0
- package/dist/fakes/eghl.js +267 -0
- package/dist/fakes/eghl.js.map +1 -0
- package/dist/fakes/fiuu.d.ts +27 -0
- package/dist/fakes/fiuu.d.ts.map +1 -0
- package/dist/fakes/fiuu.js +230 -0
- package/dist/fakes/fiuu.js.map +1 -0
- package/dist/fakes/gkash.d.ts +18 -0
- package/dist/fakes/gkash.d.ts.map +1 -0
- package/dist/fakes/gkash.js +193 -0
- package/dist/fakes/gkash.js.map +1 -0
- package/dist/fakes/hitpay.d.ts +36 -0
- package/dist/fakes/hitpay.d.ts.map +1 -0
- package/dist/fakes/hitpay.js +233 -0
- package/dist/fakes/hitpay.js.map +1 -0
- package/dist/fakes/ipay88.d.ts +16 -0
- package/dist/fakes/ipay88.d.ts.map +1 -0
- package/dist/fakes/ipay88.js +195 -0
- package/dist/fakes/ipay88.js.map +1 -0
- package/dist/fakes/senangpay.d.ts +51 -0
- package/dist/fakes/senangpay.d.ts.map +1 -0
- package/dist/fakes/senangpay.js +255 -0
- package/dist/fakes/senangpay.js.map +1 -0
- package/dist/fakes/stripe.d.ts +26 -0
- package/dist/fakes/stripe.d.ts.map +1 -0
- package/dist/fakes/stripe.js +243 -0
- package/dist/fakes/stripe.js.map +1 -0
- package/dist/fakes/toyyibpay.d.ts +14 -0
- package/dist/fakes/toyyibpay.d.ts.map +1 -0
- package/dist/fakes/toyyibpay.js +138 -0
- package/dist/fakes/toyyibpay.js.map +1 -0
- package/dist/fakes/types.d.ts +19 -0
- package/dist/fakes/types.d.ts.map +1 -0
- package/dist/fakes/types.js +3 -0
- package/dist/fakes/types.js.map +1 -0
- package/dist/fakes/xendit.d.ts +36 -0
- package/dist/fakes/xendit.d.ts.map +1 -0
- package/dist/fakes/xendit.js +300 -0
- package/dist/fakes/xendit.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/package.json +64 -4
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A fake Gkash API (host-to-host checkout `POST /api/payment/form` + `POST /api/payment/query`), built from the
|
|
3
|
+
* official documentation (doc.gkash.my), the official WooCommerce plugin and the gkashmy SDKs — see
|
|
4
|
+
* gateways/gkash/spec.md. NOT yet measured against the staging host (api-staging.pay.asia): when someone does, change
|
|
5
|
+
* this file first so it answers like the real thing, then the adapter.
|
|
6
|
+
*
|
|
7
|
+
* Where the docs are silent this fake picks one shape and says so (marked ASSUMED below); the adapter must not depend on
|
|
8
|
+
* those shapes beyond "an error is an error".
|
|
9
|
+
*/
|
|
10
|
+
import { createHash } from 'node:crypto';
|
|
11
|
+
import { createServer } from 'node:http';
|
|
12
|
+
import { flip } from './types.js';
|
|
13
|
+
/**
|
|
14
|
+
* Gkash's online-API signature, written independently of the adapter (spec §4.1/§4.2): the `;`-joined parts, the
|
|
15
|
+
* WHOLE string upper-cased (key included), SHA-512, lowercase hex.
|
|
16
|
+
*/
|
|
17
|
+
const sign = (parts) => createHash('sha512').update(parts.join(';').toUpperCase()).digest('hex');
|
|
18
|
+
/** "10.50" → "1050", "0.10" → "010": two decimals, dot removed, leading zero kept (spec §4.1). */
|
|
19
|
+
const amt = (ringgit) => Number(ringgit).toFixed(2).replace('.', '');
|
|
20
|
+
/** The id the adapter hands out is `<cartid>:<amount in sen>`; the fake keeps payments by cart id. */
|
|
21
|
+
const cartOf = (id) => id.replace(/:\d+$/, '');
|
|
22
|
+
export async function startFakeGkash(opts) {
|
|
23
|
+
let n = 0;
|
|
24
|
+
const payments = new Map();
|
|
25
|
+
const requests = [];
|
|
26
|
+
let origin = '';
|
|
27
|
+
const server = createServer((req, res) => {
|
|
28
|
+
let raw = '';
|
|
29
|
+
req.on('data', (d) => {
|
|
30
|
+
raw += d;
|
|
31
|
+
});
|
|
32
|
+
req.on('end', () => {
|
|
33
|
+
const contentType = req.headers['content-type'];
|
|
34
|
+
let body = {};
|
|
35
|
+
try {
|
|
36
|
+
const j = raw ? JSON.parse(raw) : {};
|
|
37
|
+
if (j && typeof j === 'object' && !Array.isArray(j))
|
|
38
|
+
body = j;
|
|
39
|
+
}
|
|
40
|
+
catch { }
|
|
41
|
+
const path = req.url ?? '';
|
|
42
|
+
requests.push({ method: req.method ?? '', path, body, contentType, headers: req.headers });
|
|
43
|
+
const send = (status, o) => {
|
|
44
|
+
res.writeHead(status, { 'content-type': 'application/json' });
|
|
45
|
+
res.end(JSON.stringify(o));
|
|
46
|
+
};
|
|
47
|
+
// ASSUMED: the docs publish no error body or HTTP status for refused requests.
|
|
48
|
+
const error = (status, message) => send(status, { message });
|
|
49
|
+
const s = (k) => (body[k] == null ? '' : String(body[k]));
|
|
50
|
+
if (req.method === 'POST' && path === '/api/payment/form') {
|
|
51
|
+
if (!contentType?.includes('application/json'))
|
|
52
|
+
return error(415, 'Unsupported content type');
|
|
53
|
+
// DOC says 1.5.5; the official plugin and every SDK send 1.5.0 (spec C1). Both are accepted here.
|
|
54
|
+
if (!['1.5.0', '1.5.5'].includes(s('version')))
|
|
55
|
+
return error(400, 'Invalid version');
|
|
56
|
+
if (s('CID') !== opts.cid)
|
|
57
|
+
return error(400, 'Invalid merchant');
|
|
58
|
+
const cartid = s('v_cartid');
|
|
59
|
+
if (!/^[A-Za-z0-9._-]+$/.test(cartid))
|
|
60
|
+
return error(400, 'Invalid cart id');
|
|
61
|
+
if (s('v_currency') !== 'MYR')
|
|
62
|
+
return error(400, 'Only supports MYR');
|
|
63
|
+
if (!/^\d+\.\d{2}$/.test(s('v_amount')) || Number(s('v_amount')) <= 0)
|
|
64
|
+
return error(400, 'Invalid amount');
|
|
65
|
+
const expected = sign([opts.signatureKey, opts.cid, cartid, amt(s('v_amount')), 'MYR']);
|
|
66
|
+
if (s('signature') !== expected)
|
|
67
|
+
return error(400, 'Invalid signature');
|
|
68
|
+
// ASSUMED: what Gkash does with a reused cart id is undocumented; the fake refuses it (the plugin's comment
|
|
69
|
+
// says "Gkash requires a unique cart id per request").
|
|
70
|
+
if (payments.has(cartid))
|
|
71
|
+
return error(400, 'Duplicate cart id');
|
|
72
|
+
n += 1;
|
|
73
|
+
const p = {
|
|
74
|
+
poid: `M161-PO-${String(n).padStart(6, '0')}`,
|
|
75
|
+
cartid,
|
|
76
|
+
amount: s('v_amount'),
|
|
77
|
+
currency: 'MYR',
|
|
78
|
+
status: '11 - Pending',
|
|
79
|
+
description: '',
|
|
80
|
+
};
|
|
81
|
+
payments.set(cartid, p);
|
|
82
|
+
// DOC v2 checkout-session response; its signature uses the callback formula with `11 - PENDING` (C8).
|
|
83
|
+
return send(200, {
|
|
84
|
+
status: p.status,
|
|
85
|
+
cid: opts.cid,
|
|
86
|
+
poId: p.poid,
|
|
87
|
+
cartId: p.cartid,
|
|
88
|
+
amount: p.amount,
|
|
89
|
+
currency: p.currency,
|
|
90
|
+
signature: sign([
|
|
91
|
+
opts.signatureKey,
|
|
92
|
+
opts.cid,
|
|
93
|
+
p.poid,
|
|
94
|
+
p.cartid,
|
|
95
|
+
amt(p.amount),
|
|
96
|
+
p.currency,
|
|
97
|
+
p.status,
|
|
98
|
+
]),
|
|
99
|
+
redirect: { url: `${origin}/pay/${p.poid}` },
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
if (req.method === 'POST' && path === '/api/payment/query') {
|
|
103
|
+
if (s('version') !== '1.3.0')
|
|
104
|
+
return error(400, 'Invalid version');
|
|
105
|
+
if (s('CID') !== opts.cid)
|
|
106
|
+
return error(400, 'Invalid merchant');
|
|
107
|
+
const expected = sign([opts.signatureKey, opts.cid, s('cartid'), amt(s('amount')), s('currency')]);
|
|
108
|
+
if (s('signature') !== expected)
|
|
109
|
+
return error(400, 'Invalid signature');
|
|
110
|
+
const p = payments.get(s('cartid'));
|
|
111
|
+
// ASSUMED: the answer for an unknown cart id is undocumented.
|
|
112
|
+
if (!p)
|
|
113
|
+
return error(404, 'Transaction not found');
|
|
114
|
+
// DOC query-transaction-status: unsigned, no paid time; refund fields present (values ASSUMED empty).
|
|
115
|
+
return send(200, {
|
|
116
|
+
CID: opts.cid,
|
|
117
|
+
POID: p.poid,
|
|
118
|
+
status: p.status,
|
|
119
|
+
cartid: p.cartid,
|
|
120
|
+
currency: p.currency,
|
|
121
|
+
amount: p.amount,
|
|
122
|
+
description: p.description,
|
|
123
|
+
PaymentType: '',
|
|
124
|
+
refundstatus: '',
|
|
125
|
+
refundamount: '',
|
|
126
|
+
refunddate: '',
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
error(404, 'Not found');
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
await new Promise((r) => server.listen(0, '127.0.0.1', r));
|
|
133
|
+
origin = `http://127.0.0.1:${server.address().port}`;
|
|
134
|
+
const payment = (id) => {
|
|
135
|
+
const p = payments.get(cartOf(id));
|
|
136
|
+
if (!p)
|
|
137
|
+
throw new Error(`fake Gkash: no payment ${id}`);
|
|
138
|
+
return p;
|
|
139
|
+
};
|
|
140
|
+
return {
|
|
141
|
+
url: origin,
|
|
142
|
+
requests,
|
|
143
|
+
markPaid(id) {
|
|
144
|
+
const p = payment(id);
|
|
145
|
+
p.status = '88 - Transferred';
|
|
146
|
+
p.description = '00 - Approved';
|
|
147
|
+
},
|
|
148
|
+
setStatus(id, status) {
|
|
149
|
+
payment(id).status = status;
|
|
150
|
+
},
|
|
151
|
+
callbackFor(id, override = {}) {
|
|
152
|
+
const p = payment(id);
|
|
153
|
+
// Form fields exactly as Gkash posts them (spec §5). It claims success even before markPaid (a replayed or
|
|
154
|
+
// forged-with-a-leaked-key callback); the fake's own record stays as it is.
|
|
155
|
+
const fields = {
|
|
156
|
+
CID: opts.cid,
|
|
157
|
+
POID: p.poid,
|
|
158
|
+
status: '88 - Transferred',
|
|
159
|
+
cartid: p.cartid,
|
|
160
|
+
currency: p.currency,
|
|
161
|
+
amount: p.amount,
|
|
162
|
+
description: '00 - Approved',
|
|
163
|
+
...override,
|
|
164
|
+
};
|
|
165
|
+
const { signature, ...rest } = fields;
|
|
166
|
+
const posted = {
|
|
167
|
+
...rest,
|
|
168
|
+
signature: signature ??
|
|
169
|
+
sign([
|
|
170
|
+
opts.signatureKey,
|
|
171
|
+
rest.CID ?? '',
|
|
172
|
+
rest.POID ?? '',
|
|
173
|
+
rest.cartid ?? '',
|
|
174
|
+
amt(rest.amount ?? ''),
|
|
175
|
+
rest.currency ?? '',
|
|
176
|
+
rest.status ?? '',
|
|
177
|
+
]),
|
|
178
|
+
};
|
|
179
|
+
return {
|
|
180
|
+
fields: posted,
|
|
181
|
+
rawBody: new URLSearchParams(posted).toString(),
|
|
182
|
+
headers: { 'content-type': 'application/x-www-form-urlencoded' },
|
|
183
|
+
};
|
|
184
|
+
},
|
|
185
|
+
tamper: (cb) => {
|
|
186
|
+
const fields = { ...cb.fields, signature: flip(cb.fields.signature ?? '') };
|
|
187
|
+
// The body must say what the fields say: a real tampered POST carries the altered value in its bytes too.
|
|
188
|
+
return { ...cb, fields, rawBody: cb.rawBody ? new URLSearchParams(fields).toString() : '' };
|
|
189
|
+
},
|
|
190
|
+
close: () => new Promise((r) => server.close(() => r())),
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
//# sourceMappingURL=gkash.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gkash.js","sourceRoot":"","sources":["../../src/fakes/gkash.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { CallbackInput } from '@bayarkit/core';
|
|
2
|
+
import { type FakeGateway } from './types.js';
|
|
3
|
+
type PaymentRequest = Record<string, unknown> & {
|
|
4
|
+
id: string;
|
|
5
|
+
status: string;
|
|
6
|
+
amount: string;
|
|
7
|
+
currency: string;
|
|
8
|
+
payments: Record<string, unknown>[];
|
|
9
|
+
};
|
|
10
|
+
export interface FakeHitPay extends FakeGateway {
|
|
11
|
+
requests: {
|
|
12
|
+
method: string;
|
|
13
|
+
path: string;
|
|
14
|
+
/** Body fields as received (form or JSON); repeated form keys (`payment_methods[]`) joined with `,`. */
|
|
15
|
+
body: Record<string, unknown>;
|
|
16
|
+
contentType: string | undefined;
|
|
17
|
+
headers: Record<string, string | string[] | undefined>;
|
|
18
|
+
}[];
|
|
19
|
+
/** The fake's own record (what `GET /v1/payment-requests/{id}` answers). */
|
|
20
|
+
paymentRequest(id: string): PaymentRequest | undefined;
|
|
21
|
+
/** The legacy per-request `webhook` form POST, signed with the API salt (`hmac` field). */
|
|
22
|
+
formCallbackFor(id: string, override?: Record<string, string>): CallbackInput;
|
|
23
|
+
}
|
|
24
|
+
/** Event webhook signature, written independently of the adapter: hex HMAC-SHA256(webhook salt, raw body bytes). */
|
|
25
|
+
export declare function hitpayEventSignature(webhookSalt: string, rawBody: string): string;
|
|
26
|
+
/** Legacy `hmac`: every field except `hmac`, keys sorted, `${key}${value}` joined with nothing (PHP SDK ksort+implode). */
|
|
27
|
+
export declare function hitpayFormSignature(apiSalt: string, fields: Record<string, string>): string;
|
|
28
|
+
export declare function startFakeHitPay(opts: {
|
|
29
|
+
apiKey: string;
|
|
30
|
+
/** API-key salt (Developers page): signs the legacy form callback. */
|
|
31
|
+
apiSalt: string;
|
|
32
|
+
/** Per-webhook-endpoint salt: signs event webhooks. */
|
|
33
|
+
webhookSalt: string;
|
|
34
|
+
}): Promise<FakeHitPay>;
|
|
35
|
+
export {};
|
|
36
|
+
//# sourceMappingURL=hitpay.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hitpay.d.ts","sourceRoot":"","sources":["../../src/fakes/hitpay.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AACnD,OAAO,EAAE,KAAK,WAAW,EAAQ,MAAM,YAAY,CAAA;AAEnD,KAAK,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IAC9C,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAA;CACpC,CAAA;AAED,MAAM,WAAW,UAAW,SAAQ,WAAW;IAC7C,QAAQ,EAAE;QACR,MAAM,EAAE,MAAM,CAAA;QACd,IAAI,EAAE,MAAM,CAAA;QACZ,wGAAwG;QACxG,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;QAC7B,WAAW,EAAE,MAAM,GAAG,SAAS,CAAA;QAC/B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAA;KACvD,EAAE,CAAA;IACH,4EAA4E;IAC5E,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAAA;IACtD,2FAA2F;IAC3F,eAAe,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,aAAa,CAAA;CAC9E;AAED,oHAAoH;AACpH,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAEjF;AAED,2HAA2H;AAC3H,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAO3F;AASD,wBAAsB,eAAe,CAAC,IAAI,EAAE;IAC1C,MAAM,EAAE,MAAM,CAAA;IACd,sEAAsE;IACtE,OAAO,EAAE,MAAM,CAAA;IACf,uDAAuD;IACvD,WAAW,EAAE,MAAM,CAAA;CACpB,GAAG,OAAO,CAAC,UAAU,CAAC,CA4LtB"}
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A fake HitPay API (Payment Requests), built from the official docs in `gateways/hitpay/spec.md` (not yet measured
|
|
3
|
+
* against the HitPay sandbox). When someone measures the sandbox, change this file first so it answers like the real
|
|
4
|
+
* thing, then the adapter.
|
|
5
|
+
*
|
|
6
|
+
* What it checks, and where each rule comes from (spec sections in brackets):
|
|
7
|
+
* - auth: `X-BUSINESS-API-KEY` must be the configured key AND `X-Requested-With: XMLHttpRequest` must be present; the
|
|
8
|
+
* docs list a missing header as a cause of "Invalid Business API Key" [§1]. ASSUMED: that error is HTTP 401;
|
|
9
|
+
* - create accepts BOTH form-urlencoded (guide + PHP SDK) and JSON (OpenAPI) bodies [§2, §6.4]; `currency` is required,
|
|
10
|
+
* and `amount` too (the guide says mandatory, the OpenAPI optional: the fake takes the stricter side); `amount` is in
|
|
11
|
+
* major units, 0.3 to 999999999.99, else 422 with the documented message [§2];
|
|
12
|
+
* - amounts come back as strings in major units (`"10.50"`); timestamps without an offset [§2, §3];
|
|
13
|
+
* - unknown request id → 404 `{"message":"No query results for model [App\\Business\\PaymentRequest] <id>"}` [§3];
|
|
14
|
+
* - callbacks, two schemes [§4]:
|
|
15
|
+
* - `callbackFor` = the event webhook: JSON body, `Hitpay-Signature` = hex HMAC-SHA256(webhook salt, RAW body).
|
|
16
|
+
* ASSUMED: the body escapes `/` as `\/` (PHP `json_encode` default), so a handler that re-serialises the parsed
|
|
17
|
+
* JSON gets different bytes and the signature fails, as it can on a real webhook [§6.3];
|
|
18
|
+
* - `formCallbackFor` = the legacy per-request `webhook` form POST: `hmac` = hex HMAC-SHA256(API salt, every field
|
|
19
|
+
* except `hmac`, sorted by key, `key+value` concatenated without separators, empty values included) [§4].
|
|
20
|
+
* ASSUMED (no source): the create response is HTTP 201; the checkout URL path; the shape of `payments[]` beyond the
|
|
21
|
+
* documented status/amount/fees strings.
|
|
22
|
+
*/
|
|
23
|
+
import { createHmac, randomUUID } from 'node:crypto';
|
|
24
|
+
import { createServer } from 'node:http';
|
|
25
|
+
import { flip } from './types.js';
|
|
26
|
+
/** Event webhook signature, written independently of the adapter: hex HMAC-SHA256(webhook salt, raw body bytes). */
|
|
27
|
+
export function hitpayEventSignature(webhookSalt, rawBody) {
|
|
28
|
+
return createHmac('sha256', webhookSalt).update(rawBody, 'utf8').digest('hex');
|
|
29
|
+
}
|
|
30
|
+
/** Legacy `hmac`: every field except `hmac`, keys sorted, `${key}${value}` joined with nothing (PHP SDK ksort+implode). */
|
|
31
|
+
export function hitpayFormSignature(apiSalt, fields) {
|
|
32
|
+
const keys = Object.keys(fields)
|
|
33
|
+
.filter((k) => k !== 'hmac')
|
|
34
|
+
.sort();
|
|
35
|
+
return createHmac('sha256', apiSalt)
|
|
36
|
+
.update(keys.map((k) => `${k}${fields[k] ?? ''}`).join(''), 'utf8')
|
|
37
|
+
.digest('hex');
|
|
38
|
+
}
|
|
39
|
+
const pad = (n) => String(n).padStart(2, '0');
|
|
40
|
+
/** `2025-07-03T02:18:49`: no offset, as in the docs. ASSUMED local time UTC+8 (refund example). */
|
|
41
|
+
const stamp = () => {
|
|
42
|
+
const d = new Date(Date.now() + 8 * 3600_000);
|
|
43
|
+
return `${d.getUTCFullYear()}-${pad(d.getUTCMonth() + 1)}-${pad(d.getUTCDate())}T${pad(d.getUTCHours())}:${pad(d.getUTCMinutes())}:${pad(d.getUTCSeconds())}`;
|
|
44
|
+
};
|
|
45
|
+
export async function startFakeHitPay(opts) {
|
|
46
|
+
const store = new Map();
|
|
47
|
+
const requests = [];
|
|
48
|
+
const server = createServer((req, res) => {
|
|
49
|
+
let raw = '';
|
|
50
|
+
req.on('data', (d) => {
|
|
51
|
+
raw += d;
|
|
52
|
+
});
|
|
53
|
+
req.on('end', () => {
|
|
54
|
+
const contentType = req.headers['content-type'];
|
|
55
|
+
let body = {};
|
|
56
|
+
if (contentType?.includes('application/json')) {
|
|
57
|
+
try {
|
|
58
|
+
const j = raw ? JSON.parse(raw) : {};
|
|
59
|
+
if (j && typeof j === 'object' && !Array.isArray(j))
|
|
60
|
+
body = j;
|
|
61
|
+
}
|
|
62
|
+
catch { }
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
const form = new URLSearchParams(raw);
|
|
66
|
+
for (const k of new Set(form.keys()))
|
|
67
|
+
body[k] = form.getAll(k).join(',');
|
|
68
|
+
}
|
|
69
|
+
const path = (req.url ?? '').split('?')[0] ?? '';
|
|
70
|
+
requests.push({ method: req.method ?? '', path, body, contentType, headers: req.headers });
|
|
71
|
+
const send = (status, o) => {
|
|
72
|
+
res.writeHead(status, { 'content-type': 'application/json' });
|
|
73
|
+
res.end(JSON.stringify(o));
|
|
74
|
+
};
|
|
75
|
+
if (req.headers['x-business-api-key'] !== opts.apiKey ||
|
|
76
|
+
req.headers['x-requested-with'] !== 'XMLHttpRequest') {
|
|
77
|
+
return send(401, { message: 'Invalid Business API Key' });
|
|
78
|
+
}
|
|
79
|
+
if (req.method === 'POST' && path === '/v1/payment-requests') {
|
|
80
|
+
const errors = {};
|
|
81
|
+
const s = (k) => (body[k] == null ? '' : String(body[k]).trim());
|
|
82
|
+
if (!s('currency'))
|
|
83
|
+
errors.currency = ['The currency field is required.'];
|
|
84
|
+
else if (s('currency').length > 3)
|
|
85
|
+
errors.currency = ['The currency may not be greater than 3 characters.'];
|
|
86
|
+
const amount = Number(s('amount'));
|
|
87
|
+
if (!s('amount'))
|
|
88
|
+
errors.amount = ['The amount field is required.'];
|
|
89
|
+
else if (!Number.isFinite(amount) || amount < 0.3 || amount > 999999999.99)
|
|
90
|
+
errors.amount = ['The amount must be between 0.3 and 999999999.99.'];
|
|
91
|
+
if (s('reference_number').length > 255)
|
|
92
|
+
errors.reference_number = ['The reference number may not be greater than 255 characters.'];
|
|
93
|
+
if (s('purpose').length > 255)
|
|
94
|
+
errors.purpose = ['The purpose may not be greater than 255 characters.'];
|
|
95
|
+
const first = Object.values(errors)[0];
|
|
96
|
+
if (first)
|
|
97
|
+
return send(422, { message: first[0], errors });
|
|
98
|
+
const id = randomUUID();
|
|
99
|
+
const now = stamp();
|
|
100
|
+
const pr = {
|
|
101
|
+
id,
|
|
102
|
+
name: s('name') || null,
|
|
103
|
+
email: s('email') || null,
|
|
104
|
+
phone: s('phone') || null,
|
|
105
|
+
amount: amount.toFixed(2),
|
|
106
|
+
currency: s('currency'),
|
|
107
|
+
status: 'pending',
|
|
108
|
+
purpose: s('purpose') || null,
|
|
109
|
+
reference_number: s('reference_number') || null,
|
|
110
|
+
payment_methods: s('payment_methods[]') ? s('payment_methods[]').split(',') : ['card'],
|
|
111
|
+
url: `https://securecheckout.sandbox.hit-pay.com/payment-request/@fake/${id}/checkout`,
|
|
112
|
+
redirect_url: s('redirect_url') || null,
|
|
113
|
+
webhook: s('webhook') || null,
|
|
114
|
+
send_sms: false,
|
|
115
|
+
send_email: false,
|
|
116
|
+
allow_repeated_payments: false,
|
|
117
|
+
expiry_date: null,
|
|
118
|
+
created_at: now,
|
|
119
|
+
updated_at: now,
|
|
120
|
+
payments: [],
|
|
121
|
+
};
|
|
122
|
+
store.set(id, pr);
|
|
123
|
+
const { payments: _omit, ...created } = pr;
|
|
124
|
+
return send(201, created);
|
|
125
|
+
}
|
|
126
|
+
const one = /^\/v1\/payment-requests\/([^/]+)$/.exec(path);
|
|
127
|
+
if (one && req.method === 'GET') {
|
|
128
|
+
const pr = store.get(one[1] ?? '');
|
|
129
|
+
if (!pr)
|
|
130
|
+
return send(404, {
|
|
131
|
+
message: `No query results for model [App\\Business\\PaymentRequest] ${one[1]}`,
|
|
132
|
+
});
|
|
133
|
+
return send(200, pr);
|
|
134
|
+
}
|
|
135
|
+
send(404, { message: 'Not Found' });
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
await new Promise((r) => server.listen(0, '127.0.0.1', r));
|
|
139
|
+
const url = `http://127.0.0.1:${server.address().port}`;
|
|
140
|
+
const get = (id) => {
|
|
141
|
+
const pr = store.get(id);
|
|
142
|
+
if (!pr)
|
|
143
|
+
throw new Error(`fake HitPay: no payment request ${id}`);
|
|
144
|
+
return pr;
|
|
145
|
+
};
|
|
146
|
+
/** The charge id a payment would carry; the record itself stays unpaid until markPaid. */
|
|
147
|
+
const chargeIds = new Map();
|
|
148
|
+
const chargeId = (id) => {
|
|
149
|
+
let c = chargeIds.get(id);
|
|
150
|
+
if (!c) {
|
|
151
|
+
c = randomUUID();
|
|
152
|
+
chargeIds.set(id, c);
|
|
153
|
+
}
|
|
154
|
+
return c;
|
|
155
|
+
};
|
|
156
|
+
return {
|
|
157
|
+
url,
|
|
158
|
+
requests,
|
|
159
|
+
paymentRequest: (id) => store.get(id),
|
|
160
|
+
markPaid(id) {
|
|
161
|
+
const pr = get(id);
|
|
162
|
+
const now = stamp();
|
|
163
|
+
pr.status = 'completed';
|
|
164
|
+
pr.updated_at = now;
|
|
165
|
+
pr.payments = [
|
|
166
|
+
{
|
|
167
|
+
id: chargeId(id),
|
|
168
|
+
quantity: 1,
|
|
169
|
+
status: 'succeeded',
|
|
170
|
+
buyer_name: pr.name,
|
|
171
|
+
buyer_email: pr.email,
|
|
172
|
+
currency: pr.currency,
|
|
173
|
+
amount: pr.amount,
|
|
174
|
+
refunded_amount: '0.00',
|
|
175
|
+
payment_type: 'card',
|
|
176
|
+
fees: '0.50',
|
|
177
|
+
created_at: now,
|
|
178
|
+
updated_at: now,
|
|
179
|
+
},
|
|
180
|
+
];
|
|
181
|
+
},
|
|
182
|
+
/**
|
|
183
|
+
* The event webhook (`payment_request.completed`) claiming payment, even before `markPaid` (the fake's record
|
|
184
|
+
* stays unpaid). `override` changes body fields before signing.
|
|
185
|
+
*/
|
|
186
|
+
callbackFor(id, override = {}) {
|
|
187
|
+
const pr = get(id);
|
|
188
|
+
const { payments: _omit, ...shown } = pr;
|
|
189
|
+
const event = { ...shown, status: 'completed', updated_at: stamp(), ...override };
|
|
190
|
+
const rawBody = JSON.stringify(event).replaceAll('/', '\\/');
|
|
191
|
+
return {
|
|
192
|
+
fields: {},
|
|
193
|
+
rawBody,
|
|
194
|
+
headers: {
|
|
195
|
+
'content-type': 'application/json',
|
|
196
|
+
'user-agent': 'HitPay v2.0',
|
|
197
|
+
'hitpay-event-type': 'completed',
|
|
198
|
+
'hitpay-event-object': 'payment_request',
|
|
199
|
+
'hitpay-signature': hitpayEventSignature(opts.webhookSalt, rawBody),
|
|
200
|
+
},
|
|
201
|
+
};
|
|
202
|
+
},
|
|
203
|
+
formCallbackFor(id, override = {}) {
|
|
204
|
+
const pr = get(id);
|
|
205
|
+
const fields = {
|
|
206
|
+
payment_id: chargeId(id),
|
|
207
|
+
payment_request_id: pr.id,
|
|
208
|
+
reference_number: String(pr.reference_number ?? ''),
|
|
209
|
+
phone: String(pr.phone ?? ''),
|
|
210
|
+
amount: pr.amount,
|
|
211
|
+
currency: pr.currency,
|
|
212
|
+
status: 'completed',
|
|
213
|
+
...override,
|
|
214
|
+
};
|
|
215
|
+
const { hmac, ...signed } = fields;
|
|
216
|
+
const posted = { ...signed, hmac: hmac ?? hitpayFormSignature(opts.apiSalt, signed) };
|
|
217
|
+
return {
|
|
218
|
+
fields: posted,
|
|
219
|
+
rawBody: new URLSearchParams(posted).toString(),
|
|
220
|
+
headers: { 'content-type': 'application/x-www-form-urlencoded' },
|
|
221
|
+
};
|
|
222
|
+
},
|
|
223
|
+
tamper(cb) {
|
|
224
|
+
if (cb.headers['hitpay-signature'] !== undefined) {
|
|
225
|
+
return { ...cb, headers: { ...cb.headers, 'hitpay-signature': flip(cb.headers['hitpay-signature']) } };
|
|
226
|
+
}
|
|
227
|
+
const fields = { ...cb.fields, hmac: flip(cb.fields.hmac ?? '') };
|
|
228
|
+
return { ...cb, fields, rawBody: new URLSearchParams(fields).toString() };
|
|
229
|
+
},
|
|
230
|
+
close: () => new Promise((r) => server.close(() => r())),
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
//# sourceMappingURL=hitpay.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hitpay.js","sourceRoot":"","sources":["../../src/fakes/hitpay.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type FakeGateway } from './types.js';
|
|
2
|
+
export interface FakeIPay88 extends FakeGateway {
|
|
3
|
+
/** Every request received: method, path, and the form/query parameters. */
|
|
4
|
+
requests: {
|
|
5
|
+
method: string;
|
|
6
|
+
path: string;
|
|
7
|
+
params: Record<string, string>;
|
|
8
|
+
}[];
|
|
9
|
+
/** Record a failed payment (re-query answers `Payment fail`). */
|
|
10
|
+
markFailed(id: string): void;
|
|
11
|
+
}
|
|
12
|
+
export declare function startFakeIPay88(opts: {
|
|
13
|
+
merchantCode: string;
|
|
14
|
+
merchantKey: string;
|
|
15
|
+
}): Promise<FakeIPay88>;
|
|
16
|
+
//# sourceMappingURL=ipay88.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ipay88.d.ts","sourceRoot":"","sources":["../../src/fakes/ipay88.ts"],"names":[],"mappings":"AA2BA,OAAO,EAAE,KAAK,WAAW,EAAQ,MAAM,YAAY,CAAA;AA4BnD,MAAM,WAAW,UAAW,SAAQ,WAAW;IAC7C,2EAA2E;IAC3E,QAAQ,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,EAAE,CAAA;IAC5E,iEAAiE;IACjE,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAA;CAC7B;AAoBD,wBAAsB,eAAe,CAAC,IAAI,EAAE;IAC1C,YAAY,EAAE,MAAM,CAAA;IACpB,WAAW,EAAE,MAAM,CAAA;CACpB,GAAG,OAAO,CAAC,UAAU,CAAC,CA6ItB"}
|