@casys/mcp-bridge 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/esm/_dnt.shims.d.ts +2 -0
  2. package/esm/_dnt.shims.d.ts.map +1 -0
  3. package/esm/_dnt.shims.js +57 -0
  4. package/esm/adapters/base-adapter.d.ts +25 -0
  5. package/esm/adapters/base-adapter.d.ts.map +1 -0
  6. package/esm/adapters/base-adapter.js +86 -0
  7. package/esm/adapters/line/adapter.d.ts +11 -0
  8. package/esm/adapters/line/adapter.d.ts.map +1 -0
  9. package/esm/adapters/line/adapter.js +10 -0
  10. package/esm/adapters/line/types.d.ts +25 -0
  11. package/esm/adapters/line/types.d.ts.map +1 -0
  12. package/esm/adapters/line/types.js +4 -0
  13. package/esm/adapters/telegram/adapter.d.ts +11 -0
  14. package/esm/adapters/telegram/adapter.d.ts.map +1 -0
  15. package/esm/adapters/telegram/adapter.js +10 -0
  16. package/esm/adapters/telegram/platform-adapter.d.ts +40 -0
  17. package/esm/adapters/telegram/platform-adapter.d.ts.map +1 -0
  18. package/esm/adapters/telegram/platform-adapter.js +214 -0
  19. package/esm/adapters/telegram/sdk-bridge.d.ts +8 -0
  20. package/esm/adapters/telegram/sdk-bridge.d.ts.map +1 -0
  21. package/esm/adapters/telegram/sdk-bridge.js +22 -0
  22. package/esm/adapters/telegram/types.d.ts +93 -0
  23. package/esm/adapters/telegram/types.d.ts.map +1 -0
  24. package/esm/adapters/telegram/types.js +6 -0
  25. package/esm/client/bridge.js +424 -0
  26. package/esm/core/adapter.d.ts +88 -0
  27. package/esm/core/adapter.d.ts.map +1 -0
  28. package/esm/core/adapter.js +10 -0
  29. package/esm/core/bridge-client.d.ts +77 -0
  30. package/esm/core/bridge-client.d.ts.map +1 -0
  31. package/esm/core/bridge-client.js +275 -0
  32. package/esm/core/message-router.d.ts +71 -0
  33. package/esm/core/message-router.d.ts.map +1 -0
  34. package/esm/core/message-router.js +187 -0
  35. package/esm/core/protocol.d.ts +116 -0
  36. package/esm/core/protocol.d.ts.map +1 -0
  37. package/esm/core/protocol.js +203 -0
  38. package/esm/core/resource-resolver.d.ts +27 -0
  39. package/esm/core/resource-resolver.d.ts.map +1 -0
  40. package/esm/core/resource-resolver.js +85 -0
  41. package/esm/core/transport.d.ts +46 -0
  42. package/esm/core/transport.d.ts.map +1 -0
  43. package/esm/core/transport.js +85 -0
  44. package/esm/core/types.d.ts +187 -0
  45. package/esm/core/types.d.ts.map +1 -0
  46. package/esm/core/types.js +35 -0
  47. package/esm/mod.d.ts +36 -0
  48. package/esm/mod.d.ts.map +1 -0
  49. package/esm/mod.js +33 -0
  50. package/esm/package.json +3 -0
  51. package/esm/resource-server/csp.d.ts +36 -0
  52. package/esm/resource-server/csp.d.ts.map +1 -0
  53. package/esm/resource-server/csp.js +36 -0
  54. package/esm/resource-server/injector.d.ts +18 -0
  55. package/esm/resource-server/injector.d.ts.map +1 -0
  56. package/esm/resource-server/injector.js +39 -0
  57. package/esm/resource-server/server.d.ts +107 -0
  58. package/esm/resource-server/server.d.ts.map +1 -0
  59. package/esm/resource-server/server.js +483 -0
  60. package/esm/resource-server/session.d.ts +60 -0
  61. package/esm/resource-server/session.d.ts.map +1 -0
  62. package/esm/resource-server/session.js +86 -0
  63. package/esm/resource-server/telegram-auth.d.ts +45 -0
  64. package/esm/resource-server/telegram-auth.d.ts.map +1 -0
  65. package/esm/resource-server/telegram-auth.js +161 -0
  66. package/package.json +31 -0
  67. package/script/_dnt.shims.d.ts +2 -0
  68. package/script/_dnt.shims.d.ts.map +1 -0
  69. package/script/_dnt.shims.js +60 -0
  70. package/script/adapters/base-adapter.d.ts +25 -0
  71. package/script/adapters/base-adapter.d.ts.map +1 -0
  72. package/script/adapters/base-adapter.js +113 -0
  73. package/script/adapters/line/adapter.d.ts +11 -0
  74. package/script/adapters/line/adapter.d.ts.map +1 -0
  75. package/script/adapters/line/adapter.js +14 -0
  76. package/script/adapters/line/types.d.ts +25 -0
  77. package/script/adapters/line/types.d.ts.map +1 -0
  78. package/script/adapters/line/types.js +5 -0
  79. package/script/adapters/telegram/adapter.d.ts +11 -0
  80. package/script/adapters/telegram/adapter.d.ts.map +1 -0
  81. package/script/adapters/telegram/adapter.js +14 -0
  82. package/script/adapters/telegram/platform-adapter.d.ts +40 -0
  83. package/script/adapters/telegram/platform-adapter.d.ts.map +1 -0
  84. package/script/adapters/telegram/platform-adapter.js +241 -0
  85. package/script/adapters/telegram/sdk-bridge.d.ts +8 -0
  86. package/script/adapters/telegram/sdk-bridge.d.ts.map +1 -0
  87. package/script/adapters/telegram/sdk-bridge.js +48 -0
  88. package/script/adapters/telegram/types.d.ts +93 -0
  89. package/script/adapters/telegram/types.d.ts.map +1 -0
  90. package/script/adapters/telegram/types.js +7 -0
  91. package/script/client/bridge.js +424 -0
  92. package/script/core/adapter.d.ts +88 -0
  93. package/script/core/adapter.d.ts.map +1 -0
  94. package/script/core/adapter.js +11 -0
  95. package/script/core/bridge-client.d.ts +77 -0
  96. package/script/core/bridge-client.d.ts.map +1 -0
  97. package/script/core/bridge-client.js +302 -0
  98. package/script/core/message-router.d.ts +71 -0
  99. package/script/core/message-router.d.ts.map +1 -0
  100. package/script/core/message-router.js +191 -0
  101. package/script/core/protocol.d.ts +116 -0
  102. package/script/core/protocol.d.ts.map +1 -0
  103. package/script/core/protocol.js +230 -0
  104. package/script/core/resource-resolver.d.ts +27 -0
  105. package/script/core/resource-resolver.d.ts.map +1 -0
  106. package/script/core/resource-resolver.js +89 -0
  107. package/script/core/transport.d.ts +46 -0
  108. package/script/core/transport.d.ts.map +1 -0
  109. package/script/core/transport.js +112 -0
  110. package/script/core/types.d.ts +187 -0
  111. package/script/core/types.d.ts.map +1 -0
  112. package/script/core/types.js +38 -0
  113. package/script/mod.d.ts +36 -0
  114. package/script/mod.d.ts.map +1 -0
  115. package/script/mod.js +76 -0
  116. package/script/package.json +3 -0
  117. package/script/resource-server/csp.d.ts +36 -0
  118. package/script/resource-server/csp.d.ts.map +1 -0
  119. package/script/resource-server/csp.js +39 -0
  120. package/script/resource-server/injector.d.ts +18 -0
  121. package/script/resource-server/injector.d.ts.map +1 -0
  122. package/script/resource-server/injector.js +42 -0
  123. package/script/resource-server/server.d.ts +107 -0
  124. package/script/resource-server/server.d.ts.map +1 -0
  125. package/script/resource-server/server.js +487 -0
  126. package/script/resource-server/session.d.ts +60 -0
  127. package/script/resource-server/session.d.ts.map +1 -0
  128. package/script/resource-server/session.js +90 -0
  129. package/script/resource-server/telegram-auth.d.ts +45 -0
  130. package/script/resource-server/telegram-auth.d.ts.map +1 -0
  131. package/script/resource-server/telegram-auth.js +164 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telegram-auth.d.ts","sourceRoot":"","sources":["../../src/resource-server/telegram-auth.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,8CAA8C;AAC9C,MAAM,WAAW,kBAAkB;IACjC,qCAAqC;IACrC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,qDAAqD;IACrD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,yBAAyB;IACzB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,yBAAyB;IACzB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,wBAAwB;IACxB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,yCAAyC;IACzC,QAAQ,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC;IACzB,wDAAwD;IACxD,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AASD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,wBAAwB,CAC5C,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,aAAa,GAAE,MAAgC,GAC9C,OAAO,CAAC,kBAAkB,CAAC,CA+G7B"}
@@ -0,0 +1,164 @@
1
+ "use strict";
2
+ /**
3
+ * Telegram Mini App initData HMAC-SHA256 server-side validation.
4
+ *
5
+ * Implements the algorithm documented at:
6
+ * @see https://core.telegram.org/bots/webapps#validating-data-received-via-the-mini-app
7
+ *
8
+ * Uses the Web Crypto API exclusively (works in Deno and Node.js 18+).
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.validateTelegramInitData = validateTelegramInitData;
12
+ /** Default maximum age for auth_date: 24 hours. */
13
+ const DEFAULT_MAX_AGE_SECONDS = 86_400;
14
+ // ---------------------------------------------------------------------------
15
+ // Public API
16
+ // ---------------------------------------------------------------------------
17
+ /**
18
+ * Validate Telegram Mini App `initData`.
19
+ *
20
+ * Algorithm:
21
+ * 1. Parse the initData query string.
22
+ * 2. Extract and remove the `hash` parameter.
23
+ * 3. Sort remaining key=value pairs alphabetically by key.
24
+ * 4. Join them with `\n` to form data_check_string.
25
+ * 5. Derive secret_key = HMAC-SHA256(key="WebAppData", data=botToken).
26
+ * 6. Compute expected = HMAC-SHA256(key=secret_key, data=data_check_string).
27
+ * 7. Compare hex(expected) with hash using constant-time comparison.
28
+ * 8. Check auth_date freshness.
29
+ *
30
+ * @param initData - The raw initData query string from Telegram.
31
+ * @param botToken - The bot token used to sign the data.
32
+ * @param maxAgeSeconds - Maximum acceptable age of auth_date. Defaults to 86400 (24h).
33
+ * @returns A promise resolving to the validation result.
34
+ */
35
+ async function validateTelegramInitData(initData, botToken, maxAgeSeconds = DEFAULT_MAX_AGE_SECONDS) {
36
+ // -----------------------------------------------------------------------
37
+ // 1. Input validation (fail-fast)
38
+ // -----------------------------------------------------------------------
39
+ if (!initData || typeof initData !== "string") {
40
+ return { valid: false, error: "initData is required and must be a non-empty string" };
41
+ }
42
+ if (!botToken || typeof botToken !== "string") {
43
+ throw new Error("[telegram-auth] botToken is required. " +
44
+ "Provide the Telegram Bot token for HMAC-SHA256 validation.");
45
+ }
46
+ // -----------------------------------------------------------------------
47
+ // 2. Parse query string and extract hash
48
+ // -----------------------------------------------------------------------
49
+ const params = new URLSearchParams(initData);
50
+ const receivedHash = params.get("hash");
51
+ if (!receivedHash) {
52
+ return { valid: false, error: "Missing 'hash' parameter in initData" };
53
+ }
54
+ const authDateRaw = params.get("auth_date");
55
+ if (!authDateRaw) {
56
+ return { valid: false, error: "Missing 'auth_date' parameter in initData" };
57
+ }
58
+ const authDateUnix = parseInt(authDateRaw, 10);
59
+ if (isNaN(authDateUnix)) {
60
+ return { valid: false, error: "Invalid 'auth_date' parameter: not a valid integer" };
61
+ }
62
+ // -----------------------------------------------------------------------
63
+ // 3. Build data_check_string: sorted key=value pairs excluding `hash`
64
+ // -----------------------------------------------------------------------
65
+ params.delete("hash");
66
+ const pairs = [];
67
+ for (const [key, value] of params.entries()) {
68
+ pairs.push(`${key}=${value}`);
69
+ }
70
+ pairs.sort();
71
+ const dataCheckString = pairs.join("\n");
72
+ // -----------------------------------------------------------------------
73
+ // 4. Compute HMAC-SHA256 and compare
74
+ // -----------------------------------------------------------------------
75
+ const secretKey = await hmacSha256(new TextEncoder().encode("WebAppData"), new TextEncoder().encode(botToken));
76
+ const receivedHashBytes = hexToBytes(receivedHash);
77
+ if (!receivedHashBytes) {
78
+ return { valid: false, error: "Invalid 'hash' parameter: not valid hex" };
79
+ }
80
+ // Use crypto.subtle.verify for inherently timing-safe comparison
81
+ const verifyKey = await crypto.subtle.importKey("raw", secretKey, { name: "HMAC", hash: "SHA-256" }, false, ["verify"]);
82
+ const isValid = await crypto.subtle.verify("HMAC", verifyKey, receivedHashBytes, new TextEncoder().encode(dataCheckString));
83
+ if (!isValid) {
84
+ return { valid: false, error: "HMAC-SHA256 hash mismatch: initData signature is invalid" };
85
+ }
86
+ // -----------------------------------------------------------------------
87
+ // 5. Check auth_date freshness
88
+ // -----------------------------------------------------------------------
89
+ const authDate = new Date(authDateUnix * 1000);
90
+ const nowSeconds = Math.floor(Date.now() / 1000);
91
+ const ageSeconds = nowSeconds - authDateUnix;
92
+ if (ageSeconds > maxAgeSeconds) {
93
+ return {
94
+ valid: false,
95
+ error: `initData expired: auth_date is ${ageSeconds}s old, max allowed is ${maxAgeSeconds}s`,
96
+ };
97
+ }
98
+ if (ageSeconds < -60) {
99
+ // Allow 60s clock skew into the future, but reject beyond that
100
+ return {
101
+ valid: false,
102
+ error: `initData auth_date is ${-ageSeconds}s in the future (beyond 60s tolerance)`,
103
+ };
104
+ }
105
+ // -----------------------------------------------------------------------
106
+ // 6. Parse user data
107
+ // -----------------------------------------------------------------------
108
+ const result = {
109
+ valid: true,
110
+ authDate,
111
+ ...parseUserData(params.get("user")),
112
+ };
113
+ return result;
114
+ }
115
+ // ---------------------------------------------------------------------------
116
+ // Internal helpers
117
+ // ---------------------------------------------------------------------------
118
+ /**
119
+ * Compute HMAC-SHA256 using Web Crypto API.
120
+ *
121
+ * @param key - The HMAC key as raw bytes.
122
+ * @param data - The message to sign.
123
+ * @returns The HMAC digest as a Uint8Array.
124
+ */
125
+ async function hmacSha256(key, data) {
126
+ const cryptoKey = await crypto.subtle.importKey("raw", key, { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
127
+ const signature = await crypto.subtle.sign("HMAC", cryptoKey, data);
128
+ return new Uint8Array(signature);
129
+ }
130
+ /** Convert a hex string to Uint8Array. Returns null if invalid hex. */
131
+ function hexToBytes(hex) {
132
+ if (hex.length % 2 !== 0 || !/^[0-9a-fA-F]+$/.test(hex)) {
133
+ return null;
134
+ }
135
+ const bytes = new Uint8Array(hex.length / 2);
136
+ for (let i = 0; i < hex.length; i += 2) {
137
+ bytes[i / 2] = parseInt(hex.substring(i, i + 2), 16);
138
+ }
139
+ return bytes;
140
+ }
141
+ /**
142
+ * Parse the `user` JSON field from initData.
143
+ *
144
+ * Returns an object with userId, username, firstName, lastName if present.
145
+ * Returns an empty object if user data is absent or unparseable.
146
+ */
147
+ function parseUserData(userJson) {
148
+ if (!userJson)
149
+ return {};
150
+ try {
151
+ const user = JSON.parse(userJson);
152
+ return {
153
+ userId: typeof user.id === "number" ? user.id : undefined,
154
+ username: typeof user.username === "string" ? user.username : undefined,
155
+ firstName: typeof user.first_name === "string" ? user.first_name : undefined,
156
+ lastName: typeof user.last_name === "string" ? user.last_name : undefined,
157
+ };
158
+ }
159
+ catch {
160
+ // User JSON is optional data enrichment; a parsing failure here
161
+ // does not invalidate the HMAC signature itself.
162
+ return {};
163
+ }
164
+ }