@tma.js/init-data-node 1.4.0 → 2.0.1
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 +1 -1
- package/README.md +9 -9
- package/dist/buf-converters.d.ts +13 -0
- package/dist/entries/node.cjs +80 -8
- package/dist/entries/node.cjs.map +1 -1
- package/dist/entries/node.d.ts +26 -12
- package/dist/entries/node.js +62 -10
- package/dist/entries/node.js.map +1 -1
- package/dist/entries/parsing-Cj_BXCnv.cjs +258 -0
- package/dist/entries/parsing-Cj_BXCnv.cjs.map +1 -0
- package/dist/entries/parsing-eczkSd-W.js +241 -0
- package/dist/entries/parsing-eczkSd-W.js.map +1 -0
- package/dist/entries/shared.d.ts +6 -4
- package/dist/entries/web.cjs +117 -21
- package/dist/entries/web.cjs.map +1 -1
- package/dist/entries/web.d.ts +33 -14
- package/dist/entries/web.js +97 -22
- package/dist/entries/web.js.map +1 -1
- package/dist/errors.d.ts +21 -0
- package/dist/hashToken.d.ts +2 -3
- package/dist/parsing.d.ts +58 -0
- package/dist/signDataFp.d.ts +13 -0
- package/dist/signFp.d.ts +35 -0
- package/dist/types.d.ts +2 -19
- package/dist/validation.d.ts +67 -0
- package/package.json +15 -9
- package/dist/entries/index-B-IiSE5b.js +0 -342
- package/dist/entries/index-B-IiSE5b.js.map +0 -1
- package/dist/entries/index-DQxFLF1J.cjs +0 -341
- package/dist/entries/index-DQxFLF1J.cjs.map +0 -1
- package/dist/initDataToSearchParams.d.ts +0 -3
- package/dist/sign.d.ts +0 -23
- package/dist/signData.d.ts +0 -21
- package/dist/validate.d.ts +0 -39
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -4,20 +4,20 @@
|
|
|
4
4
|
|
|
5
5
|
[docs-badge]: https://img.shields.io/badge/documentation-blue?logo=gitbook&logoColor=white
|
|
6
6
|
|
|
7
|
-
[
|
|
7
|
+
[code-link]: https://github.com/Telegram-Mini-Apps/telegram-apps/tree/master/tma.js/init-data-node
|
|
8
8
|
|
|
9
|
-
[
|
|
9
|
+
[docs-link]: https://docs.telegram-mini-apps.com/packages/tma-js-init-data-node
|
|
10
10
|
|
|
11
|
-
[
|
|
11
|
+
[npm-link]: https://npmjs.com/package/@tma.js/init-data-node
|
|
12
12
|
|
|
13
|
-
[
|
|
13
|
+
[npm-badge]: https://img.shields.io/npm/v/@tma.js/init-data-node?logo=npm
|
|
14
14
|
|
|
15
|
-
[
|
|
15
|
+
[size-badge]: https://img.shields.io/bundlephobia/minzip/@tma.js/init-data-node
|
|
16
16
|
|
|
17
|
-
[![NPM][
|
|
18
|
-
![Size][
|
|
19
|
-
[![docs-badge]][
|
|
20
|
-
[![code-badge]][
|
|
17
|
+
[![NPM][npm-badge]][npm-link]
|
|
18
|
+
![Size][size-badge]
|
|
19
|
+
[![docs-badge]][docs-link]
|
|
20
|
+
[![code-badge]][code-link]
|
|
21
21
|
|
|
22
22
|
The package provides utilities to work with the initialization data of Telegram Mini Apps on the
|
|
23
23
|
server side. To learn more about the initialization data and its usage, please refer to
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { HexStringLengthInvalidError } from './errors.js';
|
|
2
|
+
import * as E from 'fp-ts/Either';
|
|
3
|
+
/**
|
|
4
|
+
* Converts a hex string to ArrayBuffer.
|
|
5
|
+
* @param hexString - value to convert.
|
|
6
|
+
*/
|
|
7
|
+
export declare function hexToArrayBuffer(hexString: string): E.Either<InstanceType<typeof HexStringLengthInvalidError>, ArrayBuffer>;
|
|
8
|
+
/**
|
|
9
|
+
* Converts array buffer to hex.
|
|
10
|
+
* @param arrBuf - buffer to convert
|
|
11
|
+
*/
|
|
12
|
+
export declare function arrayBufferToHex(arrBuf: ArrayBuffer): string;
|
|
13
|
+
export declare function bufferToArrayBuffer(buf: Buffer): ArrayBuffer;
|
package/dist/entries/node.cjs
CHANGED
|
@@ -1,26 +1,98 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const E = require("fp-ts/Either");
|
|
4
|
+
const function_js = require("fp-ts/lib/function.js");
|
|
3
5
|
const node_crypto = require("node:crypto");
|
|
4
|
-
const
|
|
6
|
+
const parsing = require("./parsing-Cj_BXCnv.cjs");
|
|
7
|
+
const toolkit = require("@tma.js/toolkit");
|
|
8
|
+
function _interopNamespaceDefault(e) {
|
|
9
|
+
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
|
|
10
|
+
if (e) {
|
|
11
|
+
for (const k in e) {
|
|
12
|
+
if (k !== "default") {
|
|
13
|
+
const d = Object.getOwnPropertyDescriptor(e, k);
|
|
14
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
15
|
+
enumerable: true,
|
|
16
|
+
get: () => e[k]
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
n.default = e;
|
|
22
|
+
return Object.freeze(n);
|
|
23
|
+
}
|
|
24
|
+
const E__namespace = /* @__PURE__ */ _interopNamespaceDefault(E);
|
|
25
|
+
function textToBuffer(text) {
|
|
26
|
+
return Buffer.from(typeof text === "string" ? text : new Uint8Array(text));
|
|
27
|
+
}
|
|
5
28
|
const createHmac = (data, key) => {
|
|
6
|
-
return
|
|
29
|
+
return parsing.bufferToArrayBuffer(
|
|
30
|
+
node_crypto.createHmac("sha256", textToBuffer(key)).update(textToBuffer(data)).digest()
|
|
31
|
+
);
|
|
7
32
|
};
|
|
8
33
|
function hashToken(token) {
|
|
9
|
-
return
|
|
34
|
+
return Buffer.from(parsing.hashToken(token, createHmac));
|
|
35
|
+
}
|
|
36
|
+
function isValid(value, token, options) {
|
|
37
|
+
return function_js.pipe(
|
|
38
|
+
validateFp(value, token, options),
|
|
39
|
+
E__namespace.match(() => false, () => true)
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
function signFp(data, key, authDate, options) {
|
|
43
|
+
return parsing.signFp(data, key, authDate, signDataFp, options);
|
|
10
44
|
}
|
|
11
45
|
function sign(data, key, authDate, options) {
|
|
12
|
-
return
|
|
46
|
+
return function_js.pipe(
|
|
47
|
+
signFp(data, key, authDate, options),
|
|
48
|
+
E__namespace.match((e) => {
|
|
49
|
+
throw e;
|
|
50
|
+
}, (v) => v)
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
function signDataFp(data, key, options) {
|
|
54
|
+
return parsing.signDataFp(false, data, key, createHmac, options);
|
|
13
55
|
}
|
|
14
56
|
function signData(data, key, options) {
|
|
15
|
-
return
|
|
57
|
+
return function_js.pipe(
|
|
58
|
+
signDataFp(data, key, options),
|
|
59
|
+
E__namespace.match((e) => {
|
|
60
|
+
throw e;
|
|
61
|
+
}, (v) => v)
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
function validateFp(value, token, options) {
|
|
65
|
+
return parsing.validateFp(false, value, token, signDataFp, options);
|
|
16
66
|
}
|
|
17
67
|
function validate(value, token, options) {
|
|
18
|
-
|
|
68
|
+
function_js.pipe(
|
|
69
|
+
validateFp(value, token, options),
|
|
70
|
+
E__namespace.mapLeft((error) => {
|
|
71
|
+
throw error;
|
|
72
|
+
})
|
|
73
|
+
);
|
|
19
74
|
}
|
|
20
|
-
exports.
|
|
21
|
-
exports.
|
|
75
|
+
exports.AuthDateInvalidError = parsing.AuthDateInvalidError;
|
|
76
|
+
exports.ExpiredError = parsing.ExpiredError;
|
|
77
|
+
exports.HexStringLengthInvalidError = parsing.HexStringLengthInvalidError;
|
|
78
|
+
exports.SignatureInvalidError = parsing.SignatureInvalidError;
|
|
79
|
+
exports.SignatureMissingError = parsing.SignatureMissingError;
|
|
80
|
+
exports.isValid3rd = parsing.isValid3rd;
|
|
81
|
+
exports.isValid3rdFp = parsing.isValid3rdFp;
|
|
82
|
+
exports.parse = parsing.parse;
|
|
83
|
+
exports.parseFp = parsing.parseFp;
|
|
84
|
+
exports.validate3rd = parsing.validate3rd;
|
|
85
|
+
exports.validate3rdFp = parsing.validate3rdFp;
|
|
86
|
+
Object.defineProperty(exports, "deepSnakeToCamelObjKeys", {
|
|
87
|
+
enumerable: true,
|
|
88
|
+
get: () => toolkit.deepSnakeToCamelObjKeys
|
|
89
|
+
});
|
|
22
90
|
exports.hashToken = hashToken;
|
|
91
|
+
exports.isValid = isValid;
|
|
23
92
|
exports.sign = sign;
|
|
24
93
|
exports.signData = signData;
|
|
94
|
+
exports.signDataFp = signDataFp;
|
|
95
|
+
exports.signFp = signFp;
|
|
25
96
|
exports.validate = validate;
|
|
97
|
+
exports.validateFp = validateFp;
|
|
26
98
|
//# sourceMappingURL=node.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node.cjs","sources":["../../src/entries/node.ts"],"sourcesContent":["import { createHmac as nodeCreateHmac } from 'node:crypto';\nimport {
|
|
1
|
+
{"version":3,"file":"node.cjs","sources":["../../src/entries/node.ts"],"sourcesContent":["import * as E from 'fp-ts/Either';\nimport { pipe } from 'fp-ts/lib/function.js';\nimport { createHmac as nodeCreateHmac } from 'node:crypto';\n\nimport { bufferToArrayBuffer } from '../buf-converters.js';\nimport { hashToken as _hashToken } from '../hashToken.js';\nimport { signDataFp as _signDataFp, SignDataError, type SignDataOptions } from '../signDataFp.js';\nimport {\n signFp as _signFp,\n type SignableData,\n type SignOptions,\n} from '../signFp.js';\nimport type { CreateHmacFn, Text } from '../types.js';\nimport {\n validateFp as _validateFp,\n type ValidateError,\n type ValidateOptions,\n type ValidateValue,\n} from '../validation.js';\n\n/**\n * Converts Text to Node.js Buffer.\n * @param text - text to convert\n */\nfunction textToBuffer(text: Text): Buffer {\n return Buffer.from(typeof text === 'string' ? text : new Uint8Array(text));\n}\n\nconst createHmac: CreateHmacFn<false> = (data, key) => {\n return bufferToArrayBuffer(\n nodeCreateHmac('sha256', textToBuffer(key))\n .update(textToBuffer(data))\n .digest(),\n );\n};\n\n/**\n * Hashes specified token using a string, expected during init data sign.\n * @param token - token to hash.\n */\nexport function hashToken(token: Text): Buffer {\n return Buffer.from(_hashToken(token, createHmac));\n}\n\n/**\n * @param value - value to check.\n * @param token - bot secret token.\n * @param options - additional validation options.\n * @returns True is specified init data is valid.\n */\nexport function isValid(value: ValidateValue, token: Text, options?: ValidateOptions): boolean {\n return pipe(\n validateFp(value, token, options),\n E.match(() => false, () => true),\n );\n}\n\n/**\n * Signs specified init data.\n * @param data - init data to sign.\n * @param authDate - date, when this init data should be signed.\n * @param key - private key.\n * @param options - additional options.\n * @returns Signed init data presented as query parameters.\n */\nexport function signFp(\n data: SignableData,\n key: Text,\n authDate: Date,\n options?: SignOptions,\n): E.Either<SignDataError, string> {\n return _signFp(data, key, authDate, signDataFp, options);\n}\n\n/**\n * @see signFp\n */\nexport function sign(data: SignableData, key: Text, authDate: Date, options?: SignOptions): string {\n return pipe(\n signFp(data, key, authDate, options),\n E.match(e => {\n throw e;\n }, v => v),\n );\n}\n\n/**\n * Signs specified data with the passed token.\n * @param data - data to sign.\n * @param key - private key.\n * @param options - additional options.\n * @returns Data sign.\n */\nexport function signDataFp(\n data: Text,\n key: Text,\n options?: SignDataOptions,\n): E.Either<SignDataError, string> {\n return _signDataFp(false, data, key, createHmac, options);\n}\n\n/**\n * @see signDataFp\n */\nexport function signData(data: Text, key: Text, options?: SignDataOptions): string {\n return pipe(\n signDataFp(data, key, options),\n E.match(e => {\n throw e;\n }, v => v),\n );\n}\n\n/**\n * Validates passed init data.\n * @param value - value to check.\n * @param token - bot secret token.\n * @param options - additional validation options.\n */\nexport function validateFp(\n value: ValidateValue,\n token: Text,\n options?: ValidateOptions,\n): E.Either<ValidateError, void> {\n return _validateFp(false, value, token, signDataFp, options);\n}\n\n/**\n * @see validateFp\n */\nexport function validate(value: ValidateValue, token: Text, options?: ValidateOptions): void {\n pipe(\n validateFp(value, token, options),\n E.mapLeft(error => {\n throw error;\n }),\n );\n}\n\nexport * from './shared.js';\n"],"names":["bufferToArrayBuffer","nodeCreateHmac","_hashToken","pipe","E","_signFp","_signDataFp","_validateFp"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAwBA,SAAS,aAAa,MAAoB;AACjC,SAAA,OAAO,KAAK,OAAO,SAAS,WAAW,OAAO,IAAI,WAAW,IAAI,CAAC;AAC3E;AAEA,MAAM,aAAkC,CAAC,MAAM,QAAQ;AAC9C,SAAAA,QAAA;AAAA,IACLC,uBAAe,UAAU,aAAa,GAAG,CAAC,EACvC,OAAO,aAAa,IAAI,CAAC,EACzB,OAAO;AAAA,EACZ;AACF;AAMO,SAAS,UAAU,OAAqB;AAC7C,SAAO,OAAO,KAAKC,QAAW,UAAA,OAAO,UAAU,CAAC;AAClD;AAQgB,SAAA,QAAQ,OAAsB,OAAa,SAAoC;AACtF,SAAAC,YAAA;AAAA,IACL,WAAW,OAAO,OAAO,OAAO;AAAA,IAChCC,aAAE,MAAM,MAAM,OAAO,MAAM,IAAI;AAAA,EACjC;AACF;AAUO,SAAS,OACd,MACA,KACA,UACA,SACiC;AACjC,SAAOC,QAAAA,OAAQ,MAAM,KAAK,UAAU,YAAY,OAAO;AACzD;AAKO,SAAS,KAAK,MAAoB,KAAW,UAAgB,SAA+B;AAC1F,SAAAF,YAAA;AAAA,IACL,OAAO,MAAM,KAAK,UAAU,OAAO;AAAA,IACnCC,aAAE,MAAM,CAAK,MAAA;AACL,YAAA;AAAA,IAAA,GACL,OAAK,CAAC;AAAA,EACX;AACF;AASgB,SAAA,WACd,MACA,KACA,SACiC;AACjC,SAAOE,QAAAA,WAAY,OAAO,MAAM,KAAK,YAAY,OAAO;AAC1D;AAKgB,SAAA,SAAS,MAAY,KAAW,SAAmC;AAC1E,SAAAH,YAAA;AAAA,IACL,WAAW,MAAM,KAAK,OAAO;AAAA,IAC7BC,aAAE,MAAM,CAAK,MAAA;AACL,YAAA;AAAA,IAAA,GACL,OAAK,CAAC;AAAA,EACX;AACF;AAQgB,SAAA,WACd,OACA,OACA,SAC+B;AAC/B,SAAOG,QAAAA,WAAY,OAAO,OAAO,OAAO,YAAY,OAAO;AAC7D;AAKgB,SAAA,SAAS,OAAsB,OAAa,SAAiC;AAC3FJ,cAAA;AAAA,IACE,WAAW,OAAO,OAAO,OAAO;AAAA,IAChCC,aAAE,QAAQ,CAAS,UAAA;AACX,YAAA;AAAA,IACP,CAAA;AAAA,EACH;AACF;;;;;;;;;;;;;;;;;;;;;;;;"}
|
package/dist/entries/node.d.ts
CHANGED
|
@@ -1,14 +1,20 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { SignOptions } from '../
|
|
3
|
-
import {
|
|
4
|
-
import { ValidateOptions } from '../
|
|
5
|
-
import
|
|
6
|
-
|
|
1
|
+
import { SignDataError, SignDataOptions } from '../signDataFp.js';
|
|
2
|
+
import { SignableData, SignOptions } from '../signFp.js';
|
|
3
|
+
import { Text } from '../types.js';
|
|
4
|
+
import { ValidateError, ValidateOptions, ValidateValue } from '../validation.js';
|
|
5
|
+
import * as E from 'fp-ts/Either';
|
|
7
6
|
/**
|
|
8
7
|
* Hashes specified token using a string, expected during init data sign.
|
|
9
8
|
* @param token - token to hash.
|
|
10
9
|
*/
|
|
11
10
|
export declare function hashToken(token: Text): Buffer;
|
|
11
|
+
/**
|
|
12
|
+
* @param value - value to check.
|
|
13
|
+
* @param token - bot secret token.
|
|
14
|
+
* @param options - additional validation options.
|
|
15
|
+
* @returns True is specified init data is valid.
|
|
16
|
+
*/
|
|
17
|
+
export declare function isValid(value: ValidateValue, token: Text, options?: ValidateOptions): boolean;
|
|
12
18
|
/**
|
|
13
19
|
* Signs specified init data.
|
|
14
20
|
* @param data - init data to sign.
|
|
@@ -17,7 +23,11 @@ export declare function hashToken(token: Text): Buffer;
|
|
|
17
23
|
* @param options - additional options.
|
|
18
24
|
* @returns Signed init data presented as query parameters.
|
|
19
25
|
*/
|
|
20
|
-
export declare function
|
|
26
|
+
export declare function signFp(data: SignableData, key: Text, authDate: Date, options?: SignOptions): E.Either<SignDataError, string>;
|
|
27
|
+
/**
|
|
28
|
+
* @see signFp
|
|
29
|
+
*/
|
|
30
|
+
export declare function sign(data: SignableData, key: Text, authDate: Date, options?: SignOptions): string;
|
|
21
31
|
/**
|
|
22
32
|
* Signs specified data with the passed token.
|
|
23
33
|
* @param data - data to sign.
|
|
@@ -25,16 +35,20 @@ export declare function sign(data: SignData, key: Text, authDate: Date, options?
|
|
|
25
35
|
* @param options - additional options.
|
|
26
36
|
* @returns Data sign.
|
|
27
37
|
*/
|
|
38
|
+
export declare function signDataFp(data: Text, key: Text, options?: SignDataOptions): E.Either<SignDataError, string>;
|
|
39
|
+
/**
|
|
40
|
+
* @see signDataFp
|
|
41
|
+
*/
|
|
28
42
|
export declare function signData(data: Text, key: Text, options?: SignDataOptions): string;
|
|
29
43
|
/**
|
|
30
44
|
* Validates passed init data.
|
|
31
45
|
* @param value - value to check.
|
|
32
46
|
* @param token - bot secret token.
|
|
33
47
|
* @param options - additional validation options.
|
|
34
|
-
* @throws {TypeError} "auth_date" should present integer
|
|
35
|
-
* @throws {Error} "hash" is empty or not found
|
|
36
|
-
* @throws {Error} "auth_date" is empty or not found
|
|
37
|
-
* @throws {Error} Init data expired
|
|
38
48
|
*/
|
|
39
|
-
export declare function
|
|
49
|
+
export declare function validateFp(value: ValidateValue, token: Text, options?: ValidateOptions): E.Either<ValidateError, void>;
|
|
50
|
+
/**
|
|
51
|
+
* @see validateFp
|
|
52
|
+
*/
|
|
53
|
+
export declare function validate(value: ValidateValue, token: Text, options?: ValidateOptions): void;
|
|
40
54
|
export * from './shared.js';
|
package/dist/entries/node.js
CHANGED
|
@@ -1,27 +1,79 @@
|
|
|
1
|
+
import * as E from "fp-ts/Either";
|
|
2
|
+
import { pipe } from "fp-ts/lib/function.js";
|
|
1
3
|
import { createHmac as createHmac$1 } from "node:crypto";
|
|
2
|
-
import { h as hashToken$1, s as
|
|
3
|
-
import {
|
|
4
|
+
import { h as hashToken$1, s as signFp$1, a as signDataFp$1, v as validateFp$1, b as bufferToArrayBuffer } from "./parsing-eczkSd-W.js";
|
|
5
|
+
import { A, E as E2, H, S, c, i, e, p, d, f, g } from "./parsing-eczkSd-W.js";
|
|
6
|
+
import { deepSnakeToCamelObjKeys } from "@tma.js/toolkit";
|
|
7
|
+
function textToBuffer(text) {
|
|
8
|
+
return Buffer.from(typeof text === "string" ? text : new Uint8Array(text));
|
|
9
|
+
}
|
|
4
10
|
const createHmac = (data, key) => {
|
|
5
|
-
return
|
|
11
|
+
return bufferToArrayBuffer(
|
|
12
|
+
createHmac$1("sha256", textToBuffer(key)).update(textToBuffer(data)).digest()
|
|
13
|
+
);
|
|
6
14
|
};
|
|
7
15
|
function hashToken(token) {
|
|
8
|
-
return hashToken$1(token, createHmac);
|
|
16
|
+
return Buffer.from(hashToken$1(token, createHmac));
|
|
17
|
+
}
|
|
18
|
+
function isValid(value, token, options) {
|
|
19
|
+
return pipe(
|
|
20
|
+
validateFp(value, token, options),
|
|
21
|
+
E.match(() => false, () => true)
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
function signFp(data, key, authDate, options) {
|
|
25
|
+
return signFp$1(data, key, authDate, signDataFp, options);
|
|
9
26
|
}
|
|
10
27
|
function sign(data, key, authDate, options) {
|
|
11
|
-
return
|
|
28
|
+
return pipe(
|
|
29
|
+
signFp(data, key, authDate, options),
|
|
30
|
+
E.match((e2) => {
|
|
31
|
+
throw e2;
|
|
32
|
+
}, (v) => v)
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
function signDataFp(data, key, options) {
|
|
36
|
+
return signDataFp$1(false, data, key, createHmac, options);
|
|
12
37
|
}
|
|
13
38
|
function signData(data, key, options) {
|
|
14
|
-
return
|
|
39
|
+
return pipe(
|
|
40
|
+
signDataFp(data, key, options),
|
|
41
|
+
E.match((e2) => {
|
|
42
|
+
throw e2;
|
|
43
|
+
}, (v) => v)
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
function validateFp(value, token, options) {
|
|
47
|
+
return validateFp$1(false, value, token, signDataFp, options);
|
|
15
48
|
}
|
|
16
49
|
function validate(value, token, options) {
|
|
17
|
-
|
|
50
|
+
pipe(
|
|
51
|
+
validateFp(value, token, options),
|
|
52
|
+
E.mapLeft((error) => {
|
|
53
|
+
throw error;
|
|
54
|
+
})
|
|
55
|
+
);
|
|
18
56
|
}
|
|
19
57
|
export {
|
|
58
|
+
A as AuthDateInvalidError,
|
|
59
|
+
E2 as ExpiredError,
|
|
60
|
+
H as HexStringLengthInvalidError,
|
|
61
|
+
S as SignatureInvalidError,
|
|
62
|
+
c as SignatureMissingError,
|
|
63
|
+
deepSnakeToCamelObjKeys,
|
|
20
64
|
hashToken,
|
|
21
|
-
|
|
22
|
-
|
|
65
|
+
isValid,
|
|
66
|
+
i as isValid3rd,
|
|
67
|
+
e as isValid3rdFp,
|
|
68
|
+
p as parse,
|
|
69
|
+
d as parseFp,
|
|
23
70
|
sign,
|
|
24
71
|
signData,
|
|
25
|
-
|
|
72
|
+
signDataFp,
|
|
73
|
+
signFp,
|
|
74
|
+
validate,
|
|
75
|
+
f as validate3rd,
|
|
76
|
+
g as validate3rdFp,
|
|
77
|
+
validateFp
|
|
26
78
|
};
|
|
27
79
|
//# sourceMappingURL=node.js.map
|
package/dist/entries/node.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node.js","sources":["../../src/entries/node.ts"],"sourcesContent":["import { createHmac as nodeCreateHmac } from 'node:crypto';\nimport {
|
|
1
|
+
{"version":3,"file":"node.js","sources":["../../src/entries/node.ts"],"sourcesContent":["import * as E from 'fp-ts/Either';\nimport { pipe } from 'fp-ts/lib/function.js';\nimport { createHmac as nodeCreateHmac } from 'node:crypto';\n\nimport { bufferToArrayBuffer } from '../buf-converters.js';\nimport { hashToken as _hashToken } from '../hashToken.js';\nimport { signDataFp as _signDataFp, SignDataError, type SignDataOptions } from '../signDataFp.js';\nimport {\n signFp as _signFp,\n type SignableData,\n type SignOptions,\n} from '../signFp.js';\nimport type { CreateHmacFn, Text } from '../types.js';\nimport {\n validateFp as _validateFp,\n type ValidateError,\n type ValidateOptions,\n type ValidateValue,\n} from '../validation.js';\n\n/**\n * Converts Text to Node.js Buffer.\n * @param text - text to convert\n */\nfunction textToBuffer(text: Text): Buffer {\n return Buffer.from(typeof text === 'string' ? text : new Uint8Array(text));\n}\n\nconst createHmac: CreateHmacFn<false> = (data, key) => {\n return bufferToArrayBuffer(\n nodeCreateHmac('sha256', textToBuffer(key))\n .update(textToBuffer(data))\n .digest(),\n );\n};\n\n/**\n * Hashes specified token using a string, expected during init data sign.\n * @param token - token to hash.\n */\nexport function hashToken(token: Text): Buffer {\n return Buffer.from(_hashToken(token, createHmac));\n}\n\n/**\n * @param value - value to check.\n * @param token - bot secret token.\n * @param options - additional validation options.\n * @returns True is specified init data is valid.\n */\nexport function isValid(value: ValidateValue, token: Text, options?: ValidateOptions): boolean {\n return pipe(\n validateFp(value, token, options),\n E.match(() => false, () => true),\n );\n}\n\n/**\n * Signs specified init data.\n * @param data - init data to sign.\n * @param authDate - date, when this init data should be signed.\n * @param key - private key.\n * @param options - additional options.\n * @returns Signed init data presented as query parameters.\n */\nexport function signFp(\n data: SignableData,\n key: Text,\n authDate: Date,\n options?: SignOptions,\n): E.Either<SignDataError, string> {\n return _signFp(data, key, authDate, signDataFp, options);\n}\n\n/**\n * @see signFp\n */\nexport function sign(data: SignableData, key: Text, authDate: Date, options?: SignOptions): string {\n return pipe(\n signFp(data, key, authDate, options),\n E.match(e => {\n throw e;\n }, v => v),\n );\n}\n\n/**\n * Signs specified data with the passed token.\n * @param data - data to sign.\n * @param key - private key.\n * @param options - additional options.\n * @returns Data sign.\n */\nexport function signDataFp(\n data: Text,\n key: Text,\n options?: SignDataOptions,\n): E.Either<SignDataError, string> {\n return _signDataFp(false, data, key, createHmac, options);\n}\n\n/**\n * @see signDataFp\n */\nexport function signData(data: Text, key: Text, options?: SignDataOptions): string {\n return pipe(\n signDataFp(data, key, options),\n E.match(e => {\n throw e;\n }, v => v),\n );\n}\n\n/**\n * Validates passed init data.\n * @param value - value to check.\n * @param token - bot secret token.\n * @param options - additional validation options.\n */\nexport function validateFp(\n value: ValidateValue,\n token: Text,\n options?: ValidateOptions,\n): E.Either<ValidateError, void> {\n return _validateFp(false, value, token, signDataFp, options);\n}\n\n/**\n * @see validateFp\n */\nexport function validate(value: ValidateValue, token: Text, options?: ValidateOptions): void {\n pipe(\n validateFp(value, token, options),\n E.mapLeft(error => {\n throw error;\n }),\n );\n}\n\nexport * from './shared.js';\n"],"names":["nodeCreateHmac","_hashToken","_signFp","e","_signDataFp","_validateFp"],"mappings":";;;;;;AAwBA,SAAS,aAAa,MAAoB;AACjC,SAAA,OAAO,KAAK,OAAO,SAAS,WAAW,OAAO,IAAI,WAAW,IAAI,CAAC;AAC3E;AAEA,MAAM,aAAkC,CAAC,MAAM,QAAQ;AAC9C,SAAA;AAAA,IACLA,aAAe,UAAU,aAAa,GAAG,CAAC,EACvC,OAAO,aAAa,IAAI,CAAC,EACzB,OAAO;AAAA,EACZ;AACF;AAMO,SAAS,UAAU,OAAqB;AAC7C,SAAO,OAAO,KAAKC,YAAW,OAAO,UAAU,CAAC;AAClD;AAQgB,SAAA,QAAQ,OAAsB,OAAa,SAAoC;AACtF,SAAA;AAAA,IACL,WAAW,OAAO,OAAO,OAAO;AAAA,IAChC,EAAE,MAAM,MAAM,OAAO,MAAM,IAAI;AAAA,EACjC;AACF;AAUO,SAAS,OACd,MACA,KACA,UACA,SACiC;AACjC,SAAOC,SAAQ,MAAM,KAAK,UAAU,YAAY,OAAO;AACzD;AAKO,SAAS,KAAK,MAAoB,KAAW,UAAgB,SAA+B;AAC1F,SAAA;AAAA,IACL,OAAO,MAAM,KAAK,UAAU,OAAO;AAAA,IACnC,EAAE,MAAM,CAAKC,OAAA;AACL,YAAAA;AAAA,IAAA,GACL,OAAK,CAAC;AAAA,EACX;AACF;AASgB,SAAA,WACd,MACA,KACA,SACiC;AACjC,SAAOC,aAAY,OAAO,MAAM,KAAK,YAAY,OAAO;AAC1D;AAKgB,SAAA,SAAS,MAAY,KAAW,SAAmC;AAC1E,SAAA;AAAA,IACL,WAAW,MAAM,KAAK,OAAO;AAAA,IAC7B,EAAE,MAAM,CAAKD,OAAA;AACL,YAAAA;AAAA,IAAA,GACL,OAAK,CAAC;AAAA,EACX;AACF;AAQgB,SAAA,WACd,OACA,OACA,SAC+B;AAC/B,SAAOE,aAAY,OAAO,OAAO,OAAO,YAAY,OAAO;AAC7D;AAKgB,SAAA,SAAS,OAAsB,OAAa,SAAiC;AAC3F;AAAA,IACE,WAAW,OAAO,OAAO,OAAO;AAAA,IAChC,EAAE,QAAQ,CAAS,UAAA;AACX,YAAA;AAAA,IACP,CAAA;AAAA,EACH;AACF;"}
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const E = require("fp-ts/Either");
|
|
3
|
+
const TE = require("fp-ts/TaskEither");
|
|
4
|
+
const function_js = require("fp-ts/lib/function.js");
|
|
5
|
+
const transformers = require("@tma.js/transformers");
|
|
6
|
+
const _function = require("fp-ts/function");
|
|
7
|
+
const betterPromises = require("better-promises");
|
|
8
|
+
const errorKid = require("error-kid");
|
|
9
|
+
function _interopNamespaceDefault(e) {
|
|
10
|
+
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
|
|
11
|
+
if (e) {
|
|
12
|
+
for (const k in e) {
|
|
13
|
+
if (k !== "default") {
|
|
14
|
+
const d = Object.getOwnPropertyDescriptor(e, k);
|
|
15
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
16
|
+
enumerable: true,
|
|
17
|
+
get: () => e[k]
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
n.default = e;
|
|
23
|
+
return Object.freeze(n);
|
|
24
|
+
}
|
|
25
|
+
const E__namespace = /* @__PURE__ */ _interopNamespaceDefault(E);
|
|
26
|
+
const TE__namespace = /* @__PURE__ */ _interopNamespaceDefault(TE);
|
|
27
|
+
class AuthDateInvalidError extends errorKid.errorClassWithData(
|
|
28
|
+
"AuthDateInvalidError",
|
|
29
|
+
(value) => ({ value }),
|
|
30
|
+
(value) => [`"auth_date" is invalid: ${value || "value is missing"}`]
|
|
31
|
+
) {
|
|
32
|
+
}
|
|
33
|
+
class SignatureInvalidError extends errorKid.errorClass("SignatureInvalidError") {
|
|
34
|
+
}
|
|
35
|
+
class HexStringLengthInvalidError extends errorKid.errorClass(
|
|
36
|
+
"HexStringLengthInvalidError"
|
|
37
|
+
) {
|
|
38
|
+
}
|
|
39
|
+
class SignatureMissingError extends errorKid.errorClass(
|
|
40
|
+
"SignatureMissingError",
|
|
41
|
+
(thirdParty) => [`"${thirdParty ? "signature" : "hash"}" parameter is missing`]
|
|
42
|
+
) {
|
|
43
|
+
}
|
|
44
|
+
class ExpiredError extends errorKid.errorClassWithData(
|
|
45
|
+
"ExpiredError",
|
|
46
|
+
(issuedAt, expiresAt) => ({ issuedAt, expiresAt }),
|
|
47
|
+
(issuedAt, expiresAt, now) => [
|
|
48
|
+
`Init data expired. Issued at ${issuedAt.toISOString()}, expires at ${expiresAt.toISOString()}, now is ${now.toISOString()}`
|
|
49
|
+
]
|
|
50
|
+
) {
|
|
51
|
+
}
|
|
52
|
+
function hexToArrayBuffer(hexString) {
|
|
53
|
+
if (hexString.length % 2 !== 0) {
|
|
54
|
+
return E__namespace.left(new HexStringLengthInvalidError());
|
|
55
|
+
}
|
|
56
|
+
const buffer = new ArrayBuffer(hexString.length / 2);
|
|
57
|
+
const uint8Array = new Uint8Array(buffer);
|
|
58
|
+
for (let i = 0; i < hexString.length; i += 2) {
|
|
59
|
+
uint8Array[i / 2] = parseInt(hexString.substring(i, i + 2), 16);
|
|
60
|
+
}
|
|
61
|
+
return E__namespace.right(buffer);
|
|
62
|
+
}
|
|
63
|
+
function arrayBufferToHex(arrBuf) {
|
|
64
|
+
return new Uint8Array(arrBuf).reduce((acc, byte) => {
|
|
65
|
+
return acc + byte.toString(16).padStart(2, "0");
|
|
66
|
+
}, "");
|
|
67
|
+
}
|
|
68
|
+
function bufferToArrayBuffer(buf) {
|
|
69
|
+
const ab = new ArrayBuffer(buf.length);
|
|
70
|
+
buf.copy(new Uint8Array(ab));
|
|
71
|
+
return ab;
|
|
72
|
+
}
|
|
73
|
+
function hashToken(token, createHmac) {
|
|
74
|
+
return createHmac(token, "WebAppData");
|
|
75
|
+
}
|
|
76
|
+
function signDataFp(async, data, key, createHmac, options = {}) {
|
|
77
|
+
const keyHmac = options.tokenHashed ? typeof key === "string" ? hexToArrayBuffer(key) : E__namespace.right(key) : function_js.pipe(
|
|
78
|
+
E__namespace.right(hashToken(key, createHmac)),
|
|
79
|
+
E__namespace.match(() => null, (v) => {
|
|
80
|
+
return v instanceof Promise ? TE__namespace.tryCatch(() => v, (err) => err) : E__namespace.right(v);
|
|
81
|
+
})
|
|
82
|
+
);
|
|
83
|
+
if (async || typeof keyHmac === "function") {
|
|
84
|
+
return function_js.pipe(
|
|
85
|
+
typeof keyHmac === "function" ? keyHmac : TE__namespace.fromEither(keyHmac),
|
|
86
|
+
TE__namespace.chain((v) => TE__namespace.tryCatch(
|
|
87
|
+
() => Promise.resolve(createHmac(data, v)).then(arrayBufferToHex),
|
|
88
|
+
(err) => err
|
|
89
|
+
))
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
return function_js.pipe(
|
|
93
|
+
keyHmac,
|
|
94
|
+
// In this branch createHmac can't be asynchronous. If it is, keyHmac would be Promise and the
|
|
95
|
+
// result would be returned in the previous "if" statement.
|
|
96
|
+
E__namespace.chain((v) => E__namespace.right(
|
|
97
|
+
arrayBufferToHex(createHmac(data, v))
|
|
98
|
+
))
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
function signFp(data, key, authDate, signData, options) {
|
|
102
|
+
const query = new URLSearchParams(transformers.serializeInitDataQuery({ ...data, auth_date: authDate }));
|
|
103
|
+
const pairs = [...query.entries()].map(([name, value]) => `${name}=${value}`).sort();
|
|
104
|
+
const queryWithHash = (signature) => {
|
|
105
|
+
query.append("hash", signature);
|
|
106
|
+
return query.toString();
|
|
107
|
+
};
|
|
108
|
+
const eitherHash = signData(pairs.join("\n"), key, options);
|
|
109
|
+
return typeof eitherHash === "function" ? function_js.pipe(eitherHash, TE__namespace.chain((hash) => TE__namespace.right(queryWithHash(hash)))) : function_js.pipe(eitherHash, E__namespace.chain((hash) => E__namespace.right(queryWithHash(hash))));
|
|
110
|
+
}
|
|
111
|
+
function validate3rdFp(value, botId, options = {}) {
|
|
112
|
+
let authDate;
|
|
113
|
+
let authDateString;
|
|
114
|
+
let signature;
|
|
115
|
+
const pairs = [];
|
|
116
|
+
(typeof value === "string" ? new URLSearchParams(value) : value).forEach((value2, key) => {
|
|
117
|
+
if (key === "hash") {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
if (key === "signature") {
|
|
121
|
+
signature = value2;
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
if (key === "auth_date") {
|
|
125
|
+
authDateString = value2;
|
|
126
|
+
const authDateNum = parseInt(value2, 10);
|
|
127
|
+
if (!Number.isNaN(authDateNum)) {
|
|
128
|
+
authDate = new Date(authDateNum * 1e3);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
pairs.push(`${key}=${value2}`);
|
|
132
|
+
});
|
|
133
|
+
if (!signature) {
|
|
134
|
+
return TE__namespace.left(new SignatureMissingError(true));
|
|
135
|
+
}
|
|
136
|
+
if (!authDate) {
|
|
137
|
+
return TE__namespace.left(new AuthDateInvalidError(authDateString));
|
|
138
|
+
}
|
|
139
|
+
const { expiresIn = 86400 } = options;
|
|
140
|
+
if (expiresIn > 0) {
|
|
141
|
+
const expiresAtTs = authDate.getTime() + expiresIn * 1e3;
|
|
142
|
+
const nowTs = Date.now();
|
|
143
|
+
if (expiresAtTs < nowTs) {
|
|
144
|
+
return TE__namespace.left(new ExpiredError(authDate, new Date(expiresAtTs), new Date(nowTs)));
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return _function.pipe(
|
|
148
|
+
TE__namespace.tryCatch(
|
|
149
|
+
() => {
|
|
150
|
+
return betterPromises.BetterPromise.fn(async () => {
|
|
151
|
+
return crypto.subtle.verify(
|
|
152
|
+
"Ed25519",
|
|
153
|
+
await crypto.subtle.importKey(
|
|
154
|
+
"raw",
|
|
155
|
+
Buffer.from(
|
|
156
|
+
options.test ? "40055058a4ee38156a06562e52eece92a771bcd8346a8c4615cb7376eddf72ec" : "e7bf03a2fa4602af4580703d88dda5bb59f32ed8b02a56c187fe7d34caed242d",
|
|
157
|
+
"hex"
|
|
158
|
+
),
|
|
159
|
+
"Ed25519",
|
|
160
|
+
false,
|
|
161
|
+
["verify"]
|
|
162
|
+
),
|
|
163
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
|
|
164
|
+
Buffer.from(signature, "base64"),
|
|
165
|
+
Buffer.from(`${botId}:WebAppData
|
|
166
|
+
${pairs.sort().join("\n")}`)
|
|
167
|
+
);
|
|
168
|
+
}, options);
|
|
169
|
+
},
|
|
170
|
+
(e) => e
|
|
171
|
+
),
|
|
172
|
+
TE__namespace.chainW((isVerified) => {
|
|
173
|
+
return isVerified ? TE__namespace.right(void 0) : TE__namespace.left(new SignatureInvalidError());
|
|
174
|
+
})
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
function validate3rd(value, botId, options) {
|
|
178
|
+
return betterPromises.BetterPromise.fn(async () => {
|
|
179
|
+
await _function.pipe(
|
|
180
|
+
validate3rdFp(value, botId, options),
|
|
181
|
+
TE__namespace.mapLeft((error) => {
|
|
182
|
+
throw error;
|
|
183
|
+
})
|
|
184
|
+
)();
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
function isValid3rdFp(value, botId, options) {
|
|
188
|
+
return _function.pipe(validate3rdFp(value, botId, options), TE__namespace.match(
|
|
189
|
+
() => E__namespace.right(false),
|
|
190
|
+
() => E__namespace.right(true)
|
|
191
|
+
));
|
|
192
|
+
}
|
|
193
|
+
function isValid3rd(value, botId, options) {
|
|
194
|
+
return betterPromises.BetterPromise.fn(() => _function.pipe(
|
|
195
|
+
isValid3rdFp(value, botId, options),
|
|
196
|
+
TE__namespace.match(() => false, (v) => v)
|
|
197
|
+
)());
|
|
198
|
+
}
|
|
199
|
+
function validateFp(async, value, token, signData, options = {}) {
|
|
200
|
+
let authDate;
|
|
201
|
+
let authDateString;
|
|
202
|
+
let hash;
|
|
203
|
+
const pairs = [];
|
|
204
|
+
(typeof value === "string" ? new URLSearchParams(value) : value).forEach((value2, key) => {
|
|
205
|
+
if (key === "hash") {
|
|
206
|
+
hash = value2;
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
if (key === "auth_date") {
|
|
210
|
+
authDateString = value2;
|
|
211
|
+
const authDateNum = parseInt(value2, 10);
|
|
212
|
+
if (!Number.isNaN(authDateNum)) {
|
|
213
|
+
authDate = new Date(authDateNum * 1e3);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
pairs.push(`${key}=${value2}`);
|
|
217
|
+
});
|
|
218
|
+
if (!hash) {
|
|
219
|
+
return (async ? TE__namespace.left : E__namespace.left)(new SignatureMissingError(false));
|
|
220
|
+
}
|
|
221
|
+
if (!authDate) {
|
|
222
|
+
return (async ? TE__namespace.left : E__namespace.left)(new AuthDateInvalidError(authDateString));
|
|
223
|
+
}
|
|
224
|
+
const { expiresIn = 86400 } = options;
|
|
225
|
+
if (expiresIn > 0) {
|
|
226
|
+
const expiresAtTs = authDate.getTime() + expiresIn * 1e3;
|
|
227
|
+
const nowTs = Date.now();
|
|
228
|
+
if (expiresAtTs < nowTs) {
|
|
229
|
+
return (async ? TE__namespace.left : E__namespace.left)(
|
|
230
|
+
new ExpiredError(authDate, new Date(expiresAtTs), new Date(nowTs))
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
pairs.sort();
|
|
235
|
+
const eitherSignature = signData(pairs.join("\n"), token, options);
|
|
236
|
+
const onLeft = (error) => E__namespace.left(error);
|
|
237
|
+
const onRight = (signature) => signature === hash ? E__namespace.right(void 0) : E__namespace.left(new SignatureInvalidError());
|
|
238
|
+
return typeof eitherSignature === "function" ? _function.pipe(eitherSignature, TE__namespace.matchW(onLeft, onRight)) : _function.pipe(eitherSignature, E__namespace.matchW(onLeft, onRight));
|
|
239
|
+
}
|
|
240
|
+
const parse = transformers.parseInitDataQuery;
|
|
241
|
+
const parseFp = transformers.parseInitDataQueryFp;
|
|
242
|
+
exports.AuthDateInvalidError = AuthDateInvalidError;
|
|
243
|
+
exports.ExpiredError = ExpiredError;
|
|
244
|
+
exports.HexStringLengthInvalidError = HexStringLengthInvalidError;
|
|
245
|
+
exports.SignatureInvalidError = SignatureInvalidError;
|
|
246
|
+
exports.SignatureMissingError = SignatureMissingError;
|
|
247
|
+
exports.bufferToArrayBuffer = bufferToArrayBuffer;
|
|
248
|
+
exports.hashToken = hashToken;
|
|
249
|
+
exports.isValid3rd = isValid3rd;
|
|
250
|
+
exports.isValid3rdFp = isValid3rdFp;
|
|
251
|
+
exports.parse = parse;
|
|
252
|
+
exports.parseFp = parseFp;
|
|
253
|
+
exports.signDataFp = signDataFp;
|
|
254
|
+
exports.signFp = signFp;
|
|
255
|
+
exports.validate3rd = validate3rd;
|
|
256
|
+
exports.validate3rdFp = validate3rdFp;
|
|
257
|
+
exports.validateFp = validateFp;
|
|
258
|
+
//# sourceMappingURL=parsing-Cj_BXCnv.cjs.map
|