该软件包提供在 服务器端处理 Telegram 迷你应用程序初始化数据的实用程序。 要了解有关初始化数据及其用法的更多信息,请参阅 the documentation.安装
* c: z9 o! I6 b; z/ ~' O. B/ r6 k* ?- }pnpm :
2 ]0 | v0 h8 D- pnpm i @telegram-apps/init-data-node
复制代码 npm :
+ f# i4 S( ^, Y: K7 T$ S# y% B; x- npm i @telegram-apps/init-data-node
复制代码 yarn :# _( _; g2 s1 m z& j' ~
- yarn add @telegram-apps/init-data-node
复制代码 解析要将一个值解析为 init 数据,请使用 parse 方法。 该方法接受以 string 或 URLSearchParams 形式呈现的 init 数据。 - import { parse } from '@telegram-apps/init-data-node';9 o, Q! O1 L( Y9 a
- . c# ?+ q) V! l
- try {
3 t* ]* E% @; z3 e# Y( x6 j9 T - const initData = parse('...');
6 h& M" a1 ]$ z5 ~ - // {
! P% C: h0 b: i$ _2 Y - // canSendAfter: 10000,
. g8 u; |9 F5 k( } - // chat: {/ K, {' x) @. {& x7 K( {* j
- // id: 1,* o. Y) O; ~' j
- // type: 'group',/ L1 c9 J |! {0 }4 K
- // username: 'my-chat',
, t& [9 T6 L9 j( F) P( f; u - // title: 'chat-title',
' i. R/ L! ?& _4 N y - // photoUrl: 'chat-photo',& `5 P/ ~6 B0 Y9 o. |) M
- // },
9 g% z; U L1 p3 F l9 i - // chatInstance: '888',
4 u& z) e/ w8 [/ d) |: | - // chatType: 'sender',
5 c- ]" @) o$ [, Z5 C - // queryId: 'QUERY',
7 w: q5 b% p, I" f; q" W - // receiver: {) W; I( s; \* U* N4 }
- // addedToAttachmentMenu: false,: v3 l) C" R( h$ |+ J8 X4 W
- // allowsWriteToPm: true,
" }( o- ^/ O6 E) B @6 i - // firstName: 'receiver-first-name',
. O6 p! m: v# F& _# a0 | - // id: 991,* v0 c8 f8 X6 H' ^# m
- // isBot: false,
( v x) r+ I) g3 M - // isPremium: true,
/ ~/ b2 \( [& R; w T - // languageCode: 'ru', n5 h) c, g8 d' t* K7 Z
- // lastName: 'receiver-last-name',. d' X7 t$ O: `
- // photoUrl: 'receiver-photo',
9 u! [7 d! m+ O8 p9 ?6 K9 e$ D - // username: 'receiver-username',
. m1 a# j, L. }' A! T$ s) D' o0 h+ x - // }, G6 [1 Q* \$ e9 W& E3 q: d, G$ y
- // startParam: 'debug',/ j! q8 c" r0 p
- // user: {9 ^) o; Y+ N+ w
- // addedToAttachmentMenu: false,
1 Y. _% I1 s4 F- D5 U - // allowsWriteToPm: false,& X- ]) c* z! I
- // firstName: 'user-first-name',2 A( i, E4 k) A9 ~( U
- // id: 222,2 f3 w' F% q" Y9 |" p1 f
- // isBot: true,- E+ R; ^% P; \7 m& S
- // isPremium: false,; w7 e: ]( x. Y) E1 ] I$ c
- // languageCode: 'en',5 o$ K" D) L$ k0 W# ?0 B) b+ {
- // lastName: 'user-last-name',
: F0 s# U8 R8 c - // photoUrl: 'user-photo',) X0 Y# ?+ V( K3 N, D
- // username: 'user-username',4 x$ x2 h) x- E3 P6 g& l
- // },$ \, D& `" A( `8 v0 t
- // }
1 f" Y* Y! n) w& Q, r0 B - } catch (e) {; D8 D9 g3 J& u2 J; c
- console.error('Something is wrong', e);* L# A2 L5 e) p. A
- }
复制代码 验证validate要验证初始化数据的签名,需要使用validate函数。 它希望 以原始格式(搜索参数)传递初始化数据,并在 某些情况下出错。 - import { validate } from '@telegram-apps/init-data-node';
# o2 n' _* h {8 s# V1 L
. x2 V+ f% |( X# h/ {- const secretToken = '5768337691:AAH5YkoiEuPk8-FZa32hStHTqXiLPtAEhx8';4 q& \# g/ o2 A0 F; ^$ o
- const initData =
. h7 m1 R' S7 g9 \4 m; {# [ - 'query_id=AAHdF6IQAAAAAN0XohDhrOrc' +
% v N( y7 t6 \/ l1 S! |5 { - '&user=%7B%22id%22%3A279058397%2C%22first_name%22%3A%22Vladislav%22%2C%22last_name%22%3A%22Kibenko%22%2C%22username%22%3A%22vdkfrost%22%2C%22language_code%22%3A%22ru%22%2C%22is_premium%22%3Atrue%7D' +
5 w) t, ~( b z) q* J j V2 y2 k - '&auth_date=1662771648' +
~& I! f( Z* o; D3 q4 y$ ^6 | - '&hash=c501b71e775f74ce10e377dea85a7ea24ecd640b223ea86dfe453e0eaed2e2b2';& s% \2 I9 v! k; T5 P. z
1 F- F8 B7 ?0 r! K8 _% q- validate(initData, secretToken);
复制代码函数会在其中一种情况下出错: - ERR_AUTH_DATE_INVALID:auth_date 为空或未找到
- ERR_HASH_INVALID:hash 为空或未找到
- ERR_SIGN_INVALID:签名无效
- ERR_EXPIRED:初始数据已过期/ h6 X$ [5 b& q3 u, M% c
以下是您可以用来检查错误类型的代码: - import { validate, isErrorOfType } from '@telegram-apps/init-data-node';
8 b2 N5 P( p/ B. O. W% R
* I6 U7 z6 \3 {- try {
2 N- ]3 v, y: Q7 C" m - validate('init-data', 'token');
: h& }1 Y3 l+ i) ^ - } catch (e) {
5 T8 g: |# V7 O! k. C; B9 n- u - if (isErrorOfType('ERR_SIGN_INVALID')) {1 R$ T1 c0 J" Q# ?# D9 k$ a( k
- console.log('Sign is invalid');
# K1 T$ c; Y, K0 \3 W$ v8 S - }7 M4 E, I5 @2 _2 A6 z0 J! Y
- }
复制代码默认情况下,函数会检查初始化数据是否过期。 的默认过期时间设置为 1 天(86,400 秒)。 建议始终检查 初始化数据的有效期,因为它可能被盗但仍然有效。 要禁用此功能,将 { expiresIn: 0 } 作为第三个参数。 isValid或者,开发人员可以使用 isValid 函数来检查初始数据的有效性。 它不会引发错误,但会返回一个布尔值,表明初始数据的有效性。 - import { isValid } from '@telegram-apps/init-data-node';
/ ` \8 D2 ]# \6 J
( u E1 i* J! D& }( B0 c- if (isValid('init-data')) {
4 t9 k# M5 U. a. E, e5 s9 l) { - console.log('Init data is fine');) X- S* Q3 W( F% i* Q5 j
- }
复制代码 签名在某些情况下,开发人员可能需要创建自己的初始数据。 例如,如果您使用 KeyboardButton 或 InlineKeyboardButton, Telegram 不会自动发送这些数据。 Telegram 无法做到这一点,因为它不知道应该使用哪个 Telegram Bot 令牌 。 要实现这一过程,需要使用 sign 方法。 下面是完整的示例: Signing : - import { sign } from '@telegram-apps/init-data-node';8 s0 T6 {; _4 R6 C
- * |+ P+ z/ N) h. R: Y2 l2 ~4 b' d
- sign(' N( ^- i6 W' U( E4 o
- {
. Q9 \ T# N6 V% z9 `3 r - canSendAfter: 10000,+ ]. S6 c$ Q9 ]5 g1 p: T! H! w
- chat: { |5 \8 G+ @$ X+ u. O
- id: 1,
! A5 R2 E5 U3 K# }) e6 l - type: 'group',
# x; S+ [$ r) a$ F - username: 'my-chat',
) E/ Z& _" u; _% g; j1 X7 j v, {9 o - title: 'chat-title',% h5 @# J, Q9 ~" B/ s. Y: @9 r
- photoUrl: 'chat-photo',0 o! q6 X9 l7 t$ |1 U, H
- },! p7 l3 e6 P/ E
- chatInstance: '888',* A' @- F) T) h
- chatType: 'sender',+ m0 K. P( U7 s
- queryId: 'QUERY',1 ^& ^4 Z0 c+ t% j2 p' N
- receiver: {
2 m7 J# B" R* V+ o+ ~ R6 D - addedToAttachmentMenu: false,) q7 Y9 o+ q2 B" G
- allowsWriteToPm: true,
0 X8 @2 L4 ?: a( b, N5 B* f/ n - firstName: 'receiver-first-name',7 E# f8 Y) a1 G3 q7 q
- id: 991,
4 s/ c' e! Z/ p: t2 Y - isBot: false,) t2 v/ b4 {9 \$ e2 T1 Y5 \, _7 n
- isPremium: true,
$ i+ H6 Y7 K: F" _ i - languageCode: 'ru',
' c* E" B- \' x, [! S3 R7 [ - lastName: 'receiver-last-name',0 P" }" _" }2 F$ {( J" v! e
- photoUrl: 'receiver-photo',
0 J+ C0 l- q* Q& B6 Q4 s - username: 'receiver-username',
9 w7 h! R' [8 f- E6 r* _2 [ [ - },
' ~" f6 B. n' U5 I - startParam: 'debug',
4 K8 m* O, ?$ Y. J! }. {8 F - user: {1 l- @1 J6 M1 g$ _' @! r
- addedToAttachmentMenu: false,( B4 @2 Z$ r2 k) D* \2 k' [
- allowsWriteToPm: false,
d' L4 } i% Q: i1 A - firstName: 'user-first-name',
+ C {: E" e9 C- Z& v) ^ - id: 222,
* O) f! J/ U) W: M% T6 U* x/ E - isBot: true,/ @7 N9 M) U {7 h. D
- isPremium: false,
4 Z$ R. c; `; n3 m6 F }2 [ - languageCode: 'en',! Z- F, q$ D/ J( h/ n; T
- lastName: 'user-last-name',! d& ?' v* j* R3 h. }5 _
- photoUrl: 'user-photo',1 F* t Y6 H% \- a1 v! p3 D
- username: 'user-username',& o: H# B0 v. E5 d- x
- },6 \* P9 I( o, K0 P& Y" {
- },$ T, T! T" L+ o4 s+ B
- '5768337691:AAH5YkoiEuPk8-FZa32hStHTqXiLPtAEhx8',+ ] g" Q* H; F. ]1 X) z
- new Date(1000),
7 d" K: S7 x2 d5 q' y - );
复制代码Expected Result : - 'auth_date=1' +
" z8 W+ I8 x9 m# A2 a, Y; z! D - '&can_send_after=10000' +. c; X" G+ x6 o( C+ A6 h# T
- '&chat=%7B%22id%22%3A1%2C%22type%22%3A%22group%22%2C%22title%22%3A%22chat-title%22%2C%22photo_url%22%3A%22group%22%2C%22username%22%3A%22my-chat%22%7D' +
# U3 c# W% c7 A( z) ]7 r8 g - '&chat_instance=888' +
+ E0 k( B8 f# l: @$ } - '&chat_type=sender' +) r3 y* v( z8 _+ E# C, q$ R
- '&query_id=QUERY' +
. [9 g; X; f, p. r' h - '&receiver=%7B%22added_to_attachment_menu%22%3Afalse%2C%22allows_write_to_pm%22%3Atrue%2C%22first_name%22%3A%22receiver-first-name%22%2C%22id%22%3A991%2C%22is_bot%22%3Afalse%2C%22is_premium%22%3Atrue%2C%22language_code%22%3A%22ru%22%2C%22last_name%22%3A%22receiver-last-name%22%2C%22photo_url%22%3A%22receiver-photo%22%2C%22username%22%3A%22receiver-username%22%7D' +
, C7 |7 ~# A$ L( v& j9 A% C9 W - '&start_param=debug' +' P% @: W1 b* X8 z) z
- '&user=%7B%22added_to_attachment_menu%22%3Afalse%2C%22allows_write_to_pm%22%3Afalse%2C%22first_name%22%3A%22user-first-name%22%2C%22id%22%3A222%2C%22is_bot%22%3Atrue%2C%22is_premium%22%3Afalse%2C%22language_code%22%3A%22en%22%2C%22last_name%22%3A%22user-last-name%22%2C%22photo_url%22%3A%22user-photo%22%2C%22username%22%3A%22user-username%22%7D' +* j# d% {" g$ u" f1 t) p+ r8 a, z
- '&hash=47cfa22e72b887cba90c9cb833c5ea0f599975b6ce7193741844b5c4a4228b40'
复制代码该函数接受三个参数: - 要签名的数据:它表示经过解析的初始数据对象,不包括 authDate 和 hash 属性。
- 机器人令牌:该令牌由 [@BotFather] (https://t.me/botfather) 接收。
- 签署日期:此值将用作 authDate 属性的值。4 q; e5 W- `- c+ o& u5 c
因此,函数会返回带符号的 init 数据。 网络加密应用程序接口如果要在 Node.js 以外的环境中使用此软件包,开发人员可以使用 web 子目录,该子目录导出的方法与上述方法相同,但会返回承诺。 - import {
( e- z1 ^& x& S - validate,% B8 s4 G/ a: {
- sign,
: g) }7 Q+ e8 Z% X, X0 W - signData,
& F' t+ k5 S H; X" k$ K - isValid,
7 B% P& s |8 Q$ | O3 g3 p: ?5 K - } from '@telegram-apps/init-data-node/web';: e# V1 T! r7 y9 Q% g
- % U/ s* e3 J; j3 y
- await validate(...);" S! N( {# f4 b( W
- await sign(...);; N' ?% [5 ]. ~9 } Q2 \) {
- await signData(...);
7 y" _: C" c; I - await isValid(...);
复制代码 传递散列令牌 - Hashed Token所有软件包方法都允许开发人员使用散列令牌而不是原始令牌。 我们所说的 "散列令牌 "是指使用 HMAC-SHA-256 算法散列的令牌,其密钥来自 WebAppData,详见 文档的 validation 部分。 下面是一些例子: - import { validate, sign } from '@telegram-apps/init-data-node';
% d' Y1 b# ]9 E+ U3 O
- }; ?" l. f! U4 e" T( a- const secretTokenHashed = 'a5c609aa52f63cb5e6d8ceb6e4138726ea82bbc36bb786d64482d445ea38ee5f';
! T6 f* H! \2 C4 | - const initData =" ]% j, u" W2 z
- 'query_id=AAHdF6IQAAAAAN0XohDhrOrc' +
4 T6 p0 Y/ ?2 m$ ^ O5 x4 ]1 w - '&user=%7B%22id%22%3A279058397%2C%22first_name%22%3A%22Vladislav%22%2C%22last_name%22%3A%22Kibenko%22%2C%22username%22%3A%22vdkfrost%22%2C%22language_code%22%3A%22ru%22%2C%22is_premium%22%3Atrue%7D' +7 r& q' B2 U+ W* F/ w
- '&auth_date=1662771648' +
& Y2 D, p% ]' ^6 r: a2 L! T: ] - '&hash=c501b71e775f74ce10e377dea85a7ea24ecd640b223ea86dfe453e0eaed2e2b2';: b% ?. \' r0 t8 ^- k. a7 Q( w- T
5 H3 a" u& n, F8 i' B; k( V- // Validating.$ x; \/ r) {1 I2 g d
- validate(initData, secretTokenHashed, { tokenHashed: true });
& K- ^+ X+ O, i7 x
5 Y3 C6 C F( l# B: U- // Signing.
+ t& I2 G9 j1 N; i - sign(6 ~8 M5 M' f& u1 t/ }& s/ s
- {
; ~; w% b; i/ W s - canSendAfter: 10000,
$ j( ~6 {1 r3 v( n - chat: {
$ E# @- q, F: o - id: 1,- ]0 a8 _4 r# M' C6 t3 A) K* X8 t
- type: 'group',
4 T0 G: N6 V A( ^) J - username: 'my-chat',
' r9 n1 }" [$ ~+ l7 d - title: 'chat-title',. C8 S! f' x5 R: O4 B
- photoUrl: 'chat-photo',
/ F+ N4 E# N- I: Z4 r - }, I* g9 s7 o: n: ]
- chatInstance: '888',
; A) R) U8 A: [- h/ ]8 d - chatType: 'sender',
8 Z( J" j, p4 m5 ] - queryId: 'QUERY',$ ]$ @" J5 I3 R7 K3 U
- receiver: {
$ b8 h. L0 c9 R - addedToAttachmentMenu: false,
/ E5 V# n/ b7 y7 P) U - allowsWriteToPm: true,( a+ g o/ P$ A; n- g3 C$ \3 K! h
- firstName: 'receiver-first-name', x3 Y0 f2 h: F* a
- id: 991,' D* G8 k# Y( H
- isBot: false,, j; A& T$ J6 ? X9 m1 u
- isPremium: true,
) S5 J, {+ [- `0 H0 }9 K - languageCode: 'ru',
6 T# g9 i3 j; p* v# Z4 W3 B - lastName: 'receiver-last-name',8 G! p1 e# F$ \3 V! I. Z
- photoUrl: 'receiver-photo',1 _" E$ D7 t! r
- username: 'receiver-username',, e3 N7 H) y; _. q) r C
- },
# P0 u* K) J/ t - startParam: 'debug',5 F; S! \1 L% Z/ S! N, F
- user: {
6 {% Z# g: I+ z: m7 V6 a - addedToAttachmentMenu: false,% ?+ i/ v# x: P" X
- allowsWriteToPm: false,+ c5 \9 V$ }2 d3 o: \
- firstName: 'user-first-name',+ S6 k/ \! W5 d
- id: 222,* F. f7 H1 M+ f+ b7 {" ]7 U. i
- isBot: true,3 k# O# T/ A8 ~, V; c
- isPremium: false,
! Q! i! K! y& d: M0 E/ |: u g - languageCode: 'en',
9 z) L6 G, J6 @ f4 n' J4 A+ Q( j" B - lastName: 'user-last-name',9 }9 `9 b/ R: |) _% E( X- R
- photoUrl: 'user-photo'," g, F' \4 i0 X/ w9 M/ g5 ?
- username: 'user-username',
0 J) P+ h: c, Y, {, ` - },5 \$ o) g9 D6 ]4 z6 j3 u
- }, c/ ?" k& n! n/ a! y1 E
- secretTokenHashed,6 R. e0 s ?( r, l' _$ [
- new Date(1000),
* Z3 n( X3 P0 I; U$ ] - { tokenHashed: true }- ]+ c4 u2 }* t* r, C; Y
- );
复制代码使用这种方法可以减少直接传递原始标记的次数。
9 `! l$ B$ l5 w* c! S; W: V/ X& M+ @0 R8 x) t
9 _$ u4 e7 P! P+ p# O; E* d' Q) y
: d+ q& L. w! r4 h' J* X- G+ ?: M+ p! _0 D8 F+ Z
|