@mtcute/core 0.30.0 → 0.30.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/client.cjs +8 -0
  2. package/client.js +8 -0
  3. package/highlevel/client.d.cts +63 -1
  4. package/highlevel/client.d.ts +63 -1
  5. package/highlevel/methods/files/normalize-input-media.cjs +8 -0
  6. package/highlevel/methods/files/normalize-input-media.js +9 -1
  7. package/highlevel/methods/messages/create-rich-streaming-draft.cjs +39 -0
  8. package/highlevel/methods/messages/create-rich-streaming-draft.d.cts +42 -0
  9. package/highlevel/methods/messages/create-rich-streaming-draft.d.ts +42 -0
  10. package/highlevel/methods/messages/create-rich-streaming-draft.js +34 -0
  11. package/highlevel/methods/messages/normalize-rich-message.cjs +157 -0
  12. package/highlevel/methods/messages/normalize-rich-message.d.cts +10 -0
  13. package/highlevel/methods/messages/normalize-rich-message.d.ts +10 -0
  14. package/highlevel/methods/messages/normalize-rich-message.js +152 -0
  15. package/highlevel/methods/messages/send-rich-message.cjs +49 -0
  16. package/highlevel/methods/messages/send-rich-message.d.cts +38 -0
  17. package/highlevel/methods/messages/send-rich-message.d.ts +38 -0
  18. package/highlevel/methods/messages/send-rich-message.js +44 -0
  19. package/highlevel/methods.d.cts +3 -0
  20. package/highlevel/methods.d.ts +3 -0
  21. package/highlevel/types/bots/inline-message/factories.cjs +14 -0
  22. package/highlevel/types/bots/inline-message/factories.d.cts +9 -1
  23. package/highlevel/types/bots/inline-message/factories.d.ts +9 -1
  24. package/highlevel/types/bots/inline-message/factories.js +14 -0
  25. package/highlevel/types/bots/inline-message/types.d.cts +17 -1
  26. package/highlevel/types/bots/inline-message/types.d.ts +17 -1
  27. package/highlevel/types/media/input-media/types.d.cts +1 -1
  28. package/highlevel/types/media/input-media/types.d.ts +1 -1
  29. package/highlevel/types/messages/index.d.cts +1 -1
  30. package/highlevel/types/messages/index.d.ts +1 -1
  31. package/highlevel/types/messages/message.cjs +1 -1
  32. package/highlevel/types/messages/message.d.cts +1 -1
  33. package/highlevel/types/messages/message.d.ts +1 -1
  34. package/highlevel/types/messages/message.js +1 -1
  35. package/highlevel/types/messages/rich/index.d.cts +4 -0
  36. package/highlevel/types/messages/rich/index.d.ts +4 -0
  37. package/highlevel/types/messages/rich/inner.cjs +219 -0
  38. package/highlevel/types/messages/rich/inner.d.cts +127 -0
  39. package/highlevel/types/messages/rich/inner.d.ts +127 -0
  40. package/highlevel/types/messages/rich/inner.js +214 -0
  41. package/highlevel/types/messages/{rich-message.cjs → rich/rich-message.cjs} +6 -6
  42. package/highlevel/types/messages/{rich-message.d.cts → rich/rich-message.d.cts} +5 -5
  43. package/highlevel/types/messages/{rich-message.d.ts → rich/rich-message.d.ts} +5 -5
  44. package/highlevel/types/messages/{rich-message.js → rich/rich-message.js} +6 -6
  45. package/highlevel/types/messages/rich/types.d.cts +76 -0
  46. package/highlevel/types/messages/rich/types.d.ts +76 -0
  47. package/highlevel/updates/manager.cjs +4 -0
  48. package/highlevel/updates/manager.js +4 -0
  49. package/highlevel/utils/entities.cjs +176 -0
  50. package/highlevel/utils/entities.d.cts +18 -0
  51. package/highlevel/utils/entities.d.ts +18 -0
  52. package/highlevel/utils/entities.js +177 -1
  53. package/index.cjs +3 -1
  54. package/index.js +3 -1
  55. package/methods.cjs +4 -0
  56. package/methods.js +4 -0
  57. package/network/mtproxy/_fake-tls.cjs +169 -107
  58. package/network/mtproxy/_fake-tls.js +169 -107
  59. package/network/mtproxy/_fake-tls.test.d.cts +1 -0
  60. package/network/mtproxy/_fake-tls.test.d.ts +1 -0
  61. package/network/network-manager.cjs +1 -1
  62. package/network/network-manager.js +1 -1
  63. package/package.json +1 -1
  64. package/tl/api-schema.json +1 -1
  65. package/tl/binary/reader.cjs +115 -109
  66. package/tl/binary/reader.js +115 -109
  67. package/tl/binary/writer.cjs +243 -245
  68. package/tl/binary/writer.js +243 -245
  69. package/tl/index.d.cts +227 -216
  70. package/tl/index.d.ts +227 -216
  71. package/tl/inner-tl.cjs +3 -1
  72. package/tl/inner-tl.js +3 -1
  73. package/types/utils.d.cts +4 -0
  74. package/types/utils.d.ts +4 -0
  75. package/utils.cjs +2 -0
  76. package/utils.js +3 -1
@@ -1,3 +1,5 @@
1
+ import Long from "long";
2
+ import { getMarkedPeerId } from "../../utils/peer-utils.js";
1
3
  function joinTextWithEntities(parts, delim = "") {
2
4
  const textParts = [];
3
5
  const newEntities = [];
@@ -29,6 +31,180 @@ function joinTextWithEntities(parts, delim = "") {
29
31
  entities: newEntities
30
32
  };
31
33
  }
34
+ function _entityToRichTextWrapper(entity, text) {
35
+ const covered = () => text.slice(entity.offset, entity.offset + entity.length);
36
+ switch (entity._) {
37
+ case "messageEntityBold":
38
+ return (inner) => ({ _: "textBold", text: inner });
39
+ case "messageEntityItalic":
40
+ return (inner) => ({ _: "textItalic", text: inner });
41
+ case "messageEntityUnderline":
42
+ return (inner) => ({ _: "textUnderline", text: inner });
43
+ case "messageEntityStrike":
44
+ return (inner) => ({ _: "textStrike", text: inner });
45
+ case "messageEntityCode":
46
+ case "messageEntityPre":
47
+ return (inner) => ({ _: "textFixed", text: inner });
48
+ case "messageEntitySpoiler":
49
+ return (inner) => ({ _: "textSpoiler", text: inner });
50
+ case "messageEntityMention":
51
+ return (inner) => ({ _: "textMention", text: inner });
52
+ case "messageEntityHashtag":
53
+ return (inner) => ({ _: "textHashtag", text: inner });
54
+ case "messageEntityCashtag":
55
+ return (inner) => ({ _: "textCashtag", text: inner });
56
+ case "messageEntityBotCommand":
57
+ return (inner) => ({ _: "textBotCommand", text: inner });
58
+ case "messageEntityBankCard":
59
+ return (inner) => ({ _: "textBankCard", text: inner });
60
+ case "messageEntityUrl":
61
+ return (inner) => ({ _: "textUrl", text: inner, url: covered(), webpageId: Long.ZERO });
62
+ case "messageEntityTextUrl":
63
+ return (inner) => ({ _: "textUrl", text: inner, url: entity.url, webpageId: Long.ZERO });
64
+ case "messageEntityEmail":
65
+ return (inner) => ({ _: "textEmail", text: inner, email: covered() });
66
+ case "messageEntityPhone":
67
+ return (inner) => ({ _: "textPhone", text: inner, phone: covered() });
68
+ case "messageEntityMentionName":
69
+ return (inner) => ({ _: "textMentionName", text: inner, userId: entity.userId });
70
+ case "inputMessageEntityMentionName":
71
+ return (inner) => ({ _: "textMentionName", text: inner, userId: getMarkedPeerId(entity.userId) });
72
+ case "messageEntityCustomEmoji":
73
+ return () => ({ _: "textCustomEmoji", documentId: entity.documentId, alt: covered() });
74
+ case "messageEntityFormattedDate":
75
+ return (inner) => ({
76
+ _: "textDate",
77
+ text: inner,
78
+ date: entity.date,
79
+ relative: entity.relative,
80
+ shortTime: entity.shortTime,
81
+ longTime: entity.longTime,
82
+ shortDate: entity.shortDate,
83
+ longDate: entity.longDate,
84
+ dayOfWeek: entity.dayOfWeek
85
+ });
86
+ default:
87
+ return null;
88
+ }
89
+ }
90
+ function textWithEntitiesToRichText(input) {
91
+ const { text, entities } = input;
92
+ if (!text) return { _: "textEmpty" };
93
+ if (!entities?.length) return { _: "textPlain", text };
94
+ const bounds = /* @__PURE__ */ new Set([0, text.length]);
95
+ for (const e of entities) {
96
+ bounds.add(e.offset);
97
+ bounds.add(e.offset + e.length);
98
+ }
99
+ const sorted = [...bounds].filter((b) => b >= 0 && b <= text.length).sort((a, b) => a - b);
100
+ const segments = [];
101
+ for (let i = 0; i < sorted.length - 1; i++) {
102
+ const start = sorted[i];
103
+ const end = sorted[i + 1];
104
+ if (start === end) continue;
105
+ let node = { _: "textPlain", text: text.slice(start, end) };
106
+ const active = entities.filter((e) => e.offset <= start && e.offset + e.length >= end).sort((a, b) => a.length - b.length);
107
+ for (const e of active) {
108
+ const wrap = _entityToRichTextWrapper(e, text);
109
+ if (wrap) node = wrap(node);
110
+ }
111
+ segments.push(node);
112
+ }
113
+ if (segments.length === 0) return { _: "textEmpty" };
114
+ if (segments.length === 1) return segments[0];
115
+ return { _: "textConcat", texts: segments };
116
+ }
117
+ function _richTextNodeToEntity(node, offset, length) {
118
+ switch (node._) {
119
+ case "textBold":
120
+ return { _: "messageEntityBold", offset, length };
121
+ case "textItalic":
122
+ return { _: "messageEntityItalic", offset, length };
123
+ case "textUnderline":
124
+ return { _: "messageEntityUnderline", offset, length };
125
+ case "textStrike":
126
+ return { _: "messageEntityStrike", offset, length };
127
+ case "textFixed":
128
+ return { _: "messageEntityCode", offset, length };
129
+ case "textSpoiler":
130
+ return { _: "messageEntitySpoiler", offset, length };
131
+ case "textMention":
132
+ return { _: "messageEntityMention", offset, length };
133
+ case "textHashtag":
134
+ return { _: "messageEntityHashtag", offset, length };
135
+ case "textCashtag":
136
+ return { _: "messageEntityCashtag", offset, length };
137
+ case "textBotCommand":
138
+ return { _: "messageEntityBotCommand", offset, length };
139
+ case "textBankCard":
140
+ return { _: "messageEntityBankCard", offset, length };
141
+ case "textUrl":
142
+ return { _: "messageEntityTextUrl", offset, length, url: node.url };
143
+ case "textEmail":
144
+ return { _: "messageEntityEmail", offset, length };
145
+ case "textPhone":
146
+ return { _: "messageEntityPhone", offset, length };
147
+ case "textMentionName":
148
+ return { _: "messageEntityMentionName", offset, length, userId: node.userId };
149
+ case "textDate":
150
+ return {
151
+ _: "messageEntityFormattedDate",
152
+ offset,
153
+ length,
154
+ date: node.date,
155
+ relative: node.relative,
156
+ shortTime: node.shortTime,
157
+ longTime: node.longTime,
158
+ shortDate: node.shortDate,
159
+ longDate: node.longDate,
160
+ dayOfWeek: node.dayOfWeek
161
+ };
162
+ default:
163
+ return null;
164
+ }
165
+ }
166
+ function richTextToTextWithEntities(rich) {
167
+ const entities = [];
168
+ let text = "";
169
+ const walk = (node) => {
170
+ switch (node._) {
171
+ case "textEmpty":
172
+ return;
173
+ case "textPlain":
174
+ text += node.text;
175
+ return;
176
+ case "textConcat":
177
+ for (const t of node.texts) walk(t);
178
+ return;
179
+ case "textImage":
180
+ return;
181
+ case "textMath":
182
+ text += node.source;
183
+ return;
184
+ case "textCustomEmoji": {
185
+ const start = text.length;
186
+ text += node.alt;
187
+ entities.push({
188
+ _: "messageEntityCustomEmoji",
189
+ offset: start,
190
+ length: text.length - start,
191
+ documentId: node.documentId
192
+ });
193
+ return;
194
+ }
195
+ default: {
196
+ const start = text.length;
197
+ walk(node.text);
198
+ const entity = _richTextNodeToEntity(node, start, text.length - start);
199
+ if (entity) entities.push(entity);
200
+ }
201
+ }
202
+ };
203
+ walk(rich);
204
+ return { text, entities };
205
+ }
32
206
  export {
33
- joinTextWithEntities
207
+ joinTextWithEntities,
208
+ richTextToTextWithEntities,
209
+ textWithEntitiesToRichText
34
210
  };
package/index.cjs CHANGED
@@ -56,7 +56,8 @@ const messageReactions = require("./highlevel/types/messages/message-reactions.c
56
56
  const messageReplies = require("./highlevel/types/messages/message-replies.cjs");
57
57
  const message = require("./highlevel/types/messages/message.cjs");
58
58
  const repliedMessage = require("./highlevel/types/messages/replied-message.cjs");
59
- const richMessage = require("./highlevel/types/messages/rich-message.cjs");
59
+ const richMessage = require("./highlevel/types/messages/rich/rich-message.cjs");
60
+ const inner$1 = require("./highlevel/types/messages/rich/inner.cjs");
60
61
  const searchFilters = require("./highlevel/types/messages/search-filters.cjs");
61
62
  const suggestedPost = require("./highlevel/types/messages/suggested-post.cjs");
62
63
  const collectibleInfo = require("./highlevel/types/misc/collectible-info.cjs");
@@ -227,6 +228,7 @@ exports.MessageRepliesInfo = messageReplies.MessageRepliesInfo;
227
228
  exports.Message = message.Message;
228
229
  exports.RepliedMessageInfo = repliedMessage.RepliedMessageInfo;
229
230
  exports.RichMessage = richMessage.RichMessage;
231
+ exports.Rich = inner$1;
230
232
  exports.SearchFilters = searchFilters.SearchFilters;
231
233
  exports.SuggestedPostInfo = suggestedPost.SuggestedPostInfo;
232
234
  exports.CollectibleInfo = collectibleInfo.CollectibleInfo;
package/index.js CHANGED
@@ -49,7 +49,8 @@ import { MessageReactions } from "./highlevel/types/messages/message-reactions.j
49
49
  import { MessageRepliesInfo } from "./highlevel/types/messages/message-replies.js";
50
50
  import { Message } from "./highlevel/types/messages/message.js";
51
51
  import { RepliedMessageInfo } from "./highlevel/types/messages/replied-message.js";
52
- import { RichMessage } from "./highlevel/types/messages/rich-message.js";
52
+ import { RichMessage } from "./highlevel/types/messages/rich/rich-message.js";
53
+ import * as inner$1 from "./highlevel/types/messages/rich/inner.js";
53
54
  import { SearchFilters } from "./highlevel/types/messages/search-filters.js";
54
55
  import { SuggestedPostInfo } from "./highlevel/types/messages/suggested-post.js";
55
56
  import { CollectibleInfo } from "./highlevel/types/misc/collectible-info.js";
@@ -272,6 +273,7 @@ export {
272
273
  RawUpdateInfo,
273
274
  ReactionCount,
274
275
  RepliedMessageInfo,
276
+ inner$1 as Rich,
275
277
  RichMessage,
276
278
  SavedStarGift,
277
279
  SearchFilters,
package/methods.cjs CHANGED
@@ -157,6 +157,7 @@ const iterInviteLinks = require("./highlevel/methods/invite-links/iter-invite-li
157
157
  const revokeInviteLink = require("./highlevel/methods/invite-links/revoke-invite-link.cjs");
158
158
  const appendTodoList = require("./highlevel/methods/messages/append-todo-list.cjs");
159
159
  const closePoll = require("./highlevel/methods/messages/close-poll.cjs");
160
+ const createRichStreamingDraft = require("./highlevel/methods/messages/create-rich-streaming-draft.cjs");
160
161
  const createStreamingDraft = require("./highlevel/methods/messages/create-streaming-draft.cjs");
161
162
  const deleteMessages = require("./highlevel/methods/messages/delete-messages.cjs");
162
163
  const deleteScheduledMessages = require("./highlevel/methods/messages/delete-scheduled-messages.cjs");
@@ -199,6 +200,7 @@ const sendPaidReaction = require("./highlevel/methods/messages/send-paid-reactio
199
200
  const sendQuote = require("./highlevel/methods/messages/send-quote.cjs");
200
201
  const sendReaction = require("./highlevel/methods/messages/send-reaction.cjs");
201
202
  const sendReply = require("./highlevel/methods/messages/send-reply.cjs");
203
+ const sendRichMessage = require("./highlevel/methods/messages/send-rich-message.cjs");
202
204
  const sendScheduled = require("./highlevel/methods/messages/send-scheduled.cjs");
203
205
  const sendText = require("./highlevel/methods/messages/send-text.cjs");
204
206
  const sendTyping = require("./highlevel/methods/messages/send-typing.cjs");
@@ -444,6 +446,7 @@ exports.iterInviteLinks = iterInviteLinks.iterInviteLinks;
444
446
  exports.revokeInviteLink = revokeInviteLink.revokeInviteLink;
445
447
  exports.appendTodoList = appendTodoList.appendTodoList;
446
448
  exports.closePoll = closePoll.closePoll;
449
+ exports.createRichStreamingDraft = createRichStreamingDraft.createRichStreamingDraft;
447
450
  exports.createStreamingDraft = createStreamingDraft.createStreamingDraft;
448
451
  exports.deleteMessages = deleteMessages.deleteMessages;
449
452
  exports.deleteMessagesById = deleteMessages.deleteMessagesById;
@@ -498,6 +501,7 @@ exports.sendReaction = sendReaction.sendReaction;
498
501
  exports.replyMedia = sendReply.replyMedia;
499
502
  exports.replyMediaGroup = sendReply.replyMediaGroup;
500
503
  exports.replyText = sendReply.replyText;
504
+ exports.sendRichMessage = sendRichMessage.sendRichMessage;
501
505
  exports.sendScheduled = sendScheduled.sendScheduled;
502
506
  exports.sendText = sendText.sendText;
503
507
  exports.sendTyping = sendTyping.sendTyping;
package/methods.js CHANGED
@@ -150,6 +150,7 @@ import { iterInviteLinks } from "./highlevel/methods/invite-links/iter-invite-li
150
150
  import { revokeInviteLink } from "./highlevel/methods/invite-links/revoke-invite-link.js";
151
151
  import { appendTodoList } from "./highlevel/methods/messages/append-todo-list.js";
152
152
  import { closePoll } from "./highlevel/methods/messages/close-poll.js";
153
+ import { createRichStreamingDraft } from "./highlevel/methods/messages/create-rich-streaming-draft.js";
153
154
  import { createStreamingDraft } from "./highlevel/methods/messages/create-streaming-draft.js";
154
155
  import { deleteMessages, deleteMessagesById } from "./highlevel/methods/messages/delete-messages.js";
155
156
  import { deleteScheduledMessages } from "./highlevel/methods/messages/delete-scheduled-messages.js";
@@ -192,6 +193,7 @@ import { sendPaidReaction } from "./highlevel/methods/messages/send-paid-reactio
192
193
  import { quoteWithMedia, quoteWithMediaGroup, quoteWithText } from "./highlevel/methods/messages/send-quote.js";
193
194
  import { sendReaction } from "./highlevel/methods/messages/send-reaction.js";
194
195
  import { replyMedia, replyMediaGroup, replyText } from "./highlevel/methods/messages/send-reply.js";
196
+ import { sendRichMessage } from "./highlevel/methods/messages/send-rich-message.js";
195
197
  import { sendScheduled } from "./highlevel/methods/messages/send-scheduled.js";
196
198
  import { sendText } from "./highlevel/methods/messages/send-text.js";
197
199
  import { sendTyping } from "./highlevel/methods/messages/send-typing.js";
@@ -320,6 +322,7 @@ export {
320
322
  createForumTopic,
321
323
  createGroup,
322
324
  createInviteLink,
325
+ createRichStreamingDraft,
323
326
  createStickerSet,
324
327
  createStreamingDraft,
325
328
  createSupergroup,
@@ -520,6 +523,7 @@ export {
520
523
  sendPaidReaction,
521
524
  sendReaction,
522
525
  sendRecoveryCode,
526
+ sendRichMessage,
523
527
  sendScheduled,
524
528
  sendStarGift,
525
529
  sendStarGiftOffer,
@@ -8,6 +8,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
8
8
  const io = require("@fuman/io");
9
9
  const utils = require("@fuman/utils");
10
10
  const MAX_TLS_PACKET_LENGTH = 2878;
11
+ const MAX_TLS_HELLO_SIZE = 4096;
11
12
  const KEY_MOD = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEDn;
12
13
  const QUAD_RES_MOD = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEDn;
13
14
  const QUAD_RES_POW = 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6n;
@@ -34,7 +35,11 @@ function _isQuadraticResidue(a) {
34
35
  return r === 1n;
35
36
  }
36
37
  function executeTlsOperations(h) {
37
- h.string([22, 3, 1, 2, 0, 1, 0, 1, 252, 3, 3]);
38
+ h.string([22, 3, 1]);
39
+ h.beginScope();
40
+ h.string([1, 0]);
41
+ h.beginScope();
42
+ h.string([3, 3]);
38
43
  h.zero(32);
39
44
  h.string([32]);
40
45
  h.random(32);
@@ -72,67 +77,34 @@ function executeTlsOperations(h) {
72
77
  0,
73
78
  53,
74
79
  1,
75
- 0,
76
- 1,
77
- 147
80
+ 0
78
81
  ]);
79
- h.grease(2);
80
- h.string([0, 0, 0, 0]);
81
- h.beginScope();
82
82
  h.beginScope();
83
- h.string([0]);
84
- h.beginScope();
85
- h.domain();
86
- h.endScope();
87
- h.endScope();
88
- h.endScope();
89
- h.string([0, 23, 0, 0, 255, 1, 0, 1, 0, 0, 10, 0, 10, 0, 8]);
90
- h.grease(4);
91
- h.string(
92
- [
93
- 0,
94
- 29,
95
- 0,
96
- 23,
97
- 0,
98
- 24,
99
- 0,
100
- 11,
101
- 0,
102
- 2,
103
- 1,
104
- 0,
105
- 0,
106
- 35,
107
- 0,
108
- 0,
109
- 0,
110
- 16,
111
- 0,
112
- 14,
113
- 0,
114
- 12,
115
- 2,
116
- 104,
117
- 50,
118
- 8,
119
- 104,
120
- 116,
121
- 116,
122
- 112,
123
- 47,
124
- 49,
125
- 46,
126
- 49,
127
- 0,
128
- 5,
129
- 0,
130
- 5,
131
- 1,
132
- 0,
133
- 0,
134
- 0,
135
- 0,
83
+ h.grease(2);
84
+ h.string([0, 0]);
85
+ h.permutation([
86
+ (w) => {
87
+ w.string([0, 0]);
88
+ w.beginScope();
89
+ w.beginScope();
90
+ w.string([0]);
91
+ w.beginScope();
92
+ w.domain();
93
+ w.endScope();
94
+ w.endScope();
95
+ w.endScope();
96
+ },
97
+ (w) => w.string([0, 5, 0, 5, 1, 0, 0, 0, 0]),
98
+ // status_request
99
+ (w) => {
100
+ w.string([0, 10, 0, 12, 0, 10]);
101
+ w.grease(4);
102
+ w.string([17, 236, 0, 29, 0, 23, 0, 24]);
103
+ },
104
+ (w) => w.string([0, 11, 0, 2, 1, 0]),
105
+ // ec_point_formats
106
+ (w) => w.string([
107
+ // signature_algorithms
136
108
  0,
137
109
  13,
138
110
  0,
@@ -154,27 +126,76 @@ function executeTlsOperations(h) {
154
126
  8,
155
127
  6,
156
128
  6,
157
- 1,
129
+ 1
130
+ ]),
131
+ (w) => w.string([
132
+ // application_layer_protocol_negotiation (ALPN)
158
133
  0,
159
- 18,
160
- 0,
161
- 0,
162
- 0,
163
- 51,
134
+ 16,
164
135
  0,
165
- 43,
136
+ 14,
166
137
  0,
167
- 41
168
- ]
169
- );
170
- h.grease(4);
171
- h.string([0, 1, 0, 0, 29, 0, 32]);
172
- h.key();
173
- h.string([0, 45, 0, 2, 1, 1, 0, 43, 0, 11, 10]);
174
- h.grease(6);
175
- h.string([3, 4, 3, 3, 3, 2, 3, 1, 0, 27, 0, 3, 2, 0, 2]);
138
+ 12,
139
+ 2,
140
+ 104,
141
+ 50,
142
+ 8,
143
+ 104,
144
+ 116,
145
+ 116,
146
+ 112,
147
+ 47,
148
+ 49,
149
+ 46,
150
+ 49
151
+ ]),
152
+ (w) => w.string([0, 18, 0, 0]),
153
+ // signed_certificate_timestamp
154
+ (w) => w.string([0, 23, 0, 0]),
155
+ // extended_master_secret
156
+ (w) => w.string([0, 27, 0, 3, 2, 0, 2]),
157
+ // compress_certificate
158
+ (w) => w.string([0, 35, 0, 0]),
159
+ // session_ticket
160
+ (w) => {
161
+ w.string([0, 43, 0, 7, 6]);
162
+ w.grease(6);
163
+ w.string([3, 4, 3, 3]);
164
+ },
165
+ (w) => w.string([0, 45, 0, 2, 1, 1]),
166
+ // psk_key_exchange_modes
167
+ (w) => {
168
+ w.string([0, 51, 4, 239, 4, 237]);
169
+ w.grease(4);
170
+ w.string([0, 1, 0, 17, 236, 4, 192]);
171
+ w.mlKem768Key();
172
+ w.key();
173
+ w.string([0, 29, 0, 32]);
174
+ w.key();
175
+ },
176
+ (w) => w.string([68, 205, 0, 5, 0, 3, 2, 104, 50]),
177
+ // application_settings (ALPS)
178
+ (w) => {
179
+ w.string([254, 13]);
180
+ w.beginScope();
181
+ w.string([0, 0, 1, 0, 1]);
182
+ w.random(1);
183
+ w.string([0, 32]);
184
+ w.random(32);
185
+ w.beginScope();
186
+ w.echPayload();
187
+ w.endScope();
188
+ w.endScope();
189
+ },
190
+ (w) => w.string([255, 1, 0, 1, 0])
191
+ // renegotiation_info
192
+ ]);
176
193
  h.grease(3);
177
- h.string([0, 1, 0, 0, 21]);
194
+ h.string([0, 1, 0]);
195
+ h.padding();
196
+ h.endScope();
197
+ h.endScope();
198
+ h.endScope();
178
199
  }
179
200
  function initGrease(crypto, size) {
180
201
  const buf = crypto.randomBytes(size);
@@ -189,12 +210,12 @@ function initGrease(crypto, size) {
189
210
  return buf;
190
211
  }
191
212
  class TlsHelloWriter {
192
- constructor(crypto, size, domain) {
213
+ constructor(crypto, domain, grease) {
193
214
  this.crypto = crypto;
194
215
  this._domain = domain;
195
- this.buf = utils.u8.alloc(size);
216
+ this.buf = utils.u8.alloc(MAX_TLS_HELLO_SIZE);
196
217
  this.dv = utils.typed.toDataView(this.buf);
197
- this._grease = initGrease(this.crypto, 7);
218
+ this._grease = grease ?? initGrease(this.crypto, 7);
198
219
  }
199
220
  buf;
200
221
  dv;
@@ -235,6 +256,24 @@ class TlsHelloWriter {
235
256
  }
236
257
  }
237
258
  }
259
+ // fake X25519MLKEM768 hybrid keyshare's ml-kem-768 part: 384 coefficients
260
+ // (mod 3329) packed 3 bytes per 2 coefficients, followed by 32 random bytes
261
+ mlKem768Key() {
262
+ const rnd = this.crypto.randomBytes(384 * 8);
263
+ const dv = utils.typed.toDataView(rnd);
264
+ for (let i = 0; i < 384; i++) {
265
+ const a = dv.getUint32(i * 8, true) % 3329;
266
+ const b = dv.getUint32(i * 8 + 4, true) % 3329;
267
+ this.buf[this.pos++] = a & 255;
268
+ this.buf[this.pos++] = (a >> 8) + ((b & 15) << 4);
269
+ this.buf[this.pos++] = b >> 4;
270
+ }
271
+ this.random(32);
272
+ }
273
+ // GREASE ECH payload: random bytes of length 144/176/208/240
274
+ echPayload() {
275
+ this.random(this._randomInt(4) * 32 + 144);
276
+ }
238
277
  beginScope() {
239
278
  this._scopes.push(this.pos);
240
279
  this.pos += 2;
@@ -244,29 +283,55 @@ class TlsHelloWriter {
244
283
  if (begin === void 0) {
245
284
  throw new Error("endScope called without beginScope");
246
285
  }
247
- const end = this.pos;
248
- const size = end - begin - 2;
249
- this.dv.setUint16(begin, size);
286
+ this.dv.setUint16(begin, this.pos - begin - 2);
250
287
  }
251
- async finish(secret) {
252
- const padSize = 515 - this.pos;
253
- const unixTime = ~~(Date.now() / 1e3);
288
+ // render each part into its own buffer, then emit them in random order —
289
+ // mimics chrome's per-connection tls extension shuffling
290
+ permutation(parts) {
291
+ const rendered = parts.map((fn) => {
292
+ const sub = new TlsHelloWriter(this.crypto, this._domain, this._grease);
293
+ fn(sub);
294
+ return sub.buf.subarray(0, sub.pos);
295
+ });
296
+ for (let i = rendered.length - 1; i > 0; i--) {
297
+ const j = this._randomInt(i + 1);
298
+ const tmp = rendered[i];
299
+ rendered[i] = rendered[j];
300
+ rendered[j] = tmp;
301
+ }
302
+ for (const part of rendered) {
303
+ this.string(part);
304
+ }
305
+ }
306
+ // tls padding extension, only emitted for hellos smaller than 513 bytes
307
+ padding() {
308
+ if (this.pos >= 513) return;
309
+ const size = 513 - this.pos;
310
+ this.string([0, 21]);
254
311
  this.beginScope();
255
- this.zero(padSize);
312
+ this.zero(size);
256
313
  this.endScope();
257
- const hash = await this.crypto.hmacSha256(this.buf, secret);
314
+ }
315
+ _randomInt(max) {
316
+ return utils.typed.toDataView(this.crypto.randomBytes(4)).getUint32(0, true) % max;
317
+ }
318
+ async finish(secret) {
319
+ const data = this.buf.subarray(0, this.pos);
320
+ const unixTime = ~~(Date.now() / 1e3);
321
+ const hash = await this.crypto.hmacSha256(data, secret);
258
322
  const dv = utils.typed.toDataView(hash);
259
323
  const old = dv.getInt32(28, true);
260
324
  dv.setInt32(28, old ^ unixTime, true);
261
- this.buf.set(hash, 11);
262
- return this.buf;
325
+ data.set(hash, 11);
326
+ return data;
263
327
  }
264
328
  }
265
329
  async function generateFakeTlsHeader(domain, secret, crypto) {
266
- const writer = new TlsHelloWriter(crypto, 517, domain);
330
+ const writer = new TlsHelloWriter(crypto, domain);
267
331
  executeTlsOperations(writer);
268
332
  return writer.finish(secret);
269
333
  }
334
+ const EMPTY_BYTES = io.Bytes.from(utils.u8.empty);
270
335
  class FakeTlsPacketCodec {
271
336
  // protected _stream: Buffer = Buffer.alloc(0)
272
337
  constructor(_inner) {
@@ -301,23 +366,20 @@ class FakeTlsPacketCodec {
301
366
  }
302
367
  async decode(reader, eof) {
303
368
  if (eof) return null;
304
- if (reader.available < 5) return null;
305
- const header = reader.readSync(3);
306
- if (header[0] !== 23 || header[1] !== 3 || header[2] !== 3) {
307
- throw new Error("Invalid TLS header");
308
- }
309
- const length = io.read.uint16be(reader);
310
- if (length < reader.available - 5) {
311
- reader.rewind(5);
312
- return null;
313
- }
314
- const packet = reader.readSync(length);
315
- const inner = await this._inner.decode(io.Bytes.from(packet), eof);
316
- if (!inner) {
317
- reader.rewind(5 + length);
318
- return null;
369
+ while (reader.available >= 5) {
370
+ const header = reader.readSync(3);
371
+ if (header[0] !== 23 || header[1] !== 3 || header[2] !== 3) {
372
+ throw new Error("Invalid TLS header");
373
+ }
374
+ const length = io.read.uint16be(reader);
375
+ if (reader.available < length) {
376
+ reader.rewind(5);
377
+ break;
378
+ }
379
+ const inner = await this._inner.decode(io.Bytes.from(reader.readSync(length)), eof);
380
+ if (inner) return inner;
319
381
  }
320
- return inner;
382
+ return this._inner.decode(EMPTY_BYTES, eof);
321
383
  }
322
384
  reset() {
323
385
  this._isFirstTls = true;