gamemoney 6.0.0 → 7.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/LICENSE +21 -0
- package/README.md +65 -5
- package/dist/certificate.d.ts +1 -0
- package/{certs/gm.crt → dist/certificate.js} +2 -1
- package/{index.d.ts → dist/index.d.ts} +87 -35
- package/{index.js → dist/index.js} +48 -23
- package/{utils.d.ts → dist/utils.d.ts} +6 -5
- package/dist/utils.js +77 -0
- package/package.json +46 -55
- package/utils.js +0 -51
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2018 Maxim Makarov
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -4,17 +4,21 @@
|
|
|
4
4
|
|
|
5
5
|
Full API documentation [here](https://cp.gmpays.com/apidoc)
|
|
6
6
|
|
|
7
|
-
## Installation
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
8
9
|
```sh
|
|
9
10
|
$ npm install gamemoney
|
|
10
11
|
```
|
|
11
12
|
|
|
13
|
+
The package is ESM-only (there is no CommonJS build) and has no runtime dependencies. It requires Node.js `>=22.12.0`, where ES modules can also be loaded with `require()`.
|
|
14
|
+
|
|
12
15
|
## Usage
|
|
13
16
|
|
|
14
17
|
### Initialization
|
|
18
|
+
|
|
15
19
|
```typescript
|
|
16
|
-
import fs from 'fs'
|
|
17
|
-
import GameMoney from 'gamemoney'
|
|
20
|
+
import fs from 'node:fs'
|
|
21
|
+
import { GameMoney } from 'gamemoney'
|
|
18
22
|
|
|
19
23
|
const gm = new GameMoney({
|
|
20
24
|
project: 42,
|
|
@@ -23,7 +27,7 @@ const gm = new GameMoney({
|
|
|
23
27
|
// Optional. But to make checkouts must be specified
|
|
24
28
|
rsaPrivateKey: {
|
|
25
29
|
key: fs.readFileSync('./private.pem').toString(),
|
|
26
|
-
passphrase: '123' // Optional
|
|
30
|
+
passphrase: '123', // Optional
|
|
27
31
|
},
|
|
28
32
|
|
|
29
33
|
// OR:
|
|
@@ -31,8 +35,64 @@ const gm = new GameMoney({
|
|
|
31
35
|
// process.env.GM_RSA_PRIVATE_KEY ?? '',
|
|
32
36
|
// 'base64',
|
|
33
37
|
// )
|
|
38
|
+
|
|
39
|
+
// Optional. API host from the project settings. Default: https://paygate.gamemoney.com
|
|
40
|
+
apiUrl: 'https://paygate.gamemoney.com',
|
|
41
|
+
|
|
42
|
+
// Optional. GameMoney certificate or public key from the project settings,
|
|
43
|
+
// used to verify signatures of responses and notifications.
|
|
44
|
+
// Default: the certificate bundled with the package
|
|
45
|
+
gameMoneyPublicKey: fs.readFileSync('./gm.crt'),
|
|
46
|
+
|
|
47
|
+
// Optional. Request timeout in milliseconds. Default: no timeout
|
|
48
|
+
timeout: 30_000,
|
|
34
49
|
})
|
|
35
50
|
```
|
|
36
51
|
|
|
52
|
+
From CommonJS code, via Node's built-in [`require(esm)`](https://nodejs.org/api/modules.html#loading-ecmascript-modules-using-require):
|
|
53
|
+
|
|
54
|
+
```javascript
|
|
55
|
+
const { GameMoney, verifyRsaSignature } = require('gamemoney')
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Errors
|
|
59
|
+
|
|
60
|
+
- `GameMoneyError`: GameMoney responded with `"state": "error"`, the error text is in `message`.
|
|
61
|
+
- `GameMoneyHttpError`: GameMoney responded with a non-2xx HTTP status, available in `status`.
|
|
62
|
+
- `TimeoutError`: the request did not complete within `timeout`. GameMoney may still process it, so check the operation status (for example, with `getCheckoutStatus`) before retrying.
|
|
63
|
+
- `Error` with `Response signature mismatch` or `Wrong rand parameter`: the response failed verification and must not be trusted.
|
|
64
|
+
|
|
65
|
+
### Notifications
|
|
66
|
+
|
|
67
|
+
GameMoney resends payment and payout notifications for 24 hours until the project responds with `{"success": "true"}`:
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
if (!gm.verifyRsaSignature(notification)) {
|
|
71
|
+
response.send({ success: 'error', error: 'signature mismatch' })
|
|
72
|
+
return
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
response.send({ success: 'true' })
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Transfer notifications are answered with the created invoice signed with HMAC, see [the example](https://github.com/gamemoney-ps/gamemoney-node-sdk/tree/master/src/examples/transfer/callback.ts).
|
|
79
|
+
|
|
80
|
+
### Signatures
|
|
81
|
+
|
|
82
|
+
`parametersToString`, `generateHmacSignature`, `generateRsaSignature` and `verifyRsaSignature` implement the [GameMoney signature algorithm](https://cp.gmpays.com/apidoc#sign_general) and are exported for custom integrations and tests, for example to sign responses of a GameMoney mock.
|
|
83
|
+
|
|
84
|
+
### Other API methods
|
|
85
|
+
|
|
86
|
+
Any API method can be called with a signed request:
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
const response = await gm.request('exchange/rate', { from: 'USD', to: 'RUB' })
|
|
90
|
+
```
|
|
91
|
+
|
|
37
92
|
### Examples
|
|
38
|
-
|
|
93
|
+
|
|
94
|
+
See examples in [src/examples](https://github.com/gamemoney-ps/gamemoney-node-sdk/tree/master/src/examples) directory. They read the credentials from `GAMEMONEY_PROJECT_ID`, `GAMEMONEY_HMAC_PRIVATE_KEY` and `GAMEMONEY_RSA_PRIVATE_KEY` (base64) and can be run directly:
|
|
95
|
+
|
|
96
|
+
```sh
|
|
97
|
+
$ node --env-file=.env src/examples/statistics/balance.ts
|
|
98
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const gameMoneyCertificate = "-----BEGIN CERTIFICATE-----\nMIID3TCCAsWgAwIBAgIJANtAJ3UMiGLZMA0GCSqGSIb3DQEBCwUAMIGEMQswCQYD\nVQQGEwJDUjERMA8GA1UECAwIU2FuIEpvc2UxEjAQBgNVBAcMCVNhbnRhIEFuYTET\nMBEGA1UECgwKSUJTIFMuUi5MLjEeMBwGA1UEAwwVY2hlY2tpbi5nYW1lbW9uZXku\nY29tMRkwFwYJKoZIhvcNAQkBFgpjZW9AaWJzLmNyMB4XDTE2MDkwNDA3MjY0OVoX\nDTI2MDkwNjA3MjY0OVowgYQxCzAJBgNVBAYTAkNSMREwDwYDVQQIDAhTYW4gSm9z\nZTESMBAGA1UEBwwJU2FudGEgQW5hMRMwEQYDVQQKDApJQlMgUy5SLkwuMR4wHAYD\nVQQDDBVjaGVja2luLmdhbWVtb25leS5jb20xGTAXBgkqhkiG9w0BCQEWCmNlb0Bp\nYnMuY3IwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDPK9ODW+BcqZ5P\nYlQWziyLzKImuE8EDn7XuE9ZDmpKiJxwDUKZHSQYH4QtHyx0qYAbIqIGrKemfTu1\nnvW9+O8yKLFLLcaXVaSLU7mpp8uSWasGbkLqE7xVLqxQZq1zrBSEPnKR1/dNxD83\n5pNzMLx7ki02t1J01MAj0FvQ3GemIAQU15m+w+9YKX8cUYEBm+h2KuY6uziLhJTM\nBAQRIXO3z4fkZhUi/0wpiy5Zxi2jbh07gab7me5dpxxwOs/Dt10S6J8qu+AAH0DE\n3diqQS4OcaCYJuIo/kJVxrn8TO2WKzSf2CBMWMzKtA2lOIMokC79gsrTFAasRM8j\nBQkvD5/TAgMBAAGjUDBOMB0GA1UdDgQWBBTqyL+faltohjM5faVuKxRUBCG25DAf\nBgNVHSMEGDAWgBTqyL+faltohjM5faVuKxRUBCG25DAMBgNVHRMEBTADAQH/MA0G\nCSqGSIb3DQEBCwUAA4IBAQBpnItyLrXE1RWdGE+xoJ2YEbjNtgEfzaypFPpVuMO0\nhvCV1rJJDS3zs/P1uSF0akqN4weSGOeFuFyGf3v2j40M1T1XdllOA8ucBv7Rfy2W\nl1rR2aU+Hd6rl0E/7lhtx3VUobgPVKZn8k7NMKkSMtF/f2cS9jI4i6gsJfFImMr9\ngWjEZAlmwQcnilZ6ZUhhn+0yHFbCoX8fETH/sZlofZOnN8EkETyqyfThIpTX41XH\ngeivrSfScNQH1mWJuE0DXMobNrhyJpxHRJwXXQyck6TiDM8OETki4PBzjKk/Gsyc\n61gqP9VPE2AVVwKypWOJidMxMZ03n4+MlyTbz3mnBXL9\n-----END CERTIFICATE-----\n";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
export const gameMoneyCertificate = `-----BEGIN CERTIFICATE-----
|
|
2
2
|
MIID3TCCAsWgAwIBAgIJANtAJ3UMiGLZMA0GCSqGSIb3DQEBCwUAMIGEMQswCQYD
|
|
3
3
|
VQQGEwJDUjERMA8GA1UECAwIU2FuIEpvc2UxEjAQBgNVBAcMCVNhbnRhIEFuYTET
|
|
4
4
|
MBEGA1UECgwKSUJTIFMuUi5MLjEeMBwGA1UEAwwVY2hlY2tpbi5nYW1lbW9uZXku
|
|
@@ -21,3 +21,4 @@ gWjEZAlmwQcnilZ6ZUhhn+0yHFbCoX8fETH/sZlofZOnN8EkETyqyfThIpTX41XH
|
|
|
21
21
|
geivrSfScNQH1mWJuE0DXMobNrhyJpxHRJwXXQyck6TiDM8OETki4PBzjKk/Gsyc
|
|
22
22
|
61gqP9VPE2AVVwKypWOJidMxMZ03n4+MlyTbz3mnBXL9
|
|
23
23
|
-----END CERTIFICATE-----
|
|
24
|
+
`;
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import { type RsaKey, type HmacKey } from './utils.
|
|
2
|
-
export
|
|
3
|
-
|
|
4
|
-
'
|
|
5
|
-
|
|
1
|
+
import { type RsaKey, type RsaPublicKey, type HmacKey } from './utils.ts';
|
|
2
|
+
export { generateHmacSignature, generateRsaSignature, parametersToString, verifyRsaSignature, } from './utils.ts';
|
|
3
|
+
export declare const SignType: {
|
|
4
|
+
readonly HMAC: 'HMAC';
|
|
5
|
+
readonly RSA: 'RSA';
|
|
6
|
+
};
|
|
7
|
+
export type SignType = (typeof SignType)[keyof typeof SignType];
|
|
6
8
|
export type GenericRequest = {
|
|
7
9
|
[key: string]: any;
|
|
8
10
|
rand?: string;
|
|
@@ -21,9 +23,12 @@ export type Config = {
|
|
|
21
23
|
rsaPrivateKey?: RsaKey;
|
|
22
24
|
hmacPrivateKey: HmacKey;
|
|
23
25
|
project: number;
|
|
26
|
+
apiUrl?: string;
|
|
27
|
+
gameMoneyPublicKey?: RsaPublicKey;
|
|
28
|
+
timeout?: number;
|
|
24
29
|
};
|
|
25
30
|
export type CreateInvoiceRequest = {
|
|
26
|
-
[key: string]:
|
|
31
|
+
[key: string]: unknown;
|
|
27
32
|
type: string;
|
|
28
33
|
user: string;
|
|
29
34
|
ip: string;
|
|
@@ -40,6 +45,8 @@ export type CreateInvoiceRequest = {
|
|
|
40
45
|
return_mode?: 'skip';
|
|
41
46
|
recurring?: 'yes';
|
|
42
47
|
recurrent_token?: string;
|
|
48
|
+
payment_token?: string;
|
|
49
|
+
theme?: 'dark' | 'light';
|
|
43
50
|
};
|
|
44
51
|
export type CreateInvoiceResponse = {
|
|
45
52
|
invoice: number;
|
|
@@ -47,11 +54,11 @@ export type CreateInvoiceResponse = {
|
|
|
47
54
|
data: string;
|
|
48
55
|
};
|
|
49
56
|
export type GetInvoiceStatusRequestWithProjectInvoiceId = {
|
|
50
|
-
[key: string]:
|
|
57
|
+
[key: string]: unknown;
|
|
51
58
|
invoice: number;
|
|
52
59
|
};
|
|
53
60
|
export type GetInvoiceStatusRequestWithGamemoneyInvoiceId = {
|
|
54
|
-
[key: string]:
|
|
61
|
+
[key: string]: unknown;
|
|
55
62
|
project_invoice: string;
|
|
56
63
|
};
|
|
57
64
|
export type GetInvoiceStatusRequest = GetInvoiceStatusRequestWithProjectInvoiceId | GetInvoiceStatusRequestWithGamemoneyInvoiceId;
|
|
@@ -77,7 +84,7 @@ export type GetInvoiceStatusResponse = {
|
|
|
77
84
|
txid?: string;
|
|
78
85
|
};
|
|
79
86
|
export type GetInvoiceListRequest = {
|
|
80
|
-
[key: string]:
|
|
87
|
+
[key: string]: unknown;
|
|
81
88
|
start: string;
|
|
82
89
|
finish: string;
|
|
83
90
|
status?: InvoiceStatus;
|
|
@@ -86,7 +93,14 @@ export type GetInvoiceListResponse = {
|
|
|
86
93
|
list: GetInvoiceStatusResponse[];
|
|
87
94
|
is_limit_exceeded: 'yes' | 'no';
|
|
88
95
|
};
|
|
89
|
-
export type
|
|
96
|
+
export type AddTokenInvoiceRequest = {
|
|
97
|
+
[key: string]: unknown;
|
|
98
|
+
user: string;
|
|
99
|
+
};
|
|
100
|
+
export type AddTokenInvoiceResponse = {
|
|
101
|
+
token: string;
|
|
102
|
+
};
|
|
103
|
+
export type GetCardSessionStatusRequest = Record<string, unknown> & ({
|
|
90
104
|
invoice: string;
|
|
91
105
|
} | {
|
|
92
106
|
project_invoice: string;
|
|
@@ -102,11 +116,11 @@ export type FinishCardSessionStatusResponse = {
|
|
|
102
116
|
};
|
|
103
117
|
export type GetCardSessionStatusResponse = WaitOrDeclineCardSessionStatusResponse | FinishCardSessionStatusResponse;
|
|
104
118
|
export type CancelCheckoutRequest = {
|
|
105
|
-
[key: string]:
|
|
119
|
+
[key: string]: unknown;
|
|
106
120
|
projectId: string;
|
|
107
121
|
};
|
|
108
122
|
export type GetCheckoutStatusRequest = {
|
|
109
|
-
[key: string]:
|
|
123
|
+
[key: string]: unknown;
|
|
110
124
|
projectId: string;
|
|
111
125
|
};
|
|
112
126
|
export type Refund = {
|
|
@@ -136,7 +150,7 @@ export type GetCheckoutStatusResponse = {
|
|
|
136
150
|
txid?: string;
|
|
137
151
|
};
|
|
138
152
|
export type GetCheckoutListRequest = {
|
|
139
|
-
[key: string]:
|
|
153
|
+
[key: string]: unknown;
|
|
140
154
|
start: string;
|
|
141
155
|
finish: string;
|
|
142
156
|
};
|
|
@@ -145,7 +159,7 @@ export type GetCheckoutListResponse = {
|
|
|
145
159
|
is_limit_exceeded: 'yes' | 'no';
|
|
146
160
|
};
|
|
147
161
|
export type CreateCheckoutRequest = {
|
|
148
|
-
[key: string]:
|
|
162
|
+
[key: string]: unknown;
|
|
149
163
|
projectId: string;
|
|
150
164
|
user: string;
|
|
151
165
|
ip: string;
|
|
@@ -157,30 +171,52 @@ export type CreateCheckoutRequest = {
|
|
|
157
171
|
userCurrency?: string;
|
|
158
172
|
prepareToken?: string;
|
|
159
173
|
};
|
|
174
|
+
export type PrepareCheckoutRequest = Record<string, unknown> & {
|
|
175
|
+
type: string;
|
|
176
|
+
wallet?: string;
|
|
177
|
+
currency?: string;
|
|
178
|
+
userCurrency?: string;
|
|
179
|
+
} & ({
|
|
180
|
+
amount: number;
|
|
181
|
+
} | {
|
|
182
|
+
paid_amount: number;
|
|
183
|
+
});
|
|
184
|
+
export type PrepareCheckoutResponse = {
|
|
185
|
+
amount: number;
|
|
186
|
+
net_amount: number;
|
|
187
|
+
paid_amount: number;
|
|
188
|
+
currency_project: string;
|
|
189
|
+
currency_user: string;
|
|
190
|
+
token?: string;
|
|
191
|
+
rate?: number;
|
|
192
|
+
expire?: number;
|
|
193
|
+
};
|
|
160
194
|
export type AddCardRequest = {
|
|
161
|
-
[key: string]:
|
|
195
|
+
[key: string]: unknown;
|
|
162
196
|
user: string;
|
|
163
197
|
redirect: string;
|
|
198
|
+
language?: string;
|
|
199
|
+
theme?: 'dark' | 'light';
|
|
164
200
|
};
|
|
165
201
|
export type AddCardResponse = {
|
|
166
202
|
url: string;
|
|
167
203
|
};
|
|
168
204
|
export type AddTokenCardRequest = {
|
|
169
|
-
[key: string]:
|
|
205
|
+
[key: string]: unknown;
|
|
170
206
|
user: string;
|
|
171
207
|
};
|
|
172
208
|
export type AddTokenCardResponse = {
|
|
173
209
|
token: string;
|
|
174
210
|
};
|
|
175
211
|
export type GetCardListRequest = {
|
|
176
|
-
[key: string]:
|
|
212
|
+
[key: string]: unknown;
|
|
177
213
|
user: string;
|
|
178
214
|
};
|
|
179
215
|
export type GetCardListResponse = {
|
|
180
216
|
pans: string[];
|
|
181
217
|
};
|
|
182
218
|
export type GetCardFullListRequest = {
|
|
183
|
-
[key: string]:
|
|
219
|
+
[key: string]: unknown;
|
|
184
220
|
user: string;
|
|
185
221
|
};
|
|
186
222
|
export type GetCardFullListResponse = {
|
|
@@ -189,16 +225,17 @@ export type GetCardFullListResponse = {
|
|
|
189
225
|
expire_month: string;
|
|
190
226
|
expire_year: string;
|
|
191
227
|
cardholder: string;
|
|
228
|
+
country?: string;
|
|
192
229
|
}>;
|
|
193
230
|
};
|
|
194
231
|
export type DeleteCardRequest = {
|
|
195
|
-
[key: string]:
|
|
232
|
+
[key: string]: unknown;
|
|
196
233
|
user: string;
|
|
197
234
|
pan: string;
|
|
198
235
|
};
|
|
199
236
|
export type PrepareExchangeRequest = {
|
|
200
|
-
[key: string]:
|
|
201
|
-
externalId
|
|
237
|
+
[key: string]: unknown;
|
|
238
|
+
externalId?: string;
|
|
202
239
|
minAmount: number;
|
|
203
240
|
maxAmount: number;
|
|
204
241
|
from: string;
|
|
@@ -212,12 +249,12 @@ export type PrepareExchangeResponse = {
|
|
|
212
249
|
exchanged_amount_to: number;
|
|
213
250
|
};
|
|
214
251
|
export type ConvertExchangeRequest = {
|
|
215
|
-
[key: string]:
|
|
252
|
+
[key: string]: unknown;
|
|
216
253
|
id: number;
|
|
217
254
|
amount: number;
|
|
218
255
|
};
|
|
219
256
|
export type FastConvertExchangeRequest = {
|
|
220
|
-
[key: string]:
|
|
257
|
+
[key: string]: unknown;
|
|
221
258
|
amount: number;
|
|
222
259
|
from: string;
|
|
223
260
|
to: string;
|
|
@@ -227,7 +264,7 @@ export type FastConvertExchangeResponse = {
|
|
|
227
264
|
rate: number;
|
|
228
265
|
};
|
|
229
266
|
export type GetExchangeRateRequest = {
|
|
230
|
-
[key: string]:
|
|
267
|
+
[key: string]: unknown;
|
|
231
268
|
from: string;
|
|
232
269
|
to: string;
|
|
233
270
|
};
|
|
@@ -236,7 +273,7 @@ export type GetExchangeRateResponse = {
|
|
|
236
273
|
sell: number;
|
|
237
274
|
};
|
|
238
275
|
export type GetExchangeInfoRequest = {
|
|
239
|
-
[key: string]:
|
|
276
|
+
[key: string]: unknown;
|
|
240
277
|
minAmount: number;
|
|
241
278
|
maxAmount: number;
|
|
242
279
|
from: string;
|
|
@@ -250,7 +287,7 @@ export type GetExchangeInfoResponse = {
|
|
|
250
287
|
exchanged_amount_to: number;
|
|
251
288
|
};
|
|
252
289
|
export type GetExchangeStatusRequest = {
|
|
253
|
-
[key: string]:
|
|
290
|
+
[key: string]: unknown;
|
|
254
291
|
id?: number;
|
|
255
292
|
externalId?: string;
|
|
256
293
|
};
|
|
@@ -264,7 +301,7 @@ export type GetExchangeStatusResponse = {
|
|
|
264
301
|
status: string;
|
|
265
302
|
};
|
|
266
303
|
export type GetBalanceStatisticsRequest = {
|
|
267
|
-
[key: string]:
|
|
304
|
+
[key: string]: unknown;
|
|
268
305
|
currency: string;
|
|
269
306
|
};
|
|
270
307
|
export type GetBalanceStatisticsResponse = {
|
|
@@ -278,7 +315,7 @@ export type GetBalanceStatisticsResponse = {
|
|
|
278
315
|
contract_balance: number;
|
|
279
316
|
};
|
|
280
317
|
export type GetDaysBalanceStatisticsRequest = {
|
|
281
|
-
[key: string]:
|
|
318
|
+
[key: string]: unknown;
|
|
282
319
|
currency: string;
|
|
283
320
|
start: string;
|
|
284
321
|
finish: string;
|
|
@@ -309,7 +346,7 @@ export type GetPayTypesStatisticsResponse = {
|
|
|
309
346
|
checkout: PaySystem[];
|
|
310
347
|
};
|
|
311
348
|
export type CreateTerminalRequest = {
|
|
312
|
-
[key: string]:
|
|
349
|
+
[key: string]: unknown;
|
|
313
350
|
user: string;
|
|
314
351
|
amount?: number;
|
|
315
352
|
comment?: string;
|
|
@@ -319,8 +356,13 @@ export type CreateTerminalRequest = {
|
|
|
319
356
|
currency?: string;
|
|
320
357
|
use_user_select_currency?: 'yes' | 'no';
|
|
321
358
|
language?: string;
|
|
359
|
+
return_mode?: 'skip';
|
|
360
|
+
recurring?: 'yes';
|
|
322
361
|
terminal_allow_methods?: string[];
|
|
323
362
|
terminal_disable_methods?: string[];
|
|
363
|
+
terminal_livetime?: number;
|
|
364
|
+
terminal_country?: string;
|
|
365
|
+
terminal_theme?: 'dark' | 'light';
|
|
324
366
|
};
|
|
325
367
|
export type CreateTerminalResponse = {
|
|
326
368
|
url: string;
|
|
@@ -375,6 +417,7 @@ export type TransferNotification = {
|
|
|
375
417
|
currency: string;
|
|
376
418
|
user: string;
|
|
377
419
|
type: string;
|
|
420
|
+
project: number;
|
|
378
421
|
ip: string;
|
|
379
422
|
time: number;
|
|
380
423
|
comment: string;
|
|
@@ -384,23 +427,32 @@ type Payload = Record<string, unknown>;
|
|
|
384
427
|
export declare class GameMoneyError extends Error {
|
|
385
428
|
constructor(message: string);
|
|
386
429
|
}
|
|
387
|
-
export
|
|
430
|
+
export declare class GameMoneyHttpError extends Error {
|
|
431
|
+
readonly status: number;
|
|
432
|
+
constructor(status: number, statusText: string);
|
|
433
|
+
}
|
|
434
|
+
export declare class GameMoney {
|
|
388
435
|
private readonly config;
|
|
389
|
-
private readonly got;
|
|
390
436
|
constructor(config: Config);
|
|
391
437
|
request<T extends GenericResponse>(url: string, payload?: Payload, signType?: SignType): Promise<T>;
|
|
392
|
-
generateHmacSignature(body:
|
|
393
|
-
verifyRsaSignature(body:
|
|
438
|
+
generateHmacSignature(body: Record<string, unknown>): string;
|
|
439
|
+
verifyRsaSignature(body: unknown): boolean;
|
|
394
440
|
/** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#invoice_insert_api) */
|
|
395
441
|
createInvoice(body: CreateInvoiceRequest): Promise<CreateInvoiceResponse & GenericResponse>;
|
|
396
442
|
/** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#invoice_status) */
|
|
397
443
|
getInvoiceStatus(body: GetInvoiceStatusRequest): Promise<GetInvoiceStatusResponse & GenericResponse>;
|
|
398
444
|
/** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#invoice_list) */
|
|
399
445
|
getInvoiceList(body: GetInvoiceListRequest): Promise<GetInvoiceListResponse & GenericResponse>;
|
|
446
|
+
/** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#invoice_add_token) */
|
|
447
|
+
addTokenInvoice(body: AddTokenInvoiceRequest): Promise<AddTokenInvoiceResponse & GenericResponse>;
|
|
400
448
|
/** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#card_session_status) */
|
|
401
449
|
getCardSessionStatus(body: GetCardSessionStatusRequest): Promise<GetCardSessionStatusResponse & GenericResponse>;
|
|
402
450
|
/** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#checkout_insert) */
|
|
403
451
|
createCheckout(body: CreateCheckoutRequest): Promise<GenericResponse>;
|
|
452
|
+
/** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#checkout_prepare) */
|
|
453
|
+
prepareCheckout(body: PrepareCheckoutRequest): Promise<PrepareCheckoutResponse & GenericResponse>;
|
|
454
|
+
/** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#checkout_check) */
|
|
455
|
+
checkCheckout(body: CreateCheckoutRequest): Promise<GenericResponse>;
|
|
404
456
|
/** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#checkout_cancel) */
|
|
405
457
|
cancelCheckout(body: CancelCheckoutRequest): Promise<GenericResponse>;
|
|
406
458
|
/** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#checkout_status) */
|
|
@@ -415,7 +467,7 @@ export default class GameMoney {
|
|
|
415
467
|
getCardList(body: GetCardListRequest): Promise<GetCardListResponse & GenericResponse>;
|
|
416
468
|
/** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#card_fulllist) */
|
|
417
469
|
getCardFullList(body: GetCardFullListRequest): Promise<GetCardFullListResponse & GenericResponse>;
|
|
418
|
-
/** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#
|
|
470
|
+
/** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#card_delete) */
|
|
419
471
|
deleteCard(body: DeleteCardRequest): Promise<GenericResponse>;
|
|
420
472
|
/** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#exchange_prepare) */
|
|
421
473
|
prepareExchange(body: PrepareExchangeRequest): Promise<PrepareExchangeResponse & GenericResponse>;
|
|
@@ -438,4 +490,4 @@ export default class GameMoney {
|
|
|
438
490
|
/** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#invoice_api_terminal) */
|
|
439
491
|
createTerminal(body: CreateTerminalRequest): Promise<CreateTerminalResponse & GenericResponse>;
|
|
440
492
|
}
|
|
441
|
-
export
|
|
493
|
+
export default GameMoney;
|
|
@@ -1,34 +1,36 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
})(SignType || (SignType = {}));
|
|
1
|
+
import { generateRsaSignature, generateHmacSignature, getRandomString, stringifyForm, verifyRsaSignature, } from './utils.js';
|
|
2
|
+
export { generateHmacSignature, generateRsaSignature, parametersToString, verifyRsaSignature, } from './utils.js';
|
|
3
|
+
export const SignType = {
|
|
4
|
+
HMAC: 'HMAC',
|
|
5
|
+
RSA: 'RSA',
|
|
6
|
+
};
|
|
8
7
|
export class GameMoneyError extends Error {
|
|
9
8
|
constructor(message) {
|
|
10
9
|
super(message);
|
|
11
10
|
this.name = 'GameMoneyError';
|
|
12
11
|
}
|
|
13
12
|
}
|
|
14
|
-
export
|
|
13
|
+
export class GameMoneyHttpError extends Error {
|
|
14
|
+
status;
|
|
15
|
+
constructor(status, statusText) {
|
|
16
|
+
super(`Response code ${status} (${statusText})`);
|
|
17
|
+
this.name = 'GameMoneyHttpError';
|
|
18
|
+
this.status = status;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export class GameMoney {
|
|
15
22
|
config;
|
|
16
|
-
got = got.extend({
|
|
17
|
-
prefixUrl: 'https://paygate.gamemoney.com',
|
|
18
|
-
responseType: 'json',
|
|
19
|
-
});
|
|
20
23
|
constructor(config) {
|
|
21
24
|
this.config = config;
|
|
22
|
-
this.config = config;
|
|
23
25
|
}
|
|
24
26
|
async request(url, payload = {}, signType = SignType.HMAC) {
|
|
25
27
|
const form = {
|
|
26
|
-
rand: getRandomString(20),
|
|
27
|
-
project: this.config.project,
|
|
28
28
|
...payload,
|
|
29
|
+
project: payload.project ?? this.config.project,
|
|
30
|
+
rand: payload.rand ?? getRandomString(20),
|
|
29
31
|
};
|
|
30
32
|
if (signType === SignType.RSA) {
|
|
31
|
-
if (
|
|
33
|
+
if (this.config.rsaPrivateKey === undefined) {
|
|
32
34
|
throw new Error("To make requests with RSA sign type, 'rsaPrivateKey' must be provided");
|
|
33
35
|
}
|
|
34
36
|
form.signature = generateRsaSignature(form, this.config.rsaPrivateKey);
|
|
@@ -36,12 +38,22 @@ export default class GameMoney {
|
|
|
36
38
|
else {
|
|
37
39
|
form.signature = generateHmacSignature(form, this.config.hmacPrivateKey);
|
|
38
40
|
}
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
const httpResponse = await fetch(new URL(url, this.config.apiUrl ?? 'https://paygate.gamemoney.com'), {
|
|
42
|
+
method: 'POST',
|
|
43
|
+
headers: {
|
|
44
|
+
accept: 'application/json',
|
|
45
|
+
'content-type': 'application/x-www-form-urlencoded',
|
|
46
|
+
},
|
|
47
|
+
body: stringifyForm(form),
|
|
48
|
+
signal: this.config.timeout === undefined
|
|
49
|
+
? null
|
|
50
|
+
: AbortSignal.timeout(this.config.timeout),
|
|
43
51
|
});
|
|
44
|
-
if (!
|
|
52
|
+
if (!httpResponse.ok) {
|
|
53
|
+
throw new GameMoneyHttpError(httpResponse.status, httpResponse.statusText);
|
|
54
|
+
}
|
|
55
|
+
const response = (await httpResponse.json());
|
|
56
|
+
if (!verifyRsaSignature(response, this.config.gameMoneyPublicKey)) {
|
|
45
57
|
throw new Error('Response signature mismatch');
|
|
46
58
|
}
|
|
47
59
|
if (form.rand !== response.rand) {
|
|
@@ -56,7 +68,7 @@ export default class GameMoney {
|
|
|
56
68
|
return generateHmacSignature(body, this.config.hmacPrivateKey);
|
|
57
69
|
}
|
|
58
70
|
verifyRsaSignature(body) {
|
|
59
|
-
return verifyRsaSignature(body);
|
|
71
|
+
return verifyRsaSignature(body, this.config.gameMoneyPublicKey);
|
|
60
72
|
}
|
|
61
73
|
/** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#invoice_insert_api) */
|
|
62
74
|
async createInvoice(body) {
|
|
@@ -70,6 +82,10 @@ export default class GameMoney {
|
|
|
70
82
|
async getInvoiceList(body) {
|
|
71
83
|
return this.request('invoice/list', body);
|
|
72
84
|
}
|
|
85
|
+
/** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#invoice_add_token) */
|
|
86
|
+
async addTokenInvoice(body) {
|
|
87
|
+
return this.request('invoice/addtoken', body);
|
|
88
|
+
}
|
|
73
89
|
/** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#card_session_status) */
|
|
74
90
|
async getCardSessionStatus(body) {
|
|
75
91
|
return this.request('invoice/cardsession/status', body);
|
|
@@ -78,6 +94,14 @@ export default class GameMoney {
|
|
|
78
94
|
async createCheckout(body) {
|
|
79
95
|
return this.request('checkout/insert', body, SignType.RSA);
|
|
80
96
|
}
|
|
97
|
+
/** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#checkout_prepare) */
|
|
98
|
+
async prepareCheckout(body) {
|
|
99
|
+
return this.request('checkout/prepare', body);
|
|
100
|
+
}
|
|
101
|
+
/** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#checkout_check) */
|
|
102
|
+
async checkCheckout(body) {
|
|
103
|
+
return this.request('checkout/check', body, SignType.RSA);
|
|
104
|
+
}
|
|
81
105
|
/** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#checkout_cancel) */
|
|
82
106
|
async cancelCheckout(body) {
|
|
83
107
|
return this.request('checkout/cancel', body);
|
|
@@ -106,7 +130,7 @@ export default class GameMoney {
|
|
|
106
130
|
async getCardFullList(body) {
|
|
107
131
|
return this.request('card/fulllist', body);
|
|
108
132
|
}
|
|
109
|
-
/** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#
|
|
133
|
+
/** For more details and usage information see [docs](https://cp.gmpays.com/apidoc#card_delete) */
|
|
110
134
|
async deleteCard(body) {
|
|
111
135
|
return this.request('card/delete', body);
|
|
112
136
|
}
|
|
@@ -151,3 +175,4 @@ export default class GameMoney {
|
|
|
151
175
|
return this.request('terminal/create', body);
|
|
152
176
|
}
|
|
153
177
|
}
|
|
178
|
+
export default GameMoney;
|
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
/// <reference types="node" resolution-mode="require"/>
|
|
2
1
|
import crypto from 'node:crypto';
|
|
3
2
|
export type RsaKey = Parameters<crypto.Sign['sign']>[0];
|
|
3
|
+
export type RsaPublicKey = Parameters<crypto.Verify['verify']>[0];
|
|
4
4
|
export type HmacKey = Parameters<typeof crypto.createHmac>[1];
|
|
5
5
|
type JsonPrimitive = number | number[] | string | string[] | undefined | null;
|
|
6
6
|
type Json = {
|
|
7
7
|
[key: string]: Json | JsonPrimitive;
|
|
8
8
|
};
|
|
9
|
-
type
|
|
10
|
-
|
|
11
|
-
}
|
|
9
|
+
type FormValue = string | number | boolean | bigint | undefined | null | FormValue[] | {
|
|
10
|
+
[key: string]: FormValue;
|
|
11
|
+
};
|
|
12
12
|
export declare function parametersToString(body: Json): string;
|
|
13
|
-
export declare function
|
|
13
|
+
export declare function stringifyForm(form: Record<string, FormValue>): string;
|
|
14
|
+
export declare function verifyRsaSignature(body: unknown, publicKey?: RsaPublicKey): boolean;
|
|
14
15
|
export declare function generateRsaSignature(body: Json, key: RsaKey): string;
|
|
15
16
|
export declare function generateHmacSignature(body: Json, key: HmacKey): string;
|
|
16
17
|
export declare function getRandomString(length: number): string;
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import crypto from 'node:crypto';
|
|
2
|
+
import { gameMoneyCertificate } from './certificate.js';
|
|
3
|
+
export function parametersToString(body) {
|
|
4
|
+
let parametersString = '';
|
|
5
|
+
const keys = Object.keys(body).sort();
|
|
6
|
+
if (Array.isArray(body)) {
|
|
7
|
+
keys.sort((a, b) => Number(a) - Number(b));
|
|
8
|
+
}
|
|
9
|
+
for (const key of keys) {
|
|
10
|
+
let value = body[key];
|
|
11
|
+
if (key === 'signature') {
|
|
12
|
+
continue;
|
|
13
|
+
}
|
|
14
|
+
if (value === null || value === undefined) {
|
|
15
|
+
value = '';
|
|
16
|
+
}
|
|
17
|
+
if (typeof value === 'object' && value !== null) {
|
|
18
|
+
value = parametersToString(value);
|
|
19
|
+
}
|
|
20
|
+
parametersString += `${key}:${value};`;
|
|
21
|
+
}
|
|
22
|
+
return parametersString;
|
|
23
|
+
}
|
|
24
|
+
// Wire format of gamemoney@3 (request + qs): RFC 3986 escaping, nested values as `key[index]=value`
|
|
25
|
+
function encodeFormComponent(value) {
|
|
26
|
+
return encodeURIComponent(value).replaceAll(/[!'()*]/g, (char) => `%${char.codePointAt(0).toString(16).toUpperCase()}`);
|
|
27
|
+
}
|
|
28
|
+
function appendFormValue(pairs, key, value) {
|
|
29
|
+
if (value === undefined) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
if (typeof value === 'object' && value !== null) {
|
|
33
|
+
for (const [nestedKey, nestedValue] of Object.entries(value)) {
|
|
34
|
+
appendFormValue(pairs, `${key}[${nestedKey}]`, nestedValue);
|
|
35
|
+
}
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
pairs.push(`${encodeFormComponent(key)}=${encodeFormComponent(value === null ? '' : String(value))}`);
|
|
39
|
+
}
|
|
40
|
+
export function stringifyForm(form) {
|
|
41
|
+
const pairs = [];
|
|
42
|
+
for (const [key, value] of Object.entries(form)) {
|
|
43
|
+
appendFormValue(pairs, key, value);
|
|
44
|
+
}
|
|
45
|
+
return pairs.join('&');
|
|
46
|
+
}
|
|
47
|
+
export function verifyRsaSignature(body, publicKey = gameMoneyCertificate) {
|
|
48
|
+
if (typeof body !== 'object' ||
|
|
49
|
+
body === null ||
|
|
50
|
+
!('signature' in body) ||
|
|
51
|
+
typeof body.signature !== 'string' ||
|
|
52
|
+
body.signature === '') {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
return crypto
|
|
56
|
+
.createVerify('RSA-SHA256')
|
|
57
|
+
.update(parametersToString(body), 'utf8')
|
|
58
|
+
.verify(publicKey, body.signature, 'base64');
|
|
59
|
+
}
|
|
60
|
+
export function generateRsaSignature(body, key) {
|
|
61
|
+
return crypto
|
|
62
|
+
.createSign('RSA-SHA256')
|
|
63
|
+
.update(parametersToString(body), 'utf8')
|
|
64
|
+
.sign(key, 'base64');
|
|
65
|
+
}
|
|
66
|
+
export function generateHmacSignature(body, key) {
|
|
67
|
+
return crypto
|
|
68
|
+
.createHmac('sha256', key)
|
|
69
|
+
.update(parametersToString(body), 'utf8')
|
|
70
|
+
.digest('hex');
|
|
71
|
+
}
|
|
72
|
+
export function getRandomString(length) {
|
|
73
|
+
return crypto
|
|
74
|
+
.randomBytes(Math.ceil(length / 2))
|
|
75
|
+
.toString('hex')
|
|
76
|
+
.slice(0, length);
|
|
77
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gamemoney",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "7.0.0",
|
|
4
4
|
"description": "GameMoney API wrapper for Node.js",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"gamemoney",
|
|
@@ -11,75 +11,66 @@
|
|
|
11
11
|
"homepage": "https://github.com/gamemoney-ps/gamemoney-node-sdk#readme",
|
|
12
12
|
"bugs": {
|
|
13
13
|
"url": "https://github.com/gamemoney-ps/gamemoney-node-sdk/issues",
|
|
14
|
-
"email": "
|
|
14
|
+
"email": "maxpain@linux.com"
|
|
15
15
|
},
|
|
16
16
|
"author": {
|
|
17
|
-
"name": "
|
|
18
|
-
"email": "
|
|
19
|
-
"url": "https://maxpain.pro"
|
|
17
|
+
"name": "Max Makarov",
|
|
18
|
+
"email": "maxpain@linux.com"
|
|
20
19
|
},
|
|
21
20
|
"license": "MIT",
|
|
22
21
|
"repository": {
|
|
23
22
|
"type": "git",
|
|
24
|
-
"url": "https://github.com/gamemoney-ps/gamemoney-node-sdk"
|
|
23
|
+
"url": "git+https://github.com/gamemoney-ps/gamemoney-node-sdk.git"
|
|
25
24
|
},
|
|
26
25
|
"type": "module",
|
|
27
26
|
"exports": {
|
|
28
27
|
".": {
|
|
29
|
-
"
|
|
30
|
-
"
|
|
28
|
+
"types": "./dist/index.d.ts",
|
|
29
|
+
"default": "./dist/index.js"
|
|
30
|
+
},
|
|
31
|
+
"./package.json": "./package.json"
|
|
32
|
+
},
|
|
33
|
+
"main": "./dist/index.js",
|
|
34
|
+
"types": "./dist/index.d.ts",
|
|
35
|
+
"files": [
|
|
36
|
+
"dist"
|
|
37
|
+
],
|
|
38
|
+
"sideEffects": false,
|
|
39
|
+
"engines": {
|
|
40
|
+
"node": ">=22.12.0"
|
|
41
|
+
},
|
|
42
|
+
"devEngines": {
|
|
43
|
+
"runtime": {
|
|
44
|
+
"name": "node",
|
|
45
|
+
"version": ">=22.22.1",
|
|
46
|
+
"onFail": "error"
|
|
31
47
|
}
|
|
32
48
|
},
|
|
33
49
|
"scripts": {
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"lint": "
|
|
39
|
-
"
|
|
50
|
+
"build": "rm -rf dist && tsc -p tsconfig.build.json",
|
|
51
|
+
"typecheck": "tsc",
|
|
52
|
+
"test": "node --test 'src/**/*.test.ts'",
|
|
53
|
+
"lint": "oxlint && oxfmt --check",
|
|
54
|
+
"lint:fix": "oxlint --fix && oxfmt",
|
|
55
|
+
"prepublishOnly": "npm run lint && npm run typecheck && npm test",
|
|
56
|
+
"prepack": "npm run build",
|
|
57
|
+
"prepare": "husky"
|
|
40
58
|
},
|
|
41
59
|
"lint-staged": {
|
|
42
|
-
"*.ts": "
|
|
60
|
+
"*.ts": "oxlint",
|
|
61
|
+
"*": "oxfmt --check --no-error-on-unmatched-pattern"
|
|
43
62
|
},
|
|
44
|
-
"jest": {
|
|
45
|
-
"testMatch": [
|
|
46
|
-
"**/*.test.ts"
|
|
47
|
-
],
|
|
48
|
-
"preset": "ts-jest/presets/default-esm",
|
|
49
|
-
"globals": {
|
|
50
|
-
"ts-jest": {
|
|
51
|
-
"useESM": true
|
|
52
|
-
}
|
|
53
|
-
},
|
|
54
|
-
"moduleNameMapper": {
|
|
55
|
-
"^(\\.{1,2}/.*)\\.js$": "$1"
|
|
56
|
-
},
|
|
57
|
-
"maxConcurrency": 50
|
|
58
|
-
},
|
|
59
|
-
"xo": {
|
|
60
|
-
"extends": "@onmoon",
|
|
61
|
-
"prettier": true
|
|
62
|
-
},
|
|
63
|
-
"prettier": "@onmoon/prettier-config",
|
|
64
63
|
"devDependencies": {
|
|
65
|
-
"@
|
|
66
|
-
"@
|
|
67
|
-
"@
|
|
68
|
-
"
|
|
69
|
-
"
|
|
70
|
-
"
|
|
71
|
-
"
|
|
72
|
-
"
|
|
73
|
-
"
|
|
74
|
-
"
|
|
75
|
-
"
|
|
76
|
-
"lint-staged": "^13.2.3",
|
|
77
|
-
"ts-jest": "^29.1.1",
|
|
78
|
-
"typescript": "^5.1.6",
|
|
79
|
-
"uuid": "^9.0.0",
|
|
80
|
-
"xo": "^0.54.2"
|
|
81
|
-
},
|
|
82
|
-
"dependencies": {
|
|
83
|
-
"got": "^12.6.1"
|
|
64
|
+
"@types/body-parser": "^1.19.6",
|
|
65
|
+
"@types/express": "^5.0.6",
|
|
66
|
+
"@types/node": "^22.20.5",
|
|
67
|
+
"body-parser": "^2.4.0",
|
|
68
|
+
"express": "^5.3.0",
|
|
69
|
+
"husky": "^9.1.7",
|
|
70
|
+
"lint-staged": "^17.6.0",
|
|
71
|
+
"oxfmt": "^0.74.0",
|
|
72
|
+
"oxlint": "^1.89.0",
|
|
73
|
+
"oxlint-tsgolint": "^7.0.2005",
|
|
74
|
+
"typescript": "^7.0.2"
|
|
84
75
|
}
|
|
85
|
-
}
|
|
76
|
+
}
|
package/utils.js
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import { URL } from 'node:url';
|
|
2
|
-
import crypto from 'node:crypto';
|
|
3
|
-
import fs from 'node:fs';
|
|
4
|
-
const publicCert = fs
|
|
5
|
-
.readFileSync(new URL('certs/gm.crt', import.meta.url))
|
|
6
|
-
.toString();
|
|
7
|
-
export function parametersToString(body) {
|
|
8
|
-
let parametersString = '';
|
|
9
|
-
const keys = Object.keys(body).sort();
|
|
10
|
-
if (Array.isArray(body)) {
|
|
11
|
-
keys.sort((a, b) => Number(a) - Number(b));
|
|
12
|
-
}
|
|
13
|
-
for (const key of keys) {
|
|
14
|
-
let value = body[key];
|
|
15
|
-
if (key === 'signature') {
|
|
16
|
-
continue;
|
|
17
|
-
}
|
|
18
|
-
if (value === null || value === undefined) {
|
|
19
|
-
value = '';
|
|
20
|
-
}
|
|
21
|
-
if (typeof value === 'object' && value !== null) {
|
|
22
|
-
value = parametersToString(value);
|
|
23
|
-
}
|
|
24
|
-
parametersString += `${key}:${value};`;
|
|
25
|
-
}
|
|
26
|
-
return parametersString;
|
|
27
|
-
}
|
|
28
|
-
export function verifyRsaSignature(body) {
|
|
29
|
-
return crypto
|
|
30
|
-
.createVerify('RSA-SHA256')
|
|
31
|
-
.update(parametersToString(body), 'utf8')
|
|
32
|
-
.verify(publicCert, body.signature, 'base64');
|
|
33
|
-
}
|
|
34
|
-
export function generateRsaSignature(body, key) {
|
|
35
|
-
return crypto
|
|
36
|
-
.createSign('RSA-SHA256')
|
|
37
|
-
.update(parametersToString(body), 'utf8')
|
|
38
|
-
.sign(key, 'base64');
|
|
39
|
-
}
|
|
40
|
-
export function generateHmacSignature(body, key) {
|
|
41
|
-
return crypto
|
|
42
|
-
.createHmac('sha256', key)
|
|
43
|
-
.update(parametersToString(body), 'utf8')
|
|
44
|
-
.digest('hex');
|
|
45
|
-
}
|
|
46
|
-
export function getRandomString(length) {
|
|
47
|
-
return crypto
|
|
48
|
-
.randomBytes(Math.ceil(length / 2))
|
|
49
|
-
.toString('hex')
|
|
50
|
-
.slice(0, length);
|
|
51
|
-
}
|