@tma.js/init-data-node 2.0.3 → 2.0.5

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.
@@ -3,7 +3,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const E = require("fp-ts/Either");
4
4
  const function_js = require("fp-ts/lib/function.js");
5
5
  const node_crypto = require("node:crypto");
6
- const parsing = require("./parsing-Cj_BXCnv.cjs");
6
+ const parsing = require("./parsing-pEQ1lsuE.cjs");
7
7
  const toolkit = require("@tma.js/toolkit");
8
8
  function _interopNamespaceDefault(e) {
9
9
  const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
@@ -1,8 +1,8 @@
1
1
  import * as E from "fp-ts/Either";
2
2
  import { pipe } from "fp-ts/lib/function.js";
3
3
  import { createHmac as createHmac$1 } from "node:crypto";
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";
4
+ import { h as hashToken$1, s as signFp$1, a as signDataFp$1, v as validateFp$1, b as bufferToArrayBuffer } from "./parsing-B9llLYuO.js";
5
+ import { A, E as E2, H, S, c, i, e, p, d, f, g } from "./parsing-B9llLYuO.js";
6
6
  import { deepSnakeToCamelObjKeys } from "@tma.js/toolkit";
7
7
  function textToBuffer(text) {
8
8
  return Buffer.from(typeof text === "string" ? text : new Uint8Array(text));
@@ -2,8 +2,8 @@ import * as E from "fp-ts/Either";
2
2
  import * as TE from "fp-ts/TaskEither";
3
3
  import { pipe } from "fp-ts/lib/function.js";
4
4
  import { serializeInitDataQuery, parseInitDataQuery, parseInitDataQueryFp } from "@tma.js/transformers";
5
- import { pipe as pipe$1 } from "fp-ts/function";
6
5
  import { BetterPromise } from "better-promises";
6
+ import { pipe as pipe$1 } from "fp-ts/function";
7
7
  import { errorClassWithData, errorClass } from "error-kid";
8
8
  class AuthDateInvalidError extends errorClassWithData(
9
9
  "AuthDateInvalidError",
@@ -80,7 +80,11 @@ function signDataFp(async, data, key, createHmac, options = {}) {
80
80
  );
81
81
  }
82
82
  function signFp(data, key, authDate, signData, options) {
83
- const query = new URLSearchParams(serializeInitDataQuery({ ...data, auth_date: authDate }));
83
+ const query = new URLSearchParams(serializeInitDataQuery({
84
+ ...data,
85
+ auth_date: authDate,
86
+ signature: data.signature || ""
87
+ }));
84
88
  const pairs = [...query.entries()].map(([name, value]) => `${name}=${value}`).sort();
85
89
  const queryWithHash = (signature) => {
86
90
  query.append("hash", signature);
@@ -238,4 +242,4 @@ export {
238
242
  signFp as s,
239
243
  validateFp as v
240
244
  };
241
- //# sourceMappingURL=parsing-eczkSd-W.js.map
245
+ //# sourceMappingURL=parsing-B9llLYuO.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parsing-B9llLYuO.js","sources":["../../src/errors.ts","../../src/buf-converters.ts","../../src/hashToken.ts","../../src/signDataFp.ts","../../src/signFp.ts","../../src/validation.ts","../../src/parsing.ts"],"sourcesContent":["import { errorClass, errorClassWithData } from 'error-kid';\n\nexport class AuthDateInvalidError extends errorClassWithData<\n { value: string | undefined },\n [value?: string]\n>(\n 'AuthDateInvalidError',\n value => ({ value }),\n value => [`\"auth_date\" is invalid: ${value || 'value is missing'}`],\n) {\n}\n\nexport class SignatureInvalidError extends errorClass('SignatureInvalidError') {\n}\n\nexport class HexStringLengthInvalidError extends errorClass(\n 'HexStringLengthInvalidError',\n) {\n}\n\nexport class SignatureMissingError extends errorClass<[thirdParty: boolean]>(\n 'SignatureMissingError',\n thirdParty => [`\"${thirdParty ? 'signature' : 'hash'}\" parameter is missing`],\n) {\n}\n\nexport class ExpiredError extends errorClassWithData<\n { issuedAt: Date; expiresAt: Date },\n [issuedAt: Date, expiresAt: Date, now: Date]\n>(\n 'ExpiredError',\n (issuedAt, expiresAt) => ({ issuedAt, expiresAt }),\n (issuedAt, expiresAt, now) => [\n `Init data expired. Issued at ${issuedAt.toISOString()}, expires at ${expiresAt.toISOString()}, now is ${now.toISOString()}`,\n ],\n) {\n}\n","import * as E from 'fp-ts/Either';\n\nimport { HexStringLengthInvalidError } from './errors.js';\n\n/**\n * Converts a hex string to ArrayBuffer.\n * @param hexString - value to convert.\n */\nexport function hexToArrayBuffer(hexString: string): E.Either<\n InstanceType<typeof HexStringLengthInvalidError>,\n ArrayBuffer\n> {\n if (hexString.length % 2 !== 0) {\n return E.left(new HexStringLengthInvalidError());\n }\n const buffer = new ArrayBuffer(hexString.length / 2);\n const uint8Array = new Uint8Array(buffer);\n for (let i = 0; i < hexString.length; i += 2) {\n uint8Array[i / 2] = parseInt(hexString.substring(i, i + 2), 16);\n }\n return E.right(buffer);\n}\n\n/**\n * Converts array buffer to hex.\n * @param arrBuf - buffer to convert\n */\nexport function arrayBufferToHex(arrBuf: ArrayBuffer): string {\n return new Uint8Array(arrBuf).reduce((acc, byte) => {\n // Convert byte to hex and pad with zero if needed (e.g., \"0a\" instead of \"a\")\n return acc + byte.toString(16).padStart(2, '0');\n }, '');\n}\n\nexport function bufferToArrayBuffer(buf: Buffer) {\n const ab = new ArrayBuffer(buf.length);\n buf.copy(new Uint8Array(ab));\n return ab;\n}\n","import type { CreateHmacFn, Text } from './types.js';\n\nexport function hashToken<H extends CreateHmacFn<any>>(token: Text, createHmac: H): ReturnType<H> {\n return createHmac(token, 'WebAppData') as ReturnType<H>;\n}\n","import * as E from 'fp-ts/Either';\nimport * as TE from 'fp-ts/TaskEither';\nimport { pipe } from 'fp-ts/lib/function.js';\n\nimport { arrayBufferToHex, hexToArrayBuffer } from './buf-converters.js';\nimport { hashToken } from './hashToken.js';\nimport type { CreateHmacFn, Text } from './types.js';\n\nexport interface SignDataOptions {\n /**\n * True, if token is already hashed and doesn't require hashing using HMAC-SHA-256.\n */\n tokenHashed?: boolean;\n}\n\nexport type SignDataError = ReturnType<typeof hexToArrayBuffer> extends E.Either<infer U, any>\n ? U\n : never;\n\nexport function signDataFp(\n async: false,\n data: Text,\n key: Text,\n createHmac: CreateHmacFn<false>,\n options?: SignDataOptions,\n): E.Either<SignDataError, string>;\n\nexport function signDataFp(\n async: true,\n data: Text,\n key: Text,\n createHmac: CreateHmacFn<true>,\n options?: SignDataOptions,\n): TE.TaskEither<SignDataError, string>;\n\nexport function signDataFp(\n async: boolean,\n data: Text,\n key: Text,\n createHmac: CreateHmacFn<boolean>,\n options: SignDataOptions = {},\n):\n | E.Either<SignDataError, string>\n | TE.TaskEither<SignDataError, string> {\n const keyHmac = options.tokenHashed\n ? typeof key === 'string'\n // If a hashed token was passed, we assume that it is a HEX string. Not to mess with\n // the createHmac function, we should convert this HEX string to ArrayBuffer. Otherwise,\n // incorrect behavior will be met.\n ? hexToArrayBuffer(key)\n : E.right(key)\n // Otherwise we are hashing the token, but we want it to be a monad.\n : pipe(\n E.right(hashToken(key, createHmac)),\n E.match(() => null as never, v => {\n return v instanceof Promise\n ? TE.tryCatch(() => v, err => err as SignDataError)\n : E.right(v);\n }),\n );\n\n if (async || typeof keyHmac === 'function') {\n return pipe(\n typeof keyHmac === 'function' ? keyHmac : TE.fromEither(keyHmac),\n TE.chain(v => TE.tryCatch(\n () => Promise.resolve(createHmac(data, v)).then(arrayBufferToHex),\n err => err as SignDataError,\n )),\n );\n }\n return pipe(\n keyHmac,\n // In this branch createHmac can't be asynchronous. If it is, keyHmac would be Promise and the\n // result would be returned in the previous \"if\" statement.\n E.chain(v => E.right(\n arrayBufferToHex((createHmac as CreateHmacFn<false>)(data, v)),\n )),\n );\n}\n","import { type InitDataLike, serializeInitDataQuery } from '@tma.js/transformers';\nimport * as E from 'fp-ts/Either';\nimport * as TE from 'fp-ts/TaskEither';\nimport { pipe } from 'fp-ts/lib/function.js';\n\nimport type { Text } from './types.js';\n\nexport type SignableData =\n & Omit<InitDataLike, 'auth_date' | 'hash' | 'signature'>\n & { signature?: string };\n\nexport interface SignOptions {\n /**\n * True, if token is already hashed and doesn't require hashing using HMAC-SHA-256.\n */\n tokenHashed?: boolean;\n}\n\ninterface SignDataFpArg<Async extends boolean, Left> {\n (data: Text, key: Text, options?: SignOptions): Async extends true\n ? TE.TaskEither<Left, string>\n : E.Either<Left, string>;\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 signData - function signing data.\n * @param options - additional options.\n * @returns Signed init data presented as query parameters.\n */\nexport function signFp<Left>(\n data: SignableData,\n key: Text,\n authDate: Date,\n signData: SignDataFpArg<false, Left>,\n options?: SignOptions,\n): E.Either<Left, string>;\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 signData - function signing data.\n * @param options - additional options.\n * @returns Signed init data presented as query parameters.\n */\nexport function signFp<Left>(\n data: SignableData,\n key: Text,\n authDate: Date,\n signData: SignDataFpArg<true, Left>,\n options?: SignOptions,\n): TE.TaskEither<Left, string>;\n\nexport function signFp<Left>(\n data: SignableData,\n key: Text,\n authDate: Date,\n signData: SignDataFpArg<boolean, Left>,\n options?: SignOptions,\n): E.Either<Left, string> | TE.TaskEither<Left, string> {\n const query = new URLSearchParams(serializeInitDataQuery({\n ...data,\n auth_date: authDate,\n signature: data.signature || '',\n }));\n\n // Convert search params to pairs and sort the final array.\n const pairs = [...query.entries()]\n .map(([name, value]) => `${name}=${value}`)\n .sort();\n\n // Compute sign, append it to the params and return.\n const queryWithHash = (signature: string): string => {\n query.append('hash', signature);\n return query.toString();\n };\n\n const eitherHash = signData(pairs.join('\\n'), key, options);\n return typeof eitherHash === 'function'\n ? pipe(eitherHash, TE.chain(hash => TE.right(queryWithHash(hash))))\n : pipe(eitherHash, E.chain(hash => E.right(queryWithHash(hash))));\n}\n","import {\n BetterPromise,\n type BetterPromiseOptions,\n type BetterPromiseRejectReason,\n} from 'better-promises';\nimport * as E from 'fp-ts/Either';\nimport * as TE from 'fp-ts/TaskEither';\nimport { pipe } from 'fp-ts/function';\n\nimport {\n AuthDateInvalidError,\n ExpiredError,\n SignatureInvalidError,\n SignatureMissingError,\n} from './errors.js';\nimport { Text } from './types.js';\n\ntype OmittedPromiseOptions = Omit<BetterPromiseOptions, 'abortOnResolve' | 'abortOnReject'>;\n\nexport type ValidateValue = string | URLSearchParams;\nexport type Validate3rdValue = string | URLSearchParams;\n\nexport type ValidateError =\n | SignatureMissingError\n | SignatureInvalidError\n | AuthDateInvalidError\n | ExpiredError;\nexport type ValidateAsyncError = ValidateError | BetterPromiseRejectReason;\nexport type Validate3rdError =\n | SignatureMissingError\n | SignatureInvalidError\n | AuthDateInvalidError\n | ExpiredError\n | BetterPromiseRejectReason;\n\ninterface ValidateSignDataFpArg<Async extends boolean, Left> {\n (data: Text, key: Text, options?: ValidateOptions): Async extends true\n ? TE.TaskEither<Left, string>\n : E.Either<Left, string>;\n}\n\ninterface SharedValidateOptions {\n /**\n * Time in seconds which states, how long from creation time init data is considered valid.\n *\n * In other words, in case when authDate + expiresIn is before current time, init data is\n * recognized as expired.\n *\n * In case this value is equal to 0, the function does not check init data expiration.\n * @default 86400 (1 day)\n */\n expiresIn?: number;\n}\n\nexport interface ValidateOptions extends SharedValidateOptions {\n /**\n * True, if token is already hashed.\n * @default false\n */\n tokenHashed?: boolean;\n}\n\nexport interface ValidateAsyncOptions extends ValidateOptions, OmittedPromiseOptions {\n}\n\nexport interface Validate3rdOptions extends SharedValidateOptions, OmittedPromiseOptions {\n /**\n * When true, uses the test environment public key to validate init data.\n * @default false\n */\n test?: boolean;\n}\n\n/**\n * Validates passed init data using a publicly known Ee25519 key.\n * @param value - value to check.\n * @param botId - bot identifier\n * @param options - additional validation options.\n */\nexport function validate3rdFp(\n value: Validate3rdValue,\n botId: number,\n options: Validate3rdOptions = {},\n): TE.TaskEither<Validate3rdError, void> {\n // Init data required params.\n let authDate: Date | undefined;\n let authDateString: string | undefined;\n let signature: string | undefined;\n\n // All search params pairs presented as `k=v`.\n const pairs: string[] = [];\n\n // Iterate over all key-value pairs of parsed parameters and find required\n // parameters.\n (typeof value === 'string' ? new URLSearchParams(value) : value).forEach((value, key) => {\n if (key === 'hash') {\n return;\n }\n if (key === 'signature') {\n signature = value;\n return;\n }\n if (key === 'auth_date') {\n authDateString = value;\n const authDateNum = parseInt(value, 10);\n if (!Number.isNaN(authDateNum)) {\n authDate = new Date(authDateNum * 1000);\n }\n }\n\n pairs.push(`${key}=${value}`);\n });\n\n // Signature and auth date always required.\n if (!signature) {\n return TE.left(new SignatureMissingError(true));\n }\n\n if (!authDate) {\n return TE.left(new AuthDateInvalidError(authDateString));\n }\n\n // In case, expiration time passed, we do additional parameters check.\n const { expiresIn = 86400 } = options;\n if (expiresIn > 0) {\n // Check if init data expired.\n const expiresAtTs = authDate.getTime() + (expiresIn * 1000);\n const nowTs = Date.now();\n if (expiresAtTs < nowTs) {\n return TE.left(new ExpiredError(authDate, new Date(expiresAtTs), new Date(nowTs)));\n }\n }\n\n return pipe(\n TE.tryCatch(\n () => {\n return BetterPromise.fn(async () => {\n return crypto.subtle.verify(\n 'Ed25519',\n await crypto.subtle.importKey(\n 'raw',\n Buffer.from(\n options.test\n ? '40055058a4ee38156a06562e52eece92a771bcd8346a8c4615cb7376eddf72ec'\n : 'e7bf03a2fa4602af4580703d88dda5bb59f32ed8b02a56c187fe7d34caed242d',\n 'hex',\n ),\n 'Ed25519',\n false,\n ['verify'],\n ),\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion\n Buffer.from(signature as string, 'base64'),\n Buffer.from(`${botId}:WebAppData\\n${pairs.sort().join('\\n')}`),\n );\n }, options);\n },\n (e: unknown) => e,\n ),\n TE.chainW(isVerified => {\n return isVerified ? TE.right(undefined) : TE.left(new SignatureInvalidError());\n }),\n );\n}\n\n/**\n * @see validate3rdFp\n */\nexport function validate3rd(\n value: Validate3rdValue,\n botId: number,\n options?: Validate3rdOptions,\n): BetterPromise<void> {\n return BetterPromise.fn(async () => {\n await pipe(\n validate3rdFp(value, botId, options),\n TE.mapLeft(error => {\n throw error;\n }),\n )();\n });\n}\n\n/**\n * @param value - value to check.\n * @param botId - bot identifier\n * @param options - additional validation options.\n * @returns True is specified init data is signed by Telegram.\n */\nexport function isValid3rdFp(\n value: Validate3rdValue,\n botId: number,\n options?: Validate3rdOptions,\n): TE.TaskEither<void, boolean> {\n return pipe(validate3rdFp(value, botId, options), TE.match(\n () => E.right(false),\n () => E.right(true),\n ));\n}\n\n/**\n * @see isValid3rdFp\n */\nexport function isValid3rd(\n value: Validate3rdValue,\n botId: number,\n options?: Validate3rdOptions,\n): BetterPromise<boolean> {\n return BetterPromise.fn(() => pipe(\n isValid3rdFp(value, botId, options),\n TE.match(() => false, v => v),\n )());\n}\n\nexport function validateFp<Left>(\n async: false,\n value: ValidateValue,\n token: Text,\n signData: ValidateSignDataFpArg<false, Left>,\n options?: ValidateOptions,\n): E.Either<Left | ValidateError, void>;\n\nexport function validateFp<Left>(\n async: true,\n value: ValidateValue,\n token: Text,\n signData: ValidateSignDataFpArg<true, Left>,\n options?: ValidateAsyncOptions,\n): TE.TaskEither<Left | ValidateAsyncError, void>;\n\nexport function validateFp<Left>(\n async: boolean,\n value: ValidateValue,\n token: Text,\n signData: ValidateSignDataFpArg<boolean, Left>,\n options: ValidateOptions | ValidateAsyncOptions = {},\n):\n | E.Either<Left | ValidateError, void>\n | TE.TaskEither<Left | ValidateAsyncError, void> {\n // Init data required params.\n let authDate: Date | undefined;\n let authDateString: string | undefined;\n let hash: string | undefined;\n\n // All search params pairs presented as `k=v`.\n const pairs: string[] = [];\n\n // Iterate over all key-value pairs of parsed parameters and find required\n // parameters.\n (typeof value === 'string' ? new URLSearchParams(value) : value).forEach((value, key) => {\n if (key === 'hash') {\n hash = value;\n return;\n }\n\n if (key === 'auth_date') {\n authDateString = value;\n const authDateNum = parseInt(value, 10);\n if (!Number.isNaN(authDateNum)) {\n authDate = new Date(authDateNum * 1000);\n }\n }\n\n pairs.push(`${key}=${value}`);\n });\n\n // Hash and auth date always required.\n if (!hash) {\n return (async ? TE.left : E.left)(new SignatureMissingError(false));\n }\n\n if (!authDate) {\n return (async ? TE.left : E.left)(new AuthDateInvalidError(authDateString));\n }\n\n // In case, expiration time passed, we do additional parameters check.\n const { expiresIn = 86400 } = options;\n if (expiresIn > 0) {\n // Check if init data expired.\n const expiresAtTs = authDate.getTime() + (expiresIn * 1000);\n const nowTs = Date.now();\n if (expiresAtTs < nowTs) {\n return (async ? TE.left : E.left)(\n new ExpiredError(authDate, new Date(expiresAtTs), new Date(nowTs)),\n );\n }\n }\n\n // According to docs, we sort all the pairs in alphabetical order.\n pairs.sort();\n\n const eitherSignature = signData(pairs.join('\\n'), token, options);\n const onLeft = (error: Left) => E.left(error);\n const onRight = (signature: string) => (\n signature === hash ? E.right(undefined) : E.left(new SignatureInvalidError())\n );\n\n return typeof eitherSignature === 'function'\n ? pipe(eitherSignature, TE.matchW(onLeft, onRight))\n : pipe(eitherSignature, E.matchW(onLeft, onRight));\n}\n","import {\n parseInitDataQuery,\n parseInitDataQueryFp,\n type ParseInitDataQueryError,\n} from '@tma.js/transformers';\n\n/**\n * Parses an incoming value as init data.\n */\nexport const parse = parseInitDataQuery;\n\n/**\n * Parses an incoming value as init data.\n */\nexport const parseFp = parseInitDataQueryFp;\n\nexport { ParseInitDataQueryError as ParseError };\n"],"names":["value","pipe"],"mappings":"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"}
@@ -3,8 +3,8 @@ const E = require("fp-ts/Either");
3
3
  const TE = require("fp-ts/TaskEither");
4
4
  const function_js = require("fp-ts/lib/function.js");
5
5
  const transformers = require("@tma.js/transformers");
6
- const _function = require("fp-ts/function");
7
6
  const betterPromises = require("better-promises");
7
+ const _function = require("fp-ts/function");
8
8
  const errorKid = require("error-kid");
9
9
  function _interopNamespaceDefault(e) {
10
10
  const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
@@ -99,7 +99,11 @@ function signDataFp(async, data, key, createHmac, options = {}) {
99
99
  );
100
100
  }
101
101
  function signFp(data, key, authDate, signData, options) {
102
- const query = new URLSearchParams(transformers.serializeInitDataQuery({ ...data, auth_date: authDate }));
102
+ const query = new URLSearchParams(transformers.serializeInitDataQuery({
103
+ ...data,
104
+ auth_date: authDate,
105
+ signature: data.signature || ""
106
+ }));
103
107
  const pairs = [...query.entries()].map(([name, value]) => `${name}=${value}`).sort();
104
108
  const queryWithHash = (signature) => {
105
109
  query.append("hash", signature);
@@ -255,4 +259,4 @@ exports.signFp = signFp;
255
259
  exports.validate3rd = validate3rd;
256
260
  exports.validate3rdFp = validate3rdFp;
257
261
  exports.validateFp = validateFp;
258
- //# sourceMappingURL=parsing-Cj_BXCnv.cjs.map
262
+ //# sourceMappingURL=parsing-pEQ1lsuE.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parsing-pEQ1lsuE.cjs","sources":["../../src/errors.ts","../../src/buf-converters.ts","../../src/hashToken.ts","../../src/signDataFp.ts","../../src/signFp.ts","../../src/validation.ts","../../src/parsing.ts"],"sourcesContent":["import { errorClass, errorClassWithData } from 'error-kid';\n\nexport class AuthDateInvalidError extends errorClassWithData<\n { value: string | undefined },\n [value?: string]\n>(\n 'AuthDateInvalidError',\n value => ({ value }),\n value => [`\"auth_date\" is invalid: ${value || 'value is missing'}`],\n) {\n}\n\nexport class SignatureInvalidError extends errorClass('SignatureInvalidError') {\n}\n\nexport class HexStringLengthInvalidError extends errorClass(\n 'HexStringLengthInvalidError',\n) {\n}\n\nexport class SignatureMissingError extends errorClass<[thirdParty: boolean]>(\n 'SignatureMissingError',\n thirdParty => [`\"${thirdParty ? 'signature' : 'hash'}\" parameter is missing`],\n) {\n}\n\nexport class ExpiredError extends errorClassWithData<\n { issuedAt: Date; expiresAt: Date },\n [issuedAt: Date, expiresAt: Date, now: Date]\n>(\n 'ExpiredError',\n (issuedAt, expiresAt) => ({ issuedAt, expiresAt }),\n (issuedAt, expiresAt, now) => [\n `Init data expired. Issued at ${issuedAt.toISOString()}, expires at ${expiresAt.toISOString()}, now is ${now.toISOString()}`,\n ],\n) {\n}\n","import * as E from 'fp-ts/Either';\n\nimport { HexStringLengthInvalidError } from './errors.js';\n\n/**\n * Converts a hex string to ArrayBuffer.\n * @param hexString - value to convert.\n */\nexport function hexToArrayBuffer(hexString: string): E.Either<\n InstanceType<typeof HexStringLengthInvalidError>,\n ArrayBuffer\n> {\n if (hexString.length % 2 !== 0) {\n return E.left(new HexStringLengthInvalidError());\n }\n const buffer = new ArrayBuffer(hexString.length / 2);\n const uint8Array = new Uint8Array(buffer);\n for (let i = 0; i < hexString.length; i += 2) {\n uint8Array[i / 2] = parseInt(hexString.substring(i, i + 2), 16);\n }\n return E.right(buffer);\n}\n\n/**\n * Converts array buffer to hex.\n * @param arrBuf - buffer to convert\n */\nexport function arrayBufferToHex(arrBuf: ArrayBuffer): string {\n return new Uint8Array(arrBuf).reduce((acc, byte) => {\n // Convert byte to hex and pad with zero if needed (e.g., \"0a\" instead of \"a\")\n return acc + byte.toString(16).padStart(2, '0');\n }, '');\n}\n\nexport function bufferToArrayBuffer(buf: Buffer) {\n const ab = new ArrayBuffer(buf.length);\n buf.copy(new Uint8Array(ab));\n return ab;\n}\n","import type { CreateHmacFn, Text } from './types.js';\n\nexport function hashToken<H extends CreateHmacFn<any>>(token: Text, createHmac: H): ReturnType<H> {\n return createHmac(token, 'WebAppData') as ReturnType<H>;\n}\n","import * as E from 'fp-ts/Either';\nimport * as TE from 'fp-ts/TaskEither';\nimport { pipe } from 'fp-ts/lib/function.js';\n\nimport { arrayBufferToHex, hexToArrayBuffer } from './buf-converters.js';\nimport { hashToken } from './hashToken.js';\nimport type { CreateHmacFn, Text } from './types.js';\n\nexport interface SignDataOptions {\n /**\n * True, if token is already hashed and doesn't require hashing using HMAC-SHA-256.\n */\n tokenHashed?: boolean;\n}\n\nexport type SignDataError = ReturnType<typeof hexToArrayBuffer> extends E.Either<infer U, any>\n ? U\n : never;\n\nexport function signDataFp(\n async: false,\n data: Text,\n key: Text,\n createHmac: CreateHmacFn<false>,\n options?: SignDataOptions,\n): E.Either<SignDataError, string>;\n\nexport function signDataFp(\n async: true,\n data: Text,\n key: Text,\n createHmac: CreateHmacFn<true>,\n options?: SignDataOptions,\n): TE.TaskEither<SignDataError, string>;\n\nexport function signDataFp(\n async: boolean,\n data: Text,\n key: Text,\n createHmac: CreateHmacFn<boolean>,\n options: SignDataOptions = {},\n):\n | E.Either<SignDataError, string>\n | TE.TaskEither<SignDataError, string> {\n const keyHmac = options.tokenHashed\n ? typeof key === 'string'\n // If a hashed token was passed, we assume that it is a HEX string. Not to mess with\n // the createHmac function, we should convert this HEX string to ArrayBuffer. Otherwise,\n // incorrect behavior will be met.\n ? hexToArrayBuffer(key)\n : E.right(key)\n // Otherwise we are hashing the token, but we want it to be a monad.\n : pipe(\n E.right(hashToken(key, createHmac)),\n E.match(() => null as never, v => {\n return v instanceof Promise\n ? TE.tryCatch(() => v, err => err as SignDataError)\n : E.right(v);\n }),\n );\n\n if (async || typeof keyHmac === 'function') {\n return pipe(\n typeof keyHmac === 'function' ? keyHmac : TE.fromEither(keyHmac),\n TE.chain(v => TE.tryCatch(\n () => Promise.resolve(createHmac(data, v)).then(arrayBufferToHex),\n err => err as SignDataError,\n )),\n );\n }\n return pipe(\n keyHmac,\n // In this branch createHmac can't be asynchronous. If it is, keyHmac would be Promise and the\n // result would be returned in the previous \"if\" statement.\n E.chain(v => E.right(\n arrayBufferToHex((createHmac as CreateHmacFn<false>)(data, v)),\n )),\n );\n}\n","import { type InitDataLike, serializeInitDataQuery } from '@tma.js/transformers';\nimport * as E from 'fp-ts/Either';\nimport * as TE from 'fp-ts/TaskEither';\nimport { pipe } from 'fp-ts/lib/function.js';\n\nimport type { Text } from './types.js';\n\nexport type SignableData =\n & Omit<InitDataLike, 'auth_date' | 'hash' | 'signature'>\n & { signature?: string };\n\nexport interface SignOptions {\n /**\n * True, if token is already hashed and doesn't require hashing using HMAC-SHA-256.\n */\n tokenHashed?: boolean;\n}\n\ninterface SignDataFpArg<Async extends boolean, Left> {\n (data: Text, key: Text, options?: SignOptions): Async extends true\n ? TE.TaskEither<Left, string>\n : E.Either<Left, string>;\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 signData - function signing data.\n * @param options - additional options.\n * @returns Signed init data presented as query parameters.\n */\nexport function signFp<Left>(\n data: SignableData,\n key: Text,\n authDate: Date,\n signData: SignDataFpArg<false, Left>,\n options?: SignOptions,\n): E.Either<Left, string>;\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 signData - function signing data.\n * @param options - additional options.\n * @returns Signed init data presented as query parameters.\n */\nexport function signFp<Left>(\n data: SignableData,\n key: Text,\n authDate: Date,\n signData: SignDataFpArg<true, Left>,\n options?: SignOptions,\n): TE.TaskEither<Left, string>;\n\nexport function signFp<Left>(\n data: SignableData,\n key: Text,\n authDate: Date,\n signData: SignDataFpArg<boolean, Left>,\n options?: SignOptions,\n): E.Either<Left, string> | TE.TaskEither<Left, string> {\n const query = new URLSearchParams(serializeInitDataQuery({\n ...data,\n auth_date: authDate,\n signature: data.signature || '',\n }));\n\n // Convert search params to pairs and sort the final array.\n const pairs = [...query.entries()]\n .map(([name, value]) => `${name}=${value}`)\n .sort();\n\n // Compute sign, append it to the params and return.\n const queryWithHash = (signature: string): string => {\n query.append('hash', signature);\n return query.toString();\n };\n\n const eitherHash = signData(pairs.join('\\n'), key, options);\n return typeof eitherHash === 'function'\n ? pipe(eitherHash, TE.chain(hash => TE.right(queryWithHash(hash))))\n : pipe(eitherHash, E.chain(hash => E.right(queryWithHash(hash))));\n}\n","import {\n BetterPromise,\n type BetterPromiseOptions,\n type BetterPromiseRejectReason,\n} from 'better-promises';\nimport * as E from 'fp-ts/Either';\nimport * as TE from 'fp-ts/TaskEither';\nimport { pipe } from 'fp-ts/function';\n\nimport {\n AuthDateInvalidError,\n ExpiredError,\n SignatureInvalidError,\n SignatureMissingError,\n} from './errors.js';\nimport { Text } from './types.js';\n\ntype OmittedPromiseOptions = Omit<BetterPromiseOptions, 'abortOnResolve' | 'abortOnReject'>;\n\nexport type ValidateValue = string | URLSearchParams;\nexport type Validate3rdValue = string | URLSearchParams;\n\nexport type ValidateError =\n | SignatureMissingError\n | SignatureInvalidError\n | AuthDateInvalidError\n | ExpiredError;\nexport type ValidateAsyncError = ValidateError | BetterPromiseRejectReason;\nexport type Validate3rdError =\n | SignatureMissingError\n | SignatureInvalidError\n | AuthDateInvalidError\n | ExpiredError\n | BetterPromiseRejectReason;\n\ninterface ValidateSignDataFpArg<Async extends boolean, Left> {\n (data: Text, key: Text, options?: ValidateOptions): Async extends true\n ? TE.TaskEither<Left, string>\n : E.Either<Left, string>;\n}\n\ninterface SharedValidateOptions {\n /**\n * Time in seconds which states, how long from creation time init data is considered valid.\n *\n * In other words, in case when authDate + expiresIn is before current time, init data is\n * recognized as expired.\n *\n * In case this value is equal to 0, the function does not check init data expiration.\n * @default 86400 (1 day)\n */\n expiresIn?: number;\n}\n\nexport interface ValidateOptions extends SharedValidateOptions {\n /**\n * True, if token is already hashed.\n * @default false\n */\n tokenHashed?: boolean;\n}\n\nexport interface ValidateAsyncOptions extends ValidateOptions, OmittedPromiseOptions {\n}\n\nexport interface Validate3rdOptions extends SharedValidateOptions, OmittedPromiseOptions {\n /**\n * When true, uses the test environment public key to validate init data.\n * @default false\n */\n test?: boolean;\n}\n\n/**\n * Validates passed init data using a publicly known Ee25519 key.\n * @param value - value to check.\n * @param botId - bot identifier\n * @param options - additional validation options.\n */\nexport function validate3rdFp(\n value: Validate3rdValue,\n botId: number,\n options: Validate3rdOptions = {},\n): TE.TaskEither<Validate3rdError, void> {\n // Init data required params.\n let authDate: Date | undefined;\n let authDateString: string | undefined;\n let signature: string | undefined;\n\n // All search params pairs presented as `k=v`.\n const pairs: string[] = [];\n\n // Iterate over all key-value pairs of parsed parameters and find required\n // parameters.\n (typeof value === 'string' ? new URLSearchParams(value) : value).forEach((value, key) => {\n if (key === 'hash') {\n return;\n }\n if (key === 'signature') {\n signature = value;\n return;\n }\n if (key === 'auth_date') {\n authDateString = value;\n const authDateNum = parseInt(value, 10);\n if (!Number.isNaN(authDateNum)) {\n authDate = new Date(authDateNum * 1000);\n }\n }\n\n pairs.push(`${key}=${value}`);\n });\n\n // Signature and auth date always required.\n if (!signature) {\n return TE.left(new SignatureMissingError(true));\n }\n\n if (!authDate) {\n return TE.left(new AuthDateInvalidError(authDateString));\n }\n\n // In case, expiration time passed, we do additional parameters check.\n const { expiresIn = 86400 } = options;\n if (expiresIn > 0) {\n // Check if init data expired.\n const expiresAtTs = authDate.getTime() + (expiresIn * 1000);\n const nowTs = Date.now();\n if (expiresAtTs < nowTs) {\n return TE.left(new ExpiredError(authDate, new Date(expiresAtTs), new Date(nowTs)));\n }\n }\n\n return pipe(\n TE.tryCatch(\n () => {\n return BetterPromise.fn(async () => {\n return crypto.subtle.verify(\n 'Ed25519',\n await crypto.subtle.importKey(\n 'raw',\n Buffer.from(\n options.test\n ? '40055058a4ee38156a06562e52eece92a771bcd8346a8c4615cb7376eddf72ec'\n : 'e7bf03a2fa4602af4580703d88dda5bb59f32ed8b02a56c187fe7d34caed242d',\n 'hex',\n ),\n 'Ed25519',\n false,\n ['verify'],\n ),\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion\n Buffer.from(signature as string, 'base64'),\n Buffer.from(`${botId}:WebAppData\\n${pairs.sort().join('\\n')}`),\n );\n }, options);\n },\n (e: unknown) => e,\n ),\n TE.chainW(isVerified => {\n return isVerified ? TE.right(undefined) : TE.left(new SignatureInvalidError());\n }),\n );\n}\n\n/**\n * @see validate3rdFp\n */\nexport function validate3rd(\n value: Validate3rdValue,\n botId: number,\n options?: Validate3rdOptions,\n): BetterPromise<void> {\n return BetterPromise.fn(async () => {\n await pipe(\n validate3rdFp(value, botId, options),\n TE.mapLeft(error => {\n throw error;\n }),\n )();\n });\n}\n\n/**\n * @param value - value to check.\n * @param botId - bot identifier\n * @param options - additional validation options.\n * @returns True is specified init data is signed by Telegram.\n */\nexport function isValid3rdFp(\n value: Validate3rdValue,\n botId: number,\n options?: Validate3rdOptions,\n): TE.TaskEither<void, boolean> {\n return pipe(validate3rdFp(value, botId, options), TE.match(\n () => E.right(false),\n () => E.right(true),\n ));\n}\n\n/**\n * @see isValid3rdFp\n */\nexport function isValid3rd(\n value: Validate3rdValue,\n botId: number,\n options?: Validate3rdOptions,\n): BetterPromise<boolean> {\n return BetterPromise.fn(() => pipe(\n isValid3rdFp(value, botId, options),\n TE.match(() => false, v => v),\n )());\n}\n\nexport function validateFp<Left>(\n async: false,\n value: ValidateValue,\n token: Text,\n signData: ValidateSignDataFpArg<false, Left>,\n options?: ValidateOptions,\n): E.Either<Left | ValidateError, void>;\n\nexport function validateFp<Left>(\n async: true,\n value: ValidateValue,\n token: Text,\n signData: ValidateSignDataFpArg<true, Left>,\n options?: ValidateAsyncOptions,\n): TE.TaskEither<Left | ValidateAsyncError, void>;\n\nexport function validateFp<Left>(\n async: boolean,\n value: ValidateValue,\n token: Text,\n signData: ValidateSignDataFpArg<boolean, Left>,\n options: ValidateOptions | ValidateAsyncOptions = {},\n):\n | E.Either<Left | ValidateError, void>\n | TE.TaskEither<Left | ValidateAsyncError, void> {\n // Init data required params.\n let authDate: Date | undefined;\n let authDateString: string | undefined;\n let hash: string | undefined;\n\n // All search params pairs presented as `k=v`.\n const pairs: string[] = [];\n\n // Iterate over all key-value pairs of parsed parameters and find required\n // parameters.\n (typeof value === 'string' ? new URLSearchParams(value) : value).forEach((value, key) => {\n if (key === 'hash') {\n hash = value;\n return;\n }\n\n if (key === 'auth_date') {\n authDateString = value;\n const authDateNum = parseInt(value, 10);\n if (!Number.isNaN(authDateNum)) {\n authDate = new Date(authDateNum * 1000);\n }\n }\n\n pairs.push(`${key}=${value}`);\n });\n\n // Hash and auth date always required.\n if (!hash) {\n return (async ? TE.left : E.left)(new SignatureMissingError(false));\n }\n\n if (!authDate) {\n return (async ? TE.left : E.left)(new AuthDateInvalidError(authDateString));\n }\n\n // In case, expiration time passed, we do additional parameters check.\n const { expiresIn = 86400 } = options;\n if (expiresIn > 0) {\n // Check if init data expired.\n const expiresAtTs = authDate.getTime() + (expiresIn * 1000);\n const nowTs = Date.now();\n if (expiresAtTs < nowTs) {\n return (async ? TE.left : E.left)(\n new ExpiredError(authDate, new Date(expiresAtTs), new Date(nowTs)),\n );\n }\n }\n\n // According to docs, we sort all the pairs in alphabetical order.\n pairs.sort();\n\n const eitherSignature = signData(pairs.join('\\n'), token, options);\n const onLeft = (error: Left) => E.left(error);\n const onRight = (signature: string) => (\n signature === hash ? E.right(undefined) : E.left(new SignatureInvalidError())\n );\n\n return typeof eitherSignature === 'function'\n ? pipe(eitherSignature, TE.matchW(onLeft, onRight))\n : pipe(eitherSignature, E.matchW(onLeft, onRight));\n}\n","import {\n parseInitDataQuery,\n parseInitDataQueryFp,\n type ParseInitDataQueryError,\n} from '@tma.js/transformers';\n\n/**\n * Parses an incoming value as init data.\n */\nexport const parse = parseInitDataQuery;\n\n/**\n * Parses an incoming value as init data.\n */\nexport const parseFp = parseInitDataQueryFp;\n\nexport { ParseInitDataQueryError as ParseError };\n"],"names":["errorClassWithData","errorClass","E","pipe","TE","serializeInitDataQuery","value","BetterPromise","parseInitDataQuery","parseInitDataQueryFp"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAEO,MAAM,6BAA6BA,SAAA;AAAA,EAIxC;AAAA,EACA,CAAA,WAAU,EAAE;EACZ,CAAS,UAAA,CAAC,2BAA2B,SAAS,kBAAkB,EAAE;AACpE,EAAE;AACF;AAEa,MAAA,8BAA8BC,SAAAA,WAAW,uBAAuB,EAAE;AAC/E;AAEO,MAAM,oCAAoCA,SAAA;AAAA,EAC/C;AACF,EAAE;AACF;AAEO,MAAM,8BAA8BA,SAAA;AAAA,EACzC;AAAA,EACA,gBAAc,CAAC,IAAI,aAAa,cAAc,MAAM,wBAAwB;AAC9E,EAAE;AACF;AAEO,MAAM,qBAAqBD,SAAA;AAAA,EAIhC;AAAA,EACA,CAAC,UAAU,eAAe,EAAE,UAAU,UAAU;AAAA,EAChD,CAAC,UAAU,WAAW,QAAQ;AAAA,IAC5B,gCAAgC,SAAS,YAAA,CAAa,gBAAgB,UAAU,aAAa,YAAY,IAAI,YAAA,CAAa;AAAA,EAAA;AAE9H,EAAE;AACF;AC5BO,SAAS,iBAAiB,WAG/B;AACI,MAAA,UAAU,SAAS,MAAM,GAAG;AAC9B,WAAOE,aAAE,KAAK,IAAI,6BAA6B;AAAA,EAAA;AAEjD,QAAM,SAAS,IAAI,YAAY,UAAU,SAAS,CAAC;AAC7C,QAAA,aAAa,IAAI,WAAW,MAAM;AACxC,WAAS,IAAI,GAAG,IAAI,UAAU,QAAQ,KAAK,GAAG;AACjC,eAAA,IAAI,CAAC,IAAI,SAAS,UAAU,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE;AAAA,EAAA;AAEzD,SAAAA,aAAE,MAAM,MAAM;AACvB;AAMO,SAAS,iBAAiB,QAA6B;AAC5D,SAAO,IAAI,WAAW,MAAM,EAAE,OAAO,CAAC,KAAK,SAAS;AAElD,WAAO,MAAM,KAAK,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG;AAAA,KAC7C,EAAE;AACP;AAEO,SAAS,oBAAoB,KAAa;AAC/C,QAAM,KAAK,IAAI,YAAY,IAAI,MAAM;AACrC,MAAI,KAAK,IAAI,WAAW,EAAE,CAAC;AACpB,SAAA;AACT;ACpCgB,SAAA,UAAuC,OAAa,YAA8B;AACzF,SAAA,WAAW,OAAO,YAAY;AACvC;AC+BO,SAAS,WACd,OACA,MACA,KACA,YACA,UAA2B,IAGY;AACvC,QAAM,UAAU,QAAQ,cACpB,OAAO,QAAQ,WAIb,iBAAiB,GAAG,IACpBA,aAAE,MAAM,GAAG,IAEbC,YAAA;AAAA,IACAD,aAAE,MAAM,UAAU,KAAK,UAAU,CAAC;AAAA,IAClCA,aAAE,MAAM,MAAM,MAAe,CAAK,MAAA;AACzB,aAAA,aAAa,UAChBE,cAAG,SAAS,MAAM,GAAG,CAAA,QAAO,GAAoB,IAChDF,aAAE,MAAM,CAAC;AAAA,IACd,CAAA;AAAA,EACH;AAEE,MAAA,SAAS,OAAO,YAAY,YAAY;AACnC,WAAAC,YAAA;AAAA,MACL,OAAO,YAAY,aAAa,UAAUC,cAAG,WAAW,OAAO;AAAA,MAC/DA,cAAG,MAAM,CAAA,MAAKA,cAAG;AAAA,QACf,MAAM,QAAQ,QAAQ,WAAW,MAAM,CAAC,CAAC,EAAE,KAAK,gBAAgB;AAAA,QAChE,CAAO,QAAA;AAAA,MACR,CAAA;AAAA,IACH;AAAA,EAAA;AAEK,SAAAD,YAAA;AAAA,IACL;AAAA;AAAA;AAAA,IAGAD,aAAE,MAAM,CAAA,MAAKA,aAAE;AAAA,MACb,iBAAkB,WAAmC,MAAM,CAAC,CAAC;AAAA,IAC9D,CAAA;AAAA,EACH;AACF;ACpBO,SAAS,OACd,MACA,KACA,UACA,UACA,SACsD;AAChD,QAAA,QAAQ,IAAI,gBAAgBG,oCAAuB;AAAA,IACvD,GAAG;AAAA,IACH,WAAW;AAAA,IACX,WAAW,KAAK,aAAa;AAAA,EAAA,CAC9B,CAAC;AAGF,QAAM,QAAQ,CAAC,GAAG,MAAM,QAAQ,CAAC,EAC9B,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM,GAAG,IAAI,IAAI,KAAK,EAAE,EACzC,KAAK;AAGF,QAAA,gBAAgB,CAAC,cAA8B;AAC7C,UAAA,OAAO,QAAQ,SAAS;AAC9B,WAAO,MAAM,SAAS;AAAA,EACxB;AAEA,QAAM,aAAa,SAAS,MAAM,KAAK,IAAI,GAAG,KAAK,OAAO;AACnD,SAAA,OAAO,eAAe,aACzBF,YAAAA,KAAK,YAAYC,cAAG,MAAM,CAAQ,SAAAA,cAAG,MAAM,cAAc,IAAI,CAAC,CAAC,CAAC,IAChED,YAAA,KAAK,YAAYD,aAAE,MAAM,CAAA,SAAQA,aAAE,MAAM,cAAc,IAAI,CAAC,CAAC,CAAC;AACpE;ACPO,SAAS,cACd,OACA,OACA,UAA8B,CAAA,GACS;AAEnC,MAAA;AACA,MAAA;AACA,MAAA;AAGJ,QAAM,QAAkB,CAAC;AAIxB,GAAA,OAAO,UAAU,WAAW,IAAI,gBAAgB,KAAK,IAAI,OAAO,QAAQ,CAACI,QAAO,QAAQ;AACvF,QAAI,QAAQ,QAAQ;AAClB;AAAA,IAAA;AAEF,QAAI,QAAQ,aAAa;AACXA,kBAAAA;AACZ;AAAA,IAAA;AAEF,QAAI,QAAQ,aAAa;AACNA,uBAAAA;AACX,YAAA,cAAc,SAASA,QAAO,EAAE;AACtC,UAAI,CAAC,OAAO,MAAM,WAAW,GAAG;AACnB,mBAAA,IAAI,KAAK,cAAc,GAAI;AAAA,MAAA;AAAA,IACxC;AAGF,UAAM,KAAK,GAAG,GAAG,IAAIA,MAAK,EAAE;AAAA,EAAA,CAC7B;AAGD,MAAI,CAAC,WAAW;AACd,WAAOF,cAAG,KAAK,IAAI,sBAAsB,IAAI,CAAC;AAAA,EAAA;AAGhD,MAAI,CAAC,UAAU;AACb,WAAOA,cAAG,KAAK,IAAI,qBAAqB,cAAc,CAAC;AAAA,EAAA;AAInD,QAAA,EAAE,YAAY,MAAA,IAAU;AAC9B,MAAI,YAAY,GAAG;AAEjB,UAAM,cAAc,SAAS,QAAQ,IAAK,YAAY;AAChD,UAAA,QAAQ,KAAK,IAAI;AACvB,QAAI,cAAc,OAAO;AACvB,aAAOA,cAAG,KAAK,IAAI,aAAa,UAAU,IAAI,KAAK,WAAW,GAAG,IAAI,KAAK,KAAK,CAAC,CAAC;AAAA,IAAA;AAAA,EACnF;AAGK,SAAAD,UAAA;AAAA,IACLC,cAAG;AAAA,MACD,MAAM;AACG,eAAAG,eAAAA,cAAc,GAAG,YAAY;AAClC,iBAAO,OAAO,OAAO;AAAA,YACnB;AAAA,YACA,MAAM,OAAO,OAAO;AAAA,cAClB;AAAA,cACA,OAAO;AAAA,gBACL,QAAQ,OACJ,qEACA;AAAA,gBACJ;AAAA,cACF;AAAA,cACA;AAAA,cACA;AAAA,cACA,CAAC,QAAQ;AAAA,YACX;AAAA;AAAA,YAEA,OAAO,KAAK,WAAqB,QAAQ;AAAA,YACzC,OAAO,KAAK,GAAG,KAAK;AAAA,EAAgB,MAAM,KAAK,EAAE,KAAK,IAAI,CAAC,EAAE;AAAA,UAC/D;AAAA,WACC,OAAO;AAAA,MACZ;AAAA,MACA,CAAC,MAAe;AAAA,IAClB;AAAA,IACAH,cAAG,OAAO,CAAc,eAAA;AACf,aAAA,aAAaA,cAAG,MAAM,MAAS,IAAIA,cAAG,KAAK,IAAI,uBAAuB;AAAA,IAC9E,CAAA;AAAA,EACH;AACF;AAKgB,SAAA,YACd,OACA,OACA,SACqB;AACd,SAAAG,eAAAA,cAAc,GAAG,YAAY;AAC5B,UAAAJ,UAAA;AAAA,MACJ,cAAc,OAAO,OAAO,OAAO;AAAA,MACnCC,cAAG,QAAQ,CAAS,UAAA;AACZ,cAAA;AAAA,MACP,CAAA;AAAA,IAAA,EACD;AAAA,EAAA,CACH;AACH;AAQgB,SAAA,aACd,OACA,OACA,SAC8B;AAC9B,SAAOD,UAAAA,KAAK,cAAc,OAAO,OAAO,OAAO,GAAGC,cAAG;AAAA,IACnD,MAAMF,aAAE,MAAM,KAAK;AAAA,IACnB,MAAMA,aAAE,MAAM,IAAI;AAAA,EAAA,CACnB;AACH;AAKgB,SAAA,WACd,OACA,OACA,SACwB;AACjB,SAAAK,eAAA,cAAc,GAAG,MAAMJ,UAAA;AAAA,IAC5B,aAAa,OAAO,OAAO,OAAO;AAAA,IAClCC,cAAG,MAAM,MAAM,OAAO,OAAK,CAAC;AAAA,EAAA,GAC3B;AACL;AAkBO,SAAS,WACd,OACA,OACA,OACA,UACA,UAAkD,IAGD;AAE7C,MAAA;AACA,MAAA;AACA,MAAA;AAGJ,QAAM,QAAkB,CAAC;AAIxB,GAAA,OAAO,UAAU,WAAW,IAAI,gBAAgB,KAAK,IAAI,OAAO,QAAQ,CAACE,QAAO,QAAQ;AACvF,QAAI,QAAQ,QAAQ;AACXA,aAAAA;AACP;AAAA,IAAA;AAGF,QAAI,QAAQ,aAAa;AACNA,uBAAAA;AACX,YAAA,cAAc,SAASA,QAAO,EAAE;AACtC,UAAI,CAAC,OAAO,MAAM,WAAW,GAAG;AACnB,mBAAA,IAAI,KAAK,cAAc,GAAI;AAAA,MAAA;AAAA,IACxC;AAGF,UAAM,KAAK,GAAG,GAAG,IAAIA,MAAK,EAAE;AAAA,EAAA,CAC7B;AAGD,MAAI,CAAC,MAAM;AACD,YAAA,QAAQF,cAAG,OAAOF,aAAE,MAAM,IAAI,sBAAsB,KAAK,CAAC;AAAA,EAAA;AAGpE,MAAI,CAAC,UAAU;AACL,YAAA,QAAQE,cAAG,OAAOF,aAAE,MAAM,IAAI,qBAAqB,cAAc,CAAC;AAAA,EAAA;AAItE,QAAA,EAAE,YAAY,MAAA,IAAU;AAC9B,MAAI,YAAY,GAAG;AAEjB,UAAM,cAAc,SAAS,QAAQ,IAAK,YAAY;AAChD,UAAA,QAAQ,KAAK,IAAI;AACvB,QAAI,cAAc,OAAO;AACf,cAAA,QAAQE,cAAG,OAAOF,aAAE;AAAA,QAC1B,IAAI,aAAa,UAAU,IAAI,KAAK,WAAW,GAAG,IAAI,KAAK,KAAK,CAAC;AAAA,MACnE;AAAA,IAAA;AAAA,EACF;AAIF,QAAM,KAAK;AAEX,QAAM,kBAAkB,SAAS,MAAM,KAAK,IAAI,GAAG,OAAO,OAAO;AACjE,QAAM,SAAS,CAAC,UAAgBA,aAAE,KAAK,KAAK;AAC5C,QAAM,UAAU,CAAC,cACf,cAAc,OAAOA,aAAE,MAAM,MAAS,IAAIA,aAAE,KAAK,IAAI,uBAAuB;AAG9E,SAAO,OAAO,oBAAoB,aAC9BC,UAAAA,KAAK,iBAAiBC,cAAG,OAAO,QAAQ,OAAO,CAAC,IAChDD,UAAK,KAAA,iBAAiBD,aAAE,OAAO,QAAQ,OAAO,CAAC;AACrD;ACnSO,MAAM,QAAQM,aAAAA;AAKd,MAAM,UAAUC,aAAAA;;;;;;;;;;;;;;;;;"}
@@ -4,7 +4,7 @@ const betterPromises = require("better-promises");
4
4
  const E = require("fp-ts/Either");
5
5
  const TE = require("fp-ts/TaskEither");
6
6
  const function_js = require("fp-ts/lib/function.js");
7
- const parsing = require("./parsing-Cj_BXCnv.cjs");
7
+ const parsing = require("./parsing-pEQ1lsuE.cjs");
8
8
  const toolkit = require("@tma.js/toolkit");
9
9
  function _interopNamespaceDefault(e) {
10
10
  const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
@@ -1 +1 @@
1
- {"version":3,"file":"web.cjs","sources":["../../src/entries/web.ts"],"sourcesContent":["import { BetterPromise, type BetterPromiseRejectReason } from 'better-promises';\nimport * as E from 'fp-ts/Either';\nimport * as TE from 'fp-ts/TaskEither';\nimport { pipe } from 'fp-ts/lib/function.js';\n\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 ValidateValue,\n type ValidateAsyncError,\n type ValidateAsyncOptions,\n} from '../validation.js';\nimport {\n AuthDateInvalidError,\n ExpiredError,\n SignatureInvalidError,\n SignatureMissingError,\n HexStringLengthInvalidError,\n} from '../errors.js';\n\nconst createHmac: CreateHmacFn<true> = async (data, key) => {\n const encoder = new TextEncoder();\n\n return crypto.subtle.sign(\n 'HMAC',\n await crypto.subtle.importKey(\n 'raw',\n typeof key === 'string' ? encoder.encode(key) : key,\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['sign', 'verify'],\n ),\n typeof data === 'string' ? encoder.encode(data) : data,\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): Promise<ArrayBuffer> {\n return _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 isValidFp(\n value: ValidateValue,\n token: Text,\n options?: ValidateAsyncOptions,\n): TE.TaskEither<BetterPromiseRejectReason, boolean> {\n return pipe(\n validateFp(value, token, options),\n TE.match(\n error => {\n return [\n AuthDateInvalidError,\n ExpiredError,\n SignatureInvalidError,\n SignatureMissingError,\n HexStringLengthInvalidError,\n ].some(errorClass => errorClass.is(error))\n ? E.right(false)\n : E.left(error);\n },\n () => E.right(true),\n ),\n );\n}\n\n/**\n * @see isValidFp\n */\nexport function isValid(\n value: ValidateValue,\n token: Text,\n options?: ValidateAsyncOptions,\n): BetterPromise<boolean> {\n return BetterPromise.fn(() => {\n return pipe(\n isValidFp(value, token, options),\n TE.match(error => {\n throw error;\n }, isValid => isValid),\n )();\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): TE.TaskEither<SignDataError, string> {\n return _signFp(data, key, authDate, signDataFp, options);\n}\n\n/**\n * @see signFp\n */\nexport function sign(\n data: SignableData,\n key: Text,\n authDate: Date,\n options?: SignOptions,\n): BetterPromise<string> {\n return BetterPromise.fn(() => {\n return pipe(\n signFp(data, key, authDate, options),\n TE.match(e => {\n throw e;\n }, v => v),\n )();\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): TE.TaskEither<SignDataError, string> {\n return _signDataFp(true, data, key, createHmac, options);\n}\n\n/**\n * @see signDataFp\n */\nexport function signData(data: Text, key: Text, options?: SignDataOptions): BetterPromise<string> {\n return BetterPromise.fn(() => {\n return pipe(\n signDataFp(data, key, options),\n TE.match(e => {\n throw e;\n }, v => v),\n )();\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?: ValidateAsyncOptions,\n): TE.TaskEither<ValidateAsyncError, void> {\n return _validateFp(true, value, token, signDataFp, options);\n}\n\n/**\n * @see validateFp\n */\nexport function validate(\n value: ValidateValue,\n token: Text,\n options?: ValidateAsyncOptions,\n): BetterPromise<void> {\n return BetterPromise.fn(async () => {\n await pipe(\n validateFp(value, token, options),\n TE.mapLeft(error => {\n throw error;\n }),\n )();\n });\n}\n\nexport * from './shared.js';\n"],"names":["_hashToken","pipe","TE","AuthDateInvalidError","ExpiredError","SignatureInvalidError","SignatureMissingError","HexStringLengthInvalidError","E","BetterPromise","isValid","_signFp","_signDataFp","_validateFp"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AA2BA,MAAM,aAAiC,OAAO,MAAM,QAAQ;AACpD,QAAA,UAAU,IAAI,YAAY;AAEhC,SAAO,OAAO,OAAO;AAAA,IACnB;AAAA,IACA,MAAM,OAAO,OAAO;AAAA,MAClB;AAAA,MACA,OAAO,QAAQ,WAAW,QAAQ,OAAO,GAAG,IAAI;AAAA,MAChD,EAAE,MAAM,QAAQ,MAAM,UAAU;AAAA,MAChC;AAAA,MACA,CAAC,QAAQ,QAAQ;AAAA,IACnB;AAAA,IACA,OAAO,SAAS,WAAW,QAAQ,OAAO,IAAI,IAAI;AAAA,EACpD;AACF;AAMO,SAAS,UAAU,OAAmC;AACpD,SAAAA,QAAA,UAAW,OAAO,UAAU;AACrC;AAQgB,SAAA,UACd,OACA,OACA,SACmD;AAC5C,SAAAC,YAAA;AAAA,IACL,WAAW,OAAO,OAAO,OAAO;AAAA,IAChCC,cAAG;AAAA,MACD,CAAS,UAAA;AACA,eAAA;AAAA,UACLC,QAAA;AAAA,UACAC,QAAA;AAAA,UACAC,QAAA;AAAA,UACAC,QAAA;AAAA,UACAC,QAAAA;AAAAA,QACA,EAAA,KAAK,CAAc,eAAA,WAAW,GAAG,KAAK,CAAC,IACrCC,aAAE,MAAM,KAAK,IACbA,aAAE,KAAK,KAAK;AAAA,MAClB;AAAA,MACA,MAAMA,aAAE,MAAM,IAAI;AAAA,IAAA;AAAA,EAEtB;AACF;AAKgB,SAAA,QACd,OACA,OACA,SACwB;AACjB,SAAAC,eAAAA,cAAc,GAAG,MAAM;AACrB,WAAAR,YAAA;AAAA,MACL,UAAU,OAAO,OAAO,OAAO;AAAA,MAC/BC,cAAG,MAAM,CAAS,UAAA;AACV,cAAA;AAAA,MAAA,GACL,CAAAQ,aAAWA,QAAO;AAAA,IAAA,EACrB;AAAA,EAAA,CACH;AACH;AAUO,SAAS,OACd,MACA,KACA,UACA,SACsC;AACtC,SAAOC,QAAAA,OAAQ,MAAM,KAAK,UAAU,YAAY,OAAO;AACzD;AAKO,SAAS,KACd,MACA,KACA,UACA,SACuB;AAChB,SAAAF,eAAAA,cAAc,GAAG,MAAM;AACrB,WAAAR,YAAA;AAAA,MACL,OAAO,MAAM,KAAK,UAAU,OAAO;AAAA,MACnCC,cAAG,MAAM,CAAK,MAAA;AACN,cAAA;AAAA,MAAA,GACL,OAAK,CAAC;AAAA,IAAA,EACT;AAAA,EAAA,CACH;AACH;AASgB,SAAA,WACd,MACA,KACA,SACsC;AACtC,SAAOU,QAAAA,WAAY,MAAM,MAAM,KAAK,YAAY,OAAO;AACzD;AAKgB,SAAA,SAAS,MAAY,KAAW,SAAkD;AACzF,SAAAH,eAAAA,cAAc,GAAG,MAAM;AACrB,WAAAR,YAAA;AAAA,MACL,WAAW,MAAM,KAAK,OAAO;AAAA,MAC7BC,cAAG,MAAM,CAAK,MAAA;AACN,cAAA;AAAA,MAAA,GACL,OAAK,CAAC;AAAA,IAAA,EACT;AAAA,EAAA,CACH;AACH;AAQgB,SAAA,WACd,OACA,OACA,SACyC;AACzC,SAAOW,QAAAA,WAAY,MAAM,OAAO,OAAO,YAAY,OAAO;AAC5D;AAKgB,SAAA,SACd,OACA,OACA,SACqB;AACd,SAAAJ,eAAAA,cAAc,GAAG,YAAY;AAC5B,UAAAR,YAAA;AAAA,MACJ,WAAW,OAAO,OAAO,OAAO;AAAA,MAChCC,cAAG,QAAQ,CAAS,UAAA;AACZ,cAAA;AAAA,MACP,CAAA;AAAA,IAAA,EACD;AAAA,EAAA,CACH;AACH;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"web.cjs","sources":["../../src/entries/web.ts"],"sourcesContent":["import { BetterPromise, type BetterPromiseRejectReason } from 'better-promises';\nimport * as E from 'fp-ts/Either';\nimport * as TE from 'fp-ts/TaskEither';\nimport { pipe } from 'fp-ts/lib/function.js';\n\nimport {\n AuthDateInvalidError,\n ExpiredError,\n SignatureInvalidError,\n SignatureMissingError,\n HexStringLengthInvalidError,\n} from '../errors.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 ValidateValue,\n type ValidateAsyncError,\n type ValidateAsyncOptions,\n} from '../validation.js';\n\nconst createHmac: CreateHmacFn<true> = async (data, key) => {\n const encoder = new TextEncoder();\n\n return crypto.subtle.sign(\n 'HMAC',\n await crypto.subtle.importKey(\n 'raw',\n typeof key === 'string' ? encoder.encode(key) : key,\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['sign', 'verify'],\n ),\n typeof data === 'string' ? encoder.encode(data) : data,\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): Promise<ArrayBuffer> {\n return _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 isValidFp(\n value: ValidateValue,\n token: Text,\n options?: ValidateAsyncOptions,\n): TE.TaskEither<BetterPromiseRejectReason, boolean> {\n return pipe(\n validateFp(value, token, options),\n TE.match(\n error => {\n return [\n AuthDateInvalidError,\n ExpiredError,\n SignatureInvalidError,\n SignatureMissingError,\n HexStringLengthInvalidError,\n ].some(errorClass => errorClass.is(error))\n ? E.right(false)\n : E.left(error);\n },\n () => E.right(true),\n ),\n );\n}\n\n/**\n * @see isValidFp\n */\nexport function isValid(\n value: ValidateValue,\n token: Text,\n options?: ValidateAsyncOptions,\n): BetterPromise<boolean> {\n return BetterPromise.fn(() => {\n return pipe(\n isValidFp(value, token, options),\n TE.match(error => {\n throw error;\n }, isValid => isValid),\n )();\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): TE.TaskEither<SignDataError, string> {\n return _signFp(data, key, authDate, signDataFp, options);\n}\n\n/**\n * @see signFp\n */\nexport function sign(\n data: SignableData,\n key: Text,\n authDate: Date,\n options?: SignOptions,\n): BetterPromise<string> {\n return BetterPromise.fn(() => {\n return pipe(\n signFp(data, key, authDate, options),\n TE.match(e => {\n throw e;\n }, v => v),\n )();\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): TE.TaskEither<SignDataError, string> {\n return _signDataFp(true, data, key, createHmac, options);\n}\n\n/**\n * @see signDataFp\n */\nexport function signData(data: Text, key: Text, options?: SignDataOptions): BetterPromise<string> {\n return BetterPromise.fn(() => {\n return pipe(\n signDataFp(data, key, options),\n TE.match(e => {\n throw e;\n }, v => v),\n )();\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?: ValidateAsyncOptions,\n): TE.TaskEither<ValidateAsyncError, void> {\n return _validateFp(true, value, token, signDataFp, options);\n}\n\n/**\n * @see validateFp\n */\nexport function validate(\n value: ValidateValue,\n token: Text,\n options?: ValidateAsyncOptions,\n): BetterPromise<void> {\n return BetterPromise.fn(async () => {\n await pipe(\n validateFp(value, token, options),\n TE.mapLeft(error => {\n throw error;\n }),\n )();\n });\n}\n\nexport * from './shared.js';\n"],"names":["_hashToken","pipe","TE","AuthDateInvalidError","ExpiredError","SignatureInvalidError","SignatureMissingError","HexStringLengthInvalidError","E","BetterPromise","isValid","_signFp","_signDataFp","_validateFp"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AA2BA,MAAM,aAAiC,OAAO,MAAM,QAAQ;AACpD,QAAA,UAAU,IAAI,YAAY;AAEhC,SAAO,OAAO,OAAO;AAAA,IACnB;AAAA,IACA,MAAM,OAAO,OAAO;AAAA,MAClB;AAAA,MACA,OAAO,QAAQ,WAAW,QAAQ,OAAO,GAAG,IAAI;AAAA,MAChD,EAAE,MAAM,QAAQ,MAAM,UAAU;AAAA,MAChC;AAAA,MACA,CAAC,QAAQ,QAAQ;AAAA,IACnB;AAAA,IACA,OAAO,SAAS,WAAW,QAAQ,OAAO,IAAI,IAAI;AAAA,EACpD;AACF;AAMO,SAAS,UAAU,OAAmC;AACpD,SAAAA,QAAA,UAAW,OAAO,UAAU;AACrC;AAQgB,SAAA,UACd,OACA,OACA,SACmD;AAC5C,SAAAC,YAAA;AAAA,IACL,WAAW,OAAO,OAAO,OAAO;AAAA,IAChCC,cAAG;AAAA,MACD,CAAS,UAAA;AACA,eAAA;AAAA,UACLC,QAAA;AAAA,UACAC,QAAA;AAAA,UACAC,QAAA;AAAA,UACAC,QAAA;AAAA,UACAC,QAAAA;AAAAA,QACA,EAAA,KAAK,CAAc,eAAA,WAAW,GAAG,KAAK,CAAC,IACrCC,aAAE,MAAM,KAAK,IACbA,aAAE,KAAK,KAAK;AAAA,MAClB;AAAA,MACA,MAAMA,aAAE,MAAM,IAAI;AAAA,IAAA;AAAA,EAEtB;AACF;AAKgB,SAAA,QACd,OACA,OACA,SACwB;AACjB,SAAAC,eAAAA,cAAc,GAAG,MAAM;AACrB,WAAAR,YAAA;AAAA,MACL,UAAU,OAAO,OAAO,OAAO;AAAA,MAC/BC,cAAG,MAAM,CAAS,UAAA;AACV,cAAA;AAAA,MAAA,GACL,CAAAQ,aAAWA,QAAO;AAAA,IAAA,EACrB;AAAA,EAAA,CACH;AACH;AAUO,SAAS,OACd,MACA,KACA,UACA,SACsC;AACtC,SAAOC,QAAAA,OAAQ,MAAM,KAAK,UAAU,YAAY,OAAO;AACzD;AAKO,SAAS,KACd,MACA,KACA,UACA,SACuB;AAChB,SAAAF,eAAAA,cAAc,GAAG,MAAM;AACrB,WAAAR,YAAA;AAAA,MACL,OAAO,MAAM,KAAK,UAAU,OAAO;AAAA,MACnCC,cAAG,MAAM,CAAK,MAAA;AACN,cAAA;AAAA,MAAA,GACL,OAAK,CAAC;AAAA,IAAA,EACT;AAAA,EAAA,CACH;AACH;AASgB,SAAA,WACd,MACA,KACA,SACsC;AACtC,SAAOU,QAAAA,WAAY,MAAM,MAAM,KAAK,YAAY,OAAO;AACzD;AAKgB,SAAA,SAAS,MAAY,KAAW,SAAkD;AACzF,SAAAH,eAAAA,cAAc,GAAG,MAAM;AACrB,WAAAR,YAAA;AAAA,MACL,WAAW,MAAM,KAAK,OAAO;AAAA,MAC7BC,cAAG,MAAM,CAAK,MAAA;AACN,cAAA;AAAA,MAAA,GACL,OAAK,CAAC;AAAA,IAAA,EACT;AAAA,EAAA,CACH;AACH;AAQgB,SAAA,WACd,OACA,OACA,SACyC;AACzC,SAAOW,QAAAA,WAAY,MAAM,OAAO,OAAO,YAAY,OAAO;AAC5D;AAKgB,SAAA,SACd,OACA,OACA,SACqB;AACd,SAAAJ,eAAAA,cAAc,GAAG,YAAY;AAC5B,UAAAR,YAAA;AAAA,MACJ,WAAW,OAAO,OAAO,OAAO;AAAA,MAChCC,cAAG,QAAQ,CAAS,UAAA;AACZ,cAAA;AAAA,MACP,CAAA;AAAA,IAAA,EACD;AAAA,EAAA,CACH;AACH;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -2,8 +2,8 @@ import { BetterPromise } from "better-promises";
2
2
  import * as E from "fp-ts/Either";
3
3
  import * as TE from "fp-ts/TaskEither";
4
4
  import { pipe } from "fp-ts/lib/function.js";
5
- import { h as hashToken$1, A as AuthDateInvalidError, E as ExpiredError, S as SignatureInvalidError, c as SignatureMissingError, H as HexStringLengthInvalidError, s as signFp$1, a as signDataFp$1, v as validateFp$1 } from "./parsing-eczkSd-W.js";
6
- import { i, e, p, d, f, g } from "./parsing-eczkSd-W.js";
5
+ import { h as hashToken$1, A as AuthDateInvalidError, E as ExpiredError, S as SignatureInvalidError, c as SignatureMissingError, H as HexStringLengthInvalidError, s as signFp$1, a as signDataFp$1, v as validateFp$1 } from "./parsing-B9llLYuO.js";
6
+ import { i, e, p, d, f, g } from "./parsing-B9llLYuO.js";
7
7
  import { deepSnakeToCamelObjKeys } from "@tma.js/toolkit";
8
8
  const createHmac = async (data, key) => {
9
9
  const encoder = new TextEncoder();
@@ -1 +1 @@
1
- {"version":3,"file":"web.js","sources":["../../src/entries/web.ts"],"sourcesContent":["import { BetterPromise, type BetterPromiseRejectReason } from 'better-promises';\nimport * as E from 'fp-ts/Either';\nimport * as TE from 'fp-ts/TaskEither';\nimport { pipe } from 'fp-ts/lib/function.js';\n\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 ValidateValue,\n type ValidateAsyncError,\n type ValidateAsyncOptions,\n} from '../validation.js';\nimport {\n AuthDateInvalidError,\n ExpiredError,\n SignatureInvalidError,\n SignatureMissingError,\n HexStringLengthInvalidError,\n} from '../errors.js';\n\nconst createHmac: CreateHmacFn<true> = async (data, key) => {\n const encoder = new TextEncoder();\n\n return crypto.subtle.sign(\n 'HMAC',\n await crypto.subtle.importKey(\n 'raw',\n typeof key === 'string' ? encoder.encode(key) : key,\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['sign', 'verify'],\n ),\n typeof data === 'string' ? encoder.encode(data) : data,\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): Promise<ArrayBuffer> {\n return _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 isValidFp(\n value: ValidateValue,\n token: Text,\n options?: ValidateAsyncOptions,\n): TE.TaskEither<BetterPromiseRejectReason, boolean> {\n return pipe(\n validateFp(value, token, options),\n TE.match(\n error => {\n return [\n AuthDateInvalidError,\n ExpiredError,\n SignatureInvalidError,\n SignatureMissingError,\n HexStringLengthInvalidError,\n ].some(errorClass => errorClass.is(error))\n ? E.right(false)\n : E.left(error);\n },\n () => E.right(true),\n ),\n );\n}\n\n/**\n * @see isValidFp\n */\nexport function isValid(\n value: ValidateValue,\n token: Text,\n options?: ValidateAsyncOptions,\n): BetterPromise<boolean> {\n return BetterPromise.fn(() => {\n return pipe(\n isValidFp(value, token, options),\n TE.match(error => {\n throw error;\n }, isValid => isValid),\n )();\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): TE.TaskEither<SignDataError, string> {\n return _signFp(data, key, authDate, signDataFp, options);\n}\n\n/**\n * @see signFp\n */\nexport function sign(\n data: SignableData,\n key: Text,\n authDate: Date,\n options?: SignOptions,\n): BetterPromise<string> {\n return BetterPromise.fn(() => {\n return pipe(\n signFp(data, key, authDate, options),\n TE.match(e => {\n throw e;\n }, v => v),\n )();\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): TE.TaskEither<SignDataError, string> {\n return _signDataFp(true, data, key, createHmac, options);\n}\n\n/**\n * @see signDataFp\n */\nexport function signData(data: Text, key: Text, options?: SignDataOptions): BetterPromise<string> {\n return BetterPromise.fn(() => {\n return pipe(\n signDataFp(data, key, options),\n TE.match(e => {\n throw e;\n }, v => v),\n )();\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?: ValidateAsyncOptions,\n): TE.TaskEither<ValidateAsyncError, void> {\n return _validateFp(true, value, token, signDataFp, options);\n}\n\n/**\n * @see validateFp\n */\nexport function validate(\n value: ValidateValue,\n token: Text,\n options?: ValidateAsyncOptions,\n): BetterPromise<void> {\n return BetterPromise.fn(async () => {\n await pipe(\n validateFp(value, token, options),\n TE.mapLeft(error => {\n throw error;\n }),\n )();\n });\n}\n\nexport * from './shared.js';\n"],"names":["_hashToken","isValid","_signFp","e","_signDataFp","_validateFp"],"mappings":";;;;;;;AA2BA,MAAM,aAAiC,OAAO,MAAM,QAAQ;AACpD,QAAA,UAAU,IAAI,YAAY;AAEhC,SAAO,OAAO,OAAO;AAAA,IACnB;AAAA,IACA,MAAM,OAAO,OAAO;AAAA,MAClB;AAAA,MACA,OAAO,QAAQ,WAAW,QAAQ,OAAO,GAAG,IAAI;AAAA,MAChD,EAAE,MAAM,QAAQ,MAAM,UAAU;AAAA,MAChC;AAAA,MACA,CAAC,QAAQ,QAAQ;AAAA,IACnB;AAAA,IACA,OAAO,SAAS,WAAW,QAAQ,OAAO,IAAI,IAAI;AAAA,EACpD;AACF;AAMO,SAAS,UAAU,OAAmC;AACpD,SAAAA,YAAW,OAAO,UAAU;AACrC;AAQgB,SAAA,UACd,OACA,OACA,SACmD;AAC5C,SAAA;AAAA,IACL,WAAW,OAAO,OAAO,OAAO;AAAA,IAChC,GAAG;AAAA,MACD,CAAS,UAAA;AACA,eAAA;AAAA,UACL;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACA,EAAA,KAAK,CAAc,eAAA,WAAW,GAAG,KAAK,CAAC,IACrC,EAAE,MAAM,KAAK,IACb,EAAE,KAAK,KAAK;AAAA,MAClB;AAAA,MACA,MAAM,EAAE,MAAM,IAAI;AAAA,IAAA;AAAA,EAEtB;AACF;AAKgB,SAAA,QACd,OACA,OACA,SACwB;AACjB,SAAA,cAAc,GAAG,MAAM;AACrB,WAAA;AAAA,MACL,UAAU,OAAO,OAAO,OAAO;AAAA,MAC/B,GAAG,MAAM,CAAS,UAAA;AACV,cAAA;AAAA,MAAA,GACL,CAAAC,aAAWA,QAAO;AAAA,IAAA,EACrB;AAAA,EAAA,CACH;AACH;AAUO,SAAS,OACd,MACA,KACA,UACA,SACsC;AACtC,SAAOC,SAAQ,MAAM,KAAK,UAAU,YAAY,OAAO;AACzD;AAKO,SAAS,KACd,MACA,KACA,UACA,SACuB;AAChB,SAAA,cAAc,GAAG,MAAM;AACrB,WAAA;AAAA,MACL,OAAO,MAAM,KAAK,UAAU,OAAO;AAAA,MACnC,GAAG,MAAM,CAAKC,OAAA;AACN,cAAAA;AAAA,MAAA,GACL,OAAK,CAAC;AAAA,IAAA,EACT;AAAA,EAAA,CACH;AACH;AASgB,SAAA,WACd,MACA,KACA,SACsC;AACtC,SAAOC,aAAY,MAAM,MAAM,KAAK,YAAY,OAAO;AACzD;AAKgB,SAAA,SAAS,MAAY,KAAW,SAAkD;AACzF,SAAA,cAAc,GAAG,MAAM;AACrB,WAAA;AAAA,MACL,WAAW,MAAM,KAAK,OAAO;AAAA,MAC7B,GAAG,MAAM,CAAKD,OAAA;AACN,cAAAA;AAAA,MAAA,GACL,OAAK,CAAC;AAAA,IAAA,EACT;AAAA,EAAA,CACH;AACH;AAQgB,SAAA,WACd,OACA,OACA,SACyC;AACzC,SAAOE,aAAY,MAAM,OAAO,OAAO,YAAY,OAAO;AAC5D;AAKgB,SAAA,SACd,OACA,OACA,SACqB;AACd,SAAA,cAAc,GAAG,YAAY;AAC5B,UAAA;AAAA,MACJ,WAAW,OAAO,OAAO,OAAO;AAAA,MAChC,GAAG,QAAQ,CAAS,UAAA;AACZ,cAAA;AAAA,MACP,CAAA;AAAA,IAAA,EACD;AAAA,EAAA,CACH;AACH;"}
1
+ {"version":3,"file":"web.js","sources":["../../src/entries/web.ts"],"sourcesContent":["import { BetterPromise, type BetterPromiseRejectReason } from 'better-promises';\nimport * as E from 'fp-ts/Either';\nimport * as TE from 'fp-ts/TaskEither';\nimport { pipe } from 'fp-ts/lib/function.js';\n\nimport {\n AuthDateInvalidError,\n ExpiredError,\n SignatureInvalidError,\n SignatureMissingError,\n HexStringLengthInvalidError,\n} from '../errors.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 ValidateValue,\n type ValidateAsyncError,\n type ValidateAsyncOptions,\n} from '../validation.js';\n\nconst createHmac: CreateHmacFn<true> = async (data, key) => {\n const encoder = new TextEncoder();\n\n return crypto.subtle.sign(\n 'HMAC',\n await crypto.subtle.importKey(\n 'raw',\n typeof key === 'string' ? encoder.encode(key) : key,\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['sign', 'verify'],\n ),\n typeof data === 'string' ? encoder.encode(data) : data,\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): Promise<ArrayBuffer> {\n return _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 isValidFp(\n value: ValidateValue,\n token: Text,\n options?: ValidateAsyncOptions,\n): TE.TaskEither<BetterPromiseRejectReason, boolean> {\n return pipe(\n validateFp(value, token, options),\n TE.match(\n error => {\n return [\n AuthDateInvalidError,\n ExpiredError,\n SignatureInvalidError,\n SignatureMissingError,\n HexStringLengthInvalidError,\n ].some(errorClass => errorClass.is(error))\n ? E.right(false)\n : E.left(error);\n },\n () => E.right(true),\n ),\n );\n}\n\n/**\n * @see isValidFp\n */\nexport function isValid(\n value: ValidateValue,\n token: Text,\n options?: ValidateAsyncOptions,\n): BetterPromise<boolean> {\n return BetterPromise.fn(() => {\n return pipe(\n isValidFp(value, token, options),\n TE.match(error => {\n throw error;\n }, isValid => isValid),\n )();\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): TE.TaskEither<SignDataError, string> {\n return _signFp(data, key, authDate, signDataFp, options);\n}\n\n/**\n * @see signFp\n */\nexport function sign(\n data: SignableData,\n key: Text,\n authDate: Date,\n options?: SignOptions,\n): BetterPromise<string> {\n return BetterPromise.fn(() => {\n return pipe(\n signFp(data, key, authDate, options),\n TE.match(e => {\n throw e;\n }, v => v),\n )();\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): TE.TaskEither<SignDataError, string> {\n return _signDataFp(true, data, key, createHmac, options);\n}\n\n/**\n * @see signDataFp\n */\nexport function signData(data: Text, key: Text, options?: SignDataOptions): BetterPromise<string> {\n return BetterPromise.fn(() => {\n return pipe(\n signDataFp(data, key, options),\n TE.match(e => {\n throw e;\n }, v => v),\n )();\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?: ValidateAsyncOptions,\n): TE.TaskEither<ValidateAsyncError, void> {\n return _validateFp(true, value, token, signDataFp, options);\n}\n\n/**\n * @see validateFp\n */\nexport function validate(\n value: ValidateValue,\n token: Text,\n options?: ValidateAsyncOptions,\n): BetterPromise<void> {\n return BetterPromise.fn(async () => {\n await pipe(\n validateFp(value, token, options),\n TE.mapLeft(error => {\n throw error;\n }),\n )();\n });\n}\n\nexport * from './shared.js';\n"],"names":["_hashToken","isValid","_signFp","e","_signDataFp","_validateFp"],"mappings":";;;;;;;AA2BA,MAAM,aAAiC,OAAO,MAAM,QAAQ;AACpD,QAAA,UAAU,IAAI,YAAY;AAEhC,SAAO,OAAO,OAAO;AAAA,IACnB;AAAA,IACA,MAAM,OAAO,OAAO;AAAA,MAClB;AAAA,MACA,OAAO,QAAQ,WAAW,QAAQ,OAAO,GAAG,IAAI;AAAA,MAChD,EAAE,MAAM,QAAQ,MAAM,UAAU;AAAA,MAChC;AAAA,MACA,CAAC,QAAQ,QAAQ;AAAA,IACnB;AAAA,IACA,OAAO,SAAS,WAAW,QAAQ,OAAO,IAAI,IAAI;AAAA,EACpD;AACF;AAMO,SAAS,UAAU,OAAmC;AACpD,SAAAA,YAAW,OAAO,UAAU;AACrC;AAQgB,SAAA,UACd,OACA,OACA,SACmD;AAC5C,SAAA;AAAA,IACL,WAAW,OAAO,OAAO,OAAO;AAAA,IAChC,GAAG;AAAA,MACD,CAAS,UAAA;AACA,eAAA;AAAA,UACL;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACA,EAAA,KAAK,CAAc,eAAA,WAAW,GAAG,KAAK,CAAC,IACrC,EAAE,MAAM,KAAK,IACb,EAAE,KAAK,KAAK;AAAA,MAClB;AAAA,MACA,MAAM,EAAE,MAAM,IAAI;AAAA,IAAA;AAAA,EAEtB;AACF;AAKgB,SAAA,QACd,OACA,OACA,SACwB;AACjB,SAAA,cAAc,GAAG,MAAM;AACrB,WAAA;AAAA,MACL,UAAU,OAAO,OAAO,OAAO;AAAA,MAC/B,GAAG,MAAM,CAAS,UAAA;AACV,cAAA;AAAA,MAAA,GACL,CAAAC,aAAWA,QAAO;AAAA,IAAA,EACrB;AAAA,EAAA,CACH;AACH;AAUO,SAAS,OACd,MACA,KACA,UACA,SACsC;AACtC,SAAOC,SAAQ,MAAM,KAAK,UAAU,YAAY,OAAO;AACzD;AAKO,SAAS,KACd,MACA,KACA,UACA,SACuB;AAChB,SAAA,cAAc,GAAG,MAAM;AACrB,WAAA;AAAA,MACL,OAAO,MAAM,KAAK,UAAU,OAAO;AAAA,MACnC,GAAG,MAAM,CAAKC,OAAA;AACN,cAAAA;AAAA,MAAA,GACL,OAAK,CAAC;AAAA,IAAA,EACT;AAAA,EAAA,CACH;AACH;AASgB,SAAA,WACd,MACA,KACA,SACsC;AACtC,SAAOC,aAAY,MAAM,MAAM,KAAK,YAAY,OAAO;AACzD;AAKgB,SAAA,SAAS,MAAY,KAAW,SAAkD;AACzF,SAAA,cAAc,GAAG,MAAM;AACrB,WAAA;AAAA,MACL,WAAW,MAAM,KAAK,OAAO;AAAA,MAC7B,GAAG,MAAM,CAAKD,OAAA;AACN,cAAAA;AAAA,MAAA,GACL,OAAK,CAAC;AAAA,IAAA,EACT;AAAA,EAAA,CACH;AACH;AAQgB,SAAA,WACd,OACA,OACA,SACyC;AACzC,SAAOE,aAAY,MAAM,OAAO,OAAO,YAAY,OAAO;AAC5D;AAKgB,SAAA,SACd,OACA,OACA,SACqB;AACd,SAAA,cAAc,GAAG,YAAY;AAC5B,UAAA;AAAA,MACJ,WAAW,OAAO,OAAO,OAAO;AAAA,MAChC,GAAG,QAAQ,CAAS,UAAA;AACZ,cAAA;AAAA,MACP,CAAA;AAAA,IAAA,EACD;AAAA,EAAA,CACH;AACH;"}
package/dist/signFp.d.ts CHANGED
@@ -2,7 +2,9 @@ import { InitDataLike } from '@tma.js/transformers';
2
2
  import { Text } from './types.js';
3
3
  import * as E from 'fp-ts/Either';
4
4
  import * as TE from 'fp-ts/TaskEither';
5
- export type SignableData = Omit<InitDataLike, 'auth_date' | 'hash' | 'signature'>;
5
+ export type SignableData = Omit<InitDataLike, 'auth_date' | 'hash' | 'signature'> & {
6
+ signature?: string;
7
+ };
6
8
  export interface SignOptions {
7
9
  /**
8
10
  * True, if token is already hashed and doesn't require hashing using HMAC-SHA-256.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tma.js/init-data-node",
3
- "version": "2.0.3",
3
+ "version": "2.0.5",
4
4
  "description": "TypeScript Node library to operate with Telegram init data.",
5
5
  "author": "Vladislav Kibenko <wolfram.deus@gmail.com>",
6
6
  "homepage": "https://github.com/Telegram-Mini-Apps/tma.js#readme",
@@ -53,8 +53,8 @@
53
53
  "better-promises": "^1.0.0",
54
54
  "error-kid": "^1.0.2",
55
55
  "fp-ts": "^2.16.11",
56
- "@tma.js/toolkit": "^1.0.2",
57
- "@tma.js/transformers": "^1.1.1",
56
+ "@tma.js/toolkit": "^1.0.3",
57
+ "@tma.js/transformers": "^1.1.2",
58
58
  "@tma.js/types": "^1.0.2"
59
59
  },
60
60
  "scripts": {
@@ -1 +0,0 @@
1
- {"version":3,"file":"parsing-Cj_BXCnv.cjs","sources":["../../src/errors.ts","../../src/buf-converters.ts","../../src/hashToken.ts","../../src/signDataFp.ts","../../src/signFp.ts","../../src/validation.ts","../../src/parsing.ts"],"sourcesContent":["import { errorClass, errorClassWithData } from 'error-kid';\n\nexport class AuthDateInvalidError extends errorClassWithData<\n { value: string | undefined },\n [value?: string]\n>(\n 'AuthDateInvalidError',\n value => ({ value }),\n value => [`\"auth_date\" is invalid: ${value || 'value is missing'}`],\n) {\n}\n\nexport class SignatureInvalidError extends errorClass('SignatureInvalidError') {\n}\n\nexport class HexStringLengthInvalidError extends errorClass(\n 'HexStringLengthInvalidError',\n) {\n}\n\nexport class SignatureMissingError extends errorClass<[thirdParty: boolean]>(\n 'SignatureMissingError',\n thirdParty => [`\"${thirdParty ? 'signature' : 'hash'}\" parameter is missing`],\n) {\n}\n\nexport class ExpiredError extends errorClassWithData<\n { issuedAt: Date; expiresAt: Date },\n [issuedAt: Date, expiresAt: Date, now: Date]\n>(\n 'ExpiredError',\n (issuedAt, expiresAt) => ({ issuedAt, expiresAt }),\n (issuedAt, expiresAt, now) => [\n `Init data expired. Issued at ${issuedAt.toISOString()}, expires at ${expiresAt.toISOString()}, now is ${now.toISOString()}`,\n ],\n) {\n}\n","import * as E from 'fp-ts/Either';\n\nimport { HexStringLengthInvalidError } from './errors.js';\n\n/**\n * Converts a hex string to ArrayBuffer.\n * @param hexString - value to convert.\n */\nexport function hexToArrayBuffer(hexString: string): E.Either<\n InstanceType<typeof HexStringLengthInvalidError>,\n ArrayBuffer\n> {\n if (hexString.length % 2 !== 0) {\n return E.left(new HexStringLengthInvalidError());\n }\n const buffer = new ArrayBuffer(hexString.length / 2);\n const uint8Array = new Uint8Array(buffer);\n for (let i = 0; i < hexString.length; i += 2) {\n uint8Array[i / 2] = parseInt(hexString.substring(i, i + 2), 16);\n }\n return E.right(buffer);\n}\n\n/**\n * Converts array buffer to hex.\n * @param arrBuf - buffer to convert\n */\nexport function arrayBufferToHex(arrBuf: ArrayBuffer): string {\n return new Uint8Array(arrBuf).reduce((acc, byte) => {\n // Convert byte to hex and pad with zero if needed (e.g., \"0a\" instead of \"a\")\n return acc + byte.toString(16).padStart(2, '0');\n }, '');\n}\n\nexport function bufferToArrayBuffer(buf: Buffer) {\n const ab = new ArrayBuffer(buf.length);\n buf.copy(new Uint8Array(ab));\n return ab;\n}\n","import type { CreateHmacFn, Text } from './types.js';\n\nexport function hashToken<H extends CreateHmacFn<any>>(token: Text, createHmac: H): ReturnType<H> {\n return createHmac(token, 'WebAppData') as ReturnType<H>;\n}\n","import * as E from 'fp-ts/Either';\nimport * as TE from 'fp-ts/TaskEither';\nimport { pipe } from 'fp-ts/lib/function.js';\n\nimport { arrayBufferToHex, hexToArrayBuffer } from './buf-converters.js';\nimport { hashToken } from './hashToken.js';\nimport type { CreateHmacFn, Text } from './types.js';\n\nexport interface SignDataOptions {\n /**\n * True, if token is already hashed and doesn't require hashing using HMAC-SHA-256.\n */\n tokenHashed?: boolean;\n}\n\nexport type SignDataError = ReturnType<typeof hexToArrayBuffer> extends E.Either<infer U, any>\n ? U\n : never;\n\nexport function signDataFp(\n async: false,\n data: Text,\n key: Text,\n createHmac: CreateHmacFn<false>,\n options?: SignDataOptions,\n): E.Either<SignDataError, string>;\n\nexport function signDataFp(\n async: true,\n data: Text,\n key: Text,\n createHmac: CreateHmacFn<true>,\n options?: SignDataOptions,\n): TE.TaskEither<SignDataError, string>;\n\nexport function signDataFp(\n async: boolean,\n data: Text,\n key: Text,\n createHmac: CreateHmacFn<boolean>,\n options: SignDataOptions = {},\n):\n | E.Either<SignDataError, string>\n | TE.TaskEither<SignDataError, string> {\n const keyHmac = options.tokenHashed\n ? typeof key === 'string'\n // If a hashed token was passed, we assume that it is a HEX string. Not to mess with\n // the createHmac function, we should convert this HEX string to ArrayBuffer. Otherwise,\n // incorrect behavior will be met.\n ? hexToArrayBuffer(key)\n : E.right(key)\n // Otherwise we are hashing the token, but we want it to be a monad.\n : pipe(\n E.right(hashToken(key, createHmac)),\n E.match(() => null as never, v => {\n return v instanceof Promise\n ? TE.tryCatch(() => v, err => err as SignDataError)\n : E.right(v);\n }),\n );\n\n if (async || typeof keyHmac === 'function') {\n return pipe(\n typeof keyHmac === 'function' ? keyHmac : TE.fromEither(keyHmac),\n TE.chain(v => TE.tryCatch(\n () => Promise.resolve(createHmac(data, v)).then(arrayBufferToHex),\n err => err as SignDataError,\n )),\n );\n }\n return pipe(\n keyHmac,\n // In this branch createHmac can't be asynchronous. If it is, keyHmac would be Promise and the\n // result would be returned in the previous \"if\" statement.\n E.chain(v => E.right(\n arrayBufferToHex((createHmac as CreateHmacFn<false>)(data, v)),\n )),\n );\n}\n","import { type InitDataLike, serializeInitDataQuery } from '@tma.js/transformers';\nimport * as E from 'fp-ts/Either';\nimport * as TE from 'fp-ts/TaskEither';\nimport { pipe } from 'fp-ts/lib/function.js';\n\nimport type { Text } from './types.js';\n\nexport type SignableData = Omit<InitDataLike, 'auth_date' | 'hash' | 'signature'>;\n\nexport interface SignOptions {\n /**\n * True, if token is already hashed and doesn't require hashing using HMAC-SHA-256.\n */\n tokenHashed?: boolean;\n}\n\ninterface SignDataFpArg<Async extends boolean, Left> {\n (data: Text, key: Text, options?: SignOptions): Async extends true\n ? TE.TaskEither<Left, string>\n : E.Either<Left, string>;\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 signData - function signing data.\n * @param options - additional options.\n * @returns Signed init data presented as query parameters.\n */\nexport function signFp<Left>(\n data: SignableData,\n key: Text,\n authDate: Date,\n signData: SignDataFpArg<false, Left>,\n options?: SignOptions,\n): E.Either<Left, string>;\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 signData - function signing data.\n * @param options - additional options.\n * @returns Signed init data presented as query parameters.\n */\nexport function signFp<Left>(\n data: SignableData,\n key: Text,\n authDate: Date,\n signData: SignDataFpArg<true, Left>,\n options?: SignOptions,\n): TE.TaskEither<Left, string>;\n\nexport function signFp<Left>(\n data: SignableData,\n key: Text,\n authDate: Date,\n signData: SignDataFpArg<boolean, Left>,\n options?: SignOptions,\n): E.Either<Left, string> | TE.TaskEither<Left, string> {\n const query = new URLSearchParams(serializeInitDataQuery({ ...data, auth_date: authDate }));\n\n // Convert search params to pairs and sort the final array.\n const pairs = [...query.entries()]\n .map(([name, value]) => `${name}=${value}`)\n .sort();\n\n // Compute sign, append it to the params and return.\n const queryWithHash = (signature: string): string => {\n query.append('hash', signature);\n return query.toString();\n };\n\n const eitherHash = signData(pairs.join('\\n'), key, options);\n return typeof eitherHash === 'function'\n ? pipe(eitherHash, TE.chain(hash => TE.right(queryWithHash(hash))))\n : pipe(eitherHash, E.chain(hash => E.right(queryWithHash(hash))));\n}\n","import * as E from 'fp-ts/Either';\nimport * as TE from 'fp-ts/TaskEither';\nimport { pipe } from 'fp-ts/function';\nimport {\n BetterPromise,\n type BetterPromiseOptions,\n type BetterPromiseRejectReason,\n} from 'better-promises';\n\nimport {\n AuthDateInvalidError,\n ExpiredError,\n SignatureInvalidError,\n SignatureMissingError,\n} from './errors.js';\nimport { Text } from './types.js';\n\ntype OmittedPromiseOptions = Omit<BetterPromiseOptions, 'abortOnResolve' | 'abortOnReject'>;\n\nexport type ValidateValue = string | URLSearchParams;\nexport type Validate3rdValue = string | URLSearchParams;\n\nexport type ValidateError =\n | SignatureMissingError\n | SignatureInvalidError\n | AuthDateInvalidError\n | ExpiredError;\nexport type ValidateAsyncError = ValidateError | BetterPromiseRejectReason;\nexport type Validate3rdError =\n | SignatureMissingError\n | SignatureInvalidError\n | AuthDateInvalidError\n | ExpiredError\n | BetterPromiseRejectReason;\n\ninterface ValidateSignDataFpArg<Async extends boolean, Left> {\n (data: Text, key: Text, options?: ValidateOptions): Async extends true\n ? TE.TaskEither<Left, string>\n : E.Either<Left, string>;\n}\n\ninterface SharedValidateOptions {\n /**\n * Time in seconds which states, how long from creation time init data is considered valid.\n *\n * In other words, in case when authDate + expiresIn is before current time, init data is\n * recognized as expired.\n *\n * In case this value is equal to 0, the function does not check init data expiration.\n * @default 86400 (1 day)\n */\n expiresIn?: number;\n}\n\nexport interface ValidateOptions extends SharedValidateOptions {\n /**\n * True, if token is already hashed.\n * @default false\n */\n tokenHashed?: boolean;\n}\n\nexport interface ValidateAsyncOptions extends ValidateOptions, OmittedPromiseOptions {\n}\n\nexport interface Validate3rdOptions extends SharedValidateOptions, OmittedPromiseOptions {\n /**\n * When true, uses the test environment public key to validate init data.\n * @default false\n */\n test?: boolean;\n}\n\n/**\n * Validates passed init data using a publicly known Ee25519 key.\n * @param value - value to check.\n * @param botId - bot identifier\n * @param options - additional validation options.\n */\nexport function validate3rdFp(\n value: Validate3rdValue,\n botId: number,\n options: Validate3rdOptions = {},\n): TE.TaskEither<Validate3rdError, void> {\n // Init data required params.\n let authDate: Date | undefined;\n let authDateString: string | undefined;\n let signature: string | undefined;\n\n // All search params pairs presented as `k=v`.\n const pairs: string[] = [];\n\n // Iterate over all key-value pairs of parsed parameters and find required\n // parameters.\n (typeof value === 'string' ? new URLSearchParams(value) : value).forEach((value, key) => {\n if (key === 'hash') {\n return;\n }\n if (key === 'signature') {\n signature = value;\n return;\n }\n if (key === 'auth_date') {\n authDateString = value;\n const authDateNum = parseInt(value, 10);\n if (!Number.isNaN(authDateNum)) {\n authDate = new Date(authDateNum * 1000);\n }\n }\n\n pairs.push(`${key}=${value}`);\n });\n\n // Signature and auth date always required.\n if (!signature) {\n return TE.left(new SignatureMissingError(true));\n }\n\n if (!authDate) {\n return TE.left(new AuthDateInvalidError(authDateString));\n }\n\n // In case, expiration time passed, we do additional parameters check.\n const { expiresIn = 86400 } = options;\n if (expiresIn > 0) {\n // Check if init data expired.\n const expiresAtTs = authDate.getTime() + (expiresIn * 1000);\n const nowTs = Date.now();\n if (expiresAtTs < nowTs) {\n return TE.left(new ExpiredError(authDate, new Date(expiresAtTs), new Date(nowTs)));\n }\n }\n\n return pipe(\n TE.tryCatch(\n () => {\n return BetterPromise.fn(async () => {\n return crypto.subtle.verify(\n 'Ed25519',\n await crypto.subtle.importKey(\n 'raw',\n Buffer.from(\n options.test\n ? '40055058a4ee38156a06562e52eece92a771bcd8346a8c4615cb7376eddf72ec'\n : 'e7bf03a2fa4602af4580703d88dda5bb59f32ed8b02a56c187fe7d34caed242d',\n 'hex',\n ),\n 'Ed25519',\n false,\n ['verify'],\n ),\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion\n Buffer.from(signature as string, 'base64'),\n Buffer.from(`${botId}:WebAppData\\n${pairs.sort().join('\\n')}`),\n );\n }, options);\n },\n (e: unknown) => e,\n ),\n TE.chainW(isVerified => {\n return isVerified ? TE.right(undefined) : TE.left(new SignatureInvalidError());\n }),\n );\n}\n\n/**\n * @see validate3rdFp\n */\nexport function validate3rd(\n value: Validate3rdValue,\n botId: number,\n options?: Validate3rdOptions,\n): BetterPromise<void> {\n return BetterPromise.fn(async () => {\n await pipe(\n validate3rdFp(value, botId, options),\n TE.mapLeft(error => {\n throw error;\n }),\n )();\n });\n}\n\n/**\n * @param value - value to check.\n * @param botId - bot identifier\n * @param options - additional validation options.\n * @returns True is specified init data is signed by Telegram.\n */\nexport function isValid3rdFp(\n value: Validate3rdValue,\n botId: number,\n options?: Validate3rdOptions,\n): TE.TaskEither<void, boolean> {\n return pipe(validate3rdFp(value, botId, options), TE.match(\n () => E.right(false),\n () => E.right(true),\n ));\n}\n\n/**\n * @see isValid3rdFp\n */\nexport function isValid3rd(\n value: Validate3rdValue,\n botId: number,\n options?: Validate3rdOptions,\n): BetterPromise<boolean> {\n return BetterPromise.fn(() => pipe(\n isValid3rdFp(value, botId, options),\n TE.match(() => false, v => v),\n )());\n}\n\nexport function validateFp<Left>(\n async: false,\n value: ValidateValue,\n token: Text,\n signData: ValidateSignDataFpArg<false, Left>,\n options?: ValidateOptions,\n): E.Either<Left | ValidateError, void>;\n\nexport function validateFp<Left>(\n async: true,\n value: ValidateValue,\n token: Text,\n signData: ValidateSignDataFpArg<true, Left>,\n options?: ValidateAsyncOptions,\n): TE.TaskEither<Left | ValidateAsyncError, void>;\n\nexport function validateFp<Left>(\n async: boolean,\n value: ValidateValue,\n token: Text,\n signData: ValidateSignDataFpArg<boolean, Left>,\n options: ValidateOptions | ValidateAsyncOptions = {},\n):\n | E.Either<Left | ValidateError, void>\n | TE.TaskEither<Left | ValidateAsyncError, void> {\n // Init data required params.\n let authDate: Date | undefined;\n let authDateString: string | undefined;\n let hash: string | undefined;\n\n // All search params pairs presented as `k=v`.\n const pairs: string[] = [];\n\n // Iterate over all key-value pairs of parsed parameters and find required\n // parameters.\n (typeof value === 'string' ? new URLSearchParams(value) : value).forEach((value, key) => {\n if (key === 'hash') {\n hash = value;\n return;\n }\n\n if (key === 'auth_date') {\n authDateString = value;\n const authDateNum = parseInt(value, 10);\n if (!Number.isNaN(authDateNum)) {\n authDate = new Date(authDateNum * 1000);\n }\n }\n\n pairs.push(`${key}=${value}`);\n });\n\n // Hash and auth date always required.\n if (!hash) {\n return (async ? TE.left : E.left)(new SignatureMissingError(false));\n }\n\n if (!authDate) {\n return (async ? TE.left : E.left)(new AuthDateInvalidError(authDateString));\n }\n\n // In case, expiration time passed, we do additional parameters check.\n const { expiresIn = 86400 } = options;\n if (expiresIn > 0) {\n // Check if init data expired.\n const expiresAtTs = authDate.getTime() + (expiresIn * 1000);\n const nowTs = Date.now();\n if (expiresAtTs < nowTs) {\n return (async ? TE.left : E.left)(\n new ExpiredError(authDate, new Date(expiresAtTs), new Date(nowTs)),\n );\n }\n }\n\n // According to docs, we sort all the pairs in alphabetical order.\n pairs.sort();\n\n const eitherSignature = signData(pairs.join('\\n'), token, options);\n const onLeft = (error: Left) => E.left(error);\n const onRight = (signature: string) => (\n signature === hash ? E.right(undefined) : E.left(new SignatureInvalidError())\n );\n\n return typeof eitherSignature === 'function'\n ? pipe(eitherSignature, TE.matchW(onLeft, onRight))\n : pipe(eitherSignature, E.matchW(onLeft, onRight));\n}\n","import {\n parseInitDataQuery,\n parseInitDataQueryFp,\n type ParseInitDataQueryError,\n} from '@tma.js/transformers';\n\n/**\n * Parses an incoming value as init data.\n */\nexport const parse = parseInitDataQuery;\n\n/**\n * Parses an incoming value as init data.\n */\nexport const parseFp = parseInitDataQueryFp;\n\nexport { ParseInitDataQueryError as ParseError };\n"],"names":["errorClassWithData","errorClass","E","pipe","TE","serializeInitDataQuery","value","BetterPromise","parseInitDataQuery","parseInitDataQueryFp"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"parsing-eczkSd-W.js","sources":["../../src/errors.ts","../../src/buf-converters.ts","../../src/hashToken.ts","../../src/signDataFp.ts","../../src/signFp.ts","../../src/validation.ts","../../src/parsing.ts"],"sourcesContent":["import { errorClass, errorClassWithData } from 'error-kid';\n\nexport class AuthDateInvalidError extends errorClassWithData<\n { value: string | undefined },\n [value?: string]\n>(\n 'AuthDateInvalidError',\n value => ({ value }),\n value => [`\"auth_date\" is invalid: ${value || 'value is missing'}`],\n) {\n}\n\nexport class SignatureInvalidError extends errorClass('SignatureInvalidError') {\n}\n\nexport class HexStringLengthInvalidError extends errorClass(\n 'HexStringLengthInvalidError',\n) {\n}\n\nexport class SignatureMissingError extends errorClass<[thirdParty: boolean]>(\n 'SignatureMissingError',\n thirdParty => [`\"${thirdParty ? 'signature' : 'hash'}\" parameter is missing`],\n) {\n}\n\nexport class ExpiredError extends errorClassWithData<\n { issuedAt: Date; expiresAt: Date },\n [issuedAt: Date, expiresAt: Date, now: Date]\n>(\n 'ExpiredError',\n (issuedAt, expiresAt) => ({ issuedAt, expiresAt }),\n (issuedAt, expiresAt, now) => [\n `Init data expired. Issued at ${issuedAt.toISOString()}, expires at ${expiresAt.toISOString()}, now is ${now.toISOString()}`,\n ],\n) {\n}\n","import * as E from 'fp-ts/Either';\n\nimport { HexStringLengthInvalidError } from './errors.js';\n\n/**\n * Converts a hex string to ArrayBuffer.\n * @param hexString - value to convert.\n */\nexport function hexToArrayBuffer(hexString: string): E.Either<\n InstanceType<typeof HexStringLengthInvalidError>,\n ArrayBuffer\n> {\n if (hexString.length % 2 !== 0) {\n return E.left(new HexStringLengthInvalidError());\n }\n const buffer = new ArrayBuffer(hexString.length / 2);\n const uint8Array = new Uint8Array(buffer);\n for (let i = 0; i < hexString.length; i += 2) {\n uint8Array[i / 2] = parseInt(hexString.substring(i, i + 2), 16);\n }\n return E.right(buffer);\n}\n\n/**\n * Converts array buffer to hex.\n * @param arrBuf - buffer to convert\n */\nexport function arrayBufferToHex(arrBuf: ArrayBuffer): string {\n return new Uint8Array(arrBuf).reduce((acc, byte) => {\n // Convert byte to hex and pad with zero if needed (e.g., \"0a\" instead of \"a\")\n return acc + byte.toString(16).padStart(2, '0');\n }, '');\n}\n\nexport function bufferToArrayBuffer(buf: Buffer) {\n const ab = new ArrayBuffer(buf.length);\n buf.copy(new Uint8Array(ab));\n return ab;\n}\n","import type { CreateHmacFn, Text } from './types.js';\n\nexport function hashToken<H extends CreateHmacFn<any>>(token: Text, createHmac: H): ReturnType<H> {\n return createHmac(token, 'WebAppData') as ReturnType<H>;\n}\n","import * as E from 'fp-ts/Either';\nimport * as TE from 'fp-ts/TaskEither';\nimport { pipe } from 'fp-ts/lib/function.js';\n\nimport { arrayBufferToHex, hexToArrayBuffer } from './buf-converters.js';\nimport { hashToken } from './hashToken.js';\nimport type { CreateHmacFn, Text } from './types.js';\n\nexport interface SignDataOptions {\n /**\n * True, if token is already hashed and doesn't require hashing using HMAC-SHA-256.\n */\n tokenHashed?: boolean;\n}\n\nexport type SignDataError = ReturnType<typeof hexToArrayBuffer> extends E.Either<infer U, any>\n ? U\n : never;\n\nexport function signDataFp(\n async: false,\n data: Text,\n key: Text,\n createHmac: CreateHmacFn<false>,\n options?: SignDataOptions,\n): E.Either<SignDataError, string>;\n\nexport function signDataFp(\n async: true,\n data: Text,\n key: Text,\n createHmac: CreateHmacFn<true>,\n options?: SignDataOptions,\n): TE.TaskEither<SignDataError, string>;\n\nexport function signDataFp(\n async: boolean,\n data: Text,\n key: Text,\n createHmac: CreateHmacFn<boolean>,\n options: SignDataOptions = {},\n):\n | E.Either<SignDataError, string>\n | TE.TaskEither<SignDataError, string> {\n const keyHmac = options.tokenHashed\n ? typeof key === 'string'\n // If a hashed token was passed, we assume that it is a HEX string. Not to mess with\n // the createHmac function, we should convert this HEX string to ArrayBuffer. Otherwise,\n // incorrect behavior will be met.\n ? hexToArrayBuffer(key)\n : E.right(key)\n // Otherwise we are hashing the token, but we want it to be a monad.\n : pipe(\n E.right(hashToken(key, createHmac)),\n E.match(() => null as never, v => {\n return v instanceof Promise\n ? TE.tryCatch(() => v, err => err as SignDataError)\n : E.right(v);\n }),\n );\n\n if (async || typeof keyHmac === 'function') {\n return pipe(\n typeof keyHmac === 'function' ? keyHmac : TE.fromEither(keyHmac),\n TE.chain(v => TE.tryCatch(\n () => Promise.resolve(createHmac(data, v)).then(arrayBufferToHex),\n err => err as SignDataError,\n )),\n );\n }\n return pipe(\n keyHmac,\n // In this branch createHmac can't be asynchronous. If it is, keyHmac would be Promise and the\n // result would be returned in the previous \"if\" statement.\n E.chain(v => E.right(\n arrayBufferToHex((createHmac as CreateHmacFn<false>)(data, v)),\n )),\n );\n}\n","import { type InitDataLike, serializeInitDataQuery } from '@tma.js/transformers';\nimport * as E from 'fp-ts/Either';\nimport * as TE from 'fp-ts/TaskEither';\nimport { pipe } from 'fp-ts/lib/function.js';\n\nimport type { Text } from './types.js';\n\nexport type SignableData = Omit<InitDataLike, 'auth_date' | 'hash' | 'signature'>;\n\nexport interface SignOptions {\n /**\n * True, if token is already hashed and doesn't require hashing using HMAC-SHA-256.\n */\n tokenHashed?: boolean;\n}\n\ninterface SignDataFpArg<Async extends boolean, Left> {\n (data: Text, key: Text, options?: SignOptions): Async extends true\n ? TE.TaskEither<Left, string>\n : E.Either<Left, string>;\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 signData - function signing data.\n * @param options - additional options.\n * @returns Signed init data presented as query parameters.\n */\nexport function signFp<Left>(\n data: SignableData,\n key: Text,\n authDate: Date,\n signData: SignDataFpArg<false, Left>,\n options?: SignOptions,\n): E.Either<Left, string>;\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 signData - function signing data.\n * @param options - additional options.\n * @returns Signed init data presented as query parameters.\n */\nexport function signFp<Left>(\n data: SignableData,\n key: Text,\n authDate: Date,\n signData: SignDataFpArg<true, Left>,\n options?: SignOptions,\n): TE.TaskEither<Left, string>;\n\nexport function signFp<Left>(\n data: SignableData,\n key: Text,\n authDate: Date,\n signData: SignDataFpArg<boolean, Left>,\n options?: SignOptions,\n): E.Either<Left, string> | TE.TaskEither<Left, string> {\n const query = new URLSearchParams(serializeInitDataQuery({ ...data, auth_date: authDate }));\n\n // Convert search params to pairs and sort the final array.\n const pairs = [...query.entries()]\n .map(([name, value]) => `${name}=${value}`)\n .sort();\n\n // Compute sign, append it to the params and return.\n const queryWithHash = (signature: string): string => {\n query.append('hash', signature);\n return query.toString();\n };\n\n const eitherHash = signData(pairs.join('\\n'), key, options);\n return typeof eitherHash === 'function'\n ? pipe(eitherHash, TE.chain(hash => TE.right(queryWithHash(hash))))\n : pipe(eitherHash, E.chain(hash => E.right(queryWithHash(hash))));\n}\n","import * as E from 'fp-ts/Either';\nimport * as TE from 'fp-ts/TaskEither';\nimport { pipe } from 'fp-ts/function';\nimport {\n BetterPromise,\n type BetterPromiseOptions,\n type BetterPromiseRejectReason,\n} from 'better-promises';\n\nimport {\n AuthDateInvalidError,\n ExpiredError,\n SignatureInvalidError,\n SignatureMissingError,\n} from './errors.js';\nimport { Text } from './types.js';\n\ntype OmittedPromiseOptions = Omit<BetterPromiseOptions, 'abortOnResolve' | 'abortOnReject'>;\n\nexport type ValidateValue = string | URLSearchParams;\nexport type Validate3rdValue = string | URLSearchParams;\n\nexport type ValidateError =\n | SignatureMissingError\n | SignatureInvalidError\n | AuthDateInvalidError\n | ExpiredError;\nexport type ValidateAsyncError = ValidateError | BetterPromiseRejectReason;\nexport type Validate3rdError =\n | SignatureMissingError\n | SignatureInvalidError\n | AuthDateInvalidError\n | ExpiredError\n | BetterPromiseRejectReason;\n\ninterface ValidateSignDataFpArg<Async extends boolean, Left> {\n (data: Text, key: Text, options?: ValidateOptions): Async extends true\n ? TE.TaskEither<Left, string>\n : E.Either<Left, string>;\n}\n\ninterface SharedValidateOptions {\n /**\n * Time in seconds which states, how long from creation time init data is considered valid.\n *\n * In other words, in case when authDate + expiresIn is before current time, init data is\n * recognized as expired.\n *\n * In case this value is equal to 0, the function does not check init data expiration.\n * @default 86400 (1 day)\n */\n expiresIn?: number;\n}\n\nexport interface ValidateOptions extends SharedValidateOptions {\n /**\n * True, if token is already hashed.\n * @default false\n */\n tokenHashed?: boolean;\n}\n\nexport interface ValidateAsyncOptions extends ValidateOptions, OmittedPromiseOptions {\n}\n\nexport interface Validate3rdOptions extends SharedValidateOptions, OmittedPromiseOptions {\n /**\n * When true, uses the test environment public key to validate init data.\n * @default false\n */\n test?: boolean;\n}\n\n/**\n * Validates passed init data using a publicly known Ee25519 key.\n * @param value - value to check.\n * @param botId - bot identifier\n * @param options - additional validation options.\n */\nexport function validate3rdFp(\n value: Validate3rdValue,\n botId: number,\n options: Validate3rdOptions = {},\n): TE.TaskEither<Validate3rdError, void> {\n // Init data required params.\n let authDate: Date | undefined;\n let authDateString: string | undefined;\n let signature: string | undefined;\n\n // All search params pairs presented as `k=v`.\n const pairs: string[] = [];\n\n // Iterate over all key-value pairs of parsed parameters and find required\n // parameters.\n (typeof value === 'string' ? new URLSearchParams(value) : value).forEach((value, key) => {\n if (key === 'hash') {\n return;\n }\n if (key === 'signature') {\n signature = value;\n return;\n }\n if (key === 'auth_date') {\n authDateString = value;\n const authDateNum = parseInt(value, 10);\n if (!Number.isNaN(authDateNum)) {\n authDate = new Date(authDateNum * 1000);\n }\n }\n\n pairs.push(`${key}=${value}`);\n });\n\n // Signature and auth date always required.\n if (!signature) {\n return TE.left(new SignatureMissingError(true));\n }\n\n if (!authDate) {\n return TE.left(new AuthDateInvalidError(authDateString));\n }\n\n // In case, expiration time passed, we do additional parameters check.\n const { expiresIn = 86400 } = options;\n if (expiresIn > 0) {\n // Check if init data expired.\n const expiresAtTs = authDate.getTime() + (expiresIn * 1000);\n const nowTs = Date.now();\n if (expiresAtTs < nowTs) {\n return TE.left(new ExpiredError(authDate, new Date(expiresAtTs), new Date(nowTs)));\n }\n }\n\n return pipe(\n TE.tryCatch(\n () => {\n return BetterPromise.fn(async () => {\n return crypto.subtle.verify(\n 'Ed25519',\n await crypto.subtle.importKey(\n 'raw',\n Buffer.from(\n options.test\n ? '40055058a4ee38156a06562e52eece92a771bcd8346a8c4615cb7376eddf72ec'\n : 'e7bf03a2fa4602af4580703d88dda5bb59f32ed8b02a56c187fe7d34caed242d',\n 'hex',\n ),\n 'Ed25519',\n false,\n ['verify'],\n ),\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion\n Buffer.from(signature as string, 'base64'),\n Buffer.from(`${botId}:WebAppData\\n${pairs.sort().join('\\n')}`),\n );\n }, options);\n },\n (e: unknown) => e,\n ),\n TE.chainW(isVerified => {\n return isVerified ? TE.right(undefined) : TE.left(new SignatureInvalidError());\n }),\n );\n}\n\n/**\n * @see validate3rdFp\n */\nexport function validate3rd(\n value: Validate3rdValue,\n botId: number,\n options?: Validate3rdOptions,\n): BetterPromise<void> {\n return BetterPromise.fn(async () => {\n await pipe(\n validate3rdFp(value, botId, options),\n TE.mapLeft(error => {\n throw error;\n }),\n )();\n });\n}\n\n/**\n * @param value - value to check.\n * @param botId - bot identifier\n * @param options - additional validation options.\n * @returns True is specified init data is signed by Telegram.\n */\nexport function isValid3rdFp(\n value: Validate3rdValue,\n botId: number,\n options?: Validate3rdOptions,\n): TE.TaskEither<void, boolean> {\n return pipe(validate3rdFp(value, botId, options), TE.match(\n () => E.right(false),\n () => E.right(true),\n ));\n}\n\n/**\n * @see isValid3rdFp\n */\nexport function isValid3rd(\n value: Validate3rdValue,\n botId: number,\n options?: Validate3rdOptions,\n): BetterPromise<boolean> {\n return BetterPromise.fn(() => pipe(\n isValid3rdFp(value, botId, options),\n TE.match(() => false, v => v),\n )());\n}\n\nexport function validateFp<Left>(\n async: false,\n value: ValidateValue,\n token: Text,\n signData: ValidateSignDataFpArg<false, Left>,\n options?: ValidateOptions,\n): E.Either<Left | ValidateError, void>;\n\nexport function validateFp<Left>(\n async: true,\n value: ValidateValue,\n token: Text,\n signData: ValidateSignDataFpArg<true, Left>,\n options?: ValidateAsyncOptions,\n): TE.TaskEither<Left | ValidateAsyncError, void>;\n\nexport function validateFp<Left>(\n async: boolean,\n value: ValidateValue,\n token: Text,\n signData: ValidateSignDataFpArg<boolean, Left>,\n options: ValidateOptions | ValidateAsyncOptions = {},\n):\n | E.Either<Left | ValidateError, void>\n | TE.TaskEither<Left | ValidateAsyncError, void> {\n // Init data required params.\n let authDate: Date | undefined;\n let authDateString: string | undefined;\n let hash: string | undefined;\n\n // All search params pairs presented as `k=v`.\n const pairs: string[] = [];\n\n // Iterate over all key-value pairs of parsed parameters and find required\n // parameters.\n (typeof value === 'string' ? new URLSearchParams(value) : value).forEach((value, key) => {\n if (key === 'hash') {\n hash = value;\n return;\n }\n\n if (key === 'auth_date') {\n authDateString = value;\n const authDateNum = parseInt(value, 10);\n if (!Number.isNaN(authDateNum)) {\n authDate = new Date(authDateNum * 1000);\n }\n }\n\n pairs.push(`${key}=${value}`);\n });\n\n // Hash and auth date always required.\n if (!hash) {\n return (async ? TE.left : E.left)(new SignatureMissingError(false));\n }\n\n if (!authDate) {\n return (async ? TE.left : E.left)(new AuthDateInvalidError(authDateString));\n }\n\n // In case, expiration time passed, we do additional parameters check.\n const { expiresIn = 86400 } = options;\n if (expiresIn > 0) {\n // Check if init data expired.\n const expiresAtTs = authDate.getTime() + (expiresIn * 1000);\n const nowTs = Date.now();\n if (expiresAtTs < nowTs) {\n return (async ? TE.left : E.left)(\n new ExpiredError(authDate, new Date(expiresAtTs), new Date(nowTs)),\n );\n }\n }\n\n // According to docs, we sort all the pairs in alphabetical order.\n pairs.sort();\n\n const eitherSignature = signData(pairs.join('\\n'), token, options);\n const onLeft = (error: Left) => E.left(error);\n const onRight = (signature: string) => (\n signature === hash ? E.right(undefined) : E.left(new SignatureInvalidError())\n );\n\n return typeof eitherSignature === 'function'\n ? pipe(eitherSignature, TE.matchW(onLeft, onRight))\n : pipe(eitherSignature, E.matchW(onLeft, onRight));\n}\n","import {\n parseInitDataQuery,\n parseInitDataQueryFp,\n type ParseInitDataQueryError,\n} from '@tma.js/transformers';\n\n/**\n * Parses an incoming value as init data.\n */\nexport const parse = parseInitDataQuery;\n\n/**\n * Parses an incoming value as init data.\n */\nexport const parseFp = parseInitDataQueryFp;\n\nexport { ParseInitDataQueryError as ParseError };\n"],"names":["value","pipe"],"mappings":"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"}